Skip to content

refactor: marketplace split — feinschliff / builder / extra#24

Merged
marsmike merged 48 commits into
mainfrom
refactor/marketplace-split
May 21, 2026
Merged

refactor: marketplace split — feinschliff / builder / extra#24
marsmike merged 48 commits into
mainfrom
refactor/marketplace-split

Conversation

@marsmike
Copy link
Copy Markdown
Owner

Summary

Splits the monolithic feinschliff plugin into a three-plugin marketplace so end users can install only what they need:

Plugin Scope LOC
feinschliff (core) /deck, /excalidraw, /svg skills + feinschliff CLI. Ships 3 brand packs and 50 layouts. The everyday user's install. ~15.6k
feinschliff-builder Brand-pack authoring toolkit — compile-html, decompile, verify, improve-brand. Optional, lazily loaded from core. ~8.6k
feinschliff-extra 10 additional brand packs (catppuccin, nord, gruvbox, solarized, …). Pure data, no Python.

Splitting them keeps the core plugin lean and avoids installing build tools that most end users will never run.

Architecture improvements rolled into the move

This wasn't just a directory shuffle. Phases 0–2 took the chance to introduce proper interfaces and remove ambient state before phase 3 carved the code into the new homes:

  • BrandPack (feinschliff/brand/pack.py) — frozen dataclass replacing the legacy Brand shape; resolves layouts/compounds via discovery.
  • Document AST (feinschliff/dsl/ast.py) — typed Document / Slide / Element / ElementKind that the parser/expander/emitter operate on.
  • DiagnosticBag (feinschliff/diagnostics.py) — single defect container with has_errors() semantics, replacing the scattered static_verify() → list calls.
  • Renderer Protocol (feinschliff/diagrams/renderer.py) — RoughRenderer (pure Python, ~150 ms) and PlaywrightRenderer (headless Chromium fallback) implement a common interface; the dispatcher picks based on document features.
  • feinschliff/io/ — image providers, preflight, and asset I/O consolidated under one package.
  • Deck.from_brief (feinschliff/deck/orchestrate.py) — high-level entry that picks layouts, composes a Document, and renders a PPTX from one YAML.
  • layout_discovery.py — mirrors brand_discovery.py; replaces hardcoded layout paths throughout the pipeline so brand packs and layouts both surface via the same plugin-walk.

After phase 3 the core's cli/deck.py lazily imports from feinschliff_builder and gates each builder-dependent subcommand with a _require_builder("<feature>") helper that prints a friendly install hint on SystemExit(2).

Top-level re-exports

from feinschliff import BrandPack, Document, DiagnosticBag

…works without reaching into internal modules. Useful for external Python consumers and for the builder package.

Review follow-ups landed

Three smaller cleanups from the post-restructure review made it into this PR:

  1. Notes-budget hint — when feinschliff-builder is missing, deck build now prints a one-line stderr note that notes-budget validation is being skipped (suppressible via FEINSCHLIFF_QUIET_NOTES_BUDGET=1).
  2. Legacy Brand dataclass removed from brand_discovery.py (no callers; BrandPack is the supported type).
  3. cli/deck.py extractionlog-event, timing, plan-skeleton, plan-merge moved into cli/deck_subcommands/plan_log.py with a register(sub) entry point. deck.py shrunk 2116 → 1837 LOC (−13%) and the pattern is in place for further migrations.

Upstream integration

PR #23 (13 commits of XML deep-read fixes for pptx_svg_decompile.py — chart-axis visibility, <a:alpha> blending, font-size inheritance, prstGeom presets, lumMod/lumOff/tint/shade, pie legend normalisation, plotArea/manualLayout, per-bar <c:dPt> colours) was integrated via path-rewritten 3-way merge into the carved location with no conflicts.

CI

  • New feinschliff-builder job mirrors the existing feinschliff job: uv sync --group dev → ruff → pytest. Stale --ignore entries pointing at tests that moved into the builder were dropped from the core job.
  • Both packages are ruff-clean.
  • DCO job validates every commit's Signed-off-by line.

Marketplace + workspace metadata

  • .claude-plugin/marketplace.json lists all three plugins with their sources; each source points to a valid directory whose plugin.json name matches the marketplace entry.
  • Root pyproject.toml declares feinschliff + feinschliff-builder as uv workspace members; feinschliff-extra is intentionally excluded (no Python, no pyproject).
  • Each plugin has its own .claude-plugin/plugin.json and README.md.

