Commit Graph

275 Commits

Author SHA1 Message Date
harshitsinghbhandari cab0a2656d feat(core): add explicit agent reporting for workflow coordination (Stage 3)
Introduce an explicit reporting channel so worker agents can self-declare
their workflow phase (started/working/waiting/needs-input/fixing-ci/
addressing-reviews/completed). Fresh reports are trusted over weak inference
but runtime death, activity-based waiting_input, and SCM ground truth still
take precedence.

- Add `applyAgentReport`, validator, canonical mapping, and freshness helper
  in `packages/core/src/agent-report.ts`.
- Wire the fallback into `determineStatus` just before the idle-beyond-
  threshold promotion, skipping orchestrator and terminal sessions.
- Add `ao acknowledge` and `ao report <state>` CLI commands. Both resolve
  the session from `AO_SESSION_ID` when no argument is passed.
- Teach the base agent prompt and orchestrator prompt about the new
  reporting commands.
- Ship unit tests covering normalization, mapping, transition validation,
  metadata persistence, freshness, and first-start behavior.

Stage 3 of the state-machine redesign (see aa-2/state-machine-redesign-
rollout-plan.md).
2026-04-17 10:11:03 +05:30
Harshit Singh Bhandari 47c4b877f7
Merge branch 'ComposioHQ:main' into sessions-redone 2026-04-17 10:06:26 +05:30
Harshit Singh Bhandari 42e9be13a5
Merge pull request #114 from harshitsinghbhandari/plan/stage1-lifecycle-foundation
Plan/stage1 lifecycle foundation
2026-04-16 22:09:41 +05:30
yyovil f4870c41c9 Merge remote-tracking branch 'origin/main' into yyovil/fix-issue-1175
# Conflicts:
#	packages/core/src/__tests__/orchestrator-prompt.test.ts
#	packages/core/src/orchestrator-prompt.ts
2026-04-15 22:08:28 +05:30
Adil Shaikh ba77929c93
Merge pull request #1158 from ComposioHQ/feat/issue-1154
fix(cli): stop writing broken yaml when `ao start` runs in a new folder
2026-04-15 15:10:10 +05:30
harshitsinghbhandari d466118450 feat(core): add canonical lifecycle persistence foundation 2026-04-15 12:41:06 +05:30
adil 6d6822e501 refactor(cli): extract shared repo helpers and support GitLab subgroups
- New repo-utils.ts with extractOwnerRepo() and isValidRepoString()
  shared across detectEnvironment, autoCreateConfig, addProjectToConfig
- Remote regex now supports GitLab subgroup paths (group/subgroup/repo)
- Repo validation accepts multi-segment paths (owner/repo and deeper)
- Updated prompt text to mention group/subgroup/repo format
- Updated ProjectConfig.repo docstring to be provider-neutral
- Tests import from shared helpers instead of duplicating regex

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 12:30:32 +05:30
adil bd417aa670 fix(cli): handle undefined return from clack text() prompt
@clack/prompts text() can return undefined when submitted with just
the placeholder value. Guard with typeof check in promptText and
defensive (entered || "") in both callers to prevent .trim() crash.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 12:21:38 +05:30
adil 72e3620b8d test: add tests for optional repo across all changed modules
- detect-env: test GitHub/GitLab HTTPS/SSH remote extraction, unknown
  hosts returning null, missing remote, and non-git directories
- repo-validation: test the anchored regex accepts owner/repo, rejects
  empty, lone slash, missing segments, whitespace, and nested paths
- config-validation: test SCM/tracker inference skipped when repo is
  missing or has no slash, and inferred correctly with owner/repo
- scm-webhooks: test eventMatchesProject returns false when project
  has no repo configured
- orchestrator-prompt: existing test covers repo:undefined → "not configured"
- prompt-builder: existing test covers BASE_AGENT_PROMPT_NO_REPO selection

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 12:06:09 +05:30
adil 536e38b7e6 fix(cli): anchor repo regex and widen remote detection for GitLab
- Anchor repo validation regex with $ to reject trailing junk like
  "acme/repo extra" or "acme/repo#frag" — both prompt locations
