Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions src/stores/WorkspaceStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -964,13 +964,24 @@ export class WorkspaceStore {
const historicalMsgs = this.historicalMessages.get(workspaceId) ?? [];
historicalMsgs.push(data);
this.historicalMessages.set(workspaceId, historicalMsgs);
} else if (isCaughtUp) {
} else if (isCaughtUp && "role" in data) {
// Process live events immediately (after history loaded)
// Check for role field to ensure this is a CmuxMessage
aggregator.handleMessage(data);
this.states.bump(workspaceId);
this.checkAndBumpRecencyIfChanged();
} else if ("role" in data || "type" in data) {
// Unexpected: message with role/type field didn't match any condition
console.error("[WorkspaceStore] Message not processed - unexpected state", {
workspaceId,
isCaughtUp,
hasRole: "role" in data,
hasType: "type" in data,
type: "type" in data ? (data as { type: string }).type : undefined,
role: "role" in data ? (data as { role: string }).role : undefined,
});
}
// Note: Init events and stream events are handled by isStreamEvent() buffering above
// Note: Messages without role/type are silently ignored (expected for some IPC events)
}
}

Expand Down
19 changes: 17 additions & 2 deletions src/utils/messages/StreamingMessageAggregator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -511,15 +511,30 @@ export class StreamingMessageAggregator {
}

if (isInitOutput(data)) {
if (!this.initState) return; // Defensive: shouldn't happen but handle gracefully
if (!this.initState) {
console.error("Received init-output without init-start", { data });
return;
}
if (!data.line) {
console.error("Received init-output with missing line field", { data });
return;
}
const line = data.isError ? `ERROR: ${data.line}` : data.line;
// Extra defensive check (should never hit due to check above, but prevents crash if data changes)
if (typeof line !== "string") {
console.error("Init-output line is not a string", { line, data });
return;
}
this.initState.lines.push(line.trimEnd());
this.invalidateCache();
return;
}

if (isInitEnd(data)) {
if (!this.initState) return; // Defensive: shouldn't happen but handle gracefully
if (!this.initState) {
console.error("Received init-end without init-start", { data });
return;
}
this.initState.exitCode = data.exitCode;
this.initState.status = data.exitCode === 0 ? "success" : "error";
this.invalidateCache();
Expand Down