Commit Graph

304 Commits

Author SHA1 Message Date
yyovil dcfb6fe8fd
feat: add $schema support to agent-orchestrator.yaml (#1373)
* feat: add config schema support for agent-orchestrator.yaml (#1370)

Expose a committed JSON Schema and inject the canonical $schema URL into generated and updated configs so editors can autocomplete and validate AO config files.

* fix schema injection edge cases and shared constant

* fix: address config schema review feedback (#1370)
2026-04-26 19:42:45 +05:30
yyovil 32028d9362
fix(deps): bump vulnerable dependencies so pnpm audit passes cleanly (#1338)
* fix(deps): bump vulnerable dependencies

* fix(deps): align web vitest with vite 6
2026-04-26 17:01:07 +05:30
yyovil 7581af9a65
fix(cli): avoid missing repo scripts on global installs (#1252) (#1277)
* fix(cli): avoid missing repo scripts on global installs

* refactor(cli): moved ao-update.sh script into assets.

Entire-Checkpoint: b91ccadead1c

* Fix packaged doctor and update fallback

* Harden install detection and script runner

* fix(cli): align ao script launchers with packages/ao

---------

Co-authored-by: AO Bot <ao-bot@composio.dev>
2026-04-26 16:47:49 +05:30
Ashish Huddar f674422a66
Fix orchestrator identity to use one canonical session per project (#1487)
* Add canonical orchestrator identity

* Coalesce concurrent ensureOrchestrator calls

* Fix canonical orchestrator follow-ups

* Move orchestrator id helper into web utils
2026-04-25 18:57:31 +05:30
yyovil 83640c8b56
fix(cli): hide legacy second positional from ao spawn help (#1491)
* fix(cli): hide legacy spawn second positional (#1490)

Keep ao spawn help aligned with the real interface by exposing a single optional issue positional and rejecting extra positional arguments with replacement usage before any spawn work starts.

* fix(cli): align spawn usage with optional issue (#1490)

Keep the arity error and its test aligned with the optional [issue] contract surfaced by ao spawn help so review-thread guidance and user-facing usage match exactly.
2026-04-25 02:16:32 +05:30
yyovil b086908f60
add zsh completion support for ao (#1374)
* feat: add zsh completion for ao (#1371)

Add a generated zsh completion command and dynamic completion backend so ao can tab-complete projects and session IDs without relying on jq or brittle text parsing. Document standard zsh and Oh My Zsh install paths, and cover the new flow with CLI tests.

* fix(cli): address copilot completion review feedback for PR 1374

* fix completion and harden local workflow parsing

* Update packages/cli/src/lib/completion.ts

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* fix completion regressions and agent-ci review feedback

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-04-24 03:48:25 +05:30
Harsh Batheja 616c56cea2
fix(cli): derive projectId from prefixed issue id on spawn (#1330)
* fix(cli): derive projectId from prefixed issue id on spawn

When `ao spawn <projectId>/<issue>` is used in a multi-project config,
route the spawn to the prefixed project and strip the prefix from the
issue id. Previously the projectId fell back to whichever project
`ao start` was running for, tagging cross-project sessions with the
wrong project (and session prefix).

Applies to both `ao spawn` and `ao batch-spawn`; batch-spawn errors
out if issues mix multiple project prefixes.

Fixes #1329

* refactor(core,cli): lift spawn target resolution into core

Move the issue-prefix → project routing from the CLI into a reusable
core utility, `resolveSpawnTarget(projects, issueRef, fallback?)`.

- Exposes routing to any spawn entry point (CLI, web API, programmatic).
- Accepts either a project id or sessionPrefix as the prefix; project id
  wins on collision.
- `ao batch-spawn` now groups issues by resolved project and preflights
  once per group instead of erroring on mixed prefixes.

Tests:
- 8 unit tests for `resolveSpawnTarget` in core.
- CLI spawn.test.ts: adds a sessionPrefix routing test (23 tests total).

Refs #1329

* test(cli): cover batch-spawn grouping; tighten resolveSpawnTarget API

Self-review found three gaps:

- `resolveSpawnTarget` accepted `undefined` issueRef and returned
  `{ issueId: "" }` with a fallback project. Dead path — both callers
  guard against undefined. Drop it and make issueRef required.
- No tests for `batch-spawn`. Added two:
  - routes cross-project prefixed issues to the correct project and
    lists each project's sessions separately
  - skips a prefixed issue when the target project already has an
    active session for it
- `spawn` and `batch-spawn` help text didn't document the
  `<projectId>/<issue>` or `<sessionPrefix>/<issue>` forms.

* fix(core): guard resolveSpawnTarget against prototype-key matches

Second review pass found a latent bug:

Plain JS objects inherit `__proto__`, `constructor`, `toString`,
`hasOwnProperty`, etc. from Object.prototype. The previous
`if (projects[prefix])` check entered the routing branch for any of
these keys, mis-routing a user typing `ao spawn __proto__/42` with
`projectId: "__proto__"`. Downstream session-manager would then receive
a junk project object (Object.prototype itself) and fail with a
non-obvious error.

Fix: use `Object.prototype.hasOwnProperty.call(projects, prefix)` so
only actual configured project ids match.

Also:
- Document the case-sensitive matching semantic explicitly.
- Lock in the batch-spawn grouping contract by asserting exact
  `list()` and `spawn()` call counts in the cross-project test.
2026-04-22 22:18:39 +05:30
Ashish Huddar f3ce113c4c
Add multi-project storage, resolution, and project settings support (#1343)
* feat: add content-addressed project storage keys

* Add per-project resolution and hardened project routing

* Fix storage-key test isolation

* feat(web): redesign Add Project modal with Finder-native layout

* feat: multi-project support with project sidebar, settings, and improved routing

Add per-project configuration in global-config, project-aware CLI commands
(start/spawn/open/session), workspace-worktree project resolution, redesigned
ProjectSidebar with settings modal, repair flow for degraded projects, project
detail page with loading state, reload API endpoint, and comprehensive tests.

* Fix legacy config storage keys and duplicate project flow

* Fix multi-project storage migration and collision handling

* Fix merge regressions in startup and config handling

* Externalize yaml and zod from the web server bundle

* Fix session prefix matching for hashed tmux names

* Fix multi-project migration regressions

* Ignore generated worktree files in ESLint

* Fallback reload config for local-only projects

* Speed up session refresh and redirect after kill

* Use fresh session lists for dashboard polling

* fix(web): remove unused direct terminal child state

* test(web): mock router in merge conflict actions coverage

* docs: call out filesystem browse rollout requirement

* Add portfolio tests and remove unused decomposer export
2026-04-21 17:45:55 +05:30
Chirag Arora f09cc72dc8
feat(cli): hide terminal sessions in `ao session ls` by default (#1319)
* feat(cli): hide terminal session rows by default in session ls

- Filter with TERMINAL_STATUSES unless --include-terminated
- Hint when completed sessions are hidden; docs/CLI.md updated

Made-with: Cursor

* fix(cli): keep session ls JSON inventory stable

Address review concerns by preserving terminal sessions in `ao session ls --json` output while keeping terminal rows hidden by default in text output. Use the core terminal-session predicate, improve hidden-row messaging, and add regression tests for mixed/hinted and JSON behavior.

Made-with: Cursor

* fix(cli): resolve rebase conflicts with latest session ls behavior

Align session command and CLI docs with the current mainline JSON contract (`data` + `meta.hiddenTerminatedCount`) while preserving terminal-filter defaults and updated regression coverage.

Made-with: Cursor
2026-04-21 11:35:54 +05:30
Harshit Singh Bhandari e45f34e1dd
Merge pull request #1308 from harshitsinghbhandari/fix/ao-start-orchestrator-reuse-race
fix: restore dead orchestrators on ao start
2026-04-20 14:53:20 +05:30
Dhruv Sharma f0d4faf2a4
fix: fail ao send when killed session delivery is not confirmed (#1236)
* fix: fail send when killed session delivery is not confirmed

* fix(core): drop requireConfirmation throw that re-introduced duplicate-message bug

The PR's sendWithConfirmation added a throw when confirmation heuristics
did not flip within SEND_CONFIRMATION_ATTEMPTS on a restored session.
But runtimePlugin.sendMessage had already fired, so the throw bubbled up
to the lifecycle manager's catch-all, leaving lastCIFailureDispatchHash
(and its merge-conflict twin) unset. Next poll re-dispatched the same
message — exactly the duplicate-message bug that commit 77685a5 removed.

Real fix for #1074 is preserved: restoreForDelivery still throws when
waitForRestoredSession returns false, which happens before sendMessage
fires. Killed sessions that cannot be revived are still reported as
failures, with no duplicate-send risk.

- sendWithConfirmation no longer takes requireConfirmation; unconfirmed
  delivery always returns (soft success).
- prepareSession returns Session (the tuple only existed to drive the
  removed throw).
- send's retry predicate reverts to prepared.restoredAt === undefined
  && isRestorable(prepared).
- Adds regression test: restored session + sendMessage fires +
  confirmation never flips → send() resolves.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-20 13:56:31 +05:30
harshitsinghbhandari b2abcb5c3c test: fix restore mock setup in start tests 2026-04-20 13:33:34 +05:30
harshitsinghbhandari 55ebb6395a fix: tighten startup lock cleanup 2026-04-20 13:30:07 +05:30
Ashish Huddar f330a1ea69
feat(cli): filter terminated sessions from ao session ls / ao status by default (#1340)
* feat(cli): filter terminated sessions from ao session ls / ao status by default

Closes #1310. Terminated sessions (killed/terminated/done/merged/errored/cleanup,
plus lifecycle-driven terminal states) are now hidden from `ao session ls` and
`ao status` by default. A dim footer reports how many were hidden and how to
surface them. Pass `--include-terminated` to restore the full list.

JSON output wraps into `{ data: [...], meta: { hiddenTerminatedCount } }` on
both commands so text and machine-readable views tell the same story. This is a
breaking change for script consumers of `--json`; `--include-terminated` is the
escape hatch.

Orthogonal to `-a, --all` (orchestrator visibility, unchanged). Restore of
terminated sessions by id is unaffected — that path goes through `sm.get`, not
`sm.list`.

Docs (`SETUP.md`, `docs/CLI.md`) updated to match. Tests cover both the legacy
status branch and the canonical lifecycle branch of `isTerminalSession`.

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

* fix(cli): drop unused `lc` param in lifecycle-alive test case

ESLint's no-unused-vars rejects unprefixed unused args. The "alive — should
remain visible" branch of the new lifecycle-driven filter test in
`session.test.ts` took `lc` but never touched it. Switch to `()`. Matches the
equivalent case in `status.test.ts`.

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

* fix(core): preserve pr.state=merged when legacy metadata lacks pr= URL

Review blocker on PR #1340: a metadata file with `status=merged` but no `pr=`
URL was still showing as active in `ao session ls` / `ao status` by default.

Root cause: `synthesizePRState()` in lifecycle-state.ts short-circuited to
`{ state: "none" }` whenever no PR URL was present, ignoring the fact that the
legacy `status` column already encodes terminal truth. Once lifecycle was
synthesized as `session.state="idle"` + `pr.state="none"`, `deriveLegacyStatus`
returned `"idle"` and `isTerminalSession()` (lifecycle branch) returned false.
The new CLI filter then let the session through.

Fix: when legacy `status === "merged"` and no URL is available, synthesize
`pr.state="merged", reason="merged"` with `number: null, url: null`. The
terminal signal survives the flat-metadata → canonical-lifecycle round trip.

Also:
- Export `sessionFromMetadata` from the core barrel. CLI tests and external
  consumers need it to round-trip metadata through the canonical lifecycle.
- Update CLI `buildSessionsFromDir` helpers to route through `sessionFromMetadata`
  so mocked `sm.list()` reflects production reconstruction (the old shortcut
  bypassed synthesis entirely and was the reason the bug slipped past the
  original test suite).
- Add regression tests: one at the core level (`parseCanonicalLifecycle` for
  merged-without-URL) and one integration-style test per CLI command asserting
  the reviewer's exact repro produces the expected filtered output.
- One pre-existing test expectation updated: when metadata has `status=working`
  and `pr=<url>`, the reconstructed status is `pr_open`, not `working`. That's
  what production `sm.list()` has always returned; the test was previously
  hiding behind the reconstruction shortcut.

Changeset bumped to include ao-core (patch).

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

* test(cli): route review-check helper through sessionFromMetadata

Last remaining test-fidelity shortcut flagged by codex on PR #1340. The
`buildSessionsFromDir` helper in review-check.test.ts fabricated Session
objects by hand, bypassing the canonical lifecycle reconstruction that
production `sm.list()` runs. Doesn't affect review-check's actual behavior
(which reads `session.metadata["pr"]` directly), but aligns this test with
the equivalent helpers in session.test.ts and status.test.ts so future
lifecycle changes don't silently skip this surface.

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 13:05:34 +05:30
harshitsinghbhandari eee8e66ffc fix: address pr-review regressions (#1306) 2026-04-19 19:59:16 +05:30
harshitsinghbhandari 6b15e68fc3 fix: address follow-up review regressions 2026-04-19 19:59:16 +05:30
harshitsinghbhandari bb5dcf0af7 fix: address #1306 review follow-ups 2026-04-19 19:59:16 +05:30
harshitsinghbhandari aede68e8da test: remove duplicate restore mock 2026-04-19 19:59:16 +05:30
harshitsinghbhandari 27135eab0e fix: close failed startup lock writes 2026-04-19 19:59:16 +05:30
harshitsinghbhandari e1bb51f42a chore: replace changelog edits with changeset 2026-04-19 19:59:16 +05:30
harshitsinghbhandari 0481dbf158 fix: harden startup lock handling (#1306) 2026-04-19 19:59:15 +05:30
harshitsinghbhandari c6129de1c9 fix: restore dead orchestrators on start (#1306) 2026-04-19 19:59:15 +05:30
harshitsinghbhandari c00ccc773e fix: serialize ao start and stop numbered orchestrators (#1306) 2026-04-19 19:59:15 +05:30
Harsh Batheja 81489079b2
fix(cli,core): reuse orchestrator sessions across ao start; fix dashboard id mismatch (#1075)
Fixes #1048. ao start used to allocate a fresh `{prefix}-orchestrator-N`
on every invocation instead of reattaching to the previous session, and
the dashboard's orchestrator link pointed at a different id than the
CLI just printed.

Changes:

runStartup (packages/cli/src/commands/start.ts):
  - On startup, list existing orchestrators for the project, partition
    them into live (runtime still running) and restorable (terminal but
    sm.restore()-able) buckets, pick the most-recently-active from the
    chosen bucket, and reuse/restore that id instead of spawning a new
    one. Only spawn fresh when both buckets are empty.
  - Live is preferred UNCONDITIONALLY over restorable — a newer killed
    record can never beat an older-but-running one. Without this, a
    cross-bucket sort could resurrect a killed record via sm.restore()
    while the live orchestrator kept running, leaving two alive.
  - Restored sessions get an explicit "(restored)" marker in the CLI
    summary so the resurfaced id isn't a surprise.
  - The phantom `${prefix}-orchestrator` id constant is removed from
    every URL print, browser-open target, and summary line. Everything
    now uses the real selected id.

registerStop (same file):
  - ao stop now resolves the real orchestrator via sm.list(projectId)
    + isOrchestratorSession filter + most-recently-active sort, then
    calls sm.kill on that id. The old phantom `${prefix}-orchestrator`
    target never matched a real numbered record, so ao stop was a
    silent no-op and the orchestrator kept running on disk between
    start cycles. sm.list-failure warning no longer duplicates with the
    generic "no orchestrator found" message.

isOrchestratorSession (packages/core/src/types.ts):
  - Tightened: legacy bare-id records (`{projectId}-orchestrator` with
    no role metadata) are no longer recognized as orchestrators by the
    public predicate. This was the source of the dashboard/CLI id
    divergence — stale bare records with a different prefix than the
    numbered form were leaking into the dashboard's orchestrator list.

session-manager repair (packages/core/src/session-manager.ts):
  - Split `isOrchestratorSessionRecord` (permissive, used by cleanup
    protection) from a new `isRepairableOrchestratorRecord` (stricter,
    used only by repairSingleSessionMetadataOnRead and
    repairSessionMetadataOnRead).
  - The strict repair predicate accepts role-stamped records, the bare
    `{sessionPrefix}-orchestrator` correct-prefix legacy shape, and the
    numbered `{sessionPrefix}-orchestrator-N` worktree shape. It
    rejects foreign bare names like `{projectId}-orchestrator`, so
    those records never get `role: orchestrator` backfilled on read
    and therefore can no longer pass `isOrchestratorSession()` in real
    `sm.list()` output via the role-metadata branch.

Tests added (~12):
  - runStartup: live reuse, restore-on-killed, ignore-stale-bare
    legacy records, live-beats-restorable regression, multi-live
    reuse, URL fallback when --no-orchestrator.
  - ao stop: kills the actual numbered id (not the phantom), handles
    multiple orchestrators, tolerates sm.list throwing.
  - isOrchestratorSession: rejects stale bare ids without role
    metadata; accepts bare ids with role metadata stamped.
  - listDashboardOrchestrators: stale bare excluded, numbered live
    included, role-stamped legacy included.
  - session-manager repair: does not backfill role onto foreign bare-id
    records (issue #1048 regression guard).

Unblocks: review comments from cursor[bot] (dead else-if branch,
double messaging, redundant isTerminalSession check) and illegalcall
(cross-bucket sort, repair-backfill bypass of predicate tightening) —
all addressed in-place with the multi-orchestrator model preserved.

Verified: core 606/606, cli 450/450, typecheck clean across core/cli/web.
2026-04-19 13:12:28 +05:30
harshitsinghbhandari 51c3fd9b4b fix: close remaining pr1300 follow-ups 2026-04-18 15:18:24 +05:30
harshitsinghbhandari bcdda4b9ba fix: address PR #1300 requested changes 2026-04-18 11:13:53 +05:30
harshitsinghbhandari e7ad928812 feat: report non-terminal PR workflow events (#131) 2026-04-17 21:46:57 +05:30
harshitsinghbhandari 28ce462ef0 feat: unify session detail auditability and lifecycle stability (#123 #124 #126) 2026-04-17 20:48:02 +05:30
harshitsinghbhandari dd83a11503 fix: model missing activity evidence explicitly (#122)
Represent missing activity probes as first-class signal states so lifecycle inference only treats valid idle evidence as proof. This prevents false stuck transitions, keeps API/UI lifecycle truth aligned, and makes root monorepo verification deterministic by serializing recursive build and typecheck.
2026-04-17 19:28:56 +05:30
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