mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-29 01:41:42 +00:00
Switch the credential/config mounts from per-devcontainer named volumes
to bind mounts of `${localEnv:HOME}/.claude`, `~/.codex`, and
`~/.cursor`. Effect inside the container:
- Authentication is shared with the host. If you've already run
`claude login` / `codex login --device-auth` / `cursor-agent login`
on the host, you're already authenticated in the container.
- Plugins, skills, agents, memory, and settings sync both ways. Install
a plugin in the container, it shows up on the host; add a custom
agent on the host, the container sees it immediately.
- All devcontainers on the host share the same CLI state, mirroring
how host shells already share it. (Per-workspace isolation of plugins
was never a stated requirement; the previous per-devcontainer named
volumes leaked nothing useful.)
Add `.devcontainer/ensure-host-config-dirs.cjs` and wire it as
`initializeCommand`. It runs on the host before container create and
guarantees `~/.claude`, `~/.codex`, `~/.cursor` exist, so Docker doesn't
reject the bind mount when a CLI has never been used on this host.
Cross-platform via Node `os.homedir()` + `fs.mkdirSync({recursive: true})`;
idempotent; no third-party deps.
Update `.devcontainer/README.md`:
- New "How CLI state is shared with your host" section explaining the
bind-mount model up front so users know their host plugins/skills/
memory carry into the container.
- Mark first-time-login section as skippable when the user is already
authenticated on the host.
- Note the high-trust escape hatch: replace the three bind mounts with
`type=volume` named volumes if the host/container trust boundary
needs to be separated (Anthropic's reference pattern for enterprise).
- Replace the obsolete "rm named volume" troubleshooting row with one
that covers EACCES/EPERM on the host-bind-mount path.
137 lines
6.3 KiB
JSON
137 lines
6.3 KiB
JSON
// 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}"
|
|
}
|
|
},
|
|
|
|
// Runs on the HOST before the container is created. Ensures the bind
|
|
// mount sources (~/.claude, ~/.codex, ~/.cursor) exist so Docker doesn't
|
|
// reject the mount when a CLI has never been used on this host. Safe
|
|
// re-run; idempotent. See ensure-host-config-dirs.cjs.
|
|
"initializeCommand": "node .devcontainer/ensure-host-config-dirs.cjs",
|
|
|
|
// 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",
|
|
|
|
// CLI config dirs are bind-mounted from the host so the developer's
|
|
// existing plugins, skills, agents, memory, settings, and credentials
|
|
// for Claude Code / Codex / Cursor are immediately available inside the
|
|
// container, and changes inside the container flow back to the host.
|
|
// The `initializeCommand` above guarantees these source paths exist on
|
|
// first up so Docker never errors out on a missing bind source. Anthropic
|
|
// recommends per-devcontainer named volumes instead in enterprise /
|
|
// high-trust environments; for personal dev where the host + container
|
|
// share the same trust boundary, bind mounts give the better daily-driver
|
|
// experience.
|
|
//
|
|
// Shell history, npm cache, and node_modules stay in named volumes
|
|
// scoped per-workspace — history doesn't need to escape the workspace,
|
|
// node_modules belong off the bind mount for Win/Mac perf, and the npm
|
|
// cache wants the container-native FS.
|
|
"mounts": [
|
|
"source=${localEnv:HOME}/.claude,target=/home/node/.claude,type=bind",
|
|
"source=${localEnv:HOME}/.codex,target=/home/node/.codex,type=bind",
|
|
"source=${localEnv:HOME}/.cursor,target=/home/node/.cursor,type=bind",
|
|
"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), drop any stale `.husky/_` runtime cache (it
|
|
// can be left over from prior runs and Docker Desktop's Windows bind-mount
|
|
// permission translation refuses to let the new container's `node` user
|
|
// overwrite a file the previous host UID created — husky's `prepare`
|
|
// copyfile then EPERMs on `.husky/_/h`), and 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 && rm -rf .husky/_ && npm install && cd /workspace/gitnexus-shared && npm install && npm run build && cd /workspace/gitnexus-web && npm install && cd /workspace/gitnexus && npm install"
|
|
}
|