Test plan

  • uv run --package feinschliff pytest tests817 passed (19 skipped, 1 xfailed)
  • uv run --package feinschliff-builder pytest tests307 passed (5 skipped)
  • CI commands locally: feinschliff 799 passed / builder 291 passed (with CI's render-skip ignores)
  • uv run ruff check . clean in both packages
  • feinschliff deck --help shows all 17 subcommands
  • feinschliff deck log-event end-to-end smoke test writes timing.jsonl correctly
  • PR feat(decompile): three XML deep-read fixes (chart-axis + alpha + font inheritance) #23 symbols all present
  • No BSH/Bosch references in any tracked file
  • Brand discovery picks up feinschliff-extra via plugin-marketplace walk

Followups (intentionally out of scope)

  • cli/deck.py further extraction (12 more subcommand groups; plan_log.py establishes the pattern)
  • Multi-slide DSL parsing via --- separator (test currently smoke-tests single-slide only with a comment marker)

🤖 Generated with Claude Code

marsmike and others added 30 commits May 21, 2026 06:55
…very 5-source pattern

Introduces LayoutSource and Layout dataclasses, discover_layouts(),
find_layout(), and all_layout_dirs() with bundled/plugin/env/cwd-dev/user
priority order. 12 TDD tests added and passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
…iscovery

Removes REPO_ROOT, STD_COMPOUNDS, BRANDS_DIR module-level constants.
brands_dir resolution now relies on brand_root.parent (the load_tokens
default), and compounds/ is reached via a local _bundled_compounds() helper.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Removes REPO_ROOT, BRANDS_DIR, STD_COMPOUNDS module-level constants.
_resolve_layout_path now iterates all_layout_dirs() from layout_discovery.
load_tokens and load_compounds_for_brand use brand_root.parent default and
_bundled_compounds() respectively.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
…fallback

Replaces the hardcoded Path(__file__).parents[2]/"brands" fallback in
_load_tokens_with_extends with a call to find_brand() from brand_discovery,
covering all registered discovery sources uniformly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
…nt resolution

Replaces hardcoded Path(__file__).parents[2]/"brands" with discovery-based
iteration over all brands directories from discover_brands(), covering
bundled, plugin, env, cwd-dev, and user sources.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
…very

Removes REPO_ROOT, BRANDS_DIR, STD_COMPOUNDS module-level constants from
build.py, deck.py, and decompile.py. Layout lookups now use find_layout()
and all_layout_dirs() from layout_discovery; brand lookups use find_brand()
from brand_discovery; assets use _bundled_assets() helpers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
….4 followup)

Signed-off-by: Mike Mueller <mike@objektarium.de>
…cs, narrow exception)

Signed-off-by: Mike Mueller <mike@objektarium.de>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Signed-off-by: Mike Mueller <mike@objektarium.de>
…osticBag

Signed-off-by: Mike Mueller <mike@objektarium.de>
…ind_compound toolkit fallback test

Gap 1: Replace all three static_verify() call sites in cli/deck.py with
validate(plan, brand=brand_obj) from lib.verify.static. Boolean checks now use
DiagnosticBag truthiness/__bool__; JSON output retains backward-compatible
{slide_index, kind, severity, message, meta} schema for deck apply-fixes
compatibility. plan_fixes() in autofix.py updated to accept DiagnosticBag via
duck-typed _defect_slide_index()/_defect_meta() helpers; kind comparisons
changed from `is` to `==` for cross-enum compatibility.

Gap 2: Add test_find_compound_falls_back_to_toolkit to test_brand_pack.py,
mirroring test_find_layout_falls_back_to_toolkit. Uses the real toolkit
compound "card" (compounds/card.dsl) and asserts origin="toolkit".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
…agram-kind test)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
…tRenderer

Adds lib/diagrams/renderer.py with:
- Renderer Protocol (@runtime_checkable) with name, supports(src), render_png(src, out)
- RoughRenderer: supports() inspects the .excalidraw JSON for freedraw/image/frame;
  delegates to render_rough.render_excalidraw. Falls back when deps unavailable.
- PlaywrightRenderer: universal fallback for .excalidraw and .svg
- _REGISTRY + choose_renderer(src) replacing the inline try/except dispatch
- register_renderer(r, priority) for third-party injection

