AGENTS.md@packages/client/src · git:20261024.7507332 · 2026-10-24 · sha256 7d6f83d1f0ed331e
AGENTS.md@packages/client/src git:20261024.7507332A
Immutable. This exact content never changes and is served at /api/v1/blob/7d6f83d1f0ed331e.
# DOX — packages/client/src
Files in this directory. One row per source file.
| File | Purpose |
|------|---------|
| `App.tsx` | Two new shell-overlay routes: `/folder/:encodedCwd/view?path=…` (file preview) + `/pi-view?url=…` (URL… → see `App.tsx.AGENTS.md` The plugin-slot `h-[92vh]` wrapper STAYS: plugin claim bodies are `absolute inset-0` (zero intrinsic height) and would collapse to 0 under the deliberately height-INDEFINITE flush panel — a definite-height PIN, not a duplicated flex context. See change: fix-flush-dialog-scroll-and-close-collision. Hydrates `openspec.offerInitialization`/`enabled` from /api/config; threads them + readiness to SessionList/ComposerSessionActions. See change: add-openspec-init-affordances. Board prop is `worktreeAvailability` from `resolveWorktreeAvailability(cwd, sessions, folderGitMap, gitWorktreeEnabled)`, replacing the `gitBranch` derivation. See change: fix-openspec-board-worktree-button-gating. Adds `renderedCwds` memo + `useOpenSpecReconcile`; shares the openspec in-flight ref with the handler. See change: fix-connect-snapshot-frame-loss. Passes `retainedTranscript` to `ChatView`; `archivedSummaryToSession` carries `originDeviceId` + `retainedTranscript` so a read-only open of an ARCHIVED REMOTE session still distinguishes a truncated transfer from a whole one (`session_updated` is dropped for non-resident sessions). See change: serve-retained-remote-transcripts. Holds `collapsedFolders` (server-fed via `collapsed_folders_updated`) and runs the one-shot legacy `dashboard:collapsedGroups` migration AFTER the connect snapshot: sends only keys the server lacks, clears the legacy key once every canonical key is known, 10-load backstop. No optimistic mirror. See change: persist-folder-collapse-server-side Owns `pageReplyGen`/`pageExhausted` state, threaded to `useMessageHandler` + `SessionList`. See change: close-registry-frame-shed-gaps. `FileDiffView` lazy; route + `shellRenderers.renderDiff` each get a local `Suspense`. See change: add-lazy-terminal-diff-bootstrap. The `content-header-sticky` wrapper (plugin slot) is a SHRINKABLE pane row: `overflow-y-auto` own scrollport + inline `flexShrink: CHAT_HEADER_WEIGHT` / `minHeight: CHAT_HEADER_BOUND` from `lib/layout/chat-pane-row-class.ts` (bound 0 — no pixel floor; an empty slot renders 0px). It takes a share of a short pane's deficit and scrolls internally instead of painting a 476px panel over the split editor. See change: consolidate-flow-agent-cards. Session detail mounts `<YoloComposerStrip cwd={selectedSession?.cwd}/>` after `QueuePanel`, directly above `<CommandInput>`, inside `!readOnly`. See change: fix-yolo-indicator-overflow. `changedOnDisk` = Map<sid,Map<path,gen>>; passes `changeDetection`+`connectionGeneration` to session provider; `config_updated{editor}` hydrates editor-limits mirror. See change: gate-changed-on-disk-by-content. |
| `generated/plugin-sources.css` | GENERATED, committed (`!plugin-sources.css` in `generated/.gitignore`). One sorted Tailwind `@source` line per client-bearing plugin dir under `packages/` (fixture or not — dev and prod byte-identical) + claim `module` dirs outside it; paths relative to `generated/`. Written by vite plugin `regenerate` and `scripts/generate-plugin-registry.mjs`; imported by `index.css`. Do not edit. See change: decouple-plugins-from-core. |
| `index.css` | Global stylesheet + theme-variable roots. `:root` (dark) / `[data-theme="light"]` per-mode token maps, explicit `@source` lines for non-plugin packages only (`client-utils/src`, `dashboard-plugin-runtime/src`) + `@import "./generated/plugin-sources.css"` (plugin lines, generated; never hand-edit), `text-code` utility, selected-card `card-glow-fx`/`card-ring-fx`. Home of `--elevation-rim` panel-bevel inset-highlight token (dark `rgba(255,255,255,0.10)`, light `rgba(255,255,255,0.9)`); theme-agnostic, NOT in `CSS_VAR_KEYS` so it survives `applyThemeVars`. Tool-group liveness: `tool-group-shimmer`/`tool-group-spin-pulse`/`tool-group-flash` (running header + completion flash) + `chat-stream-live` (streaming-bubble edge-pulse+sweep); all transform/opacity/background-position, suppressed under `prefers-reduced-motion`. `@keyframes wtinit-slide` drives WorktreeInitChip's indeterminate progress bar. Home of `--severity-{error,warning,success,info,neutral}-{bg,fg,border}` message-severity tokens — single color source for toasts/banners; accent tiers via `color-mix` (bg 10% into `--bg-tertiary`, fg 46% toward `--text-primary`, border 40% alpha), `neutral` = literal base tokens; `--severity-info` separate from `--status-notice`. OpenSpec-board drop targeting: `.board-drop-marker::after` paints the 3px insertion bar into the EXISTING `gap-2`/`p-2` space (never an inserted flex child, which would add a second gap and oscillate the resolved slot), own z-index band above `.card-stripes-fx`; `.board-append-rail`(`-active`) sticky ≥44px append target; `.board-column-target`/`-receded`/`.board-column-body-over` drag-state legibility; `.board-edge-glow`(`-top`/`-bottom`) auto-scroll zones at `height: 0` with a negative margin cancelling the flex gap so mounting them mid-drag shifts no card. Theme tokens only. Home of `--border-strong`, the WCAG 2.1 SC 1.4.11 (3:1) boundary token for an overlay surface floating on `--bg-primary`; REUSE it rather than re-deriving — no other border token qualifies. Like every token here it MUST be declared in BOTH theme blocks: one-block-only silently resolves to an invalid value in the other theme. Home of the overlay z-index layer scale `--z-base … --z-lightbox` (ascending: base<raised<sidebar<overlay<popover<dialog<toast<lightbox) + matching `@utility z-<layer>` — single source of stacking order (z-index / stacking-context / underlap / portal / layering). Portaled overlays reference a `z-<layer>` token, NEVER a raw `z-[NNNN]` (frozen ratchet `scripts/z-layer-lint.mjs`). See changes: add-panel-elevation-system, enhance-tool-call-grouping, friendlier-worktree-init, unify-message-severity-colors, fix-openspec-board-drop-targeting, fix-replay-pill-a11y-and-collision, add-overlay-layering-system. Imports `./styles/asciidoc.css` (the `.asciidoc-body` preview typography scope) right after `@import "tailwindcss"`. See change: asciidoc-support. Base-palette text tokens MUST mirror `themes.ts` baseDark/baseLight exactly (parity tested by `src/lib/__tests__/theme-body-text-contrast.test.ts`); `--text-tertiary` raised to `#919191` (dark) / `#636363` (light) for the AA 4.5:1 body-text floor. See change: stop-discarding-known-session-state. Home of the `fx-idle` cascade: `:root.fx-idle *` pauses ALL animations while the UI is visible-but-idle (5s no input), plus the indeterminate-progress exemption ladder — `.animate-spin`/`.fx-progress` stay `running` under `fx-idle`, re-paused by the later-source `:root.app-hidden …` and higher-specificity `:root.fx-idle .fx-offscreen …` rules. See change: fix-long-session-ux-degradation (§7, design D8). New `--status-unread` (dark `#22d3ee`, light `#0891b2`) replaces hardcoded cyan in `.card-stripes-unread`; `.lane-hold-bar` (+`lane-hold-shrink`, static 50% reduced-motion), coarse-pointer `.lane-header-btn`/`.group-by-chip` 44px. See change: session-list-group-by. See change: align-ui-with-theme-tokens: adds identity tints `--tint-{green,orange,blue,purple,red}-{bg,fg,border}` (same color-mix recipe as severity); `--severity-{success,warning,info,error}-*` now alias the matching tint, values unchanged. Adds `@utility tint-action-{green,orange,blue,purple,red}` (tint fg/border/bg + (hover:hover) 70% color-mix) and `tap-target` (44px → 32px from sm:) so the recipe stays out of the JS index chunk. `[data-group]:has(> [data-group-content]:empty){display:none}` hides empty strip groups; `--composer-lifecycle-w: 9.5rem`. Visible `composer-dock` + `composer-root` sibling → root `border-top-color: transparent` (no full-width line through the dock). See change: redesign-composer-session-strip. Selected-card glow wrapped in static `.card-glow-mask`/`.card-glow-mask-outer` (content-box xor mask → glow only OUTSIDE card edge; mask never on the rotating `::before`); `--neon-rim-width: 3px` drives `.card-ring-fx` inset+padding; rim alpha 0.75 both themes; light glow alpha 0.30 / opacity 0.65. `.group-collapse > *` clip widened right (`padding-right: 14px; margin-right: -14px`) so the halo is not cut. Contract: `src/__tests__/selected-card-fx-css.test.ts`. See change: fix-selected-card-light-wash. Declares Base `--accent-<hue>-text` (6 tokens) in `:root` AND explicitly in `[data-theme="light"]` (light must not inherit dark values); mirrors `themes.ts` baseDark/baseLight, parity-tested. See change: remediate-accent-text-contrast. Card-effect gates `[data-fx-status="off"]` (suppresses status animation) and `[data-fx-glow="off"]` (suppresses `.card-glow-fx`/`.card-ring-fx`), driven by `hooks/useCardFxAttributes.ts`; contract `src/__tests__/fx-gate-css.test.ts`. See change: add-focus-mode-and-card-block-toggles. `.question-pill.arrive` one-shot 600 ms ring (`--status-needs-you`), off under reduced motion. See change: add-pending-question-stack. Plugin `@source` lines moved to generated `generated/plugin-sources.css`; `lib/__tests__/tailwind-source-coverage.test.ts` fails naming any package whose client dir or claim `module` dir is uncovered, and when the committed file differs from a fresh generation. See changes: retro-ux-plugin-settings-wave-2, decouple-plugins-from-core. |
| `main.tsx` | React app bootstrap + UI primitive registry registration. Creates root, wraps `App` in `UiPrimitiveProvider`, `Router`, `ThemeProvider`, `I18nProvider`, `MobileProvider`. Builds `primitiveRegistry` via `createUiPrimitiveRegistry` + `registerUiPrimitive` for every `UI_PRIMITIVE_KEYS.*` (`agentCard`, `markdownContent`, `confirmDialog`, `dialog`, `dialogPortal`, `searchableSelectDialog`, `zoomControls`, `formatTokens`, `formatDuration`, `actionList`, `statusPill`, `modelSelector`, `thinkingLevelSelector`, `popover`, `toolCallStep`, `thinkingBlock`, `logBlock`). Adapts `Confirm`→`ConfirmDialogPrimitive`, `ToolCallStep`→`ToolCallStepPrimitive` (minimal `ToolContext`), `ThinkingBlock`→`ThinkingBlockPrimitive`. Registers `/sw.js` service worker. Imports `katex.min.css`. Calls `installDeviceAuthFetch()` at startup (paired-device bearer on every same-origin API request). Renders `<PairLanding/>` instead of `<App/>` when `location.pathname === "/pair"` (phone-camera pairing landing, pre-auth). See change: make-pairing-qr-camera-scannable. `ui:model-selector` + `ui:thinking-level-selector` register the shell-bound wrappers from `lib/plugins/shell-primitives.tsx`. See change: upgrade-model-selector-primitives. Calls `installGrantChannelFetch()` right after `installDeviceAuthFetch()` (echo in-memory `X-Pi-Grant-Channel` on same-origin `/api/*`). See change: add-access-grant-dialog (tasks 7.1) Installs the three fetch wrappers via `installFetchWrappers()` (lib/api/install-fetch-wrappers.ts; api-base rewrite outermost so un-prefixed `/api/` follows the selected remote before the credential wrappers see it). See change: fix-remote-relative-api-fetch. Registers `UI_PRIMITIVE_KEYS.oauthFlow` → `OAuthFlowView`. See change: expose-plugin-credential-and-oauth-seams. `/pair` renders `PairLanding` via `React.lazy` + `Suspense` (device-only landing kept off the entry chunk, `mdi-chunk-size` cap). See change: add-pairing-approval-dialog. Drops global KaTeX CSS import; awaits `loadCatalog(detectInitialLanguage())` before `createRoot().render` (no English flash). See change: shrink-client-entry-lazy-islands. Registry now built by `createHostPrimitiveRegistry()` (`lib/plugins/host-primitives.tsx`) — no inline `registerUiPrimitive` list; adds `ui:chat-view` + `ui:elapsed-badge`. See change: decouple-plugins-from-core. First statement after the rejection reporter: `installTrustedTypes()`; mounts through `bootClient` (policies + violation reporter + service worker via pi-worker-url before render). See change: harden-client-sinks. Startup: `migrateLegacyDeviceBearer()` discards the legacy global bearer slot; `startDeviceBearerRotation()` rotates the saved cross-origin server's browser-held bearer. See change: harden-auth-credentials. |