- Widen detectEnvironment and addProjectToConfig remote regex to
  match gitlab.com in addition to github.com, so GitLab repos get
  auto-detected owner/repo instead of silently skipping it

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 11:33:07 +05:30
adil 101a725530 fix(test): use vi.spyOn for isHumanCaller after restoreAllMocks
afterEach calls vi.restoreAllMocks() which restores the top-level mock
to the real function. Use vi.spyOn on the module namespace instead of
vi.mocked on the destructured import so the mock survives restoration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 03:46:27 +05:30
adil e685db9d88 fix(test): mock isHumanCaller as false in autoCreateConfig test
The test has no ownerRepo detected, which triggers the interactive
repo prompt. Mock isHumanCaller to false so the prompt is skipped
in the non-interactive test environment.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 03:43:03 +05:30
adil 9db0945b0e fix: address follow-up review comments from @illegalcall
1. Fix ao start <path> regression: when target path differs from cwd,
   run autoCreateConfig on the target (which is a git repo) instead of
   cwd (which may not be). Removes the double-create pattern that added
   a second project entry.

2. Gate remaining PR/CI sections in orchestrator-prompt: PR Takeover,
   PR Review Flow, Bulk Issue Processing, and Monitoring Progress
   details are now wrapped in project.repo checks so repo-less projects
   don't get contradictory instructions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 03:38:38 +05:30
Adil Shaikh 2bb09498d4
Merge pull request #1159 from ComposioHQ/feat/issue-1150
fix(cli): prevent duplicate YAML entry on already-running `ao start`
2026-04-15 03:38:20 +05:30
adil 05a34913e3 fix(cli): address PR review feedback
- Move ensureGit() after path dedup check so already-registered paths
  return early without requiring git
- Use realpathSync for canonical path comparison (resolves symlinks,
  case variants, trailing slashes)
- Bail out with error when both SIGTERM and SIGKILL fail to stop AO
  instead of unconditionally unregistering a live instance
- Rewrite path-dedup test to exercise the path-arg branch via
  AO_CONFIG_PATH, covering addProjectToConfig's dedup lines

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 03:10:23 +05:30
adil d63231a6ea fix(test): update autoCreateConfig test to use isGitRepo: true
The test was mocking detectEnvironment with isGitRepo: false, which now
correctly triggers the fail-fast error for non-git directories. Updated
to isGitRepo: true since the test is verifying config generation
defaults, not non-git behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 03:07:12 +05:30
adil c8af50fac2 fix: address all 9 review comments from @illegalcall
1. prompt-builder: gate PR/CI instructions on project.repo — use
   trimmed BASE_AGENT_PROMPT_NO_REPO when no remote configured
2. orchestrator-prompt: gate Quick Start and Available Commands
   sections on project.repo — omit issue/PR commands when absent
3. types.ts: add changeset (minor for ao-core) with migration note
4. config.ts: consistent includes("/") guard for tracker inference
5. start.ts: fail fast with clear error when run in non-git directory
6. start.ts: stricter repo validation regex (requires non-empty
   segments on both sides of slash)
7. start.ts: addProjectToConfig now prompts for repo like
   autoCreateConfig does, with matching warning message
8. scm-webhooks.ts: pre-filter projects without repo in
   findWebhookProjects to skip unnecessary SCM plugin lookups
9. lifecycle-manager.ts: fix GitLab subgroup split — use lastIndexOf
   to correctly handle group/subgroup/repo paths

