Sign in
Join now
scn-chat
sharedcomputer.network
/
Star
Starred
Star
Something went wrong. Try again.
Fork
0
Eye filled
Watch
Watching
Watch
ATProto-based AI Assistant Chat interface.
Star
Starred
Star
Something went wrong. Try again.
Fork
Eye filled
Watch
Watching
Watch
Overview
Overview
Issues
Issues
1
1
Pulls
Pulls
Pipelines
Pipelines
scn-chat
/
apps
/
web
/
src
/
features
/
conversation
4 folders
·
3 files
at
admin-config-export
pouriade.com
·
The composer decides whether a message can be sent once, as canSend, which both disables Send and stops a submit, so a new reason not to send can't reach one and miss the other. Submitting still checks on its own for a send already on its way and for a running reply, whose Stop takes Send's place.
·
2w ago
ceed41b6
components
The composer decides whether a message can be sent once, as canSend, which both disables Send and stops a submit, so a new reason not to send can't reach one and miss the other. Submitting still checks on its own for a send already on its way and for a running reply, whose Stop takes Send's place.
2w ago
hooks
The chat list and its rows do less work, from an audit against React performance practice. Opening a search hides the chat list inside React's Activity rather than unmounting it, so closing the search brings the chats back as they were rather than mounting every row again. A chat row no longer holds three mutations: renaming and tagging are an EditChat card and deleting a DeleteChat card, each holding its own, so an idle row holds none, and cancelling a failed change clears its error with the card. Picking a tag keeps the rows shown until its chats arrive, rather than a skeleton between. The month headings of older chats come from two formatters made once, rather than one made for each chat on every change to the list. A reply's sources and a search's results take the fold's ref apart, so React Compiler compiles them rather than silently leaving them out. The conversation's rename, instructions, and sync call their mutations' own functions, so the header no longer renders with every state either passes through, and its jump outline is built only while the jump stack is open. The search spec says the list stays mounted, and the list test checks it is hidden.
2w ago
lib
The web app's message records are typed as the lexicon's MessageRecord, and a conversation's info as InfoRecord, from the local copy, which holds only records the server validated, through BranchMessage to the message, status, details, part, and tool views, so their reads need no casts. src/shared/message.ts holds what a status means, isPending and isFinished, which counts a status another client wrote that this app doesn't know as neither, along with a message's parts, whether it is encrypted, and who wrote it, in place of the checks written out in the message view, the message actions, the chat, the reply follower, and tool status. Tests build records with messageRecord in tests/helpers/records.ts, and the status rules are tested once.
2w ago
pages
On a reload, the composer's box takes typing before the page's code loads. The page's frame, which the server sends in place of the client-only chats, now holds the composer's frame at the foot of the panel: a plain textarea in the composer's card, with Attach, the model select's loading line, and Send disabled, so Enter only adds a line. The conversation's column shows it again while its code downloads. Each frame that gives way leaves its text, cursor, and focus in composer-handoff.ts, and the frame or composer that takes its place puts them back, so the swap can't be seen. Only a composer that starts empty takes a draft, never one editing a message. The frame and the composer are built from the same parts in composer-parts.tsx, and the composer binds its form field to MessageBox. An open chat's box says neither "Ask anything" nor "Reply" until its messages arrive, and sends nothing until then, since the message wouldn't know which one it answers. On a reload the turn skeleton in the page's frame shows at once, and the skeletons that take its place carry that on rather than vanishing to fade in again. The web UI spec describes it, with tests, including one that hydrates the server's frame, and an acceptance criterion.
2w ago
attachment-types.ts
Load less and rerender less. The new-chat page no longer downloads the Markdown renderer: the conversation and the search results load with React.lazy, the chat route's loader starts the conversation's download, the new-chat page starts it once it shows, and opening the search starts the results', so what / downloads drops from 335 KB to 184 KB with brotli. Streamdown imports rehype-raw for its defaults, which markdown.tsx leaves out, so vite.config.ts aliases it to an empty stand-in in parts/no-raw.ts, keeping parse5 out of the build and the Markdown chunk from 163 KB to 71 KB gzipped. The logo's paths are rounded to two decimals, from 10.0 KB to 6.6 KB gzipped. The chat routes' loader starts the models, attachment types, and profile queries without waiting for them, and their head preconnects to the avatar's CDN. attachmentTypesQuery moves to its own module, so the loader doesn't bring the store's hooks into the entry. Pointing at or focusing a link preloads its route, the query cache deciding what is stale.
2w ago
chat.ts
The web app's message records are typed as the lexicon's MessageRecord, and a conversation's info as InfoRecord, from the local copy, which holds only records the server validated, through BranchMessage to the message, status, details, part, and tool views, so their reads need no casts. src/shared/message.ts holds what a status means, isPending and isFinished, which counts a status another client wrote that this app doesn't know as neither, along with a message's parts, whether it is encrypted, and who wrote it, in place of the checks written out in the message view, the message actions, the chat, the reply follower, and tool status. Tests build records with messageRecord in tests/helpers/records.ts, and the status rules are tested once.
2w ago
reply-follower.ts
A reply the follower followed since it was sent stops being followed once the local copy holds its final record, so what streamed of it, which can include whole fetched pages, isn't kept in memory beside the record until the chat closes. The follower's tests run through useChat over the test store, rather than mounting useConversation by hand and holding the messages in state, and a test checks a finished reply's stream goes. specs/web-ui.md says the follower refreshes through the store's refresh intent so the store's hooks know nothing of streams, rather than merging the two.
2w ago