-
Notifications
You must be signed in to change notification settings - Fork 1
Devcontainer-specific devtools docs #555
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,237 @@ | ||
| # Building the Extension in a Devcontainer | ||
|
|
||
| How to set up and use a devcontainer for iterative build-test cycles of the | ||
| amicode extension and its opencode fork, with workspace state that survives | ||
| container rebuilds. | ||
|
|
||
| --- | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| The container must have the following on PATH: | ||
|
|
||
| | Tool | Purpose | Installed by | | ||
| |------|---------|-------------| | ||
| | `bun` (>= 1.x) | opencode repo install + binary compilation | Dockerfile (`bun.sh/install`) | | ||
| | `pnpm` (>= 9.x) | amicode repo install + build orchestration | Dockerfile (`get.pnpm.io`) | | ||
| | `node` (>= 20) | esbuild, vsce, general tooling | Dockerfile (via nvm) | | ||
|
|
||
| `vsce` is NOT required on PATH — it's resolved via `pnpm exec` from the | ||
| extension's devDependencies. | ||
|
|
||
| The opencode repo must be the `harmoniqs/opencode` fork (the `opencode:build` | ||
| script calls `fetch_opencode.mjs` which expects the fork's lock manifest). | ||
| Stock `sst/opencode` will not work. | ||
|
|
||
| --- | ||
|
|
||
| ## Workspace Layout | ||
|
|
||
| ### Model A: Persistent clones (recommended for iterative development) | ||
|
|
||
| The workspace directory (`/workspaces/<name>`) persists across container | ||
| rebuilds. The repos live inside it as ordinary git clones: | ||
|
|
||
| ``` | ||
| /workspaces/<workspace>/ | ||
| ├── opencode/ ← git clone of harmoniqs/opencode | ||
| ├── amicode/ ← git clone of harmoniqs/amicode | ||
| ├── artifacts/ ← vsix output directory | ||
| └── .devcontainer/ | ||
| ├── devcontainer.jsonc | ||
| └── Dockerfile | ||
| ``` | ||
|
|
||
| ### Model B: Auto-clone on creation (for fresh setups) | ||
|
|
||
| Add a `postCreateCommand` to devcontainer.jsonc that clones the repos if absent: | ||
|
|
||
| ```jsonc | ||
| "postCreateCommand": "bash .devcontainer/setup-repos.sh" | ||
| ``` | ||
|
|
||
| Where `setup-repos.sh` is an idempotent script that clones + checks out the | ||
| desired branches (see the extended example below). | ||
|
|
||
| --- | ||
|
|
||
| ## Minimal Devcontainer Configuration | ||
|
|
||
| ### `devcontainer.jsonc` | ||
|
|
||
| ```jsonc | ||
| { | ||
| "name": "Amicode Extension Dev", | ||
| "build": { | ||
| "dockerfile": "./Dockerfile", | ||
| "context": "." | ||
| }, | ||
| "forwardPorts": [43117], | ||
| "portsAttributes": { | ||
| "43117": { | ||
| "label": "Opencode Server", | ||
| "requireLocalPort": true, | ||
| "onAutoForward": "silent" | ||
| } | ||
| }, | ||
| "customizations": { | ||
| "vscode": { | ||
| "settings": { | ||
| "amicode.opencodePort": 43117 | ||
| } | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
Comment on lines
+62
to
+85
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
for command_name in node pnpm bun; do
command -v "$command_name" >/dev/null || {
printf 'Missing from PATH: %s\n' "$command_name" >&2
exit 1
}
doneRepository: harmoniqs/amicode Length of output: 178 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- docs/devcontainer-build.md: relevant sections ---'
sed -n '1,120p' docs/devcontainer-build.md
printf '%s\n' '--- Dockerfile candidates ---'
fd -i -t f 'Dockerfile' .
printf '%s\n' '--- package and devcontainer configuration candidates ---'
fd -i -t f '(package.json|pnpm-lock.yaml|devcontainer.json|devcontainer.*|.*container.*)' . | sortRepository: harmoniqs/amicode Length of output: 3926 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- Developer Tools and devcontainer references ---'
rg -n -S -g '!docs/devcontainer-build.md' \
'Devcontainer|devcontainer|Build VSIX|opencode repo|amicode repo|vsix output|opencodePort' .
printf '%s\n' '--- package scripts and engine declarations ---'
sed -n '1,180p' package.json
sed -n '1,180p' packages/extension/package.jsonRepository: harmoniqs/amicode Length of output: 16298 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- Devcontainer build implementation ---'
sed -n '640,760p' packages/extension/src/chat_bridge.ts
printf '%s\n' '--- Process execution imports and helpers in chat_bridge.ts ---'
sed -n '1,80p' packages/extension/src/chat_bridge.ts
rg -n -S 'exec|spawn|pnpm|bun|PATH|shell' packages/extension/src/chat_bridge.ts packages/extension/src
printf '%s\n' '--- Environment setup guidance in repository ---'
rg -n -S 'nvm|BASH_ENV|remoteEnv|remoteEnv|\.bun/bin|get.pnpm.io|bun.sh/install' AGENTS.md docs packages .devcontainer 2>/dev/null || trueRepository: harmoniqs/amicode Length of output: 50373 🏁 Script executed: #!/usr/bin/env bash
set -euo pipefail
printf '%s\n' '--- Exact VSIX build subprocess and packaging call ---'
sed -n '704,782p' packages/extension/src/chat_bridge.ts
printf '%s\n' '--- Devcontainer file references and explicit environment configuration ---'
git ls-files | rg '(^|/)(Dockerfile|devcontainer\.jsonc?|.*container.*)$' || true
rg -n -S '^\s*(ENV|remoteEnv|containerEnv|PATH=|BASH_ENV)|nvm|pnpm|bun' docs/devcontainer-build.md .devcontainer packages/extension 2>/dev/null || true
printf '%s\n' '--- Installer profile edits (without executing installers) ---'
curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.6/install.sh |
rg -n -m 8 'bashrc|profile|nvm\.sh|PROFILE'
curl -fsSL https://get.pnpm.io/install.sh |
rg -n -m 12 'PNPM_HOME|profile|bashrc|PATH'
curl -fsSL https://bun.sh/install |
rg -n -m 12 'BUN_INSTALL|bashrc|profile|PATH'Repository: harmoniqs/amicode Length of output: 38823 Make the installed tools available to the extension host. The documented Dockerfile adds 🤖 Prompt for AI AgentsSource: MCP tools |
||
|
|
||
| ### `Dockerfile` | ||
|
|
||
| ```dockerfile | ||
| FROM mcr.microsoft.com/devcontainers/base:ubuntu-24.04 | ||
| RUN apt-get update && apt-get install -y --no-install-recommends \ | ||
| build-essential curl python3 python3-pip python3-venv wget | ||
|
|
||
| USER vscode | ||
|
|
||
| # Node (via nvm) | ||
| RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.6/install.sh | bash | ||
| RUN ["/bin/bash", "-c", "source ${HOME}/.nvm/nvm.sh && nvm install 24"] | ||
|
|
||
| # pnpm (for amicode repo) | ||
| RUN curl -fsSL https://get.pnpm.io/install.sh | bash | ||
|
|
||
| # bun (for opencode repo) | ||
| RUN curl -fsSL https://bun.sh/install | bash | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## The Build-Test Cycle | ||
|
|
||
| ### Using the Developer Tools UI (recommended) | ||
|
|
||
| 1. Open Settings → Developer Tools | ||
| 2. Enable **Devcontainer mode (experimental)** | ||
| 3. Set the three paths: opencode repo, amicode repo, VSIX output directory | ||
| 4. Click **Build VSIX** — waits 2-5 minutes on first run, ~60-90s thereafter | ||
| 5. Right-click the emitted `.vsix` in the file explorer → "Install Extension VSIX" | ||
| 6. The new build is now active — test as needed | ||
| 7. Iterate: make changes in either repo, click Build VSIX again, reinstall | ||
|
|
||
| ### Using the terminal (manual equivalent) | ||
|
|
||
| ```bash | ||
| # From the workspace root, with opencode/ and amicode/ as subdirectories: | ||
|
|
||
| # 1. Install opencode dependencies | ||
| cd opencode && bun install && cd .. | ||
|
|
||
| # 2. Install amicode dependencies | ||
| cd amicode && pnpm install && cd .. | ||
|
|
||
| # 3. Build extension + opencode binary | ||
| cd amicode | ||
| NODE_OPTIONS="--max-old-space-size=4096" pnpm --filter amicode build | ||
| NODE_OPTIONS="--max-old-space-size=4096" pnpm --filter amicode opencode:build | ||
| cd .. | ||
|
|
||
| # 4. Package vsix | ||
| cd amicode/packages/extension | ||
| pnpm exec vsce package --no-dependencies --allow-missing-repository -o /workspaces/<workspace>/artifacts/amicode.vsix | ||
|
Comment on lines
+132
to
+140
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- candidate manifests ---'
fd -t f 'package.json' . | head -80
printf '%s\n' '--- documentation context ---'
sed -n '120,148p' docs/devcontainer-build.md
printf '%s\n' '--- extension manifest candidates ---'
for f in $(fd -t f 'package.json' . | grep '/packages/extension/package.json$'); do
printf '\n### %s\n' "$f"
cat -n "$f"
doneRepository: harmoniqs/amicode Length of output: 23271 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- workspace and amico-run manifests ---'
cat -n package.json
cat -n packages/amico-run/package.json
printf '%s\n' '--- extension build and packaging implementation ---'
for f in packages/extension/esbuild.config.mjs packages/extension/scripts/opencode_dev.mjs packages/extension/scripts/fetch_opencode.mjs packages/extension/scripts/build_exemplars.mjs; do
printf '\n### %s\n' "$f"
sed -n '1,240p' "$f"
doneRepository: harmoniqs/amicode Length of output: 30972 Use the manifest’s complete packaging sequence.
🤖 Prompt for AI Agents |
||
| cd ../../.. | ||
|
|
||
| # 5. Install | ||
| code --install-extension /workspaces/<workspace>/artifacts/amicode.vsix | ||
| ``` | ||
|
Comment on lines
+121
to
+145
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Include the test step in the documented cycle. The section is named 🤖 Prompt for AI Agents |
||
|
|
||
| --- | ||
|
|
||
| ## What Persists Across What | ||
|
|
||
| | Item | Container restart | Container rebuild | | ||
| |------|------------------|-------------------| | ||
| | Workspace files (repos, artifacts) | Yes | Yes (bind mount) | | ||
| | `node_modules` inside repos | Yes | Yes (in workspace) | | ||
| | `.pnpm-store` | Yes | Yes (in workspace) | | ||
| | Installed VS Code extensions | Yes | No (reinstalled) | | ||
| | VS Code settings (machine scope) | Yes | No (rewritten from devcontainer.jsonc) | | ||
| | Container-local state (`~/.local/`) | Yes | No | | ||
|
Comment on lines
+151
to
+158
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- target documentation ---'
sed -n '135,190p' docs/devcontainer-build.md
printf '%s\n' '--- pnpm configuration references ---'
rg -n --hidden -S 'store-dir|pnpm|PNPM_HOME|\.pnpm-store|corepack' \
--glob '!node_modules' --glob '!dist' --glob '!build' .Repository: harmoniqs/amicode Length of output: 27354 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- devcontainer-related files ---'
fd -HI 'devcontainer|Dockerfile|npmrc|pnpm-workspace|package.json' . | sort
printf '%s\n' '--- documentation setup and configuration ---'
sed -n '1,140p' docs/devcontainer-build.md
printf '%s\n' '--- package manager metadata ---'
cat -n package.json | sed -n '1,25p'Repository: harmoniqs/amicode Length of output: 41921 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- effective pnpm configuration ---'
if command -v pnpm >/dev/null 2>&1; then
printf 'pnpm: '; pnpm --version
printf 'store-dir: '; pnpm config get store-dir
else
printf '%s\n' 'pnpm is not available in the verifier environment'
fi
printf '%s\n' '--- repository devcontainer configuration ---'
cat -n .devcontainer/devcontainer.json
printf '%s\n' '--- tracked configuration files relevant to pnpm ---'
git ls-files | grep -E '(^|/)(\.npmrc|\.pnpmfile\.cjs|pnpm-workspace\.yaml|package\.json)$' | sortRepository: harmoniqs/amicode Length of output: 1647 Configure the pnpm store path or correct the persistence documentation.
🤖 Prompt for AI Agents |
||
|
|
||
| --- | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### "Build failed" after changing branches | ||
|
|
||
| Stale build artifacts from a previous branch can cause failures. Clean both repos: | ||
|
|
||
| ```bash | ||
| cd opencode && git clean -xfd && cd .. | ||
| cd amicode && git clean -xfd && cd .. | ||
| ``` | ||
|
|
||
| This deletes `node_modules`, `dist/`, and vendor binaries. The next build will | ||
| be slow (full reinstall) but clean. | ||
|
Comment on lines
+168
to
+174
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win Do not present
Suggested safer workflow-cd opencode && git clean -xfd && cd ..
-cd amicode && git clean -xfd && cd ..
+cd opencode && git clean -ndx && cd ..
+cd amicode && git clean -ndx && cd ..
+# Review the output before running any destructive cleanup.🤖 Prompt for AI AgentsSource: MCP tools |
||
|
|
||
| ### `.pnpm-store` taking up space | ||
|
|
||
| The `.pnpm-store` directory is a build-time cache populated by `pnpm install`. | ||
| It's safe to delete (only slows the next install). It has no role at runtime. | ||
|
|
||
| ### Port forwarding issues | ||
|
|
||
| The devcontainer.jsonc pins port 43117 with `requireLocalPort: true`. If you | ||
| still see port mismatch issues (blank chat panel), check the Ports tab in VS Code | ||
| and ensure 43117 maps to itself (not to a different port). | ||
|
|
||
| --- | ||
|
|
||
| ## Extended Example: Auto-Clone with Branch Pinning | ||
|
|
||
| ### `setup-repos.sh` | ||
|
|
||
| ```bash | ||
| #!/usr/bin/env bash | ||
| set -euo pipefail | ||
|
|
||
| WORKSPACE="/workspaces/$(basename "$PWD")" | ||
| OPENCODE_BRANCH="${OPENCODE_BRANCH:-local/amicode}" | ||
| AMICODE_BRANCH="${AMICODE_BRANCH:-main}" | ||
|
|
||
| if [ ! -d "$WORKSPACE/opencode/.git" ]; then | ||
| git clone https://github.com/harmoniqs/opencode.git "$WORKSPACE/opencode" | ||
| fi | ||
| cd "$WORKSPACE/opencode" | ||
| git fetch origin | ||
| git checkout "$OPENCODE_BRANCH" 2>/dev/null || git checkout -b "$OPENCODE_BRANCH" "origin/$OPENCODE_BRANCH" | ||
| git pull --ff-only origin "$OPENCODE_BRANCH" 2>/dev/null || true | ||
|
|
||
| if [ ! -d "$WORKSPACE/amicode/.git" ]; then | ||
| git clone https://github.com/harmoniqs/amicode.git "$WORKSPACE/amicode" | ||
| fi | ||
| cd "$WORKSPACE/amicode" | ||
| git fetch origin | ||
| git checkout "$AMICODE_BRANCH" 2>/dev/null || git checkout -b "$AMICODE_BRANCH" "origin/$AMICODE_BRANCH" | ||
| git pull --ff-only origin "$AMICODE_BRANCH" 2>/dev/null || true | ||
|
|
||
| mkdir -p "$WORKSPACE/artifacts" | ||
| echo "==> Repos ready: opencode@$OPENCODE_BRANCH, amicode@$AMICODE_BRANCH" | ||
| ``` | ||
|
|
||
| Override branches via environment variables: | ||
|
|
||
| ```bash | ||
| # In .env at the workspace root (picked up by devcontainer.jsonc): | ||
| OPENCODE_BRANCH=feat/my-feature | ||
| AMICODE_BRANCH=feat/my-feature | ||
| ``` | ||
|
|
||
| Add to `devcontainer.jsonc`: | ||
|
|
||
| ```jsonc | ||
| "containerEnv": { | ||
| "OPENCODE_BRANCH": "${localEnv:OPENCODE_BRANCH:local/amicode}", | ||
| "AMICODE_BRANCH": "${localEnv:AMICODE_BRANCH:main}" | ||
| }, | ||
| "postCreateCommand": "bash .devcontainer/setup-repos.sh" | ||
|
Comment on lines
+221
to
+236
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: #!/bin/bash
printf '%s\n' '--- documentation context ---'
sed -n '205,245p' docs/devcontainer-build.md
printf '%s\n' '--- devcontainer configuration files ---'
fd -i 'devcontainer.jsonc|devcontainer.json|setup-repos.sh' .devcontainer . 2>/dev/null | head -50
printf '%s\n' '--- relevant configuration references ---'
rg -n -C 4 'localEnv|containerEnv|remoteEnv|postCreateCommand|OPENCODE_BRANCH|AMICODE_BRANCH|dotenv|\.env' .devcontainer docs/devcontainer-build.mdRepository: harmoniqs/amicode Length of output: 4824 🌐 Web query:
💡 Result: The term localEnv is not a mechanism that automatically loads.env files; rather, in the context of Visual Studio Code development containers, ${localEnv:SOME_VAR} is a syntax used for variable substitution within devcontainer.json [1]. This syntax allows you to reference environment variables that are already set on your local machine (your host) and inject their values into the container's environment (via containerEnv or remoteEnv) [1]. It does not perform the task of scanning for or automatically loading a.env file from your file system [1]. If you need to load environment variables from a.env file for a development container, you must explicitly configure that file [1]. For example: 1. When using Docker Compose, you can define an env_file in your docker-compose.yml, and Docker Compose will automatically detect a file named.env if it is located in the same directory as the docker-compose.yml file [1]. 2. For Dockerfiles or images, you can configure the.env file path in your devcontainer.json using runArgs [1]: "runArgs": ["--env-file", ".devcontainer/devcontainer.env"] Citations: Document the required host export or explicit 🤖 Prompt for AI AgentsSource: MCP tools |
||
| ``` | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Add a language to the directory-tree fence.
markdownlintreports MD040 for Line 35. Mark this fence astextorplaintext.🧰 Tools
🪛 markdownlint-cli2 (0.23.2)
[warning] 35-35: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Source: Linters/SAST tools