Orchestrator sessions are control-plane sessions that clutter the ls
output alongside worker sessions. Filter them out using the existing
`isOrchestratorSessionName()` helper. Add `--all` / `-a` flag to
include them when needed.
Closes#1088
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The --decompose flag and supporting decomposer module had two
unfixable bugs (#1045): it crashed when ANTHROPIC_API_KEY was unset,
and it created multiple branches/PRs per issue, fragmenting history
and complicating review/merge. Removing the feature instead of
patching either bug.
- Delete packages/core/src/decomposer.ts and all re-exports
- Drop @anthropic-ai/sdk dependency from @composio/ao-core
- Remove --decompose / --max-depth options from ao spawn
- Remove decomposer field from ProjectConfig (zod default-strip
silently ignores existing decomposer: blocks in user yaml)
- Remove lineage / siblings from SessionSpawnConfig and the
prompt-builder Layer 4 block (only used by decomposer)
- Gut the matching backlog reactor branch in web/services.ts
so the polling path no longer hits the same bugs
- Remove decompose parameter from openclaw-plugin ao_spawn tool
- Drop decomposer mocks from web services.test.ts
1. Add symlink check for .cursor directory in extractCursorSummary
to match getCursorSessionMtime behavior (prevents path traversal)
2. Add vitest alias for @aoagents/ao-plugin-agent-cursor in CLI tests
(fixes missing module resolution in tests)
3. Add lstatSync check before readFileSync in getLaunchCommand
to reject symlinked systemPromptFile paths (security hardening)
4. Add test coverage for symlink rejection behavior
Co-Authored-By: Claude <noreply@anthropic.com>
- Resolve @composio → @aoagents package renaming conflicts
- Add cursor agent to BUILTIN_PLUGINS in plugin-registry.ts
- Add cursor agent to AGENT_PLUGINS in detect-agent.ts
- Add cursor agent import and registration in plugins.ts
- Add cursor agent dependency and import in web services.ts
- Update cursor plugin package naming to @aoagents/ao-plugin-agent-cursor
- Add cursor agent to changeset linked group
- Fix test imports to use new @aoagents package naming
Co-Authored-By: Claude <noreply@anthropic.com>
Renames all npm package scopes from @composio/* to @aoagents/* and
updates GitHub repo references from ComposioHQ/agent-orchestrator
to aoagents/ao throughout the codebase.
- All package.json names and dependencies
- README badges, links, and install instructions
- Documentation references
- Changeset config
- Source code imports and test files
Remove the post-startup "Next step: ao spawn <issue-number>" hint
per reviewer feedback — the dashboard already guides users.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace hardcoded magic number 3000 across spawn.ts, session.ts,
open.ts, dashboard.ts, and start.ts with a shared DEFAULT_PORT
constant from lib/constants.ts. Fixes Bugbot review feedback.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add mockClear() before mockReturnThis() in spawn test beforeEach to
prevent call history accumulating across tests. Fixes Bugbot review
feedback about stale mock.calls.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When dashboard is disabled, print `ao session attach <id>` instead of
an unreachable dashboard URL. Fixes Bugbot review feedback.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace raw `tmux attach -t` commands in CLI output with web dashboard
URLs (`http://localhost:{port}/sessions/{sessionId}`) across all four
CLI commands: spawn, session restore, open, and start.
Add `stripHashPrefix` helper in session-utils to extract AO session IDs
from hash-prefixed tmux session names. Remove unused `tmuxTarget`
variable from start command.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Address review feedback:
- Remove duplicate created/spawned messages — use single spinner.succeed
- Add "(if running)" qualifier for dashboard mention since ao spawn
does not start the dashboard itself
- Update test mock to expose spinner for output assertions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace verbose multi-line spawn output (worktree, branch, raw tmux
attach) with a single-line message that directs users to the dashboard
or `ao session attach <id>` instead of exposing internal tmux session
hashes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When dashboard is enabled, `ao start` now prints the session detail page
URL (e.g. http://localhost:3000/sessions/<id>) instead of the tmux attach
command. Falls back to tmux attach when --no-dashboard is used.
Closes#947
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: reduce dashboard JS bundle from 1.7MB to 170KB (gzipped) (#792)
Switch `ao start` default from `next dev` (7.6MB uncompressed) to optimized
production builds (128KB per route). Add `--dev` flag for HMR when editing
dashboard UI. Add bundle analyzer, server-only guards, and lazy-load
DirectTerminal via next/dynamic.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: skip dashboard rebuild when assets exist, fix CI timeout
Skip the production build step when .next/BUILD_ID and dist-server/
already exist (e.g. after pnpm build in CI). Add c8 ignore for
untestable process-spawning startup code to fix diff coverage.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: adopt PR #903 patterns — centralize rebuild logic and add preflight web artifact checks
Extract rebuildDashboardProductionArtifacts into dashboard-rebuild.ts, add
isInstalledUnderNodeModules/assertDashboardRebuildSupported guards, remove
findProcessWebDir, and verify .next/BUILD_ID + dist-server/start-all.js in
preflight. Dashboard command now always uses production server.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: skip production preflight in --dev mode, add coverage for rebuild helpers
- Skip preflight.checkBuilt() when --dev is passed (dev mode uses HMR,
doesn't need .next/BUILD_ID or dist-server/start-all.js)
- Add c8 ignore to dashboard.ts process-spawning code (matches start.ts pattern)
- Add tests for rebuildDashboardProductionArtifacts (success, failure, npm guard)
- Add preflight tests for npm-install web artifact hint paths
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: align preflight skip with actual dev-server condition
Only skip production artifact preflight when both --dev is passed AND
we're in the monorepo (where dev mode actually works). For npm global
installs, --dev is silently ignored and production server runs, so
preflight must still validate .next/BUILD_ID and dist-server/start-all.js.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: match @next/bundle-analyzer version to next@^15.1.0
The @next/* packages follow the Next.js release train. Pin the bundle
analyzer to ^15.1.0 to match the project's next dependency.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: correct recovery command for npm installs and remove redundant guard
- Change stale-build recovery suggestion from "ao update" (which only
works in source checkouts) to "npm install -g @composio/ao@latest"
for npm global installs
- Remove redundant assertDashboardRebuildSupported call in dashboard.ts
since rebuildDashboardProductionArtifacts already calls it internally
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): ao start navigates to session page instead of orchestrator selection
When ao start finds existing orchestrators, it now auto-selects the most
recently active one and opens /sessions/{id} directly, rather than the
/orchestrators selection page. This matches the behavior users expect:
landing on the agent terminal immediately on startup.
Closes#954
* fix(cli): navigate to session page for single orchestrator, selection page for multiple
When ao start finds existing orchestrators:
- 1 orchestrator: navigate directly to /sessions/{id} (fix for #954)
- 2+ orchestrators: keep /orchestrators?project={id} selection page so users
can choose among sessions or spawn a new one — the main dashboard only
links one orchestrator per project, making the selection page the only
startup path for multi-orchestrator projects.
Addresses review feedback on #958.
* fix(notifier): remove desktop notifications from all default configs (#960)
Desktop notifications via osascript open blank Finder windows on macOS
without providing useful information. Remove 'desktop' from all default
notifier lists so new users are not affected. Existing configs that
explicitly list 'desktop' continue to work unchanged.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(cli): add coverage for autoCreateConfig default notifiers
Line 585 in start.ts (`notifiers: []`) was not covered by the diff
coverage check. Added a test that exercises `autoCreateConfig` via
`createConfigOnly()`, verifying that the generated config does not
include 'desktop' in `defaults.notifiers`.
Required infrastructure additions:
- Mock `node:process` so `import { cwd } from "node:process"` in
start.ts can be overridden per-test via `mockProcessCwd`
- Set `detectProjectType` mock to return `{ languages: [], frameworks: [] }`
instead of null to avoid crash in autoCreateConfig
Closes#960
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(config): disable all notifications by default — fully opt-in
Change DefaultPluginsSchema.notifiers default from ["composio"] to []
and notificationRouting defaults to all empty arrays, so no notifications
are sent unless the user explicitly configures them. Addresses reviewer
feedback that composio notifier should not be active out of the box.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(config): use empty object as notificationRouting default
Empty array entries like { urgent: [] } block the ?? fallback in
notifyHuman (lifecycle-manager.ts:1169) because [] is not null/undefined.
Using {} lets unlisted priorities fall back to defaults.notifiers, so
explicit per-user notifier config is respected.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* Revert "fix: pause workers on model limits and stabilize session visibility (#367)"
This reverts commit 003eb78adb.
* fix: resolve post-revert type errors and broken test references
- Fix dangling import { in session-manager.ts (leftover from removing globalPause imports)
- Fix duplicate registerStop body in start.ts (leftover parent-version code after catch block)
- Remove --keep-session flag from stop command (was added by #367)
- Fix PullRequestsPage.tsx useSessionEvents call removing dropped initialGlobalPause arg
- Remove globalPause test cases from spawn.test.ts, communication.test.ts, api-routes.test.ts
- Remove unused updateMetadata imports from test files
* fix: remove unused allSessions variable after globalPause removal
- Fix tmux target to use session ID when runtimeHandle is missing,
preventing references to non-existent sessions
- Extract mapSessionsToOrchestrators helper to eliminate duplicate
orchestrator listing logic between page.tsx and API route
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update existing test to verify the new --no-dashboard auto-select
behavior and add a separate test for dashboard-enabled selection
message.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When --no-dashboard is used and existing orchestrators are found,
auto-select the most recently active one instead of deferring to
dashboard selection (which isn't available). This ensures the CLI
remains usable without the dashboard.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The sm.list() call was outside the existing try/catch that handles
orchestrator setup failures. If listing sessions throws, the spinner
could be left running and the dashboard process could leak.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When ao start is run and existing orchestrator sessions exist for the
project, the CLI now skips spawning a new one. Instead:
- Detects existing orchestrator sessions before spawning
- Opens the dashboard to a new /orchestrators page for session selection
- Users can resume an existing orchestrator or start a new one
Changes:
- packages/cli/src/commands/start.ts: Check for existing orchestrators,
redirect to selection page if found
- packages/web/src/app/api/orchestrators/route.ts: Add GET endpoint to
list orchestrators for a project
- packages/web/src/app/orchestrators/page.tsx: New page for orchestrator
selection
- packages/web/src/components/OrchestratorSelector.tsx: UI component for
selecting or spawning orchestrators
- packages/web/src/components/__tests__/OrchestratorSelector.test.tsx:
Tests for the selector component
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: support multiple concurrent orchestrators with isolated worktrees
- Each orchestrator session gets a numbered ID ({prefix}-orchestrator-N)
and an isolated git worktree, replacing the single shared orchestrator
- reserveNextOrchestratorIdentity atomically reserves the next available
number and detects conflicting project prefix configurations early
- isOrchestratorSession / isOrchestratorSessionName accept optional
allSessionPrefixes for cross-project false-positive prevention
- getProjectPause and resolveGlobalPause track the longest active pause
across all concurrent orchestrators instead of returning the first found
- cleanupWorktreeAndMetadata helper used consistently on all failure paths
including post-launch; system prompt file included in cleanup
- pollBacklog, status.ts, ProjectSidebar, sessions page, global-pause,
project-utils, serialize, and sessions API route all pass
allSessionPrefixes to isOrchestratorSession
- Web sessions/[id]/page.tsx fetches project prefix map and passes it
through prefixByProjectRef to avoid stale closure in fetchProjectSessions
* fix: seed sseAttentionLevels from fresh sessions on full refresh
When scheduleRefresh dispatches a reset action, derive sseAttentionLevels
from the freshly fetched sessions using getAttentionLevel. This clears
phantom entries for removed sessions and seeds correct levels for new
sessions, preventing stale favicon color and attention counts until the
next SSE snapshot.
* fix: merge duplicate @/lib/types imports into single import statement
Combining the separate import type and value import from @/lib/types
into one import to satisfy the no-duplicate-imports lint rule.