Commit Graph

130 Commits

Author SHA1 Message Date
harshitsinghbhandari 5f7a3d50cb fix: comments fixed 2026-03-28 03:15:35 +05:30
harshitsinghbhandari 2a7c4a3f57 phase3-done 2026-03-28 02:57:53 +05:30
Dhruv Sharma a26b0bc5c5
Merge pull request #728 from ComposioHQ/feat/724
refactor(core): decompose session-manager.test.ts into modular test files
2026-03-28 02:01:22 +05:30
Dhruv Sharma ff48b052a8
Merge pull request #720 from harshitsinghbhandari/patch-1
feat(core): extract shared test utilities and migrate lifecycle-manager tests
2026-03-28 00:51:58 +05:30
harshitsinghbhandari 47fa76c0de fix: latest issue 2026-03-27 22:34:05 +05:30
Dhruv Sharma c487b40919
Merge pull request #735 from ruskaruma/fix/mandate-ao-cli-in-prompt
fix(core): mandate ao send and ban raw tmux in orchestrator prompt
2026-03-27 22:16:35 +05:30
ruskaruma b65cc702be fix: correct ao send --no-wait wording per review 2026-03-27 20:50:13 +05:30
harshitsinghbhandari 540dad772b fix: comments from #720 fixed 2026-03-27 20:32:20 +05:30
Harshit Singh Bhandari 01b93706f4
Merge pull request #3 from ComposioHQ/main
merge
2026-03-27 19:30:27 +05:30
ruskaruma c975f952ff fix(core):mandate ao send and ban raw tmux (#340) 2026-03-27 12:28:02 +05:30
AO Bot 2eedb613ad refactor(core): decompose session-manager.test.ts into modular test files (#724)
The monolithic 5,032-line session-manager.test.ts has been split into
focused, domain-specific files to improve maintainability and enable
parallel test execution.

New structure:
- session-manager/test-utils.ts - shared mock factories and test setup
- session-manager/opencode-helpers.ts - parameterized shell mock installers
- session-manager/spawn.test.ts - 41 spawn tests
- session-manager/spawn-orchestrator.test.ts - 31 spawnOrchestrator tests
- session-manager/query.test.ts - 19 list + get tests
- session-manager/lifecycle.test.ts - 23 kill + cleanup tests
- session-manager/communication.test.ts - 18 send + remap tests
- session-manager/restore.test.ts - 19 restore tests
- session-manager/claim-pr.test.ts - 19 claimPR + PluginRegistry + isIssueNotFoundError tests

Total test count preserved at 174. Zero changes to core logic.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 18:28:00 +00:00
Harshit Singh Bhandari 5449acd04e
Add mock implementation for workspace list function 2026-03-26 19:30:41 +05:30
Harshit Singh Bhandari 532fdd22a4
Remove unused imports from lifecycle-manager test 2026-03-26 19:24:05 +05:30
AO Bot 0d4ddcc8c7 feat(core): extract shared test utilities and migrate lifecycle-manager tests (#715)
Create test-utils.ts with reusable factories (createTestEnvironment,
createMockPlugins, createMockRegistry, createMockSCM, createMockNotifier,
createMockSessionManager, makeSession, makePR) and refactor
lifecycle-manager.test.ts to use them, reducing setup boilerplate by >70%.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 13:41:43 +00:00
Dhruv Sharma 36d354e0c2 feat: OpenClaw plugin, AO skill, Discord notifier, and setup wizard
Adds bidirectional integration between Agent Orchestrator and OpenClaw,
enabling AI bots on Discord/Telegram/WhatsApp to manage coding agent
fleets through natural conversation.

OpenClaw Plugin (openclaw-plugin/):
- 14 AI tools: ao_spawn, ao_issues, ao_sessions, ao_status, ao_batch_spawn,
  ao_send, ao_kill, ao_session_restore, ao_session_cleanup,
  ao_session_claim_pr, ao_review_check, ao_verify, ao_doctor, ao_session_list
- Hooks: message_received + before_prompt_build for live data injection
- /ao slash command with subcommands (sessions, spawn, issues, doctor, setup)
- Background services: health monitor + issue board scanner
- Security: execFileSync with arg arrays (no shell injection)

AO Skill (skills/agent-orchestrator/):
- Natural language intent → AO tool mapping
- Decision heuristic: quick fix → direct, multi-issue → AO
- Designed for ClawHub publishing (blocked on ClawHub server bug)

CLI: ao setup openclaw (packages/cli/src/commands/setup.ts):
- Interactive wizard + non-interactive mode
- Auto-detects OpenClaw gateway on localhost
- Auto-generates secure token
- Writes both configs (agent-orchestrator.yaml + openclaw.json)
- Appends OPENCLAW_HOOKS_TOKEN to shell profile
- Validates connection end-to-end

CLI: ao doctor notifier checks:
- Probes OpenClaw gateway reachability + token validity
- --test-notify flag sends test event through all configured notifiers
- Failure count propagated to exit code

Discord Notifier (packages/plugins/notifier-discord/):
- Rich webhook embeds with colors, fields, action links
- Retry with exponential backoff + Discord Retry-After header
- Request timeouts, embed truncation, webhook URL validation
- thread_id via URL query string (Discord API requirement)

OpenClaw Notifier improvements:
- Added request timeouts via AbortController
- Improved README

Reviewed through 5 rounds of Codex code review.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 21:52:28 +05:30
github-actions[bot] c7d6634839 chore: version packages 2026-03-20 15:47:55 +00:00
suraj-markup 596913aa34 Fix review issues: busy-wait loops, lock race, import hygiene, typed errors
- 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>
2026-03-17 17:33:06 +05:30
suraj-markup 44313f925d Remove two-arg support from ao spawn and batch-spawn
- 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>
2026-03-17 14:29:14 +05:30
suraj-markup a1a9966ed5 Fix CI failures: lint eqeqeq + test manifest displayName
- 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>
2026-03-17 13:55:08 +05:30
suraj-markup 694681f728 Fix review issues: ESM compat, prompt accuracy, port registration
- 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>
2026-03-17 05:49:53 +05:30
suraj-markup f3f81dad84 Simplify onboarding: absorb init + add-project into ao start
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>
2026-03-17 01:17:33 +05:30
suraj-markup 14fa726551 Publish ao-web on npm, harden error handling, deduplicate code
- 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>
2026-03-14 19:01:49 +05:30
Joakim Sigvardt a64c051e9f
fix(lifecycle): implement stuck detection using agent-stuck threshold (#376)
* 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>
2026-03-13 10:02:33 +05:30
Harsh Batheja 1d960feb6b
fix: protect orchestrators from session cleanup (#453)
* fix: harden orchestrator cleanup selection

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: suppress orchestrators in cleanup command output

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: remove unreachable cleanup guard branch

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>
2026-03-13 09:39:49 +05:30
Harsh Batheja 63889c2b00
fix: use tmux metadata handle for reliable active session status (#449)
Treat persisted tmuxName as metadata-derived runtime identity when runtimeHandle is missing so active sessions are not misclassified as exited/unknown across agents.
2026-03-12 22:31:31 +05:30
Harsh Batheja 3deea32bda
feat: support distinct worker and orchestrator agents (#439)
* feat: add role-specific agent resolution

* test: cover role-specific agent precedence

* docs: show role-specific agent config

* fix: preserve shared agent config fallbacks

* fix: avoid role-config permission clobbering

* fix: keep orchestrator launches permissionless

* fix: remove stale lifecycle imports
2026-03-12 20:58:55 +05:30
Harsh Batheja 0797f933e1
fix: gate fresh session sends on interactive readiness (#438)
* 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>
2026-03-12 20:44:04 +05:30
Harsh Batheja b04d3e21de
feat: add end-to-end observability across core, web, and terminal (#436)
* 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
2026-03-12 16:57:40 +05:30
Jayesh Sharma 1194697b3b
fix: skip PR auto-detection for orchestrator sessions (#442)
* 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>
2026-03-12 14:46:39 +05:30
Harsh 238752b29e fix: reuse shared orchestrator detection in lifecycle manager
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.
2026-03-12 02:42:50 +05:30
Harsh 58ad53e8a3 fix: close remaining Bugbot findings
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.
2026-03-12 01:58:55 +05:30
Harsh 16a5c82b57 fix: align clean-branch merges with project filtering
Preserve the legacy project fallback in the shared session loader and keep the sessions route filtering by project after the clean branch cherry-pick, so the final PR branch matches the verified multi-project behavior.
2026-03-11 23:39:59 +05:30
Harsh 60a9c9fbb6 fix: preserve project ownership for legacy sessions
Recover the owning project from the sessions directory and archived metadata so older session files still resolve to the correct project and reuse the right orchestrator mapping.
2026-03-11 23:27:48 +05:30
Harsh 3aebf0e233 feat: add shared orchestrator session detection
Centralize orchestrator identification so core cleanup and downstream consumers can share one contract for per-project orchestrator sessions.
2026-03-11 23:26:46 +05:30
Harsh Batheja c1e8c1e839
fix: prevent orchestrator sessions from owning PRs (#432)
* fix: repair orchestrator PR metadata and session branch allocation

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: harden orchestrator prompt delegation rules

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: hide orchestrator PR ownership in status

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: restore session suffix parsing for branch allocation

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: avoid dynamic delete in metadata repair path

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: reduce read-time repair overhead and preserve activity timestamps

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* refactor: share orchestrator read-repair logic

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>
2026-03-11 22:04:38 +05:30
Harsh Batheja 2064595633
feat: add SCM webhook lifecycle triggers (#394)
* feat(core): add scm webhook contract

Defines a provider-agnostic SCM webhook contract in core types and
config so SCM plugins can verify and normalize inbound webhook events
without reshaping project config later.

* feat(scm): trigger lifecycle checks from github webhooks

Adds GitHub webhook verification and event parsing, exposes a web
webhook endpoint, and routes matching PR/branch events through the
existing lifecycle manager so CI and review reactions update immediately.

* fix(scm): verify github signatures with raw webhook bytes

Preserves the original webhook bytes alongside the decoded payload so
GitHub HMAC verification uses the exact request body while the route
continues to drive lifecycle checks through the existing manager.

* fix(web): wire scm webhook route into main branch services

Restores the main-branch service and route-test wiring while keeping the
new webhook route coverage and scoped lifecycle helper in place.

* fix(webhooks): use singleton lifecycle manager and fail closed on scm API errors

Reuses the existing services lifecycle manager for webhook-triggered checks
so reactions and state transitions don't replay from a fresh instance, and
restores fail-closed behavior for GitHub review comment fetch failures.

* fix(webhooks): tighten project matching and restore scm compatibility methods

Prevents repository-less webhook events from matching all projects, restores
GitHub SCM PR utility methods and CI status rollup fallback, and adds tests
covering the compatibility paths and safer project matching behavior.

* fix(webhooks): pre-check content length and continue on parse errors

Adds an early content-length guard against configured maxBodyBytes before
reading the body and changes candidate parse failures to fail-forward so
one malformed payload path does not abort other valid candidate handling.

* fix(scm-github): parse review-comment timestamps from comment payload

Use comment.updated_at/created_at for pull_request_review_comment webhook
timestamps so normalized events retain temporal data for comment events.

* fix(webhooks): apply early size guard only when all candidates are bounded

Uses the broadest candidate limit for pre-read content-length checks and
skips early rejection when any matching project has no configured limit,
while retaining per-candidate verification limits.

* fix(webhooks): normalize repo matching and skip terminal sessions

Match webhook repository names case-insensitively against configured project
repos and avoid lifecycle checks for terminal sessions when resolving
webhook-affected sessions.

* fix(webhooks): fail forward when lifecycle checks throw

* fix(scm-github): parse push webhook branch and sha

* refactor(scm-github): dedupe cli exec helper wrappers

* fix(scm-github): tighten exec helper type and comment timestamps

* fix(scm-github): prefer head_commit timestamp for push events

* fix(webhooks): tighten repository parsing and helper visibility

* fix(scm-github): ignore non-head refs for push branch

* chore: trigger bugbot rerun

* feat(scm-gitlab): add webhook verification and event parsing

* fix(webhooks): share parser utils and handle check_run branch

* fix(webhooks): ignore gitlab tag refs in ci branch mapping

* fix(scm-gitlab): harden token and tag ref handling

* chore(scm-gitlab): update webhook helpers around bugbot threads
2026-03-11 10:34:41 +05:30
prateek 8e8cab771f
feat(core): add feedback tools contracts, validation, storage, and dedupe
* feat(core): add feedback report tool contracts and storage

* fix(core): stabilize feedback dedupe and clear lint blocker

* fix(core): harden feedback report parsing and resilience

* docs: add feedback routing architecture and PR explainer

* fix(core): remove dedupe collisions and share atomic writes

* docs: add final PR403 bugbot resolution status

* docs: formalize feedback pipeline and fork-aware execution design

* docs: remove PR-specific review artifacts

* docs: add durable feedback pipeline explainer

* docs: add consent gates and journal semantics to feedback design

* docs: add pr403 confidence checklist with openclaw dogfood evidence

* docs: add work openclaw validation prompt helper page

* docs: record work openclaw validation evidence

* docs: remove pr-specific review artifacts from repo

* fix(core): ignore confidence in feedback dedupe key
2026-03-10 22:31:39 +05:30
Harsh Batheja 240d6423fb
fix: opencode lifecycle race hardening (#359)
* fix: opencode lifecycle race hardening

This hardens the OpenCode session lifecycle to prevent race conditions that create orphan sessions:

Root Cause:
- Concurrent spawnOrchestrator calls could both check for existing orchestrator, see none exists, and proceed to create runtime + write metadata simultaneously, leading to orphan sessions
- Fallback title discovery was sorted oldest-first instead of newest-first, causing wrong session selection when duplicates exist

Changes:
1. spawnOrchestrator: Add atomic session ID reservation before creating runtime/metadata
   - Uses reserveSessionId to prevent check-create race
   - If reservation fails, checks if existing session is alive and reuses under reuse strategy
   - Never creates duplicate/orphan runtime on reservation conflict

2. agent-opencode plugin: Improve session discovery
   - Title-based fallback now sorts by updated timestamp (newest first)   - Validates session IDs with ses_ prefix pattern
   - Handles numeric and string timestamps in sorting

Tests added:
- spawnOrchestrator reuses concurrent alive session
- spawnOrchestrator throws when session not in reusable state
- spawnOrchestrator never creates duplicate runtime on conflict
- Invalid session ID rejection tests
- Newest-first fallback sorting tests

* fix: opencode lifecycle race hardening

This hardens the OpenCode session lifecycle to prevent race conditions that create orphan sessions:

Requirements:
1) Exact session-id capture from opencode run --format json stream
2) Fallback title discovery for missing/parse fails
3) Atomic reservation before runtime/metadata write
4) Never create duplicate/orphan runtime on reservation conflict

5) Never persist invalid opencodeSessionId

Mandatory tests: preferred exact-id path, newest fallback selection, reservation conflict no duplicate runtime, invalid-id rejection

- Fixed lint error in agent-opencode plugin test file
- Fixed the failures: spawnOrchestrator reservation logic breaks existing orchestrator reuse behavior
- All core tests now pass except 1 failing in the plugin-integration test (which needs to be resolved separately)

* fix: lint error and skip failing test

- Rename unused buildContinueSessionCommand to _buildContinueSessionCommand
- Skip 'reuses archived OpenCode mapping' test - pre-existing bug where findOpenCodeSessionIds only checks latest archived metadata, not all versions

* fix: integration test expectations for --format json flag and2>&1

* fix: harden orchestrator session reservation and align opencode session tests

* fix(core): keep claim-pr ownership consolidation automatic

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* test(opencode): remove unused test scaffolding

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix(core): preserve in-progress orchestrator reservations

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix(opencode): escape discovery failure message

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* refactor(opencode): rename discovery option suffix

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix(opencode): keep fallback shell syntax valid

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix(core): enforce project pause in session manager

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* chore: trigger bugbot re-review

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* test: restore archived mapping coverage and strict mock fallback

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix(core): enforce project pause for orchestrator spawn

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* chore: retrigger bugbot pass

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

---------

Co-authored-by: Harsh <harsh@Ubuntu-24-Forrest.lan>
Co-authored-by: Harsh <harsh@example.com>
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-10 15:33:08 +05:30
Harsh Batheja 9fa0a65ec9
feat: add orchestrator recovery automation (#356) (#362)
* fix: preserve PR number in recovery and dedupe validation utilities

Bugbot #2908822306: Use parsePrFromUrl utility to correctly extract
PR number from URL instead of defaulting to 0. Applied to both
recovery/actions.ts and session-manager.ts for consistency.

Bugbot #2908822310: Extract safeJsonParse and validateStatus to
shared utils/validation.ts to eliminate duplication between
recovery/validator.ts and session-manager.ts.

Clean rebuild from origin/main with only recovery-specific changes.

* fix: add PR number fallback and remove unused import

Bugbot #2908822306: Add fallback regex to extract PR number from URL
ending when full GitHub URL pattern doesn't match (e.g., non-GitHub URLs).

Bugbot #2908822310: Remove unused SessionStatus import from session-manager.ts
(now imported from utils/validation.ts).

Tests: 406 passed, typecheck clean.

* fix(core): harden recovery action selection and escalation

* fix(core): preserve recovered agent summary metadata

* fix(core): reuse canonical PR type in URL parser

Avoid shadowing the core PRInfo type in the recovery URL parser while keeping the non-GitHub trailing-number fallback covered by tests.

* fix(core): align recovery metadata and session reconstruction

Persist restored timestamps under the canonical metadata key, share
session reconstruction logic between recovery and session loading, and
log the real escalation reason when recovery aborts on retry limits.

* fix(core): keep dry-run escalation reasons accurate

Use the assessment's actual escalation reason in dry-run results so preview output matches real execution behavior for partial-session escalations.

* fix(core): dedupe recovery scanning and honor custom log path

Reuse metadata listing rules in scanner to avoid duplicated session ID filters,
and preserve user-supplied recovery logPath in recovery manager APIs.

* fix(core): align dry-run recovery behavior with real actions

Compute recovery escalation decisions before dry-run returns and route
single-session dry runs through executeAction so action-specific fields
(reason/manual-intervention) are preserved.

* fix(core): derive dry-run recovery report from action execution

Run dry-run recovery classification through executeAction so report actions
match real execution logic, including max-attempt escalation decisions.
2026-03-10 13:43:42 +05:30
Harsh Batheja 7b7cf20068
fix(core): wire built-in GitLab integrations (#393)
* fix(core): register built-in GitLab plugins

* fix(core): infer missing GitLab project defaults
2026-03-10 12:57:35 +05:30
Harsh Batheja 4edf19df32
feat: lifecycle manager, backlog auto-claim, task decomposition, and verification gate (#365)
* feat: wire lifecycle manager, backlog auto-claim, and dashboard overhaul

- Start LifecycleManager in dashboard server (30s polling) so reactions
  actually fire: CI failures, review comments, merge conflicts are now
  auto-forwarded to agents
- Add backlog auto-claim poller (60s interval) that watches for issues
  labeled `agent:backlog` and auto-spawns agent sessions up to max
  concurrent limit (5)
- Add tabbed dashboard UI: Board (kanban), Backlog (issue queue), PRs
- Add issue creation form in dashboard — creates GitHub issues with
  `agent:backlog` label for immediate agent pickup
- Add API routes: /api/backlog, /api/issues, /api/setup-labels
- Pass notifier config through plugin registry (slack webhook fix)

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

* feat: add task decomposition layer (classify → decompose → recurse)

Adds LLM-driven recursive task decomposition upstream of session spawning.
Complex issues are broken into atomic subtasks before agents start working.
Each agent receives lineage context (where it fits in the hierarchy) and
sibling awareness (what parallel agents are doing).

Core changes:
- New decomposer module (core/src/decomposer.ts) — classify, decompose,
  plan tree, lineage formatting, using Claude API
- Extended SessionSpawnConfig with lineage/siblings fields
- Prompt builder Layer 4: decomposition context (hierarchy + siblings)
- ProjectConfig.decomposer config section with Zod validation
- Tracker plugin: added removeLabels support for label management

CLI:
- `ao spawn <project> <issue> --decompose` flag
- `--max-depth <n>` option for decomposition depth
- Spawns multiple sessions with lineage context for composite tasks

Backlog poller:
- Respects project.decomposer.enabled for auto-decomposition
- Posts plan as issue comment when requireApproval=true
- Auto-spawns subtasks with lineage when requireApproval=false

Config example:
  projects:
    my-app:
      decomposer:
        enabled: true
        maxDepth: 3
        requireApproval: true

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

* feat: add verification gate — issues stay open until human confirms fix

PR merge no longer auto-closes GitHub issues. Instead:

1. On PR merge: issue labeled `merged-unverified`, stays open
2. Human checks staging, then runs `ao verify <issue>` to close
3. Or `ao verify <issue> --fail` to flag verification failure

Changes:
- services.ts: labelIssuesForVerification() replaces closeIssuesForMergedSessions()
- New CLI command: `ao verify` (verify/fail/list modes)
- New API route: GET/POST /api/verify
- Dashboard: new Verify tab with one-click verify/fail buttons
- ao status: shows count of issues awaiting verification
- Idle session detection + auto-nudge reaction
- Use TERMINAL_STATUSES in batch-spawn dedup check

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

* fix: rename decomposerConfig to avoid variable shadowing

Addresses Bugbot medium severity issue where inner  variable
shadowed outer  from getServices().

* fix: update pnpm-lock.yaml for new @anthropic-ai/sdk dependency

* fix: resolve remaining merge conflicts and syntax errors

- Remove leftover conflict markers in types.ts
- Remove orphaned code in services.ts
- Fix semicolon to comma in config.ts
- Remove unused import in verify.ts

* fix: address final Bugbot issues

- requireApproval path now exits early with continue to prevent
  fall-through to in-progress label and session spawned comment
- remove packages/core/package-lock.json (pnpm workspace should only
  use root pnpm-lock.yaml)

* fix: idle sessions now transition back to working

When agent resumes activity after being idle, the status correctly
transitions to 'working' instead of remaining stuck in 'idle' state.

* fix(backlog): remove agent:backlog label when claiming issues

When claiming issues from the backlog, the poller now removes the
agent:backlog label in addition to adding agent:in-progress. This
prevents duplicate work if all spawned sessions reach terminal status
and the poller rediscovers the issue.

* fix(test): use Set for TERMINAL_STATUSES mock

The mock for TERMINAL_STATUSES was an array, but the real export is a
ReadonlySet. Changed to use a Set so tests with non-empty sessions won't
crash when calling .has().

* fix(web): resolve backlog/dashboard regressions after branch sync

* fix(web): align dashboard events hook and SSE test mocks

* fix(notifier-openclaw): apply exponential delay from retry index

* fix(integration-tests): align openclaw retry delay expectation

* fix(web): keep dashboard header stats in sync

* fix(openclaw): keep first retry at base delay

---------

Co-authored-by: Agent <agent@example.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Harsh <harsh@Ubuntu-24-Forrest.lan>
Co-authored-by: Harsh <harsh@example.com>
2026-03-10 12:31:25 +05:30
Harsh Batheja 650d3ad695
fix(core): enforce single-owner PR claim consolidation (#390)
* fix(core): enforce single-owner PR claim consolidation

* refactor: remove dead `takeover` option from claimPR

Since PR consolidation is now automatic (single-owner enforcement),
the `--takeover` flag became dead code. Users passing it got no
error but it had zero effect.

This commit:
- Removes takeover from ClaimPROptions interface
- Removes --takeover flag from spawn and session CLI commands
- Updates orchestrator-prompt.ts examples
- Updates tests to reflect automatic consolidation

Tests: ao-core 403 passing, ao-cli 189 passing (spawn+session)

* fix: remove stale --takeover from Quick Start example

Remove remaining --takeover reference in orchestrator prompt Quick Start section.

* feat(core): document and test asymmetric PR ownership model

- Add JSDoc to claimPR documenting RULE A (exclusive PR->Agent) and
  RULE B (Agent->Many PRs) ownership contract
- Add tests for:
  - Same session claiming multiple PRs sequentially (RULE B)
  - Idempotent re-claim by same owner
  - Stale/dead prior owner handoff
  - Exclusive PR ownership enforcement (RULE A)

139 tests passing

---------

Co-authored-by: Harsh <harsh@Ubuntu-24-Forrest.lan>
2026-03-10 11:54:26 +05:30
Harsh Batheja 003eb78adb
fix: pause workers on model limits and stabilize session visibility (#367)
* fix: pause workers on model limits and stabilize session visibility

Detect model limit exhaustion, pause project worker operations until reset, and expose pause state in dashboard/API. Also harden killed-session cleanup and SSE session reconciliation so sessions do not appear ghost-active or disappear until reload.

* fix: satisfy lint in rate-limit pause probe

* fix: address bugbot feedback for pause handling

* fix(lifecycle): prevent infinite re-pause loop for duration-based rate limits

Duration-based rate limits (e.g., 'usage limit reached for N hours') were
causing infinite re-pause loops because they always calculate reset time as
Date.now() + duration, which extends the pause on every poll cycle if the
message remains in terminal output.

Now checks for existing active pause before setting a new one:
- Skips override if same session already has active pause
- Preserves longer pauses from other sessions

Fixes infinite loop described in PR #367 review comment.

* fix(core): export global pause constants to prevent duplication

Export GLOBAL_PAUSE_*_KEY constants and parsePauseUntil utility from
@composio/ao-core so web package can import them instead of hardcoding.

This prevents silent breakage if key values ever change - now there's
a single source of truth.

Addresses review comment on PR #367.

* fix(web): globalPause as first-class state in SSE event flow

globalPause is now part of the same reducer/event flow as sessions,
not derived from provider-specific output text in the UI.

Changes:
- useSessionEvents: manage globalPause alongside sessions in reducer state
- Dashboard: consume globalPause from hook instead of SSR-only prop
- types: re-export GlobalPauseState from shared lib (provider-agnostic contract)
- Tests: 15 new tests proving banner appears/disappears from state updates
  alone, regardless of agent model/plugin (Claude Code, OpenCode, Codex)

Design requirements satisfied:
- First-class state in same reducer/event flow as sessions
- Key names sourced from shared core contract via export/import
- Provider-neutral: no Anthropic/OpenAI string coupling in control logic
- State-driven: banner visibility from reducer state updates via SSE

Addresses Bugbot finding: Dashboard pause banner never updates after
initial render (eba24a0b-9e4c-47e3-91c9-7d10be01e3cf)

* fix: remove unused import in test file

* fix(cli): consistent purge default for session kill and stop commands

The kill method's default changed from opt-in (=== true) to opt-out (!== false).
Both session kill and stop commands now use the same logic:
  purgeOpenCode = opts.purgeSession === true ? true : opts.keepSession !== true

This ensures consistent behavior across all kill paths.

Adds --keep-session flag to both commands.
Adds regression tests for provider-agnostic behavior verified.

Addresses Bugbot finding: orchestrator start cleanup inconsistent
with new purge default (2bc2535f-b2d1-4f64-96d6-150f97ed8564)
2026-03-10 08:42:17 +05:30
Harsh Batheja cf31dee0b8
fix: implement PR325 session capture fallback and spawn race hardening (#366)
* fix: capture exact OpenCode session ID from JSON stream to prevent orphan sessions

- Primary: Extract session_id from opencode run --format json step_start event
- Fallback: Title-based match with newest-first sorting for delayed visibility
- Core: Add atomic reserveSessionId check in spawnOrchestrator to prevent race conditions
- Prevents orphan sessions when multiple spawns use same title or delayed discovery

(cherry picked from commit 42cc0cfa1a)

* fix: capture OpenCode session id from stream output

(cherry picked from commit 42b3bf3ba6)

* fix: respawn orchestrators when stale metadata is left behind

(cherry picked from commit e519628017)

* fix: align respawn guard and opencode test expectation

* fix: remove unused helper from opencode launch path

* fix: remove unused function and align tests with session capture format

- Remove unused buildSessionLookupScript function from opencode agent
- Update integration tests to expect --format json flag in launch commands
- Fix assertions for exec opencode --session wrapper format

* fix: address Bugbot findings on PR #366

- Fix orphaned runtime leak when reuse strategy finds alive runtime but
  get() returns null (now destroys the orphaned runtime)
- Restore session ID format validation in fallback script with
  isValidId regex check
- Add regression tests for both fixes

* fix: address additional Bugbot findings on PR #366

- Add timestamp helper to fallback sort to avoid NaN from invalid dates
- Add session ID type/format validation to primary capture script
- Add tests for both robustness improvements
2026-03-10 08:42:07 +05:30
prateek a99d37b1d0
feat(ao): add OpenClaw notifier plugin for AO escalations
Adds AO notifier-openclaw (webhook-first Phase 0), registry wiring, tests, docs, and BugBot fixes.
2026-03-09 18:24:30 +05:30
Harsh Batheja cc2031f0f6
fix: bugbot follow-ups from PR #315 (#357)
* fix: address bugbot follow-ups in send and opencode discovery

* fix(test): update stale integration test expectation for opencode bootstrap

The getLaunchCommand implementation now uses a robust bootstrap pattern
that captures the session ID between 'opencode run' and 'exec opencode --session'.
Updated test to check both parts separately instead of expecting a contiguous
string that no longer exists.

* fix: avoid NaN in sort comparator when both timestamps are missing

The comparator (b.updatedAt ?? -Infinity) - (a.updatedAt ?? -Infinity)
produces NaN when both timestamps are missing because -Infinity - (-Infinity)
is NaN in IEEE 754. A comparator returning NaN violates ECMA-262's
'consistent comparison function' requirement, making sort results
implementation-defined.

Fixed by adding equality check before subtraction:
- If both timestamps are equal (including both -Infinity), return 0
- Otherwise return the difference
2026-03-08 12:50:54 +05:30
Harsh Batheja 4e2144d99e
feat: OpenCode session lifecycle and CLI controls (#315)
* feat: refine OpenCode session reuse strategy and cleanup

* fix: harden OpenCode session selection and lint errors

* refactor: centralize OpenCode reuse resolution flow

* fix: return 404 for missing session in message route

* feat: replace force remap with terminal reload control

* fix: protect project path from session kill cleanup

* fix: preserve fullscreen alignment without reload action

* fix: harden OpenCode session id handling and title reuse selection

* fix: show OpenCode reload control and remap before restart

* fix: preserve title-only OpenCode reuse with fallback mapping persistence

* fix: resolve remaining PR315 Bugbot findings

* fix: keep OpenCode discovery title-based without timestamp sorting

* fix: avoid enrichment race fallout in session listing

* fix: guard OpenCode discovery parse with array check

* fix: stabilize Linear comment integration check

* fix: harden OpenCode discovery and prompt option flow

* ux: clarify OpenCode terminal restart action

* fix: remap OpenCode session fresh on each restart

* fix: validate remap session ids before reuse

* fix: clean archived metadata only after purge

* docs: align OpenCode remap selection with title-based behavior

* fix: harden opencode cleanup and ignore local sisyphus state

* test: add timeout cleanup coverage for session enrichment

* fix: harden Linear integration helper against transient non-JSON errors

* fix: make linear integration assertions resilient to eventual consistency

* fix: remove unused fs import after rebase

* fix: address remaining Bugbot blockers for opencode session handling

* fix: avoid stale metadata overwrite during restore post-launch

* fix: forward subagent in orchestrator flows and defer reuse lookup

* fix: apply configured subagent fallback for session spawn

* fix: scope archived cleanup by project and delay archive restore write

* fix: normalize orchestrator strategy aliases in start display logic

* fix: centralize orchestrator strategy normalization in core

* fix: derive orchestrator reuse display from spawn result

* fix: keep cleanup results consistent across project-id collisions

* fix: namespace cleanup results when session IDs collide

* fix: harden GitHub issue stateReason fallback

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: avoid false failing CI state mapping

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: add tmux command timeouts

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: bound session API enrichment latency

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: repair scm-github merge resolution

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: repair lifecycle-manager test merge

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: delay archive metadata recreation until restore passes

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* test: restore claim-pr session mocks

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>

* fix: address review findings for OpenCode lifecycle PR

- Fix stripControlChars to preserve newlines for reload commands
- Add SessionNotFoundError and use instanceof checks in API routes
- Document orchestratorSessionStrategy in YAML example
- Validate existingSessionId with asValidOpenCodeSessionId()
- Extract inline Node script to buildSessionLookupScript helper
- Create OpenCodeSessionManager interface for remap capability
- Create OpenCodeAgentConfig type for agent-specific config
- Change default orchestratorSessionStrategy from delete to reuse

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

* fix: guard reused session display without metadata

* chore: add agent config files to .gitignore

Agent configuration files (CLAUDE.md, AGENTS.md, IMPROVEMENTS.md, etc.) are personal and project-specific. They should not be committed to the repository.

Changes:
- Remove CLAUDE.md from git tracking
- Add agent config files to .gitignore
- Create .gitignore-template for reference

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

* chore: update gitignore for agent config folder structure

Reorganized agent configuration files:
- CLAUDE.md and AGENTS.md stay in root (agents read them there)
- Tracking files move to .opencode/ (IMPROVEMENTS.md, etc.)
- Optional Claude files in .claude/

Updated .gitignore to ignore folders instead of individual files.

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

* fix: tighten opencode remap and session discovery safeguards

* fix: address Bugbot findings in session manager

* fix: scope opencode discovery to opencode sessions

* fix: restore concurrent listing and strict permission literals

* fix: throw SessionNotFoundError, parallelize list enrichment, fix permissions type

- Session manager now throws SessionNotFoundError instead of plain Error
  for missing sessions, so web API routes correctly return 404 (not 500)
- Parallelize session enrichment in list() — was sequential, causing O(N)
  latency for N sessions with subprocess enrichment
- Fix AgentLaunchConfig.permissions type to accept legacy "skip" value
  (AgentPermissionInput instead of AgentPermissionMode)
- Add happy-path and validation tests for /api/sessions/:id/message route
- Update all test mocks to use SessionNotFoundError

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

* fix: route ao send through session manager

* feat: add purge option to orchestrator stop

* fix: register opencode agent in web services

* test: align web API missing-session coverage

* fix: match notifier config by plugin name

* refactor: dedupe session lookup and tmux buffer send flow

* test: update send lifecycle wait expectation

* fix: harden send routing and cleanup purge controls

---------

Co-authored-by: Harsh <harsh@Ubuntu-24-Forrest.lan>
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Prateek <karnalprateek@gmail.com>
2026-03-08 09:55:44 +05:30
prateek ef40c529f8
fix: handle permissions=skip correctly in codex plugin (#337)
* fix: handle permissions=skip correctly in codex plugin

* refactor: rename permission mode to permissionless and align agent mappings

---------

Co-authored-by: Jayesh Sharma <wjayesh@outlook.com>
2026-03-07 20:27:01 +05:30
Jayesh Sharma 8801502871
feat: add PR claim flow for agent sessions (#326)
* feat: add PR claim flow for agent sessions

* feat: support PR claim during spawn

* fix: address PR review feedback

* feat: add lifecycle worker automation

* fix: prevent duplicate messages on unconfirmed delivery and deduplicate review prompt

sendWithConfirmation now treats unconfirmed delivery as a soft success
since the message was already sent, preventing the dispatch hash from
staying stale and causing duplicate sends on the next poll cycle.

review-check command now sources its prompt from the lifecycle reaction
config instead of hardcoding it, keeping both paths aligned.

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

* fix: pass AO_CONFIG_PATH to spawned lifecycle worker and log duplicate-worker early exit

The spawned lifecycle worker now receives AO_CONFIG_PATH in its
environment so it finds the correct config regardless of CWD. Also
added a log message when exiting early due to an existing worker.

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

* fix: prevent lifecycle worker from clearing metadata on SCM fetch failures

SCM methods (getPendingComments, getAutomatedComments) silently returned []
on error, causing maybeDispatchReviewBacklog to treat fetch failures as
"no comments" and clear all tracking metadata every poll cycle. The worker
appeared to do nothing because it kept resetting its own state.

- SCM methods now propagate errors instead of returning []
- maybeDispatchReviewBacklog distinguishes null (fetch failed, skip) from
  [] (confirmed empty, safe to clear)
- pollAll() logs errors instead of silently swallowing them
- Added heartbeat logging and stdout flush before process.exit

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

* fix: add debug breadcrumbs when review comment fetch fails

Logs a console.debug message when getPendingComments or
getAutomatedComments fails, making it clear the lifecycle loop is
preserving metadata due to a fetch failure rather than genuinely
having no comments.

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

* fix: scope lifecycle worker polling to its project and add missing test

pollAll() now passes the worker's projectId to sessionManager.list(),
so each per-project lifecycle worker only polls its own sessions. This
prevents duplicate SCM API calls and race conditions in multi-project
configs.

Also fixed misleading test name and added a test verifying that
--no-dashboard alone still starts the lifecycle worker.

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

* fix: remove dead confirmation check and respect project-level reaction overrides

Removed the unreachable "could not be confirmed" guard from the retry
logic since sendWithConfirmation now returns silently on unconfirmed
delivery.

review-check now resolves the prompt per-session by checking
project-level reaction overrides before falling back to the global
config, matching lifecycle worker behavior.

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

* fix: close TOCTOU race in lifecycle worker spawn and unexport getRegistry

Write the child PID from the parent immediately after spawn, closing
the window where a concurrent ensureLifecycleWorker could pass the
"not running" check and spawn a duplicate worker.

Also removed the unnecessary export on getRegistry since it has no
external consumers.

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

* fix: always include ao base prompt on spawn

* fix: clear heartbeat on shutdown and add initial delay to confirmation loop

Clear the heartbeat interval in the shutdown handler to prevent it
firing during the stream-flush window after lifecycle.stop().

Move the sleep in sendWithConfirmation to before each check (including
the first), so the runtime has time to reflect the message before
the first confirmation attempt.

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

* fix: resolve lint errors in lifecycle and session manager

- Replace dynamic delete with object reconstruction in lifecycle-manager
- Add { cause } to re-thrown errors in session-manager for preserve-caught-error rule

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 03:54:19 +05:30
Harsh bcc08cd229 fix: gate workspace cleanup to AO-managed worktree roots 2026-03-06 15:08:45 +05:30