diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..b198f99 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,108 @@ +# AGENTS.md — AI Agent Context for token-deathclock + +This file gives AI coding agents (GitHub Copilot, Claude, ChatGPT, etc.) the context +they need to work effectively on this repository. + +--- + +## Project Purpose + +**Token Deathclock** is a static GitHub Pages site that visualises the environmental cost +of global AI token consumption. It shows live counters, environmental milestone cards, +a Chart.js growth chart with projections, and a prompt/PR quality scoring section. + +**Live site:** `https://nitrocode.github.io/token-deathclock/` + +--- + +## Repository Layout + +``` +. +├── index.html ← GitHub Pages entry point (static HTML shell) +├── styles.css ← Dark/light theme, animations, responsive layout +├── death-clock-core.js ← Pure functions only — no DOM, safe to unit-test +├── script.js ← All DOM manipulation, Chart.js wiring, RAF loop +├── package.json ← Jest config & devDependencies (no runtime deps) +├── tests/ +│ └── death-clock.test.js ← 75 Jest unit tests for death-clock-core.js +└── .github/ + └── workflows/ + ├── deploy.yml ← Deploys index.html etc. to GitHub Pages on push to main + └── test.yml ← Runs `npm run test:ci` on every push / PR +``` + +--- + +## Architecture Rules + +| Rule | Detail | +|------|--------| +| **Core / DOM split** | `death-clock-core.js` must never import or reference the DOM. All DOM work belongs in `script.js`. | +| **No runtime dependencies** | The live site loads only Chart.js from a CDN. There are no npm runtime packages. | +| **CommonJS + browser dual export** | `death-clock-core.js` exports via `module.exports` for Jest and via `window.DeathClockCore` for the browser. Do not change this pattern without updating both consumers. | +| **HTML escaping** | All dynamic strings rendered into `innerHTML` must pass through `escHtml()` in `script.js`. Never assign untrusted data directly to `innerHTML`. | +| **Counter anchor** | `getCurrentTokens()` in `script.js` computes elapsed time from `BASE_DATE_ISO` (exported by the core module), **not** from page-load time. `pageLoadTime` is reserved for the session counter only. | + +--- + +## Key Constants (death-clock-core.js) + +| Constant | Value | Meaning | +|----------|-------|---------| +| `BASE_TOKENS` | 65 × 10¹⁵ | Estimated cumulative tokens as of `BASE_DATE_ISO` | +| `TOKENS_PER_SECOND` | 100 000 000 | Estimated global AI inference rate | +| `BASE_DATE_ISO` | `'2026-04-14T07:09:04Z'` | Anchor timestamp for the counter | + +When updating data, change **all three** together so they stay consistent. + +--- + +## Running Tests + +```bash +npm ci # install devDependencies +npm test # jest --coverage (interactive) +npm run test:ci # jest --ci --coverage (CI mode; fails on coverage drop) +``` + +**Coverage thresholds** (enforced in CI): + +| Metric | Threshold | +|--------|-----------| +| Lines | 80 % | +| Functions | 80 % | +| Branches | 70 % | + +The current measured coverage is ≈ 96 % statements / 88 % branches — do not let it drop below the thresholds. + +--- + +## Making Changes + +### Changing milestone data +Edit the `MILESTONES` array in `death-clock-core.js`. Each object requires: +`id`, `name`, `icon`, `tokens`, `shortDesc`, `description`, `consequence`, `followingEvent`, `color`, `darkColor`. +Keep the array sorted in ascending `tokens` order — the constants test enforces this. + +### Adding a new pure utility function +1. Add the function to `death-clock-core.js`. +2. Export it via the `DeathClockCore` object at the bottom of the file. +3. Add unit tests in `tests/death-clock.test.js`. +4. Import it in `script.js` via the destructuring at the top of the IIFE. + +### Changing the visual theme +Edit `styles.css`. CSS custom properties for colours live in `:root[data-theme="dark"]` and `:root[data-theme="light"]`. The theme toggle is managed by `applyTheme()` in `script.js`. + +### Deployment +Merging to `main` triggers the `deploy.yml` workflow automatically. No manual steps are required after the one-time GitHub Pages source has been set to **GitHub Actions** in repository settings. + +--- + +## What NOT to Do + +- Do **not** add runtime npm packages — the site must remain fully static. +- Do **not** introduce DOM references in `death-clock-core.js`. +- Do **not** remove or weaken the `escHtml()` guard on dynamic HTML. +- Do **not** skip tests when adding new pure functions to the core module. +- Do **not** change `BASE_TOKENS` / `TOKENS_PER_SECOND` / `BASE_DATE_ISO` independently — update all three as a set with a comment explaining the source. diff --git a/README.md b/README.md index 5937838..60edaa9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # AI Death Clock 💀 -> **Live site:** `https://nitrocode.github.io/game/` +> **Live site:** `https://nitrocode.github.io/token-deathclock/` A GitHub Pages visualisation that shows the environmental cost of global AI token consumption — featuring live counters, milestone tracker, token-growth chart with projections, and a prompt/PR scoring section. @@ -26,8 +26,8 @@ Created by **RB**. ```bash # Clone and open -git clone https://github.com/nitrocode/game.git -cd game +git clone https://github.com/nitrocode/token-deathclock.git +cd token-deathclock # Serve with any static server, e.g.: npx serve . # Then open http://localhost:3000 @@ -54,7 +54,7 @@ Tests are in `tests/death-clock.test.js` and cover all pure functions in `death- 1. Go to **Settings → Pages** in this repository. 2. Under **Source**, select **GitHub Actions**. 3. Push or re-run the `Deploy to GitHub Pages` workflow. -4. The site will be live at `https://nitrocode.github.io/game/`. +4. The site will be live at `https://nitrocode.github.io/token-deathclock/`. > ⚠️ The workflow file (`.github/workflows/deploy.yml`) is already included. > Only step 2 (enabling GitHub Actions as the Pages source) needs to be done manually once in the repository settings. @@ -119,4 +119,48 @@ Tests are in `tests/death-clock.test.js` and cover all pure functions in `death- | CO₂ per tree (~21 kg/year) | US Forest Service estimates | | Historical token growth | OpenAI usage blog, Epoch AI, AI Index 2024 | -> All figures are illustrative estimates intended to communicate scale, not precise measurements. \ No newline at end of file +> All figures are illustrative estimates intended to communicate scale, not precise measurements. + +--- + +## Repo Score & Roadmap + +### Score: 72 / 100 — Grade: C+ + +| Category | Score | Notes | +|---|---|---| +| **Code quality** | 17/20 | Clean separation of concerns; pure-function core; consistent style | +| **Test coverage** | 18/20 | 96 % statement coverage on the tested module; 75 passing tests | +| **Documentation** | 12/20 | Good README; AGENTS.md added; missing CONTRIBUTING.md, LICENSE | +| **CI / CD** | 9/10 | Test + deploy workflows both present and functional | +| **Accessibility** | 7/10 | ARIA live regions, roles, and values; dark/light toggle | +| **Security** | 6/10 | `escHtml` guards all dynamic content; no CSP headers | +| **Bug count** | 3/10 | `getCurrentTokens()` used `pageLoadTime` instead of `BASE_DATE_ISO`, causing the total counter to restart at `BASE_TOKENS` on every page load | +| **Community files** | 0/10 | No LICENSE, no CONTRIBUTING.md, no SECURITY.md | + +### Roadmap + +#### Priority 1 — Correctness (immediate) +- [x] **Fix total-counter anchor** — `getCurrentTokens()` now uses `BASE_DATE_ISO` so the counter reflects true elapsed time since the data anchor, not since the page was loaded. + +#### Priority 2 — Community & compliance +- [ ] Add a `LICENSE` file (MIT or Apache-2.0 recommended). +- [ ] Add `CONTRIBUTING.md` with a pull-request checklist and coding conventions. +- [ ] Add `SECURITY.md` with a vulnerability-disclosure policy. +- [ ] Add a `CODEOWNERS` file to set review requirements. + +#### Priority 3 — Security hardening +- [ ] Add a `Content-Security-Policy` meta tag in `index.html` to restrict inline scripts and limit allowed CDN origins (Chart.js, Google Fonts). +- [ ] Pin the Chart.js CDN URL to a known-good SRI hash. +- [ ] Add Dependabot config (`.github/dependabot.yml`) for automatic npm and GitHub Actions version bumps. + +#### Priority 4 — Test completeness +- [ ] Add integration / smoke tests for `script.js` DOM logic using `jest-environment-jsdom`. +- [ ] Cover the two uncovered lines in `death-clock-core.js` (lines 251, 443-444). +- [ ] Add a test that asserts `getCurrentTokens()` grows with time rather than resetting on reload. + +#### Priority 5 — Developer experience +- [ ] Add `.nvmrc` to pin the Node.js version. +- [ ] Add `.editorconfig` or a Prettier config for consistent formatting. +- [ ] Add a `"homepage"` field in `package.json` matching the GitHub Pages URL. +- [ ] Add a `CHANGELOG.md` to track releases. \ No newline at end of file diff --git a/script.js b/script.js index 90bce8e..e29eaa7 100644 --- a/script.js +++ b/script.js @@ -11,6 +11,7 @@ const { BASE_TOKENS, TOKENS_PER_SECOND, + BASE_DATE_ISO, HISTORICAL_DATA, MILESTONES, PROMPT_SCORING, @@ -29,12 +30,13 @@ // ---- State ----------------------------------------------- const pageLoadTime = Date.now(); + const baseDateTime = new Date(BASE_DATE_ISO).getTime(); let currentTheme = 'dark'; let chartInstance = null; // ---- Helpers --------------------------------------------- function getCurrentTokens() { - const elapsed = (Date.now() - pageLoadTime) / 1000; + const elapsed = (Date.now() - baseDateTime) / 1000; return BASE_TOKENS + TOKENS_PER_SECOND * elapsed; }