shubhjn commited on
Commit
3e61ed6
·
1 Parent(s): e8f0b97

fix state error

Browse files
.agent/memory/session.json CHANGED
@@ -1,7 +1,7 @@
1
  {
2
  "version": "1.0.0",
3
- "session_id": "a709b623",
4
- "started_at": "2026-04-07T22:15:07.430955+05:30",
5
  "workspace": "D:\\Code\\codeverse",
6
  "active_task_id": null,
7
  "active_agent": null,
 
1
  {
2
  "version": "1.0.0",
3
+ "session_id": "ca245f40",
4
+ "started_at": "2026-04-08T00:02:12.484470+05:30",
5
  "workspace": "D:\\Code\\codeverse",
6
  "active_task_id": null,
7
  "active_agent": null,
auth.ts CHANGED
@@ -5,6 +5,7 @@ import { client as db } from "@/lib/db";
5
  import { randomUUID } from "crypto";
6
  import type { Adapter, AdapterUser, AdapterAccount, AdapterSession, VerificationToken } from "@auth/core/adapters";
7
  import { JWT } from "next-auth/jwt";
 
8
 
9
  /**
10
  * 🛰️ CodeVerse Authentication Core
@@ -274,10 +275,10 @@ export const { handlers, auth, signIn, signOut } = NextAuth({
274
  async authorize(credentials) {
275
  if (credentials?.username === "dev" || credentials?.username === "guest") {
276
  return {
277
- id: "dev-user-id",
278
- name: "Developer Guest",
279
- email: "dev@codeverse.local",
280
- image: "https://github.com/identicons/dev.png",
281
  };
282
  }
283
  return null;
@@ -285,7 +286,7 @@ export const { handlers, auth, signIn, signOut } = NextAuth({
285
  })
286
  ] : []),
287
  ],
288
- session: { strategy: "jwt" },
289
  callbacks: {
290
  async jwt({ token, user }) {
291
  if (user) {
@@ -303,7 +304,7 @@ export const { handlers, auth, signIn, signOut } = NextAuth({
303
  },
304
  },
305
  pages: {
306
- signIn: "/login",
307
  },
308
  debug: process.env.NODE_ENV === "development",
309
  });
 
5
  import { randomUUID } from "crypto";
6
  import type { Adapter, AdapterUser, AdapterAccount, AdapterSession, VerificationToken } from "@auth/core/adapters";
7
  import { JWT } from "next-auth/jwt";
8
+ import { AUTH_CONFIG, ROUTES } from "@/constants";
9
 
10
  /**
11
  * 🛰️ CodeVerse Authentication Core
 
275
  async authorize(credentials) {
276
  if (credentials?.username === "dev" || credentials?.username === "guest") {
277
  return {
278
+ id: AUTH_CONFIG.DEV_USER_ID,
279
+ name: AUTH_CONFIG.DEV_USER_NAME,
280
+ email: AUTH_CONFIG.DEV_USER_EMAIL,
281
+ image: AUTH_CONFIG.DEV_AVATAR,
282
  };
283
  }
284
  return null;
 
286
  })
287
  ] : []),
288
  ],
289
+ session: { strategy: AUTH_CONFIG.SESSION_STRATEGY as "jwt" | "database" },
290
  callbacks: {
291
  async jwt({ token, user }) {
292
  if (user) {
 
304
  },
305
  },
306
  pages: {
307
+ signIn: ROUTES.LOGIN,
308
  },
309
  debug: process.env.NODE_ENV === "development",
310
  });
dist/constants/index.js ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use strict";
2
+ /**
3
+ * 🛠️ CodeVerse Global Constants
4
+ * Centralized source of truth for all non-changeable text, configuration, and magic numbers.
5
+ * Adheres to Production-Grade Standards for consistency and maintainability.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.ROUTES = exports.UI_STRINGS = exports.INFRA_CONFIG = exports.AUTH_CONFIG = exports.APP_CONFIG = void 0;
9
+ exports.APP_CONFIG = {
10
+ NAME: "CodeVerse",
11
+ VERSION: "1.0.0-stable",
12
+ DESCRIPTION: "The fully managed, agentic VS Code environment running securely in the browser.",
13
+ LOGO_SIZE: 40,
14
+ DEFAULT_LANGUAGE: "typescript",
15
+ };
16
+ exports.AUTH_CONFIG = {
17
+ DEV_USER_ID: "dev-user-id",
18
+ DEV_USER_NAME: "Developer Guest",
19
+ DEV_USER_EMAIL: "dev@codeverse.local",
20
+ DEV_AVATAR: "https://github.com/identicons/dev.png",
21
+ SESSION_STRATEGY: "jwt",
22
+ };
23
+ exports.INFRA_CONFIG = {
24
+ WORKSPACE_ROOT: process.env.WORKSPACE_ROOT || "/home/node/w",
25
+ TMPDIR: process.env.TMPDIR || "/tmp",
26
+ HF_HOME: process.env.HF_HOME || "/tmp/.cache/huggingface",
27
+ DEFAULT_PORT_START: 3001,
28
+ IDLE_TIMEOUT_MS: 30 * 60 * 1000, // 30 minutes
29
+ PERSISTENCE_INTERVAL_MS: 60 * 1000, // 1 minute
30
+ };
31
+ exports.UI_STRINGS = {
32
+ MAINTENANCE_TITLE: "Infrastructure Locked",
33
+ MAINTENANCE_MESSAGE: "CodeVerse is currently initializing hardware. Please wait while we secure your environment.",
34
+ LOGIN_TITLE: "CodeVerse Studio",
35
+ LOGIN_SUBTITLE: "The fully managed, agentic VS Code environment running securely in the browser.",
36
+ BYPASS_LABEL: "Bypass Login (Local Dev Only)",
37
+ };
38
+ exports.ROUTES = {
39
+ HOME: "/",
40
+ LOGIN: "/login",
41
+ API: {
42
+ AUTH: "/api/auth",
43
+ WORKSPACE: "/api/workspace",
44
+ }
45
+ };
dist/lib/db/index.js ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.db = exports.client = void 0;
4
+ const client_1 = require("@libsql/client");
5
+ const url = process.env.TURSO_URL || "file:local.db";
6
+ const authToken = process.env.TURSO_AUTH_TOKEN;
7
+ /**
8
+ * 🛠️ LibSQL Client Singleton (Native Edition)
9
+ * Provides 100% stable, high-performance database access without Drizzle overhead.
10
+ * Optimized for sandboxed execution on Hugging Face Spaces.
11
+ */
12
+ exports.client = (0, client_1.createClient)({
13
+ url,
14
+ authToken,
15
+ });
16
+ /**
17
+ * 🛡️ Database Client Export
18
+ * Used by authentication and action layers.
19
+ */
20
+ exports.db = exports.client;
21
+ // 🚀 Database lifecycle is managed by the server entrypoint to ensure proper synchronization.
dist/lib/db/schema.js ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rawSchema = void 0;
4
+ exports.initDb = initDb;
5
+ exports.rawSchema = `
6
+ CREATE TABLE IF NOT EXISTS users (
7
+ id TEXT PRIMARY KEY,
8
+ name TEXT,
9
+ email TEXT UNIQUE,
10
+ image TEXT,
11
+ github_username TEXT,
12
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP
13
+ );
14
+
15
+ CREATE TABLE IF NOT EXISTS accounts (
16
+ id TEXT PRIMARY KEY,
17
+ userId TEXT NOT NULL,
18
+ provider TEXT NOT NULL,
19
+ providerAccountId TEXT NOT NULL,
20
+ refresh_token TEXT,
21
+ access_token TEXT,
22
+ expires_at INTEGER,
23
+ token_type TEXT,
24
+ scope TEXT,
25
+ id_token TEXT,
26
+ session_state TEXT,
27
+ FOREIGN KEY (userId) REFERENCES users(id) ON DELETE CASCADE
28
+ );
29
+
30
+ CREATE TABLE IF NOT EXISTS workspaces (
31
+ id TEXT PRIMARY KEY,
32
+ user_id TEXT NOT NULL,
33
+ project_name TEXT NOT NULL,
34
+ container_id TEXT,
35
+ android_container_id TEXT,
36
+ status TEXT DEFAULT 'stopped',
37
+ port_mapping INTEGER,
38
+ android_port INTEGER,
39
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
40
+ FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
41
+ );
42
+
43
+ CREATE TABLE IF NOT EXISTS chat_history (
44
+ id TEXT PRIMARY KEY,
45
+ user_id TEXT NOT NULL,
46
+ workspace_id TEXT NOT NULL,
47
+ role TEXT NOT NULL,
48
+ content TEXT NOT NULL,
49
+ tool_invocations TEXT,
50
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
51
+ FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
52
+ FOREIGN KEY (workspace_id) REFERENCES workspaces(id) ON DELETE CASCADE
53
+ );
54
+ CREATE TABLE IF NOT EXISTS communities (
55
+ id TEXT PRIMARY KEY,
56
+ name TEXT NOT NULL UNIQUE,
57
+ description TEXT,
58
+ owner_id TEXT NOT NULL,
59
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
60
+ FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE CASCADE
61
+ );
62
+
63
+ CREATE TABLE IF NOT EXISTS sessions (
64
+ id TEXT PRIMARY KEY,
65
+ sessionToken TEXT UNIQUE NOT NULL,
66
+ userId TEXT NOT NULL,
67
+ expires DATETIME NOT NULL,
68
+ FOREIGN KEY (userId) REFERENCES users(id) ON DELETE CASCADE
69
+ );
70
+
71
+ CREATE TABLE IF NOT EXISTS verification_tokens (
72
+ identifier TEXT NOT NULL,
73
+ token TEXT NOT NULL,
74
+ expires DATETIME NOT NULL,
75
+ PRIMARY KEY (identifier, token)
76
+ );
77
+ `;
78
+ /**
79
+ * 🚀 Database Initialization Routine
80
+ * Hardened for Hugging Face Spaces: Ensures schema exists and dev user is seeded.
81
+ */
82
+ async function initDb(client) {
83
+ // Use raw execution for robustness during cold start
84
+ await client.executeMultiple(exports.rawSchema);
85
+ // 🌱 SEEDING (Dev Only): Create a 'Developer Guest' user for the login bypass
86
+ if (process.env.NODE_ENV === "development" || process.env.NEXT_PUBLIC_NODE_ENV === "development") {
87
+ try {
88
+ await client.execute({
89
+ sql: "INSERT OR IGNORE INTO users (id, name, email, image) VALUES (?, ?, ?, ?)",
90
+ args: ["dev-user-id", "Developer Guest", "dev@codeverse.local", "https://github.com/identicons/dev.png"]
91
+ });
92
+ console.log("[SYSTEM] Dev Seeding: 'Developer Guest' user ready.");
93
+ }
94
+ catch (e) {
95
+ console.error("[SYSTEM] Dev Seeding failed:", e);
96
+ }
97
+ }
98
+ }
dist/lib/docker/manager.js ADDED
@@ -0,0 +1,428 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.dockerManager = exports.DockerManager = exports.pendingProvisioning = exports.provisioningBus = exports.nativeProcesses = void 0;
7
+ exports.isNativeWorkspaceRunning = isNativeWorkspaceRunning;
8
+ exports.getWorkspaceStatus = getWorkspaceStatus;
9
+ exports.isDockerAvailable = isDockerAvailable;
10
+ exports.stopNativeWorkspace = stopNativeWorkspace;
11
+ exports.getNativeWorkspacePort = getNativeWorkspacePort;
12
+ exports.getAndroidPort = getAndroidPort;
13
+ exports.prewarmWorkspace = prewarmWorkspace;
14
+ exports.startWorkspaceContainer = startWorkspaceContainer;
15
+ exports.reconnectRunningWorkspaces = reconnectRunningWorkspaces;
16
+ exports.stopWorkspaceContainer = stopWorkspaceContainer;
17
+ const fs_1 = __importDefault(require("fs"));
18
+ const child_process_1 = require("child_process");
19
+ const path_1 = __importDefault(require("path"));
20
+ const dockerode_1 = __importDefault(require("dockerode"));
21
+ const events_1 = require("events");
22
+ const idx_engine_1 = require("../idx/idx-engine");
23
+ const storage_1 = require("../hf/storage");
24
+ /**
25
+ * Registry for native workspace processes (IDE instances running outside Docker)
26
+ * Map<workspaceId, { pid: number; port: number; process: WorkspaceProcess }>
27
+ */
28
+ exports.nativeProcesses = new Map();
29
+ /**
30
+ * Internal Provisioning Bus to multicast logs to concurrent clients.
31
+ */
32
+ class ProvisioningBus extends events_1.EventEmitter {
33
+ }
34
+ exports.provisioningBus = new ProvisioningBus();
35
+ /**
36
+ * Map to track active provisioning promises to prevent redundant creation loops.
37
+ */
38
+ exports.pendingProvisioning = new Map();
39
+ /**
40
+ * Checks if a native workspace is currently running.
41
+ * Supports fuzzy matching for reconnected sessions that might use a prefix key.
42
+ */
43
+ function isNativeWorkspaceRunning(id) {
44
+ if (exports.nativeProcesses.has(id))
45
+ return true;
46
+ // Prefix fallback for reconnected sessions
47
+ return Array.from(exports.nativeProcesses.keys()).some(k => id.startsWith(k));
48
+ }
49
+ /**
50
+ * Returns the current runtime status of a workspace.
51
+ */
52
+ function getWorkspaceStatus(id) {
53
+ if (exports.nativeProcesses.has(id))
54
+ return "ready";
55
+ if (exports.pendingProvisioning.has(id))
56
+ return "provisioning";
57
+ return "offline";
58
+ }
59
+ /**
60
+ * Helper for async delays.
61
+ */
62
+ const delay = (ms) => new Promise(res => setTimeout(res, ms));
63
+ /**
64
+ * Finds an available port in the 8100-9000 range.
65
+ */
66
+ function findAvailablePort() {
67
+ const occupiedPorts = Array.from(exports.nativeProcesses.values()).map(p => p.port);
68
+ let port = Math.floor(Math.random() * (9000 - 8100) + 8100);
69
+ while (occupiedPorts.includes(port)) {
70
+ port = Math.floor(Math.random() * (9000 - 8100) + 8100);
71
+ }
72
+ return port;
73
+ }
74
+ /**
75
+ * Checks if Docker is available in the current environment.
76
+ */
77
+ async function isDockerAvailable() {
78
+ const socketPath = process.platform === 'win32' ? '//./pipe/docker_engine' : '/var/run/docker.sock';
79
+ if (process.env.SIMULATE_HF === 'true') {
80
+ return { available: false, reason: "Hugging Face Simulation Mode (Artificial Sandbox)" };
81
+ }
82
+ if (process.env.SPACE_ID) {
83
+ return { available: false, reason: "Hugging Face Space (Native Sandboxed)" };
84
+ }
85
+ try {
86
+ const docker = new dockerode_1.default({ socketPath: process.platform === 'win32' ? undefined : socketPath });
87
+ await docker.ping();
88
+ return { available: true };
89
+ }
90
+ catch (_a) {
91
+ return { available: false, reason: "Docker daemon unreachable" };
92
+ }
93
+ }
94
+ /**
95
+ * Stops a native workspace process.
96
+ */
97
+ async function stopNativeWorkspace(id) {
98
+ const entry = exports.nativeProcesses.get(id);
99
+ if (entry) {
100
+ try {
101
+ entry.process.kill();
102
+ exports.nativeProcesses.delete(id);
103
+ return true;
104
+ }
105
+ catch (e) {
106
+ console.error(`[MANAGER] Failed to kill code-server ${id}:`, e);
107
+ exports.nativeProcesses.delete(id);
108
+ }
109
+ }
110
+ return false;
111
+ }
112
+ /**
113
+ * Gets the internal port for a native workspace process.
114
+ * Supports fuzzy matching for reconnected sessions.
115
+ */
116
+ function getNativeWorkspacePort(id) {
117
+ var _a;
118
+ const entry = exports.nativeProcesses.get(id);
119
+ if (entry)
120
+ return entry.port;
121
+ // Prefix fallback
122
+ const key = Array.from(exports.nativeProcesses.keys()).find(k => id.startsWith(k));
123
+ return key ? (_a = exports.nativeProcesses.get(key)) === null || _a === void 0 ? void 0 : _a.port : undefined;
124
+ }
125
+ /**
126
+ * Returns the global unified Android VNC port.
127
+ */
128
+ function getAndroidPort() {
129
+ return 6080;
130
+ }
131
+ /**
132
+ * PREDICTIVE HYDRATION: Pre-warms Nix profile and SDKs.
133
+ */
134
+ async function prewarmWorkspace(config) {
135
+ // CRITICAL (April 2026): Shorten paths to avoid Unix Domain Socket (UDS) path limit (104 chars)
136
+ const workspaceRoot = process.env.WORKSPACE_ROOT || path_1.default.join(/*turbopackIgnore: true*/ '/home/node/w');
137
+ const workspacePath = path_1.default.join(/*turbopackIgnore: true*/ workspaceRoot, config.id.slice(0, 8));
138
+ if (!fs_1.default.existsSync(workspacePath)) {
139
+ fs_1.default.mkdirSync(workspacePath, { recursive: true });
140
+ }
141
+ const idxConfig = idx_engine_1.IdxEngine.getIdxConfig(workspacePath);
142
+ if (idxConfig) {
143
+ // Run Nix sync in background if not already warmed
144
+ idx_engine_1.IdxEngine.syncNixEnvironment(workspacePath, idxConfig, (msg) => {
145
+ exports.provisioningBus.emit(`log:${config.id}`, `[HYDRATE] ${msg}`);
146
+ });
147
+ }
148
+ }
149
+ /**
150
+ * INTERNAL: Core provisioning logic with IDX support and auto-provisioning baseline.
151
+ */
152
+ async function performProvisioning(config) {
153
+ const log = (msg) => {
154
+ if (config.onLog)
155
+ config.onLog(`[IDX:ENGINE] ${msg}`);
156
+ exports.provisioningBus.emit(`log:${config.id}`, msg);
157
+ };
158
+ try {
159
+ log(`Provisioning hermetic environment for '${config.projectName}'...`);
160
+ // 0. HF PERSISTENCE: Restore profile from Dataset if available
161
+ try {
162
+ await storage_1.HFStorage.syncFromDataset((msg) => log(msg));
163
+ }
164
+ catch (e) {
165
+ log(`[WARN] Persistent profile restoration failed: ${e instanceof Error ? e.message : String(e)}. Proceeding with clean environment.`);
166
+ }
167
+ // 1. Prepare Workspace Directory
168
+ const workspaceRoot = process.env.WORKSPACE_ROOT || path_1.default.join(/*turbopackIgnore: true*/ '/home/node/w');
169
+ const workspacePath = path_1.default.join(/*turbopackIgnore: true*/ workspaceRoot, config.id.slice(0, 8));
170
+ const userDataPath = path_1.default.join(/*turbopackIgnore: true*/ workspacePath, '.vscode-server');
171
+ if (!fs_1.default.existsSync(workspacePath)) {
172
+ fs_1.default.mkdirSync(workspacePath, { recursive: true });
173
+ // Store full ID for reliable reconnection after server restarts
174
+ fs_1.default.writeFileSync(path_1.default.join(workspacePath, '.codeverse-id'), config.id);
175
+ log(`Allocated isolated filesystem segment: ${config.id.slice(0, 8)}`);
176
+ }
177
+ // 2. IDX Engine: Sync Environment
178
+ const idxConfig = idx_engine_1.IdxEngine.getIdxConfig(workspacePath);
179
+ log(`Declarative config detected (Packages: ${idxConfig.packages.length}). Initializing synchronization...`);
180
+ await idx_engine_1.IdxEngine.syncNixEnvironment(workspacePath, idxConfig, (msg) => log(msg));
181
+ const flagPath = path_1.default.join(/*turbopackIgnore: true*/ workspacePath, '.idx-created');
182
+ if (!fs_1.default.existsSync(flagPath)) {
183
+ if (idxConfig.onCreate) {
184
+ log(`Executing onCreate lifecycle hook...`);
185
+ await idx_engine_1.IdxEngine.runHook(workspacePath, 'onCreate', idxConfig.onCreate, (msg) => log(msg));
186
+ }
187
+ fs_1.default.writeFileSync(flagPath, new Date().toISOString());
188
+ }
189
+ // 4. Identify Target Port
190
+ const port = findAvailablePort();
191
+ // 5. Spawn code-server
192
+ const shellCommand = process.platform === 'win32' ? 'npx' : 'code-server';
193
+ const args = process.platform === 'win32' ? ['code-server'] : [];
194
+ const baseArgs = [
195
+ '--auth', 'none',
196
+ '--bind-addr', `127.0.0.1:${port}`,
197
+ '--user-data-dir', userDataPath,
198
+ '--disable-telemetry',
199
+ '--disable-update-check',
200
+ workspacePath
201
+ ];
202
+ const spawnEnv = { ...process.env, HOME: workspacePath };
203
+ delete spawnEnv.PORT;
204
+ delete spawnEnv.SERVER_PORT;
205
+ const child = (0, child_process_1.spawn)(shellCommand, [...args, ...baseArgs], {
206
+ env: spawnEnv,
207
+ cwd: workspacePath,
208
+ shell: process.platform === 'win32'
209
+ });
210
+ log(`Spawning VS Code Orchestrator (PID: ${child.pid})...`);
211
+ child.on('error', (err) => log(`[FATAL] IDE binary failure: ${err.message}`));
212
+ child.stdout.on('data', (data) => {
213
+ const out = data.toString().trim();
214
+ if (out.includes('listening on'))
215
+ log(`[IDX:UP] ${out}`);
216
+ else if (out.length > 0)
217
+ log(`[IDE:CORE] ${out}`);
218
+ });
219
+ child.stderr.on('data', (data) => {
220
+ const err = data.toString().trim();
221
+ if (err.length > 0)
222
+ log(`[IDE:ERR] ${err}`);
223
+ });
224
+ child.on('close', (code, signal) => {
225
+ log(`[IDE:EXIT] IDE process died with code ${code} (Signal: ${signal})`);
226
+ });
227
+ // 6. Register in active pool
228
+ exports.nativeProcesses.set(config.id, { pid: child.pid, port, process: child });
229
+ // 7. Handshake Loop
230
+ let attempts = 0;
231
+ while (attempts < 60) {
232
+ try {
233
+ const res = await fetch(`http://127.0.0.1:${port}`);
234
+ if (res.ok) {
235
+ log(`Handshake verified. Studio Engine Online.`);
236
+ if (idxConfig.onStart) {
237
+ log(`Executing background onStart lifecycle hooks...`);
238
+ idx_engine_1.IdxEngine.runHook(workspacePath, 'onStart', idxConfig.onStart, (msg) => log(msg), true);
239
+ }
240
+ const finalResult = {
241
+ success: true,
242
+ containerId: `native-${config.id}`,
243
+ androidPort: config.withAndroidEmulator ? 6080 : undefined,
244
+ port: port
245
+ };
246
+ exports.provisioningBus.emit(`ready:${config.id}`, finalResult);
247
+ return finalResult;
248
+ }
249
+ }
250
+ catch (_a) {
251
+ if (attempts % 5 === 0)
252
+ log(`[INFO] Scanning for IDE heartbeat... (Attempt ${attempts}/60)`);
253
+ if (attempts === 15)
254
+ log(`[INFO] Nix evaluation in progress. Cold boot detected.`);
255
+ if (attempts === 45)
256
+ log(`[WARN] Handshake threshold approaching. IDE core high load.`);
257
+ await delay(1000);
258
+ attempts++;
259
+ }
260
+ }
261
+ log(`[FATAL] Handshake timeout on 127.0.0.1:${port}.`);
262
+ const entry = exports.nativeProcesses.get(config.id);
263
+ if (entry) {
264
+ entry.process.kill();
265
+ exports.nativeProcesses.delete(config.id);
266
+ }
267
+ const errResult = { success: false, error: "IDE_HANDSHAKE_TIMEOUT" };
268
+ exports.provisioningBus.emit(`error:${config.id}`, errResult);
269
+ return errResult;
270
+ }
271
+ catch (e) {
272
+ const error = e instanceof Error ? e.message : String(e);
273
+ log(`[FATAL] Provisioning pipeline collapsed: ${error}`);
274
+ const errResult = { success: false, error: "PROVISIONING_FAILED" };
275
+ exports.provisioningBus.emit(`error:${config.id}`, errResult);
276
+ return errResult;
277
+ }
278
+ }
279
+ /**
280
+ * Workspace provisioner with ATOMIC single-instance locking.
281
+ */
282
+ async function startWorkspaceContainer(config) {
283
+ if (exports.nativeProcesses.has(config.id)) {
284
+ return {
285
+ success: true,
286
+ containerId: `native-${config.id}`,
287
+ port: exports.nativeProcesses.get(config.id).port
288
+ };
289
+ }
290
+ let pending = exports.pendingProvisioning.get(config.id);
291
+ if (!pending) {
292
+ pending = performProvisioning(config).finally(() => {
293
+ exports.pendingProvisioning.delete(config.id);
294
+ });
295
+ exports.pendingProvisioning.set(config.id, pending);
296
+ }
297
+ return await pending;
298
+ }
299
+ /**
300
+ * 🛠️ SELF-HEALING: Scans for running code-server instances to repopulate the proxy map.
301
+ * This allows the IDE to survive server restarts or cold boots by probing active ports.
302
+ */
303
+ async function reconnectRunningWorkspaces() {
304
+ const workspaceRoot = process.env.WORKSPACE_ROOT || '/home/node/w';
305
+ console.log(`[BOOT] Probing filesystem segment: ${workspaceRoot} for existing sessions...`);
306
+ try {
307
+ // Find all code-server processes
308
+ // Note: Using a more robust ps grep that works across most POSIX environments
309
+ const psCmd = process.platform === 'win32' ? 'tasklist' : "ps aux | grep code-server | grep -v grep";
310
+ const output = (0, child_process_1.execSync)(psCmd).toString();
311
+ const lines = output.split('\n');
312
+ for (const line of lines) {
313
+ // Looking for: ... --bind-addr 127.0.0.1:8548 ... w/44c7597c
314
+ const bindMatch = line.match(/--bind-addr 127\.0\.0\.1:(\d+)/);
315
+ // Flexible path match: look for the ID prefix after 'w/' or 'workspaces/' or just the root
316
+ const pathMatch = line.match(/[ /](?:w|workspaces)\/([a-zA-Z0-9]{8})/);
317
+ if (bindMatch && pathMatch) {
318
+ const port = parseInt(bindMatch[1]);
319
+ const shortId = pathMatch[1];
320
+ const fullPath = path_1.default.join(workspaceRoot, shortId);
321
+ const idFile = path_1.default.join(fullPath, '.codeverse-id');
322
+ let foundFullId = "";
323
+ if (fs_1.default.existsSync(idFile)) {
324
+ foundFullId = fs_1.default.readFileSync(idFile, 'utf-8').trim();
325
+ }
326
+ else {
327
+ // Fallback: If no ID file, we use the shortId as the temporary key.
328
+ foundFullId = shortId;
329
+ console.warn(`[RECONNECT:WARN] No .codeverse-id for session ${shortId}. Using prefix mapping.`);
330
+ }
331
+ if (foundFullId && !exports.nativeProcesses.has(foundFullId)) {
332
+ // Capture PID reliably from ps output (column 2)
333
+ const psParts = line.trim().split(/\s+/);
334
+ const pid = parseInt(psParts[1]);
335
+ console.log(`[RECONNECT] Identified active IDE ${foundFullId} (PID: ${pid}) on port ${port}. Restoration complete.`);
336
+ exports.nativeProcesses.set(foundFullId, {
337
+ pid,
338
+ port,
339
+ process: {
340
+ pid,
341
+ kill: () => {
342
+ try {
343
+ process.kill(pid, 'SIGKILL');
344
+ return true;
345
+ }
346
+ catch (_a) {
347
+ try {
348
+ (0, child_process_1.execSync)(`fuser -k ${port}/tcp`);
349
+ }
350
+ catch (_b) { }
351
+ return true;
352
+ }
353
+ }
354
+ }
355
+ });
356
+ }
357
+ }
358
+ }
359
+ }
360
+ catch (e) {
361
+ // No processes found or ps failed
362
+ }
363
+ }
364
+ /**
365
+ * 🟢 ENGINE WATCHDOG: Background health monitor for native IDE processes.
366
+ */
367
+ function startEngineWatchdog() {
368
+ setInterval(async () => {
369
+ for (const [id, entry] of exports.nativeProcesses.entries()) {
370
+ try {
371
+ // 1. Zombie Check
372
+ try {
373
+ process.kill(entry.pid, 0);
374
+ }
375
+ catch (_a) {
376
+ console.log(`[WATCHDOG] Process ${entry.pid} for ${id} is missing. Pruning.`);
377
+ exports.nativeProcesses.delete(id);
378
+ continue;
379
+ }
380
+ // 2. Healthz Polling
381
+ const controller = new AbortController();
382
+ const timeoutId = setTimeout(() => controller.abort(), 2000);
383
+ try {
384
+ const res = await fetch(`http://127.0.0.1:${entry.port}`, { signal: controller.signal });
385
+ if (!res.ok)
386
+ throw new Error('Unhealthy');
387
+ }
388
+ catch (_b) {
389
+ console.warn(`[WATCHDOG] IDE ${id} (Port ${entry.port}) is non-responsive.`);
390
+ // Optional: force restart if unhealthy for multiple cycles
391
+ }
392
+ finally {
393
+ clearTimeout(timeoutId);
394
+ }
395
+ }
396
+ catch (e) {
397
+ console.error(`[WATCHDOG:ERR] ${e}`);
398
+ }
399
+ }
400
+ }, 60000);
401
+ }
402
+ startEngineWatchdog();
403
+ /**
404
+ * Standardized stop method.
405
+ */
406
+ async function stopWorkspaceContainer(id) {
407
+ const success = await stopNativeWorkspace(id);
408
+ return { success: success || true };
409
+ }
410
+ /**
411
+ * Modern Docker Manager class.
412
+ */
413
+ class DockerManager {
414
+ async getContainerStatus(id) {
415
+ if (isNativeWorkspaceRunning(id))
416
+ return "running";
417
+ return "stopped";
418
+ }
419
+ async stopContainer(id) {
420
+ return stopNativeWorkspace(id);
421
+ }
422
+ async startWorkspace(config) {
423
+ const result = await startWorkspaceContainer(config);
424
+ return result.success;
425
+ }
426
+ }
427
+ exports.DockerManager = DockerManager;
428
+ exports.dockerManager = new DockerManager();
dist/lib/env-config.js ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ENV_CONFIG = void 0;
4
+ exports.validateEnvironment = validateEnvironment;
5
+ /**
6
+ * CodeVerse Environment Configuration & Requirements Manifest.
7
+ * Centralizing all system variables for production-grade reliability.
8
+ */
9
+ exports.ENV_CONFIG = {
10
+ // 1. Storage & Persistence
11
+ HF_TOKEN: process.env.HF_TOKEN || process.env.hfToken || process.env.HF_SPACE || process.env.HuggingFaceToken,
12
+ HF_DATASET_ID: process.env.HF_DATASET_ID || process.env.hfDataset || process.env.HF_DATASET,
13
+ WORKSPACE_ROOT: process.env.WORKSPACE_ROOT || '/home/node/w',
14
+ // 2. Build Acceleration
15
+ CACHIX_CACHE_NAME: process.env.CACHIX_CACHE_NAME || 'code-nix',
16
+ CACHIX_AUTH_TOKEN: process.env.CACHIX_AUTH_TOKEN,
17
+ // 3. Infrastructure State
18
+ NODE_ENV: process.env.NODE_ENV || 'production',
19
+ SPACE_ID: process.env.SPACE_ID,
20
+ APP_BASE_URL: process.env.NEXTAUTH_URL || 'http://localhost:7860',
21
+ IS_SBC: !!process.env.SPACE_ID,
22
+ // 4. Database & Auth
23
+ AUTH_SECRET: process.env.AUTH_SECRET || process.env.authSecret,
24
+ TURSO_URL: process.env.TURSO_URL || process.env.turso_url || process.env.database_url || process.env.TURSO_DATABASE_URL || process.env.DB_URL || process.env.turso_database_url,
25
+ TURSO_AUTH_TOKEN: process.env.TURSO_AUTH_TOKEN || process.env.turso_auth_token || process.env.DB_TOKEN,
26
+ TMPDIR: '/tmp',
27
+ HF_HOME: '/tmp/.cache/huggingface',
28
+ };
29
+ /**
30
+ * Validates that all critical infrastructure secrets are available.
31
+ */
32
+ function validateEnvironment() {
33
+ const missing = [];
34
+ if (!exports.ENV_CONFIG.HF_TOKEN)
35
+ missing.push('HF_TOKEN (Missing Persistence Link)');
36
+ if (!exports.ENV_CONFIG.HF_DATASET_ID)
37
+ missing.push('HF_DATASET_ID (Missing Data Segment)');
38
+ if (!exports.ENV_CONFIG.AUTH_SECRET)
39
+ missing.push('AUTH_SECRET (Security Risk)');
40
+ if (!exports.ENV_CONFIG.TURSO_URL)
41
+ missing.push('TURSO_URL (Database Missing)');
42
+ // Strategic Dataset Validation
43
+ if (exports.ENV_CONFIG.HF_DATASET_ID && !exports.ENV_CONFIG.HF_DATASET_ID.includes('/')) {
44
+ return { valid: false, missing: ['HF_DATASET_ID_FORMAT_ERROR: Must be "username/dataset"'] };
45
+ }
46
+ return {
47
+ valid: missing.length === 0,
48
+ missing: missing
49
+ };
50
+ }
dist/lib/hf/storage.js ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.HFStorage = void 0;
7
+ const child_process_1 = require("child_process");
8
+ const path_1 = __importDefault(require("path"));
9
+ const fs_1 = __importDefault(require("fs"));
10
+ /**
11
+ * Hugging Face Storage Utility for 2026 CodeVerse Persistence.
12
+ */
13
+ class HFStorage {
14
+ /**
15
+ * Internal helper for asynchronous execution with logging.
16
+ */
17
+ static async execAsync(command, onLog) {
18
+ return new Promise((resolve, reject) => {
19
+ const spawnEnv = {
20
+ ...process.env,
21
+ HF_TOKEN: this.HF_TOKEN,
22
+ HF_HOME: '/tmp/.cache/huggingface',
23
+ TMPDIR: '/tmp',
24
+ PATH: `/home/node/.local/bin:/home/node/.nix-profile/bin:/usr/local/bin:/usr/bin:${process.env.PATH}`
25
+ };
26
+ const child = (0, child_process_1.spawn)('/bin/bash', ['-c', command], {
27
+ env: spawnEnv
28
+ });
29
+ child.stdout.on('data', (data) => onLog === null || onLog === void 0 ? void 0 : onLog(data.toString().trim()));
30
+ child.stderr.on('data', (data) => {
31
+ const msg = data.toString().trim();
32
+ if (msg.includes('command not found')) {
33
+ onLog === null || onLog === void 0 ? void 0 : onLog(`[CRITICAL] Binary missing: ${msg}. Current PATH: ${spawnEnv.PATH}`);
34
+ }
35
+ onLog === null || onLog === void 0 ? void 0 : onLog(`[WARN] ${msg}`);
36
+ });
37
+ child.on('close', (code) => {
38
+ if (code === 0)
39
+ resolve();
40
+ else
41
+ reject(new Error(`Command failed with code ${code}: ${command}`));
42
+ });
43
+ });
44
+ }
45
+ /**
46
+ * Synchronizes the environment FROM the Hugging Face Dataset (Pull).
47
+ */
48
+ static async syncFromDataset(onLog) {
49
+ if (!this.HF_TOKEN || !this.HF_DATASET_ID) {
50
+ onLog === null || onLog === void 0 ? void 0 : onLog(`[HF:STORAGE] Persistence layer inactive. Missing credentials.`);
51
+ return;
52
+ }
53
+ onLog === null || onLog === void 0 ? void 0 : onLog(`[HF:STORAGE] Pulling persistent profile from '${this.HF_DATASET_ID}'...`);
54
+ try {
55
+ const tmpDir = '/tmp/hf-sync';
56
+ if (!fs_1.default.existsSync(tmpDir))
57
+ fs_1.default.mkdirSync(tmpDir, { recursive: true });
58
+ // 🟢 DELTA SYNCING: Only sync the specific workspace and IDE state directories
59
+ const home = process.env.HOME || '/home/node';
60
+ const persistDirs = ['w', '.vscode-server', '.config/code-server'];
61
+ for (const dir of persistDirs) {
62
+ const localPath = path_1.default.join(home, dir);
63
+ if (!fs_1.default.existsSync(localPath))
64
+ fs_1.default.mkdirSync(localPath, { recursive: true });
65
+ const cmd = `(command -v huggingface-cli >/dev/null && huggingface-cli download ${this.HF_DATASET_ID} --local-dir ${localPath} --include "${dir}/*" --token ${this.HF_TOKEN}) || (hf download ${this.HF_DATASET_ID} --local-dir ${localPath} --include "${dir}/*" --token ${this.HF_TOKEN})`;
66
+ onLog === null || onLog === void 0 ? void 0 : onLog(`[HF:STORAGE] Restoring ${dir} from differential profile...`);
67
+ await this.execAsync(cmd, onLog).catch(() => { }); // Continue if one dir fails
68
+ }
69
+ onLog === null || onLog === void 0 ? void 0 : onLog(`[HF:STORAGE] Profile restoration complete.`);
70
+ }
71
+ catch (e) {
72
+ const errorMessage = e instanceof Error ? e.message : String(e);
73
+ onLog === null || onLog === void 0 ? void 0 : onLog(`[ERROR] Profile restoration failed: ${errorMessage}`);
74
+ }
75
+ }
76
+ /**
77
+ * Synchronizes the environment TO the Hugging Face Dataset (Push).
78
+ */
79
+ static async syncToDataset(onLog) {
80
+ if (!this.HF_TOKEN || !this.HF_DATASET_ID)
81
+ return;
82
+ try {
83
+ onLog === null || onLog === void 0 ? void 0 : onLog(`[HF:STORAGE] Saving persistent profile to '${this.HF_DATASET_ID}'...`);
84
+ const home = process.env.HOME || '/home/node';
85
+ const persistDirs = ['w', '.vscode-server', '.config/code-server'];
86
+ for (const dir of persistDirs) {
87
+ const localPath = path_1.default.join(home, dir);
88
+ if (!fs_1.default.existsSync(localPath))
89
+ continue;
90
+ const cmd = `(command -v huggingface-cli >/dev/null && huggingface-cli upload ${this.HF_DATASET_ID} ${localPath} ${dir} --token ${this.HF_TOKEN} --message "CodeVerse Sync [${dir}]: ${new Date().toISOString()}" --exclude "node_modules/*" --exclude ".nix/*" --exclude ".direnv/*" --exclude ".cache/*") || (hf upload ${this.HF_DATASET_ID} ${localPath} ${dir} --token ${this.HF_TOKEN})`;
91
+ onLog === null || onLog === void 0 ? void 0 : onLog(`[HF:STORAGE] Performing differential backup of ${dir}...`);
92
+ await this.execAsync(cmd, onLog).catch(err => onLog === null || onLog === void 0 ? void 0 : onLog(`[WARN] Sync failed for ${dir}: ${err.message}`));
93
+ }
94
+ onLog === null || onLog === void 0 ? void 0 : onLog(`[HF:STORAGE] Profile backup successful.`);
95
+ }
96
+ catch (e) {
97
+ const errorMessage = e instanceof Error ? e.message : String(e);
98
+ onLog === null || onLog === void 0 ? void 0 : onLog(`[ERROR] Profile synchronization failed: ${errorMessage}`);
99
+ }
100
+ }
101
+ static startAutoSave(intervalMs = 300000) {
102
+ if (this.autoSaveStarted)
103
+ return;
104
+ this.autoSaveStarted = true;
105
+ console.log(`[HF:STORAGE] Persistence heartbeat initialized (Interval: ${intervalMs}ms)`);
106
+ setInterval(async () => {
107
+ await this.syncToDataset((msg) => console.log(msg)).catch(() => { });
108
+ }, intervalMs);
109
+ }
110
+ }
111
+ exports.HFStorage = HFStorage;
112
+ HFStorage.HF_TOKEN = process.env.HF_TOKEN;
113
+ HFStorage.HF_DATASET_ID = process.env.HF_DATASET_ID;
114
+ HFStorage.PROFILE_PATH = path_1.default.join(process.env.HOME || '/home/node', '.nix-profile');
115
+ HFStorage.WORKSPACE_ROOT = process.env.WORKSPACE_ROOT || '/home/node/w';
116
+ /**
117
+ * Starts the periodic persistence interval (Singleton Heartbeat).
118
+ */
119
+ HFStorage.autoSaveStarted = false;
dist/lib/idx/idx-engine.js ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.IdxEngine = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const child_process_1 = require("child_process");
10
+ /**
11
+ * IDX Engine for declarative workspace environments.
12
+ * Refactored for 2026 Asynchronous Execution to prevent Event Loop blocking.
13
+ */
14
+ class IdxEngine {
15
+ /**
16
+ * Returns a robust baseline configuration for workspaces without a dev.nix.
17
+ */
18
+ static getDefaultConfig() {
19
+ return {
20
+ packages: ['pkgs.nodejs', 'pkgs.go', 'pkgs.python3', 'pkgs.docker', 'pkgs.python3Packages.huggingface-hub'],
21
+ onCreate: 'npm install',
22
+ onStart: 'sleep 5 && npm run dev'
23
+ };
24
+ }
25
+ /**
26
+ * Detects and parses the .idx/dev.nix file in the workspace root.
27
+ */
28
+ static getIdxConfig(workspacePath) {
29
+ const configPath = path_1.default.join(/*turbopackIgnore: true*/ workspacePath, '.idx', 'dev.nix');
30
+ if (!fs_1.default.existsSync(configPath))
31
+ return this.getDefaultConfig();
32
+ try {
33
+ const content = fs_1.default.readFileSync(configPath, 'utf8');
34
+ const packagesMatch = content.match(/packages\s*=\s*\[([\s\S]*?)\]/);
35
+ const onCreateMatch = content.match(/onCreate\s*=\s*"{1,3}([\s\S]*?)"{1,3}/);
36
+ const onStartMatch = content.match(/onStart\s*=\s*"{1,3}([\s\S]*?)"{1,3}/);
37
+ const config = {
38
+ packages: packagesMatch ? packagesMatch[1].split(/[\s\n,]+/).map(p => p.trim()).filter(p => p.length > 0) : [],
39
+ onCreate: onCreateMatch ? onCreateMatch[1].trim() : undefined,
40
+ onStart: onStartMatch ? onStartMatch[1].trim() : undefined
41
+ };
42
+ // Ensure baseline safety
43
+ if (config.packages.length === 0)
44
+ config.packages = this.getDefaultConfig().packages;
45
+ return config;
46
+ }
47
+ catch (e) {
48
+ const errorMessage = e instanceof Error ? e.message : String(e);
49
+ console.warn(`[IDX-ENGINE] Failed to parse dev.nix, falling back to baseline:`, errorMessage);
50
+ return this.getDefaultConfig();
51
+ }
52
+ }
53
+ /**
54
+ * Synchronizes the Nix environment based on the declarative packages.
55
+ * ASYNCHRONOUS Spawning to prevent Blocking.
56
+ */
57
+ static async syncNixEnvironment(workspacePath, config, onLog) {
58
+ if (!config.packages || config.packages.length === 0)
59
+ return;
60
+ const log = (msg) => { if (onLog)
61
+ onLog(`[IDX:NIX] ${msg}`); };
62
+ log(`Syncing system packages: ${config.packages.join(', ')}...`);
63
+ // CACHIX ACCELERATION: Robust check for binary existence to prevent ENOENT crash
64
+ const cachixName = process.env.CACHIX_CACHE_NAME || 'code-nix';
65
+ let hasCachix = false;
66
+ try {
67
+ await new Promise((resolve) => {
68
+ const check = (0, child_process_1.spawn)('command', ['-v', 'cachix'], { shell: true });
69
+ check.on('close', (code) => {
70
+ hasCachix = (code === 0);
71
+ resolve();
72
+ });
73
+ check.on('error', () => {
74
+ hasCachix = false;
75
+ resolve();
76
+ });
77
+ });
78
+ }
79
+ catch (_a) {
80
+ hasCachix = false;
81
+ }
82
+ if (hasCachix) {
83
+ const cachixToken = process.env.CACHIX_AUTH_TOKEN;
84
+ if (cachixToken) {
85
+ log(`Cachix authentication detected. Configuring access...`);
86
+ await new Promise((resolve) => {
87
+ const auth = (0, child_process_1.spawn)('cachix', ['authtoken', cachixToken], { env: { ...process.env, HOME: workspacePath } });
88
+ auth.on('close', () => resolve());
89
+ });
90
+ }
91
+ log(`Cachix acceleration detected. Setting up cache: ${cachixName}...`);
92
+ try {
93
+ await new Promise((resolve, reject) => {
94
+ const child = (0, child_process_1.spawn)('cachix', ['use', cachixName], {
95
+ cwd: workspacePath,
96
+ env: { ...process.env, HOME: workspacePath }
97
+ });
98
+ child.on('error', (err) => reject(err));
99
+ child.on('close', (code) => code === 0 ? resolve() : reject(new Error(`Cachix failed with code ${code}`)));
100
+ });
101
+ }
102
+ catch (_b) {
103
+ log(`[WARN] Cachix setup bypassed. Falling back to default binary cache.`);
104
+ }
105
+ }
106
+ // 🟢 HYDRATION GUARD: Skip synchronization if packages haven't changed or if pre-baked baseline is available
107
+ const idxDir = path_1.default.join(workspacePath, '.idx');
108
+ if (!fs_1.default.existsSync(idxDir))
109
+ fs_1.default.mkdirSync(idxDir, { recursive: true });
110
+ const manifestPath = path_1.default.join(idxDir, 'packages.json');
111
+ const bakedManifestPath = '/home/node/.idx/baked-packages.json';
112
+ // 1. Check local manifest
113
+ if (fs_1.default.existsSync(manifestPath)) {
114
+ try {
115
+ const manifest = JSON.parse(fs_1.default.readFileSync(manifestPath, 'utf8'));
116
+ const currentSorted = [...config.packages].sort();
117
+ const manifestSorted = [...(manifest.packages || [])].sort();
118
+ if (JSON.stringify(currentSorted) === JSON.stringify(manifestSorted)) {
119
+ log(`Environment already synchronized. Skipping profile update.`);
120
+ return;
121
+ }
122
+ }
123
+ catch (e) {
124
+ log(`[WARN] Manifest corruption detected. Forcing re-sync.`);
125
+ }
126
+ }
127
+ // 2. Check pre-baked manifest (for default configs)
128
+ const sortedDefault = [...IdxEngine.getDefaultConfig().packages].sort();
129
+ const sortedCurrent = [...config.packages].sort();
130
+ const isDefaultConfig = JSON.stringify(sortedCurrent) === JSON.stringify(sortedDefault);
131
+ if (isDefaultConfig && fs_1.default.existsSync(bakedManifestPath)) {
132
+ log(`Pre-baked baseline detected. Hydrating instance instantly...`);
133
+ try {
134
+ fs_1.default.copyFileSync(bakedManifestPath, manifestPath);
135
+ log(`Hydration complete. Workspace ready.`);
136
+ return;
137
+ }
138
+ catch (e) {
139
+ log(`[WARN] Hydration failed: ${e instanceof Error ? e.message : String(e)}`);
140
+ }
141
+ }
142
+ // CACHIX ...
143
+ // ... (Cachix code remains the same or slightly optimized)
144
+ const batchTargets = config.packages.map(pkg => `nixpkgs#${pkg.replace('pkgs.', '')}`);
145
+ log(`Batch installing: ${batchTargets.join(', ')}...`);
146
+ await new Promise((resolve, reject) => {
147
+ const child = (0, child_process_1.spawn)('nix', ['profile', 'add', ...batchTargets], {
148
+ cwd: workspacePath,
149
+ env: {
150
+ ...process.env,
151
+ HOME: workspacePath,
152
+ NIX_CONFIG: 'experimental-features = nix-command flakes'
153
+ }
154
+ });
155
+ child.stdout.on('data', (data) => log(data.toString().trim()));
156
+ child.stderr.on('data', (data) => log(`[INFO] ${data.toString().trim()}`));
157
+ child.on('close', (code) => {
158
+ if (code === 0) {
159
+ fs_1.default.writeFileSync(manifestPath, JSON.stringify({ packages: config.packages, timestamp: new Date().toISOString() }));
160
+ resolve();
161
+ }
162
+ else {
163
+ reject(new Error(`Batch Nix installation failed with code ${code}`));
164
+ }
165
+ });
166
+ }).catch((err) => {
167
+ const errMsg = err instanceof Error ? err.message : String(err);
168
+ log(`[ERROR] ${errMsg}`);
169
+ });
170
+ log(`Environment synchronized successfully.`);
171
+ }
172
+ /**
173
+ * Executes the 'onCreate' and 'onStart' hooks.
174
+ * supports background execution for 'onStart' to prevent blocking the IDE handshake.
175
+ */
176
+ static async runHook(workspacePath, hookName, script, onLog, background = false) {
177
+ const log = (msg) => { if (onLog)
178
+ onLog(`[IDX:HOOK] ${hookName}: ${msg}`); };
179
+ log(`Executing script... ${background ? '(Background)' : ''}`);
180
+ const hookPromise = new Promise((resolve, reject) => {
181
+ // 🟢 PORT DE-CONFLICTION: Ensure hooks don't inherit the main orchestrator's port 7860
182
+ const spawnEnv = { ...process.env, HOME: workspacePath };
183
+ delete spawnEnv.PORT;
184
+ delete spawnEnv.SERVER_PORT;
185
+ const child = (0, child_process_1.spawn)('/bin/bash', ['-c', script], {
186
+ cwd: workspacePath,
187
+ env: spawnEnv
188
+ });
189
+ child.stdout.on('data', (data) => log(data.toString().trim()));
190
+ child.stderr.on('data', (data) => log(`[WARN] ${data.toString().trim()}`));
191
+ child.on('close', (code) => {
192
+ if (code === 0) {
193
+ log(`Hook ${hookName} completed successfully.`);
194
+ resolve();
195
+ }
196
+ else {
197
+ const err = new Error(`Hook ${hookName} failed with code ${code}`);
198
+ log(`[ERROR] ${err.message}`);
199
+ reject(err);
200
+ }
201
+ });
202
+ // If background, resolve immediately after spawn
203
+ if (background) {
204
+ log(`Hook detached and running in baseline context.`);
205
+ resolve();
206
+ }
207
+ });
208
+ if (!background) {
209
+ await hookPromise.catch(() => { }); // Catch handled in promise
210
+ }
211
+ }
212
+ }
213
+ exports.IdxEngine = IdxEngine;
dist/lib/jobs/auto-sleep.js ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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.checkIdleContainers = checkIdleContainers;
7
+ exports.startAutoSleepCron = startAutoSleepCron;
8
+ const dockerode_1 = __importDefault(require("dockerode"));
9
+ const manager_1 = require("../docker/manager");
10
+ const db_1 = require("../db");
11
+ const docker = new dockerode_1.default({ socketPath: process.platform === 'win32' ? '//./pipe/docker_engine' : '/var/run/docker.sock' });
12
+ // Store previous network RX bytes to calculate delta
13
+ const networkThresholds = new Map();
14
+ async function checkIdleContainers() {
15
+ const status = await (0, manager_1.isDockerAvailable)();
16
+ if (!status.available) {
17
+ return;
18
+ }
19
+ console.log("[Auto-Sleep] Running idle container check...");
20
+ try {
21
+ const containers = await docker.listContainers({
22
+ filters: { name: ["codeverse-workspace-"] }
23
+ });
24
+ for (const c of containers) {
25
+ const containerName = c.Names[0].replace("/", "");
26
+ const workspaceId = containerName.replace("codeverse-workspace-", "");
27
+ const container = docker.getContainer(c.Id);
28
+ const stats = await container.stats({ stream: false });
29
+ // Extract network Rx (received) bytes
30
+ let currentRx = 0;
31
+ if (stats.networks && stats.networks.eth0) {
32
+ currentRx = stats.networks.eth0.rx_bytes;
33
+ }
34
+ const previousRx = networkThresholds.get(workspaceId);
35
+ if (previousRx !== undefined) {
36
+ const delta = currentRx - previousRx;
37
+ // If delta is less than 5KB over the interval, it's considered idle
38
+ if (delta < 5000) {
39
+ console.log(`[Auto-Sleep] Workspace ${workspaceId} is idle. Shutting down.`);
40
+ await (0, manager_1.stopWorkspaceContainer)(workspaceId);
41
+ // Update DB
42
+ await db_1.db.execute({
43
+ sql: "UPDATE workspaces SET status = 'sleeping' WHERE id = ?",
44
+ args: [workspaceId]
45
+ });
46
+ networkThresholds.delete(workspaceId);
47
+ continue; // Skip setting new threshold
48
+ }
49
+ }
50
+ // Set threshold for next check
51
+ networkThresholds.set(workspaceId, currentRx);
52
+ }
53
+ }
54
+ catch (e) {
55
+ const errorMessage = e instanceof Error ? e.message : String(e);
56
+ console.error("[Auto-Sleep] Error running cron:", errorMessage);
57
+ }
58
+ }
59
+ function startAutoSleepCron() {
60
+ // Run every 30 minutes (1800000 ms)
61
+ // For testing/dev we run it every 5 minutes (300000 ms)
62
+ const interval = process.env.NODE_ENV === "production" ? 1800000 : 300000;
63
+ setInterval(checkIdleContainers, interval);
64
+ console.log(`[Auto-Sleep] Cron initialized. Running every ${interval / 60000} minutes.`);
65
+ }
dist/server.js ADDED
@@ -0,0 +1,285 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ /**
40
+ * 🛰️ GLOBAL STABILIZATION (April 2026): Catch unhandled errors that cause HF Space restarts.
41
+ */
42
+ process.on('uncaughtException', (err) => { console.error('[FATAL:EXCEPTION]', err); });
43
+ process.on('unhandledRejection', (reason) => { console.error('[FATAL:REJECTION]', reason); });
44
+ const http_1 = require("http");
45
+ const next_1 = __importDefault(require("next"));
46
+ const socket_io_1 = require("socket.io");
47
+ const ws_1 = require("ws");
48
+ const Y = __importStar(require("yjs"));
49
+ const awarenessProtocol = __importStar(require("y-protocols/awareness"));
50
+ const syncProtocol = __importStar(require("y-protocols/sync"));
51
+ const encoding = __importStar(require("lib0/encoding"));
52
+ const decoding = __importStar(require("lib0/decoding"));
53
+ const map = __importStar(require("lib0/map"));
54
+ const pty = __importStar(require("node-pty"));
55
+ const os_1 = __importDefault(require("os"));
56
+ const auto_sleep_1 = require("./lib/jobs/auto-sleep");
57
+ const manager_1 = require("./lib/docker/manager");
58
+ const schema_1 = require("./lib/db/schema");
59
+ const db_1 = require("./lib/db");
60
+ const storage_1 = require("./lib/hf/storage");
61
+ const env_config_1 = require("./lib/env-config");
62
+ const http_proxy_1 = __importDefault(require("http-proxy"));
63
+ const constants_1 = require("./constants");
64
+ /**
65
+ * PRODUCTION HARDENING (April 2026): Force writable temp paths for HF Spaces.
66
+ */
67
+ process.env.TMPDIR = constants_1.INFRA_CONFIG.TMPDIR;
68
+ process.env.HF_HOME = constants_1.INFRA_CONFIG.HF_HOME;
69
+ if (!process.env.HOME)
70
+ process.env.HOME = '/home/node';
71
+ const dev = process.env.NODE_ENV !== "production";
72
+ const app = (0, next_1.default)({ dev });
73
+ const handle = app.getRequestHandler();
74
+ const docs = new Map();
75
+ const getOrCreateDoc = (docName) => {
76
+ return map.setIfUndefined(docs, docName, () => {
77
+ const doc = new Y.Doc();
78
+ const awareness = new awarenessProtocol.Awareness(doc);
79
+ return { doc, awareness };
80
+ });
81
+ };
82
+ const proxy = http_proxy_1.default.createProxyServer({
83
+ ws: true,
84
+ xfwd: true,
85
+ timeout: 30000,
86
+ proxyTimeout: 30000
87
+ });
88
+ function renderProxyError(res, error, id) {
89
+ res.writeHead(502, { 'Content-Type': 'text/html' });
90
+ res.end(`
91
+ <!DOCTYPE html>
92
+ <html lang="en">
93
+ <head>
94
+ <meta charset="UTF-8">
95
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
96
+ <title>Workspace Connection Failure</title>
97
+ <style>
98
+ body { background: #0f1117; color: #e2e8f0; font-family: -apple-system, sans-serif; display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100vh; margin: 0; }
99
+ .card { background: #1e293b; padding: 2.5rem; border-radius: 1rem; border: 1px solid #334155; text-align: center; max-width: 450px; box-shadow: 0 25px 50px -12px rgba(0,0,0,0.5); }
100
+ h1 { color: #f87171; font-size: 1.5rem; margin-bottom: 1rem; }
101
+ p { font-size: 0.875rem; color: #94a3b8; line-height: 1.6; }
102
+ .id { font-family: monospace; background: #0f172a; padding: 0.4rem 0.6rem; border-radius: 0.4rem; color: #38bdf8; font-size: 0.8rem; }
103
+ .btn { display: inline-block; background: #38bdf8; color: #0f172a; padding: 0.6rem 1.2rem; border-radius: 0.4rem; text-decoration: none; font-weight: bold; margin-top: 1.5rem; transition: transform 0.2s; }
104
+ .btn:hover { transform: scale(1.05); }
105
+ </style>
106
+ </head>
107
+ <body>
108
+ <div class="card">
109
+ <h1>Workspace Connection Restricted</h1>
110
+ <p>Native isolation link for <span class="id">${id}</span> failed.</p>
111
+ <p style="margin-top: 1rem; text-align: left; padding: 1rem; background: #0f172a; border-radius: 0.5rem; font-size: 0.75rem; color: #64748b;">
112
+ <b>Diagnostic:</b> ${error}<br>
113
+ <b>Target:</b> Hugging Face Space (Sandboxed)
114
+ </p>
115
+ <a href="/dashboard/booting?id=${id}" class="btn">Auto-Repair & Boot</a>
116
+ </div>
117
+ </body>
118
+ </html>
119
+ `);
120
+ }
121
+ proxy.on("error", (err, req, res) => {
122
+ const host = req.headers.host || "";
123
+ const fullUrl = new URL(req.url || "/", `http://${host}`);
124
+ const pathname = fullUrl.pathname;
125
+ const headerId = req.headers['x-codeverse-id'];
126
+ const workspaceHostMatch = host.match(/^workspace-([a-zA-Z0-9-]+)\./);
127
+ const id = headerId || (workspaceHostMatch ? workspaceHostMatch[1] : (pathname.split("/")[2] || "unknown"));
128
+ console.error(`[Proxy Connection Error] ${err.message} for workspace/${id}`);
129
+ if (res instanceof http_1.ServerResponse) {
130
+ renderProxyError(res, err.message, id);
131
+ }
132
+ });
133
+ // Port and Host logic
134
+ const PORT = Number(process.env.PORT) || 7860;
135
+ const HOST = '0.0.0.0';
136
+ let isAppReady = false;
137
+ let envStatus = { valid: true, missing: [] };
138
+ /**
139
+ *Autoritative Entrypoint: We initialize the HTTP server immediately to satisfy HF Spaces health checks.
140
+ */
141
+ const server = (0, http_1.createServer)((req, res) => {
142
+ var _a;
143
+ const host = req.headers.host || "localhost";
144
+ const fullUrl = new URL(req.url || "/", `http://${host}`);
145
+ const { pathname } = fullUrl;
146
+ // 1. Initializing State
147
+ if (!isAppReady && !pathname.startsWith("/_next/static") && pathname !== "/favicon.ico") {
148
+ res.writeHead(200, { 'Content-Type': 'text/html' });
149
+ return res.end(`
150
+ <html>
151
+ <head>
152
+ <title>CodeVerse | Initializing</title>
153
+ <style>
154
+ body { background: #09090b; color: #71717a; font-family: sans-serif; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; }
155
+ .container { text-align: center; border: 1px solid #27272a; padding: 2.5rem; border-radius: 1rem; background: #111113; max-width: 400px; }
156
+ .spinner { width: 30px; height: 30px; border: 2px solid #3f3f46; border-top-color: #3b82f6; border-radius: 50%; animation: spin 1s linear infinite; margin: 0 auto 1.5rem; }
157
+ h1 { color: #f4f4f5; font-size: 1.1rem; margin: 0; }
158
+ p { font-size: 0.85rem; margin-top: 0.5rem; }
159
+ @keyframes spin { to { transform: rotate(360deg); } }
160
+ </style>
161
+ <script>setTimeout(() => window.location.reload(), 5000);</script>
162
+ </head>
163
+ <body>
164
+ <div class="container">
165
+ <div class="spinner"></div>
166
+ <h1>CodeVerse is waking up</h1>
167
+ <p>Restoring your environment and securing persistent volumes...</p>
168
+ </div>
169
+ </body>
170
+ </html>
171
+ `);
172
+ }
173
+ // 2. Maintenance / Misconfiguration State
174
+ if (isAppReady && !envStatus.valid && pathname !== "/api/health" && !pathname.startsWith("/_next/")) {
175
+ res.writeHead(503, { 'Content-Type': 'text/html' });
176
+ return res.end(`
177
+ <html>
178
+ <body style="background:#09090b;color:#f87171;padding:2rem;font-family:sans-serif;">
179
+ <h1>Infrastructure Error</h1>
180
+ <p>${constants_1.UI_STRINGS.MAINTENANCE_MESSAGE}</p>
181
+ <ul>${envStatus.missing.map(m => `<li>${m}</li>`).join('')}</ul>
182
+ </body>
183
+ </html>
184
+ `);
185
+ }
186
+ // 3. Workspace Proxying
187
+ const workspaceHostMatch = host.match(/^workspace-([a-zA-Z0-9-]+)\./);
188
+ const id = workspaceHostMatch ? workspaceHostMatch[1] : ((pathname === null || pathname === void 0 ? void 0 : pathname.startsWith("/workspace/")) ? pathname.split("/")[2] : null);
189
+ if (id) {
190
+ const isReady = (0, manager_1.isNativeWorkspaceRunning)(id);
191
+ if (isReady) {
192
+ const port = (0, manager_1.getNativeWorkspacePort)(id) || 8080;
193
+ req.headers['x-codeverse-id'] = id;
194
+ req.headers['x-codeverse-type'] = 'workspace';
195
+ const prefix = `/workspace/${id}`;
196
+ if ((_a = req.url) === null || _a === void 0 ? void 0 : _a.startsWith(prefix)) {
197
+ req.url = req.url.substring(prefix.length);
198
+ if (!req.url.startsWith("/"))
199
+ req.url = "/" + req.url;
200
+ }
201
+ return proxy.web(req, res, { target: `http://127.0.0.1:${port}`, changeOrigin: true });
202
+ }
203
+ }
204
+ // 4. Default Next.js Handle
205
+ handle(req, res);
206
+ });
207
+ // Setup Sockets
208
+ const io = new socket_io_1.Server(server, { path: "/api/socketio" });
209
+ const yjsWss = new ws_1.WebSocketServer({ noServer: true });
210
+ // Start Listening Immediately
211
+ server.listen(PORT, HOST, () => {
212
+ console.log('----------------------------------------------------');
213
+ console.log(`[READY] ${constants_1.APP_CONFIG.NAME} ${constants_1.APP_CONFIG.VERSION}`);
214
+ console.log(`[READY] Interface: ${HOST}:${PORT}`);
215
+ console.log('----------------------------------------------------');
216
+ });
217
+ // Background Async Initialization
218
+ (async () => {
219
+ try {
220
+ console.log("[BOOT] Starting Next.js preparation...");
221
+ await app.prepare();
222
+ console.log("[BOOT] Next.js payload ready.");
223
+ envStatus = (0, env_config_1.validateEnvironment)();
224
+ if (envStatus.valid) {
225
+ console.log("[BOOT] Environment validated. Synchronizing database...");
226
+ await (0, schema_1.initDb)(db_1.client);
227
+ console.log("[BOOT] Database synchronized.");
228
+ // Reconnect and Warmup
229
+ (0, manager_1.reconnectRunningWorkspaces)().catch(() => { });
230
+ (0, manager_1.prewarmWorkspace)({ id: 'baseline-warmup', userId: 'system', projectName: 'CodeVerse-Internal' }).catch(() => { });
231
+ // Crons and Persistence
232
+ storage_1.HFStorage.startAutoSave(constants_1.INFRA_CONFIG.PERSISTENCE_INTERVAL_MS * 5);
233
+ (0, auto_sleep_1.startAutoSleepCron)();
234
+ }
235
+ isAppReady = true;
236
+ console.log("[BOOT] Global state stabilized. Application is fully operational.");
237
+ }
238
+ catch (err) {
239
+ console.error("[BOOT:ERROR] Fatal initialization failure:", err);
240
+ }
241
+ })();
242
+ // Terminal and Collaboration Handlers
243
+ server.on("upgrade", (req, socket, head) => {
244
+ const { pathname } = new URL(req.url || "/", `http://${req.headers.host}`);
245
+ if (pathname === "/api/collab") {
246
+ yjsWss.handleUpgrade(req, socket, head, (ws) => {
247
+ yjsWss.emit("connection", ws, req);
248
+ });
249
+ }
250
+ });
251
+ yjsWss.on("connection", (conn, request) => {
252
+ const { doc, awareness } = getOrCreateDoc(new URL(request.url || "/", "http://l").searchParams.get('doc') || "default");
253
+ conn.binaryType = "arraybuffer";
254
+ const encoder = encoding.createEncoder();
255
+ encoding.writeVarUint(encoder, 0);
256
+ syncProtocol.writeSyncStep1(encoder, doc);
257
+ conn.send(encoding.toUint8Array(encoder));
258
+ conn.on("message", (message) => {
259
+ const encoder = encoding.createEncoder();
260
+ const decoder = decoding.createDecoder(new Uint8Array(message));
261
+ const messageType = decoding.readVarUint(decoder);
262
+ if (messageType === 0) {
263
+ encoding.writeVarUint(encoder, 0);
264
+ syncProtocol.readSyncMessage(decoder, encoder, doc, null);
265
+ if (encoding.length(encoder) > 1)
266
+ conn.send(encoding.toUint8Array(encoder));
267
+ }
268
+ });
269
+ });
270
+ io.on("connection", (socket) => {
271
+ let shell = null;
272
+ socket.on("terminal:start", ({ cols, rows }) => {
273
+ shell = pty.spawn(process.env.SHELL || (os_1.default.platform() === "win32" ? "powershell.exe" : "bash"), [], {
274
+ cols: cols || 80,
275
+ rows: rows || 24,
276
+ cwd: constants_1.INFRA_CONFIG.WORKSPACE_ROOT,
277
+ env: process.env,
278
+ });
279
+ shell.onData((data) => socket.emit("terminal:data", data));
280
+ });
281
+ socket.on("terminal:write", (data) => { if (shell)
282
+ shell.write(data); });
283
+ socket.on("disconnect", () => { if (shell)
284
+ shell.kill(); });
285
+ });
lib/db/index.ts CHANGED
@@ -1,5 +1,4 @@
1
  import { createClient, type Client } from "@libsql/client";
2
- import { initDb } from "./schema";
3
 
4
  const url = process.env.TURSO_URL || "file:local.db";
5
  const authToken = process.env.TURSO_AUTH_TOKEN;
@@ -20,8 +19,4 @@ export const client: Client = createClient({
20
  */
21
  export const db = client;
22
 
23
- // 🚀 Self-Bootstrapping Database
24
- // We pass the client directly to avoid circular dependency with schema.ts
25
- initDb(client).catch((err: unknown) => {
26
- console.error("[DB:ERROR] Database bootstrap failed:", err);
27
- });
 
1
  import { createClient, type Client } from "@libsql/client";
 
2
 
3
  const url = process.env.TURSO_URL || "file:local.db";
4
  const authToken = process.env.TURSO_AUTH_TOKEN;
 
19
  */
20
  export const db = client;
21
 
22
+ // 🚀 Database lifecycle is managed by the server entrypoint to ensure proper synchronization.
 
 
 
 
package.json CHANGED
@@ -4,6 +4,7 @@
4
  "private": true,
5
  "scripts": {
6
  "dev": "next dev",
 
7
  "build": "next build && tsc server.ts --esModuleInterop --skipLibCheck --target es2018 --module commonjs --moduleResolution node --downlevelIteration --outDir ./dist",
8
  "start": "node dist/server.js",
9
  "lint": "eslint . --ignore-pattern dist/ --ignore-pattern .next/"
 
4
  "private": true,
5
  "scripts": {
6
  "dev": "next dev",
7
+ "prebuild": "npx rimraf dist",
8
  "build": "next build && tsc server.ts --esModuleInterop --skipLibCheck --target es2018 --module commonjs --moduleResolution node --downlevelIteration --outDir ./dist",
9
  "start": "node dist/server.js",
10
  "lint": "eslint . --ignore-pattern dist/ --ignore-pattern .next/"
server.ts CHANGED
@@ -18,7 +18,7 @@ import * as pty from "node-pty";
18
  import os from "os";
19
  import { Duplex } from "stream";
20
  import { startAutoSleepCron } from "./lib/jobs/auto-sleep";
21
- import { getNativeWorkspacePort, getAndroidPort, isNativeWorkspaceRunning, prewarmWorkspace, reconnectRunningWorkspaces } from "./lib/docker/manager";
22
  import { initDb } from "./lib/db/schema";
23
  import { client as dbClient } from "./lib/db";
24
  import { HFStorage } from "./lib/hf/storage";
@@ -46,9 +46,6 @@ const getOrCreateDoc = (docName: string) => {
46
  });
47
  };
48
 
49
- /**
50
- * PRODUCTION PROXY CONFIG (2026 Optimized)
51
- */
52
  const proxy = httpProxy.createProxyServer({
53
  ws: true,
54
  xfwd: true,
@@ -56,17 +53,6 @@ const proxy = httpProxy.createProxyServer({
56
  proxyTimeout: 30000
57
  });
58
 
59
- // 🟢 Production Pre-flight Diagnostics (April 2026)
60
- console.log('----------------------------------------------------');
61
- console.log(`[BOOT] ${APP_CONFIG.NAME} ${APP_CONFIG.VERSION} Initialized.`);
62
- console.log(`[BOOT] Environment: ${process.env.NODE_ENV || 'development'}`);
63
- console.log(`[BOOT] Database State: ${process.env.TURSO_URL ? '✅ CONFIGURED' : '❌ MISSING'}`);
64
- console.log(`[BOOT] Persistence Link: ${process.env.HF_TOKEN ? '✅ CONFIGURED' : '⚠️ UNLINKED'}`);
65
- console.log('----------------------------------------------------');
66
-
67
- /**
68
- * Custom renderer for Proxy Errors and Booting screens.
69
- */
70
  function renderProxyError(res: ServerResponse, error: string, id: string) {
71
  res.writeHead(502, { 'Content-Type': 'text/html' });
72
  res.end(`
@@ -117,239 +103,168 @@ proxy.on("error", (err: Error, req: IncomingMessage, res: ServerResponse | Duple
117
  }
118
  });
119
 
120
- proxy.on("proxyReq", (proxyReq, req: IncomingMessage) => {
121
- const id = req.headers['x-codeverse-id'] as string;
122
- const type = req.headers['x-codeverse-type'] as string;
123
- if (id && type) {
124
- proxyReq.setHeader('x-codeverse-id', id);
125
- proxyReq.setHeader('x-codeverse-type', type);
126
- }
127
- });
128
-
129
- proxy.on("proxyRes", (proxyRes, req: IncomingMessage) => {
130
- const id = req.headers['x-codeverse-id'] as string;
131
- const type = req.headers['x-codeverse-type'] as string;
132
- if (id && type && proxyRes.headers.location) {
133
- const originalLocation = proxyRes.headers.location;
134
- if (originalLocation.startsWith('/') && !originalLocation.startsWith(`/${type}/${id}`)) {
135
- proxyRes.headers.location = `/${type}/${id}${originalLocation}`;
136
- }
137
- }
138
- });
139
-
140
- app.prepare()
141
- .then(() => {
142
- // Validate Production Environment (April 2026 Resilience)
143
- const envStatus = validateEnvironment();
144
- if (!envStatus.valid) {
145
- console.error("[BOOT:ERROR] Infrastructure missing core secrets:", envStatus.missing.join(', '));
146
- }
147
 
148
- if (envStatus.valid) {
149
- // Correct initDb call passing the client to avoid circular dependencies
150
- initDb(dbClient)
151
- .then(() => {
152
- console.log("[BOOT] Database synchronized.");
153
- prewarmWorkspace({
154
- id: 'baseline-warmup',
155
- userId: 'system',
156
- projectName: 'CodeVerse-Internal'
157
- }).catch(err => console.error("[BOOT] Warmup failed:", err));
158
- })
159
- .catch(err => console.error("[BOOT] Database init failed:", err));
160
-
161
- // 🛠️ Self-Healing: Reconnect to orphans from previous instance
162
- reconnectRunningWorkspaces().catch(err => console.error("[BOOT] Reconnection failed:", err));
163
-
164
- // 🛡️ Persistence: Global heartbeat
165
- HFStorage.startAutoSave(INFRA_CONFIG.PERSISTENCE_INTERVAL_MS * 5);
166
- startAutoSleepCron();
167
- }
168
 
169
- const server = createServer((req: IncomingMessage, res: ServerResponse) => {
170
- const host = req.headers.host || "localhost";
171
- const fullUrl = new URL(req.url || "/", `http://${host}`);
172
- const { pathname } = fullUrl;
 
 
 
173
 
174
- // 🚑 INFRASTRUCTURE MAINTENANCE (April 2026): Intercept requests if configuration is missing
175
- if (!envStatus.valid && pathname !== "/api/health" && !pathname.startsWith("/_next/")) {
176
- res.writeHead(503, { 'Content-Type': 'text/html' });
177
- return res.end(`
178
- <!DOCTYPE html>
179
- <html>
180
  <head>
181
- <title>${APP_CONFIG.NAME} | ${UI_STRINGS.MAINTENANCE_TITLE}</title>
182
  <style>
183
- body { background: #09090b; color: #a1a1aa; font-family: sans-serif; height: 100vh; display: flex; align-items: center; justify-content: center; margin: 0; }
184
- .panic-card { background: #18181b; border: 1px solid #27272a; padding: 2.5rem; border-radius: 1rem; max-width: 550px; box-shadow: 0 25px 50px -12px rgba(0,0,0,0.5); }
185
- h1 { color: #f4f4f5; font-size: 1.5rem; margin: 0 0 1rem; }
186
- .desc { font-size: 0.9rem; line-height: 1.6; margin-bottom: 2rem; }
187
- .status { display: flex; flex-direction: column; gap: 0.75rem; margin: 1.5rem 0; }
188
- .item { padding: 0.75rem; border-radius: 0.5rem; background: #09090b; font-size: 0.875rem; border: 1px solid #27272a; display: flex; align-items: center; gap: 0.5rem; }
189
- .item.missing { color: #f87171; border-color: #450a0a; }
190
  </style>
 
191
  </head>
192
  <body>
193
- <div class="panic-card">
194
- <h1>${UI_STRINGS.MAINTENANCE_TITLE}</h1>
195
- <p class="desc">${UI_STRINGS.MAINTENANCE_MESSAGE}</p>
196
- <div class="status">
197
- ${envStatus.missing.map(m => `<div class="item missing"><span>❌</span> ${m}</div>`).join('')}
198
- </div>
199
  </div>
200
  </body>
201
- </html>
202
- `);
203
- }
204
-
205
- const workspaceHostMatch = host.match(/^workspace-([a-zA-Z0-9-]+)\./);
206
- const id = workspaceHostMatch ? workspaceHostMatch[1] : (pathname?.startsWith("/workspace/") ? pathname.split("/")[2] : null);
207
-
208
- if (id) {
209
- const isReady = isNativeWorkspaceRunning(id);
210
- if (isReady) {
211
- const port = getNativeWorkspacePort(id) || 8080;
212
- req.headers['x-codeverse-id'] = id;
213
- req.headers['x-codeverse-type'] = 'workspace';
214
-
215
- const prefix = `/workspace/${id}`;
216
- if (req.url?.startsWith(prefix)) {
217
- req.url = req.url.substring(prefix.length);
218
- if (!req.url.startsWith("/")) req.url = "/" + req.url;
219
- }
220
-
221
- return proxy.web(req, res, { target: `http://127.0.0.1:${port}`, changeOrigin: true });
222
- } else if (!pathname?.startsWith("/api/")) {
223
- res.writeHead(503, { 'Content-Type': 'text/html', 'Retry-After': '5' });
224
- res.end(`
225
- <html>
226
- <head>
227
- <title>${APP_CONFIG.NAME} | Booting Workspace</title>
228
- <style>
229
- body { background: #09090b; color: #71717a; font-family: sans-serif; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; }
230
- .container { text-align: center; border: 1px solid #27272a; padding: 2rem; border-radius: 1rem; background: #111113; }
231
- .spinner { width: 40px; height: 40px; border: 3px solid #3f3f46; border-top-color: #3b82f6; border-radius: 50%; animation: spin 1s linear infinite; margin: 0 auto 1.5rem; }
232
- h1 { color: #f4f4f5; font-size: 1.25rem; }
233
- @keyframes spin { to { transform: rotate(360deg); } }
234
- </style>
235
- <script>setTimeout(() => window.location.reload(), 3000);</script>
236
- </head>
237
- <body>
238
- <div class="container">
239
- <div class="spinner"></div>
240
- <h1>Workspace is Booting</h1>
241
- <p>Preparing your agentic session...</p>
242
- </div>
243
- </body>
244
- </html>
245
- `);
246
- return;
247
- }
248
- }
249
-
250
- handle(req, res);
251
- });
252
-
253
- const io = new Server(server, { path: "/api/socketio" });
254
- const yjsWss = new WebSocketServer({ noServer: true });
255
 
256
- server.on("upgrade", (req: IncomingMessage, socket: Duplex, head: Buffer) => {
257
- const host = req.headers.host || "localhost";
258
- const fullUrl = new URL(req.url || "/", `http://${host}`);
259
- const { pathname } = fullUrl;
 
 
 
 
 
 
 
 
 
260
 
261
- const workspaceHostMatch = host.match(/^workspace-([a-zA-Z0-9-]+)\./);
262
- const id = workspaceHostMatch ? workspaceHostMatch[1] : (pathname?.startsWith("/workspace/") ? pathname.split("/")[2] : null);
 
263
 
264
- if (id && isNativeWorkspaceRunning(id)) {
 
 
265
  const port = getNativeWorkspacePort(id) || 8080;
266
  req.headers['x-codeverse-id'] = id;
267
  req.headers['x-codeverse-type'] = 'workspace';
268
-
269
  const prefix = `/workspace/${id}`;
270
  if (req.url?.startsWith(prefix)) {
271
  req.url = req.url.substring(prefix.length);
272
  if (!req.url.startsWith("/")) req.url = "/" + req.url;
273
  }
274
- return proxy.ws(req, socket, head, { target: `http://127.0.0.1:${port}` });
275
  }
 
276
 
277
- if (pathname === "/api/collab") {
278
- yjsWss.handleUpgrade(req, socket, head, (ws) => {
279
- yjsWss.emit("connection", ws, req);
280
- });
281
- return;
282
- }
283
- });
284
 
285
- yjsWss.on("connection", (conn: WebSocket, request: IncomingMessage) => {
286
- const host = request.headers.host || "localhost";
287
- const fullUrl = new URL(request.url || "/", `http://${host}`);
288
- const docName = fullUrl.searchParams.get('doc') || "default";
289
- const { doc, awareness } = getOrCreateDoc(docName);
290
- conn.binaryType = "arraybuffer";
291
 
292
- const encoder = encoding.createEncoder();
293
- encoding.writeVarUint(encoder, 0);
294
- syncProtocol.writeSyncStep1(encoder, doc);
295
- conn.send(encoding.toUint8Array(encoder));
 
 
 
296
 
297
- const awarenessEncoder = encoding.createEncoder();
298
- encoding.writeVarUint(awarenessEncoder, 1);
299
- encoding.writeVarUint8Array(awarenessEncoder, awarenessProtocol.encodeAwarenessUpdate(awareness, Array.from(awareness.getStates().keys())));
300
- conn.send(encoding.toUint8Array(awarenessEncoder));
 
 
301
 
302
- conn.on("message", (message: ArrayBuffer) => {
303
- const encoder = encoding.createEncoder();
304
- const decoder = decoding.createDecoder(new Uint8Array(message));
305
- const messageType = decoding.readVarUint(decoder);
306
- if (messageType === 0) {
307
- encoding.writeVarUint(encoder, 0);
308
- syncProtocol.readSyncMessage(decoder, encoder, doc, null);
309
- if (encoding.length(encoder) > 1) {
310
- conn.send(encoding.toUint8Array(encoder));
311
- }
312
- } else if (messageType === 1) {
313
- awarenessProtocol.applyAwarenessUpdate(awareness, decoding.readVarUint8Array(decoder), conn);
314
- }
315
- });
316
 
317
- const updateHandler = (update: Uint8Array, origin: unknown) => {
318
- if (origin !== conn) {
319
- const encoder = encoding.createEncoder();
320
- encoding.writeVarUint(encoder, 0);
321
- syncProtocol.writeUpdate(encoder, update);
322
- conn.send(encoding.toUint8Array(encoder));
323
- }
324
- };
325
 
326
- doc.on("update", updateHandler);
327
- conn.on("close", () => {
328
- doc.off("update", updateHandler);
329
- awarenessProtocol.removeAwarenessStates(awareness, [doc.clientID], null);
 
 
330
  });
331
- });
 
332
 
333
- io.on("connection", (socket) => {
334
- let shell: pty.IPty | null = null;
335
- socket.on("terminal:start", ({ cols, rows }: { cols: number; rows: number }) => {
336
- const shellPath = process.env.SHELL || (os.platform() === "win32" ? "powershell.exe" : "bash");
337
- shell = pty.spawn(shellPath, [], {
338
- name: "xterm-color",
339
- cols: cols || 80,
340
- rows: rows || 24,
341
- cwd: INFRA_CONFIG.WORKSPACE_ROOT,
342
- env: process.env as Record<string, string>,
343
- });
344
- shell.onData((data: string) => socket.emit("terminal:data", data));
345
- });
346
- socket.on("terminal:write", (data: string) => { if (shell) shell.write(data); });
347
- socket.on("terminal:resize", ({ cols, rows }: { cols: number; rows: number }) => { if (shell) try { shell.resize(cols, rows); } catch {} });
348
- socket.on("disconnect", () => { if (shell) { shell.kill(); shell = null; } });
 
349
  });
 
350
 
351
- const PORT = process.env.PORT || 7860;
352
- server.listen(PORT, () => {
353
- console.log(`> Ready on http://localhost:${PORT}`);
 
 
 
 
 
 
 
354
  });
 
 
355
  });
 
18
  import os from "os";
19
  import { Duplex } from "stream";
20
  import { startAutoSleepCron } from "./lib/jobs/auto-sleep";
21
+ import { getNativeWorkspacePort, isNativeWorkspaceRunning, prewarmWorkspace, reconnectRunningWorkspaces } from "./lib/docker/manager";
22
  import { initDb } from "./lib/db/schema";
23
  import { client as dbClient } from "./lib/db";
24
  import { HFStorage } from "./lib/hf/storage";
 
46
  });
47
  };
48
 
 
 
 
49
  const proxy = httpProxy.createProxyServer({
50
  ws: true,
51
  xfwd: true,
 
53
  proxyTimeout: 30000
54
  });
55
 
 
 
 
 
 
 
 
 
 
 
 
56
  function renderProxyError(res: ServerResponse, error: string, id: string) {
57
  res.writeHead(502, { 'Content-Type': 'text/html' });
58
  res.end(`
 
103
  }
104
  });
105
 
106
+ // Port and Host logic
107
+ const PORT = Number(process.env.PORT) || 7860;
108
+ const HOST = '0.0.0.0';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
 
110
+ let isAppReady = false;
111
+ let envStatus = { valid: true, missing: [] as string[] };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
+ /**
114
+ *Autoritative Entrypoint: We initialize the HTTP server immediately to satisfy HF Spaces health checks.
115
+ */
116
+ const server = createServer((req: IncomingMessage, res: ServerResponse) => {
117
+ const host = req.headers.host || "localhost";
118
+ const fullUrl = new URL(req.url || "/", `http://${host}`);
119
+ const { pathname } = fullUrl;
120
 
121
+ // 1. Initializing State
122
+ if (!isAppReady && !pathname.startsWith("/_next/static") && pathname !== "/favicon.ico") {
123
+ res.writeHead(200, { 'Content-Type': 'text/html' });
124
+ return res.end(`
125
+ <html>
 
126
  <head>
127
+ <title>CodeVerse | Initializing</title>
128
  <style>
129
+ body { background: #09090b; color: #71717a; font-family: sans-serif; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; }
130
+ .container { text-align: center; border: 1px solid #27272a; padding: 2.5rem; border-radius: 1rem; background: #111113; max-width: 400px; }
131
+ .spinner { width: 30px; height: 30px; border: 2px solid #3f3f46; border-top-color: #3b82f6; border-radius: 50%; animation: spin 1s linear infinite; margin: 0 auto 1.5rem; }
132
+ h1 { color: #f4f4f5; font-size: 1.1rem; margin: 0; }
133
+ p { font-size: 0.85rem; margin-top: 0.5rem; }
134
+ @keyframes spin { to { transform: rotate(360deg); } }
 
135
  </style>
136
+ <script>setTimeout(() => window.location.reload(), 5000);</script>
137
  </head>
138
  <body>
139
+ <div class="container">
140
+ <div class="spinner"></div>
141
+ <h1>CodeVerse is waking up</h1>
142
+ <p>Restoring your environment and securing persistent volumes...</p>
 
 
143
  </div>
144
  </body>
145
+ </html>
146
+ `);
147
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
 
149
+ // 2. Maintenance / Misconfiguration State
150
+ if (isAppReady && !envStatus.valid && pathname !== "/api/health" && !pathname.startsWith("/_next/")) {
151
+ res.writeHead(503, { 'Content-Type': 'text/html' });
152
+ return res.end(`
153
+ <html>
154
+ <body style="background:#09090b;color:#f87171;padding:2rem;font-family:sans-serif;">
155
+ <h1>Infrastructure Error</h1>
156
+ <p>${UI_STRINGS.MAINTENANCE_MESSAGE}</p>
157
+ <ul>${envStatus.missing.map(m => `<li>${m}</li>`).join('')}</ul>
158
+ </body>
159
+ </html>
160
+ `);
161
+ }
162
 
163
+ // 3. Workspace Proxying
164
+ const workspaceHostMatch = host.match(/^workspace-([a-zA-Z0-9-]+)\./);
165
+ const id = workspaceHostMatch ? workspaceHostMatch[1] : (pathname?.startsWith("/workspace/") ? pathname.split("/")[2] : null);
166
 
167
+ if (id) {
168
+ const isReady = isNativeWorkspaceRunning(id);
169
+ if (isReady) {
170
  const port = getNativeWorkspacePort(id) || 8080;
171
  req.headers['x-codeverse-id'] = id;
172
  req.headers['x-codeverse-type'] = 'workspace';
 
173
  const prefix = `/workspace/${id}`;
174
  if (req.url?.startsWith(prefix)) {
175
  req.url = req.url.substring(prefix.length);
176
  if (!req.url.startsWith("/")) req.url = "/" + req.url;
177
  }
178
+ return proxy.web(req, res, { target: `http://127.0.0.1:${port}`, changeOrigin: true });
179
  }
180
+ }
181
 
182
+ // 4. Default Next.js Handle
183
+ handle(req, res);
184
+ });
 
 
 
 
185
 
186
+ // Setup Sockets
187
+ const io = new Server(server, { path: "/api/socketio" });
188
+ const yjsWss = new WebSocketServer({ noServer: true });
 
 
 
189
 
190
+ // Start Listening Immediately
191
+ server.listen(PORT, HOST, () => {
192
+ console.log('----------------------------------------------------');
193
+ console.log(`[READY] ${APP_CONFIG.NAME} ${APP_CONFIG.VERSION}`);
194
+ console.log(`[READY] Interface: ${HOST}:${PORT}`);
195
+ console.log('----------------------------------------------------');
196
+ });
197
 
198
+ // Background Async Initialization
199
+ (async () => {
200
+ try {
201
+ console.log("[BOOT] Starting Next.js preparation...");
202
+ await app.prepare();
203
+ console.log("[BOOT] Next.js payload ready.");
204
 
205
+ envStatus = validateEnvironment();
206
+ if (envStatus.valid) {
207
+ console.log("[BOOT] Environment validated. Synchronizing database...");
208
+ await initDb(dbClient);
209
+ console.log("[BOOT] Database synchronized.");
210
+
211
+ // Reconnect and Warmup
212
+ reconnectRunningWorkspaces().catch(() => {});
213
+ prewarmWorkspace({ id: 'baseline-warmup', userId: 'system', projectName: 'CodeVerse-Internal' }).catch(() => {});
214
+
215
+ // Crons and Persistence
216
+ HFStorage.startAutoSave(INFRA_CONFIG.PERSISTENCE_INTERVAL_MS * 5);
217
+ startAutoSleepCron();
218
+ }
219
 
220
+ isAppReady = true;
221
+ console.log("[BOOT] Global state stabilized. Application is fully operational.");
222
+ } catch (err) {
223
+ console.error("[BOOT:ERROR] Fatal initialization failure:", err);
224
+ }
225
+ })();
 
 
226
 
227
+ // Terminal and Collaboration Handlers
228
+ server.on("upgrade", (req, socket, head) => {
229
+ const { pathname } = new URL(req.url || "/", `http://${req.headers.host}`);
230
+ if (pathname === "/api/collab") {
231
+ yjsWss.handleUpgrade(req, socket, head, (ws) => {
232
+ yjsWss.emit("connection", ws, req);
233
  });
234
+ }
235
+ });
236
 
237
+ yjsWss.on("connection", (conn: WebSocket, request: IncomingMessage) => {
238
+ const { doc, awareness } = getOrCreateDoc(new URL(request.url || "/", "http://l").searchParams.get('doc') || "default");
239
+ conn.binaryType = "arraybuffer";
240
+ const encoder = encoding.createEncoder();
241
+ encoding.writeVarUint(encoder, 0);
242
+ syncProtocol.writeSyncStep1(encoder, doc);
243
+ conn.send(encoding.toUint8Array(encoder));
244
+
245
+ conn.on("message", (message: ArrayBuffer) => {
246
+ const encoder = encoding.createEncoder();
247
+ const decoder = decoding.createDecoder(new Uint8Array(message));
248
+ const messageType = decoding.readVarUint(decoder);
249
+ if (messageType === 0) {
250
+ encoding.writeVarUint(encoder, 0);
251
+ syncProtocol.readSyncMessage(decoder, encoder, doc, null);
252
+ if (encoding.length(encoder) > 1) conn.send(encoding.toUint8Array(encoder));
253
+ }
254
  });
255
+ });
256
 
257
+ io.on("connection", (socket) => {
258
+ let shell: pty.IPty | null = null;
259
+ socket.on("terminal:start", ({ cols, rows }) => {
260
+ shell = pty.spawn(process.env.SHELL || (os.platform() === "win32" ? "powershell.exe" : "bash"), [], {
261
+ cols: cols || 80,
262
+ rows: rows || 24,
263
+ cwd: INFRA_CONFIG.WORKSPACE_ROOT,
264
+ env: process.env as Record<string, string>,
265
+ });
266
+ shell.onData((data: string) => socket.emit("terminal:data", data));
267
  });
268
+ socket.on("terminal:write", (data) => { if (shell) shell.write(data); });
269
+ socket.on("disconnect", () => { if (shell) shell.kill(); });
270
  });