Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
f0ebc62
fix(web): improve Codex usage graph contrast (#6669)
StiensWout Aug 15, 2026
e9ae134
docs: route feature requests to Discussions
juliusmarminge Aug 15, 2026
d8a6dfd
fix(desktop): app zoom no longer zooms the preview browser (#6649)
juliusmarminge Aug 15, 2026
afca73d
fix(server): keep provider notification consumers alive past startSes…
tsouth89 Aug 15, 2026
7547280
fix(server): treat removed Bitbucket permissions endpoint as unknown,…
lnieuwenhuis Aug 15, 2026
672216d
fix(ssh): let cold remote servers finish starting (#6168)
gbarros-dev Aug 15, 2026
1e87029
fix(web): preserve Claude insight line breaks (#4344)
nateEc Aug 15, 2026
a6ac27e
feat(web): accept file drops across the chat workspace (#6636)
dbalders Aug 15, 2026
eaa6c47
fix(web): widen ordered-list marker gutter for 3+ digit item numbers …
lnieuwenhuis Aug 15, 2026
71c6f82
fix(server): bound thread activity hydration (#6153)
t3-code[bot] Aug 15, 2026
48cba7d
fix(web): restore the Archive action in the default sidebar thread me…
lnieuwenhuis Aug 15, 2026
9f26656
fix(web): open diff files from nested projects (#6174)
gbarros-dev Aug 15, 2026
b277cc6
fix(mobile): use tryOpenExternalUrl for markdown links in ThreadFeed …
mohamedmastouri-hue Aug 15, 2026
2cb1a26
fix(web): open the file a bare filename reference names (#6297)
Brechard Aug 15, 2026
ddee418
fix(server): stop the provider title mirror from overwriting real thr…
repparw Aug 15, 2026
178da6b
fix(shared): match source-control providers by DNS label (#6175)
gbarros-dev Aug 15, 2026
b7dbbba
feat(desktop): Chrome-style hold-to-quit (#5508)
Bil0000 Aug 15, 2026
d94fbda
fix(gitlab): submit review comments on context lines (#6348)
tarik02 Aug 15, 2026
db3278f
fix(marketing): keep Grok mark clear of mobile hero copy (#4542)
NicL9923 Aug 15, 2026
3bc4fdf
fix(mobile): recover the QR pairing scanner when camera access is den…
hey-jj Aug 15, 2026
a38cac8
fix(web): keep a long path from running under the folder picker butto…
Sy-D Aug 15, 2026
270489b
fix(terminal): right-click paste works in the terminal (#5240)
StiensWout Aug 15, 2026
4db5075
fix(mobile): explain iOS-only settings on Android (#4981)
danvernon Aug 15, 2026
9bdd912
fix(web): stop counting a workflow coordinator as a working agent (#6…
Rishet11 Aug 15, 2026
6e6d1b4
fix(web): keep floating preview anchored after panel closes (#6547)
AksharP5 Aug 15, 2026
a7c5ad5
fix(web): unstick /connect after in-modal sign-in by redirecting to t…
TorbenWetter Aug 15, 2026
7afa184
fix(web): keep send reachable while a turn is running on mobile (#4781)
AMohamedAakhil Aug 15, 2026
34a12bc
fix(web): reject unsupported composer image types at attach time (#6574)
mdshzb04 Aug 15, 2026
5ffbf3c
Make ClaudeTextGeneration tests hermetic on Windows (#4508)
mihneaptu Aug 15, 2026
143f713
fix(web): show command output in work log (#4083)
LikoKiko Aug 15, 2026
06dd999
fix(web): reserve sibling column width when resizing the right panel …
Lasdw6 Aug 15, 2026
9e61d0f
fix(web): replace whitespace in new ref names with dashes (#6270)
jorj-pineda Aug 15, 2026
c7b14a8
fix(client-runtime): branch list no longer resets while paging throug…
a20hek Aug 15, 2026
b0de385
fix(web): support Shift+Insert terminal paste (#5982)
aoright Aug 15, 2026
d79f975
fix(web): keep the composer glass aligned with the context strip at a…
Williawar Aug 15, 2026
135dc15
fix(codex): keep background memory out of chats (#5468)
AksharP5 Aug 15, 2026
51c6daa
fix(server): treat a missing Codex rollout as a recoverable resume er…
Rishet11 Aug 15, 2026
3cde99b
fix(web): hide provider Update toast action while an update is runnin…
mrmg Aug 15, 2026
e204f5a
fix(desktop): agent shells inherit a UTF-8 locale on macOS (#6236)
Linus-Boehm Aug 15, 2026
474cc5f
fix(server): ignore Claude command lifecycle messages (#6606)
naveed949 Aug 15, 2026
402c9e0
docs: mention Bitbucket user read scope needed by auth probe (#6291)
thamrx Aug 15, 2026
551f4c9
fix(server): return valid preview action results (#5966)
duncan-vc Aug 15, 2026
e9e4697
fix(claude): make "Always allow for session" stick, and only for the …
kakismash Aug 15, 2026
9d0f2fc
fix(ssh): surface a failed remote t3 install instead of a silent 0-by…
TorbenWetter Aug 15, 2026
f075a58
perf(server): persist the wire projection for streaming tool.updated …
mInrOz Aug 15, 2026
c4556ab
fix(web): stop wrapping partial code block selections in markdown fen…
JoeJoeflyn Aug 15, 2026
efe1773
fix(web): hide T3 Connect toggle in web app settings (#5068)
JoeJoeflyn Aug 15, 2026
a5d3532
fix(web): show provider account accent badge in sidebar rows and hove…
vitalyiegorov Aug 15, 2026
c0f9d91
fix(server): wait for concurrent SQLite writers instead of failing wi…
ostapondo Aug 15, 2026
7c55e86
fix(web): reject oversized prompts before provider turn start (#6602)
naveed949 Aug 15, 2026
40ab7bf
feat(web): collapse the question prompt from its header (#6773)
Jardo-51 Aug 15, 2026
684d703
fix(shared): degrade an unknown system time zone to UTC in usage wind…
Rishet11 Aug 15, 2026
ad47d23
fix(claude): discover repo-local .agents/skills in skill discovery (#…
RoshanMhatre Aug 15, 2026
d715c2e
fix(server): let slow provider CLIs raise their discovery probe budge…
CDVolvik Aug 15, 2026
d5465ae
fix(web): retain terminal PR badges after checkout switch (#4755)
sebbonit Aug 15, 2026
ca37b19
fix(web): show selected model in context window tooltip (#4772)
nqrwhal Aug 15, 2026
5e14737
fix(web): scale command details with code font (#6510)
Serendeep Aug 15, 2026
cf7bfd1
fix(web): preserve XML-like tags in user messages (#4133)
0utsights Aug 15, 2026
7c8848e
fix(desktop): route mouse thumb buttons to the in-app browser (#4459)
akosbalogh Aug 15, 2026
f915320
fix(web): keep the final segment of directory paths with a trailing s…
jorvarea Aug 15, 2026
7083bce
Keep block code plain when copying from rendered markdown (#4468)
yashranaway Aug 15, 2026
21b6fb5
fix(web): add web app manifest so installed app keeps its scope (#4306)
Albro3459 Aug 15, 2026
db02c6b
Skip user hooks during Claude capability probes (#4466)
yashranaway Aug 15, 2026
31d0fb6
fix(mobile): use Android monospace font family (#4609)
tastelessjolt Aug 15, 2026
b72d5d7
fix(desktop): timestamps follow the OS locale instead of en-US (#6190)
brzzdev Aug 15, 2026
1a5ff42
fix(web): keep multi-select questions open after the first click (#6646)
RaitP1 Aug 15, 2026
d550b82
fix(web): stop clipping the changed-files expand hover on Windows (#6…
mrmg Aug 15, 2026
86fb47a
fix(server): allow long-running git pushes (#6499)
devchaudhary24k Aug 15, 2026
160c76c
fix(desktop): keep probing backend readiness while the process is ali…
lgwacker Aug 15, 2026
dc0ff8f
fix(server): allow install scripts in npm-global provider updates (#5…
hey-jj Aug 15, 2026
7ce4194
fix: detect SSH remotes with non-git user prefixes (e.g. gitlab@) (#3…
JackatDJL Aug 15, 2026
39167eb
fix(web): describe what Ultracode does in the Reasoning picker (#6092)
delltrak Aug 15, 2026
3b54a2a
fix(server): settle pending user-input requests when a Claude session…
AaronAbuUsama Aug 15, 2026
4fc80fc
fix(server): stop replaying a command receipt for a different aggrega…
ostapondo Aug 15, 2026
07e668d
fix(server): settle snoozed threads immediately (#5379)
0bkevin Aug 15, 2026
277a7cb
fix(mobile): prevent crash on sign out in settings (#4899)
shubhu121 Aug 15, 2026
f8bb92b
fix(mobile): local-checkout threads record their branch so PR badges …
Zeus-Deus Aug 15, 2026
62bb974
fix(web): contain long approval commands (#6503)
Serendeep Aug 15, 2026
e17f244
feat(web): make right panel maximize bindable (#5091)
husseinraoouf Aug 15, 2026
61b2e74
fix(server): respect inherited OPENCODE_CONFIG_CONTENT (#4242)
jonocodes Aug 15, 2026
04f2309
fix(marketing): detect Mac chip on homepage download button (#4197)
mahdibm-dev Aug 15, 2026
931e915
Keep the server alive when a response write hits a dead socket (#4470)
yashranaway Aug 15, 2026
664499c
Limit physical key fallback to non-Latin layout output (#4469)
yashranaway Aug 15, 2026
2fc6762
fix: restore CLAUDE.md symlink target (#3929)
NgoQuocViet2001 Aug 15, 2026
ec141c1
fix(clients): default clone destination to folder plus repo name (#5989)
inayayousfi Aug 15, 2026
20a7042
fix(web): keep timestamp date and time in the same locale (#7081)
juliusmarminge Aug 15, 2026
b3cd1e5
merge: sync upstream through 20a70420a
omegent-app[bot] Aug 15, 2026
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
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ body:
attributes:
value: |
Use this form for broken behavior, regressions, crashes, or reliability problems.
Feature requests belong in [Discussions](https://github.com/pingdotgg/t3code/discussions/categories/ideas).
Search existing issues first and keep the report focused on one problem.
- type: checkboxes
Expand Down
5 changes: 5 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Feature request
url: https://github.com/pingdotgg/t3code/discussions/categories/ideas
about: Suggest an improvement or new capability in Discussions.
102 changes: 0 additions & 102 deletions .github/ISSUE_TEMPLATE/feature_request.yml

This file was deleted.

1 change: 1 addition & 0 deletions .github/pr-assets/6424-after.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions .github/pr-assets/6424-before.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions .github/pr-assets/6503-after.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 5 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

We are not actively accepting contributions right now.

You can still open an issue or PR, but please do so knowing there is a high chance we close it, defer it forever, or never look at it.
You can still report a bug or open a PR, but please do so knowing there is a high chance we close it, defer it forever, or never look at it.

Feature requests and proposals belong in [Ideas discussions](https://github.com/pingdotgg/t3code/discussions/categories/ideas), not issues.

If that sounds annoying, that is because it is. This project is still early and we are trying to keep scope, quality, and direction under control.

Expand Down Expand Up @@ -50,9 +52,9 @@ If the change depends on motion, timing, transitions, or interaction details, in

If we have to guess what changed, we are much less likely to review it.

## Issues First
## Discuss Changes First

If you are thinking about a non-trivial change, open an issue first.
If you are thinking about a non-trivial change, start a discussion first. Issues are reserved for bug reports.

That still does not mean we will want the PR, but it gives you a chance to avoid wasting your time.

Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ Checkout their getting started guide for more information: https://viteplus.dev/
vp i
```

Read [CONTRIBUTING.md](./CONTRIBUTING.md) before opening an issue or PR.
Read [CONTRIBUTING.md](./CONTRIBUTING.md) before reporting a bug or opening a PR.

Have a feature request? Start an [Ideas discussion](https://github.com/pingdotgg/t3code/discussions/categories/ideas).

Need support? Join the [Discord](https://discord.gg/jn4EGJjrvv).
1 change: 1 addition & 0 deletions apps/desktop/src/app/DesktopAppIdentity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const makeElectronAppLayer = (calls: ElectronAppCalls) =>
Layer.succeed(ElectronApp.ElectronApp, {
metadata: Effect.die("unexpected metadata read"),
name: Effect.succeed("T3 Code"),
systemLocale: Effect.succeed("en-US"),
whenReady: Effect.void,
quit: Effect.void,
exit: () => Effect.void,
Expand Down
1 change: 1 addition & 0 deletions apps/desktop/src/app/DesktopLifecycle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ describe("DesktopLifecycle", () => {
const electronAppLayer = Layer.succeed(ElectronApp.ElectronApp, {
metadata: Effect.die("unexpected metadata read"),
name: Effect.succeed("T3 Code"),
systemLocale: Effect.succeed("en-US"),
whenReady: Effect.void,
quit: Effect.void,
exit: () => Effect.void,
Expand Down
78 changes: 78 additions & 0 deletions apps/desktop/src/backend/DesktopBackendManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,84 @@ describe("DesktopBackendManager", () => {
),
);

it.effect(
"re-probes readiness after the first budget expires while the backend is still alive",
() =>
Effect.scoped(
Effect.gen(function* () {
const requestUrls: Array<string> = [];
let requestCount = 0;
let readyCount = 0;
let readinessTimeoutCount = 0;
const firstProbe = yield* Deferred.make<void>();
const childExit = yield* Deferred.make<void>();

const spawnerLayer = Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make(() =>
Effect.succeed(
makeProcess({
exitCode: Deferred.await(childExit).pipe(
Effect.as(ChildProcessSpawner.ExitCode(0)),
),
}),
),
),
);

// The backend stays 503 through the first *two* readiness budgets
// and only becomes healthy (200) for the third round, i.e. it comes
// up well after the initial 50ms budget has expired.
const httpLayer = httpClientLayer((request) =>
Effect.gen(function* () {
requestCount += 1;
requestUrls.push(request.url);
yield* Deferred.succeed(firstProbe, void 0);
return responseForRequest(request, requestCount <= 2 ? 503 : 200);
}),
);

const runFiber = yield* DesktopBackendManager.runBackendProcess({
...baseConfig,
desktopTelemetryStream: Stream.empty,
readinessTimeout: Duration.millis(50),
onReady: () =>
Effect.sync(() => {
readyCount += 1;
}),
onReadinessFailure: () =>
Effect.sync(() => {
readinessTimeoutCount += 1;
}),
}).pipe(Effect.provide(Layer.merge(spawnerLayer, httpLayer)), Effect.forkChild);

yield* Deferred.await(firstProbe);
assert.equal(readyCount, 0);
assert.equal(readinessTimeoutCount, 0);

// The first 50ms readiness budget expires while the backend still
// answers 503. The child is alive and may yet become healthy, so the
// probe must start a fresh round instead of stopping permanently —
// the pre-fix behavior left the app stuck on "Connecting to WSL…"
// forever even though the backend kept running.
yield* TestClock.adjust(Duration.millis(50));
assert.equal(readinessTimeoutCount, 1);
assert.equal(readyCount, 0);

// The second budget also expires (backend still 503), then the third
// round connects. The point is the probe persisted across budgets
// while the process was alive instead of giving up after the first.
yield* TestClock.adjust(Duration.millis(100));
assert.equal(readinessTimeoutCount, 2);
assert.equal(readyCount, 1);
assert.equal(requestUrls.length, 3);

yield* Deferred.succeed(childExit, void 0);
assert.equal((yield* Fiber.join(runFiber)).code.pipe(Option.getOrUndefined), 0);
}).pipe(Effect.provide(TestClock.layer())),
),
);

it.effect("starts the configured backend and closes the scoped process on stop", () =>
Effect.scoped(
Effect.gen(function* () {
Expand Down
37 changes: 25 additions & 12 deletions apps/desktop/src/backend/DesktopBackendManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -592,20 +592,33 @@ export const runBackendProcess = Effect.fn("runBackendProcess")(function* (
).pipe(Effect.forkScoped),
);
}
yield* waitForHttpReady({
executablePath: options.executablePath,
entryPath: options.entryPath,
cwd: options.cwd,
httpBaseUrl: options.httpBaseUrl,
timeout: options.readinessTimeout ?? DEFAULT_BACKEND_READINESS_TIMEOUT,
}).pipe(
Effect.tap(() => options.onReady?.() ?? Effect.void),
Effect.catchTags({
BackendReadinessTimeoutError: (error) => options.onReadinessFailure?.(error) ?? Effect.void,
}),
Effect.forkScoped,
// Probe readiness in a loop while the backend process is still alive
// instead of giving up after the first budget. A slow cold boot (the
// WSL bundle loading across /mnt/c, or a first launch right after an
// update) can exceed the initial readiness budget while the backend is
// about to come up moments later; a one-shot probe left the app stuck
// on "Connecting to WSL…" forever even though the backend kept running
// and became healthy. Each round gets a fresh budget, and the forked
// loop is torn down with the run scope once the child exits.
const probeReadiness = Effect.fn("desktop.backendProcess.probeReadiness")(() =>
waitForHttpReady({
executablePath: options.executablePath,
entryPath: options.entryPath,
cwd: options.cwd,
httpBaseUrl: options.httpBaseUrl,
timeout: options.readinessTimeout ?? DEFAULT_BACKEND_READINESS_TIMEOUT,
}).pipe(
Effect.flatMap(() => options.onReady?.() ?? Effect.void),
Effect.as(true),
Effect.catchTags({
BackendReadinessTimeoutError: (error) =>
(options.onReadinessFailure?.(error) ?? Effect.void).pipe(Effect.as(false)),
}),
),
);

yield* probeReadiness().pipe(Effect.repeat({ while: (ready) => !ready }), Effect.forkScoped);

const exit = yield* handle.exitCode.pipe(
Effect.mapError(
(cause) =>
Expand Down
20 changes: 20 additions & 0 deletions apps/desktop/src/electron/ElectronApp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const {
autoUpdaterRemoveListenerMock,
exitMock,
getAppPathMock,
getSystemLocaleMock,
getVersionMock,
isDefaultProtocolClientMock,
onMock,
Expand All @@ -30,6 +31,7 @@ const {
autoUpdaterRemoveListenerMock: vi.fn(),
exitMock: vi.fn(),
getAppPathMock: vi.fn(() => "/app"),
getSystemLocaleMock: vi.fn(() => "en-GB"),
getVersionMock: vi.fn(() => "1.2.3"),
isDefaultProtocolClientMock: vi.fn(() => false),
onMock: vi.fn(),
Expand Down Expand Up @@ -62,6 +64,7 @@ vi.mock("electron", () => ({
setIcon: setDockIconMock,
},
getAppPath: getAppPathMock,
getSystemLocale: getSystemLocaleMock,
getVersion: getVersionMock,
isDefaultProtocolClient: isDefaultProtocolClientMock,
isPackaged: true,
Expand Down Expand Up @@ -115,6 +118,23 @@ describe("ElectronApp", () => {
}).pipe(Effect.provide(ElectronApp.layer)),
);

it.effect("reads the OS locale through the service", () =>
Effect.gen(function* () {
const electronApp = yield* ElectronApp.ElectronApp;

assert.strictEqual(yield* electronApp.systemLocale, "en-GB");
}).pipe(Effect.provide(ElectronApp.layer)),
);

it.effect("normalizes POSIX-style locale identifiers that Intl rejects", () =>
Effect.gen(function* () {
getSystemLocaleMock.mockImplementationOnce(() => "en_GB");
const electronApp = yield* ElectronApp.ElectronApp;

assert.strictEqual(yield* electronApp.systemLocale, "en-GB");
}).pipe(Effect.provide(ElectronApp.layer)),
);

it.effect("reports which app metadata property failed", () =>
Effect.gen(function* () {
const cause = new Error("version unavailable");
Expand Down
11 changes: 11 additions & 0 deletions apps/desktop/src/electron/ElectronApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ export class ElectronApp extends Context.Service<
{
readonly metadata: Effect.Effect<ElectronAppMetadata, ElectronAppMetadataReadError>;
readonly name: Effect.Effect<string>;
/**
* The OS locale, read from the operating system rather than from Chromium's
* resolved application locale — the packaged app ships only the `en-US`
* locale pak, so `app.getLocale()` and the renderer's `Intl` default are
* pinned to `en-US` however the machine is configured.
*/
readonly systemLocale: Effect.Effect<string>;
readonly whenReady: Effect.Effect<void, ElectronAppWhenReadyError>;
readonly quit: Effect.Effect<void>;
readonly exit: (code: number) => Effect.Effect<void>;
Expand Down Expand Up @@ -120,6 +127,10 @@ export const make = ElectronApp.of({
};
}),
name: Effect.sync(() => Electron.app.name),
// macOS derives this from NSLocale, which uses POSIX-style identifiers
// (`en_GB`). `Intl` rejects those outright rather than normalizing them, so
// the tag is normalized here rather than in the renderer that consumes it.
systemLocale: Effect.sync(() => Electron.app.getSystemLocale().replace(/_/g, "-")),
whenReady: Effect.gen(function* () {
const isPackaged = Electron.app.isPackaged;
yield* Effect.tryPromise({
Expand Down
2 changes: 2 additions & 0 deletions apps/desktop/src/ipc/DesktopIpcHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
getAppBranding,
getLocalEnvironmentBootstraps,
getLocalEnvironmentBearerToken,
getSystemLocale,
getWindowFullscreenState,
openExternal,
probeRemoteEditors,
Expand All @@ -55,6 +56,7 @@ export const installDesktopIpcHandlers = Effect.fn("desktop.ipc.installHandlers"
yield* PreviewIpc.installPreviewEventForwarding();

yield* ipc.handleSync(getAppBranding);
yield* ipc.handleSync(getSystemLocale);
yield* ipc.handleSync(getWindowFullscreenState);
yield* ipc.handleSync(getLocalEnvironmentBootstraps);
yield* ipc.handle(getLocalEnvironmentBearerToken);
Expand Down
Loading
Loading