- Fix CI diff coverage and review feedback
- Fix test reliability for session attach, stop, and Windows attach
- Add coverage for session attach binary protocol and edge cases
- Clean up stdin listener + add resolvePipePath tests
- Address review comments + coverage for pipe relay
- Make 80 failing tests pass on Windows (cross-platform mocks, path assertions)
- Fix production code: execFile shell option for .cmd, isPathInside separator,
openclaw binary detection via `where` on Windows
- Add platform-aware test assertions for shell escaping, PATH handling, hooks
- Add signal forwarding comment for Windows dashboard process
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
- session.ts: restore isOrchestratorSession from core (checks both name
and metadata role) instead of name-only isOrchestratorSessionName
- session.ts: remove unused allSessionPrefixes after merge conflict
- start.test.ts: update stop command tests for sm.list() flow
- toClaudeProjectPath: remove speculative space replacement, keep only
verified chars (/ : .) — addresses review comment about Unix breakage
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- session.ts: use isOrchestratorSessionName (renamed in main) for JSON output
- start.test.ts: update stop command tests to use sm.list() instead of sm.get()
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- cli/session: add Windows ao session attach via named pipe relay with
raw stdin mode and Ctrl+\ to detach; skip getTmuxActivity on Windows
- cli/start: fix ao stop looking for "tr-orchestrator" instead of the
actual numbered session (e.g. tr-orchestrator-5) — also fixes Linux
- agent-claude-code: fix toClaudeProjectPath dropping Windows drive colon
(C:\→C- not C) breaking JSONL lookup; ignore stale JSONL entries from
previous sessions in reused worktrees
- pty-client: use \r (carriage return) instead of \n for PTY Enter key
Addresses blockers W13 (partial), W14.
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
- 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>
Our Windows-specific files were written before the @composio → @aoagents
rename landed. Update all affected imports across runtime-process,
workspace-clone, workspace-worktree, cli commands, and test files.
Prevents duplicate SIGINT/SIGTERM handlers if called more than once for
the same ChildProcess — avoids double killProcessTree and racing
process.exit(1) from stacked SIGKILL fallback timers.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The function was a one-line pass-through to findPidByPort with no added
logic. Callers now import findPidByPort from @composio/ao-core directly.
waitForPortFree calls findPidByPort inline. Deleted the test file that
only tested the pass-through.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
pwsh and powershell.exe cannot run bash scripts any more than cmd.exe
can — shebangs are ignored and bash-specific syntax fails. The previous
guard only matched cmd.exe, allowing pwsh (the most common Windows
fallback) to silently invoke -File on a bash script and produce a
confusing PowerShell syntax error.
Simplify to: throw on any Windows shell without AO_BASH_PATH. Also
removes the now-dead getShell() call and -File code path from
script-runner.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Spawning with detached: true unconditionally creates a new console
window on Windows. Use the same !isWindows() pattern established
elsewhere in this PR so the process group behaviour is correct on
both platforms. killProcessTree already uses taskkill /T on Windows
so cleanup is unaffected.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- fix(platform): always use /bin/sh on Unix instead of \$SHELL so
postCreate commands and runtime launches work correctly when the
user's login shell is non-POSIX (fish, nushell, etc.)
- fix(script-runner): detect cmd.exe fallback on Windows and throw a
clear, actionable error pointing to AO_BASH_PATH rather than passing
the PowerShell-specific -File flag to cmd.exe (which produces a
cryptic error and still can't run bash scripts)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
If the child exits before the 5-second escalation window, the fallback
setTimeout would still fire and call process.exit(1). Track the timer
in the outer scope so the child.once("exit") handler can cancel it.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Extract forwardSignalsToChild(pid, child) into shell.ts — eliminates verbatim
duplication of the SIGTERM/SIGKILL forwarding logic between dashboard.ts and start.ts
- Fix build script: replace node -e "require(...)" with node --input-type=commonjs -e
"require(...)" — required because package is "type":"module" and require is not
available in node -e by default in ESM context
- Fix duplicate import in shell.ts (no-duplicate-imports lint error)
- Reject Windows drive-letter (C:\) and UNC (\server\share) paths in symlink
validation — previously only Unix absolute paths starting with "/" were blocked
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove getEnvDefaults from @composio/ao-core public API — no production callers;
the function remains in platform.ts for future use (B10/B11)
- Add 5 s SIGKILL fallback in dashboard.ts and start.ts forward() handlers so the
parent process cannot hang indefinitely if the child ignores SIGTERM
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PowerShell -Command does not forward argv elements after the command string to the
script — they are treated as top-level PowerShell args and silently dropped. Using
-File passes remaining args as positional parameters ($1, $2, …) to the script, so
e.g. `ao doctor --fix` correctly reaches the script on Windows.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Detached children run in their own process group, so Ctrl+C does not reach
them. Without forwarding, the dashboard holds the port after the parent exits.
Matches the identical pattern in start.ts lines 1154-1165.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without detached:true on Unix, killProcessTree(pid) calls process.kill(-pid)
which targets a process group the child never owns — ESRCH causes fallback to
direct kill, leaving grandchild processes alive. Matches the pattern already
used in start.ts lines 782 and 795.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
getShell() on Unix returns process.env.SHELL || /bin/sh, which may be zsh,
fish, or plain sh. When a script file is passed as an argument to these
shells (file mode), the #!/bin/bash shebang is ignored and bash-specific
syntax in ao-doctor.sh / ao-update.sh / setup.sh breaks.
Fix: hardcode bash on Unix (AO_BASH_PATH still overrides it), use getShell()
only on Windows where bash is unavailable.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix(windows): platform-aware shell for workspaces and script-runner (B07, B08, B19)
B07: workspace-worktree and workspace-clone use getShell() instead of sh -c.
B08: script-runner spawns scripts in file-mode on Unix (so $1/$2/$3 reach
positional args) and uses getShell() on Windows; AO_BASH_PATH override
uses || so empty string is treated as unset.
B19: workspace-worktree symlink falls back to cpSync on Windows.
Also fixes path separator check in workspace-worktree to use path.sep
instead of hardcoded "/" for correct Windows behaviour.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The forward handler now self-removes both listeners before calling
killProcessTree, so a second signal cannot invoke it again on an
already-dead PID.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two Bugbot issues from the detached-dashboard and killProcessTree changes:
1. Dashboard Ctrl+C orphan: with detached:true on Unix, the dashboard is in
its own process group and does not receive SIGINT from the terminal. Add
process.once(SIGINT/SIGTERM) handlers that forward the signal via
killProcessTree so the entire dashboard group is reaped on exit. Handlers
are cleaned up when the dashboard exits to avoid leaks.
2. stopLifecycleWorker wrong return value: killProcessTree swallows ESRCH,
so a stale PID entry (process already dead) now returned true ("stopped")
instead of false ("not running"). Add an isProcessRunning guard before
the kill to restore the original semantics.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dashboard was spawned with detached:false, so killProcessTree's
process.kill(-pid) failed with ESRCH (not the group leader) and fell
back to killing only the listening process, orphaning Next.js workers.
Matches the runtime-process pattern: detached:!isWindows() makes the
dashboard the process group leader on Unix so the negative-PID group
kill in killProcessTree correctly reaps all children. On Windows,
detached:false is preserved — taskkill /T /F handles the tree kill
by PID regardless of process group membership.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fixes B05 and B06: replaces all Unix-only process management with the
platform adapter so AO works on Windows with runtime: process.
- dashboard stop/rebuild uses findPidByPort() (netstat on Windows, lsof on Unix)
- runtime-process destroy uses killProcessTree() (taskkill /T /F on Windows,
negative-PID SIGKILL on Unix) with conditional detached flag
- start.ts restart, ao stop --all, and stop-dashboard paths all switched
from process.kill() to killProcessTree() so child processes are reaped
- lifecycle-service stopLifecycleWorker() replaced with killProcessTree()
- Fixed destroy() hang: exit listener now registered before awaiting kill
so fast-exiting processes don't fire before the listener attaches
Co-Authored-By: Claude Sonnet 4.6 <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>
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>