fix error
Browse files- .agent/memory/session.json +2 -2
- Dockerfile +27 -10
- lib/docker/manager.ts +2 -2
- lib/hf/storage.ts +7 -6
- lib/idx/idx-engine.ts +11 -4
- lib/jobs/auto-sleep.ts +3 -2
.agent/memory/session.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
{
|
| 2 |
"version": "1.0.0",
|
| 3 |
-
"session_id": "
|
| 4 |
-
"started_at": "2026-04-06T21:
|
| 5 |
"workspace": "D:\\Code\\codeverse",
|
| 6 |
"active_task_id": null,
|
| 7 |
"active_agent": null,
|
|
|
|
| 1 |
{
|
| 2 |
"version": "1.0.0",
|
| 3 |
+
"session_id": "cb036e35",
|
| 4 |
+
"started_at": "2026-04-06T21:37:35.313738+05:30",
|
| 5 |
"workspace": "D:\\Code\\codeverse",
|
| 6 |
"active_task_id": null,
|
| 7 |
"active_agent": null,
|
Dockerfile
CHANGED
|
@@ -18,8 +18,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
| 18 |
xvfb fluxbox novnc websockify libnss3 libatk-bridge2.0-0 libcups2 libgtk-3-0 \
|
| 19 |
&& rm -rf /var/lib/apt/lists/*
|
| 20 |
|
| 21 |
-
#
|
| 22 |
-
RUN
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
mkdir -p /etc/nix && echo "experimental-features = nix-command flakes" > /etc/nix/nix.conf
|
| 24 |
|
| 25 |
USER node
|
|
@@ -28,34 +35,44 @@ WORKDIR /home/node
|
|
| 28 |
# Use bash for reliable environment sourcing
|
| 29 |
SHELL ["/bin/bash", "-c"]
|
| 30 |
|
| 31 |
-
|
| 32 |
-
|
|
|
|
| 33 |
. /home/node/.nix-profile/etc/profile.d/nix.sh && \
|
| 34 |
-
/home/node/.nix-profile/bin/nix
|
|
|
|
| 35 |
|
| 36 |
ENV PATH="/home/node/.nix-profile/bin:/home/node/.nix-profile/sbin:${PATH}"
|
| 37 |
-
ENV NIX_PATH="nixpkgs=
|
| 38 |
|
| 39 |
# 3. Application Provisioning
|
| 40 |
USER root
|
| 41 |
-
|
|
|
|
|
|
|
|
|
|
| 42 |
COPY --chown=node:node package*.json ./
|
|
|
|
| 43 |
RUN npm install --no-audit --no-fund --quiet --legacy-peer-deps
|
| 44 |
|
|
|
|
|
|
|
| 45 |
COPY --chown=node:node . .
|
|
|
|
| 46 |
RUN npm run build
|
| 47 |
|
| 48 |
# 4. Runtime Hardening
|
| 49 |
ENV PORT=7860
|
| 50 |
ENV NODE_ENV=production
|
| 51 |
|
| 52 |
-
# Final Permissions Sync
|
|
|
|
| 53 |
RUN mkdir -p /home/node/app/workspaces && \
|
| 54 |
mkdir -p /home/node/app/dist && \
|
| 55 |
-
chown -R node:node /home/node/app /
|
| 56 |
|
| 57 |
USER node
|
| 58 |
|
| 59 |
# Authoritative Entrypoint for HF Spaces April 2026
|
| 60 |
-
#
|
| 61 |
CMD ["sh", "-c", "ulimit -s $(ulimit -Hs) 2>/dev/null || true && node dist/server.js"]
|
|
|
|
| 18 |
xvfb fluxbox novnc websockify libnss3 libatk-bridge2.0-0 libcups2 libgtk-3-0 \
|
| 19 |
&& rm -rf /var/lib/apt/lists/*
|
| 20 |
|
| 21 |
+
# Install Hugging Face CLI for persistence layer
|
| 22 |
+
RUN pip3 install --no-cache-dir "huggingface_hub[cli]"
|
| 23 |
+
|
| 24 |
+
# Install code-server (Liquid-smooth IDE binary)
|
| 25 |
+
RUN curl -fsSL https://code-server.dev/install.sh | sh
|
| 26 |
+
|
| 27 |
+
# 2. Nix Installation (Optimized for UID 1000)
|
| 28 |
+
# We set up /nix with correct permissions before switching to the node user
|
| 29 |
+
RUN mkdir -p /nix && chown node:node /nix && \
|
| 30 |
mkdir -p /etc/nix && echo "experimental-features = nix-command flakes" > /etc/nix/nix.conf
|
| 31 |
|
| 32 |
USER node
|
|
|
|
| 35 |
# Use bash for reliable environment sourcing
|
| 36 |
SHELL ["/bin/bash", "-c"]
|
| 37 |
|
| 38 |
+
# Use the Official Nix Installer (Non-interactive & No-daemon)
|
| 39 |
+
# We use a specific version for 2026 stability
|
| 40 |
+
RUN curl -L https://nixos.org/nix/install | sh -s -- --no-daemon && \
|
| 41 |
. /home/node/.nix-profile/etc/profile.d/nix.sh && \
|
| 42 |
+
/home/node/.nix-profile/bin/nix-channel --add https://nixos.org/channels/nixpkgs-unstable nixpkgs && \
|
| 43 |
+
/home/node/.nix-profile/bin/nix-channel --update
|
| 44 |
|
| 45 |
ENV PATH="/home/node/.nix-profile/bin:/home/node/.nix-profile/sbin:${PATH}"
|
| 46 |
+
ENV NIX_PATH="nixpkgs=/home/node/.nix-defexpr/channels/nixpkgs"
|
| 47 |
|
| 48 |
# 3. Application Provisioning
|
| 49 |
USER root
|
| 50 |
+
RUN mkdir -p /home/node/app && chown -R node:node /home/node/app
|
| 51 |
+
WORKDIR /home/node/app
|
| 52 |
+
|
| 53 |
+
# Copy package manifest first for better caching
|
| 54 |
COPY --chown=node:node package*.json ./
|
| 55 |
+
USER node
|
| 56 |
RUN npm install --no-audit --no-fund --quiet --legacy-peer-deps
|
| 57 |
|
| 58 |
+
# Copy rest of the application
|
| 59 |
+
USER root
|
| 60 |
COPY --chown=node:node . .
|
| 61 |
+
USER node
|
| 62 |
RUN npm run build
|
| 63 |
|
| 64 |
# 4. Runtime Hardening
|
| 65 |
ENV PORT=7860
|
| 66 |
ENV NODE_ENV=production
|
| 67 |
|
| 68 |
+
# Final Permissions Sync for persistence
|
| 69 |
+
USER root
|
| 70 |
RUN mkdir -p /home/node/app/workspaces && \
|
| 71 |
mkdir -p /home/node/app/dist && \
|
| 72 |
+
chown -R node:node /home/node/app /home/node
|
| 73 |
|
| 74 |
USER node
|
| 75 |
|
| 76 |
# Authoritative Entrypoint for HF Spaces April 2026
|
| 77 |
+
# Handle ulimit gracefully while launching the custom server
|
| 78 |
CMD ["sh", "-c", "ulimit -s $(ulimit -Hs) 2>/dev/null || true && node dist/server.js"]
|
lib/docker/manager.ts
CHANGED
|
@@ -121,7 +121,7 @@ export interface WorkspaceOperationResult {
|
|
| 121 |
* PREDICTIVE HYDRATION: Pre-warms Nix profile and SDKs.
|
| 122 |
*/
|
| 123 |
export async function prewarmWorkspace(config: WorkspaceConfig): Promise<void> {
|
| 124 |
-
const workspaceRoot = process.env.WORKSPACE_ROOT || path.join(/*turbopackIgnore: true*/ '/home/
|
| 125 |
const workspacePath = path.join(/*turbopackIgnore: true*/ workspaceRoot, config.id);
|
| 126 |
|
| 127 |
if (!fs.existsSync(workspacePath)) {
|
|
@@ -153,7 +153,7 @@ async function performProvisioning(config: WorkspaceConfig): Promise<WorkspaceOp
|
|
| 153 |
HFStorage.startAutoSave(300000); // Start 5m auto-save loop
|
| 154 |
|
| 155 |
// 1. Prepare Workspace Directory
|
| 156 |
-
const workspaceRoot = process.env.WORKSPACE_ROOT || path.join(/*turbopackIgnore: true*/ '/home/
|
| 157 |
const workspacePath = path.join(/*turbopackIgnore: true*/ workspaceRoot, config.id);
|
| 158 |
const userDataPath = path.join(/*turbopackIgnore: true*/ workspacePath, '.vscode-server');
|
| 159 |
|
|
|
|
| 121 |
* PREDICTIVE HYDRATION: Pre-warms Nix profile and SDKs.
|
| 122 |
*/
|
| 123 |
export async function prewarmWorkspace(config: WorkspaceConfig): Promise<void> {
|
| 124 |
+
const workspaceRoot = process.env.WORKSPACE_ROOT || path.join(/*turbopackIgnore: true*/ '/home/node/app/workspaces');
|
| 125 |
const workspacePath = path.join(/*turbopackIgnore: true*/ workspaceRoot, config.id);
|
| 126 |
|
| 127 |
if (!fs.existsSync(workspacePath)) {
|
|
|
|
| 153 |
HFStorage.startAutoSave(300000); // Start 5m auto-save loop
|
| 154 |
|
| 155 |
// 1. Prepare Workspace Directory
|
| 156 |
+
const workspaceRoot = process.env.WORKSPACE_ROOT || path.join(/*turbopackIgnore: true*/ '/home/node/app/workspaces');
|
| 157 |
const workspacePath = path.join(/*turbopackIgnore: true*/ workspaceRoot, config.id);
|
| 158 |
const userDataPath = path.join(/*turbopackIgnore: true*/ workspacePath, '.vscode-server');
|
| 159 |
|
lib/hf/storage.ts
CHANGED
|
@@ -9,14 +9,13 @@ export class HFStorage {
|
|
| 9 |
private static readonly HF_TOKEN = process.env.HF_TOKEN;
|
| 10 |
private static readonly HF_DATASET_ID = process.env.HF_DATASET_ID;
|
| 11 |
private static readonly PROFILE_PATH = path.join(process.env.HOME || '/home/node', '.nix-profile');
|
| 12 |
-
private static readonly WORKSPACE_ROOT = process.env.WORKSPACE_ROOT || '/app/workspaces';
|
| 13 |
|
| 14 |
/**
|
| 15 |
* Internal helper for asynchronous execution with logging.
|
| 16 |
*/
|
| 17 |
private static async execAsync(command: string, onLog?: (msg: string) => void): Promise<void> {
|
| 18 |
return new Promise((resolve, reject) => {
|
| 19 |
-
const [cmd, ...args] = command.split(' ');
|
| 20 |
const child = spawn('/bin/bash', ['-c', command], {
|
| 21 |
env: { ...process.env, HF_TOKEN: this.HF_TOKEN }
|
| 22 |
});
|
|
@@ -53,8 +52,9 @@ export class HFStorage {
|
|
| 53 |
await this.execAsync(`tar -xzf ${tarPath} -C ${process.env.HOME || '/home/node'}`, onLog);
|
| 54 |
onLog?.(`[HF:STORAGE] Profile restored successfully.`);
|
| 55 |
}
|
| 56 |
-
} catch (e:
|
| 57 |
-
|
|
|
|
| 58 |
}
|
| 59 |
}
|
| 60 |
|
|
@@ -74,8 +74,9 @@ export class HFStorage {
|
|
| 74 |
await this.execAsync(`huggingface-cli upload ${this.HF_DATASET_ID} ${tarPath} profile.tar.gz --token ${this.HF_TOKEN}`, onLog);
|
| 75 |
|
| 76 |
onLog?.(`[HF:STORAGE] Profile synchronized successfully.`);
|
| 77 |
-
} catch (e:
|
| 78 |
-
|
|
|
|
| 79 |
}
|
| 80 |
}
|
| 81 |
|
|
|
|
| 9 |
private static readonly HF_TOKEN = process.env.HF_TOKEN;
|
| 10 |
private static readonly HF_DATASET_ID = process.env.HF_DATASET_ID;
|
| 11 |
private static readonly PROFILE_PATH = path.join(process.env.HOME || '/home/node', '.nix-profile');
|
| 12 |
+
private static readonly WORKSPACE_ROOT = process.env.WORKSPACE_ROOT || '/home/node/app/workspaces';
|
| 13 |
|
| 14 |
/**
|
| 15 |
* Internal helper for asynchronous execution with logging.
|
| 16 |
*/
|
| 17 |
private static async execAsync(command: string, onLog?: (msg: string) => void): Promise<void> {
|
| 18 |
return new Promise((resolve, reject) => {
|
|
|
|
| 19 |
const child = spawn('/bin/bash', ['-c', command], {
|
| 20 |
env: { ...process.env, HF_TOKEN: this.HF_TOKEN }
|
| 21 |
});
|
|
|
|
| 52 |
await this.execAsync(`tar -xzf ${tarPath} -C ${process.env.HOME || '/home/node'}`, onLog);
|
| 53 |
onLog?.(`[HF:STORAGE] Profile restored successfully.`);
|
| 54 |
}
|
| 55 |
+
} catch (e: unknown) {
|
| 56 |
+
const errorMessage = e instanceof Error ? e.message : String(e);
|
| 57 |
+
onLog?.(`[ERROR] Profile restoration failed: ${errorMessage}`);
|
| 58 |
}
|
| 59 |
}
|
| 60 |
|
|
|
|
| 74 |
await this.execAsync(`huggingface-cli upload ${this.HF_DATASET_ID} ${tarPath} profile.tar.gz --token ${this.HF_TOKEN}`, onLog);
|
| 75 |
|
| 76 |
onLog?.(`[HF:STORAGE] Profile synchronized successfully.`);
|
| 77 |
+
} catch (e: unknown) {
|
| 78 |
+
const errorMessage = e instanceof Error ? e.message : String(e);
|
| 79 |
+
onLog?.(`[ERROR] Profile synchronization failed: ${errorMessage}`);
|
| 80 |
}
|
| 81 |
}
|
| 82 |
|
lib/idx/idx-engine.ts
CHANGED
|
@@ -51,8 +51,9 @@ export class IdxEngine {
|
|
| 51 |
if (config.packages.length === 0) config.packages = this.getDefaultConfig().packages;
|
| 52 |
|
| 53 |
return config;
|
| 54 |
-
} catch (e) {
|
| 55 |
-
|
|
|
|
| 56 |
return this.getDefaultConfig();
|
| 57 |
}
|
| 58 |
}
|
|
@@ -125,7 +126,10 @@ export class IdxEngine {
|
|
| 125 |
if (code === 0) resolve();
|
| 126 |
else reject(new Error(`Nix installation of ${pkgName} failed with code ${code}`));
|
| 127 |
});
|
| 128 |
-
}).catch(err =>
|
|
|
|
|
|
|
|
|
|
| 129 |
}
|
| 130 |
log(`Environment synchronized successfully.`);
|
| 131 |
}
|
|
@@ -151,6 +155,9 @@ export class IdxEngine {
|
|
| 151 |
if (code === 0) resolve();
|
| 152 |
else reject(new Error(`Hook ${hookName} failed with code ${code}`));
|
| 153 |
});
|
| 154 |
-
}).catch(err =>
|
|
|
|
|
|
|
|
|
|
| 155 |
}
|
| 156 |
}
|
|
|
|
| 51 |
if (config.packages.length === 0) config.packages = this.getDefaultConfig().packages;
|
| 52 |
|
| 53 |
return config;
|
| 54 |
+
} catch (e: unknown) {
|
| 55 |
+
const errorMessage = e instanceof Error ? e.message : String(e);
|
| 56 |
+
console.warn(`[IDX-ENGINE] Failed to parse dev.nix, falling back to baseline:`, errorMessage);
|
| 57 |
return this.getDefaultConfig();
|
| 58 |
}
|
| 59 |
}
|
|
|
|
| 126 |
if (code === 0) resolve();
|
| 127 |
else reject(new Error(`Nix installation of ${pkgName} failed with code ${code}`));
|
| 128 |
});
|
| 129 |
+
}).catch((err: unknown) => {
|
| 130 |
+
const errMsg = err instanceof Error ? err.message : String(err);
|
| 131 |
+
log(`[ERROR] ${errMsg}`);
|
| 132 |
+
});
|
| 133 |
}
|
| 134 |
log(`Environment synchronized successfully.`);
|
| 135 |
}
|
|
|
|
| 155 |
if (code === 0) resolve();
|
| 156 |
else reject(new Error(`Hook ${hookName} failed with code ${code}`));
|
| 157 |
});
|
| 158 |
+
}).catch((err: unknown) => {
|
| 159 |
+
const errMsg = err instanceof Error ? err.message : String(err);
|
| 160 |
+
log(`[ERROR] ${errMsg}`);
|
| 161 |
+
});
|
| 162 |
}
|
| 163 |
}
|
lib/jobs/auto-sleep.ts
CHANGED
|
@@ -53,8 +53,9 @@ export async function checkIdleContainers() {
|
|
| 53 |
// Set threshold for next check
|
| 54 |
networkThresholds.set(workspaceId, currentRx);
|
| 55 |
}
|
| 56 |
-
} catch (e) {
|
| 57 |
-
|
|
|
|
| 58 |
}
|
| 59 |
}
|
| 60 |
|
|
|
|
| 53 |
// Set threshold for next check
|
| 54 |
networkThresholds.set(workspaceId, currentRx);
|
| 55 |
}
|
| 56 |
+
} catch (e: unknown) {
|
| 57 |
+
const errorMessage = e instanceof Error ? e.message : String(e);
|
| 58 |
+
console.error("[Auto-Sleep] Error running cron:", errorMessage);
|
| 59 |
}
|
| 60 |
}
|
| 61 |
|