Commit Graph

71 Commits

Author SHA1 Message Date
Ashish Huddar c32fb6a03c Fix session polling and BottomSheet freshness 2026-03-27 01:38:54 +05:30
Ashish Huddar 8ce7366b82 Import useRef for session detail page 2026-03-27 01:34:13 +05:30
Ashish Huddar ada469556a Fix session detail project polling and orchestrator response 2026-03-27 01:27:38 +05:30
Ashish Huddar 4a842d4742 Fix ao launcher linking and mobile toast offset 2026-03-26 22:47:25 +05:30
Ashish Huddar e1867d0bef Preserve orchestrator ID when session project changes 2026-03-26 22:38:30 +05:30
Ashish Huddar 128c9101c8 Handle dashboard send failures and optimize session polling 2026-03-26 22:28:31 +05:30
Ashish Huddar 82a93a0a2b Fix metadata loading and refresh orchestrator session links 2026-03-26 11:12:55 +05:30
Ashish Huddar 618448e620 Fix mobile session row grid for 44px open button 2026-03-26 09:07:08 +05:30
Ashish Huddar fa37074a3f Show desktop quick replies and stabilize session polling 2026-03-26 08:30:22 +05:30
Ashish Huddar c38a282f29 Improve mobile nav and reduce session detail polling 2026-03-26 02:03:50 +05:30
Ashish Huddar fd742b595a Keep pull request stat cards visible on mobile 2026-03-25 14:55:09 +05:30
Ashish Huddar 1fb01f99fc Normalize dashboard project filtering and align session layout 2026-03-25 14:34:55 +05:30
Ashish Huddar d743a196d3 Polish mobile dashboard UX and harden PWA behavior 2026-03-25 13:57:40 +05:30
Ashish Huddar b8eab07d28 Fix mobile dashboard navigation and connection state handling 2026-03-25 11:41:36 +05:30
Ashish Huddar fc9edb8afb feat(web): add real-time SSE connection status indicator
Exposes connectionStatus ("connected" | "reconnecting" | "disconnected")
from useSessionEvents via onopen/onerror EventSource handlers, and renders
a fixed ConnectionBar at the top of the viewport that shows a pulsing amber
bar while reconnecting and a red 32px "Offline · tap to retry" bar when
disconnected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 23:04:42 +05:30
Ashish Huddar c361392672 feat(web): add Toast/Snackbar system and BottomSheet for destructive confirmations
- Create Toast.tsx with ToastProvider + useToast hook (3s auto-dismiss, success/error/info variants, fade+slide animation)
- Create BottomSheet.tsx replacing confirm() for kill actions (swipe-to-dismiss, keyboard Escape, session context display)
- Wire ToastProvider + BottomSheet into Dashboard.tsx; replace confirm() calls; add showToast on merge/kill/restore success and error
- Add toast and bottom-sheet CSS to globals.css (no new z-index vars needed — --z-modal/--z-toast already existed)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 22:59:18 +05:30
Ashish Huddar f4518398b1 fix(web): add aria-label to quick-reply textarea and use consistent border token
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 22:55:03 +05:30
Ashish Huddar 602635fac8 fix(web): move .quick-reply styles from 480px to 767px media query
Quick-reply UI was invisible on mobile viewports 480–767px wide because
its styles were scoped to @media (max-width: 480px). Moved all
.quick-reply* rules into the @media (max-width: 767px) block so the
component renders correctly across the full mobile range.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 22:53:31 +05:30
Ashish Huddar 3e678f7f43 feat(web): add quick-reply section on respond cards (mobile)
On mobile (<=767px), session cards with attention level "respond" now
show an inline quick-reply panel with the agent's last message summary
(2-line clamp), Continue/Abort/Skip preset buttons, and an expandable
textarea. Enter submits; all touch targets are >=44px. Hidden on
desktop via CSS-only media query.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 22:45:57 +05:30
Ashish Huddar 6672d09a50 fix(web): action strip a11y fixes and callback stability
- Extract onPillTap as handlePillTap useCallback with prefers-reduced-motion support
- Replace role="navigation" with role="group" aria-label="Session priorities" on pill strip
- Add role="status" to all-clear fallback so screen readers announce state changes
- Add :focus-visible outline to .mobile-action-pill for keyboard accessibility
- Add scroll-margin-top: 56px to .accordion-board to prevent sticky header occlusion

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 22:41:11 +05:30
Ashish Huddar 3845bd582f feat(web): mobile action strip — tappable urgency pills replace stat cards
On mobile (<=767px), replace the 4 stat cards with a single-row
MobileActionStrip showing non-zero urgency pills (respond/merge/review)
with colored dots. Tapping a pill calls setExpandedLevel and scrolls to
the accordion board via id="mobile-board". Hides stat cards, dashboard
subtitle, and board-section-head on mobile to target ~92px hero height.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 18:46:48 +05:30
Ashish Huddar 0d2804fcf9 fix(web): resolve accordion memo regression and CSS scoping
- Fix Critical 1: change onToggle to (level: AttentionLevel) => void and
  create stable handleAccordionToggle with useCallback, eliminating the
  inline arrow that defeated memo on every render
