Commit Graph

70 Commits

Author SHA1 Message Date
ChiragArora31 4d33d25126 fix: detect nested project directories in CLI auto-resolution 2026-04-01 18:28:57 +05:30
Dhruv Sharma 124f7d30ee Merge main into feat/openclaw-dx - resolve conflicts
Conflicts resolved in 3 files:
- plugin-marketplace.ts: take main's createRequire approach, keep isAbsolute fix
- plugin-scaffold.ts: take main's newline escaping (superset of backslash fix)
- plugin.test.ts: take main's importOriginal pattern

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 20:05:16 +05:30
Dhruv Sharma 166ace7477 refactor: extract fetch timeout into named constant
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:38:28 +05:30
Dhruv Sharma 6cfb1cc864 fix: guard statSync against permission errors, add fetch timeout
- Wrap statSync in try/catch in resolveLocalPluginEntrypoint so
  permission-denied errors return null instead of crashing
- Add 30s AbortSignal timeout to refreshMarketplaceCatalog fetch
  to prevent indefinite hangs on slow networks

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:37:52 +05:30
Dhruv Sharma d36c0947cf refactor: deduplicate plugin resolution logic between core and CLI
Export isPluginModule, normalizeImportedPluginModule,
resolvePackageExportsEntry, and resolveLocalPluginEntrypoint from
@composio/ao-core and import them in the CLI instead of maintaining
independent copies that have already diverged.

Removes ~70 lines of duplicated code from plugin-marketplace.ts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 13:53:30 +05:30
Dhruv Sharma 153c298a46 fix: resolve plugin-registry.json from package root
createRequire resolves relative to the compiled dist/lib/ directory
where the JSON file doesn't exist. Use readFileSync with a path
resolved from the package root (../../src/assets/) which works from
both src/lib/ and dist/lib/.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 13:45:54 +05:30
Dhruv Sharma 6930f2ee12 fix: use createRequire for JSON import (Node16 module compat)
Import attributes aren't supported with module: "Node16". Switch to
createRequire for the plugin-registry.json import and copy assets
to dist during build.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 05:11:24 +05:30
Dhruv Sharma 2c0a32da24 fix: use createRequire for JSON import (Node16 module compat)
Import attributes (`with { type: "json" }`) require module >= node18.
Use createRequire instead since tsconfig targets Node16.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 05:10:50 +05:30
Dhruv Sharma 545bede0b4 fix: add JSON import attribute for Node.js 20 compatibility
Add `with { type: "json" }` to the plugin-registry.json import to
satisfy Node.js 20's ERR_IMPORT_ASSERTION_TYPE_MISSING requirement.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 05:08:13 +05:30
Dhruv Sharma 42adf3f35d fix: add JSON import attribute for plugin-registry.json
Node.js v20 requires `with { type: "json" }` for JSON module imports.
This fixes the ERR_IMPORT_ASSERTION_TYPE_MISSING error in the onboarding
integration test.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 05:07:56 +05:30
Dhruv Sharma 41989b71bc fix: remove dead code, validate SHELL path, and guard health JSON parsing
- Remove unused printPluginList wrapper (all callers use printPluginListFromCatalog directly)
- Remove unused getAgentFromRegistry export (all callers use getAgentByNameFromRegistry)
- Validate SHELL env var starts with / before passing to spawnSync
- Add shape validation for openclaw-health.json parsed content

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 05:01:28 +05:30
Dhruv Sharma 1271ef8fbd fix: add missing default exports fallback and remove dead code
- Add top-level "default" key fallback in CLI's resolvePackageExportsEntry
  to match core's plugin-registry.ts (fixes local plugin resolution for
  packages using exports: { "default": "./dist/index.js" })
- Remove dead exports: MARKETPLACE_PLUGIN_CATALOG, printPluginList,
  getAgentFromRegistry, resolveInstalledPluginSpecifier
