Commit Graph

1626 Commits

Author SHA1 Message Date
Prateek 4028e5b77d fix: suppress immediate notification when send-to-agent reaction handles event
When a send-to-agent reaction was configured (e.g. for ci-failed), the
reactionHandledNotify flag stayed false, causing checkSession() to also
call notifyHuman() immediately — bypassing the retry/escalation workflow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 04:07:38 +05:30
Prateek 9e7a767730 fix: notify on significant transitions, preserve stuck state on probe failure
Two bugs fixed:

1. Transitions with non-info priority (e.g. merge.completed,
   review.approved, session.errored) now call notifyHuman() directly
   when no reaction config handles notification. Before, these
   transitions updated state silently with no human notification.

2. When agent.detectActivity() throws, sessions in stuck/needs_input
   state now preserve that state instead of being coerced to "working"
   by the fallback at the bottom of determineStatus().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 03:55:19 +05:30
Prateek 95fd47ef2a refactor: remove EventBus, simplify lifecycle manager
The event bus was over-engineered for a system with ~50 sessions. The
dashboard can read metadata files + poll GitHub directly. Remove the
EventBus interface, event-bus.ts module, and all emit/subscribe wiring
from session-manager and lifecycle-manager. The reaction engine (the
valuable part) stays — executeReaction now takes sessionId/projectId
directly instead of going through OrchestratorEvent.

Also fix listMetadata() to filter out directories (not just the
"archive" dir by name) so readMetadataRaw() can't crash on non-file
entries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 03:38:11 +05:30
Prateek 4c47a42b6e fix: use literal mode for tmux send-keys, prune stale lifecycle trackers
- Add -l flag to tmux send-keys for short messages so key-like payloads
  (e.g. "Enter", "Escape") are sent as text, not interpreted as keypresses
- Prune states and reactionTrackers maps in pollAll() for sessions that
  no longer appear in the session list, preventing unbounded memory growth
  and stale retry counters from applying to reused session IDs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 21:09:49 +05:30
Prateek 07b3a553f7 fix: allow notify reactions when auto is false, clean up reserved IDs on spawn failure
- Reactions with action: "notify" bypass the auto: false gate so
  merge-ready notifications fire for approved-and-green config
- All spawn failure paths now delete the reserved session metadata file

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 21:00:58 +05:30
Prateek 65787f08e3 fix: use handle.runtimeName for plugin lookup, atomic session ID reservation
- kill() and send() prefer handle.runtimeName over project defaults
- spawn() uses O_EXCL atomic file creation to prevent concurrent ID collisions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 20:41:11 +05:30
Prateek a225bc17f5 fix: runtime plugin lookup, post-create guard, restart transition detection
- kill() uses handle.runtimeName to find the correct runtime plugin
- postCreate cleanup skips destroy when workspacePath is project root
- checkSession reads persisted metadata status on first poll after restart

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 19:16:50 +05:30
Prateek 88ea7d1491 fix: prevent project workspace deletion and agent config workspace leak
- kill() skips workspace.destroy when worktree matches project.path
- spawn() wraps getLaunchCommand/getEnvironment in workspace cleanup guard

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:55:07 +05:30
Prateek ad0b45006c fix: session recovery, reaction config merge, summary priority
- stuck/needs_input sessions recover to working when agent is active
- Project reaction overrides merge with global defaults (not replace)
- summary.all_complete events get info priority (not action)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:45:33 +05:30
Prateek 24391c874e fix: ignore next-env.d.ts in ESLint config
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:42:45 +05:30
Prateek f6f5e24e3c fix: add missing cleanup status to VALID_STATUSES set
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:42:45 +05:30
Prateek 4a804503b6 fix: execute all-complete reaction and guard workspace postCreate
- summary.all_complete reactions now execute in pollAll() after emission
- workspace.postCreate errors trigger workspace cleanup to prevent leaks

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:42:45 +05:30
Prateek 2ecb011982 fix: address all review comments, lint/format, bugbot issues
Review fixes:
- metadata: sessionId validation to prevent path traversal
- event-bus: guard appendFileSync, remove unused import
- lifecycle-manager: fix reaction retry counting (track attempts,
  clear on status transition), allow retry on send failure instead
  of immediate escalation, detect killed sessions in polling loop,
  map session.killed to agent-exited reaction
- session-manager: validate status against union, clean up runtime
  and workspace on spawn failure, kill with default plugins when
  project config is missing