render.py updated with docstring directing new code to choose_renderer;
legacy render() function unchanged for backwards compatibility.

18 new tests in tests/test_renderer.py.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Moved five modules to lib/io/ via git mv (history follows):
  lib/soffice.py            → lib/io/soffice.py
  lib/dsl/pptx_to_png.py   → lib/io/pptx_to_png.py
  lib/image_provider.py    → lib/io/image_provider.py
  lib/image_preflight.py   → lib/io/image_preflight.py
  lib/providers/           → lib/io/providers/

Updated all import sites: cli/, scripts/, tests/, lib/dsl/pptx_emit.py
(relative ..image_provider refs → ..io.image_provider).

Created lib/io/__init__.py (empty — no forced re-exports).

1124 tests pass (baseline 1106 + 18 from Task 2.1). Smoke ok.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Adds lib/deck/picker.py with:
- LayoutMatch frozen dataclass (layout_name, layout_path, score, reason)
- LayoutPicker class wrapping lib.layout_picker.pick_layout:
  - candidates(slot_hint, top_k) → list[LayoutMatch]
  - pick(slot_hint) → LayoutMatch (raises ValueError when nothing matches)
  - Optional BrandPack for layout_path resolution via find_layout()

cmd_pick in cli/deck.py updated to use LayoutPicker.candidates().
Legacy lib.layout_picker.pick_layout() untouched (no removal).

17 new tests in tests/test_deck_picker.py.
1141 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Adds lib/deck/compose.py with:
- Deck(brand, document) — thin orchestrator for the typed AST pipeline
- Deck.from_dsl_text(text, brand) / Deck.from_dsl_path(path, brand) factory methods
- Deck.build(out_path) → Path: expand_document + emit_pptx_from_document
- Deck.diagnostics → DiagnosticBag (empty before build)

The class wraps the Phase 1 typed-AST pipeline
(parse_document → expand_document → emit_pptx_from_document).
The legacy compile_slide + build_multi_slide plan-YAML path in
cli/deck.py::cmd_build is unchanged.

10 new tests in tests/test_deck_compose.py.
1151 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Extract _signals_from_slide, _resolve_layout_path, _slot_budgets_for_layout,
_build_primitives_for_layout, _build_refurbished_deck, and _patch_set_hash
from cli/deck.py into lib/deck/orchestrate.py.  cli/deck.py now delegates
to orchestrate functions; 192 lines of business logic removed from the CLI
layer (2261 → 2081 LOC).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Adds Deck.from_brief(brief_path, brand) classmethod that reads a deck
plan YAML and returns a typed Deck via a new compose_from_brief() helper
in lib.deck.orchestrate. Slot interpolation is not applied (placeholders
preserved); full slot-fill stays in the legacy cmd_build pipeline.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Signed-off-by: Mike Mueller <mike@objektarium.de>
…r carve-out

Signed-off-by: Mike Mueller <mike@objektarium.de>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Signed-off-by: Mike Mueller <mike@objektarium.de>
marsmike and others added 15 commits May 21, 2026 06:55
Task 3.3 of the marketplace restructure. Establishes `feinschliff/` as
the standalone core plugin (build, deck, ship) by:

- Moving all core source modules (lib/ → feinschliff/, cli/ → cli/)
  from the staging `_feinschliff/` tree to `feinschliff/feinschliff/`
- Moving layouts/, compounds/, brands/ (core set), assets/, schemas/ to
  `feinschliff/` plugin root
- Rewriting all imports from `lib.X` / `cli.X` to `feinschliff.X` /
  `feinschliff.cli.X`
- Adding uv workspace pyproject.toml at repo root and plugin-level
  pyproject.toml files for `feinschliff` and `feinschliff-builder`
- Stripping builder subcommands (brand, compile, decompile, verify,
  verify_diagram, verify_quality) from core CLI main.py
- Wrapping builder imports in lazy try/except with None fallbacks in
  pipeline.py and cli/deck.py; guarding callsites with `if X is not None:`
- Updating cli/ship.py to call `feinschliff-builder` for gates 2/3 with
  graceful skip when builder not installed (detects ModuleNotFoundError)
- Moving builder-specific tests to feinschliff-builder/tests/
- Adding pytest.skip guards and extra-brands fallback helpers in core
  tests that depend on brands from the not-yet-carved feinschliff-extra

