|
| 1 | +--- |
| 2 | +name: New Feature |
| 3 | +description: "Implement a new Dev Container Feature in this repository." |
| 4 | +tools: |
| 5 | + - search/codebase |
| 6 | + - search/fileSearch |
| 7 | + - search/textSearch |
| 8 | + - read/readFile |
| 9 | + - edit/createDirectory |
| 10 | + - edit/createFile |
| 11 | + - edit/editFiles |
| 12 | + - execute/runInTerminal |
| 13 | + - execute/getTerminalOutput |
| 14 | + - web/fetch |
| 15 | + - web/githubRepo |
| 16 | + - todo |
| 17 | +user-invocable: true |
| 18 | +disable-model-invocation: false |
| 19 | +target: vscode |
| 20 | +--- |
| 21 | + |
| 22 | +<instructions> |
| 23 | +You MUST parse the user invocation to extract FEATURE_ID, SOURCE_REPO, and optional parameters. |
| 24 | +You MUST inspect SOURCE_REPO's latest GitHub release to determine the release asset naming pattern. |
| 25 | +You MUST install tools from GitHub releases, not from package managers like apt. |
| 26 | +You MUST support a version option defaulting to "latest" that resolves via the GitHub API. |
| 27 | +You MUST implement multi-architecture support mapping uname -m to release asset names per ARCH_MAP. |
| 28 | +You MUST create all files listed in DELIVERABLES_CREATE. |
| 29 | +You MUST update all files listed in DELIVERABLES_UPDATE with minimal targeted changes. |
| 30 | +You MUST follow the install.sh conventions from existing features in this repository. |
| 31 | +You MUST use set -e or set -euo pipefail in all generated shell scripts. |
| 32 | +You MUST include the root check pattern in generated install.sh files. |
| 33 | +You MUST include the check_packages helper for apt dependencies in generated install.sh files. |
| 34 | +You MUST verify installation with the binary's version command in install.sh. |
| 35 | +You MUST use the dev-container-features-test-lib pattern in generated test files. |
| 36 | +You MUST use conventional commit format for any commits. |
| 37 | +You MUST NOT modify unrelated files or make drive-by refactors. |
| 38 | +You MUST NOT remove or reorder existing README content beyond adding the new entry. |
| 39 | +You MUST NOT run devcontainer features test automatically. |
| 40 | +You SHOULD read an existing feature's install.sh as a reference before generating a new one. |
| 41 | +You SHOULD provide graceful fallback logic when GitHub API calls fail during version resolution. |
| 42 | +You SHOULD suggest test commands to the user after scaffolding using format:SCAFFOLD_SUMMARY. |
| 43 | +You MAY implement checksum verification if the user requests it and upstream provides checksums. |
| 44 | +You MAY add extra options to devcontainer-feature.json if the user specifies them. |
| 45 | +</instructions> |
| 46 | + |
| 47 | +<constants> |
| 48 | +INVOCATION_EXAMPLES: TEXT<< |
| 49 | +- new-feature ripgrep in @BurntSushi/ripgrep |
| 50 | +- new-feature mise in @jdx/mise version=2024.7.1 |
| 51 | +- new-feature protolint in @yoheimuta/protolint checksum=true |
| 52 | +>> |
| 53 | +
|
| 54 | +DELIVERABLES_CREATE: YAML<< |
| 55 | +- path: "src/{FEATURE_ID}/devcontainer-feature.json" |
| 56 | + purpose: "Feature metadata with id, name, version, description, and options" |
| 57 | +- path: "src/{FEATURE_ID}/install.sh" |
| 58 | + purpose: "Installer script that downloads from GitHub releases" |
| 59 | +- path: "test/{FEATURE_ID}/test.sh" |
| 60 | + purpose: "Basic smoke test using dev-container-features-test-lib" |
| 61 | +- path: "test/_global/{FEATURE_ID}-specific-version.sh" |
| 62 | + purpose: "Version-pinned test that greps for expected version string" |
| 63 | +>> |
| 64 | +
|
| 65 | +DELIVERABLES_UPDATE: YAML<< |
| 66 | +- path: "test/_global/all-tools.sh" |
| 67 | + action: "Add a check line for the new binary before reportResults" |
| 68 | +- path: "test/_global/scenarios.json" |
| 69 | + action: "Add feature to all-tools.features and add a version-pinned scenario" |
| 70 | +- path: ".github/workflows/test.yaml" |
| 71 | + action: "Add feature id to matrix.features array" |
| 72 | +- path: "README.md" |
| 73 | + action: "Add row to features table and add usage section" |
| 74 | +>> |
| 75 | +
|
| 76 | +ARCH_MAP: YAML<< |
| 77 | +x86_64: "x86_64" |
| 78 | +amd64: "x86_64" |
| 79 | +aarch64: "aarch64" |
| 80 | +arm64: "aarch64" |
| 81 | +armv7l: "armv7" |
| 82 | +i386: "i686" |
| 83 | +i686: "i686" |
| 84 | +>> |
| 85 | +
|
| 86 | +FEATURE_JSON_TEMPLATE: JSON<< |
| 87 | +{ |
| 88 | + "name": "{FEATURE_DISPLAY_NAME}", |
| 89 | + "id": "{FEATURE_ID}", |
| 90 | + "version": "1.0.0", |
| 91 | + "description": "{DESCRIPTION}", |
| 92 | + "options": { |
| 93 | + "version": { |
| 94 | + "type": "string", |
| 95 | + "default": "latest", |
| 96 | + "description": "Version to install from GitHub releases" |
| 97 | + } |
| 98 | + } |
| 99 | +} |
| 100 | +>> |
| 101 | +
|
| 102 | +INSTALL_SH_STRUCTURE: TEXT<< |
| 103 | +1. Shebang: #!/usr/bin/env bash with set -e |
| 104 | +2. Variables: REPO_OWNER, REPO_NAME, BINARY_NAME, VERSION |
| 105 | +3. Root check: exit 1 if $(id -u) is not 0 |
| 106 | +4. Clean up: rm -rf /var/lib/apt/lists/* |
| 107 | +5. check_packages helper: install apt deps if missing |
| 108 | +6. Install deps: curl jq ca-certificates tar |
| 109 | +7. get_latest_version: query GitHub API /repos/OWNER/REPO/releases/latest |
| 110 | +8. Version resolution: if empty or "latest" call get_latest_version |
| 111 | +9. Architecture: uname -m with case for x86_64, i686, aarch64, armv7l |
| 112 | +10. OS: uname -s mapped to linux/darwin identifiers |
| 113 | +11. Download URL: construct from owner/repo/version/arch/os |
| 114 | +12. Temp dir: mktemp -d, cd, curl -sSL, extract |
| 115 | +13. Move: mv binary /usr/local/bin/, chmod if needed |
| 116 | +14. Cleanup: rm -rf temp dir, rm -rf /var/lib/apt/lists/* |
| 117 | +15. Verify: run binary --version |
| 118 | +>> |
| 119 | +
|
| 120 | +TEST_PATTERN: TEXT<< |
| 121 | +#!/bin/bash |
| 122 | +set -e |
| 123 | +source dev-container-features-test-lib |
| 124 | +check "{FEATURE_ID}" {BINARY_NAME} --version |
| 125 | +reportResults |
| 126 | +>> |
| 127 | +
|
| 128 | +VERSION_TEST_PATTERN: TEXT<< |
| 129 | +#!/bin/bash |
| 130 | +set -e |
| 131 | +source dev-container-features-test-lib |
| 132 | +check "{FEATURE_ID} with specific version" /bin/bash -c "{BINARY_NAME} --version | grep '{PIN_VERSION}'" |
| 133 | +reportResults |
| 134 | +>> |
| 135 | +</constants> |
| 136 | +
|
| 137 | +<formats> |
| 138 | +<format id="SCAFFOLD_SUMMARY" name="Scaffold Summary" purpose="Report files created and modified and suggest test commands after scaffolding."> |
| 139 | +# Feature: <FEATURE_DISPLAY_NAME> (<FEATURE_ID>) |
| 140 | + |
| 141 | +Source: <SOURCE_REPO> |
| 142 | + |
| 143 | +## Files Created |
| 144 | +<CREATED_FILES> |
| 145 | + |
| 146 | +## Files Updated |
| 147 | +<UPDATED_FILES> |
| 148 | + |
| 149 | +## Suggested Test Commands |
| 150 | +<TEST_COMMANDS> |
| 151 | + |
| 152 | +## Notes |
| 153 | +<NOTES> |
| 154 | +WHERE: |
| 155 | +- <CREATED_FILES> is Markdown; bulleted list of created file paths. |
| 156 | +- <FEATURE_DISPLAY_NAME> is String; human-friendly feature name. |
| 157 | +- <FEATURE_ID> is String; lowercase identifier used in file paths. |
| 158 | +- <NOTES> is String; warnings, assumptions, or follow-up actions. |
| 159 | +- <SOURCE_REPO> is String; GitHub owner/repo of the upstream tool. |
| 160 | +- <TEST_COMMANDS> is Markdown; shell commands to test the new feature. |
| 161 | +- <UPDATED_FILES> is Markdown; bulleted list of updated file paths with change summary. |
| 162 | +</format> |
| 163 | +</formats> |
| 164 | + |
| 165 | +<runtime> |
| 166 | +FEATURE_ID: "" |
| 167 | +FEATURE_DISPLAY_NAME: "" |
| 168 | +SOURCE_REPO: "" |
| 169 | +BINARY_NAME: "" |
| 170 | +REQUESTED_VERSION: "latest" |
| 171 | +SUPPORT_CHECKSUM: false |
| 172 | +RELEASE_ASSET_PATTERN: "" |
| 173 | +</runtime> |
| 174 | + |
| 175 | +<triggers> |
| 176 | +<trigger event="user_message" target="main" /> |
| 177 | +</triggers> |
| 178 | + |
| 179 | +<processes> |
| 180 | +<process id="main" name="Main Workflow"> |
| 181 | +RUN `parse-input` |
| 182 | +RUN `inspect-upstream` |
| 183 | +RUN `scaffold` |
| 184 | +RUN `integrate` |
| 185 | +RETURN: format="SCAFFOLD_SUMMARY" |
| 186 | +</process> |
| 187 | + |
| 188 | +<process id="parse-input" name="Parse User Input"> |
| 189 | +SET FEATURE_ID := <ID> (from "Agent Inference" using INP) |
| 190 | +SET SOURCE_REPO := <REPO> (from "Agent Inference" using INP) |
| 191 | +SET FEATURE_DISPLAY_NAME := <NAME> (from "Agent Inference" using FEATURE_ID) |
| 192 | +SET BINARY_NAME := <BIN> (from "Agent Inference" using FEATURE_ID) |
| 193 | +IF INP contains "version=": |
| 194 | + SET REQUESTED_VERSION := <VER> (from "Agent Inference" using INP) |
| 195 | +IF INP contains "checksum=true": |
| 196 | + SET SUPPORT_CHECKSUM := true (from "Agent Inference") |
| 197 | +</process> |
| 198 | + |
| 199 | +<process id="inspect-upstream" name="Inspect Upstream Releases"> |
| 200 | +USE `web/githubRepo` where: query="latest release assets", repo=SOURCE_REPO |
| 201 | +CAPTURE RELEASE_ASSET_PATTERN from result |
| 202 | +</process> |
| 203 | + |
| 204 | +<process id="scaffold" name="Create Feature Files"> |
| 205 | +USE `read/readFile` where: filePath="src/bat/install.sh" |
| 206 | +CAPTURE REFERENCE_INSTALL from result |
| 207 | +USE `edit/createDirectory` where: dirPath="src/{FEATURE_ID}" |
| 208 | +SET FEATURE_JSON := <JSON> (from "Agent Inference" using FEATURE_DISPLAY_NAME, FEATURE_ID, FEATURE_JSON_TEMPLATE) |
| 209 | +USE `edit/createFile` where: content=FEATURE_JSON, filePath="src/{FEATURE_ID}/devcontainer-feature.json" |
| 210 | +SET INSTALL_SCRIPT := <SCRIPT> (from "Agent Inference" using INSTALL_SH_STRUCTURE, REFERENCE_INSTALL, RELEASE_ASSET_PATTERN, SOURCE_REPO, SUPPORT_CHECKSUM) |
| 211 | +USE `edit/createFile` where: content=INSTALL_SCRIPT, filePath="src/{FEATURE_ID}/install.sh" |
| 212 | +USE `edit/createDirectory` where: dirPath="test/{FEATURE_ID}" |
| 213 | +SET TEST_SCRIPT := <SCRIPT> (from "Agent Inference" using BINARY_NAME, FEATURE_ID, TEST_PATTERN) |
| 214 | +USE `edit/createFile` where: content=TEST_SCRIPT, filePath="test/{FEATURE_ID}/test.sh" |
| 215 | +SET VERSION_TEST := <SCRIPT> (from "Agent Inference" using BINARY_NAME, FEATURE_ID, REQUESTED_VERSION, VERSION_TEST_PATTERN) |
| 216 | +USE `edit/createFile` where: content=VERSION_TEST, filePath="test/_global/{FEATURE_ID}-specific-version.sh" |
| 217 | +</process> |
| 218 | + |
| 219 | +<process id="integrate" name="Update Existing Files"> |
| 220 | +USE `read/readFile` where: filePath="test/_global/all-tools.sh" |
| 221 | +USE `edit/editFiles` where: filePath="test/_global/all-tools.sh" |
| 222 | +USE `read/readFile` where: filePath="test/_global/scenarios.json" |
| 223 | +USE `edit/editFiles` where: filePath="test/_global/scenarios.json" |
| 224 | +USE `read/readFile` where: filePath=".github/workflows/test.yaml" |
| 225 | +USE `edit/editFiles` where: filePath=".github/workflows/test.yaml" |
| 226 | +USE `read/readFile` where: filePath="README.md" |
| 227 | +USE `edit/editFiles` where: filePath="README.md" |
| 228 | +</process> |
| 229 | +</processes> |
| 230 | + |
| 231 | +<input> |
| 232 | +Feature request in the form: <feature-id> in @<owner>/<repo> [version=<ver>] [checksum=true] |
| 233 | +Examples: "ripgrep in @BurntSushi/ripgrep", "mise in @jdx/mise version=2024.7.1" |
| 234 | +</input> |
0 commit comments