diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 7103a53..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,80 +0,0 @@ -# Changelog - -All notable changes to `de-shell`. The format follows -[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), the versioning is -[semver](https://semver.org/) with the 0.x caveat: a breaking change to the -sidecar protocol bumps the minor. - -## [Unreleased] - -## [0.2.2] - 2026-09-22 - -### Added -- `FigureView.add_rectangle_widget`: a draggable rectangle with an optional - `max_extent` size cap; `on_change(x, y, w, h)` fires when a drag settles. -- `FigureView.add_texts`: text labels at image-pixel positions, with an - optional halo; the same `name` replaces them in place. -- `FigureView.set_readout_visible` and `FigureFrame`'s `onReadout`: every - figure frame relays anyplotlib's hover readout to the host page, so an app - can hide the on-image pill and print the position and value in its own units. - -### Changed -- anyplotlib floor raised to 0.10.0, for the readout event and text halos. - -## [0.2.1] - 2026-09-02 - -Ground Crew's shell work from after the merge base, so it can move onto the -package too. - -### Added -- `createStdoutDemux` (main): the sidecar's stdout demuxer as a chunk-list - accumulator that copies each byte once. The inline parser re-copied the - whole buffered prefix per chunk, O(N^2/chunkSize) while a large frame - streamed in (11.9 s per 64 MB frame at 64 KiB chunks). A malformed - `PLOTAPP:` line is now reported on stderr rather than swallowed. -- `createSizeReporter` (renderer): `FigureFrame` skips the zero-size first - layout and any resize whose rounded size is unchanged, and holds its - `onResize` in a ref so an inline callback no longer re-runs the effect - (measured at ~1,500 sends/s over constant geometry before). -- `attachFigure` (renderer): figure registration is owned by an effect and - re-registers on every run, so React StrictMode's double-invoke no longer - leaves a figure registered nowhere with its pane black. -- `PIN_SCROLL`: every figure document undoes the focus-scroll that shifted a - fresh pane by half its overflow on first hover. - -### Changed -- anyplotlib floor raised to 0.8.0, for its fix to a tiled image born on a - placeholder rendering solid black. - -## [0.2.0] — 2026-09-02 - -The first release as its own package. Until now the shell lived as a vendored -copy inside each of SpyDE, Ground Crew and Autopilot, and the three had -diverged. - -### Added -- **One package.** The TypeScript half (`de_shell/js`: the Electron main - process, the preload bridge, the React renderer kernel, the Playwright - harness) ships inside the wheel, so `pip install -U de-shell` moves both - halves of the sidecar protocol together. `python -m de_shell.js` prints where - the tree is; apps link it into their Electron project. -- From SpyDE 0.4.3: the problem reporter (`errorReport`, `problemLog`, - `sentryEnvelope`), `recentBackendOutput`, workspace-member wheels in the - environment setup, an update handoff that tree-kills the sidecar first, - `run_on_worker`'s in-flight count and `ComputeHandle` for cancelling a - superseded compute. -- From Ground Crew: the sidecar spawn-error trap, a 5 s tree-kill grace, a - resolved `uv` path, the open-directory dialog channel, `_pin_tile_band` for - large stills, JSON emit that never writes bare `NaN`, harness hardening, and - the unit tests for all of it. -- From Autopilot: the close handler forgets only its own child process, a - report for malformed protocol messages, `useFigureEventForwarding`, and a - `LOG_CLEAR` action in the renderer state. - -### Changed -- License: MIT (the vendored copies were GPL-3.0-or-later inside SpyDE). -- Line endings are LF throughout, enforced by `.gitattributes`. - -[Unreleased]: https://github.com/directelectron/de-shell/compare/v0.2.1...HEAD -[0.2.1]: https://github.com/directelectron/de-shell/releases/tag/v0.2.1 -[0.2.0]: https://github.com/directelectron/de-shell/releases/tag/v0.2.0 diff --git a/CHANGELOG.rst b/CHANGELOG.rst new file mode 100644 index 0000000..b77276d --- /dev/null +++ b/CHANGELOG.rst @@ -0,0 +1,96 @@ +========= +Changelog +========= + +All notable changes to ``de-shell`` are recorded here. Entries are written per +pull request as fragment files under ``upcoming_changes/`` and assembled at +release time by `towncrier `_ — see +``upcoming_changes/README.rst``. + +Versioning is `semver `_ with the 0.x caveat: a breaking +change to the sidecar protocol bumps the minor. + +.. towncrier release notes start + +0.2.2 (2026-09-22) +================== + +New Features +------------ + +- ``FigureView.add_rectangle_widget``: a draggable rectangle with an optional + ``max_extent`` size cap; ``on_change(x, y, w, h)`` fires when a drag settles. +- ``FigureView.add_texts``: text labels at image-pixel positions, with an + optional halo; the same ``name`` replaces them in place. +- ``FigureView.set_readout_visible`` and ``FigureFrame``'s ``onReadout``: every + figure frame relays anyplotlib's hover readout to the host page, so an app + can hide the on-image pill and print the position and value in its own units. + +API and Behaviour Changes +------------------------- + +- anyplotlib floor raised to 0.10.0, for the readout event and text halos. + +0.2.1 (2026-09-02) +================== + +Ground Crew's shell work from after the merge base, so it can move onto the +package too. + +New Features +------------ + +- ``createStdoutDemux`` (main): the sidecar's stdout demuxer as a chunk-list + accumulator that copies each byte once. The inline parser re-copied the whole + buffered prefix per chunk, O(N^2/chunkSize) while a large frame streamed in + (11.9 s per 64 MB frame at 64 KiB chunks). A malformed ``PLOTAPP:`` line is + now reported on stderr rather than swallowed. +- ``createSizeReporter`` (renderer): ``FigureFrame`` skips the zero-size first + layout and any resize whose rounded size is unchanged, and holds its + ``onResize`` in a ref so an inline callback no longer re-runs the effect + (measured at ~1,500 sends/s over constant geometry before). +- ``attachFigure`` (renderer): figure registration is owned by an effect and + re-registers on every run, so React StrictMode's double-invoke no longer + leaves a figure registered nowhere with its pane black. +- ``PIN_SCROLL``: every figure document undoes the focus-scroll that shifted a + fresh pane by half its overflow on first hover. + +API and Behaviour Changes +------------------------- + +- anyplotlib floor raised to 0.8.0, for its fix to a tiled image born on a + placeholder rendering solid black. + +0.2.0 (2026-09-02) +================== + +The first release as its own package. Until now the shell lived as a vendored +copy inside each of SpyDE, Ground Crew and Autopilot, and the three had +diverged. + +New Features +------------ + +- **One package.** The TypeScript half (``de_shell/js``: the Electron main + process, the preload bridge, the React renderer kernel, the Playwright + harness) ships inside the wheel, so ``pip install -U de-shell`` moves both + halves of the sidecar protocol together. ``python -m de_shell.js`` prints + where the tree is; apps link it into their Electron project. +- From SpyDE 0.4.3: the problem reporter (``errorReport``, ``problemLog``, + ``sentryEnvelope``), ``recentBackendOutput``, workspace-member wheels in the + environment setup, an update handoff that tree-kills the sidecar first, + ``run_on_worker``'s in-flight count and ``ComputeHandle`` for cancelling a + superseded compute. +- From Ground Crew: the sidecar spawn-error trap, a 5 s tree-kill grace, a + resolved ``uv`` path, the open-directory dialog channel, ``_pin_tile_band`` + for large stills, JSON emit that never writes bare ``NaN``, harness + hardening, and the unit tests for all of it. +- From Autopilot: the close handler forgets only its own child process, a + report for malformed protocol messages, ``useFigureEventForwarding``, and a + ``LOG_CLEAR`` action in the renderer state. + +API and Behaviour Changes +------------------------- + +- License: MIT (the vendored copies were GPL-3.0-or-later inside SpyDE). +- Line endings are LF throughout, enforced by ``.gitattributes``. diff --git a/README.md b/README.md index e01573c..cfb9335 100644 --- a/README.md +++ b/README.md @@ -115,7 +115,12 @@ tests, and builds the wheel and checks what it carries. The version is written once, in `de_shell/__init__.py`. To release: -1. Bump `__version__`, move the `CHANGELOG.md` entries under the new version. +1. Bump `__version__`, then assemble the changelog from the pull requests' + news fragments: `uv tool run towncrier build --version X.Y.Z`. That writes the new + section into `CHANGELOG.rst` and deletes the fragments it consumed, so stage + `upcoming_changes/` with `git add -A` — a plain `git add CHANGELOG.rst` + leaves the deletions behind and the next release re-publishes them. Preview + with `--draft` first; it consumes nothing. 2. Commit, tag `vX.Y.Z`, push the tag. `.github/workflows/publish.yml` builds the distributions, refuses a tag that @@ -156,6 +161,9 @@ SpyDE commit the app copies were taken from: * **The protocol is the contract.** `PLOTAPP:` JSON lines and `PLOTBIN:` binary frames over the sidecar's stdio. Both halves of it live in this one package on purpose; keep it that way. +* **Every pull request carries its own changelog entry**, as a news fragment + under [`upcoming_changes/`](upcoming_changes/README.rst) — one file per PR, + so two of them never conflict over the same lines of `CHANGELOG.rst`. * **LF line endings**, enforced by `.gitattributes`. ## License diff --git a/pyproject.toml b/pyproject.toml index 502d3b1..ca6c7d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,7 +59,7 @@ tests = [ Homepage = "https://github.com/directelectron/de-shell" Repository = "https://github.com/directelectron/de-shell" Issues = "https://github.com/directelectron/de-shell/issues" -Changelog = "https://github.com/directelectron/de-shell/blob/main/CHANGELOG.md" +Changelog = "https://github.com/directelectron/de-shell/blob/main/CHANGELOG.rst" # One version, in one place: de_shell.__version__. The release workflow refuses # a tag that does not match it. @@ -90,3 +90,68 @@ de_shell = [ [tool.pytest.ini_options] testpaths = ["tests"] timeout = 120 + +# --------------------------------------------------------------------------- +# Changelog management (towncrier) +# --------------------------------------------------------------------------- +# towncrier assembles CHANGELOG.rst from one fragment file per PR, written while +# the change is fresh. The alternative — deriving notes from commit subjects at +# release time — reads like a commit log, because that is what it is: it cannot +# say what a change means to an app upgrading, only what the author was doing. +# It also stops two pull requests conflicting over the same few changelog lines. +# +# `package` is set: this repo's version of record IS de_shell.__version__ (the +# publish workflow refuses a tag that disagrees with it), so towncrier can read +# the version itself and `--version` is only needed to build notes for a bump +# that has not been written yet. See upcoming_changes/README.rst. +[tool.towncrier] +package = "de_shell" +package_dir = "." +directory = "upcoming_changes" +filename = "CHANGELOG.rst" +start_string = ".. towncrier release notes start\n" +issue_format = "`#{issue} `_" +title_format = "{version} ({project_date})" +underlines = ["=", "-", "~"] + +# Behaviour changes lead the notes: they are the entries an app upgrading has +# to ACT on, and they are easy to miss filed under "Bug Fixes". +[[tool.towncrier.type]] +directory = "api_change" +name = "API and Behaviour Changes" +showcontent = true + +[[tool.towncrier.type]] +directory = "new_feature" +name = "New Features" +showcontent = true + +[[tool.towncrier.type]] +directory = "bugfix" +name = "Bug Fixes" +showcontent = true + +[[tool.towncrier.type]] +directory = "performance" +name = "Performance" +showcontent = true + +[[tool.towncrier.type]] +directory = "deprecation" +name = "Deprecations" +showcontent = true + +[[tool.towncrier.type]] +directory = "removal" +name = "Removals" +showcontent = true + +[[tool.towncrier.type]] +directory = "doc" +name = "Documentation" +showcontent = true + +[[tool.towncrier.type]] +directory = "maintenance" +name = "Maintenance" +showcontent = true diff --git a/upcoming_changes/+towncrier.maintenance.rst b/upcoming_changes/+towncrier.maintenance.rst new file mode 100644 index 0000000..d142367 --- /dev/null +++ b/upcoming_changes/+towncrier.maintenance.rst @@ -0,0 +1,4 @@ +The changelog is now assembled by `towncrier +`_ from one news fragment per pull request +under ``upcoming_changes/``, as SpyDE and anyplotlib already do, and lives in +``CHANGELOG.rst`` rather than ``CHANGELOG.md``. diff --git a/upcoming_changes/README.rst b/upcoming_changes/README.rst new file mode 100644 index 0000000..7a4d0e3 --- /dev/null +++ b/upcoming_changes/README.rst @@ -0,0 +1,90 @@ +Filing Change Log Entries +========================= + +de-shell uses `towncrier `_ to assemble +``CHANGELOG.rst``. When you open a pull request that should appear in the next +release notes, add a short news **fragment file** to this directory as part of +that PR. + +Writing the entry with the change — rather than deriving notes from commit +subjects at release time — is the whole point. A commit subject says what the +author was doing; a release note has to say what the change means to someone +upgrading, and only the author knows that. It also keeps two pull requests from +conflicting over the same few lines of a shared changelog: one fragment per PR, +no shared file to edit. + +Who the reader is +----------------- + +de-shell's users are the **apps** — SpyDE, Ground Crew, Autopilot — and the +people building them. Write for someone pinning a new ``de-shell`` and asking +what they get and what they have to change. Both halves of the package count: +the Python sidecar API and the TypeScript in ``de_shell/js`` (main, preload, +renderer, the Playwright harness). + +Naming convention +----------------- + +Each fragment is a plain ``.rst`` file named:: + + {PR_number}.{type}.rst + +If the change has no natural PR number (work batched on a long-lived feature +branch), name it ``+{slug}.{type}.rst`` — the leading ``+`` marks it an +"orphan" so towncrier omits the issue link. Without it the slug renders as a +broken PR link. + +================= ============================================================== +Type Use when … +================= ============================================================== +``api_change`` Existing behaviour changed in a way an app has to act on — a + signature, a default, a protocol message, an anyplotlib + floor. Use this even when the change is a *fix*: what + matters to someone upgrading is that the old behaviour is + gone, and that is easy to miss under ``bugfix``. +``new_feature`` A user-visible capability has been added. +``bugfix`` A bug has been fixed. +``performance`` Something measurably got faster or lighter. Quote the number + — "11.9 s to 40 ms per 64 MB frame" is a release note; + "improved performance" is not. +``deprecation`` Something is deprecated and will be removed later. +``removal`` A previously deprecated API has been removed. +``doc`` Documentation improved with no code change. +``maintenance`` Internal / infrastructure change invisible to the apps. +================= ============================================================== + +Content guidelines +------------------ + +* **One sentence per file**, in the **past tense**, from the *app's* + perspective — not the implementer's. +* Say what changed for them, not which function you edited. "The packaged + sidecar no longer holds the install directory open" beats "changed ``cwd`` in + ``resolvePythonEnv``". +* Do **not** put the PR number in the sentence; towncrier appends the link. + +Examples +-------- + +``12.bugfix.rst``:: + + A figure opened on a zero-size pane stayed black until the window was + resized. + +``13.performance.rst``:: + + The sidecar's stdout demuxer copies each byte once instead of re-copying + the buffered prefix per chunk — 11.9 s to 40 ms for a 64 MB frame at + 64 KiB chunks. + +Building +-------- + +There is no Prepare Release workflow here; the changelog is assembled by hand +as step 1 of `Releasing <../README.md#releasing>`_:: + + uv tool run towncrier build --version X.Y.Z + +To preview without consuming the fragments:: + + uv tool run towncrier build --draft --version X.Y.Z