Skip to content

fix(website): bake meta at build time, stop regressing to V0.0.0#180

Merged
rohitg00 merged 1 commit intomainfrom
fix/website-meta-build-time-gen
Apr 21, 2026
Merged

fix(website): bake meta at build time, stop regressing to V0.0.0#180
rohitg00 merged 1 commit intomainfrom
fix/website-meta-build-time-gen

Conversation

@rohitg00
Copy link
Copy Markdown
Owner

@rohitg00 rohitg00 commented Apr 21, 2026

Summary

Landing page hero kept reverting to V0.0.0 after releases. Reproduced on v0.9.1 deploy (attached screenshot confirms).

Root cause

`website/lib/meta.ts` resolved the repo at runtime via `import.meta.url`:

```ts
const here = dirname(fileURLToPath(import.meta.url));
const repoRoot = join(here, "..", "..");
// ...
const pkg = safeReadJson(join(repoRoot, "package.json"));
return { version: pkg?.version ?? "0.0.0", ... };
```

Locally `here` = `website/lib`, so `../..` correctly lands at the repo root. But Next.js 16 / Turbopack compiles server components and moves them into `.next/server/app/page/...`. At runtime `import.meta.url` resolves there, not in the source tree. `../..` stays inside `.next/server/`, `readFileSync(join(repoRoot, "package.json"))` throws, `safeReadJson` swallows it, and the `?? "0.0.0"` fallback renders. Earlier deploys happened to work because of how prior Turbopack versions laid out the bundles — not because the logic was correct.

Fix: bake meta at build time

  • `website/scripts/gen-meta.mjs` (new): runs from `website/scripts/`, walks one level up to find the real repo root, reads `package.json`, `src/mcp/tools-registry.ts`, `src/triggers/api.ts`, `src/types.ts`, and `test/`, writes `website/lib/generated-meta.json`. Throws loud if version is missing — no more silent "0.0.0" fallback.
  • `website/package.json`: `predev` + `prebuild` hooks run the generator before Next spins up.
  • `website/lib/meta.ts`: collapsed from 117 lines of runtime file walking to a static `import generated from "./generated-meta.json"`. Next.js bundles the values directly into server component output — zero runtime filesystem resolution, zero `../..` guessing.
  • `website/lib/generated-meta.json`: committed seed so the import target exists for editors; prebuild overwrites on every run.

Verified locally

```
$ npx next build
$ grep "ZERO EXTERNAL" .next/server/app/index.html
ZERO EXTERNAL DATABASES · v\",\"0.9.1\"]}]
```

Version baked into the static prerender. No fallback path left.

Test plan

  • `npm run build` for website passes
  • Rendered HTML contains v0.9.1, not v0.0.0
  • Post-merge: confirm Vercel deploy at https://www.agent-memory.dev/ renders v0.9.1 in hero badge

Summary by CodeRabbit

  • Chores
    • Optimized metadata generation by moving project metrics from runtime computation to build-time pre-generation. Metrics (version, tool counts) are automatically compiled before development and production builds for improved startup performance.

The landing page kept reverting to "V0.0.0" on every release. Root
cause: website/lib/meta.ts resolved repo files at runtime via
import.meta.url, and after Next.js compiles server components the URL
resolves inside .next/server/. `../..` from there lands in the build
cache, not at the repo root, so the package.json read fails silently
and `pkg?.version ?? "0.0.0"` kicks in.

- website/scripts/gen-meta.mjs: new build-time script. Runs from
  website/scripts/, walks one level up to find the real repo root,
  reads package.json + src/mcp/tools-registry.ts +
  src/triggers/api.ts + src/types.ts + test/ and writes
  website/lib/generated-meta.json. Fails loud if version is missing
  (no silent 0.0.0 ever again).
- website/package.json: `predev` and `prebuild` hooks run gen-meta.
- website/lib/meta.ts: collapsed from 117 lines of runtime file
  resolution to a static JSON import. Next.js bundles the values
  directly into the server component output.
- website/lib/generated-meta.json: seeded with current values so
  editors don't complain about the missing import target.

Verified locally: `.next/server/app/index.html` now contains
"ZERO EXTERNAL DATABASES · v0.9.1" instead of "v0.0.0".
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agentmemory Ready Ready Preview, Comment Apr 21, 2026 0:36am

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 21, 2026

📝 Walkthrough

Walkthrough

The pull request introduces a build-time metadata generation system. A new script computes project metrics (version, tool counts, endpoint counts, test counts) from repository files and writes them to a JSON file. The metadata module now imports this pre-computed JSON instead of performing runtime file I/O and parsing.

Changes

Cohort / File(s) Summary
Build-Time Metadata Generation
website/scripts/gen-meta.mjs
New executable script that reads repository files, computes metrics via regex and recursive scanning, and generates website/lib/generated-meta.json with version, tool/endpoint/hook/test counts and timestamp.
Metadata Module Refactoring
website/lib/meta.ts
Simplified to read pre-computed metrics from imported JSON file; removed runtime file I/O, directory traversal, regex helpers, and DEFAULT_META export. Function signature unchanged.
Generated Metadata Output
website/lib/generated-meta.json
New data file containing computed metadata: version 0.9.1, counts for 45 MCP tools, 112 REST endpoints, 12 hooks, 819 passing tests, and generation timestamp.
Build Configuration
website/package.json
Added gen-meta, predev, and prebuild npm scripts to run metadata generation automatically before development and production builds.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A script hops before dawn breaks,
Counting tools and test-case stakes,
Metadata fresh, no runtime tasks—
Build-time magic fills the JSON casks!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: shifting metadata generation from runtime to build time to fix the version regression to V0.0.0.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/website-meta-build-time-gen

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
website/scripts/gen-meta.mjs (1)

110-116: Remove the volatile timestamp from the committed generated file.

generatedAt is not consumed by ProjectMeta, and it makes predev/prebuild dirty website/lib/generated-meta.json on every run even when the metadata is unchanged.

