refactor: migrate session coupled core (chat, live reload, btw, cat) to Svelte 5#68
Merged
Conversation
Absorb right-sidebar.js (scratchpad load/save, resize drag, tab switching, expand/collapse) into RightSidebar.svelte's onMount. The component exposes its controls on window.__piRightSidebar so session-ui-runner and the annotation/keyboard wiring keep working. Delete right-sidebar.js and port its tests to RightSidebar.test.js.
Replace the imperative innerHTML artifact-panel.js renderer with a reactive ArtifactPanel.svelte mounted inside RightSidebar's Artifacts pane. session.js still owns artifact collection/filtering and pushes the visible set through window.__piArtifactPanel (also consumed by the annotation layer for select/resolve). The component lazy-loads highlight.js and renders markdown previews itself. Delete artifact-panel.js and port its tests to ArtifactPanel.test.js.
Replace the imperative innerHTML annotation-layer.js with a reactive AnnotationLayer.svelte rendered inside RightSidebar's Notes pane. The notes list, floating comment popover, and note modal render declaratively; selection detection, highlight (re)application, and the annotations API stay imperative. session.js supplies runtime deps (api/scopes/composer/callbacks) through window.__piAnnotationLayer.init. The popover + modal relocate to <body> so their fixed positioning stays viewport-relative. Delete annotation-layer.js and port its tests to AnnotationLayer.test.js.
…plan Update the svelte-migration-plan §11 progress log to reflect the completed RightSidebar-group cut-over (chrome + artifact panel + annotation layer) and point the next executor at the coupled ChatComposer + LiveReload core.
…ionPage Prep for the ChatComposer + LiveReload migration. SessionPage now creates the session navigator from the reactive model and exposes navigateTo on window before the child components mount, so the tree, chat composer, and live reload share one instance. The active leaf/target/filter/search state lives solely on SessionDataModel — session.js drops its mirrored locals, its own navigator, and syncTreeRendererState; search-filters callbacks write the model directly. Pure refactor; behavior unchanged.
ChatComposer.svelte now self-inits the chat runner + git footer in onMount, and a new LiveReload.svelte self-inits the SSE live-reload runner. Both read the shared model + navigateTo (owned by SessionPage) from window. session.js no longer wires chat/live: it just exposes model reconciliation on window.__piReconcileEntries for LiveReload to call (also used by load-earlier) and drops the runner/selector imports. <LiveReload> mounts before <ChatComposer> so the optimistic message-sent listener exists before the user can send. The chat/live runner modules stay as component-owned implementation detail (deletion is the later cleanup).
Update svelte-migration-plan §11 with the navigateTo/view-state prep and the ChatComposer + LiveReload component cut-over; point the next executor at btw-popup + cat-gatekeeper (add e2e first) and session.js teardown.
btw.spec: open/close from the git bar with empty state, and the optimistic user bubble + running state on send. cat.spec: skip-to-break shows the enforced break overlay with a countdown, enabling the gatekeeper page-locally via a settings route stub so the shared server store (and the rest of the suite) stays untouched. These pin the selectors/behavior the upcoming BtwPopup + CatGatekeeper components must preserve.
…elte Split the focus/break + bedtime companion: cat-gatekeeper.js keeps the DI-testable timer/phase logic but no longer builds the overlay — it calls an injected `view` (showBreak/setBreakTimer/showSleep/hide). The overlay is now CatGatekeeper.svelte, which renders it declaratively, blocks input while shown, plays the cat video, and exposes the controller on window.__piCatGatekeeper. The overlay relocates to <body> (fixed, full-screen, top z-index). session.js drops setupCatGatekeeper; the component self-wires in onMount. cat-settings.js (pure storage) stays. Unit test reworked to assert the controller's view calls + state.
Replace the imperative innerHTML live/btw-popup.js with BtwPopup.svelte: the transcript (markdown + tool chips + optimistic/streaming/working bubbles) renders declaratively; drag, resize, per-session + per-parent SSE, status polling, and submit/cancel stay imperative. It wires its #pi-btw-button trigger (in <ChatComposer>) by id and relocates the window to <body> for fixed positioning. session.js drops setupBtwPopup; SessionPage renders <BtwPopup cwd parentId>. Delete btw-popup.js and port its tests to BtwPopup.test.js. openWindow clears `hidden` synchronously before placeInitial measures the window, so it isn't positioned off-screen while Svelte's reactive flush is still pending.
Update svelte-migration-plan §11 with the e2e-coverage-first step and the CatGatekeeper + BtwPopup component cut-overs; point the next executor at the session.js teardown + docs pass.
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
Migrates the tightly-coupled "core" of the session viewer from the imperative
innerHTMLruntime to self-contained Svelte 5 components, continuingdocs/dev/svelte-migration-plan.md(Phase 3). The motivation is to make thelive app render from declarative, state-driven components (shared with the
static export where applicable) and to shrink
session.jstoward deletion.Key changes:
RightSidebar.svelteabsorbs the scratchpadchrome (load/save, resize, tabs), and the Artifacts/Notes panes are now
ArtifactPanel.svelteandAnnotationLayer.svelte(declarative rendering;selection/highlight/SSE stay imperative). Deletes
ui/right-sidebar.js,artifacts/artifact-panel.js,annotations/annotation-layer.js.SessionPagebuilds thenavigator from the reactive
SessionDataModeland exposeswindow.navigateTobefore children mount; active leaf/target/filter/search live solely on the
model.
session.jsdrops its mirrored locals + own navigator.ChatComposer.svelteself-initsthe chat runner + git footer; new
LiveReload.svelteself-inits the SSErunner (
reactiveContent).session.jsexposes onlywindow.__piReconcileEntriesfor live reload + load-earlier.BtwPopup.svelterenders thefloating scratch-chat transcript declaratively (drag/resize/SSE imperative);
CatGatekeeper.svelterenders the focus/break overlay whilecat-gatekeeper.jskeeps the DI-testable timer logic via an injected view.Deletes
live/btw-popup.js.@testing-library/sveltecomponent tests; new e2e specs (
e2e/tests/btw.spec.ts,cat.spec.ts) wereadded before converting btw/cat (neither had coverage).
Related issue
Part of the Svelte 5 migration tracked in
docs/dev/svelte-migration-plan.md(Phase 3 — coupled core). No standalone issue number.
Type of change
refactor— code change that neither fixes a bug nor adds a featuretest— adding or updating testsLive vs. Export
internal/ui/embedded/in sync withweb/src/session/changesThe export self-containment guard (
TestExportBundleIsSelfContained) staysgreen; chat/live/btw/cat components are live-only and never imported by
web/src/export/export-entry.js.Testing
vitest) cover the change —npm run test(528 passed),npm run knipclean,npm run build(zero vite-plugin-svelte a11y warnings)npx playwright test --project="Desktop Chrome"(57 passed / 2 skipped; load-earlier passes on its documented retry)
make check/ fullgo test ./...— rango build -o pi-web ./cmd/pi-web,go test ./internal/ui/...(incl. the export guard), andgo vet ./...green.Did not run the full Go suite:
internal/git TestDescribeDefaultBranchfailsonly in this sandbox due to commit-signing (pre-existing, unrelated).