diff --git a/src/cli/cli-installer.telemetry.test.ts b/src/cli/cli-installer.telemetry.test.ts index c1b8eb8ac..772173910 100644 --- a/src/cli/cli-installer.telemetry.test.ts +++ b/src/cli/cli-installer.telemetry.test.ts @@ -39,8 +39,6 @@ describe("runCliInstaller telemetry isolation", () => { mock.module("../shared/posthog", () => ({ createCliPostHog: mock(() => ({ trackActive: mock(() => {}), - capture: mock(() => {}), - captureException: mock(() => {}), shutdown: mock(async () => { throw new Error("shutdown failed") }), diff --git a/src/index.telemetry.test.ts b/src/index.telemetry.test.ts index 99d9200b3..e93f8694d 100644 --- a/src/index.telemetry.test.ts +++ b/src/index.telemetry.test.ts @@ -30,14 +30,6 @@ const mockCreateHooks = mock(() => ({ claudeCodeHooks: undefined, })) const mockCreatePluginInterface = mock(() => ({})) -const mockCreatePluginPostHog = mock(() => ({ - trackActive: () => { - throw new Error("telemetry failed") - }, - shutdown: mock(async () => {}), -})) -const mockGetPostHogDistinctId = mock(() => "plugin-distinct-id") - function installModuleMocks(): void { mock.module("./cli/config-manager/config-context", () => ({ initConfigContext: mockInitConfigContext, @@ -98,10 +90,6 @@ function installModuleMocks(): void { cleanupTempDirectoryClients: mock(async () => {}), }, })) - mock.module("./shared/posthog", () => ({ - createPluginPostHog: mockCreatePluginPostHog, - getPostHogDistinctId: mockGetPostHogDistinctId, - })) } describe("oh-my-openagent telemetry isolation", () => { diff --git a/src/index.ts b/src/index.ts index e57eccb8f..5921bb73b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -17,7 +17,6 @@ import { injectServerAuthIntoClient, log, logLegacyPluginStartupWarning } from " import { installAgentSortShim } from "./shared/agent-sort-shim" import { detectExternalSkillPlugin, getSkillPluginConflictWarning } from "./shared/external-plugin-detector" import { startBackgroundCheck as startTmuxCheck } from "./tools/interactive-bash" -import { createPluginPostHog, getPostHogDistinctId } from "./shared/posthog" const serverPlugin: Plugin = async (input, _options): Promise => { installAgentSortShim() @@ -36,13 +35,6 @@ const serverPlugin: Plugin = async (input, _options): Promise => { const pluginConfig = loadPluginConfig(input.directory, input) - const posthog = createPluginPostHog() - const distinctId = getPostHogDistinctId() - try { - posthog.trackActive(distinctId, "plugin_loaded") - } catch { - // telemetry failure is non-fatal, silently ignore - } if (pluginConfig.openclaw) { await initializeOpenClaw(pluginConfig.openclaw) } diff --git a/src/shared/posthog.test.ts b/src/shared/posthog.test.ts index da87f69ac..b945a7e31 100644 --- a/src/shared/posthog.test.ts +++ b/src/shared/posthog.test.ts @@ -67,7 +67,7 @@ describe("posthog client creation", () => { expect(() => cliPostHog.trackActive("cli", "run_started")).not.toThrow() await expect(cliPostHog.shutdown()).resolves.toBeUndefined() - expect(() => pluginPostHog.trackActive("plugin", "plugin_loaded")).not.toThrow() + expect(() => pluginPostHog.trackActive("plugin", "run_started")).not.toThrow() await expect(pluginPostHog.shutdown()).resolves.toBeUndefined() }) @@ -104,9 +104,44 @@ describe("posthog client creation", () => { const pluginPostHog = createPluginPostHog() // then - expect(() => pluginPostHog.trackActive("plugin", "plugin_loaded")).not.toThrow() + expect(() => pluginPostHog.trackActive("plugin", "run_started")).not.toThrow() await expect(pluginPostHog.shutdown()).resolves.toBeUndefined() }) + + it("passes the strict PostHog constructor options for both clients", async () => { + // given + enableTelemetryEnv() + const capturedOptions: Array> = [] + + mock.module("posthog-node", () => ({ + PostHog: class { + constructor(_apiKey: string, options: Record) { + capturedOptions.push(options) + } + capture() {} + async shutdown() {} + }, + })) + + const { createCliPostHog, createPluginPostHog } = await importPostHogModule() + + // when + createCliPostHog() + createPluginPostHog() + + // then + expect(capturedOptions).toHaveLength(2) + for (const options of capturedOptions) { + expect(options).toMatchObject({ + enableExceptionAutocapture: false, + enableLocalEvaluation: false, + strictLocalEvaluation: true, + disableRemoteConfig: true, + flushAt: 1, + flushInterval: 0, + }) + } + }) }) describe("posthog trackActive emission contract", () => { @@ -170,7 +205,7 @@ describe("posthog trackActive emission contract", () => { const client = posthogModule.createPluginPostHog() // when - client.trackActive("distinct-plugin", "plugin_loaded") + client.trackActive("distinct-plugin", "run_started") // then expect(captured).toHaveLength(0) diff --git a/src/shared/posthog.ts b/src/shared/posthog.ts index b4c61a8f5..1d66988f9 100644 --- a/src/shared/posthog.ts +++ b/src/shared/posthog.ts @@ -29,7 +29,7 @@ const DEFAULT_POSTHOG_API_KEY = "phc_CFJhj5HyvA62QPhvyaUCtaq23aUfznnijg5VaaGkNk7 type PostHogCaptureEvent = Parameters[0] type PostHogSource = "cli" | "plugin" -type PostHogActivityReason = "run_started" | "plugin_loaded" +type PostHogActivityReason = "run_started" type PostHogClient = { trackActive: (distinctId: string, reason: PostHogActivityReason) => void @@ -151,6 +151,9 @@ export function getPostHogDistinctId(): string { export function createCliPostHog(): PostHogClient { return createPostHogClient("cli", { enableExceptionAutocapture: false, + enableLocalEvaluation: false, + strictLocalEvaluation: true, + disableRemoteConfig: true, flushAt: 1, flushInterval: 0, }) @@ -159,6 +162,9 @@ export function createCliPostHog(): PostHogClient { export function createPluginPostHog(): PostHogClient { return createPostHogClient("plugin", { enableExceptionAutocapture: false, + enableLocalEvaluation: false, + strictLocalEvaluation: true, + disableRemoteConfig: true, flushAt: 1, flushInterval: 0, })