Commit Graph

210 Commits

Author SHA1 Message Date
Harsh 456ef3e951 chore: untrack local agent-orchestrator config 2026-03-05 22:21:21 +05:30
sujayjayjay 690bd9ee3a
Merge pull request #278 from ComposioHQ/preview-banner
Add Composio banner to README
2026-03-03 22:48:20 +05:30
Sujay Choubey 17c79b21a0 Add Composio banner to README 2026-03-03 22:43:23 +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 e503caeaa3
fix: don't show 'Ready to merge' badge on merged/closed PRs (#274)
Extract isPRMergeReady() helper that checks pr.state === "open" before
evaluating merge criteria, preventing the badge from appearing alongside
the 'Merged' chip on already-merged PRs.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 14:46:54 +05:30
prateek b5128cf69f
fix: use gh repo clone for private repo auth in ao start <url> (#273)
HTTPS clone fails on private repos without credentials. Now tries
three strategies in order:
1. gh repo clone (handles GitHub auth via gh auth token)
2. git clone with SSH URL (works with SSH keys)
3. git clone with HTTPS URL (public repos fallback)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 14:42:35 +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 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
suraj-markup c9bf351481 fix: enable cleartext traffic on Android for local/Tailscale HTTP
Android blocks plain HTTP by default. Enable usesCleartextTraffic
so the app can connect to http://100.x.x.x:3000 (Tailscale) and
http://192.168.x.x:3000 (LAN) backends.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 05:17:03 +05:30
suraj-markup d6d5dd6642 fix: skip polling with empty session ID, use correct XDA parser API
- Add `enabled` option to useSession hook; OrchestratorScreen passes
  enabled: !!orchestratorId to avoid polling /api/sessions/ with an
  empty string when no orchestrator is running
- Replace term.onData XDA handler with term.parser.registerCsiHandler
  matching the web dashboard implementation — onData only fires for
  outgoing user input, not incoming WebSocket data where the CSI > q
  query actually arrives

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 05:07:27 +05:30
suraj-markup 0773137a65 feat: embed orchestrator session details inline, remove overview
Show orchestrator session details (status, activity, summary, timing,
terminal button, send message) directly on the Orchestrator page
instead of requiring navigation to a separate SessionDetail page.
Remove the Overview stats section. Commands remain in header button.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 04:53:32 +05:30
suraj-markup b5e486ffd2 fix: robot button goes to Orchestrator page with Commands in header
Revert 🤖 to navigate to Orchestrator overview (zones, stats,
orchestrator status card). The "Commands" header button on that
page opens the CLI commands reference. Tapping the orchestrator
card navigates to its session detail.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 04:50:54 +05:30
suraj-markup 185dc97ede fix: add Commands button (📋) to HomeScreen header
The Commands button was on the Orchestrator page header which is
no longer visited when the orchestrator is running. Move it to the
HomeScreen header so it's always accessible.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 04:49:43 +05:30
suraj-markup d733f107c3 feat: robot button opens orchestrator session, commands in header
- Robot button (🤖) on HomeScreen now navigates directly to the
  orchestrator's session detail when running, or to the Orchestrator
  overview when not running
- Move CLI commands to a new CommandsScreen, accessible via a
  "Commands" header button on the Orchestrator page
- Remove inline CLI commands from OrchestratorScreen body

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 04:47:12 +05:30
suraj-markup 170d54cd53 fix: move Tailscale details out of backend URL section into setup guide
Keep the backend URL hint clean — Tailscale/ngrok/LAN instructions
are already in the setup guide below.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 04:41:28 +05:30
suraj-markup 9bafd33cb3 feat: add Tailscale setup guide and hide test notifications in prod
- Add Tailscale as the recommended connection method in the setup guide
  with step-by-step instructions
- Add alternative sections for Local Wi-Fi and ngrok
- Wrap test notification buttons in __DEV__ so they only show during
  development and are stripped from production builds
- Update placeholder and hint text to show Tailscale IP format first

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 04:41:04 +05:30
suraj-markup 68a0ab1ded fix: stale fetch race condition and invalid test status
- Replace isMountedRef with generation counter (fetchGenRef) in
  useSessions and useSession hooks to prevent stale fetches from
  overwriting correct data when the backend URL changes mid-flight
- Fix test review notification using invalid "needs_review" status;
  correct value is "review_pending" per core types

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 04:39:22 +05:30
suraj-markup 6c9f74a700 feat: add review notifications and notification tap-to-navigate
- Add "review" attention level to notification triggers (background task,
  foreground hook, and scheduleNotification)
- Add notification tap handling: tapping a notification navigates directly
  to the session detail screen via navigationRef
- Handle cold-start case (app killed) via getLastNotificationResponseAsync
- Add "review" test notification button in Settings screen

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 04:21:34 +05:30
suraj-markup 53142119bd fix(mobile,web): expose orchestratorId in /api/sessions response
The /api/sessions endpoint was filtering out orchestrator sessions,
so the mobile app could never detect a running orchestrator. Now the
API finds the orchestrator session ID before filtering and includes
it in the response as orchestratorId.

- Add orchestratorId to /api/sessions JSON response
- Add orchestratorId to SessionsResponse type
- Thread orchestratorId through useSessions hook
- Use orchestratorId in OrchestratorScreen instead of searching sessions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 04:13:58 +05:30
suraj-markup 89606d4857 fix(mobile): use bot emoji for orchestrator and +Session for spawn
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 04:09:40 +05:30
suraj-markup adf82a8c04 feat(mobile): add Orchestrator screen with zone overview and CLI reference
- New OrchestratorScreen showing orchestrator status (running/not),
  session zone counts (merge/respond/review/pending/working/done),
  overview stats, and full CLI command reference
- Add "AO" button in HomeScreen header linking to Orchestrator page
- Replace "Settings" text with gear icon in header
- Register Orchestrator route in navigator

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 04:06:04 +05:30
suraj-markup 07cd72c36d fix(mobile): enable scrolling in terminal WebView
scrollEnabled was set to false, which blocked touch scroll gestures
that xterm.js needs to scroll through terminal history.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 04:00:55 +05:30
suraj-markup 034e1a0e25 fix(mobile): further increase keyboard padding for message bar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 03:59:12 +05:30
suraj-markup 40906331e7 fix(mobile): increase message bar padding above keyboard
Add extra padding (keyboardHeight + 10) so the input comfortably
clears the keyboard suggestions/accessory bar on all devices.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 03:53:39 +05:30
suraj-markup ba2053dd4c fix(mobile): replace KeyboardAvoidingView with Keyboard API listener
KeyboardAvoidingView was causing two issues: scrolling the page to the
top on focus, and not restoring the layout when dismissing the keyboard.

New approach uses Keyboard.addListener to track keyboard height and
applies it as paddingBottom on the message bar directly. This works
reliably on both iOS and Android regardless of softInputMode.

- Removed softwareKeyboardLayoutMode: "pan" from app.json
- Replaced KAV with plain View + dynamic keyboard padding
- Reverted SpawnSession/Settings screens to simple iOS-only KAV

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 03:48:44 +05:30
suraj-markup a685565bbb fix(mobile): increase keyboard offset for Android accessory bar
Bump Android keyboardVerticalOffset from 80 to 140 to account for the
suggestions/clipboard bar that sits above the keyboard on many devices.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 03:45:30 +05:30
suraj-markup fe90d5b4e7 fix(mobile): fix keyboard hiding text input on Android and iOS
- Set android.softwareKeyboardLayoutMode to "pan" in app.json to prevent
  conflict between system adjustResize and KeyboardAvoidingView
- Use behavior="padding" consistently on both platforms
- Add keyboardVerticalOffset on Android to account for nav header
- Applied fix across all screens with keyboard input

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 03:42:44 +05:30
suraj-markup fa5fcc9e91 fix(mobile): ensure message input stays visible above keyboard
- Set KeyboardAvoidingView behavior to "height" on Android (was undefined)
- Add scrollToEnd on TextInput focus so content scrolls up with keyboard
- Add keyboardShouldPersistTaps="handled" for better tap behavior

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 03:39:05 +05:30
suraj-markup 7ed6e0c2c1 fix(mobile): address second round of review comments
- Add required `type: TIME_INTERVAL` to notification trigger for SDK 53
- Remove phantom statuses from SessionStatus/ActivityState not in core
  (removed "running" from SessionStatus; "starting", "thinking", "working"
  from ActivityState)
- Handle unhandled promise rejections from scheduleNotification in
  useSessionNotifications hook with void + .catch()
- Await scheduleNotification in SettingsScreen test handlers and show
  error alert on failure instead of premature "Sent"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 03:20:48 +05:30
suraj-markup f3944b5f15 fix(mobile): address PR review comments and lint CI failure
- Exclude packages/mobile/** from root eslint config (mobile uses Expo/CJS toolchain)
- Align TERMINAL_STATUSES and NON_RESTORABLE_STATUSES with packages/core/src/types.ts
- Fix isRestorable() to use isTerminal() check matching core logic
- Change notification trigger from null to { seconds: 1 } for Android background task compat
- Add isPRRateLimited guard to merge button to prevent merge when API rate limited
- Await scheduleNotification in background task to ensure notifications are delivered

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 03:06:33 +05:30
suraj-markup 5a22a85e72 chore(mobile): update app icons and splash screen with Agent Orchestrator branding
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-03 02:38:17 +05:30
suraj-markup 2675c191e2 feat(mobile): add dashboard action parity — merge, CI fix, review comments, spawn
Adds missing action features to match the web dashboard:

- Merge PR button: green button when PR is mergeable, calls /api/prs/:id/merge
- CI checks list: individual checks with status icons and links
- "Ask to fix CI" button: sends "Please fix the failing CI checks" to agent
- Unresolved review comments: per-comment card with author, path, body
- "Ask Agent to Fix" per comment: sends context-specific message with file path
- Alert cards: CI failures, merge conflicts, changes requested warnings
- Spawn Session screen: create new sessions with project ID and optional issue ID
- "+" button on home screen header to spawn sessions
- PR title is now tappable (opens in browser)
- Color-coded CI/review/mergeability status values
- PR blockers list display

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 01:46:35 +05:30
suraj-markup c53099923d feat(mobile): add React Native app for monitoring AO sessions
Adds `packages/mobile` — an Expo SDK 53 React Native app for monitoring
agent sessions from a phone.

Features:
- Home screen: Kanban-style session list sorted by attention level
- Session detail: metadata, PR link, CI status, branch info
- Terminal screen: full xterm.js terminal via WebView (port 14801)
- Settings screen: configurable backend URL (LAN IP or ngrok)
- Push notifications: background polling for attention-level changes

Improvements over PR #235:
- Fixed terminal onmessage handler to filter JSON control messages
  (resize echoes no longer render as garbage text)
- Removed duplicate terminal.html (single source of truth in
  terminal-html.ts)
- Fixed isDone check to include "cleanup" status using isTerminal()

Tech: Expo SDK 53, React Navigation 6, React Native WebView.
Two server connections: REST API (port 3000) + WebSocket terminal (14801).

The mobile package is excluded from the pnpm workspace to avoid
interfering with the monorepo toolchain.

Closes #265

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 01:34:45 +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
suraj-markup 18dea011e7 fix: address review feedback and add preflight tests
- Consistent error formatting: single spawn now uses err.message like
  batch-spawn, avoiding redundant "Error:" prefix
- checkBuilt distinguishes missing node_modules ("pnpm install") from
  missing dist ("pnpm build") so users get the right guidance
- Add 13 preflight unit tests covering port, build, tmux, and gh checks
- Add 5 spawn integration tests covering runtime-aware tmux check,
  tracker-aware gh check, and error message formatting

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 03:05:00 +05:30
suraj-markup 62cd42b30f fix: resolve checkBuilt from web node_modules and remove unused imports
Check ao-core/dist/index.js relative to webDir's node_modules instead
of using require.resolve which fails under npm link. Also removes
unused existsSync/resolve/createRequire imports that caused lint errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 02:50:56 +05:30
suraj-markup b43b1556c0 fix: check core dist output instead of .next/BUILD_ID in checkBuilt
.next/BUILD_ID only exists after next build (production) but the
dashboard runs with next dev. Check @composio/ao-core resolve instead,
which is the actual cause of module resolution errors when packages
are not compiled.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 02:44:19 +05:30
suraj-markup cb071e122d fix: wrap batch-spawn preflight in try-catch
Preflight errors in batch-spawn were unhandled, causing unformatted
rejection output. Now caught with chalk.red formatting and
process.exit(1), matching the single spawn handler.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 02:40:12 +05:30
suraj_markup 1d7e6e3c66
Merge pull request #240 from suraj-markup/feat/issue-237
fix(terminal): OSC 52 clipboard, resize frame cap, and hardcoded height
2026-03-02 02:27:39 +05:30
suraj_markup 2d785beac5
Merge pull request #242 from suraj-markup/feat/issue-238
fix(core): atomic metadata writes, restoredAt persistence, and session count/sorting bugs
2026-03-02 02:24:51 +05:30
suraj-markup 96c7ae534a fix: run spawn preflight checks once before batch loop
Extract preflight checks from spawnSession into runSpawnPreflight and
call it once upfront in both registerSpawn and registerBatchSpawn. A
missing prerequisite now fails fast with one clear error instead of
repeating N times across the batch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 02:01:15 +05:30
suraj-markup 421e443d30 fix(terminal): remove DOM paste handler that could double-paste with xterm.js
xterm.js handles paste natively via its internal textarea — our
container-level paste listener either double-pastes (if the event
bubbles) or is dead code (if xterm calls stopPropagation). Also remove
the dead isPaste key handler block that returned true (same as default).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 01:56:02 +05:30
suraj-markup f14465335d fix: address review feedback on preflight checks
- Consistent error handling: all preflight functions now throw instead
  of mixing process.exit and throw, so callers can catch and clean up
- checkGhAuth distinguishes "not installed" (ENOENT) from "not
  authenticated" by checking gh --version first
- Move checkBuilt() after package.json existence check in start.ts so
  missing web package shows "Run: pnpm install" not "Run: pnpm build"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 01:45:39 +05:30
suraj-markup 3fc51b8882 fix(terminal): harden clipboard buffer and resize for production
Three fixes from code review:

1. Clear selection after Cmd+C so the terminal resumes receiving
   output immediately instead of staying frozen up to 5 seconds.

2. Add 1MB byte cap on the write buffer to prevent OOM if a fast
   process dumps output while the user has text selected.

3. Use ws.current instead of a stale captured websocket reference
   in the resize effect, preventing throws if the WebSocket
   reconnected during a fullscreen toggle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 01:17:16 +05:30
suraj-markup 09e2c2b540 fix(terminal): preserve selection highlight by buffering after selection exists
Buffer incoming terminal.write() only after onSelectionChange reports
a non-empty selection — NOT during mousedown. This lets xterm.js
render the selection highlight normally, then prevents incoming data
from clearing it. The buffer flushes when the user clears the
selection (click/keypress) or after a 5s safety timeout.

Previous attempts broke because they buffered during mousedown which
prevented xterm.js from rendering the highlight in the first place.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 01:08:24 +05:30
suraj-markup fb5e0c9646 fix(terminal): remove write buffer that broke selection highlighting
The write buffer intercepted all terminal.write() during mousedown,
which prevented xterm.js from rendering the selection highlight.

Simplified to: auto-copy on selection change + DOM paste event +
keyboard shortcut fallback. The selection highlight may disappear
from incoming data, but the text is already in the clipboard.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 01:04:11 +05:30
suraj-markup 2d80a1dd35 fix(terminal): preserve text selection while terminal receives output
Buffer incoming WebSocket data while the user has an active selection.
xterm.js clears the selection on every terminal.write(), so without
buffering the selection disappears instantly in a live terminal.

How it works:
- mousedown: start buffering (user is drag-selecting)
- mouseup: stop tracking mouse, but keep buffering if selection exists
- onSelectionChange(empty): selection cleared → flush buffer
- Safety timeout (5s): flush regardless to prevent unbounded buffering

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