Test suite: 794 passed, 42 skipped, 1 xfailed (no regressions)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Signed-off-by: Mike Mueller <mike@objektarium.de>
… [Task 3.4 cont]

Signed-off-by: Mike Mueller <mike@objektarium.de>
…ce.json [Task 3.6]

Signed-off-by: Mike Mueller <mike@objektarium.de>
Signed-off-by: Mike Mueller <mike@objektarium.de>
…vate APIs, dev-deps cleanup)

- Fix 1+2: add _require_builder() helper in cli/deck.py; guard all 9
  cmd_* entry-points that depend on feinschliff-builder with a clear
  user-facing error + SystemExit(2) instead of bare ImportError/TypeError
- Fix 3: rename _check_slot_overflow → check_slot_overflow and
  _iter_slot_values → iter_slot_values in content_validator.py; update all
  callers in core (content_validator, slot_budget), builder (verify/static),
  and tests
- Fix 4: rename diagrams/_text_metrics.py → diagrams/text_metrics.py; update
  all 4 core importers + builder's structural_validator cross-plugin import
- Fix 5: drop imagehash, img2pdf, numpy, scikit-image from core's dev-deps
  (zero usage in feinschliff/ or tests/); keep them in feinschliff-builder
- Fix 6: correct stale path comments in pipeline.py, verify.py docstring,
  brand/__init__.py docstring; advance defects.py planned-removal to Phase 4

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Write end-user README for feinschliff (3 skills, 3 CLI subcommands, 3
brand packs), builder-author README for feinschliff-builder (2 skills,
6 CLI subcommands), brand catalog README for feinschliff-extra (10
brands with one-liners), and a marketplace overview at repo root
explaining the three-plugin split.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Add feinschliff/docs/brand-pack-contract.md — terse contract covering
directory structure, required tokens.json groups, inheritance, layout
and compound naming conventions, the 5 discovery sources, and
distribution options (plugin or FEINSCHLIFF_BRAND_PATH).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Rewrite all `lib.X` cross-references in docstrings and comments to use
the canonical `feinschliff.X` / `feinschliff_builder.X` module paths.
Affects ~40 hits across diagnostics, defects, dsl/, deck/, diagrams/,
io/, brand_discovery, layout_budget, content_validator, and cli/deck.py.

Also remove the now-unnecessary sys.path.insert() shim from
feinschliff-builder/tests/conftest.py — the uv workspace setup makes
both packages importable without it (confirmed: 307 tests still pass).

Tighten feinschliff-extra plugin.json description to name the 10 brand
packs rather than just saying "Extra brand packs for feinschliff."

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
The _feinschliff/ directory was the original single-package layout,
retained as a reference during the three-phase marketplace split (core
feinschliff + feinschliff-builder + feinschliff-extra). All Python
source has been relocated; this removes the now-empty staging area.

Tests: 817 core + 307 builder, all passing without the directory.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Remove links to docs/ files that no longer exist (architecture.md,
brand-system.md, dsl-grammar.md, port-your-brand.md), fix
BRAND-PACK-CONTRACT.md case mismatch → brand-pack-contract.md, and
drop hero-grid.png image refs whose docs/images/ directory was not
ported.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
…kspace pyproject comment

Signed-off-by: Mike Mueller <mike@objektarium.de>
…, deck.py extraction

Three follow-ups from the post-restructure review:

1. cli/deck.py:cmd_build now prints a one-line stderr hint when
   feinschliff-builder is missing and notes-budget validation gets
   silently skipped. Suppressible via FEINSCHLIFF_QUIET_NOTES_BUDGET=1.

2. brand_discovery.py drops the legacy `Brand` dataclass (no in-repo
   callers; BrandPack has been the supported type since Phase 1).

3. cli/deck.py extracts log-event, timing, plan-skeleton, and
   plan-merge into cli/deck_subcommands/plan_log.py with a
   register(sub) entry point. deck.py shrinks 2116 → 1837 LOC
   (−13%) and establishes the pattern for migrating the remaining
   subcommands.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
…s, alpha, font inheritance, presets, color mods, …)

Integrates the upstream improvements from #23 into
the carved location (feinschliff-builder/.../pptx_svg_decompile.py).
Applied via 3-way merge against the restructure branch-base; our local
changes (namespace rewrites, discover_brands() refactor, brand-name
cleanup in comments) all preserved cleanly with no conflicts.

