Skip to content

Commit 3d048b1

Browse files
authored
Merge pull request #63 from jsburckhardt/feat/opencode
feat: add OpenCode devcontainer feature
2 parents bbd6ab6 + 0caff15 commit 3d048b1

12 files changed

Lines changed: 404 additions & 22 deletions

.devcontainer.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,7 @@
3434
"features": {
3535
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
3636
"ghcr.io/stuartleeks/dev-container-features/shell-history:0": {},
37-
"ghcr.io/jsburckhardt/devcontainer-features/gic:1": {}
38-
39-
37+
"ghcr.io/devcontainers/features/github-cli:latest": {}
4038
},
4139
"updateContentCommand": "npm install -g @devcontainers/cli",
4240
"remoteUser": "node",

.github/copilot-instructions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ When creating a new feature, follow these steps:
1414
- Update the ../../test/_global/all-tools.sh to validate the new feature is installed.
1515
- Update the ../../test/_global/scenarios.json to include the new feature.
1616
- include the feature in the workflows
17+
- run `devcontainer features test -f $(feature) -i ubuntu:latest`

.github/prompts/generate-commit-message.prompt.md

Lines changed: 0 additions & 18 deletions
This file was deleted.
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
---
2+
mode: 'agent'
3+
description: 'Implement a new Dev Container Feature in this repository.'
4+
---
5+
6+
# New Devcontainer Feature Generator
7+
8+
## Purpose
9+
Implement a new Dev Container Feature in this repository.
10+
11+
## Invocation Pattern (Human Usage Examples)
12+
- `/new-feature just in @casey/just`
13+
- `/new-feature ripgrep in @BurntSushi/ripgrep`
14+
- `/new-feature mise in @jdx/mise version=2024.7.1`
15+
- `/new-feature protolint in @yoheimuta/protolint checksum=true`
16+
17+
Copilot: Parse the user’s invocation to fill the Variables section below before generating changes.
18+
19+
## Variables (to be derived or defaulted)
20+
Extract from user command or infer:
21+
- FEATURE_ID: Lowercase id (no spaces). Example: `just`, `ripgrep`, `mise`.
22+
- FEATURE_DISPLAY_NAME: Human-friendly (capitalize if appropriate). Example: `Just`, `Ripgrep`.
23+
- SOURCE_REPO: GitHub `owner/name` the binary/tool comes from. Example: `casey/just`.
24+
- BINARY_NAME: Name of the installed executable (often equals FEATURE_ID; override if different).
25+
- REQUESTED_VERSION: Explicit version if user supplied `version=...`; else "latest".
26+
- SUPPORT_CHECKSUM: Boolean if user included `checksum=true`; default false.
27+
- EXTRA_OPTIONS: Optional structured options (e.g. additional feature options) if user appended `opt:key=value` pairs.
28+
- INITIAL_FEATURE_VERSION: Always start at `1.0.0` (Feature’s internal semver, NOT the tool upstream version).
29+
- ARCH_LIST: Default `[x86_64, i686, aarch64, armv7]` (omit unsupported ones if known).
30+
- RELEASE_ASSET_PATTERN: Infer typical asset naming scheme once you inspect the SOURCE_REPO’s latest release assets (handle suffix variations like `linux-x86_64.tar.gz`, `.zip`, plain binary, etc.).
31+
32+
If inference is ambiguous, favor adding commented fallback logic rather than guessing incorrectly.
33+
34+
## High-Level Task
35+
Create a new Feature at `src/FEATURE_ID` that:
36+
1. Installs the tool from GitHub releases (or alternative upstream if tool uses another distribution method).
37+
2. Supports a `version` option (default `"latest"`) resolving to the latest stable release (exclude pre-releases unless user explicitly requests one).
38+
3. Implements multi-architecture support mapping `uname -m` to release asset names.
39+
4. Provides graceful fallback if GitHub API calls fail (e.g. rate limit / firewall) by:
40+
- Trying API first (`https://api.github.com/repos/SOURCE_REPO/releases/latest`)
41+
- Falling back to parsing HTML of `https://github.com/SOURCE_REPO/releases/latest` or using a lightweight strategy (document what you did).
42+
5. (Optional) Performs checksum verification if SUPPORT_CHECKSUM is true AND the upstream provides checksums (e.g. `SHA256SUMS` file).
43+
6. Adds tests: basic install + pinned version test; checksum test if applicable.
44+
7. Updates root README to list the feature with usage examples.
45+
8. Integrates tests into existing CI matrix (mirroring the just feature pattern).
46+
9. Uses consistent shell style and safety (`set -euo pipefail`, traps for cleanup).
47+
10. Leaves unrelated files untouched (NO incidental formatting changes, NO kyverno/zarf edits, NO drive-by refactors).
48+
49+
## File/Directory Deliverables
50+
Create:
51+
- `src/FEATURE_ID/devcontainer-feature.json`
52+
- `src/FEATURE_ID/install.sh`
53+
- `test/FEATURE_ID/test.sh`
54+
- `test/_global/FEATURE_ID-specific-version.sh`
55+
update
56+
- `test/_global/all-tools.sh`
57+
- `test/_global/scenarios.json`
58+
- `.github/workflows/test.yaml`
59+
60+
Modify minimally:
61+
- Root `README.md` (add new feature entry & examples)
62+
63+
## devcontainer-feature.json Requirements
64+
- `id`: FEATURE_ID
65+
- `version`: INITIAL_FEATURE_VERSION
66+
- `name`: FEATURE_DISPLAY_NAME
67+
- `description`: Concise summary of what the tool does
68+
- `documentationURL`: Link to this feature’s README
69+
- `options.version`: string, default "latest"
70+
- Add any EXTRA_OPTIONS (preserve ordering)
71+
- `instantiationMode`: "onCreate"
72+
73+
## install.sh Requirements
74+
1. `#!/usr/bin/env bash`
75+
2. `set -euo pipefail`
76+
3. Parse inputs: `VERSION=$VERSION` (from feature option) -> treat "latest" specially.
77+
4. Architecture map example (adjust names per RELEASE_ASSET_PATTERN):
78+
- `x86_64` or `amd64` -> `x86_64`
79+
- `aarch64` or `arm64` -> `aarch64`
80+
- `armv7l` -> `armv7`
81+
- `i386` or `i686` -> `i686`
82+
5. Resolve version:
83+
- If VERSION == "latest":
84+
- Try GitHub API → extract tag_name minus leading `v` if present
85+
- Fallback to scraping or light pattern detection from releases page HTML
86+
- Else trust user-supplied
87+
6. Construct download URL (document pattern).
88+
7. Download to temp dir. Use curl with retry/backoff flags similar to just feature style.
89+
8. Extract / move binary:
90+
- If archive: detect extension (.tar.gz, .zip), extract accordingly.
91+
- Ensure final binary path: `/usr/local/bin/BINARY_NAME` and `chmod 0755`.
92+
9. (Optional) Checksum:
93+
- Download checksums file, grep the asset, verify via `sha256sum -c -`
94+
10. Verification:
95+
- Run `${BINARY_NAME} --version` or fallback command; ensure it prints something containing resolved version if version != "latest".
96+
11. Output a success message.
97+
98+
99+
## CI Integration
100+
- Update workflow to include FEATURE_ID in matrix if that’s how others are integrated.
101+
- Keep ordering logical (append near similar tooling features).
102+
- Avoid reorganizing unrelated entries.
103+
104+
## Commit / PR Conventions
105+
Suggested (may auto-squash):
106+
1. `chore: scaffold FEATURE_ID feature`
107+
2. `feat: implement FEATURE_ID install logic`
108+
3. `test: add tests for FEATURE_ID`
109+
4. `docs: add FEATURE_ID feature documentation`
110+
111+
PR Title:
112+
`feat: add FEATURE_ID devcontainer feature`
113+
114+
PR Body Should Include:
115+
- Summary
116+
- Version handling strategy
117+
- Architecture support
118+
- Checksum support (yes/no)
119+
- Usage examples
120+
- Tests added
121+
- Statement: “No unrelated changes; excludes kyverno/zarf fixes.”
122+
123+
## Constraints & Non-Goals
124+
- Do NOT refactor global scripts.
125+
- Do NOT adjust unrelated workflow triggers.
126+
- Do NOT rename existing features.
127+
- Do NOT remove or reorder existing README content beyond adding new entry.
128+
129+
## Acceptance Criteria
130+
- All new tests pass in CI.
131+
- Feature listed in root README.
132+
- `install.sh` resilient to GitHub API failure with fallback.
133+
- Pinning a version works.
134+
- Latest resolution works.
135+
- No unrelated file diffs (confirm with `git diff` scope).
136+
- If checksum requested and available upstream, verification implemented (skip gracefully if not).
137+
138+
## Output Format Instruction for Copilot
139+
When generating the PR:
140+
1. Create new branch (named `feature/FEATURE_ID`).
141+
2. Add/modify files exactly as specified.
142+
3. Open a pull request with the defined title and body.
143+
4. Include only relevant changes.
144+
145+
## Post-Generation Self-Check (Copilot)
146+
Before finalizing:
147+
- Re-open each new file; ensure placeholders replaced.
148+
- Ensure executable bits on `install.sh` and test scripts.
149+
- Ensure JSON is valid (no trailing commas).
150+
- Ensure shell uses POSIX-compatible constructs (or justify bash usage).
151+
- Verify version extraction logic with both “latest” and pinned flows (mentally or via test design).
152+
- Confirm absence of kyverno/zarf references / modifications.

