fix(vscode): harden Copilot agent install#738
Conversation
d9426b4 to
cbc7686
Compare
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds VS Code Copilot native SDD sub-agent support, VS Code model assignment persistence and rendering, managed Claude agent visibility updates, uninstall restore handling, and cross-platform atomic file replacement. Documentation now describes the VS Code Copilot SDD flow and model-assignment fallback behavior. ChangesVS Code Copilot SDD Agents
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (3 warnings)
✅ Passed checks (2 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/app/app.go`:
- Around line 749-751: The current code for VSCodeModelAssignments only handles
the case when the map is non-empty, but it lacks handling for the explicit
"reset to defaults" signal when the map is non-nil but empty. Add an else branch
to the existing if condition that checks len(selection.VSCodeModelAssignments) >
0. In this else branch, set current.VSCodeModelAssignments to nil to clear it
when an explicit empty map is provided. This else branch should mirror the
pattern already implemented for other assignment maps like
ClaudeModelAssignments to maintain consistent nil vs empty-map override
semantics throughout the function.
In `@internal/assets/assets_test.go`:
- Around line 577-579: The substring match check using strings.Contains in the
frontmatterKeyLine(frontmatter, "tools") validation will incorrectly flag tool
names containing "agent" as a substring. Parse the tools line to extract
individual tool names and check for an exact match of "agent" rather than using
substring matching. This can be done by splitting the tools string by commas or
spaces and checking if "agent" is one of the resulting exact tool names.
- Around line 693-701: The current implementation in requireAgentsAllowlist uses
a fragile string count check that assumes 2-space YAML indentation. While this
is acceptable for controlled embedded assets as noted in the comment, document
this known limitation by adding a code comment above the Count check explaining
why this specific format assumption is acceptable in this context and what would
need to change if YAML formatting requirements evolve in the future.
- Around line 548-586: The sdd-orchestrator.agent.md file is missing the
required agent tool declaration in its frontmatter. The test
TestVSCodeNativeAgentAssetsFrontmatter validates this requirement via the
requireInlineTool call for the coordinator agent, which checks for the presence
of the agent tool. Add the agent tool to the frontmatter of the orchestrator
agent asset file to match the requirement being validated by the test and ensure
consistency with the phase agents that do include this tool.
In `@internal/cli/sync_test.go`:
- Around line 2092-2119: The
TestRunSyncWithSelectionPropagatesVSCodeModelWarnings test lacks explanatory
comments about why it uses a fresh temp home directory and what behavior is
expected. Add a comment block immediately before the RunSyncWithSelection
function call that explains the test setup: the fresh temp home has no models
cache, which makes the VSCode model assignments unvalidated, and the sync should
emit a cache warning while omitting the model line from the generated agent
file.
In `@internal/cli/sync.go`:
- Around line 803-812: The function stateModelAssignmentsToModel is defined
identically in two separate files, creating unnecessary duplication. Remove the
duplicate definition from one of the locations and either move the function to a
shared package location (such as within the state or model package) or keep it
in one place and update the other location to import and use the centralized
version instead. This ensures a single source of truth and prevents
inconsistencies if the function logic needs to be updated in the future.
In `@internal/components/sdd/vscode_agent_visibility.go`:
- Around line 15-52: The function hideManagedClaudeInternalAgentsForVSCode
modifies user config files without creating backups, violating the backup
requirement for user config modifications. Before calling
filemerge.WriteFileAtomic for each file that gets modified by
hideClaudeAgentFromVSCodePicker, create a backup of the original file content.
Track the backups created (likely in the InjectionResult or a similar structure)
so their paths can be returned or used for restoration. Additionally, create a
companion restore function that reverts the modified files back to their
backed-up versions, similar to how injection functions typically have
corresponding undo/restore counterparts.
In `@internal/state/state.go`:
- Line 148: The mergeExplicitAgentInstallState function currently restores
several model assignment fields from newState when non-nil (ModelAssignments,
ClaudeModelAssignments, KiroModelAssignments, CodexModelAssignments,
CodexCarrilModelAssignments, CodexPhaseModelAssignments, and Persona), but it
fails to restore VSCodeModelAssignments. Add a check in the
mergeExplicitAgentInstallState function that restores VSCodeModelAssignments
from newState when it is non-nil, following the same pattern used for the other
model assignment fields being restored from newState.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: e9115036-799f-4966-87be-bcc583bdd147
⛔ Files ignored due to path filters (9)
testdata/golden/sdd-claude-agent-sdd-apply.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-archive.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-design.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-explore.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-propose.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-spec.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-tasks.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-verify.goldenis excluded by!testdata/**testdata/golden/sdd-vscode-instructions.goldenis excluded by!testdata/**
📒 Files selected for processing (51)
README.mddocs/agents.mdgo.modinternal/agents/vscode/adapter.gointernal/agents/vscode/adapter_test.gointernal/app/app.gointernal/app/app_test.gointernal/assets/assets.gointernal/assets/assets_test.gointernal/assets/claude/agents/jd-fix-agent.mdinternal/assets/claude/agents/jd-judge-a.mdinternal/assets/claude/agents/jd-judge-b.mdinternal/assets/claude/agents/sdd-apply.mdinternal/assets/claude/agents/sdd-archive.mdinternal/assets/claude/agents/sdd-design.mdinternal/assets/claude/agents/sdd-explore.mdinternal/assets/claude/agents/sdd-init.mdinternal/assets/claude/agents/sdd-onboard.mdinternal/assets/claude/agents/sdd-propose.mdinternal/assets/claude/agents/sdd-spec.mdinternal/assets/claude/agents/sdd-tasks.mdinternal/assets/claude/agents/sdd-verify.mdinternal/assets/vscode/agents/sdd-apply.agent.mdinternal/assets/vscode/agents/sdd-archive.agent.mdinternal/assets/vscode/agents/sdd-design.agent.mdinternal/assets/vscode/agents/sdd-explore.agent.mdinternal/assets/vscode/agents/sdd-init.agent.mdinternal/assets/vscode/agents/sdd-onboard.agent.mdinternal/assets/vscode/agents/sdd-orchestrator.agent.mdinternal/assets/vscode/agents/sdd-propose.agent.mdinternal/assets/vscode/agents/sdd-spec.agent.mdinternal/assets/vscode/agents/sdd-tasks.agent.mdinternal/assets/vscode/agents/sdd-verify.agent.mdinternal/cli/install_test.gointernal/cli/run.gointernal/cli/sync.gointernal/cli/sync_test.gointernal/components/filemerge/replace_default.gointernal/components/filemerge/replace_windows.gointernal/components/filemerge/writer.gointernal/components/filemerge/writer_test.gointernal/components/sdd/inject.gointernal/components/sdd/inject_test.gointernal/components/sdd/vscode_agent_visibility.gointernal/components/sdd/vscode_models.gointernal/components/sdd/vscode_models_test.gointernal/components/uninstall/service_test.gointernal/model/selection.gointernal/model/selection_test.gointernal/state/state.gointernal/state/state_test.go
cbc7686 to
b1ae7f1
Compare
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
internal/components/filemerge/writer.go (1)
96-105: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy liftAdd rollback/backup handling around the committed replace.
After Line 96 swaps the temp file into place, Lines 103-105 can still return an error. Callers then see a failed write even though the user config was already mutated and the previous contents are gone.
internal/components/sdd/inject.gouses this helper for user-owned VS Code/Copilot config files, so the overwrite path still has no restore route if the final sync fails or the install aborts mid-flight.As per path instructions, "Any write to user config must have a backup/restore path."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/components/filemerge/writer.go` around lines 96 - 105, The committed replace in writer.go can still fail after replaceFileAtomic has already swapped the temp file into place, leaving user-owned config mutated without any restore path. Update the write flow around writeFileAtomic/replaceFileAtomic and the final syncDirFn call to create and retain a backup of the original file before the swap, then restore or roll back from that backup if sync or later steps fail. Make sure the recovery path is wired through the helper used by internal/components/sdd/inject.go so user config writes always have backup/restore handling.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@go.mod`:
- Line 11: Update the golang.org/x/sys dependency in go.mod from v0.38.0 to
v0.44.0 or newer to remove the vulnerable version. After bumping the module,
ensure any code that depends on golang.org/x/sys/windows, especially
internal/components/filemerge/replace_windows.go, still builds and resolves
against the updated dependency.
In `@internal/assets/assets_test.go`:
- Around line 635-637: The helper is using a prefix heuristic that can drift
from the actual runtime contract. Update isClaudeInternalAgentName to check
against the same fixed managed filename set used by the runtime logic in
vscode_agent_visibility.go, instead of matching all sdd-* / jd-* names. Reuse
the existing managed list/constant or shared helper so this test stays aligned
with the install/uninstall behavior.
In `@internal/cli/sync.go`:
- Around line 994-1000: Preserve the nil-vs-empty semantics for
VSCodeModelAssignments in sync selection handling: the current len(...) check in
the VSCode assignment merge logic treats nil and an explicit empty map the same,
which breaks the override contract described in selection.go. Update the sync
path around the persistedState.VSCodeModelAssignments merge so only a nil
selection map is backfilled from state, while a non-nil empty map remains an
intentional reset to defaults; keep the behavior localized to the selection
population logic that builds selection.VSCodeModelAssignments.
In `@internal/components/sdd/vscode_agent_visibility.go`:
- Around line 68-77: The restore/cleanup path in the backup handling block is
swallowing failures, so fix the logic around os.Stat, filemerge.WriteFileAtomic,
and os.Remove in vscode_agent_visibility.go to surface any restore or cleanup
errors instead of treating them as success. Only ignore the explicit not-exist
case for the backup check, return wrapped errors for unexpected stat/read/write
failures, and do not discard the os.Remove(backupPath) result so callers know
when the Claude agent restore or backup cleanup did not complete.
In `@internal/components/sdd/vscode_models.go`:
- Around line 143-167: The warnings emitted by loadVSCodeModelCatalog are still
unique per agentKey, so dedupWarnings cannot collapse shared cache failures.
Update loadVSCodeModelCatalog to return normalized cache-level warning strings
that omit agent-specific data while preserving the failure reason and cache
path, and keep the agentKey only at the call site if needed for context. Make
the same normalization in the other matching catalog-load path mentioned in the
diff so identical model-cache failures dedupe correctly across phases.
In `@internal/components/uninstall/service.go`:
- Around line 539-541: The uninstall flow in
restoreClaudeVisibilityBackupOperation appends a write that restores Claude
agent files and deletes .backup files, but those paths are not being captured in
targets for rollback. Update the scheduling logic around adapter.Agent() ==
model.AgentVSCodeCopilot to snapshot the affected ~/.claude/agents/* files and
the corresponding backup files before the write is added, so any later failure
can restore them cleanly.
---
Outside diff comments:
In `@internal/components/filemerge/writer.go`:
- Around line 96-105: The committed replace in writer.go can still fail after
replaceFileAtomic has already swapped the temp file into place, leaving
user-owned config mutated without any restore path. Update the write flow around
writeFileAtomic/replaceFileAtomic and the final syncDirFn call to create and
retain a backup of the original file before the swap, then restore or roll back
from that backup if sync or later steps fail. Make sure the recovery path is
wired through the helper used by internal/components/sdd/inject.go so user
config writes always have backup/restore handling.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 27140f52-4ac2-4027-b1ea-e990a3e591fb
⛔ Files ignored due to path filters (9)
testdata/golden/sdd-claude-agent-sdd-apply.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-archive.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-design.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-explore.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-propose.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-spec.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-tasks.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-verify.goldenis excluded by!testdata/**testdata/golden/sdd-vscode-instructions.goldenis excluded by!testdata/**
📒 Files selected for processing (39)
README.mddocs/agents.mdgo.modinternal/app/app.gointernal/app/app_test.gointernal/assets/assets_test.gointernal/assets/claude/agents/jd-fix-agent.mdinternal/assets/claude/agents/jd-judge-a.mdinternal/assets/claude/agents/jd-judge-b.mdinternal/assets/claude/agents/sdd-apply.mdinternal/assets/claude/agents/sdd-archive.mdinternal/assets/claude/agents/sdd-design.mdinternal/assets/claude/agents/sdd-explore.mdinternal/assets/claude/agents/sdd-init.mdinternal/assets/claude/agents/sdd-onboard.mdinternal/assets/claude/agents/sdd-propose.mdinternal/assets/claude/agents/sdd-spec.mdinternal/assets/claude/agents/sdd-tasks.mdinternal/assets/claude/agents/sdd-verify.mdinternal/cli/install_test.gointernal/cli/run.gointernal/cli/run_state_test.gointernal/cli/sync.gointernal/cli/sync_test.gointernal/components/filemerge/replace_default.gointernal/components/filemerge/replace_windows.gointernal/components/filemerge/writer.gointernal/components/filemerge/writer_test.gointernal/components/sdd/inject.gointernal/components/sdd/inject_test.gointernal/components/sdd/vscode_agent_visibility.gointernal/components/sdd/vscode_agent_visibility_test.gointernal/components/sdd/vscode_models.gointernal/components/sdd/vscode_models_test.gointernal/components/uninstall/service.gointernal/model/selection.gointernal/model/selection_test.gointernal/state/state.gointernal/state/state_test.go
| github.com/charmbracelet/lipgloss v1.1.0 | ||
| github.com/mattn/go-isatty v0.0.20 | ||
| github.com/rivo/uniseg v0.4.7 | ||
| golang.org/x/sys v0.38.0 |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
What is the first patched version for GO-2026-5024 in golang.org/x/sys, and is v0.38.0 affected?
💡 Result:
The first patched version for GO-2026-5024 (also tracked as CVE-2026-39824) in the golang.org/x/sys module is v0.44.0 [1][2][3]. Yes, v0.38.0 is affected by this vulnerability because it is below the patched version of v0.44.0 [1][4][5]. The vulnerability involves an integer overflow in the NewNTUnicodeString function within the golang.org/x/sys/windows package [1][2][4].
Citations:
- 1: https://pkg.go.dev/vuln/GO-2026-5024
- 2: https://osv.dev/vulnerability/CVE-2026-39824
- 3: fix: bump x/sys to v0.44.0 + Go 1.25 to clear GO-2026-5024 (#12) schubydoo/claustrum#86
- 4: https://www.resolvedsecurity.com/vulnerability-catalog/CVE-2026-39824
- 5: https://pkg.go.dev/golang.org/x/sys@v0.38.0
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== go.mod ==\n'
cat -n go.mod | sed -n '1,40p'
printf '\n== replace_windows.go ==\n'
cat -n internal/components/filemerge/replace_windows.go | sed -n '1,120p'Repository: Gentleman-Programming/gentle-ai
Length of output: 2390
Bump golang.org/x/sys to v0.44.0 or newer. v0.38.0 is affected by GO-2026-5024/CVE-2026-39824, and internal/components/filemerge/replace_windows.go imports golang.org/x/sys/windows directly.
🧰 Tools
🪛 OSV Scanner (2.4.0)
[LOW] 11-11: golang.org/x/sys 0.38.0: Invoking integer overflow in NewNTUnicodeString in golang.org/x/sys/windows
(GO-2026-5024)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@go.mod` at line 11, Update the golang.org/x/sys dependency in go.mod from
v0.38.0 to v0.44.0 or newer to remove the vulnerable version. After bumping the
module, ensure any code that depends on golang.org/x/sys/windows, especially
internal/components/filemerge/replace_windows.go, still builds and resolves
against the updated dependency.
Source: Linters/SAST tools
| if len(selection.VSCodeModelAssignments) == 0 && len(persistedState.VSCodeModelAssignments) > 0 { | ||
| m := make(map[string]model.ModelAssignment, len(persistedState.VSCodeModelAssignments)) | ||
| for k, v := range persistedState.VSCodeModelAssignments { | ||
| m[k] = model.ModelAssignment{ProviderID: v.ProviderID, ModelID: v.ModelID, Effort: v.Effort} | ||
| } | ||
| selection.VSCodeModelAssignments = m | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Preserve the nil-vs-empty override contract for VS Code assignments.
internal/model/selection.go documents VSCodeModelAssignments as nil = no override and non-nil empty map = reset to defaults. This len(...) == 0 check collapses both cases, so an explicit clear still reloads assignments from state.json and sync never returns the generated .agent.md files to default-model behavior.
Suggested fix
- if len(selection.VSCodeModelAssignments) == 0 && len(persistedState.VSCodeModelAssignments) > 0 {
- m := make(map[string]model.ModelAssignment, len(persistedState.VSCodeModelAssignments))
- for k, v := range persistedState.VSCodeModelAssignments {
- m[k] = model.ModelAssignment{ProviderID: v.ProviderID, ModelID: v.ModelID, Effort: v.Effort}
- }
- selection.VSCodeModelAssignments = m
- }
+ if selection.VSCodeModelAssignments == nil && len(persistedState.VSCodeModelAssignments) > 0 {
+ selection.VSCodeModelAssignments = StateModelAssignmentsToModel(persistedState.VSCodeModelAssignments)
+ }📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if len(selection.VSCodeModelAssignments) == 0 && len(persistedState.VSCodeModelAssignments) > 0 { | |
| m := make(map[string]model.ModelAssignment, len(persistedState.VSCodeModelAssignments)) | |
| for k, v := range persistedState.VSCodeModelAssignments { | |
| m[k] = model.ModelAssignment{ProviderID: v.ProviderID, ModelID: v.ModelID, Effort: v.Effort} | |
| } | |
| selection.VSCodeModelAssignments = m | |
| } | |
| if selection.VSCodeModelAssignments == nil && len(persistedState.VSCodeModelAssignments) > 0 { | |
| selection.VSCodeModelAssignments = StateModelAssignmentsToModel(persistedState.VSCodeModelAssignments) | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@internal/cli/sync.go` around lines 994 - 1000, Preserve the nil-vs-empty
semantics for VSCodeModelAssignments in sync selection handling: the current
len(...) check in the VSCode assignment merge logic treats nil and an explicit
empty map the same, which breaks the override contract described in
selection.go. Update the sync path around the
persistedState.VSCodeModelAssignments merge so only a nil selection map is
backfilled from state, while a non-nil empty map remains an intentional reset to
defaults; keep the behavior localized to the selection population logic that
builds selection.VSCodeModelAssignments.
b1ae7f1 to
1fedc6e
Compare
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/agents.md`:
- Around line 134-135: Clarify the `Code/User/` paths in this section so
cross-platform readers know where to find the files. Update the references for
the global instructions and MCP config to include a platform-specific base
directory or a platform-agnostic note, and keep the symbols
`Code/User/prompts/gentle-ai.instructions.md` and `Code/User/mcp.json` easy to
recognize. Use the same path style consistently across the docs, matching the
surrounding guidance in `docs/agents.md`.
In `@internal/assets/vscode/agents/sdd-propose.agent.md`:
- Around line 7-9: The agent allowlist for sdd-propose.agent.md is missing the
memory MCP operations used in this phase. Update the agent’s tools configuration
to include mem_search, mem_get_observation, and mem_save explicitly, or switch
to allowing the full MCP server if that is the intended access pattern. Make the
change in the agent metadata where the tools list is defined so the phase can
invoke the memory tools successfully.
In `@internal/cli/run.go`:
- Around line 718-723: `shouldRefreshWindowsEngram()` is treating duplicate PATH
segments as separate binary hits because `engramBinaryDirsOnPath()` counts
repeated directories, so update the Windows shadow-check to deduplicate PATH
entries before deciding Engram is shadowed. Adjust the logic in
`shouldRefreshWindowsEngram()` and any related helper around
`engramBinaryDirsOnPath()` so only unique binary directories are counted,
preserving the existing OS/package-manager guards and preventing false
shadow-repair paths.
In `@internal/components/sdd/inject.go`:
- Around line 1734-1738: The early json.Unmarshal fallback in mergeJSONFile is
skipping the migration for JSONC inputs, so deprecated command.*.prompt fields
can survive unchanged. Update this path to use the same JSONC-tolerant parse
flow as the rest of mergeJSONFile, then run the rename/drop migration on the
parsed object before re-encoding so stale keys are removed consistently.
In `@internal/components/sdd/vscode_agent_visibility.go`:
- Around line 43-51: The hide flow in the managed Claude agent write path leaves
a stale backup behind when filemerge.WriteFileAtomic fails, so remove the backup
file before returning the error. Update the write logic in
vscode_agent_visibility.go around the backupPath/os.WriteFile and
filemerge.WriteFileAtomic steps so a failed hide write cleans up the newly
created .backup, and keep the restore behavior in
RestoreManagedClaudeInternalAgentsForVSCode aligned with this backup lifecycle.
In `@README.md`:
- Line 195: The README path reference is ambiguous because
`Code/User/prompts/gentle-ai.instructions.md` lacks a base directory. Update the
wording in the installation/docs text that mentions Gentle-AI’s VS Code layers
so the `Code/User/` location is prefixed with a clear platform-specific or
platform-agnostic base path, matching the style used for `~/.copilot/agents` and
`~/.copilot/skills`. Use the existing documentation sentence as the anchor and
revise the path notation so readers on macOS, Linux, and Windows can resolve it
unambiguously.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 4e6defea-42d8-4a47-86bc-cf78902bbd86
⛔ Files ignored due to path filters (9)
testdata/golden/sdd-claude-agent-sdd-apply.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-archive.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-design.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-explore.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-propose.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-spec.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-tasks.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-verify.goldenis excluded by!testdata/**testdata/golden/sdd-vscode-instructions.goldenis excluded by!testdata/**
📒 Files selected for processing (55)
README.mddocs/agents.mdgo.modinternal/agents/vscode/adapter.gointernal/agents/vscode/adapter_test.gointernal/app/app.gointernal/app/app_test.gointernal/assets/assets.gointernal/assets/assets_test.gointernal/assets/claude/agents/jd-fix-agent.mdinternal/assets/claude/agents/jd-judge-a.mdinternal/assets/claude/agents/jd-judge-b.mdinternal/assets/claude/agents/sdd-apply.mdinternal/assets/claude/agents/sdd-archive.mdinternal/assets/claude/agents/sdd-design.mdinternal/assets/claude/agents/sdd-explore.mdinternal/assets/claude/agents/sdd-init.mdinternal/assets/claude/agents/sdd-onboard.mdinternal/assets/claude/agents/sdd-propose.mdinternal/assets/claude/agents/sdd-spec.mdinternal/assets/claude/agents/sdd-tasks.mdinternal/assets/claude/agents/sdd-verify.mdinternal/assets/vscode/agents/sdd-apply.agent.mdinternal/assets/vscode/agents/sdd-archive.agent.mdinternal/assets/vscode/agents/sdd-design.agent.mdinternal/assets/vscode/agents/sdd-explore.agent.mdinternal/assets/vscode/agents/sdd-init.agent.mdinternal/assets/vscode/agents/sdd-onboard.agent.mdinternal/assets/vscode/agents/sdd-orchestrator.agent.mdinternal/assets/vscode/agents/sdd-propose.agent.mdinternal/assets/vscode/agents/sdd-spec.agent.mdinternal/assets/vscode/agents/sdd-tasks.agent.mdinternal/assets/vscode/agents/sdd-verify.agent.mdinternal/cli/install_test.gointernal/cli/run.gointernal/cli/run_engram_download_test.gointernal/cli/run_state_test.gointernal/cli/sync.gointernal/cli/sync_test.gointernal/components/filemerge/replace_default.gointernal/components/filemerge/replace_windows.gointernal/components/filemerge/writer.gointernal/components/filemerge/writer_test.gointernal/components/sdd/inject.gointernal/components/sdd/inject_test.gointernal/components/sdd/vscode_agent_visibility.gointernal/components/sdd/vscode_agent_visibility_test.gointernal/components/sdd/vscode_models.gointernal/components/sdd/vscode_models_test.gointernal/components/uninstall/service.gointernal/components/uninstall/service_test.gointernal/model/selection.gointernal/model/selection_test.gointernal/state/state.gointernal/state/state_test.go
There was a problem hiding this comment.
Caution
Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
Actionable comments posted: 6
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/agents.md`:
- Around line 134-135: Clarify the `Code/User/` paths in this section so
cross-platform readers know where to find the files. Update the references for
the global instructions and MCP config to include a platform-specific base
directory or a platform-agnostic note, and keep the symbols
`Code/User/prompts/gentle-ai.instructions.md` and `Code/User/mcp.json` easy to
recognize. Use the same path style consistently across the docs, matching the
surrounding guidance in `docs/agents.md`.
In `@internal/assets/vscode/agents/sdd-propose.agent.md`:
- Around line 7-9: The agent allowlist for sdd-propose.agent.md is missing the
memory MCP operations used in this phase. Update the agent’s tools configuration
to include mem_search, mem_get_observation, and mem_save explicitly, or switch
to allowing the full MCP server if that is the intended access pattern. Make the
change in the agent metadata where the tools list is defined so the phase can
invoke the memory tools successfully.
In `@internal/cli/run.go`:
- Around line 718-723: `shouldRefreshWindowsEngram()` is treating duplicate PATH
segments as separate binary hits because `engramBinaryDirsOnPath()` counts
repeated directories, so update the Windows shadow-check to deduplicate PATH
entries before deciding Engram is shadowed. Adjust the logic in
`shouldRefreshWindowsEngram()` and any related helper around
`engramBinaryDirsOnPath()` so only unique binary directories are counted,
preserving the existing OS/package-manager guards and preventing false
shadow-repair paths.
In `@internal/components/sdd/inject.go`:
- Around line 1734-1738: The early json.Unmarshal fallback in mergeJSONFile is
skipping the migration for JSONC inputs, so deprecated command.*.prompt fields
can survive unchanged. Update this path to use the same JSONC-tolerant parse
flow as the rest of mergeJSONFile, then run the rename/drop migration on the
parsed object before re-encoding so stale keys are removed consistently.
In `@internal/components/sdd/vscode_agent_visibility.go`:
- Around line 43-51: The hide flow in the managed Claude agent write path leaves
a stale backup behind when filemerge.WriteFileAtomic fails, so remove the backup
file before returning the error. Update the write logic in
vscode_agent_visibility.go around the backupPath/os.WriteFile and
filemerge.WriteFileAtomic steps so a failed hide write cleans up the newly
created .backup, and keep the restore behavior in
RestoreManagedClaudeInternalAgentsForVSCode aligned with this backup lifecycle.
In `@README.md`:
- Line 195: The README path reference is ambiguous because
`Code/User/prompts/gentle-ai.instructions.md` lacks a base directory. Update the
wording in the installation/docs text that mentions Gentle-AI’s VS Code layers
so the `Code/User/` location is prefixed with a clear platform-specific or
platform-agnostic base path, matching the style used for `~/.copilot/agents` and
`~/.copilot/skills`. Use the existing documentation sentence as the anchor and
revise the path notation so readers on macOS, Linux, and Windows can resolve it
unambiguously.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 4e6defea-42d8-4a47-86bc-cf78902bbd86
⛔ Files ignored due to path filters (9)
testdata/golden/sdd-claude-agent-sdd-apply.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-archive.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-design.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-explore.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-propose.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-spec.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-tasks.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-verify.goldenis excluded by!testdata/**testdata/golden/sdd-vscode-instructions.goldenis excluded by!testdata/**
📒 Files selected for processing (55)
README.mddocs/agents.mdgo.modinternal/agents/vscode/adapter.gointernal/agents/vscode/adapter_test.gointernal/app/app.gointernal/app/app_test.gointernal/assets/assets.gointernal/assets/assets_test.gointernal/assets/claude/agents/jd-fix-agent.mdinternal/assets/claude/agents/jd-judge-a.mdinternal/assets/claude/agents/jd-judge-b.mdinternal/assets/claude/agents/sdd-apply.mdinternal/assets/claude/agents/sdd-archive.mdinternal/assets/claude/agents/sdd-design.mdinternal/assets/claude/agents/sdd-explore.mdinternal/assets/claude/agents/sdd-init.mdinternal/assets/claude/agents/sdd-onboard.mdinternal/assets/claude/agents/sdd-propose.mdinternal/assets/claude/agents/sdd-spec.mdinternal/assets/claude/agents/sdd-tasks.mdinternal/assets/claude/agents/sdd-verify.mdinternal/assets/vscode/agents/sdd-apply.agent.mdinternal/assets/vscode/agents/sdd-archive.agent.mdinternal/assets/vscode/agents/sdd-design.agent.mdinternal/assets/vscode/agents/sdd-explore.agent.mdinternal/assets/vscode/agents/sdd-init.agent.mdinternal/assets/vscode/agents/sdd-onboard.agent.mdinternal/assets/vscode/agents/sdd-orchestrator.agent.mdinternal/assets/vscode/agents/sdd-propose.agent.mdinternal/assets/vscode/agents/sdd-spec.agent.mdinternal/assets/vscode/agents/sdd-tasks.agent.mdinternal/assets/vscode/agents/sdd-verify.agent.mdinternal/cli/install_test.gointernal/cli/run.gointernal/cli/run_engram_download_test.gointernal/cli/run_state_test.gointernal/cli/sync.gointernal/cli/sync_test.gointernal/components/filemerge/replace_default.gointernal/components/filemerge/replace_windows.gointernal/components/filemerge/writer.gointernal/components/filemerge/writer_test.gointernal/components/sdd/inject.gointernal/components/sdd/inject_test.gointernal/components/sdd/vscode_agent_visibility.gointernal/components/sdd/vscode_agent_visibility_test.gointernal/components/sdd/vscode_models.gointernal/components/sdd/vscode_models_test.gointernal/components/uninstall/service.gointernal/components/uninstall/service_test.gointernal/model/selection.gointernal/model/selection_test.gointernal/state/state.gointernal/state/state_test.go
🛑 Comments failed to post (6)
docs/agents.md (1)
134-135: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
Clarify the
Code/User/path notation for cross-platform readers.Same issue as README.md:
Code/User/prompts/gentle-ai.instructions.mdandCode/User/mcp.jsonlack a base directory prefix. Consider using~/.vscode/Code/User/...(Linux),~/Library/Application Support/Code/User/...(macOS), or%APPDATA%/Code/User/...(Windows), or add a platform-agnostic note.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/agents.md` around lines 134 - 135, Clarify the `Code/User/` paths in this section so cross-platform readers know where to find the files. Update the references for the global instructions and MCP config to include a platform-specific base directory or a platform-agnostic note, and keep the symbols `Code/User/prompts/gentle-ai.instructions.md` and `Code/User/mcp.json` easy to recognize. Use the same path style consistently across the docs, matching the surrounding guidance in `docs/agents.md`.internal/assets/vscode/agents/sdd-propose.agent.md (1)
7-9: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
For GitHub Copilot custom.agent.mdfiles in VS Code, does thetools:frontmatter need to explicitly list MCP tools such asmem_search,mem_get_observation, andmem_save, or are MCP tools available implicitly?💡 Result:
For GitHub Copilot custom.agent.md files in VS Code, MCP tools are available implicitly; you do not need to explicitly list them in the tools: frontmatter unless you wish to restrict access or specify only a subset of available tools [1][2][3][4]. By default, if the tools: property is omitted from the frontmatter of your.agent.md file, the custom agent is granted access to all available tools, which includes all MCP server tools that have been properly configured and enabled in your environment (e.g., repository or global settings) [1][2][3][4]. If you prefer to control which tools an agent can use, you can use the tools: property to manage access: - To allow only specific MCP tools, you can list them individually (e.g., tools: ["server_name/tool_name"]) [1][4]. - To allow all tools from a specific MCP server, you can use the wildcard syntax (e.g., tools: ["server_name/*"]) [1][4]. - If you wish to disable access to all tools, you can set tools: []. The agent will autonomously determine when to use the enabled tools based on your prompt and context [5]. Always ensure that any MCP servers you rely on are correctly configured in your project or global settings, as the tools: frontmatter serves primarily as a filter for what is already available to the agent [1][4].
Citations:
- 1: https://docs.github.com/en/copilot/reference/custom-agents-configuration
- 2: https://docs.github.com/en/copilot/concepts/agents/copilot-cli/about-custom-agents
- 3: https://learn.microsoft.com/en-us/visualstudio/ide/copilot-specialized-agents?view=visualstudio
- 4: https://github.com/github/docs/blob/main/content/copilot/reference/custom-agents-configuration.md
- 5: https://code.visualstudio.com/docs/copilot/agents/agent-tools
🌐 Web query:
GitHub Copilot custom agent.agent.mdfrontmattertools:MCP server wildcardserver_name/*custom tools allowlist behavior💡 Result:
In GitHub Copilot custom agents, the
toolsproperty in the.agent.mdYAML frontmatter controls which tools are available to an agent [1]. When configuring tools from Model Context Protocol (MCP) servers, you can use a server-specific wildcard syntax to manage access [1][2]. Wildcard and Filtering Behavior: - Enable all available tools: You can omit thetoolsproperty entirely or explicitly usetools: ["*"][1]. This enables all tools from all configured MCP servers and built-in sources [1][2]. - Enable all tools from a specific server: You can use the syntaxserver_name/*to allowlist every tool provided by a specific MCP server [1][2]. - Enable specific tools: To limit access, you can list individual tools using theserver_name/tool_nameformat [1][2]. Important Implementation Notes: - Resolution Priority: Whentoolsis unset, it defaults to enabling all tools [1][3]. - Tool Naming: GitHub Copilot typically expects MCP tools to be referenced by their server name followed by a slash (e.g.,server_name/tool_name) [1][4]. - Known Issues: There have been reports of inconsistencies where wildcard configurations likeserver_name/*or["*"]may not consistently expose tools to the model or may be misinterpreted by the underlying MCP gateway, depending on the specific version of the Copilot CLI or the SDK in use [5][6][7]. Users have also noted that iftools: ["*"]is incorrectly processed as a literal string rather than a glob by a backend component, it can result in all tools being filtered out rather than allowed [5][6]. Developers seeking to use advanced pattern-based filtering (e.g., prefix globbing such asserver_name/pattern_*) have requested this as a feature, as the current implementation generally requires either specific tool names or the*wildcard for an entire server [8].Citations:
- 1: https://docs.github.com/en/copilot/reference/custom-agents-configuration
- 2: https://github.com/github/docs/blob/main/content/copilot/reference/custom-agents-configuration.md
- 3: https://docs.github.com/en/copilot/concepts/agents/copilot-cli/about-custom-agents
- 4: github/app#1460
- 5: github/gh-aw-mcpg#3443
- 6: github/gh-aw-mcpg#3475
- 7: github/copilot-sdk#861
- 8: github/copilot-cli#1986
🏁 Script executed:
#!/bin/bash set -euo pipefail file='internal/assets/vscode/agents/sdd-propose.agent.md' nl -ba "$file" | sed -n '1,60p' printf '\n--- sibling agent references ---\n' rg -n "mem_search|mem_get_observation|mem_save|tools:" internal/assets/vscode/agents -nRepository: Gentleman-Programming/gentle-ai
Length of output: 209
Add the memory MCP tools to this agent’s allowlist
tools: [read, search, edit]excludes themem_search,mem_get_observation, andmem_saveoperations this phase invokes. Add those MCP tools explicitly, or allow the whole MCP server if that’s intended.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/assets/vscode/agents/sdd-propose.agent.md` around lines 7 - 9, The agent allowlist for sdd-propose.agent.md is missing the memory MCP operations used in this phase. Update the agent’s tools configuration to include mem_search, mem_get_observation, and mem_save explicitly, or switch to allowing the full MCP server if that is the intended access pattern. Make the change in the agent metadata where the tools list is defined so the phase can invoke the memory tools successfully.internal/cli/run.go (1)
718-723: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Deduplicate identical PATH entries before treating Engram as shadowed.
shouldRefreshWindowsEngram()currently fires on any secondengram.exehit, butengramBinaryDirsOnPath()counts duplicate PATH segments separately. A single directory repeated twice can therefore send Windows installs down the shadow-repair branch and fail with the "cannot safely repair PATH order" error even though there is only one real binary location.Suggested fix
func engramBinaryDirsOnPath(pathEntries []string, goos string) []string { var dirs []string + seen := make(map[string]struct{}, len(pathEntries)) for _, entry := range pathEntries { entry = strings.Trim(strings.TrimSpace(entry), `"`) if entry == "" { continue } + cleaned := filepath.Clean(entry) + key := cleaned + if goos == "windows" { + key = strings.ToLower(cleaned) + } + if _, ok := seen[key]; ok { + continue + } binaryName := "engram" if goos == "windows" { binaryName = "engram.exe" } - candidate := filepath.Join(entry, binaryName) + candidate := filepath.Join(cleaned, binaryName) if _, err := os.Stat(candidate); err == nil { - dirs = append(dirs, entry) + seen[key] = struct{}{} + dirs = append(dirs, cleaned) } } return dirs }Also applies to: 756-772
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/cli/run.go` around lines 718 - 723, `shouldRefreshWindowsEngram()` is treating duplicate PATH segments as separate binary hits because `engramBinaryDirsOnPath()` counts repeated directories, so update the Windows shadow-check to deduplicate PATH entries before deciding Engram is shadowed. Adjust the logic in `shouldRefreshWindowsEngram()` and any related helper around `engramBinaryDirsOnPath()` so only unique binary directories are counted, preserving the existing OS/package-manager guards and preventing false shadow-repair paths.internal/components/sdd/inject.go (1)
1734-1738: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Don't skip the migration on JSONC inputs.
mergeJSONFilealready accepts commentedopencode.jsonfiles, but this earlyjson.Unmarshalfallback returns the original bytes unchanged. If a user has JSONC plus stalecommand.*.promptfields, those deprecated keys survive sync and OpenCode will still reject the config. Run this rename/drop step through the same JSONC-tolerant parse path as the rest of the merge flow.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/components/sdd/inject.go` around lines 1734 - 1738, The early json.Unmarshal fallback in mergeJSONFile is skipping the migration for JSONC inputs, so deprecated command.*.prompt fields can survive unchanged. Update this path to use the same JSONC-tolerant parse flow as the rest of mergeJSONFile, then run the rename/drop migration on the parsed object before re-encoding so stale keys are removed consistently.internal/components/sdd/vscode_agent_visibility.go (1)
43-51: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Remove the backup if the hide write fails.
WriteFileAtomicis atomic here, so a failure leaves the original agent file untouched. Keeping the freshly written.backupmakesRestoreManagedClaudeInternalAgentsForVSCodethink the file was hidden and can later roll back to stale content, overwriting newer user edits during uninstall.Proposed fix
backupPath := path + ".backup" if err := os.WriteFile(backupPath, content, 0o644); err != nil { return InjectionResult{}, fmt.Errorf("backup managed Claude agent %s: %w", fileName, err) } writeResult, err := filemerge.WriteFileAtomic(path, []byte(updated), 0o644) if err != nil { + if removeErr := os.Remove(backupPath); removeErr != nil && !errors.Is(removeErr, os.ErrNotExist) { + return InjectionResult{}, fmt.Errorf("write managed Claude agent %s: %w (cleanup backup %s: %v)", fileName, err, backupPath, removeErr) + } return InjectionResult{}, fmt.Errorf("write managed Claude agent %s: %w", fileName, err) }As per path instructions,
internal/components/**/*.go:Any write to user config must have a backup/restore path.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.// Back up original content before write backupPath := path + ".backup" if err := os.WriteFile(backupPath, content, 0o644); err != nil { return InjectionResult{}, fmt.Errorf("backup managed Claude agent %s: %w", fileName, err) } writeResult, err := filemerge.WriteFileAtomic(path, []byte(updated), 0o644) if err != nil { if removeErr := os.Remove(backupPath); removeErr != nil && !errors.Is(removeErr, os.ErrNotExist) { return InjectionResult{}, fmt.Errorf("write managed Claude agent %s: %w (cleanup backup %s: %v)", fileName, err, backupPath, removeErr) } return InjectionResult{}, fmt.Errorf("write managed Claude agent %s: %w", fileName, err) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/components/sdd/vscode_agent_visibility.go` around lines 43 - 51, The hide flow in the managed Claude agent write path leaves a stale backup behind when filemerge.WriteFileAtomic fails, so remove the backup file before returning the error. Update the write logic in vscode_agent_visibility.go around the backupPath/os.WriteFile and filemerge.WriteFileAtomic steps so a failed hide write cleans up the newly created .backup, and keep the restore behavior in RestoreManagedClaudeInternalAgentsForVSCode aligned with this backup lifecycle.Source: Path instructions
README.md (1)
195-195: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
Clarify the
Code/User/path notation for cross-platform readers.The path
Code/User/prompts/gentle-ai.instructions.mdis ambiguous without a prefix. On macOS/Linux this is typically~/.vscode/Code/User/...(actually~/Library/Application Support/Code/User/on macOS,~/.config/Code/User/on Linux), and on Windows it's%APPDATA%/Code/User/.... Readers may not know which base directory to resolve against. Consider prefixing with~/.vscode/or%APPDATA%/(or using a platform-agnostic note) to match how~/.copilot/agents/is documented on the same line.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@README.md` at line 195, The README path reference is ambiguous because `Code/User/prompts/gentle-ai.instructions.md` lacks a base directory. Update the wording in the installation/docs text that mentions Gentle-AI’s VS Code layers so the `Code/User/` location is prefixed with a clear platform-specific or platform-agnostic base path, matching the style used for `~/.copilot/agents` and `~/.copilot/skills`. Use the existing documentation sentence as the anchor and revise the path notation so readers on macOS, Linux, and Windows can resolve it unambiguously.
1fedc6e to
d36fea5
Compare
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/components/communitytool/codegraph_guidance.go`:
- Around line 217-225: The file tracking in the guidance sync flow is counting
unchanged prompt files as modified because `injectCodeGraphGuidanceForAgent`
appends `file` to `result.Files` even when `changed` is false. Update the logic
in `codeGraphGuidanceForAgent` so `result.Files` only includes entries when
`changed` is true, while still preserving `result.Changed` behavior and the
existing error handling.
- Around line 145-156: `HasConfiguredCodeGraphForAgents` is using an unscoped
fallback that can return true for agents outside the selected `agentIDs`. Update
the fallback in this function so it only succeeds when the detected CodeGraph
wiring matches one of the requested agents, using the existing
`status.Agents`/`agentIDs` filtering logic rather than calling
`hasDetectedCodeGraphToolWiring(homeDir)` globally. Keep the agent scope
consistent with `InjectCodeGraphGuidanceForAgents` and the rest of the
agent-scoped sync path.
In `@internal/components/sdd/inject_test.go`:
- Around line 1567-1582: The shared SDD file assertion list in inject_test.go is
missing sdd-status-contract.md, so the VS Code install test no longer validates
that Inject() writes it. Re-add sdd-status-contract.md to the sharedFiles slice
in the test that checks shared convention files, keeping the os.Stat and
non-empty assertions unchanged so the regression is covered again.
In `@internal/components/sdd/inject.go`:
- Around line 335-341: The user-config write paths in inject.go still bypass the
backup/restore flow for non-VS Code adapters by calling
filemerge.WriteFileAtomic in the prompt and sub-agent write branches. Update the
touched write sites in the relevant helper paths (for example the
prompt/sub-agent write logic around the writeResult/writeErr handling) so every
user-config write goes through the backup-enabled path, not just
adapter.Agent()==model.AgentVSCodeCopilot. Ensure the same restore-capable
behavior is used consistently across all referenced write locations.
- Around line 2446-2465: The backup logic in writeFileWithBackup is taking a
fresh snapshot from disk on each write, which can preserve intermediate managed
content instead of the user’s original state. Update the inject flow to capture
the pre-sync bytes once per target path and reuse that snapshot across the whole
run, including the VS Code instructions path handled by injectFileAppend and the
later trigger-rules/strict-tdd-mode rewrites. Also ensure backups are only
created when the write actually changes content, not for no-op writes that
return Changed=false.
In `@internal/components/uninstall/service.go`:
- Around line 547-552: The uninstall flow is scheduling restore operations for
user config without backing up the .backup companions first, so a later failure
can’t roll back the consumed backup files. Update the logic around
adapter.SystemPromptFile, targets, and restoreUserFileBackupOperation so both VS
Code branches also add the corresponding path + ".backup" files to the
rollback/snapshot set before appending restore ops. Apply the same fix in the
other restore block referenced by the comment so every user config write has a
backup/restore path.
- Around line 1258-1296: The restore/delete flow in the uninstall service should
stop on unexpected backup or read errors instead of falling through to deletion.
In the backup handling block, treat any os.Stat(backupPath) error other than
not-exist as fatal, and in the managed-content check, if os.ReadFile(path)
fails, return that error rather than continuing to remove the file. Update the
logic in the restore helper that contains backupPath, isManaged, and
removeFileIfExists so only verified cases proceed to deletion.
In `@internal/tui/model_test.go`:
- Line 6171: Remove the unresolved merge-conflict marker left in the test file,
which is making the Go source invalid. Clean up the conflicting content in the
affected test section of model_test.go by resolving the merge around the test
block and ensuring no conflict markers remain in the final version.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 99db4bad-1ce6-46c6-bc09-7b83e70e5a14
⛔ Files ignored due to path filters (9)
testdata/golden/sdd-claude-agent-sdd-apply.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-archive.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-design.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-explore.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-propose.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-spec.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-tasks.goldenis excluded by!testdata/**testdata/golden/sdd-claude-agent-sdd-verify.goldenis excluded by!testdata/**testdata/golden/sdd-vscode-instructions.goldenis excluded by!testdata/**
📒 Files selected for processing (44)
README.mddocs/agents.mdgo.modinternal/app/app.gointernal/app/app_test.gointernal/assets/assets_test.gointernal/assets/claude/agents/jd-fix-agent.mdinternal/assets/claude/agents/jd-judge-a.mdinternal/assets/claude/agents/jd-judge-b.mdinternal/assets/claude/agents/sdd-apply.mdinternal/assets/claude/agents/sdd-archive.mdinternal/assets/claude/agents/sdd-design.mdinternal/assets/claude/agents/sdd-explore.mdinternal/assets/claude/agents/sdd-init.mdinternal/assets/claude/agents/sdd-onboard.mdinternal/assets/claude/agents/sdd-propose.mdinternal/assets/claude/agents/sdd-spec.mdinternal/assets/claude/agents/sdd-tasks.mdinternal/assets/claude/agents/sdd-verify.mdinternal/cli/install_test.gointernal/cli/run.gointernal/cli/run_engram_download_test.gointernal/cli/run_state_test.gointernal/cli/sync.gointernal/cli/sync_test.gointernal/components/communitytool/codegraph_guidance.gointernal/components/filemerge/replace_default.gointernal/components/filemerge/replace_windows.gointernal/components/filemerge/writer.gointernal/components/filemerge/writer_test.gointernal/components/sdd/inject.gointernal/components/sdd/inject_test.gointernal/components/sdd/vscode_agent_visibility.gointernal/components/sdd/vscode_agent_visibility_test.gointernal/components/sdd/vscode_models.gointernal/components/sdd/vscode_models_test.gointernal/components/uninstall/service.gointernal/components/uninstall/service_test.gointernal/model/selection.gointernal/model/selection_test.gointernal/state/state.gointernal/state/state_test.gointernal/tui/model.gointernal/tui/model_test.go
| func HasConfiguredCodeGraphForAgents(homeDir string, agentIDs []model.AgentID, detector Detector) bool { | ||
| status := DetectStatus(model.CommunityToolCodeGraph, homeDir, detector) | ||
| if status.CLI != AvailabilityAvailable { | ||
| return false | ||
| } | ||
| for _, agent := range status.Agents { | ||
| if slices.Contains(agentIDs, agent.Agent) && agent.Detected && agent.Configured { | ||
| return true | ||
| } | ||
| } | ||
| return hasDetectedCodeGraphToolWiring(homeDir) | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Make the fallback agent-scoped.
HasConfiguredCodeGraphForAgents filters status.Agents by agentIDs, but the fallback hasDetectedCodeGraphToolWiring(homeDir) ignores that scope. If CodeGraph is wired only for one agent, syncing a different selected agent can still return true here and drive InjectCodeGraphGuidanceForAgents to rewrite the wrong prompt files. That breaks the new agent-scoped sync contract.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@internal/components/communitytool/codegraph_guidance.go` around lines 145 -
156, `HasConfiguredCodeGraphForAgents` is using an unscoped fallback that can
return true for agents outside the selected `agentIDs`. Update the fallback in
this function so it only succeeds when the detected CodeGraph wiring matches one
of the requested agents, using the existing `status.Agents`/`agentIDs` filtering
logic rather than calling `hasDetectedCodeGraphToolWiring(homeDir)` globally.
Keep the agent scope consistent with `InjectCodeGraphGuidanceForAgents` and the
rest of the agent-scoped sync path.
| file, changed, err := injectCodeGraphGuidanceForAgent(homeDir, adapter) | ||
| if err != nil { | ||
| return result, fmt.Errorf("inject CodeGraph guidance for %s: %w", id, err) | ||
| } | ||
| if file == "" { | ||
| continue | ||
| } | ||
| result.Changed = result.Changed || changed | ||
| result.Files = append(result.Files, file) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Only report files that actually changed.
result.Files appends every non-empty prompt path, even when changed is false. Downstream, codeGraphGuidanceSyncStep.Run appends res.Files whenever any agent changed, so a multi-agent sync can overcount FilesChanged and list unchanged prompt files as modified. Only add file when changed is true.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@internal/components/communitytool/codegraph_guidance.go` around lines 217 -
225, The file tracking in the guidance sync flow is counting unchanged prompt
files as modified because `injectCodeGraphGuidanceForAgent` appends `file` to
`result.Files` even when `changed` is false. Update the logic in
`codeGraphGuidanceForAgent` so `result.Files` only includes entries when
`changed` is true, while still preserving `result.Changed` behavior and the
existing error handling.
| sharedFiles := []string{ | ||
| "persistence-contract.md", | ||
| "engram-convention.md", | ||
| "openspec-convention.md", | ||
| "sdd-phase-common.md", | ||
| "skill-resolver.md", | ||
| } | ||
| for _, fileName := range sharedFiles { | ||
| sharedPath := filepath.Join(home, ".copilot", "skills", "_shared", fileName) | ||
| info, err := os.Stat(sharedPath) | ||
| if err != nil { | ||
| t.Fatalf("expected shared SDD convention file %q: %v", sharedPath, err) | ||
| } | ||
| if info.Size() == 0 { | ||
| t.Fatalf("expected shared SDD convention file %q to be non-empty", sharedPath) | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
Re-add sdd-status-contract.md to this assertion list.
Inject() still writes skills/_shared/sdd-status-contract.md, but this narrowed list no longer checks it, so that regression now slips past the VS Code install test.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@internal/components/sdd/inject_test.go` around lines 1567 - 1582, The shared
SDD file assertion list in inject_test.go is missing sdd-status-contract.md, so
the VS Code install test no longer validates that Inject() writes it. Re-add
sdd-status-contract.md to the sharedFiles slice in the test that checks shared
convention files, keeping the os.Stat and non-empty assertions unchanged so the
regression is covered again.
| var writeResult filemerge.WriteResult | ||
| var writeErr error | ||
| if adapter.Agent() == model.AgentVSCodeCopilot { | ||
| writeResult, writeErr = writeFileWithBackup(promptPath, []byte(updated), 0o644) | ||
| } else { | ||
| writeResult, writeErr = filemerge.WriteFileAtomic(promptPath, []byte(updated), 0o644) | ||
| } |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Apply the backup path to all touched user-config writes, not just VS Code.
These branches still send non-VS Code prompt and sub-agent writes through filemerge.WriteFileAtomic, so the new restore contract only holds for one adapter family. As per path instructions, install/sync code under internal/components/**/*.go must give every user-config write a backup/restore path.
Also applies to: 383-389, 717-730, 1877-1882
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@internal/components/sdd/inject.go` around lines 335 - 341, The user-config
write paths in inject.go still bypass the backup/restore flow for non-VS Code
adapters by calling filemerge.WriteFileAtomic in the prompt and sub-agent write
branches. Update the touched write sites in the relevant helper paths (for
example the prompt/sub-agent write logic around the writeResult/writeErr
handling) so every user-config write goes through the backup-enabled path, not
just adapter.Agent()==model.AgentVSCodeCopilot. Ensure the same restore-capable
behavior is used consistently across all referenced write locations.
Source: Path instructions
| } | ||
| } | ||
|
|
||
| <<<<<<< HEAD |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
Remove the unresolved merge-conflict marker.
Line 6171 contains <<<<<<< HEAD, which makes this test file invalid Go and will break go test/CI until the conflict is resolved.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@internal/tui/model_test.go` at line 6171, Remove the unresolved
merge-conflict marker left in the test file, which is making the Go source
invalid. Clean up the conflicting content in the affected test section of
model_test.go by resolving the merge around the test block and ensuring no
conflict markers remain in the final version.
d36fea5 to
3df9409
Compare
3df9409 to
76ce695
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
internal/app/app.go (1)
657-666: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider reusing
cli.StateModelAssignmentsToModelfor the OpenCodeModelAssignmentsblock too.
VSCodeModelAssignmentsnow converts via the sharedcli.StateModelAssignmentsToModelhelper, while the adjacentModelAssignmentsblock (lines 657-663) still hand-rolls the identicalProviderID/ModelID/Effortconversion. Consolidating onto the shared helper would remove the duplication.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/app/app.go` around lines 657 - 666, The ModelAssignments conversion in app.go is duplicating the same ProviderID/ModelID/Effort mapping that VSCodeModelAssignments already uses through cli.StateModelAssignmentsToModel. Update the OpenCode ModelAssignments block in the selection-building logic to reuse cli.StateModelAssignmentsToModel as well, and keep the existing fallback condition that only fills it when selection.ModelAssignments is empty and s.ModelAssignments is present.internal/tui/model_test.go (1)
6939-7011: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick winFix the unresolved merge marker and missing closing brace in
internal/tui/model_test.gointernal/tui/model_test.go:6171,7009-7011
<<<<<<< HEADis still present at line 6171.TestStrictTDDForwardalso needs one more closing}beforefunc TestCodexAndVSCodeCopilotPresetFlowTransitionsToVSCodePickerAfterCodex.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/tui/model_test.go` around lines 6939 - 7011, Resolve the merge artifact in internal/tui/model_test.go by removing the leftover conflict marker in the test file and restoring the missing closing brace after TestStrictTDDForward. Make sure the TestStrictTDDForward function is properly closed before TestCodexAndVSCodeCopilotPresetFlowTransitionsToVSCodePickerAfterCodex, and verify the surrounding test block compiles cleanly.
♻️ Duplicate comments (3)
internal/tui/model_test.go (1)
6171-6171: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick winUnresolved merge-conflict marker still present.
Line 6171 still contains a literal
<<<<<<< HEADmarker, which makes this file invalid Go and breaksgo test/CI. This was flagged in a prior review pass but the current code shows it unresolved.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/tui/model_test.go` at line 6171, Remove the unresolved merge-conflict marker from model_test and make sure no literal conflict markers remain in the file. Clean up the affected test section around the lingering HEAD marker so the Go source is valid again and the test file can compile under go test/CI.internal/assets/assets_test.go (1)
622-646: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
isClaudeInternalAgentNamestill uses the prefix heuristic instead of the runtime-managed filename set.This still matches every
sdd-*/jd-*asset by prefix, so the test would silently pass a future non-managed public Claude agent that happens to share the prefix, decoupling it from the actual fixed list patched/restored ininternal/components/sdd/vscode_agent_visibility.go.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/assets/assets_test.go` around lines 622 - 646, The test helper is still using a prefix-based check for Claude internal agent names, which can drift from the actual managed list. Update TestClaudeInternalAgentAssetsAreHiddenFromVSCodePicker and isClaudeInternalAgentName to use the same runtime-managed filename set used by internal/components/sdd/vscode_agent_visibility.go, so the test verifies only the exact assets patched/restored there instead of matching all sdd-* and jd-* files by prefix.internal/cli/sync.go (1)
1043-1049: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winNil-vs-empty override contract for
VSCodeModelAssignmentsstill broken.
len(selection.VSCodeModelAssignments) == 0treats an explicit empty map (intentional reset to defaults) the same asnil(no override), so a user clearing VS Code model assignments still gets persisted assignments reloaded fromstate.json— the reset never sticks.run.go'smergeExplicitAgentInstallState(lines 239-241, same PR) already uses the correct!= nilcheck for the equivalentstate.InstallStatefield, confirming this is the intended pattern here too.🐛 Proposed fix
- if len(selection.VSCodeModelAssignments) == 0 && len(persistedState.VSCodeModelAssignments) > 0 { - m := make(map[string]model.ModelAssignment, len(persistedState.VSCodeModelAssignments)) - for k, v := range persistedState.VSCodeModelAssignments { - m[k] = model.ModelAssignment{ProviderID: v.ProviderID, ModelID: v.ModelID, Effort: v.Effort} - } - selection.VSCodeModelAssignments = m - } + if selection.VSCodeModelAssignments == nil && len(persistedState.VSCodeModelAssignments) > 0 { + selection.VSCodeModelAssignments = StateModelAssignmentsToModel(persistedState.VSCodeModelAssignments) + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/cli/sync.go` around lines 1043 - 1049, The `VSCodeModelAssignments` merge in `sync.go` is still using a length check, which incorrectly treats an explicit empty map as “unset” and reloads persisted assignments. Update the `selection.VSCodeModelAssignments` fallback logic to distinguish nil from empty by checking against nil, matching the `mergeExplicitAgentInstallState` pattern in `run.go`, so an intentional reset to defaults is preserved.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/components/uninstall/service_test.go`:
- Around line 799-829: The restore/uninstall test currently verifies only a
single application of each operation, so it does not lock in idempotency for
restoreUserFileBackupOperation. Update the test around the op.apply loop in
service_test.go to apply the same agentPath and promptPath operations a second
time after the backup has been consumed, and assert the files still contain
originalContent and originalPromptContent and that the backup paths remain
absent. Use the existing op.apply, agentPath, promptPath, backupPath, and
promptBackupPath symbols to keep the check anchored to the restore behavior.
In `@internal/components/uninstall/service.go`:
- Around line 1254-1304: The restoreUserFileBackupOperation apply flow can
delete a file it just restored on a later uninstall pass because it falls back
to the managed-content deletion path after removing path+".backup". Update
restoreUserFileBackupOperation so a file restored from backup is never
reconsidered for deletion on subsequent runs, either by tracking that the backup
existed/was restored and short-circuiting the no-backup branch, or by tightening
the managed-marker check to only explicit installer sentinels instead of broad
substrings like "managed" and "gentle-ai".
---
Outside diff comments:
In `@internal/app/app.go`:
- Around line 657-666: The ModelAssignments conversion in app.go is duplicating
the same ProviderID/ModelID/Effort mapping that VSCodeModelAssignments already
uses through cli.StateModelAssignmentsToModel. Update the OpenCode
ModelAssignments block in the selection-building logic to reuse
cli.StateModelAssignmentsToModel as well, and keep the existing fallback
condition that only fills it when selection.ModelAssignments is empty and
s.ModelAssignments is present.
In `@internal/tui/model_test.go`:
- Around line 6939-7011: Resolve the merge artifact in
internal/tui/model_test.go by removing the leftover conflict marker in the test
file and restoring the missing closing brace after TestStrictTDDForward. Make
sure the TestStrictTDDForward function is properly closed before
TestCodexAndVSCodeCopilotPresetFlowTransitionsToVSCodePickerAfterCodex, and
verify the surrounding test block compiles cleanly.
---
Duplicate comments:
In `@internal/assets/assets_test.go`:
- Around line 622-646: The test helper is still using a prefix-based check for
Claude internal agent names, which can drift from the actual managed list.
Update TestClaudeInternalAgentAssetsAreHiddenFromVSCodePicker and
isClaudeInternalAgentName to use the same runtime-managed filename set used by
internal/components/sdd/vscode_agent_visibility.go, so the test verifies only
the exact assets patched/restored there instead of matching all sdd-* and jd-*
files by prefix.
In `@internal/cli/sync.go`:
- Around line 1043-1049: The `VSCodeModelAssignments` merge in `sync.go` is
still using a length check, which incorrectly treats an explicit empty map as
“unset” and reloads persisted assignments. Update the
`selection.VSCodeModelAssignments` fallback logic to distinguish nil from empty
by checking against nil, matching the `mergeExplicitAgentInstallState` pattern
in `run.go`, so an intentional reset to defaults is preserved.
In `@internal/tui/model_test.go`:
- Line 6171: Remove the unresolved merge-conflict marker from model_test and
make sure no literal conflict markers remain in the file. Clean up the affected
test section around the lingering HEAD marker so the Go source is valid again
and the test file can compile under go test/CI.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: cd3496a6-d6a6-4d06-b8ae-f382aa646016
📒 Files selected for processing (16)
README.mdinternal/app/app.gointernal/assets/assets_test.gointernal/cli/run.gointernal/cli/run_engram_download_test.gointernal/cli/run_state_test.gointernal/cli/sync.gointernal/cli/sync_test.gointernal/components/sdd/inject.gointernal/components/sdd/vscode_agent_visibility.gointernal/components/sdd/vscode_agent_visibility_test.gointernal/components/sdd/vscode_models.gointernal/components/uninstall/service.gointernal/components/uninstall/service_test.gointernal/tui/model.gointernal/tui/model_test.go
| for _, op := range ops { | ||
| if op.path == agentPath || op.path == promptPath { | ||
| if _, _, err := op.apply(op.path); err != nil { | ||
| t.Fatalf("op.apply(%q) error = %v", op.path, err) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Verify both files were restored to original content and backups removed | ||
| gotAgent, err := os.ReadFile(agentPath) | ||
| if err != nil { | ||
| t.Fatalf("ReadFile(agent) error = %v", err) | ||
| } | ||
| if string(gotAgent) != originalContent { | ||
| t.Errorf("agent content = %q, want %q", string(gotAgent), originalContent) | ||
| } | ||
| if _, err := os.Stat(backupPath); !os.IsNotExist(err) { | ||
| t.Errorf("backup file %s should be removed", backupPath) | ||
| } | ||
|
|
||
| gotPrompt, err := os.ReadFile(promptPath) | ||
| if err != nil { | ||
| t.Fatalf("ReadFile(prompt) error = %v", err) | ||
| } | ||
| if string(gotPrompt) != originalPromptContent { | ||
| t.Errorf("prompt content = %q, want %q", string(gotPrompt), originalPromptContent) | ||
| } | ||
| if _, err := os.Stat(promptBackupPath); !os.IsNotExist(err) { | ||
| t.Errorf("prompt backup file %s should be removed", promptBackupPath) | ||
| } | ||
| } |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
Consider adding a second-apply assertion to lock in idempotency.
This test only applies each op once. Re-running op.apply(op.path) after the backup is consumed would exercise the "no backup" fallback and catch the idempotency/data-loss regression flagged in restoreUserFileBackupOperation (restored user content being deleted on a second run).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@internal/components/uninstall/service_test.go` around lines 799 - 829, The
restore/uninstall test currently verifies only a single application of each
operation, so it does not lock in idempotency for
restoreUserFileBackupOperation. Update the test around the op.apply loop in
service_test.go to apply the same agentPath and promptPath operations a second
time after the backup has been consumed, and assert the files still contain
originalContent and originalPromptContent and that the backup paths remain
absent. Use the existing op.apply, agentPath, promptPath, backupPath, and
promptBackupPath symbols to keep the check anchored to the restore behavior.
76ce695 to
9867240
Compare
…ram download test on Windows
…tore contracts, picker hydration, and test mock providers
… flows and test assertions
…cleanup, duplicate paths, and JSONC parsing
… uninstall targets
9867240 to
28d0885
Compare
🔗 Linked Issue
Closes #504
Depends on: #731
Related context: #708
🏷️ PR Type
What kind of change does this PR introduce?
type:bug— Bug fix (non-breaking change that fixes an issue)type:feature— New feature (non-breaking change that adds functionality)type:docs— Documentation onlytype:refactor— Code refactoring (no functional changes)type:chore— Build, CI, or tooling changestype:breaking-change— Breaking change (fix or feature that changes existing behavior)🔗 Chain Context
PR 3 of the VS Code Copilot SDD subagents stack.
This PR depends on #731. Because the stack is currently opened from a contributor fork and upstream dependency branches are not available as base branches, this PR targets
main; reviewers should use the focused diff below for this work unit.Focused review diff:
Snakeblack/gentle-ai@feat/vscode-copilot-subagents-pr2...fix/vscode-copilot-agent-hardening
📝 Summary
sdd-orchestratorvisible in VS Code while preserving internal phase agents for delegation.model:frontmatter when VS Code model assignments are missing or invalid, and updates SDD golden fixtures.📂 Changes
internal/components/filemergeMoveFileExon Windowsinternal/components/sddinternal/assets/claude/agentstestdata/golden🧠 Size Exception Rationale
This PR requests
size:exception.The focused hardening diff is slightly above the 400-line budget because the installer fix, visibility contract, stale model cleanup, and golden fixtures must be reviewed together. Splitting them would hide the important invariant: VS Code should expose only the orchestrator to users while internal agents remain available for delegation and safe sync.
🧪 Test Plan
Linux/LF full suite
go test ./... go vet ./...Focused golden/contract checks
Results:
go test ./...) in Linux/LF verification clonecd e2e && ./docker-test.sh)Note: local Windows full-suite runs still have known CRLF/env-sensitive golden noise unrelated to this PR. Final validation was done in a clean Linux/LF runner.
🤖 Automated Checks
size:exception; focused work unit is cohesiveCloses #504status:approvedstatus:approvedtype:*Labeltype:bugrequested; maintainer label neededgo test ./...✅ Contributor Checklist
status:approvedsize:exceptionwith rationale documentedtype:*label to this PR — maintainer label needed (type:bug)go test ./...)cd e2e && ./docker-test.sh)Co-Authored-Bytrailers💬 Notes for Reviewers
The key review contract is VS Code visibility: the native dropdown should expose
sdd-orchestratoronly. Phase agents are intentionally hidden from users but still available for orchestration/delegation.Summary by CodeRabbit
Release Notes
New Features
Improvements
Documentation
Tests