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
2 changes: 1 addition & 1 deletion .docs/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ bun run dev
bun run dev:desktop

# Desktop development on an isolated port set
T3CODE_DEV_INSTANCE=feature-xyz bun run dev:desktop
BCODE_DEV_INSTANCE=feature-xyz bun run dev:desktop

# Production
bun run build
Expand Down
14 changes: 7 additions & 7 deletions .docs/scripts.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
- `bun run dev` — Starts contracts, server, and web in `turbo watch` mode.
- `bun run dev:server` — Starts just the WebSocket server (uses Bun TypeScript execution).
- `bun run dev:web` — Starts just the Vite dev server for the web app.
- Dev commands default `T3CODE_STATE_DIR` to `~/.t3/dev` to keep dev state isolated from desktop/prod state.
- Dev commands default the base dir to `~/.t3` (overridable via `BCODE_HOME` or `--base-dir`) and place dev state under `$BCODE_HOME/dev` to keep it isolated from desktop/prod state.
- Override server CLI-equivalent flags from root dev commands with `--`, for example:
`bun run dev -- --base-dir ~/.t3-2`
- `bun run start` — Runs the production server (serves built web app as static files).
Expand All @@ -20,8 +20,8 @@

- Default build is unsigned/not notarized for local sharing.
- The DMG build uses `assets/macos-icon-1024.png` as the production app icon source.
- Desktop production windows load the bundled UI from `t3://app/index.html` (not a `127.0.0.1` document URL).
- Desktop packaging includes `apps/server/dist` (the `t3` backend) and starts it on loopback with an auth token for WebSocket/API traffic.
- Desktop production windows load the bundled UI from `bcode://app/index.html` (not a `127.0.0.1` document URL).
- Desktop packaging includes `apps/server/dist` (the `bcode` backend) and starts it on loopback with an auth token for WebSocket/API traffic.
- Your tester can still open it on macOS by right-clicking the app and choosing **Open** on first launch.
- To keep staging files for debugging package contents, run: `bun run dist:desktop:dmg -- --keep-stage`
- To allow code-signing/notarization when configured in CI/secrets, add: `--signed`.
Expand All @@ -33,10 +33,10 @@

## Running multiple dev instances

Set `T3CODE_DEV_INSTANCE` to any value to deterministically shift all dev ports together.
Set `BCODE_DEV_INSTANCE` to any value to deterministically shift all dev ports together.

- Default ports: server `3773`, web `5733`
- Shifted ports: `base + offset` (offset is hashed from `T3CODE_DEV_INSTANCE`)
- Example: `T3CODE_DEV_INSTANCE=branch-a bun run dev:desktop`
- Shifted ports: `base + offset` (offset is hashed from `BCODE_DEV_INSTANCE`)
- Example: `BCODE_DEV_INSTANCE=branch-a bun run dev:desktop`

If you want full control instead of hashing, set `T3CODE_PORT_OFFSET` to a numeric offset.
If you want full control instead of hashing, set `BCODE_PORT_OFFSET` to a numeric offset.
2 changes: 1 addition & 1 deletion KEYBINDINGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

T3 Code reads keybindings from:

- `~/.t3/keybindings.json`
- `~/.t3/keybindings.json` (home directory flips to `~/.bcode` in a future release with auto-migration)

The file must be a JSON array of rules:

Expand Down
4 changes: 2 additions & 2 deletions apps/desktop/scripts/dev-electron.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ function cleanupStaleDevApps() {
return;
}

spawnSync("pkill", ["-f", "--", `--t3code-dev-root=${desktopDir}`], { stdio: "ignore" });
spawnSync("pkill", ["-f", "--", `--bcode-dev-root=${desktopDir}`], { stdio: "ignore" });
}

