Skip to content

feat(website): derive version + counts from source at build#167

Merged
rohitg00 merged 2 commits intomainfrom
feat/website-auto-version
Apr 18, 2026
Merged

feat(website): derive version + counts from source at build#167
rohitg00 merged 2 commits intomainfrom
feat/website-auto-version

Conversation

@rohitg00
Copy link
Copy Markdown
Owner

@rohitg00 rohitg00 commented Apr 18, 2026

Fixes the hardcoded-drift issue. The hero chip still said `v0.8.13` after v0.9.0 shipped, and the MCP/hook/REST counts were literal strings sprinkled across four components.

What

  • `lib/meta.ts` (server-only) reads version + counts from the real source of truth at build:
    • `package.json` → version
    • `src/triggers/api.ts` → REST endpoint count (`api_path:` grep)
    • `src/mcp/tools-registry.ts` → MCP tool count (`name: "memory_"` grep)
    • `src/types.ts` `HookType` union → hook count
  • Hero chip, Stats, LiveTerminal, Features all consume counts through props.

Result

Cutting the next release bumps the hero to v automatically. Any new MCP tool or REST endpoint raises the displayed count without a component edit.

Build: `next build` clean, single static page prerendered.

Summary by CodeRabbit

  • New Features
    • Hero version now updates dynamically from project metadata
    • Statistics (MCP Tools, Auto-Hooks, REST Endpoints, Tests Passing) show live project counts and replay count animations when values change
    • Live Terminal output adapts to current project metrics
    • Features list phrasing updated to say “the rest” for AUTO-HOOKS instead of “ten more”

…uild

Website chip + stats + terminal + features were hardcoded to 0.8.13,
44, 12, 49 — they drifted every release. Now every one of them is
read at build time from the real source of truth:

- lib/meta.ts (server-only) reads package.json, src/triggers/api.ts
  (api_path count), src/mcp/tools-registry.ts (memory_* name count),
  and the HookType union in src/types.ts.
- Hero chip, Stats, LiveTerminal, and Features all consume the
  computed counts via props; no more literal strings in component
  bodies.
- Fallback defaults (44 / 12 / 49) kick in only if the source files
  cannot be read, so a monorepo re-root still boots.

Result: cutting a release bumps the website hero to v<new>
automatically, and any new MCP tool or REST endpoint raises the
displayed count without an edit.

next build stays clean — single static page prerendered.
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 18, 2026

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

Project Deployment Actions Updated (UTC)
agentmemory Ready Ready Preview, Comment Apr 18, 2026 7:53pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 18, 2026

📝 Walkthrough

Walkthrough

Page now calls a new server-side getProjectMeta() to compute project metadata (version, mcpTools, hooks, restEndpoints, testsPassing) and passes those numeric values into UI components (Stats, Features, LiveTerminal, Hero) to replace prior hardcoded values. (48 words)

Changes

Cohort / File(s) Summary
New Metadata Module
website/lib/meta.ts
Adds ProjectMeta interface, DEFAULT_META, and getProjectMeta() which safely reads repository files (package.json, triggers, tools registry, types, tests) and returns version, mcpTools, hooks, restEndpoints, testsPassing.
Page Entry Point
website/app/page.tsx
Calls getProjectMeta() on render and threads returned fields into child components as props.
Stats & LiveTerminal
website/components/Stats.tsx, website/components/LiveTerminal.tsx
Convert from no-prop to prop-driven components (mcpTools, hooks, testsPassing / mcpTools, hooks), move module-level constants into component scope, update hooks' dependency arrays, and reset animation state so counts replay when values change.
Features & Hero
website/components/Features.tsx, website/components/Hero.tsx
Features now accepts hooks, mcpTools, restEndpoints and computes its FEATURES array from props (first three k values injected). Hero reads meta to display dynamic v{meta.version}.

Sequence Diagram

