// Devcontainer for GitNexus. Pre-installs Claude Code, OpenAI Codex CLI, // and Cursor CLI alongside the Node.js native build chain. Cross-platform // (Win11+WSL2 + macOS + Linux), opened via the VS Code Dev Containers // extension. // // First-time setup, auth flows, and troubleshooting: .devcontainer/README.md. { "name": "GitNexus AI CLI Devcontainer", "build": { "dockerfile": "Dockerfile", "context": ".", "args": { "CLAUDE_CODE_VERSION": "2.1.153", "CODEX_VERSION": "0.134.0", "CURSOR_VERSION": "latest", "TZ": "${localEnv:TZ:UTC}" } }, // Anthropic's official Claude Code Feature pulls the latest stable at // build time; DISABLE_AUTOUPDATER below locks it inside the running // container so rebuild is the only way the version changes. "features": { "ghcr.io/anthropics/devcontainer-features/claude-code:1": {}, "ghcr.io/devcontainers/features/github-cli:1": {} }, "remoteUser": "node", "updateRemoteUserUID": true, "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=delegated", "workspaceFolder": "/workspace", // Named volumes scoped per-devcontainer keep auth tokens, history, and // node_modules persistent across rebuilds without leaking between // workspaces. Sub-workspace node_modules volumes keep tree-sitter native // binaries and onnxruntime off the bind mount (the real Win/Mac perf win). "mounts": [ "source=claude-config-${devcontainerId},target=/home/node/.claude,type=volume", "source=codex-config-${devcontainerId},target=/home/node/.codex,type=volume", "source=cursor-config-${devcontainerId},target=/home/node/.cursor,type=volume", "source=commandhistory-${devcontainerId},target=/commandhistory,type=volume", "source=npm-cache-${devcontainerId},target=/home/node/.npm,type=volume", "source=${localWorkspaceFolderBasename}-root-node-modules,target=/workspace/node_modules,type=volume", "source=${localWorkspaceFolderBasename}-gitnexus-node-modules,target=/workspace/gitnexus/node_modules,type=volume", "source=${localWorkspaceFolderBasename}-gitnexus-web-node-modules,target=/workspace/gitnexus-web/node_modules,type=volume", "source=${localWorkspaceFolderBasename}-gitnexus-shared-node-modules,target=/workspace/gitnexus-shared/node_modules,type=volume" ], // Interactive login is the default auth path for all three CLIs; // credentials persist in the per-devcontainer named volumes mounted above. // API keys (ANTHROPIC_API_KEY / OPENAI_API_KEY / CURSOR_API_KEY) are NOT // injected via containerEnv — `${localEnv:VAR}` resolves an unset host var // to an empty string, and Cursor in particular treats `CURSOR_API_KEY=""` // as "use this empty key" rather than "fall back to stored login", which // would silently break `cursor-agent login`. Users who need API key auth // should `export` the var in their container shell or carry it via their // VS Code dotfiles repo (see .devcontainer/README.md). "containerEnv": { "CLAUDE_CONFIG_DIR": "/home/node/.claude", "DISABLE_AUTOUPDATER": "1", "HISTFILE": "/commandhistory/.zsh_history" }, "customizations": { "vscode": { "extensions": [ "anthropic.claude-code", "dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "eamodio.gitlens" ], "settings": { "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit" }, "files.eol": "\n", "terminal.integrated.defaultProfile.linux": "zsh", "terminal.integrated.profiles.linux": { "bash": { "path": "bash", "icon": "terminal-bash" }, "zsh": { "path": "zsh" } } } } }, // 4747 (gitnexus serve) must not be remapped: gitnexus-web hardcodes // http://localhost:4747 as the default backend URL. "forwardPorts": [5173, 4747, 4173], "portsAttributes": { "5173": { "label": "Vite dev (gitnexus-web)", "onAutoForward": "notify" }, "4747": { "label": "gitnexus serve HTTP API", "onAutoForward": "notify", "requireLocalPort": true }, "4173": { "label": "Static web (Vite preview)", "onAutoForward": "silent" } }, // Sequential setup: chown the workspace-side node_modules volumes (Docker // creates them root-owned), then install in dependency order: // root (husky) → gitnexus-shared (install + build, consumed via file:..) // → gitnexus-web (must install BEFORE gitnexus, because gitnexus's // `prepare` script runs scripts/build.js which compiles gitnexus-web) // → gitnexus (last; its prepare hook needs gitnexus-web's node_modules). "postCreateCommand": "sudo chown -R node:node /workspace/node_modules /workspace/gitnexus/node_modules /workspace/gitnexus-web/node_modules /workspace/gitnexus-shared/node_modules && cd /workspace && npm install && cd /workspace/gitnexus-shared && npm install && npm run build && cd /workspace/gitnexus-web && npm install && cd /workspace/gitnexus && npm install" }