Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 0 additions & 80 deletions CHANGELOG.md

This file was deleted.

96 changes: 96 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -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 <https://towncrier.readthedocs.io/>`_ — see
``upcoming_changes/README.rst``.

Versioning is `semver <https://semver.org/>`_ 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``.
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
67 changes: 66 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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} <https://github.com/directelectron/de-shell/pull/{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
4 changes: 4 additions & 0 deletions upcoming_changes/+towncrier.maintenance.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
The changelog is now assembled by `towncrier
<https://towncrier.readthedocs.io/>`_ 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``.
90 changes: 90 additions & 0 deletions upcoming_changes/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
Filing Change Log Entries
=========================

de-shell uses `towncrier <https://towncrier.readthedocs.io/>`_ 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
Loading