diff --git a/apps/desktop/src/backend/DesktopBackendConfiguration.ts b/apps/desktop/src/backend/DesktopBackendConfiguration.ts index 2559b69e6751..7ae3ad6c9129 100644 --- a/apps/desktop/src/backend/DesktopBackendConfiguration.ts +++ b/apps/desktop/src/backend/DesktopBackendConfiguration.ts @@ -607,6 +607,7 @@ export const make = Effect.gen(function* () { const backendExposure = yield* serverExposure.backendConfig; const persistedSettings = yield* settings.get; const shared = yield* sharedInputs; + yield* wslEnvironment.preWarm(persistedSettings.wslDistro); return yield* resolveWslStartConfig({ ...shared, port: backendExposure.port, diff --git a/apps/server/src/provider/Layers/ClaudeProvider.ts b/apps/server/src/provider/Layers/ClaudeProvider.ts index bd5f7ebffc4c..59b7d0464de8 100644 --- a/apps/server/src/provider/Layers/ClaudeProvider.ts +++ b/apps/server/src/provider/Layers/ClaudeProvider.ts @@ -193,6 +193,36 @@ const BUILT_IN_MODELS: ReadonlyArray = [ ], }), }, + { + slug: "claude-sonnet-5", + name: "Claude Sonnet 5", + isCustom: false, + capabilities: createModelCapabilities({ + optionDescriptors: [ + buildSelectOptionDescriptor({ + id: "effort", + label: "Reasoning", + options: [ + { value: "low", label: "Low" }, + { value: "medium", label: "Medium" }, + { value: "high", label: "High", isDefault: true }, + { value: "xhigh", label: "Extra High" }, + { value: "max", label: "Max" }, + { value: "ultrathink", label: "Ultrathink" }, + ], + promptInjectedValues: ["ultrathink"], + }), + buildSelectOptionDescriptor({ + id: "contextWindow", + label: "Context Window", + options: [ + { value: "200k", label: "200k", isDefault: true }, + { value: "1m", label: "1M" }, + ], + }), + ], + }), + }, { slug: "claude-sonnet-4-6", name: "Claude Sonnet 4.6", @@ -322,7 +352,12 @@ export function normalizeClaudeCliEffort( if (effort === "ultracode") { return "xhigh"; } - if (effort === "xhigh" && model !== "claude-fable-5" && model !== "claude-opus-4-8") { + if ( + effort === "xhigh" && + model !== "claude-fable-5" && + model !== "claude-opus-4-8" && + model !== "claude-sonnet-5" + ) { return "max"; } if (effort === "max" && model === "claude-sonnet-4-6") { diff --git a/apps/web/src/components/RightPanelTabs.tsx b/apps/web/src/components/RightPanelTabs.tsx index efdd10af0278..27b7045b7787 100644 --- a/apps/web/src/components/RightPanelTabs.tsx +++ b/apps/web/src/components/RightPanelTabs.tsx @@ -375,6 +375,19 @@ export function RightPanelTabs(props: RightPanelTabsProps) { }, [props], ); + const handleTabMouseDown = useCallback((event: ReactMouseEvent) => { + if (event.button !== 1) return; + event.preventDefault(); + }, []); + const handleTabAuxClick = useCallback( + (event: ReactMouseEvent, surface: RightPanelSurface) => { + if (event.button !== 1) return; + event.preventDefault(); + event.stopPropagation(); + props.onCloseSurface(surface); + }, + [props], + ); useEffect(() => { const activeTab = tabListRef.current?.querySelector("[data-active-tab='true']"); @@ -411,6 +424,8 @@ export function RightPanelTabs(props: RightPanelTabsProps) {
handleTabAuxClick(event, surface)} onContextMenu={(event) => void handleTabContextMenu(event, surface)} className={cn( "group flex h-7 min-w-25 max-w-44 shrink-0 items-center gap-1.5 rounded-md px-2 text-sm", diff --git a/apps/web/src/components/settings/ProviderModelsSection.tsx b/apps/web/src/components/settings/ProviderModelsSection.tsx index 5db713495b92..f1100ab93d29 100644 --- a/apps/web/src/components/settings/ProviderModelsSection.tsx +++ b/apps/web/src/components/settings/ProviderModelsSection.tsx @@ -32,7 +32,7 @@ import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; */ const CUSTOM_MODEL_PLACEHOLDER_BY_KIND: Partial> = { [ProviderDriverKind.make("codex")]: "gpt-6.7-codex-ultra-preview", - [ProviderDriverKind.make("claudeAgent")]: "claude-sonnet-5-0", + [ProviderDriverKind.make("claudeAgent")]: "claude-sonnet-5", [ProviderDriverKind.make("cursor")]: "claude-sonnet-4-6", [ProviderDriverKind.make("opencode")]: "openai/gpt-5", }; diff --git a/docs/upstream-sync/16-cadence-pull-v0.0.29-nightly.md b/docs/upstream-sync/16-cadence-pull-v0.0.29-nightly.md new file mode 100644 index 000000000000..a0d3900b6b62 --- /dev/null +++ b/docs/upstream-sync/16-cadence-pull-v0.0.29-nightly.md @@ -0,0 +1,49 @@ +# 16 — Cadence pull: v0.0.28 → v0.0.29-nightly.20260630.695 + +First steady-state pull after the Phase 1–2 migration. Australian English. + +## Headline + +- **Window:** `2448212367` (v0.0.28, the Phase-2 merge-base) → `upstream/main` + `9d66b104f` (v0.0.29-nightly.20260630.695). **Only 3 upstream commits, 6 files.** +- **Zero conflicts.** `git merge upstream/main` produced a clean recursive merge; + the two files our fork also touched auto-merged on disjoint lines. +- All gates green; live boot smoke test against a DB copy passed. Merge commit + `01521c01d`. + +## The 3 upstream commits + +| Commit | Change | Overlap with fork? | +| ----------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `0615fd7df` | Add middle-click close for right panel tabs (#3161) | `RightPanelTabs.tsx` — our fork added Tasks/Workstream tabs + props at the top of the file; upstream added `onMouseDown`/`onAuxClick` handlers in the function body. Disjoint regions, auto-merged. | +| `51ea084c8` | Warm WSL before preflight in WSL-only backend mode (#3588) | None. `DesktopBackendConfiguration.ts` (+1 line). WSL-only; inert on Linux. | +| `9d66b104f` | Add Claude Sonnet 5 as default Claude model (#3620) | `contracts/src/model.ts` — upstream flipped `CLAUDE_DRIVER_KIND` default `claude-sonnet-4-6 → claude-sonnet-5` and added sonnet-5 aliases; our fork's `PI_DRIVER_KIND`/`PI_DEFAULT_MODEL` additions are on separate lines. Both present in the merged result. Also touches `ClaudeProvider.ts`, `ProviderModelsSection.tsx`, `model.test.ts` (no fork overlap). | + +## What I re-applied / verified + +Nothing to re-home — no fork capability was displaced. Verified the two +auto-merges semantically: the merged `model.ts` keeps upstream's new +`claude-sonnet-5` Claude default **and** our `[PI_DRIVER_KIND]: PI_DEFAULT_MODEL` +entries; `RightPanelTabs.tsx` keeps upstream's middle-click handlers **and** our +Tasks/Workstream tab surface. + +## Gates + +- `vp run typecheck`: pass (0/15; two non-blocking `suggestion` advisories in + upstream's own `apps/desktop` code, pre-existing). +- `pnpm build`: exit 0 (all 5 build targets). +- `vp check`: 0 errors, 15 warnings (pre-existing `react/no-unstable-nested-components` + in `apps/mobile`, unrelated to this pull). +- **Live smoke test:** built `apps/server/dist/bin.mjs` launched on a spare port + (13955) against a _copy_ of `~/.t3/cockpit/userdata/state.sqlite`. Booted clean, + `migrations: []` (no new migrations — consistent with zero DB/schema files in the + window), `GET /` → HTTP 200, workstream-liveness + session-reaper started. The + live cockpit on the default port was never touched. + +## Why this pull was cheap (cadence confirmation) + +This validates the Phase-2 enabling fact in practice: `merge-base` is the real +upstream commit `2448212367`, so `git merge upstream/main` Just Works with a +normal three-way merge — no grafts, no replace-refs. Conflict cost scaled with +_overlap_ (2 fork-touched files of 6), not commit count, exactly as doc 05 §4 +predicts. Frequent small pulls keep this trivial. diff --git a/packages/contracts/src/model.ts b/packages/contracts/src/model.ts index 59cf08f0694e..793affb257a9 100644 --- a/packages/contracts/src/model.ts +++ b/packages/contracts/src/model.ts @@ -149,7 +149,7 @@ export type PiThinkingLevel = (typeof PI_THINKING_LEVEL_OPTIONS)[number]; export const DEFAULT_MODEL_BY_PROVIDER: Partial> = { [CODEX_DRIVER_KIND]: DEFAULT_MODEL, - [CLAUDE_DRIVER_KIND]: "claude-sonnet-4-6", + [CLAUDE_DRIVER_KIND]: "claude-sonnet-5", [CURSOR_DRIVER_KIND]: "auto", [GROK_DRIVER_KIND]: "grok-build", [PI_DRIVER_KIND]: PI_DEFAULT_MODEL, @@ -187,7 +187,10 @@ export const MODEL_SLUG_ALIASES_BY_PROVIDER: Partial< "opus-4.6": "claude-opus-4-6", "claude-opus-4.6": "claude-opus-4-6", "claude-opus-4-6-20251117": "claude-opus-4-6", - sonnet: "claude-sonnet-4-6", + sonnet: "claude-sonnet-5", + "sonnet-5": "claude-sonnet-5", + "claude-sonnet-5.0": "claude-sonnet-5", + "claude-sonnet-5-0": "claude-sonnet-5", "sonnet-4.6": "claude-sonnet-4-6", "claude-sonnet-4.6": "claude-sonnet-4-6", "claude-sonnet-4-6-20251117": "claude-sonnet-4-6", diff --git a/packages/shared/src/model.test.ts b/packages/shared/src/model.test.ts index 00c016160056..ee91e0b53f72 100644 --- a/packages/shared/src/model.test.ts +++ b/packages/shared/src/model.test.ts @@ -1,13 +1,7 @@ import { describe, expect, it } from "vite-plus/test"; -import { - DEFAULT_MODEL, - ProviderDriverKind, - ProviderInstanceId, - type ModelCapabilities, -} from "@t3tools/contracts"; +import { ProviderInstanceId, type ModelCapabilities } from "@t3tools/contracts"; import { - applyClaudePromptEffortPrefix, buildProviderOptionSelectionsFromDescriptors, createModelCapabilities, createModelSelection, @@ -16,11 +10,6 @@ import { getProviderOptionDescriptors, getProviderOptionBooleanSelectionValue, getProviderOptionStringSelectionValue, - isClaudeUltrathinkPrompt, - normalizeModelSlug, - resolveModelSlugForProvider, - resolveSelectableModel, - trimOrNull, } from "./model.ts"; const codexCaps: ModelCapabilities = createModelCapabilities({ @@ -70,82 +59,6 @@ const claudeCaps: ModelCapabilities = createModelCapabilities({ ], }); -describe("normalizeModelSlug", () => { - it("maps known aliases to canonical slugs", () => { - const claude = ProviderDriverKind.make("claudeAgent"); - expect(normalizeModelSlug("gpt-5-codex")).toBe("gpt-5.4"); - expect(normalizeModelSlug("5.3")).toBe("gpt-5.3-codex"); - expect(normalizeModelSlug("sonnet", claude)).toBe("claude-sonnet-4-6"); - }); - - it("returns null for empty or missing values", () => { - expect(normalizeModelSlug("")).toBeNull(); - expect(normalizeModelSlug(" ")).toBeNull(); - expect(normalizeModelSlug(null)).toBeNull(); - expect(normalizeModelSlug(undefined)).toBeNull(); - }); -}); - -describe("resolveModelSlugForProvider", () => { - it("returns defaults when the model is missing", () => { - expect(resolveModelSlugForProvider(ProviderDriverKind.make("codex"), undefined)).toBe( - DEFAULT_MODEL, - ); - expect(resolveModelSlugForProvider(ProviderDriverKind.make("ollama"), undefined)).toBe( - DEFAULT_MODEL, - ); - expect(resolveModelSlugForProvider(ProviderDriverKind.make("grok"), undefined)).toBe( - "grok-build", - ); - }); - - it("preserves normalized unknown models", () => { - expect( - resolveModelSlugForProvider(ProviderDriverKind.make("codex"), "custom/internal-model"), - ).toBe("custom/internal-model"); - }); -}); - -describe("resolveSelectableModel", () => { - it("resolves exact slugs, labels, and aliases", () => { - const options = [ - { slug: "gpt-5.3-codex", name: "GPT-5.3 Codex" }, - { slug: "claude-sonnet-4-6", name: "Claude Sonnet 4.6" }, - ]; - expect(resolveSelectableModel(ProviderDriverKind.make("codex"), "gpt-5.3-codex", options)).toBe( - "gpt-5.3-codex", - ); - expect(resolveSelectableModel(ProviderDriverKind.make("codex"), "gpt-5.3 codex", options)).toBe( - "gpt-5.3-codex", - ); - expect(resolveSelectableModel(ProviderDriverKind.make("claudeAgent"), "sonnet", options)).toBe( - "claude-sonnet-4-6", - ); - }); -}); - -describe("misc helpers", () => { - it("detects ultrathink prompts", () => { - expect(isClaudeUltrathinkPrompt("Please ultrathink about this")).toBe(true); - expect(isClaudeUltrathinkPrompt("Ultrathink:\nInvestigate")).toBe(true); - expect(isClaudeUltrathinkPrompt("Investigate")).toBe(false); - }); - - it("prefixes ultrathink prompts once", () => { - expect(applyClaudePromptEffortPrefix("Investigate", "ultrathink")).toBe( - "Ultrathink:\nInvestigate", - ); - expect(applyClaudePromptEffortPrefix("Ultrathink:\nInvestigate", "ultrathink")).toBe( - "Ultrathink:\nInvestigate", - ); - }); - - it("trims strings to null", () => { - expect(trimOrNull(" hi ")).toBe("hi"); - expect(trimOrNull(" ")).toBeNull(); - }); -}); - describe("descriptor helpers", () => { it("applies selection values to capability descriptors", () => { expect(