Commit Graph

570 Commits

Author SHA1 Message Date
Christopher Monsanto
a282c8a643 Bring the data table generators into the repo
data/species.json and data/items.json were generated by scripts that
lived outside the tree, so nothing here recorded where the tables came
from or how to refresh them. Port both into tools/spritedata/, taking
the pokemon-showdown checkout as an argument instead of hardcoding an
absolute path.

Both reproduce the committed tables byte-identically against
pokemon-showdown f2fe71c87.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQicnpaee6kQXGG7uVExLS
2026-08-23 00:29:40 -04:00
Marty
6591abd406 Add Smogon Sprite Project's Gen 5-style sprites 2026-08-22 20:03:08 -04:00
Christopher Monsanto
ed199c3768 Move single-use rule sets to their call sites
rules/ exists so several deploys can declare the same rules; a set with
one caller is just indirection. Only gen10Modelslike has two (smogon xy/
and ps ani/), so it stays. The live sets move into assets.build.ts and
smogon.build.ts, and the three deprecated sets move into the commented-out
block that was their only reference, which empties minisprites.ts and
social.ts.

Declarations are copied verbatim, so no rule key moves: a full dry run
reports 7748 up to date, 0 would run, and all three deploy trees come out
byte-identical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQicnpaee6kQXGG7uVExLS
2026-08-21 01:13:16 -04:00
Christopher Monsanto
45adc3579f Make rule inputs source paths only
Nothing chains any more, so Input collapses to string and the machinery
that existed to order rules against each other goes with it: the
executor's demand graph and per-decl memo, the DryDirty sentinel, the
whole blocked outcome, the driver's producer closure, and inspect's
transitive-consumer fixpoint. What is left is a flat parallel sweep whose
only coupling is byte-identical declarations sharing one execution.

Every deploy's tree comes out byte-identical and every rule key is
unchanged: a full dry run reports 7748 up to date, 0 would run.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQicnpaee6kQXGG7uVExLS
2026-08-21 01:13:15 -04:00
Christopher Monsanto
327b2318d0 Fold the spritesheet webp into the sheet rule
The sheet's png fed a separate cwebp rule, the one place a rule output
was another rule's input. A third output plus %o1 says the same thing
in one rule; the published css and webp come out byte-identical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQicnpaee6kQXGG7uVExLS
2026-08-21 01:13:15 -04:00
Christopher Monsanto
b698ac882a Publish assets under their served prefix and name whole urls
The prefix a manifest value needs isn't knowable here: it lives in the
receiving home's services.toml, and the upload prepends it. So the two
guessed at each other and every reader carried a copy -- the forum's
SMOGON_XF_SPRITE_URL, the dex's hardcoded /__assets/sprites/.

Write the prefix on this side instead: everything served ships under
sprites/ in the tar, the upload rejects a tree that disagrees, and with
the tar path settled a manifest entry can be the whole url. Keys lose
their extension, since a url has nothing left to disambiguate. __meta/
stays at the tar root -- the upload diverts it out of the served tree.

The css pointer becomes spritesheet-css-url.txt, holding the url rather
than a suffix to paste onto one; the rename is deliberate, so a reader
of the old file fails instead of splicing a url into a prefix.

The minisprites webps go: 9d3e9abe shipped them speculatively in 2023
and nothing has read them or __meta/minisprites-hash.txt since, in any
repo. The dex draws minisprites from the spritesheet, and these are
named by PS id where it uses smogon aliases, so they never could have
lined up. newspritecopy() went with them, its only caller.

xy/ and xyicons/ keep the old shape: they ship by rsync and don't know
their url yet.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 01:13:15 -04:00
Christopher Monsanto
e3055ae3f5 Fold stamped copying into Manifest
The ctx is #private now; Manifest.copy(f, dest, name) owns the
hash-stamp-record-queue sequence (absorbing set()'s duplicate-key
check), and the sprite-name resolution in spritecopy/itemspritecopy
stays outside as free functions calling it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:15 -04:00
Christopher Monsanto
40bd3052f5 Make the deploy layer and tool I/O async
DeployCtx read/list/hash return promises (copy and write stay sync:
they only queue ops), the stamped copy helpers and buildfile deploy
blocks await them, ActionQueue materialization and packing use
fs/promises, and the CLI, config loaders, spritesheet writer, and
trim tool follow. Declaration-time globbing and the module-init data
reads stay sync: rules exist by the end of the import.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:15 -04:00
Christopher Monsanto
1d7e52ca29 Make the build core's file I/O async
hash and cas move to node:fs/promises: source reconciliation runs a
small worker pool over the stat cache, the executor's clean check
gathers CAS stats concurrently, and inserts/sweeps await their way
through. The sqlite store stays sync; that is all node:sqlite offers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:15 -04:00
Christopher Monsanto
b8d7aa50eb Replace non-null assertions with explicit checks
Parsers use charAt or check-and-throw; the executor gets a paired()
helper for its parallel arrays; matchSubsets returns {entry, matched}
pairs so the deploy loop stops indexing two arrays; spawn stdin and
pid get real guards.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:15 -04:00
Christopher Monsanto
dc2bff9738 Convert declarations to the house shapes
Interfaces become type aliases with comma members (extends becomes
intersection), and class privates use #names instead of the private
keyword.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:15 -04:00
Christopher Monsanto
73f5954407 Adopt the house import style
Node builtins come in as node:-prefixed namespace imports;
multi-symbol internal imports use short namespace aliases (artifact,
cas, subst, db, api, executor). Single-symbol pulls, types, and the
buildfile DSL names stay braced, matching the sanctioned exceptions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:14 -04:00
Christopher Monsanto
3ec1abad12 Write let instead of const
Per the house rule, const survives only where TypeScript hangs
behavior off the spelling: the <const T> type parameter in rule()
and the as const option tables.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:14 -04:00
Christopher Monsanto
ebbb5e6f2e Tighten formatting to the smogon.com house style
Annotation colons are tight (ternaries keep their spaces), plain
double-quoted strings become single-quoted, and .editorconfig comes
over verbatim. Rule cmd values are untouched; the sheet rules reran
once because their tool sources are declared deps, byte-identically.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:14 -04:00
Christopher Monsanto
3e87df43da Replace defineDeploy with free-floating deploy() blocks
deploy(ctx => ...) registers like rule() does, so a buildFile
co-locates each shipping block with the rules it ships instead of
one monolithic finish; the blocks run in registration order after
the build, sharing one output tree per module. The CLI slices the
registry across its sequential imports to know which blocks belong
to which file.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:14 -04:00
Christopher Monsanto
8f58cf3da0 Ship the smogon deploy through deploy.json5
The xy and xyicons rsyncs move from ad-hoc scripts (updatexyicons.sh
and the untracked syncdexani.sh) into dir-mode deploy entries;
deploy smogon replaces both.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:14 -04:00
Christopher Monsanto
dab5379faf Add a debug output mode to the deploy verb
deploy <names> -o <dir> materializes each entry's subset under
<dir>/<name>/<entry index>/ instead of running its command (tar
entries included), for eyeballing what would ship.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:14 -04:00
Christopher Monsanto
0a45fc92eb Drop unused debug and sprite-data deps
Nothing in tools/build or tools/deploy imports debug, and the
deploy package never imports sprite-data (its consumers live in
the root package, which declares it).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:14 -04:00
Christopher Monsanto
0711002c37 Drop make-promises-safe and better-sqlite3
Unhandled rejections crash Node by default since v15, and node:sqlite
covers the Store: readBigInts replaces defaultSafeIntegers, a manual
BEGIN/COMMIT helper replaces transaction(), busy detection keys on
errcode, and lookupRule normalizes the null-prototype rows. No native
build step remains (allowBuilds gone from the workspace).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:13 -04:00
Christopher Monsanto
c1dfaaec8c Replace commander with node's builtin parseArgs
The deploy CLI gets a hand-rolled verb dispatch over per-verb
parseArgs option tables and one usage text; trim and
smogdexspritesheet are plain parseArgs calls. tools/build only
listed the dep without importing it.

The smogdex sheet rule depends on its tool's source, so it reran
once; the rebuild was byte-identical (stamps unchanged).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:13 -04:00
Christopher Monsanto
561b7ba0fd Add a dir mode to deploy entries
An entry with dir: true materializes its subset into a temp
directory whose path replaces %d in the cmd, instead of piping a
tar on stdin -- rsync-style transports (the PS ani sync) need real
files. The flag and %d must agree, so a forgotten one is caught at
config load.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:13 -04:00
Christopher Monsanto
c56428fd9d Survive an upload command that rejects the tar
A dying consumer destroys the tar pack and its pending entry sinks,
each of which emits the EPIPE as an unhandled streamx error and
crashed the process before the child's exit code was reported. Keep
the pack and its sinks quiet; the command's exit code is the report.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:13 -04:00
Christopher Monsanto
989ffd54ce Make bare deploy list the configured deploys
Deploying is opt-in per name; with no names the verb prints each
deploy's buildFile and (subset, cmd) entries instead of shipping
everything.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:13 -04:00
Christopher Monsanto
167de94fe4 Drop the last vestiges of the __key convention
The upload command names the asset set on its command line now.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:13 -04:00
Christopher Monsanto
8bf512480a Replace the .env deploy command with deploy.json5
An untracked json5 config maps deploy names to a buildFile plus
(subset globs, cmd) entries: the deploy verb builds the named
buildFiles, finishes each, routes the outputs through the subset
globs, and pipes one tar per entry to its command. Every glob must
match an output and every output must be covered by some entry.

