Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| da40d57e07 | |||
| e99ec65cd9 | |||
| 38e481484e | |||
| 3e46bf5ec1 | |||
| c8a7bbcd6e | |||
| adb2ee4817 | |||
| 3637a0a6fc | |||
| f67066823b | |||
| 50560652cb | |||
| 0fc4ff503b | |||
| 04203e4efb | |||
| b710daac05 | |||
| 52a29da38d | |||
| ea71f71c74 | |||
| f6eceb4d94 | |||
| 84bf7841c3 | |||
| c823a30c2a | |||
| 27af9dc9c4 | |||
| 0944dcec1c | |||
| 60a2689658 |
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"enabledPlugins": {
|
||||||
|
"voltagent-dev-exp@voltagent-subagents": true,
|
||||||
|
"voltagent-lang@voltagent-subagents": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,13 @@
|
|||||||
"flux",
|
"flux",
|
||||||
"playwright",
|
"playwright",
|
||||||
"github",
|
"github",
|
||||||
"pgtuner"
|
"pgtuner",
|
||||||
]
|
"fetch",
|
||||||
|
"sequentialthinking"
|
||||||
|
],
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(git add .claude/settings.local.json .claude/settings.json && git commit -m \"$\\(cat <<'EOF'\nchore: update Claude Code settings and enable voltagent plugins\n\nAdd fetch and sequentialthinking MCP servers to allowed list, and enable\nvoltagent dev-exp and lang subagent plugins.\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>\nEOF\n\\)\" && git status)"
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,8 @@ Use this for all version releases:
|
|||||||
- ✅ Updates chart version
|
- ✅ Updates chart version
|
||||||
- ✅ Creates git tag
|
- ✅ Creates git tag
|
||||||
- ✅ Builds Docker image with all proper tags
|
- ✅ Builds Docker image with all proper tags
|
||||||
- ✅ Publishes Helm chart to GHCR
|
- ✅ Publishes Helm chart to GitHub Pages (`https://cpfarhood.github.io/devcontainer`)
|
||||||
- ✅ Creates GitHub Release with changelog
|
- ✅ Creates GitHub Release with changelog
|
||||||
- ✅ No more `[skip ci]` blocking builds!
|
|
||||||
|
|
||||||
### 2️⃣ For Quick Fixes → **Quick Fix Build**
|
### 2️⃣ For Quick Fixes → **Quick Fix Build**
|
||||||
Use this for emergency fixes without version changes:
|
Use this for emergency fixes without version changes:
|
||||||
@@ -30,8 +29,8 @@ Use this for emergency fixes without version changes:
|
|||||||
|
|
||||||
### 3️⃣ Automatic CI → **Build and Push**
|
### 3️⃣ Automatic CI → **Build and Push**
|
||||||
Runs automatically on:
|
Runs automatically on:
|
||||||
|
- Pushes to `main` (builds and pushes; skipped for release commits via `[skip ci]`)
|
||||||
- Pull requests (builds but doesn't push)
|
- Pull requests (builds but doesn't push)
|
||||||
- Tags starting with `v*` (builds and pushes)
|
|
||||||
- Manual trigger available
|
- Manual trigger available
|
||||||
|
|
||||||
## Workflow Files
|
## Workflow Files
|
||||||
@@ -90,5 +89,5 @@ gh run watch
|
|||||||
### After (Simple! 🎉)
|
### After (Simple! 🎉)
|
||||||
- **3 total workflows** (down from 6+)
|
- **3 total workflows** (down from 6+)
|
||||||
- **1 button** for complete releases
|
- **1 button** for complete releases
|
||||||
- **No more `[skip ci]`** blocking builds
|
- Release builds its own Docker image — `[skip ci]` on the version commit prevents duplicate CI builds
|
||||||
- **Clear separation** of concerns
|
- **Clear separation** of concerns
|
||||||
@@ -16,9 +16,6 @@ env:
|
|||||||
jobs:
|
jobs:
|
||||||
build-and-push:
|
build-and-push:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
# Skip builds triggered by release-unified.yaml commits (github-actions[bot])
|
|
||||||
# to prevent racing with the release workflow's own Docker build
|
|
||||||
if: github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request' || github.actor != 'github-actions[bot]'
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
packages: write
|
packages: write
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
version:
|
version:
|
||||||
description: 'Version to release (e.g., 0.1.25)'
|
description: 'Explicit version (e.g., 1.2.3). Leave blank to auto-increment.'
|
||||||
required: true
|
required: false
|
||||||
type: string
|
type: string
|
||||||
release_type:
|
release_type:
|
||||||
description: 'Release type'
|
description: 'Release type (used when version is blank)'
|
||||||
required: true
|
required: true
|
||||||
default: 'patch'
|
default: 'patch'
|
||||||
type: choice
|
type: choice
|
||||||
@@ -49,37 +49,34 @@ jobs:
|
|||||||
- name: Determine Version
|
- name: Determine Version
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
if [ "${{ github.event.inputs.version }}" != "" ]; then
|
INPUT_VERSION="${{ github.event.inputs.version }}"
|
||||||
VERSION="${{ github.event.inputs.version }}"
|
if [ -n "$INPUT_VERSION" ]; then
|
||||||
|
VERSION="$INPUT_VERSION"
|
||||||
else
|
else
|
||||||
# Auto-determine next version based on release type
|
# Auto-increment based on release_type
|
||||||
CURRENT=$(grep '^version:' chart/Chart.yaml | awk '{print $2}')
|
CURRENT=$(grep '^version:' chart/Chart.yaml | awk '{print $2}')
|
||||||
MAJOR=$(echo $CURRENT | cut -d. -f1)
|
# Strip any pre-release suffix (e.g., 2.0.0-dev -> 2.0.0)
|
||||||
MINOR=$(echo $CURRENT | cut -d. -f2)
|
CURRENT=$(echo "$CURRENT" | sed 's/-.*//')
|
||||||
PATCH=$(echo $CURRENT | cut -d. -f3)
|
MAJOR=$(echo "$CURRENT" | cut -d. -f1)
|
||||||
|
MINOR=$(echo "$CURRENT" | cut -d. -f2)
|
||||||
|
PATCH=$(echo "$CURRENT" | cut -d. -f3)
|
||||||
|
|
||||||
case "${{ github.event.inputs.release_type }}" in
|
case "${{ github.event.inputs.release_type }}" in
|
||||||
major)
|
major) VERSION="$((MAJOR + 1)).0.0" ;;
|
||||||
VERSION="$((MAJOR + 1)).0.0"
|
minor) VERSION="${MAJOR}.$((MINOR + 1)).0" ;;
|
||||||
;;
|
patch) VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))" ;;
|
||||||
minor)
|
|
||||||
VERSION="${MAJOR}.$((MINOR + 1)).0"
|
|
||||||
;;
|
|
||||||
patch)
|
|
||||||
VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))"
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
||||||
echo "tag=v${VERSION}" >> $GITHUB_OUTPUT
|
echo "tag=v${VERSION}" >> $GITHUB_OUTPUT
|
||||||
echo "🚀 Releasing version ${VERSION}"
|
echo "Releasing version ${VERSION}"
|
||||||
|
|
||||||
- name: Update Chart Version
|
- name: Update Chart Version
|
||||||
run: |
|
run: |
|
||||||
sed -i "s/^version: .*/version: ${{ steps.version.outputs.version }}/" chart/Chart.yaml
|
sed -i "s/^version: .*/version: ${{ steps.version.outputs.version }}/" chart/Chart.yaml
|
||||||
git add chart/Chart.yaml
|
git add chart/Chart.yaml
|
||||||
git commit -m "chore: release version ${{ steps.version.outputs.version }}"
|
git diff --quiet --staged || git commit -m "chore(release): ${{ steps.version.outputs.version }} [skip ci]"
|
||||||
|
|
||||||
- name: Create and Push Tag
|
- name: Create and Push Tag
|
||||||
run: |
|
run: |
|
||||||
@@ -107,27 +104,69 @@ jobs:
|
|||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
platforms: linux/amd64
|
platforms: linux/amd64
|
||||||
|
|
||||||
- name: Package Helm Chart
|
- name: Publish Helm Chart to GitHub Pages
|
||||||
run: |
|
run: |
|
||||||
helm registry login ghcr.io \
|
|
||||||
--username ${{ github.actor }} \
|
|
||||||
--password ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
helm package chart/
|
helm package chart/
|
||||||
helm push devcontainer-${{ steps.version.outputs.version }}.tgz oci://ghcr.io/cpfarhood/charts
|
CHART_TGZ="devcontainer-${{ steps.version.outputs.version }}.tgz"
|
||||||
|
|
||||||
- name: Generate Release Notes
|
# Set up gh-pages in a temporary directory
|
||||||
id: notes
|
PAGES_DIR=$(mktemp -d)
|
||||||
|
if git ls-remote --heads origin gh-pages | grep -q gh-pages; then
|
||||||
|
# gh-pages exists — shallow clone just that branch
|
||||||
|
git clone --single-branch --branch gh-pages \
|
||||||
|
"https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" \
|
||||||
|
"$PAGES_DIR"
|
||||||
|
else
|
||||||
|
# First time — initialize gh-pages
|
||||||
|
git init "$PAGES_DIR"
|
||||||
|
git -C "$PAGES_DIR" checkout --orphan gh-pages
|
||||||
|
git -C "$PAGES_DIR" remote add origin \
|
||||||
|
"https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git"
|
||||||
|
cat > "$PAGES_DIR/index.html" <<'HTMLEOF'
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head><title>Dev Container Helm Chart Repository</title></head>
|
||||||
|
<body>
|
||||||
|
<h1>Dev Container Helm Chart Repository</h1>
|
||||||
|
<p>Add this repository to Helm:</p>
|
||||||
|
<pre>helm repo add devcontainer https://cpfarhood.github.io/devcontainer</pre>
|
||||||
|
<p>Install the chart:</p>
|
||||||
|
<pre>helm install mydev devcontainer/devcontainer --set name=mydev</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
HTMLEOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
git -C "$PAGES_DIR" config user.name "github-actions[bot]"
|
||||||
|
git -C "$PAGES_DIR" config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
|
||||||
|
# Copy chart package and rebuild index
|
||||||
|
cp "$CHART_TGZ" "$PAGES_DIR/"
|
||||||
|
if [ -f "$PAGES_DIR/index.yaml" ]; then
|
||||||
|
helm repo index "$PAGES_DIR" --url https://cpfarhood.github.io/devcontainer --merge "$PAGES_DIR/index.yaml"
|
||||||
|
else
|
||||||
|
helm repo index "$PAGES_DIR" --url https://cpfarhood.github.io/devcontainer
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Commit and push
|
||||||
|
git -C "$PAGES_DIR" add .
|
||||||
|
git -C "$PAGES_DIR" commit -m "Publish chart ${{ steps.version.outputs.version }}"
|
||||||
|
git -C "$PAGES_DIR" push origin gh-pages
|
||||||
|
|
||||||
|
- name: Create GitHub Release
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
run: |
|
run: |
|
||||||
# Get commits since last tag
|
# Build release notes
|
||||||
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
|
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
|
||||||
if [ -z "$PREV_TAG" ]; then
|
if [ -z "$PREV_TAG" ]; then
|
||||||
COMMITS=$(git log --pretty=format:"- %s (%h)" HEAD)
|
COMMITS=$(git log --pretty=format:"- %s (%h)" HEAD)
|
||||||
else
|
else
|
||||||
COMMITS=$(git log --pretty=format:"- %s (%h)" ${PREV_TAG}..HEAD)
|
COMMITS=$(git log --pretty=format:"- %s (%h)" "${PREV_TAG}..HEAD")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cat << EOF > release-notes.md
|
cat > release-notes.md <<EOF
|
||||||
## 🚀 Release ${{ steps.version.outputs.version }}
|
## Release ${{ steps.version.outputs.version }}
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
${COMMITS}
|
${COMMITS}
|
||||||
@@ -139,21 +178,12 @@ jobs:
|
|||||||
|
|
||||||
### Helm Chart
|
### Helm Chart
|
||||||
\`\`\`bash
|
\`\`\`bash
|
||||||
helm install devcontainer oci://ghcr.io/cpfarhood/charts/devcontainer --version ${{ steps.version.outputs.version }}
|
helm repo add devcontainer https://cpfarhood.github.io/devcontainer
|
||||||
|
helm repo update
|
||||||
|
helm install mydev devcontainer/devcontainer --version ${{ steps.version.outputs.version }} --set name=mydev
|
||||||
\`\`\`
|
\`\`\`
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
echo "notes<<EOF" >> $GITHUB_OUTPUT
|
gh release create "${{ steps.version.outputs.tag }}" \
|
||||||
cat release-notes.md >> $GITHUB_OUTPUT
|
--title "Release ${{ steps.version.outputs.tag }}" \
|
||||||
echo "EOF" >> $GITHUB_OUTPUT
|
--notes-file release-notes.md
|
||||||
|
|
||||||
- name: Create GitHub Release
|
|
||||||
uses: actions/create-release@v1
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
|
||||||
tag_name: ${{ steps.version.outputs.tag }}
|
|
||||||
release_name: Release ${{ steps.version.outputs.tag }}
|
|
||||||
body: ${{ steps.notes.outputs.notes }}
|
|
||||||
draft: false
|
|
||||||
prerelease: false
|
|
||||||
|
|||||||
@@ -22,14 +22,6 @@
|
|||||||
"pgtuner": {
|
"pgtuner": {
|
||||||
"type": "sse",
|
"type": "sse",
|
||||||
"url": "http://localhost:8085/sse"
|
"url": "http://localhost:8085/sse"
|
||||||
},
|
|
||||||
"fetch": {
|
|
||||||
"type": "sse",
|
|
||||||
"url": "http://localhost:8082/sse"
|
|
||||||
},
|
|
||||||
"sequentialthinking": {
|
|
||||||
"type": "sse",
|
|
||||||
"url": "http://localhost:8083/sse"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
The Dev Container is a Docker-based cloud development environment that provides:
|
The Dev Container is a Docker-based cloud development environment that provides:
|
||||||
- Web-based GUI IDE (VSCode/Antigravity) via VNC on port 5800
|
- Web-based GUI IDE (VSCode/Antigravity) via VNC on port 5800
|
||||||
- Claude Code, Happy Coder, OpenCode, and Crush AI coding agents (terminal-based)
|
- Claude Code, Happy Coder, OpenCode, and Crush AI coding agents (terminal-based)
|
||||||
|
- Built-in web file manager for uploading/downloading files (optional, via `fileManager.enabled`)
|
||||||
- Automatic GitHub repository cloning on startup
|
- Automatic GitHub repository cloning on startup
|
||||||
- Kubernetes-native deployment with persistent home storage
|
- Kubernetes-native deployment with persistent home storage
|
||||||
- MCP (Model Context Protocol) sidecars for AI assistant integrations
|
- MCP (Model Context Protocol) sidecars for AI assistant integrations
|
||||||
@@ -68,7 +69,7 @@ Container start
|
|||||||
|
|
||||||
| File | Purpose |
|
| File | Purpose |
|
||||||
|------|---------|
|
|------|---------|
|
||||||
| `Dockerfile` | Image definition — installs Chrome, Node.js, VSCode, Claude Code, Happy Coder, OpenCode, Crush; creates non-root user (UID 1000) |
|
| `Dockerfile` | Image definition — installs Chrome, Node.js, VSCode, Helm, Claude Code, Happy Coder, OpenCode, Crush; creates non-root user (UID 1000) |
|
||||||
| `scripts/init-repo.sh` | Configures git credentials, clones GitHub repo |
|
| `scripts/init-repo.sh` | Configures git credentials, clones GitHub repo |
|
||||||
| `scripts/startapp.sh` | Calls init-repo.sh then opens VSCode in the workspace |
|
| `scripts/startapp.sh` | Calls init-repo.sh then opens VSCode in the workspace |
|
||||||
| `chart/` | Helm chart for Kubernetes deployment |
|
| `chart/` | Helm chart for Kubernetes deployment |
|
||||||
@@ -183,17 +184,22 @@ helm install my-devcontainer ./chart -f custom-values.yaml
|
|||||||
- `USER_ID` / `GROUP_ID` — Override UID/GID (default 1000)
|
- `USER_ID` / `GROUP_ID` — Override UID/GID (default 1000)
|
||||||
- `HAPPY_SERVER_URL` / `HAPPY_WEBAPP_URL` — Custom Happy Coder endpoints
|
- `HAPPY_SERVER_URL` / `HAPPY_WEBAPP_URL` — Custom Happy Coder endpoints
|
||||||
- `HAPPY_HOME_DIR` / `HAPPY_EXPERIMENTAL`
|
- `HAPPY_HOME_DIR` / `HAPPY_EXPERIMENTAL`
|
||||||
|
- `WEB_FILE_MANAGER` — Set to `1` to enable the built-in web file manager (controlled via `fileManager.enabled` in Helm values)
|
||||||
|
- `WEB_FILE_MANAGER_ALLOWED_PATHS` — Paths accessible by the file manager (default: `/workspace,/config`)
|
||||||
|
- `WEB_FILE_MANAGER_DENIED_PATHS` — Paths to deny access to (takes precedence over allowed)
|
||||||
|
|
||||||
### CI/CD
|
### CI/CD
|
||||||
|
|
||||||
- **`build-and-push.yaml`** — Builds and pushes to GHCR on every push to `main`, version tags (`v*`), and PRs. For version tags, also creates GitHub Release with Helm chart after Docker build completes. Tags: `latest` (main), semver, branch name, commit SHA.
|
- **`build-and-push.yaml`** — Builds and pushes to GHCR on every push to `main`, version tags (`v*`), and PRs. Tags: `latest` (main), semver, branch name, commit SHA.
|
||||||
|
- **`release-unified.yaml`** — Manual release workflow: bumps chart version, builds Docker image, publishes Helm chart to GitHub Pages (`https://cpfarhood.github.io/devcontainer`), and creates GitHub Release.
|
||||||
- **`dependabot.yml`** — Weekly updates for GitHub Actions and Docker base image.
|
- **`dependabot.yml`** — Weekly updates for GitHub Actions and Docker base image.
|
||||||
|
|
||||||
Image registry: `ghcr.io/cpfarhood/devcontainer`
|
Image registry: `ghcr.io/cpfarhood/devcontainer`
|
||||||
|
Helm repo: `https://cpfarhood.github.io/devcontainer`
|
||||||
|
|
||||||
## Kubernetes Notes
|
## Kubernetes Notes
|
||||||
|
|
||||||
- Deployed via Helm chart (`chart/`), published as OCI artifact to GHCR, reconciled by Flux
|
- Deployed via Helm chart (`chart/`), published to GitHub Pages Helm repo, reconciled by Flux
|
||||||
- Storage class is `ceph-filesystem` by default — change via `storage.className` in values
|
- Storage class is `ceph-filesystem` by default — change via `storage.className` in values
|
||||||
- Resource limits: 1–4 CPU, 2–8Gi memory
|
- Resource limits: 1–4 CPU, 2–8Gi memory
|
||||||
- Health checks (liveness/readiness probes) on port 5800
|
- Health checks (liveness/readiness probes) on port 5800
|
||||||
|
|||||||
+11
-3
@@ -72,9 +72,17 @@ RUN OPENCODE_VERSION=$(curl -sL https://api.github.com/repos/opencode-ai/opencod
|
|||||||
|
|
||||||
# Install Crush AI coding agent (OpenCode successor by Charm)
|
# Install Crush AI coding agent (OpenCode successor by Charm)
|
||||||
RUN CRUSH_VERSION=$(curl -sL https://api.github.com/repos/charmbracelet/crush/releases/latest | jq -r '.tag_name' | sed 's/^v//') && \
|
RUN CRUSH_VERSION=$(curl -sL https://api.github.com/repos/charmbracelet/crush/releases/latest | jq -r '.tag_name' | sed 's/^v//') && \
|
||||||
curl -fsSL "https://github.com/charmbracelet/crush/releases/download/v${CRUSH_VERSION}/crush_${CRUSH_VERSION}_Linux_x86_64.tar.gz" | \
|
curl -fsSL "https://github.com/charmbracelet/crush/releases/download/v${CRUSH_VERSION}/crush_${CRUSH_VERSION}_Linux_x86_64.tar.gz" -o /tmp/crush.tar.gz && \
|
||||||
tar -xz --strip-components=1 -C /usr/local/bin "crush_${CRUSH_VERSION}_Linux_x86_64/crush" && \
|
tar -xzf /tmp/crush.tar.gz -C /tmp && \
|
||||||
chmod +x /usr/local/bin/crush
|
mv /tmp/crush_${CRUSH_VERSION}_Linux_x86_64/crush /usr/local/bin/crush && \
|
||||||
|
chmod +x /usr/local/bin/crush && \
|
||||||
|
rm -rf /tmp/crush*
|
||||||
|
|
||||||
|
# Install Helm CLI for Kubernetes chart management
|
||||||
|
ARG HELM_VERSION=3.17.1
|
||||||
|
RUN curl -fsSL "https://get.helm.sh/helm-v${HELM_VERSION}-linux-amd64.tar.gz" | \
|
||||||
|
tar -xz --strip-components=1 -C /usr/local/bin linux-amd64/helm && \
|
||||||
|
chmod +x /usr/local/bin/helm
|
||||||
|
|
||||||
# Install VSCode
|
# Install VSCode
|
||||||
RUN wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /usr/share/keyrings/packages.microsoft.gpg && \
|
RUN wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /usr/share/keyrings/packages.microsoft.gpg && \
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# Variables
|
# Variables
|
||||||
REGISTRY ?= ghcr.io/cpfarhood
|
REGISTRY ?= ghcr.io/cpfarhood
|
||||||
IMAGE_NAME ?= antigravity
|
IMAGE_NAME ?= devcontainer
|
||||||
IMAGE_TAG ?= latest
|
IMAGE_TAG ?= latest
|
||||||
FULL_IMAGE = $(REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG)
|
FULL_IMAGE = $(REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG)
|
||||||
|
|
||||||
@@ -29,15 +29,15 @@ run:
|
|||||||
-e HAPPY_EXPERIMENTAL="true" \
|
-e HAPPY_EXPERIMENTAL="true" \
|
||||||
-v $(PWD)/home:/home \
|
-v $(PWD)/home:/home \
|
||||||
-v $(PWD)/workspace:/workspace \
|
-v $(PWD)/workspace:/workspace \
|
||||||
--name antigravity \
|
--name devcontainer \
|
||||||
$(FULL_IMAGE)
|
$(FULL_IMAGE)
|
||||||
@echo "Access at http://localhost:5800"
|
@echo "Access at http://localhost:5800"
|
||||||
|
|
||||||
# Stop the running container
|
# Stop the running container
|
||||||
stop:
|
stop:
|
||||||
@echo "Stopping antigravity container..."
|
@echo "Stopping devcontainer..."
|
||||||
docker stop antigravity || true
|
docker stop devcontainer || true
|
||||||
docker rm antigravity || true
|
docker rm devcontainer || true
|
||||||
|
|
||||||
# Clean up local volumes
|
# Clean up local volumes
|
||||||
clean: stop
|
clean: stop
|
||||||
@@ -81,7 +81,7 @@ helm-port-forward:
|
|||||||
|
|
||||||
# Show help
|
# Show help
|
||||||
help:
|
help:
|
||||||
@echo "Antigravity Dev Container Makefile"
|
@echo "Dev Container Makefile"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Usage: make [target]"
|
@echo "Usage: make [target]"
|
||||||
@echo ""
|
@echo ""
|
||||||
@@ -101,7 +101,7 @@ help:
|
|||||||
@echo ""
|
@echo ""
|
||||||
@echo "Variables:"
|
@echo "Variables:"
|
||||||
@echo " REGISTRY - Docker registry (default: ghcr.io/cpfarhood)"
|
@echo " REGISTRY - Docker registry (default: ghcr.io/cpfarhood)"
|
||||||
@echo " IMAGE_NAME - Image name (default: antigravity)"
|
@echo " IMAGE_NAME - Image name (default: devcontainer)"
|
||||||
@echo " IMAGE_TAG - Image tag (default: latest)"
|
@echo " IMAGE_TAG - Image tag (default: latest)"
|
||||||
@echo " RELEASE_NAME - Helm release name (default: mydev)"
|
@echo " RELEASE_NAME - Helm release name (default: mydev)"
|
||||||
@echo " NAMESPACE - Kubernetes namespace (default: default)"
|
@echo " NAMESPACE - Kubernetes namespace (default: default)"
|
||||||
|
|||||||
@@ -6,29 +6,38 @@ A containerized cloud development environment with web-based GUI access, featuri
|
|||||||
- **VSCode or Google Antigravity** via browser-based VNC (port 5800)
|
- **VSCode or Google Antigravity** via browser-based VNC (port 5800)
|
||||||
- **SSH access** option (OpenSSH on port 22, additive with any IDE)
|
- **SSH access** option (OpenSSH on port 22, additive with any IDE)
|
||||||
- **Claude Code**, **Happy Coder**, **OpenCode**, and **Crush** AI coding agents (terminal-based)
|
- **Claude Code**, **Happy Coder**, **OpenCode**, and **Crush** AI coding agents (terminal-based)
|
||||||
|
- **Built-in web file manager** for uploading/downloading files via the VNC web interface
|
||||||
|
- **Helm CLI** included for Kubernetes chart development and deployment
|
||||||
- **Automatic GitHub repo cloning** on startup
|
- **Automatic GitHub repo cloning** on startup
|
||||||
- **Persistent home directory** via ReadWriteMany PVC
|
- **Persistent home directory** via ReadWriteMany PVC
|
||||||
- **Kubernetes-native** Helm chart deployment
|
- **Kubernetes-native** Helm chart deployment
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
### Option A: Quickstart (Recommended)
|
### Option A: Install from Helm Repo (Recommended)
|
||||||
|
|
||||||
For 80% of users, use the simplified quickstart values:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Copy and customize the quickstart template
|
# Add the Helm repository
|
||||||
|
helm repo add devcontainer https://cpfarhood.github.io/devcontainer
|
||||||
|
helm repo update
|
||||||
|
|
||||||
|
# Deploy with one command
|
||||||
|
helm install mydev devcontainer/devcontainer \
|
||||||
|
--set name=mydev \
|
||||||
|
--set githubRepo=https://github.com/youruser/yourrepo
|
||||||
|
```
|
||||||
|
|
||||||
|
### Option B: Install from Source
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clone and customize the quickstart template
|
||||||
cp chart/values-quickstart.yaml my-values.yaml
|
cp chart/values-quickstart.yaml my-values.yaml
|
||||||
|
# Edit my-values.yaml to set your name and repository
|
||||||
|
|
||||||
# Edit my-values.yaml to set your name and repository:
|
|
||||||
# name: mydev
|
|
||||||
# githubRepo: https://github.com/youruser/yourrepo
|
|
||||||
|
|
||||||
# Deploy with minimal configuration
|
|
||||||
helm install mydev ./chart -f my-values.yaml
|
helm install mydev ./chart -f my-values.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
### Option B: One-Command Deploy
|
### Option C: One-Command from Source
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
helm install mydev ./chart \
|
helm install mydev ./chart \
|
||||||
@@ -121,6 +130,7 @@ The Helm chart uses a logical organization with these main sections:
|
|||||||
| `githubRepo` | `""` | Repository to clone into `/workspace` on startup |
|
| `githubRepo` | `""` | Repository to clone into `/workspace` on startup |
|
||||||
| `ide.type` | `vscode` | IDE to launch — `vscode`, `antigravity`, or `none` (see below) |
|
| `ide.type` | `vscode` | IDE to launch — `vscode`, `antigravity`, or `none` (see below) |
|
||||||
| `ssh.enabled` | `false` | Also start an OpenSSH server on port 22 (additive, any IDE) |
|
| `ssh.enabled` | `false` | Also start an OpenSSH server on port 22 (additive, any IDE) |
|
||||||
|
| `fileManager.enabled` | `false` | Enable the built-in web file manager for upload/download |
|
||||||
| `image.repository` | `ghcr.io/cpfarhood/devcontainer` | Container image |
|
| `image.repository` | `ghcr.io/cpfarhood/devcontainer` | Container image |
|
||||||
| `image.tag` | `latest` | Image tag |
|
| `image.tag` | `latest` | Image tag |
|
||||||
|
|
||||||
@@ -161,6 +171,24 @@ kubectl port-forward deployment/devcontainer-mydev 2222:22
|
|||||||
ssh -p 2222 user@localhost
|
ssh -p 2222 user@localhost
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Web file manager
|
||||||
|
|
||||||
|
The base image includes a built-in web file manager for uploading and downloading files through the VNC web interface (port 5800). No additional sidecar is needed.
|
||||||
|
|
||||||
|
| Value | Default | Description |
|
||||||
|
|-------|---------|-------------|
|
||||||
|
| `fileManager.enabled` | `false` | Enable the web file manager |
|
||||||
|
| `fileManager.allowedPaths` | `/workspace,/config` | Paths accessible by the file manager (`AUTO`, `ALL`, or comma-separated) |
|
||||||
|
| `fileManager.deniedPaths` | `""` | Paths to deny (takes precedence over allowed) |
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Enable the file manager
|
||||||
|
helm install mydev ./chart \
|
||||||
|
--set name=mydev \
|
||||||
|
--set githubRepo=https://github.com/youruser/yourrepo \
|
||||||
|
--set fileManager.enabled=true
|
||||||
|
```
|
||||||
|
|
||||||
### Happy Coder
|
### Happy Coder
|
||||||
|
|
||||||
| Value | Default | Description |
|
| Value | Default | Description |
|
||||||
|
|||||||
+1
-1
@@ -2,5 +2,5 @@ apiVersion: v2
|
|||||||
name: devcontainer
|
name: devcontainer
|
||||||
description: Dev Container with AI coding agents and MCP sidecars
|
description: Dev Container with AI coding agents and MCP sidecars
|
||||||
type: application
|
type: application
|
||||||
version: 0.4.5
|
version: 1.0.2
|
||||||
appVersion: "latest"
|
appVersion: "latest"
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
Dev Container "{{ .Values.name }}" has been deployed.
|
||||||
|
|
||||||
|
{{- if ne (.Values.ide.type | default "vscode") "none" }}
|
||||||
|
|
||||||
|
Access the IDE:
|
||||||
|
kubectl port-forward deployment/{{ include "devcontainer.fullname" . }} 5800:5800 -n {{ .Release.Namespace }}
|
||||||
|
Then open: http://localhost:5800
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- if .Values.ssh.enabled }}
|
||||||
|
|
||||||
|
SSH access:
|
||||||
|
kubectl port-forward deployment/{{ include "devcontainer.fullname" . }} 2222:22 -n {{ .Release.Namespace }}
|
||||||
|
Then: ssh -p 2222 user@localhost
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
Useful commands:
|
||||||
|
Logs: kubectl logs -f deployment/{{ include "devcontainer.fullname" . }} -n {{ .Release.Namespace }}
|
||||||
|
Shell: kubectl exec -it deployment/{{ include "devcontainer.fullname" . }} -n {{ .Release.Namespace }} -- bash
|
||||||
|
|
||||||
|
{{- if not (lookup "v1" "Secret" .Release.Namespace (include "devcontainer.envSecretName" .)) }}
|
||||||
|
|
||||||
|
Optional: Create a secret for GITHUB_TOKEN, VNC_PASSWORD, etc:
|
||||||
|
kubectl create secret generic {{ include "devcontainer.envSecretName" . }} \
|
||||||
|
--from-literal=GITHUB_TOKEN=ghp_xxx \
|
||||||
|
--from-literal=VNC_PASSWORD=changeme \
|
||||||
|
-n {{ .Release.Namespace }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
Note: The PVC "{{ include "devcontainer.pvcName" . }}" is protected from deletion on helm uninstall.
|
||||||
|
To remove it manually: kubectl delete pvc {{ include "devcontainer.pvcName" . }} -n {{ .Release.Namespace }}
|
||||||
@@ -2,6 +2,9 @@
|
|||||||
Resource name prefix: devcontainer-{name}
|
Resource name prefix: devcontainer-{name}
|
||||||
*/}}
|
*/}}
|
||||||
{{- define "devcontainer.fullname" -}}
|
{{- define "devcontainer.fullname" -}}
|
||||||
|
{{- if not .Values.name }}
|
||||||
|
{{- fail "values.name is required and must not be empty" }}
|
||||||
|
{{- end }}
|
||||||
{{- printf "devcontainer-%s" .Values.name }}
|
{{- printf "devcontainer-%s" .Values.name }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
@@ -25,6 +28,18 @@ Common labels
|
|||||||
{{- define "devcontainer.labels" -}}
|
{{- define "devcontainer.labels" -}}
|
||||||
app: devcontainer
|
app: devcontainer
|
||||||
instance: {{ .Values.name }}
|
instance: {{ .Values.name }}
|
||||||
|
app.kubernetes.io/name: devcontainer
|
||||||
|
app.kubernetes.io/instance: {{ .Values.name }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Selector labels — keep narrow since changing these requires recreating the Deployment
|
||||||
|
*/}}
|
||||||
|
{{- define "devcontainer.selectorLabels" -}}
|
||||||
|
app: devcontainer
|
||||||
|
instance: {{ .Values.name }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
{{/*
|
{{/*
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ spec:
|
|||||||
replicas: 1
|
replicas: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
{{- include "devcontainer.labels" . | nindent 6 }}
|
{{- include "devcontainer.selectorLabels" . | nindent 6 }}
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
@@ -23,7 +23,7 @@ spec:
|
|||||||
{{- if and .Values.ide.type (eq .Values.ide.type "antigravity") }}
|
{{- if and .Values.ide.type (eq .Values.ide.type "antigravity") }}
|
||||||
initContainers:
|
initContainers:
|
||||||
- name: setup-userdata
|
- name: setup-userdata
|
||||||
image: busybox:latest
|
image: busybox:1.37
|
||||||
command: ['sh', '-c']
|
command: ['sh', '-c']
|
||||||
args:
|
args:
|
||||||
- |
|
- |
|
||||||
@@ -69,6 +69,16 @@ spec:
|
|||||||
value: {{ .Values.display.height | quote }}
|
value: {{ .Values.display.height | quote }}
|
||||||
- name: SECURE_CONNECTION
|
- name: SECURE_CONNECTION
|
||||||
value: {{ .Values.display.secureConnection | quote }}
|
value: {{ .Values.display.secureConnection | quote }}
|
||||||
|
{{- if .Values.fileManager.enabled }}
|
||||||
|
- name: WEB_FILE_MANAGER
|
||||||
|
value: "1"
|
||||||
|
- name: WEB_FILE_MANAGER_ALLOWED_PATHS
|
||||||
|
value: {{ .Values.fileManager.allowedPaths | quote }}
|
||||||
|
{{- if .Values.fileManager.deniedPaths }}
|
||||||
|
- name: WEB_FILE_MANAGER_DENIED_PATHS
|
||||||
|
value: {{ .Values.fileManager.deniedPaths | quote }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
- name: HAPPY_HOME_DIR
|
- name: HAPPY_HOME_DIR
|
||||||
value: {{ .Values.happy.homeDir | quote }}
|
value: {{ .Values.happy.homeDir | quote }}
|
||||||
- name: HAPPY_EXPERIMENTAL
|
- name: HAPPY_EXPERIMENTAL
|
||||||
@@ -166,52 +176,10 @@ spec:
|
|||||||
resources:
|
resources:
|
||||||
{{- toYaml .Values.mcp.sidecars.flux.resources | nindent 12 }}
|
{{- toYaml .Values.mcp.sidecars.flux.resources | nindent 12 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- if .Values.mcp.sidecars.fetch.enabled }}
|
|
||||||
- name: fetch-mcp
|
|
||||||
image: "{{ .Values.mcp.sidecars.fetch.image.repository }}:{{ .Values.mcp.sidecars.fetch.image.tag }}"
|
|
||||||
imagePullPolicy: Always
|
|
||||||
command: ["fastmcp", "run", "--transport", "sse", "--host", "0.0.0.0", "--port", "{{ .Values.mcp.sidecars.fetch.port }}"]
|
|
||||||
ports:
|
|
||||||
- name: fetch
|
|
||||||
containerPort: {{ .Values.mcp.sidecars.fetch.port }}
|
|
||||||
livenessProbe:
|
|
||||||
tcpSocket:
|
|
||||||
port: {{ .Values.mcp.sidecars.fetch.port }}
|
|
||||||
initialDelaySeconds: 10
|
|
||||||
periodSeconds: 10
|
|
||||||
readinessProbe:
|
|
||||||
tcpSocket:
|
|
||||||
port: {{ .Values.mcp.sidecars.fetch.port }}
|
|
||||||
initialDelaySeconds: 5
|
|
||||||
periodSeconds: 5
|
|
||||||
resources:
|
|
||||||
{{- toYaml .Values.mcp.sidecars.fetch.resources | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if .Values.mcp.sidecars.sequentialthinking.enabled }}
|
|
||||||
- name: sequentialthinking-mcp
|
|
||||||
image: "{{ .Values.mcp.sidecars.sequentialthinking.image.repository }}:{{ .Values.mcp.sidecars.sequentialthinking.image.tag }}"
|
|
||||||
imagePullPolicy: Always
|
|
||||||
command: ["fastmcp", "run", "--transport", "sse", "--host", "0.0.0.0", "--port", "{{ .Values.mcp.sidecars.sequentialthinking.port }}"]
|
|
||||||
ports:
|
|
||||||
- name: sequentialthinking
|
|
||||||
containerPort: {{ .Values.mcp.sidecars.sequentialthinking.port }}
|
|
||||||
livenessProbe:
|
|
||||||
tcpSocket:
|
|
||||||
port: {{ .Values.mcp.sidecars.sequentialthinking.port }}
|
|
||||||
initialDelaySeconds: 10
|
|
||||||
periodSeconds: 10
|
|
||||||
readinessProbe:
|
|
||||||
tcpSocket:
|
|
||||||
port: {{ .Values.mcp.sidecars.sequentialthinking.port }}
|
|
||||||
initialDelaySeconds: 5
|
|
||||||
periodSeconds: 5
|
|
||||||
resources:
|
|
||||||
{{- toYaml .Values.mcp.sidecars.sequentialthinking.resources | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if .Values.mcp.sidecars.homeassistant.enabled }}
|
{{- if .Values.mcp.sidecars.homeassistant.enabled }}
|
||||||
- name: homeassistant-mcp
|
- name: homeassistant-mcp
|
||||||
image: "{{ .Values.mcp.sidecars.homeassistant.image.repository }}:{{ .Values.mcp.sidecars.homeassistant.image.tag }}"
|
image: "{{ .Values.mcp.sidecars.homeassistant.image.repository }}:{{ .Values.mcp.sidecars.homeassistant.image.tag }}"
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: IfNotPresent
|
||||||
command: ["fastmcp", "run", "--transport", "sse", "--host", "0.0.0.0", "--port", "{{ .Values.mcp.sidecars.homeassistant.port }}"]
|
command: ["fastmcp", "run", "--transport", "sse", "--host", "0.0.0.0", "--port", "{{ .Values.mcp.sidecars.homeassistant.port }}"]
|
||||||
ports:
|
ports:
|
||||||
- name: homeassistant
|
- name: homeassistant
|
||||||
@@ -245,7 +213,7 @@ spec:
|
|||||||
{{- if .Values.mcp.sidecars.pgtuner.enabled }}
|
{{- if .Values.mcp.sidecars.pgtuner.enabled }}
|
||||||
- name: pgtuner-mcp
|
- name: pgtuner-mcp
|
||||||
image: "{{ .Values.mcp.sidecars.pgtuner.image.repository }}:{{ .Values.mcp.sidecars.pgtuner.image.tag }}"
|
image: "{{ .Values.mcp.sidecars.pgtuner.image.repository }}:{{ .Values.mcp.sidecars.pgtuner.image.tag }}"
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always # pgtuner uses `latest` tag (no versioned releases available)
|
||||||
command: ["python", "-m", "pgtuner_mcp", "--mode", "sse", "--host", "0.0.0.0", "--port", "{{ .Values.mcp.sidecars.pgtuner.port }}"]
|
command: ["python", "-m", "pgtuner_mcp", "--mode", "sse", "--host", "0.0.0.0", "--port", "{{ .Values.mcp.sidecars.pgtuner.port }}"]
|
||||||
ports:
|
ports:
|
||||||
- name: pgtuner
|
- name: pgtuner
|
||||||
@@ -279,7 +247,7 @@ spec:
|
|||||||
{{- if .Values.mcp.sidecars.playwright.enabled }}
|
{{- if .Values.mcp.sidecars.playwright.enabled }}
|
||||||
- name: playwright-mcp
|
- name: playwright-mcp
|
||||||
image: "{{ .Values.mcp.sidecars.playwright.image.repository }}:{{ .Values.mcp.sidecars.playwright.image.tag }}"
|
image: "{{ .Values.mcp.sidecars.playwright.image.repository }}:{{ .Values.mcp.sidecars.playwright.image.tag }}"
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: IfNotPresent
|
||||||
command: ["node"]
|
command: ["node"]
|
||||||
args:
|
args:
|
||||||
- cli.js
|
- cli.js
|
||||||
|
|||||||
@@ -2,12 +2,16 @@ apiVersion: v1
|
|||||||
kind: PersistentVolumeClaim
|
kind: PersistentVolumeClaim
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ include "devcontainer.pvcName" . }}
|
name: {{ include "devcontainer.pvcName" . }}
|
||||||
|
annotations:
|
||||||
|
helm.sh/resource-policy: keep
|
||||||
labels:
|
labels:
|
||||||
{{- include "devcontainer.labels" . | nindent 4 }}
|
{{- include "devcontainer.labels" . | nindent 4 }}
|
||||||
spec:
|
spec:
|
||||||
accessModes:
|
accessModes:
|
||||||
- ReadWriteMany
|
- ReadWriteMany
|
||||||
|
{{- if .Values.storage.className }}
|
||||||
storageClassName: {{ .Values.storage.className }}
|
storageClassName: {{ .Values.storage.className }}
|
||||||
|
{{- end }}
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
storage: {{ .Values.storage.size }}
|
storage: {{ .Values.storage.size }}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
"title": "Dev Container Helm Chart Values Schema",
|
"title": "Dev Container Helm Chart Values Schema",
|
||||||
"description": "Schema for validating values.yaml in the Dev Container Helm chart",
|
"description": "Schema for validating values.yaml in the Dev Container Helm chart",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"additionalProperties": true,
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -34,7 +35,7 @@
|
|||||||
"githubRepo": {
|
"githubRepo": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "GitHub repository URL to clone",
|
"description": "GitHub repository URL to clone",
|
||||||
"pattern": "^https://github\\.com/.+/.+$"
|
"pattern": "^https?://.+/.+/.+$"
|
||||||
},
|
},
|
||||||
"ide": {
|
"ide": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@@ -107,7 +108,7 @@
|
|||||||
"description": "Storage class name (must support ReadWriteMany)"
|
"description": "Storage class name (must support ReadWriteMany)"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["size", "className"]
|
"required": ["size"]
|
||||||
},
|
},
|
||||||
"resources": {
|
"resources": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@@ -142,12 +143,10 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"serverUrl": {
|
"serverUrl": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "uri",
|
|
||||||
"description": "Happy Coder server URL"
|
"description": "Happy Coder server URL"
|
||||||
},
|
},
|
||||||
"webappUrl": {
|
"webappUrl": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "uri",
|
|
||||||
"description": "Happy Coder webapp URL"
|
"description": "Happy Coder webapp URL"
|
||||||
},
|
},
|
||||||
"homeDir": {
|
"homeDir": {
|
||||||
@@ -160,7 +159,7 @@
|
|||||||
"description": "Enable experimental Happy features"
|
"description": "Enable experimental Happy features"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["serverUrl", "webappUrl", "homeDir", "experimental"]
|
"required": ["homeDir", "experimental"]
|
||||||
},
|
},
|
||||||
"mcp": {
|
"mcp": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@@ -192,6 +191,11 @@
|
|||||||
"envSecretName": {
|
"envSecretName": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Custom environment secret name"
|
"description": "Custom environment secret name"
|
||||||
|
},
|
||||||
|
"resourceProfile": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["auto", "small", "medium", "large", "xlarge"],
|
||||||
|
"description": "Resource profile preset"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["name"],
|
"required": ["name"],
|
||||||
|
|||||||
+15
-33
@@ -27,6 +27,16 @@ ide:
|
|||||||
ssh:
|
ssh:
|
||||||
enabled: false
|
enabled: false
|
||||||
|
|
||||||
|
# Web file manager — built-in upload/download via the VNC web interface (port 5800)
|
||||||
|
# Uses the base image's WEB_FILE_MANAGER feature (no extra sidecar needed)
|
||||||
|
fileManager:
|
||||||
|
enabled: false
|
||||||
|
# Paths the file manager can access (default: AUTO = mapped volumes)
|
||||||
|
# Options: AUTO | ALL | comma-separated list of paths
|
||||||
|
allowedPaths: "/workspace,/config"
|
||||||
|
# Paths to deny (takes precedence over allowedPaths)
|
||||||
|
deniedPaths: ""
|
||||||
|
|
||||||
# VNC display settings
|
# VNC display settings
|
||||||
display:
|
display:
|
||||||
width: "1920"
|
width: "1920"
|
||||||
@@ -45,7 +55,7 @@ user:
|
|||||||
# Storage configuration
|
# Storage configuration
|
||||||
storage:
|
storage:
|
||||||
size: 32Gi
|
size: 32Gi
|
||||||
className: ceph-filesystem
|
className: "" # Empty string uses the cluster's default StorageClass (must support ReadWriteMany)
|
||||||
|
|
||||||
# Resource allocation
|
# Resource allocation
|
||||||
resources:
|
resources:
|
||||||
@@ -70,8 +80,8 @@ clusterAccess: none
|
|||||||
|
|
||||||
# Happy Coder AI assistant configuration
|
# Happy Coder AI assistant configuration
|
||||||
happy:
|
happy:
|
||||||
serverUrl: "https://happy.farh.net"
|
serverUrl: ""
|
||||||
webappUrl: "https://happy-coder.farh.net"
|
webappUrl: ""
|
||||||
homeDir: "/config/userdata/.happy"
|
homeDir: "/config/userdata/.happy"
|
||||||
experimental: "true"
|
experimental: "true"
|
||||||
|
|
||||||
@@ -108,42 +118,14 @@ mcp:
|
|||||||
memory: "256Mi"
|
memory: "256Mi"
|
||||||
cpu: "500m"
|
cpu: "500m"
|
||||||
|
|
||||||
# Web content fetching capabilities
|
|
||||||
fetch:
|
|
||||||
enabled: true
|
|
||||||
image:
|
|
||||||
repository: mcp/fetch
|
|
||||||
tag: latest
|
|
||||||
port: 8082
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
memory: "64Mi"
|
|
||||||
cpu: "50m"
|
|
||||||
limits:
|
|
||||||
memory: "256Mi"
|
|
||||||
cpu: "500m"
|
|
||||||
|
|
||||||
# Sequential thinking and problem-solving
|
|
||||||
sequentialthinking:
|
|
||||||
enabled: true
|
|
||||||
image:
|
|
||||||
repository: mcp/sequentialthinking
|
|
||||||
tag: latest
|
|
||||||
port: 8083
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
memory: "64Mi"
|
|
||||||
cpu: "50m"
|
|
||||||
limits:
|
|
||||||
memory: "256Mi"
|
|
||||||
cpu: "500m"
|
|
||||||
|
|
||||||
# Home Assistant smart home control
|
# Home Assistant smart home control
|
||||||
homeassistant:
|
homeassistant:
|
||||||
enabled: false # Requires HOMEASSISTANT_URL and HOMEASSISTANT_TOKEN
|
enabled: false # Requires HOMEASSISTANT_URL and HOMEASSISTANT_TOKEN
|
||||||
image:
|
image:
|
||||||
repository: ghcr.io/homeassistant-ai/ha-mcp
|
repository: ghcr.io/homeassistant-ai/ha-mcp
|
||||||
tag: stable
|
tag: v6.7.1
|
||||||
port: 8087
|
port: 8087
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
@@ -173,7 +155,7 @@ mcp:
|
|||||||
enabled: true
|
enabled: true
|
||||||
image:
|
image:
|
||||||
repository: mcr.microsoft.com/playwright/mcp
|
repository: mcr.microsoft.com/playwright/mcp
|
||||||
tag: latest
|
tag: v0.0.68
|
||||||
port: 8086
|
port: 8086
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
|
|||||||
@@ -2,5 +2,9 @@
|
|||||||
# Fix the app user (UID 1000) created by baseimage-gui at runtime.
|
# Fix the app user (UID 1000) created by baseimage-gui at runtime.
|
||||||
# baseimage-gui sets shell=/sbin/nologin and home=/dev/null, which
|
# baseimage-gui sets shell=/sbin/nologin and home=/dev/null, which
|
||||||
# prevents VSCode from opening terminals.
|
# prevents VSCode from opening terminals.
|
||||||
usermod -s /bin/bash app
|
if id app >/dev/null 2>&1; then
|
||||||
usermod -d /config/userdata app
|
usermod -s /bin/bash app
|
||||||
|
usermod -d /config/userdata app
|
||||||
|
else
|
||||||
|
echo "WARNING: 'app' user not found, skipping usermod" >&2
|
||||||
|
fi
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ if [ -n "$GITHUB_TOKEN" ]; then
|
|||||||
|
|
||||||
# Create or update the credentials file
|
# Create or update the credentials file
|
||||||
CREDENTIALS_FILE="/config/userdata/.git-credentials"
|
CREDENTIALS_FILE="/config/userdata/.git-credentials"
|
||||||
|
mkdir -p "$(dirname "$CREDENTIALS_FILE")"
|
||||||
|
|
||||||
# Support multiple git hosting providers
|
# Support multiple git hosting providers
|
||||||
# GitHub supports both oauth2 and token as username
|
# GitHub supports both oauth2 and token as username
|
||||||
@@ -51,6 +52,7 @@ else
|
|||||||
|
|
||||||
# Create an empty credentials file with proper permissions
|
# Create an empty credentials file with proper permissions
|
||||||
CREDENTIALS_FILE="/config/userdata/.git-credentials"
|
CREDENTIALS_FILE="/config/userdata/.git-credentials"
|
||||||
|
mkdir -p "$(dirname "$CREDENTIALS_FILE")"
|
||||||
touch "$CREDENTIALS_FILE"
|
touch "$CREDENTIALS_FILE"
|
||||||
chmod 600 "$CREDENTIALS_FILE"
|
chmod 600 "$CREDENTIALS_FILE"
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ case "$IDE" in
|
|||||||
exec sleep infinity
|
exec sleep infinity
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
|
if [ "$IDE" != "vscode" ]; then
|
||||||
|
echo "WARNING: Unknown IDE value '$IDE', defaulting to VSCode"
|
||||||
|
fi
|
||||||
echo "Opening VSCode in: $WORKSPACE_DIR"
|
echo "Opening VSCode in: $WORKSPACE_DIR"
|
||||||
exec code --new-window --wait "$WORKSPACE_DIR"
|
exec code --new-window --wait "$WORKSPACE_DIR"
|
||||||
;;
|
;;
|
||||||
|
|||||||
Reference in New Issue
Block a user