Upstream changes folded in:

- font-size inheritance from layout/master (<p:txStyles>, lstStyle)
- <a:alpha> on fills (pre-blend on white)
- bar chart <c:catAx>/<c:valAx>/<c:dLbls>/<c:delete>/<c:showVal>
- per-bar <c:dPt> colours
- prstGeom presets (triangle/rtTriangle/diamond/parallelogram/
  trapezoid/pentagon/hexagon/heptagon/octagon/chevron/{up,down,left,
  right}Arrow)
- bar-chart legend + title gated on source presence
- lumMod/lumOff/tint/shade in both color resolvers
- pie legend corner-position normalisation (tr/tl/br/bl)
- <c:firstSliceAng> on pie/doughnut
- chart series + dPt colours skip nearest_token to preserve hex
- value labels in horizontal stacked/percentStacked bars
- <c:plotArea>/<c:manualLayout> for pie sizing

Also drops the now-unused `os` import (env-path parsing was replaced
by discover_brands() in the restructure carve).

Net: +521 / -109 lines. Tests: 817 core + 307 builder = 1124 passing.
Ruff clean.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
- ci.yml gains a feinschliff-builder job mirroring feinschliff (uv sync,
  ruff, pytest) so the carved plugin gets the same gate. Stale --ignore
  entries pointing at tests that moved to feinschliff-builder are
  dropped from the feinschliff job; new builder-side --ignore list
  covers render/refurbish/chrome tests that auto-skip in CI.
- dsl/parser.py: add TYPE_CHECKING block for Document/Element so the
  forward-ref return annotations resolve under ruff.
- tests/test_deck_compose.py::test_build_multi_slide_deck: drop the
  unused multi-slide Document scaffolding — parse_document doesn't yet
  recognise the `---` separator, so the test was building a doc it
  never used. Now smoke-tests Deck.build on _minimal_doc() with a
  comment marking the followup.
- Remaining changes are auto-fix from `ruff check --fix`: unused
  imports / variables across both packages, plus a `import pytest;
  pytest.skip(...)` semicolon cleanup in test_verify_static.py.

Both packages now ruff-clean and tests green:
  feinschliff: 799 passed (16 skipped, 4 deselected)
  feinschliff-builder: 291 passed (2 skipped)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
@marsmike marsmike force-pushed the refactor/marketplace-split branch from b5e9fac to 9b25b3f Compare May 21, 2026 04:56
marsmike and others added 3 commits May 21, 2026 07:00
Tests fail in the per-package CI setup because:

1. Cross-plugin brand tests reference brand names that live in
   feinschliff-extra (catppuccin-macchiato, nord, gruvbox-dark,
   feinschliff-dark). Per-package `uv sync` from feinschliff/ never
   surfaces them. Locally they're picked up via the plugin-marketplace
   walk (`~/.claude/plugins/.../feinschliff-extra/brands`), which CI
   has no equivalent of.

2. test_cli_ship calls `feinschliff ship`, which delegates to
   feinschliff-builder for the verify-quality leg of the pipeline.
   When only feinschliff is installed, ship exits 2 via
   `_require_builder`.

Both jobs now `uv sync --all-packages --all-groups` at the workspace
root and set `FEINSCHLIFF_BRAND_PATH=$GITHUB_WORKSPACE/feinschliff-extra/brands`,
so discover_brands() finds the extra packs and the integrated ship
pipeline has builder available.

Verified locally with the exact CI commands: feinschliff 799 passed,
feinschliff-builder 291 passed.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
…act)

main's branch protection lists "feinschliff lib tests" + "DCO sign-off"
as required status checks. My earlier rename to "feinschliff tests"
broke that contract — the PR sits at "Expected — Waiting for status to
be reported" forever even though the job ran and passed.

Restore the original display name. The new feinschliff-builder job
continues as an additional check (not required by branch protection,
but visible on every PR).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
Aligns the marketplace-split release with the next-minor bump from
v0.1.0 (the final monolithic release tagged on main). Both packages
previously carried 0.3.0 from an earlier copy-paste; resetting to
0.2.0 keeps the version line continuous.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Mike Mueller <mike@objektarium.de>
@marsmike marsmike merged commit 6461b7a into main May 21, 2026
3 checks passed
@marsmike marsmike deleted the refactor/marketplace-split branch May 21, 2026 05:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant