From a4dbb3ca8982e7e0e20abd4ae1f64f13cfdd3b2c Mon Sep 17 00:00:00 2001 From: Lee Chapman Date: Fri, 31 Jul 2026 11:38:19 -0700 Subject: [PATCH 1/3] feat(dkai): preinstall dev language toolchains Install Node/pnpm, Python/uv, Go, Rust, Java, Ruby, PHP, .NET, and C/C++ via distro packages (apt on dkai-dev, pacman on Arch templates) so workspaces are ready for polyglot work without dotfiles. Document toolchains in build-parameters.md and extend startup summary. Co-authored-by: Cursor --- docs/build-parameters.md | 30 +++++++++++++--- templates/dkai-agent/README.md | 1 + templates/dkai-agent/main.tf | 31 +++++++++++++++- templates/dkai-arch/README.md | 4 ++- templates/dkai-arch/main.tf | 31 +++++++++++++++- templates/dkai-dev/README.md | 2 ++ templates/dkai-dev/main.tf | 64 +++++++++++++++++++++++++++++++++ templates/dkai-hermes/README.md | 1 + templates/dkai-hermes/main.tf | 31 +++++++++++++++- 9 files changed, 187 insertions(+), 8 deletions(-) diff --git a/docs/build-parameters.md b/docs/build-parameters.md index 83bff17..9534b79 100644 --- a/docs/build-parameters.md +++ b/docs/build-parameters.md @@ -22,8 +22,30 @@ Topics covered include: | Template | Parameters | |-----------|----------------------------------------------------------------------------| -| DKAI DevPod (`dkai-dev`) | CPU (2/4 cores), Memory (4/8 GB), Home disk size (50–100 GB, monotonic ↑). Cursor IDE only (no subdomain). | -| DKAI Arch (`dkai-arch`) | Same parameters as **DKAI DevPod** (`dkai-dev`). Arch Linux base image; Cursor IDE only (no subdomain). | -| DKAI Agent (`dkai-agent`) | Same CPU/memory/home disk as DKAI Arch, plus **tool_config_disk_size** (default 5 GiB, 1–50 GiB) for the shared **ReadWriteMany** tool-config PVC at `/mnt/coder-tool-config` (one per Coder owner: `coder--tool-config`; plan-time cluster check creates if missing else attaches). **cursor_worker_idle_timeout** (30–86400 s, default 600) for `agent worker start --idle-release-timeout`; optional **cursor_api_key** (masked; `CURSOR_API_KEY` via `coder_env`). | -| DKAI Hermes (`dkai-hermes`) | Same as **DKAI Agent** (tool PVC, gh/glab/kubectl/rancher), but **Hermes Agent controller only** — **[Enodios](https://github.com/DataKnifeAI/enodios) vLLM runs remotely** (not in workspace). Hermes config points at **vllm_base_url** (default `https://vllm.dataknife.net/v1`), **vllm_model** (`hermes3:8b`), optional **vllm_api_key**; optional **hermes_worker_git_url** for project code. | +| DKAI DevPod (`dkai-dev`) | CPU (2/4 cores), Memory (4/8 GB), Home disk size (50–100 GB, monotonic ↑). Cursor IDE only (no subdomain). Startup installs Node.js, **Rust** (`rustc`/`cargo` via apt), `gh`, `glab`. | +| DKAI Arch (`dkai-arch`) | Same parameters as **DKAI DevPod** (`dkai-dev`). Arch Linux base image; Cursor IDE only (no subdomain). Startup installs **Rust** (`rust`/`gcc` via pacman) with Node.js, `gh`, `glab`. | +| DKAI Agent (`dkai-agent`) | Same CPU/memory/home disk as DKAI Arch, plus **tool_config_disk_size** (default 5 GiB, 1–50 GiB) for the shared **ReadWriteMany** tool-config PVC at `/mnt/coder-tool-config` (one per Coder owner: `coder--tool-config`; plan-time cluster check creates if missing else attaches). **cursor_worker_idle_timeout** (30–86400 s, default 600) for `agent worker start --idle-release-timeout`; optional **cursor_api_key** (masked; `CURSOR_API_KEY` via `coder_env`). Includes **Rust** (`rustc`/`cargo` via pacman). | +| DKAI Hermes (`dkai-hermes`) | Same as **DKAI Agent** (tool PVC, gh/glab/kubectl/rancher, **Rust**), but **Hermes Agent controller only** — **[Enodios](https://github.com/DataKnifeAI/enodios) vLLM runs remotely** (not in workspace). Hermes config points at **vllm_base_url** (default `https://vllm.dataknife.net/v1`), **vllm_model** (`hermes3:8b`), optional **vllm_api_key**; optional **hermes_worker_git_url** for project code. | | kubernetes| See [templates/kubernetes/README.md](../templates/kubernetes/README.md) | + +## Preinstalled dev toolchains + +DKAI templates install popular language toolchains in the **`startup_script`** (not user-selectable build parameters). Versions follow the distro package manager (Arch **pacman** or Ubuntu **apt**) unless noted. + +| Toolchain | DKAI DevPod (`dkai-dev`) | DKAI Arch / Agent / Hermes | +|-----------|--------------------------|----------------------------| +| **Node.js** | NodeSource 20.x if base image < 20 | `nodejs` (pacman) | +| **pnpm** | `npm install -g pnpm` | `pnpm` (pacman) | +| **Python** | `python3`, `pip`, `venv` (apt) | `python` (pacman) | +| **uv** | [Astral install script](https://docs.astral.sh/uv/) → `/usr/local/bin` | `uv` (pacman) | +| **Go** | `golang-go` (apt) | `go` (pacman) | +| **Rust** | `rustc`, `cargo`, `build-essential` (apt) | `rust`, `gcc` (pacman) | +| **Java** | OpenJDK (`default-jdk`), Maven, Gradle (apt) | `jdk-openjdk`, `maven`, `gradle` (pacman) | +| **Ruby** | `ruby-full` (apt) | `ruby` (pacman) | +| **PHP** | `php-cli`, `php` (apt) | `php` (pacman) | +| **.NET** | `dotnet-sdk-8.0` (Microsoft apt feed) | `dotnet-sdk` (pacman) | +| **C/C++** | `build-essential` (`gcc`, etc.) | `gcc` (pacman) | + +The **`kubernetes`** template installs **code-server** only; add languages via a custom container image or dotfiles (see [templates/kubernetes/README.md](../templates/kubernetes/README.md)). + +Startup logs print a **=== Startup summary ===** block with detected versions for each toolchain. diff --git a/templates/dkai-agent/README.md b/templates/dkai-agent/README.md index e5fa558..73daca1 100644 --- a/templates/dkai-agent/README.md +++ b/templates/dkai-agent/README.md @@ -14,6 +14,7 @@ Fork of **DKAI Arch** (`dkai-arch`) with the same Arch Linux base, AppArmor sand ## What you get - **`agent` CLI** installed under `/home/coder/.local/bin` (and on `PATH`), same as DKAI Arch. +- **Dev toolchains** — same **pacman** language stack as **DKAI Arch** (Node.js, pnpm, Python, uv, Go, Rust, Java/Maven/Gradle, Ruby, PHP, .NET, gcc). See [docs/build-parameters.md](../../docs/build-parameters.md#preinstalled-dev-toolchains). - **`kubectl`** from Arch **`extra/kubectl`** via the initial **`pacman`** install (`/usr/bin/kubectl`). **`kubectx`** and **`kubens`** from Arch **`extra/kubectx`** (same install; context / namespace helpers). **`rancher`** CLI is downloaded from GitHub releases to `/usr/local/bin` when missing. - **`terraform`** installed to **`/usr/local/bin/terraform`** from [HashiCorp releases](https://releases.hashicorp.com/terraform/) (pinned version in startup script; upgraded when the pin changes). Uses **`unzip`** from **`pacman`** for the official Linux amd64 zip. - **Tool config volume** — one **ReadWriteMany** PVC per **Coder user** at **`/mnt/coder-tool-config`** named **`coder--tool-config`**. At **plan** time the template checks the cluster (in-cluster API or `kubectl`); if the PVC is missing Terraform **creates** it; if it already exists (another workspace or a prior apply), Terraform **imports** it into this workspace’s state so updates never **destroy** the claim. The PVC resource uses **`lifecycle { prevent_destroy = true }`** so Terraform will not delete it on workspace teardown (shared across your dkai-agent workspaces; remove from state manually if you must drop the claim). **`tool_config_disk_size`** sizes that shared volume. On each boot the startup script **`mkdir`**s layout there, **merges** legacy **`/home/coder`** paths into the PVC (including **`glab-cli`**), then **`ln -sfn`** the same paths for **both** **`/root`** and **`/home/coder`**: **`~/.kube`**, **`~/.config/gh`**, **`~/.config/glab-cli`**, **`~/.config/coderv2`**, **`~/.rancher`**. **Coder CLI** uses **`~/.config/coderv2`** (same as **`coder --global-config`** / default **`$CODER_CONFIG_DIR`**). The PVC dirs are **`chown`’d `coder:coder`** each boot so **`gh`**, **`glab`**, **`kubectl`**, **`coder`**, and **`rancher`** see the same files whether you use **`HOME=/home/coder`** or **`HOME=/root`** (root still reads/writes everything). diff --git a/templates/dkai-agent/main.tf b/templates/dkai-agent/main.tf index a38727d..7f8ac0e 100644 --- a/templates/dkai-agent/main.tf +++ b/templates/dkai-agent/main.tf @@ -195,7 +195,7 @@ resource "coder_agent" "main" { "Exec = /usr/bin/true" \ >/etc/pacman.d/hooks/detect-old-perl-modules.hook pacman -Sy --needed --noconfirm --disable-sandbox \ - apparmor bash binutils curl git kubectl kubectx nano nodejs unzip zstd + apparmor bash binutils curl dotnet-sdk gcc git go gradle jdk-openjdk kubectl kubectx maven nano nodejs php pnpm python ruby rust unzip uv zstd # Git 2.35+: "dubious ownership" when .git owner != invoking user (NFS root_squash → nobody, or root in a coder-owned tree). git config --system --add safe.directory '*' 2>/dev/null || true # Coder often sets GIT_ASKPASS for git; neutralize so gh/glab credential helpers can supply HTTPS tokens. @@ -510,6 +510,35 @@ WORKERHELPER echo "" echo "Node.js" node -v 2>/dev/null || echo " (not found)" + if command -v pnpm >/dev/null 2>&1; then pnpm -v 2>/dev/null | sed "s/^/ pnpm: v/"; else echo " pnpm: (not found)"; fi + echo "" + echo "Python" + python3 --version 2>/dev/null || echo " (not found)" + if command -v uv >/dev/null 2>&1; then uv --version 2>/dev/null | head -n1; else echo " uv: (not found)"; fi + echo "" + echo "Go" + go version 2>/dev/null || echo " (not found)" + echo "" + echo "Rust" + rustc --version 2>/dev/null || echo " rustc: (not found)" + cargo --version 2>/dev/null || echo " cargo: (not found)" + echo "" + echo "Java" + javac -version 2>/dev/null || echo " javac: (not found)" + if command -v mvn >/dev/null 2>&1; then mvn -version 2>/dev/null | head -n1; else echo " maven: (not found)"; fi + if command -v gradle >/dev/null 2>&1; then gradle --version 2>/dev/null | head -n1; else echo " gradle: (not found)"; fi + echo "" + echo "Ruby" + ruby --version 2>/dev/null || echo " (not found)" + echo "" + echo "PHP" + php --version 2>/dev/null | head -n1 || echo " (not found)" + echo "" + echo ".NET" + dotnet --version 2>/dev/null || echo " (not found)" + echo "" + echo "C/C++" + gcc --version 2>/dev/null | head -n1 || echo " gcc: (not found)" echo "" echo "CLI tools" if command -v gh >/dev/null 2>&1; then gh version 2>/dev/null | head -n1; else echo " gh: not found"; fi diff --git a/templates/dkai-arch/README.md b/templates/dkai-arch/README.md index 2a3ee50..a4fd626 100644 --- a/templates/dkai-arch/README.md +++ b/templates/dkai-arch/README.md @@ -9,7 +9,9 @@ tags: [kubernetes, container, archlinux, cursor] # DKAI Arch -Same layout as **DKAI DevPod** (`dkai-dev`) (CPU/memory/disk parameters, Cursor module, persistent `/home/coder`), but the workload uses the official **[`archlinux`](https://hub.docker.com/_/archlinux)** image and **pacman** for tooling (`apparmor`, `binutils` for `ar`, `zstd`, `nodejs`, `github-cli` (`gh`), `glab`). Cursor’s **`cursor-sandbox-apparmor`** `.deb` is unpacked with `ar` + `zstd` (not `dpkg`, which mishandles this package on Arch), then **`apparmor_parser -r`** is run so the profile loads even without systemd’s `apparmor.service` (the `.deb` postinst normally skips that in containers). +Same layout as **DKAI DevPod** (`dkai-dev`) (CPU/memory/disk parameters, Cursor module, persistent `/home/coder`), but the workload uses the official **[`archlinux`](https://hub.docker.com/_/archlinux)** image and **pacman** for tooling (`apparmor`, `binutils`, `gcc`, `zstd`, `nodejs`, `pnpm`, `python`, `uv`, `go`, `rust`, `jdk-openjdk`, `maven`, `gradle`, `ruby`, `php`, `dotnet-sdk`, plus `gh`/`glab` from release binaries). Cursor’s **`cursor-sandbox-apparmor`** `.deb` is unpacked with `ar` + `zstd` (not `dpkg`, which mishandles this package on Arch), then **`apparmor_parser -r`** is run so the profile loads even without systemd’s `apparmor.service` (the `.deb` postinst normally skips that in containers). + +Full toolchain list: [docs/build-parameters.md](../../docs/build-parameters.md#preinstalled-dev-toolchains). The Cursor module opens **`/home/coder/git`** (i.e. `~/git` for the `coder` user). That directory is created at startup if missing. diff --git a/templates/dkai-arch/main.tf b/templates/dkai-arch/main.tf index cc0583a..5f6c968 100644 --- a/templates/dkai-arch/main.tf +++ b/templates/dkai-arch/main.tf @@ -108,7 +108,7 @@ resource "coder_agent" "main" { "Exec = /usr/bin/true" \ >/etc/pacman.d/hooks/detect-old-perl-modules.hook pacman -Sy --needed --noconfirm --disable-sandbox \ - apparmor bash binutils curl git nano nodejs zstd + apparmor bash binutils curl dotnet-sdk gcc git go gradle jdk-openjdk maven nano nodejs php pnpm python ruby rust uv zstd git config --system --add safe.directory '*' 2>/dev/null || true printf '%s\n' \ '# Coder may set GIT_ASKPASS; use gh/glab credential helpers for HTTPS (see templates/dkai-arch/README.md).' \ @@ -230,6 +230,35 @@ resource "coder_agent" "main" { echo "" echo "Node.js" node -v 2>/dev/null || echo " (not found)" + if command -v pnpm >/dev/null 2>&1; then pnpm -v 2>/dev/null | sed "s/^/ pnpm: v/"; else echo " pnpm: (not found)"; fi + echo "" + echo "Python" + python3 --version 2>/dev/null || echo " (not found)" + if command -v uv >/dev/null 2>&1; then uv --version 2>/dev/null | head -n1; else echo " uv: (not found)"; fi + echo "" + echo "Go" + go version 2>/dev/null || echo " (not found)" + echo "" + echo "Rust" + rustc --version 2>/dev/null || echo " rustc: (not found)" + cargo --version 2>/dev/null || echo " cargo: (not found)" + echo "" + echo "Java" + javac -version 2>/dev/null || echo " javac: (not found)" + if command -v mvn >/dev/null 2>&1; then mvn -version 2>/dev/null | head -n1; else echo " maven: (not found)"; fi + if command -v gradle >/dev/null 2>&1; then gradle --version 2>/dev/null | head -n1; else echo " gradle: (not found)"; fi + echo "" + echo "Ruby" + ruby --version 2>/dev/null || echo " (not found)" + echo "" + echo "PHP" + php --version 2>/dev/null | head -n1 || echo " (not found)" + echo "" + echo ".NET" + dotnet --version 2>/dev/null || echo " (not found)" + echo "" + echo "C/C++" + gcc --version 2>/dev/null | head -n1 || echo " gcc: (not found)" echo "" echo "CLI tools" if command -v gh >/dev/null 2>&1; then gh version 2>/dev/null | head -n1; else echo " gh: not found"; fi diff --git a/templates/dkai-dev/README.md b/templates/dkai-dev/README.md index 140d874..11198d2 100644 --- a/templates/dkai-dev/README.md +++ b/templates/dkai-dev/README.md @@ -11,6 +11,8 @@ tags: [kubernetes, container] Kubernetes [Coder workspaces](https://coder.com/docs/workspaces) with Cursor Desktop integration (`coder/cursor` module) and an Ubuntu-based dev container. +**Startup installs** (idempotent): Node.js 20+, **pnpm**, **Python** (pip/venv) + **uv**, **Go**, **Rust**, **Java** (OpenJDK, Maven, Gradle), **Ruby**, **PHP**, **.NET SDK 8**, **C/C++** (`build-essential`), plus **gh**, **glab**, Cursor sandbox AppArmor, and Coder/Cursor CLI. See [docs/build-parameters.md](../../docs/build-parameters.md#preinstalled-dev-toolchains). + ## Prerequisites diff --git a/templates/dkai-dev/main.tf b/templates/dkai-dev/main.tf index 42eec20..bf483e6 100644 --- a/templates/dkai-dev/main.tf +++ b/templates/dkai-dev/main.tf @@ -119,6 +119,41 @@ resource "coder_agent" "main" { curl -fsSL "https://raw.githubusercontent.com/upciti/wakemeops/main/assets/install_repository" | sudo bash sudo apt-get install -y glab fi + # Popular dev languages (apt; idempotent — skip packages already installed) + LANG_APT= + command -v go >/dev/null 2>&1 || LANG_APT="$LANG_APT golang-go" + if ! command -v python3 >/dev/null 2>&1; then + LANG_APT="$LANG_APT python3 python3-pip python3-venv" + elif ! command -v pip3 >/dev/null 2>&1; then + LANG_APT="$LANG_APT python3-pip python3-venv" + fi + command -v javac >/dev/null 2>&1 || LANG_APT="$LANG_APT default-jdk maven gradle" + command -v ruby >/dev/null 2>&1 || LANG_APT="$LANG_APT ruby-full" + command -v php >/dev/null 2>&1 || LANG_APT="$LANG_APT php-cli php" + command -v rustc >/dev/null 2>&1 || LANG_APT="$LANG_APT rustc cargo build-essential" + if [ -n "$LANG_APT" ]; then + sudo apt-get update + # shellcheck disable=SC2086 + sudo apt-get install -y $LANG_APT + fi + # .NET SDK (Microsoft apt feed) + if ! command -v dotnet >/dev/null 2>&1; then + if [ ! -f /etc/apt/sources.list.d/microsoft-prod.list ]; then + UBUNTU_VER=$(. /etc/os-release && echo "$VERSION_ID") + curl -fsSL "https://packages.microsoft.com/config/ubuntu/$UBUNTU_VER/packages-microsoft-prod.deb" -o /tmp/packages-microsoft-prod.deb + sudo dpkg -i /tmp/packages-microsoft-prod.deb + fi + sudo apt-get update + sudo apt-get install -y dotnet-sdk-8.0 + fi + # pnpm (Node package manager) + if command -v npm >/dev/null 2>&1 && ! command -v pnpm >/dev/null 2>&1; then + sudo npm install -g pnpm + fi + # uv (Python package manager) + if ! command -v uv >/dev/null 2>&1; then + curl -LsSf https://astral.sh/uv/install.sh | sudo env UV_INSTALL_DIR=/usr/local/bin sh + fi sudo git config --system --add safe.directory '*' 2>/dev/null || true printf '%s\n' \ '# Coder may set GIT_ASKPASS; use gh/glab credential helpers for HTTPS (see templates/dkai-dev/README.md).' \ @@ -180,6 +215,35 @@ resource "coder_agent" "main" { echo '' echo 'Node.js' node -v 2>/dev/null || echo ' (not found)' + if command -v pnpm >/dev/null 2>&1; then pnpm -v 2>/dev/null | sed 's/^/ pnpm: v/'; else echo ' pnpm: (not found)'; fi + echo '' + echo 'Python' + python3 --version 2>/dev/null || echo ' (not found)' + if command -v uv >/dev/null 2>&1; then uv --version 2>/dev/null | head -n1; else echo ' uv: (not found)'; fi + echo '' + echo 'Go' + go version 2>/dev/null || echo ' (not found)' + echo '' + echo 'Rust' + rustc --version 2>/dev/null || echo ' rustc: (not found)' + cargo --version 2>/dev/null || echo ' cargo: (not found)' + echo '' + echo 'Java' + javac -version 2>/dev/null || echo ' javac: (not found)' + if command -v mvn >/dev/null 2>&1; then mvn -version 2>/dev/null | head -n1; else echo ' maven: (not found)'; fi + if command -v gradle >/dev/null 2>&1; then gradle --version 2>/dev/null | head -n1; else echo ' gradle: (not found)'; fi + echo '' + echo 'Ruby' + ruby --version 2>/dev/null || echo ' (not found)' + echo '' + echo 'PHP' + php --version 2>/dev/null | head -n1 || echo ' (not found)' + echo '' + echo '.NET' + dotnet --version 2>/dev/null || echo ' (not found)' + echo '' + echo 'C/C++' + gcc --version 2>/dev/null | head -n1 || echo ' gcc: (not found)' echo '' echo 'CLI tools' if command -v gh >/dev/null 2>&1; then gh version 2>/dev/null | head -n1; else echo ' gh: not found'; fi diff --git a/templates/dkai-hermes/README.md b/templates/dkai-hermes/README.md index ed29513..bfaddeb 100644 --- a/templates/dkai-hermes/README.md +++ b/templates/dkai-hermes/README.md @@ -32,6 +32,7 @@ You ──► Hermes Agent (this Coder workspace — tools, files, terminal) ## What you get - **`hermes` CLI** — agent with tools; config on tool PVC at `~/.hermes`. +- **Dev toolchains** — same **pacman** language stack as **DKAI Arch** (Node.js, pnpm, Python, uv, Go, Rust, Java/Maven/Gradle, Ruby, PHP, .NET, gcc). See [docs/build-parameters.md](../../docs/build-parameters.md#preinstalled-dev-toolchains). - **Remote vLLM parameters** — Hermes `custom_providers` block (Enodios layout) rewritten each start: - **`vllm_base_url`** — default `https://vllm.dataknife.net/v1` - **`vllm_model`** — default `hermes3:8b` diff --git a/templates/dkai-hermes/main.tf b/templates/dkai-hermes/main.tf index 2f34d6c..cfabd06 100644 --- a/templates/dkai-hermes/main.tf +++ b/templates/dkai-hermes/main.tf @@ -202,7 +202,7 @@ resource "coder_agent" "main" { "Exec = /usr/bin/true" \ >/etc/pacman.d/hooks/detect-old-perl-modules.hook pacman -Sy --needed --noconfirm --disable-sandbox \ - apparmor bash binutils curl git kubectl kubectx nano nodejs python zstd + apparmor bash binutils curl dotnet-sdk gcc git go gradle jdk-openjdk kubectl kubectx maven nano nodejs php pnpm python ruby rust uv zstd # Git 2.35+: "dubious ownership" when .git owner != invoking user (NFS root_squash → nobody, or root in a coder-owned tree). git config --system --add safe.directory '*' 2>/dev/null || true # Coder often sets GIT_ASKPASS for git; neutralize so gh/glab credential helpers can supply HTTPS tokens. @@ -480,6 +480,35 @@ HERMESHELPER echo "" echo "Node.js" node -v 2>/dev/null || echo " (not found)" + if command -v pnpm >/dev/null 2>&1; then pnpm -v 2>/dev/null | sed "s/^/ pnpm: v/"; else echo " pnpm: (not found)"; fi + echo "" + echo "Python" + python3 --version 2>/dev/null || echo " (not found)" + if command -v uv >/dev/null 2>&1; then uv --version 2>/dev/null | head -n1; else echo " uv: (not found)"; fi + echo "" + echo "Go" + go version 2>/dev/null || echo " (not found)" + echo "" + echo "Rust" + rustc --version 2>/dev/null || echo " rustc: (not found)" + cargo --version 2>/dev/null || echo " cargo: (not found)" + echo "" + echo "Java" + javac -version 2>/dev/null || echo " javac: (not found)" + if command -v mvn >/dev/null 2>&1; then mvn -version 2>/dev/null | head -n1; else echo " maven: (not found)"; fi + if command -v gradle >/dev/null 2>&1; then gradle --version 2>/dev/null | head -n1; else echo " gradle: (not found)"; fi + echo "" + echo "Ruby" + ruby --version 2>/dev/null || echo " (not found)" + echo "" + echo "PHP" + php --version 2>/dev/null | head -n1 || echo " (not found)" + echo "" + echo ".NET" + dotnet --version 2>/dev/null || echo " (not found)" + echo "" + echo "C/C++" + gcc --version 2>/dev/null | head -n1 || echo " gcc: (not found)" echo "" echo "CLI tools" if command -v gh >/dev/null 2>&1; then gh version 2>/dev/null | head -n1; else echo " gh: not found"; fi From 5a912a3efb251e61b3d70e5320b0348f359d596f Mon Sep 17 00:00:00 2001 From: Lee Chapman Date: Fri, 31 Jul 2026 11:42:15 -0700 Subject: [PATCH 2/3] fix(dkai): address Bugbot review on toolchain startup Split Java apt package checks, capture javac stderr in startup summary, and guard php/gcc version probes when binaries are missing. Co-authored-by: Cursor --- templates/dkai-agent/main.tf | 6 +++--- templates/dkai-arch/main.tf | 6 +++--- templates/dkai-dev/main.tf | 10 ++++++---- templates/dkai-hermes/main.tf | 6 +++--- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/templates/dkai-agent/main.tf b/templates/dkai-agent/main.tf index 7f8ac0e..8b3f9ad 100644 --- a/templates/dkai-agent/main.tf +++ b/templates/dkai-agent/main.tf @@ -524,7 +524,7 @@ WORKERHELPER cargo --version 2>/dev/null || echo " cargo: (not found)" echo "" echo "Java" - javac -version 2>/dev/null || echo " javac: (not found)" + javac -version 2>&1 || echo " javac: (not found)" if command -v mvn >/dev/null 2>&1; then mvn -version 2>/dev/null | head -n1; else echo " maven: (not found)"; fi if command -v gradle >/dev/null 2>&1; then gradle --version 2>/dev/null | head -n1; else echo " gradle: (not found)"; fi echo "" @@ -532,13 +532,13 @@ WORKERHELPER ruby --version 2>/dev/null || echo " (not found)" echo "" echo "PHP" - php --version 2>/dev/null | head -n1 || echo " (not found)" + if command -v php >/dev/null 2>&1; then php --version 2>/dev/null | head -n1; else echo " php: (not found)"; fi echo "" echo ".NET" dotnet --version 2>/dev/null || echo " (not found)" echo "" echo "C/C++" - gcc --version 2>/dev/null | head -n1 || echo " gcc: (not found)" + if command -v gcc >/dev/null 2>&1; then gcc --version 2>/dev/null | head -n1; else echo " gcc: (not found)"; fi echo "" echo "CLI tools" if command -v gh >/dev/null 2>&1; then gh version 2>/dev/null | head -n1; else echo " gh: not found"; fi diff --git a/templates/dkai-arch/main.tf b/templates/dkai-arch/main.tf index 5f6c968..6673b8a 100644 --- a/templates/dkai-arch/main.tf +++ b/templates/dkai-arch/main.tf @@ -244,7 +244,7 @@ resource "coder_agent" "main" { cargo --version 2>/dev/null || echo " cargo: (not found)" echo "" echo "Java" - javac -version 2>/dev/null || echo " javac: (not found)" + javac -version 2>&1 || echo " javac: (not found)" if command -v mvn >/dev/null 2>&1; then mvn -version 2>/dev/null | head -n1; else echo " maven: (not found)"; fi if command -v gradle >/dev/null 2>&1; then gradle --version 2>/dev/null | head -n1; else echo " gradle: (not found)"; fi echo "" @@ -252,13 +252,13 @@ resource "coder_agent" "main" { ruby --version 2>/dev/null || echo " (not found)" echo "" echo "PHP" - php --version 2>/dev/null | head -n1 || echo " (not found)" + if command -v php >/dev/null 2>&1; then php --version 2>/dev/null | head -n1; else echo " php: (not found)"; fi echo "" echo ".NET" dotnet --version 2>/dev/null || echo " (not found)" echo "" echo "C/C++" - gcc --version 2>/dev/null | head -n1 || echo " gcc: (not found)" + if command -v gcc >/dev/null 2>&1; then gcc --version 2>/dev/null | head -n1; else echo " gcc: (not found)"; fi echo "" echo "CLI tools" if command -v gh >/dev/null 2>&1; then gh version 2>/dev/null | head -n1; else echo " gh: not found"; fi diff --git a/templates/dkai-dev/main.tf b/templates/dkai-dev/main.tf index bf483e6..fbc891c 100644 --- a/templates/dkai-dev/main.tf +++ b/templates/dkai-dev/main.tf @@ -127,7 +127,9 @@ resource "coder_agent" "main" { elif ! command -v pip3 >/dev/null 2>&1; then LANG_APT="$LANG_APT python3-pip python3-venv" fi - command -v javac >/dev/null 2>&1 || LANG_APT="$LANG_APT default-jdk maven gradle" + command -v javac >/dev/null 2>&1 || LANG_APT="$LANG_APT default-jdk" + command -v mvn >/dev/null 2>&1 || LANG_APT="$LANG_APT maven" + command -v gradle >/dev/null 2>&1 || LANG_APT="$LANG_APT gradle" command -v ruby >/dev/null 2>&1 || LANG_APT="$LANG_APT ruby-full" command -v php >/dev/null 2>&1 || LANG_APT="$LANG_APT php-cli php" command -v rustc >/dev/null 2>&1 || LANG_APT="$LANG_APT rustc cargo build-essential" @@ -229,7 +231,7 @@ resource "coder_agent" "main" { cargo --version 2>/dev/null || echo ' cargo: (not found)' echo '' echo 'Java' - javac -version 2>/dev/null || echo ' javac: (not found)' + javac -version 2>&1 || echo ' javac: (not found)' if command -v mvn >/dev/null 2>&1; then mvn -version 2>/dev/null | head -n1; else echo ' maven: (not found)'; fi if command -v gradle >/dev/null 2>&1; then gradle --version 2>/dev/null | head -n1; else echo ' gradle: (not found)'; fi echo '' @@ -237,13 +239,13 @@ resource "coder_agent" "main" { ruby --version 2>/dev/null || echo ' (not found)' echo '' echo 'PHP' - php --version 2>/dev/null | head -n1 || echo ' (not found)' + if command -v php >/dev/null 2>&1; then php --version 2>/dev/null | head -n1; else echo ' php: (not found)'; fi echo '' echo '.NET' dotnet --version 2>/dev/null || echo ' (not found)' echo '' echo 'C/C++' - gcc --version 2>/dev/null | head -n1 || echo ' gcc: (not found)' + if command -v gcc >/dev/null 2>&1; then gcc --version 2>/dev/null | head -n1; else echo ' gcc: (not found)'; fi echo '' echo 'CLI tools' if command -v gh >/dev/null 2>&1; then gh version 2>/dev/null | head -n1; else echo ' gh: not found'; fi diff --git a/templates/dkai-hermes/main.tf b/templates/dkai-hermes/main.tf index cfabd06..15273de 100644 --- a/templates/dkai-hermes/main.tf +++ b/templates/dkai-hermes/main.tf @@ -494,7 +494,7 @@ HERMESHELPER cargo --version 2>/dev/null || echo " cargo: (not found)" echo "" echo "Java" - javac -version 2>/dev/null || echo " javac: (not found)" + javac -version 2>&1 || echo " javac: (not found)" if command -v mvn >/dev/null 2>&1; then mvn -version 2>/dev/null | head -n1; else echo " maven: (not found)"; fi if command -v gradle >/dev/null 2>&1; then gradle --version 2>/dev/null | head -n1; else echo " gradle: (not found)"; fi echo "" @@ -502,13 +502,13 @@ HERMESHELPER ruby --version 2>/dev/null || echo " (not found)" echo "" echo "PHP" - php --version 2>/dev/null | head -n1 || echo " (not found)" + if command -v php >/dev/null 2>&1; then php --version 2>/dev/null | head -n1; else echo " php: (not found)"; fi echo "" echo ".NET" dotnet --version 2>/dev/null || echo " (not found)" echo "" echo "C/C++" - gcc --version 2>/dev/null | head -n1 || echo " gcc: (not found)" + if command -v gcc >/dev/null 2>&1; then gcc --version 2>/dev/null | head -n1; else echo " gcc: (not found)"; fi echo "" echo "CLI tools" if command -v gh >/dev/null 2>&1; then gh version 2>/dev/null | head -n1; else echo " gh: not found"; fi From e0492d6df5facb46e3d6fe00ceb455a9f26e4c35 Mon Sep 17 00:00:00 2001 From: Lee Chapman Date: Fri, 31 Jul 2026 13:23:17 -0700 Subject: [PATCH 3/3] fix(dkai-dev): split build-essential from rustc apt gate Co-authored-by: Cursor --- templates/dkai-dev/main.tf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/templates/dkai-dev/main.tf b/templates/dkai-dev/main.tf index fbc891c..e771d94 100644 --- a/templates/dkai-dev/main.tf +++ b/templates/dkai-dev/main.tf @@ -132,7 +132,8 @@ resource "coder_agent" "main" { command -v gradle >/dev/null 2>&1 || LANG_APT="$LANG_APT gradle" command -v ruby >/dev/null 2>&1 || LANG_APT="$LANG_APT ruby-full" command -v php >/dev/null 2>&1 || LANG_APT="$LANG_APT php-cli php" - command -v rustc >/dev/null 2>&1 || LANG_APT="$LANG_APT rustc cargo build-essential" + command -v rustc >/dev/null 2>&1 || LANG_APT="$LANG_APT rustc cargo" + command -v gcc >/dev/null 2>&1 || LANG_APT="$LANG_APT build-essential" if [ -n "$LANG_APT" ]; then sudo apt-get update # shellcheck disable=SC2086