- Fix Critical 2: remove grouped from useEffect deps so user accordion
  selection is not reset on every SSE update; seed only on isMobile change
- Fix Important 3: move accordion CSS block inside @media (max-width: 767px)
  so it is scoped to mobile only, consistent with rest of file
- Fix Important 4: add Safari 16+ compatibility comment on
  grid-template-rows transition
- Fix Suggestion 5: replace ▶/▼ character swap with single ▶ rotated via
  CSS transform so the declared transition: transform actually animates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 18:44:08 +05:30
Ashish Huddar ffef8d4a79 feat(web): mobile accordion layout — urgency-first kanban on mobile
Replace vertical kanban stacking on mobile (<=767px) with a single-open
accordion ordered Respond > Merge > Review > Pending > Working.
Auto-expands the most urgent non-empty section on load; empty sections
render as header-only rows (no dashed placeholder). Desktop layout is
unchanged. Added window.matchMedia stub to the Vitest setup file so
Dashboard unit tests pass in jsdom.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 18:37:53 +05:30
Ashish Huddar 402dc1f861 fix(web): fix mobile sidebar specificity and toggle close behavior
- Increase .project-sidebar--mobile-open specificity to (0,2,0) so it
  overrides .project-sidebar.project-sidebar--collapsed transform
- Make "Hide sidebar" and "Show project sidebar" buttons also call
  onMobileClose to dismiss the mobile drawer when toggling collapse

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 08:04:47 +05:30
Ashish Huddar 4622be19cd feat(web): add PWA support and mobile flawlessness fixes
- Add web app manifest (manifest.ts) with dynamic project name, standalone display
- Add service worker (sw.js) with network-first strategy and offline fallback page
- Add PWA icons: apple-touch-icon (180x180), 192x192, 512x512 via shared renderer
- Add viewport meta with viewport-fit=cover for safe-area-inset support
- Add Apple Web App meta tags for iOS home screen installation
- Add theme-color meta for browser chrome coloring
- Extract shared icon-renderer.tsx to deduplicate icon generation logic
- Add ServiceWorkerRegistrar client component for SW registration
- Configure next.config.js with no-cache headers for service worker
- Add dvh fallbacks for 100vh usage (body, kanban-board, Terminal, DirectTerminal)
- Add safe-area-inset padding for mobile sidebar and dashboard main
- Add iOS auto-zoom prevention (16px font on inputs)
- Add -webkit-tap-highlight-color: transparent and text-size-adjust
- Add PWA standalone mode body padding for safe areas

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 07:53:34 +05:30
Ashish Huddar 8fc778cf30 chore(web): add mobile-responsive layout for dashboard and session views
Add proper mobile breakpoints (768px, 480px) with structural layout changes:

- Sidebar: auto-hide on mobile with hamburger toggle and overlay drawer
- Dashboard hero: stack stats cards and controls vertically on mobile
- Kanban board: stack columns vertically instead of horizontal scroll
- Session cards: flexible height with 44px minimum touch targets
- Session detail: responsive header metadata and full-width terminal
- Global: phone-specific breakpoint (480px) for single-column layouts

Desktop layout remains completely unchanged.

Closes #633

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 00:55:37 +05:30
Ashish Huddar 254d64de8f fix(web): use flat color for dark mode --card-merge-bg
The variable was a linear-gradient (an <image>), but it's used inside
color-mix() which only accepts <color> values. This made the entire
background declaration invalid, rendering merge-ready cards transparent
in dark mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 17:15:07 +05:30
Ashish Huddar 6b7a8bd20c chore(web): design audit fixes — rename column, refine styles, fix terminal
- Rename "Merge Ready" kanban column to "Ready"
- Refine card design system and globals.css theme tokens
- Fix terminal scrollbar and theme handling in DirectTerminal
- Update SessionDetail layout
- Update tests to match component changes
- Add .gstack/ to .gitignore

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 09:58:24 +05:30
Ashish Huddar 9ee1660dfa chore(web): refine card design, terminal scrollbar, and add card showcase
Flatten card shadows, add subtle borders, simplify SessionCard markup,
apply macOS-style auto-hide scrollbar to terminal, and add dev card
showcase page for visual testing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 20:32:43 +05:30
Ashish Huddar 038620ffd1 fix(web): pre-landing review fixes
- Remove unnecessary !important on light mode background
- Add useMemo to ProjectSidebar session grouping (O(n*m) → O(n))
- Filter done sessions from sidebar nav (prevents empty board)
- Fix stale session param showing empty columns instead of empty state
- Add dark class to server-rendered HTML to prevent FOUC

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 13:17:06 +05:30
Ashish Huddar f24abc2145 Add collapsible project sidebar with bottom toggle 2026-03-21 11:49:39 +05:30
Ashish Huddar 4b171cd37b fix(web): wire up ThemeToggle with next-themes provider
- Install next-themes dependency
- Wrap app in ThemeProvider with class-based dark mode
- Remove hardcoded dark class from html element

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 11:06:41 +05:30
Ashish Huddar bfe100c543 chore(web): remove showcase page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 11:03:53 +05:30
Ashish Huddar f9feb4bbf8 chore(web): kanban dashboard redesign — Linear-inspired design system
Redesign the kanban dashboard with a Linear-inspired aesthetic:
- New design tokens (neutral charcoal darks, white-alpha borders, muted status colors, indigo accent)
- Tighter spacing, visible column backgrounds, dark mode weight reduction
- Redesigned SessionCard, ProjectSidebar, and AttentionZone components
- Removed list view toggle, reordered columns (respond → merge → done)
- Added ThemeToggle, Skeleton/EmptyState components, and showcase page
- Exported CI_STATUS and getSizeLabel for component consumption

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 11:01:31 +05:30
Harsh Batheja 0a41b7dcdb
feat: add dashboard orchestrator spawn action (#441)
* feat: add dashboard orchestrator spawn action

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

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

* test: cover dashboard orchestrator spawn flow

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

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

* fix: stabilize dashboard orchestrator default state

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

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

* fix: remove stale api-routes import after rebase

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:24 +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
Harsh 7025c1c2e1 fix: align project filtering and global pause state
Use one project-matching rule across the sessions API and SSR dashboard paths, and keep global pause derived from the full session set even when the API request is scoped to a single project.
2026-03-12 02:26:04 +05:30
Harsh 3968bb0dc8 fix: reset dashboard state on page load failures
Keep the SSR dashboard page using unified project filtering while clearing orchestrator links and pause state whenever enrichment fails, so error paths cannot render stale state beside an empty session list.
2026-03-12 02:15:03 +05:30
Harsh 1d1c4533a2 fix: unify page project filtering and client helpers
Use the same project matching logic for dashboard orchestrators and workers, and switch the client detail page to the lightweight core types entry so the canonical orchestrator helper stays shared without pulling server-only modules into the browser bundle.
2026-03-12 02:07:52 +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 c537e01aee fix: stabilize orchestrator detail zone refresh
Keep the orchestrator detail page keyed on stable project-scoped values so zone-count polling does not recreate its callback on every session fetch and hammer the sessions API.
2026-03-12 01:08:26 +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 b97bac5e94 fix: scope dashboard orchestrator links by project
Render every project's orchestrator explicitly and keep orchestrator detail pages scoped to their own project so multi-project dashboards show the right control session.
2026-03-11 23:32:35 +05:30
Harsh dee64fbc42 fix: return project-scoped orchestrators from sessions api
Expose orchestrator links per project and keep them out of worker session stats so dashboard consumers stop collapsing multi-project state into one global orchestrator.
2026-03-11 23:29:28 +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
Harsh Batheja c7c04c14df
feat(web): Project-scoped dashboard with sidebar navigation (#381)
* feat(web): add project-based dashboard architecture

- Add project query parameter to API routes
- Filter sessions by project in both SSR and SSE
- Update useSessionEvents hook to accept project param
- Update Dashboard and pass project to hook
- Add unit tests for project filtering
- Add architecture spec document

Implements project-based architecture as defined in docs/specs/project-based-dashboard-architecture.md:
- GET /api/sessions?project=X returns sessions for project X
- GET /api/events?project=X streams only sessions for project X
- Dashboard uses project filter from config
- SSE URL includes project param when provided
- Project matching uses projectId and sessionPrefix
- Full backward compatibility maintained (no param = all sessions)

* fix: remove duplicate export default in page.tsx

* fix(web): clean project-scoped dashboard verification

* fix(web): scope dashboard using project id

* fix(web): address Bugbot findings in project-scoped dashboard

- Consolidate triplicated matchesProject into shared lib/project-utils.ts
- Fix Dashboard to receive both projectId (for SSE filtering) and projectName (for display)
- Remove inline matchesProject definitions from page.tsx, sessions/route.ts, events/route.ts

* fix(web): resolve Bugbot issues in project-scoped dashboard

- Add ?project=all query param support in SSR page to show all sessions
  (previously getPrimaryProjectId() always returned non-empty, making
  else branches unreachable)
- Exclude orchestrator sessions from SSE stream to match SSR/API behavior
  (orchestrator sessions get their own button, not a card)
- Add tests for SSE stream orchestrator exclusion and project filtering

Addresses Bugbot issues:
- #2903595986: Dead else branches when project filter always applied
- #2903595995: SSE stream includes orchestrator sessions unlike SSR/API

* feat(web): add project navigation sidebar

Add visible left sidebar with project navigation for multi-project setups:
- ProjectSidebar component with active state styling
- /api/projects endpoint to fetch configured projects
- getAllProjects() helper in project-name.ts
- Sidebar appears only when 2+ projects configured
- Click navigation updates ?project= query param
- Active project highlighted with accent color

Tests:
- ProjectSidebar component tests (8 tests)
- API routes tests with proper mocking
- All 386 web tests passing

Manual test steps:
1. Configure 2+ projects in agent-orchestrator.yaml
2. Start dashboard - sidebar should appear on left
3. Click different projects - URL updates, sessions filter
4. Click "All Projects" - shows all sessions across projects
5. Active project highlighted in sidebar

* fix(web): remove duplicate import in test file

* fix(web): consolidate ProjectInfo type to shared source

Remove duplicated ProjectInfo interface definitions from Dashboard.tsx and
ProjectSidebar.tsx. Both now import the type from @/lib/project-name where it is exported as the single source of truth.

This addresses Bugbot issue #2906835895: Triplicated ProjectInfo type instead of shared import.

* fix(web): integrate globalPause state from main

* fix(web): consolidate duplicate @/lib/types import

* feat(web): add project-based dashboard architecture

- Add project query parameter to API routes
- Filter sessions by project in both SSR and SSE
- Update useSessionEvents hook to accept project param
- Update Dashboard and pass project to hook
- Add unit tests for project filtering
- Add architecture spec document

Implements project-based architecture as defined in docs/specs/project-based-dashboard-architecture.md:
- GET /api/sessions?project=X returns sessions for project X
- GET /api/events?project=X streams only sessions for project X
- Dashboard uses project filter from config
- SSE URL includes project param when provided
- Project matching uses projectId and sessionPrefix
- Full backward compatibility maintained (no param = all sessions)

* fix: remove duplicate export default in page.tsx

* fix(web): clean project-scoped dashboard verification

* fix(web): scope dashboard using project id

* fix(web): address Bugbot findings in project-scoped dashboard

- Consolidate triplicated matchesProject into shared lib/project-utils.ts
- Fix Dashboard to receive both projectId (for SSE filtering) and projectName (for display)
- Remove inline matchesProject definitions from page.tsx, sessions/route.ts, events/route.ts

* fix(web): resolve Bugbot issues in project-scoped dashboard

- Add ?project=all query param support in SSR page to show all sessions
  (previously getPrimaryProjectId() always returned non-empty, making
  else branches unreachable)
- Exclude orchestrator sessions from SSE stream to match SSR/API behavior
  (orchestrator sessions get their own button, not a card)
- Add tests for SSE stream orchestrator exclusion and project filtering

Addresses Bugbot issues:
- #2903595986: Dead else branches when project filter always applied
- #2903595995: SSE stream includes orchestrator sessions unlike SSR/API

* feat(web): add project navigation sidebar

Add visible left sidebar with project navigation for multi-project setups:
- ProjectSidebar component with active state styling
- /api/projects endpoint to fetch configured projects
- getAllProjects() helper in project-name.ts
- Sidebar appears only when 2+ projects configured
- Click navigation updates ?project= query param
- Active project highlighted with accent color

Tests:
- ProjectSidebar component tests (8 tests)
- API routes tests with proper mocking
- All 386 web tests passing

Manual test steps:
1. Configure 2+ projects in agent-orchestrator.yaml
2. Start dashboard - sidebar should appear on left
3. Click different projects - URL updates, sessions filter
4. Click "All Projects" - shows all sessions across projects
5. Active project highlighted in sidebar

* fix(web): remove duplicate import in test file

* fix(web): consolidate ProjectInfo type to shared source

Remove duplicated ProjectInfo interface definitions from Dashboard.tsx and
ProjectSidebar.tsx. Both now import the type from @/lib/project-name where it is exported as the single source of truth.

This addresses Bugbot issue #2906835895: Triplicated ProjectInfo type instead of shared import.

* fix(web): integrate globalPause state from main

* fix(web): consolidate duplicate @/lib/types import

* fix(web): restore global pause state and membership refresh

* fix(web): satisfy lint in project-scoped page defaults

* fix(web): remove dead global pause reducer action

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

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

* fix(web): restore global pause resume time

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

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

* chore(web): retrigger bugbot after thread reset

* refactor(web): centralize project session filtering helpers

* fix(web): reset pause banner dismissal on new pause

* fix(web): remove useless orchestrator assignment

* fix(web): derive header stats from live session state

* fix(web): restore project name in dashboard header

* fix(web): restore backlog poller startup in events stream

* refactor(web): keep project-utils helpers internal

* chore: retrigger bugbot evaluation

* chore: retrigger stuck bugbot check

* fix: address latest bugbot findings for dashboard events

* test(web): add dashboard bugbot regression coverage

* refactor(web): simplify projectId selection in dashboard props

* fix(web): derive selected project name from project filter

* refactor(web): initialize dashboard defaults before service load

* fix(web): satisfy lint in dashboard page error path
2026-03-11 09:22:37 +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 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 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
suraj_markup d1bf5a5b03
Merge pull request #266 from suraj-markup/feat/issue-265
feat(mobile): React Native app for monitoring AO sessions
2026-03-03 05:21:20 +05:30