feat(omo-codex): wire Codex SessionStart telemetry for DAU/WAU/MAU
Adds a new Codex plugin component `telemetry` that emits a single omo_codex_daily_active event (reason: session_start) from every Codex SessionStart hook, with the same UTC-day deduplication, hashed installation identifier, and four-flag opt-out as the install-time event. Previously omo-codex telemetry only fired on install_completed, so DAU/WAU/MAU under-reported real Codex usage. - New plugin component packages/omo-codex/plugin/components/telemetry/ mirrors the rules/comment-checker/lsp pattern: own src/, tsc build, vitest tests, package.json (posthog-node dep), hooks/hooks.json. - src/codex-hook.ts wraps createPluginPostHog().trackActive(..., "session_start") with safeShutdown so Codex session startup never blocks on telemetry. - Plugin root hooks.json + workspaces register the new component alongside rules and ultrawork on SessionStart. - Aggregate test expectations updated to include the telemetry directory. - cross-package-equivalence.test.ts pins product-identity constants and shouldDisablePostHog behavior to stay byte-equivalent between the CLI installer (src/telemetry/) and the plugin runtime (plugin/components/telemetry/src/), so the two PostHog sources never drift on event name, distinct_id base, dedup file path, or opt-out flags. - PostHogActivityReason union in the CLI-side posthog.ts gains "session_start" so future CLI paths can emit the same reason without a type break.
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import { describe, expect, it } from "bun:test"
|
||||
|
||||
import * as cliIdentity from "./product-identity"
|
||||
|
||||
describe("cross-package telemetry identity equivalence", () => {
|
||||
describe("#given the omo-codex CLI telemetry product-identity module and the Codex plugin component product-identity module", () => {
|
||||
it("#when both are imported #then PRODUCT_NAME, PACKAGE_NAME, CACHE_DIR_NAME, EVENT_NAME, DEFAULT_POSTHOG_HOST, and DEFAULT_POSTHOG_API_KEY are identical", async () => {
|
||||
const pluginIdentity = await import(
|
||||
"../../plugin/components/telemetry/src/product-identity"
|
||||
)
|
||||
|
||||
expect(pluginIdentity.PRODUCT_NAME).toBe(cliIdentity.PRODUCT_NAME)
|
||||
expect(pluginIdentity.PACKAGE_NAME).toBe(cliIdentity.PACKAGE_NAME)
|
||||
expect(pluginIdentity.CACHE_DIR_NAME).toBe(cliIdentity.CACHE_DIR_NAME)
|
||||
expect(pluginIdentity.EVENT_NAME).toBe(cliIdentity.EVENT_NAME)
|
||||
expect(pluginIdentity.DEFAULT_POSTHOG_HOST).toBe(cliIdentity.DEFAULT_POSTHOG_HOST)
|
||||
expect(pluginIdentity.DEFAULT_POSTHOG_API_KEY).toBe(cliIdentity.DEFAULT_POSTHOG_API_KEY)
|
||||
expect(pluginIdentity.LEGACY_PARENT_PACKAGE).toBe(cliIdentity.LEGACY_PARENT_PACKAGE)
|
||||
})
|
||||
})
|
||||
|
||||
describe("#given the omo-codex CLI env-flags module and the Codex plugin component env-flags module", () => {
|
||||
it("#when shouldDisablePostHog is checked under each opt-out env var #then both modules disable on the same flags", async () => {
|
||||
const cliEnv = await import("./env-flags")
|
||||
const pluginEnv = await import(
|
||||
"../../plugin/components/telemetry/src/env-flags"
|
||||
)
|
||||
|
||||
const flags = [
|
||||
"OMO_DISABLE_POSTHOG",
|
||||
"OMO_SEND_ANONYMOUS_TELEMETRY",
|
||||
"OMO_CODEX_DISABLE_POSTHOG",
|
||||
"OMO_CODEX_SEND_ANONYMOUS_TELEMETRY",
|
||||
] as const
|
||||
const previousValues = new Map<string, string | undefined>()
|
||||
for (const flag of flags) {
|
||||
previousValues.set(flag, process.env[flag])
|
||||
delete process.env[flag]
|
||||
}
|
||||
try {
|
||||
expect(cliEnv.shouldDisablePostHog()).toBe(false)
|
||||
expect(pluginEnv.shouldDisablePostHog()).toBe(false)
|
||||
|
||||
for (const optOutFlag of ["OMO_DISABLE_POSTHOG", "OMO_CODEX_DISABLE_POSTHOG"] as const) {
|
||||
process.env[optOutFlag] = "1"
|
||||
expect(cliEnv.shouldDisablePostHog()).toBe(true)
|
||||
expect(pluginEnv.shouldDisablePostHog()).toBe(true)
|
||||
delete process.env[optOutFlag]
|
||||
}
|
||||
|
||||
for (const sendFlag of ["OMO_SEND_ANONYMOUS_TELEMETRY", "OMO_CODEX_SEND_ANONYMOUS_TELEMETRY"] as const) {
|
||||
process.env[sendFlag] = "0"
|
||||
expect(cliEnv.shouldDisablePostHog()).toBe(true)
|
||||
expect(pluginEnv.shouldDisablePostHog()).toBe(true)
|
||||
delete process.env[sendFlag]
|
||||
}
|
||||
} finally {
|
||||
for (const flag of flags) {
|
||||
const previous = previousValues.get(flag)
|
||||
if (previous === undefined) {
|
||||
delete process.env[flag]
|
||||
} else {
|
||||
process.env[flag] = previous
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
export { DEFAULT_POSTHOG_API_KEY, DEFAULT_POSTHOG_HOST }
|
||||
|
||||
export type PostHogSource = "cli" | "plugin" | "install"
|
||||
export type PostHogActivityReason = "install_started" | "install_completed" | "cli_run"
|
||||
export type PostHogActivityReason = "install_started" | "install_completed" | "cli_run" | "session_start"
|
||||
|
||||
export type PostHogClient = {
|
||||
trackActive: (distinctId: string, reason: PostHogActivityReason) => void
|
||||
|
||||
Reference in New Issue
Block a user