function startApp() {
Expand All @@ -69,7 +69,7 @@ function startApp() {

const app = spawn(
resolveElectronPath(),
[`--t3code-dev-root=${desktopDir}`, "dist-electron/main.js"],
[`--bcode-dev-root=${desktopDir}`, "dist-electron/main.js"],
{
cwd: desktopDir,
env: childEnv,
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/scripts/electron-launcher.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ 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 = isDevelopment ? "com.t3tools.t3code.dev" : "com.t3tools.t3code";
const APP_BUNDLE_ID = isDevelopment ? "com.berkayorhan.bcode.dev" : "com.berkayorhan.bcode";
const LAUNCHER_VERSION = 1;

const __dirname = dirname(fileURLToPath(import.meta.url));
Expand Down
55 changes: 29 additions & 26 deletions apps/desktop/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import type {
import { autoUpdater } from "electron-updater";

import type { ContextMenuItem } from "@bcode/contracts";
import { readEnv } from "@bcode/shared/env";
import { RotatingFileSink } from "@bcode/shared/logging";
import { parsePersistedServerObservabilitySettings } from "@bcode/shared/serverSettings";
import { DEFAULT_DESKTOP_BACKEND_PORT, resolveDesktopBackendPort } from "./backendPort";
Expand Down Expand Up @@ -100,22 +101,22 @@ const SET_SAVED_ENVIRONMENT_SECRET_CHANNEL = "desktop:set-saved-environment-secr
const REMOVE_SAVED_ENVIRONMENT_SECRET_CHANNEL = "desktop:remove-saved-environment-secret";
const GET_SERVER_EXPOSURE_STATE_CHANNEL = "desktop:get-server-exposure-state";
const SET_SERVER_EXPOSURE_MODE_CHANNEL = "desktop:set-server-exposure-mode";
const BASE_DIR = process.env.T3CODE_HOME?.trim() || Path.join(OS.homedir(), ".t3");
const BASE_DIR = readEnv("HOME")?.trim() || Path.join(OS.homedir(), ".t3");
const STATE_DIR = Path.join(BASE_DIR, "userdata");
const DESKTOP_SETTINGS_PATH = Path.join(STATE_DIR, "desktop-settings.json");
const CLIENT_SETTINGS_PATH = Path.join(STATE_DIR, "client-settings.json");
const SAVED_ENVIRONMENT_REGISTRY_PATH = Path.join(STATE_DIR, "saved-environments.json");
const DESKTOP_SCHEME = "t3";
const DESKTOP_SCHEME = "bcode";
const ROOT_DIR = Path.resolve(__dirname, "../../..");
const isDevelopment = Boolean(process.env.VITE_DEV_SERVER_URL);
const desktopAppBranding: DesktopAppBranding = resolveDesktopAppBranding({
isDevelopment,
appVersion: app.getVersion(),
});
const APP_DISPLAY_NAME = desktopAppBranding.displayName;
const APP_USER_MODEL_ID = isDevelopment ? "com.t3tools.t3code.dev" : "com.t3tools.t3code";
const LINUX_DESKTOP_ENTRY_NAME = isDevelopment ? "t3code-dev.desktop" : "t3code.desktop";
const LINUX_WM_CLASS = isDevelopment ? "t3code-dev" : "t3code";
const APP_USER_MODEL_ID = isDevelopment ? "com.berkayorhan.bcode.dev" : "com.berkayorhan.bcode";
const LINUX_DESKTOP_ENTRY_NAME = isDevelopment ? "bcode-dev.desktop" : "bcode.desktop";
const LINUX_WM_CLASS = isDevelopment ? "bcode-dev" : "bcode";
const USER_DATA_DIR_NAME = isDevelopment ? "t3code-dev" : "t3code";
const LEGACY_USER_DATA_DIR_NAME = isDevelopment ? "T3 Code (Dev)" : "T3 Code (Alpha)";
const COMMIT_HASH_PATTERN = /^[0-9a-f]{7,40}$/i;
Expand Down Expand Up @@ -259,13 +260,15 @@ function resolveDesktopDevServerUrl(): string {

function backendChildEnv(): NodeJS.ProcessEnv {
const env = { ...process.env };
delete env.T3CODE_PORT;
delete env.T3CODE_MODE;
delete env.T3CODE_NO_BROWSER;
delete env.T3CODE_HOST;
delete env.T3CODE_DESKTOP_WS_URL;
delete env.T3CODE_DESKTOP_LAN_ACCESS;
delete env.T3CODE_DESKTOP_LAN_HOST;
for (const prefix of ["BCODE_", "T3CODE_"] as const) {
delete env[`${prefix}PORT`];
delete env[`${prefix}MODE`];
delete env[`${prefix}NO_BROWSER`];
delete env[`${prefix}HOST`];
delete env[`${prefix}DESKTOP_WS_URL`];
delete env[`${prefix}DESKTOP_LAN_ACCESS`];
delete env[`${prefix}DESKTOP_LAN_HOST`];
}
return env;
}

Expand All @@ -286,7 +289,7 @@ function getDesktopSecretStorage() {
}

function resolveAdvertisedHostOverride(): string | undefined {
const override = process.env.T3CODE_DESKTOP_LAN_HOST?.trim();
const override = readEnv("DESKTOP_LAN_HOST")?.trim();
return override && override.length > 0 ? override : undefined;
}

Expand Down Expand Up @@ -703,8 +706,8 @@ function resolveEmbeddedCommitHash(): string | null {

try {
const raw = FS.readFileSync(packageJsonPath, "utf8");
const parsed = JSON.parse(raw) as { t3codeCommitHash?: unknown };
return normalizeCommitHash(parsed.t3codeCommitHash);
const parsed = JSON.parse(raw) as { bcodeCommitHash?: unknown };
return normalizeCommitHash(parsed.bcodeCommitHash);
} catch {
return null;
}
Expand All @@ -715,7 +718,7 @@ function resolveAboutCommitHash(): string | null {
return aboutCommitHashCache;
}

const envCommitHash = normalizeCommitHash(process.env.T3CODE_COMMIT_HASH);
const envCommitHash = normalizeCommitHash(readEnv("COMMIT_HASH"));
if (envCommitHash) {
aboutCommitHashCache = envCommitHash;
return aboutCommitHashCache;
Expand Down Expand Up @@ -870,13 +873,13 @@ function dispatchMenuAction(action: string): void {

function handleCheckForUpdatesMenuClick(): void {
const hasUpdateFeedConfig =
readAppUpdateYml() !== null || Boolean(process.env.T3CODE_DESKTOP_MOCK_UPDATES);
readAppUpdateYml() !== null || Boolean(readEnv("DESKTOP_MOCK_UPDATES"));
const disabledReason = getAutoUpdateDisabledReason({
isDevelopment,
isPackaged: app.isPackaged,
platform: process.platform,
appImage: process.env.APPIMAGE,
disabledByEnv: process.env.T3CODE_DISABLE_AUTO_UPDATE === "1",
disabledByEnv: readEnv("DISABLE_AUTO_UPDATE") === "1",
hasUpdateFeedConfig,
});
if (disabledReason) {
Expand Down Expand Up @@ -1147,14 +1150,14 @@ function applyAutoUpdaterChannel(channel: DesktopUpdateChannel): void {

function shouldEnableAutoUpdates(): boolean {
const hasUpdateFeedConfig =
readAppUpdateYml() !== null || Boolean(process.env.T3CODE_DESKTOP_MOCK_UPDATES);
readAppUpdateYml() !== null || Boolean(readEnv("DESKTOP_MOCK_UPDATES"));
return (
getAutoUpdateDisabledReason({
isDevelopment,
isPackaged: app.isPackaged,
platform: process.platform,
appImage: process.env.APPIMAGE,
disabledByEnv: process.env.T3CODE_DISABLE_AUTO_UPDATE === "1",
disabledByEnv: readEnv("DISABLE_AUTO_UPDATE") === "1",
hasUpdateFeedConfig,
}) === null
);
Expand Down Expand Up @@ -1240,7 +1243,7 @@ async function installDownloadedUpdate(): Promise<{ accepted: boolean; completed

function configureAutoUpdater(): void {
const githubToken =
process.env.T3CODE_DESKTOP_UPDATE_GITHUB_TOKEN?.trim() || process.env.GH_TOKEN?.trim() || "";
readEnv("DESKTOP_UPDATE_GITHUB_TOKEN")?.trim() || process.env.GH_TOKEN?.trim() || "";
if (githubToken) {
// When a token is provided, re-configure the feed with `private: true` so
// electron-updater uses the GitHub API (api.github.com) instead of the
Expand All @@ -1256,10 +1259,10 @@ function configureAutoUpdater(): void {
}
}

if (process.env.T3CODE_DESKTOP_MOCK_UPDATES) {
if (readEnv("DESKTOP_MOCK_UPDATES")) {
autoUpdater.setFeedURL({
provider: "generic",
url: `http://localhost:${process.env.T3CODE_DESKTOP_MOCK_UPDATE_SERVER_PORT ?? 3000}`,
url: `http://localhost:${readEnv("DESKTOP_MOCK_UPDATE_SERVER_PORT") ?? 3000}`,
});
}

Expand Down Expand Up @@ -1406,7 +1409,7 @@ function startBackend(): void {
mode: "desktop",
noBrowser: true,
port: backendPort,
t3Home: BASE_DIR,
bcodeHome: BASE_DIR,
host: backendBindHost,
desktopBootstrapToken: backendBootstrapToken,
...(backendObservabilitySettings.otlpTracesUrl
Expand Down Expand Up @@ -2040,9 +2043,9 @@ configureAppIdentity();

async function bootstrap(): Promise<void> {
writeDesktopLogHeader("bootstrap start");
const configuredBackendPort = resolveConfiguredDesktopBackendPort(process.env.T3CODE_PORT);
const configuredBackendPort = resolveConfiguredDesktopBackendPort(readEnv("PORT"));
if (isDevelopment && configuredBackendPort === undefined) {
throw new Error("T3CODE_PORT is required in desktop development.");
throw new Error("BCODE_PORT is required in desktop development.");
}

backendPort =
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/updateState.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ describe("getAutoUpdateDisabledReason", () => {
disabledByEnv: true,
hasUpdateFeedConfig: true,
}),
).toContain("T3CODE_DISABLE_AUTO_UPDATE");
).toContain("BCODE_DISABLE_AUTO_UPDATE");
});

it("reports linux non-AppImage builds as disabled", () => {
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/updateState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export function getAutoUpdateDisabledReason(args: {
return "Automatic updates are only available in packaged production builds.";
}
if (args.disabledByEnv) {
return "Automatic updates are disabled by the T3CODE_DISABLE_AUTO_UPDATE setting.";
return "Automatic updates are disabled by the BCODE_DISABLE_AUTO_UPDATE setting.";
}
if (args.platform === "linux" && !args.appImage) {
return "Automatic updates on Linux require running the AppImage build.";
Expand Down
8 changes: 4 additions & 4 deletions apps/server/integration/perf/serverPerfHarness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,10 @@ import type {
import { seedPerfState, type PerfSeededState } from "./seedPerfState.ts";

const repoRoot = fileURLToPath(new URL("../../../../", import.meta.url));
const PERF_ARTIFACT_DIR_ENV = "T3CODE_PERF_ARTIFACT_DIR";
const PERF_PROVIDER_ENV = "T3CODE_PERF_PROVIDER";
const PERF_SCENARIO_ENV = "T3CODE_PERF_SCENARIO";
const AUTO_BOOTSTRAP_PROJECT_ENV = "T3CODE_AUTO_BOOTSTRAP_PROJECT_FROM_CWD";
const PERF_ARTIFACT_DIR_ENV = "BCODE_PERF_ARTIFACT_DIR";
const PERF_PROVIDER_ENV = "BCODE_PERF_PROVIDER";
const PERF_SCENARIO_ENV = "BCODE_PERF_SCENARIO";
const AUTO_BOOTSTRAP_PROJECT_ENV = "BCODE_AUTO_BOOTSTRAP_PROJECT_FROM_CWD";

const makeWsRpcClient = RpcClient.make(WsRpcGroup);
type WsRpcClient =
Expand Down
Loading
Loading