pixelkiln 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +92 -0
- package/LICENSE +21 -0
- package/NAMING.md +87 -0
- package/PROVIDERS.md +96 -0
- package/README.md +333 -0
- package/SECURITY.md +38 -0
- package/bin/pixelkiln.js +2 -0
- package/dist/cli.d.ts +47 -0
- package/dist/cli.js +5889 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +5129 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +2679 -0
- package/dist/index.d.ts +2679 -0
- package/dist/index.js +4990 -0
- package/dist/index.js.map +1 -0
- package/docs/AGENTS.md +64 -0
- package/docs/ARCHITECTURE.md +120 -0
- package/docs/ARTIFACTS.md +162 -0
- package/docs/CLI.md +248 -0
- package/docs/ENDPOINTS.md +344 -0
- package/docs/GENERATORS.md +170 -0
- package/docs/GETTING_STARTED.md +170 -0
- package/docs/LIBRARY.md +157 -0
- package/docs/MANIFEST.md +162 -0
- package/docs/QUALITY.md +107 -0
- package/docs/README.md +44 -0
- package/docs/RECOVERY.md +124 -0
- package/docs/TILES.md +118 -0
- package/examples/minimal/README.md +26 -0
- package/examples/minimal/pixelkiln.manifest.json +21 -0
- package/package.json +100 -0
- package/schema/manifest.schema.json +255 -0
- package/skills/pixelkiln/SKILL.md +51 -0
- package/skills/pixelkiln/agents/openai.yaml +5 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/types.ts","../src/client.ts","../src/provider.ts","../src/providers/pixellab.ts","../src/png.ts","../src/providers/fake.ts","../src/manifest.ts","../src/hash.ts","../src/lock.ts","../src/outputs.ts","../src/artifacts.ts","../src/pipeline/plan.ts","../src/pipeline/audit.ts","../src/pipeline/cache-health.ts","../src/cache.ts","../src/pipeline/pack.ts","../src/pipeline/tileset-export.ts","../src/pipeline/submit.ts","../src/pipeline/poll.ts","../src/pipeline/fetch.ts","../src/pipeline/doctor.ts","../src/pipeline/adopt.ts","../src/pick/sheet.ts","../src/pick/review-server.ts","../src/pick/server.ts","../src/pipeline/init.ts","../src/pipeline/salvage.ts","../src/pick/salvage-server.ts","../src/pick/salvage-sheet.ts"],"sourcesContent":["export * from \"./types.ts\"\nexport * from \"./client.ts\"\nexport * from \"./provider.ts\"\nexport { PixelLabProvider } from \"./providers/pixellab.ts\"\nexport { FakeProvider, FAKE_PNG, type FakeOptions } from \"./providers/fake.ts\"\nexport * from \"./manifest.ts\"\nexport * from \"./lock.ts\"\nexport * from \"./hash.ts\"\nexport * from \"./outputs.ts\"\nexport * from \"./artifacts.ts\"\nexport { buildPlan, summarize, type Plan, type PlanItem, type PlanState } from \"./pipeline/plan.ts\"\nexport * from \"./pipeline/audit.ts\"\nexport * from \"./pipeline/cache-health.ts\"\nexport * from \"./pipeline/pack.ts\"\nexport * from \"./pipeline/tileset-export.ts\"\nexport { submit, type SubmitOptions, type SubmitResult } from \"./pipeline/submit.ts\"\nexport { poll, type PollOptions, type PollResult } from \"./pipeline/poll.ts\"\nexport { fetchAssets, pushTags, type FetchResult } from \"./pipeline/fetch.ts\"\nexport { doctor, type DoctorCheck, type DoctorLevel, type DoctorOptions, type DoctorReport } from \"./pipeline/doctor.ts\"\nexport { adopt, tagAdopted, type AdoptResult } from \"./pipeline/adopt.ts\"\nexport { runPicker, type PickResult } from \"./pick/server.ts\"\nexport { renderSheet, type SheetGroup } from \"./pick/sheet.ts\"\nexport { scanAssets, buildManifest, pngSize, slugify, type ScannedAsset } from \"./pipeline/init.ts\"\nexport {\n loadClaims,\n findOrphans,\n matchOrphanStyle,\n groupOrphansByStyle,\n idFromPrompt,\n applyTags,\n type Orphan,\n type OrphanGroups,\n type SiblingManifest,\n type SalvageAction,\n} from \"./pipeline/salvage.ts\"\nexport { runSalvage, type SalvageResult } from \"./pick/salvage-server.ts\"\nexport { renderSalvageSheet } from \"./pick/salvage-sheet.ts\"\n","import { z } from \"zod\"\n\n/**\n * Which PixelLab endpoint produces the asset. The choice is mostly about cost,\n * and the gap is enormous — all figures measured against a live account.\n *\n * map POST /map-objects — THE DEFAULT.\n * A flat 1 generation at any size. Purpose-built for standalone props\n * with transparent backgrounds, which is what an icon or a prop is.\n * Arbitrary width x height. Returns exactly one result, so there is no\n * selection step: if you dislike it, re-roll for 1 more.\n *\n * 1dir POST /create-1-direction-object — 20-40 generations.\n * The single-facing sibling of create-8-direction-object, meant for\n * objects you may later want rotations or animations of. Square only.\n * Returns 4-64 candidates for its one fixed price, which is genuinely\n * useful when you want to compare options side by side — but at 40x the\n * cost of a map object, re-rolling a map object forty times is the same\n * money. Reach for this when you need rotations, or when the extra\n * rendering detail is worth 40x.\n *\n * Rule of thumb: if the asset is a standalone image and you are not going to\n * animate or rotate it, `map` is the right call. Generating 65 icons costs 65\n * generations that way and 2,600 the other.\n *\n * Not yet implemented, but measured and worth knowing (see README):\n * POST /create-image-pixflux also costs 1 generation, returns the image\n * INLINE with no polling, and accepts `color_image` — a forced palette that\n * constrains output to exact hex values. Verified: a four-colour Game Boy\n * swatch produced output containing precisely those four colours. The same\n * parameter on /map-objects returns a 500, so the palette lock is\n * pixflux-only. Its rendering is flatter than 1dir's.\n */\nexport const GeneratorSchema = z.enum([\"1dir\", \"map\", \"pixflux\", \"tiles\"])\nexport type Generator = z.infer<typeof GeneratorSchema>\n\n/** A decoded style reference ready for a provider-specific request body. */\nexport interface ResolvedStyleImage {\n base64: string\n width: number\n height: number\n format: \"png\" | \"jpeg\"\n}\n\n/**\n * `tiles` is the odd one out: the unit of work is a *set*, not a sprite.\n *\n * POST /create-tiles-pro draws tile shape outlines and fills them, returning\n * many variations from one call. Independent variations land in the same\n * review-then-pick flow as `1dir`; connectable features are structural sets\n * and every returned storage URL is retained. There is no select-frames step\n * to run for either form.\n *\n * Two properties make it worth a generator of its own rather than a flag on\n * `1dir`:\n *\n * - **Style mode overrides geometry.** Passing `styleImages` makes the API\n * copy tile shape and dimensions from the reference and ignore\n * `tileType`/`tileView` entirely. For an existing tileset that is the\n * point: it is the only way to land new art on the same ground plane as\n * the tiles already in the sheet.\n * - **`tileFeature` generates connectable sets.** `\"tileset\"` returns a\n * 16-tile Wang corner set for a terrain transition, `\"roads\"` an\n * 18-configuration path set. Those are structural outputs; a consumer\n * slices them by index, not by eye.\n */\n\n/**\n * Variations a `tiles` call returns. The API derives this from the tile size\n * and how many numbered descriptions the prompt contains; observed at 4 per\n * numbered description for 32px isometric tiles. Clamped so a prompt with no\n * numbering still reports at least one.\n */\nexport function tileVariationCount(descriptions: number): number {\n return Math.max(1, descriptions) * 4\n}\n\n/** Known structural output counts for connectable tile features. */\nexport function tileFeatureOutputCount(feature: string | undefined): number | null {\n if (feature === \"roads\") return 18\n if (feature === \"tileset\") return 16\n // PixelLab does not document a stable count for the building kit. Its\n // returned storage URLs remain authoritative at download time.\n return null\n}\n\n/**\n * Numbered items in a `tiles` prompt. The endpoint documents `\"1). grass\n * 2). dirt\"` as the way to control what comes back, and returns a group of\n * variations per number.\n */\nexport function countNumberedDescriptions(prompt: string): number {\n return (prompt.match(/\\d+\\s*\\)\\s*\\./g) ?? []).length\n}\n\n/** Candidate frames returned per call, derived from size. Extra candidates are free. */\nexport function candidateCount(size: number): number {\n if (size <= 42) return 64\n if (size <= 85) return 16\n if (size <= 170) return 4\n return 1\n}\n\n/**\n * Generation cost per call. Measured against a live account, not inferred.\n *\n * The two generators are priced completely differently, and the gap is wide\n * enough to change which one you should reach for:\n *\n * map FLAT 1 generation, any size. Verified: a 32x36 and a 64x96 map object\n * each cost exactly 1 (balance 4751 → 4750 → 4749). Single result.\n *\n * 1dir 20-40 by canvas tier (1K=20, 2K=25, 4K=40), returning 4-64\n * candidates for that one price.\n *\n * tiles 20-40 on the same canvas tiers as `1dir`, but the canvas is picked\n * from tile size x variation count rather than a single sprite, so a\n * small tile in a large set can still reach the top tier. Reported by\n * the API at submit time; estimated here from the widest canvas the\n * request can produce, which is the honest direction to be wrong in\n * for a `--budget` check.\n *\n * So `1dir` buys candidate variety at 20-40x the price, and `map` buys\n * arbitrary (non-square) dimensions nearly free. For a single-result asset,\n * forty re-rolls of a map object cost the same as one 1dir call.\n */\nexport function generationCost(\n width: number,\n height: number,\n generator: Generator = \"map\",\n): number {\n if (generator === \"map\" || generator === \"pixflux\") return 1\n const px = width * height\n if (px <= 1024) return 20\n if (px <= 2048) return 25\n return 40\n}\n\n/**\n * Cost of one `tiles` call. Same canvas tiers as `1dir`, but the canvas is the\n * sheet the API lays the variations out on, not one tile — so tile size alone\n * under-reads it badly (a 32px tile is 1024px on its own and would always\n * price at the floor).\n *\n * Estimated from tileSize^2 x variations, which is the area actually drawn.\n * `plan` prints this before anything is spent and `--budget` refuses on it, so\n * over-reading is the safe direction: a call that comes in cheaper than\n * budgeted is a pleasant surprise, one that comes in dearer is an overspend.\n */\nexport function tilesCost(tileSize: number, variations: number): number {\n const px = tileSize * tileSize * Math.max(1, variations)\n if (px <= 1024) return 20\n if (px <= 2048) return 25\n return 40\n}\n\nconst StyleImageSchema = z.object({\n /** Path to a PNG/JPEG, relative to the manifest file. Max 256x256. */\n path: z.string(),\n})\n\nexport const StyleSchema = z\n .object({\n // `map` is the default because it is 20-40x cheaper and correct for any\n // asset that is not going to be rotated or animated.\n generator: GeneratorSchema.default(\"map\"),\n /** Square edge length for `1dir`. 32-256. */\n size: z.number().int().min(32).max(256).optional(),\n view: z.string().optional(),\n /** Appended to every asset prompt in this style. Where the look is defined. */\n promptSuffix: z.string().default(\"\"),\n /** Prepended to every asset prompt in this style. */\n promptPrefix: z.string().default(\"\"),\n /** Style reference images. */\n styleImages: z.array(StyleImageSchema).default([]),\n /** Output root for this style, relative to the manifest. */\n outDir: z.string(),\n /** `map` generator only. */\n outline: z.string().optional(),\n shading: z.string().optional(),\n detail: z.string().optional(),\n /**\n * `tiles` generator only. Edge length of one tile, 16-256.\n *\n * Ignored when `styleImages` is set — style mode takes the tile's shape\n * and dimensions from the reference image, which is the whole reason to\n * use it against an existing sheet.\n */\n tileSize: z.number().int().min(16).max(256).optional(),\n /** `tiles` generator only. Defaults to the API's `isometric`. */\n tileType: z\n .enum([\"hex\", \"hex_pointy\", \"isometric\", \"oblique\", \"octagon\", \"square_topdown\"])\n .optional(),\n /** `tiles` generator only. Defaults to the API's `low top-down`. */\n tileView: z.enum([\"top-down\", \"high top-down\", \"low top-down\", \"side\"]).optional(),\n /**\n * `tiles` generator only. Asks for a connectable set instead of\n * independent variations:\n *\n * roads 18-configuration path set\n * tileset 16-tile Wang corner set for a terrain transition — describe\n * the asset as the transition itself (\"fairway grass to rough\n * meadow\"), not as one terrain\n * building floor/wall/doorway construction kit\n *\n * A consumer slices these by index, so the order the API returns them in\n * is load-bearing; do not sort a connectable set by anything else.\n */\n tileFeature: z.enum([\"roads\", \"tileset\", \"building\"]).optional(),\n /**\n * `tiles` generator only. How tile edges are drawn.\n *\n * The API default is `outline`, which draws a dark border around every\n * tile. That is right for tiles meant to read as discrete objects and\n * wrong for ground: laid on a grid, the per-tile borders turn a continuous\n * surface into visible quilting, with a dark seam at every cell edge.\n * `segmentation` omits them and the same set tiles seamlessly.\n *\n * Measured on a fairway-to-rough terrain set — the difference decided\n * whether the art was usable at all, so it is worth setting deliberately\n * rather than inheriting.\n */\n outlineMode: z.enum([\"outline\", \"segmentation\"]).optional(),\n /**\n * `pixflux` only. Whether to strip the generated background.\n *\n * Defaults to true, which is right for the sprites this tool was built\n * for — a prop or an icon wants to sit on whatever is behind it. It is\n * wrong for anything that IS a scene: a cover banner, a splash, a\n * backdrop. The API's own default is false; forcing it true unconditionally\n * meant a full-bleed image came back as a small subject floating in a\n * mostly-empty frame, and prose asking for an \"opaque background\" does not\n * override it.\n */\n noBackground: z.boolean().default(true),\n /** Fixed seed for reproducibility where the endpoint supports it. */\n seed: z.number().int().optional(),\n /**\n * Forced palette, as `#rrggbb` values. `pixflux` only.\n *\n * Unlike prose, this is a hard constraint — the API is handed a swatch\n * image and the output is limited to those colours. Verified: a four-colour\n * Game Boy palette produced output containing exactly those four values.\n * Prose asking for the same thing does not reliably hold, which is why the\n * map-generated monochrome sets came back with a yellow star and a brown\n * chocolate bar.\n */\n palette: z\n .array(z.string().regex(/^#?[0-9a-f]{6}$/i, \"expected a six-digit hex colour\"))\n .default([]),\n /**\n * Composites this style's assets into declared cells of a sheet, rather\n * than letting `pack` derive a layout. Use it when the atlas coordinates\n * are already load-bearing somewhere else — a tile engine naming tiles by\n * cell, or saved data storing cell indices — since `pack`'s id-sorted grid\n * moves every position when an asset is added or renamed.\n *\n * Assets in a mounted style declare their own `cell`; ones that do not are\n * left out of the sheet.\n */\n mount: z\n .object({\n /**\n * Existing sheet to composite into, relative to the manifest. Every\n * pixel outside a declared cell survives byte-for-byte, so a\n * hand-authored sheet can be part generated and part drawn. Omit to\n * start from transparent.\n */\n base: z.string().optional(),\n cellWidth: z.number().int().positive(),\n cellHeight: z.number().int().positive(),\n /** Where the composited sheet is written, relative to the manifest. */\n out: z.string(),\n })\n .strict()\n .optional(),\n /** Tags applied to every object generated in this style, for server-side filtering. */\n tags: z.array(z.string()).default([]),\n })\n .strict()\n /**\n * The API rejects a connectable set combined with style tiles:\n * \"Connectable features (roads/tileset/building) cannot be combined with\n * style tiles\". Catching it here means `plan` reports it for free rather\n * than a `submit` discovering it after the run has started — and the two\n * are individually the best reasons to use this generator, so reaching for\n * both at once is an easy mistake to make.\n */\n .refine((s) => !(s.tileFeature && s.styleImages.length), {\n message:\n \"tileFeature and styleImages cannot be combined — a connectable set \" +\n \"derives its own tile geometry, so remove one or the other\",\n path: [\"tileFeature\"],\n })\n\nexport const AssetSchema = z\n .object({\n /** The subject. Style wrapping comes from the style's prefix/suffix. */\n prompt: z.string(),\n /** Subdirectory under the style's outDir. Optional. */\n category: z.string().optional(),\n /** Overrides the style default. `map` generator only. */\n width: z.number().int().min(16).max(400).optional(),\n height: z.number().int().min(16).max(400).optional(),\n /** Overrides the style default. `1dir` generator only. */\n size: z.number().int().min(32).max(256).optional(),\n /** Explicit output path relative to outDir. Defaults to `<category>/<id>.png`. */\n file: z.string().optional(),\n /**\n * Grid cell this asset owns in a mounted style, as [column, row].\n *\n * Declared rather than derived, which is the point of `mount`: the\n * coordinate is a contract with whatever already reads the sheet, so it\n * must not move when the asset set changes. Assets without one are left\n * out of the mounted sheet.\n */\n cell: z.tuple([z.number().int().min(0), z.number().int().min(0)]).optional(),\n /**\n * Path, relative to the manifest, of the art that goes on a mounted\n * sheet — when that is not the raw generated output.\n *\n * `mount` otherwise takes its pixels from the lockfile, which records\n * what the API returned. That is the wrong file whenever the art needs a\n * step pixelkiln does not perform: a palette reduction onto a sheet's\n * closed palette, a hand touch-up, an alignment shift. Without somewhere\n * to say so, the choice is to mount the unprocessed art or to abandon\n * `mount` and composite by hand — and the hand-composited sheet is\n * exactly the unreproducible artifact `mount` exists to replace.\n *\n * An asset with a `source` needs no lockfile entry at all, so art\n * generated outside pixelkiln can still be placed by cell alongside art\n * that wasn't. `prompt` still records what was asked for.\n */\n source: z.string().optional(),\n /**\n * Generated output role to place in `cell` when this asset expands to\n * several files. Omit for ordinary single-output assets. A structural set\n * is otherwise ambiguous and `mount` refuses to guess by taking index zero.\n */\n outputRole: z.string().min(1).optional(),\n tags: z.array(z.string()).default([]),\n /** Restrict this asset to specific styles. Empty means all styles. */\n styles: z.array(z.string()).default([]),\n /**\n * Per-style replacement for `prompt`, keyed by style id.\n *\n * A style can need different wording rather than different styling. A\n * monochrome style is the clear case: prompts that name colours\n * (\"green purple gold\", \"colorful rainbow\") override the palette\n * instruction and survive into the output, while the same prompt is\n * exactly right for a colour style. Editing the shared prompt to suit one\n * style would invalidate every other style's already-generated art.\n */\n promptByStyle: z.record(z.string()).default({}),\n })\n .strict()\n\nexport const ManifestSchema = z\n .object({\n $schema: z.string().optional(),\n name: z.string(),\n styles: z.record(StyleSchema),\n assets: z.record(AssetSchema),\n })\n .strict()\n\nexport type Manifest = z.infer<typeof ManifestSchema>\nexport type Style = z.infer<typeof StyleSchema>\nexport type Asset = z.infer<typeof AssetSchema>\n\n/**\n * One line of the lockfile: the mapping from a spec to the PixelLab object that\n * satisfies it and the file on disk that came from it. This is the record that\n * did not exist before — without it, generated objects and downloaded files are\n * two unrelated piles.\n */\nexport const LockEntrySchema = z.object({\n styleId: z.string(),\n assetId: z.string(),\n /** sha256 of the resolved spec. Changing a prompt/size/style invalidates it. */\n specHash: z.string(),\n generator: GeneratorSchema,\n /** Connectable tiles must remain multi-output even when polling is resumed later. */\n tileFeature: z.string().nullable().default(null),\n /** The resolved prompt actually sent, kept for auditing and for adopt matching. */\n prompt: z.string(),\n width: z.number().int(),\n height: z.number().int(),\n\n /** Set at submit time, before the request is awaited, so a crash is recoverable. */\n jobId: z.string().nullable().default(null),\n /** For `1dir`: the multi-candidate parent object awaiting selection. */\n reviewObjectId: z.string().nullable().default(null),\n /** The chosen candidate's own object id, once selected. */\n objectId: z.string().nullable().default(null),\n candidateIndex: z.number().int().nullable().default(null),\n\n status: z\n .enum([\n \"pending\",\n \"processing\",\n \"review\",\n \"selected\",\n \"downloaded\",\n \"download-failed\",\n \"failed\",\n ])\n .default(\"pending\"),\n error: z.string().nullable().default(null),\n\n sourceUrl: z.string().nullable().default(null),\n /** Every source in a structural multi-output result, in provider order. */\n sourceUrls: z\n .array(\n z.object({\n url: z.string(),\n role: z.string().optional(),\n }),\n )\n .default([]),\n\n /**\n * Files this entry produced. A plain object generates one; asset kinds that\n * expand into many — an animated character is ~35 spritesheets plus an engine\n * resource — need the list, which is why v1's single `file` became this.\n *\n * `role` labels non-primary artifacts (e.g. \"portrait\", \"spriteframes\") so a\n * consumer can find the one it wants without pattern-matching on paths.\n */\n outputs: z\n .array(\n z.object({\n path: z.string(),\n sha256: z.string(),\n role: z.string().optional(),\n }),\n )\n .default([]),\n\n /**\n * Provider-owned data retained for downstream consumers, namespaced by\n * provider id. PixelLab connectable sets keep their exact `tileRules` here\n * so exporters can map images to adjacency rules.\n */\n providerMetadata: z.record(z.record(z.unknown())).default({}),\n\n submittedAt: z.string().nullable().default(null),\n downloadedAt: z.string().nullable().default(null),\n /** Successful-submission estimate in `costUnit`; may be fractional USD. */\n cost: z.number().finite().nonnegative().default(0),\n /** Unit for `cost`. Defaults preserve pre-unit PixelLab lockfiles. */\n costUnit: z.enum([\"generations\", \"usd\", \"free\"]).default(\"generations\"),\n /** Which provider produced this. Absent on entries written before providers. */\n provider: z.string().default(\"pixellab\"),\n})\n\nexport const LockSchema = z.object({\n version: z.literal(2),\n entries: z.record(LockEntrySchema),\n})\n\nexport type LockEntry = z.infer<typeof LockEntrySchema>\nexport type Lock = z.infer<typeof LockSchema>\nexport type LockOutput = LockEntry[\"outputs\"][number]\n\n/**\n * Parses a lockfile, rejecting anything that is not v2.\n *\n * There is deliberately no migration path. Both consuming projects were\n * onboarded after v2 landed, so a v1 file would be a corruption or a\n * hand-edit rather than a legacy artifact — better to fail loudly than to\n * quietly reinterpret it.\n */\nexport function parseLock(raw: unknown): Lock {\n const parsed = LockSchema.safeParse(raw)\n if (parsed.success) return parsed.data\n throw new Error(\n `Lockfile is not valid v2:\\n${parsed.error.issues\n .slice(0, 5)\n .map((i) => ` ${i.path.join(\".\")}: ${i.message}`)\n .join(\"\\n\")}`,\n )\n}\n\n/** The file a consumer means when it says \"the asset\" — the first output. */\nexport function primaryOutput(entry: LockEntry): LockOutput | null {\n return entry.outputs.find((o) => !o.role) ?? entry.outputs[0] ?? null\n}\n\n/** Lock entries are keyed `<styleId>/<assetId>`, which makes styles a namespace. */\nexport function lockKey(styleId: string, assetId: string): string {\n return `${styleId}/${assetId}`\n}\n\n/** A manifest entry resolved against its style — everything needed to generate. */\nexport interface ResolvedSpec {\n /** Absolute directory containing the manifest; excluded from the spec hash. */\n root: string\n styleId: string\n assetId: string\n generator: Generator\n prompt: string\n width: number\n height: number\n view: string\n size: number\n styleImagePaths: string[]\n outFile: string\n /**\n * Manifest-relative path of committed art that stands in for generated\n * output; excluded from the spec hash. Set only when the asset declares\n * `source`, which also means it needs no lock entry.\n */\n source?: string\n tags: string[]\n specHash: string\n cost: number\n costUnit: \"generations\" | \"usd\" | \"free\"\n candidates: number\n outline?: string\n shading?: string\n detail?: string\n seed?: number\n /** Forced palette hex values; empty unless the style sets one. */\n palette: string[]\n /** `pixflux` only — strip the generated background. Defaults to true. */\n noBackground: boolean\n /** `tiles` generator only — see StyleSchema for what each one means. */\n tileSize?: number\n tileType?: string\n tileView?: string\n tileFeature?: string\n outlineMode?: string\n}\n","import type { ResolvedStyleImage } from \"./types.ts\"\nimport { z } from \"zod\"\n\n/**\n * PixelLab REST client.\n *\n * Verified against https://api.pixellab.ai/v2/openapi.json. Every endpoint used\n * here was exercised against a live account before being written, so the shapes\n * are observed rather than assumed.\n *\n * Notably this needs no LLM and no MCP client — it is ordinary HTTP.\n */\n\nconst BASE = process.env.PIXELLAB_API_BASE ?? \"https://api.pixellab.ai/v2\"\n\nexport const MAX_RETRIES = 4\nexport const MAX_DOWNLOAD_BYTES = 64 * 1024 * 1024\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))\n\nexport function shouldRetry(status: number): boolean {\n return status === 429 || status === 408 || status >= 500\n}\n\n/** Exponential backoff with jitter, so parallel workers don't retry in lockstep. */\nexport function backoffMs(attempt: number): number {\n const base = Math.min(1000 * 2 ** attempt, 16_000)\n return base + Math.floor(Math.random() * 400)\n}\n\n/** Supports both Retry-After forms: seconds and an HTTP date. */\nexport function retryAfterMs(value: string | null, now = Date.now()): number | null {\n if (!value) return null\n const seconds = Number(value)\n if (Number.isFinite(seconds) && seconds >= 0) return seconds * 1000\n const date = Date.parse(value)\n if (!Number.isFinite(date)) return null\n return Math.max(0, date - now)\n}\n\nexport interface Balance {\n usd: number\n generations: number\n total: number\n plan: string\n}\n\nexport interface PixelLabObject {\n id: string\n name: string | null\n prompt: string\n size: { width: number; height: number }\n directions: number\n created_at: string\n view: string | null\n preview_url?: string | null\n rotation_urls?: Record<string, string | null> | null\n /** Populated only while status === \"review\". Index order is what select-frames expects. */\n frame_urls?: string[] | null\n tags: string[]\n status: string | null\n progress_percent?: number | null\n eta_seconds?: number | null\n}\n\n/**\n * A tiles-pro job. Unlike an object or a map object there is no `status`\n * field: GET /tiles-pro/{id} answers 423 while the set is still drawing and\n * 200 with `storage_urls` once it is done, so the HTTP code IS the status.\n */\nexport interface TilesPro {\n /** Keyed `tile_0`, `tile_1`, ... Index order is load-bearing for a\n * connectable set (`tile_feature`), where a consumer slices by index. */\n storage_urls: Record<string, string>\n kind: string | null\n tile_rules?: Record<string, unknown> | null\n}\n\nexport interface MapObject {\n object_id: string\n status: string\n description: string | null\n width: number | null\n height: number | null\n download_url: string | null\n}\n\nconst BalanceResponseSchema = z\n .object({\n credits: z.object({ usd: z.number() }).passthrough(),\n subscription: z\n .object({\n generations: z.number(),\n total: z.number(),\n plan: z.string().nullable().optional(),\n })\n .passthrough(),\n })\n .passthrough()\n\nconst ObjectSubmitSchema = z\n .object({\n background_job_id: z.string().min(1),\n object_id: z.string().min(1),\n status: z.string().default(\"queued\"),\n n_frames: z.number().int().min(0),\n })\n .passthrough()\nconst MapSubmitSchema = z\n .object({\n background_job_id: z.string().min(1),\n object_id: z.string().min(1),\n status: z.string().default(\"processing\"),\n })\n .passthrough()\nconst TilesSubmitSchema = z\n .object({\n tile_id: z.string().min(1),\n background_job_id: z.string().min(1),\n status: z.literal(\"processing\").default(\"processing\"),\n })\n .passthrough()\nconst TilesProSchema = z\n .object({\n storage_urls: z.record(z.string()),\n kind: z.string().nullable().default(null),\n tile_rules: z.record(z.unknown()).nullable().optional(),\n })\n .passthrough()\nconst PixelLabObjectSchema = z\n .object({\n id: z.string().min(1),\n name: z.string().nullable().default(null),\n prompt: z.string().default(\"\"),\n size: z.object({ width: z.number().int().positive(), height: z.number().int().positive() }),\n directions: z.number().default(0),\n created_at: z.string(),\n view: z.string().nullable().default(null),\n preview_url: z.string().nullable().optional(),\n rotation_urls: z.record(z.string().nullable()).nullable().optional(),\n frame_urls: z.array(z.string()).nullable().optional(),\n tags: z.array(z.string()).default([]),\n status: z.string().nullable().default(null),\n progress_percent: z.number().nullable().optional(),\n eta_seconds: z.number().nullable().optional(),\n })\n .passthrough()\nconst MapObjectSchema = z\n .object({\n object_id: z.string().min(1),\n status: z.string(),\n description: z.string().nullable().default(null),\n width: z.number().nullable().default(null),\n height: z.number().nullable().default(null),\n download_url: z.string().nullable().default(null),\n })\n .passthrough()\nconst ObjectListSchema = z\n .object({ objects: z.array(PixelLabObjectSchema), total: z.number().int().min(0) })\n .passthrough()\nconst PixfluxResponseSchema = z\n .object({ image: z.object({ base64: z.string().min(1) }).passthrough(), usage: z.unknown().optional() })\n .passthrough()\nconst SelectFramesSchema = z.object({ created_object_ids: z.array(z.string()) }).passthrough()\n\nfunction validateResponse<S extends z.ZodTypeAny>(\n schema: S,\n raw: unknown,\n operation: string,\n): z.output<S> {\n const parsed = schema.safeParse(raw)\n if (parsed.success) return parsed.data\n const issues = parsed.error.issues\n .slice(0, 4)\n .map((i) => `${i.path.join(\".\") || \"response\"}: ${i.message}`)\n .join(\"; \")\n throw new Error(`Invalid PixelLab response for ${operation}: ${issues}`)\n}\n\nexport class PixelLabError extends Error {\n constructor(\n message: string,\n readonly status: number,\n readonly body: string,\n ) {\n super(message)\n this.name = \"PixelLabError\"\n }\n}\n\nexport class PixelLabClient {\n constructor(\n private readonly apiKey: string,\n private readonly timeoutMs = 120_000,\n ) {\n if (!apiKey) throw new Error(\"PIXELLAB_API_KEY is required\")\n }\n\n /**\n * Retries only what is safe to retry: transport failures, 429, and 5xx.\n * A 4xx other than 429 is a bad request and retrying it just wastes time.\n *\n * POSTs that create objects are included, which is a deliberate trade: the\n * failure mode of not retrying (a dropped asset in a 65-item run) is more\n * common than the failure mode of retrying (a duplicate object), and a\n * duplicate is visible and free to delete whereas a silent gap is neither.\n */\n private async request<T>(path: string, init?: RequestInit, attempt = 0): Promise<T> {\n const auth = this.apiKey.startsWith(\"Bearer \") ? this.apiKey : `Bearer ${this.apiKey}`\n let res: Response\n try {\n res = await fetch(`${BASE}${path}`, {\n ...init,\n signal: init?.signal ?? AbortSignal.timeout(this.timeoutMs),\n headers: {\n Authorization: auth,\n \"Content-Type\": \"application/json\",\n ...(init?.headers ?? {}),\n },\n })\n } catch (err) {\n if (attempt < MAX_RETRIES) {\n await sleep(backoffMs(attempt))\n return this.request<T>(path, init, attempt + 1)\n }\n throw err\n }\n\n if (!res.ok && shouldRetry(res.status) && attempt < MAX_RETRIES) {\n // Honour Retry-After when the server sends one; it knows better than we do.\n const waitMs = retryAfterMs(res.headers.get(\"retry-after\")) ?? backoffMs(attempt)\n await sleep(waitMs)\n return this.request<T>(path, init, attempt + 1)\n }\n\n const text = await res.text()\n if (!res.ok) {\n throw new PixelLabError(`${init?.method ?? \"GET\"} ${path} → ${res.status}`, res.status, text)\n }\n if (!text) return {} as T\n try {\n return JSON.parse(text) as T\n } catch {\n throw new Error(`${init?.method ?? \"GET\"} ${path} returned invalid JSON`)\n }\n }\n\n async balance(): Promise<Balance> {\n const raw = validateResponse(BalanceResponseSchema, await this.request<unknown>(\"/balance\"), \"balance\")\n return {\n usd: raw.credits?.usd ?? 0,\n generations: raw.subscription?.generations ?? 0,\n total: raw.subscription?.total ?? 0,\n plan: raw.subscription?.plan ?? \"unknown\",\n }\n }\n\n /**\n * Square objects that persist indefinitely.\n *\n * `size` and `styleImages` are mutually exclusive at the API level: when style\n * images are supplied the largest one dictates the output size. So style\n * references must already be at the target resolution — a 128px reference\n * silently produces 128px output and a different candidate count.\n */\n async create1Direction(args: {\n description: string\n size?: number\n view?: string\n styleImages?: ResolvedStyleImage[]\n itemDescriptions?: string[]\n }): Promise<{ object_id: string; status: string; n_frames: number }> {\n const body: Record<string, unknown> = { description: args.description }\n if (args.styleImages?.length) {\n body.style_images = args.styleImages.map(({ base64, format }) => ({\n type: \"base64\",\n base64,\n format,\n }))\n } else if (args.size != null) {\n body.size = args.size\n }\n if (args.view) body.view = args.view\n if (args.itemDescriptions?.length) body.item_descriptions = args.itemDescriptions\n const raw = await this.request<unknown>(\"/create-1-direction-object\", {\n method: \"POST\",\n body: JSON.stringify(body),\n })\n const parsed = validateResponse(ObjectSubmitSchema, raw, \"create-1-direction-object\")\n return parsed\n }\n\n /**\n * Arbitrary width x height. Returns a single result — no selection step.\n *\n * These AUTO-DELETE AFTER 8 HOURS, so `fetch` must run in the same session as\n * `submit`. The pipeline warns when a map-object entry is older than that.\n */\n async createMapObject(args: {\n description: string\n width: number\n height: number\n view?: string\n outline?: string\n shading?: string\n detail?: string\n seed?: number\n }): Promise<{ object_id: string; status: string }> {\n const body: Record<string, unknown> = {\n description: args.description,\n image_size: { width: args.width, height: args.height },\n }\n if (args.view) body.view = args.view\n if (args.outline) body.outline = args.outline\n if (args.shading) body.shading = args.shading\n if (args.detail) body.detail = args.detail\n if (args.seed != null) body.seed = args.seed\n return validateResponse(\n MapSubmitSchema,\n await this.request<unknown>(\"/map-objects\", { method: \"POST\", body: JSON.stringify(body) }),\n \"create map object\",\n )\n }\n\n /**\n * Draws a whole tile set in one call — many variations, or a connectable\n * set when `tileFeature` is given.\n *\n * `styleImages` here is NOT the shape `create-1-direction-object` uses.\n * TilesProStyleImage is flat — `{base64, width, height}`, all three\n * required — where 1dir wants `{type, base64, format}`. Confirmed against\n * the OpenAPI schema; sending 1dir's shape is rejected as an extra field.\n *\n * Passing style images also makes the API ignore `tileType` and `tileView`\n * and copy the reference's tile geometry instead.\n */\n async createTilesPro(args: {\n description: string\n tileSize?: number\n tileType?: string\n tileView?: string\n tileFeature?: string\n outlineMode?: string\n seed?: number\n styleImages?: { base64: string; width: number; height: number }[]\n }): Promise<{ tile_id: string; background_job_id: string; status: string }> {\n const body: Record<string, unknown> = { description: args.description }\n if (args.tileSize != null) body.tile_size = args.tileSize\n if (args.tileType) body.tile_type = args.tileType\n if (args.tileView) body.tile_view = args.tileView\n if (args.tileFeature) body.tile_feature = args.tileFeature\n if (args.outlineMode) body.outline_mode = args.outlineMode\n if (args.seed != null) body.seed = args.seed\n if (args.styleImages?.length) body.style_images = args.styleImages\n return validateResponse(\n TilesSubmitSchema,\n await this.request<unknown>(\"/create-tiles-pro\", { method: \"POST\", body: JSON.stringify(body) }),\n \"create tiles\",\n )\n }\n\n /** Throws PixelLabError(423) while the set is still drawing — see TilesPro. */\n async getTilesPro(tileId: string): Promise<TilesPro> {\n return validateResponse(\n TilesProSchema,\n await this.request<unknown>(`/tiles-pro/${tileId}`),\n \"get tiles\",\n )\n }\n\n /**\n * Synchronous single-image generation. Returns the PNG inline rather than a\n * job id, and is the only endpoint that honours a forced palette —\n * `color_image` on /map-objects returns a 500 whatever the payload shape.\n */\n async createImagePixflux(args: {\n description: string\n width: number\n height: number\n noBackground?: boolean\n paletteSwatchBase64?: string\n seed?: number\n }): Promise<{ png: Buffer; usage: unknown }> {\n const body: Record<string, unknown> = {\n description: args.description,\n image_size: { width: args.width, height: args.height },\n no_background: args.noBackground ?? true,\n }\n if (args.paletteSwatchBase64) {\n body.color_image = { type: \"base64\", base64: args.paletteSwatchBase64, format: \"png\" }\n }\n if (args.seed != null) body.seed = args.seed\n\n const res = validateResponse(\n PixfluxResponseSchema,\n await this.request<unknown>(\"/create-image-pixflux\", {\n method: \"POST\",\n body: JSON.stringify(body),\n }),\n \"create pixflux image\",\n )\n const b64 = res.image.base64\n return { png: Buffer.from(b64, \"base64\"), usage: res.usage }\n }\n\n async getObject(objectId: string): Promise<PixelLabObject> {\n return validateResponse(\n PixelLabObjectSchema,\n await this.request<unknown>(`/objects/${objectId}`),\n \"get object\",\n )\n }\n\n async getMapObject(objectId: string): Promise<MapObject> {\n return validateResponse(\n MapObjectSchema,\n await this.request<unknown>(`/map-objects/${objectId}`),\n \"get map object\",\n )\n }\n\n async listObjects(limit = 50, offset = 0): Promise<{ objects: PixelLabObject[]; total: number }> {\n return validateResponse(\n ObjectListSchema,\n await this.request<unknown>(`/objects?limit=${limit}&offset=${offset}`),\n \"list objects\",\n )\n }\n\n /** Walks the whole account. Used by `adopt` to reconcile orphaned objects. */\n async *iterateObjects(pageSize = 100): AsyncGenerator<PixelLabObject> {\n let offset = 0\n for (;;) {\n const page = await this.listObjects(pageSize, offset)\n for (const obj of page.objects) yield obj\n offset += page.objects.length\n if (page.objects.length === 0 || offset >= page.total) return\n }\n }\n\n /**\n * Promotes chosen candidates to standalone objects, each with its own id.\n * The review parent survives until nothing is left in it, so the returned\n * `created_object_ids` — not the parent id — is what should be recorded.\n */\n async selectFrames(\n objectId: string,\n indices: number[],\n commonTag?: string,\n ): Promise<{ created_object_ids?: string[] }> {\n const raw = await this.request<unknown>(`/objects/${objectId}/select-frames`, {\n method: \"POST\",\n body: JSON.stringify(commonTag ? { indices, common_tag: commonTag } : { indices }),\n })\n return validateResponse(SelectFramesSchema, raw, \"select frames\")\n }\n\n /** Irreversible. Only reached via `purge`, behind an explicit confirmation. */\n deleteObject(objectId: string): Promise<unknown> {\n return this.request(`/objects/${objectId}`, { method: \"DELETE\" })\n }\n\n dismissReview(objectId: string): Promise<unknown> {\n return this.request(`/objects/${objectId}/dismiss-review`, { method: \"POST\" })\n }\n\n /** Free and synchronous. Replaces the full tag set — include tags you want to keep. */\n setTags(objectId: string, tags: string[]): Promise<unknown> {\n return this.request(`/objects/${objectId}/tags`, { method: \"PATCH\", body: JSON.stringify({ tags }) })\n }\n\n /** Storage URLs are public; no auth header, and sending one can break the CDN request. */\n async download(url: string): Promise<Buffer> {\n const res = await fetch(url, { signal: AbortSignal.timeout(this.timeoutMs) })\n if (!res.ok) throw new PixelLabError(`download ${url} → ${res.status}`, res.status, \"\")\n const declared = Number(res.headers.get(\"content-length\"))\n if (Number.isFinite(declared) && declared > MAX_DOWNLOAD_BYTES) {\n throw new Error(`download ${url} exceeds the ${MAX_DOWNLOAD_BYTES}-byte safety limit`)\n }\n const buf = Buffer.from(await res.arrayBuffer())\n if (buf.length > MAX_DOWNLOAD_BYTES) {\n throw new Error(`download ${url} exceeds the ${MAX_DOWNLOAD_BYTES}-byte safety limit`)\n }\n return buf\n }\n}\n\nexport function clientFromEnv(): PixelLabClient {\n const key = process.env.PIXELLAB_API_KEY\n if (!key) {\n throw new Error(\n \"PIXELLAB_API_KEY is not set.\\n\" +\n \"Looked in the environment, and in .env.local / .env beside the manifest and in the current directory.\",\n )\n }\n return new PixelLabClient(key)\n}\n","import type { Generator, ResolvedSpec, ResolvedStyleImage } from \"./types.ts\"\n\n/**\n * What a provider charges in. Cost is not universally \"generations\": PixelLab\n * bills a subscription quota, OpenAI bills dollars per image, a local model\n * bills nothing. `plan` prints the unit alongside the number so the figure is\n * never silently misread, and `--budget` is interpreted in the active unit.\n */\nexport type CostUnit = \"generations\" | \"usd\" | \"free\"\n\nexport interface CostEstimate {\n unit: CostUnit\n amount: number\n /**\n * How many candidates one call returns. This is a provider property, not a\n * universal truth — PixelLab's `1dir` returns up to 64 for a single fixed\n * price, whereas a per-image provider returns one and charges N times for N.\n * The \"generate small, pick from many\" strategy only pays off where this is\n * greater than 1 at no extra cost.\n */\n candidates: number\n}\n\n/** Runtime guard for third-party adapters before estimates influence a budget. */\nexport function validateCostEstimate(providerId: string, value: unknown): CostEstimate {\n if (!value || typeof value !== \"object\") {\n throw new Error(`Provider \"${providerId}\" returned an invalid cost estimate`)\n }\n const estimate = value as Partial<CostEstimate>\n if (!([\"generations\", \"usd\", \"free\"] as readonly unknown[]).includes(estimate.unit)) {\n throw new Error(`Provider \"${providerId}\" returned an invalid cost unit`)\n }\n if (!Number.isFinite(estimate.amount) || estimate.amount! < 0) {\n throw new Error(`Provider \"${providerId}\" returned an invalid cost amount`)\n }\n if (estimate.unit === \"free\" && estimate.amount !== 0) {\n throw new Error(`Provider \"${providerId}\" returned a nonzero amount with the free cost unit`)\n }\n if (!Number.isInteger(estimate.candidates) || estimate.candidates! < 1) {\n throw new Error(`Provider \"${providerId}\" returned an invalid candidate count`)\n }\n return estimate as CostEstimate\n}\n\nexport interface OutputSource {\n url: string\n /** Stable semantic/index role used in filenames and lockfile outputs. */\n role?: string\n}\n\nexport interface PollContext {\n /** Distinguishes structural tile sets from independent tile candidates. */\n tileFeature?: string\n}\n\n/** Provider-owned, JSON-serializable details needed by downstream exporters. */\nexport type ProviderMetadata = Record<string, unknown>\n\n/** Terminal and non-terminal states a queued job can be observed in. */\nexport type JobState =\n | { status: \"processing\"; progressPercent?: number | null; etaSeconds?: number | null }\n | { status: \"review\"; candidateUrls: string[] }\n | {\n status: \"ready\"\n objectId: string\n /** Kept for compatibility with single-output provider implementations. */\n sourceUrl: string | null\n /** Present for structural multi-output results. */\n sources?: OutputSource[]\n /** Preserved under the provider's namespace in the lockfile. */\n metadata?: ProviderMetadata\n }\n | { status: \"failed\"; error: string }\n\n/** A previously generated asset as the provider reports it. */\nexport interface RemoteAsset {\n id: string\n prompt: string\n width: number\n height: number\n createdAt: string\n previewUrl: string | null\n tags: string[]\n status: string\n}\n\nexport interface BalanceInfo {\n unit: CostUnit\n remaining: number\n total?: number\n plan?: string\n}\n\nexport interface BalanceChange {\n unit: CostUnit\n before: number\n after: number\n /** Provider-reported quota/currency consumed between the two readings. */\n spent: number\n /** Quota/currency added between readings, e.g. a refill during the run. */\n credited: number\n}\n\n/** Compare two provider readings without ever combining incompatible units. */\nexport function measureBalanceChange(\n before: BalanceInfo,\n after: BalanceInfo,\n): BalanceChange | null {\n if (\n before.unit !== after.unit ||\n !Number.isFinite(before.remaining) ||\n !Number.isFinite(after.remaining)\n ) return null\n const delta = before.remaining - after.remaining\n return {\n unit: before.unit,\n before: before.remaining,\n after: after.remaining,\n spent: Math.max(0, delta),\n credited: Math.max(0, -delta),\n }\n}\n\n/**\n * Submission constraints a backend enforces upstream, in its own units —\n * `submit` has no business knowing these numbers itself.\n */\nexport interface RateLimit {\n /** Minimum time between successive submissions, global across the account. */\n spacingMs: number\n /** Background jobs allowed in flight at once. */\n maxInFlight: number\n}\n\n/**\n * Used when a provider doesn't declare `rateLimit()` — conservative enough\n * not to be a real constraint for a provider that has none of its own, and\n * overridable per run via `submit`'s own options regardless.\n */\nexport const DEFAULT_RATE_LIMIT: RateLimit = { spacingMs: 2500, maxInFlight: 8 }\n\n/**\n * A backend that turns a resolved spec into image bytes.\n *\n * Everything above this interface — the manifest, the lockfile, plan diffing,\n * salvage, the contact sheets — is provider-agnostic. Everything that knows a\n * URL shape or an auth header lives below it.\n *\n * The optional members are genuinely optional capabilities rather than\n * convenience: a provider with no queryable asset list cannot support `adopt`\n * or `salvage`, and the CLI reports that rather than failing obscurely.\n */\nexport interface Provider {\n readonly id: string\n\n /** False for a generator this backend cannot express (e.g. non-square). */\n supports(generator: Generator): boolean\n\n /** Never performs I/O — `plan` must stay free and offline. */\n estimate(spec: ResolvedSpec): CostEstimate\n\n /** This backend's own submission constraints. Falls back to\n * `DEFAULT_RATE_LIMIT` when absent — see that constant's doc. */\n rateLimit?(): RateLimit\n\n submit(spec: ResolvedSpec, styleImages: ResolvedStyleImage[]): Promise<{ jobId: string }>\n\n poll(jobId: string, generator: Generator, context?: PollContext): Promise<JobState>\n\n /**\n * Promote one candidate from a review-status job to a standalone asset.\n * Only meaningful where `estimate().candidates > 1`.\n *\n * `generator` is passed because \"promote\" is not universal: PixelLab's\n * frame-based generators create a new account object, while a tiles\n * variation is already a finished image and there is nothing to promote.\n * A provider that treats every candidate alike can ignore it.\n */\n selectCandidate(\n jobId: string,\n index: number,\n commonTag?: string,\n generator?: Generator,\n ): Promise<{ objectId: string; sourceUrl: string | null }>\n\n /** Storage URLs are usually public; implementations should not send auth. */\n download(url: string): Promise<Buffer>\n\n balance(): Promise<BalanceInfo>\n\n /** Free-form labels on the remote asset. Absent if unsupported. */\n setTags?(objectId: string, tags: string[]): Promise<void>\n\n /** Walk every asset on the account. Required by `adopt` and `salvage`. */\n list?(): AsyncGenerator<RemoteAsset>\n\n /** Irreversible. Only reached via `purge`, behind explicit confirmation. */\n delete?(assetId: string): Promise<void>\n}\n\nexport class UnsupportedCapabilityError extends Error {\n constructor(providerId: string, capability: string) {\n super(\n `Provider \"${providerId}\" does not support ${capability}. ` +\n `That command is unavailable with this backend.`,\n )\n this.name = \"UnsupportedCapabilityError\"\n }\n}\n\n/** Narrowing helpers so call sites fail with a clear message, not `undefined is not a function`. */\nexport function requireList(provider: Provider): NonNullable<Provider[\"list\"]> {\n if (!provider.list) throw new UnsupportedCapabilityError(provider.id, \"listing remote assets\")\n return provider.list.bind(provider)\n}\n\nexport function requireDelete(provider: Provider): NonNullable<Provider[\"delete\"]> {\n if (!provider.delete) throw new UnsupportedCapabilityError(provider.id, \"deleting remote assets\")\n return provider.delete.bind(provider)\n}\n\nexport function formatCost(unit: CostUnit, amount: number): string {\n if (unit === \"free\") return \"free\"\n if (unit === \"usd\") return `$${amount.toFixed(2)}`\n return `${amount} generation${amount === 1 ? \"\" : \"s\"}`\n}\n","import { mkdirSync, existsSync, readFileSync, writeFileSync } from \"node:fs\"\nimport { randomUUID } from \"node:crypto\"\nimport os from \"node:os\"\nimport path from \"node:path\"\nimport { PixelLabClient, PixelLabError, clientFromEnv } from \"../client.ts\"\nimport { paletteSwatch } from \"../png.ts\"\nimport {\n candidateCount,\n generationCost,\n type Generator,\n type ResolvedSpec,\n type ResolvedStyleImage,\n} from \"../types.ts\"\nimport type { BalanceInfo, CostEstimate, JobState, PollContext, Provider, RateLimit, RemoteAsset } from \"../provider.ts\"\n\n/**\n * PixelLab, the reference implementation.\n *\n * All PixelLab-specific knowledge lives here: the three generators and their\n * very different pricing, the review/candidate flow, the fact that a map\n * object's job record expires while its image does not, and that pixflux\n * returns bytes inline instead of a job id.\n */\nexport class PixelLabProvider implements Provider {\n readonly id = \"pixellab\"\n\n constructor(private readonly client: PixelLabClient) {}\n\n static fromEnv(): PixelLabProvider {\n return new PixelLabProvider(clientFromEnv())\n }\n\n /** Public storage URLs and the local content cache do not require API auth. */\n static forDownloads(): PixelLabProvider {\n return PixelLabProvider.forOffline()\n }\n\n /** Capability and cost estimation only; makes no network request itself. */\n static forOffline(): PixelLabProvider {\n return new PixelLabProvider(new PixelLabClient(\"download-only\"))\n }\n\n supports(generator: Generator): boolean {\n return (\n generator === \"1dir\" ||\n generator === \"map\" ||\n generator === \"pixflux\" ||\n generator === \"tiles\"\n )\n }\n\n /** PixelLab's own constraints: submissions must be >2s apart, and\n * background jobs in flight are capped by subscription tier (Tier 1=8,\n * Tier 2=10, Tier 3=20) — 8 is the safe floor across every tier. */\n rateLimit(): RateLimit {\n return { spacingMs: 2500, maxInFlight: 8 }\n }\n\n /**\n * Where synchronous pixflux results are parked between `submit` and `fetch`.\n *\n * pixflux returns the PNG inline rather than a job id, but the pipeline is\n * built around submit → poll → fetch running as separate commands. Writing\n * the bytes to a known path keeps that model intact: the \"job id\" is the\n * filename, polling is an existence check, and downloading is a file read.\n */\n private static cacheDir(): string {\n const dir = path.join(os.tmpdir(), \"pixelkiln-pixflux\")\n mkdirSync(dir, { recursive: true })\n return dir\n }\n\n estimate(spec: ResolvedSpec): CostEstimate {\n // `tiles` prices and counts off the whole set, both of which the manifest\n // layer already worked out — see tilesCost / tileVariationCount.\n if (spec.generator === \"tiles\") {\n return { unit: \"generations\", amount: spec.cost, candidates: spec.candidates }\n }\n return {\n unit: \"generations\",\n amount: generationCost(spec.width, spec.height, spec.generator),\n candidates: spec.generator === \"1dir\" ? candidateCount(spec.size) : 1,\n }\n }\n\n async submit(spec: ResolvedSpec, styleImages: ResolvedStyleImage[]): Promise<{ jobId: string }> {\n if (spec.generator === \"pixflux\") {\n const swatch = spec.palette.length\n ? paletteSwatch(spec.palette).toString(\"base64\")\n : undefined\n const { png } = await this.client.createImagePixflux({\n description: spec.prompt,\n width: spec.width,\n height: spec.height,\n noBackground: spec.noBackground,\n paletteSwatchBase64: swatch,\n seed: spec.seed,\n })\n const jobId = randomUUID()\n writeFileSync(path.join(PixelLabProvider.cacheDir(), `${jobId}.png`), png)\n return { jobId }\n }\n\n if (spec.generator === \"tiles\") {\n const res = await this.client.createTilesPro({\n description: spec.prompt,\n tileSize: spec.tileSize,\n tileType: spec.tileType,\n tileView: spec.tileView,\n tileFeature: spec.tileFeature,\n outlineMode: spec.outlineMode,\n seed: spec.seed,\n // TilesProStyleImage is flat and wants the reference's real dimensions,\n // unlike 1dir's {type, base64, format} payload.\n styleImages: styleImages.map(({ base64, width, height }) => ({ base64, width, height })),\n })\n return { jobId: res.tile_id }\n }\n\n if (spec.generator === \"1dir\") {\n const res = await this.client.create1Direction({\n description: spec.prompt,\n size: spec.size,\n view: spec.view === \"sidescroller\" ? \"sidescroller\" : \"top-down\",\n styleImages,\n })\n return { jobId: res.object_id }\n }\n const res = await this.client.createMapObject({\n description: spec.prompt,\n width: spec.width,\n height: spec.height,\n view: spec.view,\n outline: spec.outline,\n shading: spec.shading,\n detail: spec.detail,\n seed: spec.seed,\n })\n return { jobId: res.object_id }\n }\n\n async poll(jobId: string, generator: Generator, context?: PollContext): Promise<JobState> {\n if (generator === \"pixflux\") {\n const file = path.join(PixelLabProvider.cacheDir(), `${jobId}.png`)\n if (existsSync(file)) {\n const sourceUrl = `file://${file}`\n return { status: \"ready\", objectId: jobId, sourceUrl, sources: [{ url: sourceUrl }] }\n }\n // The bytes only ever lived here, so a missing file means the temp dir\n // was cleared. Nothing to recover from upstream — say so plainly.\n return {\n status: \"failed\",\n error: \"pixflux result is no longer cached locally; re-run submit for this asset\",\n }\n }\n if (generator === \"map\") return this.pollMap(jobId)\n if (generator === \"tiles\") return this.pollTiles(jobId, Boolean(context?.tileFeature))\n\n const obj = await this.client.getObject(jobId)\n if (obj.status === \"review\") {\n return { status: \"review\", candidateUrls: obj.frame_urls ?? [] }\n }\n if (obj.status === \"completed\") {\n const url = firstUrl(obj.rotation_urls) ?? obj.preview_url ?? null\n return { status: \"ready\", objectId: obj.id, sourceUrl: url, sources: url ? [{ url }] : [] }\n }\n if (obj.status === \"failed\") return { status: \"failed\", error: \"generation failed upstream\" }\n return {\n status: \"processing\",\n progressPercent: obj.progress_percent ?? null,\n etaSeconds: obj.eta_seconds ?? null,\n }\n }\n\n /**\n * Map objects need their own path because the `/map-objects/{id}` record is\n * deleted upstream roughly 8 hours after creation while the image survives in\n * the objects collection. Verified: a March 2026 sprite still resolves from\n * `/objects` four months on, with `/map-objects` returning 404 for the same\n * id. So a 404 here is not evidence the work is lost.\n */\n private async pollMap(jobId: string): Promise<JobState> {\n try {\n const obj = await this.client.getMapObject(jobId)\n if (obj.status === \"completed\" && obj.download_url) {\n return {\n status: \"ready\",\n objectId: jobId,\n sourceUrl: obj.download_url,\n sources: [{ url: obj.download_url }],\n }\n }\n if (obj.status === \"failed\") return { status: \"failed\", error: \"generation failed upstream\" }\n return { status: \"processing\" }\n } catch (err) {\n if (!(err instanceof PixelLabError) || err.status !== 404) throw err\n const survivor = await this.client.getObject(jobId).catch(() => null)\n const url = firstUrl(survivor?.rotation_urls) ?? survivor?.preview_url ?? null\n if (survivor?.status === \"completed\" && url) {\n return { status: \"ready\", objectId: survivor.id, sourceUrl: url, sources: [{ url }] }\n }\n return {\n status: \"failed\",\n error: \"map object record deleted upstream and no surviving image found\",\n }\n }\n }\n\n /**\n * Tiles report progress through the HTTP status: 423 while drawing, 200 with\n * `storage_urls` once finished. There is no `status` field to read and no\n * progress percentage on offer, so \"processing\" here carries no ETA.\n */\n private async pollTiles(tileId: string, connectable: boolean): Promise<JobState> {\n try {\n const set = await this.client.getTilesPro(tileId)\n const tiles = tilesInIndexOrder(set.storage_urls)\n if (!tiles.length) return { status: \"failed\", error: \"tiles job returned no storage urls\" }\n if (!connectable) return { status: \"review\", candidateUrls: tiles.map((tile) => tile.url) }\n return {\n status: \"ready\",\n objectId: tileId,\n sourceUrl: tiles[0]?.url ?? null,\n sources: tiles.map((tile) => ({\n url: tile.url,\n role: `tile-${String(tile.index).padStart(2, \"0\")}`,\n })),\n metadata: {\n tileKind: set.kind,\n ...(set.tile_rules ? { tileRules: set.tile_rules } : {}),\n },\n }\n } catch (err) {\n if (err instanceof PixelLabError && err.status === 423) return { status: \"processing\" }\n throw err\n }\n }\n\n async selectCandidate(\n jobId: string,\n index: number,\n commonTag?: string,\n generator?: Generator,\n ): Promise<{ objectId: string; sourceUrl: string | null }> {\n // A tiles variation is already a finished image at a stable URL — there is\n // no frame to promote and no new account object to create. The identity we\n // record is the job plus the index, which is what actually reproduces it.\n if (generator === \"tiles\") {\n const set = await this.client.getTilesPro(jobId)\n const url = tilesInIndexOrder(set.storage_urls)[index]?.url\n if (!url) throw new Error(`tiles job ${jobId} has no variation at index ${index}`)\n return { objectId: `${jobId}#${index}`, sourceUrl: url }\n }\n const promoted = await this.client.selectFrames(jobId, [index], commonTag)\n const objectId = promoted.created_object_ids?.[0]\n if (!objectId) {\n // The review parent is transient; recording its id would leave a mapping\n // that breaks once the parent is emptied. Fail loudly instead.\n throw new Error(`select-frames returned no created_object_ids for job ${jobId}`)\n }\n const obj = await this.client.getObject(objectId).catch(() => null)\n return { objectId, sourceUrl: firstUrl(obj?.rotation_urls) ?? obj?.preview_url ?? null }\n }\n\n async download(url: string): Promise<Buffer> {\n if (url.startsWith(\"file://\")) return readFileSync(url.slice(\"file://\".length))\n return this.client.download(url)\n }\n\n async balance(): Promise<BalanceInfo> {\n const b = await this.client.balance()\n return { unit: \"generations\", remaining: b.generations, total: b.total, plan: b.plan }\n }\n\n async setTags(objectId: string, tags: string[]): Promise<void> {\n await this.client.setTags(objectId, tags.slice(0, 20))\n }\n\n async *list(): AsyncGenerator<RemoteAsset> {\n for await (const obj of this.client.iterateObjects(100)) {\n yield {\n id: obj.id,\n prompt: obj.prompt ?? \"\",\n width: obj.size.width,\n height: obj.size.height,\n createdAt: obj.created_at,\n previewUrl: obj.preview_url ?? null,\n tags: obj.tags ?? [],\n status: obj.status ?? \"unknown\",\n }\n }\n }\n\n async delete(assetId: string): Promise<void> {\n await this.client.deleteObject(assetId)\n }\n}\n\n/**\n * `storage_urls` is an object keyed `tile_0`, `tile_1`, ... — JSON object order\n * is not something to rely on, and a connectable set is sliced by index, so\n * sort numerically rather than taking Object.values() as it comes.\n */\nfunction tilesInIndexOrder(urls: Record<string, string>): Array<{ index: number; url: string }> {\n return Object.entries(urls)\n .map(([key, url]) => ({ index: Number(key.replace(/^tile_/, \"\")), url }))\n .filter((tile) => Number.isFinite(tile.index))\n .sort((a, b) => a.index - b.index)\n}\n\nfunction firstUrl(urls: Record<string, string | null> | null | undefined): string | null {\n if (!urls) return null\n return Object.values(urls).find((u): u is string => typeof u === \"string\") ?? null\n}\n","import { deflateSync, inflateSync } from \"node:zlib\"\n\nexport interface DecodedPng {\n width: number\n height: number\n /** RGBA, 4 bytes per pixel, row-major. */\n pixels: Buffer\n}\n\nconst SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])\nconst MAX_DECODED_BYTES = 256 * 1024 * 1024\n\ninterface PngHeader {\n width: number\n height: number\n bitDepth: number\n colorType: number\n channels: number\n}\n\nconst CHANNELS = new Map([\n [0, 1], // greyscale\n [2, 3], // RGB\n [3, 1], // indexed colour\n [4, 2], // greyscale + alpha\n [6, 4], // RGBA\n])\n\nconst LEGAL_DEPTHS = new Map<number, Set<number>>([\n [0, new Set([1, 2, 4, 8, 16])],\n [2, new Set([8, 16])],\n [3, new Set([1, 2, 4, 8])],\n [4, new Set([8, 16])],\n [6, new Set([8, 16])],\n])\n\n/**\n * Dependency-free decoder for standard non-interlaced PNG colour modes.\n *\n * Inputs are normalized to 8-bit RGBA for the audit and sheet pipelines. Adam7\n * remains deliberately unsupported: provider and game-art PNGs are normally\n * non-interlaced, and refusing the uncommon layout is safer than implementing\n * a second scanline geometry without a dedicated image dependency.\n */\nexport function decodePng(buf: Buffer): DecodedPng {\n if (buf.length < 8 || !buf.subarray(0, 8).equals(SIGNATURE)) {\n throw new Error(\"not a PNG\")\n }\n\n let header: PngHeader | null = null\n let palette: Buffer | null = null\n let transparency: Buffer | null = null\n let sawImageData = false\n let sawEnd = false\n const idat: Buffer[] = []\n\n let offset = 8\n while (offset < buf.length) {\n if (offset + 12 > buf.length) throw new Error(\"truncated PNG chunk header\")\n const length = buf.readUInt32BE(offset)\n const type = buf.toString(\"ascii\", offset + 4, offset + 8)\n if (!/^[A-Za-z]{4}$/.test(type) || /[a-z]/.test(type[2]!)) {\n throw new Error(`PNG has an invalid chunk type ${JSON.stringify(type)}`)\n }\n const end = offset + 12 + length\n if (!Number.isSafeInteger(end) || end > buf.length) {\n throw new Error(`truncated PNG chunk ${type || \"(unknown)\"}`)\n }\n const data = buf.subarray(offset + 8, offset + 8 + length)\n const expectedCrc = buf.readUInt32BE(offset + 8 + length)\n const actualCrc = crc32(buf.subarray(offset + 4, offset + 8 + length)) >>> 0\n if (actualCrc !== expectedCrc) throw new Error(`PNG chunk ${type} has an invalid checksum`)\n\n if (!header && type !== \"IHDR\") throw new Error(\"PNG is missing its leading IHDR chunk\")\n\n if (type === \"IHDR\") {\n if (header) throw new Error(\"PNG has more than one IHDR chunk\")\n if (data.length !== 13) throw new Error(\"PNG has an invalid IHDR chunk\")\n const width = data.readUInt32BE(0)\n const height = data.readUInt32BE(4)\n const bitDepth = data[8]!\n const colorType = data[9]!\n const channels = CHANNELS.get(colorType)\n if (!width || !height) throw new Error(\"PNG dimensions must be positive\")\n if (!channels || !LEGAL_DEPTHS.get(colorType)?.has(bitDepth)) {\n throw new Error(`unsupported PNG: bitDepth=${bitDepth} colorType=${colorType}`)\n }\n if (data[10] !== 0) throw new Error(`unsupported PNG compression method ${data[10]}`)\n if (data[11] !== 0) throw new Error(`unsupported PNG filter method ${data[11]}`)\n if (data[12] !== 0) throw new Error(\"unsupported PNG: interlaced\")\n header = { width, height, bitDepth, colorType, channels }\n } else if (type === \"PLTE\") {\n if (sawImageData) throw new Error(\"PNG palette appears after image data\")\n if (palette) throw new Error(\"PNG has more than one palette\")\n if (!data.length || data.length % 3 !== 0 || data.length > 256 * 3) {\n throw new Error(\"PNG has an invalid palette\")\n }\n palette = Buffer.from(data)\n } else if (type === \"tRNS\") {\n if (sawImageData) throw new Error(\"PNG transparency appears after image data\")\n if (transparency) throw new Error(\"PNG has more than one transparency chunk\")\n transparency = Buffer.from(data)\n } else if (type === \"IDAT\") {\n sawImageData = true\n idat.push(data)\n } else if (type === \"IEND\") {\n if (data.length !== 0) throw new Error(\"PNG has an invalid IEND chunk\")\n sawEnd = true\n break\n } else if (/^[A-Z]/.test(type)) {\n throw new Error(`unsupported critical PNG chunk ${type}`)\n }\n offset = end\n }\n\n if (!header) throw new Error(\"PNG has no image header\")\n if (!sawEnd) throw new Error(\"PNG has no IEND chunk\")\n if (!idat.length) throw new Error(\"PNG has no image data\")\n validatePalette(header, palette)\n validateTransparency(header.colorType, transparency, palette)\n\n const bitsPerPixel = header.channels * header.bitDepth\n const stride = Math.ceil((header.width * bitsPerPixel) / 8)\n const rawLength = (stride + 1) * header.height\n const rgbaLength = header.width * header.height * 4\n if (\n !Number.isSafeInteger(rawLength) ||\n !Number.isSafeInteger(rgbaLength) ||\n rawLength > MAX_DECODED_BYTES ||\n rgbaLength > MAX_DECODED_BYTES\n ) {\n throw new Error(\"PNG dimensions exceed the 256 MiB decoded-image limit\")\n }\n\n let raw: Buffer\n try {\n raw = inflateSync(Buffer.concat(idat), { maxOutputLength: rawLength })\n } catch (err) {\n throw new Error(`invalid PNG image data: ${err instanceof Error ? err.message : String(err)}`)\n }\n if (raw.length !== rawLength) {\n throw new Error(`invalid PNG image data length: expected ${rawLength}, got ${raw.length}`)\n }\n\n const filterBytes = Math.max(1, Math.ceil(bitsPerPixel / 8))\n const samples = unfilter(raw, stride, header.height, filterBytes)\n return {\n width: header.width,\n height: header.height,\n pixels: toRgba(samples, header, stride, palette, transparency),\n }\n}\n\nfunction validatePalette(header: PngHeader, palette: Buffer | null): void {\n if (header.colorType === 3 && !palette) throw new Error(\"indexed PNG has no palette\")\n if ((header.colorType === 0 || header.colorType === 4) && palette) {\n throw new Error(\"greyscale PNG cannot contain a palette\")\n }\n if (header.colorType === 3 && palette && palette.length / 3 > 2 ** header.bitDepth) {\n throw new Error(\"indexed PNG palette has more entries than its bit depth permits\")\n }\n}\n\n/**\n * Reverses PNG's per-scanline filters. Each row is prefixed with a filter byte\n * and predicted from the row above and the pixel to the left.\n */\nfunction unfilter(raw: Buffer, stride: number, height: number, bpp: number): Buffer {\n const out = Buffer.alloc(stride * height)\n\n for (let y = 0; y < height; y++) {\n const filter = raw[y * (stride + 1)]!\n const src = raw.subarray(y * (stride + 1) + 1, y * (stride + 1) + 1 + stride)\n const dst = out.subarray(y * stride, (y + 1) * stride)\n const prev = y > 0 ? out.subarray((y - 1) * stride, y * stride) : null\n\n for (let x = 0; x < stride; x++) {\n const a = x >= bpp ? dst[x - bpp]! : 0 // left\n const b = prev ? prev[x]! : 0 // above\n const c = prev && x >= bpp ? prev[x - bpp]! : 0 // upper-left\n const v = src[x]!\n switch (filter) {\n case 0: dst[x] = v; break\n case 1: dst[x] = (v + a) & 0xff; break\n case 2: dst[x] = (v + b) & 0xff; break\n case 3: dst[x] = (v + ((a + b) >> 1)) & 0xff; break\n case 4: dst[x] = (v + paeth(a, b, c)) & 0xff; break\n default: throw new Error(`unknown PNG filter ${filter} on row ${y}`)\n }\n }\n }\n return out\n}\n\nfunction validateTransparency(\n colorType: number,\n transparency: Buffer | null,\n palette: Buffer | null,\n): void {\n if (!transparency) return\n if (colorType === 0 && transparency.length !== 2) {\n throw new Error(\"greyscale PNG has an invalid transparency chunk\")\n }\n if (colorType === 2 && transparency.length !== 6) {\n throw new Error(\"RGB PNG has an invalid transparency chunk\")\n }\n if (colorType === 3 && transparency.length > (palette?.length ?? 0) / 3) {\n throw new Error(\"indexed PNG transparency exceeds its palette\")\n }\n if (colorType === 4 || colorType === 6) {\n throw new Error(\"PNG with an alpha channel cannot also contain tRNS\")\n }\n}\n\nfunction toRgba(\n samples: Buffer,\n header: PngHeader,\n stride: number,\n palette: Buffer | null,\n transparency: Buffer | null,\n): Buffer {\n const out = Buffer.alloc(header.width * header.height * 4)\n const transparentGrey = header.colorType === 0 && transparency\n ? transparency.readUInt16BE(0)\n : null\n const transparentRgb = header.colorType === 2 && transparency\n ? [\n transparency.readUInt16BE(0),\n transparency.readUInt16BE(2),\n transparency.readUInt16BE(4),\n ]\n : null\n\n for (let y = 0; y < header.height; y++) {\n const row = samples.subarray(y * stride, (y + 1) * stride)\n for (let x = 0; x < header.width; x++) {\n const dst = (y * header.width + x) * 4\n if (header.colorType === 0) {\n const grey = sample(row, x, 0, header.channels, header.bitDepth)\n const byte = sampleToByte(grey, header.bitDepth)\n out[dst] = byte\n out[dst + 1] = byte\n out[dst + 2] = byte\n out[dst + 3] = grey === transparentGrey ? 0 : 255\n } else if (header.colorType === 2) {\n const rgb = [0, 1, 2].map((channel) =>\n sample(row, x, channel, header.channels, header.bitDepth))\n out[dst] = sampleToByte(rgb[0]!, header.bitDepth)\n out[dst + 1] = sampleToByte(rgb[1]!, header.bitDepth)\n out[dst + 2] = sampleToByte(rgb[2]!, header.bitDepth)\n out[dst + 3] = transparentRgb && rgb.every((value, i) => value === transparentRgb[i])\n ? 0\n : 255\n } else if (header.colorType === 3) {\n const index = sample(row, x, 0, 1, header.bitDepth)\n const paletteOffset = index * 3\n if (!palette || paletteOffset + 2 >= palette.length) {\n throw new Error(`indexed PNG pixel references missing palette entry ${index}`)\n }\n out[dst] = palette[paletteOffset]!\n out[dst + 1] = palette[paletteOffset + 1]!\n out[dst + 2] = palette[paletteOffset + 2]!\n out[dst + 3] = transparency?.[index] ?? 255\n } else if (header.colorType === 4) {\n const grey = sampleToByte(sample(row, x, 0, 2, header.bitDepth), header.bitDepth)\n out[dst] = grey\n out[dst + 1] = grey\n out[dst + 2] = grey\n out[dst + 3] = sampleToByte(sample(row, x, 1, 2, header.bitDepth), header.bitDepth)\n } else {\n out[dst] = sampleToByte(sample(row, x, 0, 4, header.bitDepth), header.bitDepth)\n out[dst + 1] = sampleToByte(sample(row, x, 1, 4, header.bitDepth), header.bitDepth)\n out[dst + 2] = sampleToByte(sample(row, x, 2, 4, header.bitDepth), header.bitDepth)\n out[dst + 3] = sampleToByte(sample(row, x, 3, 4, header.bitDepth), header.bitDepth)\n }\n }\n }\n return out\n}\n\nfunction sample(\n row: Buffer,\n x: number,\n channel: number,\n channels: number,\n bitDepth: number,\n): number {\n if (bitDepth === 8) return row[x * channels + channel]!\n if (bitDepth === 16) return row.readUInt16BE((x * channels + channel) * 2)\n const bitOffset = x * bitDepth\n const shift = 8 - bitDepth - (bitOffset % 8)\n return (row[Math.floor(bitOffset / 8)]! >> shift) & ((1 << bitDepth) - 1)\n}\n\nfunction sampleToByte(value: number, bitDepth: number): number {\n if (bitDepth === 8) return value\n if (bitDepth === 16) return Math.round(value / 257)\n return Math.round((value * 255) / ((1 << bitDepth) - 1))\n}\n\nfunction paeth(a: number, b: number, c: number): number {\n const p = a + b - c\n const pa = Math.abs(p - a)\n const pb = Math.abs(p - b)\n const pc = Math.abs(p - c)\n if (pa <= pb && pa <= pc) return a\n return pb <= pc ? b : c\n}\n\nexport interface PaletteEntry {\n r: number\n g: number\n b: number\n /** Share of opaque pixels using this colour, 0-1. */\n weight: number\n}\n\n/**\n * Dominant colours of an image, ignoring transparency.\n *\n * Pixel art uses a small deliberate palette, so exact colour counting works —\n * no clustering needed. Nearly-transparent pixels are excluded because\n * anti-aliased edges would otherwise dominate the histogram of a small sprite.\n */\nexport function extractPalette(png: DecodedPng, topN = 8, alphaThreshold = 128): PaletteEntry[] {\n const counts = new Map<number, number>()\n let opaque = 0\n\n for (let i = 0; i < png.pixels.length; i += 4) {\n const alpha = png.pixels[i + 3]!\n if (alpha < alphaThreshold) continue\n opaque++\n const key = (png.pixels[i]! << 16) | (png.pixels[i + 1]! << 8) | png.pixels[i + 2]!\n counts.set(key, (counts.get(key) ?? 0) + 1)\n }\n if (opaque === 0) return []\n\n return [...counts.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, topN)\n .map(([key, n]) => ({\n r: (key >> 16) & 0xff,\n g: (key >> 8) & 0xff,\n b: key & 0xff,\n weight: n / opaque,\n }))\n}\n\n/** Fraction of pixels that are effectively transparent — a silhouette check. */\nexport function transparencyRatio(png: DecodedPng, alphaThreshold = 128): number {\n let clear = 0\n const total = png.pixels.length / 4\n for (let i = 0; i < png.pixels.length; i += 4) {\n if (png.pixels[i + 3]! < alphaThreshold) clear++\n }\n return total === 0 ? 0 : clear / total\n}\n\n/** CRC-32 as PNG specifies it. Small enough not to warrant a dependency. */\nfunction crc32(buf: Buffer): number {\n let c = ~0\n for (const byte of buf) {\n c ^= byte\n for (let k = 0; k < 8; k++) c = (c >>> 1) ^ (0xedb88320 & -(c & 1))\n }\n return ~c\n}\n\nfunction chunk(type: string, data: Buffer): Buffer {\n const len = Buffer.alloc(4)\n len.writeUInt32BE(data.length)\n const body = Buffer.concat([Buffer.from(type, \"ascii\"), data])\n const crc = Buffer.alloc(4)\n crc.writeUInt32BE(crc32(body) >>> 0)\n return Buffer.concat([len, body, crc])\n}\n\n/**\n * Writes an 8-bit RGB PNG. Used to build the small swatch image that carries a\n * forced palette to the API — not a general encoder.\n */\nexport function encodeRgbPng(width: number, height: number, rgb: Buffer): Buffer {\n if (rgb.length !== width * height * 3) {\n throw new Error(`expected ${width * height * 3} bytes of RGB, got ${rgb.length}`)\n }\n const stride = width * 3\n // Filter byte 0 (none) per scanline.\n const raw = Buffer.alloc((stride + 1) * height)\n for (let y = 0; y < height; y++) {\n raw[y * (stride + 1)] = 0\n rgb.copy(raw, y * (stride + 1) + 1, y * stride, (y + 1) * stride)\n }\n const ihdr = Buffer.alloc(13)\n ihdr.writeUInt32BE(width, 0)\n ihdr.writeUInt32BE(height, 4)\n ihdr[8] = 8 // bit depth\n ihdr[9] = 2 // colour type: RGB\n return Buffer.concat([\n Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]),\n chunk(\"IHDR\", ihdr),\n chunk(\"IDAT\", deflateSync(raw)),\n chunk(\"IEND\", Buffer.alloc(0)),\n ])\n}\n\n/**\n * Writes an 8-bit RGBA PNG.\n *\n * Separate from `encodeRgbPng` rather than replacing it: the palette swatch\n * the API accepts is RGB, and sprite sheets must keep their alpha channel —\n * flattening it would fill every sprite's transparent background with black\n * and the sheet would be unusable over anything but that colour.\n */\nexport function encodeRgbaPng(width: number, height: number, rgba: Buffer): Buffer {\n if (rgba.length !== width * height * 4) {\n throw new Error(`expected ${width * height * 4} bytes of RGBA, got ${rgba.length}`)\n }\n const stride = width * 4\n // Filter byte 0 (none) per scanline. Pixel art compresses well enough that\n // the adaptive filters are not worth the complexity here.\n const raw = Buffer.alloc((stride + 1) * height)\n for (let y = 0; y < height; y++) {\n raw[y * (stride + 1)] = 0\n rgba.copy(raw, y * (stride + 1) + 1, y * stride, (y + 1) * stride)\n }\n const ihdr = Buffer.alloc(13)\n ihdr.writeUInt32BE(width, 0)\n ihdr.writeUInt32BE(height, 4)\n ihdr[8] = 8 // bit depth\n ihdr[9] = 6 // colour type: RGBA\n return Buffer.concat([\n Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]),\n chunk(\"IHDR\", ihdr),\n chunk(\"IDAT\", deflateSync(raw)),\n chunk(\"IEND\", Buffer.alloc(0)),\n ])\n}\n\n/**\n * Builds the palette swatch the API expects: a block of solid colour per entry.\n *\n * Deliberately chunky rather than one pixel per colour — a 4x1 image was\n * rejected outright with \"cannot identify image file\", while a 64x64 block\n * swatch was accepted.\n */\nexport function paletteSwatch(hexes: string[], size = 64): Buffer {\n const colours = hexes.map(parseHex)\n if (!colours.length) throw new Error(\"palette is empty\")\n const rgb = Buffer.alloc(size * size * 3)\n const band = Math.max(1, Math.floor(size / colours.length))\n for (let y = 0; y < size; y++) {\n for (let x = 0; x < size; x++) {\n const c = colours[Math.min(colours.length - 1, Math.floor(x / band))]!\n const o = (y * size + x) * 3\n rgb[o] = c.r\n rgb[o + 1] = c.g\n rgb[o + 2] = c.b\n }\n }\n return encodeRgbPng(size, size, rgb)\n}\n\nexport function parseHex(hex: string): { r: number; g: number; b: number } {\n const m = /^#?([0-9a-f]{6})$/i.exec(hex.trim())\n if (!m) throw new Error(`invalid hex colour \"${hex}\" — expected #rrggbb`)\n const n = parseInt(m[1]!, 16)\n return { r: (n >> 16) & 0xff, g: (n >> 8) & 0xff, b: n & 0xff }\n}\n","import { createHash } from \"node:crypto\"\nimport type { BalanceInfo, CostEstimate, JobState, Provider, RemoteAsset } from \"../provider.ts\"\nimport type { Generator, ResolvedSpec } from \"../types.ts\"\n\n/**\n * An in-memory Provider for tests.\n *\n * This exists because the stages that spend money — submit, poll, fetch — were\n * the only ones without coverage, and four of the five real bugs found so far\n * lived in them. A fake at this seam exercises the actual state machine,\n * including the review/candidate path, without a network or an API key.\n *\n * Deliberately configurable in the ways that broke things for real: how many\n * candidates come back, whether a job fails, and whether the queue is observed\n * as still processing before it settles.\n */\nexport interface FakeOptions {\n /** Candidates per call. >1 routes through review, as PixelLab's 1dir does. */\n candidates?: number\n /** Polls to report `processing` before settling. Exercises the poll loop. */\n processingPolls?: number\n /** Asset ids that should fail instead of completing. */\n failAssets?: Set<string>\n /** Simulate a provider with no listing capability (adopt/salvage unavailable). */\n supportsList?: boolean\n costUnit?: BalanceInfo[\"unit\"]\n startingBalance?: number\n}\n\ninterface FakeJob {\n jobId: string\n spec: ResolvedSpec\n pollsRemaining: number\n candidates: number\n failed: boolean\n selectedIndex: number | null\n objectId: string | null\n}\n\n/** A valid 1x1 PNG, so `fetch`'s signature check passes on fake output. */\nexport const FAKE_PNG = Buffer.from(\n \"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==\",\n \"base64\",\n)\n\nexport class FakeProvider implements Provider {\n readonly id = \"fake\"\n\n readonly jobs = new Map<string, FakeJob>()\n readonly assets = new Map<string, RemoteAsset>()\n readonly tags = new Map<string, string[]>()\n readonly deleted: string[] = []\n /** Every submit, in order — lets a test assert on call count and spacing. */\n readonly submissions: { jobId: string; assetId: string; at: number }[] = []\n\n private counter = 0\n private balanceRemaining: number\n\n constructor(private readonly opts: FakeOptions = {}) {\n this.balanceRemaining = opts.startingBalance ?? 10_000\n if (opts.supportsList !== false) this.list = this.listImpl.bind(this)\n }\n\n supports(generator: Generator): boolean {\n return generator === \"1dir\" || generator === \"map\"\n }\n\n estimate(spec: ResolvedSpec): CostEstimate {\n return {\n unit: this.opts.costUnit ?? \"generations\",\n amount: spec.generator === \"map\" ? 1 : 40,\n candidates: this.opts.candidates ?? (spec.generator === \"map\" ? 1 : 4),\n }\n }\n\n async submit(spec: ResolvedSpec): Promise<{ jobId: string }> {\n const jobId = `job-${++this.counter}`\n const candidates = this.estimate(spec).candidates\n this.jobs.set(jobId, {\n jobId,\n spec,\n pollsRemaining: this.opts.processingPolls ?? 0,\n candidates,\n failed: this.opts.failAssets?.has(spec.assetId) ?? false,\n selectedIndex: null,\n objectId: null,\n })\n this.submissions.push({ jobId, assetId: spec.assetId, at: this.submissions.length })\n this.balanceRemaining -= this.estimate(spec).amount\n return { jobId }\n }\n\n async poll(jobId: string): Promise<JobState> {\n const job = this.jobs.get(jobId)\n if (!job) return { status: \"failed\", error: `unknown job ${jobId}` }\n if (job.pollsRemaining > 0) {\n job.pollsRemaining--\n return { status: \"processing\", progressPercent: 50 }\n }\n if (job.failed) return { status: \"failed\", error: \"fake failure\" }\n if (job.candidates > 1 && job.selectedIndex === null) {\n return {\n status: \"review\",\n candidateUrls: Array.from(\n { length: job.candidates },\n (_, i) => `fake://${jobId}/candidate/${i}`,\n ),\n }\n }\n const objectId = job.objectId ?? `obj-${jobId}`\n job.objectId = objectId\n this.register(objectId, job.spec)\n const sourceUrl = `fake://${objectId}.png`\n return { status: \"ready\", objectId, sourceUrl, sources: [{ url: sourceUrl }] }\n }\n\n async selectCandidate(\n jobId: string,\n index: number,\n commonTag?: string,\n ): Promise<{ objectId: string; sourceUrl: string | null }> {\n const job = this.jobs.get(jobId)\n if (!job) throw new Error(`unknown job ${jobId}`)\n if (index < 0 || index >= job.candidates) {\n throw new Error(`candidate ${index} out of range for ${jobId}`)\n }\n job.selectedIndex = index\n // Mirrors the real provider: the promoted candidate gets its OWN id,\n // distinct from the review parent's.\n const objectId = `obj-${jobId}-c${index}`\n job.objectId = objectId\n this.register(objectId, job.spec, commonTag ? [commonTag] : [])\n return { objectId, sourceUrl: `fake://${objectId}.png` }\n }\n\n async download(url: string): Promise<Buffer> {\n if (!url.startsWith(\"fake://\")) throw new Error(`fake provider cannot download ${url}`)\n // Vary bytes per URL so hashes differ between assets, as real output would.\n const salt = createHash(\"sha256\").update(url).digest()\n return Buffer.concat([FAKE_PNG, salt.subarray(0, 4)])\n }\n\n async balance(): Promise<BalanceInfo> {\n return {\n unit: this.opts.costUnit ?? \"generations\",\n remaining: this.balanceRemaining,\n total: this.opts.startingBalance ?? 10_000,\n plan: \"fake\",\n }\n }\n\n async setTags(objectId: string, tags: string[]): Promise<void> {\n this.tags.set(objectId, [...tags])\n const asset = this.assets.get(objectId)\n if (asset) asset.tags = [...tags]\n }\n\n /**\n * Assigned in the constructor rather than declared as a method, so a test can\n * model a provider that genuinely lacks listing (making `adopt` and `salvage`\n * unavailable) instead of one that throws.\n */\n list?: () => AsyncGenerator<RemoteAsset>\n\n private async *listImpl(): AsyncGenerator<RemoteAsset> {\n for (const asset of this.assets.values()) yield asset\n }\n\n async delete(assetId: string): Promise<void> {\n this.deleted.push(assetId)\n this.assets.delete(assetId)\n }\n\n /** Seed a pre-existing remote asset, for adopt / salvage tests. */\n seed(asset: Partial<RemoteAsset> & { id: string }): RemoteAsset {\n const full: RemoteAsset = {\n prompt: \"seeded\",\n width: 64,\n height: 64,\n createdAt: \"2026-01-01T00:00:00Z\",\n previewUrl: `fake://${asset.id}.png`,\n tags: [],\n status: \"completed\",\n ...asset,\n }\n this.assets.set(full.id, full)\n return full\n }\n\n private register(objectId: string, spec: ResolvedSpec, tags: string[] = []): void {\n if (this.assets.has(objectId)) return\n this.assets.set(objectId, {\n id: objectId,\n prompt: spec.prompt,\n width: spec.width,\n height: spec.height,\n createdAt: new Date(0).toISOString(),\n previewUrl: `fake://${objectId}.png`,\n tags,\n status: \"completed\",\n })\n }\n}\n","import { readFile } from \"node:fs/promises\"\nimport { existsSync } from \"node:fs\"\nimport path from \"node:path\"\nimport {\n ManifestSchema,\n candidateCount,\n countNumberedDescriptions,\n generationCost,\n tileVariationCount,\n tileFeatureOutputCount,\n tilesCost,\n type Manifest,\n type ResolvedSpec,\n type ResolvedStyleImage,\n} from \"./types.ts\"\nimport { sha256, specHash } from \"./hash.ts\"\nimport { validateCostEstimate, type Provider } from \"./provider.ts\"\n\nexport interface LoadedManifest {\n manifest: Manifest\n /** Directory the manifest lives in. All relative paths resolve against it. */\n root: string\n path: string\n}\n\nexport async function loadManifest(manifestPath: string): Promise<LoadedManifest> {\n const abs = path.resolve(manifestPath)\n if (!existsSync(abs)) throw new Error(`No manifest at ${abs}`)\n const parsed = ManifestSchema.safeParse(JSON.parse(await readFile(abs, \"utf8\")))\n if (!parsed.success) {\n const issues = parsed.error.issues.map((i) => ` ${i.path.join(\".\")}: ${i.message}`).join(\"\\n\")\n throw new Error(`Manifest at ${abs} is invalid:\\n${issues}`)\n }\n const styleIds = new Set(Object.keys(parsed.data.styles))\n const unknownReferences: string[] = []\n for (const [assetId, asset] of Object.entries(parsed.data.assets)) {\n for (const styleId of asset.styles) {\n if (!styleIds.has(styleId)) unknownReferences.push(`assets.${assetId}.styles: unknown style \"${styleId}\"`)\n }\n for (const styleId of Object.keys(asset.promptByStyle)) {\n if (!styleIds.has(styleId)) {\n unknownReferences.push(`assets.${assetId}.promptByStyle: unknown style \"${styleId}\"`)\n }\n }\n }\n if (unknownReferences.length) {\n throw new Error(`Manifest at ${abs} is invalid:\\n${unknownReferences.map((i) => ` ${i}`).join(\"\\n\")}`)\n }\n return { manifest: parsed.data, root: path.dirname(abs), path: abs }\n}\n\n/**\n * Expands the manifest into one concrete spec per (style, asset) pair. This is\n * where a style becomes a namespace: adding a style re-derives the entire asset\n * set under a separate output root and separate lock keys, which is what makes\n * a whole-collection restyle a one-flag operation.\n */\nexport async function resolveSpecs(\n loaded: LoadedManifest,\n filter?: {\n styles?: string[]\n assets?: string[]\n /** Optional provider makes offline plan cost/candidate estimates adapter-owned. */\n provider?: Pick<Provider, \"supports\" | \"estimate\" | \"id\">\n },\n): Promise<ResolvedSpec[]> {\n const { manifest, root } = loaded\n const specs: ResolvedSpec[] = []\n\n const styleIds = Object.keys(manifest.styles).filter(\n (id) => !filter?.styles?.length || filter.styles.includes(id),\n )\n for (const unknownStyle of filter?.styles ?? []) {\n if (!manifest.styles[unknownStyle]) {\n throw new Error(\n `Unknown style \"${unknownStyle}\". Defined: ${Object.keys(manifest.styles).join(\", \") || \"(none)\"}`,\n )\n }\n }\n for (const unknownAsset of filter?.assets ?? []) {\n if (!manifest.assets[unknownAsset]) {\n throw new Error(`Unknown asset \"${unknownAsset}\".`)\n }\n }\n\n // Style images are hashed, not just named: editing a reference image must\n // invalidate every spec that depends on it.\n const styleImageCache = new Map<\n string,\n { base64: string; hash: string; width: number; height: number; format: \"png\" | \"jpeg\" }\n >()\n async function loadStyleImage(rel: string) {\n const abs = path.resolve(root, rel)\n let hit = styleImageCache.get(abs)\n if (!hit) {\n if (!existsSync(abs)) throw new Error(`Style image not found: ${abs}`)\n const buf = await readFile(abs)\n const metadata = imageMetadata(buf)\n if (!metadata) throw new Error(`Style image is not a readable PNG or JPEG: ${abs}`)\n if (metadata.width < 1 || metadata.height < 1 || metadata.width > 256 || metadata.height > 256) {\n throw new Error(\n `Style image exceeds the API's 256x256 limit: ${abs} ` +\n `(${metadata.width}x${metadata.height})`,\n )\n }\n hit = { base64: buf.toString(\"base64\"), hash: sha256(buf), ...metadata }\n styleImageCache.set(abs, hit)\n }\n return hit\n }\n\n for (const styleId of styleIds) {\n const style = manifest.styles[styleId]!\n const styleImageHashes: string[] = []\n const styleImageDimensions: { width: number; height: number }[] = []\n for (const img of style.styleImages) {\n const loadedImage = await loadStyleImage(img.path)\n styleImageHashes.push(loadedImage.hash)\n styleImageDimensions.push(loadedImage)\n }\n\n for (const [assetId, asset] of Object.entries(manifest.assets)) {\n if (filter?.assets?.length && !filter.assets.includes(assetId)) continue\n if (asset.styles.length && !asset.styles.includes(styleId)) continue\n\n const generator = style.generator\n if (filter?.provider && !filter.provider.supports(generator)) {\n throw new Error(`Provider \"${filter.provider.id}\" does not support generator \"${generator}\"`)\n }\n let width: number\n let height: number\n let size: number\n\n if (generator === \"1dir\") {\n // Square only. When style images are in play the API derives the size\n // from the largest reference, so the manifest's `size` is advisory.\n size = styleImageDimensions.length\n ? Math.max(...styleImageDimensions.flatMap((img) => [img.width, img.height]))\n : (asset.size ?? style.size ?? 64)\n width = size\n height = size\n } else if (generator === \"tiles\") {\n // Style mode copies the reference geometry; otherwise the endpoint\n // uses tileSize. Asset-level map dimensions do not apply to tiles.\n width = styleImageDimensions.length\n ? Math.max(...styleImageDimensions.map((img) => img.width))\n : (style.tileSize ?? 32)\n height = styleImageDimensions.length\n ? Math.max(...styleImageDimensions.map((img) => img.height))\n : (style.tileSize ?? 32)\n size = Math.max(width, height)\n } else {\n width = asset.width ?? style.size ?? 64\n height = asset.height ?? style.size ?? 64\n size = Math.max(width, height)\n }\n\n // A per-style override replaces the subject wording, not the style\n // wrapping — prefix and suffix still apply.\n const subject = asset.promptByStyle[styleId] ?? asset.prompt\n const prompt = [style.promptPrefix, subject, style.promptSuffix]\n .map((p) => p.trim())\n .filter(Boolean)\n .join(\", \")\n\n const relFile = asset.file ?? path.join(asset.category ?? \"\", `${assetId}.png`)\n const outFile = path.resolve(root, style.outDir, relFile)\n\n // One `tiles` call draws a whole set, so its price and its candidate\n // count both come off the set rather than off a single sprite.\n const tileSize = generator === \"tiles\" ? size : (style.tileSize ?? 32)\n const tileVariations =\n tileFeatureOutputCount(generator === \"tiles\" ? style.tileFeature : undefined) ??\n tileVariationCount(countNumberedDescriptions(prompt))\n\n const base = {\n styleId,\n assetId,\n generator,\n prompt,\n width,\n height,\n size,\n view: style.view ?? (generator === \"1dir\" ? \"top-down\" : \"high top-down\"),\n styleImagePaths: style.styleImages.map((s) => s.path),\n outline: style.outline,\n shading: style.shading,\n detail: style.detail,\n seed: style.seed,\n palette: style.palette,\n noBackground: style.noBackground,\n tileSize: generator === \"tiles\" ? tileSize : undefined,\n tileType: generator === \"tiles\" ? style.tileType : undefined,\n tileView: generator === \"tiles\" ? style.tileView : undefined,\n tileFeature: generator === \"tiles\" ? style.tileFeature : undefined,\n outlineMode: generator === \"tiles\" ? style.outlineMode : undefined,\n cost:\n generator === \"tiles\"\n ? tilesCost(tileSize, tileVariations)\n : generationCost(width, height, generator),\n costUnit: \"generations\" as const,\n candidates:\n generator === \"tiles\"\n ? tileVariations\n : generator === \"1dir\"\n ? candidateCount(size)\n : 1,\n }\n\n const tags = [\n ...new Set([\n ...style.tags,\n ...asset.tags,\n `pixelkiln:${manifest.name}`,\n `asset:${assetId}`,\n `style:${styleId}`,\n ]),\n ]\n if (tags.length > 20) {\n throw new Error(\n `${styleId}/${assetId} resolves to ${tags.length} tags, but PixelLab allows at most 20`,\n )\n }\n\n const resolved: ResolvedSpec = {\n ...base,\n root,\n outFile,\n tags,\n source: asset.source,\n specHash: specHash(base, styleImageHashes),\n }\n if (filter?.provider) {\n const estimate = validateCostEstimate(filter.provider.id, filter.provider.estimate(resolved))\n resolved.cost = estimate.amount\n resolved.costUnit = estimate.unit\n resolved.candidates = estimate.candidates\n }\n specs.push(resolved)\n }\n }\n\n const byOutput = new Map<string, string>()\n for (const spec of specs) {\n const key = `${spec.styleId}/${spec.assetId}`\n const owner = byOutput.get(spec.outFile)\n if (owner) {\n throw new Error(`Output collision: ${owner} and ${key} both resolve to ${spec.outFile}`)\n }\n byOutput.set(spec.outFile, key)\n }\n\n return specs\n}\n\n/** Reference image bytes and measured dimensions, in manifest order. */\nexport async function resolveStyleImages(\n loaded: LoadedManifest,\n styleId: string,\n): Promise<ResolvedStyleImage[]> {\n const style = loaded.manifest.styles[styleId]\n if (!style) throw new Error(`Unknown style \"${styleId}\"`)\n const out: ResolvedStyleImage[] = []\n for (const img of style.styleImages) {\n const file = path.resolve(loaded.root, img.path)\n const buf = await readFile(file)\n const metadata = imageMetadata(buf)\n if (!metadata) throw new Error(`Style image is not a readable PNG or JPEG: ${file}`)\n if (metadata.width < 1 || metadata.height < 1 || metadata.width > 256 || metadata.height > 256) {\n throw new Error(\n `Style image exceeds the API's 256x256 limit: ${file} ` +\n `(${metadata.width}x${metadata.height})`,\n )\n }\n out.push({ base64: buf.toString(\"base64\"), ...metadata })\n }\n return out\n}\n\n/** Retained for callers that only need the encoded bytes. */\nexport async function styleImagesBase64(loaded: LoadedManifest, styleId: string): Promise<string[]> {\n return (await resolveStyleImages(loaded, styleId)).map((img) => img.base64)\n}\n\n/** Reads dimensions without decoding pixel data. */\nexport function imageMetadata(\n buf: Buffer,\n): Pick<ResolvedStyleImage, \"width\" | \"height\" | \"format\"> | null {\n if (\n buf.length >= 24 &&\n buf.readUInt32BE(0) === 0x89504e47 &&\n buf.readUInt32BE(4) === 0x0d0a1a0a &&\n buf.toString(\"ascii\", 12, 16) === \"IHDR\"\n ) {\n return { width: buf.readUInt32BE(16), height: buf.readUInt32BE(20), format: \"png\" }\n }\n\n if (buf.length < 4 || buf[0] !== 0xff || buf[1] !== 0xd8) return null\n let offset = 2\n while (offset + 3 < buf.length) {\n if (buf[offset] !== 0xff) return null\n while (buf[offset] === 0xff) offset++\n const marker = buf[offset++]\n if (marker == null || marker === 0xd9 || marker === 0xda) break\n if (marker === 0x01 || (marker >= 0xd0 && marker <= 0xd7)) continue\n if (offset + 2 > buf.length) return null\n const length = buf.readUInt16BE(offset)\n if (length < 2 || offset + length > buf.length) return null\n const isStartOfFrame =\n marker >= 0xc0 &&\n marker <= 0xcf &&\n ![0xc4, 0xc8, 0xcc].includes(marker)\n if (isStartOfFrame) {\n if (length < 7) return null\n return {\n width: buf.readUInt16BE(offset + 5),\n height: buf.readUInt16BE(offset + 3),\n format: \"jpeg\",\n }\n }\n offset += length\n }\n return null\n}\n","import { createHash } from \"node:crypto\"\nimport { readFile } from \"node:fs/promises\"\nimport type { ResolvedSpec } from \"./types.ts\"\n\nexport function sha256(data: Buffer | string): string {\n return createHash(\"sha256\").update(data).digest(\"hex\")\n}\n\nexport async function sha256File(path: string): Promise<string> {\n return sha256(await readFile(path))\n}\n\n/**\n * Identity of a spec: everything that would change the generated image.\n * Project root, `outFile`, `source`, and `tags` are deliberately excluded —\n * moving a checkout, renaming the destination, swapping the committed art a\n * `mount` places, or retagging should not regenerate art.\n *\n * Generator-specific parameters are hashed only where they apply, and are\n * left `undefined` otherwise so `JSON.stringify` drops the key entirely.\n * That matters: adding a field unconditionally rewrites the hash of every\n * spec in every existing lockfile, and each one then reports as `stale` and\n * invites a full regeneration of art that never changed. Adding `palette`\n * unconditionally did exactly that once already.\n */\nexport function specHash(\n spec: Omit<ResolvedSpec, \"specHash\" | \"root\" | \"outFile\" | \"source\" | \"tags\">,\n styleImageHashes: string[],\n): string {\n return sha256(\n JSON.stringify({\n generator: spec.generator,\n prompt: spec.prompt,\n width: spec.width,\n height: spec.height,\n view: spec.view,\n outline: spec.outline ?? null,\n shading: spec.shading ?? null,\n detail: spec.detail ?? null,\n seed: spec.seed ?? null,\n palette: spec.palette,\n // `noBackground` only reaches the wire for pixflux; the tile fields are\n // undefined for every other generator. `tileSize` is intentionally\n // absent — width/height are derived from it, so it is already covered.\n noBackground: spec.generator === \"pixflux\" ? spec.noBackground : undefined,\n tileType: spec.tileType,\n tileView: spec.tileView,\n tileFeature: spec.tileFeature,\n outlineMode: spec.outlineMode,\n styleImages: styleImageHashes,\n }),\n )\n}\n","import { readFile, writeFile, rename, mkdir, rmdir, rm, stat } from \"node:fs/promises\"\nimport { existsSync } from \"node:fs\"\nimport path from \"node:path\"\nimport { parseLock, type Lock, type LockEntry } from \"./types.ts\"\nimport type { CostUnit } from \"./provider.ts\"\n\n/**\n * The lockfile is the record that maps a spec to the PixelLab object that\n * satisfies it and the file on disk that came from it. It is written after\n * every state transition — including immediately after submitting, before the\n * job is awaited — so an interrupted run never loses track of paid-for work.\n */\nexport async function loadLock(lockPath: string): Promise<Lock> {\n if (!existsSync(lockPath)) return { version: 2, entries: {} }\n try {\n return parseLock(JSON.parse(await readFile(lockPath, \"utf8\")))\n } catch (err) {\n throw new Error(\n `Lockfile at ${lockPath} is malformed:\\n${err instanceof Error ? err.message : String(err)}`,\n )\n }\n}\n\n/**\n * Serializes saves per path.\n *\n * Concurrent stages (parallel downloads in `fetch`) each save after their own\n * upsert. Without this they race on the shared `<path>.tmp`: one worker's\n * rename moves the file out from under another's, which fails with ENOENT and\n * loses that write. Queuing keeps the atomic write-then-rename intact and\n * guarantees the last save reflects the latest in-memory state.\n */\nconst saveQueues = new Map<string, Promise<void>>()\nconst dirtyPatches = new WeakMap<Lock, Map<string, Partial<LockEntry>>>()\nconst dirtyDeletes = new WeakMap<Lock, Set<string>>()\n\n/** Atomic write — a crash mid-save must not leave a truncated lockfile. */\nexport function saveLock(lockPath: string, lock: Lock): Promise<void> {\n const queueKey = path.resolve(lockPath)\n const previous = saveQueues.get(queueKey) ?? Promise.resolve()\n const next = previous\n .catch(() => {}) // one failed save must not poison every later one\n .then(() => writeLockNow(lockPath, lock))\n saveQueues.set(queueKey, next)\n // Drop the queue entry once drained so long-lived processes don't retain it.\n const cleanup = () => {\n if (saveQueues.get(queueKey) === next) saveQueues.delete(queueKey)\n }\n // Using `finally()` here would create a second rejected promise when a save\n // fails. If nobody observes that derived promise Node reports an unhandled\n // rejection even when the caller correctly handles `next`.\n void next.then(cleanup, cleanup)\n return next\n}\n\nasync function writeLockNow(lockPath: string, lock: Lock): Promise<void> {\n await mkdir(path.dirname(path.resolve(lockPath)), { recursive: true })\n const release = await acquireFileLock(lockPath)\n try {\n await writeLockWhileHeld(lockPath, lock)\n } finally {\n await release()\n }\n}\n\nasync function writeLockWhileHeld(file: string, lock: Lock): Promise<void> {\n let disk: Lock = { version: 2, entries: {} }\n if (existsSync(file)) {\n try {\n disk = parseLock(JSON.parse(await readFile(file, \"utf8\")))\n } catch (err) {\n throw new Error(\n `Refusing to overwrite malformed lockfile at ${file}: ` +\n `${err instanceof Error ? err.message : String(err)}`,\n )\n }\n }\n\n const dirty = dirtyPatches.get(lock) ?? new Map<string, Partial<LockEntry>>()\n const snapshot = new Map<string, Partial<LockEntry>>()\n for (const [key, patch] of dirty) snapshot.set(key, { ...patch })\n\n const merged: Lock[\"entries\"] = { ...disk.entries }\n for (const [key, patch] of snapshot) {\n const local = lock.entries[key]\n if (!local) continue\n merged[key] = merged[key] ? ({ ...merged[key], ...patch } as LockEntry) : local\n }\n // Preserve entries inserted directly by library callers. Production code\n // uses `upsert`, which additionally gives us field-level merge precision.\n for (const [key, entry] of Object.entries(lock.entries)) {\n if (!merged[key]) merged[key] = entry\n }\n\n // Removals are intents, recorded by `remove`, and are applied last. Merging\n // starts from the disk view so a concurrent writer's entries survive, which\n // means a key deleted only from `lock.entries` is read straight back off\n // disk and silently resurrected. Applying deletions after both merge passes\n // is what makes a removal actually stick.\n const deletes = dirtyDeletes.get(lock)\n const deleteSnapshot = deletes ? new Set(deletes) : new Set<string>()\n for (const key of deleteSnapshot) delete merged[key]\n\n const sorted: Lock[\"entries\"] = {}\n for (const key of Object.keys(merged).sort()) {\n sorted[key] = merged[key]!\n }\n const tmp = `${file}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`\n try {\n await writeFile(tmp, JSON.stringify({ version: 2, entries: sorted }, null, 2) + \"\\n\")\n await rename(tmp, file)\n } finally {\n await rm(tmp, { force: true })\n }\n\n // Clear only fields included in this snapshot. Mutations made while the\n // write awaited I/O remain dirty and are reapplied to the merged disk view.\n const currentDirty = dirtyPatches.get(lock)\n if (currentDirty) {\n for (const [key, patch] of snapshot) {\n const current = currentDirty.get(key)\n if (!current) continue\n for (const [field, value] of Object.entries(patch)) {\n if (Object.is(current[field as keyof LockEntry], value)) {\n delete current[field as keyof LockEntry]\n }\n }\n if (Object.keys(current).length === 0) currentDirty.delete(key)\n }\n }\n\n const stillDirty = dirtyDeletes.get(lock)\n if (stillDirty) {\n for (const key of deleteSnapshot) stillDirty.delete(key)\n if (stillDirty.size === 0) dirtyDeletes.delete(lock)\n }\n\n const localAfterWrite = lock.entries\n lock.entries = { ...merged }\n for (const [key, patch] of currentDirty ?? []) {\n const base = lock.entries[key] ?? localAfterWrite[key]\n if (base) lock.entries[key] = { ...base, ...patch } as LockEntry\n }\n}\n\nexport function upsert(lock: Lock, key: string, patch: Partial<LockEntry>): LockEntry {\n // Re-adding a key cancels any pending removal, or the save would delete the\n // entry that was just written.\n dirtyDeletes.get(lock)?.delete(key)\n const existing = lock.entries[key]\n const next = { ...existing, ...patch } as LockEntry\n lock.entries[key] = next\n let dirty = dirtyPatches.get(lock)\n if (!dirty) {\n dirty = new Map()\n dirtyPatches.set(lock, dirty)\n }\n dirty.set(key, { ...(dirty.get(key) ?? {}), ...patch })\n return next\n}\n\n/**\n * Drop a lock entry, and record the removal so the next save honours it.\n *\n * Deleting from `lock.entries` alone does nothing: `writeLockWhileHeld` merges\n * onto whatever is on disk, so the entry is read back and restored. Callers\n * that need an entry gone must come through here. Returns false when the key\n * was not present, so a caller can tell a no-op from a removal.\n */\nexport function remove(lock: Lock, key: string): boolean {\n if (!lock.entries[key]) return false\n delete lock.entries[key]\n const patches = dirtyPatches.get(lock)\n if (patches) {\n patches.delete(key)\n if (patches.size === 0) dirtyPatches.delete(lock)\n }\n let deletes = dirtyDeletes.get(lock)\n if (!deletes) {\n deletes = new Set()\n dirtyDeletes.set(lock, deletes)\n }\n deletes.add(key)\n return true\n}\n\nconst FILE_LOCK_TIMEOUT_MS = 10_000\nconst STALE_FILE_LOCK_MS = 2 * 60 * 1000\n\nasync function acquireFileLock(file: string): Promise<() => Promise<void>> {\n const lockDir = `${file}.lock`\n const deadline = Date.now() + FILE_LOCK_TIMEOUT_MS\n for (;;) {\n try {\n await mkdir(lockDir)\n return async () => {\n await rmdir(lockDir).catch(() => {})\n }\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code\n if (code !== \"EEXIST\") throw err\n try {\n const age = Date.now() - (await stat(lockDir)).mtimeMs\n if (age > STALE_FILE_LOCK_MS) {\n await rmdir(lockDir)\n continue\n }\n } catch (lockErr) {\n if ((lockErr as NodeJS.ErrnoException).code === \"ENOENT\") continue\n }\n if (Date.now() >= deadline) {\n throw new Error(`Timed out waiting for lockfile writer ${lockDir}`)\n }\n await new Promise((resolve) => setTimeout(resolve, 25 + Math.floor(Math.random() * 25)))\n }\n }\n}\n\n/** Recorded successful-submission estimates, kept separate by provider unit. */\nexport function spendByUnit(lock: Lock): Record<CostUnit, number> {\n const totals: Record<CostUnit, number> = { generations: 0, usd: 0, free: 0 }\n for (const entry of Object.values(lock.entries)) {\n totals[entry.costUnit ?? \"generations\"] += entry.cost ?? 0\n }\n return totals\n}\n\n/** @deprecated Prefer spendByUnit; summing unlike provider units is unsafe. */\nexport function totalSpend(lock: Lock, unit: CostUnit = \"generations\"): number {\n return spendByUnit(lock)[unit]\n}\n","import path from \"node:path\"\nimport { upsert } from \"./lock.ts\"\nimport { lockKey, type Lock, type LockEntry, type LockOutput, type ResolvedSpec } from \"./types.ts\"\n\n/** One lockfile output with the identity consumers should expose publicly. */\nexport interface ResolvedOutput extends LockOutput {\n assetId: string\n /** Stable within a style's atlas or report. Single-output assets keep their old id. */\n id: string\n index: number\n absolutePath: string\n}\n\n/** Store generated paths relative to the manifest so committed locks survive a clone/move. */\nexport function portableOutputPath(file: string, manifestDir: string): string {\n const root = path.resolve(manifestDir)\n const absolute = path.isAbsolute(file) ? path.normalize(file) : path.resolve(root, file)\n const relative = path.relative(root, absolute)\n // Different Windows drives cannot be expressed as a relative path. This is\n // the one case where retaining an absolute path is more honest than writing\n // a value that resolves somewhere else.\n const value = path.isAbsolute(relative) ? absolute : relative\n return value.split(path.sep).join(\"/\")\n}\n\n/** Resolve a portable lock path against the manifest, never the process cwd. */\nexport function resolveOutputPath(recordedPath: string, manifestDir: string): string {\n if (path.isAbsolute(recordedPath)) return path.normalize(recordedPath)\n // A lock committed by Windows before paths became portable cannot be opened\n // directly on POSIX. `normalizeLockOutputPaths` rebases it from the spec.\n if (path.win32.isAbsolute(recordedPath)) return recordedPath\n return path.resolve(manifestDir, recordedPath.split(/[\\\\/]/).join(path.sep))\n}\n\n/** Deterministic current destination for one provider output. */\nexport function expectedOutputPath(\n spec: ResolvedSpec,\n role: string | undefined,\n index: number,\n total: number,\n): string {\n if (total === 1) return spec.outFile\n const originalExt = path.extname(spec.outFile)\n const ext = originalExt || \".png\"\n const stem = originalExt ? spec.outFile.slice(0, -originalExt.length) : spec.outFile\n const safeRole = (role ?? fallbackOutputRole(index)).replace(/[^a-zA-Z0-9_-]+/g, \"-\")\n return `${stem}-${safeRole}${ext}`\n}\n\n/** Resolve one recorded output from the current manifest-owned destination. */\nexport function currentOutputPath(\n output: Pick<LockOutput, \"path\" | \"role\">,\n spec: ResolvedSpec,\n index: number,\n total: number,\n): string {\n // The lock records where bytes were written; the manifest owns where they\n // belong now. Always deriving from the current spec both rebases a clone and\n // prevents a hand-edited lock path from redirecting restore into an unrelated\n // project file. Output roles preserve structural-set identity.\n return expectedOutputPath(spec, output.role, index, total)\n}\n\n/** Resolve an entry member using the complete source-set order when available. */\nexport function currentEntryOutputPath(\n entry: LockEntry,\n spec: ResolvedSpec,\n index: number,\n): string {\n const output = entry.outputs[index]!\n const sourceIndex = output.role\n ? (entry.sourceUrls ?? []).findIndex((source) => source.role === output.role)\n : -1\n const position = sourceIndex >= 0 ? sourceIndex : index\n const total = Math.max(entry.outputs.length, entry.sourceUrls?.length ?? 0)\n return currentOutputPath(output, spec, position, total)\n}\n\n/**\n * Rebase legacy absolute output paths onto this checkout and canonicalize all\n * selected entries in memory. Persistence remains the caller's decision.\n */\nexport function normalizeLockOutputPaths(lock: Lock, specs: ResolvedSpec[]): number {\n const byKey = new Map(specs.map((spec) => [lockKey(spec.styleId, spec.assetId), spec]))\n let changed = 0\n for (const [key, entry] of Object.entries(lock.entries)) {\n const spec = byKey.get(key)\n if (!spec) continue\n let entryChanged = false\n const outputs = entry.outputs.map((output, index) => {\n const absolute = currentEntryOutputPath(entry, spec, index)\n const portable = portableOutputPath(absolute, spec.root)\n if (portable === output.path) return output\n changed++\n entryChanged = true\n return { ...output, path: portable }\n })\n if (entryChanged) upsert(lock, key, { outputs })\n }\n return changed\n}\n\n/** The fallback role used when a provider returns several unnamed outputs. */\nexport function fallbackOutputRole(index: number): string {\n return `output-${String(index).padStart(2, \"0\")}`\n}\n\n/**\n * Gives every output a stable, collision-resistant consumer id.\n *\n * A conventional one-file asset remains `grass`, preserving existing atlas\n * lookups. A structural set becomes `grass/tile-00`, `grass/tile-01`, … so no\n * downstream command has to silently pretend its first file is the whole set.\n */\nexport function outputId(\n assetId: string,\n output: Pick<LockOutput, \"role\">,\n index: number,\n total: number,\n): string {\n if (total === 1) return assetId\n return `${assetId}/${output.role ?? fallbackOutputRole(index)}`\n}\n\n/** Resolve every output recorded for one manifest asset, preserving lock order. */\nexport function resolveEntryOutputs(\n entry: LockEntry,\n assetId: string,\n manifestDir: string,\n): ResolvedOutput[] {\n return entry.outputs.map((output, index) => ({\n ...output,\n assetId,\n id: outputId(assetId, output, index, entry.outputs.length),\n index,\n absolutePath: resolveOutputPath(output.path, manifestDir),\n }))\n}\n\n/** Resolve an entry using its current spec, including cross-checkout v2 migration. */\nexport function resolveSpecEntryOutputs(\n entry: LockEntry,\n spec: ResolvedSpec,\n): ResolvedOutput[] {\n return entry.outputs.map((output, index) => ({\n ...output,\n assetId: spec.assetId,\n id: outputId(spec.assetId, output, index, entry.outputs.length),\n index,\n absolutePath: currentEntryOutputPath(entry, spec, index),\n }))\n}\n\n/** Resolve all outputs for a style in deterministic asset-id order. */\nexport function resolveStyleOutputs(\n lock: Lock,\n styleId: string,\n manifestDir: string,\n): ResolvedOutput[] {\n const prefix = `${styleId}/`\n return Object.entries(lock.entries)\n .filter(([key]) => key.startsWith(prefix))\n .sort(([a], [b]) => a.localeCompare(b))\n .flatMap(([key, entry]) =>\n resolveEntryOutputs(entry, key.slice(prefix.length), manifestDir),\n )\n}\n\nexport type OutputSelection =\n | { ok: true; output: LockOutput }\n | { ok: false; reason: string }\n\n/**\n * Select the one output needed by a single-cell consumer such as `mount`.\n * Multi-output sets are deliberately ambiguous unless the manifest names a\n * role; choosing index zero is silent data loss disguised as convenience.\n */\nexport function selectEntryOutput(entry: LockEntry, role?: string): OutputSelection {\n if (role) {\n const output = entry.outputs.find((candidate) => candidate.role === role)\n return output\n ? { ok: true, output }\n : { ok: false, reason: `output role \"${role}\" is not recorded` }\n }\n if (entry.outputs.length === 0) return { ok: false, reason: \"no output recorded in the lockfile\" }\n if (entry.outputs.length === 1) return { ok: true, output: entry.outputs[0]! }\n\n const primary = entry.outputs.filter((output) => !output.role)\n if (primary.length === 1) return { ok: true, output: primary[0]! }\n return {\n ok: false,\n reason: `${entry.outputs.length} outputs are recorded; set \\`outputRole\\` to choose one`,\n }\n}\n\n/** Lock outputs for a resolved spec, or its conventional path before adoption. */\nexport function resolveSpecOutputs(\n spec: ResolvedSpec,\n lock: Lock | undefined,\n manifestDir: string,\n): ResolvedOutput[] {\n const entry = lock?.entries[lockKey(spec.styleId, spec.assetId)]\n if (entry?.outputs.length) return resolveSpecEntryOutputs(entry, spec)\n return [{\n assetId: spec.assetId,\n id: spec.assetId,\n index: 0,\n path: spec.outFile,\n absolutePath: path.resolve(spec.outFile),\n sha256: \"\",\n }]\n}\n","import path from \"node:path\"\nimport { createHash, randomUUID } from \"node:crypto\"\nimport { mkdir, readFile, rename, rm, writeFile } from \"node:fs/promises\"\n\nexport interface ArtifactFile {\n path: string\n data: string | Uint8Array\n}\n\nexport interface ArtifactBundleResult {\n changed: string[]\n unchanged: string[]\n}\n\nexport interface ArtifactBundleOptions {\n /** @internal Failure-injection hook used to verify staging cleanup. */\n beforeStage?: (destination: string, index: number) => void | Promise<void>\n /** @internal Failure-injection hook used to verify rollback behavior. */\n beforePromote?: (destination: string, index: number) => void | Promise<void>\n /** @internal Durable transaction journal used by the managed writer. */\n recoveryFile?: string\n /** @internal Failure-injection hook used to simulate a crash after commit. */\n afterCommit?: () => void | Promise<void>\n}\n\nexport interface ManagedArtifactBundleOptions extends ArtifactBundleOptions {\n /** Explicitly replace unowned or manually modified destinations. */\n force?: boolean\n}\n\nexport interface ArtifactSource {\n id: string\n path: string\n sha256: string | null\n included: boolean\n}\n\nexport interface ArtifactProvenance {\n kind: \"pack\" | \"mount\" | \"tileset\"\n sources: ArtifactSource[]\n /** Every non-source input that can change the derived bytes. */\n options: unknown\n}\n\nexport interface ArtifactBundleManifest {\n format: \"pixelkiln-artifact-bundle\"\n version: 1\n kind: ArtifactProvenance[\"kind\"]\n fingerprint: string\n sources: ArtifactSource[]\n options: unknown\n outputs: Array<{ path: string; sha256: string }>\n}\n\nexport interface ArtifactVerification {\n current: boolean\n fingerprintValid: boolean\n changedSources: string[]\n changedOutputs: string[]\n}\n\ninterface PreparedArtifact {\n destination: string\n data: Buffer\n existed: boolean\n stage?: string\n backup?: string\n backedUp: boolean\n promoted: boolean\n}\n\ninterface ArtifactTransaction {\n format: \"pixelkiln-artifact-transaction\"\n version: 1\n pid: number\n createdAt: string\n entries: Array<{\n destination: string\n stage: string\n backup?: string\n sha256: string\n }>\n}\n\nconst activeTransactions = new Set<string>()\n\nfunction message(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n\nfunction digest(data: string | Uint8Array): string {\n return createHash(\"sha256\").update(data).digest(\"hex\")\n}\n\nfunction portableRelative(from: string, to: string): string {\n return path.relative(from, path.resolve(to)).split(path.sep).join(\"/\") || \".\"\n}\n\nfunction canonical(value: unknown): unknown {\n if (value === null || typeof value === \"string\" || typeof value === \"boolean\") return value\n if (typeof value === \"number\") {\n if (!Number.isFinite(value)) throw new Error(\"Artifact provenance numbers must be finite.\")\n return value\n }\n if (Array.isArray(value)) return value.map(canonical)\n if (typeof value === \"object\") {\n const sorted: Record<string, unknown> = {}\n for (const key of Object.keys(value).sort()) {\n const item = (value as Record<string, unknown>)[key]\n if (item !== undefined) sorted[key] = canonical(item)\n }\n return sorted\n }\n throw new Error(`Artifact provenance cannot contain ${typeof value} values.`)\n}\n\nfunction fingerprint(provenance: Pick<ArtifactBundleManifest, \"kind\" | \"sources\" | \"options\" | \"outputs\">): string {\n return digest(JSON.stringify(canonical({\n kind: provenance.kind,\n sources: provenance.sources,\n options: provenance.options,\n outputs: provenance.outputs,\n })))\n}\n\nfunction parseArtifactManifest(absolute: string, data: string): ArtifactBundleManifest {\n let raw: Partial<ArtifactBundleManifest>\n try {\n raw = JSON.parse(data) as Partial<ArtifactBundleManifest>\n } catch (error) {\n throw new Error(`${absolute} is not valid JSON: ${message(error)}`, { cause: error })\n }\n if (\n raw.format !== \"pixelkiln-artifact-bundle\" ||\n raw.version !== 1 ||\n (raw.kind !== \"pack\" && raw.kind !== \"mount\" && raw.kind !== \"tileset\") ||\n typeof raw.fingerprint !== \"string\" ||\n raw.options === undefined ||\n !Array.isArray(raw.sources) ||\n !Array.isArray(raw.outputs)\n ) {\n throw new Error(`${absolute} is not a PixelKiln artifact bundle manifest.`)\n }\n for (const source of raw.sources) {\n if (\n !source ||\n typeof source.id !== \"string\" ||\n typeof source.path !== \"string\" ||\n (source.sha256 !== null && typeof source.sha256 !== \"string\") ||\n typeof source.included !== \"boolean\"\n ) {\n throw new Error(`${absolute} contains an invalid artifact source.`)\n }\n }\n for (const output of raw.outputs) {\n if (!output || typeof output.path !== \"string\" || typeof output.sha256 !== \"string\") {\n throw new Error(`${absolute} contains an invalid artifact output.`)\n }\n }\n return raw as ArtifactBundleManifest\n}\n\nasync function readOptional(file: string): Promise<Buffer | null> {\n try {\n return await readFile(file)\n } catch (error) {\n if (isCode(error, \"ENOENT\")) return null\n throw error\n }\n}\n\nfunction transactionMarker(journal: string): string {\n return `${journal}.committed`\n}\n\nfunction processIsAlive(pid: number): boolean {\n if (!Number.isInteger(pid) || pid < 1) return false\n try {\n process.kill(pid, 0)\n return true\n } catch (error) {\n return !isCode(error, \"ESRCH\")\n }\n}\n\nfunction validTemporaryPath(\n candidate: string,\n destination: string,\n type: \"stage\" | \"backup\",\n): boolean {\n return (\n path.dirname(candidate) === path.dirname(destination) &&\n path.basename(candidate).startsWith(\n `.${path.basename(destination)}.pixelkiln-${type}-`,\n )\n )\n}\n\nfunction parseTransaction(journal: string, data: string): ArtifactTransaction {\n let raw: Partial<ArtifactTransaction>\n try {\n raw = JSON.parse(data) as Partial<ArtifactTransaction>\n } catch (error) {\n throw new Error(`${journal} is not valid transaction JSON: ${message(error)}`, { cause: error })\n }\n if (\n raw.format !== \"pixelkiln-artifact-transaction\" ||\n raw.version !== 1 ||\n !Number.isInteger(raw.pid) ||\n typeof raw.createdAt !== \"string\" ||\n !Array.isArray(raw.entries) ||\n !raw.entries.length\n ) {\n throw new Error(`${journal} is not a PixelKiln artifact transaction.`)\n }\n return raw as ArtifactTransaction\n}\n\nasync function removeTransactionFiles(journal: string): Promise<void> {\n // Journal first: a marker without a journal means the destinations were\n // already committed and cleanup may safely be considered complete.\n await rm(journal, { force: true })\n await rm(transactionMarker(journal), { force: true })\n}\n\nasync function recoverArtifactTransaction(\n recoveryFile: string,\n allowedDestinations: Set<string>,\n): Promise<void> {\n const journal = path.resolve(recoveryFile)\n const bytes = await readOptional(journal)\n if (!bytes) {\n await rm(transactionMarker(journal), { force: true })\n return\n }\n\n if (activeTransactions.has(journal)) {\n throw new Error(`Another artifact write in this process is already using ${journal}.`)\n }\n const transaction = parseTransaction(journal, bytes.toString(\"utf8\"))\n if (transaction.pid !== process.pid && processIsAlive(transaction.pid)) {\n throw new Error(\n `Artifact transaction ${journal} is still owned by live process ${transaction.pid}; ` +\n `refusing concurrent recovery.`,\n )\n }\n\n for (const entry of transaction.entries) {\n if (\n typeof entry.destination !== \"string\" ||\n typeof entry.stage !== \"string\" ||\n typeof entry.sha256 !== \"string\" ||\n (entry.backup !== undefined && typeof entry.backup !== \"string\") ||\n !allowedDestinations.has(path.resolve(entry.destination)) ||\n !validTemporaryPath(entry.stage, entry.destination, \"stage\") ||\n (entry.backup !== undefined && !validTemporaryPath(entry.backup, entry.destination, \"backup\"))\n ) {\n throw new Error(\n `Refusing unsafe artifact recovery from ${journal}; its destinations or temporary ` +\n `paths do not match the current bundle.`,\n )\n }\n }\n\n const committed = (await readOptional(transactionMarker(journal))) !== null\n const errors: string[] = []\n if (committed) {\n for (const entry of transaction.entries) {\n if (entry.backup) await remove(entry.backup, errors)\n await remove(entry.stage, errors)\n }\n } else {\n for (const entry of [...transaction.entries].reverse()) {\n const backup = entry.backup ? await readOptional(entry.backup) : null\n const destination = await readOptional(entry.destination)\n if (backup) {\n if (destination && digest(destination) !== entry.sha256) {\n errors.push(\n `destination changed during interrupted recovery: ${entry.destination}; ` +\n `previous file remains at ${entry.backup}`,\n )\n continue\n }\n await remove(entry.destination, errors)\n try {\n await rename(entry.backup!, entry.destination)\n } catch (error) {\n errors.push(\n `could not restore ${entry.destination}; previous file remains at ` +\n `${entry.backup}: ${message(error)}`,\n )\n }\n } else if (destination && digest(destination) === entry.sha256) {\n await remove(entry.destination, errors)\n }\n await remove(entry.stage, errors)\n }\n }\n\n if (errors.length) {\n throw new Error(\n `Artifact transaction recovery needs attention; journal retained at ${journal}: ` +\n errors.join(\"; \"),\n )\n }\n await removeTransactionFiles(journal)\n}\n\n/** Build the deterministic companion metadata written beside a derived bundle. */\nexport function createArtifactBundleManifest(\n manifestPath: string,\n outputs: ArtifactFile[],\n provenance: ArtifactProvenance,\n): ArtifactBundleManifest {\n const root = path.dirname(path.resolve(manifestPath))\n const sources = provenance.sources.map((source) => ({\n ...source,\n path: portableRelative(root, source.path),\n }))\n const normalized = {\n kind: provenance.kind,\n sources,\n options: canonical(provenance.options),\n }\n const manifestOutputs = outputs.map((output) => ({\n path: portableRelative(root, output.path),\n sha256: digest(output.data),\n }))\n return {\n format: \"pixelkiln-artifact-bundle\",\n version: 1,\n ...normalized,\n fingerprint: fingerprint({ ...normalized, outputs: manifestOutputs }),\n outputs: manifestOutputs,\n }\n}\n\n/** Add deterministic provenance metadata to a related set of generated files. */\nexport function withArtifactManifest(\n manifestPath: string,\n outputs: ArtifactFile[],\n provenance: ArtifactProvenance,\n): ArtifactFile[] {\n const manifest = createArtifactBundleManifest(manifestPath, outputs, provenance)\n return [\n ...outputs,\n { path: manifestPath, data: JSON.stringify(manifest, null, 2) + \"\\n\" },\n ]\n}\n\n/**\n * Persist a generated bundle while protecting files not demonstrably owned by\n * its existing companion manifest. Byte-identical legacy files are adopted\n * without rewriting; `force` is required to take over anything else.\n */\nexport async function writeManagedArtifactBundle(\n manifestPath: string,\n outputs: ArtifactFile[],\n provenance: ArtifactProvenance,\n options: ManagedArtifactBundleOptions = {},\n): Promise<ArtifactBundleResult> {\n const absoluteManifest = path.resolve(manifestPath)\n const recoveryFile = `${absoluteManifest}.transaction`\n const allowedDestinations = new Set([\n absoluteManifest,\n ...outputs.map((output) => path.resolve(output.path)),\n ])\n await recoverArtifactTransaction(recoveryFile, allowedDestinations)\n const existingManifestBytes = await readOptional(absoluteManifest)\n let previous: ArtifactBundleManifest | null = null\n\n if (existingManifestBytes && !options.force) {\n try {\n previous = parseArtifactManifest(absoluteManifest, existingManifestBytes.toString(\"utf8\"))\n const valid = previous.fingerprint === fingerprint(previous)\n if (!valid) throw new Error(\"its integrity fingerprint does not match\")\n } catch (error) {\n throw new Error(\n `Refusing to replace unrecognized or modified provenance at ${absoluteManifest}: ` +\n `${message(error)}. Pass { force: true } (CLI: --force) to take ownership ` +\n `of this artifact bundle.`,\n { cause: error },\n )\n }\n }\n\n if (!options.force) {\n const root = path.dirname(absoluteManifest)\n const recorded = new Map(\n previous?.outputs.map((output) => [path.resolve(root, output.path), output.sha256]) ?? [],\n )\n const conflicts: string[] = []\n for (const output of outputs) {\n const destination = path.resolve(output.path)\n const current = await readOptional(destination)\n if (!current || digest(current) === digest(output.data)) continue\n const expected = recorded.get(destination)\n if (!expected || digest(current) !== expected) conflicts.push(destination)\n }\n if (conflicts.length) {\n throw new Error(\n `Refusing to overwrite modified or unowned artifact file(s):\\n` +\n conflicts.map((file) => ` ${file}`).join(\"\\n\") +\n `\\nPass { force: true } (CLI: --force) to take ownership and replace ` +\n `the complete bundle.`,\n )\n }\n }\n\n const { force: _force, ...bundleOptions } = options\n return writeArtifactBundle(\n withArtifactManifest(absoluteManifest, outputs, provenance),\n { ...bundleOptions, recoveryFile },\n )\n}\n\n/** Verify stored provenance and source/output hashes without rebuilding output. */\nexport async function verifyArtifactBundle(manifestPath: string): Promise<ArtifactVerification> {\n const absolute = path.resolve(manifestPath)\n const raw = parseArtifactManifest(absolute, await readFile(absolute, \"utf8\"))\n\n const root = path.dirname(absolute)\n const changedSources: string[] = []\n const changedOutputs: string[] = []\n for (const source of raw.sources) {\n let actual: string | null = null\n try {\n actual = digest(await readFile(path.resolve(root, source.path)))\n } catch (error) {\n if (!isCode(error, \"ENOENT\")) throw error\n }\n if (actual !== source.sha256) changedSources.push(source.id)\n }\n for (const output of raw.outputs) {\n try {\n if (digest(await readFile(path.resolve(root, output.path))) !== output.sha256) {\n changedOutputs.push(output.path)\n }\n } catch (error) {\n if (!isCode(error, \"ENOENT\")) throw error\n changedOutputs.push(output.path)\n }\n }\n\n const fingerprintValid = raw.fingerprint === fingerprint({\n kind: raw.kind,\n sources: raw.sources,\n options: raw.options,\n outputs: raw.outputs,\n })\n return {\n current: fingerprintValid && !changedSources.length && !changedOutputs.length,\n fingerprintValid,\n changedSources,\n changedOutputs,\n }\n}\n\nfunction isCode(error: unknown, code: string): boolean {\n return typeof error === \"object\" && error !== null && \"code\" in error && error.code === code\n}\n\nasync function remove(file: string, errors?: string[]): Promise<void> {\n try {\n await rm(file, { force: true })\n } catch (error) {\n errors?.push(`could not remove ${file}: ${message(error)}`)\n }\n}\n\nasync function rollback(prepared: PreparedArtifact[]): Promise<string[]> {\n const errors: string[] = []\n\n // Remove newly-promoted members before putting their previous versions back.\n for (const artifact of [...prepared].reverse()) {\n if (artifact.promoted) await remove(artifact.destination, errors)\n }\n\n for (const artifact of [...prepared].reverse()) {\n if (!artifact.backup || !artifact.backedUp) continue\n try {\n await rename(artifact.backup, artifact.destination)\n artifact.backedUp = false\n } catch (error) {\n errors.push(\n `could not restore ${artifact.destination}; previous file remains at ` +\n `${artifact.backup}: ${message(error)}`,\n )\n }\n }\n\n for (const artifact of prepared) {\n if (artifact.stage) await remove(artifact.stage, errors)\n }\n return errors\n}\n\n/**\n * Write a related set of generated files without leaving a partial bundle\n * after an ordinary write failure.\n *\n * All changed members are staged before any destination is replaced. If an\n * ordinary filesystem error interrupts promotion, prior files are restored.\n * Byte-identical members are not rewritten.\n */\nexport async function writeArtifactBundle(\n files: ArtifactFile[],\n options: ArtifactBundleOptions = {},\n): Promise<ArtifactBundleResult> {\n if (!files.length) throw new Error(\"An artifact bundle must contain at least one file.\")\n\n const normalized = files.map((file) => {\n if (!file.path.trim()) throw new Error(\"Artifact paths cannot be empty.\")\n return { destination: path.resolve(file.path), data: Buffer.from(file.data) }\n })\n const destinations = new Set<string>()\n for (const artifact of normalized) {\n if (destinations.has(artifact.destination)) {\n throw new Error(`Artifact bundle contains duplicate destination: ${artifact.destination}`)\n }\n destinations.add(artifact.destination)\n }\n if (options.recoveryFile) {\n await recoverArtifactTransaction(options.recoveryFile, destinations)\n }\n\n const changed: PreparedArtifact[] = []\n const unchanged: string[] = []\n for (const artifact of normalized) {\n try {\n const current = await readFile(artifact.destination)\n if (current.equals(artifact.data)) {\n unchanged.push(artifact.destination)\n } else {\n changed.push({ ...artifact, existed: true, backedUp: false, promoted: false })\n }\n } catch (error) {\n if (!isCode(error, \"ENOENT\")) throw error\n changed.push({ ...artifact, existed: false, backedUp: false, promoted: false })\n }\n }\n\n if (!changed.length) return { changed: [], unchanged }\n\n const token = randomUUID()\n for (const [index, artifact] of changed.entries()) {\n const basename = path.basename(artifact.destination)\n artifact.stage = path.join(\n path.dirname(artifact.destination),\n `.${basename}.pixelkiln-stage-${token}-${index}`,\n )\n if (artifact.existed) {\n artifact.backup = path.join(\n path.dirname(artifact.destination),\n `.${basename}.pixelkiln-backup-${token}-${index}`,\n )\n }\n }\n\n const journal = options.recoveryFile ? path.resolve(options.recoveryFile) : null\n if (journal) {\n await mkdir(path.dirname(journal), { recursive: true })\n const transaction: ArtifactTransaction = {\n format: \"pixelkiln-artifact-transaction\",\n version: 1,\n pid: process.pid,\n createdAt: new Date().toISOString(),\n entries: changed.map((artifact) => ({\n destination: artifact.destination,\n stage: artifact.stage!,\n ...(artifact.backup ? { backup: artifact.backup } : {}),\n sha256: digest(artifact.data),\n })),\n }\n try {\n await writeFile(journal, JSON.stringify(transaction, null, 2) + \"\\n\", { flag: \"wx\" })\n activeTransactions.add(journal)\n } catch (error) {\n throw new Error(\n `Could not start durable artifact transaction at ${journal}: ${message(error)}`,\n { cause: error },\n )\n }\n }\n\n try {\n for (const [index, artifact] of changed.entries()) {\n await mkdir(path.dirname(artifact.destination), { recursive: true })\n await options.beforeStage?.(artifact.destination, index)\n await writeFile(artifact.stage!, artifact.data, { flag: \"wx\" })\n }\n } catch (error) {\n const cleanupErrors = await rollback(changed)\n if (journal && !cleanupErrors.length) await removeTransactionFiles(journal)\n if (journal) activeTransactions.delete(journal)\n const suffix = cleanupErrors.length ? ` Cleanup also failed: ${cleanupErrors.join(\"; \")}` : \"\"\n throw new Error(`Could not stage artifact bundle: ${message(error)}.${suffix}`, { cause: error })\n }\n\n let durableCommit = false\n try {\n // Move every prior member aside first. Once promotion begins, rollback has\n // a complete snapshot even when several destinations are being replaced.\n for (const artifact of changed) {\n if (!artifact.existed) continue\n await rename(artifact.destination, artifact.backup!)\n artifact.backedUp = true\n }\n\n for (const [index, artifact] of changed.entries()) {\n await options.beforePromote?.(artifact.destination, index)\n await rename(artifact.stage!, artifact.destination)\n artifact.stage = undefined\n artifact.promoted = true\n }\n if (journal) {\n await writeFile(transactionMarker(journal), `${token}\\n`, { flag: \"wx\" })\n durableCommit = true\n await options.afterCommit?.()\n }\n } catch (error) {\n if (durableCommit) {\n if (journal) activeTransactions.delete(journal)\n throw new Error(\n `Artifact bundle was committed, but final cleanup was interrupted: ${message(error)}. ` +\n `The next write will finish cleanup from ${journal}.`,\n { cause: error },\n )\n }\n const rollbackErrors = await rollback(changed)\n if (journal && !rollbackErrors.length) await removeTransactionFiles(journal)\n if (journal) activeTransactions.delete(journal)\n const suffix = rollbackErrors.length\n ? ` Rollback needs attention: ${rollbackErrors.join(\"; \")}`\n : \" Previous bundle restored.\"\n throw new Error(`Could not promote artifact bundle: ${message(error)}.${suffix}`, { cause: error })\n }\n\n const cleanupErrors: string[] = []\n for (const artifact of changed) {\n if (artifact.backup) await remove(artifact.backup, cleanupErrors)\n }\n if (cleanupErrors.length) {\n if (journal) activeTransactions.delete(journal)\n throw new Error(\n `Artifact bundle was written, but old backup cleanup failed: ${cleanupErrors.join(\"; \")}`,\n )\n }\n if (journal) {\n try {\n await removeTransactionFiles(journal)\n } finally {\n activeTransactions.delete(journal)\n }\n }\n\n return {\n changed: changed.map((artifact) => artifact.destination),\n unchanged,\n }\n}\n","import { existsSync } from \"node:fs\"\nimport path from \"node:path\"\nimport { sha256File } from \"../hash.ts\"\nimport { currentEntryOutputPath } from \"../outputs.ts\"\nimport { lockKey, type Lock, type LockEntry, type ResolvedSpec } from \"../types.ts\"\nimport type { CostUnit } from \"../provider.ts\"\n\nexport type PlanState =\n | \"ok\" // spec unchanged, file present and matching — nothing to do\n | \"missing\" // no lock entry and no file — genuinely needs generating\n | \"untracked\" // file exists but has no lock entry; the art is fine, provenance is not known\n | \"stale\" // prompt/style/size changed since the file was made\n | \"orphaned\" // the bytes that should be on disk are gone or altered\n | \"in-flight\" // submitted, not yet downloaded\n | \"recoverable\" // generation succeeded; download can be retried without spending\n | \"failed\"\n\n/**\n * True if any recorded output no longer hashes to what was written.\n *\n * Checked across every output, not just the primary: a character's engine\n * resource being hand-edited matters as much as its spritesheets changing.\n */\nasync function anyOutputModified(entry: LockEntry, spec: ResolvedSpec): Promise<boolean> {\n for (let index = 0; index < entry.outputs.length; index++) {\n const output = entry.outputs[index]!\n if (\n (await sha256File(currentEntryOutputPath(entry, spec, index))) !== output.sha256\n ) return true\n }\n return false\n}\n\nexport interface PlanItem {\n spec: ResolvedSpec\n key: string\n state: PlanState\n reason: string\n}\n\nexport interface Plan {\n items: PlanItem[]\n /** Items that would incur provider cost if the plan were executed. */\n actionable: PlanItem[]\n cost: number\n costUnit: CostUnit\n candidates: number\n}\n\n/**\n * Diffs the manifest against the lockfile and the files on disk. Nothing here\n * touches the network, so it is safe to run constantly — it is the cheap\n * \"what would this cost me?\" question that should precede every real run.\n */\nexport async function buildPlan(\n specs: ResolvedSpec[],\n lock: Lock,\n opts: { force?: boolean } = {},\n): Promise<Plan> {\n const items: PlanItem[] = []\n\n for (const spec of specs) {\n const key = lockKey(spec.styleId, spec.assetId)\n const entry = lock.entries[key]\n\n let state: PlanState\n let reason: string\n\n if (opts.force) {\n state = \"missing\"\n reason = \"--force\"\n } else if (!entry && spec.source) {\n // An asset with a `source` is placed from committed art by `mount`, and\n // AssetSchema.source says it needs no lock entry at all. Treating it as\n // `missing` puts art pixelkiln did not make and will never generate into\n // the actionable list, and bills a generation cost for each one.\n if (existsSync(path.resolve(spec.root, spec.source))) {\n state = \"ok\"\n reason = `placed from ${spec.source}; not generated`\n } else {\n state = \"orphaned\"\n reason = `declared source is missing: ${spec.source}`\n }\n } else if (!entry) {\n // Distinguish \"no art\" from \"art exists but unmatched upstream\". Calling\n // the latter `missing` invites regenerating perfectly good files — which\n // is exactly what happens to assets that were retouched by hand after\n // download, since their bytes no longer match any remote object.\n if (existsSync(spec.outFile)) {\n state = \"untracked\"\n reason = \"file on disk, no provenance recorded\"\n } else {\n state = \"missing\"\n reason = \"not in lockfile\"\n }\n } else if (entry.specHash !== spec.specHash) {\n state = \"stale\"\n reason = \"prompt, size, or style changed\"\n } else if (entry.status === \"download-failed\") {\n state = \"recoverable\"\n reason = `${entry.error ?? \"download failed\"}; run fetch or restore (no generation cost)`\n } else if (entry.status === \"failed\") {\n state = \"failed\"\n reason = entry.error ?? \"previous attempt failed\"\n } else if (entry.status !== \"downloaded\") {\n state = \"in-flight\"\n reason = `awaiting ${entry.status}`\n } else if (\n entry.outputs.length === 0 ||\n entry.outputs.some((_output, index) =>\n !existsSync(currentEntryOutputPath(entry, spec, index)))\n ) {\n state = \"orphaned\"\n reason =\n entry.outputs.length === 0\n ? \"no recorded output files\"\n : `missing on disk: ${entry.outputs\n .filter((_output, index) =>\n !existsSync(currentEntryOutputPath(entry, spec, index)))\n .map((o) => o.role ?? \"asset\")\n .join(\", \")}`\n } else if (await anyOutputModified(entry, spec)) {\n // The file was edited by hand. That is a legitimate thing to do, so this\n // is reported rather than silently overwritten.\n state = \"orphaned\"\n reason = \"output modified since download\"\n } else {\n state = \"ok\"\n reason = \"up to date\"\n }\n\n items.push({ spec, key, state, reason })\n }\n\n // \"orphaned\" entries may be re-downloadable from a persisted object without\n // paying again; only genuinely new work is counted toward cost.\n const actionable = items.filter((i) => i.state === \"missing\" || i.state === \"stale\" || i.state === \"failed\")\n const units = new Set(actionable.map((item) => item.spec.costUnit ?? \"generations\"))\n if (units.size > 1) throw new Error(\"A single plan cannot combine incompatible provider cost units\")\n\n return {\n items,\n actionable,\n cost: actionable.reduce((sum, i) => sum + i.spec.cost, 0),\n costUnit: actionable[0]?.spec.costUnit ?? specs[0]?.costUnit ?? (specs.length ? \"generations\" : \"free\"),\n candidates: actionable.reduce((sum, i) => sum + i.spec.candidates, 0),\n }\n}\n\nexport function summarize(plan: Plan): Record<PlanState, number> {\n const counts = {\n ok: 0, missing: 0, untracked: 0, stale: 0, orphaned: 0, \"in-flight\": 0,\n recoverable: 0, failed: 0,\n } as Record<PlanState, number>\n for (const item of plan.items) counts[item.state]++\n return counts\n}\n","import { readFile } from \"node:fs/promises\"\nimport { existsSync } from \"node:fs\"\nimport path from \"node:path\"\nimport { decodePng, extractPalette, transparencyRatio, type PaletteEntry } from \"../png.ts\"\nimport type { LoadedManifest } from \"../manifest.ts\"\nimport type { Lock, ResolvedSpec } from \"../types.ts\"\nimport { resolveSpecOutputs } from \"../outputs.ts\"\n\n/**\n * Perceptual-ish distance between two colours, 0-255ish.\n *\n * \"Redmean\" — a cheap weighting that tracks human perception far better than\n * raw RGB euclidean and needs no colour-space conversion or dependency. Good\n * enough to rank outliers, which is all this is for; it is not colourimetry.\n */\nexport function colorDistance(\n a: { r: number; g: number; b: number },\n b: { r: number; g: number; b: number },\n): number {\n const rmean = (a.r + b.r) / 2\n const dr = a.r - b.r\n const dg = a.g - b.g\n const db = a.b - b.b\n return Math.sqrt(\n (((512 + rmean) * dr * dr) / 256) + 4 * dg * dg + (((767 - rmean) * db * db) / 256),\n )\n}\n\n/**\n * How far an asset's palette sits from a reference palette.\n *\n * For each colour in the asset, weighted by how much of the image it covers,\n * take the distance to its nearest reference colour. An asset built entirely\n * from on-style colours scores ~0; one introducing a foreign hue scores high\n * in proportion to how much of the image that hue occupies.\n */\nexport function paletteDistance(asset: PaletteEntry[], reference: PaletteEntry[]): number {\n if (!asset.length || !reference.length) return 0\n let total = 0\n let weight = 0\n for (const color of asset) {\n let nearest = Infinity\n for (const ref of reference) nearest = Math.min(nearest, colorDistance(color, ref))\n total += nearest * color.weight\n weight += color.weight\n }\n return weight === 0 ? 0 : total / weight\n}\n\n/** Merge many palettes into one, summing weights for repeated colours. */\nexport function mergePalettes(palettes: PaletteEntry[][], topN = 24): PaletteEntry[] {\n const totals = new Map<string, PaletteEntry>()\n for (const palette of palettes) {\n for (const color of palette) {\n const key = `${color.r},${color.g},${color.b}`\n const existing = totals.get(key)\n if (existing) existing.weight += color.weight\n else totals.set(key, { ...color })\n }\n }\n const merged = [...totals.values()].sort((a, b) => b.weight - a.weight).slice(0, topN)\n const sum = merged.reduce((s, c) => s + c.weight, 0) || 1\n return merged.map((c) => ({ ...c, weight: c.weight / sum }))\n}\n\nexport interface AssetAudit {\n assetId: string\n /** Present when this is one member of a structural multi-output asset. */\n outputRole?: string\n /** Stable report/atlas identity: assetId for one output, assetId/role for many. */\n id: string\n file: string\n width: number\n height: number\n /** Distance from the style's reference palette. Higher is more off-style. */\n paletteDistance: number\n /** Share of the canvas that is transparent. Very low suggests a baked background. */\n transparency: number\n /** Distinct opaque colours. Very high suggests photo-like rendering, not pixel art. */\n colorCount: number\n palette: PaletteEntry[]\n}\n\nexport interface StyleAudit {\n styleId: string\n /** True when the reference came from the style's own styleImages. */\n referenceFromStyleImages: boolean\n reference: PaletteEntry[]\n assets: AssetAudit[]\n missing: string[]\n unreadable: string[]\n}\n\nexport interface AuditThresholds {\n /** Absolute palette-distance ceiling. Omit to rely on relative outliers. */\n maxDistance?: number\n /** Minimum transparent share of the canvas, from 0 to 1. */\n minTransparency?: number\n /** Maximum number of distinct opaque colors. */\n maxColors?: number\n /** Relative outlier cutoff. Defaults to 1.5 standard deviations. */\n sigma?: number\n}\n\nexport interface AuditViolation {\n id: string\n reasons: string[]\n}\n\nexport interface AuditEvaluation {\n safe: boolean\n thresholds: Required<Pick<AuditThresholds, \"sigma\">> & Omit<AuditThresholds, \"sigma\">\n outliers: string[]\n violations: AuditViolation[]\n missing: string[]\n unreadable: string[]\n}\n\n/**\n * Measures how consistently a style's assets actually hold together.\n *\n * This exists to answer \"is this variant working?\" with a number instead of an\n * eyeball. Measured on a real neon trial, prose alone carried the style on\n * subjects with no strong inherent colour but was ignored on ones that had\n * some — a chocolate bar stayed brown, a camera stayed grey. Those are exactly\n * the assets this ranks to the top, before another 57 are generated to match.\n *\n * Reference palette comes from the style's `styleImages` when set, since those\n * are the declared intent. Otherwise the assets are compared against their own\n * collective palette, which still surfaces outliers but cannot tell you the\n * whole set has drifted together.\n */\nexport async function auditStyle(\n loaded: LoadedManifest,\n specs: ResolvedSpec[],\n styleId: string,\n lock?: Lock,\n): Promise<StyleAudit> {\n const style = loaded.manifest.styles[styleId]\n if (!style) throw new Error(`Unknown style \"${styleId}\"`)\n\n const mine = specs.filter((s) => s.styleId === styleId)\n const assets: AssetAudit[] = []\n const missing: string[] = []\n const unreadable: string[] = []\n\n for (const spec of mine) {\n for (const output of resolveSpecOutputs(spec, lock, loaded.root)) {\n if (!existsSync(output.absolutePath)) {\n missing.push(output.id)\n continue\n }\n try {\n const png = decodePng(await readFile(output.absolutePath))\n const palette = extractPalette(png, 12)\n assets.push({\n assetId: spec.assetId,\n ...(output.role ? { outputRole: output.role } : {}),\n id: output.id,\n file: output.absolutePath,\n width: png.width,\n height: png.height,\n paletteDistance: 0, // filled once the reference is known\n transparency: transparencyRatio(png),\n colorCount: countColors(png),\n palette,\n })\n } catch (err) {\n unreadable.push(`${output.id}: ${err instanceof Error ? err.message : String(err)}`)\n }\n }\n }\n\n // Prefer the declared intent over the set's own average.\n let reference: PaletteEntry[] = []\n let referenceFromStyleImages = false\n const refPalettes: PaletteEntry[][] = []\n for (const img of style.styleImages) {\n const abs = path.resolve(loaded.root, img.path)\n if (!existsSync(abs)) continue\n try {\n refPalettes.push(extractPalette(decodePng(await readFile(abs)), 12))\n } catch {\n // A malformed reference should not sink the audit.\n }\n }\n if (refPalettes.length) {\n reference = mergePalettes(refPalettes)\n referenceFromStyleImages = true\n for (const asset of assets) {\n asset.paletteDistance = paletteDistance(asset.palette, reference)\n }\n } else {\n // Reported reference is the whole set, but each asset is scored against\n // the set MINUS itself. Including an asset in its own reference lets it\n // match perfectly, which would make the most divergent asset — the one\n // worth finding — score zero.\n reference = mergePalettes(assets.map((a) => a.palette))\n for (const asset of assets) {\n const others = assets.filter((a) => a !== asset).map((a) => a.palette)\n asset.paletteDistance = others.length\n ? paletteDistance(asset.palette, mergePalettes(others))\n : 0\n }\n }\n assets.sort((a, b) => b.paletteDistance - a.paletteDistance)\n\n return { styleId, referenceFromStyleImages, reference, assets, missing, unreadable }\n}\n\nfunction countColors(png: { pixels: Buffer }): number {\n const seen = new Set<number>()\n for (let i = 0; i < png.pixels.length; i += 4) {\n if (png.pixels[i + 3]! < 128) continue\n seen.add((png.pixels[i]! << 16) | (png.pixels[i + 1]! << 8) | png.pixels[i + 2]!)\n }\n return seen.size\n}\n\n/** Assets more than `sigma` standard deviations off the mean distance. */\nexport function outliers(audit: StyleAudit, sigma = 1.5): AssetAudit[] {\n const n = audit.assets.length\n if (n < 3) return []\n const mean = audit.assets.reduce((s, a) => s + a.paletteDistance, 0) / n\n const variance = audit.assets.reduce((s, a) => s + (a.paletteDistance - mean) ** 2, 0) / n\n const sd = Math.sqrt(variance)\n if (sd === 0) return []\n return audit.assets.filter((a) => a.paletteDistance > mean + sigma * sd)\n}\n\n/** Turn an audit into a stable CI decision without hiding the underlying measurements. */\nexport function evaluateAudit(\n audit: StyleAudit,\n thresholds: AuditThresholds = {},\n): AuditEvaluation {\n const resolved = { ...thresholds, sigma: thresholds.sigma ?? 1.5 }\n const relative = outliers(audit, resolved.sigma)\n const relativeIds = new Set(relative.map((asset) => asset.id))\n const violations: AuditViolation[] = []\n\n for (const asset of audit.assets) {\n const reasons: string[] = []\n if (relativeIds.has(asset.id)) {\n reasons.push(`palette outlier beyond ${resolved.sigma} standard deviations`)\n }\n if (resolved.maxDistance !== undefined && asset.paletteDistance > resolved.maxDistance) {\n reasons.push(\n `palette distance ${asset.paletteDistance.toFixed(1)} exceeds ${resolved.maxDistance}`,\n )\n }\n if (\n resolved.minTransparency !== undefined &&\n asset.transparency < resolved.minTransparency\n ) {\n reasons.push(\n `transparency ${(asset.transparency * 100).toFixed(1)}% is below ` +\n `${(resolved.minTransparency * 100).toFixed(1)}%`,\n )\n }\n if (resolved.maxColors !== undefined && asset.colorCount > resolved.maxColors) {\n reasons.push(`color count ${asset.colorCount} exceeds ${resolved.maxColors}`)\n }\n if (reasons.length) violations.push({ id: asset.id, reasons })\n }\n\n return {\n safe: violations.length === 0 && audit.missing.length === 0 && audit.unreadable.length === 0,\n thresholds: resolved,\n outliers: [...relativeIds],\n violations,\n missing: [...audit.missing],\n unreadable: [...audit.unreadable],\n }\n}\n\nexport function hex(c: { r: number; g: number; b: number }): string {\n return `#${[c.r, c.g, c.b].map((v) => v.toString(16).padStart(2, \"0\")).join(\"\")}`\n}\n","import { existsSync } from \"node:fs\"\nimport { readFile, readdir, rm } from \"node:fs/promises\"\nimport path from \"node:path\"\nimport {\n cachePathFor,\n isSha256Hash,\n parseCache,\n saveCache,\n type HashCache,\n} from \"../cache.ts\"\nimport { sha256 } from \"../hash.ts\"\nimport type { Lock } from \"../types.ts\"\nimport { decodePng } from \"../png.ts\"\n\nconst PNG_SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])\n\nexport interface ContentCacheIssue {\n name: string\n reason: string\n}\n\nexport interface ContentCacheHealth {\n path: string\n exists: boolean\n files: number\n bytes: number\n valid: number\n referenced: number\n unreferenced: string[]\n missingReferenced: string[]\n invalid: ContentCacheIssue[]\n}\n\nexport interface RemoteHashCacheHealth {\n path: string\n exists: boolean\n entries: number\n valid: number\n invalidIds: string[]\n error: string | null\n}\n\nexport interface CacheHealthReport {\n safe: boolean\n content: ContentCacheHealth\n remoteHashes: RemoteHashCacheHealth\n removed: {\n contentFiles: number\n remoteHashEntries: number\n resetRemoteHashCache: boolean\n }\n}\n\nexport interface CacheHealthOptions {\n /** Remove invalid and unreferenced content, plus invalid remote hash entries. */\n prune?: boolean\n}\n\n/**\n * Inspect both local caches without contacting the provider.\n *\n * Content PNGs are project-local and keyed by lockfile SHA, so orphaned bytes\n * can be removed safely. The object-hash cache is account-wide: this function\n * validates its schema and hashes but never removes an object merely because\n * the current project does not reference it. `adopt` owns that live-ID prune,\n * because only it has walked the complete provider account.\n */\nexport async function inspectCaches(\n lock: Lock,\n lockPath: string,\n options: CacheHealthOptions = {},\n): Promise<CacheHealthReport> {\n if (options.prune && !existsSync(lockPath)) {\n throw new Error(`Refusing to prune without an existing lockfile at ${path.resolve(lockPath)}`)\n }\n const contentDir = path.resolve(path.dirname(lockPath), \".pixelkiln\", \"cache\")\n const remotePath = path.resolve(cachePathFor(lockPath))\n const referenced = new Set(\n Object.values(lock.entries).flatMap((entry) => entry.outputs.map((output) => output.sha256)),\n )\n\n let content = await inspectContentCache(contentDir, referenced)\n let remoteHashes = await inspectRemoteHashCache(remotePath)\n const removed = { contentFiles: 0, remoteHashEntries: 0, resetRemoteHashCache: false }\n\n if (options.prune) {\n const names = new Set([\n ...content.unreferenced,\n ...content.invalid.map((issue) => issue.name),\n ])\n for (const name of names) {\n // Every name came directly from a non-recursive readdir of contentDir;\n // removing this explicit child cannot escape through path traversal.\n try {\n await rm(path.join(contentDir, name), { force: true })\n removed.contentFiles++\n } catch {\n // Directories and permission failures remain in the follow-up report.\n }\n }\n\n if (remoteHashes.error) {\n await saveCache(remotePath, { version: 1, hashes: {} })\n removed.resetRemoteHashCache = true\n } else if (remoteHashes.invalidIds.length) {\n const cache = parseCache(JSON.parse(await readFile(remotePath, \"utf8\")))\n for (const id of remoteHashes.invalidIds) delete cache.hashes[id]\n removed.remoteHashEntries = remoteHashes.invalidIds.length\n await saveCache(remotePath, cache)\n }\n\n content = await inspectContentCache(contentDir, referenced)\n remoteHashes = await inspectRemoteHashCache(remotePath)\n }\n\n return {\n safe: content.invalid.length === 0 && !remoteHashes.error && remoteHashes.invalidIds.length === 0,\n content,\n remoteHashes,\n removed,\n }\n}\n\nasync function inspectContentCache(\n contentDir: string,\n referenced: Set<string>,\n): Promise<ContentCacheHealth> {\n const report: ContentCacheHealth = {\n path: contentDir,\n exists: existsSync(contentDir),\n files: 0,\n bytes: 0,\n valid: 0,\n referenced: 0,\n unreferenced: [],\n missingReferenced: [],\n invalid: [],\n }\n if (!report.exists) {\n report.missingReferenced = [...referenced].sort()\n return report\n }\n\n const present = new Set<string>()\n const entries = await readdir(contentDir, { withFileTypes: true })\n for (const entry of entries) {\n if (!entry.isFile()) {\n report.invalid.push({ name: entry.name, reason: \"not a regular file\" })\n continue\n }\n report.files++\n const file = path.join(contentDir, entry.name)\n const expected = entry.name.endsWith(\".png\") ? entry.name.slice(0, -4) : \"\"\n let bytes: Buffer\n try {\n bytes = await readFile(file)\n report.bytes += bytes.length\n } catch (err) {\n report.invalid.push({\n name: entry.name,\n reason: `unreadable: ${err instanceof Error ? err.message : String(err)}`,\n })\n continue\n }\n if (!isSha256Hash(expected)) {\n report.invalid.push({ name: entry.name, reason: \"filename is not <sha256>.png\" })\n continue\n }\n if (!bytes.subarray(0, 8).equals(PNG_SIGNATURE)) {\n report.invalid.push({ name: entry.name, reason: \"not a PNG\" })\n continue\n }\n if (sha256(bytes) !== expected) {\n report.invalid.push({ name: entry.name, reason: \"bytes do not match filename hash\" })\n continue\n }\n try {\n decodePng(bytes)\n } catch (err) {\n report.invalid.push({\n name: entry.name,\n reason: `invalid PNG: ${err instanceof Error ? err.message : String(err)}`,\n })\n continue\n }\n present.add(expected)\n report.valid++\n if (referenced.has(expected)) report.referenced++\n else report.unreferenced.push(entry.name)\n }\n report.unreferenced.sort()\n report.missingReferenced = [...referenced].filter((hash) => !present.has(hash)).sort()\n return report\n}\n\nasync function inspectRemoteHashCache(remotePath: string): Promise<RemoteHashCacheHealth> {\n const report: RemoteHashCacheHealth = {\n path: remotePath,\n exists: existsSync(remotePath),\n entries: 0,\n valid: 0,\n invalidIds: [],\n error: null,\n }\n if (!report.exists) return report\n let cache: HashCache\n try {\n cache = parseCache(JSON.parse(await readFile(remotePath, \"utf8\")))\n } catch (err) {\n report.error = err instanceof Error ? err.message : String(err)\n return report\n }\n report.entries = Object.keys(cache.hashes).length\n for (const [id, hash] of Object.entries(cache.hashes)) {\n if (isSha256Hash(hash)) report.valid++\n else report.invalidIds.push(id)\n }\n report.invalidIds.sort()\n return report\n}\n","import { mkdir, readFile, rename, rm, writeFile } from \"node:fs/promises\"\nimport { existsSync } from \"node:fs\"\nimport pathModule from \"node:path\"\nimport { z } from \"zod\"\n\nexport const HashCacheSchema = z.object({\n version: z.literal(1),\n /** objectId → sha256 of that object's image bytes. */\n hashes: z.record(z.string()),\n})\n\nexport type HashCache = z.infer<typeof HashCacheSchema>\nconst SHA256_HEX = /^[a-f0-9]{64}$/\n\nexport function isSha256Hash(value: string): boolean {\n return SHA256_HEX.test(value)\n}\n\n/** Strict parser for diagnostics; ordinary cache loading remains self-healing. */\nexport function parseCache(value: unknown): HashCache {\n return HashCacheSchema.parse(value)\n}\n\n/**\n * Remembers the hash of every remote object already downloaded.\n *\n * `adopt` and `salvage` work by hashing image bytes, which means downloading\n * every object on the account on every run — measured at 363 downloads and\n * ~4.5s for one project, and it grows with the account rather than with the\n * work. Generated objects are immutable, so a hash only ever needs computing\n * once.\n *\n * Purely derived state: deleting the file costs one slow run and nothing else.\n * It belongs in .gitignore.\n */\nexport async function loadCache(path: string): Promise<HashCache> {\n if (!existsSync(path)) return { version: 1, hashes: {} }\n try {\n const parsed = HashCacheSchema.safeParse(JSON.parse(await readFile(path, \"utf8\")))\n if (!parsed.success) return { version: 1, hashes: {} }\n // Never trust malformed derived data during adoption. Dropping one cache\n // entry costs one download; trusting it can hide a real provenance match.\n return {\n version: 1,\n hashes: Object.fromEntries(\n Object.entries(parsed.data.hashes).filter(([, hash]) => isSha256Hash(hash)),\n ),\n }\n } catch {\n // A corrupt cache is not worth failing a run over — rebuild it.\n return { version: 1, hashes: {} }\n }\n}\n\nexport async function saveCache(path: string, cache: HashCache): Promise<void> {\n const sorted: Record<string, string> = {}\n for (const key of Object.keys(cache.hashes).sort()) {\n const hash = cache.hashes[key]!\n if (!isSha256Hash(hash)) throw new Error(`Refusing to cache invalid SHA-256 for ${key}`)\n sorted[key] = hash\n }\n await mkdir(pathModule.dirname(pathModule.resolve(path)), { recursive: true })\n const tmp = `${path}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`\n try {\n await writeFile(tmp, JSON.stringify({ version: 1, hashes: sorted }, null, 2) + \"\\n\")\n await rename(tmp, path)\n } finally {\n await rm(tmp, { force: true })\n }\n}\n\n/** Drop entries for objects that no longer exist, so the file cannot grow forever. */\nexport function pruneCache(cache: HashCache, liveIds: Set<string>): number {\n let removed = 0\n for (const id of Object.keys(cache.hashes)) {\n if (!liveIds.has(id)) {\n delete cache.hashes[id]\n removed++\n }\n }\n return removed\n}\n\n/**\n * A lockfile named exactly `*.lock.json` gets the conventional\n * `*.cache.json` sibling. Anything else — a custom `--lock` name, which\n * projects in this monorepo already use for variant lockfiles — falls back\n * to appending `.cache.json` to the whole path instead of returning it\n * unchanged. Returning the input unchanged here used to mean the cache,\n * which is a completely different schema, got written straight over the\n * real lockfile on the very first `adopt`.\n */\nexport function cachePathFor(lockPath: string): string {\n if (lockPath.endsWith(\".lock.json\")) return lockPath.replace(/\\.lock\\.json$/, \".cache.json\")\n return `${lockPath}.cache.json`\n}\n","import { readFileSync } from \"node:fs\"\nimport path from \"node:path\"\nimport { decodePng, encodeRgbaPng } from \"../png.ts\"\nimport type { Lock } from \"../types.ts\"\nimport { resolveEntryOutputs, resolveOutputPath, selectEntryOutput } from \"../outputs.ts\"\nimport { sha256 } from \"../hash.ts\"\n\nexport interface PackedSource {\n id: string\n /** Absolute source path. Artifact manifests make it relative to themselves. */\n path: string\n /** Null when the source could not be read. */\n sha256: string | null\n /** False when the source was present but could not be decoded or selected. */\n included: boolean\n}\n\nexport interface PackedFrame {\n /** Asset id, so a consumer can look a sprite up by name rather than index. */\n id: string\n x: number\n y: number\n width: number\n height: number\n}\n\nexport interface PackedSheet {\n png: Buffer\n atlas: {\n style: string\n sheet: { width: number; height: number }\n /** Uniform cell the grid was laid out on. Frames may be smaller. */\n cell: { width: number; height: number }\n columns: number\n frames: PackedFrame[]\n }\n /** Assets skipped because their file was missing or unreadable. */\n skipped: { id: string; reason: string }[]\n /** Inputs and their exact bytes, for deterministic derived-artifact provenance. */\n sources: PackedSource[]\n}\n\n/**\n * Composites one style's sprites into a single sheet plus a frame atlas.\n *\n * A grid rather than a bin-packer. Every sprite in a style shares a generator\n * and a size, so rectangles are near-uniform and the gain from tight packing\n * is a few percent of area — not worth the loss of a stable, predictable\n * layout. A grid also means a frame's position is derivable from its index,\n * which matters when someone is reading the sheet by eye to debug it.\n *\n * The cell is the largest sprite in the set. Assets can override width/height\n * individually, so assuming uniformity would silently clip the odd one out.\n * Smaller sprites are placed at the cell's top-left and their real dimensions\n * recorded, rather than being centred: centring would bake half-pixel offsets\n * into odd-sized differences, and a consumer that ignores the atlas and slices\n * on the cell grid still gets a correct — if padded — sprite.\n */\nexport interface SpriteInput {\n /** The name this sprite is looked up by in the atlas. */\n id: string\n /** Absolute path to the PNG. */\n path: string\n}\n\n/**\n * Validates and resolves the JSON contract behind `pack --inputs`.\n *\n * A plain function rather than inline in the CLI so it is testable without\n * spawning the binary: `main()` in cli.ts runs at module load and is not\n * exported, so anything left inline there has no seam a test can reach. This\n * is also the only place that needs to know the file is JSON at all — once it\n * returns, everything downstream just deals in `SpriteInput[]`.\n *\n * `entry.path` resolves relative to `inputsFilePath`'s directory, not the\n * process's cwd, so a caller can write the JSON into a scratch directory\n * without rewriting every entry to be absolute. An already-absolute\n * `entry.path` passes through unchanged, since `path.resolve` discards\n * earlier segments once it hits one.\n */\nexport function resolvePackInputs(raw: unknown, inputsFilePath: string): SpriteInput[] {\n if (!Array.isArray(raw) || !raw.length) {\n throw new Error(\"--inputs must be a non-empty JSON array of { id, path }\")\n }\n const baseDir = path.dirname(path.resolve(inputsFilePath))\n return raw.map((entry, i) => {\n const e = entry as { id?: unknown; path?: unknown }\n if (typeof e.id !== \"string\" || typeof e.path !== \"string\") {\n throw new Error(`--inputs[${i}] needs string \"id\" and \"path\"`)\n }\n return { id: e.id, path: path.resolve(baseDir, e.path) }\n })\n}\n\n/**\n * The packing primitive: an explicit list of sprites in, one sheet out.\n *\n * Separate from `packStyle` because the lockfile is not the only way to decide\n * what belongs on a sheet. A consumer may draw from several manifests, or key\n * frames by its own vocabulary rather than by pixelkiln asset ids — heybud's\n * review-form icons do both. Keeping the pixel work here and the \"which files,\n * called what\" decision at the call site avoids teaching this module about\n * anyone else's naming.\n */\nexport function packSprites(\n inputs: SpriteInput[],\n options: { columns?: number; order?: \"id\" | \"input\" } = {},\n): PackedSheet {\n if (!inputs.length) throw new Error(\"packSprites: no sprites given\")\n\n // Two inputs sharing an id would silently produce two frames under the same\n // key, and a consumer doing `frames.find(f => f.id === x)` gets whichever\n // came first with no signal that the other was dropped. Caught here, before\n // any file I/O, rather than left for the next caller to discover the hard\n // way — heybud's own sync script has to dedupe upstream today for exactly\n // this reason (its archetype sources deliberately overlap).\n const seen = new Set<string>()\n const dupes = new Set<string>()\n for (const input of inputs) {\n if (seen.has(input.id)) dupes.add(input.id)\n seen.add(input.id)\n }\n if (dupes.size) {\n throw new Error(`packSprites: duplicate sprite id(s): ${[...dupes].join(\", \")}`)\n }\n\n // Ordinary sprite atlases sort by id so they are byte-identical across\n // runs. Structural sets opt into provider order because their index is part\n // of the format, not presentation.\n const ordered = options.order === \"input\"\n ? [...inputs]\n : [...inputs].sort((a, b) => a.id.localeCompare(b.id))\n\n const sprites: { id: string; width: number; height: number; pixels: Buffer }[] = []\n const skipped: { id: string; reason: string }[] = []\n const sources: PackedSource[] = []\n\n for (const input of ordered) {\n let sourceHash: string | null = null\n try {\n const bytes = readFileSync(input.path)\n sourceHash = sha256(bytes)\n const png = decodePng(bytes)\n sprites.push({ id: input.id, width: png.width, height: png.height, pixels: png.pixels })\n sources.push({ ...input, sha256: sourceHash, included: true })\n } catch (err) {\n skipped.push({ id: input.id, reason: err instanceof Error ? err.message : String(err) })\n sources.push({ ...input, sha256: sourceHash, included: false })\n }\n }\n\n if (!sprites.length) {\n throw new Error(`packSprites: nothing readable — ${skipped.length} skipped.`)\n }\n\n const cellW = Math.max(...sprites.map((s) => s.width))\n const cellH = Math.max(...sprites.map((s) => s.height))\n const columns = options.columns ?? Math.ceil(Math.sqrt(sprites.length))\n const rows = Math.ceil(sprites.length / columns)\n\n const sheetW = columns * cellW\n const sheetH = rows * cellH\n // Zero-filled means fully transparent, which is what the gaps should be.\n const rgba = Buffer.alloc(sheetW * sheetH * 4)\n const frames: PackedFrame[] = []\n\n sprites.forEach((sprite, i) => {\n const ox = (i % columns) * cellW\n const oy = Math.floor(i / columns) * cellH\n for (let y = 0; y < sprite.height; y++) {\n const src = y * sprite.width * 4\n const dst = ((oy + y) * sheetW + ox) * 4\n sprite.pixels.copy(rgba, dst, src, src + sprite.width * 4)\n }\n frames.push({ id: sprite.id, x: ox, y: oy, width: sprite.width, height: sprite.height })\n })\n\n return {\n png: encodeRgbaPng(sheetW, sheetH, rgba),\n atlas: {\n style: \"\",\n sheet: { width: sheetW, height: sheetH },\n cell: { width: cellW, height: cellH },\n columns,\n frames,\n },\n skipped,\n sources,\n }\n}\n\nexport function packStyle(\n lock: Lock,\n styleId: string,\n manifestDir: string,\n options: { columns?: number; outputRoles?: string[]; primaryOnly?: boolean } = {},\n): PackedSheet {\n // Lock keys are `<styleId>/<assetId>`.\n const prefix = `${styleId}/`\n const entries = Object.entries(lock.entries).filter(([key]) => key.startsWith(prefix))\n\n if (!entries.length) {\n throw new Error(\n `No locked assets for style \"${styleId}\". Run \\`pixelkiln gen --style ${styleId}\\` first.`,\n )\n }\n\n const inputs: SpriteInput[] = []\n const noOutput: { id: string; reason: string }[] = []\n\n for (const [key, entry] of entries) {\n const id = key.slice(prefix.length)\n const outputs = resolveEntryOutputs(entry, id, manifestDir)\n let selected = outputs\n if (options.outputRoles?.length) {\n selected = outputs.filter(\n (output) => output.role && options.outputRoles!.includes(output.role),\n )\n } else if (options.primaryOnly) {\n const selection = selectEntryOutput(entry)\n selected = selection.ok\n ? outputs.filter((output) => output.path === selection.output.path)\n : []\n }\n if (!selected.length) {\n const reason = options.outputRoles?.length\n ? `no output matches role(s): ${options.outputRoles.join(\", \")}`\n : options.primaryOnly && outputs.length > 1\n ? \"no unambiguous primary output; use --output-role\"\n : \"no output recorded in the lockfile\"\n noOutput.push({ id, reason })\n continue\n }\n for (const output of selected) inputs.push({ id: output.id, path: output.absolutePath })\n }\n\n if (!inputs.length) {\n throw new Error(`No readable sprites for style \"${styleId}\" — ${noOutput.length} skipped.`)\n }\n\n const packed = packSprites(inputs, options)\n return {\n ...packed,\n atlas: { ...packed.atlas, style: styleId },\n skipped: [...noOutput, ...packed.skipped],\n }\n}\n\nexport interface MountPlacement extends SpriteInput {\n /** Grid cell this sprite owns, as [column, row]. */\n cell: [number, number]\n}\n\nexport interface MountedSheet {\n png: Buffer\n atlas: {\n style: string\n sheet: { width: number; height: number }\n cell: { width: number; height: number }\n frames: PackedFrame[]\n }\n skipped: { id: string; reason: string }[]\n /** Inputs and their exact bytes, for deterministic derived-artifact provenance. */\n sources: PackedSource[]\n /** True when an existing sheet was composited into rather than replaced. */\n overBase: boolean\n}\n\n/**\n * Places sprites at *declared* grid cells, optionally into an existing sheet.\n *\n * The sibling of `packSprites`, for the case its layout rules cannot serve.\n * `packSprites` derives position from index and sorts by asset id so the sheet\n * is byte-stable — excellent when pixelkiln owns the whole sheet, and fatal\n * when it does not. A consumer whose atlas coordinates are already load-bearing\n * (a tile engine naming tiles by cell, a scene file storing cell indices in\n * saved data) cannot accept a layout that moves when an asset is added or\n * renamed: every existing reference would silently point at different art.\n *\n * So here the caller declares the cell and pixelkiln honours it. Two\n * consequences worth stating:\n *\n * - **Only declared cells are touched.** With a `base` sheet, every other\n * pixel survives byte-for-byte, so a hand-authored sheet can be part\n * generated and part drawn without the generated half claiming the file.\n * - **A cell is replaced, not blended.** The sprite owns its cell, so the\n * cell is cleared first. Compositing instead would make a regenerated\n * tile show through to whatever it replaced, and the residue would be\n * invisible until it shipped.\n *\n * Sprites larger than the cell are a declaration error, not something to crop\n * silently — cropping would produce a sheet that looks right in isolation and\n * is wrong at every seam.\n */\nexport function mountSprites(\n placements: MountPlacement[],\n options: { cellWidth: number; cellHeight: number; basePng?: Buffer },\n): MountedSheet {\n if (!placements.length) throw new Error(\"mountSprites: no sprites given\")\n const { cellWidth, cellHeight } = options\n if (cellWidth <= 0 || cellHeight <= 0) {\n throw new Error(\"mountSprites: cell dimensions must be positive\")\n }\n\n const byCell = new Map<string, string>()\n for (const p of placements) {\n const key = `${p.cell[0]},${p.cell[1]}`\n const owner = byCell.get(key)\n if (owner) {\n throw new Error(\n `mountSprites: \"${p.id}\" and \"${owner}\" both claim cell ${key} — ` +\n `a cell has exactly one owner`,\n )\n }\n byCell.set(key, p.id)\n }\n\n const loaded: { p: MountPlacement; width: number; height: number; pixels: Buffer }[] = []\n const skipped: { id: string; reason: string }[] = []\n const sources: PackedSource[] = []\n for (const p of placements) {\n let sourceHash: string | null = null\n try {\n const bytes = readFileSync(p.path)\n sourceHash = sha256(bytes)\n const png = decodePng(bytes)\n if (png.width > cellWidth || png.height > cellHeight) {\n throw new Error(\n `is ${png.width}x${png.height}, larger than the ${cellWidth}x${cellHeight} cell`,\n )\n }\n loaded.push({ p, width: png.width, height: png.height, pixels: png.pixels })\n sources.push({ id: p.id, path: p.path, sha256: sourceHash, included: true })\n } catch (err) {\n skipped.push({ id: p.id, reason: err instanceof Error ? err.message : String(err) })\n sources.push({ id: p.id, path: p.path, sha256: sourceHash, included: false })\n }\n }\n if (!loaded.length) {\n throw new Error(`mountSprites: nothing readable — ${skipped.length} skipped.`)\n }\n\n // The sheet must cover the base if there is one, and every declared cell\n // either way — a cell past the base's edge grows it rather than failing,\n // so adding a row of tiles does not need the base redrawn first.\n const maxCol = Math.max(...loaded.map((l) => l.p.cell[0]))\n const maxRow = Math.max(...loaded.map((l) => l.p.cell[1]))\n const base = options.basePng ? decodePng(options.basePng) : null\n const sheetW = Math.max((maxCol + 1) * cellWidth, base?.width ?? 0)\n const sheetH = Math.max((maxRow + 1) * cellHeight, base?.height ?? 0)\n\n const rgba = Buffer.alloc(sheetW * sheetH * 4)\n if (base) {\n for (let y = 0; y < base.height; y++) {\n const src = y * base.width * 4\n base.pixels.copy(rgba, y * sheetW * 4, src, src + base.width * 4)\n }\n }\n\n const frames: PackedFrame[] = []\n for (const { p, width, height, pixels } of loaded) {\n const ox = p.cell[0] * cellWidth\n const oy = p.cell[1] * cellHeight\n // Clear the whole cell before writing: the sprite owns it, and leaving the\n // base showing around a smaller sprite is the \"invisible until it ships\"\n // failure this function exists to avoid.\n for (let y = 0; y < cellHeight; y++) {\n rgba.fill(0, ((oy + y) * sheetW + ox) * 4, ((oy + y) * sheetW + ox + cellWidth) * 4)\n }\n for (let y = 0; y < height; y++) {\n const src = y * width * 4\n pixels.copy(rgba, ((oy + y) * sheetW + ox) * 4, src, src + width * 4)\n }\n frames.push({ id: p.id, x: ox, y: oy, width, height })\n }\n\n frames.sort((a, b) => a.y - b.y || a.x - b.x)\n return {\n png: encodeRgbaPng(sheetW, sheetH, rgba),\n atlas: {\n style: \"\",\n sheet: { width: sheetW, height: sheetH },\n cell: { width: cellWidth, height: cellHeight },\n frames,\n },\n skipped,\n sources,\n overBase: base !== null,\n }\n}\n\n/**\n * `mountSprites` driven by the lockfile and the manifest's `mount` block.\n *\n * The manifest is the source of cells rather than the lockfile: a cell is a\n * declaration about where art belongs, not a record of what was generated, and\n * it has to be readable and editable before anything has been generated at all.\n */\nexport function mountStyle(\n lock: Lock,\n styleId: string,\n manifestDir: string,\n mount: { base?: string; cellWidth: number; cellHeight: number },\n cells: Record<string, [number, number]>,\n sources: Record<string, string> = {},\n outputRoles: Record<string, string> = {},\n): MountedSheet {\n // Driven by the declared cells, not by the lockfile. The cell is what says\n // \"this belongs on the sheet\"; whether pixelkiln generated the pixels is a\n // separate question, and `source` assets answer it with a file on disk.\n const ids = Object.keys(cells)\n if (!ids.length) {\n throw new Error(\n `No assets in style \"${styleId}\" declare a \\`cell\\`. Add one to each asset ` +\n `that belongs on the sheet.`,\n )\n }\n\n const placements: MountPlacement[] = []\n const skipped: { id: string; reason: string }[] = []\n for (const id of ids) {\n const cell = cells[id]!\n const source = sources[id]\n if (source) {\n placements.push({ id, path: path.resolve(manifestDir, source), cell })\n continue\n }\n const entry = lock.entries[`${styleId}/${id}`]\n if (!entry) {\n skipped.push({\n id,\n reason: `not generated in style \"${styleId}\", and no \\`source\\` declared`,\n })\n continue\n }\n const selection = selectEntryOutput(entry, outputRoles[id])\n if (!selection.ok) {\n skipped.push({ id, reason: selection.reason })\n continue\n }\n placements.push({ id, path: resolveOutputPath(selection.output.path, manifestDir), cell })\n }\n\n if (!placements.length) {\n const detail = skipped.length\n ? ` (${skipped.map((item) => `${item.id}: ${item.reason}`).join(\"; \")})`\n : \"\"\n throw new Error(\n `Nothing to mount for style \"${styleId}\": ${ids.length} asset(s) declare a ` +\n `cell, but none has generated output or a \\`source\\`. Run ` +\n `\\`pixelkiln gen --style ${styleId}\\`, or point each at a file.${detail}`,\n )\n }\n\n const basePng = mount.base ? readFileSync(path.resolve(manifestDir, mount.base)) : undefined\n const mounted = mountSprites(placements, {\n cellWidth: mount.cellWidth,\n cellHeight: mount.cellHeight,\n basePng,\n })\n return {\n ...mounted,\n sources: mount.base\n ? [{\n id: \"$base\",\n path: path.resolve(manifestDir, mount.base),\n sha256: sha256(basePng!),\n included: true,\n }, ...mounted.sources]\n : mounted.sources,\n atlas: { ...mounted.atlas, style: styleId },\n skipped: [...skipped, ...mounted.skipped],\n }\n}\n","import type { LockEntry, ResolvedSpec } from \"../types.ts\"\nimport { fallbackOutputRole, resolveSpecEntryOutputs } from \"../outputs.ts\"\nimport { packSprites, type PackedFrame, type PackedSource } from \"./pack.ts\"\n\nexport type TilesetFormat = \"generic\" | \"tiled\" | \"godot\"\n\nexport interface NormalizedTileRules {\n ruleType: \"edge\" | \"corner\" | \"outline\"\n arity: 4 | 6\n connectivity?: \"same\" | \"other\"\n terrains: string[]\n /** Provider tile index to adjacency mask. Tiles absent here are stamp-only. */\n masks: Record<number, number>\n raw: Record<string, unknown>\n}\n\nexport interface GenericTileset {\n format: \"pixelkiln-tileset\"\n version: 1\n name: string\n style: string\n asset: string\n image: string\n tile: { width: number; height: number }\n sheet: { width: number; height: number; columns: number }\n tiles: Array<{\n id: number\n /** Original provider index; can differ from id when stamp-only keys leave gaps. */\n sourceIndex: number\n role: string\n x: number\n y: number\n width: number\n height: number\n bitmask?: number\n stampOnly: boolean\n }>\n /** Complete provider object, even when its rule family is not normalized yet. */\n providerRules: Record<string, unknown> | null\n rules: NormalizedTileRules | null\n}\n\nexport interface TilesetExport {\n png: Buffer\n extension: \".json\" | \".tsj\" | \".tres\"\n document: string\n generic: GenericTileset\n sources: PackedSource[]\n}\n\nexport interface TilesetExportOptions {\n format: TilesetFormat\n manifestDir: string\n imageName: string\n columns?: number\n}\n\n/** Parse the deliberately open provider schema into the stable export subset. */\nexport function normalizeTileRules(raw: unknown): NormalizedTileRules | null {\n if (!isRecord(raw)) return null\n const ruleType = raw.rule_type\n const arity = raw.arity\n if (ruleType !== \"edge\" && ruleType !== \"corner\" && ruleType !== \"outline\") return null\n if (arity !== 4 && arity !== 6) return null\n\n const masks: Record<number, number> = {}\n if (isRecord(raw.tiles)) {\n for (const [key, value] of Object.entries(raw.tiles)) {\n const index = tileIndex(key)\n const mask = typeof value === \"number\"\n ? value\n : isRecord(value) && typeof value.bitmask === \"number\"\n ? value.bitmask\n : isRecord(value) && typeof value.mask === \"number\"\n ? value.mask\n : null\n if (index !== null && mask !== null && Number.isInteger(mask) && mask >= 0) masks[index] = mask\n }\n }\n\n const connectivity = raw.connectivity === \"same\" || raw.connectivity === \"other\"\n ? raw.connectivity\n : undefined\n const terrains = Array.isArray(raw.terrains)\n ? raw.terrains.filter((item): item is string => typeof item === \"string\")\n : []\n return {\n ruleType,\n arity,\n ...(connectivity ? { connectivity } : {}),\n terrains,\n masks,\n raw,\n }\n}\n\n/** Build an atlas plus generic, Tiled TSJ, or Godot 4 TileSet metadata. */\nexport function exportTileset(\n entry: LockEntry,\n spec: ResolvedSpec,\n options: TilesetExportOptions,\n): TilesetExport {\n const outputs = resolveSpecEntryOutputs(entry, spec)\n if (!outputs.length) throw new Error(`${spec.styleId}/${spec.assetId} has no downloaded outputs`)\n\n const packed = packSprites(\n outputs.map((output) => ({\n id: output.role ?? fallbackOutputRole(output.index),\n path: output.absolutePath,\n })),\n { columns: options.columns, order: \"input\" },\n )\n if (packed.skipped.length) {\n throw new Error(\n `Cannot export ${spec.styleId}/${spec.assetId}: ` +\n packed.skipped.map((item) => `${item.id}: ${item.reason}`).join(\"; \"),\n )\n }\n\n const metadata = entry.providerMetadata?.[entry.provider]\n const rawRules = isRecord(metadata) ? metadata.tileRules : undefined\n const rules = normalizeTileRules(rawRules)\n const frames = packed.atlas.frames\n const generic = buildGeneric(\n spec,\n options.imageName,\n packed.atlas,\n frames,\n isRecord(rawRules) ? rawRules : null,\n rules,\n )\n\n if (options.format === \"generic\") {\n return {\n png: packed.png,\n extension: \".json\",\n document: JSON.stringify(generic, null, 2) + \"\\n\",\n generic,\n sources: packed.sources,\n }\n }\n\n assertUniformTiles(generic)\n if ((rawRules !== undefined || entry.tileFeature) && !rules) {\n throw new Error(\n `${options.format} export needs recognized adjacency rules; use --format generic ` +\n `to retain this provider rule object without guessing`,\n )\n }\n if (rules?.arity === 6) {\n throw new Error(\n `${options.format} export does not yet map six-edge hex masks safely; use --format generic`,\n )\n }\n if (rules?.ruleType === \"outline\") {\n throw new Error(\n `${options.format} export cannot infer adjacency from outline/stamp-only rules; use --format generic`,\n )\n }\n\n if (options.format === \"tiled\") {\n return {\n png: packed.png,\n extension: \".tsj\",\n document: JSON.stringify(buildTiled(generic), null, 2) + \"\\n\",\n generic,\n sources: packed.sources,\n }\n }\n return {\n png: packed.png,\n extension: \".tres\",\n document: buildGodot(generic, spec),\n generic,\n sources: packed.sources,\n }\n}\n\nfunction buildGeneric(\n spec: ResolvedSpec,\n imageName: string,\n atlas: { sheet: { width: number; height: number }; cell: { width: number; height: number }; columns: number },\n frames: PackedFrame[],\n providerRules: Record<string, unknown> | null,\n rules: NormalizedTileRules | null,\n): GenericTileset {\n return {\n format: \"pixelkiln-tileset\",\n version: 1,\n name: `${spec.styleId}/${spec.assetId}`,\n style: spec.styleId,\n asset: spec.assetId,\n image: imageName,\n tile: { ...atlas.cell },\n sheet: { ...atlas.sheet, columns: atlas.columns },\n tiles: frames.map((frame, index) => {\n const sourceIndex = tileIndex(frame.id) ?? index\n return {\n id: index,\n sourceIndex,\n role: frame.id,\n x: frame.x,\n y: frame.y,\n width: frame.width,\n height: frame.height,\n ...(rules?.masks[sourceIndex] !== undefined ? { bitmask: rules.masks[sourceIndex] } : {}),\n stampOnly: rules ? rules.masks[sourceIndex] === undefined : true,\n }\n }),\n providerRules,\n rules,\n }\n}\n\nfunction buildTiled(generic: GenericTileset): Record<string, unknown> {\n const rules = generic.rules\n const tiled: Record<string, unknown> = {\n type: \"tileset\",\n version: \"1.10\",\n tiledversion: \"1.12.2\",\n name: generic.name.replace(\"/\", \"-\"),\n tilewidth: generic.tile.width,\n tileheight: generic.tile.height,\n tilecount: generic.tiles.length,\n columns: generic.sheet.columns,\n image: generic.image,\n imagewidth: generic.sheet.width,\n imageheight: generic.sheet.height,\n margin: 0,\n spacing: 0,\n }\n if (!rules || rules.ruleType === \"outline\") return tiled\n\n const terrainNames = terrainNamesFor(rules)\n tiled.wangsets = [{\n name: generic.name,\n type: rules.ruleType,\n tile: representativeTile(generic, 0),\n colors: terrainNames.map((name, index) => ({\n name,\n color: index === 0 ? \"#5ab552\" : \"#4c78a8\",\n tile: representativeTile(generic, index),\n probability: 1,\n })),\n properties: rules.connectivity\n ? [{ name: \"pixelkiln:connectivity\", type: \"string\", value: rules.connectivity }]\n : [],\n wangtiles: generic.tiles\n .filter((tile) => tile.bitmask !== undefined)\n .map((tile) => ({ tileid: tile.id, wangid: tiledWangId(rules, tile.bitmask!) })),\n }]\n return tiled\n}\n\nfunction tiledWangId(rules: NormalizedTileRules, mask: number): number[] {\n const bitColor = (bit: number) => ((mask & (1 << bit)) !== 0 ? 1 : 2)\n if (rules.ruleType === \"corner\") {\n // Tiled order: top edge, NE, right edge, SE, bottom edge, SW, left edge, NW.\n return [0, bitColor(2), 0, bitColor(0), 0, bitColor(1), 0, bitColor(3)]\n }\n // PixelLab edge mask: bit0=N bit1=E bit2=S bit3=W.\n return [bitColor(0), 0, bitColor(1), 0, bitColor(2), 0, bitColor(3), 0]\n}\n\nfunction buildGodot(generic: GenericTileset, spec: ResolvedSpec): string {\n const rules = generic.rules\n const lines = [\n `[gd_resource type=\"TileSet\" load_steps=3 format=3]`,\n \"\",\n `[ext_resource type=\"Texture2D\" path=${JSON.stringify(`./${generic.image}`)} id=\"1_texture\"]`,\n \"\",\n `[sub_resource type=\"TileSetAtlasSource\" id=\"TileSetAtlasSource_pixelkiln\"]`,\n `texture = ExtResource(\"1_texture\")`,\n `texture_region_size = Vector2i(${generic.tile.width}, ${generic.tile.height})`,\n ]\n\n for (const tile of generic.tiles) {\n const x = tile.id % generic.sheet.columns\n const y = Math.floor(tile.id / generic.sheet.columns)\n lines.push(`${x}:${y}/0 = 0`)\n if (!rules || tile.bitmask === undefined || rules.ruleType === \"outline\") continue\n const values = godotTerrainBits(rules, tile.bitmask)\n lines.push(`${x}:${y}/0/terrain_set = 0`)\n lines.push(`${x}:${y}/0/terrain = ${dominantTerrain(values)}`)\n for (const [side, value] of Object.entries(values)) {\n lines.push(`${x}:${y}/0/terrains_peering_bit/${side} = ${value}`)\n }\n }\n\n lines.push(\"\", \"[resource]\")\n lines.push(`tile_size = Vector2i(${generic.tile.width}, ${generic.tile.height})`)\n const shape = godotTileShape(spec.tileType ?? \"isometric\")\n if (shape !== 0) lines.push(`tile_shape = ${shape}`)\n if (rules && rules.ruleType !== \"outline\") {\n lines.push(`terrain_set_0/mode = ${rules.ruleType === \"corner\" ? 1 : 2}`)\n for (const [index, name] of terrainNamesFor(rules).entries()) {\n lines.push(`terrain_set_0/terrain_${index}/name = ${JSON.stringify(name)}`)\n lines.push(\n `terrain_set_0/terrain_${index}/color = ` +\n (index === 0 ? \"Color(0.3529, 0.7098, 0.3216, 1)\" : \"Color(0.298, 0.4706, 0.6588, 1)\"),\n )\n }\n }\n lines.push(`sources/0 = SubResource(\"TileSetAtlasSource_pixelkiln\")`, \"\")\n return lines.join(\"\\n\")\n}\n\nfunction godotTerrainBits(rules: NormalizedTileRules, mask: number): Record<string, number> {\n const terrain = (bit: number) => ((mask & (1 << bit)) !== 0 ? 0 : 1)\n if (rules.ruleType === \"corner\") {\n return {\n top_left_corner: terrain(3),\n top_right_corner: terrain(2),\n bottom_left_corner: terrain(1),\n bottom_right_corner: terrain(0),\n }\n }\n return {\n top_side: terrain(0),\n right_side: terrain(1),\n bottom_side: terrain(2),\n left_side: terrain(3),\n }\n}\n\nfunction dominantTerrain(values: Record<string, number>): number {\n const terrainZero = Object.values(values).filter((value) => value === 0).length\n return terrainZero * 2 >= Object.keys(values).length ? 0 : 1\n}\n\nfunction godotTileShape(tileType: string | undefined): number {\n if (tileType === \"isometric\" || tileType === \"oblique\") return 1\n if (tileType === \"hex\" || tileType === \"hex_pointy\") return 3\n return 0\n}\n\nfunction representativeTile(generic: GenericTileset, terrainIndex: number): number {\n const rules = generic.rules!\n const full = (1 << rules.arity) - 1\n const wanted = terrainIndex === 0 ? full : 0\n return generic.tiles.find((tile) => tile.bitmask === wanted)?.id ?? -1\n}\n\nfunction terrainNamesFor(rules: NormalizedTileRules): string[] {\n return [rules.terrains[0] ?? \"feature\", rules.terrains[1] ?? \"background\"]\n}\n\nfunction assertUniformTiles(generic: GenericTileset): void {\n const mismatched = generic.tiles.filter(\n (tile) => tile.width !== generic.tile.width || tile.height !== generic.tile.height,\n )\n if (mismatched.length) {\n throw new Error(\n `Engine tilesets require uniform ${generic.tile.width}x${generic.tile.height} cells; ` +\n `mismatched: ${mismatched.map((tile) => tile.role).join(\", \")}. Use --format generic.`,\n )\n }\n}\n\nfunction tileIndex(key: string): number | null {\n const match = key.match(/(?:^|[_-])(\\d+)$/)\n return match ? Number(match[1]) : null\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n","import {\n DEFAULT_RATE_LIMIT,\n formatCost,\n validateCostEstimate,\n type CostUnit,\n type Provider,\n} from \"../provider.ts\"\nimport { saveLock, upsert } from \"../lock.ts\"\nimport { resolveStyleImages, type LoadedManifest } from \"../manifest.ts\"\nimport type { Lock, ResolvedSpec, ResolvedStyleImage } from \"../types.ts\"\nimport type { PlanItem } from \"./plan.ts\"\n\n/**\n * Two distinct limits, easy to conflate:\n * - submissions must be spaced apart (a rate, global across the account)\n * - background jobs in flight (a count)\n *\n * Both are the provider's own constraint (PixelLab: >2s apart; Tier 1=8,\n * Tier 2=10, Tier 3=20 in flight) surfaced through `provider.rateLimit()`,\n * not a number this pipeline layer should know on its own — a second\n * provider with different limits must not silently inherit PixelLab's.\n *\n * Submission is fast and job execution is slow, so the correct shape is a\n * serial submit loop with a global spacing gate, which pauses when too many\n * jobs are still running. Parallel workers each sleeping `spacing` would give a\n * global rate of workers/spacing and quietly breach the first limit.\n */\nconst IN_FLIGHT_POLL_MS = 5000\n\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))\n\nexport interface SubmitOptions {\n maxInFlight?: number\n spacingMs?: number\n /** How often to re-check occupied background-job slots. */\n slotPollMs?: number\n /** Stop waiting for an unreadable/stuck slot instead of hanging forever. */\n slotTimeoutMs?: number\n /** Refuse to submit if the run would exceed this much, in the provider's unit. */\n budget?: number\n onProgress?: (msg: string) => void\n}\n\nexport interface SubmitResult {\n submitted: number\n failed: number\n /** Successful-submission estimates in `unit`. */\n spent: number\n unit: CostUnit\n}\n\nexport async function submit(\n provider: Provider,\n loaded: LoadedManifest,\n items: PlanItem[],\n lock: Lock,\n lockPath: string,\n opts: SubmitOptions = {},\n): Promise<SubmitResult> {\n const limits = provider.rateLimit?.() ?? DEFAULT_RATE_LIMIT\n const maxInFlight = opts.maxInFlight ?? limits.maxInFlight\n const spacing = opts.spacingMs ?? limits.spacingMs\n const slotPollMs = opts.slotPollMs ?? IN_FLIGHT_POLL_MS\n const slotTimeoutMs = opts.slotTimeoutMs ?? 15 * 60 * 1000\n const log = opts.onProgress ?? (() => {})\n\n const estimates = new Map(items.map((item) => [\n item.key,\n validateCostEstimate(provider.id, provider.estimate(item.spec)),\n ]))\n const units = new Set([...estimates.values()].map((estimate) => estimate.unit))\n if (units.size > 1) {\n throw new Error(`Provider \"${provider.id}\" returned mixed cost units for one submission batch`)\n }\n const unit = units.values().next().value ?? \"free\"\n\n if (opts.budget != null) {\n const cost = [...estimates.values()].reduce((sum, estimate) => sum + estimate.amount, 0)\n if (cost > opts.budget) {\n throw new Error(\n `This run would spend ${formatCost(unit, cost)} but the budget is ` +\n `${formatCost(unit, opts.budget)}. ` +\n `Narrow it with --only/--style, or raise --budget.`,\n )\n }\n }\n\n const styleImages = new Map<string, ResolvedStyleImage[]>()\n for (const styleId of new Set(items.map((i) => i.spec.styleId))) {\n styleImages.set(styleId, await resolveStyleImages(loaded, styleId))\n }\n\n let submitted = 0\n let failed = 0\n let spent = 0\n let lastSubmitAt = 0\n\n /** Jobs submitted this run not yet observed as settled, with their generator. */\n const inFlight = new Map<string, ResolvedSpec>()\n let lastSlotError: string | null = null\n\n async function pruneInFlight(): Promise<void> {\n for (const [id, spec] of [...inFlight]) {\n try {\n const state = await provider.poll(id, spec.generator, spec)\n if (state.status !== \"processing\") inFlight.delete(id)\n lastSlotError = null\n } catch (err) {\n // A transient provider/network error is not evidence that a paid job\n // settled. Keep the slot occupied so we never exceed the upstream cap.\n lastSlotError = err instanceof Error ? err.message : String(err)\n }\n }\n }\n\n async function waitForSlot(): Promise<void> {\n const started = Date.now()\n while (inFlight.size >= maxInFlight) {\n if (Date.now() - started >= slotTimeoutMs) {\n throw new Error(\n `Timed out waiting for a generation slot` +\n (lastSlotError ? `; last poll error: ${lastSlotError}` : \"\"),\n )\n }\n await sleep(slotPollMs)\n await pruneInFlight()\n }\n }\n\n for (const { spec, key } of items) {\n const estimate = estimates.get(key)!\n await waitForSlot()\n\n const since = Date.now() - lastSubmitAt\n if (since < spacing) await sleep(spacing - since)\n\n // Record intent before spending, so an interrupted run stays diagnosable.\n upsert(lock, key, {\n styleId: spec.styleId,\n assetId: spec.assetId,\n specHash: spec.specHash,\n generator: spec.generator,\n tileFeature: spec.tileFeature ?? null,\n prompt: spec.prompt,\n width: spec.width,\n height: spec.height,\n status: \"pending\",\n jobId: null,\n objectId: null,\n reviewObjectId: null,\n candidateIndex: null,\n error: null,\n outputs: [],\n providerMetadata: {},\n sourceUrl: null,\n sourceUrls: [],\n submittedAt: new Date().toISOString(),\n cost: estimate.amount,\n costUnit: estimate.unit,\n downloadedAt: null,\n })\n await saveLock(lockPath, lock)\n\n lastSubmitAt = Date.now()\n try {\n const refs =\n spec.generator === \"1dir\" || spec.generator === \"tiles\"\n ? (styleImages.get(spec.styleId) ?? [])\n : []\n const { jobId } = await provider.submit(spec, refs)\n upsert(lock, key, {\n jobId,\n // A multi-candidate generator routes through review; record the parent\n // so `pick` knows where to look.\n reviewObjectId: estimate.candidates > 1 && !spec.tileFeature ? jobId : null,\n status: \"processing\",\n provider: provider.id,\n })\n inFlight.set(jobId, spec)\n submitted++\n spent += estimate.amount\n log(\n ` ${key} → ${jobId} (${spec.width}x${spec.height}` +\n (estimate.candidates > 1\n ? `, ${estimate.candidates} ${spec.tileFeature ? \"outputs\" : \"candidates\"}`\n : \"\") +\n `, ${estimate.amount})`,\n )\n } catch (err) {\n failed++\n const message = err instanceof Error ? err.message : String(err)\n // A rejected request is not billed, so cost is cleared rather than kept.\n upsert(lock, key, { status: \"failed\", error: message, cost: 0 })\n log(` FAILED ${key}: ${message}`)\n }\n await saveLock(lockPath, lock)\n }\n\n return { submitted, failed, spent, unit }\n}\n","import { saveLock, upsert } from \"../lock.ts\"\nimport type { Provider } from \"../provider.ts\"\nimport type { Lock } from \"../types.ts\"\nimport { lockKey, type ResolvedSpec } from \"../types.ts\"\n\nconst sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))\n\nexport interface PollOptions {\n intervalMs?: number\n timeoutMs?: number\n onProgress?: (msg: string) => void\n specs?: ResolvedSpec[]\n}\n\nexport interface PollResult {\n review: number\n completed: number\n failed: number\n stillRunning: number\n}\n\n/**\n * Advances every unfinished lock entry to its settled state.\n *\n * Safe to run repeatedly and safe to interrupt — all state lives in the\n * lockfile, so a re-run picks up exactly where the last one stopped. Provider\n * quirks (a job record that expires before its image does, review-status\n * candidate lists) are the provider's problem, not this loop's.\n */\nexport async function poll(\n provider: Provider,\n lock: Lock,\n lockPath: string,\n opts: PollOptions = {},\n): Promise<PollResult> {\n const interval = opts.intervalMs ?? 5000\n const timeout = opts.timeoutMs ?? 15 * 60 * 1000\n const log = opts.onProgress ?? (() => {})\n const started = Date.now()\n const specByKey = new Map((opts.specs ?? []).map((s) => [lockKey(s.styleId, s.assetId), s]))\n\n const result: PollResult = { review: 0, completed: 0, failed: 0, stillRunning: 0 }\n\n const pending = () =>\n Object.entries(lock.entries).filter(\n ([, e]) => e.jobId && (e.status === \"pending\" || e.status === \"processing\"),\n )\n\n while (pending().length > 0) {\n if (Date.now() - started > timeout) {\n result.stillRunning = pending().length\n log(` timed out with ${result.stillRunning} job(s) still running — re-run \\`poll\\` to resume`)\n break\n }\n\n for (const [key, entry] of pending()) {\n try {\n const currentSpec = specByKey.get(key)\n const state = await provider.poll(entry.jobId!, entry.generator, {\n tileFeature: entry.tileFeature ?? currentSpec?.tileFeature,\n })\n if (state.status === \"review\") {\n upsert(lock, key, { status: \"review\", reviewObjectId: entry.jobId })\n result.review++\n log(` review ${key} (${state.candidateUrls.length} candidates)`)\n } else if (state.status === \"ready\") {\n const sourceUrls = state.sources?.length\n ? state.sources\n : state.sourceUrl\n ? [{ url: state.sourceUrl }]\n : []\n upsert(lock, key, {\n status: \"selected\",\n objectId: state.objectId,\n sourceUrl: sourceUrls[0]?.url ?? null,\n sourceUrls,\n providerMetadata: state.metadata\n ? { ...entry.providerMetadata, [provider.id]: state.metadata }\n : entry.providerMetadata,\n error: null,\n })\n result.completed++\n log(` ready ${key}`)\n } else if (state.status === \"failed\") {\n upsert(lock, key, { status: \"failed\", error: state.error })\n result.failed++\n log(` FAILED ${key}: ${state.error}`)\n }\n } catch (err) {\n log(` error polling ${key}: ${err instanceof Error ? err.message : String(err)}`)\n }\n }\n\n await saveLock(lockPath, lock)\n if (pending().length > 0) await sleep(interval)\n }\n\n await saveLock(lockPath, lock)\n return result\n}\n","import { existsSync } from \"node:fs\"\nimport { mkdir, readFile, rename, rm, writeFile } from \"node:fs/promises\"\nimport path from \"node:path\"\nimport type { Provider } from \"../provider.ts\"\nimport { sha256, sha256File } from \"../hash.ts\"\nimport { saveLock, upsert } from \"../lock.ts\"\nimport {\n expectedOutputPath,\n normalizeLockOutputPaths,\n portableOutputPath,\n resolveOutputPath,\n} from \"../outputs.ts\"\nimport { lockKey, type Lock, type LockOutput, type ResolvedSpec } from \"../types.ts\"\nimport { decodePng } from \"../png.ts\"\n\n/** PNG magic number — guards against writing an error page as a .png. */\nconst PNG_SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])\n\nexport interface FetchResult {\n downloaded: number\n skipped: number\n failed: number\n}\n\n/**\n * Downloads every selected object to its manifest-defined path and records the\n * file hash. The hash is what lets `plan` tell \"untouched\" from \"edited by\n * hand\" on later runs, so a manual retouch is never silently clobbered. The\n * same hash keys a local content cache, allowing `restore` to outlive a\n * provider's temporary storage URL.\n */\nexport async function fetchAssets(\n provider: Provider,\n specs: ResolvedSpec[],\n lock: Lock,\n lockPath: string,\n opts: {\n onProgress?: (msg: string) => void\n concurrency?: number\n repair?: boolean\n /** Content-addressed PNG cache. Defaults beside the lockfile; false disables it. */\n cacheDir?: string | false\n } = {},\n): Promise<FetchResult> {\n const log = opts.onProgress ?? (() => {})\n const result: FetchResult = { downloaded: 0, skipped: 0, failed: 0 }\n const specByKey = new Map(specs.map((s) => [lockKey(s.styleId, s.assetId), s]))\n normalizeLockOutputPaths(lock, specs)\n const cacheDir =\n opts.cacheDir === false\n ? null\n : path.resolve(opts.cacheDir ?? path.join(path.dirname(lockPath), \".pixelkiln\", \"cache\"))\n\n // Downloads are independent and IO-bound, so they run concurrently. The\n // lockfile is still written after each one, keeping an interrupted run\n // recoverable.\n const pending = Object.entries(lock.entries).filter(([key, e]) => {\n if (e.status === \"selected\" || e.status === \"download-failed\") return true\n if (!opts.repair || e.status !== \"downloaded\") return false\n const spec = specByKey.get(key)\n return e.outputs.length === 0 || !spec ||\n e.outputs.some((output) => !existsSync(resolveOutputPath(output.path, spec.root)))\n })\n const concurrency = Math.min(Math.max(1, opts.concurrency ?? 8), Math.max(1, pending.length))\n let cursor = 0\n\n async function worker(): Promise<void> {\n for (;;) {\n const next = pending[cursor++]\n if (!next) return\n const [key, entry] = next\n\n const spec = specByKey.get(key)\n if (!spec) {\n // In the lockfile but no longer in the manifest — the asset was removed.\n log(` skip ${key} (not in current manifest)`)\n result.skipped++\n continue\n }\n if (entry.specHash !== spec.specHash) {\n log(` skip ${key} (source belongs to a stale spec)`)\n result.skipped++\n continue\n }\n const sources = entry.sourceUrls?.length\n ? entry.sourceUrls\n : entry.sourceUrl\n ? [{ url: entry.sourceUrl }]\n : opts.repair && entry.outputs.length\n ? entry.outputs.map((o) => ({ url: \"\", role: o.role }))\n : []\n if (!sources.length) {\n upsert(lock, key, {\n status: \"download-failed\",\n error: \"no persisted source URL to download; poll the job again if it still exists upstream\",\n })\n result.failed++\n continue\n }\n\n const outputs: LockOutput[] = []\n try {\n for (let index = 0; index < sources.length; index++) {\n const source = sources[index]!\n const recorded = entry.outputs.find((o) =>\n source.role ? o.role === source.role : !o.role && sources.length === 1,\n )\n const target = recorded\n ? resolveOutputPath(recorded.path, spec.root)\n : expectedOutputPath(spec, source.role, index, sources.length)\n\n if (existsSync(target)) {\n if (!recorded) {\n throw new Error(`refusing to overwrite untracked output ${target}`)\n }\n if ((await sha256File(target)) !== recorded.sha256) {\n throw new Error(`refusing to overwrite modified output ${target}`)\n }\n if (cacheDir) await cachePng(cacheDir, await readFile(target), recorded.sha256)\n outputs.push({ ...recorded, path: portableOutputPath(target, spec.root) })\n continue\n }\n\n let buf = recorded && cacheDir ? await readCachedPng(cacheDir, recorded.sha256) : null\n if (buf) {\n log(` cached ${path.relative(process.cwd(), target)}`)\n } else {\n if (!source.url) {\n throw new Error(`no source URL or cached bytes remain for ${source.role ?? \"asset\"}`)\n }\n buf = await provider.download(source.url)\n }\n if (!buf.subarray(0, 8).equals(PNG_SIGNATURE)) {\n throw new Error(`response for ${source.role ?? \"asset\"} was not a PNG (${buf.length} bytes)`)\n }\n try {\n decodePng(buf)\n } catch (err) {\n throw new Error(\n `response for ${source.role ?? \"asset\"} was not a valid PNG: ` +\n `${err instanceof Error ? err.message : String(err)}`,\n )\n }\n if (cacheDir) await cachePng(cacheDir, buf)\n await mkdir(path.dirname(target), { recursive: true })\n const tmp = `${target}.pixelkiln.tmp`\n await writeFile(tmp, buf)\n outputs.push({\n path: portableOutputPath(target, spec.root),\n sha256: sha256(buf),\n ...(source.role ? { role: source.role } : {}),\n })\n // Record the intended rename before performing it. If the process\n // dies in either half of this two-step commit, the next repair sees\n // a missing recorded output and safely downloads it again; it never\n // sees an untracked final file and gets stuck refusing to overwrite.\n upsert(lock, key, { outputs: mergeOutputs(entry.outputs, outputs) })\n await saveLock(lockPath, lock)\n await rename(tmp, target)\n log(` wrote ${path.relative(process.cwd(), target)}`)\n }\n upsert(lock, key, {\n status: \"downloaded\",\n provider: provider.id,\n outputs,\n // Inline providers can hand the pipeline a machine-local temp file.\n // Once its bytes are in the durable content cache, retaining that\n // path makes a committed lockfile non-portable and falsely suggests\n // the source still exists on another checkout.\n ...(cacheDir && sources.every((source) => source.url.startsWith(\"file://\"))\n ? { sourceUrl: null, sourceUrls: [] }\n : {}),\n downloadedAt: new Date().toISOString(),\n error: null,\n })\n result.downloaded++\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n upsert(lock, key, {\n status: \"download-failed\",\n outputs: mergeOutputs(entry.outputs, outputs),\n error: `download failed: ${message}`,\n })\n result.failed++\n log(` FAILED ${key}: ${message}`)\n }\n await saveLock(lockPath, lock)\n }\n }\n\n await Promise.all(Array.from({ length: concurrency }, worker))\n await saveLock(lockPath, lock)\n return result\n}\n\nasync function readCachedPng(cacheDir: string, hash: string): Promise<Buffer | null> {\n const file = path.join(cacheDir, `${hash}.png`)\n if (!existsSync(file)) return null\n try {\n const buf = await readFile(file)\n if (!buf.subarray(0, 8).equals(PNG_SIGNATURE) || sha256(buf) !== hash) return null\n decodePng(buf)\n return buf\n } catch {\n return null\n }\n}\n\nasync function cachePng(cacheDir: string, buf: Buffer, knownHash?: string): Promise<void> {\n const hash = knownHash ?? sha256(buf)\n const file = path.join(cacheDir, `${hash}.png`)\n if (await readCachedPng(cacheDir, hash)) return\n await mkdir(cacheDir, { recursive: true })\n const tmp = `${file}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`\n await writeFile(tmp, buf)\n try {\n await rename(tmp, file)\n } catch (err) {\n // Two workers can discover the same content concurrently. If the other\n // one won the rename race, the cache is already complete.\n if (!existsSync(file)) throw err\n } finally {\n await rm(tmp, { force: true })\n }\n}\n\nfunction mergeOutputs(previous: LockOutput[], current: LockOutput[]): LockOutput[] {\n const merged = new Map<string, LockOutput>()\n for (const output of [...previous, ...current]) {\n merged.set(output.role ? `role:${output.role}` : `path:${output.path}`, output)\n }\n return [...merged.values()]\n}\n\n/**\n * Applies the manifest's tags to each generated object upstream. Tagging is\n * free and synchronous, and it makes the account itself queryable — the thing\n * that was missing when 350 objects accumulated with no way to tell which 65\n * were the keepers.\n */\nexport async function pushTags(\n provider: Provider,\n specs: ResolvedSpec[],\n lock: Lock,\n opts: { onProgress?: (msg: string) => void } = {},\n): Promise<number> {\n const log = opts.onProgress ?? (() => {})\n const specByKey = new Map(specs.map((s) => [lockKey(s.styleId, s.assetId), s]))\n let tagged = 0\n\n for (const [key, entry] of Object.entries(lock.entries)) {\n const spec = specByKey.get(key)\n if (!spec || !entry.objectId) continue\n // pixflux results are local files with a synthetic id, not account\n // objects — tagging one would 404.\n if (entry.generator === \"pixflux\") continue\n if (!provider.setTags) return tagged // capability absent; nothing to do\n try {\n await provider.setTags(entry.objectId, spec.tags)\n tagged++\n } catch (err) {\n log(` tag failed ${key}: ${err instanceof Error ? err.message : String(err)}`)\n }\n }\n return tagged\n}\n","import { constants, existsSync } from \"node:fs\"\nimport { access, stat } from \"node:fs/promises\"\nimport path from \"node:path\"\nimport type { LoadedManifest } from \"../manifest.ts\"\nimport type { Provider } from \"../provider.ts\"\nimport type { Lock, ResolvedSpec } from \"../types.ts\"\nimport { sha256File } from \"../hash.ts\"\nimport { currentEntryOutputPath, resolveOutputPath } from \"../outputs.ts\"\nimport { buildPlan, summarize } from \"./plan.ts\"\n\nexport type DoctorLevel = \"ok\" | \"warning\" | \"error\"\n\nexport interface DoctorCheck {\n id: string\n level: DoctorLevel\n message: string\n}\n\nexport interface DoctorReport {\n ok: boolean\n checks: DoctorCheck[]\n}\n\nexport interface DoctorOptions {\n provider?: Provider\n /** Skip provider connectivity while retaining every local check. */\n offline?: boolean\n apiKeyPresent?: boolean\n}\n\n/**\n * Checks the whole project without changing it. Loading/resolving the manifest\n * and loading the lock happen before this function, so schema, style-image,\n * filter, and output-collision validation have already passed if it runs.\n */\nexport async function doctor(\n loaded: LoadedManifest,\n specs: ResolvedSpec[],\n lock: Lock,\n lockPath: string,\n opts: DoctorOptions = {},\n): Promise<DoctorReport> {\n const checks: DoctorCheck[] = []\n const add = (id: string, level: DoctorLevel, message: string) => checks.push({ id, level, message })\n\n add(\n \"manifest\",\n \"ok\",\n `${Object.keys(loaded.manifest.styles).length} style(s), ` +\n `${Object.keys(loaded.manifest.assets).length} asset(s), ${specs.length} resolved spec(s)`,\n )\n add(\"lock\", \"ok\", `${Object.keys(lock.entries).length} valid v2 lock entr(ies)`)\n\n const dirs = [...new Set(specs.map((s) => path.dirname(s.outFile)))]\n const unwritable: string[] = []\n for (const dir of dirs) {\n const ancestor = await nearestExistingDirectory(dir)\n try {\n await access(ancestor, constants.W_OK)\n } catch {\n unwritable.push(dir)\n }\n }\n add(\n \"outputs\",\n unwritable.length ? \"error\" : \"ok\",\n unwritable.length\n ? `output path is not writable: ${unwritable.slice(0, 3).join(\", \")}`\n : `${dirs.length} output director${dirs.length === 1 ? \"y is\" : \"ies are\"} writable`,\n )\n\n const outputOwners = new Map<string, string>()\n const duplicateOutputs: string[] = []\n const specByKey = new Map(specs.map((spec) => [`${spec.styleId}/${spec.assetId}`, spec]))\n for (const [key, entry] of Object.entries(lock.entries)) {\n for (let index = 0; index < entry.outputs.length; index++) {\n const output = entry.outputs[index]!\n const spec = specByKey.get(key)\n const absolute = spec\n ? currentEntryOutputPath(entry, spec, index)\n : resolveOutputPath(output.path, path.dirname(lockPath))\n const owner = outputOwners.get(absolute)\n if (owner && owner !== key) duplicateOutputs.push(`${output.path} (${owner}, ${key})`)\n outputOwners.set(absolute, key)\n }\n }\n if (duplicateOutputs.length) {\n // Name the remedy. This almost always means an asset was renamed or moved\n // between styles and the old entry stayed behind still claiming the path,\n // which `prune` clears — reporting the breakage without saying what fixes\n // it left the only route as hand-editing the lockfile.\n add(\n \"lock-outputs\",\n \"error\",\n `lock entries share output paths: ${duplicateOutputs.slice(0, 3).join(\", \")}` +\n `${duplicateOutputs.length > 3 ? `, and ${duplicateOutputs.length - 3} more` : \"\"}` +\n ` — run \\`pixelkiln prune\\` if the manifest no longer declares them`,\n )\n } else {\n add(\"lock-outputs\", \"ok\", `${outputOwners.size} recorded output path(s) are uniquely owned`)\n }\n\n const cacheDir = path.join(path.dirname(lockPath), \".pixelkiln\", \"cache\")\n const stranded: string[] = []\n const invalidState: string[] = []\n const staleMapUrls: string[] = []\n const now = Date.now()\n for (const [key, entry] of Object.entries(lock.entries)) {\n if ((entry.status === \"pending\" || entry.status === \"processing\") && !entry.jobId) {\n invalidState.push(`${key} (${entry.status} without job id)`)\n }\n if (entry.status === \"review\" && !entry.reviewObjectId) {\n invalidState.push(`${key} (review without review object id)`)\n }\n if (entry.status !== \"selected\" && entry.status !== \"download-failed\") continue\n const hasSource = Boolean(entry.sourceUrl || entry.sourceUrls?.length)\n let hasCache = false\n for (const output of entry.outputs) {\n const cached = path.join(cacheDir, `${output.sha256}.png`)\n if (existsSync(cached) && (await sha256File(cached)) === output.sha256) {\n hasCache = true\n break\n }\n }\n if (!hasSource && !hasCache) stranded.push(key)\n if (\n entry.generator === \"map\" &&\n entry.submittedAt &&\n now - Date.parse(entry.submittedAt) > 8 * 60 * 60 * 1000\n ) {\n staleMapUrls.push(key)\n }\n }\n add(\n \"recovery\",\n stranded.length || invalidState.length ? \"error\" : staleMapUrls.length ? \"warning\" : \"ok\",\n invalidState.length\n ? `invalid resumable state: ${invalidState.slice(0, 5).join(\", \")}`\n : stranded.length\n ? `${stranded.length} unfinished entr(ies) have neither source URLs nor cached bytes: ${stranded.slice(0, 5).join(\", \")}`\n : staleMapUrls.length\n ? `${staleMapUrls.length} unfinished map entr(ies) are older than the provider's 8-hour job window`\n : \"no unfinished downloads are stranded without a source or cached bytes\",\n )\n\n const plan = await buildPlan(specs, lock)\n const counts = summarize(plan)\n const unsettled = plan.items.filter((i) => i.state !== \"ok\").length\n add(\n \"plan\",\n unsettled ? \"warning\" : \"ok\",\n unsettled\n ? `${unsettled} spec(s) are not current: ` +\n Object.entries(counts)\n .filter(([, n]) => n > 0)\n .map(([state, n]) => `${n} ${state}`)\n .join(\", \")\n : \"every resolved spec is current\",\n )\n\n if (opts.offline) {\n add(\"provider\", \"warning\", \"provider connectivity skipped (--dry-run)\")\n } else if (!opts.provider) {\n add(\n \"provider\",\n \"error\",\n opts.apiKeyPresent === false ? \"PIXELLAB_API_KEY is not configured\" : \"provider is not configured\",\n )\n } else {\n try {\n const balance = await opts.provider.balance()\n add(\"provider\", \"ok\", `${opts.provider.id} reachable; ${balance.remaining} ${balance.unit} remaining`)\n } catch (err) {\n add(\"provider\", \"error\", `provider connectivity failed: ${err instanceof Error ? err.message : String(err)}`)\n }\n }\n\n return { ok: !checks.some((c) => c.level === \"error\"), checks }\n}\n\nasync function nearestExistingDirectory(start: string): Promise<string> {\n let current = start\n for (;;) {\n try {\n if ((await stat(current)).isDirectory()) return current\n } catch {\n // Walk upward until a parent exists; creating descendants needs write\n // permission on that nearest existing ancestor.\n }\n const parent = path.dirname(current)\n if (parent === current) return current\n current = parent\n }\n}\n","import { existsSync } from \"node:fs\"\nimport { readFile, writeFile } from \"node:fs/promises\"\nimport path from \"node:path\"\nimport { requireList, validateCostEstimate, type Provider, type RemoteAsset } from \"../provider.ts\"\nimport { sha256 } from \"../hash.ts\"\nimport { loadCache, saveCache, pruneCache, cachePathFor, type HashCache } from \"../cache.ts\"\nimport { saveLock, upsert } from \"../lock.ts\"\nimport { portableOutputPath } from \"../outputs.ts\"\nimport { decodePng } from \"../png.ts\"\nimport { lockKey, type Lock, type ResolvedSpec } from \"../types.ts\"\n\nexport interface AdoptResult {\n scanned: number\n matched: number\n unmatchedLocal: string[]\n /** Objects on the account that correspond to no local file — safe to delete. */\n unmatchedRemote: RemoteAsset[]\n ambiguous: string[]\n}\n\n/**\n * Reconciles an account full of previously generated objects against the files\n * already committed in the repo, and writes the mapping into the lockfile.\n *\n * Matching is by exact SHA-256 of the image bytes. That was verified to hold:\n * a file downloaded from PixelLab storage is byte-identical to the copy sitting\n * in the repo, so a hash match is proof of provenance rather than a guess. No\n * fuzzy prompt matching is involved and nothing is regenerated.\n */\nexport async function adopt(\n provider: Provider,\n specs: ResolvedSpec[],\n lock: Lock,\n lockPath: string,\n opts: { onProgress?: (msg: string) => void; concurrency?: number; noCache?: boolean } = {},\n): Promise<AdoptResult> {\n const log = opts.onProgress ?? (() => {})\n const concurrency = opts.concurrency ?? 8\n // Generated objects are immutable, so a hash computed once stays valid.\n const cachePath = cachePathFor(lockPath)\n const cache: HashCache = opts.noCache ? { version: 1, hashes: {} } : await loadCache(cachePath)\n let cacheHits = 0\n\n // 1. Hash every local file the manifest expects to exist.\n const localByHash = new Map<string, ResolvedSpec[]>()\n const unmatchedLocal: string[] = []\n for (const spec of specs) {\n if (!existsSync(spec.outFile)) {\n unmatchedLocal.push(`${spec.styleId}/${spec.assetId} (no file at ${spec.outFile})`)\n continue\n }\n const bytes = await readFile(spec.outFile)\n try {\n decodePng(bytes)\n } catch (err) {\n unmatchedLocal.push(\n `${spec.styleId}/${spec.assetId} (invalid PNG: ` +\n `${err instanceof Error ? err.message : String(err)})`,\n )\n continue\n }\n const hash = sha256(bytes)\n const bucket = localByHash.get(hash) ?? []\n bucket.push(spec)\n localByHash.set(hash, bucket)\n }\n log(` hashed ${localByHash.size} distinct local image(s)`)\n\n // 2. Walk the account and hash every remote object's image.\n const remote: RemoteAsset[] = []\n for await (const obj of requireList(provider)()) remote.push(obj)\n log(` found ${remote.length} object(s) on the account`)\n\n const matchedRemote = new Set<string>()\n const ambiguous: string[] = []\n let matched = 0\n let cursor = 0\n\n async function worker() {\n for (;;) {\n const obj = remote[cursor++]\n if (!obj) return\n const url = obj.previewUrl\n if (!url || obj.status !== \"completed\") continue\n\n let hash: string | undefined = cache.hashes[obj.id]\n if (hash) {\n cacheHits++\n } else {\n try {\n const bytes = await provider.download(url)\n decodePng(bytes)\n hash = sha256(bytes)\n } catch {\n continue\n }\n cache.hashes[obj.id] = hash\n }\n\n const hits = localByHash.get(hash)\n if (!hits?.length) continue\n\n matchedRemote.add(obj.id)\n for (const spec of hits) {\n const key = lockKey(spec.styleId, spec.assetId)\n const existing = lock.entries[key]\n if (existing?.objectId && existing.objectId !== obj.id) {\n // Two account objects produced identical bytes. Harmless, but the\n // first wins so re-running adopt stays deterministic.\n ambiguous.push(`${key}: already mapped to ${existing.objectId}, also matches ${obj.id}`)\n continue\n }\n upsert(lock, key, {\n styleId: spec.styleId,\n assetId: spec.assetId,\n // Deliberately the CURRENT spec hash: adoption declares \"the file on\n // disk satisfies today's spec\", so plan reports it as ok, not stale.\n specHash: spec.specHash,\n generator: spec.generator,\n prompt: obj.prompt || spec.prompt,\n width: obj.width,\n height: obj.height,\n jobId: obj.id,\n objectId: obj.id,\n reviewObjectId: null,\n candidateIndex: null,\n status: \"downloaded\",\n error: null,\n sourceUrl: url,\n outputs: [{ path: portableOutputPath(spec.outFile, spec.root), sha256: hash }],\n submittedAt: obj.createdAt,\n downloadedAt: new Date().toISOString(),\n cost: 0, // already paid for, in a previous billing period\n costUnit: validateCostEstimate(provider.id, provider.estimate(spec)).unit,\n provider: provider.id,\n })\n matched++\n log(` adopted ${key} ← ${obj.id}`)\n }\n }\n }\n\n await Promise.all(Array.from({ length: Math.min(concurrency, remote.length || 1) }, worker))\n await saveLock(lockPath, lock)\n\n if (!opts.noCache) {\n pruneCache(cache, new Set(remote.map((o) => o.id)))\n await saveCache(cachePath, cache)\n if (cacheHits) log(` reused ${cacheHits} cached hash(es); downloaded ${remote.length - cacheHits}`)\n }\n\n return {\n scanned: remote.length,\n matched,\n unmatchedLocal,\n unmatchedRemote: remote.filter((o) => !matchedRemote.has(o.id)),\n ambiguous,\n }\n}\n\n/** Applies manifest tags to every adopted object so the account becomes filterable. */\nexport async function tagAdopted(\n provider: Provider,\n specs: ResolvedSpec[],\n lock: Lock,\n opts: { onProgress?: (msg: string) => void } = {},\n): Promise<number> {\n const log = opts.onProgress ?? (() => {})\n const specByKey = new Map(specs.map((s) => [lockKey(s.styleId, s.assetId), s]))\n let count = 0\n for (const [key, entry] of Object.entries(lock.entries)) {\n const spec = specByKey.get(key)\n if (!spec || !entry.objectId) continue\n if (!provider.setTags) return count // capability absent\n try {\n await provider.setTags(entry.objectId, spec.tags)\n count++\n } catch (err) {\n log(` tag failed ${key}: ${err instanceof Error ? err.message : String(err)}`)\n }\n }\n return count\n}\n\n/**\n * Backfills empty manifest prompts from the prompts recorded on adopted objects.\n *\n * For a project onboarded with `init`, this is how the manifest becomes real:\n * the prompts that actually produced the shipped art are recovered from the\n * account rather than reconstructed by guesswork. Only empty prompts are\n * touched, so hand-authored text is never overwritten.\n */\nexport async function writePromptsBack(\n manifestPath: string,\n lock: Lock,\n opts: { onProgress?: (msg: string) => void } = {},\n): Promise<{ filled: number; stillEmpty: string[] }> {\n const log = opts.onProgress ?? (() => {})\n const raw = JSON.parse(await readFile(manifestPath, \"utf8\")) as {\n assets: Record<string, { prompt?: string }>\n }\n\n // An asset can be adopted under several styles; prefer the longest recovered\n // prompt, which is the most complete description of what was generated.\n const best = new Map<string, string>()\n for (const entry of Object.values(lock.entries)) {\n if (!entry.objectId || !entry.prompt) continue\n const current = best.get(entry.assetId)\n if (!current || entry.prompt.length > current.length) best.set(entry.assetId, entry.prompt)\n }\n\n let filled = 0\n const stillEmpty: string[] = []\n for (const [id, asset] of Object.entries(raw.assets)) {\n if (asset.prompt && asset.prompt.trim()) continue\n const recovered = best.get(id)\n if (recovered) {\n asset.prompt = recovered\n filled++\n } else {\n stillEmpty.push(id)\n }\n }\n\n await writeFile(manifestPath, JSON.stringify(raw, null, 2) + \"\\n\")\n log(` filled ${filled} prompt(s) from adopted objects`)\n return { filled, stillEmpty }\n}\n\nexport function formatUnmatchedRemote(objects: RemoteAsset[], limit = 15): string {\n const lines = objects\n .slice(0, limit)\n .map((o) => ` ${o.id} ${o.createdAt.slice(0, 10)} ${(o.prompt || \"\").slice(0, 60)}`)\n if (objects.length > limit) lines.push(` … and ${objects.length - limit} more`)\n return lines.join(\"\\n\")\n}\n\nexport function relativeToCwd(p: string): string {\n return path.relative(process.cwd(), p) || p\n}\n","export interface SheetGroup {\n key: string\n assetId: string\n styleId: string\n prompt: string\n reviewObjectId: string\n frameUrls: string[]\n size: number\n}\n\nconst escapeHtml = (s: string) =>\n s.replace(/[&<>\"']/g, (c) => ({ \"&\": \"&\", \"<\": \"<\", \">\": \">\", '\"': \""\", \"'\": \"'\" })[c]!)\n\n/**\n * A contact sheet for choosing among generated candidates.\n *\n * This is the only step that needs human judgement, so it is optimised for one\n * thing: deciding fast. Candidates render at 4x with a transparency\n * checkerboard and a true-size swatch beside them, because a pixel icon that\n * looks good enlarged can still be unreadable at its real size. Keyboard-first,\n * one row per asset, and the page posts back and closes itself.\n */\nexport function renderSheet(groups: SheetGroup[]): string {\n // Prompts are author-controlled but arbitrary text, and they reach the page\n // both as JSON inside a <script> and via innerHTML. Escape for both: HTML\n // entities for the markup path, and `<\\/` for the script-tag path so a\n // prompt containing \"</script>\" cannot break out.\n const safe = groups.map((g) => ({\n ...g,\n styleId: escapeHtml(g.styleId),\n assetId: escapeHtml(g.assetId),\n prompt: escapeHtml(g.prompt),\n }))\n const data = JSON.stringify(safe).replace(/<\\//g, \"<\\\\/\")\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>pixelkiln — pick candidates</title>\n<style>\n :root {\n --bg: #17150f; --panel: #201d17; --panel-deep: #100f0c;\n --line: rgba(243,234,214,.16); --line-strong: rgba(243,234,214,.3);\n --text: #f3ead6; --dim: #9b9384; --accent: #ff6b35;\n --accent-soft: #ff9c5f; --ok: #b9f27c; --warn: #ff9c5f;\n }\n * { box-sizing: border-box; }\n body { margin:0; background:var(--bg); color:var(--text);\n font:14px/1.5 ui-sans-serif,-apple-system,\"SF Pro Text\",Inter,system-ui,sans-serif; }\n header { position:sticky; top:0; z-index:10; background:var(--panel);\n border-bottom:1px solid var(--line-strong); padding:15px 22px;\n display:flex; align-items:center; gap:16px; flex-wrap:wrap; }\n h1 { font:700 14px/1 ui-monospace,SFMono-Regular,Menlo,monospace;\n margin:0; letter-spacing:-.02em; }\n h1::before { content:'◆'; color:var(--accent); margin-right:9px; font-size:11px; }\n .count { color:var(--dim); font-variant-numeric:tabular-nums; }\n button { font:inherit; font-weight:600; border-radius:0; padding:9px 16px;\n border:1px solid var(--line); background:transparent; color:var(--text); cursor:pointer; }\n button.primary { background:var(--accent); border-color:var(--accent); color:var(--bg); }\n button:disabled { opacity:.45; cursor:not-allowed; }\n .group { border-bottom:1px solid var(--line); padding:22px; }\n .group.done { background:rgba(185,242,124,.035); }\n .ghead { display:flex; align-items:baseline; gap:12px; margin-bottom:16px; flex-wrap:wrap; }\n .style { font-size:10.5px; font-weight:650; text-transform:uppercase; letter-spacing:.03em;\n color:var(--accent-soft); border:1px solid var(--accent); border-radius:0; padding:2px 6px; }\n .aid { font-weight:650; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }\n .prompt { flex:1; min-width:280px; color:var(--dim); font-size:12.5px; max-width:80ch; }\n .frames { display:flex; flex-wrap:wrap; gap:10px; }\n .cand { border:2px solid var(--line-strong); border-radius:0; padding:7px; background:var(--panel-deep);\n cursor:pointer; display:flex; flex-direction:column; align-items:center; gap:5px; position:relative; }\n .cand:hover { border-color:var(--dim); }\n .cand.active { border-color:var(--dim); box-shadow:0 0 0 2px color-mix(in srgb, var(--dim) 20%, transparent); }\n .cand.sel { border-color:var(--ok); box-shadow:0 0 0 3px color-mix(in srgb, var(--ok) 22%, transparent); }\n .cand img { image-rendering:pixelated; display:block;\n background-image:\n linear-gradient(45deg,#0000 25%,#7f7f7f22 25%,#7f7f7f22 75%,#0000 75%),\n linear-gradient(45deg,#0000 25%,#7f7f7f22 25%,#7f7f7f22 75%,#0000 75%);\n background-size:12px 12px; background-position:0 0,6px 6px; border-radius:0; }\n .idx { font-size:10.5px; color:var(--dim); font-variant-numeric:tabular-nums; }\n .actual { position:absolute; right:-3px; bottom:-3px; image-rendering:pixelated;\n border:1px solid var(--line); border-radius:0; background:var(--panel); }\n .skip { align-self:center; color:var(--dim); font-size:12px; }\n footer { padding:26px 20px 60px; color:var(--dim); }\n kbd { border:1px solid var(--line); border-bottom-width:2px; border-radius:0;\n padding:1px 5px; font-size:11px; font-family:ui-monospace,Menlo,monospace; }\n #status { color:var(--warn); }\n</style>\n</head>\n<body>\n<header>\n <h1>pixelkiln</h1>\n <span class=\"count\"><span id=\"picked\">0</span> of <span id=\"total\">0</span> chosen</span>\n <span id=\"status\"></span>\n <span style=\"flex:1\"></span>\n <button id=\"submit\" class=\"primary\" disabled>Apply selections</button>\n</header>\n<main id=\"root\"></main>\n<footer>\n Click a candidate to choose it; click again to unchoose. In the focused row,\n <kbd>←</kbd>/<kbd>→</kbd> browses every candidate and <kbd>Enter</kbd> chooses;\n <kbd>1</kbd>–<kbd>9</kbd> picks directly, <kbd>0</kbd> skips, and\n <kbd>↑</kbd>/<kbd>↓</kbd> changes rows. Unchosen rows stay in review — nothing is\n discarded by closing this page.\n</footer>\n<script>\nconst GROUPS = ${data};\nconst picks = new Map();\nconst root = document.getElementById('root');\ndocument.getElementById('total').textContent = GROUPS.length;\n\nGROUPS.forEach((g, gi) => {\n const el = document.createElement('section');\n el.className = 'group';\n el.tabIndex = 0;\n el.dataset.gi = String(gi);\n const scale = g.size <= 48 ? 4 : g.size <= 96 ? 3 : 2;\n el.innerHTML =\n '<div class=\"ghead\"><span class=\"style\">' + g.styleId + '</span>' +\n '<span class=\"aid\">' + g.assetId + '</span>' +\n '<span class=\"prompt\">' + g.prompt + '</span></div>' +\n '<div class=\"frames\"></div>';\n const frames = el.querySelector('.frames');\n g.frameUrls.forEach((url, i) => {\n const c = document.createElement('button');\n c.type = 'button';\n c.className = 'cand';\n c.tabIndex = -1;\n c.setAttribute('aria-label', 'Choose candidate ' + (i + 1) + ' of ' + g.frameUrls.length);\n\n const preview = document.createElement('img');\n preview.src = url;\n preview.width = g.size * scale;\n preview.height = g.size * scale;\n preview.loading = 'lazy';\n const index = document.createElement('span');\n index.className = 'idx';\n index.textContent = String(i + 1);\n const actual = document.createElement('img');\n actual.className = 'actual';\n actual.src = url;\n actual.width = g.size;\n actual.height = g.size;\n actual.loading = 'lazy';\n c.append(preview, index, actual);\n\n c.onclick = () => {\n activate(i, frames);\n choose(gi, i, c, frames, el);\n // Keep the row as the keyboard target. Otherwise a clicked <button>\n // receives focus and Enter would invoke both its native click and the\n // row shortcut, toggling the same choice twice.\n el.focus();\n };\n c.onmouseenter = () => activate(i, frames);\n frames.appendChild(c);\n });\n frames.dataset.active = '0';\n frames.querySelector('.cand')?.classList.add('active');\n root.appendChild(el);\n});\n\nfunction activate(i, frames) {\n const candidates = [...frames.querySelectorAll('.cand')];\n if (!candidates.length) return null;\n const next = ((i % candidates.length) + candidates.length) % candidates.length;\n candidates.forEach(n => n.classList.remove('active'));\n candidates[next].classList.add('active');\n frames.dataset.active = String(next);\n candidates[next].scrollIntoView({ block: 'nearest', inline: 'nearest' });\n return candidates[next];\n}\n\nfunction choose(gi, i, node, frames, groupEl) {\n const current = picks.get(gi);\n frames.querySelectorAll('.cand').forEach(n => n.classList.remove('sel'));\n if (current === i) { picks.delete(gi); groupEl.classList.remove('done'); }\n else { picks.set(gi, i); node.classList.add('sel'); groupEl.classList.add('done'); }\n refresh();\n}\nfunction refresh() {\n document.getElementById('picked').textContent = picks.size;\n document.getElementById('submit').disabled = picks.size === 0;\n}\ndocument.addEventListener('keydown', e => {\n const g = document.activeElement?.closest?.('.group');\n if (!g) return;\n const gi = Number(g.dataset.gi);\n const frames = g.querySelector('.frames');\n const candidates = [...frames.querySelectorAll('.cand')];\n const active = Number(frames.dataset.active || 0);\n let advance = false;\n\n if (e.key === 'ArrowLeft') activate(active - 1, frames);\n else if (e.key === 'ArrowRight') activate(active + 1, frames);\n else if (e.key === 'Home') activate(0, frames);\n else if (e.key === 'End') activate(candidates.length - 1, frames);\n else if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {\n const sibling = e.key === 'ArrowUp' ? g.previousElementSibling : g.nextElementSibling;\n if (sibling) { sibling.focus(); sibling.scrollIntoView({ block: 'center', behavior: 'smooth' }); }\n } else if (e.key === 'Enter' || e.key === ' ') {\n const node = candidates[active];\n if (!node) return;\n choose(gi, active, node, frames, g);\n advance = true;\n } else if (e.key === '0') {\n picks.delete(gi); g.classList.remove('done');\n frames.querySelectorAll('.cand').forEach(n => n.classList.remove('sel'));\n refresh();\n advance = true;\n } else if (/^[1-9]$/.test(e.key)) {\n const i = Number(e.key) - 1;\n const node = candidates[i];\n if (!node) return;\n activate(i, frames);\n choose(gi, i, node, frames, g);\n advance = true;\n } else {\n return;\n }\n if (advance) {\n const next = g.nextElementSibling;\n if (next) { next.focus(); next.scrollIntoView({ block: 'center', behavior: 'smooth' }); }\n }\n e.preventDefault();\n});\n\ndocument.getElementById('submit').onclick = async () => {\n const btn = document.getElementById('submit');\n btn.disabled = true;\n const status = document.getElementById('status');\n status.textContent = 'applying…';\n const selections = [...picks.entries()].map(([gi, index]) => ({ key: GROUPS[gi].key, index }));\n try {\n const res = await fetch('/apply', {\n method: 'POST', headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ selections }),\n });\n if (!res.ok) throw new Error(await res.text());\n status.textContent = 'done — you can close this tab';\n document.body.style.opacity = '.6';\n } catch (err) {\n status.textContent = 'failed: ' + err.message;\n btn.disabled = false;\n }\n};\n</script>\n</body>\n</html>`\n}\n","import { createServer } from \"node:http\"\nimport { spawn } from \"node:child_process\"\n\n/**\n * The HTTP plumbing shared by every local review page (`pick`, `salvage`):\n * serve one static page at `/`, accept one POST of decisions, hand the parsed\n * body to the caller, and resolve once that caller's handler succeeds.\n *\n * This exists because `pick` and `salvage` each hand-rolled the identical\n * server — same GET/POST routing, same ephemeral-port dance, same `open`\n * spawn, same error handling — and a bug fixed in one silently stayed a bug\n * in the other (as happened here: `salvage`'s manifest-write bug had no\n * equivalent in `pick` only because `pick` never merges a whole manifest back\n * in). A third review page now gets this for free instead of a third copy to\n * keep in sync.\n *\n * Deliberately NOT a full framework: one page, one apply endpoint, one round\n * trip. Anything needing more should not reach for this.\n */\nexport interface ReviewServerOptions<TResult> {\n /** The full HTML document served at GET /. */\n html: string\n /** Parses the POSTed decisions and performs them. Only closes the server\n * on success — a thrown error leaves the page free to retry. */\n handleApply: (body: unknown) => Promise<TResult>\n /** Logged once the server is listening, given its localhost URL. */\n onReady: (url: string) => void\n port?: number\n /** Open the URL in the system browser once listening. Default true. */\n open?: boolean\n onProgress?: (msg: string) => void\n}\n\nexport function serveReviewPage<TResult>(opts: ReviewServerOptions<TResult>): Promise<TResult> {\n const log = opts.onProgress ?? (() => {})\n\n return new Promise<TResult>((resolve, reject) => {\n const server = createServer(async (req, res) => {\n if (req.method === \"GET\" && (req.url === \"/\" || req.url?.startsWith(\"/?\"))) {\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" })\n res.end(opts.html)\n return\n }\n\n if (req.method === \"POST\" && req.url === \"/apply\") {\n const expectedOrigin = req.headers.host ? `http://${req.headers.host}` : null\n if (req.headers.origin && req.headers.origin !== expectedOrigin) {\n res.writeHead(403, { \"Content-Type\": \"text/plain\" })\n res.end(\"cross-origin review submissions are not allowed\")\n return\n }\n if (!req.headers[\"content-type\"]?.toLowerCase().startsWith(\"application/json\")) {\n res.writeHead(415, { \"Content-Type\": \"text/plain\" })\n res.end(\"application/json is required\")\n return\n }\n try {\n const chunks: Buffer[] = []\n let bytes = 0\n for await (const c of req) {\n const chunk = c as Buffer\n bytes += chunk.length\n if (bytes > 64 * 1024) {\n res.writeHead(413, { \"Content-Type\": \"text/plain\" })\n res.end(\"review submission is too large\")\n return\n }\n chunks.push(chunk)\n }\n const body: unknown = JSON.parse(Buffer.concat(chunks).toString(\"utf8\"))\n const result = await opts.handleApply(body)\n res.writeHead(200, { \"Content-Type\": \"application/json\" })\n res.end(JSON.stringify(result))\n server.close(() => resolve(result))\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n log(` apply failed: ${message}`)\n res.writeHead(500, { \"Content-Type\": \"text/plain\" })\n res.end(message)\n }\n return\n }\n\n res.writeHead(404)\n res.end()\n })\n\n server.on(\"error\", reject)\n server.listen(opts.port ?? 0, \"127.0.0.1\", () => {\n const address = server.address()\n const port = typeof address === \"object\" && address ? address.port : opts.port\n opts.onReady(`http://127.0.0.1:${port}/`)\n if (opts.open !== false && process.platform === \"darwin\") {\n spawn(\"open\", [`http://127.0.0.1:${port}/`], { stdio: \"ignore\", detached: true }).unref()\n }\n })\n })\n}\n","import type { Provider } from \"../provider.ts\"\nimport { saveLock, upsert } from \"../lock.ts\"\nimport type { Lock } from \"../types.ts\"\nimport { renderSheet, type SheetGroup } from \"./sheet.ts\"\nimport { serveReviewPage } from \"./review-server.ts\"\n\nexport interface PickResult {\n selected: number\n skipped: number\n}\n\n/**\n * Serves the contact sheet on localhost, waits for the selections to be\n * applied, then shuts down.\n *\n * Selections are committed to PixelLab (`select-frames` promotes the chosen\n * candidate to its own object and drops the rest) and written to the lockfile\n * before the browser gets its response, so a closed tab never loses a choice.\n */\nexport async function runPicker(\n provider: Provider,\n lock: Lock,\n lockPath: string,\n opts: { port?: number; open?: boolean; onProgress?: (msg: string) => void } = {},\n): Promise<PickResult> {\n const log = opts.onProgress ?? (() => {})\n\n const groups: SheetGroup[] = []\n for (const [key, entry] of Object.entries(lock.entries)) {\n if (entry.status !== \"review\" || !entry.reviewObjectId) continue\n try {\n const state = await provider.poll(entry.reviewObjectId, entry.generator)\n if (state.status !== \"review\" || !state.candidateUrls.length) continue\n groups.push({\n key,\n assetId: entry.assetId,\n styleId: entry.styleId,\n prompt: entry.prompt,\n reviewObjectId: entry.reviewObjectId,\n frameUrls: state.candidateUrls,\n size: Math.max(entry.width, entry.height),\n })\n } catch (err) {\n log(` could not load candidates for ${key}: ${err instanceof Error ? err.message : String(err)}`)\n }\n }\n\n if (groups.length === 0) return { selected: 0, skipped: 0 }\n\n const html = renderSheet(groups)\n const byKey = new Map(groups.map((g) => [g.key, g]))\n\n return serveReviewPage<PickResult>({\n html,\n port: opts.port,\n open: opts.open,\n onProgress: log,\n onReady: (url) => {\n log(`\\n ${groups.length} asset(s) awaiting selection: ${url}`)\n log(` (leave this running; it exits once you apply)\\n`)\n },\n handleApply: async (body) => {\n const { selections } = body as { selections: { key: string; index: number }[] }\n\n let selected = 0\n for (const { key, index } of selections) {\n const group = byKey.get(key)\n const entry = lock.entries[key]\n if (!group || !entry?.reviewObjectId) continue\n if (!Number.isInteger(index) || index < 0 || index >= group.frameUrls.length) continue\n\n // Promote the chosen candidate; the review parent is removed upstream\n // once nothing is left in it.\n const { objectId, sourceUrl } = await provider.selectCandidate(\n entry.reviewObjectId,\n index,\n `asset:${entry.assetId}`,\n entry.generator,\n )\n\n upsert(lock, key, {\n status: \"selected\",\n objectId,\n candidateIndex: index,\n sourceUrl: sourceUrl ?? group.frameUrls[index] ?? null,\n sourceUrls: [],\n provider: provider.id,\n })\n selected++\n log(` picked ${key} → candidate ${index + 1}`)\n }\n\n await saveLock(lockPath, lock)\n return { selected, skipped: groups.length - selected }\n },\n })\n}\n","import { readdir, readFile, writeFile } from \"node:fs/promises\"\nimport { existsSync } from \"node:fs\"\nimport path from \"node:path\"\nimport type { Generator, Manifest } from \"../types.ts\"\n\n/** Minimal PNG header read — avoids pulling in an image library just for dimensions. */\nexport function pngSize(buf: Buffer): { width: number; height: number } | null {\n if (buf.length < 24) return null\n const isPng = buf.readUInt32BE(0) === 0x89504e47 && buf.readUInt32BE(4) === 0x0d0a1a0a\n if (!isPng) return null\n if (buf.toString(\"ascii\", 12, 16) !== \"IHDR\") return null\n return { width: buf.readUInt32BE(16), height: buf.readUInt32BE(20) }\n}\n\n/** Path segment → a stable, readable asset id. */\nexport function slugify(value: string): string {\n return value\n .replace(/\\.png$/i, \"\")\n .replace(/[^a-zA-Z0-9]+/g, \"_\")\n .replace(/^_+|_+$/g, \"\")\n .toLowerCase()\n}\n\nexport interface ScannedAsset {\n id: string\n category: string\n file: string\n width: number\n height: number\n}\n\nasync function walk(dir: string, exclude: string[]): Promise<string[]> {\n const out: string[] = []\n for (const entry of await readdir(dir, { withFileTypes: true })) {\n const full = path.join(dir, entry.name)\n if (exclude.some((x) => full.includes(x))) continue\n if (entry.isDirectory()) out.push(...(await walk(full, exclude)))\n else if (entry.name.toLowerCase().endsWith(\".png\")) out.push(full)\n }\n return out\n}\n\n/**\n * Scans an existing asset tree and produces manifest entries for it.\n *\n * Prompts are left empty on purpose. For a project whose art already exists,\n * the accurate prompts are the ones actually used upstream — `adopt\n * --write-prompts` recovers those from the matched objects rather than having\n * anyone invent plausible-looking replacements.\n */\nexport async function scanAssets(\n root: string,\n opts: { exclude?: string[] } = {},\n): Promise<{ assets: ScannedAsset[]; skipped: string[] }> {\n const exclude = opts.exclude ?? []\n const files = await walk(root, exclude)\n const assets: ScannedAsset[] = []\n const skipped: string[] = []\n const seen = new Map<string, number>()\n\n for (const file of files.sort()) {\n const size = pngSize(await readFile(file))\n if (!size) {\n skipped.push(`${file} (not a readable PNG)`)\n continue\n }\n const rel = path.relative(root, file)\n const category = path.dirname(rel) === \".\" ? \"\" : path.dirname(rel)\n let id = slugify(path.basename(rel))\n\n // Basenames repeat across category folders; disambiguate rather than collide.\n if (seen.has(id)) {\n const n = seen.get(id)! + 1\n seen.set(id, n)\n id = `${slugify(category.replace(/[/\\\\]/g, \"_\"))}_${id}`.replace(/^_+/, \"\")\n } else {\n seen.set(id, 1)\n }\n\n assets.push({ id, category, file: rel, width: size.width, height: size.height })\n }\n\n return { assets, skipped }\n}\n\nexport function buildManifest(\n name: string,\n styleId: string,\n generator: Generator,\n outDir: string,\n scanned: ScannedAsset[],\n): Manifest {\n const squares = scanned.filter((a) => a.width === a.height)\n const commonSize = squares.length ? mode(squares.map((a) => a.width)) : 64\n\n const assets: Manifest[\"assets\"] = {}\n for (const asset of scanned) {\n assets[asset.id] = {\n prompt: \"\",\n promptByStyle: {},\n category: asset.category || undefined,\n file: asset.file,\n tags: [],\n styles: [],\n ...(generator === \"map\"\n ? { width: asset.width, height: asset.height }\n : asset.width === asset.height && asset.width !== commonSize\n ? { size: asset.width }\n : {}),\n }\n }\n\n return {\n name,\n styles: {\n [styleId]: {\n generator,\n size: commonSize,\n // Matches the schema default: a scaffolded style is for sprites, and\n // a sprite wants its background stripped.\n noBackground: true,\n promptPrefix: \"\",\n promptSuffix: \"\",\n styleImages: [],\n palette: [],\n outDir,\n tags: [name],\n },\n },\n assets,\n }\n}\n\nfunction mode(values: number[]): number {\n const counts = new Map<number, number>()\n for (const v of values) counts.set(v, (counts.get(v) ?? 0) + 1)\n return [...counts.entries()].sort((a, b) => b[1] - a[1])[0]?.[0] ?? 64\n}\n\nexport async function writeManifestFile(target: string, manifest: Manifest): Promise<void> {\n if (existsSync(target)) {\n throw new Error(`${target} already exists — refusing to overwrite an existing manifest.`)\n }\n await writeFile(target, JSON.stringify(manifest, null, 2) + \"\\n\")\n}\n","import { readFile } from \"node:fs/promises\"\nimport { existsSync } from \"node:fs\"\nimport { requireList, type Provider, type RemoteAsset } from \"../provider.ts\"\nimport { parseLock, type Lock, type Manifest } from \"../types.ts\"\n\n/**\n * Objects on the account that no known lockfile claims.\n *\n * The point of this is recovery, not cleanup. An account accumulates work that\n * was generated, paid for, and never landed in a repo — alternate takes,\n * abandoned experiments, whole categories that were explored and forgotten.\n * Measured on one account: 190 of 361 objects were unclaimed, and a visual\n * sample showed usable character portraits, tree variants, terrain tiles, and\n * UI icons rather than rejects.\n *\n * Correctness here depends entirely on being given EVERY lockfile. One account\n * is shared across projects, so an incomplete claim set makes another project's\n * shipped art look like an orphan.\n */\nexport async function loadClaims(lockPaths: string[]): Promise<Set<string>> {\n const claimed = new Set<string>()\n for (const p of lockPaths) {\n if (!existsSync(p)) throw new Error(`Claim lockfile not found: ${p}`)\n let parsed: Lock\n try {\n parsed = parseLock(JSON.parse(await readFile(p, \"utf8\")))\n } catch {\n throw new Error(`Claim lockfile is malformed: ${p}`)\n }\n for (const entry of Object.values(parsed.entries)) {\n if (entry.objectId) claimed.add(entry.objectId)\n if (entry.reviewObjectId) claimed.add(entry.reviewObjectId)\n if (entry.jobId) claimed.add(entry.jobId)\n }\n }\n return claimed\n}\n\nexport interface Orphan {\n id: string\n prompt: string\n width: number\n height: number\n createdAt: string\n previewUrl: string\n tags: string[]\n}\n\nexport async function findOrphans(\n provider: Provider,\n claimed: Set<string>,\n opts: { onProgress?: (msg: string) => void } = {},\n): Promise<{ orphans: Orphan[]; total: number }> {\n const log = opts.onProgress ?? (() => {})\n const all: RemoteAsset[] = []\n for await (const obj of requireList(provider)()) all.push(obj)\n log(` scanned ${all.length} object(s) on the account`)\n\n const orphans = all\n .filter((o) => !claimed.has(o.id) && o.status === \"completed\" && o.previewUrl)\n .map((o) => ({\n id: o.id,\n prompt: o.prompt || \"(no prompt recorded)\",\n width: o.width,\n height: o.height,\n createdAt: o.createdAt,\n previewUrl: o.previewUrl!,\n tags: o.tags ?? [],\n }))\n // Newest first: recent work is likeliest to be worth recovering.\n .sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n\n return { orphans, total: all.length }\n}\n\n/**\n * Fragments shorter than this match too much by accident (an empty\n * `promptPrefix`/`promptSuffix`, or a short one like \"clean\", would otherwise\n * \"match\" nearly every prompt via `.includes`).\n */\nconst MIN_STYLE_FRAGMENT_LENGTH = 12\n\n/**\n * Whether a style's `promptPrefix`/`promptSuffix` — boilerplate baked into\n * every generation of that style — appears in a prompt. Unlike\n * `matchOrphanStyle`, this never assumes a match just because a manifest\n * only has one style: it is the \"is this genuinely recognisable\" check, used\n * both by `matchOrphanStyle` and to test a prompt against a project that\n * isn't the current one.\n */\nfunction matchStyleByPattern(prompt: string, manifest: Manifest): string | null {\n const p = prompt.toLowerCase()\n for (const styleId of Object.keys(manifest.styles)) {\n const style = manifest.styles[styleId]!\n for (const raw of [style.promptPrefix, style.promptSuffix]) {\n const frag = raw?.trim().toLowerCase()\n if (frag && frag.length >= MIN_STYLE_FRAGMENT_LENGTH && p.includes(frag)) return styleId\n }\n }\n return null\n}\n\n/**\n * Which manifest style, if any, an orphan's prompt was generated from.\n *\n * A manifest with only one style skips the pattern check entirely — there is\n * nothing to disambiguate, and a style with an empty prefix/suffix (common\n * for single-style projects that don't template their prompts, like a\n * `map`-generator asset pack) would otherwise match nothing at all. This is\n * a routing decision (\"where would salvage import this\"), not a claim that\n * the content is genuinely this project's — see `groupOrphansByStyle`'s\n * `siblings` param for that distinction, which single-style manifests need\n * and multi-style ones get from the plain pattern check already.\n */\nexport function matchOrphanStyle(prompt: string, manifest: Manifest): string | null {\n const styleIds = Object.keys(manifest.styles)\n if (styleIds.length <= 1) return styleIds[0] ?? null\n return matchStyleByPattern(prompt, manifest)\n}\n\n/** A sibling project's manifest, consulted only to recognise its own style\n * patterns — never as an import target. */\nexport interface SiblingManifest {\n /** How to refer to this sibling in output — a project directory name, typically. */\n label: string\n manifest: Manifest\n}\n\nexport interface OrphanGroups {\n /** styleId → its matched orphans, in manifest style order. */\n matched: Map<string, Orphan[]>\n /** Orphans that matched no style anywhere known — this manifest or any sibling. */\n unmatched: Orphan[]\n /** \"<sibling label>: <styleId>\" → orphans that confidently matched a\n * SIBLING's own pattern instead of this manifest's — excluded from\n * `matched` even where this manifest would otherwise have swallowed them\n * by default (a single-style manifest with nothing of its own to check\n * against). Empty unless `siblings` was passed to `groupOrphansByStyle`. */\n elsewhere: Map<string, Orphan[]>\n}\n\n/**\n * Splits orphans by the style that most likely produced them.\n *\n * `salvage` used to hand a single `--style` to a whole session regardless of\n * how many the orphan pool actually spanned, so importing anything wrong\n * silently mislabeled it under the first style in the manifest. Grouping\n * first lets the caller run one correctly-scoped session per style instead.\n *\n * A single-style manifest has no pattern of its own to filter by, so by\n * default everything routes to that one style — correct for a genuinely\n * single-project account, wrong for a shared one where the orphan pool is\n * mostly a sibling's art. Passing that sibling's manifest via `siblings` (its\n * lockfile sits beside it, by the same convention `--lock` defaults from\n * `--manifest`) lets a confident match against ITS pattern win instead,\n * pulling those orphans out of `matched` and into `elsewhere` even though\n * this manifest would otherwise have claimed them.\n */\nexport function groupOrphansByStyle(\n orphans: Orphan[],\n manifest: Manifest,\n siblings: SiblingManifest[] = [],\n): OrphanGroups {\n const matched = new Map<string, Orphan[]>()\n const elsewhere = new Map<string, Orphan[]>()\n const unmatched: Orphan[] = []\n const ownStyleIds = Object.keys(manifest.styles)\n for (const styleId of ownStyleIds) matched.set(styleId, [])\n\n for (const o of orphans) {\n const own = matchStyleByPattern(o.prompt, manifest)\n if (own) {\n matched.get(own)!.push(o)\n continue\n }\n\n const sibling = siblings.find((s) => matchStyleByPattern(o.prompt, s.manifest))\n if (sibling) {\n const key = `${sibling.label}: ${matchStyleByPattern(o.prompt, sibling.manifest)}`\n const list = elsewhere.get(key) ?? []\n list.push(o)\n elsewhere.set(key, list)\n continue\n }\n\n // Nothing recognised it anywhere. A single-style manifest still has no\n // better place to put it than its one style — the same pragmatic default\n // matchOrphanStyle uses — but a multi-style one genuinely doesn't know.\n if (ownStyleIds.length <= 1 && ownStyleIds[0]) matched.get(ownStyleIds[0])!.push(o)\n else unmatched.push(o)\n }\n for (const [styleId, list] of [...matched]) if (!list.length) matched.delete(styleId)\n return { matched, unmatched, elsewhere }\n}\n\n/**\n * A prompt makes a better id than a UUID. These are a starting point meant to\n * be renamed, so the goal is \"recognisable at a glance\", not perfection.\n */\nconst STYLE_WORDS = new Set([\n \"a\", \"an\", \"the\", \"one\", \"two\", \"three\", \"single\", \"centered\", \"center\", \"with\", \"and\",\n \"of\", \"on\", \"in\", \"for\", \"its\", \"has\", \"pixel\", \"art\", \"style\", \"game\", \"icon\",\n \"transparent\", \"background\", \"no\", \"premium\", \"indie\", \"achievement\", \"sprite\",\n \"isometric\", \"topdown\", \"top\", \"down\", \"view\", \"high\", \"low\", \"detailed\", \"simple\",\n \"clean\", \"bold\", \"dark\", \"outline\", \"silhouette\", \"colour\", \"color\", \"palette\",\n])\n\nexport function idFromPrompt(prompt: string, taken: Set<string>): string {\n // Prompts commonly read \"<style boilerplate>: <the actual subject>\". When a\n // colon is present the subject is after it, and using the whole string would\n // name every asset after the shared prefix.\n const colon = prompt.indexOf(\":\")\n const subject = colon >= 0 && colon < prompt.length - 12 ? prompt.slice(colon + 1) : prompt\n\n const words = subject\n .toLowerCase()\n .replace(/[^a-z0-9\\s]/g, \" \")\n .split(/\\s+/)\n .filter((w) => w.length > 2 && !STYLE_WORDS.has(w))\n .slice(0, 4)\n\n let base = words.join(\"_\") || \"salvaged\"\n let id = base\n let n = 2\n while (taken.has(id)) id = `${base}_${n++}`\n taken.add(id)\n return id\n}\n\n/**\n * Placeholder spec hash written by a salvage import. The real hash cannot be\n * computed until the manifest has been rewritten with the new asset, so the CLI\n * re-baselines these immediately afterwards. Exported so the writer and the\n * re-baseliner reference one constant rather than two copies of a string.\n */\nexport const SALVAGED_SPEC_HASH = \"salvaged\"\n\nexport type SalvageAction = \"import\" | \"keep\" | \"discard\"\n\nexport interface SalvageDecision {\n id: string\n action: SalvageAction\n}\n\n/**\n * Tags are the durable record of a decision. They are free and synchronous, and\n * unlike a local file they survive on the account itself — so a later salvage\n * run from a different machine sees what was already triaged.\n *\n * `discard` deliberately only tags. Deleting is a separate, explicit command.\n */\nexport async function applyTags(\n provider: Provider,\n decisions: SalvageDecision[],\n existing: Map<string, string[]>,\n opts: { onProgress?: (msg: string) => void } = {},\n): Promise<{ tagged: number; failed: number }> {\n const log = opts.onProgress ?? (() => {})\n let tagged = 0\n let failed = 0\n\n for (const { id, action } of decisions) {\n const current = (existing.get(id) ?? []).filter(\n (t) => t !== \"pixelkiln:keep\" && t !== \"pixelkiln:discard\" && t !== \"pixelkiln:imported\",\n )\n const decisionTag = `pixelkiln:${action === \"import\" ? \"imported\" : action}`\n // PixelLab caps tags at 20. Preserve the decision tag even when the object\n // already has 20 unrelated tags; it is the durable record of this action.\n const next = [...current.slice(0, 19), decisionTag]\n if (!provider.setTags) return { tagged, failed }\n try {\n await provider.setTags(id, next)\n tagged++\n } catch (err) {\n failed++\n log(` tag failed ${id}: ${err instanceof Error ? err.message : String(err)}`)\n }\n }\n return { tagged, failed }\n}\n","import { mkdir, writeFile, readFile } from \"node:fs/promises\"\nimport path from \"node:path\"\nimport type { Provider } from \"../provider.ts\"\nimport { sha256 } from \"../hash.ts\"\nimport { saveLock, upsert } from \"../lock.ts\"\nimport { portableOutputPath } from \"../outputs.ts\"\nimport { decodePng } from \"../png.ts\"\nimport { lockKey, type Lock, type Manifest } from \"../types.ts\"\nimport {\n applyTags,\n idFromPrompt,\n SALVAGED_SPEC_HASH,\n type Orphan,\n type SalvageDecision,\n} from \"../pipeline/salvage.ts\"\nimport { renderSalvageSheet } from \"./salvage-sheet.ts\"\nimport { serveReviewPage } from \"./review-server.ts\"\n\nconst PNG_SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])\n\nexport interface SalvageResult {\n imported: number\n kept: number\n discarded: number\n failed: number\n}\n\n/**\n * Serves the triage sheet and applies decisions.\n *\n * `import` is the only action that touches local state: it downloads the image,\n * writes a manifest asset and a lock entry, so a recovered sprite becomes a\n * first-class tracked asset rather than a loose file. `keep` and `discard` only\n * write tags upstream — no object is ever deleted here.\n */\nexport async function runSalvage(\n provider: Provider,\n orphans: Orphan[],\n ctx: {\n manifestPath: string\n manifest: Manifest\n styleId: string\n importDir: string\n lock: Lock\n lockPath: string\n },\n opts: { port?: number; open?: boolean; onProgress?: (msg: string) => void } = {},\n): Promise<SalvageResult> {\n const log = opts.onProgress ?? (() => {})\n const html = renderSalvageSheet(orphans, {\n styleId: ctx.styleId,\n importDir: path.relative(process.cwd(), ctx.importDir) || \".\",\n })\n const byId = new Map(orphans.map((o) => [o.id, o]))\n const existingTags = new Map(orphans.map((o) => [o.id, o.tags]))\n\n return serveReviewPage<SalvageResult>({\n html,\n port: opts.port,\n open: opts.open,\n onProgress: log,\n onReady: (url) => {\n log(`\\n ${orphans.length} unclaimed object(s) to triage: ${url}`)\n log(` (nothing is deleted here — discard only tags)\\n`)\n },\n handleApply: async (body) => {\n const { decisions } = body as { decisions: SalvageDecision[] }\n\n const result: SalvageResult = { imported: 0, kept: 0, discarded: 0, failed: 0 }\n const taken = new Set(Object.keys(ctx.manifest.assets))\n const importedAssetIds: string[] = []\n\n for (const decision of decisions) {\n const orphan = byId.get(decision.id)\n if (!orphan) continue\n\n if (decision.action === \"import\") {\n try {\n const buf = await provider.download(orphan.previewUrl)\n if (!buf.subarray(0, 8).equals(PNG_SIGNATURE)) throw new Error(\"not a PNG\")\n decodePng(buf)\n\n const assetId = idFromPrompt(orphan.prompt, taken)\n const rel = path.join(\"_salvaged\", `${assetId}.png`)\n const outFile = path.resolve(ctx.importDir, rel)\n await mkdir(path.dirname(outFile), { recursive: true })\n await writeFile(outFile, buf)\n\n ctx.manifest.assets[assetId] = {\n prompt: orphan.prompt,\n promptByStyle: {},\n category: \"_salvaged\",\n file: rel,\n tags: [\"salvaged\"],\n styles: [ctx.styleId],\n ...(orphan.width === orphan.height\n ? { size: orphan.width }\n : { width: orphan.width, height: orphan.height }),\n }\n\n upsert(ctx.lock, lockKey(ctx.styleId, assetId), {\n styleId: ctx.styleId,\n assetId,\n specHash: SALVAGED_SPEC_HASH,\n generator: orphan.width === orphan.height ? \"1dir\" : \"map\",\n prompt: orphan.prompt,\n width: orphan.width,\n height: orphan.height,\n jobId: orphan.id,\n reviewObjectId: null,\n objectId: orphan.id,\n candidateIndex: null,\n status: \"downloaded\",\n error: null,\n sourceUrl: orphan.previewUrl,\n outputs: [{\n path: portableOutputPath(outFile, path.dirname(ctx.manifestPath)),\n sha256: sha256(buf),\n }],\n submittedAt: orphan.createdAt,\n downloadedAt: new Date().toISOString(),\n cost: 0, // already paid for, in an earlier period\n costUnit: \"generations\",\n provider: provider.id,\n })\n importedAssetIds.push(assetId)\n result.imported++\n log(` imported ${assetId} ← ${orphan.id}`)\n } catch (err) {\n result.failed++\n log(` import failed ${orphan.id}: ${err instanceof Error ? err.message : String(err)}`)\n }\n } else if (decision.action === \"keep\") {\n result.kept++\n } else {\n result.discarded++\n }\n }\n\n await applyTags(provider, decisions, existingTags, { onProgress: log })\n\n // Persist the manifest additions and the lock together. Only the\n // newly imported entries are written back — re-merging the whole\n // in-memory manifest would overwrite every pre-existing asset with\n // its loadManifest()-normalized copy, turning a one-asset import\n // into a diff touching the entire file.\n const raw = JSON.parse(await readFile(ctx.manifestPath, \"utf8\")) as Manifest\n for (const id of importedAssetIds) raw.assets[id] = ctx.manifest.assets[id]!\n await writeFile(ctx.manifestPath, JSON.stringify(raw, null, 2) + \"\\n\")\n await saveLock(ctx.lockPath, ctx.lock)\n\n return result\n },\n })\n}\n","import type { Orphan } from \"../pipeline/salvage.ts\"\n\nconst escapeHtml = (s: string) =>\n s.replace(/[&<>\"']/g, (c) => ({ \"&\": \"&\", \"<\": \"<\", \">\": \">\", '\"': \""\", \"'\": \"'\" })[c]!)\n\nexport interface SalvageSheetContext {\n /** The style every \"import\" on this page will be tagged and routed under. */\n styleId: string\n /** Where an import lands, shown so the page answers \"where does this go\"\n * without anyone needing to go check the manifest. */\n importDir: string\n}\n\n/**\n * Triage sheet for unclaimed account objects.\n *\n * Optimised for volume: a couple of hundred items, most of which get a\n * one-keystroke verdict. Everything defaults to no decision, so closing the tab\n * changes nothing, and `discard` only ever writes a tag — deletion is a\n * separate command that has to be asked for by name.\n *\n * `salvage` opens one tab per matched style in sequence (grouping — see\n * pipeline/salvage.ts), and every one of them used to render the exact same\n * generic title. With several left open across styles there was no way to\n * tell them apart short of squinting at which images loaded. The tab title\n * and header now name the style the page is actually scoped to.\n */\nexport function renderSalvageSheet(orphans: Orphan[], ctx?: SalvageSheetContext): string {\n const safe = orphans.map((o) => ({ ...o, prompt: escapeHtml(o.prompt) }))\n const data = JSON.stringify(safe).replace(/<\\//g, \"<\\\\/\")\n const styleId = ctx ? escapeHtml(ctx.styleId) : null\n const importDir = ctx ? escapeHtml(ctx.importDir) : null\n\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>pixelkiln salvage${styleId ? ` — ${styleId}` : \"\"}</title>\n<style>\n :root { --bg:#0f1115; --panel:#171a21; --line:#262b36; --text:#e6e8ee; --dim:#8b93a7;\n --import:#6ee7a8; --keep:#7cc4ff; --discard:#f87171; }\n @media (prefers-color-scheme: light) {\n :root { --bg:#f6f7f9; --panel:#fff; --line:#dfe3ea; --text:#1a1d23; --dim:#666e80;\n --import:#0a8f52; --keep:#1a6fd4; --discard:#c0392b; }\n }\n * { box-sizing:border-box; }\n body { margin:0; background:var(--bg); color:var(--text);\n font:14px/1.5 ui-sans-serif,-apple-system,\"SF Pro Text\",Inter,system-ui,sans-serif; }\n header { position:sticky; top:0; z-index:10; background:var(--panel);\n border-bottom:1px solid var(--line); padding:12px 20px; display:flex; gap:14px;\n align-items:center; flex-wrap:wrap; }\n h1 { font-size:15px; margin:0; font-weight:600; }\n h1 .ctx { font-weight:500; color:var(--dim); }\n h1 .dest { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:12.5px; }\n .tally { color:var(--dim); font-variant-numeric:tabular-nums; }\n .tally b { color:var(--text); font-weight:600; }\n button { font:inherit; font-weight:550; border-radius:7px; padding:7px 14px;\n border:1px solid var(--line); background:transparent; color:var(--text); cursor:pointer; }\n button.primary { background:var(--import); border-color:var(--import); color:#08130d; }\n button:disabled { opacity:.45; cursor:not-allowed; }\n main { display:grid; grid-template-columns:repeat(auto-fill,minmax(190px,1fr)); gap:12px; padding:18px 20px 80px; }\n .card { border:2px solid var(--line); border-radius:10px; background:var(--panel);\n padding:10px; display:flex; flex-direction:column; gap:8px; }\n .card.import { border-color:var(--import); }\n .card.keep { border-color:var(--keep); }\n .card.discard { border-color:var(--discard); opacity:.5; }\n .thumb { height:120px; display:flex; align-items:center; justify-content:center;\n border-radius:6px;\n background-image:\n linear-gradient(45deg,#0000 25%,#7f7f7f22 25%,#7f7f7f22 75%,#0000 75%),\n linear-gradient(45deg,#0000 25%,#7f7f7f22 25%,#7f7f7f22 75%,#0000 75%);\n background-size:12px 12px; background-position:0 0,6px 6px; }\n .thumb img { image-rendering:pixelated; max-height:112px; max-width:100%; }\n .meta { font-size:11px; color:var(--dim); font-variant-numeric:tabular-nums; }\n .prompt { font-size:11.5px; color:var(--dim); max-height:3.2em; overflow:hidden; }\n .acts { display:flex; gap:5px; }\n .acts button { flex:1; padding:5px 0; font-size:11.5px; }\n .acts button.on-import { background:var(--import); border-color:var(--import); color:#08130d; }\n .acts button.on-keep { background:var(--keep); border-color:var(--keep); color:#04121f; }\n .acts button.on-discard { background:var(--discard); border-color:var(--discard); color:#fff; }\n footer { position:fixed; bottom:0; left:0; right:0; background:var(--panel);\n border-top:1px solid var(--line); padding:10px 20px; font-size:12px; color:var(--dim); }\n kbd { border:1px solid var(--line); border-bottom-width:2px; border-radius:4px;\n padding:1px 5px; font-size:11px; font-family:ui-monospace,Menlo,monospace; }\n</style>\n</head>\n<body>\n<header>\n <h1>pixelkiln salvage${\n styleId\n ? ` <span class=\"ctx\">— ${styleId}<span class=\"dest\"> → ${importDir}/_salvaged/</span></span>`\n : \"\"\n }</h1>\n <span class=\"tally\"><b id=\"ti\">0</b> import · <b id=\"tk\">0</b> keep · <b id=\"td\">0</b> discard ·\n <b id=\"tu\">0</b> undecided</span>\n <span style=\"flex:1\"></span>\n <button id=\"allDiscard\">Discard all undecided</button>\n <button id=\"allKeep\">Keep all undecided</button>\n <button id=\"submit\" class=\"primary\" disabled>Apply</button>\n</header>\n<main id=\"grid\"></main>\n<footer>\n <b>import</b> downloads it and adds it to your manifest · <b>keep</b> tags it and leaves it ·\n <b>discard</b> only tags it — nothing is deleted here.\n Hover a card and press <kbd>i</kbd> / <kbd>k</kbd> / <kbd>d</kbd>, or <kbd>u</kbd> to undo.\n</footer>\n<script>\nconst ITEMS = ${data};\nconst picks = new Map();\nconst grid = document.getElementById('grid');\nlet hovered = null;\n\nITEMS.forEach((o, i) => {\n const el = document.createElement('div');\n el.className = 'card';\n el.dataset.i = String(i);\n el.innerHTML =\n '<div class=\"thumb\"><img src=\"' + o.previewUrl + '\" loading=\"lazy\"></div>' +\n '<div class=\"meta\">' + o.width + '×' + o.height + ' · ' + o.createdAt.slice(0,10) + '</div>' +\n '<div class=\"prompt\">' + o.prompt + '</div>' +\n '<div class=\"acts\">' +\n '<button data-a=\"import\">import</button>' +\n '<button data-a=\"keep\">keep</button>' +\n '<button data-a=\"discard\">discard</button>' +\n '</div>';\n el.querySelectorAll('.acts button').forEach(b => {\n b.onclick = () => choose(i, b.dataset.a);\n });\n el.onmouseenter = () => { hovered = i; };\n grid.appendChild(el);\n});\n\nfunction choose(i, action) {\n if (picks.get(i) === action) picks.delete(i); else picks.set(i, action);\n const el = grid.children[i];\n el.className = 'card' + (picks.has(i) ? ' ' + picks.get(i) : '');\n el.querySelectorAll('.acts button').forEach(b => {\n b.className = picks.get(i) === b.dataset.a ? 'on-' + b.dataset.a : '';\n });\n refresh();\n}\n\nfunction refresh() {\n const c = { import: 0, keep: 0, discard: 0 };\n for (const a of picks.values()) c[a]++;\n ti.textContent = c.import; tk.textContent = c.keep; td.textContent = c.discard;\n tu.textContent = ITEMS.length - picks.size;\n document.getElementById('submit').disabled = picks.size === 0;\n}\n\ndocument.addEventListener('keydown', e => {\n if (hovered === null) return;\n const map = { i: 'import', k: 'keep', d: 'discard' };\n if (map[e.key]) { choose(hovered, map[e.key]); e.preventDefault(); }\n else if (e.key === 'u') { picks.delete(hovered); choose(hovered, '__none__'); }\n});\n\ndocument.getElementById('allKeep').onclick = () => {\n ITEMS.forEach((_, i) => { if (!picks.has(i)) choose(i, 'keep'); });\n};\ndocument.getElementById('allDiscard').onclick = () => {\n ITEMS.forEach((_, i) => { if (!picks.has(i)) choose(i, 'discard'); });\n};\n\ndocument.getElementById('submit').onclick = async () => {\n const btn = document.getElementById('submit');\n btn.disabled = true; btn.textContent = 'applying…';\n const decisions = [...picks.entries()].map(([i, action]) => ({ id: ITEMS[i].id, action }));\n try {\n const res = await fetch('/apply', {\n method: 'POST', headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ decisions }),\n });\n if (!res.ok) throw new Error(await res.text());\n btn.textContent = 'done — close this tab';\n document.body.style.opacity = '.6';\n } catch (err) {\n btn.textContent = 'failed: ' + err.message; btn.disabled = false;\n }\n};\nrefresh();\n</script>\n</body>\n</html>`\n}\n"],"mappings":"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","names":["import_zod","message","path","hex","path","os","res","import_node_crypto","import_promises","import_node_fs","import_node_path","import_node_crypto","path","path","import_promises","import_node_fs","import_node_path","path","import_node_path","path","import_node_path","import_node_crypto","import_promises","path","remove","cleanupErrors","import_node_fs","import_node_path","path","import_promises","import_node_fs","import_node_path","path","import_node_fs","import_promises","import_node_path","import_promises","import_node_fs","import_node_path","import_zod","path","pathModule","path","import_node_fs","import_node_path","path","sleep","message","sleep","import_node_fs","import_promises","import_node_path","PNG_SIGNATURE","path","message","import_node_fs","import_promises","import_node_path","message","path","import_node_fs","import_promises","import_node_path","chunk","message","import_promises","import_node_fs","import_node_path","path","import_promises","import_node_fs","import_promises","import_node_path","escapeHtml","PNG_SIGNATURE","path"]}
|