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.
@@ -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 ?? String(exports.DEFAULT_PORT), 10);
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;
@@ -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 app_1 = require("./app");
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, app_1.resolvePackageRoot)();
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, app_1.resolvePackageRoot)();
131
- const databasePath = flags.databasePath ?? process.env.DATABASE_PATH ?? (0, app_1.resolveDefaultDatabasePath)();
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 ?? String(app_1.DEFAULT_PORT), 10);
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 (0, app_1.startRemCodexServer)({
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 = node_path_1.default.join(process.cwd(), "server", "src", "db", "schema.sql");
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.10",
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
+ }