Commit Graph
36 Commits
Author SHA1 Message Date
DumiFlex 2eb0e365b7 feat(ts): combineConstraintFactor mirror + shared corpus parity
Add the TypeScript mirror of engine/modules/_constraint_math.py with
identical semantics, validated against the SAME shared corpus
(tests/fixtures/constraint-corpus.json) so Py === TS parity holds. Vitest
covers 2 unit cases (multi-tag multiply, exclude-absorbing) plus the 4
corpus cases (multi-tag->1, multi-pick->6, exclude->EXCLUDE, exception->0.25).

Also bump bundle TOTAL_LIMIT 405 -> 430 KB for the upcoming SP3 constraint
reach UI; entry/per-file limits unchanged.
2026-06-11 06:49:59 +03:00
DumiFlex 8000e1b75c fix(ui): render embed/canvas checkboxes via a scoped WpCheck component
The inline `<span class="wp-check">` controls relied on the global `.wp-check`
rule from manager/styles/tokens.css, which is loaded in the SPA but NOT on the
ComfyUI canvas (settings.ts pulls a hand-picked CSS set; tokens.css is not in
it). So in canvas-mounted instance modals the converted checkboxes rendered as
unstyled, zero-size spans — invisible. (`.opt__check` survived because it is
component-scoped CSS, which ships into every bundle the component renders in.)

Fix: extract the wildcard-option box into `WpCheck.vue` — a shared component
whose `<style scoped>` mirrors `.opt__check` verbatim. Scoped CSS is compiled
into the component chunk, so it travels into the SPA *and* the canvas bundle
with no dependency on any global stylesheet. Route PoolSection, DisabledRules-
Section, SubcategoryFilterPicker, Push/PushBundleToLibraryModal, and
DisplayPlaygroundModal through it.

The SPA keeps its global `.wp-check` (ui/Checkbox.vue consumers) untouched.
Reverts the 405 -> 407 KB budget bump: one shared component is leaner than the
13 inline copies, so the total lands back under 405 KB.
2026-06-10 01:59:33 +03:00
DumiFlex c6baeb8136 refactor(ui): convert remaining native checkboxes to the shared wp-check look
Sweep the leftover browser-native `<input type="checkbox">` controls onto the
inline `wp-check` span so every checkmark box reads as the wildcard-option
style. Bumps the bundle budget 405 -> 407 KB for the added markup (~0.8 KB
gzip); the embed entry stays slim.

Converted (true checkboxes):
- DisabledRulesSection: per-rule disable toggles (onToggle now takes a bool).
- SubcategoryFilterPicker: exclude-null (manager twin of the pool toggle).
- PushToLibraryModal: "propagate to bundles".
- PushBundleToLibraryModal: cascade "restore missing refs".
- DisplayPlaygroundModal: 7 display-pref switches (drop the dead wp-pg__check
  rule; rows become <div> so no orphaned <label> remains).

Intentionally left as-is — these are toggle SWITCHES / custom toggle buttons,
not checkmark boxes: the row-enable sliders (ModuleRow, InjectorRow,
MockModuleCard, BundleHeader), the internal-flag toggle, and seed-lock.

Tests updated to the aria-checked / click contract.
2026-06-10 01:34:05 +03:00
DumiFlex 33e6bd0d34 feat(ui): nested-ref filter popover + chip + in-graph pool editor
Chunk F (src/manager/components): SubcategoryFilterPicker reworked into a text-first boolean-expression editor (insert-at-cursor chips/operators, live reads-as + 'N of M match' count + validateExpression, exclude-null toggle; emits {expr, excludeNull}). RefChip shows a compact funnel indicator + hover tooltip instead of an inline subcat suffix. RichTextInput serializes ref atoms to @{uuid#name:expr!null}.

Chunk G (src/components/context/editors/wildcard): probability.ts isEnabled matches the boolean category_filter expression (parse+matches) + exclude_null. OptionRow renders per-tag CATEGORY chips colored by tag_groups axis. PoolSection: grouped quick pills (or within a group, and across) + an advanced boolean editor + exclude-null toggle.

Foundation/cascade: _shared.ts Instance.category_filter string[]->string + exclude_null; prune.ts drops stale tokens from the expression via subcatExprCascade; ContextWidget tooltip renders the expression string. Bundle-size budget 395->405 KB for the graph editor + shared parser (documented). Full vue-tsc + vitest green.
2026-06-07 03:41:01 +03:00
DumiFlex 51f6793177 test(validators): engine-parity harness to stop validator drift
The community TS validators re-implement the engine's payload shapes by
hand, and drifted repeatedly (fixed_values entries-vs-values, wildcard
is_null omitted) -- each drift surfaced as a publish failure for a user.
This makes the engine the single source of truth.

- scripts/dump_engine_shapes.py: builds one sample payload per module
  subtype, validates each against that subtype's own engine
  Handler.validate_payload (raises if not engine-valid), and writes the
  engine-row shape to src/validators/fixtures/engine-parity/*.json. Run
  it whenever an engine module shape changes; commit the regenerated
  fixtures.
- src/validators/__tests__/engine-parity.test.ts: asserts the STRICT
  community validator accepts every engine-dumped fixture. 5/5 pass.

Now drift fails CI on either side: a sample that no longer matches its
handler fails the generator; a validator that rejects the real shape
fails the parity test. CLAUDE.md schema section documents the loop.
2026-06-06 10:44:01 +03:00
DumiFlex 730721fa1a feat(registry): comfyignore + 21:9 banner + includes + collapsed changelog header
Five tightly-related changes to the registry-publishing path.

.comfyignore
  Drops dev-only + repo-plumbing files from the registry archive
  even though they stay in git: src/ (frontend source), tests/,
  .github/, .husky/, public/images/docs/ (doc screenshots used at
  SPA build time, baked into web/ anyway), vite + eslint + commitlint
  + semantic-release configs, scripts/, repo metadata (CHANGELOG,
  CONTRIBUTING, CODEOWNERS, CODE_OF_CONDUCT, SECURITY). Syntax is
  gitignore-style globs per the Registry spec.

[tool.comfy] in pyproject.toml
  - Banner: 21:9 svg at public/images/comfy-banner.svg served via
    raw.githubusercontent so the listing card on registry.comfy.org
    renders the project banner instead of an empty placeholder.
  - requires-comfyui = ">=0.3.36" — floor that introduces the V3
    io.* schema (io.Schema, io.ComfyNode, @comfytype, ComfyTypeIO)
    the entire wp_nodes/ tree uses. Older runtimes would fail at
    import; the Manager warns instead.
  - includes = ["js", "web"] — both build-output trees are
    gitignored, so without this the registry archive would ship
    without the canvas widgets (js/) or the manager SPA (web/).

public/images/comfy-banner.svg
  Standalone 1400×600 svg (≈2.33:1, matches 21:9). Left half: title +
  underline accent + tagline + module-kind badges (Wildcard / Fixed /
  Combine / Derivation / Constraint, kind-colored). Right half: WP
  Context → emits → resolved $vars → fills → Prompt Assembler flow.
  Faint canvas-grid background so it reads as "this lives in
  ComfyUI" at a glance.

scripts/pack-release.mjs
  Fixes the manager outDir literal: ships web/ (the actual vite
  outDir per vite.config.mts), not the stale web_dist/ name in the
  CLAUDE.md comment. Without this the github-release zip would
  ship without the SPA.

.releaserc.js — collapsed-changelog header / footer partials
  release-notes-generator's writerOpts now wraps the per-commit
  list in a <details> element with a fixed "Wildcard Pipeline
  <version>" + doc/discord/install/issues links header. GitHub
  renders <details> natively in release markdown — readers see the
  TL;DR + 5 useful links above the fold (well under GitHub's
  "Read more" character cutoff) and click to expand the full
  feat/fix/perf log. The header text is also the part most likely
  to stay useful weeks after the release.
2026-05-28 14:09:39 +03:00
DumiFlex 9b91012195 feat(github): publish workflow + issue/PR templates + release-zip + cleaner notes
Drops six pieces of repo plumbing in one go.

publish workflow (.github/workflows/publish.yml)
  Fires on every published GitHub release + manual dispatch. Builds
  the extension + manager SPA, then invokes Comfy-Org/publish-node-action
  with REGISTRY_ACCESS_TOKEN so the ComfyUI Manager listing stays in
  lockstep with semantic-release tags. Without this the README's
  "search Wildcard Pipeline in the ComfyUI Manager" path would never
  see new versions.

issue + PR forms (.github/ISSUE_TEMPLATE/, PULL_REQUEST_TEMPLATE.md)
  - config.yml: blank issues off, three contact links (Discord first,
    Discussions, Wiki).
  - bug_report.yml: structured form with version chip, multi-select
    surface dropdown covering all 10 nodes + 5 SPA areas + engine +
    build, ComfyUI version, OS, Python version, repro, expected vs
    actual, traceback (shell render), workflow JSON (json render),
    WP Debug warnings paste-box.
  - feature_request.yml: problem + proposal + alternatives + scope +
    importance dropdown; nudges toward "describe the underlying
    problem, not just the solution".
  - PULL_REQUEST_TEMPLATE.md: summary, conventional-commit type
    checkboxes mapped to release impact, related-issues line,
    local-verification gate checklist, screenshots prompt for
    visible changes, risk callout box.

release-zip + cleaner notes (.releaserc.js + scripts/pack-release.mjs)
  - Switched commit-analyzer + release-notes-generator to the
    conventionalcommits preset (already a transitive dep, no install).
  - Marked chore/docs/style/test/build/ci as hidden:true so they
    don't render in the GitHub release body. Only feat/fix/perf/
    refactor/revert show. Past releases (v1.8.0) keep their long
    notes; v1.9.0+ ships clean.
  - New scripts/pack-release.mjs zips the deployable file set
    (engine/, wp_nodes/, wp_api/, js/, web_dist/, public/, docs/help/,
    __init__.py, pyproject.toml, README.md, LICENSE) into
    dist/ComfyUI-Wildcard-Pipeline-v<version>.zip.
  - @semantic-release/exec prepareCmd runs the version-stamping
    AND the pack-release.mjs invocation so the zip carries the
    right version in its name.
  - @semantic-release/github assets config attaches the zip to the
    GitHub release page so manual installers can grab a single
    artifact instead of cloning at a specific tag.

Notes on what's NOT changed:
  - ci.yml + release.yml stay as-is — local versions are a strict
    superset of origin's (coverage gate, perf gate, fuzz job,
    bundle-size budget). Release workflow already had the env +
    permissions needed for semantic-release.
  - bundle-size-pr.yml stays (local-only, useful).
2026-05-28 13:42:51 +03:00
DumiFlex ccbf38af99 feat(nodes): add wp_seedlist + split loop config types + wp_ prefix sweep + tooltips
Three coordinated changes to the WP_* node family.

1. New WP_SeedList node
   Emits a list of N derived seeds for a downstream loop (is_output_list).
   Three independent override toggles (override_seed / override_count /
   override_strategy) each mirror the wired Loop's base_seed / count /
   strategy. Connecting loop_config auto-flips override_count +
   override_strategy ON so the natural intent of wiring in a loop gets
   the defaults right; override_seed stays explicit opt-in.
   All emitted seeds are masked to 50 bits via the new MAX_SAFE_SEED
   constant in engine.seed_derive so values sit inside ComfyUI's
   frontend randomize range and copy-paste reproduces identically in a
   standalone sampler.

2. Context Loop type split + downstream Context seed widget lock
   Split WP_CONTEXT_LOOP_CONFIG (wire payload) from a new
   WP_CONTEXT_LOOP_WIDGET (DOM-widget-only TYPE). Loop's own widget
   mounts on the widget type; the wire type has no factory so consumers
   like WP_SeedList render their loop_config socket as a plain input
   instead of being hidden by a fallback-undefined widget.
   New graph walker hasUpstreamLoopOverridingSeed: WP_Context's widget
   glue greys out the local seed stock widget when an upstream Loop has
   override_seed ON, so users read "this value is dead while the Loop
   drives it" without inspecting the Loop config separately.

3. wp_ prefix sweep + tooltips across every WP_* node input
   Custom DOM widget input names now carry the wp_ prefix so canvas
   socket labels read as branded WP widgets: modules -> wp_modules,
   rows -> wp_rows, viewer -> wp_viewer, cleaner -> wp_cleaner,
   context_loop_config -> wp_context_loop_config. Every stock input
   across the node family gets a tooltip describing what it does and
   when to wire it from another node. Tests + comfy_api stub updated.
   CLAUDE.md notes the wp_ convention for future custom widgets.

Bundle size budget bumped 388 -> 395 KB to fit the SeedList Vue chunk
(~4.9 KB net gzip) + override lock UI; entry stays at ~4 KB gzipped.
2026-05-28 12:40:44 +03:00
DumiFlex 2d72fe4345 feat(injector): two-tier socket + general-template row model
Socket rows now scope their optional template to their OWN slot only
(top-to-bottom resolution; other $input_M stay literal). Adds a durable
general-template row (kind: "general") that survives socket churn, is
resolved after all socket rows, and composes from both raw sockets
($input_N) and socket-row bindings ($test). Engine processes socket rows
first then general rows in order; general rows honor binding validation +
the internal flag. Frontend: kind discriminator, "Add template row"
affordance, general-aware reconcile that keeps general rows, inline
binding+template editor with a refs hint, conflict-scanner + docs updates.
2026-05-28 03:39:45 +03:00
DumiFlex 3e404fbd98 revert(size): restore 385 KB budget — docs is in web_dist, not js/
The bundle-size gate measures only the extension bundle (js/). The
Documentation tab lives in the manager SPA (web_dist/), so it does not
affect this budget; the earlier 395 KB bump was unnecessary and is
reverted to keep the extension gate meaningful.
2026-05-27 06:21:36 +03:00
DumiFlex f36ac51d5b chore(size): bump total bundle budget 385 -> 395 KB for docs tab
The in-SPA Documentation tab adds a lazy Docs chunk (registry + doc
primitives + ~26 authored content pages). Hand-authored Vue, no markdown
dep; entry main.js untouched.
2026-05-27 06:07:34 +03:00
DumiFlex df95e81ec6 feat(assembler): round-trip template identity + richer Save/Load modals
Load now persists the picked template's {id,name} on node.properties
(workflow-serialized, survives reload), so Save can offer to update the
exact row the user loaded — the template-side analogue of the bundle
push-to-library identity. Clearing the template drops the ref.

Rebuilds both modals on ModalShell with the library look adapted from
ModulePickerModal / PushToLibraryModal:
- LoadTemplateModal: search + category/tags/favorites filter popover +
  scrollable rows, single-click pick (no kind tabs / multi-select).
- SaveTemplateModal: name/description/category/tags + live preview, with
  a dual footer — "Update existing" (the loaded or same-name row) and
  "Save as new entry" (create, auto-suffixed). Saving rebinds the load
  identity so the next Save defaults to updating that entry.

Bumps the total bundle budget 380 -> 385 KB for the two heavier lazy
modal chunks (~3 KB net gzip; entry untouched).
2026-05-27 02:22:41 +03:00
DumiFlex 34f71d2ecf feat(main): register wp_var_picker widget + raise size budget to 380kb 2026-05-26 15:19:29 +03:00
DumiFlex 9fd9db04a1 feat(cleaner): node, widget, api, migration, mount glue + bundle bump 340->360 2026-05-25 02:28:04 +03:00
DumiFlex 4a69c5e212 fix: cross-node constraint drag + scanner slot allocator + library fallback + save hydrate
- Cross-node drag MOVE-becomes-COPY race: ContextWidget.onDrop sync-claims
  consumedBy before any await so the source widget's dragend reads the
  set value. dragend filters by _uid (idempotent) instead of stale
  srcIdx — fixes the secondary issue where the backup pendingHandoffs
  queue + dragend double-removed an adjacent target wildcard.
- pendingHandoffs queue in drag-store: belt-and-suspenders source-side
  cleanup that runs even when dragend skips (constraint rows inside the
  bundle frame were the trigger).
- Conflict scanner constraint_orphan_target slot allocator: per-target
  sorted local positions + remaining downstream count. Each constraint
  claims smallest local slot > own index, else a downstream slot. Fixes
  duplicated constraints with target downstream cross-node + correctly
  flags when only one local target sits BEFORE the constraint.
- collectDownstreamWildcardUuids: per-instance occurrences (not Set-
  deduped) so duplicated downstream targets each count as a separate
  claimable slot.
- RichTextPreview + ConstraintInstanceModal: cross-Context refs fall
  back to preview-resolver cache (sub_categories, option values,
  options_by_id, hasNullOption) so the canvas modal renders the actual
  wildcard name, sub-cat list, and chip suffix instead of "source"/
  "target" placeholders + stale matrix keys.
- Preview-resolver schema extended with subCategories / optionValues /
  optionsById / hasNullOption populated from embed-bundle response.
- Constraint save hydrate: wp_api modules + bundles endpoints fill
  exception source_value / target_value from source_id / target_id by
  looking up the wildcard's option list before validation. Heals
  library rows that stored only ids.
- TestRunner constraint table uses RichTextPreview for column headers
  + row values so nested @{uuid} refs render as chips.
- Inverted null filter UI: SubcategoryFilterPicker "Exclude null"
  checkbox + RefChip "!null" suffix render.
- Bundle size budget bumped 330 KB to 340 KB.
- Drop stale CHECKPOINT-*.md docs.
2026-05-25 00:17:20 +03:00
DumiFlex 2449c0f407 fix(bundles): exclude entire dragged-range from drop candidates
User reported: dragging a bundle doesn't show an indicator and won't drop below its current position. Root cause: the resolver's "skip the dragged bundle" filter was too narrow — it excluded the dragged bundle's frame and rows whose bundle_origin === draggedUid, but kept the bundle's NESTED descendants (inner bundles + leaves whose bundle_origin matches an inner bundle of the dragged outer) as candidates.

When dragging the outer "hair_style" bundle, the inner "demo_bundle" and its leaves were still drop targets. Pointer over inner's body or its leaves resolved to zones targeting elements that move with the outer — applyDrop would no-op (self-related zone) or produce a misleading indicator at the source.

Fix:
  - New helper `collectMovingBundleUids(draggedUid, bundles)` walks parent_uid descendants and returns the set of bundle uids that move with the dragged range.
  - `classifyAgainst` (top-level walker) skips any bundle in that set AND any row whose bundle_origin is in that set.
  - `classifyWithinBundle` body walk uses the same filter for its directRows iteration.
  - Added a guard at the top of `classifyWithinBundle`: if the bundle the pointer is inside is part of the moving set (e.g. pointer in the inner bundle while dragging the outer), return null entirely. The whole region moves with the drag — no valid drop target.

Bundle-size budget bumped from 312 KB → 316 KB to accommodate the cumulative drag-redesign work (container-scoped resolver + pure applier + indicator SFC + zoom-aware offsetTop walker + moving-range filter). Net add ~1 KB; the +4 KB headroom is for follow-up polish in the same area.

Verified live via Chrome MCP at ComfyUI's 91% canvas zoom:
  - Drag outer header → inner middle: returns null (no valid drop in self-region)
  - Drag outer header → below outer (past everything): bar at end zone
  - dragState clears on dragend ✓
2026-05-21 15:45:43 +03:00
DumiFlex 6103c7c84f feat(canvas-combine): reuse RichTextInput in combine TemplateSection
The canvas combine TemplateSection used a plain textarea + a custom $var insert dropdown. The SPA's RichTextInput (atomic-chip editor) had drifted significantly ahead — chip rendering, $/\@ autocomplete with raw-text-space probe, chipify-on-boundary, click-to-edit, picker-anchored-near-chip — and the canvas was the only surface still showing raw $name text without chip visuals.

TemplateSection now mounts RichTextInput via defineAsyncComponent (chunk-split so the combine modal only pulls it in when opened) with surface="combine", varSuggestions=availableVars, and the existing template_override / library-default collapse semantics. The bespoke insert-var dropdown is gone — the chip editor's $-trigger autocomplete surfaces the same list. Detected pills, preview pane, and resolved-preview pane stay (they're separate read-only panes, not editing surfaces).

Bundle budget bumped 300 → 312 KB to fit the lazy-loaded RichTextInput chunk (~9 KB gzipped). Test rewrites use a small stub for RichTextInput so prop wiring and emit-driven updates can be asserted without booting the async resolver in jsdom.
2026-05-20 16:08:35 +03:00
DumiFlex 207fe08ee8 fix(css): prefix modal-head and modal-template-ctrls selectors with wp-
Brings 25 legacy BEM-style class selectors into compliance with the
extension's wp-* CSS namespace convention (per CLAUDE.md "Extension
isolation"). Renames .cbm__* / .cnm__* / .dvm__* / .fvm__* / .wcm__*
in _modal-head.css and .tpl__* in _modal-template-ctrls.css, plus
every consumer reference across .vue / .ts / .css / .test files.

Also renames the root element classes .wcm and .fvm (referenced from
unscoped display-prefs.css) to .wp-wcm / .wp-fvm, and clears both
entries from the LEGACY_ALLOWLIST in check-css-isolation.mjs now that
they are properly prefixed.

pnpm check:css-isolation now exits 0; all gates clean.
2026-05-18 14:52:51 +03:00
DumiFlex 780b3a142c docs(manager): document check:radius out-of-scope CSS files
Audit only sees src/manager/**/*.vue style blocks. tokens.css and
rich-text.css together hold ~88 raw border-radius values that the
script cannot reach. Spell this out in the header so future readers
don't misread `[check:radius] clean` as global coverage.

Also note the deferred-extraction point for the shared audit-script
helper — at three scripts, premature; revisit at four.
2026-05-17 23:48:35 +03:00
DumiFlex bf2dcb44f9 refactor(manager): route border-radius through --wp-radius-* tokens + audit
New check:radius audit flags raw border-radius values (including
directional and logical-property variants) in manager SFCs. Migrates
every existing offender to the radius scale (sm 6 / md 8 / lg 12 /
xl 16). Pill/circle exempts (50%, 9999px) left alone.
2026-05-17 23:33:16 +03:00
DumiFlex 23bd64e9bf docs(manager): mark font: shorthand as out-of-scope for check:typography
Audit script catches font-size/line-height longhand but bypasses the
CSS `font:` shorthand. 10 pre-existing instances in manager SFCs are
tagged `audit-exempt: font-shorthand` so a grep surfaces them as
known debt. Header docstring updated with the gap explanation +
CSS relative-size-keyword exemption note.

No code-path change. No new offenders introduced.
2026-05-17 23:00:06 +03:00
DumiFlex db6e027821 refactor(manager): introduce --wp-text-*/--wp-line-*/--wp-weight-* scale + audit
Eight-step type scale (11/12/13/14/16/20/24/30) with paired line-heights
and four weight tokens. New check:typography audit flags raw font-size
/ line-height in manager SFCs. Migrates every existing offender.

Off-grid values below 11px (8.5/9/9.5/10px) kept raw with audit-exempt
as micro badges below scale floor. Fractional values (10.5→xs, 11.5→xs,
12.5→sm, 13.5→base) rounded to nearest step, preserving compact density.
Icon accent sizes: 18px→xl(20), 26px→2xl(24), 28px→3xl(30).
2026-05-17 22:36:33 +03:00
DumiFlex 4a37005c2b chore(manager): tighten check:spacing regex + clarify hairline-exemption docs
- Audit regex now catches padding-inline-start / margin-block-end /
  etc. logical properties; previously the single -segment suffix only
  matched padding-inline. Confirmed via injection of
  `padding-inline-end: 14px` → audit exits 1.
- Docstring + tokens.css comment now correctly distinguish 2px
  (= --wp-space-1 token) from 1px (off-grid hairline exemption).
- HAS_PX_RE guard comment lists all three cases it skips.

Pure documentation + latent-bug fix from code review. No consumer
files changed.
2026-05-17 22:17:32 +03:00
DumiFlex 95e5ad3210 fix(manager): correct check:spacing per-piece validation; trim noise audit-exempt notes
- Audit script no longer short-circuits multi-value shorthand when one
  piece is a token — every piece must independently be a token or
  allowed-raw hairline.
- Strip `audit-exempt` keyword from ~72 migration-history comments
  left on lines that successfully tokenized. Reserve the keyword for
  actual raw-px exemptions so grep `audit-exempt` stays a reliable
  signal.
2026-05-17 22:01:27 +03:00
DumiFlex 783e70ad80 refactor(manager): introduce --wp-space-* scale + audit script
Adds nine-step spacing scale (0, 2, 4, 6, 8, 12, 16, 24, 32) and a
check:spacing audit that flags raw px in padding/margin/gap inside
manager SFCs. Migrates every existing offender to tokens.

Density work in Phase 1.4 will wrap these values in calc() with a
--wp-density multiplier; this commit establishes the fixed-pixel
baseline.
2026-05-17 21:46:48 +03:00
DumiFlex 6a0c0bf97b refactor: remove pipelines feature; add unified AllItems library view
Pipelines never paid off as a separate module kind, so peel out:

- Engine: drop pipeline_handler, remove "pipeline" from valid module
  types in repositories + schema parity.
- Manager: delete Pipelines/PipelineEditor views, PipelineSteps +
  PipelineStepPicker components and their tests. Router, sidebar,
  topbar, dashboard, TestRunner, ImportExport, resolver and
  bundleSelection repointed off the removed routes/types.
- wp_api: drop pipeline branch from modules.py + import_export.py
  (and its test).

In its place, add a unified library view:

- src/manager/views/AllItems.vue — modules + bundles in one filter
  panel with kind multi-select (OR across the 6 kinds). Reachable
  via the Dashboard "View all" link.
- ModuleListView grew the slots/props AllItems needs; BundleAddChild
  + Dashboard + ImportExport updated alongside.

Misc polish along the way: kind-icons / theme tokens / display-prefs
touch-ups, ContextWidget + DebugViewer + AssemblerHelper small fixes,
MockModuleCard + ModulePickerModal tweaks, _shared widget cleanup.
2026-05-17 20:50:26 +03:00
DumiFlex 35a5d8b316 chore(extension): document isolation conventions + css audit script
Four-layer extension isolation now documented in CLAUDE.md:
- .wp-* class namespace + .var-N helpers (primary)
- @layer wp-extension wrap on standalone CSS (cascade priority)
- WeakMap stashes for litegraph object metadata (collision-proof)
- node.properties string keys for persistent state only

scripts/check-css-isolation.mjs walks src/components, src/extension,
src/widgets and flags any unscoped top-level class selector that
doesn't start with .wp- or .var-N. Runs via pnpm check:css-isolation.
Two pre-existing BEM-style class roots (.wcm, .fvm) are allowlisted
with TODO notes — renaming them to .wp-* prefix is a follow-up task.

The script is intentionally light (no stylelint dep — ~80MB of dev
deps avoided). Catches the most common convention violation; deeper
issues (e.g. scoped block leaks via :deep, scope-breaking @import)
remain a manual-review concern.
2026-05-13 15:01:45 +03:00
DumiFlex 5ed697d566 chore(size): bump total budget 256 → 300 KB for batch 2 + headroom
Batch 2 (bundle drag/drop overhaul) lands four new feature surfaces
that the 256 KB gate could not absorb without per-task code-contortion
that ate into clarity: bundle-as-unit drag, before/inside/after drop
indicators, suppressMove FLIP polish, and the regression test surface.
Bumping to 300 KB matches the prior cycle's scope-and-approve pattern
(250→256 KB at 2026-05-10) and leaves headroom for subsequent batches
without forcing another bump per cycle.

Entry budget (30 KB main.js) unchanged.
2026-05-12 06:58:53 +03:00
DumiFlex 617bb9f59e chore(bundles): seed_demo_bundle.py script for manual testing 2026-05-11 04:04:20 +03:00
DumiFlex aa710eeaf4 build(size): bump total budget 250 -> 256 KB for Phase B duplicate/fork 2026-05-10 10:30:25 +03:00
DumiFlex 6921606570 feat(context): module picker + lock/internal + card indicators (#8)
Phase 5.5.4 (SPA library picker for ContextWidget) plus QA-driven polish.

* New ModulePickerModal with search, kind tabs, single + multi-pick, and
  compact filter UX (favorites/hide-added inline; category + tag chips
  behind popover with active-count badge).
* ModuleEditModal kind-aware body — wildcard option editor with
  enable/disable, weight overrides, mode picker (random/subset/pinned),
  sub-category multi-select.
* Lock + internal per-instance overrides ported and adapted: locked_seed
  derives a per-wildcard rng via sha256(seed:binding); internal hides
  bindings from the public PIPELINE_CONTEXT payload.
* Card indicators: modified dot (option-pool overrides), missing-from-
  library dot (polled hash check), in-card lock + internal toggles.
* RNG-faithful assembler preview via new /wp/api/preview/resolve; header
  shows "PREVIEW · 42". UNRESOLVED chips clickable to strip $var.
* Bulk collapse/expand toggle, focus toast w/ pulsing border overlay
  that tracks node bounds, friendly @name substitution in modal.
* Backend: new /wp/api/modules/import-from-workflow endpoint preserves
  uuid; engine emits per-module effective seeds via WP_Context UI
  payload for authoritative lock-toggle defaults.
2026-04-30 00:53:13 +03:00
DumiFlex af6ff7885e chore(scripts): migrate value-keyed constraint matrices to subcat keys
One-shot Python migration that walks every existing constraint module's
payload.matrix and rewrites rows keyed by source-option VALUE to be
keyed by source SUB_CATEGORY instead. Closes the data-shape gap left
by the d47e50e SPA flip (matrix UI is now subcat × subcat) — without
this script, legacy constraints still have value-keyed rows that
render zero cells in the new editor.

Behavior:
  - Already subcat-keyed rows are kept (idempotent, safe to re-run).
  - Value rows are remapped via source.payload.options[*].sub_category
    lookup; multiple values mapping to the same subcat merge cells (last
    cell wins per target column, with a `merged` warning in the log).
  - Orphan rows (neither subcat nor known option value) are dropped.
  - Missing/broken source_wildcard_id → constraint skipped with a `!`
    warning, no crash.
  - --dry-run flag prints the plan without writing.

Also updates seed_mock_data.py:shirt_x_color_compat to use the new
subcat-keyed shape (formal × warm reduce) plus carries the original
"white linen × red exclude" intent into the exceptions table — so
re-seeding a fresh DB doesn't reintroduce the legacy shape.
2026-04-28 23:42:46 +03:00
DumiFlex 96f5f4260f chore(scripts): add mock-data seeder for integration testing
Idempotent Python seeder under scripts/seed_mock_data.py. Populates the
local SQLite DB with comprehensive fixtures covering every feature.

15 wildcards (incl. 4-deep chain, A↔B cycle pair, self-ref, weighted
bias), 3 fixed_values, 4 combines (chained $var flow + inline picks),
2 derivations (all 4 ops + IF/ELIF/ELSE + 3 action modes), 3 constraints
(value-keyed matrix, sub-category matrix with exceptions, exception-
heavy), 3 pipelines (full 15-step orchestration, smoke, walker-stress).
5 categories with distinct colors/icons. Tags + favorites throughout.

Re-runs are safe: existing modules are updated in place — uuid stays
stable so constraint payloads + pipeline step references keep working.
Run via `python scripts/seed_mock_data.py`; override DB via WP_DB_PATH.
2026-04-28 22:44:23 +03:00
DumiFlex 926eb2cb07 feat: i18n locales (en) + per-node help pages (#2)
Wires two ComfyUI extension points so the nodes are discoverable to
casual users without reading source.

* i18n — `locales/en/` follows ComfyUI's auto-scan layout:
  - `nodeDefs.json` — display names, descriptions, input/output names,
    tooltips for WP_Context, WP_PromptAssembler, WP_Debug.
  - `settings.json` — Reduce motion + Contrast accessibility combos
    keyed as `wildcardPipeline_a11y_*`.
  - `main.json` — settings category labels (Wildcard Pipeline,
    Accessibility).
  English baseline only; structure ready for community PRs to add
  zh/ja/fr/etc. without code changes.
  Docs: https://docs.comfy.org/custom-nodes/i18n

* Help pages — `docs/help/<NodeId>.md` (markdown) gets copied to
  `js/docs/` (the WEB_DIRECTORY) at build time via
  `scripts/copy-help-docs.mjs`. ComfyUI auto-scans
  `${WEB_DIRECTORY}/docs/<NodeId>.md` and surfaces the rendered
  markdown in the node-help panel. Three pages written in casual-user
  voice: what the node does, how to use it, what icons mean — no dev
  jargon (no "last-write-wins", "idempotent", regex, etc.).
  Docs: https://docs.comfy.org/custom-nodes/help_page

* Build pipeline: `pnpm build:extension` now chains
  `vite build && pnpm docs:copy` so a fresh `js/` always carries the
  latest help pages alongside the bundled JS chunks. CI picks this up
  automatically (the same script ran by .github/workflows/ci.yml).
2026-04-26 05:51:57 +03:00
DumiFlex d185e20557 feat: polish suite — MVP frontend + subgraph support + DX + a11y
Lands the P4 frontend MVP plus 9 follow-up polish batches (88 commits squashed).

* Pipeline Context, Prompt Assembler, Debug Viewer widgets
* PIPELINE_CONTEXT chain crosses subgraph boundaries
* Conflict badges on SubgraphNodes containing WP nodes
* Empty-state hero, soft-delete + Undo toasts, corrupt-workflow recovery
* Bundled Inter + JetBrains Mono variable fonts, brand identity end-to-end
* Settings panel: Reduce motion + Contrast (a11y) with live updates
* DX: coverage gate, stricter ESLint, pre-commit pnpm size, PR size-delta workflow, contract doc

Closes the polish-brainstorm spec.
2026-04-26 05:39:22 +03:00
DumiFlex 3ebfb87cfe chore: add bundle-size gate script 2026-04-25 00:39:44 +03:00