- N1: extract the copy-pasted pointerName/segmentName helpers from
gitFileList.ts and gitFileTree.ts into gitFileShared.ts.
- N3: drop the dead conditional "tree" class (no CSS rule exists).
- N4 (P3): memoize computeViewState on (status, view) identity so renders
from expand/collapse or diff selection skip the full model rebuild;
expand state is read live at render time, never cached.
The right-anchored .toolbar-actions group rendered the view toggle left of
the conditional expand/collapse-all button, so the toggle jumped left
whenever the button appeared. Render expand/collapse-all first (leftmost)
so only the space to its left changes; the toggle and Refresh stay put.
Re-add the minimise chevron to the expanded session-warnings pane in
ChatView, wired to the existing unified onToggleWarnings (toggle ≡
collapse in the expanded state). The status-bar warning toggle from
a13778c is retained unchanged; both controls share the single
sessionWarningVisibility mutation, so they cannot desync.
- ChatView: onToggleWarnings prop + handleToggleWarnings; chevron
rendered inline via html (no svg re-import), guarded by
onToggleWarnings === undefined.
- PiWebApp: renderChatView <chat-view> passes .onToggleWarnings.
- shared.ts: restore .session-warnings-controls / -collapse / icon CSS.
- ChatView.test.ts: restore the chevron-wiring test against
onToggleWarnings via the session-warnings-collapse marker.
Relay restore-warning-chevron leg 1.
Recurse into dirty submodules when building the Git status so their
modified and untracked files appear as full-path entries, and add a
commit-pointer entry (with short SHAs) only when the recorded commit
actually moved. Route diffs whose path falls inside a submodule to run
in that submodule's working tree so real per-file diffs are shown.
The changed-file list groups these under the submodule: tree view keeps
the nested structure and marks the submodule root with a badge, list
view flattens them into one expandable group pinned above the ordinary
files. Depth 1 only; ignored files are excluded; the panel stays
read-only.
Covered by client tree/list-grouping tests, parser tests, and a
server test that drives a real temporary repository and submodule.
Extract the Git panel into a dedicated `workspace-git-panel` Lit component
(mirroring the Files panel) and add a segmented List/Tree toggle next to
Refresh.
Tree view builds an in-memory, collapsible directory tree from the changed
files, starts fully collapsed, and offers a single expand-all/collapse-all
button (visible only in tree view). List view keeps the existing flat,
full-path rows. The selected view mode persists in localStorage under
`pi-web.gitFileView`; per-directory expand state is intentionally ephemeral.
- gitFileViewPreference.ts: localStorage-backed view preference (+ test)
- gitFileTree.ts: pure flat-paths -> nested-tree builder (+ test)
- WorkspaceGitPanel.ts: the panel component with toggle + tree state
- Only increment visual branch depth after forks so long linear session
histories stay in one lane instead of scrolling off-screen; lower the
max visual depth cap to match.
- Reset to the no-summary default when leaving an invalid custom summary
choice so Navigate is never permanently disabled by a stale invalid entry.
Skip opportunistic status requests when the flow's originating machine is no longer selected, and discard in-flight status results after the machine or session selection changes.\n\nRefs #74
Retain client-owned machine affinity for each interactive auth flow and use it for prompt responses, polling, cancellation, and completion refreshes. This prevents a later machine selection from forwarding secrets to a different remote.\n\nRefs #74
Best-effort cancel a running auth flow when its start response arrives after the browser operation was closed or superseded, so sessiond does not retain orphaned provider polling or callback listeners.\n\nRefs #72
Remove the three shared template-inspection test helpers that had no
consumer after the Slice B migrations: templateStaticMarkup,
collectTemplateStrings, and collectStringValues. They were kept alive
only by a temporary @public knip shim; with no in-window test needing
them, the finish-line requirement forbids dead helpers, so remove them
outright. knip is now satisfied without the shim.
Reclassify ChatView.test.ts per the testing-guide skill: move content/text/
attribute/ordering assertions to new pure public seams on ChatView.ts
(chatSessionWarningRows, chatQueuedSectionShowsClearAction, chatGroupAnchorKey,
chatEventAnchorKey, chatGroupScrollMarkerId, chatMessageGroupClassName,
chatMessageGroupLabel) with the component render code delegating to them, and
route the genuine Clear-queue/dismiss/toggle event wiring through the shared
templateInspection.testSupport helpers with escape-hatch comments. Delete the
per-file TemplateResult-inspection cluster. Drop the now-consumed @public tag
from templateEventHandlerNearMarker.
Replace the per-file TemplateResult inspection helper cluster in
ChatView.image.test.ts with the shared templateInspection.testSupport
escape hatch for genuine event wiring (@load re-pin, @click zoom), and
move content/attribute assertions to new pure public seams on ChatView
(chatImagePartSource, chatToolOutputLabel, chatMessageAnchorKey) that
the component's own render code now delegates to.
Route genuine Lit event-wiring (upload input change, form submit, file-tree
row clicks) through the shared templateInspection.testSupport escape hatch and
add the required proportionality comment. Move viewer content messaging
(empty/loading/binary states) to a new public workspaceFileViewerStatusLabel
seam on the component instead of scraping Lit markup for text. Delete the
per-file inspection helper cluster; drop @public from the two shared helpers
that now have a real importer.
Replace the SettingsDialog.general.test.ts markup-scraping assertion (which
scraped the rendered TemplateResult for '<settings-general-panel', 'scope-note',
'This tab edits:') with an exported pure routing seam activeSettingsPanelTag()
and assert the section->panel contract directly. Delete the now-unused
collectTemplateStrings helper and its private template-reflection cluster from
SettingsDialog.testSupport.ts.
The .packages/.plugins/.sessiond siblings inspect no TemplateResult internals
(orchestration reflection only), so no migration was needed for them.
Migrate the prime Finding-2 offender off Lit TemplateResult scraping. The
panel's dynamic notice-stack logic is extracted into an exported pure
sessiondPanelNotices() (plus SessiondPanelNoticeContext) and the existing
sessiondDescription is exported, so the test asserts notice
composition/ordering and the scope description through public seams instead of
flattening rendered template internals. Save and draft-preservation behavior
are observed via the injected onSave callback and public state.
Removes all per-file template-inspection helpers and the escape-hatch need for
this file (testing-guide Findings 1-3).
Consolidate the duplicated, per-file Lit TemplateResult inspection helper
cluster into one shared, strictly-typed, type-guarded seam at
src/client/src/templateInspection.testSupport.ts, documented as the
testing-guide escape hatch. Migrate PiWebApp.clearQueue.test.ts to it as a
proof and delete its local copies. Tag not-yet-consumed public entry points
with @public so knip does not flag them until Slice B adds consumers.
Relay: testing-skill-compliance leg 1 (Finding 1).
Show a pinned banner at the top of the session view with resource and
runtime diagnostics (skills, prompts, themes, extension load errors) plus
the Anthropic subscription-auth billing notice, recomputed live from the
current runtime so they stay accurate across browser reloads.
Warnings carry an optional dismiss capability; the Anthropic notice is
dismissable and durably suppressed through pi's own anthropicExtraUsage
warning setting. Also fixes the testing-guide skill frontmatter so it
loads.
Seed the in-flight partial assistant message (text, thinking, and
in-progress tool calls) when opening or reconnecting to a session that is
mid-stream, then continue streaming live deltas on top of it. Replaces the
blocking "Catching up..." placeholder and the end-of-turn transcript reload.
Server stamps every per-session UI event with a monotonic seq at the
SessionEventHub publish choke point and exposes
GET /sessions/:sessionId/stream-snapshot returning { seq, partial }. The
client fetches the snapshot on join, seeds the normalized partial into the
in-memory transcript (never the history cache), and applies buffered/live
events using the seq watermark for exactly-once delivery.
The snapshot is a progressive enhancement: a 404 from an older remote
pi-web or a not-yet-restarted session daemon falls back to an empty seed
(seq 0, drops nothing), so sessions still open and stream normally. The
stream-snapshot route is registered in the federation allowlist for
remote-machine proxying.