- Fix incomplete string escaping in plugin scaffold (backslash/newline)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 04:57:25 +05:30
Dhruv Sharma 846ddc4135 refactor: enhance OpenClaw plugin interfaces and improve setup options 2026-03-31 04:56:03 +05:30
Dhruv Sharma 4d142eac1f add credential resolver for OpenClaw key sharing 2026-03-31 04:02:33 +05:30
Dhruv Sharma a10ceb6c09 enhance openclaw-probe with installation detection 2026-03-31 04:02:33 +05:30
Dhruv Sharma 7445e134c4 add plugin spec and update docs 2026-03-31 04:02:25 +05:30
Dhruv Sharma 594c371e37 add browser-open error handling 2026-03-31 04:02:25 +05:30
Dhruv Sharma 9ba04391d9 use plugin store for shared loader paths 2026-03-31 04:02:25 +05:30
Dhruv Sharma df9409eceb add plugin scaffold generator 2026-03-31 04:02:25 +05:30
Dhruv Sharma bd60fb7b52 extract marketplace catalog to JSON with refresh 2026-03-31 04:02:25 +05:30
Dhruv Sharma 39396d4534 add cli error formatter and plugin store 2026-03-31 04:02:25 +05:30
Gautam Tayal 5ba73016e0 fix: update promptSelect to handle undefined initialValue 2026-03-29 18:39:32 +05:30
Gautam Tayal a180520575 refactor(cli): replace readline prompts with clack prompts 2026-03-29 18:06:27 +05:30
Dhruv Sharma 5933991252
Merge pull request #631 from illegalcall/feat/openclaw-integration
feat: OpenClaw plugin, AO skill, Discord notifier, and setup wizard
2026-03-27 09:48:25 +05:30
Dhruv Sharma 62ecad06b1 fix: address final CodeRabbit PR review findings
- openclaw-probe.ts: fix trailing ": " when response body is empty —
  use conditional interpolation instead of .trim() on the full string
- doctor.ts: split connectivity check and test-notify into separate
  try-catch blocks with distinct error messages so failures are
  attributed correctly ("Notifier connectivity check failed" vs
  "Sending test notifications failed")

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 23:17:42 +05:30
Dhruv Sharma 570f3b588f fix: address CodeRabbit review comments
- Use consistent regex for OPENCLAW_HOOKS_TOKEN detection and replacement
  in shell profile (prevents silent no-ops for non-exported lines)
- Broaden token detection regex to match lines with/without export prefix
  and leading whitespace
- Fix misleading --non-interactive help text (token is auto-generated)
- Fix doctor.ts catch block to say "Notifier checks failed" not "load config"
- Fix 204 mock in Discord notifier test (ok: true, not ok: false)
- Fix weak no-duplicate assertion in setup.test.ts (actually count list items)
- Add discord to notifier options comment in config-instruction.ts
- URL-encode threadId in Discord webhook URL construction
- Add aoCwd to required[] in openclaw.plugin.json configSchema
- Add HTTPS recommendation comment to agent-orchestrator.yaml.example
- Add rimraf for cross-platform clean script in notifier-discord
- Rename "Recommended Settings" to "Required: Disable Conflicting Built-in Skills"
  with explicit warning in docs
- Add /ao setup post-setup reminder to manually disable coding-agent skill
- Fix misleading README non-interactive example wording

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 21:58:19 +05:30
suraj-markup aa7e360898 refactor(cli): centralize agent runtime selection logic 2026-03-26 15:48:22 +05:30
suraj-markup c5cc0620e2 fix(cli): disable tmux auto-install in spawn preflight 2026-03-26 13:59:29 +05:30
suraj-markup eee9d773f4 fix: interactive tmux install with user consent, log before auto-install
- Refactor ensureTmux() to use askYesNo() + tryInstallWithAttempts()
  matching the existing ensureGit() pattern — no silent sudo
- Add log line before each auto-install attempt in preflight.checkTmux()
- Update config warning: "will prompt to install at startup"
- Update design doc to reflect interactive consent flow
- Include prior uncommitted changes: interactive install prompts for
  git/gh/agent-runtime, ensureGit(), canPromptForInstall(), askYesNo()

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 17:46:56 +05:30
suraj-markup 761173456d fix: true two-step setup — tmux auto-install, process fallback, restart bookkeeping
- checkTmux() now attempts auto-install (brew/apt/dnf) before erroring
- Config generation uses runtime: "process" when tmux unavailable
- start.ts tries auto-install during config creation, falls back gracefully
- Fix restart bookkeeping in start-all.ts: slot-based tracking prevents
  duplicate children entries that broke cleanup countdown