sequenceDiagram
    participant Page as Page.tsx
    participant Meta as getProjectMeta()
    participant FS as Filesystem
    participant Stats as Stats
    participant Features as Features
    participant LiveTerminal as LiveTerminal
    participant Hero as Hero

    Page->>Meta: invoke getProjectMeta()
    Meta->>FS: read package.json, src/triggers/api.ts, src/mcp/tools-registry.ts, src/types.ts, test/
    FS-->>Meta: return file contents / counts
    Meta-->>Page: {version, mcpTools, hooks, restEndpoints, testsPassing}

    Page->>Stats: pass mcpTools, hooks, testsPassing
    Page->>Features: pass hooks, mcpTools, restEndpoints
    Page->>LiveTerminal: pass mcpTools, hooks
    Page->>Hero: pass version

    Stats->>Stats: build STATS with props
    Features->>Features: compute FEATURES from props
    LiveTerminal->>LiveTerminal: generate script with injected values
    Hero->>Hero: render v{version}
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I dug through files both near and far,
Pulled versions, hooks, and tools like a star,
Threaded them through every view,
Counts that update, shiny and new,
Hop, meta, hop — the site sings czar! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: deriving version and counts from source at build time instead of using hardcoded values.

✏️ 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 feat/website-auto-version

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: 2

🧹 Nitpick comments (4)
website/components/Stats.tsx (1)

33-79: Effect re-runs on prop change, but animation won't replay.

Dependency array now includes mcpTools/hooks/testsPassing, so on prop change the effect tears down the observer and builds a new one — but the target elements still carry data-done="1" from the first pass, so the new observer will unobserve without counting. In practice these props are build-time constants so this never triggers, but if the component is ever reused with mutable props the animation will silently stop working. Either reset data-done at the start of the effect, or keep the old [] deps and read the latest values from refs.

