From 59a719530fc61762ac535bdaed3fb1179bf44db0 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 1 Sep 2026 19:18:49 +0000 Subject: [PATCH] Add verify-kylecesmat pstack skill and prove homepage once Project-local Launch/Doctor/Drive/Evidence/Cleanup helpers for the static Astro preview. Feature map covers hiring brief, writing/talks, about/contact, now/archive, and build artifacts. Assertions use the locked qualitative hero and forbid quantitative metrics. Preview-only. Co-authored-by: Kyle Cesmat --- .../skills/verify-kylecesmat/.run/.gitkeep | 0 .cursor/skills/verify-kylecesmat/SKILL.md | 115 ++++++++++++++++++ .../verify-kylecesmat/evidence/.gitkeep | 0 .../verify-kylecesmat/features/README.md | 38 ++++++ .../features/about-and-contact.md | 34 ++++++ .../features/build-and-headers.md | 33 +++++ .../features/homepage-hiring-brief.md | 38 ++++++ .../features/now-and-archive.md | 32 +++++ .../features/writing-and-talks.md | 35 ++++++ .../helpers/aria_snapshot.py | 70 +++++++++++ .../verify-kylecesmat/helpers/cleanup.sh | 43 +++++++ .../verify-kylecesmat/helpers/doctor.sh | 107 ++++++++++++++++ .../verify-kylecesmat/helpers/launch.sh | 106 ++++++++++++++++ .../verify-kylecesmat/helpers/snapshot.sh | 51 ++++++++ .gitignore | 6 + 15 files changed, 708 insertions(+) create mode 100644 .cursor/skills/verify-kylecesmat/.run/.gitkeep create mode 100644 .cursor/skills/verify-kylecesmat/SKILL.md create mode 100644 .cursor/skills/verify-kylecesmat/evidence/.gitkeep create mode 100644 .cursor/skills/verify-kylecesmat/features/README.md create mode 100644 .cursor/skills/verify-kylecesmat/features/about-and-contact.md create mode 100644 .cursor/skills/verify-kylecesmat/features/build-and-headers.md create mode 100644 .cursor/skills/verify-kylecesmat/features/homepage-hiring-brief.md create mode 100644 .cursor/skills/verify-kylecesmat/features/now-and-archive.md create mode 100644 .cursor/skills/verify-kylecesmat/features/writing-and-talks.md create mode 100755 .cursor/skills/verify-kylecesmat/helpers/aria_snapshot.py create mode 100755 .cursor/skills/verify-kylecesmat/helpers/cleanup.sh create mode 100755 .cursor/skills/verify-kylecesmat/helpers/doctor.sh create mode 100755 .cursor/skills/verify-kylecesmat/helpers/launch.sh create mode 100755 .cursor/skills/verify-kylecesmat/helpers/snapshot.sh diff --git a/.cursor/skills/verify-kylecesmat/.run/.gitkeep b/.cursor/skills/verify-kylecesmat/.run/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.cursor/skills/verify-kylecesmat/SKILL.md b/.cursor/skills/verify-kylecesmat/SKILL.md new file mode 100644 index 0000000..c438223 --- /dev/null +++ b/.cursor/skills/verify-kylecesmat/SKILL.md @@ -0,0 +1,115 @@ +--- +name: verify-kylecesmat +description: Prove kylecesmat.com — a static Astro personal site (browser). Use after homepage, IA, or content changes. Preview-only local/preview proof; never production go-live, custom domain, or orange-cloud. +--- + +# Verify kylecesmat.com + +Static Astro 7 personal site. Users hit HTML in a browser. There is no app server, auth, or database. Verification proves a **local preview** of `dist/`. Do not attach `kylecesmat.com`, orange-cloud DNS, or retire GitHub Pages / `gh-pages`. + +Hard constraints from Kyle: + +1. **No quantitative metrics** in site copy or in assertions that require numbers on the page (no `0→15`, enablement %, MCP counts, latency). The Syntax.fm episode title is a talk name, not a KPI — match the heading text, do not treat it as a metric. +2. **Preview-only.** This skill never deploys, never flips DNS, never hits production as the system under test. +3. **Locked qualitative hero.** Homepage `

` is `Building Agent Experience for enterprise engineering orgs`. If you still see `headlinePick` or `[TODO: headline`, stop and fix copy before driving. + +Default origin: `http://127.0.0.1:4321`. + +## Launch + +Preferred (production-build proof): + +```bash +npm install +npm run build +.cursor/skills/verify-kylecesmat/helpers/launch.sh +``` + +`launch.sh` stops this checkout’s leftover Astro preview **lockfile PID** (`.astro/preview.json`) if present, then runs `./node_modules/.bin/astro preview --host 127.0.0.1 --port ${VERIFY_PORT:-4321}` with `ASTRO_PREVIEW_BACKGROUND=1` so Cursor does not daemonize the server out from under the recorded PID. It writes PID/port to `.cursor/skills/verify-kylecesmat/.run/state` and waits until `/` returns 200 **and** that PID tree owns the port. + +Do not `pkill astro`. Do not kill a listener that is not this checkout’s lockfile PID. + +Faster loops (not a production-build proof): `npm run dev` on the same host/port, then write the PID you started into `.run/state` yourself. Prefer `launch.sh` for a recorded proof. + +Teardown: `.cursor/skills/verify-kylecesmat/helpers/cleanup.sh` (kills the PID in `.run/state` and any listener it spawned). Never `pkill astro` / never kill by process name. + +If port `4321` is already bound by a process this run did not start, **refuse**. Set `VERIFY_PORT` to an open port only for an instance **you** launch. Do not drive a foreign preview. + +## Doctor + +```bash +.cursor/skills/verify-kylecesmat/helpers/doctor.sh +``` + +Read-only. Passes only when all of these hold: + +- Node major version `>= 22` (`node -v`, `.nvmrc` is `22`). +- `.run/state` exists and names a live PID. +- That PID (or a descendant) owns `LISTEN` on `VERIFY_PORT` / `127.0.0.1`. +- `GET /` returns **200**. +- Response body contains the locked hero string: `Building Agent Experience for enterprise engineering orgs`. +- Response body contains the trajectory line: `Coinbase SEM · formerly Formidable`. + +Fail if the hero is still a placeholder (`headlinePick`, `[TODO: headline`). Do not assert counts, percents, or latency figures. + +## Drive + +Harness: **curl** (HTTP + HTML) plus **Google Chrome headless** for screenshots. Prefer visible **link text and headings** (`about`, `writing`, `talks`, `contact`, section `h2`s). Do not target CSS classes as the primary handle. + +Stable routes (from `src/pages/`): + +| User path | Handle | +| --- | --- | +| Home | `/` — heading `Building Agent Experience for enterprise engineering orgs` | +| About | nav link `about` → `/about` | +| Writing index | nav `writing` or home `all writing` → `/writing` | +| Talks index | nav `talks` or home `all talks` → `/talks` | +| Contact | nav `contact` → `/contact` | +| Now | footer `now` → `/now` (not in primary nav) | +| Archive | footer `archive` → `/archive` (not in primary nav) | + +Chrome (this environment): `/usr/bin/google-chrome-stable`. Always pass `--headless=new --disable-gpu --no-sandbox`. + +```bash +RUN_ID=homepage-$(date -u +%Y%m%dT%H%M%SZ) +export RUN_ID +.cursor/skills/verify-kylecesmat/helpers/snapshot.sh http://127.0.0.1:${VERIFY_PORT:-4321}/ homepage +``` + +Read `features/` before driving. For the first proof, drive **homepage-hiring-brief** only. + +## Evidence + +Directory: `.cursor/skills/verify-kylecesmat/evidence//` (gitignored except `.gitkeep`). + +A homepage proof must include (stem `homepage`): + +- `homepage.status.txt` — HTTP status for `/` (expect `200`) +- `homepage.html` — response body +- `homepage.aria.txt` — headings, `aria-label` / `aria-current`, and link names +- `homepage.png` — screenshot with the wordmark `Kyle Cesmat` and hero heading visible + +Capture the **request** (URL) and the **resulting** HTML/screenshot together. Do not prove via reading `src/` instead of fetching the preview. + +Cleanup must **not** delete this directory. + +## Cleanup + +```bash +.cursor/skills/verify-kylecesmat/helpers/cleanup.sh +``` + +Stops only the preview PID recorded in `.run/state`. Removes `.run/state`. Leaves `evidence/` untouched. Confirm evidence still exists at the named path after cleanup. + +## Helpers + +All under `.cursor/skills/verify-kylecesmat/helpers/`. Executable. Invocations: + +| Script | Purpose | +| --- | --- | +| `launch.sh` | `npm install` + `npm run build` + `astro preview`; write `.run/state`; wait until `/` answers | +| `doctor.sh` | Node, PID owns port, GET `/` 200, locked hero + trajectory strings | +| `snapshot.sh ` | curl headers/body + Chrome screenshot + heading/link snapshot into `evidence/$RUN_ID/` | +| `cleanup.sh` | kill recorded PID only; keep evidence | + +Optional env: `VERIFY_PORT` (default `4321`), `RUN_ID` (snapshot target folder name). diff --git a/.cursor/skills/verify-kylecesmat/evidence/.gitkeep b/.cursor/skills/verify-kylecesmat/evidence/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.cursor/skills/verify-kylecesmat/features/README.md b/.cursor/skills/verify-kylecesmat/features/README.md new file mode 100644 index 0000000..1201f84 --- /dev/null +++ b/.cursor/skills/verify-kylecesmat/features/README.md @@ -0,0 +1,38 @@ +# kylecesmat.com verification map + +Maintained source for proving user-facing behavior of the static Astro site. Read this index, then the matching feature file. + +## Baseline preconditions + +- Preview origin `http://127.0.0.1:${VERIFY_PORT:-4321}` started by `helpers/launch.sh` (build then `astro preview`). +- `helpers/doctor.sh` exits 0 (Node >=22, our PID owns the port, `/` is 200, locked qualitative hero is present). +- Never drive a foreign process on 4321. +- Never assert quantitative metrics (org size, enablement %, MCP counts, latency). +- Preview-only: do not treat production `kylecesmat.com` as the system under test. + +## Driving conventions + +- Start from `/` unless a feature lists another entry. +- Prefer link text and headings over CSS. +- Use `helpers/snapshot.sh` for HTTP + HTML + screenshot + `aria.txt`. +- Chrome: `/usr/bin/google-chrome-stable --headless=new --disable-gpu --no-sandbox`. +- Cleanup with `helpers/cleanup.sh`; evidence stays on disk. + +## Proof and skip reporting + +- Capture the URL fetched and the resulting status/HTML/screenshot. +- UI proof includes `aria.txt` and a screenshot with `Kyle Cesmat` visible. +- Record `RUN_ID` and feature id on every artifact. +- Do not report a skipped route as verified via a different URL. + +## Feature entry contract + +Each feature file: H1, one paragraph, then exactly four H2s — `Sub-features`, `How to get to it (user POV)`, `Driving it with helpers`, `Gotchas`. + +## Features + +- [Homepage hiring brief](./homepage-hiring-brief.md) — hero, trajectory, three qualitative proof blocks, writing/talks, contact. +- [Writing and talks](./writing-and-talks.md) — MDX writing stubs; Syntax.fm episode listed first. +- [About and contact](./about-and-contact.md) — press-kit bio, ways I can help, email and LinkedIn. +- [Now and archive](./now-and-archive.md) — `/now` stub; Formidable work demoted to `/archive`. +- [Build and headers](./build-and-headers.md) — `npm run build`; `dist` has robots, sitemap, `_headers`. diff --git a/.cursor/skills/verify-kylecesmat/features/about-and-contact.md b/.cursor/skills/verify-kylecesmat/features/about-and-contact.md new file mode 100644 index 0000000..6fe1d52 --- /dev/null +++ b/.cursor/skills/verify-kylecesmat/features/about-and-contact.md @@ -0,0 +1,34 @@ +# About and contact + +About is the press kit: qualitative bio, ways I can help, and contact links. Contact is a short page with the same email and LinkedIn. + +## Sub-features + +- `about-bio` shows the qualitative Agent Experience bio (no org-size or enablement figures). +- `about-help` shows `Ways I can help` and the governed-leverage paragraph. +- `about-contact` lists `kylecesmat@gmail.com` and `LinkedIn`. +- `contact-page` repeats email and LinkedIn at `/contact`. + +## How to get to it (user POV) + +- Primary nav `about`. +- Primary nav `contact`. +- Home section `contact` mailto / LinkedIn (same destinations). + +## Driving it with helpers + +Preconditions: + +- Preview is healthy (`helpers/doctor.sh`). + +- **Open about.** Choose nav link `about`. Run `helpers/snapshot.sh http://127.0.0.1:${VERIFY_PORT:-4321}/about about`. Status `200`. Heading `About`. Body includes `Senior Engineering Manager at Coinbase leading Agent Experience` and `Ways I can help`. Fail if the bio contains metric patterns (`0→`, `2,200`, enablement `%`). +- **Confirm help.** Paragraph starting `I help engineering organizations turn AI coding tools into governed, measurable developer leverage`. +- **Confirm about contact.** Links `kylecesmat@gmail.com` and `LinkedIn`. +- **Open contact page.** Choose nav `contact`. Snapshot `/contact`. Status `200`. Same email and LinkedIn link names. +- **Proof.** Screenshots show `about` or `contact` current in nav (`aria-current="page"`). + +## Gotchas + +- About is MDX (`src/pages/about.mdx`); prove the rendered page, not the source file alone. +- LinkedIn is off-site; proving the href is enough — do not scrape LinkedIn. +- Do not “fix” a failed bio assertion by allowing numbers back onto the page. diff --git a/.cursor/skills/verify-kylecesmat/features/build-and-headers.md b/.cursor/skills/verify-kylecesmat/features/build-and-headers.md new file mode 100644 index 0000000..e70ae79 --- /dev/null +++ b/.cursor/skills/verify-kylecesmat/features/build-and-headers.md @@ -0,0 +1,33 @@ +# Build and headers + +A production static build writes `dist/` with HTML plus `robots.txt`, sitemap, and Cloudflare `_headers`. CI is build-only (no deploy). + +## Sub-features + +- `build-ok` — `npm run build` exits 0. +- `robots` — `dist/robots.txt` exists and allows crawlers, pointing at the sitemap. +- `sitemap` — `dist/sitemap-index.xml` exists. +- `headers` — `dist/_headers` exists (security headers for when the hostname is later proxied). + +## How to get to it (user POV) + +- A visitor never sees this directly. Authors run `npm run build` or CI `Build`. Preview serves the same `dist/` via `astro preview`. + +## Driving it with helpers + +Preconditions: + +- Node >=22. This feature does **not** require a running preview if you only inspect `dist/`. For a served proof, run `helpers/launch.sh` first (it builds). + +- **Build.** From repo root: `npm run build`. Exit code `0`. Directory `dist/` exists. +- **Robots.** `test -f dist/robots.txt`. File contains `User-agent: *` and a `Sitemap:` line. Do not require production DNS to resolve. +- **Sitemap.** `test -f dist/sitemap-index.xml`. +- **Headers.** `test -f dist/_headers`. File mentions `X-Content-Type-Options` (and typically `Referrer-Policy`). +- **Optional serve check.** After launch, `curl -sI http://127.0.0.1:${VERIFY_PORT:-4321}/robots.txt` is 200. +- **Proof.** Copy those three files (or `ls -l` output) into `evidence/$RUN_ID/` as `robots.txt`, `sitemap-index.xml`, `_headers`. Cleanup must not delete `evidence/`. Do not delete `dist/` in cleanup (build output is not proof; the copies in `evidence/` are). + +## Gotchas + +- CI must stay build-only. A passing build is not permission to attach a custom domain or orange-cloud. +- `_headers` apply on Cloudflare when the hostname is proxied; absence of `cf-ray` on today’s live GitHub Pages origin is expected. +- `npm run check` (`astro check`) is useful but not a substitute for the `dist/` artifact checks. diff --git a/.cursor/skills/verify-kylecesmat/features/homepage-hiring-brief.md b/.cursor/skills/verify-kylecesmat/features/homepage-hiring-brief.md new file mode 100644 index 0000000..ea5c17a --- /dev/null +++ b/.cursor/skills/verify-kylecesmat/features/homepage-hiring-brief.md @@ -0,0 +1,38 @@ +# Homepage hiring brief + +The home page is a short hiring brief: locked qualitative headline and subhead, a one-line trajectory, three restrained proof blocks, writing and talks lists, then contact. + +## Sub-features + +- `hero-lock` shows heading `Building Agent Experience for enterprise engineering orgs` and the qualitative subhead (no `headlinePick` placeholder). +- `trajectory` shows `Coinbase SEM · formerly Formidable`. +- `proof-blocks` shows three headings: `Agent Experience`, `Governed agent platform`, `Platform / App Infra`, each with a qualitative paragraph (no numeric KPIs). +- `writing-tease` lists writing titles and an `all writing` link. +- `talks-tease` lists talks with Syntax.fm first and an `all talks` link. +- `contact-cta` shows `kylecesmat@gmail.com` and `LinkedIn`. + +## How to get to it (user POV) + +- Open `/` (wordmark `Kyle Cesmat` also returns here). +- Land from any primary nav item by choosing the wordmark. + +## Driving it with helpers + +Preconditions: + +- `helpers/launch.sh` has started preview. +- `helpers/doctor.sh` exits 0. + +- **Open home.** Fetch `/`. Run `helpers/snapshot.sh http://127.0.0.1:${VERIFY_PORT:-4321}/ homepage`. `status.txt` is `200`. `aria.txt` and `homepage.html` include the locked `

` text `Building Agent Experience for enterprise engineering orgs`. +- **Confirm trajectory.** In the same HTML, the line `Coinbase SEM · formerly Formidable` is present. +- **Confirm proof.** Headings `Agent Experience`, `Governed agent platform`, and `Platform / App Infra` appear. Bodies are prose. Fail the proof if the HTML contains metric patterns such as `0→`, `%→`, or `MCP servers`. +- **Confirm writing and talks.** A heading `writing` and a link `all writing`; a heading `talks` and a link `all talks`. Syntax.fm talk title is listed (match the visible title string; do not assert a productivity percentage). +- **Confirm contact.** Links named `kylecesmat@gmail.com` (mailto) and `LinkedIn`. +- **Proof.** `homepage.png` shows the wordmark `Kyle Cesmat` and the locked hero heading. Keep artifacts under `evidence/$RUN_ID/`. + +## Gotchas + +- A 200 with a placeholder hero (`[TODO: headline`) is a failed proof, not a pass. +- Do not use production `https://kylecesmat.com` as the origin. +- Nav labels are lowercase (`about`, `writing`, `talks`, `contact`). +- Proof copy is qualitative. If a future edit reintroduces counts or percents, fail — do not “update the assertion” to match metrics. diff --git a/.cursor/skills/verify-kylecesmat/features/now-and-archive.md b/.cursor/skills/verify-kylecesmat/features/now-and-archive.md new file mode 100644 index 0000000..4b981d0 --- /dev/null +++ b/.cursor/skills/verify-kylecesmat/features/now-and-archive.md @@ -0,0 +1,32 @@ +# Now and archive + +`/now` is a dated-focus stub. `/archive` holds Formidable-era projects and meetup talks off the primary nav. + +## Sub-features + +- `now-stub` renders `/now` with heading `now` and placeholder focus/reading/location slots. +- `archive-demote` renders `/archive` with Formidable projects and meetup talks, not linked from primary nav. + +## How to get to it (user POV) + +- Footer link `now`. +- Footer link `archive`. +- Direct URL `/now` or `/archive`. +- Not listed in the primary nav (`about` / `writing` / `talks` / `contact`). + +## Driving it with helpers + +Preconditions: + +- Preview is healthy (`helpers/doctor.sh`). + +- **Confirm demotion.** Snapshot `/`. `aria.txt` primary nav (`aria-label="Primary"`) has `about`, `writing`, `talks`, `contact` and does **not** include `now` or `archive`. Footer does. +- **Open now.** Choose footer `now`. Run `helpers/snapshot.sh http://127.0.0.1:${VERIFY_PORT:-4321}/now now`. Status `200`. Heading `now`. +- **Open archive.** Choose footer `archive`. Snapshot `/archive`. Status `200`. Heading `archive`. Visible copy mentions Formidable and lists project titles (NDA-light). +- **Proof.** Keep HTML + screenshot for both routes plus the homepage nav snapshot that shows they are footer-only. + +## Gotchas + +- `/currently` redirects to `/` (legacy). Do not treat it as Now. +- Archive titles are historical names, not current hiring metrics. +- Placeholders on `/now` (`[TODO: now`) are expected until that copy is written. diff --git a/.cursor/skills/verify-kylecesmat/features/writing-and-talks.md b/.cursor/skills/verify-kylecesmat/features/writing-and-talks.md new file mode 100644 index 0000000..7d04b0e --- /dev/null +++ b/.cursor/skills/verify-kylecesmat/features/writing-and-talks.md @@ -0,0 +1,35 @@ +# Writing and talks + +Writing is a list of MDX pillar stubs. Talks is a separate list with the Syntax.fm episode first, plus notes at `/talks/syntax-fm-944`. + +## Sub-features + +- `writing-index` lists pillar stubs at `/writing` with titles from MDX frontmatter. +- `writing-piece` opens a stub at `/writing/` (heading is the piece title). +- `talks-index` lists talks at `/talks` with Syntax.fm first. +- `talk-notes` opens `/talks/syntax-fm-944` notes. + +## How to get to it (user POV) + +- Primary nav `writing` or home link `all writing`. +- Primary nav `talks` or home link `all talks`. +- A writing or talk title on the home page. + +## Driving it with helpers + +Preconditions: + +- Preview is healthy (`helpers/doctor.sh`). +- Drive from `/` unless noted. + +- **Open writing.** Choose link `writing` or `all writing`. Run `helpers/snapshot.sh http://127.0.0.1:${VERIFY_PORT:-4321}/writing writing-index`. Status `200`. Heading `writing`. At least one title link is present (stubs may say `draft`). +- **Open a piece.** Follow a writing title link (prefer the visible title, not a CSS selector). Snapshot that URL. Status `200`. The `

` matches the link text. +- **Open talks.** Choose `talks` or `all talks`. Run `helpers/snapshot.sh http://127.0.0.1:${VERIFY_PORT:-4321}/talks talks-index`. Status `200`. First listed title is `Is Coinbase Really Writing Half Their Code With AI?` (episode name, not a metric assertion). +- **Open notes.** Follow that title to `/talks/syntax-fm-944`. Status `200`. Heading matches the talk title. +- **Proof.** Keep HTML, `aria.txt`, and screenshots for index + one piece + talk notes. + +## Gotchas + +- Writing stubs are placeholders; empty body is OK if the title heading renders. +- Do not require a public Syntax.fm URL; notes are on-site. +- `#944` is the episode id in the venue string — match the visible venue/title, do not parse it as a site KPI. diff --git a/.cursor/skills/verify-kylecesmat/helpers/aria_snapshot.py b/.cursor/skills/verify-kylecesmat/helpers/aria_snapshot.py new file mode 100755 index 0000000..1e9d9c2 --- /dev/null +++ b/.cursor/skills/verify-kylecesmat/helpers/aria_snapshot.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +"""Extract headings, labeled landmarks, and link names from HTML for an ARIA-ish snapshot.""" +from __future__ import annotations + +import sys +from html.parser import HTMLParser +from pathlib import Path + + +class Snapshot(HTMLParser): + def __init__(self) -> None: + super().__init__(convert_charrefs=True) + self.lines: list[str] = [] + self._capture: list[str] | None = None + self._buf: list[str] = [] + self._skip = 0 + + def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None: + if tag in {"script", "style"}: + self._skip += 1 + return + ad = {k: v or "" for k, v in attrs} + if tag in {"h1", "h2", "h3", "title", "a", "nav"}: + self._capture = tag + self._buf = [] + extra = [] + if ad.get("aria-label"): + extra.append(f"aria-label={ad['aria-label']!r}") + if ad.get("aria-current"): + extra.append(f"aria-current={ad['aria-current']!r}") + if tag == "a" and ad.get("href"): + extra.append(f"href={ad['href']!r}") + self._pending_extra = extra + elif ad.get("aria-label") or ad.get("aria-current"): + bits = [tag] + if ad.get("aria-label"): + bits.append(f"aria-label={ad['aria-label']!r}") + if ad.get("aria-current"): + bits.append(f"aria-current={ad['aria-current']!r}") + self.lines.append(" ".join(bits)) + + def handle_endtag(self, tag: str) -> None: + if tag in {"script", "style"} and self._skip: + self._skip -= 1 + return + if self._capture == tag: + text = "".join(self._buf).strip() + extra = getattr(self, "_pending_extra", []) + suffix = (" " + " ".join(extra)) if extra else "" + if text or extra: + self.lines.append(f"{tag}: {text}{suffix}".rstrip()) + self._capture = None + self._buf = [] + + def handle_data(self, data: str) -> None: + if self._skip: + return + if self._capture is not None: + self._buf.append(data) + + +def main() -> None: + path = Path(sys.argv[1]) + parser = Snapshot() + parser.feed(path.read_text(encoding="utf-8", errors="replace")) + sys.stdout.write("\n".join(parser.lines) + "\n") + + +if __name__ == "__main__": + main() diff --git a/.cursor/skills/verify-kylecesmat/helpers/cleanup.sh b/.cursor/skills/verify-kylecesmat/helpers/cleanup.sh new file mode 100755 index 0000000..0781b8a --- /dev/null +++ b/.cursor/skills/verify-kylecesmat/helpers/cleanup.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +# Stop only the preview this run started. Do not delete evidence. +set -euo pipefail + +HELPERS="$(cd "$(dirname "$0")" && pwd)" +SKILL_DIR="$(cd "$HELPERS/.." && pwd)" +STATE="$SKILL_DIR/.run/state" + +if [[ ! -f "$STATE" ]]; then + echo "cleanup: no state file; nothing to stop" + exit 0 +fi +# shellcheck disable=SC1090 +source "$STATE" + +kill_tree() { + local pid="$1" + local kids + kids="$(ps -o pid= --ppid "$pid" 2>/dev/null || true)" + for k in $kids; do + kill_tree "$k" + done + if kill -0 "$pid" 2>/dev/null; then + kill "$pid" 2>/dev/null || true + fi +} + +if [[ -n "${PID:-}" ]] && kill -0 "$PID" 2>/dev/null; then + kill_tree "$PID" + for _ in $(seq 1 20); do + kill -0 "$PID" 2>/dev/null || break + sleep 0.1 + done + if kill -0 "$PID" 2>/dev/null; then + kill -9 "$PID" 2>/dev/null || true + fi + echo "cleanup: stopped pid=$PID" +else + echo "cleanup: recorded pid ${PID:-unset} already gone" +fi + +rm -f "$STATE" +echo "cleanup: evidence directories were not touched" diff --git a/.cursor/skills/verify-kylecesmat/helpers/doctor.sh b/.cursor/skills/verify-kylecesmat/helpers/doctor.sh new file mode 100755 index 0000000..d3b1663 --- /dev/null +++ b/.cursor/skills/verify-kylecesmat/helpers/doctor.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env bash +# Read-only: is this preview instance worth driving? +set -euo pipefail + +HELPERS="$(cd "$(dirname "$0")" && pwd)" +SKILL_DIR="$(cd "$HELPERS/.." && pwd)" +ROOT="$(cd "$SKILL_DIR/../../.." && pwd)" +STATE="$SKILL_DIR/.run/state" +HERO='Building Agent Experience for enterprise engineering orgs' +TRAJECTORY='Coinbase SEM · formerly Formidable' + +if [[ ! -f "$STATE" ]]; then + echo "doctor: missing $STATE (run launch.sh)" >&2 + exit 1 +fi +# shellcheck disable=SC1090 +source "$STATE" + +NODE_V="$(node -v)" +NODE_MAJOR="${NODE_V#v}" +NODE_MAJOR="${NODE_MAJOR%%.*}" +if [[ "$NODE_MAJOR" -lt 22 ]]; then + echo "doctor: Node >=22 required, got $NODE_V" >&2 + exit 1 +fi + +NVMRC="$(tr -d '[:space:]' <"$ROOT/.nvmrc")" +if [[ "$NVMRC" != "22" ]]; then + echo "doctor: .nvmrc is '$NVMRC', expected 22" >&2 + exit 1 +fi + +if [[ -z "${PID:-}" ]] || ! kill -0 "$PID" 2>/dev/null; then + echo "doctor: recorded PID ${PID:-unset} is not running" >&2 + exit 1 +fi + +LISTEN_PIDS="" +if command -v lsof >/dev/null 2>&1; then + LISTEN_PIDS="$(lsof -iTCP:"$PORT" -sTCP:LISTEN -t 2>/dev/null || true)" +fi + +owns=0 +for lp in $LISTEN_PIDS; do + if [[ "$lp" == "$PID" ]]; then + owns=1 + break + fi + # npm/npx often spawn a child that actually binds the port + if [[ "$(ps -o ppid= -p "$lp" 2>/dev/null | tr -d ' ')" == "$PID" ]]; then + owns=1 + break + fi + # walk a couple of ancestors + cur="$lp" + for _ in 1 2 3 4; do + parent="$(ps -o ppid= -p "$cur" 2>/dev/null | tr -d ' ' || true)" + [[ -z "$parent" || "$parent" == "1" ]] && break + if [[ "$parent" == "$PID" ]]; then + owns=1 + break + fi + cur="$parent" + done + [[ "$owns" == 1 ]] && break +done + +if [[ "$owns" != 1 ]]; then + echo "doctor: port $PORT is not owned by pid $PID (listen pids: ${LISTEN_PIDS:-none})" >&2 + exit 1 +fi + +TMP="$(mktemp)" +STATUS="$(curl -sS -o "$TMP" -w '%{http_code}' "http://${HOST}:${PORT}/")" +if [[ "$STATUS" != "200" ]]; then + echo "doctor: GET / returned $STATUS" >&2 + rm -f "$TMP" + exit 1 +fi + +if ! grep -q "$HERO" "$TMP"; then + echo "doctor: homepage missing locked hero string" >&2 + rm -f "$TMP" + exit 1 +fi + +if grep -q '\[TODO: headline' "$TMP" || grep -q 'headlinePick' "$TMP"; then + echo "doctor: homepage still has placeholder headline" >&2 + rm -f "$TMP" + exit 1 +fi + +if ! grep -q "$TRAJECTORY" "$TMP"; then + echo "doctor: homepage missing trajectory line" >&2 + rm -f "$TMP" + exit 1 +fi + +# Fail if quantitative hiring metrics leaked back onto the homepage. +if grep -E '0→|2,200|0%→94%|~170 MCP|4\.8k|16k runs|26s→|98% down' "$TMP"; then + echo "doctor: homepage contains quantitative metrics (forbidden)" >&2 + rm -f "$TMP" + exit 1 +fi + +rm -f "$TMP" +echo "doctor: ok node=$NODE_V pid=$PID http://${HOST}:${PORT}/ hero=locked" diff --git a/.cursor/skills/verify-kylecesmat/helpers/launch.sh b/.cursor/skills/verify-kylecesmat/helpers/launch.sh new file mode 100755 index 0000000..733cd4e --- /dev/null +++ b/.cursor/skills/verify-kylecesmat/helpers/launch.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash +# Start a local astro preview owned by this verification run. +set -euo pipefail + +HELPERS="$(cd "$(dirname "$0")" && pwd)" +SKILL_DIR="$(cd "$HELPERS/.." && pwd)" +ROOT="$(cd "$SKILL_DIR/../../.." && pwd)" +RUN_DIR="$SKILL_DIR/.run" +STATE="$RUN_DIR/state" +PORT="${VERIFY_PORT:-4321}" +HOST="${VERIFY_HOST:-127.0.0.1}" + +mkdir -p "$RUN_DIR" + +if [[ -f "$STATE" ]]; then + # shellcheck disable=SC1090 + source "$STATE" + if [[ -n "${PID:-}" ]] && kill -0 "$PID" 2>/dev/null; then + echo "verify-kylecesmat: already launched pid=$PID port=$PORT" >&2 + exit 0 + fi + rm -f "$STATE" +fi + +LOCK="$ROOT/.astro/preview.json" +if [[ -f "$LOCK" ]]; then + lock_pid="$(python3 -c "import json; print(json.load(open('$LOCK')).get('pid',''))" 2>/dev/null || true)" + if [[ -n "$lock_pid" ]] && kill -0 "$lock_pid" 2>/dev/null; then + echo "verify-kylecesmat: stopping this checkout's leftover preview pid=$lock_pid" + kill "$lock_pid" 2>/dev/null || true + for _ in $(seq 1 30); do + kill -0 "$lock_pid" 2>/dev/null || break + sleep 0.1 + done + if kill -0 "$lock_pid" 2>/dev/null; then + kill -9 "$lock_pid" 2>/dev/null || true + fi + fi + rm -f "$LOCK" +fi + +if command -v lsof >/dev/null 2>&1 && lsof -iTCP:"$PORT" -sTCP:LISTEN >/dev/null 2>&1; then + echo "verify-kylecesmat: port $PORT still bound after releasing this checkout's lock. Refuse." >&2 + exit 1 +fi + +cd "$ROOT" +npm install +npm run build + +# ASTRO_PREVIEW_BACKGROUND=1 keeps preview in the foreground under our PID +# (Cursor would otherwise daemonize `astro preview` and drop ownership). +LOG="$RUN_DIR/preview.log" +: >"$LOG" +ASTRO_PREVIEW_BACKGROUND=1 ./node_modules/.bin/astro preview --host "$HOST" --port "$PORT" >"$LOG" 2>&1 & +PID=$! + +{ + echo "PID=$PID" + echo "PORT=$PORT" + echo "HOST=$HOST" + echo "STARTED_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)" +} >"$STATE" + +cleanup_on_fail() { + if kill -0 "$PID" 2>/dev/null; then + kill "$PID" 2>/dev/null || true + wait "$PID" 2>/dev/null || true + fi + rm -f "$STATE" +} + +owns_listen() { + local want="$1" + local lp parent cur + lp="$(lsof -iTCP:"$PORT" -sTCP:LISTEN -t 2>/dev/null | head -1 || true)" + [[ -z "$lp" ]] && return 1 + [[ "$lp" == "$want" ]] && return 0 + cur="$lp" + for _ in 1 2 3 4 5; do + parent="$(ps -o ppid= -p "$cur" 2>/dev/null | tr -d ' ' || true)" + [[ -z "$parent" || "$parent" == "1" ]] && break + [[ "$parent" == "$want" ]] && return 0 + cur="$parent" + done + return 1 +} + +for _ in $(seq 1 40); do + if curl -sf -o /dev/null "http://${HOST}:${PORT}/" && owns_listen "$PID"; then + echo "verify-kylecesmat: ready pid=$PID http://${HOST}:${PORT}/" + exit 0 + fi + if ! kill -0 "$PID" 2>/dev/null; then + echo "verify-kylecesmat: preview exited before ready. log:" >&2 + cat "$LOG" >&2 || true + cleanup_on_fail + exit 1 + fi + sleep 0.25 +done + +echo "verify-kylecesmat: timed out waiting for http://${HOST}:${PORT}/" >&2 +cat "$LOG" >&2 || true +cleanup_on_fail +exit 1 diff --git a/.cursor/skills/verify-kylecesmat/helpers/snapshot.sh b/.cursor/skills/verify-kylecesmat/helpers/snapshot.sh new file mode 100755 index 0000000..8d9bc28 --- /dev/null +++ b/.cursor/skills/verify-kylecesmat/helpers/snapshot.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +# Fetch a preview URL into evidence/$RUN_ID/: HTTP status, HTML, aria-ish snapshot, screenshot. +set -euo pipefail + +HELPERS="$(cd "$(dirname "$0")" && pwd)" +SKILL_DIR="$(cd "$HELPERS/.." && pwd)" +STATE="$SKILL_DIR/.run/state" + +URL="${1:-}" +STEM="${2:-page}" +if [[ -z "$URL" ]]; then + echo "usage: snapshot.sh [stem]" >&2 + exit 1 +fi + +if [[ -z "${RUN_ID:-}" ]]; then + echo "snapshot.sh: set RUN_ID (evidence folder name)" >&2 + exit 1 +fi + +OUT="$SKILL_DIR/evidence/$RUN_ID" +mkdir -p "$OUT" + +STATUS="$(curl -sS -D "$OUT/${STEM}.headers" -o "$OUT/${STEM}.html" -w '%{http_code}' "$URL")" +echo "$STATUS" >"$OUT/${STEM}.status.txt" +echo "url=$URL" >"$OUT/${STEM}.meta.txt" +echo "status=$STATUS" >>"$OUT/${STEM}.meta.txt" +echo "fetched_at=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >>"$OUT/${STEM}.meta.txt" +if [[ -f "$STATE" ]]; then + echo "state=$(tr '\n' ' ' <"$STATE")" >>"$OUT/${STEM}.meta.txt" +fi + +python3 "$HELPERS/aria_snapshot.py" "$OUT/${STEM}.html" >"$OUT/${STEM}.aria.txt" + +CHROME="${CHROME_BIN:-/usr/bin/google-chrome-stable}" +if [[ -x "$CHROME" ]]; then + "$CHROME" \ + --headless=new \ + --disable-gpu \ + --no-sandbox \ + --hide-scrollbars \ + --window-size=1280,1800 \ + --screenshot="$OUT/${STEM}.png" \ + "$URL" >/dev/null 2>"$OUT/${STEM}.chrome.log" || { + echo "snapshot.sh: chrome screenshot failed (see ${STEM}.chrome.log)" >&2 + } +else + echo "snapshot.sh: no chrome at $CHROME; skipped screenshot" >&2 +fi + +echo "snapshot: $OUT/${STEM}.* status=$STATUS" diff --git a/.gitignore b/.gitignore index 4bc9b02..bcd760a 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,9 @@ yarn-error.log* .DS_Store *.pem .vercel + +# pstack verification evidence and live preview PID (keep .gitkeep) +.cursor/skills/verify-kylecesmat/evidence/* +!.cursor/skills/verify-kylecesmat/evidence/.gitkeep +.cursor/skills/verify-kylecesmat/.run/* +!.cursor/skills/verify-kylecesmat/.run/.gitkeep