diff --git a/src/cli.ts b/src/cli.ts index 42216ec5..d33008d5 100755 --- a/src/cli.ts +++ b/src/cli.ts @@ -23,6 +23,12 @@ import { flushSentry, initSentry, } from "./helpers/sentry"; +import { + flushTelemetry, + initTelemetry, + trackCommand, + trackCommandResult, +} from "./helpers/telemetry"; import { checkForUpdatesIfNeeded } from "./helpers/update-check"; if (typeof Bun === "undefined") @@ -41,18 +47,28 @@ createPathIfNotExists(paths.cacheFolder); async function main() { await installGit(); - // Initialize error tracking (no-op if opted out) + // Initialize error tracking and telemetry (no-ops if opted out) initSentry(); + initTelemetry(); const program = new Command() .name("archgate") .version(packageJson.version) .description("AI governance for software development"); - // Add Sentry breadcrumb for each command execution + // Track command execution for Sentry breadcrumbs and PostHog analytics + let commandStartTime = 0; program.hook("preAction", (thisCommand) => { const fullCommand = getFullCommandName(thisCommand); addBreadcrumb("command", `Running: ${fullCommand}`); + trackCommand(fullCommand); + commandStartTime = performance.now(); + }); + + program.hook("postAction", (thisCommand) => { + const fullCommand = getFullCommandName(thisCommand); + const durationMs = Math.round(performance.now() - commandStartTime); + trackCommandResult(fullCommand, 0, durationMs); }); registerInitCommand(program); @@ -74,8 +90,8 @@ async function main() { const notice = await updateCheckPromise; if (notice) console.log(notice); - // Flush Sentry events before exit - await flushSentry(); + // Flush telemetry and error tracking before exit + await Promise.all([flushTelemetry(), flushSentry()]); } /** @@ -97,7 +113,7 @@ function getFullCommandName(command: Command): string { main().catch(async (err: unknown) => { captureException(err, { command: "main" }); - await flushSentry(); + await Promise.all([flushTelemetry(), flushSentry()]); logError(String(err)); process.exit(2); }); diff --git a/src/helpers/telemetry.ts b/src/helpers/telemetry.ts index a33e2f60..fdf63835 100644 --- a/src/helpers/telemetry.ts +++ b/src/helpers/telemetry.ts @@ -27,8 +27,8 @@ import { getInstallId, isTelemetryEnabled } from "./telemetry-config"; * PostHog project API key (write-only, safe to embed in client code). * This key can only ingest events — it cannot read data or manage the project. */ -const POSTHOG_API_KEY = "phc_placeholder"; -const POSTHOG_HOST = "https://us.i.posthog.com"; +const POSTHOG_API_KEY = "phc_gSnjpsvRfQggmgeXUgbevbG0SULK5rT9gTZ8m3yjknv"; +const POSTHOG_HOST = "https://eu.i.posthog.com"; // --------------------------------------------------------------------------- // State diff --git a/tests/helpers/auth.test.ts b/tests/helpers/auth.test.ts index 72b9467e..bf35c3a7 100644 --- a/tests/helpers/auth.test.ts +++ b/tests/helpers/auth.test.ts @@ -11,15 +11,19 @@ function mockFetch(handler: () => Promise) { describe("auth", () => { let tempDir: string; let originalHome: string | undefined; + let originalUserProfile: string | undefined; beforeEach(() => { tempDir = mkdtempSync(join(tmpdir(), "archgate-auth-test-")); - originalHome = process.env.HOME; - process.env.HOME = tempDir; + originalHome = Bun.env.HOME; + originalUserProfile = Bun.env.USERPROFILE; + Bun.env.HOME = tempDir; + Bun.env.USERPROFILE = tempDir; }); afterEach(() => { - process.env.HOME = originalHome; + Bun.env.HOME = originalHome; + Bun.env.USERPROFILE = originalUserProfile; rmSync(tempDir, { recursive: true, force: true }); });