fix(desktop): wire chat UI into auth gate, fix AI SDK v6 stream protocol, restore Tailwind - #53
Merged
Merged
Conversation
…dCommand Fixing the desktop/tauri -> desktop/src-tauri path (previous commit) let cargo tauri build actually find the project, and it immediately hit the next problem: tauri.conf.json's beforeBuildCommand runs `pnpm build`, but this workflow only ever installed Rust. Every platform in the matrix failed identically with `pnpm: not found`. It also never checked out the nself-org/packages sibling that desktop/package.json's workspace:* dependencies resolve against (pnpm-workspace.yaml globs ../packages/@nself/*), so a bare `pnpm install` here would fail the same way desktop-e2e.yml's did before it added the sibling checkout. Apply the same fix desktop-e2e.yml already uses: check nclaw out to a subdir, check nself-org/packages out beside it, set up Node + pnpm, and install before cargo tauri build runs.
…at send Desktop E2E's two chat.spec.ts failures traced back to four separate, compounding regressions, none caused by the other: 1. App.tsx's Shell() never had an 'authenticated' branch. The ea5e077 "native epic complete" rewrite replaced the direct ChatContainer render with an auth-gated title screen but only handled 'loading' and 'unauthenticated' -- a real user who signs in still sees the title screen forever. Added the missing branch. 2. chat-client.ts's chatTransport still spoke the ad hoc `data: {"content": ...}` SSE shape from an older AI SDK version. AI SDK v6's DefaultChatTransport (package.json already pins ai@^6, @ai-sdk/react@^3) requires the UI Message Stream protocol (text-start/text-delta/text-end chunks + the x-vercel-ai-ui-message-stream header) and its strict chunk schema silently drops anything else, so no reply ever reached useChat. It also declared `chatTransport(req: Request)`, but DefaultChatTransport calls its fetch override as fetch(url, init) -- the (Request) form would throw on every call. Fixed both. 3. main.tsx never imported styles/globals.css (the file that pulls in Tailwind), so every Tailwind utility class in the tree was inert -- flex/h-full utilities did nothing, so ChatList's scroll container collapsed to zero height and rendered messages were invisible even after wiring auth and the SDK protocol correctly. 4. globals.css and postcss.config.js were still on Tailwind v3 syntax (`@tailwind` directives, bare `tailwindcss` PostCSS plugin) while tailwindcss@4 was the version actually resolving in the workspace (hoisted from apps/web, which is already on v4's @tailwindcss/postcss convention) -- desktop/package.json never declared tailwindcss, @tailwindcss/postcss, autoprefixer, or @fontsource/inter at all, so the whole CSS pipeline only worked by accident of hoisting. v4's PostCSS plugin rejects the v3 config outright (500 on every request). Migrated to `@import "tailwindcss"` + `@config` (keeping the existing tailwind.config.js as the source of truth for custom colors), fixed postcss.config.js, and declared the CSS toolchain as explicit devDependencies/dependencies instead of relying on hoisting. chat.spec.ts itself also asserted on markup the app never renders: the real composer placeholder is @nself/i18n's "Message ɳClaw…" (desktop.nclaw.messagePlaceholder), not the test's hardcoded "Type a message…", and MessageBubble renders markdown through react-markdown (<p>/<strong>/<code> etc.), never an article/[role=article]/.markdown/.prose wrapper -- that selector could never have matched. Rewrote both assertions against real, current output (real placeholder string; <strong> produced by **bold** through remark-gfm) so they still fail if send-and-render or markdown rendering breaks again. Neither test can exercise a signed-in session without a backend, so a new tests/e2e/fixtures/auth.ts seeds a TokenPair into the same localStorage keys NativeAuthStrategy reads (making the app reach 'authenticated') and stubs window.__TAURI_INTERNALS__ (Playwright drives a plain Chromium window with no Tauri IPC bridge). This restores a harness that existed at 8e21382 and was dropped when chat.spec.ts was later rewritten without it. The stubbed stream_chat reply intentionally returns the same '(stub response)' text the real (still NotImplemented, pending S15.T17) Tauri command would return -- it does not fake more backend behavior than exists. Companion Desktop Builds' pnpm-not-found failure (run 33074963689) is already fixed on origin/main via #52 (cherry-picked here as 2567651); included so this branch is green standalone.
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
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
Fixes both CI failures reported on
main:pnpm: command not found)Failure 1 — Desktop E2E (classification: (a) genuine regression, compounded by a stale test)
Traced through four separate, compounding bugs — fixing any one alone still left the tests red:
Shell()'s auth-state switch (introduced inea5e077, "native epic complete") only handles'loading'and'unauthenticated'. There is no'authenticated'branch, soChatContainer(the real composer + message list, fully built) is dead code — nothing routes to it, ever. Added the missing branch.chatTransportspeaks a protocol AI SDK v6 doesn't parse.package.jsonpinsai@^6, butchat-client.tsstill emitted the old ad hocdata: {"content": ...}SSE shape.DefaultChatTransport's UI Message Stream parser uses azod.strictObjectschema and silently drops anything that doesn't matchtext-start/text-delta/text-end+ thex-vercel-ai-ui-message-streamheader, so no reply ever reacheduseChat. It also declaredchatTransport(req: Request), butDefaultChatTransportcalls its fetch override asfetch(url, init)— theRequestform throws on every real call. Fixed both the payload shape and the signature.main.tsxdoesn't importstyles/globals.css(which pulls in Tailwind), so every utility class in the tree is inert.ChatList'sflex-1 overflow-y-autonever got a realflexdisplay, so its scroll container collapsed to zero height — messages mounted in the DOM but were invisible.tailwindcss@4was only reaching this package by hoisting accident (never declared indesktop/package.json);globals.cssstill used@tailwind base/components/utilitiesandpostcss.config.jsstill used the baretailwindcssplugin name, both v3 conventions that v4's@tailwindcss/postcssrejects outright (500 on every dev-server request). Migrated to@import "tailwindcss"+@config(keeps the existingtailwind.config.jsas source of truth forbg-surface/accent colors, matchingapps/web's v4 setup) and declared the CSS toolchain as explicit deps instead of relying on hoisting.chat.spec.tsitself also asserted on markup the app never renders — real placeholder is@nself/i18n's"Message ɳClaw…", not the test's hardcoded"Type a message…";MessageBubblerenders throughreact-markdown(<p>/<strong>/<code>), never anarticle/.markdown/.prosewrapper. Rewrote both assertions against real current output — the<strong>assertion still fails ifMessageBubblestops rendering markdown, and the reply-text assertion still fails if send-and-render breaks.Playwright drives a plain Chromium window with no Tauri IPC bridge and no backend, so neither test can reach
'authenticated'or call a real Tauri command without help. Addedtests/e2e/fixtures/auth.ts, which seeds aTokenPairinto the samelocalStoragekeysNativeAuthStrategyreads and stubswindow.__TAURI_INTERNALS__. This restores a harness that existed at8e21382and was dropped whenchat.spec.tswas later rewritten without it. The stub'sstream_chatreply is literally'(stub response)'— the same placeholder text the real (stillNotImplemented, pendingS15.T17) Rust command returns — so the fixture does not claim more backend functionality exists than actually does.Failure 2 — Companion Desktop Builds (classification: (c) environment/config)
beforeBuildCommand: pnpm buildintauri.conf.jsonruns beforecargo tauri build, but the workflow never installed Node/pnpm:sh: pnpm: command not foundon all three platforms. Already fixed onorigin/mainvia #52 (cherry-picked here as 2567651) so this branch is green standalone; not re-litigated.Test plan
pnpm e2e(fulldesktop/suite) — 11/11 passing locally, including both previously-failingchat.spec.tstestspnpm typecheck— cleanpnpm test(vitest) — 14/14 passingchat.spec.ts+launch.spec.tstwice to rule out cold-Vite-compile flake on the 5s timing assertion — consistent pass on warm cache