Files
DumiFlex 4005954615 feat(debug): give WP Debug a view of its own for the Loop, Model Info, Toggles and Injector (#360)
Variables grouped into per-node cards with kind squares, module facts, toggle true/false and value + .bool, Injector type chips, Loop frame line; long values fold until Show all; .axis/.bool/tags as kit chips. Trace stays numbered run order. Show node blinks the module or field on the canvas. Grouped right-click menus with a kind header. Loop trace rows, node warning labels and links.
2026-11-12 02:12:23 +01:00

470 lines
29 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
import { gzipSync } from "node:zlib";
import { readFileSync, readdirSync, statSync, writeFileSync, mkdirSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
const JS_DIR = fileURLToPath(new URL("../js", import.meta.url));
// `--json <path>` writes a machine-readable manifest alongside the human
// console report. Used by .github/workflows/bundle-size-pr.yml to compute
// the delta between base and head.
const args = process.argv.slice(2);
const jsonIdx = args.indexOf("--json");
const jsonPath = jsonIdx >= 0 ? args[jsonIdx + 1] : null;
// Budgets (gzipped bytes) — tune only with explicit review
// 2026-05-10: total bumped 250 → 256 KB to fit Phase B duplicate/fork
// system (per-kind save-to-library fork handlers + supporting helpers
// + flash/shake CSS). Cycle was explicitly scoped + approved.
// 2026-05-12: total bumped 256 → 300 KB to fit Batch 2 bundle drag/drop
// overhaul + headroom for follow-up batches without per-task contortion.
// Cycle was explicitly scoped + approved.
// 2026-05-20: total bumped 300 → 312 KB to fit RichTextInput atomic-chip
// editor reused inside the canvas combine TemplateSection (lazy chunk
// ~9 KB gzipped). The textarea-with-pills pattern was replaced with the
// SPA's chip editor so canvas + SPA share one $var/@ref editing surface.
// Explicitly approved feature request.
const ENTRY_LIMIT = 30 * 1024; // 30 KB
// 316 KB — bumped from 312 KB during the nested-bundle drag redesign.
// The container-scoped resolver (drop-zone.ts), pure applier (drop.ts),
// floating indicator SFC (BundleDropBar.vue), zoom-aware offsetTop
// walker, and moving-range filter for bundle drags added ~1 KB net.
// Bump approved alongside the feature land.
// 321 KB — bumped from 316 KB for the bundle edit modal
// (BundleInstanceModal + IdentitySection + RuntimeSection). Modal is
// lazy-loaded so the entry chunk is unaffected; total grows ~5 KB
// gzipped for the once-per-bundle edit surface (display name + frame
// color + master Lock/Hide cascades + Save/Reset-to-library footer).
// Mirrors the per-kind module modal shell users already know.
// 323 KB — bumped from 321 KB to fit the HSV color popover inside
// the bundle modal (shared HsvPicker.vue + hsv.ts moved to
// `src/components/shared/` so SPA's ColorPicker / TweaksPanel and
// the canvas bundle modal both drive one picker). Adds ~2 KB
// gzipped in the lazy modal chunk; entry stays untouched.
// 324 KB — bumped from 323 KB for the bundle-modal polish round:
// SPA link in footer, popover Teleport + viewport-aware positioning,
// always-on "clear color" affordance, stableStringify-based bundle
// fingerprint that folds meta + instance overrides into the MOD
// signal, and child-uid preservation on reset-to-library so the
// outer bundle's MOD evaluates against its existing snapshot rather
// than flipping to "modified" via spurious uid churn. ~0.5 KB net.
// 325 KB — bumped from 324 KB for the bundle detach + master toggle
// rework + true-duplicate-with-local-edits. Adds `setBundleInternal`
// / `setBundleLock` helpers that delegate to inner-bundle masters
// (skipping inner-owned rows + recursing into them) and the smart
// OFF cascade, plus the per-instance deep-clone duplicate that
// rewrites bundle_origin + parent_uid through a uid map. Net
// growth ~0.2 KB gzip.
// 327 KB — bumped from 325 KB for the rule matrix redesign. Replaces
// the 4-state click-cycle + cog-anchored CellFactorPopover with a
// click-driven CellRulePopover (4 labeled state buttons + numeric
// factor input) plus a new collapsible MatrixLegend. Net growth
// ~1.2 KB gzip across the lazy ContextWidget chunk; entry untouched.
// 328 KB — bumped from 327 KB for the rule matrix polish pass: popover
// now Teleports to body (escapes the cell's hover / clipping context),
// adds a reset-to-library button + native-styled stepper input (mirror
// of OptionRow's spinner), and the watcher narrows so factor typing
// no longer select-all-clobbers each keystroke. ~0.4 KB net gzip in
// the lazy ContextWidget chunk; entry stays put.
// 330 KB — bumped from 328 KB for the null-wildcard-option feature
// (2026-05-24). Adds `is_null` option flag + "+ Add null" button on
// the wildcard editor, pi-ban chip rendering across canvas OptionRow
// + ExceptionsSection + TestRunner + WildcardEditor, "Include null"
// checkbox on the nested-ref sub-cat picker, new is_empty /
// is_not_empty derivation operators + flipped "is empty" tick UI,
// and engine-side validation + nested-ref filter keyword support.
// ~0.7 KB net gzip across the lazy ContextWidget chunk; entry stays
// put. See docs/superpowers/specs/2026-05-24-null-wildcard-option-design.md.
// 340 KB — bumped from 330 KB during the polish-cleanup cycle.
// Absorbs the count-aware cross-node downstream scanner + per-instance
// wildcard uuid collection (graph.ts), library-fallback RichTextPreview
// wired into the preview-resolver cache (so constraint-modal exception
// chips + the test-runner constraint table resolve `@{uuid}` against
// the wildcard library, not just the local node), sync `consumedBy`
// claim that fixes the cross-node MOVE-becomes-COPY race in
// ContextWidget's onDrop, plus the constraint pairing badge work
// landing alongside on the same branch. Approved with the bundle of
// bug fixes — see the polish-cleanup PR description.
// 360 KB — bumped from 340 KB for the WP_PromptCleaner widget
// (2026-05-25). Adds the CleanerWidget spectrum-dial SFC, the
// BlocklistModal body-teleported editor, the cleaner mount glue
// chunk, and shared types/intensity helpers. ~9 KB net gzip across
// the lazy cleaner chunks; entry stays put. See
// docs/superpowers/specs/2026-05-25-prompt-cleaner-node-design.md.
// Bumped 360 -> 380 KB on 2026-05-26 to accommodate the WP_VarToInt /
// WP_VarToFloat / WP_VarToBool converter nodes. New chunks: var-picker
// SFC + TS parser mirror + widget glue. ~4 KB net gzip across the lazy
// chunks; entry stays put. See
// docs/superpowers/specs/2026-05-26-converter-nodes-design.md.
// Bumped 380 -> 385 KB on 2026-05-27 for the prompt-template-library
// round-trip modals. LoadTemplateModal gains the ModulePicker-style
// chrome (search + category/tags filter popover + scrollable rows) and
// SaveTemplateModal gains the push-to-library layout (category select +
// Update-existing / Save-as-new dual action). ~3 KB net gzip across the
// two lazy assembler modal chunks; entry stays put.
// NOTE: this gate measures the EXTENSION bundle (`js/`, from
// build:extension) only — NOT the manager SPA (`web_dist/`). The 2026-05-27
// Documentation tab lives entirely in src/manager → web_dist, so it does
// not affect this budget; no bump was needed for it.
// Bumped 385 -> 387 KB on 2026-05-28 for the injector two-tier row model.
// Adds the durable general-template row to the InjectorWidget lazy chunk:
// the inline binding+template editor + refs hint in InjectorRow.vue, the
// `kind` discriminator + addGeneralRow + general-aware reconcile in
// InjectorWidget.vue, and the general-row branch in the conflict scanner.
// ~1.5 KB net gzip in the lazy InjectorWidget chunk (baseline was already
// at 393968/394240 — only 272 B free — so the bump is required); entry
// stays put.
// Bumped 387 -> 388 KB on 2026-05-28 for the kind-aware RefChip. Engine
// warnings like `constraint_never_applied` wrap NON-wildcard ids (the
// constraint module's own id + the target wildcard id) as `@{uuid}` in
// the message text. Pre-fix, RefChip painted every `@{uuid}` as a
// wildcard chip — the constraint id fell through as a red `?` because
// the resolver only consulted the wildcard catalog. Adds the
// `moduleKind` prop + `--wp-refchip-tone` inline style + per-kind
// PrimeIcon switch in RefChip.vue, the `resolveModuleChip` library-
// wide search in resolveChip.ts, a `uuidToKind` prop on RichTextPreview
// wiring through the preview-resolver `kind` field, and a trace-derived
// `uuidToKindMap` in DebugViewer. ~0.3 KB net gzip across the lazy
// DebugViewer + _shared + preview-resolver chunks; entry stays put.
// Bumped 388 -> 393 KB on 2026-05-28 for the WP_SeedList DOM widget.
// Replaces the three stock widgets (strategy Combo + 2× Boolean
// override toggles) with a single socketless DOM widget owning the
// strategy chip group + both override toggles inside one SFC. Adds
// the SeedListWidget Vue chunk (~4.2 KB gzip) + the seed_list glue
// chunk (~0.7 KB gzip) for a ~4.9 KB total bump; entry stays put.
// Same cycle also prefixed every custom DOM widget input name with
// `wp_*` (modules → wp_modules, rows → wp_rows, viewer → wp_viewer,
// etc.) so the canvas socket labels read as branded WP widgets — no
// bundle impact from the rename alone.
// 2026-05-28: bumped 393 -> 395 KB for the SeedListWidget override
// lock UI (disabled-attr on strategy chips + `--locked` wrapper class +
// strategyLocked computed + two new lock-state Vitest cases). Plus the
// host glue (`setStockWidgetDisabled` + `syncStockWidgetGates` callers
// in onUpdate/onValueRestored/microtask). Net ~0.5 KB gzip; 2 KB
// headroom buffer to avoid the "17 bytes from budget" tightness from
// the previous bump.
// Bumped 395 -> 405 KB on 2026-06-07 for SP1 Chunk G (in-graph multi-tag
// pool editor). PoolSection gains grouped quick pills + an ƒ(x) Advanced
// boolean-expression editor; OptionRow gains per-tag CATEGORY chips; and
// the shared engine-parity subcat_filter parser (parse/matches/readsAs)
// is now imported into the wildcard graph editor chunk. ~4 KB net gzip
// across the lazy ContextWidget chunk; entry stays put. Approved with the
// SP1 multi-tag + boolean-filter feature (docs/superpowers/specs/
// 2026-06-06-wildcard-multi-subcategory-boolean-filter-design.md §4.2).
// Bumped 405 -> 430 KB on 2026-06-11 for SP3 constraint reach UI headroom.
// SP3 Task 13 lands the TS combineConstraintFactor mirror (+ shared corpus
// parity test) now; the upcoming reach/constraint-matrix UI phases need the
// total budget headroom in the lazy ContextWidget chunk. Approved alongside
// the SP3 constraint feature.
// Bumped 430 -> 431 KB on 2026-06-18 — two same-day landings share the
// ceiling (both CSS/glue; the manager-only bulk UI adds nothing to js/):
// - editor robustness: RichTextInput renderEpoch crash fix + useEditorDraft
// flush-on-unmount/unload + ErrorBoundary copy + clipboard-shield wired
// into _shared.ts / main.ts (Ctrl-A/C/V/X guard on editable inputs).
// - instance-modal scroll/sticky: sticky header + runtime/footer dock +
// own-scrollbar inner lists (options/values/rules/exceptions) + compact
// exceptions trash, across all 6 edit modals.
// Bumped 431 -> 432 KB on 2026-06-18 for the syntax + UI fix batch: inline
// `{N::a|b}` branch weights (engine + TS resolver mirror), the filter / pick /
// exclude-null MOD-dot fix, the "X of Y options" + "picks N-M" wildcard
// subtitle, the library-aware nested-ref check (kills the false BROKEN REF),
// and the constraint source-missing debug warning + label. ~0.4 KB net gzip
// across the ContextWidget + conflicts chunks; entry stays put.
// Bumped 432 -> 435 KB on 2026-06-22 for the canvas constraint-matrix grouping
// parity. MatrixSection (the ComfyUI instance-modal grid) gains the SPA's
// grouped-axis layout — column bands, row header chips, solo eyebrow, the
// labelled "uncategorized" bucket, and frozen headers + both-axis scroll —
// plus the shared components/shared/matrix-axis module the SPA matrix now
// imports too. ~1.1 KB net gzip in the lazy ContextWidget chunk; entry stays
// put. Approved with the matrix-parity feature request.
// Bumped 435 -> 442 KB on 2026-06-23 for per-iteration seeds modal
// (T8+T9). ContextLoopWidget gains the SeedListModal + SeedLockRow lazy
// body (v-if gated) — adds ~5.5 KB net gzip to the ContextLoopWidget
// lazy chunk. SeedListWidget gains a matching button in T9. Headroom
// covers both T8 and T9 landings without per-task bump friction.
// Bumped 442 -> 443 KB on 2026-06-23 for T9 (SeedListWidget seeds
// button). The SeedListWidget chunk grew ~0.7 KB gzip adding the button
// template + ref/computed script + seedbtn CSS; T8's headroom estimate
// was tight. Minimal bump to the actual measured ceiling.
// Bumped 443 -> 444 KB on 2026-06-23 for T12 (seed-list preview
// effective base/count/strategy from wired loop). Adds preview.ts pure
// resolver + graph-walk glue in seed_list.ts + previewStrategy prop in
// SeedListWidget.vue. ~0.4 KB net gzip in the seed_list widget chunk.
// Bumped 444 -> 445 KB on 2026-06-23 for T16 (seed modal paste-to-replace).
// Adds parseSeedLocks in seed-derive + pasteAll/Paste button in SeedListModal.
// Measured 454900 bytes (244 over the 444 ceiling); minimal bump.
// Bumped 445 -> 446 KB on 2026-06-24 for UI-C (wire ContextWidget frame edits).
// Adds imports of frame-cursor / frame-overrides / INSTANCE_FIELDS_PER_KIND into
// the ContextWidget lazy chunk + the merge-on-open / write-redirect logic.
// Measured 455772 bytes (92 over the 445 ceiling); minimal bump.
// Bumped 446 -> 447 KB on 2026-06-24 for RF2 (frame-aware row quick-lock).
// Adds toggleFrameLock helper in frame-overrides.ts + effectiveLockedSeed +
// frame branch in toggleLockOnCard + frame-aware isLocked. Net ~168 bytes
// gzip in the lazy ContextWidget chunk; entry stays put.
// Bumped 447 -> 448 KB on 2026-06-24 for the symmetric per-frame enable
// redesign (a `frame_enabled` override map replaces the `disabled_frames`
// blocklist so a base-off module can be turned ON for select frames). Adds
// frameEnabledAt / effectiveEnabled / frameEnableOverride / toggleFrameEnabled
// to frame-overrides.ts, the effective-enabled checkbox + bidirectional
// on-#k / off-#k badge in ModuleRow, and the .wp-mod-badge--on CSS. Measured
// 457868 bytes (140 over the 447 ceiling); minimal bump.
// Bumped 448 -> 449 KB on 2026-06-25 for the per-frame seed-lock correctness
// work: the Loop's derived-series capture (loop_seeds UI payload + onExecuted
// store + frameSeedReader preference, so the lock pins the PREVIOUS run's
// per-frame seed under control_after_generate=randomize) plus the modal
// Lock-button resolver (lock-seed-ctx provide/inject into SeedLockControls).
// Landed exactly at the 448 ceiling (458752/458752); bump for headroom.
// Bumped 449 -> 450 KB on 2026-06-28 for the row context-menu Hold toggle.
// Adds HOLD_KINDS + isHoldable + toggleHold to ContextWidget plus the quick
// "Hold across run" / "Release hold" menu item (2-click seed_scope toggle,
// base-only with a frame-active disabled hint) in the lazy ContextWidget
// chunk; entry stays put. Measured 459909 bytes (133 over the 449 ceiling);
// minimal bump.
// Bumped 450 -> 453 KB on 2026-07-21 for loop bypass frames (#13): the
// `bypass_frames` config field + the SeedLockRow bypass toggle, the
// SeedListModal opt-in bypass column, and the ContextLoopWidget "N bypassed"
// badge. Config field alone landed 34 bytes over 450; the ~3 KB headroom
// covers the UI additions in the same feature.
// Bumped 453 -> 461 KB on 2026-07-23 for the chip-UX + library-linkage feature
// set (issues #1-#9). Workstream B (RefChip hover card: uuid + filter reads-as
// + live "N of M options match" from the extended preview-resolver) landed the
// canvas within 10 bytes of the 453 ceiling; the +8 KB gives the remaining
// workstreams D (library re-link UI) and E (nested-ref propagation) room in the
// same approved feature set. Explicitly approved.
// Bumped 461 -> 468 KB on 2026-07-30 for the QoL sweep (P0+P1). The bulk is UI
// that had to grow: export/import row detail per entity kind, the category
// IconPicker, the feedback modal, cross-bucket search, collapsible tag pools,
// and finally `collectUpstreamProducers` + the var-chip producer card, which
// tipped it 180 bytes over. Explicitly approved by the maintainer, who asked
// for the budget to be raised as needed rather than features trimmed to fit.
// Bumped 468 -> 490 KB on 2026-08-02 for the `@`/`$` autocomplete + sub-category
// filter redesign. The popover rows carry structure now (icon, uuid, option /
// axis / tag facts, and for `$` the producer line and override badge) instead
// of one line of text, and the shared filter panel that follows adds the
// axis-grouped palette with collapse + search, the live match count and the
// zero-match / unknown-term states. Sized with headroom deliberately: the
// previous bump left 179 bytes free, which meant every subsequent change had
// to argue with the gate. Explicitly approved by the maintainer, who asked for
// the budget to be raised as needed rather than features trimmed to fit.
// LOWERED 490 -> 420 KB on 2026-08-06, after the webfonts stopped being bundled.
// Vite library mode ignores `assetsInlineLimit` and base64-inlined both woff2
// files into a JS chunk; they are now copied to js/assets/fonts/ and <link>ed at
// runtime (see src/extension/fonts.ts). Measured 492,407 -> 403,055 bytes.
//
// Tightened rather than banked, because the gate is what stops it silently
// regressing: re-inlining the fonts would add ~90 KB, which fits under 490 KB
// and would have passed unnoticed. It does not fit under 420 KB. The 17 KB of
// headroom left is deliberate — enough for ordinary work, not enough to hide a
// whole asset class coming back.
// RAISED 420 -> 424 KB on 2026-10-02 for the wildcard fallback option (canvas
// badge + Debug note): dev sat at 429,971 bytes, 109 under the gate, and the
// feature needed ~200. Approved by the maintainer ("you are allowed to
// increase the bundle budget if necessary"). 4 KB leaves room for a few more
// small features while a re-inlined font (~90 KB) still trips the gate.
// RAISED 424 -> 428 KB on 2026-10-05 for Context Loop sweep mode (Sweep
// panel in the loop widget chunk, downstream-wildcard walk in boot): dev sat
// at 430,134 bytes and the feature adds ~4.8 KB. The maintainer treats this
// budget as a guide to raise when a needed feature does not fit.
// RAISED 428 -> 436 KB on 2026-10-06 for model-aware pipelines (WP Model Info
// walker branches + variant rules + its widget glue in boot, the Model Info
// widget chunk with pins, Assembler toggles and the shared row-primitive
// buttons, Match variable control in the wildcard modal chunk, LoRA by model
// preset): the feature adds ~6 KB and tipped dev ~3.2 KB over. Same "guide,
// not a cap" rule as above.
// RAISED 436 -> 440 KB on 2026-10-06 for the constraint "rules out all"
// warning (the constraint factor math and wildcard pool helpers now reach the
// ContextWidget chunk): dev sat at 446,313 of 446,464 bytes and the check adds
// ~2.2 KB. Same "guide, not a cap" rule as above.
// RAISED 440 -> 452 KB on 2026-10-07 for WP Image Filter (pick-and-pass
// node): its picker modal (~7.6 KB) and node widget (~3.4 KB) are lazy
// chunks, plus ~1.5 KB of event + widget glue in boot. dev sat at 448,610
// bytes. Same "guide, not a cap" rule as above.
// RAISED 452 -> 464 KB on 2026-10-07 for the Image Filter refine step
// (frame labels, sweep grid, compare, prompt edits, mask painter, Send to
// Loop): the picker chunk grows ~8 KB and stays lazy. The branch sat at
// 462,555 bytes before it. Same "guide, not a cap" rule as above.
// RAISED 464 -> 468 KB on 2026-10-07 for the zoom's Details panel and the
// frame-click zoom (lazy picker chunk); the branch sat at 476,239 bytes.
// RAISED 468 -> 472 KB on 2026-10-14 for the Split loading mark in the canvas
// modals (Load template, Push to library); Dumi asked for it everywhere.
// RAISED 472 -> 476 KB on 2026-10-14 for negatives on node fixed values and
// combines (NegativeField in their lazy editor chunks) and the chat round;
// the branch sat at 483,532 bytes.
// RAISED 476 -> 480 KB on 2026-10-14 when the AI knowledge round (canvas-facts
// answer, ~0.6 KB in boot) landed on top of it.
// Same "guide, not a cap" rule as above.
// dev's canvas widget lifecycle fix (2026-10-16, ~0.65 KB in boot) fits in
// the same 480 KB.
// RAISED 480 -> 496 KB on 2026-10-17 for client-side shape checks on install
// (review finding H1): the canvas can install community dependencies, so the
// Zod validators ship as their own lazy chunk (shape-check-*.mjs, ~17 KB
// gzip) that loads only when something is installed. dev sat at 485,671
// bytes; the branch at 502,904.
// RAISED 496 -> 512 KB on 2026-10-27 for the shared component kit (Dumi
// approved one component per control for canvas + manager): ContextMenu now
// places itself through kit/floating.ts (branch 508,348 bytes,
// 444 over), and the canvas twins (Button, Switch, Tabs, Popover, Tooltip)
// land next in widget chunks, never in boot.
// RAISED 512 -> 536 KB on 2026-10-29 for WP Toggles (#200) landing on top of
// WP Note (#199): the toggles widget, its row outputs and the merge command
// are lazy widget chunks (boot unchanged); the merge sat at 545,077 bytes.
// RAISED 536 -> 552 KB on 2026-10-29 for WP Toggles' mute / bypass control
// and WP Node Group (a new frontend-only node + panel), the clean/edit views
// and the richer Pick one: lazy widget chunks plus a few KB of boot glue
// (registration, the prompt strip); the branch sat at 552,937 bytes.
// RAISED 552 -> 576 KB on 2026-10-29 for the WP Note editor: a formatting
// bar, links to any docs page and section (the page/section catalog, ~5 KB
// gzip) and icons from the full PrimeIcons list. All of it is in the note's
// lazy chunks (NoteWidget, NotePeek, note-markdown), loaded only when a
// note is on the canvas; boot unchanged. dev sat at ~556,000 bytes after #201, the merge at 575,436.
// RAISED 576 -> 584 KB on 2026-10-29 for WP Bookmark (a frontend-only node
// that jumps the canvas to a saved spot): its widget and the Bookmarks dock
// are lazy chunks (~11 KB, plus the kit pieces they share), with ~5 KB of
// boot glue for the node, the jump, the hidden filter and the one shortcut
// listener, plus a WP Note that can be a bookmark (the shared jump fields);
// the branch sat at 595,973 bytes after merging the WP Note editor.
// RAISED 584 -> 586 KB on 2026-10-29 for the bookmark polish: frameless WP
// Bookmark (shared with WP Note in _frameless.ts), the free-area measuring
// for jumps and the dock, the draggable dock and Use this view; boot +1 KB,
// the rest in the lazy bookmark chunks; the branch sat at 598,327 bytes.
// RAISED 586 -> 590 KB on 2026-11-02 for bookmarks on the free canvas (the
// side / bottom panel pane, minimap and zoom controls, the dock's snap
// spots), the page key probe for shortcuts, and the note's tables, task
// boxes and callouts (~1.2 KB gzip, in the bookmark and note chunks).
// RAISED 590 -> 596 KB on 2026-11-02 for kit 0.5.0 (one field box, one
// Chip, CodeBlock syntax colours, Skeleton shapes; ~2.5 KB gzip on its own,
// dev at 606,638 bytes) and the loading shapes that replace empty states and
// spinners in the list pages, editors, pickers and settings (~1.2 KB, mostly
// in lazy manager chunks); the branch sat at 607,885 bytes.
// RAISED 596 -> 600 KB on 2026-11-02 for kit 0.6.0: one Button, Modal,
// Checkbox, switch and colour field for both sides. Button now carries its
// stylesheet scoped plus the tooltip, ConfirmModal runs on Modal + ModalShell
// with the focus trap, and Checkbox/Popover grew to cover what WpCheck and the
// canvas popovers did; WpButton, CloseButton, ConfirmDialog and WpCheck went
// (net ~4.1 KB gzip: dev 607,885 -> 611,998 bytes).
// RAISED 600 -> 603 KB on 2026-11-03 for the kit buttons batch A: the
// sub-category filter picker (shared with the canvas Pool section) now draws
// its tags, operators and axis rows with Chip and ListRow and its actions
// with Button, which pulls those pieces and the tooltip into its chunk
// (dev 613,654 -> 616,336 bytes).
// RAISED 603 -> 607 KB on 2026-11-03 for the canvas kit buttons (batches A
// and B): the note editor's toolbar is the kit Toolbar with Buttons, the note
// and bundle colours RadioGroup swatches (+ ColorField), the Var Picker the kit
// Combobox with its Popover, the pickers' rows ListRows, and the debug viewer /
// image filter use Button and WpIconButton, which pull those pieces into the
// canvas chunks (dev ~616,500 -> 619,558 bytes).
// RAISED 607 -> 608 KB on 2026-11-03 for the end of the kit migration: every
// text field (manager and canvas) is the kit Input / Textarea / SearchInput and
// the last canvas toggles are Chips (kit 0.10.0), which pull those pieces into
// more chunks (619,558 -> 622,398 bytes).
// RAISED 608 -> 610 KB on 2026-11-03 for kit 0.11.0: Input and Textarea carry
// their own scoped styles (so canvas fields look right without local copies)
// and the editors' menus moved onto Popover / DropdownMenu / Modal
// (621,933 -> 623,679 bytes). Batch B drops the canvas fields' local copies.
// RAISED 610 -> 614 KB on 2026-11-03 for the selection-toolbar "?" and pencil
// (#225: the help dialog chunk and the toolbar commands in the boot chunk),
// the labels-toggle fix (#249) and kit 0.14's bigger canvas controls
// (623,679 -> 626,405 bytes).
// RAISED 614 -> 630 KB on 2026-11-03 for the WP Note add-to-library button
// (#252): pressing it runs the Import tab's install pipeline (shape check
// with Zod, migrations, commit, reattach) from the canvas, so those land in
// the extension build as lazy chunks that load on the press only
// (626,405 -> 636,864 bytes).
// RAISED 630 -> 640 KB on 2026-11-04 for pictures in WP Note: the
// Pictures panel, the canvas re-encode (note-images.ts) and the picture
// syntax ride in the note's lazy editor chunk (dev was already ~636.9 KB).
// RAISED 640 -> 650 KB on 2026-11-10: kit 0.14 -> 0.15.3 (colour picker
// fixes, PostCard samples, overlay-scrollbar room) put the total at ~640.9 KB.
// RAISED 650 -> 655 KB on 2026-11-11: WP Debug's newer-node support (node
// cards in Variables, Show node blink, toggle values/.bool) put it at ~650.04 KB.
// RAISED 655 -> 665 KB on 2026-11-12: every docs screenshot can go in a WP
// Note (note-assets.json + the kit's ImageGrid/SearchInput in the note's lazy
// editor chunk) put the total at ~652.9 KB.
// RAISED 660 -> 670 KB on 2026-11-12: with both of those, WP Toggles' toggle
// window (Value box, icon picker and colour fields in a lazy chunk) and the
// toggle looks put the total at ~660.0 KB, 9 bytes under the old line.
const TOTAL_LIMIT = 670 * 1024; // 670 KB
// The total budget is a guide, not a cap (Dumi, 2026-10-06), so the gate has
// two bands: over TOTAL_LIMIT it warns (CI stays green and shows a
// `::warning` annotation), and only past TOTAL_LIMIT + 5% does it fail. A
// warning means "raise the budget in this PR with a line above saying why";
// a failure means something grew by far more than one feature should.
const TOTAL_FAIL_LIMIT = Math.round(TOTAL_LIMIT * 1.05);
function gzipSize(path) {
return gzipSync(readFileSync(path)).length;
}
function allJsFiles(dir) {
const out = [];
for (const name of readdirSync(dir)) {
const full = join(dir, name);
if (statSync(full).isDirectory()) {
out.push(...allJsFiles(full));
} else if (name.endsWith(".js") || name.endsWith(".mjs")) {
out.push(full);
}
}
return out;
}
let failed = false;
const files = allJsFiles(JS_DIR);
let total = 0;
const manifest = { entry: null, total: 0, files: {} };
console.log(`\nBundle size report (gzipped):\n`);
for (const file of files) {
const size = gzipSize(file);
total += size;
const rel = file.substring(JS_DIR.length + 1);
// Strip the rolled-up content hash so PR ↔ base file names match. Vite
// emits `assets/<name>-<hash>.js` per chunk; the hash changes with any
// content edit and would otherwise show every chunk as added/removed.
// Normalize Windows backslashes so the manifest diffs cleanly against
// CI runs (which always emit forward slashes on Linux).
// Lazy chunks are `.mjs` (see vite.config.mts); report them under `.js` so
// manifests from before that switch still diff chunk-for-chunk.
const stable = rel.replace(/-[A-Za-z0-9_-]{8,}\.m?js$/, ".js").replaceAll("\\", "/");
manifest.files[stable] = size;
console.log(` ${rel.padEnd(40)} ${(size / 1024).toFixed(2).padStart(7)} KB`);
}
manifest.total = total;
manifest.budget = TOTAL_LIMIT;
manifest.failAt = TOTAL_FAIL_LIMIT;
console.log(` ${"TOTAL".padEnd(40)} ${(total / 1024).toFixed(2).padStart(7)} KB`);
const entry = files.find((f) => f.endsWith("main.js"));
if (entry) {
const entrySize = gzipSize(entry);
manifest.entry = entrySize;
if (entrySize > ENTRY_LIMIT) {
console.error(`\n✗ Entry main.js gzip ${entrySize} bytes exceeds budget ${ENTRY_LIMIT}`);
failed = true;
} else {
console.log(`\n✓ Entry within budget (${entrySize} / ${ENTRY_LIMIT} bytes gzipped)`);
}
}
if (total > TOTAL_FAIL_LIMIT) {
console.error(
`✗ Total js/ gzip ${total} bytes exceeds budget ${TOTAL_LIMIT} by more than 5% (fails above ${TOTAL_FAIL_LIMIT})`,
);
failed = true;
} else if (total > TOTAL_LIMIT) {
const msg = `Total js/ gzip ${total} bytes is over the ${TOTAL_LIMIT}-byte budget (fails above ${TOTAL_FAIL_LIMIT}); raise TOTAL_LIMIT in scripts/check-bundle-size.mjs with a note saying why`;
console.warn(`⚠ ${msg}`);
if (process.env.GITHUB_ACTIONS) console.log(`::warning title=Bundle size::${msg}`);
} else {
console.log(`✓ Total within budget (${total} / ${TOTAL_LIMIT} bytes gzipped)`);
}
if (jsonPath) {
mkdirSync(dirname(jsonPath), { recursive: true });
writeFileSync(jsonPath, JSON.stringify(manifest, null, 2));
console.log(`\nWrote size manifest to ${jsonPath}`);
}
process.exit(failed ? 1 : 0);