From c39d7beb052e3f582fd3bd7c60f19a5f6d2eaf73 Mon Sep 17 00:00:00 2001 From: Rhuan Barreto Date: Sun, 22 Mar 2026 23:08:02 +0100 Subject: [PATCH 1/3] feat: wire PostHog telemetry into CLI lifecycle Connect the existing telemetry module to the CLI entry point so analytics events are actually captured. Sets the real PostHog API key, initializes telemetry at startup, tracks command invocations and completions (with duration), and flushes events before exit. --- src/cli.ts | 26 +++++++++++++++++++++----- src/helpers/telemetry.ts | 2 +- 2 files changed, 22 insertions(+), 6 deletions(-) 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..f0a77176 100644 --- a/src/helpers/telemetry.ts +++ b/src/helpers/telemetry.ts @@ -27,7 +27,7 @@ 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_API_KEY = "phc_gSnjpsvRfQggmgeXUgbevbG0SULK5rT9gTZ8m3yjknv"; const POSTHOG_HOST = "https://us.i.posthog.com"; // --------------------------------------------------------------------------- From fa2a11ecb9b7535de5727e57b0ebee6882031328 Mon Sep 17 00:00:00 2001 From: Rhuan Barreto Date: Sun, 22 Mar 2026 23:12:27 +0100 Subject: [PATCH 2/3] fix: use EU PostHog host instead of US --- src/helpers/telemetry.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/telemetry.ts b/src/helpers/telemetry.ts index f0a77176..fdf63835 100644 --- a/src/helpers/telemetry.ts +++ b/src/helpers/telemetry.ts @@ -28,7 +28,7 @@ import { getInstallId, isTelemetryEnabled } from "./telemetry-config"; * This key can only ingest events — it cannot read data or manage the project. */ const POSTHOG_API_KEY = "phc_gSnjpsvRfQggmgeXUgbevbG0SULK5rT9gTZ8m3yjknv"; -const POSTHOG_HOST = "https://us.i.posthog.com"; +const POSTHOG_HOST = "https://eu.i.posthog.com"; // --------------------------------------------------------------------------- // State From e3c075f5cb64c7185a0c910f5b61b8db2a2a52ef Mon Sep 17 00:00:00 2001 From: Rhuan Barreto Date: Sun, 22 Mar 2026 23:48:17 +0100 Subject: [PATCH 3/3] fix: use Bun.env.HOME in auth tests for Windows compatibility The auth tests were setting process.env.HOME which doesn't affect Bun.env on Windows. Since internalPath() reads Bun.env.HOME, the tests were hitting the real ~/.archgate/ directory on Windows CI, causing credential store hangs and wrong file reads. --- tests/helpers/auth.test.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) 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 }); });