remcodex 0.1.0-beta.10 → 0.1.0-beta.12
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/dist/server/src/app.js
CHANGED
|
@@ -3,13 +3,9 @@ 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;
|
|
7
|
-
exports.resolvePackageRoot = resolvePackageRoot;
|
|
8
|
-
exports.resolveDefaultDatabasePath = resolveDefaultDatabasePath;
|
|
9
6
|
exports.startRemCodexServer = startRemCodexServer;
|
|
10
7
|
const node_fs_1 = require("node:fs");
|
|
11
8
|
const node_http_1 = __importDefault(require("node:http"));
|
|
12
|
-
const node_os_1 = require("node:os");
|
|
13
9
|
const node_path_1 = __importDefault(require("node:path"));
|
|
14
10
|
const express_1 = __importDefault(require("express"));
|
|
15
11
|
const codex_options_controller_1 = require("./controllers/codex-options.controller");
|
|
@@ -24,36 +20,15 @@ const codex_rollout_sync_1 = require("./services/codex-rollout-sync");
|
|
|
24
20
|
const project_manager_1 = require("./services/project-manager");
|
|
25
21
|
const session_manager_1 = require("./services/session-manager");
|
|
26
22
|
const session_timeline_service_1 = require("./services/session-timeline-service");
|
|
23
|
+
const runtime_paths_1 = require("./utils/runtime-paths");
|
|
27
24
|
const command_1 = require("./utils/command");
|
|
28
25
|
const errors_1 = require("./utils/errors");
|
|
29
|
-
function isPackageRoot(root) {
|
|
30
|
-
return ((0, node_fs_1.existsSync)(node_path_1.default.join(root, "package.json")) &&
|
|
31
|
-
(0, node_fs_1.existsSync)(node_path_1.default.join(root, "web", "index.html")));
|
|
32
|
-
}
|
|
33
|
-
function resolvePackageRoot(startDir = __dirname) {
|
|
34
|
-
let current = node_path_1.default.resolve(startDir);
|
|
35
|
-
while (true) {
|
|
36
|
-
if (isPackageRoot(current)) {
|
|
37
|
-
return current;
|
|
38
|
-
}
|
|
39
|
-
const parent = node_path_1.default.dirname(current);
|
|
40
|
-
if (parent === current) {
|
|
41
|
-
break;
|
|
42
|
-
}
|
|
43
|
-
current = parent;
|
|
44
|
-
}
|
|
45
|
-
return process.cwd();
|
|
46
|
-
}
|
|
47
|
-
function resolveDefaultDatabasePath() {
|
|
48
|
-
return node_path_1.default.join((0, node_os_1.homedir)(), ".remcodex", "remcodex.db");
|
|
49
|
-
}
|
|
50
|
-
exports.DEFAULT_PORT = 18840;
|
|
51
26
|
function buildRemCodexServer(options = {}) {
|
|
52
|
-
const repoRoot = options.repoRoot ? node_path_1.default.resolve(options.repoRoot) : resolvePackageRoot();
|
|
53
|
-
const port = options.port ?? Number.parseInt(process.env.PORT ??
|
|
27
|
+
const repoRoot = options.repoRoot ? node_path_1.default.resolve(options.repoRoot) : (0, runtime_paths_1.resolvePackageRoot)();
|
|
28
|
+
const port = options.port ?? Number.parseInt(process.env.PORT ?? "18840", 10);
|
|
54
29
|
const databasePath = options.databasePath ??
|
|
55
30
|
process.env.DATABASE_PATH ??
|
|
56
|
-
resolveDefaultDatabasePath();
|
|
31
|
+
(0, runtime_paths_1.resolveDefaultDatabasePath)();
|
|
57
32
|
const codexCommand = (0, command_1.resolveExecutable)(options.codexCommand ?? process.env.CODEX_COMMAND ?? "codex");
|
|
58
33
|
const codexMode = options.codexMode ?? (process.env.CODEX_MODE === "exec-json" ? "exec-json" : "app-server");
|
|
59
34
|
const projectRootsEnv = options.projectRootsEnv ?? process.env.PROJECT_ROOTS;
|
package/dist/server/src/cli.js
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
3
36
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
37
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
38
|
};
|
|
@@ -8,7 +41,7 @@ const node_fs_1 = require("node:fs");
|
|
|
8
41
|
const node_child_process_1 = require("node:child_process");
|
|
9
42
|
const node_os_1 = require("node:os");
|
|
10
43
|
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
-
const
|
|
44
|
+
const runtime_paths_1 = require("./utils/runtime-paths");
|
|
12
45
|
const command_1 = require("./utils/command");
|
|
13
46
|
function print(message = "") {
|
|
14
47
|
process.stdout.write(`${message}\n`);
|
|
@@ -18,7 +51,7 @@ function printError(message = "") {
|
|
|
18
51
|
}
|
|
19
52
|
function readPackageVersion() {
|
|
20
53
|
try {
|
|
21
|
-
const packageRoot = (0,
|
|
54
|
+
const packageRoot = (0, runtime_paths_1.resolvePackageRoot)();
|
|
22
55
|
const packageJson = JSON.parse((0, node_fs_1.readFileSync)(node_path_1.default.join(packageRoot, "package.json"), "utf8"));
|
|
23
56
|
return typeof packageJson.version === "string" ? packageJson.version : "0.0.0";
|
|
24
57
|
}
|
|
@@ -123,12 +156,24 @@ function usage() {
|
|
|
123
156
|
print(" --db <path> Use a specific SQLite database path");
|
|
124
157
|
print(" --no-open Do not open a browser automatically");
|
|
125
158
|
}
|
|
159
|
+
function formatNativeModuleError(error) {
|
|
160
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
161
|
+
if (!message.includes("NODE_MODULE_VERSION")) {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
return [
|
|
165
|
+
"Native module failed to load. This usually means RemCodex was installed with a different Node.js version.",
|
|
166
|
+
`Current Node: ${process.version}`,
|
|
167
|
+
"Reinstall remcodex with the same Node.js version you will use to run it.",
|
|
168
|
+
"If you use nvm/fnm/asdf, switch to the target Node version first, then reinstall.",
|
|
169
|
+
].join("\n");
|
|
170
|
+
}
|
|
126
171
|
async function runDoctor(flags) {
|
|
127
172
|
const version = readPackageVersion();
|
|
128
173
|
const rawCodexCommand = process.env.CODEX_COMMAND ?? "codex";
|
|
129
174
|
const codex = commandExists(rawCodexCommand);
|
|
130
|
-
const packageRoot = (0,
|
|
131
|
-
const databasePath = flags.databasePath ?? process.env.DATABASE_PATH ?? (0,
|
|
175
|
+
const packageRoot = (0, runtime_paths_1.resolvePackageRoot)();
|
|
176
|
+
const databasePath = flags.databasePath ?? process.env.DATABASE_PATH ?? (0, runtime_paths_1.resolveDefaultDatabasePath)();
|
|
132
177
|
const databaseDir = node_path_1.default.dirname(databasePath);
|
|
133
178
|
const databaseDirExists = (0, node_fs_1.existsSync)(databaseDir);
|
|
134
179
|
const databaseDirWritable = databaseDirExists && (() => {
|
|
@@ -161,6 +206,18 @@ async function runDoctor(flags) {
|
|
|
161
206
|
return 0;
|
|
162
207
|
}
|
|
163
208
|
async function runStart(flags) {
|
|
209
|
+
let startRemCodexServer;
|
|
210
|
+
try {
|
|
211
|
+
({ startRemCodexServer } = await Promise.resolve().then(() => __importStar(require("./app"))));
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
const nativeModuleMessage = formatNativeModuleError(error);
|
|
215
|
+
if (nativeModuleMessage) {
|
|
216
|
+
printError(nativeModuleMessage);
|
|
217
|
+
return 1;
|
|
218
|
+
}
|
|
219
|
+
throw error;
|
|
220
|
+
}
|
|
164
221
|
const version = readPackageVersion();
|
|
165
222
|
const rawCodexCommand = process.env.CODEX_COMMAND ?? "codex";
|
|
166
223
|
const codex = commandExists(rawCodexCommand);
|
|
@@ -169,14 +226,14 @@ async function runStart(flags) {
|
|
|
169
226
|
printError("Install Codex first, or set CODEX_COMMAND to the correct executable.");
|
|
170
227
|
return 1;
|
|
171
228
|
}
|
|
172
|
-
const preferredPort = flags.port ?? Number.parseInt(process.env.PORT ??
|
|
229
|
+
const preferredPort = flags.port ?? Number.parseInt(process.env.PORT ?? "18840", 10);
|
|
173
230
|
const codexMode = process.env.CODEX_MODE === "exec-json" ? "exec-json" : "app-server";
|
|
174
231
|
let started = null;
|
|
175
232
|
let activePort = preferredPort;
|
|
176
233
|
for (let offset = 0; offset < 20; offset += 1) {
|
|
177
234
|
const candidate = preferredPort + offset;
|
|
178
235
|
try {
|
|
179
|
-
started = await
|
|
236
|
+
started = await startRemCodexServer({
|
|
180
237
|
port: candidate,
|
|
181
238
|
databasePath: flags.databasePath,
|
|
182
239
|
codexCommand: rawCodexCommand,
|
|
@@ -6,6 +6,35 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.runMigrations = runMigrations;
|
|
7
7
|
const node_fs_1 = require("node:fs");
|
|
8
8
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
function isPackageRoot(root) {
|
|
10
|
+
return (0, node_fs_1.existsSync)(node_path_1.default.join(root, "package.json")) && (0, node_fs_1.existsSync)(node_path_1.default.join(root, "web", "index.html"));
|
|
11
|
+
}
|
|
12
|
+
function resolvePackageRoot(startDir = __dirname) {
|
|
13
|
+
let current = node_path_1.default.resolve(startDir);
|
|
14
|
+
while (true) {
|
|
15
|
+
if (isPackageRoot(current)) {
|
|
16
|
+
return current;
|
|
17
|
+
}
|
|
18
|
+
const parent = node_path_1.default.dirname(current);
|
|
19
|
+
if (parent === current) {
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
current = parent;
|
|
23
|
+
}
|
|
24
|
+
return process.cwd();
|
|
25
|
+
}
|
|
26
|
+
function resolveSchemaFile() {
|
|
27
|
+
const packageRoot = resolvePackageRoot();
|
|
28
|
+
const candidates = [
|
|
29
|
+
node_path_1.default.join(packageRoot, "server", "src", "db", "schema.sql"),
|
|
30
|
+
node_path_1.default.join(packageRoot, "dist", "server", "src", "db", "schema.sql"),
|
|
31
|
+
];
|
|
32
|
+
const resolved = candidates.find((candidate) => (0, node_fs_1.existsSync)(candidate));
|
|
33
|
+
if (!resolved) {
|
|
34
|
+
throw new Error(`Database schema file not found. Tried: ${candidates.join(", ")}`);
|
|
35
|
+
}
|
|
36
|
+
return resolved;
|
|
37
|
+
}
|
|
9
38
|
function ensureColumn(db, table, column, definition) {
|
|
10
39
|
const rows = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
11
40
|
if (rows.some((row) => row.name === column)) {
|
|
@@ -14,7 +43,7 @@ function ensureColumn(db, table, column, definition) {
|
|
|
14
43
|
db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
|
|
15
44
|
}
|
|
16
45
|
function runMigrations(db) {
|
|
17
|
-
const schemaFile =
|
|
46
|
+
const schemaFile = resolveSchemaFile();
|
|
18
47
|
const schema = (0, node_fs_1.readFileSync)(schemaFile, "utf8");
|
|
19
48
|
db.exec(schema);
|
|
20
49
|
ensureColumn(db, "sessions", "source_kind", "TEXT NOT NULL DEFAULT 'native'");
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS projects (
|
|
2
|
+
id TEXT PRIMARY KEY,
|
|
3
|
+
name TEXT NOT NULL,
|
|
4
|
+
path TEXT NOT NULL,
|
|
5
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))
|
|
6
|
+
);
|
|
7
|
+
|
|
8
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
9
|
+
id TEXT PRIMARY KEY,
|
|
10
|
+
title TEXT,
|
|
11
|
+
project_id TEXT NOT NULL,
|
|
12
|
+
status TEXT NOT NULL,
|
|
13
|
+
pid INTEGER,
|
|
14
|
+
codex_thread_id TEXT,
|
|
15
|
+
source_kind TEXT NOT NULL DEFAULT 'native',
|
|
16
|
+
source_rollout_path TEXT,
|
|
17
|
+
source_thread_id TEXT,
|
|
18
|
+
source_sync_cursor INTEGER,
|
|
19
|
+
source_last_synced_at TEXT,
|
|
20
|
+
source_rollout_has_open_turn INTEGER NOT NULL DEFAULT 0,
|
|
21
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
22
|
+
updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
23
|
+
FOREIGN KEY (project_id) REFERENCES projects(id)
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
CREATE TABLE IF NOT EXISTS session_events (
|
|
27
|
+
id TEXT PRIMARY KEY,
|
|
28
|
+
session_id TEXT NOT NULL,
|
|
29
|
+
turn_id TEXT,
|
|
30
|
+
seq INTEGER NOT NULL,
|
|
31
|
+
event_type TEXT NOT NULL,
|
|
32
|
+
message_id TEXT,
|
|
33
|
+
call_id TEXT,
|
|
34
|
+
request_id TEXT,
|
|
35
|
+
phase TEXT,
|
|
36
|
+
stream TEXT,
|
|
37
|
+
payload_json TEXT NOT NULL,
|
|
38
|
+
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
|
|
39
|
+
FOREIGN KEY (session_id) REFERENCES sessions(id),
|
|
40
|
+
UNIQUE (session_id, seq)
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_project_id ON sessions(project_id);
|
|
44
|
+
CREATE INDEX IF NOT EXISTS idx_session_events_session_seq ON session_events(session_id, seq);
|
|
45
|
+
CREATE INDEX IF NOT EXISTS idx_session_events_type_seq ON session_events(session_id, event_type, seq);
|
|
46
|
+
CREATE INDEX IF NOT EXISTS idx_session_events_message_id ON session_events(session_id, message_id, seq);
|
|
47
|
+
CREATE INDEX IF NOT EXISTS idx_session_events_call_id ON session_events(session_id, call_id, seq);
|
|
48
|
+
CREATE INDEX IF NOT EXISTS idx_session_events_request_id ON session_events(session_id, request_id, seq);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.resolvePackageRoot = resolvePackageRoot;
|
|
7
|
+
exports.resolveDefaultDatabasePath = resolveDefaultDatabasePath;
|
|
8
|
+
const node_fs_1 = require("node:fs");
|
|
9
|
+
const node_os_1 = require("node:os");
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
function isPackageRoot(root) {
|
|
12
|
+
return ((0, node_fs_1.existsSync)(node_path_1.default.join(root, "package.json")) &&
|
|
13
|
+
(0, node_fs_1.existsSync)(node_path_1.default.join(root, "web", "index.html")));
|
|
14
|
+
}
|
|
15
|
+
function resolvePackageRoot(startDir = __dirname) {
|
|
16
|
+
let current = node_path_1.default.resolve(startDir);
|
|
17
|
+
while (true) {
|
|
18
|
+
if (isPackageRoot(current)) {
|
|
19
|
+
return current;
|
|
20
|
+
}
|
|
21
|
+
const parent = node_path_1.default.dirname(current);
|
|
22
|
+
if (parent === current) {
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
current = parent;
|
|
26
|
+
}
|
|
27
|
+
return process.cwd();
|
|
28
|
+
}
|
|
29
|
+
function resolveDefaultDatabasePath() {
|
|
30
|
+
return node_path_1.default.join((0, node_os_1.homedir)(), ".remcodex", "remcodex.db");
|
|
31
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "remcodex",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.12",
|
|
4
4
|
"description": "Control Codex from anywhere. Even on your phone.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|
|
11
11
|
"web",
|
|
12
|
+
"scripts/check-node-version.js",
|
|
12
13
|
"scripts/fix-node-pty-helper.js",
|
|
13
14
|
"README.md"
|
|
14
15
|
],
|
|
@@ -16,8 +17,11 @@
|
|
|
16
17
|
"postinstall": "node scripts/fix-node-pty-helper.js",
|
|
17
18
|
"dev": "tsx watch server/src/app.ts",
|
|
18
19
|
"start": "tsx server/src/cli.ts --no-open",
|
|
19
|
-
"build": "tsc -p tsconfig.json",
|
|
20
|
-
"cli": "tsx server/src/cli.ts --no-open"
|
|
20
|
+
"build": "tsc -p tsconfig.json && node scripts/copy-db-assets.js",
|
|
21
|
+
"cli": "tsx server/src/cli.ts --no-open",
|
|
22
|
+
"preinstall": "node scripts/check-node-version.js",
|
|
23
|
+
"smoke:tarball": "node scripts/smoke-test-tarball.js",
|
|
24
|
+
"smoke:start": "node scripts/smoke-start-tarball.js"
|
|
21
25
|
},
|
|
22
26
|
"dependencies": {
|
|
23
27
|
"better-sqlite3": "^11.8.1",
|
|
@@ -32,5 +36,8 @@
|
|
|
32
36
|
"@types/ws": "^8.5.14",
|
|
33
37
|
"tsx": "^4.19.3",
|
|
34
38
|
"typescript": "^5.8.2"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": "20.x"
|
|
35
42
|
}
|
|
36
43
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const supportedMajor = 20;
|
|
2
|
+
const currentVersion = process.versions.node;
|
|
3
|
+
const currentMajor = Number.parseInt(currentVersion.split(".")[0] || "", 10);
|
|
4
|
+
|
|
5
|
+
if (currentMajor !== supportedMajor) {
|
|
6
|
+
console.error(
|
|
7
|
+
[
|
|
8
|
+
`remcodex requires Node.js ${supportedMajor}.x for the published package.`,
|
|
9
|
+
`Current Node.js: ${currentVersion}`,
|
|
10
|
+
"Switch Node versions first, then reinstall remcodex so native modules are built against the same runtime.",
|
|
11
|
+
].join("\n"),
|
|
12
|
+
);
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|