fantasm 0.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. fantasm-0.1.2/.github/workflows/ci.yml +16 -0
  2. fantasm-0.1.2/.github/workflows/readme-check.yml +28 -0
  3. fantasm-0.1.2/.github/workflows/release.yml +64 -0
  4. fantasm-0.1.2/.github/workflows/test.yml +90 -0
  5. fantasm-0.1.2/.gitignore +59 -0
  6. fantasm-0.1.2/.pre-commit-config.yaml +15 -0
  7. fantasm-0.1.2/CLAUDE.md +138 -0
  8. fantasm-0.1.2/LICENSE +21 -0
  9. fantasm-0.1.2/PKG-INFO +201 -0
  10. fantasm-0.1.2/README.md +178 -0
  11. fantasm-0.1.2/docs/configuration.md +289 -0
  12. fantasm-0.1.2/docs/index.md +17 -0
  13. fantasm-0.1.2/docs/inventory.md +106 -0
  14. fantasm-0.1.2/docs/migration_readiness.md +164 -0
  15. fantasm-0.1.2/docs/testing.md +63 -0
  16. fantasm-0.1.2/pyproject.toml +90 -0
  17. fantasm-0.1.2/scripts/generate_readme.py +125 -0
  18. fantasm-0.1.2/scripts/readme_template.md.j2 +108 -0
  19. fantasm-0.1.2/src/fantasm/__init__.py +5 -0
  20. fantasm-0.1.2/src/fantasm/api/__init__.py +240 -0
  21. fantasm-0.1.2/src/fantasm/api/asm_extract.py +183 -0
  22. fantasm-0.1.2/src/fantasm/api/audit.py +486 -0
  23. fantasm-0.1.2/src/fantasm/api/backfill.py +742 -0
  24. fantasm-0.1.2/src/fantasm/api/blockmatch.py +259 -0
  25. fantasm-0.1.2/src/fantasm/api/cfg.py +358 -0
  26. fantasm-0.1.2/src/fantasm/api/comment_check.py +588 -0
  27. fantasm-0.1.2/src/fantasm/api/compare.py +423 -0
  28. fantasm-0.1.2/src/fantasm/api/context.py +315 -0
  29. fantasm-0.1.2/src/fantasm/api/find_shared.py +164 -0
  30. fantasm-0.1.2/src/fantasm/api/fingerprint.py +92 -0
  31. fantasm-0.1.2/src/fantasm/api/insert_point.py +194 -0
  32. fantasm-0.1.2/src/fantasm/api/labels.py +228 -0
  33. fantasm-0.1.2/src/fantasm/api/lint.py +301 -0
  34. fantasm-0.1.2/src/fantasm/api/mos6502.py +221 -0
  35. fantasm-0.1.2/src/fantasm/api/paths.py +220 -0
  36. fantasm-0.1.2/src/fantasm/api/project.py +197 -0
  37. fantasm-0.1.2/src/fantasm/api/promote.py +174 -0
  38. fantasm-0.1.2/src/fantasm/api/rename_labels.py +139 -0
  39. fantasm-0.1.2/src/fantasm/api/suggest.py +175 -0
  40. fantasm-0.1.2/src/fantasm/api/verify.py +140 -0
  41. fantasm-0.1.2/src/fantasm/api/version_graph.py +477 -0
  42. fantasm-0.1.2/src/fantasm/cli.py +2556 -0
  43. fantasm-0.1.2/src/fantasm/cli_helpers.py +179 -0
  44. fantasm-0.1.2/src/fantasm/config.py +65 -0
  45. fantasm-0.1.2/tests/api/__init__.py +0 -0
  46. fantasm-0.1.2/tests/api/test_asm_extract.py +199 -0
  47. fantasm-0.1.2/tests/api/test_audit.py +317 -0
  48. fantasm-0.1.2/tests/api/test_backfill.py +475 -0
  49. fantasm-0.1.2/tests/api/test_blockmatch_fingerprint.py +174 -0
  50. fantasm-0.1.2/tests/api/test_comment_check.py +392 -0
  51. fantasm-0.1.2/tests/api/test_compare.py +230 -0
  52. fantasm-0.1.2/tests/api/test_insert_point_cfg_context.py +545 -0
  53. fantasm-0.1.2/tests/api/test_labels.py +253 -0
  54. fantasm-0.1.2/tests/api/test_lint.py +248 -0
  55. fantasm-0.1.2/tests/api/test_mos6502.py +165 -0
  56. fantasm-0.1.2/tests/api/test_paths.py +187 -0
  57. fantasm-0.1.2/tests/api/test_project.py +194 -0
  58. fantasm-0.1.2/tests/api/test_promote_findshared.py +238 -0
  59. fantasm-0.1.2/tests/api/test_suggest.py +162 -0
  60. fantasm-0.1.2/tests/api/test_verify_rename.py +186 -0
  61. fantasm-0.1.2/tests/api/test_version_graph.py +556 -0
  62. fantasm-0.1.2/tests/conftest.py +28 -0
  63. fantasm-0.1.2/tests/test_cli.py +89 -0
  64. fantasm-0.1.2/tests/test_cli_commands.py +893 -0
  65. fantasm-0.1.2/tests/test_cli_project.py +229 -0
@@ -0,0 +1,16 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ branches: [master]
8
+
9
+ jobs:
10
+ test:
11
+ uses: ./.github/workflows/test.yml
12
+
13
+ readme-check:
14
+ # Belt-and-braces against contributors who bypass the pre-commit
15
+ # hook. Same job is reused by release.yml as a publication gate.
16
+ uses: ./.github/workflows/readme-check.yml
@@ -0,0 +1,28 @@
1
+ name: README check
2
+
3
+ # Reusable workflow: verifies that README.md is in sync with the
4
+ # generator (scripts/generate_readme.py). Called by ci.yml on push/PR
5
+ # and by release.yml as a publication gate so a v-tag with a stale
6
+ # README is held back from PyPI.
7
+
8
+ on:
9
+ workflow_call:
10
+
11
+ jobs:
12
+ check:
13
+ name: README.md is in sync with the generator
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - name: Install uv
19
+ uses: astral-sh/setup-uv@v6
20
+ with:
21
+ python-version: "3.13"
22
+ cache-dependency-glob: pyproject.toml
23
+
24
+ - name: Install dev dependencies
25
+ run: uv sync
26
+
27
+ - name: Verify README.md matches the generator's output
28
+ run: uv run python scripts/generate_readme.py --check
@@ -0,0 +1,64 @@
1
+ name: Release
2
+
3
+ # Atomic release workflow: on a `v*` tag produced by bump-my-version,
4
+ # runs the full test matrix and the README sync check in parallel as
5
+ # two gates. Only when BOTH gates are green does publish-pypi run.
6
+ #
7
+ # `workflow_dispatch` is enabled so a release can be re-attempted
8
+ # manually if the publish step fails transiently after the gates
9
+ # pass. Individual failed jobs can also be re-run from the Actions UI.
10
+
11
+ on:
12
+ push:
13
+ tags: ["v*"]
14
+ workflow_dispatch:
15
+
16
+ # Default read-only permissions for the workflow; the publishing job
17
+ # narrows its own permissions to what it actually needs.
18
+ permissions:
19
+ contents: read
20
+
21
+ jobs:
22
+ test:
23
+ # Reuses the matrix defined in test.yml so CI and Release exercise
24
+ # the exact same test surface against the built wheel.
25
+ uses: ./.github/workflows/test.yml
26
+
27
+ readme-check:
28
+ # Same gate ci.yml runs on every push.
29
+ uses: ./.github/workflows/readme-check.yml
30
+
31
+ publish-pypi:
32
+ name: Publish to PyPI
33
+ # Both gates must pass before publication. If either fails, this
34
+ # job does not run.
35
+ needs: [test, readme-check]
36
+ runs-on: ubuntu-latest
37
+ # The `pypi` GitHub deployment environment is the gate for the
38
+ # PYPI_TOKEN secret (and/or trusted-publishing OIDC config).
39
+ environment:
40
+ name: pypi
41
+ url: https://pypi.org/project/fantasm/
42
+ permissions:
43
+ # Required if/when the project opts into PyPI trusted publishing
44
+ # via OIDC. Harmless when using a token instead.
45
+ id-token: write
46
+ steps:
47
+ - uses: actions/checkout@v4
48
+
49
+ - name: Install uv
50
+ uses: astral-sh/setup-uv@v6
51
+ with:
52
+ python-version: "3.13"
53
+
54
+ - name: Build distributions
55
+ run: uv build
56
+
57
+ - name: Publish to PyPI
58
+ # Uses UV_PUBLISH_TOKEN if set; otherwise uv falls back to
59
+ # PyPI trusted publishing via the OIDC token minted by
60
+ # GitHub (works when the project is registered as a trusted
61
+ # publisher under the `pypi` environment).
62
+ run: uv publish
63
+ env:
64
+ UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }}
@@ -0,0 +1,90 @@
1
+ name: Test
2
+
3
+ # Reusable workflow: builds a wheel and runs the test suite against the
4
+ # installed wheel (not the source tree) on a matrix of OS x Python
5
+ # version. Called by ci.yml on push/PR so verification always exercises
6
+ # the exact artefact shape users will install -- catching packaging
7
+ # regressions like missing package data, omitted entry points, or an
8
+ # unshipped py.typed marker that an editable install would hide.
9
+
10
+ on:
11
+ workflow_call:
12
+
13
+ jobs:
14
+ resolve-python-versions:
15
+ name: Resolve supported Python versions from pyproject classifiers
16
+ runs-on: ubuntu-latest
17
+ outputs:
18
+ versions: ${{ steps.extract.outputs.versions }}
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - id: extract
22
+ name: Pick earliest + latest declared Python version
23
+ # Reading the supported versions from the classifiers keeps the CI
24
+ # matrix in sync with the published metadata. ubuntu-latest ships
25
+ # a stdlib tomllib-capable Python (>=3.11).
26
+ run: |
27
+ versions=$(python - <<'PY'
28
+ import json
29
+ import re
30
+ import tomllib
31
+ from pathlib import Path
32
+
33
+ data = tomllib.loads(Path("pyproject.toml").read_text())
34
+ declared = sorted(
35
+ (
36
+ c.rsplit(" :: ", 1)[-1]
37
+ for c in data["project"]["classifiers"]
38
+ if re.match(r"^Programming Language :: Python :: 3\.\d+$", c)
39
+ ),
40
+ key=lambda v: tuple(map(int, v.split("."))),
41
+ )
42
+ if not declared:
43
+ raise SystemExit("No 'Programming Language :: Python :: 3.x' classifiers found")
44
+ selected = [declared[0], declared[-1]] if len(declared) >= 2 else declared
45
+ print(json.dumps(selected))
46
+ PY
47
+ )
48
+ echo "versions=$versions" >> "$GITHUB_OUTPUT"
49
+
50
+ test:
51
+ name: Test on ${{ matrix.os }} / Python ${{ matrix.python-version }}
52
+ needs: resolve-python-versions
53
+ runs-on: ${{ matrix.os }}
54
+ strategy:
55
+ fail-fast: false
56
+ matrix:
57
+ os: [ubuntu-latest, macos-latest, windows-latest]
58
+ python-version: ${{ fromJson(needs.resolve-python-versions.outputs.versions) }}
59
+ steps:
60
+ - uses: actions/checkout@v4
61
+
62
+ - name: Install uv
63
+ uses: astral-sh/setup-uv@v6
64
+ with:
65
+ python-version: ${{ matrix.python-version }}
66
+ cache-dependency-glob: pyproject.toml
67
+
68
+ - name: Install dependency environment (without fantasm itself)
69
+ # Sync all dev/test deps into the venv but skip installing the
70
+ # fantasm project. We install it from a freshly built wheel below
71
+ # so tests exercise the distribution artefact rather than the
72
+ # source tree.
73
+ run: uv sync --no-install-project
74
+
75
+ - name: Build wheel
76
+ run: uv build
77
+
78
+ - name: Install the built wheel into the test environment
79
+ # Force bash so dist/*.whl globs on Windows runners too (default
80
+ # pwsh does not glob the same way).
81
+ shell: bash
82
+ run: uv pip install dist/*.whl
83
+
84
+ - name: Run tests against the installed wheel
85
+ # --no-sync keeps the existing venv (with the wheel-installed
86
+ # fantasm) intact; without it `uv run` would re-sync and
87
+ # reinstate an editable install of the source tree, defeating
88
+ # the point. Confirmed locally that the test process imports
89
+ # fantasm from site-packages.
90
+ run: uv run --no-sync pytest -v
@@ -0,0 +1,59 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+
8
+ # Distribution / packaging
9
+ build/
10
+ dist/
11
+ *.egg-info/
12
+ *.egg
13
+ .eggs/
14
+ wheels/
15
+ share/python-wheels/
16
+
17
+ # Installer logs
18
+ pip-log.txt
19
+ pip-delete-this-directory.txt
20
+
21
+ # Unit test / coverage
22
+ .tox/
23
+ .nox/
24
+ .coverage
25
+ .coverage.*
26
+ .cache
27
+ htmlcov/
28
+ .pytest_cache/
29
+ .ruff_cache/
30
+ .mypy_cache/
31
+ .dmypy.json
32
+ dmypy.json
33
+
34
+ # Virtual environments
35
+ .venv/
36
+ venv/
37
+ env/
38
+ ENV/
39
+
40
+ # uv
41
+ .uv/
42
+ # Fantasm is a library as much as an application; consumers resolve
43
+ # their own dependency versions, so uv.lock stays out of git.
44
+ uv.lock
45
+
46
+ # Environments / secrets
47
+ .env
48
+ .env.*
49
+
50
+ # IDEs / editors
51
+ .idea/
52
+ .vscode/
53
+ *.swp
54
+ *.swo
55
+ .DS_Store
56
+
57
+ # Project-local scratch
58
+ scratch/
59
+ tmp/
@@ -0,0 +1,15 @@
1
+ repos:
2
+ - repo: local
3
+ hooks:
4
+ - id: generate-readme-check
5
+ name: README.md is in sync with the generator
6
+ entry: uv run python scripts/generate_readme.py --check
7
+ language: system
8
+ pass_filenames: false
9
+ files: |
10
+ (?x)^(
11
+ README\.md
12
+ | scripts/generate_readme\.py
13
+ | scripts/readme_template\.md\.j2
14
+ | src/fantasm/.*\.py
15
+ )$
@@ -0,0 +1,138 @@
1
+ # Fantasm — guidance for AI assistants
2
+
3
+ Project goal: consolidate 6502 disassembly tooling from four sibling
4
+ acornaeology repositories (`acorn-6502-tube-client`, `acorn-adfs`,
5
+ `acorn-econet-bridge`, `acorn-nfs`) into a single `fantasm` package with a
6
+ Click CLI and a programmatic `fantasm.api` package.
7
+
8
+ ## Layout
9
+
10
+ - `src/fantasm/` — package
11
+ - `src/fantasm/cli.py` — Click entrypoint, hierarchical sub-command groups
12
+ - `src/fantasm/api/` — programmatic API; flat re-exports from `__init__.py`
13
+ - `src/fantasm/config.py` — project-root resolution and `fantasm.toml` loading
14
+ - `tests/` — pytest suite with shared fixtures in `conftest.py`
15
+ - `docs/` — user/developer docs
16
+
17
+ ## Testing strategy
18
+
19
+ The original code being consolidated has **no tests**. As code is ported in
20
+ we add tests, but the approach is constrained by the recovery context:
21
+
22
+ - We cannot TDD pre-existing behaviour. Instead, write **characterisation
23
+ tests** that pin down current observable behaviour on representative
24
+ inputs. These are the safety net that lets us merge the four divergent
25
+ forks and refactor afterwards.
26
+ - Prefer small hand-crafted fixtures (a few bytes, a tiny `.asm` file) over
27
+ full ROM dumps — fast, reviewable, and easy to reason about.
28
+ - For modules that emit assembly source, write **round-trip tests** that
29
+ assemble the output with `beebasm` and compare the resulting bytes to the
30
+ original input.
31
+
32
+ See `docs/testing.md` for a fuller treatment.
33
+
34
+ ## README is generated, not hand-written
35
+
36
+ `README.md` is produced by `scripts/generate_readme.py` from a Jinja2
37
+ template at `scripts/readme_template.md.j2`. The generator imports
38
+ `fantasm.cli.main` and runs it via `click.testing.CliRunner` (inside
39
+ `isolated_filesystem`, with `COLUMNS=80` / `NO_COLOR=1` and
40
+ `FANTASM_PROJECT_ROOT` cleared) to capture deterministic `--help` text
41
+ and a sample `info` table.
42
+
43
+ ```bash
44
+ uv run python scripts/generate_readme.py # regenerate README.md
45
+ uv run python scripts/generate_readme.py --check # verify; prints diff + exits 1 on drift
46
+ ```
47
+
48
+ A pre-commit hook (`.pre-commit-config.yaml`) runs the `--check`
49
+ variant whenever `README.md`, the generator, the template, or any
50
+ `src/fantasm/*.py` changes — so editing the public CLI surface forces
51
+ a README regeneration before the commit lands. First-time setup in a
52
+ fresh clone:
53
+
54
+ ```bash
55
+ uv run pre-commit install
56
+ ```
57
+
58
+ A `readme-check` job in `.github/workflows/ci.yml` runs the same
59
+ `--check` on every push and PR as a safety net for contributors who
60
+ bypass the local hook. **Never hand-edit `README.md`** — edit the
61
+ template (or the generator, or the CLI source) and re-run the
62
+ generator.
63
+
64
+ ## External tooling assumed available
65
+
66
+ - **py8dis** (the disassembler that produces the JSON / ASM /
67
+ driver-script artefacts fantasm operates on) — a workflow
68
+ prerequisite, **not** a runtime dependency of fantasm. Users are
69
+ expected to have it installed in their development environment to
70
+ generate disassembly output; fantasm consumes the artefacts and
71
+ never imports the package. Currently a private fork at
72
+ https://github.com/acornaeology/py8dis; will eventually be
73
+ published on PyPI as `msabeeb`. Don't list it in `[project]
74
+ dependencies` — PyPI rejects direct git-URL deps and fantasm
75
+ doesn't actually link against it.
76
+ - **beebasm** (the BBC Micro 6502 cross-assembler) — assumed on `PATH`.
77
+ Tests obtain its location via the `beebasm_filepath` fixture in
78
+ `tests/conftest.py` and skip cleanly when it is absent.
79
+ - **uv** for dependency management. Use `uv sync` and `uv run`.
80
+
81
+ ## Project-root resolution
82
+
83
+ Three-step lookup, highest priority first:
84
+
85
+ 1. `--project-root` on the top-level `fantasm` group
86
+ 2. `FANTASM_PROJECT_ROOT` environment variable
87
+ 3. Walk upwards from cwd looking for `fantasm.toml`
88
+
89
+ Commands that need a project root should check `ctx.obj["project"].has_root`
90
+ and fail with a clear message if unresolved.
91
+
92
+ ## Output formatting
93
+
94
+ Commands that produce structured results use `asyoulikeit.report_output`,
95
+ which gives them a uniform `--as display|tsv|json` story. See
96
+ `src/fantasm/cli.py::info` for the canonical pattern. When a command needs
97
+ the Click context, use `click.get_current_context()` inside the body
98
+ rather than mixing `@click.pass_context` with `@report_output`.
99
+
100
+ ## Versioning and releases
101
+
102
+ Version is managed via `bump-my-version` (configured in `pyproject.toml`
103
+ under `[tool.bumpversion]`). The single source of truth is `__version__`
104
+ in `src/fantasm/__init__.py`; hatchling reads it dynamically via
105
+ `[tool.hatch.version]` and exposes it as the wheel's installed version.
106
+ Do not edit the version by hand in more than one place — let
107
+ `bump-my-version` update both the module and the
108
+ `[tool.bumpversion] current_version` copy in lock-step.
109
+
110
+ Release flow (on a clean working tree, from `master`):
111
+
112
+ ```bash
113
+ uv run bump-my-version bump --dry-run --verbose patch # preview
114
+ uv run bump-my-version bump patch # or `minor` / `major`
115
+ git push --follow-tags # publish commit + v<X.Y.Z> tag
116
+ ```
117
+
118
+ Each real bump produces one commit (`Bump version: X.Y.Z → X.Y.Z+1`) and
119
+ one annotated tag (`vX.Y.Z+1`). bump-my-version refuses to run with a
120
+ dirty tree — that is the intended safety net.
121
+
122
+ A `release.yml` workflow triggers on `v*` tags (the ones
123
+ `bump-my-version` produces) plus manual `workflow_dispatch`. Two
124
+ parallel gates — the full test matrix from `test.yml` and the
125
+ README-sync check from `readme-check.yml` — feed a single
126
+ `publish-pypi` job. Nothing is published unless **both** gates are
127
+ green. PyPI publication uses `uv publish` with `UV_PUBLISH_TOKEN`
128
+ from the `PYPI_TOKEN` repo secret, scoped to the `pypi` GitHub
129
+ deployment environment. To release: bump the version, push the
130
+ `v<X.Y.Z>` tag, watch the Actions UI. A failed publish can be
131
+ re-attempted via the **Run workflow** button.
132
+
133
+ ## Naming conventions
134
+
135
+ - Use `_filename`, `_filepath`, `_dirpath`, `_dirname` suffixes; avoid the
136
+ ambiguous `_dir` / `_file` suffixes.
137
+ - Keep code comments and commit messages free of references to specific AI
138
+ tools or model providers.
fantasm-0.1.2/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Robert Smallshire
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
fantasm-0.1.2/PKG-INFO ADDED
@@ -0,0 +1,201 @@
1
+ Metadata-Version: 2.4
2
+ Name: fantasm
3
+ Version: 0.1.2
4
+ Summary: Fantasm — the Fantastic (dis-/re-)Assembly tools for 6502 code
5
+ Author: Robert Smallshire
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: MacOS
12
+ Classifier: Operating System :: Microsoft :: Windows
13
+ Classifier: Operating System :: POSIX
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Software Development :: Disassemblers
18
+ Requires-Python: >=3.12
19
+ Requires-Dist: asyoulikeit>=0.1
20
+ Requires-Dist: click>=8.1
21
+ Requires-Dist: networkx>=3.0
22
+ Description-Content-Type: text/markdown
23
+
24
+ # Fantasm
25
+
26
+ The Fantastic (dis-/re-)Assembly tools for 6502 code, version `0.1.2`.
27
+
28
+ Fantasm is a consolidated suite of tools for working on annotated
29
+ disassemblies of 6502-based ROMs (originally those from the Acorn / BBC
30
+ Microcomputer family). It brings together capabilities that previously
31
+ lived in per-project forks under the `acornaeology` umbrella, behind a
32
+ single `fantasm` command and a programmatic `fantasm.api` package.
33
+
34
+ ## Status
35
+
36
+ Early scaffolding. The CLI shell is in place; the consolidation of
37
+ per-project tools into `fantasm` is in progress.
38
+
39
+ ## Install (development)
40
+
41
+ ```sh
42
+ uv sync
43
+ ```
44
+
45
+ ## CLI
46
+
47
+ ```console
48
+ $ fantasm --help
49
+ Usage: fantasm [OPTIONS] COMMAND [ARGS]...
50
+
51
+ Fantasm — the Fantastic (dis-/re-)Assembly tools for 6502 code.
52
+
53
+ Options:
54
+ --version Show the version and exit.
55
+ --project-root DIRECTORY Project root directory. Overrides
56
+ FANTASM_PROJECT_ROOT. If neither is given, fantasm
57
+ searches upwards from the current directory for a
58
+ fantasm.toml.
59
+ -h, --help Show this message and exit.
60
+
61
+ Commands:
62
+ addresses Address translation across ROM versions.
63
+ annotations Cross-version annotation diff and management.
64
+ asm Assembly-source extraction and inspection.
65
+ audit Subroutine annotation audit.
66
+ backfill Propose annotation propagations from SOURCE_VERSION to...
67
+ cfg Inter-procedural call-graph queries.
68
+ comments Comment / annotation consistency checks.
69
+ compare Compare two ROM versions at byte / opcode / full-instruction...
70
+ context Code context queries (depth, sub-context, uncommented gaps).
71
+ fingerprint Fingerprint each block of a ROM version's bytes and report...
72
+ info Show the resolved project context.
73
+ labels Auto-generated label classification and renaming.
74
+ lint Validate that a driver script's annotation addresses...
75
+ project Initialise and manage fantasm projects.
76
+ promote Score labelled code items as candidates for promotion to...
77
+ shared Find shared 6502 code fragments between a primary ROM and...
78
+ sub Subroutine workflow helpers.
79
+ verify Verify a disassembly round-trips: assemble its .asm with...
80
+ ```
81
+
82
+ The top-level `fantasm` command accepts a `--project-root` option and
83
+ also reads `FANTASM_PROJECT_ROOT` from the environment. When neither is
84
+ given, fantasm walks upwards from the current working directory looking
85
+ for a `fantasm.toml` to identify the project root.
86
+
87
+ ### `fantasm info`
88
+
89
+ The `info` sub-command shows the resolved project context for the
90
+ current invocation. Like every fantasm command that produces structured
91
+ output, it inherits a uniform `--as display | tsv | json` story (and
92
+ friends) from
93
+ [asyoulikeit](https://github.com/sixty-north/asyoulikeit):
94
+
95
+ ```console
96
+ $ fantasm info --help
97
+ Usage: fantasm info [OPTIONS]
98
+
99
+ Show the resolved project context.
100
+
101
+ Options:
102
+ Report Output Options:
103
+ --no-reports Suppress all report output. The handler still runs
104
+ (useful for action commands whose reports are
105
+ incidental); only rendering is skipped. Mutually
106
+ exclusive with --report and --all-reports.
107
+ --all-reports Render every report the handler returns,
108
+ regardless of the command's default_reports.
109
+ Useful for commands whose default is a subset (or
110
+ silent) but where you want the full picture this
111
+ time. Mutually exclusive with --report and --no-
112
+ reports.
113
+ --report [project] Report name(s) to display (can be specified
114
+ multiple times). Shows all if omitted. Valid
115
+ values: project.
116
+ --header / --no-header Include column headers in output. Overrides each
117
+ report's default. Format-specific: TSV prefixes
118
+ first cell with '#', display omits
119
+ headers/title/caption, JSON ignores this flag.
120
+ --detailed / --essential Include detailed columns or only essential
121
+ columns. Auto-detects based on output format if
122
+ not specified.
123
+ --as [display|json|tsv] Output format for tabular data. Defaults to
124
+ 'display' for terminals, 'tsv' for pipes.
125
+ -h, --help Show this message and exit.
126
+ ```
127
+
128
+ Sample output (an explicit project root that does not contain a
129
+ `fantasm.toml`):
130
+
131
+ ```console
132
+ $ fantasm --project-root /path/to/your/project info
133
+ Fantasm project
134
+ ┏━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┓
135
+ ┃ Key ┃ Value ┃
136
+ ┡━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━┩
137
+ │ project_root │ /path/to/your/project │
138
+ │ config_filepath │ (none) │
139
+ │ config_keys │ (empty) │
140
+ └─────────────────┴───────────────────────┘
141
+ Resolved project context for the current
142
+ invocation.
143
+ ```
144
+
145
+ The same invocation through a pipe (or with `--as tsv`) emits
146
+ tab-separated output suitable for downstream tooling:
147
+
148
+ ```console
149
+ $ fantasm --project-root /path/to/your/project info --as tsv
150
+ # Key Value
151
+ project_root /path/to/your/project
152
+ config_filepath (none)
153
+ config_keys (empty)
154
+ ```
155
+
156
+ ## Programmatic API
157
+
158
+ ```python
159
+ from fantasm.api import ... # surface filled in as modules are ported
160
+ ```
161
+
162
+ ## Testing
163
+
164
+ The codebase fantasm consolidates is untested. As modules are ported in,
165
+ fantasm adds **characterisation tests** that pin down observable
166
+ behaviour on representative inputs — these are the safety net for
167
+ merging the four upstream forks. Modules that emit 6502 assembly source
168
+ are exercised with **round-trip tests** that re-assemble the output with
169
+ `beebasm` and compare bytes; the `beebasm_filepath` pytest fixture skips
170
+ such tests when the assembler is not on `PATH`. See `docs/testing.md`
171
+ for the patterns and `CLAUDE.md` for the project-level guidance.
172
+
173
+ ## Layout
174
+
175
+ ```
176
+ src/fantasm/ the package
177
+ src/fantasm/cli.py Click entrypoint
178
+ src/fantasm/api/ programmatic API (re-exports the public surface)
179
+ src/fantasm/config.py project-root resolution + fantasm.toml loading
180
+ tests/ pytest suite (with shared fixtures in conftest.py)
181
+ docs/ user and developer documentation
182
+ scripts/ README generator + Jinja2 template
183
+ ```
184
+
185
+ ## Related projects
186
+
187
+ - [py8dis (fork)](https://github.com/acornaeology/py8dis) — the tracing
188
+ disassembler fantasm builds on top of (will eventually become
189
+ `msabeeb`).
190
+ - The four sibling repositories under `acornaeology` from which fantasm
191
+ draws its initial tooling: `acorn-6502-tube-client`, `acorn-adfs`,
192
+ `acorn-econet-bridge`, `acorn-nfs`.
193
+
194
+ ---
195
+
196
+ This README is generated from `scripts/readme_template.md.j2` by
197
+ `scripts/generate_readme.py`. **Do not edit it directly** — edit the
198
+ template (or the generator, or the source files whose output it
199
+ captures) and re-run `uv run python scripts/generate_readme.py`. The
200
+ pre-commit hook and the `readme-check` CI job both run the
201
+ generator's `--check` mode and will refuse stale READMEs.