fix(tui): welcome preflight passes in installed mode#14
Closed
21tmccauley wants to merge 15 commits into
Closed
Conversation
…content Plan for shipping the CLI via pipx/Homebrew with user-owned, self-updating content: multi-root fetcher discovery, a hashed workspace manifest, a paramify sync reconcile with .new conflict handling, schema-version migrations, release integration, platform nuances (Mac/Windows/Linux), and a phased prototype plan with an acceptance test. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…y model The expected customization is creating fetchers for unsupported platforms, not editing built-ins — so ship read-only bundled content + a writable user overlay instead of a materialized workspace reconciled by a sync engine. The no-clobber guarantee becomes structural: upgrades never write where users do. The reviewed workspace-sync design moves to docs/deferred/ with its revival trigger (evidence of customers editing many built-ins in place). Decision #243 supersedes #223; #224 (content bundled per release) stands. Co-Authored-By: Claude Fable 5 <[email protected]>
- framework/roots.py: ordered content roots — $PARAMIFY_FETCHERS_PATH → dev checkout → $PARAMIFY_HOME/fetchers (platformdirs) → the installed bundle (framework/_bundled, shipped by a later commit). - Discovery walks all roots: the first root wins a name collision, reported as a shadow (never silent); within-root duplicates stay a hard error; a broken fetcher.yaml is skipped and reported instead of aborting discovery (refuse, don't crash). Category files union per-file across roots, so a user dir can define entirely new platforms. - Schemas and ksis.yaml resolve package-relative; every CLI command tolerates a missing checkout (api.locate_root); run manifests fall back to the cwd. The dev clone outranks the user dir so in-tree edits win. - paramify create <category>/<name> scaffolds a user fetcher from the shipped template; paramify customize <fetcher> is the copy-on-write override, with a .customized.json sidecar (source, tool version, per-file hashes); doctor gains a distribution section reporting roots, shadows, stale/orphaned overrides, and invalid fetchers. Co-Authored-By: Claude Fable 5 <[email protected]>
setup.py's build_py hook assembles framework/_bundled/ (fetchers + examples; logos excluded — README furniture) straight into build_lib, so every build path produces the bundle and the source tree never grows a stale copy. Package data covers the schemas, the KSI reference, and the TUI stylesheet; uploaders/ becomes a proper package so paramify upload works installed (api falls back to the packaged module outside a checkout). MANIFEST.in keeps sdists — including the GitHub source tarball — complete. tests/test_installed.py builds the wheel, installs it into an isolated target, and drives catalog + a real demo_hello run from an empty cwd with no checkout on disk — the 'green in dev, broken installed' gap, now gated — plus the user-dir-shadows-bundle override path. Co-Authored-By: Claude Fable 5 <[email protected]>
Console scripts installed next to the running interpreter — a pipx venv, an unactivated .venv — were invisible to fetchers: pipx inject checkov lands the CLI in a bin/ that pipx never puts on PATH, and _build_env passed children only the inherited PATH. Prepend Path(sys.executable).parent (deduped) so venv-installed CLIs resolve under pipx and dev venvs alike. Co-Authored-By: Claude Fable 5 <[email protected]>
packaging/brew/ holds the tap formula template (virtualenv-based; the external CLIs the catalog shells out to as deps — the one thing brew can declare that pipx can't; setuptools/wheel as resources because brew builds offline and the bundle-assembling build hook needs them) plus the per-release stamp procedure (shasum + brew update-python-resources). releasing.md gains build-and-attach-the-wheel and tap-bump steps, and the Artifacts section drops the wheel/PyPI blocker removed by the overlay distribution work — PyPI is now a channel decision, not a technical one. Co-Authored-By: Claude Fable 5 <[email protected]>
…tra hint
The TUI gated the manifest picker, welcome-screen manifest table, and the
run action on root_path — a checkout-era assumption. The api facade now
handles root=None (manifests resolve from the cwd, content from the overlay
roots), so the gates just made those features silently dead under a pipx
install. Removed them.
The missing-textual hint named the wrong package ('paramify') and only the
pip flow; it now gives the pipx and pip commands for paramify-fetchers.
Co-Authored-By: Claude Fable 5 <[email protected]>
Found in dist testing: brew's pipx 1.15 (uv venv backend) exits 1 on pipx install --force into an existing venv and silently leaves the old version installed. UV_VENV_CLEAR=1 or uninstall-first works; the upgrade instructions now say so. Co-Authored-By: Claude Fable 5 <[email protected]>
Distributable install: the overlay model (multi-root discovery, bundled wheel, create/customize, pipx)
rust is a build dep (rpds-py via jsonschema builds from sdist under brew's --no-binary policy), and update-python-resources can't resolve a package that isn't on PyPI — the README now documents the freeze + PyPI-JSON fallback used to stamp the 21tmccauley test tap. Co-Authored-By: Claude Fable 5 <[email protected]>
Found in tap testing: a brew install shipped only the base closure, so paramify tui failed out of the box — wrong for the batteries-included path. The template now carries a textual resource and a test asserting the import; pipx users keep opting in via the [tui] extra. Co-Authored-By: Claude Fable 5 <[email protected]>
docs(brew): formula learnings from tap testing (TUI bundling, resource generation)
Co-Authored-By: Claude Fable 5 <[email protected]>
chore(release): v0.3.0-rc.1
The welcome screen's startup readout treated a missing checkout as a failure: "repo root ✗ not found" in red, with the catalog and uploader checks dashed out — on every pipx/brew install, where everything actually works. A checkout is one way to have content, not a requirement. - Check 0 is now "content roots": the checkout name in dev mode, "installed bundle" (or a root count) installed, red only when discovery found no roots at all. - The catalog check answers from app.catalog_data regardless of a checkout; the uploader check falls back to the packaged uploaders.paramify_evidence module. - "New manifest" no longer requires a repo root — api.new_manifest_path(None, ...) already lands it in ./manifests/. Regression tests cover installed / installed+user-dir / dev / empty. Co-Authored-By: Claude Fable 5 <[email protected]>
Collaborator
Author
|
Opened against upstream by mistake — this work is staged on the 21tmccauley/paramify-fetchers-distribute fork for now. Recreating there. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On a brew/pipx install,
paramify tuinow launches — but the welcome screen's animated startup checks fail:The readout was written when a checkout was the only way to have content. Under the overlay model that's wrong on both ends: no checkout is the normal installed state, and the catalog/uploader work fine without one (
api.catalog(None)reads the bundled snapshot + user dir; the uploader ships in the wheel).Fix
✓ installed bundle(or✓ installed · N rootsonce a user dir exists) installed, and only goes red when discovery found no roots at all.app.catalog_dataregardless of a checkout; the uploader check falls back toimportlib.util.find_spec("uploaders.paramify_evidence").api.new_manifest_path(None, ...)already falls back to./manifests/(covered bytests/test_roots.py).Installed mode now settles to the green one-liner:
✓ workspace ok · 109 fetchers · no manifests yet · uploader ready.Tests
New
tests/test_tui_welcome.pydrives_resolve_checksthrough installed / installed+user-dir / dev-checkout / no-content-anywhere (the last still fails red, as it should). Skips cleanly when textual isn't installed.pytest238 passed ·ruff check framework/clean ·mypy framework/clean.🤖 Generated with Claude Code