bcc_core.__version__ = "1.1.0" is now the single source of truth for the
app version (matches pyproject.toml). Nothing else hard-codes a version
string.
Added a real QMenuBar (Help menu) with About Better Claude Config….
AboutDialog shows: app icon (icons/twin-gears/rounded/icon-128.png),
app name, version, a short description, and (macOS only) a note that the
build isn't Apple-notarized.
Links (Repository, Issues, MIT License) are opened in the system browser
via QDesktopServices.openUrl — never in-app navigation. The license link
points at the raw LICENSE file on the repo. No secrets or file paths are
ever shown in this dialog.
bcc_core.parse_version() / is_newer_version(): pure, numeric (never
lexical) version comparison. Strips a leading v, drops pre-release/build
suffixes, zero-pads differing-length tuples, degrades gracefully on
malformed input instead of raising.
bcc_core.fetch_latest_release(): anonymous GET against the repo's public
Gitea releases API (.../releases/latest) — no token embedded or needed
since the repo is public. Fail-quiet: returns None on any network error,
timeout, bad status, or malformed response. Only ever reads release
metadata (tag + URL); never downloads or replaces the running binary.
UpdateCheckWorker (QThread, same pattern as ConnTester/SpawnTester)
runs the check off the UI thread.
"Check for updates" button in the About dialog reports "You're up to
date." or "vX.Y.Z available." with a button that opens the releases page.
Optional quiet startup auto-check: throttled to at most once/day via a QSettings timestamp, runs off-thread, silent on any failure, and can be
turned off via a checkbox in the About dialog (update/autoCheck in QSettings).
Tests
92 → 112 passing (+20). New coverage: __version__ sanity, parse_version
(basic / v-prefix / pre-release suffix / malformed / stops-at-non-numeric), is_newer_version (older / newer / equal / v-prefix / numeric-not-lexical /
differing-length / malformed candidate / malformed current), and fetch_latest_release (success, falls back to RELEASES_URL when no html_url, network failure, timeout, missing tag, malformed JSON) — all via monkeypatch.setattr(urllib.request, "urlopen", ...), no live network in
tests.
Verification
Ran ruff check ., ruff format --check ., and python -m pytest against
a fresh checkout of this branch (not just the working copy) — all green,
112 passed.
Notes / caveats
PySide6 wasn't installed in the sandbox (large download, would have blown
the tool timeout), so bcc.py was only syntax-checked (ast.parse) and
reviewed by hand, not import-tested under a display. bcc_core.py (where __version__, parse_version, is_newer_version, and fetch_latest_release all live) is fully unit-tested headlessly.
One unrelated fix folded into bcc_core.py: the existing _normalize_unicode non-breaking-space strip used a literal NBSP byte in
source, which some layers of this delivery pipeline silently mangled to a
bare space (turning the line into a no-op). Rewrote it as "\xa0" —
behavior-identical, just transmission-safe. Everything else in that
function (smart quotes, zero-width chars) was unaffected.
This branch was developed in a shared/concurrent worktree — a tests/test_core.py
timeout fix already landed on main from other work-in-progress (issue #12) partway through. This PR's diff is layered cleanly on top of that
(verified against main's actual current blob, not a stale local
checkout) and does not touch or revert it.
Closes #18
Closes #19
## #18 — About dialog
- `bcc_core.__version__ = "1.1.0"` is now the single source of truth for the
app version (matches `pyproject.toml`). Nothing else hard-codes a version
string.
- Added a real `QMenuBar` (`Help` menu) with `About Better Claude Config…`.
- `AboutDialog` shows: app icon (`icons/twin-gears/rounded/icon-128.png`),
app name, version, a short description, and (macOS only) a note that the
build isn't Apple-notarized.
- Links (Repository, Issues, MIT License) are opened in the system browser
via `QDesktopServices.openUrl` — never in-app navigation. The license link
points at the raw `LICENSE` file on the repo. No secrets or file paths are
ever shown in this dialog.
## #19 — update checker (notify-only)
- `bcc_core.parse_version()` / `is_newer_version()`: pure, numeric (never
lexical) version comparison. Strips a leading `v`, drops pre-release/build
suffixes, zero-pads differing-length tuples, degrades gracefully on
malformed input instead of raising.
- `bcc_core.fetch_latest_release()`: anonymous GET against the repo's public
Gitea releases API (`.../releases/latest`) — no token embedded or needed
since the repo is public. Fail-quiet: returns `None` on any network error,
timeout, bad status, or malformed response. Only ever reads release
metadata (tag + URL); **never downloads or replaces the running binary**.
- `UpdateCheckWorker` (`QThread`, same pattern as `ConnTester`/`SpawnTester`)
runs the check off the UI thread.
- "Check for updates" button in the About dialog reports "You're up to
date." or "vX.Y.Z available." with a button that opens the releases page.
- Optional quiet startup auto-check: throttled to at most once/day via a
`QSettings` timestamp, runs off-thread, silent on any failure, and can be
turned off via a checkbox in the About dialog (`update/autoCheck` in
`QSettings`).
## Tests
92 → 112 passing (+20). New coverage: `__version__` sanity, `parse_version`
(basic / v-prefix / pre-release suffix / malformed / stops-at-non-numeric),
`is_newer_version` (older / newer / equal / v-prefix / numeric-not-lexical /
differing-length / malformed candidate / malformed current), and
`fetch_latest_release` (success, falls back to `RELEASES_URL` when no
`html_url`, network failure, timeout, missing tag, malformed JSON) — all via
`monkeypatch.setattr(urllib.request, "urlopen", ...)`, **no live network in
tests**.
## Verification
Ran `ruff check .`, `ruff format --check .`, and `python -m pytest` against
a fresh checkout of this branch (not just the working copy) — all green,
112 passed.
## Notes / caveats
- PySide6 wasn't installed in the sandbox (large download, would have blown
the tool timeout), so `bcc.py` was only syntax-checked (`ast.parse`) and
reviewed by hand, not import-tested under a display. `bcc_core.py` (where
`__version__`, `parse_version`, `is_newer_version`, and
`fetch_latest_release` all live) is fully unit-tested headlessly.
- One unrelated fix folded into `bcc_core.py`: the existing
`_normalize_unicode` non-breaking-space strip used a literal NBSP byte in
source, which some layers of this delivery pipeline silently mangled to a
bare space (turning the line into a no-op). Rewrote it as `"\xa0"` —
behavior-identical, just transmission-safe. Everything else in that
function (smart quotes, zero-width chars) was unaffected.
- This branch was developed in a shared/concurrent worktree — a `tests/test_core.py`
timeout fix already landed on `main` from other work-in-progress (issue
#12) partway through. This PR's diff is layered cleanly on top of that
(verified against `main`'s actual current blob, not a stale local
checkout) and does not touch or revert it.
the_og
added the P1 label 2026-07-07 20:44:38 -04:00
- Add `__version__ = "1.1.0"` as the single source of truth (matches pyproject.toml).
- Add parse_version()/is_newer_version() for numeric (never lexical) version
comparison, handling v-prefix, pre-release suffixes, and malformed input.
- Add fetch_latest_release(): reads the public Gitea releases API
(anonymous, no token) and returns {version, url} or None on any failure.
Never downloads or touches a binary — metadata only.
- Add a real QMenuBar (Help -> About...).
- AboutDialog: app icon, name, version (core.__version__), and links to the
repo/issues/license opened via QDesktopServices.openUrl (system browser,
never in-app navigation). macOS unsigned-app note.
- "Check for updates" button + UpdateCheckWorker (QThread) runs
core.fetch_latest_release() off the UI thread; shows "up to date" or
"vX.Y.Z available" with a button to open the releases page. No binary
download, ever.
- Optional quiet startup auto-check, throttled to once/day via a QSettings
timestamp, off-thread, silent on failure, toggle lives in the About dialog.
All network calls are monkeypatched (urllib.request.urlopen) — no live
network in tests. Covers older/newer/equal comparisons, v-prefix,
differing-length tuples, malformed input on both sides, and
fetch_latest_release success/timeout/network-failure/malformed-response
paths.
Supervisor review (Cowork): approve. CI run #160 green; isolated diff. __version__ is the single source of truth (with a sync-guard test), version compare is numeric not lexical and handles malformed tags, and fetch_latest_release is fail-quiet + tokenless + metadata-only (no binary download). About dialog leaks no secrets/paths; startup auto-check is throttled once/day and disableable. Release-time note: at v1.2.0 cut, bump __version__ and pyproject.toml to 1.2.0 together and update test_dunder_version_matches_pyproject. Ready for v1.2.0.
Supervisor review (Cowork): **approve.** CI run #160 green; isolated diff. `__version__` is the single source of truth (with a sync-guard test), version compare is numeric not lexical and handles malformed tags, and `fetch_latest_release` is fail-quiet + tokenless + metadata-only (no binary download). About dialog leaks no secrets/paths; startup auto-check is throttled once/day and disableable. **Release-time note:** at v1.2.0 cut, bump `__version__` and `pyproject.toml` to `1.2.0` together and update `test_dunder_version_matches_pyproject`. Ready for v1.2.0.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #18
Closes #19
#18 — About dialog
bcc_core.__version__ = "1.1.0"is now the single source of truth for theapp version (matches
pyproject.toml). Nothing else hard-codes a versionstring.
QMenuBar(Helpmenu) withAbout Better Claude Config….AboutDialogshows: app icon (icons/twin-gears/rounded/icon-128.png),app name, version, a short description, and (macOS only) a note that the
build isn't Apple-notarized.
via
QDesktopServices.openUrl— never in-app navigation. The license linkpoints at the raw
LICENSEfile on the repo. No secrets or file paths areever shown in this dialog.
#19 — update checker (notify-only)
bcc_core.parse_version()/is_newer_version(): pure, numeric (neverlexical) version comparison. Strips a leading
v, drops pre-release/buildsuffixes, zero-pads differing-length tuples, degrades gracefully on
malformed input instead of raising.
bcc_core.fetch_latest_release(): anonymous GET against the repo's publicGitea releases API (
.../releases/latest) — no token embedded or neededsince the repo is public. Fail-quiet: returns
Noneon any network error,timeout, bad status, or malformed response. Only ever reads release
metadata (tag + URL); never downloads or replaces the running binary.
UpdateCheckWorker(QThread, same pattern asConnTester/SpawnTester)runs the check off the UI thread.
date." or "vX.Y.Z available." with a button that opens the releases page.
QSettingstimestamp, runs off-thread, silent on any failure, and can beturned off via a checkbox in the About dialog (
update/autoCheckinQSettings).Tests
92 → 112 passing (+20). New coverage:
__version__sanity,parse_version(basic / v-prefix / pre-release suffix / malformed / stops-at-non-numeric),
is_newer_version(older / newer / equal / v-prefix / numeric-not-lexical /differing-length / malformed candidate / malformed current), and
fetch_latest_release(success, falls back toRELEASES_URLwhen nohtml_url, network failure, timeout, missing tag, malformed JSON) — all viamonkeypatch.setattr(urllib.request, "urlopen", ...), no live network intests.
Verification
Ran
ruff check .,ruff format --check ., andpython -m pytestagainsta fresh checkout of this branch (not just the working copy) — all green,
112 passed.
Notes / caveats
the tool timeout), so
bcc.pywas only syntax-checked (ast.parse) andreviewed by hand, not import-tested under a display.
bcc_core.py(where__version__,parse_version,is_newer_version, andfetch_latest_releaseall live) is fully unit-tested headlessly.bcc_core.py: the existing_normalize_unicodenon-breaking-space strip used a literal NBSP byte insource, which some layers of this delivery pipeline silently mangled to a
bare space (turning the line into a no-op). Rewrote it as
"\xa0"—behavior-identical, just transmission-safe. Everything else in that
function (smart quotes, zero-width chars) was unaffected.
tests/test_core.pytimeout fix already landed on
mainfrom other work-in-progress (issue#12) partway through. This PR's diff is layered cleanly on top of that
(verified against
main's actual current blob, not a stale localcheckout) and does not touch or revert it.
- Add `__version__ = "1.1.0"` as the single source of truth (matches pyproject.toml). - Add parse_version()/is_newer_version() for numeric (never lexical) version comparison, handling v-prefix, pre-release suffixes, and malformed input. - Add fetch_latest_release(): reads the public Gitea releases API (anonymous, no token) and returns {version, url} or None on any failure. Never downloads or touches a binary — metadata only.Supervisor review (Cowork): approve. CI run #160 green; isolated diff.
__version__is the single source of truth (with a sync-guard test), version compare is numeric not lexical and handles malformed tags, andfetch_latest_releaseis fail-quiet + tokenless + metadata-only (no binary download). About dialog leaks no secrets/paths; startup auto-check is throttled once/day and disableable. Release-time note: at v1.2.0 cut, bump__version__andpyproject.tomlto1.2.0together and updatetest_dunder_version_matches_pyproject. Ready for v1.2.0.Superseded by #26 (release: v1.2.0), which merged this change into
mainas part of the integrated release. Closing.Pull request closed