Lint/format fixes:
- Remove unused imports across all test files
- Replace `Function` type with typed callback in tmux tests
- Replace require() with dynamic import() in tests
- Replace dynamic delete with object spread in metadata
- Apply prettier formatting to all files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:42:45 +05:30
Prateek c49649c2c1 fix: address codex review — path traversal, retry logic, type safety
- metadata: validate sessionId against ^[a-zA-Z0-9_-]+$ to prevent
  path traversal attacks
- lifecycle-manager: fix reaction retry/escalation to count attempts
  (not just successes), escalate after maxRetries attempts; map
  session.killed to agent-exited reaction (was unreachable session.exited)
- session-manager: validate status against known SessionStatus union
  (default to "spawning" for unknown values); clean up workspace on
  runtime creation failure to prevent resource leaks
- event-bus: guard appendFileSync in try/catch so disk errors don't
  crash event emitters

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:42:45 +05:30
Prateek d6ec95402d fix: address PR review — unsafe casts, tmux race, concurrent polling
- session-manager: replace readMetadata with readMetadataRaw (no unsafe casts),
  add safeJsonParse for JSON.parse guards, escapeRegex for session prefix,
  explicit branch priority, convert from this-based to closure-based methods
- tmux: named buffers (load-buffer -b / paste-buffer -b -d) to prevent
  global paste buffer race on concurrent sendKeys; send Escape before text
  to clear partial input
- lifecycle-manager: concurrent polling with Promise.allSettled instead of
  sequential for-of await, allCompleteEmitted guard to prevent repeated
  summary.all_complete events, polling re-entrancy guard, safe reaction
  config handling with action/auto checks
- tests: update tmux tests for Escape-first and named buffer changes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:42:45 +05:30
Prateek 2b9a28a031 test: add comprehensive unit tests for all core services
Add vitest test suite with 103 tests across 5 test files:

- metadata.test.ts (19 tests): read/write/update/delete/list, key=value
  parsing, comments, values with equals signs, archiving, dotfile exclusion
- event-bus.test.ts (22 tests): emit/on/off, wildcard listeners, handler
  error resilience, priority inference, JSONL persistence round-trip,
  filtered history with sessionId/projectId/type/priority/since/limit
- tmux.test.ts (23 tests): all tmux wrappers with mocked child_process,
  session listing/parsing, send-keys short vs load-buffer long text,
  capture-pane, kill, getPaneTTY
- session-manager.test.ts (23 tests): spawn pipeline with mocked plugins,
  session numbering, branch derivation, event emission, metadata writing,
  list with dead runtime detection, kill with cleanup, send via runtime
- lifecycle-manager.test.ts (16 tests): state transitions (spawning→working,
  killed, stuck, needs_input, ci_failed, merged, mergeable), reaction
  triggering, auto=false suppression, on/off handlers, getStates isolation

Also fixes inferPriority to handle merge.completed as "action" priority.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:42:45 +05:30
Prateek de86054b9d feat: implement core services (metadata, event-bus, tmux, session-manager, lifecycle-manager)
Implement the 5 core service modules in packages/core/src/:

- metadata.ts: Flat-file key=value session metadata read/write matching
  existing bash script format. Supports read, write, update, delete
  (with archive), and list operations.

- event-bus.ts: In-process pub/sub with JSONL append-only persistence.
  Supports typed and wildcard listeners, priority inference from event
  type, filtered history queries, and a createEvent() helper.

- tmux.ts: Async wrappers around tmux commands using child_process.execFile
  (no shell injection). Handles long/multiline messages via load-buffer/
  paste-buffer. Covers list, create, send-keys, capture-pane, kill, and
  pane TTY discovery.

- session-manager.ts: Session CRUD that orchestrates Runtime + Agent +
  Workspace plugins. Full spawn pipeline (workspace → runtime → agent),
  list with live runtime checks, kill with cleanup, batch cleanup checking
  PR state + issue state + runtime liveness, and message delivery.

- lifecycle-manager.ts: State machine per session with configurable polling
  interval. Detects status transitions, emits events, triggers configured
  reactions (send-to-agent, notify, auto-merge) with retry counting and
  time-based escalation. Routes notifications by priority to configured
  notifier plugins.

