Commit Graph

9 Commits

Author SHA1 Message Date
whoisasx 8449f5b856 Merge remote-tracking branch 'origin/main' into ao/reverbcode-2/issue-2272-prompts
# Conflicts:
#	backend/internal/adapters/agent/amp/amp.go
#	backend/internal/adapters/agent/continueagent/continueagent.go
#	backend/internal/adapters/agent/copilot/copilot.go
#	backend/internal/adapters/agent/kiro/kiro.go
#	backend/internal/adapters/agent/opencode/opencode.go
#	backend/internal/adapters/agent/vibe/vibe.go
2026-07-05 01:05:18 +05:30
Harshit Singh Bhandari 2c08597ee6
refactor(adapters): cut ~3,100 LOC of redundancy in the agent adapter layer (#2349) (#2355)
* 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>
2026-07-04 20:49:15 +05:30
whoisasx 9e39df43cf Merge remote-tracking branch 'origin/main' into ao/reverbcode-2/issue-2272-prompts
# Conflicts:
#	backend/internal/adapters/agent/copilot/copilot.go
#	backend/internal/adapters/agent/opencode/opencode.go
#	backend/internal/adapters/agent/opencode/opencode_test.go
#	backend/internal/adapters/agent/vibe/vibe.go
#	backend/internal/service/session/service.go
#	backend/internal/service/session/service_test.go
#	backend/internal/session_manager/manager.go
#	docs/agent/README.md
2026-07-04 19:45:13 +05:30
NIKHIL ACHALE a639e2025c
feat: add agent catalog/auth API and safer orchestrator switching (#2309)
* 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>
2026-07-04 10:59:34 +05:30
whoisasx fc19c48f39 fix: align adapter prompt injection 2026-07-04 01:31:21 +05:30
Ashish Huddar 40bd2dfb2b
fix(sessions): stop AO hook files from making every worktree permanently dirty (#169)
* fix(sessions): stop AO hook files from making every worktree permanently dirty

Agent adapters write hook files (.codex/hooks.json, .opencode/plugins/
ao-activity.ts, .claude/settings.local.json, ...) into fresh session
worktrees as untracked files. `git worktree remove` (deliberately run
without --force) refuses on any untracked file, so Workspace.Destroy
failed for every session of the 12 workspace-writing harnesses:
POST /sessions/{id}/kill returned an unlogged 500 INTERNAL_ERROR and
`ao session cleanup` reported 'Would clean N' then '0 sessions cleaned'
with no reason, leaking workspaces forever.

Three coordinated fixes, none of which force-deletes user/agent work:

- Root cause: every adapter now writes a sentinel-guarded, self-ignoring
  .gitignore next to its hook files (hookutil.EnsureWorkspaceGitignore),
  so AO's own files no longer count as dirt while anything an agent
  drops — even in the same directory — still blocks teardown. A
  registry-wide conformance test enforces the contract for all current
  and future adapters. (Per-worktree .git/worktrees/<name>/info/exclude
  was evaluated first but git does not honor it.)
- Typed refusal: gitworktree.Destroy classifies a still-dirty refusal as
  ports.ErrWorkspaceDirty (git status probe). Kill maps it to success
  with freed=false (session terminated, worktree preserved); Cleanup
  reports it per-session as skipped-with-reason through the API
  (CleanupSessionsResponse.skipped), and the CLI prints
  'Skipped: <id> (workspace has uncommitted changes)' plus a summary.
- Observability: envelope.WriteError records the raw service error into
  a request-scoped slot and the access log attaches it to 5xx lines, so
  any remaining internal error is diagnosable server-side.

Worktrees created before this fix gain the .gitignore on restore (hook
install re-runs); their cleanup is otherwise reported as skipped instead
of erroring.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(cleanup): address Greptile P2s — surface dirty-probe failures, stop leaking raw errors

Two review findings on this PR:

- gitworktree.Destroy: when the isDirty probe itself failed, the error was
  silently discarded and the refusal looked identical to "registered but not
  dirty". The probe failure now rides the returned error (dirty probe: ...),
  so it reaches the access log via the 5xx error capture.

- Cleanup skip reasons: a non-dirty teardown failure put the raw error —
  including internal filesystem paths — into the public skipped[].reason
  field. The public reason is now the fixed string "workspace teardown
  failed"; the full cause goes to the daemon log (warn, with sessionID and
  path). The dirty-refusal reason is unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(gitworktree): wrap the dirty-probe error with %w per errorlint

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 11:06:45 +05:30
yyovil 3152cdc948
feat(agents): agent platform — registry, activity hooks, harness allowlist (#119)
Introduces the shared platform that per-agent adapters plug into, wired for the
three shipped harnesses (claude-code, codex, opencode):

- adapters/agent/registry: single source of truth for shipped adapters
  (Constructors), consumed by the daemon to resolve a session's harness.
- adapters/agent/activitydispatch + 'ao hooks' command: maps an agent's native
  hook callbacks onto AO activity states (active/idle/waiting/...).
- claudecode/codex/opencode: emit SessionStart/UserPromptSubmit/Stop activity.
- HTTP + OpenAPI: report session activity state.
- db: single migration widening sessions.harness to all shipped harnesses, so
  adding an adapter needs no further migration.
- domain: harness constants + --agent alias for 'ao spawn'.

Adding a new agent is now one adapter package plus a line in Constructors().

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Harshit Singh Bhandari <claudeagain@pkarnal.com>
2026-06-07 00:52:40 +05:30
yyovil 3c7344b233
[codex] add ao hooks activity command (#113)
* feat: add ao hooks activity command

* fix(activity): address review nits

- lcm: sameActivity ignores LastActivityAt so same-state repeats no-op
  and don't churn UpdatedAt / CDC events.
- cli/hooks: surface stdin read errors to stderr for parity with the
  daemon-error path; still exit 0 so a failed hook can't break the agent.
- claudecode: GetAgentHooks docstring covers Notification + SessionEnd
  (the slice already included them; only the comment was stale).

---------

Co-authored-by: harshitsinghbhandari <dev@theharshitsingh.com>
2026-06-06 20:29:00 +05:30
yyovil e25b2ad4de
feat(agent): opencode adapter + activity plugin hooks (#80)
* 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>
2026-06-03 17:06:32 +05:30