From c9daf3dd07bb103f98da536e4e9e563355ca1e0c Mon Sep 17 00:00:00 2001 From: Markeljan Date: Thu, 21 May 2026 12:14:05 -0400 Subject: [PATCH] feat(landing): fetch live npm version for UI chips instead of stamping The Header/Hero/Footer version chips were stamped into source by the bump script on every release. They now fetch from registry.npmjs.org/agentsec/latest via a new lib/version.ts helper using Next.js ISR (1h revalidate), with a fallback to packages/cli/package.json on failure. Page server components thread the resolved version to
/; Footer fetches directly. scripts/version-stamps.ts drops the three landing entries (7 stamps -> 4) and AGENTS.md is updated to reflect the new behavior. Co-Authored-By: Claude Opus 4.7 (1M context) --- AGENTS.md | 5 +++-- apps/landing/app/examples/page.tsx | 6 ++++-- apps/landing/app/page.tsx | 8 +++++--- apps/landing/app/skill-watch/page.tsx | 5 +++-- apps/landing/components/Footer.tsx | 6 ++++-- apps/landing/components/Header.tsx | 4 ++-- apps/landing/components/Hero.tsx | 4 ++-- apps/landing/lib/version.ts | 20 ++++++++++++++++++++ scripts/version-stamps.ts | 15 --------------- 9 files changed, 43 insertions(+), 30 deletions(-) create mode 100644 apps/landing/lib/version.ts diff --git a/AGENTS.md b/AGENTS.md index 98a3db0..c0305bc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -106,7 +106,7 @@ This is a **security-focused project**. Follow these rules strictly: ## Versioning -The agentsec version is stamped in **seven** files plus regenerated sample reports. **Never edit them by hand** — always use the bump script. The list lives in [scripts/version-stamps.ts](scripts/version-stamps.ts); the source of truth is `packages/cli/package.json`. +The agentsec version is stamped in **four** files plus regenerated sample reports. **Never edit them by hand** — always use the bump script. The list lives in [scripts/version-stamps.ts](scripts/version-stamps.ts); the source of truth is `packages/cli/package.json`. ```bash # Bump to a new version (also regenerates examples) @@ -125,9 +125,10 @@ What the bump script touches: - `packages/shared/src/constants.ts` — `AUDIT_VERSION` (used by `--version` and SARIF driver) - `skills/agentsec/SKILL.md` — GitHub-canonical SKILL.md - `apps/landing/public/skill.md` — landing site mirror (re-mirrored from SKILL.md every bump) -- `apps/landing/components/{Hero,Header,Footer}.tsx` — UI version chips - `examples/audit-report.{txt,json,html,sarif}` and the same files in `apps/landing/public/examples/` — regenerated by running the CLI against `e2e/fixtures` +The landing site's UI version chips (Hero, Header, Footer) are **not** stamped — they fetch the latest published version from `https://registry.npmjs.org/agentsec/latest` at request time via [apps/landing/lib/version.ts](apps/landing/lib/version.ts) (Next.js ISR, 1-hour revalidation). If the npm registry is unreachable they fall back to the version imported from `packages/cli/package.json`, so the chips still match the in-repo canonical version even offline. + If you add a new place where the version needs to appear, add an entry to `STAMPS` in `scripts/version-stamps.ts` and the bump + check scripts pick it up automatically. After bumping: review the diff, commit, then push `main` and the `vX.Y.Z` tag in **separate** pushes (GitHub Actions silently drops the tag-push event when bundled with a branch push, so don't `git push --tags` together with main). The release workflow runs three jobs: diff --git a/apps/landing/app/examples/page.tsx b/apps/landing/app/examples/page.tsx index 9c043f1..f6662b0 100644 --- a/apps/landing/app/examples/page.tsx +++ b/apps/landing/app/examples/page.tsx @@ -2,6 +2,7 @@ import type { Metadata } from "next"; import Link from "next/link"; import { Footer } from "@/components/Footer"; import { Header } from "@/components/Header"; +import { getAgentsecVersion } from "@/lib/version"; import { SITE_NAME } from "../_brand/constants"; export const metadata: Metadata = { @@ -190,7 +191,8 @@ const ICONS: Record = { ), }; -export default function ExamplesPage(): React.ReactNode { +export default async function ExamplesPage(): Promise { + const version = await getAgentsecVersion(); return ( <> Skip to main content -
+
diff --git a/apps/landing/app/page.tsx b/apps/landing/app/page.tsx index 03d44d6..59b7ec0 100644 --- a/apps/landing/app/page.tsx +++ b/apps/landing/app/page.tsx @@ -9,8 +9,10 @@ import { HowItWorks } from "@/components/HowItWorks"; import { Install } from "@/components/Install"; import { Policy } from "@/components/Policy"; import { TenCommandments } from "@/components/TenCommandments"; +import { getAgentsecVersion } from "@/lib/version"; -export default function Home(): React.ReactNode { +export default async function Home(): Promise { + const version = await getAgentsecVersion(); return ( <> Skip to main content -
+
- + diff --git a/apps/landing/app/skill-watch/page.tsx b/apps/landing/app/skill-watch/page.tsx index a00d519..755b083 100644 --- a/apps/landing/app/skill-watch/page.tsx +++ b/apps/landing/app/skill-watch/page.tsx @@ -2,6 +2,7 @@ import type { Metadata } from "next"; import Link from "next/link"; import { Footer } from "@/components/Footer"; import { Header } from "@/components/Header"; +import { getAgentsecVersion } from "@/lib/version"; import { SITE_NAME } from "../_brand/constants"; import { OwaspBars } from "./OwaspBars"; import { SkillWatchTable } from "./SkillWatchTable"; @@ -145,7 +146,7 @@ function slimEntity(e: SkillWatchEntity): SkillWatchEntity { } export default async function SkillWatchPage(): Promise { - const skills = await fetchSkillWatch(); + const [skills, version] = await Promise.all([fetchSkillWatch(), getAgentsecVersion()]); const agg = aggregate(skills); const slimSkills = skills.map(slimEntity); @@ -157,7 +158,7 @@ export default async function SkillWatchPage(): Promise { > Skip to main content -
+
{skills.length === 0 ? ( diff --git a/apps/landing/components/Footer.tsx b/apps/landing/components/Footer.tsx index d35660e..56754c5 100644 --- a/apps/landing/components/Footer.tsx +++ b/apps/landing/components/Footer.tsx @@ -1,3 +1,4 @@ +import { getAgentsecVersion } from "@/lib/version"; import { Logo } from "./Logo"; type FooterCol = { @@ -58,7 +59,8 @@ const COLS: readonly FooterCol[] = [ }, ]; -export function Footer(): React.ReactNode { +export async function Footer(): Promise { + const version = await getAgentsecVersion(); return (