- Updated design doc reflecting all fixes and review feedback

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 03:31:06 +05:30
suraj-markup 90ee21c3e1 fix: repair npm global install — walk-up dep resolution, spawn-helper chmod, platform-aware messages
- Replace hardcoded single-level checkBuilt() with findPackageUp() walk-up
  resolver that handles npm hoisting (fixes #619)
- Add postinstall script to chmod node-pty spawn-helper for global installs
  (fixes #624)
- Platform-aware tmux install messages (brew/apt/dnf/WSL instead of
  hardcoded brew)
- Auto-restart crashed terminal servers in start-all.ts (up to 3 retries)
- ESLint config for packages/ao/bin scripts
- Expanded preflight tests (3 → 5 checkBuilt cases)

Closes #619, closes #624

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 03:06:40 +05:30
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
suraj-markup 4fcdc674d4 Rename npm package from @composio/agent-orchestrator to @composio/ao
Users can now install with:
  npm install -g @composio/ao

Instead of the longer:
  npm install -g @composio/agent-orchestrator

- Rename packages/agent-orchestrator → packages/ao
- Update package.json name and directory field
- Update all references in README, SETUP.md, changeset config, and CLI error messages

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 02:17:02 +05:30
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 511d2b7fb9 Resolve remaining PR review comments
- Remove redundant project-existence check after autoDetectProject
- Wrap SIGTERM in try/catch for restart flow (dead process case)
- Remove unused setCallerContext export from caller-context.ts
- Fix unused vi import lint error in init.test.ts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 15:51:02 +05:30
suraj-markup 09f757dd0e Fix PR review comments: spawn hint, dead code, detect import
- Fix spawn hint in start.ts to use new single-arg syntax
- Remove dead addProjectOnly() export (add-project fully deleted)
- Make detect-agent.ts handle both named and default export shapes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 15:14:42 +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 630586f66c Fix medium issues: lockfile, SIGTERM wait, config overwrite, spawn ambiguity
- Add advisory lockfile (O_EXCL) to running-state.ts to prevent TOCTOU
  race when multiple ao start processes run concurrently
- Wait up to 5s for old process to exit after SIGTERM in Override menu,
  escalate to SIGKILL if needed — prevents port conflict on restart
- Guard autoCreateConfig against overwriting existing config files —
  returns existing config instead of silently replacing it
- Fix spawn single-arg disambiguation: in single-project configs, always
  treat the arg as an issue ID (user never needs to specify project)
- Clean up running.json by deleting file instead of writing "null"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 05:57:26 +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
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 3d518aed2f
feat: add doctor and update maintenance tooling (#437)
* feat: add ao doctor maintenance checks

* feat: add ao update refresh script

* feat: add shared CLI script runner

* feat: add doctor and update CLI commands

* docs: document doctor and update commands

* fix: harden maintenance safety checks

* fix: harden ao update behavior

* fix: strip inline comments from doctor config values
2026-03-12 20:59:22 +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
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
prateek a4a1a32e96
fix: auto-detect free port in ao start <url> config generation (#275)
* fix: auto-detect free port in ao start <url> config generation

When generating a new config via `ao start <url>`, auto-detect a free
port instead of hardcoding 3000. Reuses `findFreePort` (extracted to
shared web-dir.ts from init.ts). When port was auto-selected, skip the
strict preflight port check and silently find another free port if
needed (race condition).

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

* fix: add polling to listIssues integration test for Linear API consistency

The listIssues test was failing because Linear's API has eventual
consistency — a just-created issue may not appear in list queries
immediately. Other tests in this file already use pollUntilEqual for
the same reason. Use pollUntil to retry until the issue appears.

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

* fix: restore coupling between MAX_PORT_SCAN and findFreePort

MAX_PORT_SCAN was decoupled from findFreePort after extraction to
web-dir.ts — init.ts kept a local constant only used in messages while
findFreePort had its own default, and start.ts hardcoded 99. Export
MAX_PORT_SCAN from web-dir.ts as the single source of truth, use it as
findFreePort's default parameter, and import it in both callers.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 15:03:20 +05:30
prateek e72593d4f8
fix: URL start multi-project resolution and cross-platform browser open (#272)
* fix: URL start handles multi-project configs and cross-platform browser open

When `ao start <url>` loads an existing config with multiple projects,
resolve the correct project by matching the URL's owner/repo against
each project's `repo` field instead of failing with "Multiple projects".

Also fix browser open to use platform-appropriate command (open/xdg-open/start)
instead of hardcoded macOS `open`.

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

* fix: use shallow clone (--depth 1) for faster repo onboarding

Full clones of large repos can take minutes. Shallow clone with
depth 1 fetches only the latest commit, making `ao start <url>`
near-instant for any repo size.

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

* fix: use cmd.exe /c start for Windows browser open

`start` is a cmd.exe builtin, not a standalone executable — spawn
would fail with ENOENT. Run via cmd.exe /c with empty title arg.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 14:26:41 +05:30
prateek 80a1d59999
feat: add `ao start <url>` one-command project onboarding (#267)
* feat: add `ao start <url>` one-command project onboarding

When `ao start` receives a repo URL instead of a project ID, it now:
1. Parses the URL (supports GitHub, GitLab, Bitbucket — HTTPS and SSH)
2. Clones the repo (or reuses if already present with matching remote)
3. Auto-generates agent-orchestrator.yaml with sensible defaults:
   - SCM/tracker plugins inferred from URL host
   - Default branch detected from local refs
   - Project type detected (language, package manager)
   - Post-create install commands set based on package manager
4. Starts the orchestrator + dashboard as usual

New core module `config-generator.ts` handles URL parsing, SCM detection,
project info detection, and config generation. All logic is in core (not
CLI) for reusability. 36 unit tests cover URL parsing, SCM detection,
default branch detection, project info, config generation, and clone
target resolution.

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

* fix: address bugbot review feedback

1. Non-JS postCreate fix: Only set postCreate install commands for JS
   package managers (pnpm/yarn/bun/npm). Rust/Go/Python projects no
   longer get an incorrect "npm install" command.

2. Deduplicate startup logic: Extract shared `runStartup()` helper used
   by both URL-mode and normal-mode start flows. Eliminates ~100 lines
   of duplicated dashboard+orchestrator startup code.

3. SSH URL matching: Normalize SSH URLs to HTTPS format in
   `isRepoAlreadyCloned()` so repos cloned via SSH
   (git@github.com:owner/repo) are correctly detected as matching.

4. SCM/tracker always explicit: Always set scm and tracker fields in
   generated config so `applyProjectDefaults()` doesn't silently
   override with github defaults for non-GitHub repos.

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

* fix: sanitize repo names for project IDs and session prefixes

Address remaining bugbot comments:
- Add sanitizeProjectId() to handle dots/special chars in repo names
  (e.g. "my.app" → "my-app" instead of failing Zod validation)
- Preserve original case for generateSessionPrefix() so CamelCase
  detection works (e.g. "DevOS" → prefix "dos", not "dev")
- Strip invalid chars before prefix generation to prevent dots
  leaking into sessionPrefix

Also update README and SETUP docs with `ao start <url>` quick
onboarding flow.

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

* feat: auto-open browser to orchestrator page on `ao start`

Opens the orchestrator session page (/sessions/{id}) instead of the
root dashboard, since the Kanban board is empty on first startup
with no worker sessions yet.

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

* fix: replace fixed 3s delay with port polling for browser open

Poll the dashboard port via TCP connection attempts (300ms intervals,
30s timeout) instead of a hardcoded setTimeout. Opens the browser only
once the server is actually accepting connections — deterministic
regardless of how long Next.js takes to compile.

Applied to both `ao start` and `ao dashboard` commands.

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

* test: add CLI tests for start/stop commands

12 new tests covering:
- Project resolution: single project, explicit arg, missing project,
  multi-project ambiguity, empty config
- URL argument: reuse existing clone, git clone flow, existing config
  detection, clone failure error handling
- Port polling: waitForPortAndOpen polls isPortAvailable before opening
  browser (proves deterministic behavior vs fixed delay)
- Stop command: session kill + dashboard stop, graceful missing session

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

* refactor: deduplicate waitForPortAndOpen into shared utility

Move waitForPortAndOpen to lib/web-dir.ts (alongside isPortAvailable)
so both start.ts and dashboard.ts share a single cancellation-aware
implementation. start.ts now uses AbortSignal like dashboard.ts —
polling stops immediately if the dashboard process exits early.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 13:52:49 +05:30
suraj_markup 7aa883c217
Merge pull request #254 from suraj-markup/feat/try-pr-script
feat(scripts): add try-pr.sh for testing PR worktrees locally
2026-03-03 01:18:06 +05:30
suraj_markup 01a6c56e1b
Merge pull request #246 from suraj-markup/feat/issue-245
fix(setup): improve setup.sh prereq validation and add start/spawn pre-flight checks
2026-03-02 03:24:14 +05:30
suraj-markup 6603685a2f feat(scripts): add try-pr.sh for testing PR worktrees locally
Adds scripts/try-pr.sh — a helper to switch the global 'ao' command to
any session's worktree for manual testing, then restore back to main.

Usage:
  bash scripts/try-pr.sh <session-id>            # CLI/core/plugins only
  bash scripts/try-pr.sh <session-id> --with-web # also builds + starts dashboard
  bash scripts/try-pr.sh --restore               # switch back to main

Also fixes isPortAvailable() to use a connect-based probe instead of
bind-based. The old approach had false positives on macOS when Next.js
listens on :: (IPv6 wildcard) — binding 127.0.0.1 succeeded even though
the port was taken. A TCP connect correctly detects any listener
regardless of which address it's bound to.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 03:19:49 +05:30