remote-codex 0.11.3 → 0.11.4
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 +4 -0
- package/apps/relay-server/dist/index.js +35 -2
- package/apps/supervisor-api/dist/chunk-ZWZQVPDT.js +27893 -0
- package/apps/supervisor-api/dist/index.js +4 -25727
- package/apps/supervisor-api/dist/worker-index.d.ts +2 -0
- package/apps/supervisor-api/dist/worker-index.js +197 -0
- package/apps/supervisor-web/dist/assets/index-CbdWtyx0.js +5 -0
- package/apps/supervisor-web/dist/assets/index-Di1JBevU.css +1 -0
- package/apps/supervisor-web/dist/assets/thread-ui-ICfwCbte.js +3604 -0
- package/apps/supervisor-web/dist/assets/ui-vendor-D1uxdi-d.js +430 -0
- package/apps/supervisor-web/dist/index.html +6 -7
- package/bin/remote-codex.mjs +534 -19
- package/package.json +41 -2
- package/packages/agent-runtime/src/types.ts +2 -1
- package/packages/codex/src/appServerManager.ts +1 -0
- package/packages/codex/src/historyItems.test.ts +45 -0
- package/packages/codex/src/historyItems.ts +22 -0
- package/packages/codex/src/runtimeAdapter.ts +6 -0
- package/packages/codex/src/types.ts +2 -1
- package/packages/db/migrations/0018_control_plane.sql +129 -0
- package/packages/db/migrations/0019_control_plane_projects.sql +19 -0
- package/packages/db/migrations/0020_control_workspace_status.sql +1 -0
- package/packages/db/migrations/0021_control_sandbox_lifecycle_fields.sql +3 -0
- package/packages/db/migrations/0022_control_sandbox_resource_profile.sql +1 -0
- package/packages/db/migrations/0023_control_usage_import_state.sql +18 -0
- package/packages/db/migrations/0024_control_auth.sql +23 -0
- package/packages/db/migrations/0025_control_harness_credentials.sql +29 -0
- package/packages/db/migrations/0026_control_harness_usage_events.sql +27 -0
- package/packages/db/src/schema.ts +305 -1
- package/packages/shared/src/index.ts +32 -0
- package/packages/shared/src/tokens.ts +137 -0
- package/apps/supervisor-web/dist/assets/index-CBIze1VS.css +0 -1
- package/apps/supervisor-web/dist/assets/index-YpGAPjED.js +0 -4
- package/apps/supervisor-web/dist/assets/thread-ui-BEieA99i.css +0 -1
- package/apps/supervisor-web/dist/assets/thread-ui-CF80LEEN.js +0 -3613
- package/apps/supervisor-web/dist/assets/ui-vendor-CW6egZBG.js +0 -430
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildApp
|
|
3
|
+
} from "./chunk-ZWZQVPDT.js";
|
|
4
|
+
|
|
5
|
+
// src/worker-index.ts
|
|
6
|
+
import fs2 from "fs";
|
|
7
|
+
|
|
8
|
+
// src/worker-environment.ts
|
|
9
|
+
import fs from "fs";
|
|
10
|
+
import path from "path";
|
|
11
|
+
var DEFAULT_ENABLED_PROVIDER_RUNTIMES = ["codex", "claude", "opencode"];
|
|
12
|
+
function requireEnv(env, name) {
|
|
13
|
+
const value = env[name];
|
|
14
|
+
if (!value || !value.trim()) {
|
|
15
|
+
throw new Error(`${name} is required in worker mode.`);
|
|
16
|
+
}
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
function assertPath(expected, actual, name) {
|
|
20
|
+
if (path.resolve(actual ?? "") !== expected) {
|
|
21
|
+
throw new Error(`${name} must be ${expected} in worker mode.`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function ensureDirectory(filesystem, dir, name) {
|
|
25
|
+
filesystem.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
26
|
+
const stat = filesystem.statSync(dir);
|
|
27
|
+
if (!stat.isDirectory()) {
|
|
28
|
+
throw new Error(`${name} must be a directory: ${dir}`);
|
|
29
|
+
}
|
|
30
|
+
filesystem.accessSync(dir, fs.constants.R_OK | fs.constants.W_OK);
|
|
31
|
+
}
|
|
32
|
+
function assertPathInside(parent, child, name) {
|
|
33
|
+
const resolvedParent = path.resolve(parent);
|
|
34
|
+
const resolvedChild = path.resolve(child);
|
|
35
|
+
const relative = path.relative(resolvedParent, resolvedChild);
|
|
36
|
+
if (relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
37
|
+
throw new Error(`${name} must be inside ${resolvedParent} in worker mode.`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function ensureNotWorldWritable(filesystem, filePath, name) {
|
|
41
|
+
if (!filesystem.existsSync(filePath)) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const stat = filesystem.statSync(filePath);
|
|
45
|
+
if ("mode" in stat && typeof stat.mode === "number" && (stat.mode & 2) !== 0) {
|
|
46
|
+
throw new Error(`${name} must not be world-writable in worker mode: ${filePath}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function enabledProviderRuntimes(env) {
|
|
50
|
+
const raw = env.REMOTE_CODEX_ENABLED_AGENT_PROVIDERS;
|
|
51
|
+
if (raw === void 0) {
|
|
52
|
+
return DEFAULT_ENABLED_PROVIDER_RUNTIMES;
|
|
53
|
+
}
|
|
54
|
+
return raw.split(",").map((provider) => provider.trim().toLowerCase()).filter(Boolean);
|
|
55
|
+
}
|
|
56
|
+
function parseBoolean(value) {
|
|
57
|
+
return value !== void 0 && ["1", "true", "yes", "on"].includes(value.toLowerCase());
|
|
58
|
+
}
|
|
59
|
+
function validateMcpConfigPaths(env, filesystem) {
|
|
60
|
+
const home = env.HOME ?? "/home/agent";
|
|
61
|
+
const providerConfigs = [
|
|
62
|
+
{
|
|
63
|
+
enabled: enabledProviderRuntimes(env).includes("codex"),
|
|
64
|
+
home: env.CODEX_HOME ?? path.join(home, ".codex"),
|
|
65
|
+
file: "config.toml",
|
|
66
|
+
name: "Codex MCP config path"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
enabled: enabledProviderRuntimes(env).includes("claude"),
|
|
70
|
+
home: env.CLAUDE_HOME ?? path.join(home, ".claude"),
|
|
71
|
+
file: "settings.json",
|
|
72
|
+
name: "Claude MCP config path"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
enabled: enabledProviderRuntimes(env).includes("opencode"),
|
|
76
|
+
home: env.OPENCODE_HOME ?? path.join(home, ".opencode"),
|
|
77
|
+
file: "opencode.json",
|
|
78
|
+
name: "OpenCode MCP config path"
|
|
79
|
+
}
|
|
80
|
+
];
|
|
81
|
+
for (const config of providerConfigs) {
|
|
82
|
+
if (!config.enabled) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
assertPathInside(home, config.home, config.name);
|
|
86
|
+
ensureNotWorldWritable(
|
|
87
|
+
filesystem,
|
|
88
|
+
path.join(config.home, config.file),
|
|
89
|
+
config.name
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function validateGatewayEnvironment(env) {
|
|
94
|
+
if (enabledProviderRuntimes(env).length === 0) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const baseUrl = requireEnv(env, "REMOTE_CODEX_LLM_GATEWAY_BASE_URL");
|
|
98
|
+
requireEnv(env, "REMOTE_CODEX_LLM_GATEWAY_TOKEN");
|
|
99
|
+
try {
|
|
100
|
+
new URL(baseUrl);
|
|
101
|
+
} catch {
|
|
102
|
+
throw new Error("REMOTE_CODEX_LLM_GATEWAY_BASE_URL must be a valid URL.");
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function validateHarnessEnvironment(env) {
|
|
106
|
+
if (!parseBoolean(env.REMOTE_CODEX_CHEMISTRY_TOOLS_ENABLED)) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const baseUrl = requireEnv(env, "ELAGENTE_HARNESS_BASE_URL");
|
|
110
|
+
requireEnv(env, "INACT_X_APP_KEY");
|
|
111
|
+
try {
|
|
112
|
+
new URL(baseUrl);
|
|
113
|
+
} catch {
|
|
114
|
+
throw new Error("ELAGENTE_HARNESS_BASE_URL must be a valid URL.");
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function validateWorkerEntrypointEnvironment(env = process.env, filesystem = fs) {
|
|
118
|
+
if (env.REMOTE_CODEX_RUNTIME_ROLE !== "worker") {
|
|
119
|
+
throw new Error("REMOTE_CODEX_RUNTIME_ROLE must be worker for the worker entrypoint.");
|
|
120
|
+
}
|
|
121
|
+
requireEnv(env, "REMOTE_CODEX_SANDBOX_ID");
|
|
122
|
+
requireEnv(env, "REMOTE_CODEX_USER_ID");
|
|
123
|
+
requireEnv(env, "REMOTE_CODEX_WORKER_AUTH_TOKEN");
|
|
124
|
+
assertPath("/workspace", env.WORKSPACE_ROOT, "WORKSPACE_ROOT");
|
|
125
|
+
assertPath("/home/agent", env.HOME, "HOME");
|
|
126
|
+
ensureDirectory(filesystem, "/workspace", "WORKSPACE_ROOT");
|
|
127
|
+
ensureDirectory(filesystem, "/home/agent", "HOME");
|
|
128
|
+
ensureDirectory(filesystem, env.CODEX_HOME ?? "/home/agent/.codex", "CODEX_HOME");
|
|
129
|
+
ensureDirectory(filesystem, env.CLAUDE_HOME ?? "/home/agent/.claude", "CLAUDE_HOME");
|
|
130
|
+
ensureDirectory(filesystem, env.OPENCODE_HOME ?? "/home/agent/.opencode", "OPENCODE_HOME");
|
|
131
|
+
validateMcpConfigPaths(env, filesystem);
|
|
132
|
+
validateGatewayEnvironment(env);
|
|
133
|
+
validateHarnessEnvironment(env);
|
|
134
|
+
}
|
|
135
|
+
function workerStartupLogPayload(env = process.env) {
|
|
136
|
+
return {
|
|
137
|
+
sandboxId: env.REMOTE_CODEX_SANDBOX_ID ?? null,
|
|
138
|
+
userId: env.REMOTE_CODEX_USER_ID ?? null,
|
|
139
|
+
workspaceRoot: env.WORKSPACE_ROOT ?? null,
|
|
140
|
+
home: env.HOME ?? null,
|
|
141
|
+
gatewayConfigured: Boolean(env.REMOTE_CODEX_LLM_GATEWAY_BASE_URL),
|
|
142
|
+
harnessConfigured: Boolean(env.ELAGENTE_HARNESS_BASE_URL),
|
|
143
|
+
chemistryToolsEnabled: parseBoolean(env.REMOTE_CODEX_CHEMISTRY_TOOLS_ENABLED)
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// src/worker-index.ts
|
|
148
|
+
if (fs2.existsSync(".env")) {
|
|
149
|
+
process.loadEnvFile?.(".env");
|
|
150
|
+
}
|
|
151
|
+
process.env.REMOTE_CODEX_RUNTIME_ROLE ??= "worker";
|
|
152
|
+
process.env.HOST ??= "0.0.0.0";
|
|
153
|
+
process.env.WORKSPACE_ROOT ??= "/workspace";
|
|
154
|
+
process.env.HOME ??= "/home/agent";
|
|
155
|
+
process.env.CODEX_HOME ??= "/home/agent/.codex";
|
|
156
|
+
process.env.CLAUDE_HOME ??= "/home/agent/.claude";
|
|
157
|
+
process.env.CLAUDE_CONFIG_DIR ??= "/home/agent/.claude";
|
|
158
|
+
process.env.OPENCODE_HOME ??= "/home/agent/.opencode";
|
|
159
|
+
process.env.REMOTE_CODEX_DISABLE_BUILD_RESTART ??= "true";
|
|
160
|
+
validateWorkerEntrypointEnvironment();
|
|
161
|
+
var app = buildApp();
|
|
162
|
+
var { host, port } = app.services.config;
|
|
163
|
+
var shutdownStarted = false;
|
|
164
|
+
async function shutdown(signal) {
|
|
165
|
+
if (shutdownStarted) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
shutdownStarted = true;
|
|
169
|
+
const hardExit = setTimeout(() => {
|
|
170
|
+
app.log.error({ signal }, "Remote Codex Worker graceful shutdown timed out.");
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}, 55e3);
|
|
173
|
+
hardExit.unref();
|
|
174
|
+
try {
|
|
175
|
+
app.log.info({ signal }, "Remote Codex Worker shutting down.");
|
|
176
|
+
await app.close();
|
|
177
|
+
process.exit(0);
|
|
178
|
+
} catch (error) {
|
|
179
|
+
app.log.error({ error, signal }, "Remote Codex Worker shutdown failed.");
|
|
180
|
+
process.exit(1);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
process.once("SIGTERM", () => {
|
|
184
|
+
void shutdown("SIGTERM");
|
|
185
|
+
});
|
|
186
|
+
process.once("SIGINT", () => {
|
|
187
|
+
void shutdown("SIGINT");
|
|
188
|
+
});
|
|
189
|
+
app.listen({ host, port }).then(() => {
|
|
190
|
+
app.log.info(
|
|
191
|
+
workerStartupLogPayload(process.env),
|
|
192
|
+
`Remote Codex Worker listening on http://${host}:${port}`
|
|
193
|
+
);
|
|
194
|
+
}).catch((error) => {
|
|
195
|
+
app.log.error(error);
|
|
196
|
+
process.exit(1);
|
|
197
|
+
});
|