Set up Changesets for version management, add publish metadata to all 20
packages under the @composio scope, create an unscoped wrapper package
(@composio/agent-orchestrator) for global install, and add a GitHub
Actions release workflow.
- Rename all packages from @agent-orchestrator/* to @composio/ao-*
- Add @composio/agent-orchestrator wrapper (bin shim → @composio/ao-cli)
- Add license, repository, homepage, bugs, files, engines to all packages
- Add .npmrc (access=public), MIT LICENSE file
- Add .changeset/ config with linked versioning for all packages
- Add .github/workflows/release.yml (changesets publish CI)
- Add changeset, version-packages, release scripts to root
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat: wire xterm.js terminal embed into web dashboard
- Add xterm.js dependencies (@xterm/xterm, @xterm/addon-fit)
- Create SSE streaming endpoint at /api/sessions/:id/terminal
- Polls tmux capture-pane every 2 seconds
- Streams ANSI-aware output with colors/formatting
- Handles session exit gracefully
- Implement Terminal component with xterm.js
- Live output streaming from tmux pane
- Fullscreen mode toggle
- Optional input mode to send messages to agent
- Read-only by default
- Import xterm.js CSS in globals.css
The terminal shows live agent activity in the browser with full
ANSI color support. Users can optionally enable input mode to
send messages to the running agent.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: improve terminal rendering and remove clunky input interface
- Fix rendering issues:
- Use term.reset() instead of clear() for proper clearing
- Only update when content changes (prevents flickering)
- Add scrollToBottom() to show latest output
- Increase scrollback buffer to 10000 lines
- Add convertEol for proper line endings
- Increase default height to 600px
- Add padding around terminal content
- Simplify interface:
- Remove separate input box (was clunky)
- Make it clearly "Read-only" by default
- Clean up header UI
- Better fullscreen sizing calculation
Next step: Consider WebSocket-based bidirectional terminal for
true interactive sessions (like tmux attach).
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat: implement proper interactive terminal with WebSocket
Replace hacky SSE polling with real-time WebSocket for bidirectional
terminal communication. This is a proper interactive terminal - type
directly, like tmux attach in the browser.
Architecture:
- WebSocket server on port 3001 alongside Next.js
- Uses tmux pipe-pane for real-time output streaming
- Sends input character-by-character via tmux send-keys
- Handles terminal resize events
- Connection status indicator
Implementation:
- packages/web/src/server/terminal-websocket.ts: WebSocket server
- Terminal component now fully interactive (not read-only)
- Runs both servers via concurrently in dev mode
- Green dot = connected, red dot = disconnected
- Proper cursor, no more clunky input box
Benefits:
- Real-time streaming (not 2-second polling)
- Type directly into terminal
- Proper terminal control sequences
- Handles resize
- Like native tmux attach
Dependencies added:
- ws (WebSocket server)
- @types/ws
- concurrently (run multiple servers)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: improve terminal rendering - hide extra cursor, faster polling
- Hide xterm cursor (tmux output has its own)
- Increase polling from 500ms to 100ms (5x faster, less lag)
- Add -J flag to join wrapped lines (reduce truncation)
- Increase scrollback to 200 lines
Note: Current polling approach has limitations:
- Still some lag when typing (replacing full content)
- Not true real-time streaming
- For interactive use, prefer 'tmux attach' directly
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: improve terminal auto-sizing - multiple fit attempts
- Fit terminal multiple times (0ms, 100ms, 250ms, 500ms) to catch layout changes
- Add w-full class to ensure terminal takes full width
- Better error handling for fit operations
- Should eliminate need to manually zoom out
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: use const for pollInterval, expand WORKING zone by default
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: import WebSocket as value, not type-only
WebSocket.OPEN is used as a runtime value, so it cannot be a type-only import.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat: implement proper tmux control mode streaming
Replace hacky polling approach with professional tmux control mode:
- Use 'tmux -C attach-session' for true incremental streaming
- Parse control mode protocol (%output, %exit, %layout-change)
- Send commands via stdin (not spawning processes)
- Unescape octal sequences from tmux output
- Event-driven (not polling) - lower latency, less CPU
- Only sends new output (not full snapshots)
Benefits:
- 10x less bandwidth (no repeated snapshots)
- Lower latency (~10ms vs 100ms)
- No missed output (event-driven)
- Proper professional solution (how iTerm2 does it)
Based on research of VS Code, tmux control mode documentation,
and industry best practices for terminal streaming.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* refactor: replace custom WebSocket terminal with ttyd
- Replace broken custom tmux control mode + xterm.js with ttyd (iframe)
- ttyd handles all terminal rendering, ANSI, resize, input correctly
- Terminal server now manages ttyd instances per session on dynamic ports
- Enable mouse mode on tmux sessions for proper scroll behavior
- Remove dead code: @xterm/xterm, @xterm/addon-fit, ws deps
- Remove dead SSE terminal API route
- Remove xterm.css import
- Clean up Terminal component: single status dot, no decorative dots
- Make Linear issue link clickable in SessionDetail
- Extract issue label from URL for display (INT-1327 from full URL)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat: add tracker plugin integration for issue label extraction
Replaces hardcoded URL parsing with proper tracker plugin abstraction.
Now the dashboard uses tracker.issueLabel() to extract human-readable
labels from issue URLs (e.g., "INT-1327", "#42") in a plugin-agnostic way.
Changes:
- Core: Add optional issueLabel() method to Tracker interface
- Plugins: Implement issueLabel() in tracker-github and tracker-linear
- Web: Add issueUrl and issueLabel fields to DashboardSession
- Web: Add enrichSessionIssue() to populate labels via tracker plugin
- Web: Update SessionDetail and SessionCard to use new fields
- Web: Add getTracker() helper to services.ts
This is fully generic - any tracker plugin can implement issueLabel()
and the dashboard will automatically use it.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: add delay before Enter in tmux sendMessage to ensure text delivery
The dashboard "ask to resolve" button was putting messages in the input
buffer without submitting them. The tmux send-keys Enter was arriving
before the pasted text was fully processed. Match the bash send-to-session
script behavior with a 300ms delay.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use node:timers/promises for async setTimeout
node:util does not export setTimeout — the async sleep function
lives in node:timers/promises.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: hide tmux status bar in terminal for cleaner appearance
Added 'status off' option to remove the green tmux bar at the bottom
of the terminal for a cleaner, less cluttered interface.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: add health check to wait for ttyd before returning URL
Fixes race condition where iframe loads before ttyd is ready,
causing 'localhost refused to connect' on direct page loads.
Now waits up to 3s for ttyd to be listening before responding.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat: enable hot reloading for terminal server with tsx watch
Both frontend (Next.js) and backend (terminal server) now have
hot reloading enabled for faster development iteration.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: add PR enrichment to session detail page
The session detail page was not enriching PR data with live stats
from GitHub, causing it to show +0 -0. Now calls enrichSessionPR()
to fetch additions, deletions, CI status, and review data.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: clean up and collapse unresolved PR comments
- Extract title and description from Bugbot comments
- Strip out HTML comments, metadata, and image links
- Make comments collapsible (collapsed by default)
- Show clean summary with expand for details
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat: convert session detail page to client-side with live updates
- Changed from SSR to client-side component
- Added polling every 5 seconds for real-time data
- Created /api/sessions/[id] endpoint for single session fetch
- Faster navigation with client-side routing
- No page refresh needed to see updates
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: remove machine-specific symlinks from repository
- Remove .claude and packages/web/agent-orchestrator.yaml symlinks
- Add them to .gitignore to prevent re-committing
- These are development convenience links created per-worktree
Fixes Bugbot comment about environment-dependent paths that break
on other machines.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat: improve session detail UI and fix activity detection
- Fix session activity detection and timestamps
- session-manager now checks if runtime is alive in get()
- Use file birthtime/mtime for createdAt/lastActivityAt
- Fixes "Idle" status and "Created just now" issues
- Improve session detail UI
- Hide empty projectId chip
- Add PR# chip to header
- Fix "0 checks failing" logic
- Remove duplicate status display
- Humanize attention level labels ("review" → "Pending Review")
- Add Linear tracker support
- Register Linear tracker plugin in web services
- Issue labels now show "INT-1354" instead of full URL
- Add "Ask Agent to Fix" feature
- Button for each unresolved comment
- API endpoint to send messages to agent via tmux
- /api/sessions/[id]/message endpoint
- Fix waitForTtyd timeout handling
- Add timeout event handler to prevent hanging requests
- Properly abort timed-out requests
- Fix lint errors
- Remove duplicate imports
- Fix unused variables
- Use type-only imports where appropriate
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: address production issues in terminal implementation
- Use dynamic hostname instead of hardcoded localhost
- Terminal.tsx uses window.location.hostname
- terminal-websocket.ts derives URL from request host
- Supports remote access and reverse proxy scenarios
- Fixes high-severity Bugbot comments
- Add SIGTERM handling for graceful shutdown
- Previously only handled SIGINT
- Now cleans up ttyd processes on SIGTERM too
- Prevents orphan processes after restarts
- Adds 5s timeout to prevent hanging
Fixes Bugbot comments:
- r2807572056: Terminal embed hardcodes localhost endpoints
- r2807630014: Terminal URLs are hardcoded to localhost
- r2807604002: ttyd children survive non-interrupt shutdowns
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: properly validate message delivery to tmux sessions
Use execFile with promisify instead of spawn to:
- Wait for tmux commands to complete
- Check exit codes for failures
- Return proper error if send-keys fails
- Add 5s timeout to prevent hanging
Previously the endpoint returned success immediately without
verifying if the message was actually delivered to the session.
Fixes Bugbot comment r2807674035
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: use runtime plugin sendMessage for proper message delivery
Address Bugbot review comments:
- Use session.runtimeHandle instead of raw session id
- Use Runtime plugin's sendMessage method for proper sanitization
- Remove direct tmux command execution
The Runtime plugin's sendMessage handles:
- Proper runtime handle resolution
- Input sanitization and control character stripping
- Safe message delivery via load-buffer for long messages
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: sanitize message input and support runtime defaults
Address Bugbot review comments:
- Add stripControlChars sanitization to prevent control character injection
- Fall back to config.defaults.runtime when project.runtime is not set
- Validate that message is not empty after sanitization
This aligns the message endpoint with the existing send endpoint's
security model and ensures proper runtime resolution.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: address all Bugbot review comments
Comprehensive fixes for all remaining issues:
**message/route.ts:**
- Add session ID validation with validateIdentifier
- Add JSON parse error handling with try/catch
- Add message length validation with MAX_MESSAGE_LENGTH
- Add type guard for non-string messages
- Add URL encoding for session IDs
**terminal-websocket.ts:**
- Fix memory leak in waitForTtyd by tracking and canceling timeouts
- Add cleanup() function to cancel pending requests and timers
- Add MAX_PORT limit to prevent port exhaustion
- Add error handlers for spawned tmux processes
- Use once() instead of on() for exit/error to prevent race condition
- Add unref() to shutdown timeout to allow graceful exit
**page.tsx:**
- Use useCallback to memoize fetchSession
- Add fetchSession to useEffect dependency arrays
- Add URL encoding for session ID in fetch
**Terminal.tsx:**
- Add URL encoding for session ID in terminal fetch URL
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: remove unused err variable in JSON parse catch block
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: add security improvements for terminal and message endpoints
Address remaining Bugbot security concerns:
**terminal-websocket.ts:**
- Add TODO comments about authentication requirements
- Restrict CORS to localhost origins only (was allowing any origin)
- Add session existence validation before spawning ttyd
- Import fs and path modules for session validation
**Authentication:**
Full authentication with session ownership validation is tracked
separately and requires architectural decisions about auth middleware.
These changes provide defense-in-depth for the current implementation.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: remove unused readFileSync import
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat: terminal button opens ttyd directly in new tab
Instead of navigating to the session detail page, the terminal button
now fetches the ttyd URL from the terminal server and opens it directly
in a new browser tab. Falls back to the session detail page if the
terminal server is unavailable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address final 4 Bugbot review comments
**Issue 1: Terminal lookup ignores configured data directory (HIGH)**
- Load config using loadConfig() from @agent-orchestrator/core
- Use config.dataDir instead of hardcoded path for session validation
- Ensures terminal works with custom dataDir configurations
**Issue 2: Terminal ports exhaust without reuse (MEDIUM)**
- Implement port recycling with availablePorts Set
- Recycle ports when ttyd instances exit or error
- Prevents port exhaustion after 100 allocations
**Issue 3: Remote dashboard blocked by terminal CORS (MEDIUM)**
- Replace hardcoded localhost whitelist with dynamic origin validation
- Allow CORS if origin hostname matches request host
- Supports remote deployments while maintaining security
**Issue 4: Message endpoint can pick wrong runtime plugin (MEDIUM)**
- Use session.runtimeHandle.runtimeName instead of project config
- Ensures message delivery uses the runtime that created the session
- Handles sessions created with different runtime than current config
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
* feat: implement runtime and workspace plugins (tmux, process, worktree, clone)
Implement all 4 runtime/workspace plugins for the agent orchestrator,
replacing the stub files with full implementations of the Runtime and
Workspace interfaces from @agent-orchestrator/core.
- runtime-tmux: tmux session lifecycle with busy detection, wait-for-idle
message delivery, capture-pane output, and load-buffer for long messages
- runtime-process: child process management with rolling output buffer,
graceful SIGTERM/SIGKILL shutdown, and stdin message delivery
- workspace-worktree: git worktree create/destroy/list with symlink support
for shared resources and postCreate hook execution
- workspace-clone: git clone --reference for fast isolated clones with
postCreate hooks
Closes INT-1328
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address all PR review comments on runtime/workspace plugins
Fixes for all 13 review issues:
1. Move processes Map inside create() for per-instance isolation (#1)
2. Wrap stdin.write in promise with error/backpressure handling (#2)
3. Use child.once("exit") instead of on("exit") to prevent leaks (#3)
4. Use child.once("exit") in destroy() timeout to prevent leaks (#4)
5. Add assertValidSessionId() with /^[a-zA-Z0-9_-]+$/ regex (#5)
6. Single capture-pane call in isBusy() to avoid TOCTOU (#6)
7. Throw error when sendMessage sends to busy session after timeout (#7)
8. Use crypto.randomUUID() for temp file names to avoid collisions (#8)
9. Document that postCreate commands run with full shell privileges (#9)
10. Inspect worktree add error — only retry on "already exists" (#10)
11. Delete orphaned branch after worktree remove in destroy() (#11)
12. Log warning for corrupted clones in list() instead of silent skip (#12)
13. Return "not running" attach info for exited processes (#13)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: harden runtime/workspace plugins (spawn errors, stdin races, git injection)
- runtime-process: catch spawn errors with setImmediate pattern, prevent
double resolve/reject in sendMessage with done-flag, add late error
handler to prevent unhandled crashes, eliminate non-null assertions
- runtime-tmux: guard config.environment with ?? {} fallback
- workspace-worktree: add -- separator to git checkout/branch commands
to prevent option injection, guard branch deletion to feature branches
only (must contain /), ensure parent dirs exist before symlink creation
- workspace-clone: add -- separator to git checkout commands, suppress
no-console lint for expected diagnostic warning
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address codex review — spawn race, path traversal, temp file perms
- runtime-process: replace setImmediate with spawn/error event listeners
to fix race where create() returns handle for failed process; document
intentional shell:true usage
- runtime-tmux: restrict temp file permissions to 0o600
- workspace-worktree: validate projectId/sessionId as safe path segments,
reject absolute/traversal symlink paths, verify resolved targets stay
within workspace
- workspace-clone: validate projectId/sessionId as safe path segments
in both create() and list()
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address all review comments and fix CI
- workspace-clone/worktree: remove incorrect -- from git checkout
(switches to path mode, breaking branch operations)
- workspace-worktree: fix prefix collision in list() by appending /
to startsWith check (foo no longer matches foobar)
- runtime-tmux: use named tmux buffers (-b flag) to prevent concurrent
sendMessage calls from overwriting each other's paste content
- runtime-process: check signalCode in addition to exitCode for
accurate liveness detection of signal-killed processes
- runtime-process: reject duplicate session IDs to prevent orphaned
child processes from overwritten map entries
- runtime-tmux: anchor $ in busy detection to line start (^\$\s) to
avoid false idle detection from dollar signs in output
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: forward plugin config through registry so workspace dirs take effect
The plugin registry was calling plugin.create() with no arguments,
silently ignoring configured worktreeDir/cloneDir settings. Added
extractPluginConfig() to map orchestrator config to per-plugin config,
and updated register()/loadBuiltins() to pass config through.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: clean up orphaned worktrees/clones on checkout failure, remove risky branch -D
- Worktree: remove git branch -D from destroy() — the "/" heuristic
could delete pre-existing local branches unrelated to the workspace
- Worktree: wrap fallback checkout in try/catch, clean up orphaned
worktree if checkout fails
- Clone: wrap fallback checkout in try/catch, rmSync the orphaned clone
directory if both checkout attempts fail
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: clean up partial clone directory when git clone fails
Wrap the git clone call in try/catch so a failed clone removes any
partial clonePath left on disk, preventing orphaned directories that
block retries for the same sessionId.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: remove busy detection from tmux runtime
Busy/idle detection is an agent-layer concern, not a runtime concern.
Each agent (Claude Code, Codex, Aider) has its own native mechanism for
checking activity status. The tmux runtime should only manage sessions
and send messages immediately without polling.
Removed: isBusy() heuristics, sleep-based polling loop, sentWhileBusy
error. sendMessage() now sends immediately.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: clean up tmux session when launch command send-keys fails
If send-keys fails after new-session succeeds, the orphaned tmux
session was left running and unmanaged. Now wraps send-keys in
try/catch that kills the session before rethrowing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: prevent clone error handler from deleting pre-existing workspace
Add early existence check before git clone so create() fails
immediately if clonePath already exists, rather than cloning into it,
failing, and then deleting the pre-existing workspace in the catch block.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: clean up leaked tmux buffer when paste-buffer fails
The -d flag on paste-buffer only deletes the named buffer on success.
If paste fails, the buffer persists in the tmux server. Added
delete-buffer in the finally block to ensure cleanup regardless of
paste outcome.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: prevent orphan processes on duplicate sessionId, auto-remove exited sessions
- Move processes.has() check before spawn() so duplicate sessionIds are
rejected before any child process is created
- Auto-remove exited sessions from the process map in the exit handler
so the sessionId can be reused without manual destroy()
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: register process in map before exit handler to prevent stale entries
A fast-exiting child could fire the exit event before processes.set()
ran, causing delete() to no-op and set() to insert a permanently stale
entry. Moving set() before the exit handler registration ensures
delete() always finds the entry.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: atomic session reservation and immediate exit handler registration
- Reserve map slot synchronously (no await gap between has() and set())
so concurrent create() calls cannot both pass the duplicate check
- Register exit handler immediately after spawn(), before any await,
so fast-exiting processes cannot miss cleanup
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: kill process group on destroy, use literal mode for tmux send-keys
- runtime-process: use process.kill(-pid) to kill the entire process
group, not just the shell. Added detached:true so child gets its own
process group. Falls back to child.kill() if group kill fails.
- runtime-tmux: add -l flag to send-keys for short messages so text
like "Enter" or "Space" is sent literally, not as key names.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: add comprehensive unit and integration tests for all 4 plugins
Add 136 unit tests and 35 integration tests covering runtime-tmux,
runtime-process, workspace-worktree, and workspace-clone plugins.
Also adds 13 unit tests for the core plugin-registry.
Unit tests (136 total):
- runtime-tmux (25): create/destroy, send-keys modes, getOutput, isAlive, getMetrics
- runtime-process (40): spawn lifecycle, SIGKILL escalation, output buffering, isolation
- workspace-worktree (40): create/destroy, tilde expansion, branch fallback, symlinks
- workspace-clone (31): create/destroy, --reference clone, pre-existence check, cleanup
Integration tests (35 total):
- runtime-tmux (8): full lifecycle with real tmux sessions
- runtime-process (11): full lifecycle with real child processes
- workspace-worktree (8): real git worktree operations
- workspace-clone (8): real git clone operations
Plugin-registry tests (13):
- register/get/list, config forwarding, slot isolation, loadBuiltins, loadFromConfig
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: guard against null process in runtime-process methods
ProcessEntry.process is null between reservation and spawn completion.
Add explicit null checks in destroy(), sendMessage(), isAlive(), and
getAttachInfo() to prevent TypeError if called during that window.
Addresses bugbot review comment about transient null process crash.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: buffer partial lines in runtime-process output capture
Stream chunks split at arbitrary boundaries, so splitting on "\n" and
pushing each piece as a complete line corrupts output when a line spans
two chunks. Buffer the trailing partial line and only push complete
(newline-terminated) lines. Flush remaining partial on process exit.
Addresses bugbot review comment about incorrect output chunk splitting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: correct vitest peer dep resolution in pnpm-lock.yaml
The lockfile referenced vitest@3.2.4 without jiti/jsdom/lightningcss
peer deps, but that resolution didn't exist in the packages section.
Update to match the full resolution available on main.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use per-stream partial buffers in runtime-process output capture
stdout and stderr shared one partial-line buffer, so interleaved chunks
from different streams could be concatenated into corrupted lines. Each
stream now gets its own closure with an independent partial buffer.
Addresses bugbot review comment about mixed stream chunk corruption.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
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>