Closes #1154

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 03:04:12 +05:30
adil 80932f367a fix(cli): address review — use exit handler, verify PIDs, filter kills (#645)
1. Replace SIGINT/SIGTERM handlers with a process `exit` handler to avoid
   conflicting with the shutdown handler that flushes lifecycle state and
   exits with the correct code (130 for SIGINT).

2. Expand dashboard process pattern to match dev mode (next dev, ao-web)
   in addition to production (next-server, start-all.js).

3. Only kill dashboard-matching PIDs from lsof output, leaving unrelated
   co-listeners (sidecars, SO_REUSEPORT) untouched.

4. Use killDashboardOnPort for the first port attempt too, preventing
   blind kills on the configured port when running.json is stale.

5. Add test for mixed-PID filtering on a single port.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 03:01:41 +05:30
adil 47e14782d1 fix(cli): clean up signal listeners when dashboard exits
Remove SIGINT/SIGTERM/exit listeners from process when the dashboard
child exits, preventing listener accumulation if runStartup is called
multiple times in the same process.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 22:34:55 +05:30
adil 9ae7c00cef test: add coverage for optional repo and ignore interactive prompt lines
- Add test for orchestrator-prompt with repo: undefined (verifies
  "not configured" fallback instead of showing literal "undefined")
- Add c8 ignore for interactive prompt code in autoCreateConfig and
  promptText (same pattern as existing promptConfirm/promptSelect)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 22:13:03 +05:30
adil 4c31685584 fix(cli): prompt user for repo when remote is not auto-detected
Instead of silently omitting the repo field when no GitHub remote is
found, interactively ask the user to enter their owner/repo. This way
users on GitLab or other hosts can provide the correct value during
first-run setup rather than having to manually edit the yaml afterward.

If the user skips the prompt, the config is still valid (repo remains
optional) with a clear warning about what features are unavailable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 22:13:03 +05:30
adil 2cf9128101 refactor: clean up redundant requireRepo calls and nullish coalescing
- Use ?? instead of || for ownerRepo fallback (semantically correct for
  null-to-undefined conversion)
- Extract requireRepo() result into a local variable in tracker-gitlab's
  updateIssue and issueUrl to avoid redundant validation calls

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 22:13:02 +05:30
adil 17ea240f68 fix(cli): stop writing broken yaml when `ao start` runs in a new folder
- Make `repo` field optional in ProjectConfig and Zod schema so projects
  without a detected GitHub remote can still load and run
- Remove placeholder `repo: "owner/repo"` from autoCreateConfig() and
  addProjectToConfig() — omit the field entirely when no remote is found
- Always use actual workingDir for `path` instead of unreliable `~/<projectId>`
  fallback for non-git directories
- Add null guards for `project.repo` across SCM plugins, tracker plugins,
  lifecycle manager, webhooks, and prompt builders to prevent crashes when
  repo is not configured

Closes #1154

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 22:13:01 +05:30
adil e666c88098 fix(cli): address review — verify dashboard process before kill, restore exit on SIGINT
1. Port scan now uses killDashboardOnPort() which checks `ps -p <pid> -o args=`
   for next-server/start-all.js before killing, avoiding collateral damage to
   unrelated services on nearby ports.

2. SIGINT/SIGTERM handlers now call process.exit() after killing the child,
   restoring default exit behavior so Ctrl+C doesn't leave the parent hung
   if the child is unresponsive.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 22:12:58 +05:30
adil 4958512d9e test(cli): add coverage for port scan fallback and c8 ignore for signal handlers
Adds test for stopDashboard finding an orphaned dashboard on a reassigned
port via the port-range scan fallback. Marks signal handler body with
c8 ignore since it only fires on process termination.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 22:12:57 +05:30
adil e620a182c9 fix(cli): kill dashboard child on SIGINT and scan ports in stopDashboard (#645)
Two bugs caused `ao stop` to fail when the dashboard port was auto-reassigned:

1. Ctrl+C did not propagate to the dashboard child process because Node.js
   doesn't guarantee signal forwarding. Added SIGINT/SIGTERM/exit handlers
   in runStartup() to explicitly kill the dashboard child.

2. stopDashboard() only checked the configured port, missing orphaned
   dashboards on reassigned ports. Refactored into killOnPort() helper
   and added a port-range scan fallback (up to MAX_PORT_SCAN ports).

Closes #645

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 22:12:56 +05:30
adil 24a29194eb fix(cli): fix flaky multi-project test by setting non-interactive caller
The "errors when multiple projects and no arg" test expects the error
path (not the prompt path) in resolveProject. Set mockIsHumanCaller
to false so the test reliably hits the non-interactive error branch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 17:42:47 +05:30
adil f5818c8b88 test(cli): add tests for already-running detection and path-based dedup
Cover the moved isAlreadyRunning() check (non-TTY exit, quit, open,
restart, new orchestrator) and the path-based dedup guard in
addProjectToConfig(). Uses hoisted mocks for isAlreadyRunning,
isHumanCaller, promptSelect, unregister, and waitForExit to ensure
proper test isolation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 17:42:47 +05:30
adil cea7bfa51c fix(cli): prevent duplicate YAML entry when `ao start` detects already-running instance
Move the `isAlreadyRunning()` check before any config-mutating operations
so that running `ao start` on an already-running project no longer writes
a phantom duplicate entry to agent-orchestrator.yaml. The "new orchestrator"
choice is deferred via a flag until after config is loaded.

Also add path-based deduplication in `addProjectToConfig()` so that a
project whose resolved path already exists in config is returned as-is
instead of being appended with a numeric suffix.

Closes #1150

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 17:42:47 +05:30
Dhruv Sharma ad10dbf7aa
Merge pull request #1119 from harshitsinghbhandari/feat/1072
feat(power): prevent macOS idle sleep while AO is running
2026-04-14 17:26:58 +05:30
Harsh Batheja 95fbecc379
refactor(cli): remove lifecycle-worker subprocess, poll in-process (#1186)
* refactor(cli): remove lifecycle-worker subprocess model, run polling in-process

Replaces the per-project `ao lifecycle-worker` subprocess with an in-process
polling loop managed inside `lifecycle-service`. All registered projects are
now polled from the single long-lived `ao start` process.

- Drops the `lifecycle-worker` command and its registration.
- Rewrites `lifecycle-service` around a `Map<projectId, ActiveLoop>`,
  with SIGINT/SIGTERM/beforeExit graceful shutdown.
- Removes PID-file coordination (PID file, log file, status, etc.) —
  these only existed to track subprocess state.
- Per-project error isolation is preserved: the core lifecycle manager's
  `pollAll()` already catches per-cycle errors, and stop failures in one
  project can't prevent others from stopping.
- Updates `start`/`spawn` callers and tests to drop the PID/logFile shape.
- Adds `lifecycle-service.test.ts` covering idempotency, unknown projects,
  error isolation across projects, and graceful stop-all.

Closes #1185

* fix(cli): address bugbot review on lifecycle-service in-process refactor

- `ao spawn` / `ao batch-spawn` no longer call `ensureLifecycleWorker`.
  That call used to start `setInterval` polling in the one-shot spawn
  process, which (a) kept the CLI alive forever after the session spawned
  and (b) duplicated polling already running in `ao start`. Replaced with
  a `warnIfAONotRunning()` helper that checks `running.json` and prints a
  hint if the orchestrator isn't up.
- `ao stop` no longer calls `stopLifecycleWorker`. That call always ran
  against a fresh in-memory map (stop is a separate process from start),
  so it always returned false and printed "Lifecycle worker not running"
  misleadingly. SIGTERM to the `ao start` PID already triggers the shared
  shutdown handler in `lifecycle-service`, which stops every loop.
- Drop duplicated shutdown closure inside `registerSignalsOnce` — signal
  handlers now reference `stopAllLifecycleWorkers` directly.
- Update tests accordingly: spawn.test.ts mocks `running-state.getRunning`,
  start.test.ts drops `stopLifecycleWorker` expectations.

* fix(cli): drop SIGINT/SIGTERM listeners from lifecycle-service

Installing listeners for those signals removes Node.js's default
"exit on signal" behavior (per Node docs: "its default behavior will
be removed — Node.js will no longer exit"). Since the registered
listener doesn't call process.exit(), the `ao start` process would
hang on SIGTERM with the setInterval timer keeping the event loop
alive forever — effectively breaking `ao stop`.

Default signal handling terminates the process cleanly; the OS
reclaims the interval timer and dashboard child. `stopAllLifecycleWorkers`
stays exported for callers that want explicit cleanup before exit.

* fix(cli): project-scoped spawn warning + flush lifecycle health on exit

Addresses reviewer feedback on PR #1186:

- `warnIfAONotRunning` now takes a projectId and warns not only when no
  AO is running, but also when the running instance isn't polling the
  target project (e.g. `ao start A` then `ao spawn` in B left users
  silent about the fact that B wasn't being polled).
- `running.json` now records only the project this `ao start` actually
  polls, not every project in config. Previously this list was a lie —
  `ensureLifecycleWorker` is called for the selected project only.
- `ao start` installs SIGINT/SIGTERM handlers that call
  `stopAllLifecycleWorkers()` (flushing per-project "stopped" health
  state) and then `process.exit()`. Installing the handler safely
  requires an explicit exit because SIGINT/SIGTERM listeners remove
  Node's default exit behavior.

* fix(cli): remove dead stopLifecycleWorker, add missing test mock

Addresses bugbot comments on PR #1186:

- Delete `stopLifecycleWorker` from `lifecycle-service.ts`. It was only
  called from `ao stop` in the old subprocess model; in the in-process
  model, SIGTERM to the `ao start` pid + the shutdown handler in
  `start.ts` covers cleanup. No production caller remains.
- Add `stopAllLifecycleWorkers: vi.fn()` to `start.test.ts`'s
  `lifecycle-service.js` mock. Without it, `vi.mock` replaced the module
  and the named import resolved to undefined; the shutdown handler's
  try/catch would silently swallow the resulting TypeError, hiding any
  regression in how shutdown is wired.
- Update `lifecycle-service.test.ts` to drop references to the removed
  export (one test removed, one repurposed as a no-op smoke test for
  `stopAllLifecycleWorkers` against an empty active map).
2026-04-14 17:23:33 +05:30
yyovil 50ee804e2f test(cli): load markdown prompt templates 2026-04-13 21:28:27 +05:30
Dhruv Sharma ab1e4fb069
Merge pull request #1180 from yyovil/add/type-resolution
Add node type resolution for non-web packages
2026-04-13 19:56:36 +05:30
yyovil 9bed49d453 fix: scope node types to node packages 2026-04-13 18:25:21 +05:30
Ashish Huddar 07f01ef6a5
feat(cli): install-aware ao update, startup notifier, doctor version check (#1156)
* feat(cli): install-aware update command, startup notifier, and doctor version check

Make `ao update` detect whether AO was installed via npm or git source and
route accordingly: git installs use the existing shell script, npm installs
prompt to run `npm install -g @aoagents/ao@latest`, and unknown installs
print guidance. Add `--check` flag for JSON version info output.

Add a startup version notifier that reads a cached update check (no network
on startup) and prints a one-liner to stderr when outdated. Background
cache refresh runs after command completion via unref'd timer.

Add a version freshness check to `ao doctor` using cached data only (no
network dependency in diagnostics).

Closes #1136

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test(cli): high coverage for update service, command routing, and notifier

Add comprehensive tests per maintainer request for full coverage of all
update paths:

update-check.ts (57 tests):
- isVersionOutdated: major/minor/patch comparisons, equal, newer, missing parts
- detectInstallMethod: all 4 scenarios (git, npm-global, partial, unknown)
- readCachedUpdateInfo: fresh, expired, 23h boundary, version mismatch,
  invalid JSON, missing fields, empty file
- fetchLatestVersion: success, 404, 500, network error, timeout, non-JSON,
  missing version, non-string version, AbortSignal presence
- checkForUpdate: cache hit, cache bypass with force, stale cache fetch,
  cache write on success, no cache write on failure, version match,
  unreachable registry, result shape
- maybeShowUpdateNotice: positive print case, not outdated, no cache,
  non-TTY, AO_NO_UPDATE_NOTIFIER, CI, AGENT_ORCHESTRATOR_CI,
  each skipArg (update/doctor/--version/-V/--help/-h)
- scheduleBackgroundRefresh: does not throw

update.ts (17 tests):
- conflicting flags rejection
- --check: valid JSON output, forces fresh fetch, no side effects
- git: default args, --skip-smoke, --smoke-only, cache invalidation
- npm-global: no script-runner, already up-to-date, registry unreachable
  exits non-zero, --skip-smoke warning, forces fresh fetch
- unknown: help message, shows latest version, registry unreachable,
  suggests npm command

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): address all review feedback — coverage gaps, code fixes, Codex findings

Code fixes:
- Extract classifyInstallPath() for testable npm-global detection
- Convert IS_TTY from module-level constant to isTTY() function call
  (testable without import-time mocking)
- Fix non-TTY npm update silently exiting 0 → now exits 1 so scripts
  detect that no upgrade happened (Codex P2)
- Handle pre-release version tags in isVersionOutdated() — strips
  suffixes before comparing, handles NaN safely
- Export getCacheDir() and writeCache() for test coverage

Test coverage (69 + 24 + 9 + 3 = 105 tests):
- classifyInstallPath: npm-global (Unix + Windows paths), git, partial, unknown
- isVersionOutdated: pre-release tags, NaN handling, same-with-prerelease
- getCacheDir: XDG_CACHE_HOME override, fallback to ~/.cache
- writeCache: success, EACCES mkdir failure, ENOSPC write failure
- handleNpmUpdate full flow: confirm → spawn success, spawn failure with
  sudo suggestion, spawn error (ENOENT), non-TTY exit, flag warning,
  user decline, registry unreachable
- --check with unreachable registry still outputs valid JSON
- maybeShowUpdateNotice: happy path print, AGENT_ORCHESTRATOR_CI guard,
  each skipArg individually
- scheduleBackgroundRefresh: no-throw, swallows errors

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): move background refresh earlier, distinguish local vs global node_modules

- Move scheduleBackgroundRefresh() before parseAsync() so the fetch runs
  in parallel with command execution. Short-lived commands now have a
  better chance of seeding the cache before exit. (Codex P2)
- Distinguish global npm installs (lib/node_modules, .pnpm store) from
  local project node_modules (npx, linked installs). Local installs now
  classify as "unknown" instead of "npm-global" to avoid suggesting
  npm install -g to npx users. (Codex P2)
- Add tests: pnpm global store path, nvm global path, npx local path

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(lint): remove forbidden import() type annotations in test mocks

Replace `vi.importActual<typeof import("node:fs")>(...)` with untyped
`vi.importActual(...)` to satisfy @typescript-eslint/consistent-type-imports.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): don't misclassify local pnpm installs as npm-global

Local pnpm projects have node_modules/.pnpm/ which matched the /.pnpm/
heuristic. Replace with /pnpm/global/ check which only matches pnpm's
actual global store path (~/.local/share/pnpm/global/...).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): non-TTY exits 0, remove misleading sudo suggestion

- Non-TTY ao update now exits 0 after printing the command. Exit 1
  implied error but the user just needs to run the command manually.
- Remove blanket sudo suggestion on npm failure. npm can exit 1 for
  many reasons (network, version conflict, engine mismatch). Just
  print the exit code and let the user diagnose.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): pnpm global support, defer background refresh after parseAsync

- Detect pnpm global installs separately from npm global. pnpm users
  now see `pnpm add -g @aoagents/ao@latest` instead of the npm command.
  New InstallMethod value: "pnpm-global".
- Move scheduleBackgroundRefresh() to .then() after parseAsync() completes.
  Prevents in-flight fetch from holding the event loop open during
  short-lived commands when the registry is slow/offline. (Codex P2)
- Use info.recommendedCommand instead of hardcoded npm string in
  handleNpmUpdate, so the correct package manager command is always used.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): use actual command name in error message, not hardcoded "npm"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(cli): handle signaled npm update exits