Keep the generated artifact deterministic
 const meta = {
   version,
   mcpTools: mcpTools || 45,
   hooks: hooks || 12,
   restEndpoints: restEndpoints || 107,
   testsPassing: testsPassing || 794,
-  generatedAt: new Date().toISOString(),
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/scripts/gen-meta.mjs` around lines 110 - 116, The commit currently
injects a volatile generatedAt timestamp into the meta object which makes the
output non-deterministic; remove the generatedAt property before writing the
file so the JSON output is deterministic. Concretely, stop setting
meta.generatedAt (or delete meta.generatedAt) prior to the writeFileSync call
that serializes meta (look for the meta object and the writeFileSync/outPath
usage in gen-meta.mjs) so generated-meta.json no longer changes on every run.
website/package.json (1)

6-10: Consider inlining gen-meta into the build script for explicitness.

Currently, gen-meta relies on npm's prebuild lifecycle hook. While Vercel's default build command for Next.js projects with a build script is npm run build (which does respect lifecycle hooks), inlining the generator into the build command makes the dependency explicit and eliminates reliance on npm lifecycle behavior:

Explicit build approach
   "scripts": {
     "gen-meta": "node scripts/gen-meta.mjs",
-    "predev": "node scripts/gen-meta.mjs",
-    "prebuild": "node scripts/gen-meta.mjs",
-    "dev": "next dev",
-    "build": "next build",
+    "dev": "npm run gen-meta && next dev",
+    "build": "npm run gen-meta && next build",
     "start": "next start",
     "lint": "next lint"
   },

This ensures generated-meta.json is regenerated in all build scenarios, including direct next build invocations and any future deployment changes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/package.json` around lines 6 - 10, The build currently relies on the
npm prebuild lifecycle to run the generator script (scripts/gen-meta.mjs via the
gen-meta/prebuild scripts); instead, make the generation explicit by invoking
the generator directly from the "build" script so generated-meta.json is always
produced regardless of lifecycle behavior. Edit package.json scripts to have the
"build" script run the generator (node scripts/gen-meta.mjs) before running next
build (i.e., run the generator && next build), and remove or keep the redundant
"prebuild" entry as desired so "gen-meta" is no longer a hidden lifecycle
dependency.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@website/scripts/gen-meta.mjs`:
- Around line 104-109: The meta object currently uses numeric fallbacks for
mcpTools/hooks/restEndpoints/testsPassing which can silently hide upstream
parse/path failures; instead, in the code that constructs meta (the meta
constant and the variables mcpTools, hooks, restEndpoints, testsPassing),
validate that each metric resolved to a non-zero value and throw a descriptive
error (or exit non-zero) if any are null/undefined/0 so generation fails loudly
(similar to how version is handled), rather than using hardcoded defaults like
45/12/107/794.

---

Nitpick comments:
In `@website/package.json`:
- Around line 6-10: The build currently relies on the npm prebuild lifecycle to
run the generator script (scripts/gen-meta.mjs via the gen-meta/prebuild
scripts); instead, make the generation explicit by invoking the generator
directly from the "build" script so generated-meta.json is always produced
regardless of lifecycle behavior. Edit package.json scripts to have the "build"
script run the generator (node scripts/gen-meta.mjs) before running next build
(i.e., run the generator && next build), and remove or keep the redundant
"prebuild" entry as desired so "gen-meta" is no longer a hidden lifecycle
dependency.

In `@website/scripts/gen-meta.mjs`:
- Around line 110-116: The commit currently injects a volatile generatedAt
timestamp into the meta object which makes the output non-deterministic; remove
the generatedAt property before writing the file so the JSON output is
deterministic. Concretely, stop setting meta.generatedAt (or delete
meta.generatedAt) prior to the writeFileSync call that serializes meta (look for
the meta object and the writeFileSync/outPath usage in gen-meta.mjs) so
generated-meta.json no longer changes on every run.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8716bce4-97a5-4779-aa7e-55868edc23fd

📥 Commits

Reviewing files that changed from the base of the PR and between bb60b7a and c36aedf.

📒 Files selected for processing (4)
  • website/lib/generated-meta.json
  • website/lib/meta.ts
  • website/package.json
  • website/scripts/gen-meta.mjs

Comment on lines +104 to +109
const meta = {
version,
mcpTools: mcpTools || 45,
hooks: hooks || 12,
restEndpoints: restEndpoints || 107,
testsPassing: testsPassing || 794,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Avoid silently falling back to stale metric counts.

These fallbacks can mask parser/path failures and bake incorrect marketing stats; line 108 is already stale versus the generated value of 112. Prefer failing loudly when expected counters resolve to 0, matching the version handling above.

Fail fast instead of baking fallback counts
+function requireNonZeroCount(label, value, sourcePath) {
+  if (value === 0) {
+    throw new Error(
+      `gen-meta: ${label} count resolved to 0 from ${sourcePath}. ` +
+        `Update the parser or source path before building the website.`,
+    );
+  }
+  return value;
+}
+
+const apiPath = join(repoRoot, "src", "triggers", "api.ts");
+const toolsPath = join(repoRoot, "src", "mcp", "tools-registry.ts");
+const typesPath = join(repoRoot, "src", "types.ts");
+const testPath = join(repoRoot, "test");
+
-const restEndpoints = safeCountMatches(
-  join(repoRoot, "src", "triggers", "api.ts"),
-  /config:\s*\{\s*api_path:\s*"/g,
-);
-const mcpTools = safeCountMatches(
-  join(repoRoot, "src", "mcp", "tools-registry.ts"),
-  /name:\s*"memory_/g,
-);
-const hooks = countHookTypes(join(repoRoot, "src", "types.ts"));
-const testsPassing = countTestCases(join(repoRoot, "test"));
+const restEndpoints = requireNonZeroCount(
+  "REST endpoint",
+  safeCountMatches(apiPath, /config:\s*\{\s*api_path:\s*"/g),
+  apiPath,
+);
+const mcpTools = requireNonZeroCount(
+  "MCP tool",
+  safeCountMatches(toolsPath, /name:\s*"memory_/g),
+  toolsPath,
+);
+const hooks = requireNonZeroCount("hook", countHookTypes(typesPath), typesPath);
+const testsPassing = requireNonZeroCount("test", countTestCases(testPath), testPath);
+
 const meta = {
   version,
-  mcpTools: mcpTools || 45,
-  hooks: hooks || 12,
-  restEndpoints: restEndpoints || 107,
-  testsPassing: testsPassing || 794,
+  mcpTools,
+  hooks,
+  restEndpoints,
+  testsPassing,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/scripts/gen-meta.mjs` around lines 104 - 109, The meta object
currently uses numeric fallbacks for mcpTools/hooks/restEndpoints/testsPassing
which can silently hide upstream parse/path failures; instead, in the code that
constructs meta (the meta constant and the variables mcpTools, hooks,
restEndpoints, testsPassing), validate that each metric resolved to a non-zero
value and throw a descriptive error (or exit non-zero) if any are
null/undefined/0 so generation fails loudly (similar to how version is handled),
rather than using hardcoded defaults like 45/12/107/794.

@rohitg00 rohitg00 merged commit 4036640 into main Apr 21, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant