Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions CLAUDE.md

Large diffs are not rendered by default.

18 changes: 11 additions & 7 deletions config/tsconfig.browser.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
"target": "esnext",
"module": "esnext",
"moduleResolution": "bundler",
"paths": { "/*": ["../www/*"] },
// The served URL root is a COMPOSITE now: build.mjs stages www/, src/client/
// and src/styles/ into one tree, so /hoist.js and /nav.js resolve out of
// src/client while /index.html and /images/* still come from www/. Listing
// both is what keeps an absolute specifier checkable after the split.
"paths": { "/*": ["../src/client/*", "../src/styles/*", "../www/*"] },
"lib": ["esnext", "dom", "dom.iterable"],
"skipLibCheck": true,
"strict": false
Expand All @@ -19,11 +23,11 @@
// tsc follows their static imports. The shell's Run and tray islands complete
// the first-interaction surface without pulling Worker modules into this graph.
"include": [
"../www/hoist.js",
"../www/tooltip.js",
"../www/infotip.js",
"../www/nav.js",
"../www/nav-run.js",
"../www/nav-tray.js"
"../src/client/hoist.js",
"../src/client/tooltip.js",
"../src/client/infotip.js",
"../src/client/nav.js",
"../src/client/nav-run.js",
"../src/client/nav-tray.js"
]
}
2 changes: 1 addition & 1 deletion design/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ before treating anything below as a spec.
- **`DESIGN.md`** — the Luna brief. The canonical reference plus the
DON'T-modernize guardrails. CLAUDE.md points here.
- **`tokens/`** — the canonical token set (colors, bevels, fonts, typography;
115 custom properties). `www/luna.css` derives from these and never
115 custom properties). `src/styles/luna.css` derives from these and never
redefines them. Change a token here first, then flow it into luna.css.
- **`styles.css`** — the entry point that `@import`s the four token files.
Nothing the site serves links it; the `aadhar-sh-design` skill package does.
Expand Down
6 changes: 3 additions & 3 deletions docs/MAINTENANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -934,7 +934,7 @@ Key facts (don't hardcode these elsewhere, they drift):
- RN_KV namespace id: `3cb8a107c58e47dc9244e75b33401f36`
- R2 bucket: `aadhar-photos` (SOOC originals + full-res JPGs)
- Thumbnails are content-addressed at `/i/<stem>.<hash8>.<ext>` (hashes.json via `hash-thumbnails.sh`); `THUMB_VERSION` is gone entirely (retired with the last legacy fallback — `lib/const.js` keeps only `CANONICAL_HOST` + `ARCHIVE_VERSION`).
- The service worker RETIRED in v136 (2026-07-03): `www/sw.js` is an unregister stub that must keep serving 200 for a year+. There is no `CACHE_VERSION`; the deploy-log number lives in D1 (`bump-version.sh` derives the next from `MAX(vnum)`).
- The service worker RETIRED in v136 (2026-07-03): `src/client/sw.js` is an unregister stub that must keep serving 200 for a year+. There is no `CACHE_VERSION`; the deploy-log number lives in D1 (`bump-version.sh` derives the next from `MAX(vnum)`).
- Canonical photo source: the aadhar-photos R2 bucket. Raw source files are
never committed to GitHub; the Actions workflow downloads only the requested
object keys into disposable runner storage.
Expand Down Expand Up @@ -964,7 +964,7 @@ files) are served straight from disk. Worker-owned routes are enumerated in
| `/lens`, `/lens/`, `/lens/fetch`, `/lens/shot` | `handleLens` / `handleLensFetch` / `handleLensShot` | `lens.js` |
| `/coffee`, `/coffee/*` | Cal booking module delegation | `../cal/src/index.js` |
| `/serendipity`, `/serendipity/*` | Serendipity module delegation + local CSP | `../serendipity/serendipity.js` |
| `/lens.js` | static client renderer | `www/lens.js` (served asset) |
| `/lens.js` | static client renderer | `src/client/lens.js` (served asset) |
| `/llms-full.txt` | `handleLlmsFull` (x402 bot paywall; free until `X402_PAY_TO` is set) | `x402.js` |
| `/ledger`, `/ledger.json` | `handleLedger` / `handleLedgerJson` (AI-crawler invoice from Analytics Engine; counting via `countCrawlerHit` in `index.js`) | `ledger.js` |
| `/writing`, `/writing/`, `/writing/<slug>` | `handleWritingIndex` / `handleWritingPost` (Notepad) | `writing.js` |
Expand Down Expand Up @@ -1529,7 +1529,7 @@ Two variants ship because the card has two honest jobs:

The chips are COUNTED from `config/site-manifest.json` and
`www/images/hashes.json` rather than typed, because a card outlives most of what
it describes. The wallpaper and the window icon are read out of `www/luna.css`
it describes. The wallpaper and the window icon are read out of `src/styles/luna.css`
and `www/index.html` for the same reason, so there is no second copy of either.

Nothing in the pipeline uploads it: GitHub exposes no API for the social preview.
Expand Down
34 changes: 20 additions & 14 deletions scripts/build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ async function checkInvariants() {
: s.replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "");
if (/@view-transition\s*\{/.test(css)) hard.push(`${f}: re-opts into View Transitions (@view-transition), removed site-wide 2026-07-30`);
}
const luna = await read("www/luna.css");
const luna = await read("src/styles/luna.css");

// 3b (hard) — luna.css parses as valid CSS. A botched find-replace in v143
// wrapped several .window/.xp-button declarations in :where(...) and left
Expand All @@ -200,7 +200,7 @@ async function checkInvariants() {
// releases (the .window box-shadow + the whole .xp-button base rule dropped
// from the CSSOM). Transform as CSS and block on any warning.
try {
const res = transformCss({ filename: "www/luna.css", code: Buffer.from(luna), minify: false });
const res = transformCss({ filename: "src/styles/luna.css", code: Buffer.from(luna), minify: false });
for (const w of res.warnings) hard.push(`luna.css CSS parse warning: ${w.message}${w.loc ? ` (line ${w.loc.line})` : ""}`);
} catch (e) {
hard.push(`luna.css failed to parse as CSS: ${e.message.split("\n")[0]}`);
Expand Down Expand Up @@ -238,7 +238,7 @@ async function checkInvariants() {
// file that carries the calc must agree with luna.css, or first paint lands
// a different window height than the final.
const floors = new Map();
for (const f of ["www/luna.css", "src/worker/lib/chrome.js", "src/worker/writing.js", "serendipity/serendipity.js"]) {
for (const f of ["src/styles/luna.css", "src/worker/lib/chrome.js", "src/worker/writing.js", "serendipity/serendipity.js"]) {
let s; try { s = await read(f); } catch { continue; }
// the BODY floor only (`height:calc(...)`), not a window `max-height:calc(...)`
for (const m of s.matchAll(/(?<!max-)height:calc\(100dvh - (\d+)px\)/g)) floors.set(f, m[1]);
Expand All @@ -251,7 +251,7 @@ async function checkInvariants() {
// If the declaration can't be found in luna.css there is nothing to inject and
// every page silently loses its first-paint mirror, so this blocks rather than
// warns: a missing rule here is a rename or a bad edit, not a taste call.
if (!clientEdgeDecl(await read("www/luna.css"))) hard.push("luna.css: the client-edge declaration went missing (search \"THE CLIENT EDGE\") — build.mjs injects it into every windowed page and has nothing to inject");
if (!clientEdgeDecl(await read("src/styles/luna.css"))) hard.push("luna.css: the client-edge declaration went missing (search \"THE CLIENT EDGE\") — build.mjs injects it into every windowed page and has nothing to inject");

// 6 (warn) — the local-dev twin (wrangler.dev.jsonc) must declare the same
// bindings as the deploy config (wrangler.jsonc), or local `wrangler dev`
Expand Down Expand Up @@ -322,7 +322,7 @@ async function checkInvariants() {
let manifestChecked = 0;
try {
const { surfaces } = readManifest();
const nav = await read("www/nav-run.js");
const nav = await read("src/client/nav-run.js");
const desktop = await read("src/worker/lib/desktop.js");

// 8a — generated projections match `pnpm run gen:manifest` output exactly.
Expand Down Expand Up @@ -639,6 +639,12 @@ await cp("www", `${OUT}/www`, {
// at .build/src/worker/index.js, and every deploy path and content hash
// downstream is therefore untouched by the move.
await cp("src/worker", `${OUT}/src/worker`, { recursive: true });
// The client islands and stylesheets author in src/ beside the Worker, and stage
// back to the ROOT of the served tree because their public URLs are /nav.js and
// /luna.css. Source layout and URL layout are different questions; only the first
// one moved, so every served byte and every /a/ content hash is untouched.
await cp("src/client", `${OUT}/www`, { recursive: true });
await cp("src/styles", `${OUT}/www`, { recursive: true });
await mkdir(`${OUT}/cal`, { recursive: true });
await cp("cal/src", `${OUT}/cal/src`, { recursive: true });
await mkdir(`${OUT}/serendipity`, { recursive: true });
Expand Down Expand Up @@ -700,7 +706,7 @@ await cp("serendipity/serendipity.js", `${OUT}/serendipity/serendipity.js`);
// file. Pages that load luna.css render-blocking (garage/gpt56.html) carry no
// geometry mirror and correctly get nothing.
{
const decl = clientEdgeDecl(await readFile("www/luna.css", "utf8"));
const decl = clientEdgeDecl(await readFile("src/styles/luna.css", "utf8"));
const targets = (await readdir(`${OUT}/www`, { recursive: true }))
.filter((f) => /\.(html|js)$/.test(f) && !/\.src\.|^(i|images|og|cars)\//.test(f))
.map((f) => `${OUT}/www/${f}`)
Expand Down Expand Up @@ -1271,10 +1277,10 @@ let dressPage = () => { throw new Error("explorer: dressPage used before 1g2 def

// 3) shells: deploy the readable original as <name>.src.js, minify the served file
for (const [file, srcPath, marker] of SHELLS) {
const src = await readFile(`www/${file}`, "utf8");
const src = await readFile(`src/client/${file}`, "utf8");
await writeFile(`${OUT}/www/${srcPath.slice(1)}`, src);

const code = minifyJavaScript(`www/${file}`, src);
const code = minifyJavaScript(`src/client/${file}`, src);
const banner = `/*! minified at deploy - readable source: ${srcPath} */\n`;
const min = banner + code;

Expand All @@ -1296,18 +1302,18 @@ for (const [file, srcPath, marker] of SHELLS) {
// minify. The three first-interaction sheets below are explicit exceptions: each
// was extracted byte-for-byte from luna.css and loads only with its matching JS.
{
const src = await readFile("www/luna.css", "utf8");
const src = await readFile("src/styles/luna.css", "utf8");
await writeFile(`${OUT}/www/luna.src.css`, src);
const code = minifyCss("www/luna.css", src);
const code = minifyCss("src/styles/luna.css", src);
const out = `/*! minified at deploy - readable source: /luna.src.css */\n` + code;
await writeFile(`${OUT}/www/luna.css`, out);
console.log(`luna.css: ${src.length} -> ${out.length} bytes (+ /luna.src.css)`);
}

for (const file of ["nav-run.css", "nav-tray.css", "infotip.css"]) {
const src = await readFile(`www/${file}`, "utf8");
const src = await readFile(`src/styles/${file}`, "utf8");
await writeFile(`${OUT}/www/${file.replace(".css", ".src.css")}`, src);
const code = minifyCss(`www/${file}`, src);
const code = minifyCss(`src/styles/${file}`, src);
const out = `/*! minified at deploy - readable source: /${file.replace(".css", ".src.css")} */\n` + code;
await writeFile(`${OUT}/www/${file}`, out);
console.log(`${file}: ${src.length} -> ${out.length} bytes`);
Expand All @@ -1317,9 +1323,9 @@ for (const file of ["nav-run.css", "nav-tray.css", "infotip.css"]) {
// instead of embedding it eleven times. Keep the same readable-twin contract as
// luna.css: author the source directly, ship a small minified render-blocker.
{
const src = await readFile("www/lwe-base.css", "utf8");
const src = await readFile("src/styles/lwe-base.css", "utf8");
await writeFile(`${OUT}/www/lwe-base.src.css`, src);
const code = minifyCss("www/lwe-base.css", src);
const code = minifyCss("src/styles/lwe-base.css", src);
const out = `/*! minified at deploy - readable source: /lwe-base.src.css */\n` + code;
await writeFile(`${OUT}/www/lwe-base.css`, out);
console.log(`lwe-base.css: ${src.length} -> ${out.length} bytes (+ /lwe-base.src.css)`);
Expand Down
Loading
Loading