From 72a60aa28b7e08bad1cb5185b7b320e69ea881a3 Mon Sep 17 00:00:00 2001 From: Crespin Alexandre <114501859+kunail0804@users.noreply.github.com> Date: Tue, 7 Jul 2026 16:59:32 +0200 Subject: [PATCH] chore: initialize repository structure and tooling (#1) (#45) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scaffold the Phase 0 foundation per MASTER_SPEC §24: - Directory layout: nodes/, compiler/{analyzer,validator,resolver,splitter, builder,common}/, knowledge_base/, schemas/, prompts/, config/, tests/{analyzer,resolver,validator,integration,regression}/, examples/, scripts/, docs/. - pyproject.toml targeting Python 3.11+, jsonschema as the single runtime dep, ruff + pytest as dev deps, explicit package list, and ruff/pytest config. - ruff for linting and formatting; pytest with repo root on pythonpath. - GitHub Actions CI running install, ruff lint, ruff format check, and pytest on Python 3.11 and 3.12 for pushes and pull requests. - docs/ skeleton and CONTRIBUTING.md referencing the wiki. - Layout test asserting the §24 structure and package importability. Co-authored-by: kunail0804 Co-authored-by: Claude Opus 4.8 --- .github/workflows/ci.yml | 34 +++++++++++++++ .gitignore | 22 ++++++++++ CONTRIBUTING.md | 36 ++++++++++++++++ __init__.py | 16 +++++++ compiler/__init__.py | 1 + compiler/analyzer/__init__.py | 1 + compiler/builder/__init__.py | 1 + compiler/common/__init__.py | 1 + compiler/resolver/__init__.py | 1 + compiler/splitter/__init__.py | 1 + compiler/validator/__init__.py | 1 + config/.gitkeep | 0 docs/.gitkeep | 0 docs/README.md | 19 +++++++++ examples/.gitkeep | 0 knowledge_base/.gitkeep | 0 nodes/__init__.py | 1 + prompts/.gitkeep | 0 pyproject.toml | 59 ++++++++++++++++++++++++++ schemas/__init__.py | 1 + scripts/.gitkeep | 0 tests/__init__.py | 0 tests/analyzer/__init__.py | 0 tests/integration/.gitkeep | 0 tests/integration/__init__.py | 0 tests/regression/.gitkeep | 0 tests/regression/__init__.py | 0 tests/resolver/__init__.py | 0 tests/test_repository_layout.py | 74 +++++++++++++++++++++++++++++++++ tests/validator/__init__.py | 0 30 files changed, 269 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 CONTRIBUTING.md create mode 100644 __init__.py create mode 100644 compiler/__init__.py create mode 100644 compiler/analyzer/__init__.py create mode 100644 compiler/builder/__init__.py create mode 100644 compiler/common/__init__.py create mode 100644 compiler/resolver/__init__.py create mode 100644 compiler/splitter/__init__.py create mode 100644 compiler/validator/__init__.py create mode 100644 config/.gitkeep create mode 100644 docs/.gitkeep create mode 100644 docs/README.md create mode 100644 examples/.gitkeep create mode 100644 knowledge_base/.gitkeep create mode 100644 nodes/__init__.py create mode 100644 prompts/.gitkeep create mode 100644 pyproject.toml create mode 100644 schemas/__init__.py create mode 100644 scripts/.gitkeep create mode 100644 tests/__init__.py create mode 100644 tests/analyzer/__init__.py create mode 100644 tests/integration/.gitkeep create mode 100644 tests/integration/__init__.py create mode 100644 tests/regression/.gitkeep create mode 100644 tests/regression/__init__.py create mode 100644 tests/resolver/__init__.py create mode 100644 tests/test_repository_layout.py create mode 100644 tests/validator/__init__.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..802d164 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,34 @@ +name: CI + +on: + push: + branches: ["**"] + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.11", "3.12"] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install project (with dev tools) + run: python -m pip install --upgrade pip && pip install -e ".[dev]" + + - name: Lint (ruff) + run: ruff check . + + - name: Format check (ruff) + run: ruff format --check . + + - name: Run tests + run: pytest diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c964466 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +# Python +__pycache__/ +*.py[cod] +*.egg-info/ +.eggs/ +build/ +dist/ + +# Environments +.venv/ +venv/ +env/ + +# Tooling caches +.pytest_cache/ +.ruff_cache/ +.mypy_cache/ + +# Editor / OS +.vscode/ +.idea/ +.DS_Store diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..b108bfd --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,36 @@ +# Contributing + +Full contributor guidelines live in the project wiki: +[Development, Testing & Contributing](https://github.com/kunail0804/ComfyUI-Scene-Compiler/wiki/Development-Testing-and-Contributing). +The authoritative specification is [`MASTER_SPEC.md`](MASTER_SPEC.md) (see §24–§28). + +## Local setup + +Requires **Python 3.11+**. + +```bash +git clone https://github.com/kunail0804/ComfyUI-Scene-Compiler.git +cd ComfyUI-Scene-Compiler +python -m pip install -e ".[dev]" +``` + +## Checks + +Run the same checks CI runs before opening a pull request: + +```bash +ruff check . # lint +ruff format --check . # formatting +pytest # tests +``` + +## Ground rules + +- **Determinism first** — identical input + Knowledge Base + config always produces + identical output. No randomness. +- **No hardcoded tag mappings** — concept-to-tag knowledge lives in `knowledge_base/`. +- **Separation of concerns** — `compiler/` never imports ComfyUI; `nodes/` contains no + compiler logic. +- **Tests ship with code** — new functionality includes tests; every bug fix adds a + regression test. +- Explicit type hints on public functions, docstrings, and structured logging (no `print`). diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..75c35de --- /dev/null +++ b/__init__.py @@ -0,0 +1,16 @@ +"""ComfyUI Scene Compiler — ComfyUI custom node entry point. + +ComfyUI loads this module by path and reads ``NODE_CLASS_MAPPINGS`` / +``NODE_DISPLAY_NAME_MAPPINGS`` to register the compiler's nodes. The mappings are +populated in Phase 5 when the nodes are implemented; until then they are empty so +that a fresh install imports cleanly without registering anything. + +Compiler logic never lives here — it belongs in the ``compiler/`` package. This +file is an interface for ComfyUI only. +""" + +# Populated by nodes/ in Phase 5 (issues #19–#26). +NODE_CLASS_MAPPINGS: dict[str, type] = {} +NODE_DISPLAY_NAME_MAPPINGS: dict[str, str] = {} + +__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"] diff --git a/compiler/__init__.py b/compiler/__init__.py new file mode 100644 index 0000000..4d20a1b --- /dev/null +++ b/compiler/__init__.py @@ -0,0 +1 @@ +"""compiler package.""" diff --git a/compiler/analyzer/__init__.py b/compiler/analyzer/__init__.py new file mode 100644 index 0000000..8d993f7 --- /dev/null +++ b/compiler/analyzer/__init__.py @@ -0,0 +1 @@ +"""compiler/analyzer package.""" diff --git a/compiler/builder/__init__.py b/compiler/builder/__init__.py new file mode 100644 index 0000000..10b32d9 --- /dev/null +++ b/compiler/builder/__init__.py @@ -0,0 +1 @@ +"""compiler/builder package.""" diff --git a/compiler/common/__init__.py b/compiler/common/__init__.py new file mode 100644 index 0000000..abf141a --- /dev/null +++ b/compiler/common/__init__.py @@ -0,0 +1 @@ +"""compiler/common package.""" diff --git a/compiler/resolver/__init__.py b/compiler/resolver/__init__.py new file mode 100644 index 0000000..d011e56 --- /dev/null +++ b/compiler/resolver/__init__.py @@ -0,0 +1 @@ +"""compiler/resolver package.""" diff --git a/compiler/splitter/__init__.py b/compiler/splitter/__init__.py new file mode 100644 index 0000000..dc1ffa8 --- /dev/null +++ b/compiler/splitter/__init__.py @@ -0,0 +1 @@ +"""compiler/splitter package.""" diff --git a/compiler/validator/__init__.py b/compiler/validator/__init__.py new file mode 100644 index 0000000..49305da --- /dev/null +++ b/compiler/validator/__init__.py @@ -0,0 +1 @@ +"""compiler/validator package.""" diff --git a/config/.gitkeep b/config/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/.gitkeep b/docs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..e7b0729 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,19 @@ +# Documentation + +Project documentation is maintained primarily in the +[GitHub Wiki](https://github.com/kunail0804/ComfyUI-Scene-Compiler/wiki), and the +authoritative specification is [`MASTER_SPEC.md`](../MASTER_SPEC.md) at the +repository root. + +This `docs/` directory holds documentation that is **not** part of the wiki — +for example design notes, developer guides, and generated references added in +later phases. + +## Where to look + +- **Overview & vision** — wiki *Overview and Vision* +- **Requirements** — wiki *Requirements and Success Criteria* +- **Architecture & pipeline** — wiki *Architecture and Pipeline* +- **Data model & schemas** — wiki *Data Model*, *Scene JSON and Schemas* +- **Knowledge Base** — wiki *Knowledge Base* +- **Contributing** — [`CONTRIBUTING.md`](../CONTRIBUTING.md) diff --git a/examples/.gitkeep b/examples/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/knowledge_base/.gitkeep b/knowledge_base/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/nodes/__init__.py b/nodes/__init__.py new file mode 100644 index 0000000..c3743dc --- /dev/null +++ b/nodes/__init__.py @@ -0,0 +1 @@ +"""nodes package.""" diff --git a/prompts/.gitkeep b/prompts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..ca630a8 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,59 @@ +[build-system] +requires = ["setuptools>=68"] +build-backend = "setuptools.build_meta" + +[project] +name = "comfyui-scene-compiler" +version = "0.1.0" +description = "Deterministic natural-language-to-prompt compiler for ComfyUI (Illustrious)." +readme = "README.md" +requires-python = ">=3.11" +license = { file = "LICENSE" } +authors = [{ name = "kunail0804" }] + +# Runtime dependencies are kept minimal; prefer the standard library (MASTER_SPEC §25.9). +# jsonschema is the single validation dependency, used by the schema layer (issue #2 onward). +dependencies = [ + "jsonschema>=4.0", +] + +[project.optional-dependencies] +dev = [ + "pytest>=8.0", + "ruff>=0.6", +] + +[project.urls] +Homepage = "https://github.com/kunail0804/ComfyUI-Scene-Compiler" +Wiki = "https://github.com/kunail0804/ComfyUI-Scene-Compiler/wiki" + +# The repository root is a ComfyUI custom node; its subdirectories are the importable +# packages. We enumerate them explicitly so packaging does not treat data directories +# (knowledge_base/, prompts/, ...) as Python packages. +[tool.setuptools] +packages = [ + "nodes", + "compiler", + "compiler.analyzer", + "compiler.validator", + "compiler.resolver", + "compiler.splitter", + "compiler.builder", + "compiler.common", + "schemas", +] + +[tool.ruff] +target-version = "py311" +line-length = 100 + +[tool.ruff.lint] +# E/W pycodestyle, F pyflakes, I import sorting, UP pyupgrade, B bugbear. +select = ["E", "W", "F", "I", "UP", "B"] + +[tool.pytest.ini_options] +testpaths = ["tests"] +# Put the repository root on sys.path so `import compiler`, `import schemas`, etc. +# resolve as top-level packages during tests (the root itself is loaded by ComfyUI +# by path, not by name). +pythonpath = ["."] diff --git a/schemas/__init__.py b/schemas/__init__.py new file mode 100644 index 0000000..592fe46 --- /dev/null +++ b/schemas/__init__.py @@ -0,0 +1 @@ +"""schemas package.""" diff --git a/scripts/.gitkeep b/scripts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/analyzer/__init__.py b/tests/analyzer/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/integration/.gitkeep b/tests/integration/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/integration/__init__.py b/tests/integration/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/regression/.gitkeep b/tests/regression/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/regression/__init__.py b/tests/regression/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/resolver/__init__.py b/tests/resolver/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_repository_layout.py b/tests/test_repository_layout.py new file mode 100644 index 0000000..359b9bb --- /dev/null +++ b/tests/test_repository_layout.py @@ -0,0 +1,74 @@ +"""Verify the repository layout matches MASTER_SPEC §24. + +This guards the acceptance criterion "Directory layout matches section 24 exactly" +and doubles as the smoke test proving pytest collects and runs successfully. +""" + +from __future__ import annotations + +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parent.parent + +# Directories required by MASTER_SPEC §24 (Repository Structure). +REQUIRED_DIRS = [ + "nodes", + "compiler", + "compiler/analyzer", + "compiler/validator", + "compiler/resolver", + "compiler/splitter", + "compiler/builder", + "compiler/common", + "knowledge_base", + "schemas", + "prompts", + "config", + "tests", + "tests/analyzer", + "tests/resolver", + "tests/validator", + "tests/integration", + "tests/regression", + "examples", + "scripts", + "docs", +] + +# Files required at the repository root by §24. +REQUIRED_ROOT_FILES = [ + "__init__.py", + "LICENSE", + "README.md", + "pyproject.toml", +] + +# Python packages that must be importable (root loaded by ComfyUI by path, not here). +CODE_PACKAGES = [ + "compiler", + "compiler.analyzer", + "compiler.validator", + "compiler.resolver", + "compiler.splitter", + "compiler.builder", + "compiler.common", + "nodes", + "schemas", +] + + +def test_required_directories_exist() -> None: + missing = [d for d in REQUIRED_DIRS if not (REPO_ROOT / d).is_dir()] + assert not missing, f"Missing directories from MASTER_SPEC §24: {missing}" + + +def test_required_root_files_exist() -> None: + missing = [f for f in REQUIRED_ROOT_FILES if not (REPO_ROOT / f).is_file()] + assert not missing, f"Missing required root files: {missing}" + + +def test_code_packages_are_importable() -> None: + import importlib + + for package in CODE_PACKAGES: + importlib.import_module(package) diff --git a/tests/validator/__init__.py b/tests/validator/__init__.py new file mode 100644 index 0000000..e69de29