From 2e01bc1fab72415cd6ff4d239389579388f18789 Mon Sep 17 00:00:00 2001 From: Jay1 Date: Sun, 24 May 2026 19:30:57 -0400 Subject: [PATCH 1/4] Import upstream quality fixes - Avoid duplicate checkpoint existence checks - Add Windows shell coverage for provider updates - Test idempotent theme DOM application --- .../Layers/CheckpointDiffQuery.test.ts | 2 +- .../Layers/CheckpointDiffQuery.ts | 12 +- .../provider/Layers/ProviderHealth.test.ts | 110 +++++++++++++++++- apps/web/src/hooks/useTheme.test.ts | 56 +++++++++ apps/web/src/hooks/useTheme.ts | 2 +- .../2026-05-24-upstream-quality-imports.md | 52 +++++++++ ...6-05-24-upstream-quality-imports-design.md | 104 +++++++++++++++++ 7 files changed, 329 insertions(+), 9 deletions(-) create mode 100644 apps/web/src/hooks/useTheme.test.ts create mode 100644 docs/superpowers/plans/2026-05-24-upstream-quality-imports.md create mode 100644 docs/superpowers/specs/2026-05-24-upstream-quality-imports-design.md diff --git a/apps/server/src/checkpointing/Layers/CheckpointDiffQuery.test.ts b/apps/server/src/checkpointing/Layers/CheckpointDiffQuery.test.ts index c1580d156..f67fa664f 100644 --- a/apps/server/src/checkpointing/Layers/CheckpointDiffQuery.test.ts +++ b/apps/server/src/checkpointing/Layers/CheckpointDiffQuery.test.ts @@ -111,7 +111,7 @@ describe("CheckpointDiffQueryLive", () => { ); const expectedFromRef = checkpointRefForThreadTurnStart(threadId, TurnId.makeUnsafe("turn-1")); - expect(hasCheckpointRefCalls).toEqual([expectedFromRef, expectedFromRef, toCheckpointRef]); + expect(hasCheckpointRefCalls).toEqual([expectedFromRef, toCheckpointRef]); expect(diffCheckpointsCalls).toEqual([ { cwd: "/tmp/workspace", diff --git a/apps/server/src/checkpointing/Layers/CheckpointDiffQuery.ts b/apps/server/src/checkpointing/Layers/CheckpointDiffQuery.ts index f048dc97d..b5d9a630b 100644 --- a/apps/server/src/checkpointing/Layers/CheckpointDiffQuery.ts +++ b/apps/server/src/checkpointing/Layers/CheckpointDiffQuery.ts @@ -132,6 +132,7 @@ const make = Effect.gen(function* () { detail: `Checkpoint diff is not available yet for turn ${input.toTurnCount}.`, }); } + let fromCheckpointExists = false; if (input.toTurnCount === input.fromTurnCount + 1) { const turnStartCheckpointRef = checkpointRefForThreadTurnStart( input.threadId, @@ -143,15 +144,18 @@ const make = Effect.gen(function* () { }); if (turnStartExists) { fromCheckpointRef = turnStartCheckpointRef; + fromCheckpointExists = true; } } const [fromExists, toExists] = yield* Effect.all( [ - checkpointStore.hasCheckpointRef({ - cwd: workspaceCwd, - checkpointRef: fromCheckpointRef, - }), + fromCheckpointExists + ? Effect.succeed(true) + : checkpointStore.hasCheckpointRef({ + cwd: workspaceCwd, + checkpointRef: fromCheckpointRef, + }), checkpointStore.hasCheckpointRef({ cwd: workspaceCwd, checkpointRef: toCheckpointRef, diff --git a/apps/server/src/provider/Layers/ProviderHealth.test.ts b/apps/server/src/provider/Layers/ProviderHealth.test.ts index 4436d1f93..a3798131f 100644 --- a/apps/server/src/provider/Layers/ProviderHealth.test.ts +++ b/apps/server/src/provider/Layers/ProviderHealth.test.ts @@ -3,7 +3,7 @@ import { describe, it, assert } from "@effect/vitest"; import { DEFAULT_SERVER_SETTINGS } from "@jcode/contracts"; import { Effect, FileSystem, Layer, Path, Sink, Stream } from "effect"; import * as PlatformError from "effect/PlatformError"; -import { ChildProcessSpawner } from "effect/unstable/process"; +import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"; import { checkClaudeProviderStatus, @@ -19,8 +19,12 @@ import { makeCheckOpenCodeProviderStatus, parseAuthStatusFromOutput, parseClaudeAuthStatusFromOutput, + ProviderHealthLive, readCodexConfigModelProvider, } from "./ProviderHealth"; +import { ServerConfig } from "../../config"; +import { ServerSettingsService } from "../../serverSettings"; +import { ProviderHealth } from "../Services/ProviderHealth"; // ── Test helpers ──────────────────────────────────────────────────── @@ -45,6 +49,7 @@ function mockSpawnerLayer( handler: ( args: ReadonlyArray, command: string, + options: ChildProcess.CommandOptions, ) => { stdout: string; stderr: string; @@ -54,12 +59,36 @@ function mockSpawnerLayer( return Layer.succeed( ChildProcessSpawner.ChildProcessSpawner, ChildProcessSpawner.make((command) => { - const cmd = command as unknown as { command: string; args: ReadonlyArray }; - return Effect.succeed(mockHandle(handler(cmd.args, cmd.command))); + const cmd = command as unknown as { + command: string; + args: ReadonlyArray; + options: ChildProcess.CommandOptions; + }; + return Effect.succeed(mockHandle(handler(cmd.args, cmd.command, cmd.options))); }), ); } +function withProcessPlatform( + platform: NodeJS.Platform, + effect: Effect.Effect, +): Effect.Effect { + return Effect.acquireUseRelease( + Effect.sync(() => { + const descriptor = Object.getOwnPropertyDescriptor(process, "platform"); + Object.defineProperty(process, "platform", { value: platform }); + return descriptor; + }), + () => effect, + (descriptor) => + Effect.sync(() => { + if (descriptor) { + Object.defineProperty(process, "platform", descriptor); + } + }), + ); +} + function failingSpawnerLayer(description: string) { return Layer.succeed( ChildProcessSpawner.ChildProcessSpawner, @@ -858,6 +887,81 @@ it.layer(NodeServices.layer)("ProviderHealth", (it) => { ); }); + // ── provider update command tests ────────────────────────────────── + + describe("updateProvider", () => { + it.effect("runs provider update commands through a shell on Windows", () => { + const calls: Array<{ + args: ReadonlyArray; + command: string; + shell: ChildProcess.CommandOptions["shell"]; + }> = []; + + return withProcessPlatform( + "win32", + Effect.gen(function* () { + const providerHealth = yield* ProviderHealth; + const result = yield* providerHealth.updateProvider({ provider: "cursor" }); + + assert.strictEqual(result.providers.length, 0); + assert.deepStrictEqual(calls, [ + { + args: ["update"], + command: "agent", + shell: true, + }, + ]); + }), + ).pipe( + Effect.provide(ProviderHealthLive), + Effect.provide( + mockSpawnerLayer((args, command, options) => { + calls.push({ args, command, shell: options.shell }); + return { stdout: "", stderr: "update failed", code: 1 }; + }), + ), + Effect.provide(ServerSettingsService.layerTest()), + Effect.provide(ServerConfig.layerTest(process.cwd(), { prefix: "jcode-provider-health-" })), + ); + }); + }); + + describe("updateProvider", () => { + it.effect("runs provider update commands through a shell on Windows", () => { + const calls: Array<{ + command: string; + args: ReadonlyArray; + shell: ChildProcess.CommandOptions["shell"]; + }> = []; + + return withProcessPlatform( + "win32", + Effect.gen(function* () { + const providerHealth = yield* ProviderHealth; + yield* providerHealth.updateProvider({ provider: "cursor" }); + }).pipe( + Effect.provide(ProviderHealthLive), + Effect.provide(ServerSettingsService.layerTest()), + Effect.provide( + ServerConfig.layerTest(process.cwd(), { prefix: "jcode-provider-health-" }), + ), + Effect.provide( + mockSpawnerLayer((args, command, options) => { + calls.push({ command, args, shell: options.shell }); + return { stdout: "", stderr: "update failed\n", code: 1 }; + }), + ), + ), + ).pipe( + Effect.tap(() => + Effect.sync(() => { + assert.deepStrictEqual(calls, [{ command: "agent", args: ["update"], shell: true }]); + }), + ), + ); + }); + }); + // ── parseClaudeAuthStatusFromOutput pure tests ──────────────────── describe("parseClaudeAuthStatusFromOutput", () => { diff --git a/apps/web/src/hooks/useTheme.test.ts b/apps/web/src/hooks/useTheme.test.ts new file mode 100644 index 000000000..83c2b406d --- /dev/null +++ b/apps/web/src/hooks/useTheme.test.ts @@ -0,0 +1,56 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; + +import { DEFAULT_THEME_STATE } from "../theme/theme.logic"; + +function installThemeDom() { + const classList = { + add: vi.fn(), + remove: vi.fn(), + toggle: vi.fn(), + }; + const style = { + removeProperty: vi.fn(), + setProperty: vi.fn(), + }; + const root = { + classList, + offsetHeight: 0, + setAttribute: vi.fn(), + style, + }; + + vi.stubGlobal("document", { documentElement: root }); + vi.stubGlobal("localStorage", { + getItem: vi.fn(() => null), + setItem: vi.fn(), + }); + vi.stubGlobal("window", { + matchMedia: vi.fn(() => ({ matches: false })), + }); + + return { classList, root, style }; +} + +afterEach(() => { + vi.resetModules(); + vi.unstubAllGlobals(); +}); + +describe("applyThemeState", () => { + it("does not rewrite DOM attributes or variables for identical theme inputs", async () => { + const dom = installThemeDom(); + const { applyThemeState } = await import("./useTheme"); + + const initialAttributeWrites = dom.root.setAttribute.mock.calls.length; + const initialClassToggles = dom.classList.toggle.mock.calls.length; + const initialVariableWrites = dom.style.setProperty.mock.calls.length; + const initialVariableRemovals = dom.style.removeProperty.mock.calls.length; + + applyThemeState(DEFAULT_THEME_STATE); + + expect(dom.root.setAttribute).toHaveBeenCalledTimes(initialAttributeWrites); + expect(dom.classList.toggle).toHaveBeenCalledTimes(initialClassToggles); + expect(dom.style.setProperty).toHaveBeenCalledTimes(initialVariableWrites); + expect(dom.style.removeProperty).toHaveBeenCalledTimes(initialVariableRemovals); + }); +}); diff --git a/apps/web/src/hooks/useTheme.ts b/apps/web/src/hooks/useTheme.ts index b861264c1..275ed1309 100644 --- a/apps/web/src/hooks/useTheme.ts +++ b/apps/web/src/hooks/useTheme.ts @@ -139,7 +139,7 @@ function subscribe(listener: () => void): () => void { // ─── DOM projection ─────────────────────────────────────────────────────── -function applyThemeState(state: ThemeState, suppressTransitions = false) { +export function applyThemeState(state: ThemeState, suppressTransitions = false) { if (typeof document === "undefined" || typeof window === "undefined") { return; } diff --git a/docs/superpowers/plans/2026-05-24-upstream-quality-imports.md b/docs/superpowers/plans/2026-05-24-upstream-quality-imports.md new file mode 100644 index 000000000..cad99e355 --- /dev/null +++ b/docs/superpowers/plans/2026-05-24-upstream-quality-imports.md @@ -0,0 +1,52 @@ +# Upstream Quality Imports Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Import three high-value upstream ideas into JCode with local tests and minimal, idiomatic adaptations. + +## File Structure + +- `docs/superpowers/specs/2026-05-24-upstream-quality-imports-design.md`: approved design for the import tranche. +- `docs/superpowers/plans/2026-05-24-upstream-quality-imports.md`: this implementation plan. +- `apps/web/src/hooks/useTheme.ts`: theme mode resolution and DOM synchronization seam. +- `apps/web/src/hooks/useTheme.test.ts` or existing theme hook/runtime test file: focused tests for repeated theme sync no-op behavior. +- `apps/server/src/provider/Layers/ProviderHealth.ts`: provider update command execution seam. +- `apps/server/src/provider/Layers/ProviderHealth.test.ts`: focused tests that update commands run through a shell on Windows. +- `apps/server/src/checkpointing/Layers/CheckpointDiffQuery.ts`: checkpoint diff query seam for narrow hot-path improvement. +- `apps/server/src/checkpointing/Layers/CheckpointDiffQuery.test.ts`: focused tests for scoped diff reads and stable checkpoint lookup behavior. +- `apps/web/src/components/DiffPanel.tsx`: only touch if server-side diff seam cannot fully address the hot path. + +## Tasks + +- [ ] Create or update a focused theme sync test that fails because repeated identical theme application rewrites DOM state. +- [ ] Run the focused theme test and confirm the failure is the expected repeated-write assertion. +- [ ] Implement the smallest theme sync no-op cache in `useTheme.ts` or a helper extracted from it. +- [ ] Run the focused theme test and confirm it passes. +- [ ] Create or update a focused provider update test for Windows shell execution. +- [ ] Run the focused provider test and confirm the expected shell assertion. +- [ ] Implement the provider update Windows-shell adaptation in `ProviderHealth.ts` if the test shows it is missing, without changing update locking or result reporting. +- [ ] Run the focused provider test and confirm it passes. +- [ ] Inspect `CheckpointDiffQuery` current tests and choose one narrow DPCode #129 hot-path behavior that is locally testable. +- [ ] Create or update a focused checkpoint diff test that fails for the chosen hot-path behavior. +- [ ] Run the focused checkpoint diff test and confirm the expected failure. +- [ ] Implement the smallest checkpoint/diff adaptation needed to pass the test. +- [ ] Run the focused checkpoint diff test and confirm it passes. +- [ ] Run focused workspace tests for all touched areas. +- [ ] Run `bun run --cwd apps/web typecheck` and `bun run --cwd apps/server typecheck`. +- [ ] Run `bun run fmt:check -- `. +- [ ] Run LSP diagnostics for touched TypeScript files. +- [ ] Run Aikido full scan on modified first-party code. + +## Acceptance Criteria + +- [ ] Reapplying the same theme inputs is a no-op while real theme changes still apply. +- [ ] Provider update commands run through a shell on Windows. +- [ ] One narrow diff/checkpoint hot-path improvement is implemented and tested. +- [ ] No upstream branch is merged wholesale or copied 1:1 without local adaptation. +- [ ] All focused verification and security checks pass or are reported with exact evidence. + +## Notes + +- Keep the slices independently revertible. +- Stop and defer the DPCode diff slice if it expands beyond a narrow tested seam. +- Prefer strengthening existing JCode tests when an upstream idea is already implemented. diff --git a/docs/superpowers/specs/2026-05-24-upstream-quality-imports-design.md b/docs/superpowers/specs/2026-05-24-upstream-quality-imports-design.md new file mode 100644 index 000000000..f7672d1d8 --- /dev/null +++ b/docs/superpowers/specs/2026-05-24-upstream-quality-imports-design.md @@ -0,0 +1,104 @@ +# Upstream Quality Imports Design + +| Field | Value | +| --------------- | ---------------------------------------------------------------------------------------------- | +| Status | Draft | +| Type | Design specification | +| Owner | Engineering | +| Audience | Maintainers and automation agents | +| Canonical path | `docs/superpowers/specs/2026-05-24-upstream-quality-imports-design.md` | +| Last reviewed | 2026-05-24 | +| Review cadence | Event-driven; review when DPCode/T3Code import candidates or JCode quality priorities change | +| Source of truth | `docs/jcode-operating-model.md`, `.jcode/upstream-watch/state.json`, and fetched upstream refs | + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:writing-plans before implementation. Treat DPCode and T3Code as source material; do not merge or cherry-pick upstream wholesale. + +**Goal:** Import the best recent DPCode and T3Code ideas into JCode with high quality, adapting the ideas to JCode seams instead of copying upstream 1:1. + +## Context + +JCode is synced to `origin/main` after PR #3 and has local upstream watch state recorded for DPCode and T3Code deltas. Recent upstream discovery highlighted: + +- DPCode `v0.0.49` and PR #129: diff loading, startup hot paths, projection snapshot query, checkpoint diff query, runtime ingestion, and thread retention improvements. +- T3Code #2760: provider-scoped reasoning/model option preservation. +- T3Code #2779: idempotent theme DOM synchronization. +- T3Code #2781: provider update commands running through a shell on Windows. +- T3Code #2794/#2792/#2780/#2791: render-health, settings navigation, shell snapshot, and Effect idiom work. + +Direct inspection found that JCode already has substantial provider-scoped model option preservation tests and behavior in `apps/web/src/composerDraftStore.ts` and `apps/web/src/composerDraftStore.test.ts`, so T3Code #2760 is not the best first import. + +## Recommended Import Tranche + +| Priority | Source | Idea | JCode seam | Why now | +| -------- | ------------ | ------------------------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------ | +| 1 | T3Code #2779 | Idempotent theme DOM synchronization | `apps/web/src/hooks/useTheme.ts` or adjacent theme runtime helper | Low risk, removes repeated startup/browser-resume work | +| 2 | T3Code #2781 | Provider update commands use Windows shell | `apps/server/src/provider/Layers/ProviderHealth.ts` | Robustness improvement for Windows updater execution | +| 3 | DPCode #129 | Targeted diff/checkpoint hot-path reduction | `CheckpointDiffQuery`, `ProjectionSnapshotQuery`, `DiffPanel`, retention seams | High value, but import only a narrow tested subset | + +## Explicit Non-Goals + +- Do not merge upstream branches into `main`. +- Do not cherry-pick complete DPCode/T3Code commits without review. +- Do not import provider surface area such as Grok or Hermes in this tranche. +- Do not add React Scan recordings/artifacts as product code. +- Do not rework the whole checkpoint/projection architecture in one change. + +## Design + +### Slice 1: Idempotent Theme Sync + +Add or extend focused tests around theme application so repeated calls with the same `{theme, systemDark}` do not rewrite DOM attributes, color-scheme style, or local storage. Keep the public hook/interface unchanged. + +Expected behavior: + +- Initial theme application still updates the DOM. +- Changing explicit theme or system dark state still updates the DOM. +- Reapplying the same effective inputs is a no-op. + +### Slice 2: Provider Update Windows Shell + +Add a server/provider test that runs a provider update command while `process.platform` is `win32`. Then adapt `ProviderHealth` only if needed so update commands execute through a shell on Windows without changing non-Windows command execution. + +Expected behavior: + +- Provider update commands use `shell: true` on Windows. +- Provider update commands preserve existing non-Windows shell behavior. +- Existing provider update locking and result reporting stays unchanged. +- Failures continue to surface through existing provider update messages. + +### Slice 3: Narrow Diff Hot-Path Import + +Use DPCode #129 as source material, but import only the smallest local improvement that can be proven with tests. Candidate adaptations: + +- Avoid broad checkpoint/diff reads when a selected turn or conversation range is already known. +- Reuse projection snapshot query results through a deeper server-side query seam. +- Keep `DiffPanel` query inputs stable so UI refetches are limited to actual range changes. + +Expected behavior: + +- Existing diff results remain identical for selected-turn and whole-conversation views. +- Query/cache inputs are stable and scoped. +- New tests cover the targeted hot path before implementation. + +## Quality Bar + +- Every production change starts with a failing focused test. +- Prefer one small local adaptation per source idea. +- Keep interfaces stable unless the test proves an interface change is needed. +- Preserve JCode naming, contracts, and publishable defaults. +- Run focused tests/typechecks, LSP diagnostics, formatting checks, and Aikido scan for modified first-party code. + +## Acceptance Criteria + +- [ ] Theme sync repeated-input no-op behavior is tested and implemented. +- [ ] Provider update commands run with resolved provider environment and are tested. +- [ ] One narrow DPCode #129 diff/checkpoint hot-path improvement is tested and implemented. +- [ ] No upstream branch is merged wholesale. +- [ ] No unrelated provider/product surface area is introduced. +- [ ] Verification evidence is captured before completion. + +## Open Implementation Notes + +- If Slice 3 proves too broad during implementation, stop after Slices 1 and 2 and record DPCode #129 as a separate follow-up. +- If a candidate is already implemented in JCode, add or strengthen tests instead of duplicating upstream structure. +- Keep each slice independently revertible. From dc5abb1c72eef0c08db66299e89eb6e2b8e5d1b9 Mon Sep 17 00:00:00 2001 From: Jay1 Date: Sun, 24 May 2026 19:57:38 -0400 Subject: [PATCH 2/4] Document upstream import and Catppuccin depth plans - Clarify upstream quality import verification and source references - Add Catppuccin theme depth design and implementation plan - Remove duplicate Windows provider update test block --- .../provider/Layers/ProviderHealth.test.ts | 38 +------- .../2026-05-24-catppuccin-theme-depth.md | 57 ++++++++++++ .../2026-05-24-upstream-quality-imports.md | 15 ++-- ...026-05-24-catppuccin-theme-depth-design.md | 87 +++++++++++++++++++ ...6-05-24-upstream-quality-imports-design.md | 34 ++++---- 5 files changed, 173 insertions(+), 58 deletions(-) create mode 100644 docs/superpowers/plans/2026-05-24-catppuccin-theme-depth.md create mode 100644 docs/superpowers/specs/2026-05-24-catppuccin-theme-depth-design.md diff --git a/apps/server/src/provider/Layers/ProviderHealth.test.ts b/apps/server/src/provider/Layers/ProviderHealth.test.ts index a3798131f..bd22c266d 100644 --- a/apps/server/src/provider/Layers/ProviderHealth.test.ts +++ b/apps/server/src/provider/Layers/ProviderHealth.test.ts @@ -892,8 +892,8 @@ it.layer(NodeServices.layer)("ProviderHealth", (it) => { describe("updateProvider", () => { it.effect("runs provider update commands through a shell on Windows", () => { const calls: Array<{ - args: ReadonlyArray; command: string; + args: ReadonlyArray; shell: ChildProcess.CommandOptions["shell"]; }> = []; @@ -906,39 +906,11 @@ it.layer(NodeServices.layer)("ProviderHealth", (it) => { assert.strictEqual(result.providers.length, 0); assert.deepStrictEqual(calls, [ { - args: ["update"], command: "agent", + args: ["update"], shell: true, }, ]); - }), - ).pipe( - Effect.provide(ProviderHealthLive), - Effect.provide( - mockSpawnerLayer((args, command, options) => { - calls.push({ args, command, shell: options.shell }); - return { stdout: "", stderr: "update failed", code: 1 }; - }), - ), - Effect.provide(ServerSettingsService.layerTest()), - Effect.provide(ServerConfig.layerTest(process.cwd(), { prefix: "jcode-provider-health-" })), - ); - }); - }); - - describe("updateProvider", () => { - it.effect("runs provider update commands through a shell on Windows", () => { - const calls: Array<{ - command: string; - args: ReadonlyArray; - shell: ChildProcess.CommandOptions["shell"]; - }> = []; - - return withProcessPlatform( - "win32", - Effect.gen(function* () { - const providerHealth = yield* ProviderHealth; - yield* providerHealth.updateProvider({ provider: "cursor" }); }).pipe( Effect.provide(ProviderHealthLive), Effect.provide(ServerSettingsService.layerTest()), @@ -952,12 +924,6 @@ it.layer(NodeServices.layer)("ProviderHealth", (it) => { }), ), ), - ).pipe( - Effect.tap(() => - Effect.sync(() => { - assert.deepStrictEqual(calls, [{ command: "agent", args: ["update"], shell: true }]); - }), - ), ); }); }); diff --git a/docs/superpowers/plans/2026-05-24-catppuccin-theme-depth.md b/docs/superpowers/plans/2026-05-24-catppuccin-theme-depth.md new file mode 100644 index 000000000..7d554d1aa --- /dev/null +++ b/docs/superpowers/plans/2026-05-24-catppuccin-theme-depth.md @@ -0,0 +1,57 @@ +# Catppuccin Theme Depth Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Add a semantic app-depth token layer, tune Catppuccin to official palette roles, and apply the tokens to the high-impact app surfaces visible in the main chat UI. + +## File Map + +- `apps/web/src/theme/theme.logic.ts`: Add app-depth token derivation and Catppuccin-specific palette mapping. +- `apps/web/src/theme/theme.logic.test.ts`: Add focused tests for Catppuccin app-depth tokens and fallback token availability. +- `apps/web/src/theme/theme.seed.generated.ts`: Update Catppuccin seeds to official Latte/Mocha values when current seed is incomplete or less precise. +- `apps/web/src/index.css`: Add safe fallback values for app-depth variables and bridge shared global tokens. +- `apps/web/src/components/ThemePackEditor.tsx`: Add compact theme-depth preview in Settings. +- `apps/web/src/routes/_chat.tsx`: Use app sidebar surface token if needed by layout shell. +- `apps/web/src/components/Sidebar.tsx`: Apply sidebar/thread selected/hover depth tokens. +- `apps/web/src/components/chat/ChatHeader.tsx`: Apply topbar surface and border depth tokens. +- `apps/web/src/components/chat/MessagesTimeline.tsx`: Apply changed-files card and transcript summary surface tokens. +- `apps/web/src/components/chat/ChangedFilesTree.tsx`: Apply row hover/selected and separator tokens for changed files. +- `apps/web/src/components/ui/toast.tsx`: Apply status surface tokens for toast variants. +- `apps/web/src/components/ChatView.tsx` and/or composer components: Apply composer surface/focus depth tokens where the composer shell is defined. + +## Task 1: Add Theme Token Tests + +- [ ] Add a failing test in `theme.logic.test.ts` for Catppuccin dark app-depth tokens. Assert specific official Mocha-derived values for canvas/sidebar/card/hover/selected/focus/error/diff tokens. +- [ ] Add a failing test for a non-Catppuccin theme ensuring every app-depth token exists and is non-empty. +- [ ] Run `snip bun run --cwd apps/web test src/theme/theme.logic.test.ts` and confirm failures match missing app-depth tokens. + +## Task 2: Implement Theme Token Derivation + +- [ ] Add app-depth token names in `theme.logic.ts` as CSS variables returned from `buildThemeCssVariables`. +- [ ] Add a Catppuccin palette helper for Latte/Mocha role values scoped to theme derivation. +- [ ] Add fallback derivation for non-Catppuccin themes using existing computed theme values and color mixing. +- [ ] Update Catppuccin seeds in `theme.seed.generated.ts` only where needed to match official Latte/Mocha base/accent/text/semantic values. +- [ ] Run `snip bun run --cwd apps/web test src/theme/theme.logic.test.ts` and confirm tests pass. + +## Task 3: Add Settings Preview + +- [ ] Add a compact depth preview component in `ThemePackEditor.tsx` using derived CSS variables from the active card context. +- [ ] Keep existing editable fields unchanged. +- [ ] Verify Settings still renders both light/dark theme cards without adding new required persisted schema fields. + +## Task 4: Apply Tokens To Visible Surfaces + +- [ ] Update sidebar shell/thread row classes to use `--app-surface-sidebar`, `--app-state-hover`, `--app-state-selected`, and `--app-state-selected-border`. +- [ ] Update chat header/topbar classes to use `--app-surface-topbar` and stronger app border tokens. +- [ ] Update changed-files card/header/rows to use `--app-diff-card-bg`, `--app-diff-card-header-bg`, and state tokens. +- [ ] Update toast styling to use status surface tokens per variant. +- [ ] Update composer shell/focus surface to use `--app-surface-composer` and `--app-state-focus`. + +## Task 5: Verification And Manual QA + +- [ ] Run focused tests: `snip bun run --cwd apps/web test src/theme/theme.logic.test.ts`. +- [ ] Run `snip bun run --cwd apps/web typecheck`. +- [ ] Run `snip bun run fmt:check -- `. +- [ ] Run `lsp_diagnostics` on modified TS/TSX files. +- [ ] Run Aikido full scan on modified first-party code. +- [ ] Use Playwright/browser QA to load the app, switch/apply Catppuccin dark if needed, capture screenshot, and verify actual visible surfaces: sidebar, selected thread, topbar, transcript panel/card, toast/card, changed-files list, and composer have distinct restrained layers. diff --git a/docs/superpowers/plans/2026-05-24-upstream-quality-imports.md b/docs/superpowers/plans/2026-05-24-upstream-quality-imports.md index cad99e355..b52863ff0 100644 --- a/docs/superpowers/plans/2026-05-24-upstream-quality-imports.md +++ b/docs/superpowers/plans/2026-05-24-upstream-quality-imports.md @@ -1,12 +1,17 @@ # Upstream Quality Imports Implementation Plan +| Field | Value | +| --------------- | -------------------------------------------------------------------------------------------------------------------------------- | +| Canonical path | `docs/superpowers/plans/2026-05-24-upstream-quality-imports.md` | +| Source of truth | [`docs/superpowers/specs/2026-05-24-upstream-quality-imports-design.md`](../specs/2026-05-24-upstream-quality-imports-design.md) | + > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Import three high-value upstream ideas into JCode with local tests and minimal, idiomatic adaptations. ## File Structure -- `docs/superpowers/specs/2026-05-24-upstream-quality-imports-design.md`: approved design for the import tranche. +- [`docs/superpowers/specs/2026-05-24-upstream-quality-imports-design.md`](../specs/2026-05-24-upstream-quality-imports-design.md): approved design for the import tranche. - `docs/superpowers/plans/2026-05-24-upstream-quality-imports.md`: this implementation plan. - `apps/web/src/hooks/useTheme.ts`: theme mode resolution and DOM synchronization seam. - `apps/web/src/hooks/useTheme.test.ts` or existing theme hook/runtime test file: focused tests for repeated theme sync no-op behavior. @@ -32,10 +37,10 @@ - [ ] Implement the smallest checkpoint/diff adaptation needed to pass the test. - [ ] Run the focused checkpoint diff test and confirm it passes. - [ ] Run focused workspace tests for all touched areas. -- [ ] Run `bun run --cwd apps/web typecheck` and `bun run --cwd apps/server typecheck`. -- [ ] Run `bun run fmt:check -- `. -- [ ] Run LSP diagnostics for touched TypeScript files. -- [ ] Run Aikido full scan on modified first-party code. +- [ ] Run the existing workspace scripts: `bun run --cwd apps/web typecheck` (`apps/web/package.json`) and `bun run --cwd apps/server typecheck` (`apps/server/package.json`). +- [ ] Run the root formatter check with touched files passed through to `oxfmt --check`: `bun run fmt:check -- `. +- [ ] Run LSP diagnostics for touched TypeScript files through the editor/OpenCode LSP diagnostics tool; this is a manual IDE-agent verification step, not a repo script. +- [ ] Run the external Aikido MCP `aikido_full_scan` on modified first-party code; the repo does not commit Aikido configuration. ## Acceptance Criteria diff --git a/docs/superpowers/specs/2026-05-24-catppuccin-theme-depth-design.md b/docs/superpowers/specs/2026-05-24-catppuccin-theme-depth-design.md new file mode 100644 index 000000000..518940bfc --- /dev/null +++ b/docs/superpowers/specs/2026-05-24-catppuccin-theme-depth-design.md @@ -0,0 +1,87 @@ +# Catppuccin Theme Depth Design + +| Field | Value | +| --------------- | ----------------------------------------------------------------------------------------------------------- | +| Status | Approved | +| Type | Design specification | +| Owner | Engineering | +| Audience | Maintainers and automation agents | +| Canonical path | `docs/superpowers/specs/2026-05-24-catppuccin-theme-depth-design.md` | +| Last reviewed | 2026-05-24 | +| Review cadence | Event-driven; review when adding richer theme levers or porting depth to another bundled community theme | +| Source of truth | Catppuccin palette/style guide, JCode theme logic, screenshot review, and existing web component conventions | + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:writing-plans before implementation. For implementation, use frontend-design, test-driven-development, webapp-testing, verification-before-completion, and aikido-security. + +**Goal:** Make Catppuccin feel like a high-quality client-facing app theme by adding restrained semantic depth tokens and applying them to the visible shell surfaces that currently collapse into one flat color. + +## Context + +The current theme model is intentionally compact: a theme has `surface`, `ink`, `accent`, `contrast`, fonts, translucency, and three semantic colors. `apps/web/src/theme/theme.logic.ts` derives most UI tokens from those few fields. That keeps Settings simple, but it also means the sidebar, main transcript canvas, top bar, cards, toast, changed-files list, and composer can share nearly identical dark tones. + +Catppuccin has enough official palette structure to do better without making the UI noisy. Its style guide separates background pane, secondary panes, surface elements, overlays, text, subtext, and accents. The VS Code port also shows a useful pattern: app chrome is mostly neutral surface layering, with accent colors reserved for focus, active state, git/diff/status, and selected affordances. + +## Problems To Solve + +- The screenshot shows too many app surfaces at nearly the same luminance. +- Active thread, selected tabs, changed-files rows, toast, top bar, and composer need clearer hierarchy. +- Settings exposes only shallow levers, so richer theme quality has no stable app token model to build on. +- Any improvement must stay restrained: no rainbow UI, no per-component hardcoded palette spread, and no one-off Catppuccin-only CSS hacks. + +## Design + +Add a semantic app-depth token layer derived from the existing theme pack. Catppuccin gets the first hand-tuned mapping using Latte and Mocha palette roles. Other themes keep compatible derived fallbacks from existing `surface`, `ink`, `accent`, `contrast`, and semantic colors. + +### Token Groups + +- Shell surfaces: `--app-surface-canvas`, `--app-surface-sidebar`, `--app-surface-topbar`, `--app-surface-panel`, `--app-surface-card`, `--app-surface-card-header`, `--app-surface-composer`. +- Interaction states: `--app-state-hover`, `--app-state-selected`, `--app-state-selected-border`, `--app-state-focus`. +- Semantic panels: `--app-status-error-bg`, `--app-status-error-border`, `--app-status-warning-bg`, `--app-diff-card-bg`, `--app-diff-card-header-bg`. +- Accent hints: `--app-accent-soft`, `--app-accent-muted`, `--app-accent-strong`. + +These tokens are app-facing aliases. They should be generated in `theme.logic.ts` and emitted through `useTheme.ts` like existing CSS variables. + +### Catppuccin Mapping + +Use official roles, not arbitrary color choices: + +- Dark Catppuccin should align to Mocha: `crust` for app canvas, `mantle` for sidebar/topbar, `base` for cards/composer, `surface0/1` for hover/selected, `overlay0/1` for borders, `text/subtext` for content, `mauve` for primary accent, `lavender/blue` for focus/information, `green/red/yellow/peach` for diff/status. +- Light Catppuccin should align to Latte: `base` for app canvas, `mantle/crust` for secondary panes where useful, `surface0/1` for cards and hover, `mauve/blue` for active/focus, and same semantic status roles. + +### Surface Wiring + +Apply new tokens to high-impact visible surfaces: + +- Sidebar shell and selected/hover thread rows. +- Top chat header and toolbar buttons. +- Transcript canvas and major assistant summary cards. +- Changed-files card header and rows. +- Toast root and error/warning/success variants. +- Composer container/focus border. +- Settings theme preview/editor so users can see/edit richer distinctions. + +### Settings Levers + +First implementation should not add a large custom theme editor overhaul. It should expose enough evidence in Settings to validate the richer system: + +- Keep existing controls for accent/background/foreground/contrast. +- Add a compact preview strip/card that displays the derived depth ladder for the active pack. +- Avoid adding many new editable fields until Catppuccin proves the token model. + +## Non-Goals + +- No complete redesign of app layout. +- No new theme marketplace/import format. +- No full editor syntax theme rewrite. +- No porting every bundled theme in this first pass. +- No hardcoded component-level Catppuccin checks outside theme derivation. + +## Acceptance Criteria + +- Catppuccin dark and light seeds use official palette values for base surfaces and semantic colors. +- `buildThemeCssVariables` emits app-depth tokens with deterministic values. +- Existing default/non-Catppuccin themes continue to produce valid app-depth tokens. +- Screenshot-visible surfaces have visibly distinct layers in Catppuccin without excessive accent color. +- Settings shows a useful theme depth preview. +- Focused unit tests cover Catppuccin depth tokens and fallback derivation. +- Browser QA captures the app in Catppuccin dark and verifies sidebar, topbar, toast/card/composer surfaces are visually distinct. diff --git a/docs/superpowers/specs/2026-05-24-upstream-quality-imports-design.md b/docs/superpowers/specs/2026-05-24-upstream-quality-imports-design.md index f7672d1d8..1bcc09a06 100644 --- a/docs/superpowers/specs/2026-05-24-upstream-quality-imports-design.md +++ b/docs/superpowers/specs/2026-05-24-upstream-quality-imports-design.md @@ -1,15 +1,15 @@ # Upstream Quality Imports Design -| Field | Value | -| --------------- | ---------------------------------------------------------------------------------------------- | -| Status | Draft | -| Type | Design specification | -| Owner | Engineering | -| Audience | Maintainers and automation agents | -| Canonical path | `docs/superpowers/specs/2026-05-24-upstream-quality-imports-design.md` | -| Last reviewed | 2026-05-24 | -| Review cadence | Event-driven; review when DPCode/T3Code import candidates or JCode quality priorities change | -| Source of truth | `docs/jcode-operating-model.md`, `.jcode/upstream-watch/state.json`, and fetched upstream refs | +| Field | Value | +| --------------- | ------------------------------------------------------------------------------------------------------------------------- | +| Status | Draft | +| Type | Design specification | +| Owner | Engineering | +| Audience | Maintainers and automation agents | +| Canonical path | `docs/superpowers/specs/2026-05-24-upstream-quality-imports-design.md` | +| Last reviewed | 2026-05-24 | +| Review cadence | Event-driven; review when DPCode/T3Code import candidates or JCode quality priorities change | +| Source of truth | `docs/jcode-operating-model.md`, `docs/runbooks/upstream-watch.md`, `scripts/upstream-watch.ts`, and linked upstream refs | > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:writing-plans before implementation. Treat DPCode and T3Code as source material; do not merge or cherry-pick upstream wholesale. @@ -17,13 +17,13 @@ ## Context -JCode is synced to `origin/main` after PR #3 and has local upstream watch state recorded for DPCode and T3Code deltas. Recent upstream discovery highlighted: +JCode is synced to `origin/main` after PR #3. Upstream watch state is local and intentionally ignored under `.jcode/upstream-watch/`; see `docs/runbooks/upstream-watch.md` and `scripts/upstream-watch.ts` for the source repositories and state semantics. Recent upstream discovery highlighted: -- DPCode `v0.0.49` and PR #129: diff loading, startup hot paths, projection snapshot query, checkpoint diff query, runtime ingestion, and thread retention improvements. -- T3Code #2760: provider-scoped reasoning/model option preservation. -- T3Code #2779: idempotent theme DOM synchronization. -- T3Code #2781: provider update commands running through a shell on Windows. -- T3Code #2794/#2792/#2780/#2791: render-health, settings navigation, shell snapshot, and Effect idiom work. +- DPCode [`v0.0.49`](https://github.com/Emanuele-web04/dpcode/releases/tag/v0.0.49) and [PR #129](https://github.com/Emanuele-web04/dpcode/pull/129): diff loading, startup hot paths, projection snapshot query, checkpoint diff query, runtime ingestion, and thread retention improvements. +- T3Code [#2760](https://github.com/pingdotgg/t3code/pull/2760): provider-scoped reasoning/model option preservation. +- T3Code [#2779](https://github.com/pingdotgg/t3code/pull/2779): idempotent theme DOM synchronization. +- T3Code [#2781](https://github.com/pingdotgg/t3code/pull/2781): provider update commands running through a shell on Windows. +- T3Code [#2794](https://github.com/pingdotgg/t3code/pull/2794), [#2792](https://github.com/pingdotgg/t3code/pull/2792), [#2780](https://github.com/pingdotgg/t3code/pull/2780), and [#2791](https://github.com/pingdotgg/t3code/pull/2791): render-health, settings navigation, shell snapshot, and Effect idiom work. Direct inspection found that JCode already has substantial provider-scoped model option preservation tests and behavior in `apps/web/src/composerDraftStore.ts` and `apps/web/src/composerDraftStore.test.ts`, so T3Code #2760 is not the best first import. @@ -91,7 +91,7 @@ Expected behavior: ## Acceptance Criteria - [ ] Theme sync repeated-input no-op behavior is tested and implemented. -- [ ] Provider update commands run with resolved provider environment and are tested. +- [ ] Provider update commands run with the provider-specific environment resolved by `ProviderHealthLive` and are tested. - [ ] One narrow DPCode #129 diff/checkpoint hot-path improvement is tested and implemented. - [ ] No upstream branch is merged wholesale. - [ ] No unrelated provider/product surface area is introduced. From 197f29bb42342a80743f710dc04745210998b263 Mon Sep 17 00:00:00 2001 From: Jay1 Date: Sun, 24 May 2026 20:42:58 -0400 Subject: [PATCH 3/4] Update apps files --- apps/web/src/components/ChatView.tsx | 38 +++--- apps/web/src/components/Sidebar.logic.test.ts | 16 +-- apps/web/src/components/Sidebar.logic.ts | 22 +--- apps/web/src/components/ThemePackEditor.tsx | 51 ++++++++ .../src/components/chat/MessagesTimeline.tsx | 10 +- apps/web/src/components/ui/sidebar.tsx | 2 +- apps/web/src/components/ui/toast.tsx | 18 ++- apps/web/src/index.css | 33 ++++- apps/web/src/routes/_chat.tsx | 4 +- apps/web/src/theme/theme.logic.test.ts | 80 ++++++++++++ apps/web/src/theme/theme.logic.ts | 118 ++++++++++++++++++ 11 files changed, 335 insertions(+), 57 deletions(-) diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index 5980bcba9..90734c281 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -7448,7 +7448,7 @@ export default function ChatView({ key={queuedTurn.id} data-testid="queued-follow-up-row" className={cn( - "chat-composer-surface flex items-center gap-2 border border-b-0 border-[color:var(--color-border)] px-2.5 py-2 text-[12px] shadow-[0_1px_0_rgba(255,255,255,0.03)_inset]", + "chat-composer-surface flex items-center gap-2 border border-b-0 px-2.5 py-2 text-[12px] shadow-[0_1px_0_rgba(255,255,255,0.03)_inset]", queuedTurnIndex === 0 && !taskListAboveComposer ? "rounded-t-2xl" : "rounded-none", @@ -7463,7 +7463,7 @@ export default function ChatView({
{fileChangesExpanded && ( -
+
{checkpointFiles.map((file) => (