Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions feature-versions/state.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@
"installed": "sha256:dbf431d6b42d55cde50fa1df75c7f7c3999a90cde6d73f7a7071174b3c3d0cc4",
"filter": ".*\\/\\.devcontainer\\.json"
},
"ghcr.io/devcontainers/features/node": {
"tag": "1",
"installed": "sha256:8c0de46939b61958041700ee89e3493f3b2e4131a06dc46b4d9423427d06e5f6",
"filter": ".*\\/\\.devcontainer\\.json"
},
"ghcr.io/anthropics/devcontainer-features/claude-code": {
"tag": "1.0",
"installed": "sha256:cfc2e7d3e9fd3b9b01f8d5cb158508a884c8c0ede2e23ed10f32dea5d4ffe69a",
"filter": ".*\\/\\.devcontainer\\.json"
},
"us-west2-docker.pkg.dev/shared-pub-buckets-94mvrf/workbench-artifacts/app-wondershaper": {
"tag": "latest",
"installed": "sha256:6cb6bde6ace7dd7e82b9397e6c9d580e00969091e8091d78fea591ebecf0f6cb",
Expand Down
24 changes: 24 additions & 0 deletions features/src/gemini-cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

# Gemini CLI (gemini-cli)

Installs the Gemini CLI globally

## Example Usage

```json
"features": {
"./.devcontainer/features/gemini-cli": {}
}
```

## Options

| Options Id | Description | Type | Default Value |
|-----|-----|-----|-----|
| username | Username of the container user | string | root |



---

_Note: This file was auto-generated from the [devcontainer-feature.json](devcontainer-feature.json). Add additional notes to a `NOTES.md`._
17 changes: 17 additions & 0 deletions features/src/gemini-cli/devcontainer-feature.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "Gemini CLI",
"id": "gemini-cli",
"version": "1.0.0",
"description": "Installs the Gemini CLI globally",
"documentationURL": "https://github.com/google-gemini/gemini-cli",
"options": {
"username": {
"type": "string",
"default": "root",
"description": "Username of the container user"
}
},
"installsAfter": [
"ghcr.io/devcontainers/features/node"
]
}
73 changes: 73 additions & 0 deletions features/src/gemini-cli/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
set -o xtrace

readonly USERNAME="${USERNAME:-"root"}"

install_gemini_cli() {
local username="${1}"
echo "Installing Gemini CLI..."

if [ "${username}" = "root" ]; then
npm install -g @google/gemini-cli
else
local nvm_dir="${NVM_DIR:-/usr/local/share/nvm}"
local user_home
user_home=$(eval echo "~${username}" 2>/dev/null || echo "/home/${username}")
[ -d "${nvm_dir}" ] && chown -R "${username}:" "${nvm_dir}"
[ -d "${user_home}/.npm" ] && chown -R "${username}:" "${user_home}/.npm"
sudo -u "${username}" env PATH="${PATH}" npm install -g @google/gemini-cli
fi

if which gemini >/dev/null 2>&1; then
echo "Gemini CLI installed successfully!"
return 0
else
echo "ERROR: Gemini CLI installation failed!"
return 1
fi
}

fix_permissions() {
local username="${1}"

if [ "${username}" = "root" ]; then
return 0
fi

local user_home
user_home=$(eval echo "~${username}" 2>/dev/null || echo "/home/${username}")

mkdir -p "${user_home}/.gemini"
printf '{"general.enableAutoUpdate": false, "ui": {"autoThemeSwitching": false, "theme": "ANSI Light"}}\n' > "${user_home}/.gemini/settings.json"
chown -R "${username}:" "${user_home}/.gemini"
}

print_nodejs_requirement() {
cat <<EOF

ERROR: Node.js and npm are required but not found!
Please add the Node.js feature to your devcontainer.json:

"features": {
"ghcr.io/devcontainers/features/node:1": {},
"./.devcontainer/features/gemini-cli": { "username": "your-user" }
}

EOF
exit 1
}

