Skip to content

Commit de34391

Browse files
juliusmarmingemaria-rcksBil0000shivamhwpvitalyiegorov
authored
feat(orchestrator): introduce new orchestrator (pingdotgg#2829)
Co-authored-by: maria-rcks <maria@kuuro.net> Co-authored-by: Bilal Bakr <62337003+Bil0000@users.noreply.github.com> Co-authored-by: shivam <91240327+shivamhwp@users.noreply.github.com> Co-authored-by: Vitalii Yehorov <vitalyiegorov@gmail.com> Co-authored-by: Jake Leventhal <jakeleventhal@me.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: Alex Southwell <saphid@gmail.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Nicholas Wasmiller <derped@mineperial.com> Co-authored-by: PB <poilmb@gmail.com> Co-authored-by: Exotic <118054752+extoci@users.noreply.github.com> Co-authored-by: Yash Singh <saiansh2525@gmail.com> Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Theo Browne <me@t3.gg> Co-authored-by: Gabriel De Andrade <30420087+gabrielelpidio@users.noreply.github.com> Co-authored-by: Dara Adedeji <76637177+SunkenInTime@users.noreply.github.com> Co-authored-by: scratchyone <scratchywon@gmail.com> Co-authored-by: Dominic Roy <dominic@sdko.org> Co-authored-by: chukfinley <chuk@chuk.dev> Co-authored-by: Primož Ajdišek <bigpod@bigpod.si> Co-authored-by: benthecarman <benthecarman@live.com> Co-authored-by: NaveDanan <nave0712@gmail.com> Co-authored-by: aaditagrawal <103925638+aaditagrawal@users.noreply.github.com> Co-authored-by: Aditya Garud <153842990+yashranaway@users.noreply.github.com> Co-authored-by: Nick Anisimov <n.anisimov.23@gmail.com> Co-authored-by: MacKinley Smith <smithmackinley@gmail.com> Co-authored-by: Yordis Prieto <yordis.prieto@gmail.com> Co-authored-by: t3-code[bot] <269035359+t3-code[bot]@users.noreply.github.com> Co-authored-by: AKolenda <akole779@mtroyal.ca> Co-authored-by: Guillermo Casanova <75276669+Gigioxx@users.noreply.github.com> Co-authored-by: Otavio Salvador <otavio@ossystems.com.br> Co-authored-by: Shirish Pothi <183252392+shirishpothi@users.noreply.github.com> Co-authored-by: Ishaan Kothari <ishaanko.mail@gmail.com> Co-authored-by: Bob Fowler <bob@rjf.ca> Co-authored-by: Anton Bezdenezhnykh <gamer392@yandex.ru> Co-authored-by: ValeraZSD <48602572+ValeraZSD@users.noreply.github.com> Co-authored-by: Ephraim <ephraim39hr14m@gmail.com> Co-authored-by: Ryan Ilano <ryanilano@users.noreply.github.com> Co-authored-by: Alex <me@pixp.cc> Co-authored-by: maco <gosarmarcel7@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Tristan Knight <admin@snappeh.com> Co-authored-by: PR Batch Tester <agent@local.test> Co-authored-by: oliver <97427849+flamboh@users.noreply.github.com> Co-authored-by: kamkm <99585688+Kamkmgamer@users.noreply.github.com> Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
1 parent 024d495 commit de34391

1,912 files changed

Lines changed: 380729 additions & 203651 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/ci.yml‎

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,16 @@ jobs:
148148
!/.repos/
149149
sparse-checkout-cone-mode: false
150150

151+
# Blacksmith boots GitHub's Ubuntu runner image (gcc is usually present),
152+
# but ACP process-tree live tests compile a small pthread fixture with `cc`
153+
# and soft-skip when it is missing. Install build-essential so that path
154+
# always runs in CI instead of silently no-oping.
155+
- name: Install C toolchain for process-tree fixtures
156+
run: |
157+
sudo apt-get update
158+
sudo apt-get install -y --no-install-recommends build-essential
159+
command -v cc
160+
151161
- uses: ./.github/actions/setup-apt-mirrors
152162

153163
# The desktop tests compile the browser secret helper. The install runs in
@@ -251,7 +261,7 @@ jobs:
251261
T3CODE_TRANSFER_BUDGET_RESULT_PATH: ${{ runner.temp }}/thread-transfer-result.json
252262
run: vp run --filter t3 test --shard ${{ matrix.shard }}/${{ strategy.job-total }}
253263

254-
# src/server.test.ts writes the budget report, so exactly one shard
264+
# integration/transferBudgetV2.integration.test.ts writes the report; exactly one shard
255265
# produces these files. Gating the upload on their presence keeps a
256266
# single `thread-transfer-results` artifact per run, which is the name
257267
# thread-transfer-report.yml resolves.
@@ -283,6 +293,17 @@ jobs:
283293
if-no-files-found: ignore
284294
retention-days: 30
285295

296+
transfer-report:
297+
name: Transfer report artifact
298+
needs: test_server
299+
runs-on: ubuntu-24.04
300+
steps:
301+
- name: Require transfer measurements
302+
uses: actions/download-artifact@v8
303+
with:
304+
name: thread-transfer-results
305+
path: ${{ runner.temp }}/thread-transfer
306+
286307
# Split out of Check and Test: both paid ~7-9s to install a Rust toolchain
287308
# for checks that take under 3s, on the critical path of every PR.
288309
rust:

‎.github/workflows/mobile-eas-production.yml‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,20 +25,21 @@ name: Mobile EAS Production
2525
# workflow_dispatch remains as a manual override for both modes (e.g. to
2626
# retry an errored build or force an OTA).
2727
# Manual v2-preview builds keep the production app identity and disable OTA.
28+
# They auto-submit to TestFlight and the Google Play closed testing track v2.
2829
# Select the v2 branch when dispatching a preview build.
2930
on:
3031
workflow_dispatch:
3132
inputs:
3233
mode:
33-
description: "build (+ auto-submit to TestFlight) or update (OTA)"
34+
description: "build (+ auto-submit to TestFlight / Google Play) or update (OTA)"
3435
required: true
3536
type: choice
3637
default: build
3738
options:
3839
- build
3940
- update
4041
profile:
41-
description: "Store build profile (v2-preview supports build mode only)"
42+
description: "Store build profile (v2-preview: TestFlight + Play closed track v2; build only)"
4243
required: true
4344
type: choice
4445
default: production
@@ -49,7 +50,7 @@ on:
4950
description: "Target platform"
5051
required: true
5152
type: choice
52-
default: ios
53+
default: all
5354
options:
5455
- ios
5556
- android

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ squashfs-root/
2727
.vercel
2828
.gstack/
2929
.plans/
30+
/audits/
3031
dist-electron/
3132
.electron-runtime/
3233
.showcase/

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ Full docs live in [docs/](./docs). There's no docs site yet.
9292
- [Permission modes](./docs/user/permission-modes.md)
9393
- [Keyboard shortcuts](./docs/user/keybindings.md)
9494
- [Project settings](./docs/user/project-settings.md)
95+
- [Appearance preferences](./docs/user/appearance.md)
9596
- [Remote access from a phone or another machine](./docs/user/remote-access.md)
9697
- [Keeping app and server in sync](./docs/user/updating.md)
9798
- [Source control integrations](./docs/user/source-control.md)

‎apps/desktop/src/app/DesktopAppIdentity.test.ts‎

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import * as DesktopAppIdentity from "./DesktopAppIdentity.ts";
1414
import * as DesktopAssets from "./DesktopAssets.ts";
1515
import * as DesktopConfig from "./DesktopConfig.ts";
1616
import * as DesktopEnvironment from "./DesktopEnvironment.ts";
17+
import * as DesktopUserData from "./DesktopUserData.ts";
1718

1819
const defaultEnvironmentInput = {
1920
dirname: "/repo/apps/desktop/dist-electron",
@@ -124,13 +125,14 @@ const withIdentity = <A, E, R>(
124125
return effect.pipe(
125126
Effect.provide(
126127
DesktopAppIdentity.layer.pipe(
128+
Layer.provide(NodePath.layerPosix),
127129
Layer.provideMerge(
128130
FileSystem.layerNoop({
129131
exists: (path) =>
130132
input.legacyPathProbeError
131133
? Effect.fail(input.legacyPathProbeError)
132134
: Effect.succeed(
133-
input.legacyPathExists === true && path.includes("T3 Code (Alpha)"),
135+
input.legacyPathExists === true && /T3 Code \((Alpha|Dev)\)/.test(path),
134136
),
135137
readFileString: () =>
136138
Effect.succeed(input.packageJson ?? '{"t3codeCommitHash":"abcdef1234567890"}'),
@@ -145,20 +147,36 @@ const withIdentity = <A, E, R>(
145147
};
146148

147149
describe("DesktopAppIdentity", () => {
148-
it.effect("keeps using the legacy userData path when it already exists", () =>
150+
it.effect("isolates the V2 profile even when the legacy V1 profile exists", () =>
149151
withIdentity(
150152
Effect.gen(function* () {
151153
const identity = yield* DesktopAppIdentity.DesktopAppIdentity;
152154
const userDataPath = yield* identity.resolveUserDataPath;
153155

154-
assert.equal(userDataPath, "/Users/alice/Library/Application Support/T3 Code (Alpha)");
156+
assert.equal(userDataPath, "/Users/alice/Library/Application Support/t3code-v2");
155157
}),
156158
{ legacyPathExists: true },
157159
),
158160
);
159161

162+
it.effect("keeps using the legacy development profile", () =>
163+
withIdentity(
164+
Effect.gen(function* () {
165+
const identity = yield* DesktopAppIdentity.DesktopAppIdentity;
166+
assert.equal(
167+
yield* identity.resolveUserDataPath,
168+
"/Users/alice/Library/Application Support/T3 Code (Dev)",
169+
);
170+
}),
171+
{
172+
legacyPathExists: true,
173+
environment: { env: { VITE_DEV_SERVER_URL: "http://localhost:5173" } },
174+
},
175+
),
176+
);
177+
160178
it.effect("preserves failures while inspecting the legacy userData path", () => {
161-
const legacyPath = "/Users/alice/Library/Application Support/T3 Code (Alpha)";
179+
const legacyPath = "/Users/alice/Library/Application Support/T3 Code (Dev)";
162180
const cause = PlatformError.systemError({
163181
_tag: "PermissionDenied",
164182
module: "FileSystem",
@@ -172,15 +190,18 @@ describe("DesktopAppIdentity", () => {
172190
const identity = yield* DesktopAppIdentity.DesktopAppIdentity;
173191
const error = yield* identity.resolveUserDataPath.pipe(Effect.flip);
174192

175-
assert.instanceOf(error, DesktopAppIdentity.DesktopUserDataPathResolutionError);
176-
assert.equal(error.legacyPath, legacyPath);
193+
assert.instanceOf(error, DesktopUserData.DesktopUserDataInitializationError);
194+
assert.equal(error.resourcePath, legacyPath);
177195
assert.strictEqual(error.cause, cause);
178196
assert.equal(
179197
error.message,
180-
`Failed to inspect legacy desktop user-data path at "${legacyPath}".`,
198+
`Could not initialize Electron user data during inspect at ${legacyPath} (PermissionDenied).`,
181199
);
182200
}),
183-
{ legacyPathProbeError: cause },
201+
{
202+
legacyPathProbeError: cause,
203+
environment: { env: { VITE_DEV_SERVER_URL: "http://localhost:5173" } },
204+
},
184205
);
185206
});
186207

‎apps/desktop/src/app/DesktopAppIdentity.ts‎

Lines changed: 9 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ import * as Effect from "effect/Effect";
33
import * as FileSystem from "effect/FileSystem";
44
import * as Layer from "effect/Layer";
55
import * as Option from "effect/Option";
6+
import * as Path from "effect/Path";
67
import * as Ref from "effect/Ref";
78
import * as Schema from "effect/Schema";
89

910
import * as ElectronApp from "../electron/ElectronApp.ts";
1011
import * as DesktopAssets from "./DesktopAssets.ts";
1112
import * as DesktopEnvironment from "./DesktopEnvironment.ts";
13+
import * as DesktopUserData from "./DesktopUserData.ts";
1214

1315
const COMMIT_HASH_PATTERN = /^[0-9a-f]{7,40}$/i;
1416
const COMMIT_HASH_DISPLAY_LENGTH = 12;
@@ -18,22 +20,13 @@ const AppPackageMetadata = Schema.Struct({
1820
});
1921
const decodeAppPackageMetadata = Schema.decodeEffect(Schema.fromJsonString(AppPackageMetadata));
2022

21-
export class DesktopUserDataPathResolutionError extends Schema.TaggedError<DesktopUserDataPathResolutionError>()(
22-
"DesktopUserDataPathResolutionError",
23-
{
24-
legacyPath: Schema.String,
25-
cause: Schema.Defect(),
26-
},
27-
) {
28-
override get message(): string {
29-
return `Failed to inspect legacy desktop user-data path at "${this.legacyPath}".`;
30-
}
31-
}
32-
3323
export class DesktopAppIdentity extends Context.Service<
3424
DesktopAppIdentity,
3525
{
36-
readonly resolveUserDataPath: Effect.Effect<string, DesktopUserDataPathResolutionError>;
26+
readonly resolveUserDataPath: Effect.Effect<
27+
string,
28+
DesktopUserData.DesktopUserDataInitializationError
29+
>;
3730
readonly configure: Effect.Effect<void>;
3831
}
3932
>()("@t3tools/desktop/app/DesktopAppIdentity") {}
@@ -45,33 +38,13 @@ const normalizeCommitHash = (value: string): Option.Option<string> => {
4538
: Option.none();
4639
};
4740

48-
export const resolveUserDataPath = Effect.gen(function* () {
49-
const environment = yield* DesktopEnvironment.DesktopEnvironment;
50-
const fileSystem = yield* FileSystem.FileSystem;
51-
const legacyPath = environment.path.join(
52-
environment.appDataDirectory,
53-
environment.legacyUserDataDirName,
54-
);
55-
const legacyPathExists = yield* fileSystem.exists(legacyPath).pipe(
56-
Effect.mapError(
57-
(cause) =>
58-
new DesktopUserDataPathResolutionError({
59-
legacyPath,
60-
cause,
61-
}),
62-
),
63-
);
64-
return legacyPathExists
65-
? legacyPath
66-
: environment.path.join(environment.appDataDirectory, environment.userDataDirName);
67-
}).pipe(Effect.withSpan("desktop.appIdentity.resolveUserDataPath"));
68-
6941
/** @public Service construction is part of the canonical Effect module API. */
7042
export const make = Effect.gen(function* () {
7143
const assets = yield* DesktopAssets.DesktopAssets;
7244
const electronApp = yield* ElectronApp.ElectronApp;
7345
const environment = yield* DesktopEnvironment.DesktopEnvironment;
7446
const fileSystem = yield* FileSystem.FileSystem;
47+
const userDataContext = yield* Effect.context<FileSystem.FileSystem | Path.Path>();
7548
const commitHashCache = yield* Ref.make<Option.Option<Option.Option<string>>>(Option.none());
7649

7750
const resolveEmbeddedCommitHash = Effect.gen(function* () {
@@ -112,10 +85,8 @@ export const make = Effect.gen(function* () {
11285
return commitHash;
11386
});
11487

115-
const userDataPath = resolveUserDataPath.pipe(
116-
Effect.provide(
117-
yield* Effect.context<DesktopEnvironment.DesktopEnvironment | FileSystem.FileSystem>(),
118-
),
88+
const userDataPath = DesktopUserData.resolveUserDataPath(environment).pipe(
89+
Effect.provide(userDataContext),
11990
);
12091

12192
const configure = Effect.gen(function* () {

‎apps/desktop/src/app/DesktopClerk.test.ts‎

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// @effect-diagnostics nodeBuiltinImport:off globalFetchInEffect:off - Hosted handoff test uses a real localhost listener without an OpenAI account.
22
import * as NodeHttp from "node:http";
3+
import * as NodePath from "@effect/platform-node/NodePath";
34
import { codexAuthHandoffUrl, readCodexAuthDelivery } from "@t3tools/shared/codexAuthHandoff";
45
import { EnvironmentId, ProviderInstanceId } from "@t3tools/contracts";
56
import { HostProcessArguments } from "@t3tools/shared/hostProcess";
@@ -35,10 +36,15 @@ import * as ElectronShell from "../electron/ElectronShell.ts";
3536
import * as ElectronWindow from "../electron/ElectronWindow.ts";
3637
import * as DesktopClerk from "./DesktopClerk.ts";
3738
import * as DesktopEnvironment from "./DesktopEnvironment.ts";
39+
import * as DesktopPreReadyFileSystem from "./DesktopPreReadyFileSystem.ts";
3840

3941
const makeDesktopClerkLayer = (
4042
isDevelopment = true,
4143
events: string[] = [],
44+
platform: NodeJS.Platform = "darwin",
45+
fileSystemLayer: Layer.Layer<FileSystem.FileSystem> = FileSystem.layerNoop({
46+
exists: () => Effect.succeed(false),
47+
}),
4248
shell: ElectronShell.ElectronShell["Service"] = {
4349
openExternal: () => Effect.succeed(true),
4450
openSystemSettings: () => Effect.succeed(false),
@@ -49,9 +55,7 @@ const makeDesktopClerkLayer = (
4955
stateDir: "/tmp/t3-state",
5056
isDevelopment,
5157
appDataDirectory: "/tmp/app-data",
52-
userDataDirName: isDevelopment ? "t3code-dev" : "t3code",
53-
legacyUserDataDirName: isDevelopment ? "T3 Code (Dev)" : "T3 Code (Alpha)",
54-
path: { join: (...parts: ReadonlyArray<string>) => parts.join("/") },
58+
platform,
5559
} as unknown as DesktopEnvironment.DesktopEnvironment["Service"]);
5660

5761
const electronApp = {
@@ -64,10 +68,11 @@ const makeDesktopClerkLayer = (
6468
return DesktopClerk.layer.pipe(
6569
Layer.provide(
6670
Layer.mergeAll(
71+
NodePath.layerPosix,
6772
Layer.succeed(DesktopEnvironment.DesktopEnvironment, environment),
6873
Layer.succeed(ElectronApp.ElectronApp, electronApp),
6974
Layer.succeed(ElectronShell.ElectronShell, shell),
70-
FileSystem.layerNoop({ exists: () => Effect.succeed(false) }),
75+
fileSystemLayer,
7176
),
7277
),
7378
);
@@ -110,6 +115,43 @@ describe("DesktopClerk", () => {
110115
});
111116
});
112117

118+
it.each([
119+
{
120+
name: "packaged Windows",
121+
isDevelopment: false,
122+
platform: "win32" as const,
123+
userData: "/tmp/app-data/t3code-v2",
124+
},
125+
{
126+
name: "development",
127+
isDevelopment: true,
128+
platform: "win32" as const,
129+
userData: "/tmp/app-data/t3code-dev",
130+
},
131+
])(
132+
"creates the bridge before startup can yield to the event loop ($name)",
133+
({ isDevelopment, platform, userData }) => {
134+
const events: string[] = [];
135+
storageMock.mockReturnValue(storageAdapter);
136+
createClerkBridgeMock.mockImplementation(() => {
137+
events.push("createClerkBridge");
138+
return { cleanup: vi.fn(), isPrimaryInstance: true };
139+
});
140+
// runSync throws if the layer ever suspends, which would let Electron emit
141+
// ready before the bridge exists. main.ts provides the same FileSystem.
142+
// oxlint-disable-next-line t3code/no-manual-effect-runtime-in-tests -- The assertion IS that the layer builds synchronously; it.effect would mask a regression to async.
143+
Effect.runSync(
144+
Effect.scoped(
145+
Layer.build(
146+
makeDesktopClerkLayer(isDevelopment, events, platform, DesktopPreReadyFileSystem.layer),
147+
),
148+
),
149+
);
150+
151+
assert.deepEqual(events, [`setPath:userData:${userData}`, "createClerkBridge"]);
152+
},
153+
);
154+
113155
it.effect("preserves bridge initialization failures", () => {
114156
const cause = new Error("bridge initialization failed");
115157
storageMock.mockReturnValue(storageAdapter);
@@ -331,7 +373,7 @@ for (const entry of ["startup", "open-url"] as const) {
331373
assert.strictEqual(delivery?.flowId, request.flowId);
332374
assert.strictEqual(delivery?.returnUrl, request.returnUrl);
333375
}).pipe(
334-
Effect.provide(makeDesktopClerkLayer(true, [], shell)),
376+
Effect.provide(makeDesktopClerkLayer(true, [], "darwin", undefined, shell)),
335377
Effect.provideService(HostProcessArguments, entry === "startup" ? ["t3", link] : ["t3"]),
336378
Effect.provideService(ElectronApp.ElectronApp, electronApp),
337379
Effect.provideService(

‎apps/desktop/src/app/DesktopClerk.ts‎

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { clerkFrontendApiHostnameFromPublishableKey } from "@t3tools/shared/rela
1616
import * as ElectronApp from "../electron/ElectronApp.ts";
1717
import * as ElectronProtocol from "../electron/ElectronProtocol.ts";
1818
import * as ElectronWindow from "../electron/ElectronWindow.ts";
19-
import * as DesktopAppIdentity from "./DesktopAppIdentity.ts";
19+
import * as DesktopUserData from "./DesktopUserData.ts";
2020
import * as DesktopEnvironment from "./DesktopEnvironment.ts";
2121

2222
declare const __T3CODE_BUILD_CLERK_PUBLISHABLE_KEY__: string | undefined;
@@ -94,13 +94,9 @@ export const make = Effect.gen(function* () {
9494
const electronApp = yield* ElectronApp.ElectronApp;
9595
const shell = yield* ElectronShell.ElectronShell;
9696

97-
// Electron scopes the single-instance lock to the userData directory and
98-
// creates that directory when the lock is acquired. The SDK bridge takes
99-
// the lock at creation, so userData must already point at the real
100-
// directory here — under the default productName-derived path, acquiring
101-
// the lock would create "T3 Code (Alpha)" and make the legacy-install
102-
// detection in resolveUserDataPath match on fresh installs.
103-
const userDataPath = yield* DesktopAppIdentity.resolveUserDataPath;
97+
// The SDK bridge acquires Electron's profile-scoped single-instance lock.
98+
// Must not yield: the bridge registers a scheme Electron rejects once ready.
99+
const userDataPath = yield* DesktopUserData.resolveUserDataPath(environment);
104100
yield* electronApp.setPath("userData", userDataPath);
105101

106102
const bridge = yield* Effect.acquireRelease(

0 commit comments

Comments
 (0)