Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
4a39cad
fix(web): offer recovery from missing pages (#11314)
shivamhwp Sep 13, 2026
e628683
fix(web): retry startup after the server recovers (#11291)
shivamhwp Sep 13, 2026
ca2cc13
feat(web): add optional compact sidebar rail (#11525)
maria-rcks Sep 13, 2026
42b6bcc
feat(web): add opt-in in-app thread notifications (#11570)
Bil0000 Sep 13, 2026
f26198d
feat(web): organize connections by environment (#11542)
maria-rcks Sep 13, 2026
0118b52
fix(web): keep sparse sidebar shelves at the bottom (#11595)
maria-rcks Sep 13, 2026
9bf349c
fix(cursor): preserve internal agent errors without transport labels …
shivamhwp Sep 13, 2026
dd6ba84
fix(server): fall back when new worktrees are unavailable (#6208)
tris203 Sep 13, 2026
6e5e986
feat: badge background thread notifications on desktop and web (#11569)
Bil0000 Sep 13, 2026
77bca8b
feat(web): add compact thread list mode (#9417)
saphid Sep 13, 2026
df7ccc8
feat(web): refine compact thread row badges (#11644)
maria-rcks Sep 13, 2026
7b61099
feat(web): show the linked pull request in the compact sidebar rail (…
maria-rcks Sep 13, 2026
9086a1f
fix(mobile): adopt system glass for Live Activities (#11604)
juliusmarminge Sep 13, 2026
3689c98
fix(web): separate expanded tool output from adjacent hover highlight…
dominic-r Sep 13, 2026
66e39ca
fix(web): apply device settings to selected environments (#11541)
juliusmarminge Sep 14, 2026
c07575f
feat(server): show finished paragraphs and code blocks while the resp…
t3dotgg Sep 14, 2026
2d73746
fix(web): disconnect offline servers from threads (#11671)
t3dotgg Sep 14, 2026
5e961d3
feat(web): flatten the connections page into one environments list (#…
t3dotgg Sep 14, 2026
5647191
fix(mobile): keep usage widget rows consistently sized (#11669)
juliusmarminge Sep 14, 2026
3b75e60
feat(server): add reusable auth token for dev worktrees (#8606)
t3dotgg Sep 14, 2026
1bbca0e
feat(settings): choose how responses stream, with a warning on legacy…
t3dotgg Sep 14, 2026
d81278a
revert(web): remove the compact sidebar (#11685)
maria-rcks Sep 14, 2026
683aa87
build(desktop): bundle the main process and stage only its native ext…
juliusmarminge Sep 14, 2026
06de59b
build(server): make the CLI bundle loadable as a Node single-executab…
juliusmarminge Sep 14, 2026
eb8f6f4
ci(release): build, sign, and publish self-contained CLI archives (#1…
juliusmarminge Sep 14, 2026
8f90b38
feat(server): install preview runtimes from release archives (#11318)
juliusmarminge Sep 14, 2026
13c134c
feat(ssh): run preview builds on remotes from the release archive (#1…
juliusmarminge Sep 14, 2026
c7f23c4
feat(cli): add t3 update for self-contained installs (#11451)
juliusmarminge Sep 14, 2026
af6c138
feat(server): manage runtimes as release archives only, never from np…
juliusmarminge Sep 14, 2026
0754920
feat(desktop): run the WSL backend from the Linux CLI archive (#11511)
juliusmarminge Sep 14, 2026
2c54f2f
ci(release): build CLI archives for five targets, each on its own arc…
juliusmarminge Sep 14, 2026
2f7616e
ci(release): build the JS bundle once and run every platform and arch…
juliusmarminge Sep 14, 2026
91cd91c
feat(release): publish npx t3 as a launcher over per-platform executa…
juliusmarminge Sep 14, 2026
b70015b
feat(cli): add t3 uninstall for self-contained installs (#11659)
juliusmarminge Sep 14, 2026
73b206f
feat(web): show each worktree setup step and let users cancel it (#11…
t3dotgg Sep 14, 2026
1ced38a
fix(server): skip device hosts that resolve to the local machine (#11…
juliusmarminge Sep 14, 2026
8984f81
fix(web): test device hosts across selected environments (#11699)
juliusmarminge Sep 14, 2026
0b54e00
Change input type from 'full_diff' to 'incremental'
juliusmarminge Sep 14, 2026
e3792a5
Update model and input type in ui-consistency.md
juliusmarminge Sep 14, 2026
cba7dd7
feat(desktop): allow disabling the local environment (#9194)
juliusmarminge Sep 14, 2026
d8655ed
feat(cli): add t3 service restart and make t3 update repoint the serv…
juliusmarminge Sep 14, 2026
01e05c1
docs(claude): clarify OpenRouter model selection (#11369)
shivamhwp Sep 14, 2026
0dec07d
fix(web): keep large image previews from stalling composer typing (#1…
shivamhwp Sep 14, 2026
8ef478e
fix(server): avoid extra round trips for terminal output (#11407)
Bil0000 Sep 14, 2026
6f00d38
fix(web): remember panel width for each thread (#11310)
shivamhwp Sep 14, 2026
9375c77
fix(release): preserve updates from npm-based services (#11732)
t3dotgg Sep 14, 2026
8b1ea4d
fix(desktop): restore Node discovery for WSL providers (#11741)
akj Sep 14, 2026
ae67c5b
fix(release): stop npm from pruning the platform packages' shipped no…
juliusmarminge Sep 14, 2026
955b787
fix(server): parse CLI versions with a "v" prefix (#11738)
NikodemNowak Sep 14, 2026
05e3bcb
fix(desktop): keep preview releases out of the nightly update changel…
juliusmarminge Sep 14, 2026
ec5ede5
fix(web): open video attachment thumbnails in the viewer (#11734)
chrisdeeming Sep 14, 2026
494cfac
Allow setting T3CODE_OTLP_HEADERS (#11218)
bahlo Sep 14, 2026
47ace94
fix(web): use consistent PR section toggles (#11763)
Bil0000 Sep 14, 2026
33118d9
Add T3CODE_OTLP_PROTOCOL to allow protobuf protocol (#11224)
bahlo Sep 14, 2026
9130d93
feat(web): add composer and PR number shortcuts (#11615)
Bil0000 Sep 14, 2026
f328db3
chore(server): keep the legacy service entry point to the npm package…
juliusmarminge Sep 14, 2026
112a708
fix(web): use project monograms for automatic icon fallbacks (#11572)
ShpetimA Sep 14, 2026
8d7c700
feat(web): clone repositories in the background instead of holding th…
juliusmarminge Sep 14, 2026
549d182
feat(mobile): clone repositories in the background and gate the draft…
juliusmarminge Sep 14, 2026
9d4bb55
fix(mobile): scale inline pills with Dynamic Type (#11792)
juliusmarminge Sep 14, 2026
bcc2024
chore(deps): bump the Clerk stack to current releases (#11764)
juliusmarminge Sep 14, 2026
0f21fcb
feat(mobile): add a T3 Connect page to the Clerk profile (#11765)
juliusmarminge Sep 14, 2026
dc0869b
feat(server): use Clerk's device authorization grant for headless con…
juliusmarminge Sep 14, 2026
8419238
Add new GitHub user f-trycua
juliusmarminge Sep 14, 2026
7931227
fix(server): stop refreshing providers on every config subscription (…
juliusmarminge Sep 14, 2026
5bf43c9
fix(web): align monogram project icons in menus (#11806)
juliusmarminge Sep 14, 2026
9a49d6d
ci(desktop): sign fork PR macOS previews without exposing signing sec…
juliusmarminge Sep 14, 2026
014016a
fix(web): make copy PR link discoverable in keybindings (#11826)
Bil0000 Sep 15, 2026
3be02ae
feat: add custom snooze dates and durations (#11800)
juliusmarminge Sep 15, 2026
ea6af59
feat(mobile): redesign the Android agent activity card (#11645)
SunkenInTime Sep 15, 2026
6dbea7e
chore(mobile): bump app version to 1.2.0
t3-code[bot] Sep 15, 2026
5ea6439
feat(web): inline worktree setup rows and async setup scripts (#11832)
juliusmarminge Sep 15, 2026
765298e
chore: merge upstream/main while preserving fork features
Fryuni Sep 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .github/VOUCHED.td
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ github:D3OXY
github:dbalders
github:eggfriedrice24
github:extoci
github:f-trycua
github:flamboh
github:FllipEis
github:gbarros-dev
Expand Down
76 changes: 76 additions & 0 deletions .github/scripts/stage-preview-bundle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
"""Stage an untrusted preview ZIP without letting it replace packaging code."""

import shutil
import stat
import sys
import zipfile
from pathlib import Path

ROOTS = ("server/dist", "desktop/dist-electron")
REQUIRED_FILES = {
"server/dist/bin.mjs",
"server/dist/client/index.html",
"desktop/dist-electron/main.cjs",
}
# The current bundle is about 32 MiB compressed. Bound extraction on the
# trusted runner even when the PR replaces the uploader entirely.
MAX_ARCHIVE_BYTES = 512 * 1024 * 1024
MAX_EXPANDED_BYTES = 2 * 1024 * 1024 * 1024
MAX_ENTRIES = 50_000


def stage_bundle(archive: Path, destination: Path):
if archive.stat().st_size > MAX_ARCHIVE_BYTES:
raise ValueError("Preview archive is too large")
with zipfile.ZipFile(archive) as bundle:
entries = bundle.infolist()
if len(entries) > MAX_ENTRIES:
raise ValueError("Preview archive has too many entries")
if sum(entry.file_size for entry in entries) > MAX_EXPANDED_BYTES:
raise ValueError("Expanded preview bundle is too large")
seen = set()
files = set()
for entry in entries:
name = entry.filename.removesuffix("/")
parts = name.split("/")
# Reject ambiguous paths before normalization, including names
# that would alias on the macOS signing runner.
if (
entry.orig_filename != entry.filename
or any(part in ("", ".", "..") for part in parts)
or any(char in name for char in "\\:")
or not name.isascii()
or any(ord(char) < 32 or ord(char) == 127 for char in name)
):
raise ValueError(f"Unsafe preview path: {entry.filename!r}")
allowed = any(name.startswith(root + "/") for root in ROOTS)
if entry.is_dir():
allowed |= any(root == name or root.startswith(name + "/") for root in ROOTS)
if not allowed:
raise ValueError(f"Unexpected preview path: {name!r}")
kind = stat.S_IFMT(entry.external_attr >> 16)
if kind not in (0, stat.S_IFDIR if entry.is_dir() else stat.S_IFREG):
raise ValueError(f"Non-regular preview entry: {name!r}")
if name.casefold() in seen:
raise ValueError(f"Duplicate preview path: {name!r}")
seen.add(name.casefold())
if not entry.is_dir():
files.add(name)
if not REQUIRED_FILES <= files:
raise ValueError("Preview bundle is missing required entry points")
# Validate all names before writing anything. This is a fresh directory
# outside the checkout; neither pre-existing links nor trusted files
# can be followed or overwritten. ZIP permissions are never restored.
destination.mkdir(parents=True, exist_ok=False)
for entry in entries:
target = destination / entry.filename
if entry.is_dir():
target.mkdir(parents=True, exist_ok=True)
else:
target.parent.mkdir(parents=True, exist_ok=True)
with bundle.open(entry) as source, target.open("xb") as output:
shutil.copyfileobj(source, output)


if __name__ == "__main__":
stage_bundle(Path(sys.argv[1]), Path(sys.argv[2]))
97 changes: 97 additions & 0 deletions .github/scripts/stage-preview-bundle.test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import importlib.util
import stat
import tempfile
import unittest
import zipfile
from pathlib import Path
from unittest.mock import patch

spec = importlib.util.spec_from_file_location(
"stage_preview_bundle", Path(__file__).with_name("stage-preview-bundle.py")
)
staging = importlib.util.module_from_spec(spec)
spec.loader.exec_module(staging)


class StagePreviewBundleTests(unittest.TestCase):
def setUp(self):
self.temp = tempfile.TemporaryDirectory()
self.addCleanup(self.temp.cleanup)
self.root = Path(self.temp.name)
self.archive = self.root / "bundle.zip"
self.destination = self.root / "staged"

def bundle(self, extra=(), missing=None):
with zipfile.ZipFile(self.archive, "w") as bundle:
for name in sorted(staging.REQUIRED_FILES - {missing}):
bundle.writestr(name, b"bundle data, never executed")
for name, content in extra:
bundle.writestr(name, content)

def stage(self):
staging.stage_bundle(self.archive, self.destination)

def test_preserves_valid_bundle_layout_and_bytes(self):
self.bundle([("server/", b""), ("server/dist/", b""),
("desktop/dist-electron/chunks/helper.cjs", b"chunk")])
self.stage()
for name in staging.REQUIRED_FILES:
self.assertEqual((self.destination / name).read_bytes(), b"bundle data, never executed")
self.assertEqual((self.destination / "desktop/dist-electron/chunks/helper.cjs").read_bytes(), b"chunk")

def test_rejects_builder_overwrite_and_unsafe_paths_before_writing(self):
for name in [
"desktop/node_modules/electron-builder/cli.js",
"desktop/package.json",
"server/dist/../../desktop/package.json",
"../package.json",
"/server/dist/absolute",
"server/dist/./alias",
"server/dist//alias",
"server/dist/back\\slash",
"server/dist/file:stream",
"server/dist/BIN.MJS",
]:
with self.subTest(name=name):
self.bundle([(name, b"untrusted")])
with self.assertRaises(ValueError):
self.stage()
self.assertFalse(self.destination.exists())

def test_rejects_links_and_special_files(self):
for mode in [stat.S_IFLNK, stat.S_IFIFO, stat.S_IFCHR]:
with self.subTest(mode=mode):
entry = zipfile.ZipInfo("server/dist/link")
entry.create_system = 3
entry.external_attr = (mode | 0o777) << 16
self.bundle([(entry, b"../../../desktop/node_modules")])
with self.assertRaises(ValueError):
self.stage()
self.assertFalse(self.destination.exists())

def test_requires_entry_points(self):
self.bundle(missing="desktop/dist-electron/main.cjs")
with self.assertRaises(ValueError):
self.stage()
self.assertFalse(self.destination.exists())

def test_bounds_archive_size_expanded_size_and_entry_count(self):
for limit in ["MAX_ARCHIVE_BYTES", "MAX_EXPANDED_BYTES", "MAX_ENTRIES"]:
with self.subTest(limit=limit), patch.object(staging, limit, 1):
self.bundle()
with self.assertRaises(ValueError):
self.stage()
self.assertFalse(self.destination.exists())

def test_refuses_existing_destination(self):
self.bundle()
self.destination.mkdir()
sentinel = self.destination / "trusted"
sentinel.write_text("untouched")
with self.assertRaises(FileExistsError):
self.stage()
self.assertEqual(sentinel.read_text(), "untouched")


if __name__ == "__main__":
unittest.main()
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ jobs:
run: |
sudo apt-get update && sudo apt-get install -y libsecret-1-dev pkg-config

- name: Test preview artifact validation
run: python3 -B .github/scripts/stage-preview-bundle.test.py

- name: Test workflow scripts
run: node --test .github/scripts/*.test.cjs

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ node_modules
*.log
*.tsbuildinfo
apps/*/dist
apps/*/dist-exe
infra/*/dist
.astro
packages/*/dist
Expand Down
2 changes: 1 addition & 1 deletion .macroscope/check-run-agents/effect-service-conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Effect Service Conventions
model: gpt-5-6-sol
effort: medium
input: full_diff
input: incremental
tools:
- browse_code
- modify_pr
Expand Down
4 changes: 2 additions & 2 deletions .macroscope/check-run-agents/ui-consistency.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
---
title: UI Consistency
model: gpt-5-6-terra
model: gpt-5-6-sol
effort: medium
input: full_diff
input: incremental
tools:
- browse_code
- modify_pr
Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ The most common defect in this repo is a change that works on the path you teste
- `vp i` installs. Worktrees get this from the t3.json setup script; if module resolution looks broken, it probably did not run.
- `vp run dev` starts server and web. In a worktree, state defaults to that worktree's gitignored `.t3`, which deliberately outranks an ambient `T3CODE_HOME` so you cannot land on shared state by accident. An explicit `--home-dir` still wins.
- Ports derive from the worktree path and are stable across restarts, but read the real ones from the `[dev-runner]` line since occupied ports shift.
- Sharing over the tailnet is three steps: run `vp run dev --share` in the background, wait for the `pairingUrl:` line in its output, paste that full URL (token included) in your reply. Do not wire up `tailscale serve` by hand for this, and do not open the URL yourself.
- The web app requires pairing. Hand over the pairing URL, not the bare origin. A URL without its token is useless to whoever you gave it to. If the token got consumed, mint a fresh one with `node apps/server/src/bin.ts pair` — note it carries standard scopes, while the startup URL carries admin scopes (needed for Settings → Connections management).
- Sharing over the tailnet is three steps: run `vp run dev --share` in the background, wait for the `pairingUrl:` line in its output, then give that full URL to an unpaired browser. Do not wire up `tailscale serve` by hand, open the URL yourself, or consume the user's pairing link. A browser with the reusable dev cookie can use the bare origin. If a normal one-time token was consumed, mint a fresh one with `node apps/server/src/bin.ts pair`. It carries standard scopes, while the startup URL carries admin scopes needed for Connections settings.
- To reuse web dev auth across worktrees, configure one fixed `T3CODE_DEV_AUTH_TOKEN` in the main checkout's gitignored `.env`. The `t3.json` setup links that file into worktrees. Never commit or publish the token or a startup URL. See [Reusable dev credential](docs/operations/development.md#reusable-dev-credential).
- Stop what you started, by the PID you tracked. See rule 1.

## Test data
Expand Down
2 changes: 2 additions & 0 deletions apps/desktop/scripts/electron-launcher.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ export function makeDevelopmentEnvironmentScript(environment) {
["T3CODE_COMMIT_HASH", environment.T3CODE_COMMIT_HASH],
["T3CODE_OTLP_TRACES_URL", environment.T3CODE_OTLP_TRACES_URL],
["T3CODE_OTLP_EXPORT_INTERVAL_MS", environment.T3CODE_OTLP_EXPORT_INTERVAL_MS],
["T3CODE_OTLP_HEADERS", environment.T3CODE_OTLP_HEADERS],
["T3CODE_OTLP_PROTOCOL", environment.T3CODE_OTLP_PROTOCOL],
["T3CODE_DESKTOP_APP_USER_MODEL_ID", APP_BUNDLE_ID],
].filter((entry) => typeof entry[1] === "string" && entry[1].trim().length > 0);
return [
Expand Down
5 changes: 5 additions & 0 deletions apps/desktop/scripts/electron-launcher.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,17 @@ describe("electron development launcher", () => {
VITE_DEV_SERVER_URL: "http://127.0.0.1:8526",
T3CODE_PORT: "16566",
T3CODE_HOME: "/tmp/t3",
T3CODE_OTLP_PROTOCOL: "http/protobuf",
});

assert.include(
environmentScript,
"if [ -z \"${VITE_DEV_SERVER_URL:-}\" ]; then export VITE_DEV_SERVER_URL='http://127.0.0.1:8526'; fi",
);
assert.include(
environmentScript,
"if [ -z \"${T3CODE_OTLP_PROTOCOL:-}\" ]; then export T3CODE_OTLP_PROTOCOL='http/protobuf'; fi",
);
assert.notInclude(environmentScript, "\nexport VITE_DEV_SERVER_URL=");
});

Expand Down
57 changes: 34 additions & 23 deletions apps/desktop/src/app/DesktopApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,18 +158,43 @@ export const stopAllPoolInstances = Effect.fn("desktop.app.stopAllPoolInstances"
);

const bootstrap = Effect.gen(function* () {
const pool = yield* DesktopBackendPool.DesktopBackendPool;
const primaryBackend = yield* pool.primary;
const state = yield* DesktopState.DesktopState;
const environment = yield* DesktopEnvironment.DesktopEnvironment;
const desktopSettings = yield* DesktopAppSettings.DesktopAppSettings;
const serverExposure = yield* DesktopServerExposure.DesktopServerExposure;
const wslBackend = yield* DesktopWslBackend.DesktopWslBackend;
const desktopWindow = yield* DesktopWindow.DesktopWindow;
const snapShot = yield* DesktopSnapShot.DesktopSnapShot;
const appActivation = yield* DesktopAppActivation.DesktopAppActivation;
yield* logBootstrapInfo("bootstrap start");

const settings = yield* desktopSettings.get;
// The renderer is served from the bundled client (or Vite in development)
// rather than through the local backend, so the window can open without one.
const electronProtocol = yield* ElectronProtocol.ElectronProtocol;
yield* electronProtocol.registerDesktopProtocol({
scheme: ElectronProtocol.getDesktopScheme(environment.isDevelopment),
...(environment.isDevelopment
? { targetOrigin: Option.getOrThrow(environment.devServerUrl) }
: { assetDirectory: environment.clientAssetsDir }),
clerkFrontendApiHostname: DesktopClerk.desktopClerkFrontendApiHostname,
});
yield* installDesktopIpcHandlers();
yield* logBootstrapInfo("bootstrap ipc handlers registered");

yield* snapShot.initialize;

if (!settings.localEnvironmentEnabled) {
yield* logBootstrapInfo("bootstrap skipping local environment (disabled in settings)");
if (!(yield* Ref.get(state.quitting))) {
yield* desktopWindow.createMainIfBackendReady;
}
return;
}

const pool = yield* DesktopBackendPool.DesktopBackendPool;
const primaryBackend = yield* pool.primary;
const serverExposure = yield* DesktopServerExposure.DesktopServerExposure;
const wslBackend = yield* DesktopWslBackend.DesktopWslBackend;

if (environment.isDevelopment && Option.isNone(environment.configuredBackendPort)) {
return yield* new DesktopDevelopmentBackendPortRequiredError();
}
Expand All @@ -186,24 +211,13 @@ const bootstrap = Effect.gen(function* () {
},
);

const settings = yield* desktopSettings.get;
if (settings.serverExposureMode !== environment.defaultDesktopSettings.serverExposureMode) {
yield* logBootstrapInfo("bootstrap restoring persisted server exposure mode", {
mode: settings.serverExposureMode,
});
}
const serverExposureState = yield* serverExposure.configureFromSettings({ port: backendPort });
const backendConfig = yield* serverExposure.backendConfig;
const electronProtocol = yield* ElectronProtocol.ElectronProtocol;
const rendererTarget = environment.isDevelopment
? Option.getOrThrow(environment.devServerUrl)
: backendConfig.httpBaseUrl;
yield* electronProtocol.registerDesktopProtocol({
scheme: ElectronProtocol.getDesktopScheme(environment.isDevelopment),
targetOrigin: rendererTarget,
backendOrigin: backendConfig.httpBaseUrl,
clerkFrontendApiHostname: DesktopClerk.desktopClerkFrontendApiHostname,
});
yield* logBootstrapInfo("bootstrap resolved backend endpoint", {
baseUrl: backendConfig.httpBaseUrl.href,
});
Expand All @@ -219,16 +233,13 @@ const bootstrap = Effect.gen(function* () {
"bootstrap fell back to local-only because no advertised network host was available",
);
}
yield* snapShot.initialize;

yield* installDesktopIpcHandlers();
yield* logBootstrapInfo("bootstrap ipc handlers registered");

if (!(yield* Ref.get(state.quitting))) {
// In wsl-only mode the renderer is served by the WSL backend, which can be
// slow to cold-boot — show a "Connecting to WSL" splash immediately so the
// app feels responsive instead of presenting no window until WSL is ready.
// (Dual mode opens fast off the Windows primary, so no splash there.)
// The main window waits for the primary backend. In wsl-only mode that is
// the WSL backend, which can be slow to cold-boot — show a "Connecting to
// WSL" splash immediately so the app feels responsive instead of presenting
// no window until WSL is ready. (Dual mode opens fast off the Windows
// primary, so no splash there.)
if (settings.wslOnly === true && settings.wslBackendEnabled === true) {
yield* desktopWindow.showConnectingSplash;
}
Expand Down
5 changes: 5 additions & 0 deletions apps/desktop/src/app/DesktopConfig.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { OtlpHeadersFromString, OtlpProtocol } from "@t3tools/shared/observability";
import * as Config from "effect/Config";
import * as ConfigProvider from "effect/ConfigProvider";
import * as Option from "effect/Option";
Expand Down Expand Up @@ -48,6 +49,10 @@ export const DesktopConfig = Config.all({
otlpExportIntervalMs: Config.int("T3CODE_OTLP_EXPORT_INTERVAL_MS").pipe(
Config.withDefault(10_000),
),
otlpHeaders: Config.schema(OtlpHeadersFromString, "T3CODE_OTLP_HEADERS").pipe(Config.option),
otlpProtocol: Config.schema(OtlpProtocol, "T3CODE_OTLP_PROTOCOL").pipe(
Config.withDefault("http/json"),
),
appImagePath: trimmedString("APPIMAGE"),
disableAutoUpdate: optionalBoolean("T3CODE_DISABLE_AUTO_UPDATE"),
mockUpdates: optionalBoolean("T3CODE_DESKTOP_MOCK_UPDATES"),
Expand Down
Loading
Loading