.github/workflows/test.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ jobs:
2929
- codex
3030
- bat
3131
- just
32+
- opencode
3233
baseImage:
3334
- debian:latest
3435
- ubuntu:latest

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ This repository contains a _collection_ of Features.
2424
| just | https://github.com/casey/just | A command runner. Just is a handy way to save and run project-specific commands. |
2525
| UV/UVX | https://docs.astral.sh/uv/ | An extremely fast Python package and project manager, written in Rust. A single tool to replace pip, pip-tools, pipx, poetry, pyenv, virtualenv, and more. |
2626
| Ruff | https://docs.astral.sh/ruff/ | An extremely fast Python linter and code formatter, written in Rust. |
27+
| OpenCode | https://opencode.ai/ | AI coding agent, built for the terminal. An open-source alternative to Claude Code with support for multiple LLM providers. |
2728
| Codex-cli | https://github.com/openai/codex | Codex CLI is an experimental project under active development. |
2829

2930

@@ -283,6 +284,24 @@ Running `k3d` inside the built container will print the help menu of k3d.
283284
```bash
284285
k3d --version
285286
```
287+
288+
### `opencode`
289+
290+
Running `opencode` inside the built container will allow you to use the AI coding agent.
291+
292+
```jsonc
293+
{
294+
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
295+
"features": {
296+
"ghcr.io/jsburckhardt/devcontainer-features/opencode:1": {}
297+
}
298+
}
299+
```
300+
301+
```bash
302+
opencode --version
303+
```
304+
286305
### `Codex-CLI`
287306

288307
Running `codex` inside the built container will print the help menu of codex.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "OpenCode",
3+
"id": "opencode",
4+
"version": "1.0.0",
5+
"description": "AI coding agent, built for the terminal. An open-source alternative to Claude Code with support for multiple LLM providers.",
6+
"documentationURL": "https://opencode.ai/docs",
7+
"options": {
8+
"version": {
9+
"type": "string",
10+
"default": "latest",
11+
"description": "Version of opencode to install from GitHub releases e.g. 0.10.4"
12+
}
13+
},
14+
"customizations": {
15+
"vscode": {
16+
"extensions": [
17+
"sst-dev.opencode"
18+
]
19+
}
20+
}
21+
}

0 commit comments

Comments
 (0)