Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history

build-info.ts

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

build-info.tsBlame85 lines · 1 contributor
05cdb85Claude1/**
2 * Build info — captured once at boot, exposed everywhere.
3 *
4 * Reads git HEAD + boot time on first access so the running process can
5 * tell anyone (the /api/version endpoint, the footer SHA stamp, the
6 * client-side update poller) exactly which commit it's serving.
7 *
8 * Falls back gracefully when the .git directory isn't available
9 * (e.g. running from a Docker image that didn't include it).
10 */
11
12import { spawnSync } from "child_process";
13import { existsSync } from "fs";
14import { join } from "path";
15
16export interface BuildInfo {
17 sha: string; // 7-char short sha
18 shaFull: string; // 40-char full sha
19 branch: string;
20 builtAt: string; // ISO of process boot
21 uptimeMs: number; // computed at access time
22}
23
24const STARTED_AT = Date.now();
25
26let _cached: Omit<BuildInfo, "uptimeMs"> | null = null;
27
28function read(): Omit<BuildInfo, "uptimeMs"> {
29 if (_cached) return _cached;
30
31 // Honour explicit env overrides first (set by the deploy script in
32 // immutable container images that strip the .git directory).
33 const envSha = process.env.GIT_SHA?.trim();
34 const envBranch = process.env.GIT_BRANCH?.trim();
35 if (envSha) {
36 _cached = {
37 sha: envSha.slice(0, 7),
38 shaFull: envSha,
39 branch: envBranch || "main",
40 builtAt: new Date(STARTED_AT).toISOString(),
41 };
42 return _cached;
43 }
44
45 // Otherwise read from local .git
46 const cwd = process.cwd();
47 const hasGit = existsSync(join(cwd, ".git"));
48 if (!hasGit) {
49 _cached = {
50 sha: "unknown",
51 shaFull: "unknown",
52 branch: "unknown",
53 builtAt: new Date(STARTED_AT).toISOString(),
54 };
55 return _cached;
56 }
57
58 try {
59 const sha = spawnSync("git", ["rev-parse", "HEAD"], { cwd, encoding: "utf8" });
60 const branch = spawnSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd, encoding: "utf8" });
61 const shaFull = (sha.stdout || "").trim();
62 _cached = {
63 sha: shaFull.slice(0, 7) || "unknown",
64 shaFull: shaFull || "unknown",
65 branch: (branch.stdout || "").trim() || "main",
66 builtAt: new Date(STARTED_AT).toISOString(),
67 };
68 } catch {
69 _cached = {
70 sha: "unknown",
71 shaFull: "unknown",
72 branch: "unknown",
73 builtAt: new Date(STARTED_AT).toISOString(),
74 };
75 }
76 return _cached;
77}
78
79export function getBuildInfo(): BuildInfo {
80 const base = read();
81 return {
82 ...base,
83 uptimeMs: Date.now() - STARTED_AT,
84 };
85}