All services implement interfaces defined in types.ts. Updated index.ts
to export all new modules.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:42:45 +05:30
prateek 0c535c98d7
fix: CI handles Next.js build separately, fix web tsconfig (#14)
* fix: CI workflow handles Next.js build separately, fix web tsconfig rootDir

- Remove rootDir from web tsconfig (conflicts with Next.js generated .next/types)
- Include .next/types/**/*.ts in web tsconfig
- CI: build non-web packages first, web build allowed to soft-fail
- CI: typecheck excludes web (typechecked by next build)
- CI: test excludes web build dependency

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

* fix: remove || true from web build — bugbot caught it, web errors should fail CI

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

* fix: override rootDir in web tsconfig to "." for Next.js compat

Next.js generates .next/types/ files that must be under rootDir.
Base tsconfig sets rootDir to "src", web needs "." to include both
src/ and .next/types/.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:41:58 +05:30
Prateek c8061ce03f chore: add ESLint, Prettier, CI workflow, and comprehensive CLAUDE.md conventions
- ESLint flat config with typescript-eslint strict rules
- Prettier config (double quotes, semicolons, 2-space indent)
- GitHub Actions CI: lint + typecheck + test on PRs
- Cursor BugBot config (.cursor/BUGBOT.md)
- Comprehensive CLAUDE.md with code conventions, security rules,
  plugin patterns, and common mistakes to avoid
- Fix unused param lint error in plugin-registry.ts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 18:01:52 +05:30
Prateek 5058c409d5 feat: scaffold TypeScript monorepo with all plugin interfaces
Phase 0 complete. Establishes:
- pnpm workspace with 18 packages (core, cli, web, 15 plugins)
- Complete type definitions in packages/core/src/types.ts defining
  all 8 plugin slot interfaces (Runtime, Agent, Workspace, Tracker,
  SCM, Notifier, Terminal) + core service interfaces
- YAML config loader with Zod validation and sensible defaults
- Plugin registry with built-in discovery
- CLAUDE.md with conventions for spawned agents

All agents can now branch from main and implement their assigned
packages against the interfaces defined in types.ts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 17:02:42 +05:30
Prateek 36b0792eb6 docs: add parallel implementation plan with 7-agent work breakdown
Maps dependency graph, identifies 7 truly independent work streams
after Phase 0 (scaffold + types), with Linear tickets and spawn
commands ready to go.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 16:41:06 +05:30
Prateek 3eecca8460 docs: update architecture with push-first notification model
The human never polls. The system notifies the human. Two-tier event
handling: auto-handle routine issues silently, push notifications only
when human judgment is required. Escalation chains, priority-based
routing, and the dashboard is a drill-down tool, not the primary interface.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 16:38:00 +05:30
Prateek 74001b22d0 docs: add competitive research and architecture design artifacts
Comprehensive analysis of 16+ competing agent orchestration tools
(Gas Town, OpenHands, SWE-ReX, Par, claude-flow, etc.) and detailed
architecture design with 8-slot plugin system, session lifecycle state
machine, and human attention optimization patterns.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 16:35:46 +05:30
Prateek 1601ad75c0 feat: add agent-orchestrator (ao) as a self-hosting project
- Create claude-ao-session: worktree-based session manager for ao
  (Linear tickets, GitHub PRs, AO_SESSION env var)
- Add ao|agent-orchestrator case to all shared scripts:
  claude-batch-spawn, claude-spawn, claude-status, claude-open-all,
  claude-review-check, claude-bugbot-fix
- Rewrite CLAUDE.orchestrator.md with full self-hosting instructions:
  commands reference, workflows, architecture, tips
- Session prefix: ao, metadata: ~/.ao-sessions/, worktrees: ~/.worktrees/ao/

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-13 15:44:17 +05:30
Prateek c16103fb4d rename CLAUDE.local.md to CLAUDE.orchestrator.md
This file contains the shared orchestrator instructions that ship with
the repo. It's loaded explicitly via --append-system-prompt-file when
launching an orchestrator session, rather than auto-discovered as a
CLAUDE.local.md. Users can still have their own CLAUDE.local.md for
personal overrides.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-13 15:34:24 +05:30
Prateek 0273e8f3d0 feat: initial commit with orchestrator scripts and dev instructions
Import all 18 production orchestrator scripts from ~/. These are direct
copies with hardcoded paths — generalization is the next step. Includes
CLAUDE.local.md with project overview, architecture notes, and roadmap.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-13 15:25:31 +05:30