Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
280b47d
feat: use LLC message pagination and message list state optimistic up…
MartinCupela Jan 12, 2026
1003896
Merge branch 'master' into feat/message-paginator
MartinCupela Jan 13, 2026
81f9689
feat(LayoutController): implement Core Types and Controller Engine an…
MartinCupela Feb 26, 2026
64ff386
feat(LayoutController): implement ChatView Integration (Context and P…
MartinCupela Feb 26, 2026
1bf06f6
feat(LayoutController): implement Built-in Two-Step DX Layout API
MartinCupela Feb 27, 2026
4c72159
feat(LayoutController): implement Docs and Spec Alignment
MartinCupela Feb 27, 2026
28f224a
chore(LayoutController): add new requirements to layout control API
MartinCupela Feb 27, 2026
3c3d0cf
feat(LayoutController): implement Slot Parent Stack and Back Navigation
MartinCupela Feb 27, 2026
95ea03a
feat(LayoutController): implement Unify ChannelList into Slot Model
MartinCupela Feb 27, 2026
8a3d6ba
feat(LayoutController): implement Min Slots and Fallback Workspace St…
MartinCupela Feb 27, 2026
f0a9ba2
feat(LayoutController): implement Generic Slot Component with Mount-P…
MartinCupela Feb 27, 2026
3223e46
feat(LayoutController): implement Deep-Linking, Serialization, and op…
MartinCupela Feb 27, 2026
bad6681
feat(LayoutController): implement High-Level Navigation Hook and Cont…
MartinCupela Feb 27, 2026
862a0ed
feat(LayoutController): adjust Thread and ThreadContext.tsx to be ind…
MartinCupela Feb 27, 2026
4b28a74
feat(LayoutController): implement Thread Component Layout-Controller …
MartinCupela Feb 27, 2026
55a7e37
feat(LayoutController): add translations to "aria/Go back"
MartinCupela Feb 27, 2026
f5f328e
feat(LayoutController): implement Slot Self-Visibility from Slot Prop…
MartinCupela Feb 27, 2026
3a0efb6
refactor(channel): remove thread pagination from channel contexts
MartinCupela Feb 28, 2026
1e42b28
feat: remove non-pagination state from ChannelStateContext
MartinCupela Mar 3, 2026
8cacbb3
Merge branch 'master' into feat/message-paginator
MartinCupela Mar 3, 2026
9680b7a
Merge branch 'master' into feat/chat-view-layout
MartinCupela Mar 4, 2026
e36f496
feat(chatview): remove ChatContext active channel/nav routing; add us…
MartinCupela Mar 4, 2026
1e5d9ae
refactor: remove Hardcoded `channel.messagePaginator` Usage from Reac…
MartinCupela Mar 4, 2026
98231e5
feat: remove ChannelActionContext
MartinCupela Mar 4, 2026
5a81ea1
feat: keep suppressAutoscrol management inside message lists
MartinCupela Mar 4, 2026
deabbcb
feat: port highlighted message functionality and use client notificat…
MartinCupela Mar 5, 2026
2fd3327
feat: adapt bootstrap/loading/error guards, listener lifecycle, mark-…
MartinCupela Mar 5, 2026
e5d9d1b
fix: clear channelUnreadUiState upon clicking on UnreadMessagesSepara…
MartinCupela Mar 5, 2026
4b54c38
fix: prevent showing NewMessageNotification & ScrollToLatestMessageBu…
MartinCupela Mar 5, 2026
3e83138
fix: make sure to scroll to the bottom, when the first batch of messa…
MartinCupela Mar 5, 2026
7431d07
fix: update reply count in MessageRepliesCountButton
MartinCupela Mar 5, 2026
1959233
fix: reflect deleted message text in QuotedMessagePreview
MartinCupela Mar 5, 2026
ff1cb05
fix: show cursor pointer when hovering above QuotedMessage in message…
MartinCupela Mar 6, 2026
429500b
fix: make the UnreadMessagesSeparator driven by MessagePaginator unre…
MartinCupela Mar 6, 2026
fb48d09
feat: make slot layout for threads and channels
MartinCupela Mar 6, 2026
bcca6e7
Merge branch 'master' into feat/message-paginator
MartinCupela Mar 6, 2026
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
8 changes: 4 additions & 4 deletions .cursor/skills/ralph-protocol/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: ralph-protocol
description: Collaboration protocol for Ralph loop (Plan → Act → Reflect → Refine). Use when working from goal.md, plan.md, state.json, decisions.md; when executing tasks in a shared plan; or when the user mentions Ralph, multi-agent, or file-based collaboration.
description: Collaboration protocol for Ralph loop (Plan → Act → Reflect → Refine). Use when working from spec.md, plan.md, state.json, decisions.md; when executing tasks in a shared plan; or when the user mentions Ralph, multi-agent, or file-based collaboration.
---

# Ralph Protocol (Agent Collaboration)
Expand All @@ -11,14 +11,14 @@ Files are the source of truth. All agents share memory via files. No silent deci

| File | Purpose |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **goal.md** | What we achieve; success criteria; constraints; non-goals. Read first. Only change if goal actually changes. No implementation details. |
| **spec.md** | What we achieve; success criteria; constraints; non-goals. Read first. Only change if scope or constraints actually change. No implementation details. |
| **plan.md** | How we achieve it. Ordered tasks, ownership, dependencies, status (`pending \| in-progress \| done \| blocked`). Propose changes before big deviations; don't rewrite completed sections. |
| **state.json** | Current memory. Task statuses, flags (`blocked`, `needs-review`, etc.). Update immediately after acting. Read before assuming anything. |
| **decisions.md** | Log of non-trivial decisions (what + why). Append only; never delete. Prevents reopening or contradicting past choices. |

## Workflow

**Before acting:** Read goal.md → plan.md → state.json → decisions.md.
**Before acting:** Read spec.md → plan.md → state.json → decisions.md.

**During:** Follow the plan; no overlapping work unless coordinated; no undocumented decisions.

Expand All @@ -42,6 +42,6 @@ When acceptance criteria involve UI: use Playwright (MCP or project config). Tak

## Loop reminder

Each iteration: Plan (update plan.md if needed) → Act (scoped work) → Reflect (learnings) → Refine (plan or decisions).
Each iteration: Plan (update plan.md if needed) → Act (scoped work) → Reflect (learnings) → Refine (plan or decision log).

For decision log format and state.json example, see [reference.md](reference.md). Plan structure and worktrees: use make-plans and worktrees skills.
75 changes: 47 additions & 28 deletions examples/vite/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,40 +5,43 @@ import {
ChannelSort,
LocalMessage,
TextComposerMiddleware,
createCommandInjectionMiddleware,
createDraftCommandInjectionMiddleware,
createActiveCommandGuardMiddleware,
createCommandInjectionMiddleware,
createCommandStringExtractionMiddleware,
createDraftCommandInjectionMiddleware,
} from 'stream-chat';
import {
AIStateIndicator,
Channel,
ChannelSlot,
ChannelAvatar,
ChannelHeader,
ChannelList,
ChannelListSlot,
Chat,
ChatView,
MessageInput,
MessageList,
ReactionsList,
Thread,
ThreadListSlot,
ThreadSlot,
ThreadList,
useCreateChatClient,
// VirtualizedMessageList as MessageList,
MessageList,
Window,
WithComponents,
ReactionsList,
WithDragAndDropUpload,
useChatContext,
defaultReactionOptions,
ReactionOptions,
mapEmojiMartData,
useChannel,
useChatContext,
useCreateChatClient,
type ReactionOptions,
} from 'stream-chat-react';
import { createTextComposerEmojiMiddleware, EmojiPicker } from 'stream-chat-react/emojis';
import data from '@emoji-mart/data';
import { init, SearchIndex } from 'emoji-mart';
import data from '@emoji-mart/data/sets/14/native.json';
import { humanId } from 'human-id';
import { chatViewSelectorItemSet } from './Sidebar/ChatViewSelectorItemSet.tsx';
import { useAppSettingsState } from './AppSettings';
import { chatViewSelectorItemSet } from './Sidebar/ChatViewSelectorItemSet.tsx';

init({ data });

Expand Down Expand Up @@ -196,18 +199,20 @@ const App = () => {
}}
>
<Chat client={chatClient} isMessageAIGenerated={isMessageAIGenerated}>
<ChatView>
<ChatView maxSlots={3} minSlots={2} slotNames={['list', 'main', 'thread']}>
<ChatView.Selector itemSet={chatViewSelectorItemSet} />
<ChatView.Channels>
<ChannelList
Avatar={ChannelAvatar}
filters={filters}
options={options}
sort={sort}
showChannelSearch
additionalChannelSearchProps={{ searchForChannels: true }}
/>
<Channel>
<ChatView.Channels slots={['list', 'main', 'thread']}>
<ChannelListSlot slot='list'>
<ChannelList
Avatar={ChannelAvatar}
filters={filters}
options={options}
sort={sort}
showChannelSearch
additionalChannelSearchProps={{ searchForChannels: true }}
/>
</ChannelListSlot>
<ChannelSlot slot='main'>
<WithDragAndDropUpload>
<Window>
<ChannelHeader Avatar={ChannelAvatar} />
Expand All @@ -222,15 +227,28 @@ const App = () => {
<ChannelExposer />
</Window>
</WithDragAndDropUpload>
</ChannelSlot>
<ThreadSlot slot='thread'>
<WithDragAndDropUpload className='str-chat__dropzone-root--thread'>
<Thread virtualized />
<Thread />
</WithDragAndDropUpload>
</Channel>
</ThreadSlot>
</ChatView.Channels>
<ChatView.Threads>
<ThreadList />
<ChatView.Threads slots={['list', 'main-thread', 'optional-thread']}>
<ThreadListSlot slot='list'>
<ThreadList />
</ThreadListSlot>
<ChatView.ThreadAdapter>
<Thread virtualized />
<ThreadSlot slot='main-thread'>
<WithDragAndDropUpload className='str-chat__dropzone-root--thread'>
<Thread />
</WithDragAndDropUpload>
</ThreadSlot>
<ThreadSlot slot='optional-thread'>
<WithDragAndDropUpload className='str-chat__dropzone-root--thread'>
<Thread />
</WithDragAndDropUpload>
</ThreadSlot>
</ChatView.ThreadAdapter>
</ChatView.Threads>
</ChatView>
Expand All @@ -240,7 +258,8 @@ const App = () => {
};

const ChannelExposer = () => {
const { channel, client } = useChatContext();
const channel = useChannel();
const { client } = useChatContext();
// @ts-expect-error expose client and channel for debugging purposes
window.client = client;
// @ts-expect-error expose client and channel for debugging purposes
Expand Down
40 changes: 19 additions & 21 deletions examples/vite/src/AppSettings/tabs/Reactions/ReactionsTab.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import {
Button,
ChannelActionProvider,
ChannelStateProvider,
ChannelInstanceProvider,
ComponentProvider,
Message,
useComponentContext,
} from 'stream-chat-react';
import { appSettingsStore, useAppSettingsState } from '../../state';
import {
reactionsPreviewChannelActions,
reactionsPreviewChannelState,
reactionsPreviewMessage,
reactionsPreviewOptions,
Expand Down Expand Up @@ -108,24 +106,24 @@ export const ReactionsTab = () => {
<div className='app__settings-modal__field'>
<div className='app__settings-modal__field-label'>Preview</div>
<div className='app__settings-modal__preview'>
<ChannelActionProvider value={reactionsPreviewChannelActions as never}>
<ChannelStateProvider value={reactionsPreviewChannelState as never}>
<ComponentProvider
value={{
...componentContext,
reactionOptions: reactionsPreviewOptions,
}}
>
<li className='str-chat__li--single'>
<Message
groupStyles={['single']}
message={reactionsPreviewMessage}
messageActions={[]}
/>
</li>
</ComponentProvider>
</ChannelStateProvider>
</ChannelActionProvider>
<ChannelInstanceProvider
value={{ channel: reactionsPreviewChannelState.channel as never }}
>
<ComponentProvider
value={{
...componentContext,
reactionOptions: reactionsPreviewOptions,
}}
>
<li className='str-chat__li--single'>
<Message
groupStyles={['single']}
message={reactionsPreviewMessage}
messageActions={[]}
/>
</li>
</ComponentProvider>
</ChannelInstanceProvider>
</div>
</div>
</div>
Expand Down
9 changes: 7 additions & 2 deletions examples/vite/src/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ body {
}

@layer stream-overrides {
.str-chat {
.str-chat:not(.str-chat__channel) {
height: 100%;
width: 100%;
}
Expand All @@ -36,6 +36,10 @@ body {
min-height: 0;
}

.str-chat__channel {
flex: 1;
}

.str-chat__chat-view {
height: 100%;
container-type: inline-size;
Expand All @@ -46,6 +50,7 @@ body {
gap: 0;
}

.str-chat__thread-list-container,
.str-chat__channel-list {
flex: 0 0 300px;
max-width: 300px;
Expand Down Expand Up @@ -90,7 +95,7 @@ body {
}

.str-chat__dropzone-root--thread,
.str-chat__thread-list-container,
//.str-chat__thread-list-container,
.str-chat__thread-container {
//flex: 0 0 360px;
width: 100%;
Expand Down
8 changes: 4 additions & 4 deletions examples/vite/src/stream-imports-layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

//@use 'stream-chat-react/dist/scss/v2/Avatar/Avatar-layout';
//@use 'stream-chat-react/dist/scss/v2/AttachmentList/AttachmentList-layout';
//@use 'stream-chat-react/dist/scss/v2/AttachmentPreviewList/AttachmentPreviewList-layout'; // X
//@use 'stream-chat-react/dist/scss/v2/AttachmentPreviewList/AttachmentPreviewList-layout';
//@use 'stream-chat-react/dist/scss/v2/Autocomplete/Autocomplete-layout';
//@use 'stream-chat-react/dist/scss/v2/AudioRecorder/AudioRecorder-layout';
//@use 'stream-chat-react/dist/scss/v2/BaseImage/BaseImage-layout';
Expand All @@ -17,19 +17,19 @@
@use 'stream-chat-react/dist/scss/v2/common/CircleFAButton/CircleFAButton-layout';
//@use 'stream-chat-react/dist/scss/v2/Dialog/Dialog-layout';
//@use 'stream-chat-react/dist/scss/v2/DragAndDropContainer/DragAndDropContainer-layout';
//@use 'stream-chat-react/dist/scss/v2/DropzoneContainer/DropzoneContainer-layout'; // X
//@use 'stream-chat-react/dist/scss/v2/DropzoneContainer/DropzoneContainer-layout';
//@use 'stream-chat-react/dist/scss/v2/EditMessageForm/EditMessageForm-layout';
//@use 'stream-chat-react/dist/scss/v2/Form/Form-layout';
//@use 'stream-chat-react/dist/scss/v2/ImageCarousel/ImageCarousel-layout';
//@use 'stream-chat-react/dist/scss/v2/Icon/Icon-layout';
@use 'stream-chat-react/dist/scss/v2/InfiniteScrollPaginator/InfiniteScrollPaginator-layout';
//@use 'stream-chat-react/dist/scss/v2/LinkPreview/LinkPreview-layout'; // X
//@use 'stream-chat-react/dist/scss/v2/LinkPreview/LinkPreview-layout';
@use 'stream-chat-react/dist/scss/v2/LoadingIndicator/LoadingIndicator-layout';
@use 'stream-chat-react/dist/scss/v2/Location/Location-layout';
//@use 'stream-chat-react/dist/scss/v2/Message/Message-layout';
//@use 'stream-chat-react/dist/scss/v2/MessageActionsBox/MessageActionsBox-layout';
//@use 'stream-chat-react/dist/scss/v2/MessageBouncePrompt/MessageBouncePrompt-layout';
//@use 'stream-chat-react/dist/scss/v2/MessageInput/MessageInput-layout'; // X
//@use 'stream-chat-react/dist/scss/v2/MessageInput/MessageInput-layout';
//@use 'stream-chat-react/dist/scss/v2/MessageList/MessageList-layout';
//@use 'stream-chat-react/dist/scss/v2/MessageList/VirtualizedMessageList-layout';
// @use 'stream-chat-react/dist/scss/v2/MessageReactions/MessageReactions-layout';
Expand Down
Loading
Loading