Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion apps/desktop/src/app/DesktopApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import * as DesktopShellEnvironment from "../shell/DesktopShellEnvironment.ts";
import * as DesktopState from "./DesktopState.ts";
import * as DesktopUpdates from "../updates/DesktopUpdates.ts";
import * as DesktopWslBackend from "../wsl/DesktopWslBackend.ts";
import { desktopAppDisplayName } from "./desktopDistro.ts";

const DEFAULT_DESKTOP_BACKEND_PORT = 3773;
const MAX_TCP_PORT = 65_535;
Expand Down Expand Up @@ -131,7 +132,7 @@ const handleFatalStartupError = Effect.fn("desktop.startup.handleFatalStartupErr
const wasQuitting = yield* Ref.getAndSet(state.quitting, true);
if (!wasQuitting) {
yield* electronDialog.showErrorBox(
"T3 Code failed to start",
`${desktopAppDisplayName()} failed to start`,
`Stage: ${stage}\n${message}${detail}`,
);
}
Expand Down
16 changes: 16 additions & 0 deletions apps/desktop/src/app/desktopDistro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,19 @@ export function resolveRuntimeDesktopDistro(input: {
linuxWmClass: input.isDevelopment ? "t3code-dev" : "t3code",
};
}

/**
* The product name for messages the user reads, resolved from the running
* build. Main-process code that only needs a name (an error dialog, a keyring
* hint) can call this instead of threading DesktopEnvironment through.
*/
export function desktopAppDisplayName(
env: NodeJS.ProcessEnv = process.env,
appPath?: string,
): string {
return resolveRuntimeDesktopDistro({
env,
...(appPath === undefined ? {} : { appPath }),
isDevelopment: false,
}).baseName;
}
3 changes: 2 additions & 1 deletion apps/desktop/src/backend/DesktopLocalEnvironmentAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import * as Semaphore from "effect/Semaphore";
import * as HttpClient from "effect/unstable/http/HttpClient";

import * as DesktopBackendPool from "./DesktopBackendPool.ts";
import { desktopAppDisplayName } from "../app/desktopDistro.ts";

export class DesktopLocalEnvironmentAuthBackendNotConfiguredError extends Schema.TaggedErrorClass<DesktopLocalEnvironmentAuthBackendNotConfiguredError>()(
"DesktopLocalEnvironmentAuthBackendNotConfiguredError",
Expand Down Expand Up @@ -71,7 +72,7 @@ export const make = Effect.gen(function* () {
httpBaseUrl: config.httpBaseUrl.href,
credential,
clientMetadata: {
label: "T3 Code Desktop",
label: `${desktopAppDisplayName()} Desktop`,
deviceType: "desktop",
},
}).pipe(
Expand Down
6 changes: 4 additions & 2 deletions apps/desktop/src/linuxSecretStorage.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { desktopAppDisplayName } from "./app/desktopDistro.ts";

export type LinuxPasswordStorePreference =
| "auto"
| "gnome-libsecret"
Expand Down Expand Up @@ -112,11 +114,11 @@ export function resolveLinuxSecretStorageUnavailableMessage(input: {
}

function getGnomeKeyringRemediationMessage(): string {
return "T3 Code could not access GNOME Keyring to save this environment credential. Install and start GNOME Keyring, then restart T3 Code.";
return `${desktopAppDisplayName()} could not access GNOME Keyring to save this environment credential. Install and start GNOME Keyring, then restart ${desktopAppDisplayName()}.`;
}

function getKWalletRemediationMessage(): string {
return "T3 Code could not access KWallet to save this environment credential. Enable the KDE wallet subsystem in System Settings, then restart T3 Code.";
return `${desktopAppDisplayName()} could not access KWallet to save this environment credential. Enable the KDE wallet subsystem in System Settings, then restart ${desktopAppDisplayName()}.`;
}

// Advisory only: this picks between the GNOME Keyring and KWallet wording in the failure notice. It
Expand Down
3 changes: 2 additions & 1 deletion apps/desktop/src/ssh/DesktopSshEnvironment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import * as HttpClient from "effect/unstable/http/HttpClient";
import * as ChildProcessSpawner from "effect/unstable/process/ChildProcessSpawner";

import * as DesktopSshPasswordPrompts from "./DesktopSshPasswordPrompts.ts";
import { desktopAppDisplayName } from "../app/desktopDistro.ts";

export type DesktopSshEnvironmentRuntimeServices =
| ChildProcessSpawner.ChildProcessSpawner
Expand Down Expand Up @@ -96,7 +97,7 @@ export function toSshPasswordPromptError(
break;
case "DesktopSshPromptWindowUnavailableError":
case "DesktopSshPromptPresentationError":
message = "T3 Code window is not available for SSH authentication.";
message = `${desktopAppDisplayName()} window is not available for SSH authentication.`;
break;
case "DesktopSshPromptTimedOutError":
message = `SSH authentication timed out for ${cause.destination}.`;
Expand Down
3 changes: 2 additions & 1 deletion apps/desktop/src/wsl/DesktopWslEnvironment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { satisfiesSemverRange } from "@t3tools/shared/semver";

import * as DesktopEnvironment from "../app/DesktopEnvironment.ts";
import { parseWslDistroList, type WslDistro } from "./wslPathParsing.ts";
import { desktopAppDisplayName } from "../app/desktopDistro.ts";

const PROCESS_TERMINATE_GRACE = Duration.seconds(1);
const LIST_TIMEOUT = Duration.seconds(8);
Expand Down Expand Up @@ -220,7 +221,7 @@ const NODE_PTY_PREBUILD_MISSING_EXIT_CODE = 4;

export const formatNodePtyProbeFailureReason = (exitCode: number): string | null =>
exitCode === NODE_PTY_PREBUILD_MISSING_EXIT_CODE
? "WSL support is missing from this T3 Code build: the packaged Linux node-pty binary was not included. Rebuild the Windows artifact with `--wsl-prebuild <path-to-linux-pty.node>` or install a build that includes WSL support."
? `WSL support is missing from this ${desktopAppDisplayName()} build: the packaged Linux node-pty binary was not included. Rebuild the Windows artifact with \`--wsl-prebuild <path-to-linux-pty.node>\` or install a build that includes WSL support.`
: null;

const NODE_PTY_PROBE_SCRIPT = (
Expand Down
5 changes: 3 additions & 2 deletions apps/server/src/bin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { runServerCommand, serveCommand, startCommand } from "./cli/server.ts";
import { serviceCommand } from "./cli/service.ts";
import { servicePreflightCommand } from "./cli/servicePreflight.ts";
import { triageCommand } from "./cli/triage.ts";
import { resolveAppDisplayName } from "./appDisplayName.ts";

const DESKTOP_OPEN_POLL_ATTEMPTS = 40;
const DESKTOP_OPEN_POLL_DELAY = Duration.millis(500);
Expand Down Expand Up @@ -50,7 +51,7 @@ const openProjectViaDesktopOrLiveServer = Effect.fn("openProjectViaDesktopOrLive
}

yield* Console.error(
"Launched T3 Code desktop, but it did not become ready in time. Falling back to the CLI server.",
`Launched ${resolveAppDisplayName()} desktop, but it did not become ready in time. Falling back to the CLI server.`,
);
return false;
},
Expand Down Expand Up @@ -85,7 +86,7 @@ const connectUnavailableCommand = Command.make("connect", {
export const makeCli = ({ cloudEnabled = hasCloudPublicConfig } = {}) =>
Command.make("t3", { ...sharedServerCommandFlags }).pipe(
Command.withDescription(
"Run the T3 Code server, or open a directory in the desktop app / a running server.",
`Run the ${resolveAppDisplayName()} server, or open a directory in the desktop app / a running server.`,
),
Command.withHandler((flags) =>
Effect.gen(function* () {
Expand Down
3 changes: 2 additions & 1 deletion apps/server/src/plugins/CodexPluginMarketplace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import { deriveProviderInstanceConfigMap } from "../provider/Layers/ProviderInst
import * as ServerSettings from "../serverSettings.ts";
import { collectUint8StreamText } from "../stream/collectUint8StreamText.ts";
import * as McpOAuthRuntime from "./McpOAuthRuntime.ts";
import { resolveAppDisplayName } from "../appDisplayName.ts";
import {
CHATGPT_PUBLIC_MARKETPLACE_NAME,
CHATGPT_PUBLIC_PLUGIN_SEARCH_MAX_PAGES,
Expand Down Expand Up @@ -3028,7 +3029,7 @@ const makeCodexPluginRuntime = (
yield* client.request("initialize", {
clientInfo: {
name: "t3code_plugin_marketplace",
title: "T3 Code Plugin Marketplace",
title: `${resolveAppDisplayName()} Plugin Marketplace`,
version: "0.1.0",
},
capabilities: { experimentalApi: true },
Expand Down
3 changes: 2 additions & 1 deletion apps/server/src/plugins/McpOAuthRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { HostProcessEnvironment, HostProcessWorkingDirectory } from "@t3tools/sh
import { resolveSpawnCommand } from "@t3tools/shared/shell";

import * as ProcessRunner from "../processRunner.ts";
import { resolveAppDisplayName } from "../appDisplayName.ts";

export type McpOAuthHarness = Extract<PluginMarketplaceHarnessId, "codex" | "claude" | "cursor">;

Expand Down Expand Up @@ -517,7 +518,7 @@ export const make = (options: McpOAuthRuntimeOptions = {}) =>
yield* client.request("initialize", {
clientInfo: {
name: "t3code_mcp_oauth",
title: "T3 Code MCP Authentication",
title: `${resolveAppDisplayName()} MCP Authentication`,
version: "0.1.0",
},
capabilities: { experimentalApi: true },
Expand Down
3 changes: 2 additions & 1 deletion apps/server/src/serverRuntimeStartup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import * as ProviderSessionReaper from "./provider/Services/ProviderSessionReape
import * as SessionStartupReconciler from "./provider/Services/SessionStartupReconciler.ts";
import { forkParked } from "./serverActivation.ts";
import * as ServiceLauncherClient from "./cloud/serviceLauncherClient.ts";
import { resolveAppDisplayName } from "./appDisplayName.ts";
import {
formatHeadlessServeOutput,
formatHostForUrl,
Expand Down Expand Up @@ -445,7 +446,7 @@ export const make = (options?: StartupOptions) =>
const startupBrowserTarget = yield* resolveStartupBrowserTarget;
if (serverConfig.mode !== "desktop") {
yield* Effect.logInfo(
"Authentication required. Open T3 Code using the pairing URL.",
`Authentication required. Open ${resolveAppDisplayName()} using the pairing URL.`,
).pipe(Effect.annotateLogs({ pairingUrl: startupBrowserTarget }));
}
yield* runStartupPhase("browser.open", maybeOpenBrowser(startupBrowserTarget));
Expand Down
3 changes: 2 additions & 1 deletion apps/server/src/startupAccess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { HttpServer } from "effect/unstable/http";

import { ServerConfig } from "./config.ts";
import * as EnvironmentAuth from "./auth/EnvironmentAuth.ts";
import { resolveAppDisplayName } from "./appDisplayName.ts";

export interface HeadlessServeAccessInfo {
readonly connectionString: string;
Expand Down Expand Up @@ -121,7 +122,7 @@ export const renderTerminalQrCode = (value: string, margin = 2): string => {

export const formatHeadlessServeOutput = (accessInfo: HeadlessServeAccessInfo): string =>
[
"T3 Code server is ready.",
`${resolveAppDisplayName()} server is ready.`,
`Connection string: ${accessInfo.connectionString}`,
`Token: ${accessInfo.token}`,
`Pairing URL: ${accessInfo.pairingUrl}`,
Expand Down
3 changes: 2 additions & 1 deletion apps/server/src/textGeneration/OpenCodeTextGeneration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
clampPullRequestRankings,
} from "./TextGenerationUtils.ts";
import * as OpenCodeRuntime from "../provider/opencodeRuntime.ts";
import { resolveAppDisplayName } from "../appDisplayName.ts";

const OPENCODE_TEXT_GENERATION_IDLE_TTL = "30 seconds";

Expand Down Expand Up @@ -397,7 +398,7 @@ export const makeOpenCodeTextGeneration = Effect.fn("makeOpenCodeTextGeneration"
const session = yield* Effect.tryPromise({
try: () =>
client.session.create({
title: `T3 Code ${input.operation}`,
title: `${resolveAppDisplayName()} ${input.operation}`,
permission: [{ permission: "*", pattern: "*", action: "deny" }],
}),
catch: (cause) =>
Expand Down
16 changes: 10 additions & 6 deletions apps/web/src/components/Icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -705,12 +705,16 @@ export const MtModelIcon: Icon = ({ className, ...props }) => (
className={cn("fill-current", className)}
aria-hidden
>
{/* The Munim mark, same path the app icon draws. */}
<path
d="M52.547 87.884L52.710 88.313L51.914 88.231L-0.000 603.926L105.522 614.537L135.846 313.360L180.699 434.810L181.210 439.258L182.291 439.136L184.066 443.911L265.794 413.732L273.569 383.736L293.716 313.043L312.994 481.660L219.104 524.021L180.964 657.000L668.780 436.993L668.189 435.670L631.008 110.432L725.000 105.249L719.204 0.000L419.046 16.549L424.862 121.797L525.037 116.268L554.382 372.820L413.312 436.422L366.622 27.955L262.488 39.871L262.937 43.850L212.900 219.495L150.865 51.563Z"
fillRule="nonzero"
transform="translate(22.067 26.000) scale(0.115677)"
/>
{/* The Munim mark, same path the app icon draws. Scaled about the centre so
it reads at the same optical size as the other provider marks, which
fill more of their own box. */}
<g transform="translate(64 64) scale(1.34) translate(-64 -64)">
<path
d="M52.547 87.884L52.710 88.313L51.914 88.231L-0.000 603.926L105.522 614.537L135.846 313.360L180.699 434.810L181.210 439.258L182.291 439.136L184.066 443.911L265.794 413.732L273.569 383.736L293.716 313.043L312.994 481.660L219.104 524.021L180.964 657.000L668.780 436.993L668.189 435.670L631.008 110.432L725.000 105.249L719.204 0.000L419.046 16.549L424.862 121.797L525.037 116.268L554.382 372.820L413.312 436.422L366.622 27.955L262.488 39.871L262.937 43.850L212.900 219.495L150.865 51.563Z"
fillRule="nonzero"
transform="translate(22.067 26.000) scale(0.115677)"
/>
</g>
</svg>
);

Expand Down
Binary file modified assets/munim/munim-icon-dark-1024.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/munim/munim-icon-light-1024.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions native/t3-desktop-mcp-rs/src/browser.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Agent-owned Chrome tabs, via the T3 Code Chrome extension.
//! Agent-owned Chrome tabs, via the MT Code Chrome extension.
//!
//! Chrome owns the lifetime of a native messaging host: it spawns the host when
//! the extension connects and speaks 4-byte-length-prefixed JSON over that
Expand Down Expand Up @@ -172,7 +172,7 @@ impl BrowserBridge {
pub fn call(&mut self, command: &str, args: &Value) -> Result<String, String> {
if !self.connected() {
return Err(format!(
"browser_{command} needs the T3 Code Chrome extension, which is not connected. \
"browser_{command} needs the MT Code Chrome extension, which is not connected. \
Install it from native/t3-chrome-extension, or use the desktop tools instead: \
get_app_state on the browser window, then click"
));
Expand Down
2 changes: 1 addition & 1 deletion native/t3-desktop-mcp/Sources/BrowserBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ final class BrowserBridge {
lock.lock()
guard clientFD >= 0 else {
lock.unlock()
return .failure("the T3 Code Chrome extension is not connected")
return .failure("the MT Code Chrome extension is not connected")
}
nextID += 1
let id = nextID
Expand Down
2 changes: 1 addition & 1 deletion native/t3-desktop-mcp/Sources/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2014,7 +2014,7 @@ func toolBrowserPressKey(_ args: [String: Any]) -> String {

func toolBrowserCloseAllTabs(_ args: [String: Any]) -> String {
guard BrowserBridge.shared.isConnected else {
return "error: the T3 Code Chrome extension is not connected"
return "error: the MT Code Chrome extension is not connected"
}
return bridgeText(BrowserBridge.shared.call("close_all_tabs")) { payload in
let closed = payload["closed"] as? Int ?? 0
Expand Down
Loading