Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
2fdc704
perf(web): duty-cycle status animations and remove fixed noise overla…
t3dotgg Jul 15, 2026
7b928d5
fix(docs): correct CI task-runner commands in ci.md (#3990)
kridaydave Jul 15, 2026
c69120f
fix(docs): repair broken source links in architecture overview (#3991)
kridaydave Jul 15, 2026
4624426
fix(docs): replace stale codething-mvp absolute paths with repo-relat…
kridaydave Jul 15, 2026
d359789
docs: Add T3 Code Legal Docs (#3972)
juliusmarminge Jul 15, 2026
ecb35f7
Fix Legal modal header crash (#4000)
juliusmarminge Jul 15, 2026
b982337
[codex] Fix onboarding connection status (#4001)
juliusmarminge Jul 16, 2026
5e8b2c8
Isolate native diff highlight grammar state (#4029)
juliusmarminge Jul 16, 2026
0418301
Fix macOS fullscreen titlebar spacing (#4019)
D3OXY Jul 16, 2026
d114e27
Prevent duplicate project workspace roots (#3829)
juliusmarminge Jul 16, 2026
54f167e
Normalize over-indented markdown list items (#4020)
juliusmarminge Jul 16, 2026
52afe17
perf(web): duty-cycle status animations and remove fixed noise overla…
t3dotgg Jul 15, 2026
b1901df
[codex] Fix onboarding connection status (#4001)
juliusmarminge Jul 16, 2026
84657ee
Normalize over-indented markdown list items (#4020)
juliusmarminge Jul 16, 2026
3a2d533
fix(web): allow reconnect for saved idle/error cloud environments
Jul 16, 2026
e3cd2ec
Isolate native diff highlight grammar state (#4029)
juliusmarminge Jul 16, 2026
1ced949
Fix macOS fullscreen titlebar spacing (#4019)
D3OXY Jul 16, 2026
41380db
sync: port upstream duplicate workspace roots guard (#3829)
juliusmarminge Jul 16, 2026
07612d4
fix(web): keep duplicate project refs for sidebar thread lookup
Jul 16, 2026
7009cae
Record upstream ancestry through July 16 (#3978, #3990–#3992, #3972, …
Jul 16, 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
2 changes: 2 additions & 0 deletions apps/desktop/src/ipc/DesktopIpcHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
getLocalEnvironmentBootstraps,
getLocalEnvironmentBearerToken,
getLogDir,
getWindowFullscreenState,
listLogFiles,
openLogDir,
openExternal,
Expand All @@ -52,6 +53,7 @@ export const installDesktopIpcHandlers = Effect.fn("desktop.ipc.installHandlers"
yield* PreviewIpc.installPreviewEventForwarding();

yield* ipc.handleSync(getAppBranding);
yield* ipc.handleSync(getWindowFullscreenState);
yield* ipc.handleSync(getLocalEnvironmentBootstraps);
yield* ipc.handle(getLocalEnvironmentBearerToken);

Expand Down
2 changes: 2 additions & 0 deletions apps/desktop/src/ipc/channels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export const SET_THEME_CHANNEL = "desktop:set-theme";
export const CONTEXT_MENU_CHANNEL = "desktop:context-menu";
export const OPEN_EXTERNAL_CHANNEL = "desktop:open-external";
export const MENU_ACTION_CHANNEL = "desktop:menu-action";
export const GET_WINDOW_FULLSCREEN_STATE_CHANNEL = "desktop:get-window-fullscreen-state";
export const WINDOW_FULLSCREEN_STATE_CHANNEL = "desktop:window-fullscreen-state";
export const UPDATE_STATE_CHANNEL = "desktop:update-state";
export const UPDATE_GET_STATE_CHANNEL = "desktop:update-get-state";
export const UPDATE_SET_CHANNEL_CHANNEL = "desktop:update-set-channel";
Expand Down
21 changes: 21 additions & 0 deletions apps/desktop/src/ipc/methods/window.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { assert, describe, it } from "@effect/vitest";
import * as Effect from "effect/Effect";
import * as Layer from "effect/Layer";
import * as Option from "effect/Option";

import type * as Electron from "electron";

import * as DesktopBackendManager from "../../backend/DesktopBackendManager.ts";
import * as DesktopBackendPool from "../../backend/DesktopBackendPool.ts";
import * as ElectronWindow from "../../electron/ElectronWindow.ts";
import {
extractWslDistroFromEnvironmentId,
getLocalEnvironmentBootstraps,
getWindowFullscreenState,
resolveSelectedWslLinuxPath,
resolveWslPickerDistro,
} from "./window.ts";
Expand Down Expand Up @@ -187,3 +192,19 @@ describe("resolveSelectedWslLinuxPath", () => {
);
});
});

describe("getWindowFullscreenState", () => {
it.effect("reads the current native window state", () => {
const window = { isFullScreen: () => true } as Electron.BrowserWindow;

return Effect.gen(function* () {
assert.isTrue(yield* getWindowFullscreenState.handler());
}).pipe(
Effect.provide(
Layer.mock(ElectronWindow.ElectronWindow)({
currentMainOrFirst: Effect.succeed(Option.some(window)),
}),
),
);
});
});
10 changes: 10 additions & 0 deletions apps/desktop/src/ipc/methods/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ export const getAppBranding = DesktopIpc.makeSyncIpcMethod({
}),
});

export const getWindowFullscreenState = DesktopIpc.makeSyncIpcMethod({
channel: IpcChannels.GET_WINDOW_FULLSCREEN_STATE_CHANNEL,
result: Schema.Boolean,
handler: Effect.fn("desktop.ipc.window.getWindowFullscreenState")(function* () {
const electronWindow = yield* ElectronWindow.ElectronWindow;
const window = yield* electronWindow.currentMainOrFirst;
return Option.isSome(window) && window.value.isFullScreen();
}),
});

export const getLocalEnvironmentBootstraps = DesktopIpc.makeSyncIpcMethod({
channel: IpcChannels.GET_LOCAL_ENVIRONMENT_BOOTSTRAPS_CHANNEL,
result: Schema.Array(DesktopEnvironmentBootstrapSchema),
Expand Down
13 changes: 13 additions & 0 deletions apps/desktop/src/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,19 @@ contextBridge.exposeInMainWorld("desktopBridge", {
ipcRenderer.removeListener(IpcChannels.MENU_ACTION_CHANNEL, wrappedListener);
};
},
getWindowFullscreenState: () =>
ipcRenderer.sendSync(IpcChannels.GET_WINDOW_FULLSCREEN_STATE_CHANNEL) === true,
onWindowFullscreenStateChange: (listener) => {
const wrappedListener = (_event: Electron.IpcRendererEvent, fullscreen: unknown) => {
if (typeof fullscreen !== "boolean") return;
listener(fullscreen);
};

ipcRenderer.on(IpcChannels.WINDOW_FULLSCREEN_STATE_CHANNEL, wrappedListener);
return () => {
ipcRenderer.removeListener(IpcChannels.WINDOW_FULLSCREEN_STATE_CHANNEL, wrappedListener);
};
},
getUpdateState: () => ipcRenderer.invoke(IpcChannels.UPDATE_GET_STATE_CHANNEL),
setUpdateChannel: (channel) =>
ipcRenderer.invoke(IpcChannels.UPDATE_SET_CHANNEL_CHANNEL, channel),
Expand Down
40 changes: 38 additions & 2 deletions apps/desktop/src/window/DesktopWindow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import * as ElectronMenu from "../electron/ElectronMenu.ts";
import * as ElectronShell from "../electron/ElectronShell.ts";
import * as ElectronTheme from "../electron/ElectronTheme.ts";
import * as ElectronWindow from "../electron/ElectronWindow.ts";
import { MENU_ACTION_CHANNEL } from "../ipc/channels.ts";
import { MENU_ACTION_CHANNEL, WINDOW_FULLSCREEN_STATE_CHANNEL } from "../ipc/channels.ts";
import * as DesktopServerExposure from "../backend/DesktopServerExposure.ts";
import * as DesktopWindow from "./DesktopWindow.ts";
import * as PreviewManager from "../preview/Manager.ts";
Expand All @@ -47,6 +47,7 @@ const environmentInput = {
} satisfies DesktopEnvironment.MakeDesktopEnvironmentInput;

function makeFakeBrowserWindow() {
const windowListeners = new Map<string, (...args: readonly unknown[]) => void>();
const webContentsListeners = new Map<string, (...args: readonly unknown[]) => void>();
const webContents = {
copyImageAt: vi.fn(),
Expand All @@ -67,10 +68,13 @@ function makeFakeBrowserWindow() {
close: vi.fn(),
focus: vi.fn(),
isDestroyed: vi.fn(() => false),
isFullScreen: vi.fn(() => false),
isMinimized: vi.fn(() => false),
isVisible: vi.fn(() => true),
loadURL: vi.fn(() => Promise.resolve()),
on: vi.fn(),
on: vi.fn((eventName: string, listener: (...args: readonly unknown[]) => void) => {
windowListeners.set(eventName, listener);
}),
once: vi.fn(),
restore: vi.fn(),
setBackgroundColor: vi.fn(),
Expand All @@ -89,6 +93,7 @@ function makeFakeBrowserWindow() {
send: webContents.send,
setAutoHideCursor: window.setAutoHideCursor,
webContentsListeners,
windowListeners,
};
}

Expand Down Expand Up @@ -348,6 +353,37 @@ describe("DesktopWindow", () => {
}),
);

it.effect("publishes native macOS fullscreen changes to the renderer", () =>
Effect.gen(function* () {
const fakeWindow = makeFakeBrowserWindow();
const createCount = yield* Ref.make(0);
const mainWindow = yield* Ref.make<Option.Option<Electron.BrowserWindow>>(Option.none());
const layer = makeTestLayer({
window: fakeWindow.window,
createCount,
mainWindow,
});

yield* Effect.gen(function* () {
const desktopWindow = yield* DesktopWindow.DesktopWindow;
yield* desktopWindow.handleBackendReady(new URL("http://127.0.0.1:3773"));

const enterFullscreen = fakeWindow.windowListeners.get("enter-full-screen");
const leaveFullscreen = fakeWindow.windowListeners.get("leave-full-screen");
if (!enterFullscreen || !leaveFullscreen) {
return yield* Effect.die("fullscreen listeners were not registered");
}

enterFullscreen();
leaveFullscreen();
assert.deepEqual(fakeWindow.send.mock.calls, [
[WINDOW_FULLSCREEN_STATE_CHANNEL, true],
[WINDOW_FULLSCREEN_STATE_CHANNEL, false],
]);
}).pipe(Effect.provide(layer));
}),
);

it.effect("recovers when the development renderer is temporarily unreachable", () =>
Effect.gen(function* () {
const fakeWindow = makeFakeBrowserWindow();
Expand Down
11 changes: 10 additions & 1 deletion apps/desktop/src/window/DesktopWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import * as ElectronProtocol from "../electron/ElectronProtocol.ts";
import * as ElectronShell from "../electron/ElectronShell.ts";
import * as ElectronTheme from "../electron/ElectronTheme.ts";
import * as ElectronWindow from "../electron/ElectronWindow.ts";
import { MENU_ACTION_CHANNEL } from "../ipc/channels.ts";
import { MENU_ACTION_CHANNEL, WINDOW_FULLSCREEN_STATE_CHANNEL } from "../ipc/channels.ts";
import * as PreviewManager from "../preview/Manager.ts";

const TITLEBAR_HEIGHT = 40;
Expand Down Expand Up @@ -367,6 +367,15 @@ export const make = Effect.gen(function* () {
window.setTitle(environment.displayName);
});

if (environment.platform === "darwin") {
window.on("enter-full-screen", () => {
window.webContents.send(WINDOW_FULLSCREEN_STATE_CHANNEL, true);
});
window.on("leave-full-screen", () => {
window.webContents.send(WINDOW_FULLSCREEN_STATE_CHANNEL, false);
});
}

let developmentLoadRetryIndex = 0;
let developmentLoadRetryFiber: Fiber.Fiber<void, never> | undefined;
const clearDevelopmentLoadRetry = () => {
Expand Down
189 changes: 189 additions & 0 deletions apps/mobile/src/features/diffs/nativeReviewDiffHighlighter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import { describe, expect, it } from "vite-plus/test";

import type { NativeReviewDiffRow } from "./nativeReviewDiffSurface";
import type { NativeReviewDiffFile } from "./nativeReviewDiffTypes";
import { highlightNativeReviewDiffVisibleRows } from "./nativeReviewDiffHighlighter";

const TYPESCRIPT_FILE: NativeReviewDiffFile = {
id: "file-1",
path: "example.ts",
language: "typescript",
additions: 0,
deletions: 0,
};

function makeLine(
input: Pick<NativeReviewDiffRow, "id" | "content" | "change" | "oldLineNumber" | "newLineNumber">,
): NativeReviewDiffRow {
return {
kind: "line",
fileId: TYPESCRIPT_FILE.id,
...input,
};
}

function makeHunk(id: string): NativeReviewDiffRow {
return {
kind: "hunk",
id,
fileId: TYPESCRIPT_FILE.id,
text: "@@",
};
}

function highlight(
rows: ReadonlyArray<NativeReviewDiffRow>,
alreadyHighlightedRowIds?: ReadonlySet<string>,
) {
return highlightNativeReviewDiffVisibleRows({
rows,
files: [TYPESCRIPT_FILE],
scheme: "dark",
engine: "javascript",
firstRowIndex: 0,
lastRowIndex: rows.length - 1,
overscanRows: 0,
maxRows: 100,
alreadyHighlightedRowIds,
});
}

describe("highlightNativeReviewDiffVisibleRows", () => {
it("does not carry grammar state across hunk boundaries", async () => {
const exportRow = makeLine({
id: "export-row",
content: "export async function run() {}",
change: "add",
oldLineNumber: null,
newLineNumber: 100,
});
const rows = [
makeHunk("hunk-1"),
makeLine({
id: "import-open",
content: "import {",
change: "context",
oldLineNumber: 1,
newLineNumber: 1,
}),
makeLine({
id: "import-entry",
content: " Model,",
change: "context",
oldLineNumber: 2,
newLineNumber: 2,
}),
makeHunk("hunk-2"),
exportRow,
];

const [highlighted, standalone] = await Promise.all([
highlight(rows),
highlight([makeHunk("standalone-hunk"), exportRow]),
]);

expect(highlighted.tokensByRowId[exportRow.id]).toEqual(standalone.tokensByRowId[exportRow.id]);
});

it("keeps grammar state across inline comment rows", async () => {
const openingRow = makeLine({
id: "template-open",
content: "const message = `open",
change: "add",
oldLineNumber: null,
newLineNumber: 1,
});
const closingRow = makeLine({
id: "template-close",
content: "closed`;",
change: "add",
oldLineNumber: null,
newLineNumber: 2,
});
const trailingRow = makeLine({
id: "trailing-row",
content: "export const answer = 42;",
change: "add",
oldLineNumber: null,
newLineNumber: 3,
});
const commentRow: NativeReviewDiffRow = {
kind: "comment",
id: "comment-1",
fileId: TYPESCRIPT_FILE.id,
commentText: "Review note",
};

const [withComment, contiguous] = await Promise.all([
highlight([openingRow, commentRow, closingRow, trailingRow]),
highlight([openingRow, closingRow, trailingRow]),
]);

expect(withComment.tokensByRowId).toEqual(contiguous.tokensByRowId);
});

it("does not join unhighlighted rows across cached gaps", async () => {
const trailingRow = makeLine({
id: "trailing-row",
content: "export const answer = 42;",
change: "add",
oldLineNumber: null,
newLineNumber: 3,
});
const rows = [
makeLine({
id: "template-open",
content: "const message = `open",
change: "add",
oldLineNumber: null,
newLineNumber: 1,
}),
makeLine({
id: "template-close",
content: "closed`;",
change: "add",
oldLineNumber: null,
newLineNumber: 2,
}),
trailingRow,
];

const [highlighted, standalone] = await Promise.all([
highlight(rows, new Set(["template-close"])),
highlight([trailingRow]),
]);

expect(highlighted.tokensByRowId[trailingRow.id]).toEqual(
standalone.tokensByRowId[trailingRow.id],
);
});

it("keeps deletion grammar state out of addition rows", async () => {
const additionRow = makeLine({
id: "addition-row",
content: "export const answer = 42;",
change: "add",
oldLineNumber: null,
newLineNumber: 1,
});
const rows = [
makeLine({
id: "deletion-row",
content: "const removed = `open",
change: "delete",
oldLineNumber: 1,
newLineNumber: null,
}),
additionRow,
];

const [highlighted, standalone] = await Promise.all([
highlight(rows),
highlight([additionRow]),
]);

expect(highlighted.tokensByRowId[additionRow.id]).toEqual(
standalone.tokensByRowId[additionRow.id],
);
});
});
Loading
Loading