diff --git a/docs/todos/2026-06-20-issue-346-agent-picker-opencode/todo.md b/docs/todos/2026-06-20-issue-346-agent-picker-opencode/todo.md new file mode 100644 index 00000000..b4a4baae --- /dev/null +++ b/docs/todos/2026-06-20-issue-346-agent-picker-opencode/todo.md @@ -0,0 +1,171 @@ +# Issue 346 Agent Picker OpenCode Selection + +Task id: `2026-06-20-issue-346-agent-picker-opencode` + +## Scope + +Handle GitHub issue #346, "Agent picker: selected `OpenCode` becomes `Claude Code`", +on branch `issue/346-agent-picker-opencode-claude-code` in the isolated worktree +`/Users/A1538552/.codex/worktrees/5b56/agentmemory`. + +Target remote: `origin` (`https://github.com/wbugitlab1/agentmemory.git`) only. +Do not target `https://github.com/rohitg00/agentmemory/`. + +## Sprint Contract + +Goal: make first-run agent selection avoid or clearly prevent the reported +OpenCode-vs-Claude-Code confusion while preserving existing connect adapters and +agent wiring behavior. + +Scope: +- Read-only validation of issue #346 and local code paths before edits. +- Onboarding agent picker behavior in `src/cli/onboarding.ts`. +- Focused onboarding tests under `test/`. +- Existing OpenCode connect support checks only if needed to prove the issue is + stale in part. + +Non-goals: +- Do not change public MCP, REST, schema, persistence, auth, dependency, or + architecture boundaries. +- Do not change OpenCode config schema or adapter install behavior unless arena + evidence proves the issue cannot be fixed in onboarding alone. +- Do not target or reference the upstream remote in branch, push, or PR actions. + +Acceptance criteria: +- Issue legitimacy is decided from current GitHub issue evidence and repo + evidence before implementation. +- `$arena` validity/fix-direction synthesis is recorded before implementation. +- If the issue is valid, a failing test demonstrates the confusing onboarding + behavior or the chosen regression seam before production code changes. +- The minimal fix preserves OpenCode in supported agents and keeps + `agentmemory connect opencode` working. +- Focused tests and required verification/security gates pass, or blockers are + recorded with exact evidence. + +Intended verification: +- `corepack pnpm exec vitest run --exclude test/integration.test.ts test/onboarding.test.ts test/cli-onboarding.test.ts test/cli-connect.test.ts` +- `git diff --check` +- Required security gates after implementation and staging per repo policy. + +Known boundaries: +- This task starts from `origin/main` at + `5ad88c08197c2cb15675a4a974b9e8f37dfd1f00`. +- `node_modules` is not materialized at task start; repo policy says to run + `corepack pnpm install --frozen-lockfile --ignore-scripts` if pnpm commands + are blocked by missing dependencies or pnpm hardening. +- Issue comments show the original `connect opencode` workaround failed in + v0.9.27, but current repo evidence shows OpenCode support exists in + `src/cli/connect/opencode.ts` and `ADAPTERS`. + +Stop conditions: +- Stop for a Human Checkpoint before closing the issue as invalid, stale, + duplicate, unreproducible, or already fixed. +- Stop before broadening behavior into public API/tool/schema/persistence, + dependency, architecture, remote, or project-policy changes. +- Stop before accepting skipped, failing, flaky, or incomplete verification. + +## Feature / Verification Matrix + +| Change | Verification method | Status | Evidence | +| --- | --- | --- | --- | +| Context confirmed | Git commands and instruction reads | Done | `git status -sb --untracked-files=all`, `git remote -v`, `git worktree list --porcelain`; `AGENTS.md` and triage skill read. | +| Branch created | Git ref check | Done | Created `issue/346-agent-picker-opencode-claude-code` from `origin/main` `5ad88c08197c2cb15675a4a974b9e8f37dfd1f00`. | +| Issue evidence collected | GitHub issue read and local code search | Done | `gh issue view 346 ...`; `rg` found onboarding and OpenCode connect surfaces. | +| Arena validation | Candidate reports and synthesis | Done | Candidates converged: #346 is partially actionable; stale `connect opencode` support is already fixed, picker default-selection UX remains valid. Judge selected Candidate 1 as base. | +| Regression test | Targeted Vitest red/green | Done | Red failed as expected: `getInitialAgentValues({})` returned `["claude-code"]` and multiselect received `initialValues: ["claude-code"]`; green focused run passed after implementation. | +| Minimal implementation | Source diff review | Done | Changed `getInitialAgentValues()` generic fallback from `["claude-code"]` to `[]`; Copilot detection remains unchanged. | +| Focused verification | Targeted Vitest, full test, diff checks | Done | Pre-merge: focused run passed 3 files / 50 tests and `corepack pnpm test` passed 220 files / 3006 tests. Post-merge from `origin/main` `257238ab1c318b2e9ae5efcbe72863b99c41ee35`: focused run passed 3 files / 50 tests and `corepack pnpm test` passed 222 files / 3042 tests. `git diff --check` and `git diff --cached --check` passed. | +| Security gates | Required scanners after staging | Done | Pre-merge and post-merge `semgrep scan --config p/default --error --metrics=off .` passed with 0 findings; post-merge scan covered 997 tracked files. `gitleaks protect --staged --redact` passed with no leaks before the first commit and after the final task-note update. | + +## Subagent Ledger + +| Workstream | Scope | Edits allowed | Expected output | Result | Residual risk | +| --- | --- | --- | --- | --- | --- | +| Arena candidate 1 | Issue #346 validity and fix direction | No | Validity report with reproduction seam, affected files, recommended tests | Done: selected base; recommended no generic `claude-code` preselection, preserving Copilot detection | Did not run tests. | +| Arena candidate 2 | Issue #346 validity and fix direction | No | Validity report with reproduction seam, affected files, recommended tests | Done: same validity/root cause; added stale-connect guard and optional note-copy concern | Note-copy change rejected as extra surface for this fix. | +| Arena candidate 3 | Issue #346 validity and fix direction | No | Validity report with reproduction seam, affected files, recommended tests | Done: same validity/root cause; highlighted that making selection required is broader | Prompt-copy tweak rejected as optional. | +| Arena judge | Candidate scoring | No | Rubric scores and base recommendation | Done: Candidate 1 scored 9/10 and selected as base | No checkpoint needed for onboarding-only fix. | + +## Arena Synthesis + +Base: Candidate 1. + +Decision: issue #346 is valid/actionable for first-run onboarding picker UX. +The `connect opencode` unknown-agent follow-up is stale in current code because +`opencode` is registered in `ADAPTERS`, appears in `knownAgents()`, and has +focused adapter tests. The remaining failure path is `getInitialAgentValues({})` +returning `["claude-code"]`, which is passed as Clack multiselect +`initialValues`; focus can move to OpenCode while the checked value remains +Claude Code. + +Grafts: +- From Candidate 2: keep `test/cli-connect.test.ts` as the stale-connect guard; + do not retest adapter internals beyond existing focused coverage unless the + fix touches them. +- From Candidate 3: do not make the multiselect required or add an explicit + skip option; that would be broader than the issue needs because onboarding + intentionally allows users to skip wiring agents. + +Rejected: +- Candidate 2's agent-neutral post-selection note change is plausible polish but + not required for the evidence-backed minimal fix. +- Candidate 3's prompt wording tweak is optional copy work and not needed for + the regression seam. +- Adapter/schema/MCP/REST/persistence/dependency changes are out of scope. + +## Evidence Notes + +- Issue #346 is open. The imported report says selecting `OpenCode` in the + first-run agent picker leads to a later `Claude Code` message, and the user + expected `OpenCode`. +- Imported maintainer comment explains the picker is a multi-select: arrow keys + move focus, Space toggles, Enter confirms checked rows. Claude Code was + pre-checked while OpenCode was focused. +- Imported follow-up says `agentmemory connect opencode` was unknown in v0.9.27. + Current repo evidence shows `opencode` is now present in `ADAPTERS`, listed in + `knownAgents()`, and tested in `test/cli-connect.test.ts`. +- Local code currently defaults `getInitialAgentValues({})` to + `["claude-code"]`, so a user can focus `OpenCode` while still confirming + preselected `Claude Code`. + +## Progress Notes + +- 2026-06-20: Read active repo instructions, triage workflow, arena workflow, + systematic debugging, and TDD guidance. +- 2026-06-20: Confirmed worktree, branch, remotes, and start ref. Created + branch `issue/346-agent-picker-opencode-claude-code`. +- 2026-06-20: Read issue #346 and local onboarding/connect code. Current + hypothesis: the actionable bug is onboarding default-selection UX, while the + OpenCode connect alias part is stale/fixed by existing `opencode` adapter + support. +- 2026-06-20: Completed `$arena`. Candidates and judge converged on an + onboarding-only fix: remove generic `claude-code` preselection while + preserving confident Copilot CLI detection. No Human Checkpoint is needed for + this implementation path; checkpoint remains required before stale/invalid + closure or boundary changes. +- 2026-06-20: Added red tests in `test/onboarding.test.ts` and + `test/cli-onboarding.test.ts`. Initial `corepack pnpm exec vitest ...` was + blocked by pnpm ignored-build hardening, so ran + `corepack pnpm install --frozen-lockfile --ignore-scripts` per repo + instructions, then reran the focused tests. Red failure matched the expected + onboarding default-selection behavior. +- 2026-06-20: Implemented the one-line onboarding fix. Focused green + verification passed for onboarding/connect tests. Full `corepack pnpm test` + passed 220 files / 3006 tests. Removed the generated pnpm `allowBuilds` + placeholder that pnpm had added during dependency setup; no package metadata + or lockfile changes remain. +- 2026-06-20: Repo-wide Semgrep default scan passed with 0 findings across + tracked files. +- 2026-06-20: Staged Gitleaks scan passed with no leaks. +- 2026-06-20: Committed `fix(onboarding): avoid default Claude Code + preselection` at `4f2e2b09480e619ced578390b8290075ae9da8f8`. +- 2026-06-20: Fetched `origin` and merged `origin/main` + `257238ab1c318b2e9ae5efcbe72863b99c41ee35` into the branch. The merge + required sandbox escalation because the worktree Git metadata directory + rejected sandbox writes to `ORIG_HEAD.lock`. PR diff remains limited to this + task's onboarding source, tests, and task record. +- 2026-06-20: Post-merge focused tests passed 3 files / 50 tests; full + `corepack pnpm test` passed 222 files / 3042 tests; post-merge Semgrep + default scan passed with 0 findings across 997 tracked files. +- 2026-06-20: Final staged Gitleaks scan after the task-note update passed with + no leaks. diff --git a/src/cli/onboarding.ts b/src/cli/onboarding.ts index 2a015325..79250101 100644 --- a/src/cli/onboarding.ts +++ b/src/cli/onboarding.ts @@ -95,7 +95,7 @@ export function getInitialAgentValues( if (env["COPILOT_CLI"] === "1" || env["COPILOT_AGENT_SESSION_ID"]) { return ["copilot-cli"]; } - return ["claude-code"]; + return []; } // Mirror src/cli.ts findEnvExample so onboarding ships the same .env diff --git a/test/cli-onboarding.test.ts b/test/cli-onboarding.test.ts index d78cc5e3..d5574f76 100644 --- a/test/cli-onboarding.test.ts +++ b/test/cli-onboarding.test.ts @@ -117,4 +117,37 @@ describe("cli onboarding", () => { "Also set AZURE_OPENAI_ENDPOINT= and AZURE_OPENAI_DEPLOYMENT=", ); }); + + it("does not preselect Claude Code before an OpenCode-only onboarding choice", async () => { + setTTY(true); + prompts.multiselect.mockResolvedValueOnce(["opencode"]); + prompts.select.mockResolvedValueOnce("skip"); + prompts.confirm + .mockResolvedValueOnce(false) + .mockResolvedValueOnce(false); + const { runOnboarding } = await freshOnboarding(); + + const result = await runOnboarding(); + + expect(prompts.multiselect).toHaveBeenCalledWith( + expect.objectContaining({ + initialValues: [], + }), + ); + expect(result).toEqual({ agents: ["opencode"], provider: null }); + + const preferencesPath = join(sandboxHome, ".agentmemory", "preferences.json"); + const preferences = JSON.parse(readFileSync(preferencesPath, "utf-8")); + expect(preferences).toMatchObject({ + lastAgent: "opencode", + lastAgents: ["opencode"], + lastProvider: null, + skipSplash: true, + }); + + const noteText = prompts.note.mock.calls + .map(([body]) => String(body)) + .join("\n"); + expect(noteText).toContain("agentmemory connect opencode"); + }); }); diff --git a/test/onboarding.test.ts b/test/onboarding.test.ts index a1e766bb..ab8bb033 100644 --- a/test/onboarding.test.ts +++ b/test/onboarding.test.ts @@ -38,7 +38,7 @@ describe("first-run onboarding", () => { expect(getInitialAgentValues({ COPILOT_AGENT_SESSION_ID: "session" })).toEqual(["copilot-cli"]); }); - it("keeps Claude Code as the default outside known agent environments", () => { - expect(getInitialAgentValues({})).toEqual(["claude-code"]); + it("does not preselect an agent outside known agent environments", () => { + expect(getInitialAgentValues({})).toEqual([]); }); });