Skip to content

refactor(adapters): cut ~3,100 LOC of redundancy in the agent adapter layer (#2349)#2355

Open
harshitsinghbhandari wants to merge 4 commits into
AgentWrapper:mainfrom
harshitsinghbhandari:ao/agent-orchestrator-18/adapter-dedup
Open

refactor(adapters): cut ~3,100 LOC of redundancy in the agent adapter layer (#2349)#2355
harshitsinghbhandari wants to merge 4 commits into
AgentWrapper:mainfrom
harshitsinghbhandari:ao/agent-orchestrator-18/adapter-dedup

Conversation

@harshitsinghbhandari

Copy link
Copy Markdown
Collaborator

Closes #2349.

Consolidates the copy-pasted logic across the 23 agent adapters in backend/internal/adapters/agent/ into a handful of shared helpers, with no behavioral change and one latent correctness fix (missing fsync).

Net delta

-3,105 LOC of non-test production code (-3,454 total incl. tests): 78 files changed, 1,212 insertions, 4,666 deletions.

New shared packages

  • hooksjson — generic matcher-group hooks file (Read/Write/Install/Uninstall/AreInstalled). The claude/goose/qwen/droid hooks.go each collapse from ~180-380 LOC to ~60.
  • binaryutil.ResolveBinary(ctx, BinarySpec) — table-driven binary search; per-adapter resolvers shrink to a ~10-line BinarySpec literal.
  • agentbase.Base (embed) + agentbase.StandardSessionInfo — default no-op ports.Agent methods + the shared session-metadata reader.
  • activitystate.StandardDeriveActivityState — the name-only hook→activity mapping shared via activitydispatch.
  • ports.NormalizePermissionMode and hookutil.FileExists — the two most-copied one-liners.

What was removed (findings from #2349)

Finding Result
1. Matcher-group hook skeleton hooksjson.Manager (claudecode, goose, qwen, droid)
2. Binary resolver boilerplate binaryutil.BinarySpec (19 resolvers)
3. normalizePermissionMode ×15 ports.NormalizePermissionMode
4. Identical DeriveActivityState ×8 activitystate.StandardDeriveActivityState; activity.go deleted
5. atomicWriteFile ×7 (4 missing fsync) hookutil.AtomicWriteFile
6. SessionInfo boilerplate agentbase.StandardSessionInfo
7-9. GetPromptDeliveryStrategy / GetConfigSpec / tier-C no-op stubs agentbase.Base embed
10. fileExists ×23 hookutil.FileExists

Correctness fix: the private atomicWriteFile copies in autohand/cline/goose/kiro omitted tmp.Sync(); routing them through hookutil.AtomicWriteFile restores the fsync before rename.

Kept deliberately separate (per #2349)

  • Per-agent permission/approval flag mapping (real behavior).
  • Special binary resolvers: codex (windows shim), opencode (bare-name fallback), aider & cursor (home-before-abs candidate order).
  • Non-matcher-group hook formats (cursor/kiro flat entries, copilot owns its file, cline per-file scripts, codex TOML flags, opencode/kilocode TS plugins, autohand global config).
  • Payload-parsing activity derivers (claudecode, codex, droid, agy, opencode).

Verification

go build ./..., go vet ./..., and go test ./... all green from backend/1,647 tests pass across 84 packages. Per-adapter public behavior (launch/restore argv, hook file contents, session info, binary resolution) is unchanged; test expectations were only migrated where they referenced now-shared internal types.

🤖 Generated with Claude Code

harshitsinghbhandari and others added 4 commits July 2, 2026 19:30
…r#2349)

Introduce the shared building blocks the per-adapter cleanup will use:
- ports.NormalizePermissionMode (finding 3)
- hookutil.FileExists (finding 10)
- binaryutil.ResolveBinary + BinarySpec (finding 2)
- activitystate.StandardDeriveActivityState (finding 4)
- agentbase.Base embed + StandardSessionInfo (findings 6-9)

No adapters wired up yet; behavior unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…Wrapper#2349)

Reference conversion proving the shared packages against real tests:
- hooks.go collapses onto hooksjson.Manager (finding 1)
- ResolveGooseBinary via binaryutil.BinarySpec (finding 2)
- gooseMode uses ports.NormalizePermissionMode (finding 3)
- activity.go deleted; dispatch points at activitystate (findings 4, 5)
- SessionInfo via agentbase.StandardSessionInfo; Base embed drops the
  GetConfigSpec/GetPromptDeliveryStrategy no-ops (findings 6-8)
- fileExists/atomicWriteFile copies removed (findings 5, 10)

Also adds hooksjson package + activitystate test. goose: 327->~90 LOC.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…pers (AgentWrapper#2349)

Applies the shared helpers across every remaining adapter:
- hooksjson.Manager for the matcher-group cohort (claudecode, qwen, droid)
- binaryutil.BinarySpec for 19 binary resolvers (aider/cursor/opencode/codex
  keep their special resolvers; all now use hookutil.FileExists)
- ports.NormalizePermissionMode replaces 15 private copies
- agentbase.Base embed drops the GetConfigSpec/GetPromptDeliveryStrategy no-ops
  (and GetAgentHooks/GetRestoreCommand/SessionInfo no-ops on hookless adapters)
- agentbase.StandardSessionInfo replaces the per-adapter metadata readers
- activitystate.StandardDeriveActivityState via dispatch for the 8 name-only
  derivers; their activity.go files removed (claudecode/codex/droid/agy/opencode
  keep payload-parsing derivers)
- 4 private atomicWriteFile copies missing fsync now use hookutil.AtomicWriteFile
- 23 private fileExists copies removed

Full backend build + vet + test suite green (1647 tests).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cut ~3,000 LOC of redundancy in the agent adapter layer

1 participant