diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 0754c0d1c8..66b769c757 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -27,5 +27,5 @@ "vitest": "catalog:", "wait-on": "^8.0.2" }, - "productName": "T3 Code (Alpha)" + "productName": "Haven Code (Alpha)" } diff --git a/apps/desktop/scripts/electron-launcher.mjs b/apps/desktop/scripts/electron-launcher.mjs index 9d7c522781..c0b3233376 100644 --- a/apps/desktop/scripts/electron-launcher.mjs +++ b/apps/desktop/scripts/electron-launcher.mjs @@ -17,8 +17,8 @@ import { dirname, join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; const isDevelopment = Boolean(process.env.VITE_DEV_SERVER_URL); -const APP_DISPLAY_NAME = isDevelopment ? "T3 Code (Dev)" : "T3 Code (Alpha)"; -const APP_BUNDLE_ID = "com.t3tools.t3code"; +const APP_DISPLAY_NAME = isDevelopment ? "Haven Code (Dev)" : "Haven Code (Alpha)"; +const APP_BUNDLE_ID = "com.haven.havencode"; const LAUNCHER_VERSION = 1; const __dirname = dirname(fileURLToPath(import.meta.url)); diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index c3dba6016e..015b6c83f5 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -57,13 +57,13 @@ const UPDATE_GET_STATE_CHANNEL = "desktop:update-get-state"; const UPDATE_DOWNLOAD_CHANNEL = "desktop:update-download"; const UPDATE_INSTALL_CHANNEL = "desktop:update-install"; const STATE_DIR = - process.env.T3CODE_STATE_DIR?.trim() || Path.join(OS.homedir(), ".t3", "userdata"); + process.env.T3CODE_STATE_DIR?.trim() || Path.join(OS.homedir(), ".haven-code", "userdata"); const DESKTOP_SCHEME = "t3"; const ROOT_DIR = Path.resolve(__dirname, "../../.."); const isDevelopment = Boolean(process.env.VITE_DEV_SERVER_URL); -const APP_DISPLAY_NAME = isDevelopment ? "T3 Code (Dev)" : "T3 Code (Alpha)"; -const APP_USER_MODEL_ID = "com.t3tools.t3code"; -const USER_DATA_DIR_NAME = isDevelopment ? "t3code-dev" : "t3code"; +const APP_DISPLAY_NAME = isDevelopment ? "Haven Code (Dev)" : "Haven Code (Alpha)"; +const APP_USER_MODEL_ID = "com.haven.havencode"; +const USER_DATA_DIR_NAME = isDevelopment ? "havencode-dev" : "havencode"; const LEGACY_USER_DATA_DIR_NAME = isDevelopment ? "T3 Code (Dev)" : "T3 Code (Alpha)"; const COMMIT_HASH_PATTERN = /^[0-9a-f]{7,40}$/i; const COMMIT_HASH_DISPLAY_LENGTH = 12; @@ -440,7 +440,7 @@ function handleFatalStartupError(stage: string, error: unknown): void { console.error(`[desktop] fatal startup error (${stage})`, error); if (!isQuitting) { isQuitting = true; - dialog.showErrorBox("T3 Code failed to start", `Stage: ${stage}\n${message}${detail}`); + dialog.showErrorBox("Haven Code failed to start", `Stage: ${stage}\n${message}${detail}`); } stopBackend(); restoreStdIoCapture?.(); @@ -545,7 +545,7 @@ async function checkForUpdatesFromMenu(): Promise { void dialog.showMessageBox({ type: "info", title: "You're up to date!", - message: `T3 Code ${updateState.currentVersion} is currently the newest version available.`, + message: `Haven Code ${updateState.currentVersion} is currently the newest version available.`, buttons: ["OK"], }); } else if (updateState.status === "error") { diff --git a/apps/server/src/checkpointing/Layers/CheckpointStore.ts b/apps/server/src/checkpointing/Layers/CheckpointStore.ts index fac183ff7a..92cd50aa96 100644 --- a/apps/server/src/checkpointing/Layers/CheckpointStore.ts +++ b/apps/server/src/checkpointing/Layers/CheckpointStore.ts @@ -99,10 +99,10 @@ const makeCheckpointStore = Effect.gen(function* () { const commitEnv: NodeJS.ProcessEnv = { ...process.env, GIT_INDEX_FILE: tempIndexPath, - GIT_AUTHOR_NAME: "T3 Code", - GIT_AUTHOR_EMAIL: "t3code@users.noreply.github.com", - GIT_COMMITTER_NAME: "T3 Code", - GIT_COMMITTER_EMAIL: "t3code@users.noreply.github.com", + GIT_AUTHOR_NAME: "Haven Code", + GIT_AUTHOR_EMAIL: "havencode@users.noreply.github.com", + GIT_COMMITTER_NAME: "Haven Code", + GIT_COMMITTER_EMAIL: "havencode@users.noreply.github.com", }; const headExists = yield* hasHeadCommit(input.cwd); diff --git a/apps/server/src/codexAppServerManager.test.ts b/apps/server/src/codexAppServerManager.test.ts index cea8df0a0b..277d094d44 100644 --- a/apps/server/src/codexAppServerManager.test.ts +++ b/apps/server/src/codexAppServerManager.test.ts @@ -273,8 +273,8 @@ describe("startSession", () => { it("enables Codex experimental api capabilities during initialize", () => { expect(buildCodexInitializeParams()).toEqual({ clientInfo: { - name: "t3code_desktop", - title: "T3 Code Desktop", + name: "havencode_desktop", + title: "Haven Code Desktop", version: "0.1.0", }, capabilities: { diff --git a/apps/server/src/codexAppServerManager.ts b/apps/server/src/codexAppServerManager.ts index a8a8ce4607..1d8f35421d 100644 --- a/apps/server/src/codexAppServerManager.ts +++ b/apps/server/src/codexAppServerManager.ts @@ -404,8 +404,8 @@ export function normalizeCodexModelSlug( export function buildCodexInitializeParams() { return { clientInfo: { - name: "t3code_desktop", - title: "T3 Code Desktop", + name: "havencode_desktop", + title: "Haven Code Desktop", version: "0.1.0", }, capabilities: { diff --git a/apps/server/src/git/Layers/GitCore.ts b/apps/server/src/git/Layers/GitCore.ts index f5b9168abb..954f960e3f 100644 --- a/apps/server/src/git/Layers/GitCore.ts +++ b/apps/server/src/git/Layers/GitCore.ts @@ -1188,7 +1188,7 @@ const makeGitCore = Effect.gen(function* () { const repoName = path.basename(input.cwd); const homeDir = process.env.HOME ?? process.env.USERPROFILE ?? "/tmp"; const worktreePath = - input.path ?? path.join(homeDir, ".t3", "worktrees", repoName, sanitizedBranch); + input.path ?? path.join(homeDir, ".haven-code", "worktrees", repoName, sanitizedBranch); const args = input.newBranch ? ["worktree", "add", "-b", input.newBranch, worktreePath, input.branch] : ["worktree", "add", worktreePath, input.branch]; diff --git a/apps/server/src/main.ts b/apps/server/src/main.ts index 0a33be0cbb..f317a8c14f 100644 --- a/apps/server/src/main.ts +++ b/apps/server/src/main.ts @@ -262,7 +262,7 @@ const makeServerProgram = (input: CliInput) => ? `http://${formatHostForUrl(config.host)}:${config.port}` : localUrl; const { authToken, devUrl, ...safeConfig } = config; - yield* Effect.logInfo("T3 Code running", { + yield* Effect.logInfo("Haven Code running", { ...safeConfig, devUrl: devUrl?.toString(), authEnabled: Boolean(authToken), @@ -342,6 +342,6 @@ export const t3Cli = Command.make("t3", { autoBootstrapProjectFromCwd: autoBootstrapProjectFromCwdFlag, logWebSocketEvents: logWebSocketEventsFlag, }).pipe( - Command.withDescription("Run the T3 Code server."), + Command.withDescription("Run the Haven Code server."), Command.withHandler((input) => Effect.scoped(makeServerProgram(input))), ); diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts index d190b97c63..fb535dfa38 100644 --- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts +++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts @@ -73,7 +73,7 @@ const serverCommandId = (tag: string): CommandId => const HANDLED_TURN_START_KEY_MAX = 10_000; const HANDLED_TURN_START_KEY_TTL = Duration.minutes(30); const DEFAULT_RUNTIME_MODE: RuntimeMode = "full-access"; -const WORKTREE_BRANCH_PREFIX = "t3code"; +const WORKTREE_BRANCH_PREFIX = "havencode"; const TEMP_WORKTREE_BRANCH_PATTERN = new RegExp(`^${WORKTREE_BRANCH_PREFIX}\\/[0-9a-f]{8}$`); const sameModelOptions = ( diff --git a/apps/server/src/os-jank.ts b/apps/server/src/os-jank.ts index 586aca6f79..e80a56543f 100644 --- a/apps/server/src/os-jank.ts +++ b/apps/server/src/os-jank.ts @@ -30,7 +30,7 @@ export const expandHomePath = Effect.fn(function* (input: string) { export const resolveStateDir = Effect.fn(function* (raw: string | undefined) { const { join, resolve } = yield* Path.Path; if (!raw || raw.trim().length === 0) { - return join(OS.homedir(), ".t3", "userdata"); + return join(OS.homedir(), ".haven-code", "userdata"); } return resolve(yield* expandHomePath(raw.trim())); }); diff --git a/apps/server/src/provider/Layers/ProviderHealth.test.ts b/apps/server/src/provider/Layers/ProviderHealth.test.ts index e24f07bcfa..75c9d660f7 100644 --- a/apps/server/src/provider/Layers/ProviderHealth.test.ts +++ b/apps/server/src/provider/Layers/ProviderHealth.test.ts @@ -146,7 +146,7 @@ it.layer(NodeServices.layer)("ProviderHealth", (it) => { assert.strictEqual(status.authStatus, "unknown"); assert.strictEqual( status.message, - "Codex CLI v0.36.0 is too old for T3 Code. Upgrade to v0.37.0 or newer and restart T3 Code.", + "Codex CLI v0.36.0 is too old for Haven Code. Upgrade to v0.37.0 or newer and restart Haven Code.", ); }).pipe( Effect.provide( diff --git a/apps/server/src/provider/codexCliVersion.ts b/apps/server/src/provider/codexCliVersion.ts index 544020016c..3ca60b5cbf 100644 --- a/apps/server/src/provider/codexCliVersion.ts +++ b/apps/server/src/provider/codexCliVersion.ts @@ -137,5 +137,5 @@ export function isCodexCliVersionSupported(version: string): boolean { export function formatCodexCliUpgradeMessage(version: string | null): string { const versionLabel = version ? `v${version}` : "the installed version"; - return `Codex CLI ${versionLabel} is too old for T3 Code. Upgrade to v${MINIMUM_CODEX_CLI_VERSION} or newer and restart T3 Code.`; + return `Codex CLI ${versionLabel} is too old for Haven Code. Upgrade to v${MINIMUM_CODEX_CLI_VERSION} or newer and restart Haven Code.`; } diff --git a/apps/server/src/telemetry/Identify.ts b/apps/server/src/telemetry/Identify.ts index cf6ac72178..1ba28a73f5 100644 --- a/apps/server/src/telemetry/Identify.ts +++ b/apps/server/src/telemetry/Identify.ts @@ -59,7 +59,7 @@ const upsertAnonymousId = Effect.gen(function* () { /** * getTelemetryIdentifier - Users are "identified" by finding the first match of the following, then hashing the value. * 1. ~/.codex/auth.json tokens.account_id - * 2. ~/.t3/telemetry/anonymous-id + * 2. ~/.haven-code/telemetry/anonymous-id */ export const getTelemetryIdentifier = Effect.gen(function* () { const codexAccountId = yield* Effect.result(getCodexAccountId); diff --git a/apps/web/index.html b/apps/web/index.html index 0322f2d019..b2d5884574 100644 --- a/apps/web/index.html +++ b/apps/web/index.html @@ -11,7 +11,7 @@ href="https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,300..800;1,9..40,300..800&display=swap" rel="stylesheet" /> - T3 Code (Alpha) + Haven Code (Alpha)
diff --git a/apps/web/src/appSettings.ts b/apps/web/src/appSettings.ts index 1e51f7fec2..233b69dd28 100644 --- a/apps/web/src/appSettings.ts +++ b/apps/web/src/appSettings.ts @@ -39,6 +39,9 @@ const AppSettingsSchema = Schema.Struct({ Schema.withConstructorDefault(() => Option.some([])), ), textGenerationModel: Schema.optional(TrimmedNonEmptyString), + enableCodexProvider: Schema.Boolean.pipe( + Schema.withConstructorDefault(() => Option.some(false)), + ), claudeUseBedrock: Schema.Boolean.pipe( Schema.withConstructorDefault(() => Option.some(false)), ), diff --git a/apps/web/src/branding.ts b/apps/web/src/branding.ts index bffd983815..b7183f5750 100644 --- a/apps/web/src/branding.ts +++ b/apps/web/src/branding.ts @@ -1,4 +1,4 @@ -export const APP_BASE_NAME = "T3 Code"; +export const APP_BASE_NAME = "Haven Code"; export const APP_STAGE_LABEL = import.meta.env.DEV ? "Dev" : "Alpha"; export const APP_DISPLAY_NAME = `${APP_BASE_NAME} (${APP_STAGE_LABEL})`; export const APP_VERSION = import.meta.env.APP_VERSION || "0.0.0"; diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index 76b34b4cad..e4711a0075 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -242,6 +242,13 @@ export default function ChatView({ threadId }: ChatViewProps) { const setStoreThreadError = useStore((store) => store.setError); const setStoreThreadBranch = useStore((store) => store.setThreadBranch); const { settings } = useAppSettings(); + const filteredAvailableProviders = useMemo( + () => + AVAILABLE_PROVIDER_OPTIONS.filter( + (option) => option.value !== "codex" || settings.enableCodexProvider, + ), + [settings.enableCodexProvider], + ); const timestampFormat = settings.timestampFormat; const navigate = useNavigate(); const rawSearch = useSearch({ @@ -460,7 +467,7 @@ export default function ChatView({ threadId }: ChatViewProps) { ? buildLocalDraftThread( threadId, draftThread, - fallbackDraftProject?.model ?? DEFAULT_MODEL_BY_PROVIDER.codex, + fallbackDraftProject?.model ?? DEFAULT_MODEL_BY_PROVIDER.claudeAgent, localDraftError, ) : undefined, @@ -589,7 +596,7 @@ export default function ChatView({ threadId }: ChatViewProps) { const lockedProvider: ProviderKind | null = hasThreadStarted ? (sessionProvider ?? selectedProviderByThreadId ?? null) : null; - const selectedProvider: ProviderKind = lockedProvider ?? selectedProviderByThreadId ?? "codex"; + const selectedProvider: ProviderKind = lockedProvider ?? selectedProviderByThreadId ?? "claudeAgent"; const baseThreadModel = resolveModelSlugForProvider( selectedProvider, activeThread?.model ?? activeProject?.model ?? getDefaultModel(selectedProvider), @@ -718,7 +725,7 @@ export default function ChatView({ threadId }: ChatViewProps) { }, [modelOptionsByProvider, selectedModelForPicker, selectedProvider]); const searchableModelOptions = useMemo( () => - AVAILABLE_PROVIDER_OPTIONS.filter( + filteredAvailableProviders.filter( (option) => lockedProvider === null || option.value === lockedProvider, ).flatMap((option) => modelOptionsByProvider[option.value].map(({ slug, name }) => ({ @@ -731,7 +738,7 @@ export default function ChatView({ threadId }: ChatViewProps) { searchProvider: option.label.toLowerCase(), })), ), - [lockedProvider, modelOptionsByProvider], + [filteredAvailableProviders, lockedProvider, modelOptionsByProvider], ); const phase = derivePhase(activeThread?.session ?? null); const isSendBusy = sendPhase !== "idle"; @@ -3825,6 +3832,7 @@ export default function ChatView({ threadId }: ChatViewProps) { model={selectedModelForPickerWithCustomFallback} lockedProvider={lockedProvider} modelOptionsByProvider={modelOptionsByProvider} + availableProviders={filteredAvailableProviders} ultrathinkActive={isClaudeUltrathink} bedrockActive={ settings.claudeUseBedrock || diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx index beacd1d943..35dadc37f4 100644 --- a/apps/web/src/components/Sidebar.tsx +++ b/apps/web/src/components/Sidebar.tsx @@ -162,19 +162,12 @@ function prStatusIndicator(pr: ThreadPr): PrStatusIndicator | null { return null; } -function T3Wordmark() { +function HavenWordmark() { return ( - - - + + Haven + Code + ); } @@ -432,7 +425,7 @@ export default function Sidebar() { projectId, title, workspaceRoot: cwd, - defaultModel: DEFAULT_MODEL_BY_PROVIDER.codex, + defaultModel: DEFAULT_MODEL_BY_PROVIDER.claudeAgent, createdAt, }); await handleNewThread(projectId, { @@ -1150,11 +1143,8 @@ export default function Sidebar() { - - - Code - +
+ {APP_STAGE_LABEL} diff --git a/apps/web/src/components/chat/ProviderModelPicker.tsx b/apps/web/src/components/chat/ProviderModelPicker.tsx index cb07d57f46..13a62f60ef 100644 --- a/apps/web/src/components/chat/ProviderModelPicker.tsx +++ b/apps/web/src/components/chat/ProviderModelPicker.tsx @@ -86,6 +86,7 @@ export const ProviderModelPicker = memo(function ProviderModelPicker(props: { model: ModelSlug; lockedProvider: ProviderKind | null; modelOptionsByProvider: Record>; + availableProviders?: ReadonlyArray<{ value: ProviderKind; label: string; available: true }>; ultrathinkActive?: boolean; bedrockActive?: boolean; compact?: boolean; @@ -93,6 +94,13 @@ export const ProviderModelPicker = memo(function ProviderModelPicker(props: { onProviderModelChange: (provider: ProviderKind, model: ModelSlug) => void; }) { const [isMenuOpen, setIsMenuOpen] = useState(false); + const availableProviderOptions = props.availableProviders ?? AVAILABLE_PROVIDER_OPTIONS; + const unavailableProviderOptions = props.availableProviders + ? PROVIDER_OPTIONS.filter( + (option) => + option.available && !props.availableProviders!.some((p) => p.value === option.value), + ) + : UNAVAILABLE_PROVIDER_OPTIONS; const activeProvider = props.lockedProvider ?? props.provider; const selectedProviderOptions = props.modelOptionsByProvider[activeProvider]; const selectedModelLabel = @@ -177,7 +185,7 @@ export const ProviderModelPicker = memo(function ProviderModelPicker(props: { ) : ( <> - {AVAILABLE_PROVIDER_OPTIONS.map((option) => { + {availableProviderOptions.map((option) => { const OptionIcon = PROVIDER_ICON_BY_PROVIDER[option.value]; return ( @@ -212,8 +220,8 @@ export const ProviderModelPicker = memo(function ProviderModelPicker(props: { ); })} - {UNAVAILABLE_PROVIDER_OPTIONS.length > 0 && } - {UNAVAILABLE_PROVIDER_OPTIONS.map((option) => { + {unavailableProviderOptions.length > 0 && } + {unavailableProviderOptions.map((option) => { const OptionIcon = PROVIDER_ICON_BY_PROVIDER[option.value]; return ( @@ -228,7 +236,7 @@ export const ProviderModelPicker = memo(function ProviderModelPicker(props: { ); })} - {UNAVAILABLE_PROVIDER_OPTIONS.length === 0 && } + {unavailableProviderOptions.length === 0 && } {COMING_SOON_PROVIDER_OPTIONS.map((option) => { const OptionIcon = option.icon; return ( diff --git a/apps/web/src/components/desktopUpdate.logic.ts b/apps/web/src/components/desktopUpdate.logic.ts index faf30883cc..cd3ff9f708 100644 --- a/apps/web/src/components/desktopUpdate.logic.ts +++ b/apps/web/src/components/desktopUpdate.logic.ts @@ -47,12 +47,12 @@ export function getArm64IntelBuildWarningDescription(state: DesktopUpdateState): const action = resolveDesktopUpdateButtonAction(state); if (action === "download") { - return "This Mac has Apple Silicon, but T3 Code is still running the Intel build under Rosetta. Download the available update to switch to the native Apple Silicon build."; + return "This Mac has Apple Silicon, but Haven Code is still running the Intel build under Rosetta. Download the available update to switch to the native Apple Silicon build."; } if (action === "install") { - return "This Mac has Apple Silicon, but T3 Code is still running the Intel build under Rosetta. Restart to install the downloaded Apple Silicon build."; + return "This Mac has Apple Silicon, but Haven Code is still running the Intel build under Rosetta. Restart to install the downloaded Apple Silicon build."; } - return "This Mac has Apple Silicon, but T3 Code is still running the Intel build under Rosetta. The next app update will replace it with the native Apple Silicon build."; + return "This Mac has Apple Silicon, but Haven Code is still running the Intel build under Rosetta. The next app update will replace it with the native Apple Silicon build."; } export function getDesktopUpdateButtonTooltip(state: DesktopUpdateState): string { diff --git a/apps/web/src/routes/_chat.settings.tsx b/apps/web/src/routes/_chat.settings.tsx index d16eb3be98..36d8a7fe65 100644 --- a/apps/web/src/routes/_chat.settings.tsx +++ b/apps/web/src/routes/_chat.settings.tsx @@ -248,7 +248,7 @@ function SettingsRouteView() {

Appearance

- Choose how T3 Code looks across the app. + Choose how Haven Code looks across the app.

@@ -342,6 +342,22 @@ function SettingsRouteView() {
+
+
+

Enable Codex provider

+

+ Show the Codex (OpenAI) provider in the model picker. Disabled by default. +

+
+ + updateSettings({ enableCodexProvider: Boolean(checked) }) + } + aria-label="Enable Codex provider" + /> +
+