* refactor(adapters): add shared helpers for adapter dedup (#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>
* refactor(goose): convert to shared adapter helpers (reference) (#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>
* refactor(adapters): dedup remaining 22 agent adapters onto shared helpers (#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>
* chore: format with prettier [skip ci]
* fix(binaryutil): preserve per-adapter Windows candidate order (#2349)
Review feedback: the shared resolver hardcoded Windows candidate order as
APPDATA then LOCALAPPDATA, which flipped Kiro's lookup so the npm shim
(%APPDATA%\npm\kiro-cli.*) was probed before the native install
(%LOCALAPPDATA%\Programs\kiro\kiro-cli.exe). A fixed order can't preserve every
adapter's original order (goose/vibe want APPDATA first, kiro wants LOCALAPPDATA
first), so BinarySpec now takes an ordered WinPaths []WinPath list where each
entry names its base (WinAppData/WinLocalAppData/WinHome). Every adapter's list
reproduces its pre-refactor order exactly; kiro's native path is restored to
first.
go build / vet / test all green (1647 tests).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test(adapters): drop unused resolvedBinary writes flagged by govet (#2349)
Embedding agentbase.Base (value receiver) lets govet's unusedwrite analyzer
prove that setting resolvedBinary in tests that only call Base-promoted methods
(GetConfigSpec/GetPromptDeliveryStrategy/SessionInfo/cancellation) is a dead
write. Drop the field from those 23 constructions; GetLaunchCommand/GetRestore
tests that actually read it keep it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* style: gofmt manager_test.go struct alignment (#2349)
Inherited via the merge of main: a SessionRecord literal aligned its Metadata
field across a multi-key line, which gofmt/goimports rejects. One-line reformat
to unblock CI.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* docs(adapters): fix stale resolver fallback comments (#2349)
Review nit: 6 Resolve*Binary functions now delegate to binaryutil.ResolveBinary,
which returns a wrapped ports.ErrAgentBinaryNotFound rather than the bare binary
name. Update their doc comments (kiro, vibe, amp, agy, crush, cline) to match.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* feat: add agent catalog API and integrate with project settings
- Implemented AgentsController to handle /agents endpoint, returning a list of supported and installed agents.
- Created agent inventory service to manage agent data and detect installed agents.
- Updated ProjectSettingsForm to fetch and display agent information, including installed and supported agents.
- Enhanced error handling for agent detection and orchestrator restarts.
- Added tests for agent catalog and service to ensure correct functionality and error handling.
* Implement agent authorization status checks and update frontend to reflect changes
- Added `AuthStatus` method to various agent plugins to check authorization status using CLI probes.
- Introduced `authprobe` package to handle common CLI command checks for agent authorization.
- Updated backend tests to include scenarios for authorized and unauthorized agents.
- Modified frontend API schema to include `authorized` counts and `authStatus` for agents.
- Enhanced `ProjectSettingsForm` to display authorized agents and their statuses, including prompts for login when necessary.
- Adjusted agent selection logic to prioritize authorized agents and provide feedback for unauthorized or uninstalled agents.
* fix: simplify orchestrator replacement retry flow
* refactor: cache agent catalog ,remove AgentCounts schema and related references from API and frontend
* fix: clarify orchestrator replacement recovery state
* feat: enhance project settings and agent management
- Updated NewTaskDialog tests to increase timeout for async operations.
- Modified ProjectSettingsForm tests to improve agent handling and validation messages.
- Refactored ProjectSettingsForm component to streamline agent selection and validation logic.
- Introduced new agent service to manage agent inventory and authentication status.
- Improved Sidebar tests to ensure proper agent options are loaded and handled.
- Enhanced SessionsBoard component by removing unused imports and optimizing state management.
- Fixed Select component styling for better consistency in UI.
- Added error handling for AO daemon readiness in ShellLayout.
* chore: format with prettier [skip ci]
* feat: add AuthStatus method documentation and improve error handling in session manager
* feat: enhance agent authentication and configuration management
- Implement local authentication status checks for PI, Qwen, and Vibe agents.
- Introduce JSON-based authentication status retrieval for PI agents.
- Add environment variable checks for Qwen agents and improve settings file parsing.
- Enhance Vibe agent authentication with support for environment variables and session logs.
- Update agent service to handle asynchronous probing for installed and authorized agents.
- Modify session manager to support prompt delivery strategies based on agent capabilities.
- Improve frontend agent selection UI with loading states and error handling.
- Add tests for new authentication logic and session management features.
* chore: format with prettier [skip ci]
* test: fix session manager fake after rebase
* feat: enhance agent authentication status checks
- Implement local authentication status checks for the Devin, Droid, Kiro, and other agents.
- Add support for reading credentials from specific configuration files and environment variables.
- Introduce new tests for various agents to ensure proper authentication status reporting.
- Refactor existing authentication logic to improve clarity and maintainability.
- Remove deprecated agent setup warnings from the SessionsBoard component in the frontend.
* feat: clear environment variables in auth status tests for Aider and OpenCode
* feat: enhance error handling in authentication status functions and update component props
* feat: integrate fallback agents in RequiredAgentField and streamline props handling
* fix: refactor Sidebar test imports and parameters for clarity
* refactor: remove orchestrator retirement logic and related tests
- Deleted the RetireOrchestrator function and its associated error handling.
- Removed tests related to orchestrator retirement and state management.
- Simplified ProjectSettingsForm by eliminating orchestrator restart logic and related UI elements.
- Updated API client mocks to reflect the removal of orchestrator-related functionality.
* feat: enhance agent management and error handling
- Added agent refresh functionality in ProjectSettingsForm with UI updates for agent availability.
- Implemented `refreshAgents` API call to fetch the latest agent catalog.
- Updated agent selection logic to disable unavailable agents and show appropriate error messages.
- Enhanced error handling in `apiErrorMessage` to include daemon error codes alongside messages.
- Created new test cases for agent availability and error handling in Sidebar component.
- Introduced `ResolveBinary` method for multiple agent adapters to standardize binary resolution.
- Added new agent adapter files for various agents (e.g., Aider, Claude Code, etc.) to support binary resolution.
* chore: format with prettier [skip ci]
* fix: satisfy backend lint checks
* refactor: clean up authentication logic and improve error handling across agents
* chore: format with prettier [skip ci]
* feat(authprobe): enhance status classification for authentication outputs and add tests for explicit false/true keys
chore(docs): update README to remove outdated agent adapter contract references
fix(components): improve agent selection logic to handle unknown auth status and update related tests
* chore: format with prettier [skip ci]
* refactor: remove shell environment authentication logic and update related tests
* feat(tests): integrate QueryClient for agent data in CreateProjectAgentSheet tests
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* feat(agent): add opencode adapter + activity plugin hooks
Add an opencode (sst/opencode) agent adapter implementing the 6-method
ports.Agent interface and register it in the daemon's agent resolver, so a
session with harness "opencode" spawns and restores a real opencode worker.
opencode diverges from the claude-code/codex adapters in two ways the adapter
bridges:
- No native command-hook config. Unlike Claude Code (.claude/settings.local.json)
and Codex (.codex/hooks.json), opencode has no "run this command on event"
config (see sst/opencode#5409). Its only lifecycle surface is a JS/TS plugin
loaded from .opencode/plugins/. GetAgentHooks therefore //go:embeds an
AO-owned plugin (assets/ao-activity.ts) and writes it atomically; install is an
idempotent overwrite and uninstall is a sentinel-guarded delete, so
user-authored plugins are never touched. The plugin maps opencode events onto
AO's three normalized activity events: session.created -> session-start,
message.updated/message.part.updated -> user-prompt-submit, and
session.status(idle) -> stop (NOT the deprecated session.idle, which is
unreliable under `opencode run`). It shells `ao hooks opencode <event>` via a
guarded sh -c so a missing `ao` binary is a silent no-op.
- A single approval flag. opencode exposes only --dangerously-skip-permissions
(no graduated accept-edits/auto) and no system-prompt flag, so those map to a
bypass-only permission flag and a documented no-op for the system prompt
(deferred to opencode's own config).
Launch uses the interactive TUI (`opencode --prompt <p>`); restore continues a
captured native session via `opencode --session <id>`.
opencode_test.go mirrors codex_test.go (12 tests) and the daemon wiring test now
asserts the opencode harness resolves.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(agent): address Greptile review on opencode adapter (#80)
- Dispatch all opencode plugin hooks synchronously (Bun.spawnSync). The
session.created handler previously fired session-start via an async
Bun.spawn; if opencode does not await the event handler, a following
message.updated -> user-prompt-submit (sync) could complete before the
in-flight async session-start, so AO would see the prompt before the session
was registered. A sync spawn blocks opencode's single-threaded event loop, so
events are now reported strictly in dispatch order. Removes the now-unused
async callHook helper.
- Fix package/doc comments that said .opencode/plugin/ (singular) to match the
plural .opencode/plugins/ the adapter actually writes to.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(agent): surface opencode hook failures instead of swallowing them
The activity plugin previously discarded every failure: callHookSync ignored
the subprocess exit code/stderr and both catch blocks were empty, so a failing
`ao hooks` invocation or a malformed event payload was completely invisible.
Now failures are reported through opencode's structured logger (client.app.log)
while still never crashing opencode:
- callHookSync pipes stderr and checks result.success; a non-zero exit (a real
`ao hooks` failure — the `command -v ao` guard makes a missing binary exit 0)
is logged with its exit code and stderr.
- spawn exceptions (e.g. no `sh`) are caught and logged.
- the event-handler catch logs the offending event type instead of swallowing.
- logHookFailure is itself best-effort (optional-chained, rejection swallowed),
so logging can never throw back into opencode.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(agent): address opencode adapter review — install guard, prompt dedup, hook timeout
Maintainer review on #80 surfaced three pre-merge issues:
- GetAgentHooks could clobber a user file: install overwrote
.opencode/plugins/ao-activity.ts unconditionally while uninstall was
sentinel-guarded. Install now refuses (loud error) to overwrite a file that
isn't AO-managed; absent/AO-managed targets still write idempotently.
- Empty-prompt report poisoned the dedup: message.updated fired
user-prompt-submit with an empty prompt AND marked the message seen, so the
text from the following message.part.updated was deduped away and never
reached AO — breaking title-from-prompt. reportUserPrompt now reports at most
twice: an optional early empty report (keeps run-mode flows active) that does
NOT block a later text report, and a text report that is terminal.
- Bun.spawnSync had no timeout, so a hung `ao hooks` could block opencode
indefinitely. Each spawn is now time-boxed at 30s, matching the claude-code
and codex hook timeouts.
Adds TestGetAgentHooksRefusesToClobberForeignFile and a spawn-timeout assertion.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix: harden opencode activity hooks
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: harshitsinghbhandari <24b4506@iitb.ac.in>