Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
14bf3f6
fix(web): toggle a single stashed prompt with Cmd+S (#9644)
t3dotgg Sep 4, 2026
eb77683
fix(server): prevent duplicate desktop clients after restart
seeb1337 Sep 4, 2026
d487dfb
fix(web): resume Antigravity threads without repeated sign-in (#9647)
t3dotgg Sep 4, 2026
d5b9410
feat(mobile): paste the phone clipboard into the terminal (#9199)
lnieuwenhuis Sep 4, 2026
f034732
feat(web): show which sidebar threads hold an unsent draft (#9658)
t3dotgg Sep 4, 2026
01f3e50
fix(server): unblock OpenCode approvals and stop (#9653)
t3dotgg Sep 4, 2026
caa8a0d
fix(desktop): quit immediately on a second shortcut press (#9657)
t3dotgg Sep 4, 2026
560afff
fix(server): update Claude Agent SDK to 0.3.260 (#9135)
t3dotgg Sep 4, 2026
8ac5462
perf(server): stop loading message bodies for thread summaries (#9662)
t3dotgg Sep 4, 2026
cccd7e3
perf(web): speed up terminal snapshots (#9663)
t3dotgg Sep 4, 2026
082cab2
fix(web): show machine icons in the environment picker (#9668)
t3dotgg Sep 4, 2026
3b6be3e
perf(mobile): bound diff syntax highlighting work (#9673)
t3dotgg Sep 4, 2026
887ece3
perf(web): keep Markdown mounted during streaming (#9677)
t3dotgg Sep 4, 2026
7cf5b28
perf(mobile): skip unused legacy list work (#9679)
t3dotgg Sep 4, 2026
8e3aa32
perf(marketing): serve images at their display size (#9682)
t3dotgg Sep 4, 2026
27e6cc2
perf(server): cache and stream static web assets (#9669)
t3dotgg Sep 4, 2026
2263e13
perf(server): batch projector cursor writes (#9671)
t3dotgg Sep 4, 2026
f2e3764
perf(server): stop retaining unused OpenCode tool history (#9684)
t3dotgg Sep 4, 2026
44dc8ae
perf(mobile): reuse chat feed rows during streaming (#9688)
t3dotgg Sep 4, 2026
ec8b211
perf(server): omit repeated OpenCode progress logs (#9689)
t3dotgg Sep 4, 2026
2460649
perf(clients): avoid waiting to read cached relay tokens (#9691)
t3dotgg Sep 4, 2026
777f5bb
perf(mobile): reuse diff rows during comment edits (#9693)
t3dotgg Sep 4, 2026
dab5f6e
perf(web): defer composer draft serialization (#9695)
t3dotgg Sep 4, 2026
1587f24
feat(server): measure provider turn token usage (#9132)
t3dotgg Sep 4, 2026
4ee2a9d
perf(marketing): stop continuous homepage motion (#9697)
t3dotgg Sep 4, 2026
c163d50
perf(server): avoid full patches for checkpoint summaries (#9694)
t3dotgg Sep 4, 2026
b3e1d88
perf(web): defer diff workers until a code view opens (#9692)
t3dotgg Sep 4, 2026
010d6bb
perf(marketing): serve website fonts locally (#9701)
t3dotgg Sep 4, 2026
3bbbc1d
perf(server): stop rebuilding terminal history per chunk (#9703)
t3dotgg Sep 4, 2026
dffb4cd
perf(server): use one query for buffered provider events (#9706)
t3dotgg Sep 4, 2026
c75299e
perf(relay): avoid repeated activity decoding (#9708)
t3dotgg Sep 4, 2026
c7c1dfe
perf(web): stop continuous chat status animations (#9709)
t3dotgg Sep 4, 2026
7839140
fix(mobile): preserve saved work after storage read failures (#9710)
t3dotgg Sep 4, 2026
da7e46d
perf(web): stop replaying terminal buffers on rollover (#9707)
t3dotgg Sep 4, 2026
9510390
feat(web): preview pull request links (#9631)
maria-rcks Sep 4, 2026
c66f15f
perf(client): reduce thread-list update work (#9716)
t3dotgg Sep 4, 2026
d536b05
fix(server): settle inactive threads with open PRs (#9610)
Gigioxx Sep 4, 2026
108f295
fix(server): bound slow-client event buffers (#9715)
t3dotgg Sep 4, 2026
8ccb933
test(server): allow either valid file-search match (#9720)
t3dotgg Sep 4, 2026
8357eef
fix(web): match provider settings layout for disconnected devices (#9…
flamboh Sep 4, 2026
120fab1
fix(web): keep the slash menu above the composer when vertical space …
Mnigos Sep 4, 2026
9eb4d71
fix(mobile): remove provider setup (#9721)
juliusmarminge Sep 4, 2026
5eab021
perf(web): stop rendering hidden terminals (#9718)
t3dotgg Sep 4, 2026
c4353bc
fix(mobile): read file-backed image drafts before enabling them (#9713)
t3dotgg Sep 4, 2026
50bfca4
perf(server): replay only the selected thread (#9726)
t3dotgg Sep 4, 2026
7d5dc66
fix(web): mute composer helper text (#9654)
jakeleventhal Sep 4, 2026
c7bf311
feat(web): unpin threads from the sidebar multi-select menu (#9651)
gsimone Sep 4, 2026
19c1710
perf(web): reuse timeline rows while text streams (#9725)
t3dotgg Sep 4, 2026
088cc3f
fix(relay): bound stalled push requests (#9734)
t3dotgg Sep 4, 2026
c8f77e0
perf(server): stop caching unused OpenCode tool parts (#9738)
t3dotgg Sep 4, 2026
cfc9bf3
fix(web): fold single trailing activity (#9739)
maria-rcks Sep 4, 2026
cbe93e8
fix(web): show project settings for new threads (#9743)
maria-rcks Sep 4, 2026
d6e29dc
perf(mobile): bound the parsed review cache (#9749)
t3dotgg Sep 4, 2026
fec606f
perf(web): avoid repeated terminal metadata scans (#9747)
t3dotgg Sep 4, 2026
cf9729d
perf(server): bound terminal history by bytes (#9748)
t3dotgg Sep 4, 2026
a76b898
feat(web): link pull request authors to profiles (#9627)
maria-rcks Sep 4, 2026
0de956e
fix(web): refine server update notice (#9744)
maria-rcks Sep 4, 2026
d7cf8aa
perf(client): stop thread streams when unused (#9740)
t3dotgg Sep 4, 2026
77b655c
perf(mobile): defer file preview highlighter startup (#9752)
t3dotgg Sep 4, 2026
6365919
perf(server): skip history reads for metadata commands (#9758)
t3dotgg Sep 4, 2026
2a96882
sync: adopt upstream streaming and persistence performance work
aaditagrawal Sep 5, 2026
130e60f
fix(sync): adapt upstream tests to fork thread replay and highlighter…
cursoragent Sep 5, 2026
449f5a3
test(mobile): isolate cold highlighting from wall-clock contention
aaditagrawal Sep 5, 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
75 changes: 57 additions & 18 deletions apps/desktop/src/window/QuitHold.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,24 +252,31 @@ describe("makeQuitShortcutHandler", () => {
expect(harness.notifications).toEqual([]);
});

it("honors a quick double press when both key releases beat their mode reads", async () => {
const resolvers: Array<(mode: QuitConfirmationMode) => void> = [];
const harness = makeHarness({
getMode: () => new Promise((resolve) => resolvers.push(resolve)),
});
await harness.send(makeInput({}));
await harness.send(makeInput({ type: "keyUp" }));
vi.advanceTimersByTime(QUIT_DOUBLE_PRESS_MS - 100);
await harness.send(makeInput({}));
await harness.send(makeInput({ type: "keyUp" }));

resolvers[1]?.("double-click");
await Promise.resolve();
await Promise.resolve();

expect(harness.quit).toHaveBeenCalledTimes(1);
expect(harness.notifications).toEqual([]);
});
it.each(["direct", "hold", "double-click"] as const)(
"quits on a quick second press without waiting for a pending %s mode read",
async (mode) => {
const resolvers: Array<(mode: QuitConfirmationMode) => void> = [];
const harness = makeHarness({
getMode: () => new Promise((resolve) => resolvers.push(resolve)),
});
await harness.send(makeInput({}));
await harness.send(makeInput({ type: "keyUp" }));
vi.advanceTimersByTime(QUIT_DOUBLE_PRESS_MS - 100);
await harness.send(makeInput({}));

expect(harness.quit).toHaveBeenCalledTimes(1);
expect(harness.notifications).toEqual([]);

await harness.send(makeInput({ type: "keyUp" }));

resolvers[0]?.(mode);
await Promise.resolve();
await Promise.resolve();

expect(harness.quit).toHaveBeenCalledTimes(1);
expect(harness.notifications).toEqual([]);
},
);

it("discards a stale mode resolution from a superseded press", async () => {
// Press #1's mode is still pending when the user releases and
Expand Down Expand Up @@ -378,6 +385,38 @@ describe("makeQuitShortcutHandler", () => {
expect(harness.notifications).toEqual([HOLD_DOWN, UP]);
});

it("quits on a quick second press in hold mode when the first release is unseen", async () => {
const harness = makeHarness();
await harness.send(makeInput({}));
vi.advanceTimersByTime(QUIT_DOUBLE_PRESS_MS - 100);
await harness.send(makeInput({}));

expect(harness.concealWindow).not.toHaveBeenCalled();
expect(harness.quit).toHaveBeenCalledTimes(1);
expect(harness.notifications).toEqual([HOLD_DOWN, UP]);
});

it("does not count auto-repeat as a second press", async () => {
const harness = makeHarness();
await harness.send(makeInput({}));
await harness.holdFor(QUIT_DOUBLE_PRESS_MS - 100);

expect(harness.quit).not.toHaveBeenCalled();
expect(harness.notifications).toEqual([HOLD_DOWN]);
});

it("does not count a released tap after another shortcut interrupts it", async () => {
const harness = makeHarness();
await harness.send(makeInput({}));
await harness.send(makeInput({ type: "keyUp" }));
await harness.send(makeInput({ key: "c" }));
vi.advanceTimersByTime(100);
await harness.send(makeInput({}));

expect(harness.quit).not.toHaveBeenCalled();
expect(harness.notifications).toEqual([HOLD_DOWN, UP, HOLD_DOWN]);
});

it("cancels the hold when another key interrupts it", async () => {
const harness = makeHarness();
await harness.send(makeInput({}));
Expand Down
35 changes: 17 additions & 18 deletions apps/desktop/src/window/QuitHold.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ export const QUIT_DOUBLE_PRESS_MS = 500;
// tap release can go completely unseen and a release-based timer would quit
// anyway. Once held, quitting waits for Q keyUp or a quiet grace period after
// repeats stop so they cannot reach the next app. Keyboards with
// auto-repeat disabled fall back to the application menu Quit action.
// auto-repeat disabled must use a double press or the application menu Quit action.
// Supporting holds without repeats requires a native physical key-state check.
export const QUIT_HOLD_RELEASE_GRACE_MS = 600;
// A slow repeat rate can exceed the fixed grace. Waiting for two observed
// cadences keeps the timer behind the next repeat without slowing normal rates.
Expand Down Expand Up @@ -52,8 +53,8 @@ export function makeQuitShortcutHandler(
let lastRepeatAt = 0;
let repeatCadenceMs = 0;
// Incremented when a press is superseded or explicitly cancelled. A plain
// key release does not invalidate its pending mode read: direct mode and a
// completed second press must still be honored after that read settles.
// key release does not invalidate its pending mode read: a direct-mode
// press must still quit after that read settles.
let generation = 0;

const clearWatchdog = () => {
Expand All @@ -64,9 +65,9 @@ export function makeQuitShortcutHandler(
};

const release = (cancelPendingMode = true, keepDoublePressHint = false) => {
if (cancelPendingMode) generation += 1;
if (!holding && !notified) return;
const keepHint = keepDoublePressHint && mode === "double-click" && notified;
if (cancelPendingMode) generation += 1;
holding = false;
armed = false;
quitOnRelease = false;
Expand All @@ -85,6 +86,7 @@ export function makeQuitShortcutHandler(
// Dismisses any overlay first so a cancelled quit cannot leave a stale hint.
const quitNow = () => {
release();
lastPressAt = 0;
options.quit();
};

Expand Down Expand Up @@ -138,13 +140,10 @@ export function makeQuitShortcutHandler(
// quit shortcut, so it must not cancel an active double-press window.
if (key === modifierKey && !input.alt && !input.shift) return;

// Any other key (or an extra modifier) pressed mid-hold breaks the
// gesture; without this the hold timer keeps running through the
// interruption and the next qualifying repeat would quit early. The
// interrupted press also stops counting toward a double press, but only
// here, not in release(), which runs mid-restart on an unseen-release
// re-press and must not wipe that press's own tap timestamp.
if ((holding || notified) && !input.isAutoRepeat) {
// Other keys cancel the hold and the first tap, even after release.
// Keep this separate from release(), which also runs when a fresh Q
// keydown follows a keyUp that macOS did not deliver.
if (!input.isAutoRepeat) {
lastPressAt = 0;
release();
}
Expand All @@ -171,6 +170,13 @@ export function makeQuitShortcutHandler(
if (holding || notified) release();

generation += 1;
// Every mode accepts two presses. Quit before reading settings so a slow
// read cannot delay the second press. Repeats never reach this branch.
if (previousPressAt !== 0 && now - previousPressAt <= QUIT_DOUBLE_PRESS_MS) {
quitNow();
return;
}

const pressGeneration = generation;
holding = true;
heldSince = now;
Expand All @@ -181,13 +187,6 @@ export function makeQuitShortcutHandler(
quitNow();
return;
}
// Keep a second press as an escape hatch when macOS misses the events
// that would complete a hold.
if (previousPressAt !== 0 && now - previousPressAt <= QUIT_DOUBLE_PRESS_MS) {
quitNow();
return;
}

if (resolvedMode === "double-click") {
const remainingMs = QUIT_DOUBLE_PRESS_MS - (Date.now() - now);
if (remainingMs <= 0) {
Expand Down
3 changes: 2 additions & 1 deletion apps/marketing/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
},
"dependencies": {
"@t3tools/shared": "workspace:*",
"astro": "^7.0.3"
"astro": "^7.0.3",
"sharp": "0.34.5"
},
"devDependencies": {
"@astrojs/check": "^0.9.7",
Expand Down
93 changes: 93 additions & 0 deletions apps/marketing/public/fonts/dm-sans-OFL.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
Copyright 2014 The DM Sans Project Authors (https://github.com/googlefonts/dm-fonts)

This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://scripts.sil.org/OFL


-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------

PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.

The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.

DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.

"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).

"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).

"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.

"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.

PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:

1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.

2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.

3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.

4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.

5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.

TERMINATION
This license becomes null and void if any of the above conditions are
not met.

DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
93 changes: 93 additions & 0 deletions apps/marketing/public/fonts/jetbrains-mono-OFL.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)

This Font Software is licensed under the SIL Open Font License, Version 1.1.

This license is copied below, and is also available with a FAQ at: https://scripts.sil.org/OFL


-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------

PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.

The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.

DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.

"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).

"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).

"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.

"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.

PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:

1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.

2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.

3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.

4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.

5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.

TERMINATION
This license becomes null and void if any of the above conditions are
not met.

DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File renamed without changes
Loading
Loading