Clean up workBenches base and devBench tooling#1
Conversation
Reviewer's GuideRefactors base and devBench AI/spec tooling by moving spec-kit/OpenSpec into the dev-bench base layer with reusable Speckit worktree helpers, adds SonarQube/SonarScanner tooling and SonarCloud coverage helpers, introduces robust yolo/ct shell functions, and extends project detection and docs for pyBench/phpBench while tightening docker/devcontainer reconciliation and AI provider configuration. Sequence diagram for Speckit worktree and AI helper workflowsequenceDiagram
actor Dev
participant speckit_worktree_enable
participant git_feature as create-new-feature.sh
participant git_worktree as git_worktree
participant feature_json as feature.json
participant ct as ct_functions
participant select_wt as select-worktree.sh
participant claude_cli as claude
Dev->>speckit_worktree_enable: run speckit-worktree-enable
speckit_worktree_enable->>feature_json: install git extension config
speckit_worktree_enable->>ct: install ct, cta, ctc, ctg, cts
Dev->>speckit_worktree_enable: run /speckit.specify
speckit_worktree_enable->>git_feature: invoke speckit-git-feature hook
git_feature->>git_worktree: git worktree add -b <branch>
git_feature-->>speckit_worktree_enable: BRANCH_NAME, WORKTREE_PATH
speckit_worktree_enable->>feature_json: write feature_directory for spec
Dev->>ct: cta
ct->>select_wt: select-worktree.sh --path
select_wt-->>ct: WORKTREE_PATH
ct->>claude_cli: start claude in tmux at WORKTREE_PATH
claude_cli-->>Dev: interactive AI session in feature worktree
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
@codex review |
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- The Speckit git/worktree templates include project- and user-specific values (e.g.,
worktree_root: ../ledgerlinc-model-ocr-pipeline-worktreesingit-config.ymland the hardcoded/home/brett/...path inct.zsh); consider replacing these with generic defaults or relative paths so generated projects are not tied to a specific environment. - There is a fair amount of duplicated logic between the project-local worktree helpers (e.g.,
.specify/shell/worktrees.sh) and the globalct-functions.zsh; it may be worth centralizing common behavior into a single shared script to reduce drift and simplify future changes. - In
reconcile-devcontainer-container.sh, failing hard when the expected image is missing (exit 1) might be surprising in multi-bench workflows; consider treating this as a non-fatal condition (log and exit 0) so callers can decide whether a missing image should stop their pipeline.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The Speckit git/worktree templates include project- and user-specific values (e.g., `worktree_root: ../ledgerlinc-model-ocr-pipeline-worktrees` in `git-config.yml` and the hardcoded `/home/brett/...` path in `ct.zsh`); consider replacing these with generic defaults or relative paths so generated projects are not tied to a specific environment.
- There is a fair amount of duplicated logic between the project-local worktree helpers (e.g., `.specify/shell/worktrees.sh`) and the global `ct-functions.zsh`; it may be worth centralizing common behavior into a single shared script to reduce drift and simplify future changes.
- In `reconcile-devcontainer-container.sh`, failing hard when the expected image is missing (`exit 1`) might be surprising in multi-bench workflows; consider treating this as a non-fatal condition (log and exit 0) so callers can decide whether a missing image should stop their pipeline.
## Individual Comments
### Comment 1
<location path="devBenches/base-image/files/speckit-worktree/templates/specify/shell/worktrees.sh" line_range="10-13" />
<code_context>
+
+# Auto-detect repo root from this script's own location so the file is
+# relocatable and does not embed a host-specific absolute path.
+LEDGERLINC_SPECKIT_REPO_ROOT="$(CDPATH="" cd "${${(%):-%x}:A:h}/../.." 2>/dev/null && pwd)"
+if [ -z "$LEDGERLINC_SPECKIT_REPO_ROOT" ]; then
+ # bash fallback when the zsh prompt expansion above is unavailable
+ LEDGERLINC_SPECKIT_REPO_ROOT="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]:-$0}")/../.." 2>/dev/null && pwd)"
+fi
+LEDGERLINC_SPECKIT_LAST_WORKTREE_SCRIPT="$LEDGERLINC_SPECKIT_REPO_ROOT/.specify/extensions/git/scripts/bash/get-last-worktree.sh"
</code_context>
<issue_to_address>
**issue (bug_risk):** Sourcing this script in bash will fail due to unguarded zsh-specific parameter expansion.
Because the script is advertised as source-able from both bash and zsh, the unguarded `${${(%):-%x}:A:h}` causes `bad substitution` in bash before the fallback can run. Please gate the zsh-only expansion on `$ZSH_VERSION`, for example:
```bash
if [ -n "${ZSH_VERSION:-}" ]; then
LEDGERLINC_SPECKIT_REPO_ROOT="$(CDPATH="" cd "${${(%):-%x}:A:h}/../.." 2>/dev/null && pwd)"
else
LEDGERLINC_SPECKIT_REPO_ROOT="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]:-$0}")/../.." 2>/dev/null && pwd)"
fi
```
</issue_to_address>
### Comment 2
<location path="devBenches/goBench/README.md" line_range="140-141" />
<code_context>
# Go shortcuts
# (alias examples - these would be configured in shell)
go run, go build, go test, go mod, etc.
+go-sonar-coverage # go test coverage.out + sonar-scanner
# Docker & Kubernetes
</code_context>
<issue_to_address>
**issue (typo):** The documented SonarCloud coverage helper uses two different command names (`go-sonar-coverage` vs `sonarcloud-go-coverage`).
Alias examples use `go-sonar-coverage`, while the dedicated section uses `sonarcloud-go-coverage`. Please either standardize on one name or clarify if they are different tools to avoid user confusion.
```suggestion
go run, go build, go test, go mod, etc.
sonarcloud-go-coverage # go test coverage.out + sonar-scanner
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Pull request overview
This PR updates the shared workBench/devBench base tooling, moves spec-driven tooling into the devBench base layer, adds SonarQube/SonarCloud helpers, removes Grok from supported AI tooling, and refreshes bench inventory from pythonBench to pyBench with added phpBench support.
Changes:
- Reworks base/devBench AI and spec CLI installation, yolo/ct helpers, and OpenCode plugin handling.
- Adds Speckit worktree tooling, SonarQube MCP startup, and Java/Go/C++ SonarCloud coverage helpers.
- Updates bench detection/config/docs/tests for
pyBench,phpBench, Grok removal, and new devBench tooling.
Reviewed changes
Copilot reviewed 87 out of 88 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
.gitignore |
Updates ignored bench directories and Python artifacts. |
README.md |
Refreshes image layer and bench inventory documentation. |
base-image/Dockerfile |
Updates Layer 0 version, removes spec CLI ownership, and adds yolo function. |
base-image/files/opencode/opencode.json |
Removes pinned OpenCode auth plugin versions. |
base-image/install-ai-clis.sh |
Updates AI CLI install flow, adds Antigravity, removes Grok/OpenSpec. |
bench-config.json.backup |
Renames Python bench backup entry to pyBench. |
config/bench-config.json |
Renames Python bench config and adds phpBench config. |
config/shell/zshrc |
Converts yolo alias into a tmux-backed function. |
devBenches/.devcontainer/devcontainer.json |
Starts SonarQube MCP for the devBenches workspace. |
devBenches/README.md |
Documents phpBench/pyBench and shared Sonar tools. |
devBenches/base-image/Dockerfile |
Adds spec-driven tools, ct helpers, and worktree bootstrap into Layer 1a. |
devBenches/base-image/files/ct/ct-functions.zsh |
Adds global Speckit worktree launcher functions. |
devBenches/base-image/files/opencode/opencode.json |
Removes pinned OpenCode auth plugin versions. |
devBenches/base-image/files/openspeckit/setup-openspeckit |
Adds repo bootstrapper for shared OpenSpec/Speckit agent context. |
devBenches/base-image/files/speckit-worktree/speckit-worktree-enable |
Adds Speckit worktree workflow bootstrap command. |
devBenches/base-image/files/speckit-worktree/templates/agents/skills/speckit-git-feature/SKILL.md |
Adds shared agent skill for Speckit git feature creation. |
devBenches/base-image/files/speckit-worktree/templates/claude/skills/speckit-git-feature/SKILL.md |
Adds Claude skill for Speckit git feature workflow. |
devBenches/base-image/files/speckit-worktree/templates/claude/skills/speckit-specify/SKILL.md |
Adds Claude skill for Speckit specify workflow. |
devBenches/base-image/files/speckit-worktree/templates/codex/skills/speckit-git-feature/SKILL.md |
Adds Codex wrapper skill for Speckit git feature workflow. |
devBenches/base-image/files/speckit-worktree/templates/codex/skills/speckit-git-feature/agents/openai.yaml |
Adds Codex agent metadata for git feature skill. |
devBenches/base-image/files/speckit-worktree/templates/codex/skills/speckit-specify/SKILL.md |
Adds Codex wrapper skill for Speckit specify workflow. |
devBenches/base-image/files/speckit-worktree/templates/codex/skills/speckit-specify/agents/openai.yaml |
Adds Codex agent metadata for specify skill. |
devBenches/base-image/files/speckit-worktree/templates/specify/extensions/git/README.md |
Documents the bundled Speckit git extension. |
devBenches/base-image/files/speckit-worktree/templates/specify/extensions/git/commands/speckit.git.commit.md |
Adds Speckit auto-commit command prompt. |
devBenches/base-image/files/speckit-worktree/templates/specify/extensions/git/commands/speckit.git.feature.md |
Adds Speckit feature checkout command prompt. |
devBenches/base-image/files/speckit-worktree/templates/specify/extensions/git/commands/speckit.git.initialize.md |
Adds Speckit git initialize command prompt. |
devBenches/base-image/files/speckit-worktree/templates/specify/extensions/git/commands/speckit.git.remote.md |
Adds Speckit remote detection command prompt. |
devBenches/base-image/files/speckit-worktree/templates/specify/extensions/git/commands/speckit.git.validate.md |
Adds Speckit branch validation command prompt. |
devBenches/base-image/files/speckit-worktree/templates/specify/extensions/git/config-template.yml |
Adds generic git extension config template. |
devBenches/base-image/files/speckit-worktree/templates/specify/extensions/git/extension.yml |
Defines bundled Speckit git extension hooks and commands. |
devBenches/base-image/files/speckit-worktree/templates/specify/extensions/git/git-config.yml |
Adds default git extension config. |
devBenches/base-image/files/speckit-worktree/templates/specify/extensions/git/scripts/bash/auto-commit.sh |
Adds Bash auto-commit helper. |
devBenches/base-image/files/speckit-worktree/templates/specify/extensions/git/scripts/bash/get-last-worktree.sh |
Adds Bash last-worktree lookup helper. |
devBenches/base-image/files/speckit-worktree/templates/specify/extensions/git/scripts/bash/git-common.sh |
Adds Bash git utility functions. |
devBenches/base-image/files/speckit-worktree/templates/specify/extensions/git/scripts/bash/initialize-repo.sh |
Adds Bash git initialization helper. |
devBenches/base-image/files/speckit-worktree/templates/specify/extensions/git/scripts/powershell/auto-commit.ps1 |
Adds PowerShell auto-commit helper. |
devBenches/base-image/files/speckit-worktree/templates/specify/extensions/git/scripts/powershell/git-common.ps1 |
Adds PowerShell git utility functions. |
devBenches/base-image/files/speckit-worktree/templates/specify/extensions/git/scripts/powershell/initialize-repo.ps1 |
Adds PowerShell git initialization helper. |
devBenches/base-image/files/speckit-worktree/templates/specify/shell/ct.zsh |
Adds per-repo ct wrapper template. |
devBenches/base-image/files/speckit-worktree/templates/specify/shell/select-worktree.sh |
Adds worktree selector helper. |
devBenches/base-image/files/speckit-worktree/templates/specify/shell/worktrees.sh |
Adds per-repo fallback worktree helpers. |
devBenches/base-image/install-ai-clis.sh |
Aligns devBench AI CLI install docs/logic with Grok removal and OpenCode upstream. |
devBenches/base-image/install-testing-tools.sh |
Adds Sonar tools and bumps testing utility versions. |
devBenches/cppBench/.devcontainer/devcontainer.json |
Chains Sonar MCP, Layer 3 ensure, and stale-container reconciliation. |
devBenches/cppBench/Dockerfile.layer2 |
Adds C++ coverage tooling and Sonar helper alias. |
devBenches/cppBench/README.md |
Documents C++ SonarCloud coverage workflow. |
devBenches/devcontainer.test/README.md |
Documents expanded devBench base test coverage. |
devBenches/devcontainer.test/test-ct-launchers.sh |
Adds ct launcher behavior tests. |
devBenches/devcontainer.test/test.sh |
Expands Layer 1a tests for spec, ct, Sonar, and PATH tooling. |
devBenches/goBench/.devcontainer/devcontainer.json |
Chains Sonar MCP, Layer 3 ensure, and stale-container reconciliation. |
devBenches/goBench/Dockerfile.layer2 |
Adds Go SonarCloud coverage helper and alias. |
devBenches/goBench/README.md |
Documents Go SonarCloud coverage workflow and pyBench naming. |
devBenches/goBench/files/sonarcloud-go-coverage |
Adds Go coverage and Sonar scanner wrapper. |
devBenches/javaBench/.devcontainer/devcontainer.json |
Chains Sonar MCP, Layer 3 ensure, and stale-container reconciliation. |
devBenches/javaBench/Dockerfile.layer2 |
Adds JaCoCo/SonarCloud helpers and aliases. |
devBenches/javaBench/README.md |
Documents Java SonarCloud coverage workflows. |
devBenches/pythonBench/.devcontainer/devcontainer.json |
Removes legacy pythonBench devcontainer. |
devBenches/pythonBench/.devcontainer/docker-compose.yml |
Removes legacy pythonBench compose file. |
devBenches/pythonBench/.env |
Removes legacy pythonBench environment file. |
devBenches/pythonBench/Dockerfile.layer2 |
Removes legacy pythonBench Layer 2 image. |
devBenches/pythonBench/scripts/build-layer.sh |
Removes legacy pythonBench build wrapper. |
devBenches/pythonBench/setup.sh |
Removes legacy pythonBench setup script. |
devBenches/scripts/ai-cli-adapter.sh |
Removes Grok support and filters unsupported configured providers. |
devBenches/scripts/ensure-sonarqube-mcp.sh |
Adds reusable SonarQube MCP/proxy startup script. |
devBenches/scripts/launchDevBench |
Adds PHP bench description/detection/help text. |
devBenches/scripts/update-devBench-project.sh |
Adds PHP project detection and pyBench naming. |
devBenches/scripts/workspace-type-detector.sh |
Adds PHP workspace indicators and TUI option. |
devcontainer.test/test.sh |
Updates yolo test for function implementation. |
docker-compose.mounts.yml |
Removes Grok mount and updates AI/spec CLI mount reference. |
docs/CONTAINER-ARCHITECTURE.md |
Updates Layer 0/1a tool ownership documentation. |
docs/MOUNTS-README.md |
Updates standard mounts, Grok removal, and spec CLI ownership docs. |
docs/newBench.md |
Updates new bench mount template with .agents and no Grok. |
docs/spec-driven-development.md |
Clarifies spec-driven tools are for developer benches. |
scripts/AI-PROVIDER-SETUP.md |
Removes Grok from provider documentation. |
scripts/configure-ai-priority.sh |
Removes Grok and filters unsupported providers from saved priority config. |
scripts/ensure-layer3.sh |
Reworks Layer 3 user/group validation without running containers. |
scripts/interactive-setup.sh |
Updates default bench list to pyBench. |
scripts/launchBench |
Adds PHP bench description. |
scripts/metadata-helper.sh |
Adds PHP sibling detection and pyBench naming. |
scripts/new-project.sh |
Updates AI prompt examples to pyBench. |
scripts/reconcile-devcontainer-container.sh |
Adds stale devcontainer reconciliation helper. |
scripts/setup-ui/src/utils/config.ts |
Updates UI default benches to pyBench. |
scripts/update-bench-config.sh |
Updates bench descriptions for pyBench and phpBench. |
scripts/update-project.sh |
Adds PHP indicators and updates prompt examples to pyBench. |
sysBenches/devcontainer.test/test.sh |
Updates yolo test for function implementation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| { | ||
| "name": "devBenches / javaBench", | ||
| "initializeCommand": "bash ${localWorkspaceFolder}/../../scripts/ensure-layer3.sh --base java-bench:latest", | ||
| "initializeCommand": "bash ${localWorkspaceFolder}/../../scripts/ensure-sonarqube-mcp.sh && bash ${localWorkspaceFolder}/../../scripts/ensure-layer3.sh --base java-bench:latest --user ${localEnv:USER} && bash ${localWorkspaceFolder}/../../scripts/reconcile-devcontainer-container.sh --container java-bench --image java-bench:${localEnv:USER}", |
| { | ||
| "name": "devBenches / goBench", | ||
| "initializeCommand": "bash ${localWorkspaceFolder}/../../scripts/ensure-layer3.sh --base go-bench:latest --chown /go", | ||
| "initializeCommand": "bash ${localWorkspaceFolder}/../../scripts/ensure-sonarqube-mcp.sh && bash ${localWorkspaceFolder}/../../scripts/ensure-layer3.sh --base go-bench:latest --chown /go --user ${localEnv:USER} && bash ${localWorkspaceFolder}/../../scripts/reconcile-devcontainer-container.sh --container go-bench --image go-bench:${localEnv:USER}", |
| { | ||
| "name": "devBenches / cppBench", | ||
| "initializeCommand": "bash ${localWorkspaceFolder}/../../scripts/ensure-layer3.sh --base cpp-bench:latest --chown /opt/vcpkg", | ||
| "initializeCommand": "bash ${localWorkspaceFolder}/../../scripts/ensure-sonarqube-mcp.sh && bash ${localWorkspaceFolder}/../../scripts/ensure-layer3.sh --base cpp-bench:latest --chown /opt/vcpkg --user ${localEnv:USER} && bash ${localWorkspaceFolder}/../../scripts/reconcile-devcontainer-container.sh --container cpp-bench --image cpp-bench:${localEnv:USER}", |
| # Example: | ||
| # source /home/brett/projects/ledgerlinc/ledgerlinc-model-ocr-pipeline/.specify/shell/ct.zsh | ||
|
|
||
| source /home/brett/projects/ledgerlinc/ledgerlinc-model-ocr-pipeline/.specify/shell/worktrees.sh |
| base_branch: main | ||
|
|
||
| # Parent directory for linked worktrees. Relative paths resolve from the repo root. | ||
| worktree_root: ../ledgerlinc-model-ocr-pipeline-worktrees |
| source /usr/local/share/ct/ct-functions.zsh | ||
|
|
||
| cd "$REPO_ROOT" | ||
| cta --claude-extra |
| if [ -f "$path" ] && grep -q 'speckit\.git\.feature' "$path"; then | ||
| return 0 | ||
| fi | ||
|
|
||
| backup_file "$path" | ||
| cat > "$path" <<'EOF' | ||
| installed: [] | ||
| settings: | ||
| auto_execute_hooks: true | ||
| hooks: | ||
| before_specify: | ||
| - extension: git | ||
| command: speckit.git.feature | ||
| enabled: true | ||
| optional: false | ||
| prompt: Execute speckit.git.feature? | ||
| description: Create feature checkout before specification | ||
| condition: null | ||
| EOF |
| write_git_config() { | ||
| local path="$repo_root/.specify/extensions/git/git-config.yml" | ||
|
|
||
| mkdir -p "$(dirname "$path")" |
| WORKTREE_ROOT=$(resolve_worktree_root "$REPO_ROOT") | ||
| LATEST_WORKTREE="" | ||
| if [ -d "$WORKTREE_ROOT" ]; then | ||
| LATEST_WORKTREE=$(find "$WORKTREE_ROOT" -maxdepth 1 -mindepth 1 -type d -printf '%T@ %p\n' 2>/dev/null | sort -nr | awk 'NR == 1 {print $2}') | ||
| fi |
| echo " - pyBench: Python projects" | ||
| echo " - javaBench: Java/Maven/Gradle projects" | ||
| echo " - dotNetBench: .NET/C# projects" | ||
| echo " - cppBench: C++/CMake projects" |
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 21cdc35cae
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| 4) | ||
| echo "php" | ||
| return 0 |
There was a problem hiding this comment.
Remove unsupported PHP workspace selection
Returning php from the TUI creates a dead-end in the current routing flow: new-workspace.sh, update-workspace.sh, and delete-workspace.sh only normalize frappe|flutter|dotnet, so a php selection is left unmapped and later resolves to a missing script path. This means users can be shown a valid-looking option that reliably fails at execution time; the selector should only surface types that have corresponding workspace handlers.
Useful? React with 👍 / 👎.
| cat > "$path" <<'EOF' | ||
| installed: [] | ||
| settings: | ||
| auto_execute_hooks: true | ||
| hooks: |
There was a problem hiding this comment.
Preserve existing extension config instead of overwriting it
When .specify/extensions.yml exists but does not yet contain speckit.git.feature, this function rewrites the entire file from a hard-coded template, which drops any pre-existing extension settings and hooks in that repo. In repositories already using other Specify extensions, running speckit-worktree-enable will silently remove those integrations; this should merge or append the new hook rather than replacing the whole config.
Useful? React with 👍 / 👎.
| if [ -d "$project_path/src" ] && find "$project_path/src" -name "*.php" -type f | head -1 >/dev/null 2>&1; then | ||
| php_confidence=$((php_confidence + 15)) |
There was a problem hiding this comment.
Check PHP source matches before adding confidence
This condition always succeeds when src/ exists, because head -1 returns success even when find outputs no matches; as a result, non-PHP projects with a src folder still get a +15 PHP boost. That inflates phpBench scoring and can misclassify mixed or non-PHP repos during bench detection.
Useful? React with 👍 / 👎.
| if [ $php_confidence -gt $max_confidence ]; then | ||
| max_confidence=$php_confidence | ||
| best_bench="phpBench" |
There was a problem hiding this comment.
Avoid selecting phpBench before phpBench support exists
This new branch can pick phpBench as the best match, but this repository currently has no devBenches/phpBench updater script, so the workflow deterministically fails in delegation for PHP projects after successful detection. The detector should only emit bench names that have runnable update handlers (or guard with an availability check before assigning phpBench).
Useful? React with 👍 / 👎.
| { | ||
| "name": "devBenches / javaBench", | ||
| "initializeCommand": "bash ${localWorkspaceFolder}/../../scripts/ensure-layer3.sh --base java-bench:latest", | ||
| "initializeCommand": "bash ${localWorkspaceFolder}/../../scripts/ensure-sonarqube-mcp.sh && bash ${localWorkspaceFolder}/../../scripts/ensure-layer3.sh --base java-bench:latest --user ${localEnv:USER} && bash ${localWorkspaceFolder}/../../scripts/reconcile-devcontainer-container.sh --container java-bench --image java-bench:${localEnv:USER}", |
There was a problem hiding this comment.
Provide fallback when localEnv USER is unset
The initialize command now hardcodes ${localEnv:USER} into --user and image tags; Dev Container variable substitution leaves unset host vars empty, so hosts that expose USERNAME (or no USER) will pass an empty value and break ensure-layer3.sh argument parsing before startup. Add a default/fallback (${localEnv:USER:${localEnv:USERNAME}}) or remove the required --user dependency.
Useful? React with 👍 / 👎.
|
@codex review |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 87 out of 88 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (1)
devBenches/cppBench/.devcontainer/devcontainer.json:90
- Grok has been removed from the supported provider list and the standard mount documentation in this PR, but this bench still keeps the Grok credential mount. Remove this stale mount and comment so the devcontainer matches the supported AI CLI inventory and doesn't require an unused host path.
| fi | ||
|
|
||
| mkdir -p "$target" | ||
| cp -a "$source/." "$target/" |
| log_info "PHP PHPUnit project detected: 85% confidence" >&2 | ||
| fi | ||
|
|
||
| if [ -d "$project_path/src" ] && find "$project_path/src" -name "*.php" -type f | head -1 >/dev/null 2>&1; then |
| "source=${localEnv:HOME}/.codex,target=/home/${localEnv:USER}/.codex,type=bind,consistency=cached", | ||
| "source=${localEnv:HOME}/.config/sonarqube,target=/home/${localEnv:USER}/.config/sonarqube,type=bind,readonly", | ||
| "source=${localEnv:HOME}/.gemini,target=/home/${localEnv:USER}/.gemini,type=bind,consistency=cached", | ||
| "source=${localEnv:HOME}/.grok,target=/home/${localEnv:USER}/.grok,type=bind,readonly", |
| // Grok (xAI) | ||
| "source=${localEnv:HOME}/.grok,target=/home/${localEnv:USER}/.grok,type=bind,readonly", |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 373a7e8f58
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| COPY files/jacoco-cli /usr/local/bin/jacoco-cli | ||
| COPY files/sonarcloud-java-maven /usr/local/bin/sonarcloud-java-maven | ||
| COPY files/sonarcloud-java-gradle /usr/local/bin/sonarcloud-java-gradle |
There was a problem hiding this comment.
Add missing Java helper scripts before copying
These COPY instructions reference files/jacoco-cli, files/sonarcloud-java-maven, and files/sonarcloud-java-gradle, but those paths are not present in this commit, so building java-bench will fail during Docker build when Docker cannot find the sources in the build context. Because this happens at image build time, every Java bench rebuild is blocked until the files are added (or the COPY lines are removed).
Useful? React with 👍 / 👎.
| lizard \ | ||
| || echo "⚠️ Some Python C++ tools failed, skipping" | ||
|
|
||
| COPY files/sonarcloud-cpp-gcovr /usr/local/bin/sonarcloud-cpp-gcovr |
There was a problem hiding this comment.
Include C++ Sonar coverage script in repository
This COPY expects files/sonarcloud-cpp-gcovr, but that file is not added anywhere in the commit, so cpp-bench image builds fail immediately when Docker tries to resolve this source path. Since the Dockerfile now unconditionally copies it, the C++ bench layer cannot be rebuilt successfully without adding the missing script or removing this step.
Useful? React with 👍 / 👎.
| if ! timeout 30s docker create --name "$check_name" "$image" >/dev/null; then | ||
| status=1 | ||
| elif ! timeout 30s docker cp "$check_name:$file" "$output" >/dev/null 2>&1; then | ||
| status=1 |
There was a problem hiding this comment.
Avoid hard dependency on GNU timeout in host init
ensure-layer3.sh now calls timeout in the fast-path image checks, and this script is invoked by initializeCommand (host-side) in the updated devcontainer configs; on macOS hosts, timeout is typically unavailable by default, so these checks fail and the script falls through to rebuilding Layer 3 images on each startup instead of using the up-to-date image. This introduces repeated unnecessary rebuilds and significantly slows container startup for those environments.
Useful? React with 👍 / 👎.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 437a5b1831
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| log_info "PHP PHPUnit project detected: 85% confidence" >&2 | ||
| fi | ||
|
|
||
| if [ -d "$project_path/src" ] && find "$project_path/src" -name "*.php" -type f | head -1 >/dev/null 2>&1; then |
There was a problem hiding this comment.
Check PHP file existence using find output, not head status
The PHP confidence boost currently triggers whenever src/ exists, even if there are no PHP files, because find ... | head -1 >/dev/null returns the exit status of head (success on empty input) in this script (set -e but no pipefail). That inflates php_confidence by +15 for non-PHP projects with a src folder and can cause incorrect bench selection (for example preferring phpBench over the actual language bench). Use a test that depends on actual output (e.g., command substitution with -n, find ... -print -quit | grep -q ., or enable pipefail).
Useful? React with 👍 / 👎.
| fi | ||
|
|
||
| mkdir -p "$target" | ||
| cp -a "$source/." "$target/" |
There was a problem hiding this comment.
Honor --force when overlaying existing template files
copy_overlay_dir overwrites existing files even when --force is not set, because cp -a "$source/." "$target/" replaces matching paths by default. In repositories that already customized .specify scripts or skill files, rerunning speckit-worktree-enable will silently clobber those edits despite the CLI contract that --force is what should replace existing managed files.
Useful? React with 👍 / 👎.
| if ! timeout 30s docker create --name "$check_name" "$image" >/dev/null; then | ||
| status=1 | ||
| elif ! timeout 30s docker cp "$check_name:$file" "$output" >/dev/null 2>&1; then |
There was a problem hiding this comment.
Remove non-portable timeout from host-side layer checks
ensure-layer3.sh is executed via initializeCommand on the host, but copy_image_file now unconditionally calls GNU timeout. On hosts where timeout is unavailable (common outside GNU userlands), those checks fail and the fast-path validation always treats the cached user image as invalid, forcing unnecessary Layer 3 rebuilds on every startup. Guard for timeout availability or use a portable fallback so host checks don’t regress.
Useful? React with 👍 / 👎.
| { | ||
| "name": "devBenches / goBench", | ||
| "initializeCommand": "bash ${localWorkspaceFolder}/../../scripts/ensure-layer3.sh --base go-bench:latest --chown /go", | ||
| "initializeCommand": "bash ${localWorkspaceFolder}/../scripts/ensure-sonarqube-mcp.sh && bash ${localWorkspaceFolder}/../../scripts/ensure-layer3.sh --base go-bench:latest --chown /go --user ${localEnv:USER} && bash ${localWorkspaceFolder}/../../scripts/reconcile-devcontainer-container.sh --container go-bench --image go-bench:${localEnv:USER}", |
There was a problem hiding this comment.
Add default for localEnv USER in initializeCommand
The new initialize command hardcodes ${localEnv:USER} for both --user and the expected image tag, but unlike your compose files it has no fallback (for example ${USER:-brett}). If USER is absent in the host environment, this expands to an empty value, which can break argument parsing in ensure-layer3.sh and produce an invalid expected tag for reconciliation. Add a fallback/defaulted variable to keep startup robust across host environments.
Useful? React with 👍 / 👎.
|
@codex review |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 90 out of 91 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (1)
devBenches/cppBench/.devcontainer/devcontainer.json:90
- Grok has been removed from the installer, provider priority, adapter, and canonical mount docs, but this devcontainer still retains the Grok credential mount/comment. Remove the stale Grok mount here so the bench matches the supported AI provider set and does not keep depending on a deprecated credential path.
| COPY files/jacoco-cli /usr/local/bin/jacoco-cli | ||
| COPY files/sonarcloud-java-maven /usr/local/bin/sonarcloud-java-maven | ||
| COPY files/sonarcloud-java-gradle /usr/local/bin/sonarcloud-java-gradle |
| COPY files/sonarcloud-cpp-gcovr /usr/local/bin/sonarcloud-cpp-gcovr | ||
| RUN chmod +x /usr/local/bin/sonarcloud-cpp-gcovr |
| // Grok (xAI) | ||
| "source=${localEnv:HOME}/.grok,target=/home/${localEnv:USER}/.grok,type=bind,readonly", |
| "source=${localEnv:HOME}/.codex,target=/home/${localEnv:USER}/.codex,type=bind,consistency=cached", | ||
| "source=${localEnv:HOME}/.config/sonarqube,target=/home/${localEnv:USER}/.config/sonarqube,type=bind,readonly", | ||
| "source=${localEnv:HOME}/.gemini,target=/home/${localEnv:USER}/.gemini,type=bind,consistency=cached", | ||
| "source=${localEnv:HOME}/.grok,target=/home/${localEnv:USER}/.grok,type=bind,readonly", |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d7c8457178
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| log_info "PHP PHPUnit project detected: 85% confidence" >&2 | ||
| fi | ||
|
|
||
| if [ -d "$project_path/src" ] && find "$project_path/src" -name "*.php" -type f | head -1 >/dev/null 2>&1; then |
There was a problem hiding this comment.
Gate PHP confidence boost on actual PHP files
The new PHP heuristic always adds 15% confidence for any project that has a src/ directory, even when there are no *.php files. In this pipeline, head -1 exits successfully on empty input, so the if condition passes as long as src/ exists. That can skew bench selection toward phpBench for non-PHP repositories with sparse signals. Please make this check depend on actual matches (for example, by checking non-empty find output).
Useful? React with 👍 / 👎.
| @@ -0,0 +1,61 @@ | |||
| #!/bin/bash | |||
There was a problem hiding this comment.
Make stale-container reconciliation script executable
This new helper has a shebang and lives under scripts/, but it was added with mode 0644 instead of executable permissions. Running it directly (for example from automation or a hook as scripts/reconcile-devcontainer-container.sh ...) will fail with Permission denied, so stale container cleanup won’t run unless every caller wraps it with bash.
Useful? React with 👍 / 👎.
|
|
||
| ${YELLOW}ARGUMENTS:${NC} | ||
| BENCH_TYPE Direct bench selection (flutter, dotnet, python, java, cpp) | ||
| BENCH_TYPE Direct bench selection (flutter, dotnet, python, java, cpp, php) |
There was a problem hiding this comment.
Align Python bench selector with pyBench naming
The usage text still advertises python as a direct BENCH_TYPE, but bench names are derived from directory names by stripping Bench (so pyBench becomes py). With the new pyBench naming, users following this help text will pass python, which won’t match available benches and is rejected. Add a python alias or update the advertised selector to the actual accepted token.
Useful? React with 👍 / 👎.
| if ! timeout 30s docker create --name "$check_name" "$image" >/dev/null; then | ||
| status=1 | ||
| elif ! timeout 30s docker cp "$check_name:$file" "$output" >/dev/null 2>&1; then |
There was a problem hiding this comment.
Avoid GNU-only timeout in host-side layer3 fast path
ensure-layer3.sh now depends on timeout in its fast-path image checks, but this script runs from Dev Container initializeCommand on the host (see updated go/java/cpp devcontainer configs). On hosts without GNU timeout (common on macOS), these checks fail and the script falls through to rebuilding layer3 every time instead of exiting early, causing repeated slow rebuilds on each open/reconnect.
Useful? React with 👍 / 👎.
| log_info "" | ||
|
|
||
| required_clis=(claude codex gemini opencode) | ||
| required_clis=(claude codex gemini agy opencode) |
There was a problem hiding this comment.
Keep Antigravity optional or stop claiming non-fatal install
The Antigravity install branch logs installation failed (continuing), but agy is now included in required_clis, so any transient failure downloading/installing Antigravity now hard-fails the whole base image build at the final required-tools check. Either remove agy from the required set or treat its installation failure as fatal at the failure site to keep behavior consistent.
Useful? React with 👍 / 👎.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d52f633e8c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| "source=${localEnv:HOME}/.claude.json,target=/home/${localEnv:USER}/.claude.json,type=bind,consistency=cached", | ||
| // Codex (OpenAI) | ||
| "source=${localEnv:HOME}/.codex,target=/home/${localEnv:USER}/.codex,type=bind,consistency=cached", | ||
| "source=${localEnv:HOME}/.config/sonarqube,target=/home/${localEnv:USER}/.config/sonarqube,type=bind,readonly", |
There was a problem hiding this comment.
Make SonarQube credential mount optional
This new bind mount can prevent the devcontainer from starting on hosts that have not created ~/.config/sonarqube yet. With type=bind mount syntax, Docker errors when the source path is missing, so users without SonarQube setup will fail before the container launches. Since SonarQube credentials are optional in this workflow, gate this mount behind an existence check or ensure the directory is created ahead of startup (the same pattern was added in the Go/Java devcontainer configs too).
Useful? React with 👍 / 👎.
| if ! timeout 30s docker create --name "$check_name" "$image" >/dev/null; then | ||
| status=1 | ||
| elif ! timeout 30s docker cp "$check_name:$file" "$output" >/dev/null 2>&1; then | ||
| status=1 |
There was a problem hiding this comment.
Guard timeout usage in ensure-layer3 fast path
The cache-check path now hard-depends on timeout for docker create/docker cp. On hosts where timeout is unavailable (common on default macOS shells), these checks fail, copy_image_file returns failure, and the script always treats the user image as invalid, forcing expensive Layer 3 rebuilds on every startup. Add a fallback when timeout is missing (or skip the timeout wrapper) so the up-to-date fast path still works.
Useful? React with 👍 / 👎.
| { | ||
| "name": "devBenches / cppBench", | ||
| "initializeCommand": "bash ${localWorkspaceFolder}/../../scripts/ensure-layer3.sh --base cpp-bench:latest --chown /opt/vcpkg", | ||
| "initializeCommand": "bash ${localWorkspaceFolder}/../scripts/ensure-sonarqube-mcp.sh && bash ${localWorkspaceFolder}/../../scripts/ensure-layer3.sh --base cpp-bench:latest --chown /opt/vcpkg --user ${localEnv:USER} && bash ${localWorkspaceFolder}/../../scripts/reconcile-devcontainer-container.sh --container cpp-bench --image cpp-bench:${localEnv:USER}", |
There was a problem hiding this comment.
Avoid hard-coding ${localEnv:USER} in initializeCommand
Passing --user ${localEnv:USER} assumes the host always defines USER; on platforms/shells where it is unset (common on Windows hosts), this expands to an empty value and produces invalid image tags like cpp-bench: in both ensure-layer3.sh and reconcile-devcontainer-container.sh, breaking initialization before the container starts. Keep the script default (whoami) or provide a fallback variable so startup remains cross-platform.
Useful? React with 👍 / 👎.
| COMPOSE_IGNORE_ORPHANS=True docker compose \ | ||
| -p "$COMPOSE_PROJECT_NAME" \ | ||
| -f "$COMPOSE_FILE" \ | ||
| up -d |
There was a problem hiding this comment.
Check for docker compose plugin before invoking it
The script only verifies docker exists, then unconditionally runs docker compose up -d; on hosts with Docker Engine but without the Compose plugin, this exits non-zero and causes initializeCommand to fail. Since this helper is now chained into bench startup, add an explicit docker compose version capability check (and skip gracefully when absent) to avoid blocking container launch for users who don’t have Compose installed.
Useful? React with 👍 / 👎.
| 4) | ||
| echo "php" | ||
| return 0 |
There was a problem hiding this comment.
Prevent unsupported PHP type from manual detector output
The manual workspace selector now returns php, but the workspace router scripts (new-workspace.sh, update-workspace.sh, delete-workspace.sh) still only map Frappe/Flutter/.NET creators/updaters/deleters. In no-AI mode, selecting option 4 leads to an unmapped type and downstream "script not found" failures instead of a valid workflow. Either add PHP routing support alongside this option or suppress the PHP choice until corresponding workspace scripts exist.
Useful? React with 👍 / 👎.
|
|
||
| ${YELLOW}ARGUMENTS:${NC} | ||
| BENCH_TYPE Direct bench selection (flutter, dotnet, python, java, cpp) | ||
| BENCH_TYPE Direct bench selection (flutter, dotnet, python, java, cpp, php) |
There was a problem hiding this comment.
Accept pyBench naming in launchDevBench bench argument
After the bench rename to pyBench, bench discovery normalizes the directory name to py (${bench_name%Bench}), but the CLI contract still documents and expects python. As a result, users following the help text can pass launchDevBench python and hit the unknown-bench path even when pyBench is installed. Add an alias map (python -> py) or switch discovery/argument handling to preserve the new bench name consistently.
Useful? React with 👍 / 👎.
| COPY files/jacoco-cli /usr/local/bin/jacoco-cli | ||
| COPY files/sonarcloud-java-maven /usr/local/bin/sonarcloud-java-maven | ||
| COPY files/sonarcloud-java-gradle /usr/local/bin/sonarcloud-java-gradle |
| COPY files/sonarcloud-cpp-gcovr /usr/local/bin/sonarcloud-cpp-gcovr | ||
| RUN chmod +x /usr/local/bin/sonarcloud-cpp-gcovr |
| "source=${localEnv:HOME}/.claude,target=/home/${localEnv:USER}/.claude,type=bind,consistency=cached", | ||
| "source=${localEnv:HOME}/.claude.json,target=/home/${localEnv:USER}/.claude.json,type=bind,consistency=cached", | ||
| "source=${localEnv:HOME}/.codex,target=/home/${localEnv:USER}/.codex,type=bind,consistency=cached", | ||
| "source=${localEnv:HOME}/.config/sonarqube,target=/home/${localEnv:USER}/.config/sonarqube,type=bind,readonly", |
| "source=${localEnv:HOME}/.claude,target=/home/${localEnv:USER}/.claude,type=bind,consistency=cached", | ||
| "source=${localEnv:HOME}/.claude.json,target=/home/${localEnv:USER}/.claude.json,type=bind,consistency=cached", | ||
| "source=${localEnv:HOME}/.codex,target=/home/${localEnv:USER}/.codex,type=bind,consistency=cached", | ||
| "source=${localEnv:HOME}/.config/sonarqube,target=/home/${localEnv:USER}/.config/sonarqube,type=bind,readonly", |
| "source=${localEnv:HOME}/.claude.json,target=/home/${localEnv:USER}/.claude.json,type=bind,consistency=cached", | ||
| // Codex (OpenAI) | ||
| "source=${localEnv:HOME}/.codex,target=/home/${localEnv:USER}/.codex,type=bind,consistency=cached", | ||
| "source=${localEnv:HOME}/.config/sonarqube,target=/home/${localEnv:USER}/.config/sonarqube,type=bind,readonly", |
Summary
Validation
Summary by Sourcery
Align shared base and devBench tooling for AI/spec CLIs, SonarQube integrations, and spec-kit workflows while adding PHP bench support and improving workspace detection and tests.
New Features:
Bug Fixes:
Enhancements:
Build:
Documentation:
Tests:
Chores: