Skip to content

Commit 987b033

Browse files
committed
Merge branch 'main' into posthog-code/token-saving-integrations
2 parents 884a63d + bb651ea commit 987b033

354 files changed

Lines changed: 22776 additions & 4106 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/mobile-build.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,5 @@ jobs:
8989
with:
9090
platform: all
9191
profile: production
92-
secrets: inherit
92+
secrets:
93+
EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }}

.github/workflows/test.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,20 @@ jobs:
7171
- name: Run tests
7272
run: pnpm test
7373

74+
- name: Upload test results to Trunk
75+
# Run even when tests fail so flaky/failed results are still reported,
76+
# but never let an upload problem fail the job.
77+
if: ${{ !cancelled() }}
78+
continue-on-error: true
79+
uses: trunk-io/analytics-uploader@385f1ccdf345b4532dc4b6c665dd432b702b8e28 # v2.1.2
80+
with:
81+
# Scope to each package root. A bare **/junit.xml glob descends into
82+
# node_modules, where pnpm symlinks workspace packages, and uploads
83+
# every report many times over.
84+
junit-paths: "apps/*/junit.xml,packages/*/junit.xml"
85+
org-slug: posthog-inc
86+
token: ${{ secrets.TRUNK_API_TOKEN }}
87+
7488
integration-test:
7589
needs: changes
7690
# Fail closed: if change detection itself failed, run instead of skipping.
@@ -140,6 +154,17 @@ jobs:
140154
env:
141155
CI: true
142156

157+
- name: Upload test results to Trunk
158+
# Run even when E2E tests fail so flaky/failed results are still
159+
# reported, but never let an upload problem fail the job.
160+
if: ${{ !cancelled() }}
161+
continue-on-error: true
162+
uses: trunk-io/analytics-uploader@385f1ccdf345b4532dc4b6c665dd432b702b8e28 # v2.1.2
163+
with:
164+
junit-paths: "apps/code/tests/e2e/junit.xml"
165+
org-slug: posthog-inc
166+
token: ${{ secrets.TRUNK_API_TOKEN }}
167+
143168
- name: Upload Playwright report
144169
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
145170
if: failure()

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ test-results/
5757
*storybook.log
5858
.session-store.json
5959
.playwright-mcp
60+
# Trunk Flaky Tests JUnit reports (one per package, uploaded from CI)
61+
junit.xml
6062

6163
# Downloaded binaries
6264
apps/code/resources/codex-acp/

apps/code/electron.vite.config.ts

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import { readFileSync } from "node:fs";
1+
import { existsSync, readFileSync } from "node:fs";
22
import { builtinModules, createRequire } from "node:module";
33
import path from "node:path";
44
import { fileURLToPath } from "node:url";
55
import tailwindcss from "@tailwindcss/vite";
6-
import { devtools } from "@tanstack/devtools-vite";
76
import { TanStackRouterVite } from "@tanstack/router-plugin/vite";
87
import react from "@vitejs/plugin-react";
98
import { defineConfig } from "electron-vite";
@@ -45,6 +44,43 @@ const nodeExternals = [
4544
// the staged node_modules at runtime (see scripts/before-pack.ts).
4645
const nativeModules = buildExternals;
4746

47+
const nearestPackageType = (fromFile: string): string | undefined => {
48+
let dir = path.dirname(fromFile);
49+
while (true) {
50+
const manifest = path.join(dir, "package.json");
51+
if (existsSync(manifest)) {
52+
try {
53+
return JSON.parse(readFileSync(manifest, "utf-8")).type;
54+
} catch {
55+
return undefined;
56+
}
57+
}
58+
const parent = path.dirname(dir);
59+
if (parent === dir) return undefined;
60+
dir = parent;
61+
}
62+
};
63+
64+
const resolvesToCommonJs = (name: string): boolean => {
65+
let resolved: string;
66+
try {
67+
resolved = require.resolve(name);
68+
} catch {
69+
return false;
70+
}
71+
if (resolved.endsWith(".cjs")) return true;
72+
if (resolved.endsWith(".mjs")) return false;
73+
return nearestPackageType(resolved) !== "module";
74+
};
75+
76+
const computeDevThirdPartyExternals = (): RegExp[] =>
77+
Object.keys(pkg.dependencies ?? {})
78+
.filter((name) => !name.startsWith("@posthog/") && resolvesToCommonJs(name))
79+
.map(
80+
(name) =>
81+
new RegExp(`^${name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(/.+)?$`),
82+
);
83+
4884
export default defineConfig(({ mode }) => {
4985
const env = loadEnv(mode, path.resolve(__dirname, "../.."), "");
5086
const isDev = mode === "development";
@@ -115,6 +151,7 @@ export default defineConfig(({ mode }) => {
115151
"electron/main",
116152
...nodeExternals,
117153
...nativeModules,
154+
...(isDev ? computeDevThirdPartyExternals() : []),
118155
],
119156
onwarn(warning, warn) {
120157
if (warning.code === "UNUSED_EXTERNAL_IMPORT") return;
@@ -161,7 +198,6 @@ export default defineConfig(({ mode }) => {
161198
renderer: {
162199
root: __dirname,
163200
plugins: [
164-
isDev && devtools(),
165201
TanStackRouterVite({
166202
target: "react",
167203
autoCodeSplitting: true,

apps/code/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
"@storybook/addon-a11y": "10.4.1",
4848
"@storybook/addon-docs": "10.4.1",
4949
"@storybook/react-vite": "10.4.1",
50-
"@tanstack/devtools-vite": "^0.7.0",
5150
"@testing-library/jest-dom": "^6.9.1",
5251
"@testing-library/react": "^16.3.0",
5352
"@testing-library/user-event": "^14.6.1",
@@ -57,7 +56,7 @@
5756
"@types/react": "^19.2.15",
5857
"@types/react-dom": "^19.2.3",
5958
"@types/semver": "^7.7.1",
60-
"@vitejs/plugin-react": "^4.7.0",
59+
"@vitejs/plugin-react": "^5.2.0",
6160
"@vitest/ui": "^4.1.8",
6261
"adm-zip": "^0.5.17",
6362
"electron": "^42.3.0",
@@ -138,6 +137,7 @@
138137
"react": "19.2.6",
139138
"react-dom": "19.2.6",
140139
"react-hotkeys-hook": "^4.4.4",
140+
"react-scan": "^0.5.6",
141141
"reflect-metadata": "^0.2.2",
142142
"semver": "^7.8.1",
143143
"shadcn": "^4.1.2",

apps/code/src/main/di/bindings.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,13 @@ import type {
107107
} from "@posthog/platform/analytics";
108108
import type { APP_LIFECYCLE_SERVICE } from "@posthog/platform/app-lifecycle";
109109
import type { APP_META_SERVICE } from "@posthog/platform/app-meta";
110+
import type { APP_METRICS_SERVICE } from "@posthog/platform/app-metrics";
110111
import type { BUNDLED_RESOURCES_SERVICE } from "@posthog/platform/bundled-resources";
111112
import type { CLIPBOARD_SERVICE } from "@posthog/platform/clipboard";
112113
import type { CONTEXT_MENU_SERVICE } from "@posthog/platform/context-menu";
113114
import type { CRYPTO_SERVICE } from "@posthog/platform/crypto";
114115
import type { DEEP_LINK_SERVICE } from "@posthog/platform/deep-link";
116+
import type { DEV_HOST_ACTIONS_SERVICE } from "@posthog/platform/dev-host-actions";
115117
import type { DIALOG_SERVICE } from "@posthog/platform/dialog";
116118
import type { FILE_ICON_SERVICE } from "@posthog/platform/file-icon";
117119
import type { IMAGE_PROCESSOR_SERVICE } from "@posthog/platform/image-processor";
@@ -126,11 +128,13 @@ import type { WORKSPACE_SETTINGS_SERVICE } from "@posthog/platform/workspace-set
126128
import type { WorkspaceClient } from "@posthog/workspace-client/client";
127129
import type { DatabaseService } from "@posthog/workspace-server/db/service";
128130
import type { GIT_SERVICE as WS_GIT_SERVICE } from "@posthog/workspace-server/di/tokens";
131+
import type { AgentService } from "@posthog/workspace-server/services/agent/agent";
129132
import type {
130133
AGENT_AUTH,
131134
AGENT_LOGGER,
132135
AGENT_MCP_APPS,
133136
AGENT_REPO_FILES,
137+
AGENT_SERVICE,
134138
AGENT_SLEEP_COORDINATOR,
135139
} from "@posthog/workspace-server/services/agent/identifiers";
136140
import type {
@@ -207,10 +211,12 @@ import type { WorkspaceService } from "@posthog/workspace-server/services/worksp
207211
import type { FileWatcherBridge } from "../index";
208212
import type { ElectronAppLifecycle } from "../platform-adapters/electron-app-lifecycle";
209213
import type { ElectronAppMeta } from "../platform-adapters/electron-app-meta";
214+
import type { ElectronAppMetrics } from "../platform-adapters/electron-app-metrics";
210215
import type { ElectronBundledResources } from "../platform-adapters/electron-bundled-resources";
211216
import type { ElectronClipboard } from "../platform-adapters/electron-clipboard";
212217
import type { ElectronContextMenu } from "../platform-adapters/electron-context-menu";
213218
import type { ElectronCrypto } from "../platform-adapters/electron-crypto";
219+
import type { ElectronDevHostActions } from "../platform-adapters/electron-dev-host-actions";
214220
import type { ElectronDialog } from "../platform-adapters/electron-dialog";
215221
import type { ElectronFileIcon } from "../platform-adapters/electron-file-icon";
216222
import type { ElectronImageProcessor } from "../platform-adapters/electron-image-processor";
@@ -231,6 +237,11 @@ import type {
231237
TokenCipherPortAdapter,
232238
} from "../services/auth/port-adapters";
233239
import type { DeepLinkService } from "../services/deep-link/service";
240+
import type { DevActionsService } from "../services/dev-actions/service";
241+
import type { DevFlagsService } from "../services/dev-flags/service";
242+
import type { DevLogsService } from "../services/dev-logs/service";
243+
import type { DevMetricsService } from "../services/dev-metrics/service";
244+
import type { DevNetworkService } from "../services/dev-network/service";
234245
import type { DiscordPresenceService } from "../services/discord-presence/service";
235246
import type { EncryptionService } from "../services/encryption/service";
236247
import type { SecureStoreService } from "../services/secure-store/service";
@@ -250,6 +261,11 @@ import type {
250261
DATABASE_SERVICE as MAIN_DATABASE_SERVICE,
251262
DEEP_LINK_SERVICE as MAIN_DEEP_LINK_SERVICE,
252263
DEFAULT_ADDITIONAL_DIRECTORY_REPOSITORY as MAIN_DEFAULT_ADDITIONAL_DIRECTORY_REPOSITORY,
264+
DEV_ACTIONS_SERVICE as MAIN_DEV_ACTIONS_SERVICE,
265+
DEV_FLAGS_SERVICE as MAIN_DEV_FLAGS_SERVICE,
266+
DEV_LOGS_SERVICE as MAIN_DEV_LOGS_SERVICE,
267+
DEV_METRICS_SERVICE as MAIN_DEV_METRICS_SERVICE,
268+
DEV_NETWORK_SERVICE as MAIN_DEV_NETWORK_SERVICE,
253269
DISCORD_PRESENCE_SERVICE as MAIN_DISCORD_PRESENCE_SERVICE,
254270
ENCRYPTION_SERVICE as MAIN_ENCRYPTION_SERVICE,
255271
EXTERNAL_APPS_SERVICE as MAIN_EXTERNAL_APPS_SERVICE,
@@ -301,6 +317,8 @@ export interface MainBindings {
301317
[BUNDLED_RESOURCES_SERVICE]: ElectronBundledResources;
302318
[IMAGE_PROCESSOR_SERVICE]: ElectronImageProcessor;
303319
[WORKSPACE_SETTINGS_SERVICE]: ElectronWorkspaceSettings;
320+
[APP_METRICS_SERVICE]: ElectronAppMetrics;
321+
[DEV_HOST_ACTIONS_SERVICE]: ElectronDevHostActions;
304322

305323
// Database (main aliases + ws-server source tokens via toService)
306324
[MAIN_DATABASE_SERVICE]: DatabaseService;
@@ -441,6 +459,13 @@ export interface MainBindings {
441459
[MAIN_ENCRYPTION_SERVICE]: EncryptionService;
442460
[MAIN_DISCORD_PRESENCE_SERVICE]: DiscordPresenceService;
443461

462+
// Dev toolbar diagnostics
463+
[MAIN_DEV_FLAGS_SERVICE]: DevFlagsService;
464+
[MAIN_DEV_METRICS_SERVICE]: DevMetricsService;
465+
[MAIN_DEV_NETWORK_SERVICE]: DevNetworkService;
466+
[MAIN_DEV_LOGS_SERVICE]: DevLogsService;
467+
[MAIN_DEV_ACTIONS_SERVICE]: DevActionsService;
468+
444469
// ws-server git service (bound to(GitService))
445470
[WS_GIT_SERVICE]: GitService;
446471

@@ -458,6 +483,7 @@ export interface MainBindings {
458483
[FS_SERVICE]: FsCapability;
459484

460485
// Typed container.get-only tokens (bound via loaded modules)
486+
[AGENT_SERVICE]: AgentService;
461487
[OAUTH_SERVICE]: OAuthService;
462488
[GITHUB_INTEGRATION_SERVICE]: GitHubIntegrationService;
463489
[SLACK_INTEGRATION_SERVICE]: SlackIntegrationService;

apps/code/src/main/di/container.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,13 @@ import {
9999
import { ANALYTICS_SERVICE } from "@posthog/platform/analytics";
100100
import { APP_LIFECYCLE_SERVICE } from "@posthog/platform/app-lifecycle";
101101
import { APP_META_SERVICE } from "@posthog/platform/app-meta";
102+
import { APP_METRICS_SERVICE } from "@posthog/platform/app-metrics";
102103
import { BUNDLED_RESOURCES_SERVICE } from "@posthog/platform/bundled-resources";
103104
import { CLIPBOARD_SERVICE } from "@posthog/platform/clipboard";
104105
import { CONTEXT_MENU_SERVICE } from "@posthog/platform/context-menu";
105106
import { CRYPTO_SERVICE } from "@posthog/platform/crypto";
106107
import { DEEP_LINK_SERVICE } from "@posthog/platform/deep-link";
108+
import { DEV_HOST_ACTIONS_SERVICE } from "@posthog/platform/dev-host-actions";
107109
import { DIALOG_SERVICE } from "@posthog/platform/dialog";
108110
import { FILE_ICON_SERVICE } from "@posthog/platform/file-icon";
109111
import { IMAGE_PROCESSOR_SERVICE } from "@posthog/platform/image-processor";
@@ -217,10 +219,12 @@ import ExternalAppsStoreImpl from "electron-store";
217219
import type { FileWatcherBridge } from "../index";
218220
import { ElectronAppLifecycle } from "../platform-adapters/electron-app-lifecycle";
219221
import { ElectronAppMeta } from "../platform-adapters/electron-app-meta";
222+
import { ElectronAppMetrics } from "../platform-adapters/electron-app-metrics";
220223
import { ElectronBundledResources } from "../platform-adapters/electron-bundled-resources";
221224
import { ElectronClipboard } from "../platform-adapters/electron-clipboard";
222225
import { ElectronContextMenu } from "../platform-adapters/electron-context-menu";
223226
import { ElectronCrypto } from "../platform-adapters/electron-crypto";
227+
import { ElectronDevHostActions } from "../platform-adapters/electron-dev-host-actions";
224228
import { ElectronDialog } from "../platform-adapters/electron-dialog";
225229
import { ElectronFileIcon } from "../platform-adapters/electron-file-icon";
226230
import { ElectronImageProcessor } from "../platform-adapters/electron-image-processor";
@@ -243,6 +247,11 @@ import {
243247
TokenCipherPortAdapter,
244248
} from "../services/auth/port-adapters";
245249
import { DeepLinkService } from "../services/deep-link/service";
250+
import { DevActionsService } from "../services/dev-actions/service";
251+
import { DevFlagsService } from "../services/dev-flags/service";
252+
import { DevLogsService } from "../services/dev-logs/service";
253+
import { DevMetricsService } from "../services/dev-metrics/service";
254+
import { DevNetworkService } from "../services/dev-network/service";
246255
import { DiscordPresenceService } from "../services/discord-presence/service";
247256
import { EncryptionService } from "../services/encryption/service";
248257
import { SecureStoreService } from "../services/secure-store/service";
@@ -265,6 +274,11 @@ import {
265274
DATABASE_SERVICE as MAIN_DATABASE_SERVICE,
266275
DEEP_LINK_SERVICE as MAIN_DEEP_LINK_SERVICE,
267276
DEFAULT_ADDITIONAL_DIRECTORY_REPOSITORY as MAIN_DEFAULT_ADDITIONAL_DIRECTORY_REPOSITORY,
277+
DEV_ACTIONS_SERVICE as MAIN_DEV_ACTIONS_SERVICE,
278+
DEV_FLAGS_SERVICE as MAIN_DEV_FLAGS_SERVICE,
279+
DEV_LOGS_SERVICE as MAIN_DEV_LOGS_SERVICE,
280+
DEV_METRICS_SERVICE as MAIN_DEV_METRICS_SERVICE,
281+
DEV_NETWORK_SERVICE as MAIN_DEV_NETWORK_SERVICE,
268282
DISCORD_PRESENCE_SERVICE as MAIN_DISCORD_PRESENCE_SERVICE,
269283
ENCRYPTION_SERVICE as MAIN_ENCRYPTION_SERVICE,
270284
EXTERNAL_APPS_SERVICE as MAIN_EXTERNAL_APPS_SERVICE,
@@ -318,6 +332,8 @@ container.bind(CONTEXT_MENU_SERVICE).to(ElectronContextMenu);
318332
container.bind(BUNDLED_RESOURCES_SERVICE).to(ElectronBundledResources);
319333
container.bind(IMAGE_PROCESSOR_SERVICE).to(ElectronImageProcessor);
320334
container.bind(WORKSPACE_SETTINGS_SERVICE).to(ElectronWorkspaceSettings);
335+
container.bind(APP_METRICS_SERVICE).to(ElectronAppMetrics);
336+
container.bind(DEV_HOST_ACTIONS_SERVICE).to(ElectronDevHostActions);
321337

322338
container.load(databaseModule);
323339
container.load(repositoriesModule);
@@ -711,6 +727,8 @@ container.bind(LOGS_SERVICE).toDynamicValue((ctx) => {
711727
},
712728
readLocalLogs: (taskRunId: string) =>
713729
ws.localLogs.read.query({ taskRunId }),
730+
readLocalLogsTail: (taskRunId: string, maxBytes: number) =>
731+
ws.localLogs.readTail.query({ taskRunId, maxBytes }),
714732
writeLocalLogs: (taskRunId: string, content: string) =>
715733
ws.localLogs.write.mutate({ taskRunId, content }),
716734
};
@@ -726,3 +744,9 @@ container.load(canvasCoreModule);
726744
// Browser tabs for the Channels canvas surface. Authoritative sqlite-backed
727745
// service in the main process; resolved by the host-router browserTabs router.
728746
container.load(browserTabsModule);
747+
748+
container.bind(MAIN_DEV_FLAGS_SERVICE).to(DevFlagsService);
749+
container.bind(MAIN_DEV_METRICS_SERVICE).to(DevMetricsService);
750+
container.bind(MAIN_DEV_NETWORK_SERVICE).to(DevNetworkService);
751+
container.bind(MAIN_DEV_LOGS_SERVICE).to(DevLogsService);
752+
container.bind(MAIN_DEV_ACTIONS_SERVICE).to(DevActionsService);

apps/code/src/main/di/tokens.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,18 @@ export const WORKSPACE_SERVER_SERVICE = Symbol.for(
127127
export const DISCORD_PRESENCE_SERVICE = Symbol.for(
128128
"posthog.host.main.discord-presence.service",
129129
);
130+
export const DEV_FLAGS_SERVICE = Symbol.for(
131+
"posthog.host.main.dev-flags.service",
132+
);
133+
export const DEV_METRICS_SERVICE = Symbol.for(
134+
"posthog.host.main.dev-metrics.service",
135+
);
136+
export const DEV_NETWORK_SERVICE = Symbol.for(
137+
"posthog.host.main.dev-network.service",
138+
);
139+
export const DEV_LOGS_SERVICE = Symbol.for(
140+
"posthog.host.main.dev-logs.service",
141+
);
142+
export const DEV_ACTIONS_SERVICE = Symbol.for(
143+
"posthog.host.main.dev-actions.service",
144+
);

apps/code/src/main/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ import {
7272
import { posthogNodeAnalytics } from "./platform-adapters/posthog-analytics";
7373
import { registerMcpSandboxProtocol } from "./protocols/mcp-sandbox";
7474
import type { AppLifecycleService } from "./services/app-lifecycle/service";
75+
import { initDevToolbar } from "./services/dev-toolbar";
7576
import type { DiscordPresenceService } from "./services/discord-presence/service";
7677
import {
7778
focusSessionStore,
@@ -239,6 +240,8 @@ app.on("child-process-gone", (_event, details) => {
239240
});
240241

241242
async function initializeServices(): Promise<void> {
243+
initDevToolbar();
244+
242245
container.get<DatabaseService>(DATABASE_SERVICE);
243246
container.get<OAuthService>(OAUTH_SERVICE);
244247
const authService = container.get<AuthService>(AUTH_SERVICE);
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import type {
2+
AppProcessMetric,
3+
IAppMetrics,
4+
} from "@posthog/platform/app-metrics";
5+
import { app } from "electron";
6+
import { injectable } from "inversify";
7+
8+
@injectable()
9+
export class ElectronAppMetrics implements IAppMetrics {
10+
public getAppMetrics(): AppProcessMetric[] {
11+
return app.getAppMetrics().map((m) => ({
12+
pid: m.pid,
13+
type: m.type,
14+
name: m.name,
15+
cpu: m.cpu ? { percentCPUUsage: m.cpu.percentCPUUsage } : undefined,
16+
memory: m.memory
17+
? { workingSetSize: m.memory.workingSetSize }
18+
: undefined,
19+
}));
20+
}
21+
}

0 commit comments

Comments
 (0)