Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
38f3c62
fix(shared): local-path remotes no longer crash legacy PR link projec…
pujitha24 Sep 29, 2026
adfc924
fix(server): preserve usage in oversized transcript records (#13650)
shivamhwp Sep 29, 2026
e518866
fix(server): OpenCode stop no longer hangs when a turn is interrupted…
SunkenInTime Sep 29, 2026
5da5595
feat: save Bitbucket credentials from Source Control settings (#14103)
gabrielelpidio Sep 29, 2026
76fa23d
fix(provider): mark OpenCode v2 incompatible (#14198)
juliusmarminge Sep 29, 2026
d2c9281
fix(web): pull request badge sits on the sidebar row's baseline (#14007)
Jardo-51 Sep 29, 2026
27bdf1a
feat(codex): connect ChatGPT accounts with managed authentication (#1…
juliusmarminge Sep 29, 2026
5e83e99
Update currentModels in model-manifest.json
juliusmarminge Sep 29, 2026
2cbc24f
chore(release): prepare v0.0.43
t3-code[bot] Sep 29, 2026
451afcb
fix(codex): Pro Max accounts load, so Ultrafast shows up (#14304)
t3dotgg Sep 29, 2026
1a553d0
fix(shared): merge OpenCode Go limits by credential (#14209)
Yash-Singh1 Sep 29, 2026
4222485
feat(codex): regenerate protocol bindings for Codex 0.159 (#14311)
juliusmarminge Sep 29, 2026
ff1db03
chore(release): prepare v0.0.44
t3-code[bot] Sep 29, 2026
8792f95
test(server): stop pinning codex install advisory to a release range …
maria-rcks Sep 29, 2026
63b61e6
chore: stop CodeRabbit from editing PR descriptions (#14307)
t3dotgg Sep 30, 2026
60cb7d1
fix(web): unresolved pull request links use the compact link tooltip …
flamboh Sep 30, 2026
88fbc2c
fix(client-runtime): keep model ids in inline code from becoming file…
otavio Sep 30, 2026
916ec94
fix(web): show the agent's question on user-input timeline rows (#12900)
saphid Sep 30, 2026
55ec55b
fix(web): open workspace root links in the file explorer (#12449)
saphid Sep 30, 2026
050cfad
fix(grok): recover from crashed provider sessions (#10607)
saphid Sep 30, 2026
2a23c30
fix(web): let command menu descriptions use the full row width (#8865)
jakaskerjanc Sep 30, 2026
0fcd5f9
fix(web): multi-PR badges open the linked pull requests panel (#13211)
flamboh Sep 30, 2026
6e09e32
Merge upstream main into Fold
BreakTheBeta Sep 30, 2026
7b8a78b
fix: repair tests broken on the fork and the bugs they caught
BreakTheBeta Sep 30, 2026
215c01d
fix(test): upgrade legacy Codex replay frames and serve the desktop f…
BreakTheBeta Sep 30, 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 .coderabbit.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
reviews:
high_level_summary: false
review_status: false
auto_review:
enabled: true
Expand Down
112 changes: 112 additions & 0 deletions apps/desktop/src/app/CodexAuthCallback.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// @effect-diagnostics nodeBuiltinImport:off globalFetch:off - Tests exercise the real native loopback listener without an OpenAI account.
import * as NodeHttp from "node:http";
import { describe, expect, it } from "vite-plus/test";
import { codexAuthDeliveryUrl, readCodexAuthDelivery } from "@t3tools/shared/codexAuthHandoff";
import { EnvironmentId, ProviderInstanceId } from "@t3tools/contracts";
import { receiveCodexAuthCallback, cancelCodexAuthCallback } from "./CodexAuthCallback.ts";

async function freePort() {
const server = NodeHttp.createServer();
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
const address = server.address();
if (!address || typeof address === "string") throw new Error("address");
await new Promise<void>((resolve) => server.close(() => resolve()));
return address.port;
}
function request(port: number, state = "a".repeat(43)) {
const url = new URL("https://auth.openai.com/api/accounts/authorize");
url.search = new URLSearchParams({
client_id: "dynamic_agent_client",
response_type: "code",
redirect_uri: `http://127.0.0.1:${port}/auth/callback`,
state,
code_challenge_method: "S256",
code_challenge: "b".repeat(43),
}).toString();
return url.toString();
}
function callback(authorizationUrl: string) {
const request = new URL(authorizationUrl);
const url = new URL(request.searchParams.get("redirect_uri")!);
url.search = new URLSearchParams({
state: request.searchParams.get("state")!,
code: "test-code",
client_id: "oaiapp_test",
}).toString();
return url.toString();
}

describe("desktop Codex callback helper", () => {
it("binds before opening sign-in, ignores a foreign response, and returns only the code callback", async () => {
const authorizationUrl = request(await freePort());
const expected = callback(authorizationUrl);
const received = await receiveCodexAuthCallback(authorizationUrl, async () => {
const invalid = new URL(expected);
invalid.searchParams.set("state", "foreign");
expect((await fetch(invalid)).status).toBe(400);
const response = await fetch(expected);
expect(response.headers.get("cache-control")).toBe("no-store");
expect(await response.text()).not.toContain("test-code");
return true;
});
expect(received).toBe(expected);
});
it("returns hosted web to the exact instance and environment without putting the code in its query", async () => {
const authorizationUrl = request(await freePort());
const expected = callback(authorizationUrl);
const input = {
authorizationUrl,
returnUrl: "https://app.t3.codes/settings/providers?environmentId=remote-one&instanceId=work",
environmentId: EnvironmentId.make("remote-one"),
instanceId: ProviderInstanceId.make("work"),
flowId: "flow-one",
};
await receiveCodexAuthCallback(
authorizationUrl,
async () => {
const response = await fetch(expected, { redirect: "manual" });
expect(response.status).toBe(303);
const delivery = response.headers.get("location")!;
expect(new URL(delivery).searchParams.has("code")).toBe(false);
expect(readCodexAuthDelivery(delivery)?.callbackUrl).toBe(expected);
expect(readCodexAuthDelivery(delivery)?.returnUrl).toBe(input.returnUrl);
return true;
},
(url) => codexAuthDeliveryUrl(input, url),
);
});
it("cancels and releases its listener so exact-port reauthorization can run again", async () => {
const authorizationUrl = request(await freePort());
await expect(
receiveCodexAuthCallback(authorizationUrl, async () => {
cancelCodexAuthCallback(authorizationUrl);
return true;
}),
).rejects.toThrow("cancelled");
expect(
await receiveCodexAuthCallback(authorizationUrl, async () => {
await fetch(callback(authorizationUrl));
return true;
}),
).toBe(callback(authorizationUrl));
});
it("allows two accounts to complete independently", async () => {
const a = request(await freePort(), "a".repeat(43));
const b = request(await freePort(), "c".repeat(43));
const openedA = Promise.withResolvers<void>();
const openedB = Promise.withResolvers<void>();
const receiveA = receiveCodexAuthCallback(a, async () => {
openedA.resolve();
await openedB.promise;
await fetch(callback(a));
return true;
});
const receiveB = receiveCodexAuthCallback(b, async () => {
openedB.resolve();
await openedA.promise;
await fetch(callback(b));
return true;
});
expect(await Promise.all([receiveA, receiveB])).toEqual([callback(a), callback(b)]);
});
});
5 changes: 5 additions & 0 deletions apps/desktop/src/app/CodexAuthCallback.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export {
CodexAuthCallbackError,
cancelCodexAuthCallback,
receiveCodexAuthCallback,
} from "@t3tools/shared/codexAuthCallback";
143 changes: 142 additions & 1 deletion apps/desktop/src/app/DesktopClerk.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
// @effect-diagnostics nodeBuiltinImport:off globalFetchInEffect:off - Hosted handoff test uses a real localhost listener without an OpenAI account.
import * as NodePath from "@effect/platform-node/NodePath";
import * as NodeHttp from "node:http";
import { codexAuthHandoffUrl, readCodexAuthDelivery } from "@t3tools/shared/codexAuthHandoff";
import { EnvironmentId, ProviderInstanceId } from "@t3tools/contracts";
import { HostProcessArguments } from "@t3tools/shared/hostProcess";
import { assert, describe, it } from "@effect/vitest";
import * as Cause from "effect/Cause";
import * as Effect from "effect/Effect";
Expand All @@ -23,9 +28,11 @@ vi.mock("@clerk/electron/storage", () => ({
storage: storageMock,
}));

import * as Option from "effect/Option";
import * as Exit from "effect/Exit";
import * as FileSystem from "effect/FileSystem";
import * as ElectronApp from "../electron/ElectronApp.ts";
import * as ElectronShell from "../electron/ElectronShell.ts";
import * as ElectronWindow from "../electron/ElectronWindow.ts";
import * as DesktopClerk from "./DesktopClerk.ts";
import * as DesktopEnvironment from "./DesktopEnvironment.ts";
Expand All @@ -38,6 +45,11 @@ const makeDesktopClerkLayer = (
fileSystemLayer: Layer.Layer<FileSystem.FileSystem> = FileSystem.layerNoop({
exists: () => Effect.succeed(false),
}),
shell: ElectronShell.ElectronShell["Service"] = {
openExternal: () => Effect.succeed(true),
openSystemSettings: () => Effect.succeed(false),
copyText: () => Effect.void,
},
) => {
const environment = DesktopEnvironment.DesktopEnvironment.of({
stateDir: "/tmp/t3-state",
Expand All @@ -60,6 +72,7 @@ const makeDesktopClerkLayer = (
Layer.succeed(DesktopEnvironment.DesktopEnvironment, environment),
Layer.succeed(ElectronApp.ElectronApp, electronApp),
fileSystemLayer,
Layer.succeed(ElectronShell.ElectronShell, shell),
),
),
);
Expand Down Expand Up @@ -207,7 +220,7 @@ describe("DesktopClerk", () => {

assert.isTrue(Exit.isSuccess(exit));
assert.equal(quit.mock.calls.length, 0);
assert.deepEqual(registeredEvents, ["second-instance"]);
assert.deepEqual(registeredEvents, ["open-url", "second-instance"]);
}).pipe(
Effect.provide(makeDesktopClerkLayer()),
Effect.provideService(ElectronApp.ElectronApp, electronApp),
Expand Down Expand Up @@ -243,3 +256,131 @@ describe("DesktopClerk", () => {
);
});
});

it.effect(
"provider auth deep links navigate and reveal the running desktop without handling Clerk URLs",
() => {
storageMock.mockReturnValue(storageAdapter);
createClerkBridgeMock.mockReturnValue({ cleanup: vi.fn(), isPrimaryInstance: true });
const listeners = new Map<string, (...args: unknown[]) => void>();
const revealed = Promise.withResolvers<void>();
const loadURL = vi.fn(async (_url: string) => undefined);
const window = { loadURL };
const electronApp = {
on: (name: string, listener: (...args: unknown[]) => void) =>
Effect.sync(() => {
listeners.set(name, listener);
}),
} as unknown as ElectronApp.ElectronApp["Service"];
const electronWindow = {
currentMainOrFirst: Effect.succeed(Option.some(window)),
reveal: () => Effect.sync(() => revealed.resolve()),
} as unknown as ElectronWindow.ElectronWindow["Service"];
return Effect.gen(function* () {
const clerk = yield* DesktopClerk.DesktopClerk;
yield* clerk.configure;
const event = { preventDefault: vi.fn() };
listeners.get("open-url")!(event, "t3code-dev://app/auth/callback?code=clerk-code");
listeners.get("open-url")!(event, "t3code://app/welcome");
assert.equal(loadURL.mock.calls.length, 0);
assert.equal(event.preventDefault.mock.calls.length, 0);
listeners.get("second-instance")!({}, [
"t3",
"t3code-dev://app/settings/providers?instanceId=work&code=never-forward",
]);
yield* Effect.promise(() => revealed.promise);
assert.deepEqual(loadURL.mock.calls, [
["t3code-dev://app/settings/providers?instanceId=work"],
]);
listeners.get("open-url")!(event, "t3code-dev://app/welcome#agents:machine-id");
assert.equal(event.preventDefault.mock.calls.length, 1);
}).pipe(
Effect.scoped,
Effect.provide(makeDesktopClerkLayer()),
Effect.provideService(ElectronApp.ElectronApp, electronApp),
Effect.provideService(ElectronWindow.ElectronWindow, electronWindow),
);
},
);

for (const entry of ["startup", "open-url"] as const) {
it.effect(`receives hosted web sign-in through the desktop ${entry} handler`, () =>
Effect.gen(function* () {
storageMock.mockReturnValue(storageAdapter);
createClerkBridgeMock.mockReturnValue({ cleanup: vi.fn(), isPrimaryInstance: true });
const port = yield* Effect.promise(async () => {
const server = NodeHttp.createServer();
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
const address = server.address();
if (!address || typeof address === "string") throw new Error("address");
await new Promise<void>((resolve) => server.close(() => resolve()));
return address.port;
});
const authorize = new URL("https://auth.openai.com/api/accounts/authorize");
authorize.search = new URLSearchParams({
client_id: "dynamic_agent_client",
response_type: "code",
redirect_uri: `http://127.0.0.1:${port}/auth/callback`,
state: "a".repeat(43),
code_challenge_method: "S256",
code_challenge: "b".repeat(43),
}).toString();
const request = {
authorizationUrl: authorize.toString(),
returnUrl: "https://app.t3.codes/welcome#agents:remote-one",
environmentId: EnvironmentId.make("remote-one"),
instanceId: ProviderInstanceId.make("work"),
flowId: "flow-one",
};
const link = codexAuthHandoffUrl(request, true);
const delivered = Promise.withResolvers<string>();
const shell = ElectronShell.ElectronShell.of({
openExternal: (value) =>
Effect.promise(async () => {
const url = new URL(String(value));
const callback = new URL(url.searchParams.get("redirect_uri")!);
callback.search = new URLSearchParams({
state: url.searchParams.get("state")!,
code: "test-code",
client_id: "oaiapp_test",
}).toString();
const response = await fetch(callback, { redirect: "manual" });
delivered.resolve(response.headers.get("location")!);
return true;
}),
openSystemSettings: () => Effect.succeed(false),
copyText: () => Effect.void,
});
const listeners = new Map<string, (...args: unknown[]) => void>();
const electronApp = {
whenReady: Effect.void,
on: (name: string, listener: (...args: unknown[]) => void) =>
Effect.sync(() => {
listeners.set(name, listener);
}),
} as unknown as ElectronApp.ElectronApp["Service"];
yield* Effect.gen(function* () {
const clerk = yield* DesktopClerk.DesktopClerk;
yield* clerk.configure;
if (entry === "open-url") {
const event = { preventDefault: vi.fn() };
listeners.get("open-url")!(event, link);
assert.strictEqual(event.preventDefault.mock.calls.length, 1);
}
const delivery = readCodexAuthDelivery(yield* Effect.promise(() => delivered.promise));
assert.strictEqual(delivery?.environmentId, request.environmentId);
assert.strictEqual(delivery?.instanceId, request.instanceId);
assert.strictEqual(delivery?.flowId, request.flowId);
assert.strictEqual(delivery?.returnUrl, request.returnUrl);
}).pipe(
Effect.provide(makeDesktopClerkLayer(true, [], "darwin", undefined, shell)),
Effect.provideService(HostProcessArguments, entry === "startup" ? ["t3", link] : ["t3"]),
Effect.provideService(ElectronApp.ElectronApp, electronApp),
Effect.provideService(
ElectronWindow.ElectronWindow,
{} as ElectronWindow.ElectronWindow["Service"],
),
);
}).pipe(Effect.scoped),
);
}
63 changes: 59 additions & 4 deletions apps/desktop/src/app/DesktopClerk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import * as Option from "effect/Option";
import * as Schema from "effect/Schema";
import * as Scope from "effect/Scope";

import { codexAuthDeliveryUrl, readCodexAuthHandoff } from "@t3tools/shared/codexAuthHandoff";
import { receiveCodexAuthCallback, CodexAuthCallbackError } from "./CodexAuthCallback.ts";
import * as ElectronShell from "../electron/ElectronShell.ts";
import { providerAuthReturnUrl } from "@t3tools/shared/providerAuthReturnUrl";
import { HostProcessArguments } from "@t3tools/shared/hostProcess";
import { clerkFrontendApiHostnameFromPublishableKey } from "@t3tools/shared/relayAuth";
import * as ElectronApp from "../electron/ElectronApp.ts";
import * as ElectronProtocol from "../electron/ElectronProtocol.ts";
Expand Down Expand Up @@ -87,6 +92,7 @@ function createDesktopClerkBridge(stateDir: string, isDevelopment: boolean) {
export const make = Effect.gen(function* () {
const environment = yield* DesktopEnvironment.DesktopEnvironment;
const electronApp = yield* ElectronApp.ElectronApp;
const shell = yield* ElectronShell.ElectronShell;

// The SDK bridge acquires Electron's profile-scoped single-instance lock.
// Must not yield: the bridge registers a scheme Electron rejects once ready.
Expand Down Expand Up @@ -132,13 +138,62 @@ export const make = Effect.gen(function* () {
return yield* Effect.interrupt;
}

yield* electronApp.on("second-instance", () => {
const startProviderAuthHandoff = (value: string | undefined) => {
if (!value) return false;
const request = readCodexAuthHandoff(value, environment.isDevelopment);
if (!request) return false;
void runPromise(
Effect.gen(function* () {
yield* electronApp.whenReady;
yield* Effect.tryPromise({
try: () =>
receiveCodexAuthCallback(
request.authorizationUrl,
(url) => runPromise(shell.openExternal(url)),
(callbackUrl) => codexAuthDeliveryUrl(request, callbackUrl),
),
catch: () =>
new CodexAuthCallbackError({
detail:
"Could not receive hosted web ChatGPT sign-in. Retry or use the redirect URL in the web app.",
}),
});
}).pipe(
Effect.catch(() => Effect.logWarning("Could not complete ChatGPT desktop handoff.")),
),
);
return true;
};
const resumeProviderAuth = (value: string | undefined) => {
const destination = providerAuthReturnUrl(value);
const expectedOrigin = `${ElectronProtocol.getDesktopScheme(environment.isDevelopment)}://app`;
if (!destination?.startsWith(`${expectedOrigin}/`)) return false;
void runPromise(
Effect.gen(function* () {
const mainWindow = yield* electronWindow.currentMainOrFirst;
if (Option.isNone(mainWindow)) return;
yield* Effect.promise(() => mainWindow.value.loadURL(destination));
yield* electronWindow.reveal(mainWindow.value);
}).pipe(
Effect.catchCause((cause) =>
Effect.logWarning("Could not return to provider setup", cause),
),
),
);
return true;
};
const args = yield* HostProcessArguments;
args.some((value) => startProviderAuthHandoff(value));
yield* electronApp.on("open-url", (event: { preventDefault: () => void }, url: string) => {
if (startProviderAuthHandoff(url) || resumeProviderAuth(url)) event.preventDefault();
});
yield* electronApp.on("second-instance", (_event: unknown, argv: readonly string[]) => {
if (argv?.some((value) => startProviderAuthHandoff(value) || resumeProviderAuth(value)))
return;
void runPromise(
Effect.gen(function* () {
const mainWindow = yield* electronWindow.currentMainOrFirst;
if (Option.isSome(mainWindow)) {
yield* electronWindow.reveal(mainWindow.value);
}
if (Option.isSome(mainWindow)) yield* electronWindow.reveal(mainWindow.value);
}),
);
});
Expand Down
Loading
Loading