♻️ Optional hardening
   useEffect(() => {
     if (!rootRef.current) return;
+    rootRef.current
+      .querySelectorAll<HTMLDivElement>("[data-num]")
+      .forEach((n) => { delete n.dataset.done; });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/components/Stats.tsx` around lines 33 - 79, The effect attaching the
IntersectionObserver (inside useEffect) re-runs when mcpTools/hooks/testsPassing
change but doesn’t reset per-element state so elements keep data-done="1" and
the animation never replays; fix by clearing that flag at the start of the
effect (iterate rootRef.current.querySelectorAll("[data-num]") and delete/clear
dataset.done) or alternatively revert the dependency array to [] and read latest
values via refs; update the code paths referencing rootRef, the count function,
and the IntersectionObserver setup to ensure data-done is reset before
observing.
website/components/Features.tsx (1)

9-13: Default magic numbers duplicated across components.

12 / 44 / 49 are repeated here, in Stats, LiveTerminal, and inside getProjectMeta. If the fallback ever needs to change, four files must stay in sync. Consider exporting a DEFAULT_META constant from @/lib/meta and reusing it (either as the literal default, or by making props non-optional and always threading meta).

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

In `@website/components/Features.tsx` around lines 9 - 13, Default numeric
defaults (12, 44, 49) are duplicated across components; export a single
DEFAULT_META constant from "@/lib/meta" (e.g., DEFAULT_META = { hooks: 12,
mcpTools: 44, restEndpoints: 49 }) and update Features (the Features function
signature and its Props), Stats, LiveTerminal and getProjectMeta to use that
constant (either by using DEFAULT_META as the inline default for the props or by
making props required and supplying DEFAULT_META where components are
instantiated) so all fallback values come from one source of truth.
website/lib/meta.ts (2)

47-51: Redundant double fallback.

mcpTools already falls back to 44 on line 51, so mcpTools || 44 on line 62 is dead code. Same shape for hooks/restEndpoints — fallback is applied inconsistently (once at computation, again in the return). Pick one location so the defaults live in exactly one place.

♻️ Proposed cleanup
-  return {
-    version: pkg?.version ?? "0.0.0",
-    mcpTools: mcpTools || 44,
-    hooks: hooks || 12,
-    restEndpoints: restEndpoints || 49,
-    testsPassing: 777,
-  };
+  return {
+    version: pkg?.version ?? "0.0.0",
+    mcpTools,
+    hooks,
+    restEndpoints: restEndpoints || 49,
+    testsPassing: 777,
+  };

Also applies to: 60-64

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

In `@website/lib/meta.ts` around lines 47 - 51, The computed counts (mcpTools,
hooks, restEndpoints) currently apply the default value twice (once inside the
safeCountMatches expression and again at the return), creating dead code; choose
a single place for defaults and make them consistent — either remove the
trailing "|| 44" / "|| 30" at the return site or remove the defaults inside the
safeCountMatches assignments so each variable (mcpTools, hooks, restEndpoints)
has its fallback applied exactly once; update the code paths that reference
mcpTools, hooks, and restEndpoints to rely on that single fallback location
(functions: safeCountMatches, and the variables mcpTools, hooks, restEndpoints)
so there are no redundant fallbacks.

53-58: Hook counting via quote-division is fragile.

(matches / 2) only works because every union member is a double-quoted string and nothing else in the captured span uses ". A future doc-comment like // e.g. "session_start" inside the union, or a HookType alias written with backticks, silently halves or doubles the count. Prefer matching the union variants directly:

♻️ Proposed fix
-  const hookUnionFile = readFileSafe(join(repoRoot, "src", "types.ts"));
-  const hookUnion = hookUnionFile.match(
-    /export type HookType[\s\S]*?;(?=\s*\n)/,
-  );
-  const hooks = hookUnion ? (hookUnion[0].match(/"/g)?.length ?? 0) / 2 : 12;
+  const hookUnionFile = readFileSafe(join(repoRoot, "src", "types.ts"));
+  const hookUnionMatch = hookUnionFile.match(
+    /export type HookType\s*=\s*([\s\S]*?);/,
+  );
+  const hooks =
+    hookUnionMatch?.[1].match(/"[a-z_]+"/g)?.length ?? 12;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/lib/meta.ts` around lines 53 - 58, The current hook-counting logic
(using hookUnion and hooks derived from readFileSafe(... "src/types.ts")) is
fragile because it counts quotes rather than actual union members; update the
extraction to first capture the HookType union body (hookUnion), then find and
count actual string-literal variants inside that body (e.g., match
double-quoted, single-quoted, or backtick-quoted literals) instead of dividing
quote occurrences by 2—alternatively split the union body on '|' and trim/filter
empty entries to compute the correct count; change the logic around hookUnion
and hooks accordingly so it robustly counts members regardless of inline
comments or other quotes.
🤖 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/lib/meta.ts`:
- Line 65: The hardcoded testsPassing: 777 in the ProjectMeta object will rot;
replace it with a real source or remove it: either compute testsPassing
dynamically (e.g., add a function that parses CI JUnit/JSON reports or walks the
test/ directory and counts occurrences of "it(" / "test(" and assign that value
to the testsPassing property used by ProjectMeta) or remove the testsPassing
property from ProjectMeta and update the Stats tile and any consumers to stop
reading it. Locate the testsPassing symbol in meta.ts and update ProjectMeta
consumers (the Stats tile and any imports) to use the new dynamic getter or to
handle the absence of the stat.
- Around line 40-44: The REST endpoint counter (restEndpoints) currently uses a
too-broad regex (/api_path:/g) and a mistaken fallback (|| 49); replace that
expression to call safeCountMatches with the tighter regex
/config:\s*\{\s*api_path:\s*"/g (use repoRoot and the same target file as
before) and remove the hardcoded "|| 49" fallback so the code reports the
tighter count directly; also update any README references ("104-endpoints" /
"107 endpoints on port 3111") after you verify the corrected count so
documentation matches the new measurement.

---

Nitpick comments:
In `@website/components/Features.tsx`:
- Around line 9-13: Default numeric defaults (12, 44, 49) are duplicated across
components; export a single DEFAULT_META constant from "@/lib/meta" (e.g.,
DEFAULT_META = { hooks: 12, mcpTools: 44, restEndpoints: 49 }) and update
Features (the Features function signature and its Props), Stats, LiveTerminal
and getProjectMeta to use that constant (either by using DEFAULT_META as the
inline default for the props or by making props required and supplying
DEFAULT_META where components are instantiated) so all fallback values come from
one source of truth.

In `@website/components/Stats.tsx`:
- Around line 33-79: The effect attaching the IntersectionObserver (inside
useEffect) re-runs when mcpTools/hooks/testsPassing change but doesn’t reset
per-element state so elements keep data-done="1" and the animation never
replays; fix by clearing that flag at the start of the effect (iterate
rootRef.current.querySelectorAll("[data-num]") and delete/clear dataset.done) or
alternatively revert the dependency array to [] and read latest values via refs;
update the code paths referencing rootRef, the count function, and the
IntersectionObserver setup to ensure data-done is reset before observing.

In `@website/lib/meta.ts`:
- Around line 47-51: The computed counts (mcpTools, hooks, restEndpoints)
currently apply the default value twice (once inside the safeCountMatches
expression and again at the return), creating dead code; choose a single place
for defaults and make them consistent — either remove the trailing "|| 44" / "||
30" at the return site or remove the defaults inside the safeCountMatches
assignments so each variable (mcpTools, hooks, restEndpoints) has its fallback
applied exactly once; update the code paths that reference mcpTools, hooks, and
restEndpoints to rely on that single fallback location (functions:
safeCountMatches, and the variables mcpTools, hooks, restEndpoints) so there are
no redundant fallbacks.
- Around line 53-58: The current hook-counting logic (using hookUnion and hooks
derived from readFileSafe(... "src/types.ts")) is fragile because it counts
quotes rather than actual union members; update the extraction to first capture
the HookType union body (hookUnion), then find and count actual string-literal
variants inside that body (e.g., match double-quoted, single-quoted, or
backtick-quoted literals) instead of dividing quote occurrences by
2—alternatively split the union body on '|' and trim/filter empty entries to
compute the correct count; change the logic around hookUnion and hooks
accordingly so it robustly counts members regardless of inline comments or other
quotes.
🪄 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: afa0df0f-7a63-4854-9aaf-dc20a7610bad

📥 Commits

Reviewing files that changed from the base of the PR and between ba39a18 and b99c9ec.

📒 Files selected for processing (6)
  • website/app/page.tsx
  • website/components/Features.tsx
  • website/components/Hero.tsx
  • website/components/LiveTerminal.tsx
  • website/components/Stats.tsx
  • website/lib/meta.ts

Comment thread website/lib/meta.ts Outdated
Comment thread website/lib/meta.ts Outdated
- testsPassing no longer hardcoded to 777. New countTestCases() walks
  the test/ tree and counts it()/test() call sites at build. Prerender
  now shows the live count (currently 795) instead of a stale literal.
- restEndpoints regex tightened from /api_path:/ to
  /config:\s*\{\s*api_path:\s*"/. Comments, example strings, and
  docstrings no longer inflate the count.
- Fallback defaults consolidated into one exported DEFAULT_META
  constant. Each count applies its fallback in exactly one place (at
  the return, if the safeCountMatches result is 0). No more double
  defaults.
- Hook counting no longer divides quote characters by 2. It parses
  the HookType union body, splits on '|', and filters to string-
  literal members — robust to inline comments or quotes elsewhere in
  the union.
- Stats, Features, and LiveTerminal props are now required and take
  their fallbacks from DEFAULT_META via getProjectMeta(). No
  per-component duplication.
- Stats effect resets data-done on every rerun so a meta change at
  build replays the count animation against the new target instead
  of stranding a stale value.
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: 2

🧹 Nitpick comments (2)
website/components/Features.tsx (1)

99-108: Header "TWELVE THINGS" is still hardcoded while tile counts are dynamic.

The section title TWELVE THINGS YOU DID NOT WANT TO BUILD. is a static string, but the FEATURES array below is fixed at 12 entries and independent of the derived props — so no immediate bug. Worth a comment or a derived count (FEATURES.length → number-to-word) if you expect the list to grow; otherwise the title will silently drift.

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

In `@website/components/Features.tsx` around lines 99 - 108, The heading "TWELVE
THINGS YOU DID NOT WANT TO BUILD." is hardcoded; derive the count from the
FEATURES array instead to prevent drift: replace the static string in the
element with a dynamically composed title using FEATURES.length (or a small
helper like numberToWords(count)) so the heading reads "<NUMBER-IN-WORDS> THINGS
YOU DID NOT WANT TO BUILD." Reference the FEATURES constant and the h2 with id
"feat-title" to locate the change, and add/implement a lightweight
number-to-words helper (e.g., for 0–20 and tens) if none exists to render the
numeric count as words.
website/lib/meta.ts (1)

14-19: DEFAULT_META fallback values will silently mask counting regressions.

If any counter returns 0 (e.g., a regex breaks after a refactor of api.ts or tools-registry.ts), x || DEFAULT_META.x at Line 112-115 substitutes stale hardcoded numbers (44 tools, 49 endpoints, 777 tests) and you'll ship misleading figures without any build-time signal. Consider logging a console.warn in getProjectMeta() when a counter yields 0 so CI logs surface the regression, or failing the build in that case since the whole point of this module is to avoid stale constants.

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

In `@website/lib/meta.ts` around lines 14 - 19, DEFAULT_META contains hardcoded
fallback counters and current usage in getProjectMeta (where values are selected
via expressions like restEndpoints || DEFAULT_META.restEndpoints) will silently
mask regressions when a real counter is 0; update getProjectMeta to detect any
counter that equals 0 (for keys mcpTools, hooks, restEndpoints, testsPassing)
and either emit a clear console.warn with the counter name and computed value OR
throw an Error to fail CI depending on build policy, ensuring you reference
DEFAULT_META and the getProjectMeta function when making the change so the
fallback logic is replaced by explicit zero detection rather than blind "||"
fallbacks.
🤖 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/lib/meta.ts`:
- Around line 21-22: The repoRoot computed from import.meta.url (here, repoRoot
in website/lib/meta.ts) can be incorrect after Next.js server bundling; update
getProjectMeta to derive repository root from a stable anchor instead—use
process.cwd() (i.e., join(process.cwd(), "..") or similar) or implement a small
upward walk from process.cwd() to locate package.json with the expected name,
and fallback to DEFAULT_META only if that search fails; replace uses of
here/import.meta.url for repoRoot with this deterministic resolution so file
reads in getProjectMeta and related logic reliably locate project files.
- Around line 62-83: countTestCases currently treats skipped/todo and
commented-out tests as passing because the regex m =
txt.match(/(?:^|\s)(?:it|test)(?:\.\w+)?\s*\(/g) will match variants like
it.skip/test.todo and matches lines with leading comment whitespace; update
countTestCases to first strip line comments (remove //... and optionally block
comments) from the file text before matching, and tighten the regex to exclude
.skip and .todo variants (e.g., require (?:\.(?!skip|todo)\w+)? or only match
plain it/test or allowed modifiers), and then update the displayed label in
Stats.tsx (change "TESTS PASSING" to "TEST CASES" if you prefer counting all
test cases) so the UI reflects the corrected metric.

---

Nitpick comments:
In `@website/components/Features.tsx`:
- Around line 99-108: The heading "TWELVE THINGS YOU DID NOT WANT TO BUILD." is
hardcoded; derive the count from the FEATURES array instead to prevent drift:
replace the static string in the element with a dynamically composed title using
FEATURES.length (or a small helper like numberToWords(count)) so the heading
reads "<NUMBER-IN-WORDS> THINGS YOU DID NOT WANT TO BUILD." Reference the
FEATURES constant and the h2 with id "feat-title" to locate the change, and
add/implement a lightweight number-to-words helper (e.g., for 0–20 and tens) if
none exists to render the numeric count as words.

In `@website/lib/meta.ts`:
- Around line 14-19: DEFAULT_META contains hardcoded fallback counters and
current usage in getProjectMeta (where values are selected via expressions like
restEndpoints || DEFAULT_META.restEndpoints) will silently mask regressions when
a real counter is 0; update getProjectMeta to detect any counter that equals 0
(for keys mcpTools, hooks, restEndpoints, testsPassing) and either emit a clear
console.warn with the counter name and computed value OR throw an Error to fail
CI depending on build policy, ensuring you reference DEFAULT_META and the
getProjectMeta function when making the change so the fallback logic is replaced
by explicit zero detection rather than blind "||" fallbacks.
🪄 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: ae88f3dc-688b-4161-bbb5-9f52e7f14e1d

📥 Commits

Reviewing files that changed from the base of the PR and between b99c9ec and 9520a9f.

📒 Files selected for processing (4)
  • website/components/Features.tsx
  • website/components/LiveTerminal.tsx
  • website/components/Stats.tsx
  • website/lib/meta.ts

Comment thread website/lib/meta.ts
Comment on lines +21 to +22
const here = dirname(fileURLToPath(import.meta.url));
const repoRoot = join(here, "..", "..");
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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm meta.ts location and inspect any build output that might reveal where it lands after compilation
fd -t f 'meta.ts' website/lib
fd -t d '.next' website 2>/dev/null
rg -nP 'import\.meta\.url|process\.cwd' website/lib/meta.ts

Repository: rohitg00/agentmemory

Length of output: 140


🏁 Script executed:

cat -n website/lib/meta.ts

Repository: rohitg00/agentmemory

Length of output: 4168


🏁 Script executed:

rg -n 'getProjectMeta|from.*meta\.ts|import.*meta' website/ --type ts --type tsx

Repository: rohitg00/agentmemory

Length of output: 91


🏁 Script executed:

rg -n 'getProjectMeta|from.*meta\.ts|import.*meta' website/ -t ts

Repository: rohitg00/agentmemory

Length of output: 554


🏁 Script executed:

cat -n website/components/Hero.tsx

Repository: rohitg00/agentmemory

Length of output: 1465


🏁 Script executed:

cat -n website/app/page.tsx

Repository: rohitg00/agentmemory

Length of output: 1664


repoRoot derived from import.meta.url may break under Next.js bundling.

getProjectMeta() is invoked during static generation of page.tsx and Hero component (both server components in the app/ directory). When Next.js bundles server modules into .next/server/..., the relative path resolution from import.meta.url becomes incorrect—../.. from the bundled location will not point to the repository root. While the current implementation gracefully falls back to DEFAULT_META values when file reads fail (lines 112–115), this masks a latent fragility: the behavior depends on default values remaining accurate.

For more robust runtime path resolution, consider anchoring from process.cwd() (which in next build is the website/ directory, making join(cwd, "..") deterministic) or finding a stable marker file (e.g., walk up the directory tree until package.json with the expected name field is found).

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

In `@website/lib/meta.ts` around lines 21 - 22, The repoRoot computed from
import.meta.url (here, repoRoot in website/lib/meta.ts) can be incorrect after
Next.js server bundling; update getProjectMeta to derive repository root from a
stable anchor instead—use process.cwd() (i.e., join(process.cwd(), "..") or
similar) or implement a small upward walk from process.cwd() to locate
package.json with the expected name, and fallback to DEFAULT_META only if that
search fails; replace uses of here/import.meta.url for repoRoot with this
deterministic resolution so file reads in getProjectMeta and related logic
reliably locate project files.

Comment thread website/lib/meta.ts
Comment on lines +62 to +83
function countTestCases(testDir: string): number {
let total = 0;
let entries: import("node:fs").Dirent[];
try {
entries = readdirSync(testDir, { withFileTypes: true });
} catch {
return 0;
}
for (const entry of entries) {
const full = join(testDir, entry.name);
if (entry.isDirectory()) {
total += countTestCases(full);
continue;
}
if (!/\.test\.[jt]sx?$/.test(entry.name)) continue;
const txt = readFileSafe(full);
if (!txt) continue;
const m = txt.match(/(?:^|\s)(?:it|test)(?:\.\w+)?\s*\(/g);
if (m) total += m.length;
}
return total;
}
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

countTestCases counts skipped/todo tests as "passing".

/(?:^|\s)(?:it|test)(?:\.\w+)?\s*\(/g matches it.skip(, it.todo(, test.skip(, describe.skip-nested cases, and commented-out tests (// it(...) still has leading whitespace before it). The stat is labeled "TESTS PASSING" in Stats.tsx, so the number is misleading. Either exclude .skip/.todo variants and strip line comments before matching, or relabel the stat to "TEST CASES".

♻️ Suggested tightening
-    const m = txt.match(/(?:^|\s)(?:it|test)(?:\.\w+)?\s*\(/g);
-    if (m) total += m.length;
+    // Strip line comments so commented-out tests don't count.
+    const stripped = txt.replace(/\/\/[^\n]*/g, "");
+    // Match it(, test(, it.each(, test.each( — exclude .skip/.todo.
+    const m = stripped.match(
+      /(?:^|[\s;{])(?:it|test)(?:\.(?!skip\b|todo\b)\w+)?\s*\(/g,
+    );
+    if (m) total += m.length;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@website/lib/meta.ts` around lines 62 - 83, countTestCases currently treats
skipped/todo and commented-out tests as passing because the regex m =
txt.match(/(?:^|\s)(?:it|test)(?:\.\w+)?\s*\(/g) will match variants like
it.skip/test.todo and matches lines with leading comment whitespace; update
countTestCases to first strip line comments (remove //... and optionally block
comments) from the file text before matching, and tighten the regex to exclude
.skip and .todo variants (e.g., require (?:\.(?!skip|todo)\w+)? or only match
plain it/test or allowed modifiers), and then update the displayed label in
Stats.tsx (change "TESTS PASSING" to "TEST CASES" if you prefer counting all
test cases) so the UI reflects the corrected metric.

@rohitg00 rohitg00 merged commit c9aedbf into main Apr 18, 2026
5 checks passed
@rohitg00 rohitg00 deleted the feat/website-auto-version branch April 18, 2026 20:14
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