The tar no longer carries __key; the upload command names the asset
set itself (smogonctl assets upload sprites).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:13 -04:00
Christopher Monsanto
a3f4dada09 Rename the deploy modules to *.build.ts
They are the buildFiles the upcoming deploy config points at; "deploy"
now belongs to the config entries that ship their outputs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:13 -04:00
Christopher Monsanto
bc39c94851 Fix review findings in the content-addressed core
- casInsert verifies an existing object's bytes before trusting it, fsyncs
  before the rename, and the store records object sizes so a crash-truncated
  object reads as dirty instead of clean forever.
- The driver hashes sources over the producer closure, so partial builds
  (inspect) that pull in producers outside the demanded set work.
- Unknown executor errors are reported and abort the build instead of
  vanishing into allSettled.
- %b/%B expand to nominal names at declaration (never CAS basenames), which
  also puts name-dependence in the identity key; cmds are key-joined with
  NUL so a multi-line command cannot collide with split commands. This
  churns every rule key once.
- Rules must declare at least one output; output names reject shell-hostile
  characters.
- run --link copies read-only (CAS) sources instead of hardlinking 0444
  modes into deploy trees; ctx.list filters dotfiles and directories like
  the build-side glob; inspect resolves targets against the invoking cwd.
- The registry dedupes identical declarations (same cmds/inputs/deps/
  outputs/display), returning the existing artifacts, so shared rule sets
  are plain functions and memo() is gone; ps.deploy.ts no longer declares
  the gen5 gif set it never ships.
- rule() returns a tuple typed by its literal output list (single string
  output returns the Artifact directly), so destructuring needs no
  non-null assertions.
- Manifest is a class carrying the deploy ctx: set() rejects duplicate
  keys, write(dst) emits the sorted JSON, and spritecopy/itemspritecopy/
  stampcopy take just the manifest. The unstamped smogon sets (xyitems,
  fbsprites, twittersprites) are deprecated and commented out.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:12 -04:00
Christopher Monsanto
f6e0b189f3 Cut over to content-addressed deploys
pnpm build/deploy now run the umbrella CLI (build/deploy/run/inspect); the
fixed-name build/ tree, the old planner (rename detection, adopt, tamper
checks), and the vm deploy sandbox are gone. Also lands tools/deploy/api.ts
and the CLI, which earlier commits referenced but an overbroad local
gitignore pattern had silently excluded.

Migration: the store migrates the v1 db in place; build/ is dead and can be
deleted. A full rebuild repopulated .build/cas, and the old and new deploy
trees were diffed: byte-identical except the two multi-file hash pointers
(algorithm change), fb/twitter PNG re-encodes (pixel-identical; old outputs
predated current tool versions), and a stale 2023 orphan sprite the old
system never cleaned up.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:12 -04:00
Christopher Monsanto
499651b3f8 Strip PNG date chunks from magick outputs
date:create/date:modify tEXt chunks made rebuilds nondeterministic, which
would churn every content-addressed name.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:12 -04:00
Christopher Monsanto
460da484a1 Port the Buildfile and deploy scripts to co-located deploy modules
rules/ holds the shared sets (memoized) and the publish helpers that were
duplicated across the vm scripts; assets/smogon/ps .deploy.ts each declare
their rules and finish. The smogdex sheet is split into two chained rules,
retiring the undeclared spritesheet.png temp.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:12 -04:00
Christopher Monsanto
feb3166bbb Add the deploy finish API and umbrella CLI
makeCtx serves finish over the CAS and ActionQueue; cli.ts adds the
build/deploy/run/inspect verbs (unwired until cutover). Copy-mode
materialization chmods CAS-sourced files back to 0644.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:12 -04:00
Christopher Monsanto
6ba5c04b5e Add the demand-driven executor and build driver
Keys resolve after producers finish, so there is no upfront plan; identical
keys share one execution, failures block dependents, and GC (union builds
only) drops undeclared keys then sweeps the CAS.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:12 -04:00
Christopher Monsanto
58089f0231 Extract DSL helpers; add the content-addressed rule model
helpers.ts is a pure move out of api.ts; artifact.ts introduces
Artifact-returning rule()/forEachRule() with execution-time content keys.
The old api.ts machinery still powers Buildfile.ts until cutover.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:12 -04:00
Christopher Monsanto
4ec5574c34 Add the v2 rule store keyed by content identity
Keeps the v1 file_cache on migration; failures are never recorded, so
failed and never-ran are the same state.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:11 -04:00
Christopher Monsanto
71ecd991ba Add the content-addressed store (cas.ts)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:11 -04:00
Christopher Monsanto
d075d27885 Move BuildError to errors.ts
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:11 -04:00
Christopher Monsanto
11282e1002 Add indexed %oN output substitution
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:11 -04:00
Christopher Monsanto
a132276e78 Retire the wrappers superseded by pnpm deploy
updatepmdsprites.sh is gone entirely; updateminisprites.sh loses its
spritesheet/forumsprites/dex-suffix steps and becomes updatexyicons.sh.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:11 -04:00
Christopher Monsanto
dd2396719d Add pnpm deploy: pipe the assets tar to DEPLOY_COMMAND from .env
The deploy tool grows a deploy subcommand that runs the build, packs the
tar, and streams it to the command .env names. Packing now finalizes the
archive; without the end-of-archive marker, strict stream readers
(Python tarfile, hence smogonctl) die on truncation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:11 -04:00
Christopher Monsanto
41119f63a3 Split the hashed asset sets into assets.deploy.js
spritesheet, minisprites, pmd, and forumsprites now ship as a tar to the
__assets tree: __key leads the tar, and the mutable pointer files
(manifests, css suffix, minisprites hash) ride in __meta/ instead of
being published as immortal assets. xy and xyicons stay in
smogon.deploy.js on the rsync path for now.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:11 -04:00
Christopher Monsanto
997668ec2e Build dex spritesheet assets in the deploy script
Replaces the esbuild invocation that ran out of the smogon.com checkout:
the deploy script now stamps the webp, rewrites the css urls, and writes
the hashed css plus the suffix file that updateminisprites.sh ships to
/smog2/dex/spritesheet_css_suffix.txt. updateminisprites.sh no longer
depends on ~/smogon/smogon.com/run, esbuild, python, or zopfli/brotli
(css precompression dropped; to be handled separately). Minification is
also dropped (machine-generated css, ~same size compressed).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:10 -04:00
Christopher Monsanto
f772bf1357 Hash-stamp the pmd set
Same scheme as the other sets; pmd/manifest.json rides the
updatepmdsprites.sh rsync.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:10 -04:00
Christopher Monsanto
b6e70c2c41 Hash-stamp the xy dex animations set
Same scheme as forumsprites/xyicons; xy/manifest.json rides the
syncdexani.sh rsync.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:10 -04:00
Christopher Monsanto
db0f5bbd7a Hash-stamp forumsprites and xyicons, write url manifests
Deployed names become <alias>-<HASH>.png (sha256/base32/8, same format as
the existing minisprites dir hash) with a manifest.json per set mapping
the unhashed name to the hashed one, riding the existing rsyncs. Other
deploy sections are unchanged; alias collisions now error via the
manifest-key check since hashed destinations no longer collide.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 01:13:10 -04:00
Marty
56f2e8680d Update PS Pokemon spritesheet 2026-08-16 19:32:35 -04:00
Marty
6c5874c197 Update minisprites 2026-08-16 19:25:20 -04:00
Christopher Monsanto
2d1dd3a119 Replace build.sh with pnpm build; type-check is now pnpm check
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 22:47:10 -04:00
Christopher Monsanto
44fb49a96f Refresh stored rule template/display when their computed form drifts
They are outside the rule key, so a format change (like the one in the
previous commit) silently disabled rename detection for existing records.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 22:34:11 -04:00
Christopher Monsanto
2d83f4a16f Fix review findings in tools/build
- Verify rename sources against recorded stats at copy time; colliding
  rename destinations/sources fall back to running the rule
- Restrict rename detection to single-input, no-deps rules (sheet-style
  rules embed input names in output bytes)
- Include input extensions in the rename template (magick picks output
  format from extensions)
- Adopt only rules with no stored record, never known-dirty ones
- Skip dotfiles in glob (tup parity)
- Complete sheet dep closures (data/lib, lib/root)
- Validate --jobs; reject non-numeric values instead of silently no-oping
- Worker pool drains all workers before rethrowing; per-rule internal
  errors abort scheduling instead of racing db.close()
- SIGKILL all live process groups on second Ctrl-C
- Transactional loadStoredRules snapshot; dry run without existing state
  uses an in-memory db; idempotent DDL
- rule() rejects % placeholders in literal outputs

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 22:32:59 -04:00
Christopher Monsanto
02194b17f0 Remove tup: delete Lua build config, tupctime, and tup state
The build is now driven by tools/build (see Buildfile.ts). tupctime is
obsolete: the new tool hashes content behind a stat cache, so ctime/mtime
churn without content changes no longer causes rebuilds.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 22:09:51 -04:00