* fix(cli): detect prereleases behind stable releases

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 11:46:26 +05:30
i-trytoohard 36a64c98b7
chore: bump all package versions to 0.2.5 (#1190)
* chore: release 0.2.5

Realign main with npm registry after off-branch publish of 0.2.3/0.2.4.
Bump all 21 linked packages to 0.2.5 and cherry-pick the startup-grace-period
fix for #989 (was in 5e4244a8 but never merged to main).

Also sync non-linked plugin versions (notifier-discord, notifier-openclaw,
scm-gitlab, tracker-gitlab) to their current npm versions.

* Revert "chore: release 0.2.5"

This reverts commit eb17f32834.

* chore: bump all package versions to 0.2.5, remove release workflow

- Bump all 25 packages to 0.2.5 to realign with npm registry
- Update package-version test to expect 0.2.5
- Remove stale .changeset/linear-spawn-branch-name.md
- Delete .github/workflows/release.yml (changesets-based NPM publish)

---------

Co-authored-by: Prateek <karnalprateek@gmail.com>
Co-authored-by: AO Bot <ao-bot@composio.dev>
2026-04-13 05:47:08 +05:30
yyovil d73ec8edfd fix(cli): update stale ao-core imports (#1143) 2026-04-12 03:56:37 +05:30
yyovil c48b078a7b
Merge pull request #982 from yyovil/fix/cli-config-not-found-error-981
fix(cli): catch ConfigNotFoundError for clean error output
2026-04-12 00:42:15 +05:30
Dhruv Sharma 663c61e16d fix: merge main and address review findings for prompt-driven spawn
- Merge main to pick up @composio/ao-core → @aoagents/ao-core rename
  and decomposer removal (#1104)
- Fix @composio/ao-core import in prompt-spawn.test.ts → @aoagents/ao-core
- Remove unreachable dead code in CLI spawn (empty-string guard after || undefined)
- Update format.ts JSDoc to document 8-item fallback chain including userPrompt
- Add clarifying comment on validation/sanitization separation in spawn route
- Integrate userPrompt display into redesigned SessionCard footer

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-11 21:44:57 +05:30
harshitsinghbhandari 8436505862 fix(power): address PR review feedback for sleep prevention
- Fix test flakiness: Use configurable property descriptor for process.platform
  mocking to prevent TypeError on property redefinition
- Fix spawn detection: Return null when caffeinate fails to spawn (child.pid
  undefined) instead of returning handle that does nothing
- Fix TypeScript: Make power config optional in OrchestratorConfig interface
  to avoid breaking existing consumers (populated post-validation)
- Add test for spawn failure case

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-11 21:06:32 +05:30
adil 0f4e2bcc3c feat(cli): hide orchestrator sessions from `ao session ls` by default (#1088)
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>
2026-04-11 12:25:14 +05:30
Dhruv Sharma ba899f9c30
Merge pull request #1104 from ComposioHQ/feat/issue-1045
refactor: remove ao spawn --decompose feature
2026-04-11 10:22:22 +05:30
harshitsinghbhandari 5e1414e7ad feat(power): prevent macOS idle sleep while AO is running (#1072)
Add idle sleep prevention on macOS using `caffeinate -i -w <pid>` to keep
the Mac awake while AO is running, enabling remote dashboard access (e.g.,
via Tailscale) without the machine going to sleep.

Changes:
- Add `preventIdleSleep()` helper in packages/cli/src/lib/prevent-sleep.ts
- Add `power.preventIdleSleep` config option (defaults to true on macOS)
- Wire sleep prevention into `ao start` command
- Add tests for the helper function and config validation
- Document the feature in README and example config

Note: Lid-close sleep is enforced by macOS hardware and cannot be prevented
by userspace assertions. Use clamshell mode for that use case.

Closes #1072

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-11 00:11:45 +05:30
Dhruv Sharma b7464e5657 fix(spawn): persist userPrompt to metadata and prevent injection
writeMetadata() used a hard-coded field whitelist that silently dropped
userPrompt. The in-memory Session.metadata also never included it, so
the spawn response always returned null. Additionally, prompts containing
newlines could inject arbitrary key=value pairs into the flat-file
metadata format.

Fixes:
- Add userPrompt to writeMetadata() whitelist and readMetadata() return
- Populate session.metadata with userPrompt during spawn
- Strip newlines from prompts in both web API and CLI (defense-in-depth)
- Harden serializeMetadata() to replace newlines in all values
- Add prompt length validation (4096 max) in CLI to match web API

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 18:54:48 +05:30
Dhruv Sharma ff9bb76e63
Merge pull request #1076 from harshitsinghbhandari/feat/cursor-agent-support
feat: add Cursor agent CLI support (#1060)
2026-04-10 15:29:55 +05:30
Harsh Batheja 3fb2ddf06d refactor: remove --decompose feature entirely
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
2026-04-10 13:02:52 +05:30
harshitsinghbhandari e47b03807c fix(agent-cursor): address Cursor Bugbot security findings
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>
2026-04-10 12:16:37 +05:30
harshitsinghbhandari f154f87add fix: merge upstream main and resolve conflicts for cursor agent
- 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>
2026-04-10 11:48:27 +05:30
ChiragArora31 98c5e1518c Merge upstream/main into feat/session-ls-json 2026-04-10 06:43:25 +05:30
Dhruv Sharma c9c41ad6dc
Merge pull request #967 from ChiragArora31/fix/notifier-alias-lifecycle-routing
fix(core): resolve notifier aliases in lifecycle routing
2026-04-10 03:02:36 +05:30