-
Notifications
You must be signed in to change notification settings - Fork 5
🤖 Stream .cmux/init hook on workspace creation #228
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
ammar-agent
wants to merge
6
commits into
main
Choose a base branch
from
feat/init-hook
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+907
−12
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
84bac2e
to
20740c5
Compare
Complete end-to-end infrastructure for streaming .cmux/init hook output: - Backend detects and runs optional project-level .cmux/init on workspace creation - Stream stdout/stderr lines to renderer via WORKSPACE_STREAM_META IPC channel - Buffer output for late subscribers; replay on subscribe - UI displays live output with auto-hide on success, persistent banner on failure - Workspace remains usable regardless of hook exit code Backend (ipcMain.ts): - Add WorkspaceMetaEvent type imports (fix inline import() eslint errors) - Implement runWorkspaceInitHook with line-buffered streaming - Add metaEventBuffer for replay to late subscribers - Remove duplicate workspace:meta:subscribe handlers Frontend (AIView.tsx): - Add typed WorkspaceMetaEvent handler (no any types) - Prefer line when present in error events, else error field - Auto-hide success banner (800ms), persist failure banner Types: - Add WorkspaceMetaEvent union (start/output/error/end) - Strong typing throughout preload and IPC layer Tests: - Add integration test suite (workspaceInitHook.test.ts) - Verify start/output/error/end event sequence - Verify workspace remains usable on hook failure - Verify no events when hook absent Generated with cmux
Simplifies init hook architecture by reusing existing chat stream infrastructure instead of creating parallel IPC system. Changes: - Add WorkspaceInitEvent union to WorkspaceChatMessage (3 event types) - Backend emits init events via AgentSession.emitChatEvent() - Frontend handles init events from chat subscription - Tests filter init events from chat channel - Remove metaEventBuffer, onMeta(), and WORKSPACE_STREAM_META Benefits: - ~80 net LoC reduction (removed ~150, added ~70) - 1 subscription per workspace instead of 2 - Automatic replay via existing history mechanism - Cleaner types (no redundant workspaceId field) - Single buffer for all workspace events Init events are ephemeral (not persisted) and flow through the same stream as caught-up, stream-error, and delete messages.
…ntralize bash execution - Added workspace-init DisplayedMessage type with status tracking - Extended StreamingMessageAggregator to convert init events to DisplayedMessage - Created InitMessage component to render init banners in message stream - Removed local init state management from AIView (eliminated parallel infrastructure) - Removed legacy WorkspaceMetaEvent type (no longer used) - Created BashExecutionService to centralize all bash execution - Provides single abstraction point for future host migration (containers, remote, etc.) - Eliminates duplicate environment setup across init hooks and bash tool - executeStreaming() mode for line-by-line output (init hooks) - Updated IpcMain to use BashExecutionService for init hook execution Benefits: - Init events flow through same path as other workspace events - Centralized state management (no local component state) - Single source of truth for bash environment setup - Easier to abstract workspace hosts in future Tests: - Added unit tests for aggregator init handling (2 tests) - All integration tests passing (3/3 init hook tests) - Typecheck passing for both renderer and main processes
d5750bc
to
d0170f2
Compare
- Added log.debug() for init hook detection and script execution - Added log.info() for init hook start and completion with exit codes - Added log.error() for init hook failures - Added logging to BashExecutionService for streaming command execution - Added process error logging for bash execution failures This improves debuggability when init hooks don't work as expected.
Init events were being buffered until "caught-up" but init hooks run during workspace creation, before the workspace has any history or caught-up status. Changes: - Added isInitStart, isInitOutput, isInitEnd imports to WorkspaceStore - Updated isStreamEvent() to include init events (process immediately) - Added explicit init event handling in processStreamEvent() - Init events now bypass caught-up check and process immediately This ensures the init banner appears in the UI when workspaces are created.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
Completes end-to-end "init hook streaming" infrastructure. The
.cmux/init
hook is now detected, executed, and its output streamed live to the UI on workspace creation. Non-zero exit codes are allowed; workspace remains usable regardless.Changes
Backend (Electron main)
workspace:meta:subscribe
/unsubscribe
handlers and malformed braces insrc/services/ipcMain.ts
import("@/types/workspace").WorkspaceMetaEvent
with top-levelimport type { WorkspaceMetaEvent }
to resolve eslint errorsvoid this.runWorkspaceInitHook()
) - fire-and-forget with line-buffered streaming and non-interactive envmetaEventBuffer
stores events per workspace; late subscribers receive replay viaworkspace:meta:subscribe
Preload API
onMeta(workspaceId: string, callback: (data: WorkspaceMetaEvent) => void)
with proper type importRenderer (UI)
WorkspaceMetaEvent
(noany
), prefersline
in error events when present, elseerror
Types (shared)
src/types/ipc.ts
usesimport type { WorkspaceMetaEvent }
instead of inline importTests
tests/ipcMain/workspaceInitHook.test.ts
):.cmux/init
absentenv.sentEvents
(not mockIpcRenderer.on) to detect meta eventsNon-goals (can be follow-ups)
Testing
make lint
,make fmt
,make typecheck
all passTEST_INTEGRATION=1 bun x jest tests/ipcMain/workspaceInitHook.test.ts
Generated with
cmux