echo "Activating feature 'gemini-cli'"

if ! command -v node >/dev/null || ! command -v npm >/dev/null; then
print_nodejs_requirement
fi

install_gemini_cli "${USERNAME}" || exit 1

fix_permissions "${USERNAME}"

echo "Done!"
5 changes: 5 additions & 0 deletions src/custom-workbench-jupyter-template/.devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
"${templateOption:login}"
],
"features": {
"ghcr.io/devcontainers/features/node@sha256:8c0de46939b61958041700ee89e3493f3b2e4131a06dc46b4d9423427d06e5f6": {
"version": "24.11.0"
},
"ghcr.io/anthropics/devcontainer-features/claude-code@sha256:cfc2e7d3e9fd3b9b01f8d5cb158508a884c8c0ede2e23ed10f32dea5d4ffe69a": {},
"./.devcontainer/features/gemini-cli": { "username": "jupyter" },
"./.devcontainer/features/workbench-tools": {
"libEnv": "/opt/conda/envs/jupyter", // Use the jupyter conda environment
"cloud": "${templateOption:cloud}",
Expand Down
5 changes: 5 additions & 0 deletions src/nemo_jupyter/.devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
"version": "17"
},
"ghcr.io/dhoeric/features/google-cloud-cli@sha256:fa5d894718825c5ad8009ac8f2c9f0cea3d1661eb108a9d465cba9f3fc48965f": {},
"ghcr.io/devcontainers/features/node@sha256:8c0de46939b61958041700ee89e3493f3b2e4131a06dc46b4d9423427d06e5f6": {
"version": "24.11.0"
},
"ghcr.io/anthropics/devcontainer-features/claude-code@sha256:cfc2e7d3e9fd3b9b01f8d5cb158508a884c8c0ede2e23ed10f32dea5d4ffe69a": {},
"./.devcontainer/features/gemini-cli": { "username": "jupyter" },
"./.devcontainer/features/workbench-tools": {
"libPythonVersion": "3.12", // Must match python version in nemo image
"cloud": "${templateOption:cloud}",
Expand Down
5 changes: 5 additions & 0 deletions src/r-analysis/.devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@
},
"ghcr.io/devcontainers/features/aws-cli@sha256:17cb4a40151f59144b46957b9264683663b0214371a041ecd53dccc015a4b923": {},
"ghcr.io/dhoeric/features/google-cloud-cli@sha256:fa5d894718825c5ad8009ac8f2c9f0cea3d1661eb108a9d465cba9f3fc48965f": {},
"ghcr.io/devcontainers/features/node@sha256:8c0de46939b61958041700ee89e3493f3b2e4131a06dc46b4d9423427d06e5f6": {
"version": "24.11.0"
},
"ghcr.io/anthropics/devcontainer-features/claude-code@sha256:cfc2e7d3e9fd3b9b01f8d5cb158508a884c8c0ede2e23ed10f32dea5d4ffe69a": {},
"./.devcontainer/features/gemini-cli": { "username": "rstudio" },
"./.devcontainer/features/workbench-tools": {
"cloud": "${templateOption:cloud}",
"username": "rstudio",
Expand Down
5 changes: 5 additions & 0 deletions src/vscode/.devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@
"ghcr.io/devcontainers/features/java@sha256:e75d274ac969b29a59ba6f34c2d098f6a52144d0ec027ef326b724ea4b8b7b4e": {
"version": "17"
},
"ghcr.io/devcontainers/features/node@sha256:8c0de46939b61958041700ee89e3493f3b2e4131a06dc46b4d9423427d06e5f6": {
"version": "24.11.0"
},
"ghcr.io/devcontainers/features/aws-cli@sha256:17cb4a40151f59144b46957b9264683663b0214371a041ecd53dccc015a4b923": {},
"ghcr.io/dhoeric/features/google-cloud-cli@sha256:fa5d894718825c5ad8009ac8f2c9f0cea3d1661eb108a9d465cba9f3fc48965f": {},
"ghcr.io/anthropics/devcontainer-features/claude-code@sha256:cfc2e7d3e9fd3b9b01f8d5cb158508a884c8c0ede2e23ed10f32dea5d4ffe69a": {},
"./.devcontainer/features/gemini-cli": { "username": "abc" },
"./.devcontainer/features/workbench-tools": {
"cloud": "${templateOption:cloud}",
"username": "abc",
Expand Down
19 changes: 19 additions & 0 deletions src/vscode/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
FROM lscr.io/linuxserver/code-server:4.100.3

# Gemini: https://open-vsx.org/extension/Google/geminicodeassist
# Claude: https://open-vsx.org/extension/Anthropic/claude-code
RUN apt-get update \
&& apt-get install -y --no-install-recommends jq \
&& rm -rf /var/lib/apt/lists/* \
&& curl -fsSL "https://open-vsx.org/api/Google/geminicodeassist/latest" \
| jq -r '.files.download' \
| xargs curl -fL --compressed -o /opt/geminicodeassist.vsix \
&& curl -fsSL "https://open-vsx.org/api/Anthropic/claude-code/latest" \
| jq -r '.files.download' \
| xargs curl -fL --compressed -o /opt/claudecode.vsix

# Install extensions during container init, before code-server starts
COPY install-extensions.sh /etc/cont-init.d/99-install-extensions
RUN chmod +x /etc/cont-init.d/99-install-extensions

WORKDIR /config
4 changes: 3 additions & 1 deletion src/vscode/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ version: "2.4"
services:
app:
container_name: "application-server"
image: "lscr.io/linuxserver/code-server:4.100.3"
build:
context: .
dockerfile: Dockerfile
restart: always
volumes:
- .:/workspace:cached
Expand Down
10 changes: 10 additions & 0 deletions src/vscode/install-extensions.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/with-contenv bash
# shellcheck shell=bash
# Installs VS Code extensions once on first container boot.

[ -f /config/.extensions-installed ] && exit 0

HOME=/config s6-setuidgid abc /app/code-server/bin/code-server --extensions-dir /config/extensions --install-extension /opt/geminicodeassist.vsix
HOME=/config s6-setuidgid abc /app/code-server/bin/code-server --extensions-dir /config/extensions --install-extension /opt/claudecode.vsix

touch /config/.extensions-installed
5 changes: 5 additions & 0 deletions src/workbench-jupyter-parabricks/.devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@
},
"ghcr.io/dhoeric/features/google-cloud-cli@sha256:fa5d894718825c5ad8009ac8f2c9f0cea3d1661eb108a9d465cba9f3fc48965f": {},
"ghcr.io/devcontainers/features/aws-cli@sha256:17cb4a40151f59144b46957b9264683663b0214371a041ecd53dccc015a4b923":{},
"ghcr.io/devcontainers/features/node@sha256:8c0de46939b61958041700ee89e3493f3b2e4131a06dc46b4d9423427d06e5f6": {
"version": "24.11.0"
},
"ghcr.io/anthropics/devcontainer-features/claude-code@sha256:cfc2e7d3e9fd3b9b01f8d5cb158508a884c8c0ede2e23ed10f32dea5d4ffe69a": {},
"./.devcontainer/features/gemini-cli": { "username": "jupyter" },
"./.devcontainer/features/workbench-tools": {
"cloud": "${templateOption:cloud}",
"username": "jupyter",
Expand Down
11 changes: 11 additions & 0 deletions startupscript/setup-bashrc.sh
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,14 @@ export AWS_VAULT_FILE_PASSPHRASE=""
EOF

fi

# Headless devcontainers: no real display/browser for gcloud, Claude Code, Gemini CLI.
emit "Adding headless CLI environment to ~/.bashrc ..."

cat << 'EOF' >> "${USER_BASHRC}"

# Headless Workbench (gcloud, Claude Code, Gemini CLI)
export DISPLAY=
export BROWSER=
export NO_BROWSER=1
EOF
Loading