Skip to content

fix(desktop): wire chat UI into auth gate, fix AI SDK v6 stream protocol, restore Tailwind - #53

Merged
acamarata merged 2 commits into
mainfrom
fix/main-ci-green
Aug 27, 2026
Merged

acamarata merged 2 commits into
mainfrom
fix/main-ci-green

Conversation

@acamarata

Copy link
Copy Markdown
Contributor

Summary

Fixes both CI failures reported on main:

  • Desktop E2E (chat.spec.ts, 2 failing tests)
  • Companion Desktop Builds (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:

  1. App.tsx never renders the chat UI for a signed-in user. Shell()'s auth-state switch (introduced in ea5e077, "native epic complete") only handles 'loading' and 'unauthenticated'. There is no 'authenticated' branch, so ChatContainer (the real composer + message list, fully built) is dead code — nothing routes to it, ever. Added the missing branch.
  2. chatTransport speaks a protocol AI SDK v6 doesn't parse. package.json pins ai@^6, but chat-client.ts still emitted the old ad hoc data: {"content": ...} SSE shape. DefaultChatTransport's UI Message Stream parser uses a zod.strictObject schema and silently drops anything that doesn't match text-start/text-delta/text-end + the x-vercel-ai-ui-message-stream header, 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 throws on every real call. Fixed both the payload shape and the signature.
  3. Tailwind CSS was never loaded. main.tsx doesn't import styles/globals.css (which pulls in Tailwind), so every utility class in the tree is inert. ChatList's flex-1 overflow-y-auto never got a real flex display, so its scroll container collapsed to zero height — messages mounted in the DOM but were invisible.
  4. Tailwind config was v3 syntax against a v4 install. tailwindcss@4 was only reaching this package by hoisting accident (never declared in desktop/package.json); globals.css still used @tailwind base/components/utilities and postcss.config.js still used the bare tailwindcss plugin name, both v3 conventions that v4's @tailwindcss/postcss rejects outright (500 on every dev-server request). Migrated to @import "tailwindcss" + @config (keeps the existing tailwind.config.js as source of truth for bg-surface/accent colors, matching apps/web's v4 setup) and declared the CSS toolchain as explicit deps instead of relying on hoisting.

chat.spec.ts itself also asserted on markup the app never renders — real placeholder is @nself/i18n's "Message ɳClaw…", not the test's hardcoded "Type a message…"; MessageBubble renders through react-markdown (<p>/<strong>/<code>), never an article/.markdown/.prose wrapper. Rewrote both assertions against real current output — the <strong> assertion still fails if MessageBubble stops 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. Added tests/e2e/fixtures/auth.ts, which seeds a TokenPair into the same localStorage keys NativeAuthStrategy reads and stubs window.__TAURI_INTERNALS__. This restores a harness that existed at 8e21382 and was dropped when chat.spec.ts was later rewritten without it. The stub's stream_chat reply is literally '(stub response)' — the same placeholder text the real (still NotImplemented, pending S15.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 build in tauri.conf.json runs before cargo tauri build, but the workflow never installed Node/pnpm: sh: pnpm: command not found on all three platforms. Already fixed on origin/main via #52 (cherry-picked here as 2567651) so this branch is green standalone; not re-litigated.

Test plan

  • pnpm e2e (full desktop/ suite) — 11/11 passing locally, including both previously-failing chat.spec.ts tests
  • pnpm typecheck — clean
  • pnpm test (vitest) — 14/14 passing
  • Re-ran chat.spec.ts + launch.spec.ts twice to rule out cold-Vite-compile flake on the 5s timing assertion — consistent pass on warm cache

…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.
@acamarata
acamarata merged commit e923d36 into main Aug 27, 2026
14 checks passed
@acamarata
acamarata deleted the fix/main-ci-green branch August 27, 2026 14:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant