Files
zeekay 4fd349aa06 beta: the portal says less, and opting in and sharing are one press
Prose that carried no decision or fact is gone: the hero, the questions, the
gate and every step are a heading and at most a line. What scores is said once
(the leaderboard step), and every claim the cloud does not keep is out.

Step 1 is one share card (the member's link, Copy, the device's share sheet on
phones, seven channels as icons, Customize behind a text button) and a quiet
invite-by-email card. Step 3 is one searched, grouped list with one control a
row: On when `opens` says so, Get access when it does not, Requested at once
after the press. Stars and follows moved under the leaderboard as Earn more.

The 1,800-line dashboard is a shell over share, rank, betas and alpha; what
they read is one hook (standing.ts); the questions are data (program.ts).
Dead access, card, hint and referral components are deleted. Every press is
44px, every input too, and a gate walks each screen at 390px.

scripts/brands and scripts/prebuild are TypeScript now; the three marks the
share row draws ship in a JSON only /beta loads. /beta's title and card say
what the page says.

Claude-Session: https://claude.ai/code/session_017vrVus6PPBgP5YRzKV1iqW
2026-10-26 03:29:13 -07:00

54 lines
1.7 KiB
JavaScript

#!/usr/bin/env node
// What `next build` reads, regenerated before it runs.
//
// The first group each write files of their own and read none the others
// write, so they run at once: one after another they were 23 s of every
// deploy, most of it waiting on the network. The last three read what the
// first group wrote (the route tree's policy joins the catalog, and
// keep-stamps compares every snapshot), so they run after it, in order.
//
// Every script runs to its end before the build is refused, so one failure
// does not hide another.
import { spawn } from 'node:child_process'
import { existsSync } from 'node:fs'
const AT_ONCE = [
'gen-gui-css',
'rooms-assets',
'sync-mark',
'brands',
'zen',
'kai',
'coding',
'tools',
'sync-catalog',
'sync-models',
'sync-papers',
'sync-blog',
'sync-oss',
'sync-releases',
'sync-menu',
]
const AFTER = ['sync-rooms', 'sync-pages', 'keep-stamps']
// A script is TypeScript (`.ts`, run by Node's own type stripping) or a `.mjs` not yet converted.
const run = (name: string) =>
new Promise<string | null>((done) => {
spawn(process.execPath, [existsSync(`scripts/${name}.ts`) ? `scripts/${name}.ts` : `scripts/${name}.mjs`], { stdio: 'inherit' })
.on('error', (err) => done(`${name}: ${err.message}`))
.on('exit', (code, signal) => done(code === 0 ? null : `${name} exited ${signal ?? code}`))
})
const failed = (await Promise.all(AT_ONCE.map(run))).filter(Boolean)
if (failed.length) {
for (const f of failed) console.error(`prebuild: ${f}`)
process.exit(1)
}
for (const name of AFTER) {
const f = await run(name)
if (f) {
console.error(`prebuild: ${f}`)
process.exit(1)
}
}