Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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);
Expand All @@ -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()]);
}

/**
Expand All @@ -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);
});
4 changes: 2 additions & 2 deletions src/helpers/telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 7 additions & 3 deletions tests/helpers/auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,19 @@ function mockFetch(handler: () => Promise<Response>) {
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 });
});

Expand Down
Loading