- Fix autoDetectProject path matching: expand ~ before comparing project
paths to cwd, so `path: ~/my-repo` matches `/Users/user/my-repo`
- Fix addProjectToConfig: detect duplicate directory names and auto-suffix
instead of silently overwriting existing project entries
- Fix agent detect() in all 4 plugins: replace `which` (Unix-only) with
direct `--version` invocation for cross-platform compatibility
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace CPU-burning spin loops in running-state.ts with async setTimeout
and jittered backoff; make all exports async
- Fix TOCTOU race in acquireLock by extracting tryAcquire helper with
retry loop instead of force-remove-and-retry-once
- Hoist dynamic imports in addProjectToConfig/choice-2 to static imports
- Add try/finally around readline in detectAgentRuntime
- Validate session prefix uniqueness in "Start new orchestrator" menu
- Add ConfigNotFoundError class to @composio/ao-core, replace fragile
string matching in ao start with instanceof check
- Fix setup.sh to recommend `ao start` instead of deprecated `ao init`
- Fix start-all.ts: resolve next binary with fallback, wait for children
on SIGTERM instead of immediate process.exit
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove redundant project-existence check after autoDetectProject
- Wrap SIGTERM in try/catch for restart flow (dead process case)
- Remove unused setCallerContext export from caller-context.ts
- Fix unused vi import lint error in init.test.ts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add vi.mock() for running-state, caller-context, detect-env,
detect-agent, and project-detection modules imported by start.ts
- Without these mocks, vitest threads never exit (open handles)
- Remove init.test.ts test that triggered dynamic import of start.js
- Relax waitForPortAndOpen assertion (port resolution depends on
full dashboard startup which is mocked out)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix spawn hint in start.ts to use new single-arg syntax
- Remove dead addProjectOnly() export (add-project fully deleted)
- Make detect-agent.ts handle both named and default export shapes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When users run `ao spawn <project> <issue>`, show a yellow warning
explaining the new syntax (`ao spawn <issue>`) instead of Commander's
raw "too many arguments" error.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- spawn now takes only `[issue]` — project is always auto-detected
- batch-spawn now takes only `<issues...>` — no project prefix
- Commander rejects extra positional args automatically
- Update orchestrator prompt to remove projectId from spawn example
- Rewrite spawn tests to use auto-detected project (single project in config)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rewrite init.test.ts to match simplified deprecated init command
(old tests referenced removed --output, --auto, --smart flags)
- Add eslint-disable for consistent-type-imports in direct-terminal-ws.ts
(node-pty is optional, must use import() type annotations)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Change != null to !== undefined && !== null in caller-context.ts and
session-manager.ts (3 locations) to satisfy eqeqeq lint rule
- Add displayName field to all 4 agent plugin test manifest assertions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove unused getCallerType import from start.ts
- Fix ao stop orphaning dashboard: always run stopDashboard via lsof
after killing parent PID, since SIGTERM may not propagate to child
- Revert spawn single-project special case back to always matching
project ID (backward compat)
- Update README: replace ao init --interactive and ao add-project
references with ao start equivalents, update spawn syntax
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add advisory lockfile (O_EXCL) to running-state.ts to prevent TOCTOU
race when multiple ao start processes run concurrently
- Wait up to 5s for old process to exit after SIGTERM in Override menu,
escalate to SIGKILL if needed — prevents port conflict on restart
- Guard autoCreateConfig against overwriting existing config files —
returns existing config instead of silently replacing it
- Fix spawn single-arg disambiguation: in single-project configs, always
treat the arg as an issue ID (user never needs to specify project)
- Clean up running.json by deleting file instead of writing "null"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace require() with execFileSync in all 4 agent plugin detect()
functions — fixes ReferenceError in ESM-only environments
- Remove non-existent -p flag from orchestrator prompt spawn/batch-spawn
docs — prevents orchestrator agent from generating broken commands
- Return actual port from runStartup() and pass to register() — fixes
running.json storing wrong port when auto-escalation picks a free port
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reduces onboarding to `npm install -g @composio/ao && ao start`.
- Absorb init and add-project logic into `ao start` with auto-config
creation, environment detection, and project type detection
- Add single-instance tracking via running.json with already-running
interactive menu (human) and info+exit (agent)
- Add caller context detection (human/orchestrator/agent) via TTY and
AO_CALLER_TYPE env var
- Add plugin-based agent runtime detection — no hardcoded binary paths,
each plugin exports detect() and displayName
- Simplify `ao spawn` to just `ao spawn <issue>` with auto-detected
project (backward compat: `ao spawn <project> <issue>` still works)
- Set AO_CALLER_TYPE, AO_PROJECT_ID, AO_CONFIG_PATH, AO_PORT env vars
on all spawned sessions (worker, orchestrator, restore)
- Add `ao config-help` subcommand for config schema reference
- Deprecate `ao init` to thin wrapper, fully remove `ao add-project`
- Register/unregister in running.json on start/stop
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Updates the cd-prefix stripping regex to require a space before the
delimiter (&& or ;). This allows paths containing & or ; characters
to be matched correctly while still finding the command separator.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Store the regex pattern in a variable and remove confusing single quotes
from the character class. The pattern now uses [^&;]* to explicitly
exclude & and ; without mixing shell quoting into the regex pattern.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Publish @composio/ao-web dashboard as npm package (removed private flag,
added files field, production entry point, node-pty made optional)
- CLI auto-detects dev vs production mode for dashboard startup
- Use local next binary instead of npx in production start-all.ts
- findWebDir() throws with install-specific guidance instead of returning
broken path
- Fix CI-silent failure: setup.sh and ao-update.sh exit 1 on non-interactive
npm link failure
- Deduplicate detectDefaultBranch into shared cli/lib/git-utils.ts
- Add EACCES permission guidance to README.md and SETUP.md
- Move resolveProjectIdForSessionId to @composio/ao-core
- Update design doc with problems #8-13, changes #9-12, known limitations
section, and expanded test plan
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Every command now prints what to run next and from where:
- setup.sh → tells user to cd to project dir and run ao init
- ao init → tells user to run ao start (with directory context)
- ao add-project → tells user to run ao start and ao spawn
- ao start → tells user to run ao spawn <project> <issue>
Eliminates confusion about running commands in the wrong directory
(e.g., ao init inside agent-orchestrator instead of the project repo).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- npm link retry logic decision tree
- ao init auto vs interactive decision flow
- ao add-project 8-step pipeline diagram
- ao start port resolution flowchart
- Before/after horizontal bar chart for UX metrics
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Swap markdown design doc for a styled HTML version with dark theme,
before/after comparisons, impact metrics, and flow diagrams.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add design doc covering all changes, UX impact, and new flow
- Update README: add ao init, ao add-project, ao start to Quick Start and CLI sections
- Remove --auto flag from README examples (now the default)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- `ao init` now auto-detects project with zero prompts by default
- Old 13-prompt wizard moved to `ao init --interactive`
- Removed dead `--smart` placeholder flag
- `ao start` auto-finds next free port if configured port is busy
instead of crashing with an error
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix npm link EACCES permission error in setup.sh, ao-update.sh, and ao-doctor.sh
by auto-retrying with sudo when interactive
- Add `ao add-project <path>` command that auto-detects git remote, default branch,
project type, and generates agent rules — appends to existing config in one step
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(lifecycle): implement stuck detection using agent-stuck threshold
The agent-stuck reaction config supported a threshold field (e.g.
"10m"), but determineStatus() never returned "stuck" — there was no
code path that consumed the threshold or transitioned sessions based
on idle time. Sessions would stay parked at pr_open/working forever
even when the agent had been idle for hours.
Added idle-time check in determineStatus(): when getActivityState()
reports "idle" or "blocked" with a timestamp, compare the idle
duration against the agent-stuck.threshold config. If exceeded,
return "stuck" so the reaction system can fire notifications.
Also removed the priority !== "info" guard on transition
notifications, so all priority levels (including info) are routed
through notificationRouting. This lets the config control which
notifiers receive each priority level, rather than silently dropping
info-level transition events.
* fix(lifecycle): add post-PR stuck detection as safety net
The original stuck check in step 2 (before PR checks) can be bypassed
when getActivityState() returns null (session file not found, cache miss,
I/O failure). When this happens, the code falls through to the PR path
which returns 'pr_open' without ever checking idle duration.
Fix: extract isIdleBeyondThreshold() helper and call it in three places:
1. Step 2: before PR checks (fast path, catches most cases)
2. Step 4b: after PR checks return 'pr_open' (safety net)
3. Step 5: after all checks, for agents that finish without a PR
This ensures stuck detection fires even when the JSONL activity detection
fails to return idle state. Sessions can no longer get permanently stuck
at 'pr_open' when the agent has been idle beyond the threshold.
Also removes the debug console.error calls from the previous commit.
* fix(lifecycle): treat reviewDecision 'none' as approved for merge readiness
PRs with no required reviewers never reached 'mergeable' status because
getReviewDecision returned 'none', which was not handled. The lifecycle
poll fell through to 'review_pending' or the default, so merge.ready
never fired and the approved-and-green reaction never triggered.
Also: skip stuck short-circuit when session has an open PR so merge
readiness checks in step 4 can still run. Without this, idle agents
with open PRs get stuck status and never transition to mergeable.
Closes composio#0 (internal fix)
* fix(opencode): classify activity state from session timestamps
* test(lifecycle): cover opencode idle-threshold stuck transition
* fix(lifecycle): preserve global stuck threshold with project overrides
* fix(lifecycle): run PR auto-detection before stuck transitions
---------
Co-authored-by: Harsh <harshb012@gmail.com>
* perf: coalesce dashboard session refreshes
Batch membership-driven refreshes behind a short cadence and keep low-frequency steady-state refreshes so pause and PR data stay current without hammering /api/sessions during SSE churn.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
* perf: memoize dashboard session views
Keep unchanged zones and cards cold during same-membership SSE updates by stabilizing dashboard callbacks, caching project groupings, and memoizing the session view tree with a render-cadence regression test.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
* fix: prevent stale refresh scheduling after project switch
Abort in-flight refreshes and ignore late completions from disposed effects so old project fetches cannot re-arm timers or reset the new project state.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
---------
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
* docs: add CONTRIBUTING.md, expand development guide, fix broken CLAUDE.md links
- Add CONTRIBUTING.md covering bug reports, dev setup, plugin development, PR process
- Expand docs/DEVELOPMENT.md into a comprehensive architecture + conventions reference
(architecture overview, plugin pattern with full example, spawn flow, TypeScript and
shell command conventions, key design decisions, common dev tasks)
- Update README.md docs table to reference docs/DEVELOPMENT.md instead of gitignored CLAUDE.md
- Fix broken CLAUDE.md links in SETUP.md to point to docs/DEVELOPMENT.md
CLAUDE.md is gitignored (personal agent config) so links to it were always broken.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs: document ao update workflow and fix guide links
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Harsh <harshb012@gmail.com>
Treat persisted tmuxName as metadata-derived runtime identity when runtimeHandle is missing so active sessions are not misclassified as exited/unknown across agents.
* fix: gate fresh session sends on interactive readiness
Wait for spawning tmux-backed sessions to settle before injecting input, and use OpenCode session timestamps to confirm delivery without relying on pane churn alone.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
* fix: satisfy lint in opencode send regression helper
Remove unnecessary escaping in generated shell snippets used by the new OpenCode confirmation tests so CI lint passes cleanly.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
* fix: avoid false opencode delivery confirmation
Only treat OpenCode timestamp confirmation as delivered when updatedAt advances beyond a known baseline, and add regression coverage for transient baseline visibility.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
---------
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
* feat: add end-to-end observability across core, web, and terminal
Instrument lifecycle/API/websocket flows with correlation-aware metrics and operator health surfaces so the system can self-diagnose and escalate failures.
* fix: realign session restore set and unblock claim PR typecheck
* fix(web): restore project-filtered sessions route after main merge
* fix(core): remove unused orchestrator import to unblock lint
* fix(core): always record lifecycle poll failures and remove dead review branches
* fix(web): harden websocket metrics and reuse SSE observers
* fix(web): preserve primary session API errors when services bootstrap fails
* fix(web): use full orchestrator config type in SSE observer helper
* fix(web): restore project-scoped SSE and guard observability error paths
* fix(web): address remaining Bugbot review gaps
* fix(web): align SSE project attribution and share session project resolver
* fix(web): require request arg for SSE route and align tests
* fix(web): record websocket error disconnects as failures
* fix(web): use path alias for session project resolver import
* fix(web): include active connection count in disconnect metrics
* fix: skip PR auto-detection for orchestrator sessions
Orchestrator sessions sit on the base branch (e.g. master) and should
never own a PR. When the lifecycle worker ran detectPR for these
sessions, any PR whose head branch matched master (e.g. a master->prod
deploy PR) would get incorrectly attached and keep re-attaching after
manual cleanup.
Add a role=orchestrator check to the PR auto-detection guard so
orchestrator sessions are skipped entirely.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add session ID suffix fallback for orchestrator PR auto-detection skip
Pre-existing orchestrator sessions spawned before the role metadata field
was added lack role=orchestrator. Mirror the session-manager pattern by
also checking session.id.endsWith("-orchestrator") as a fallback.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Treat the all-projects dashboard as a project overview surface with per-project metrics and orchestrator access, while keeping the detailed kanban lanes for single-project workflows.
Drop the lifecycle manager's local orchestrator predicate so the final remaining core polling path follows the same shared detection logic as session cleanup, web filters, and CLI status.
Scan every orchestrator for active pause metadata instead of stopping at the first control session, so pause banners stay visible even when metadata-role orchestrators appear before the paused orchestrator in session listings.
Use one project-matching rule across the sessions API and SSR dashboard paths, and keep global pause derived from the full session set even when the API request is scoped to a single project.
Keep the SSR dashboard page using unified project filtering while clearing orchestrator links and pause state whenever enrichment fails, so error paths cannot render stale state beside an empty session list.
Use the same project matching logic for dashboard orchestrators and workers, and switch the client detail page to the lightweight core types entry so the canonical orchestrator helper stays shared without pulling server-only modules into the browser bundle.
Carry legacy project ownership through recovery, drop the redundant dashboard worker filter, and remove the now-unused orchestrator helper so the PR branch stays aligned with the shared per-project orchestration contract.
Use the core orchestrator detector in web filtering paths so SSE snapshots, backlog polling, and pause state all treat metadata-role orchestrators consistently with the dashboard and sessions API.