Releases: awizemann/GitTickets
Release list
GitTickets 2.5.0
Additive minor. Fixes a privacy defect introduced in 2.4.0, and adds an
adopter opt-out for screenshot capture. All three items were reported by an
adopter against 2.4.0.
Adopters on 2.4.0 should upgrade.
No public API removed or changed in signature. Platform floor unchanged at
macOS 14 / iOS 18. An existing upToNextMajorVersion pin from 2.x resolves
to this release automatically.
Fixed:
- The form's screenshot captured the WHOLE DISPLAY, not just the host app.
2.4.0 used SCContentFilter(display:excludingWindows:), which is the entire
display minus one window — every other running application, the desktop,
anything on screen — while the docs promised "the app behind the form".
On a public repository that means another app's content could be attached
to an issue. The filter is now scoped to the host process's own
applications via SCContentFilter(display:including:exceptingWindows:).
Verified against real ScreenCaptureKit output, not reasoned about: the
capture contains the host window and nothing else. See
Harnesses/RefreshAffordance —cd Harnesses/RefreshAffordancethen
swift run ScreenshotScope. - A race could exclude the wrong window. The report window was identified
AFTERawait SCShareableContent…; if focus moved while that call was in
flight, the wrong window was excluded, capturing the form and hiding what
the user meant to show. It is now read before the first await.
Added:
- PrivacyPolicy.allowsScreenshotCapture, default true so existing adopters
see no change. Set false to remove the "Add screenshot" control entirely.
Pinning an old version was previously the only way for an adopter to
promise users the SDK would never photograph their screen, and a pin is a
bad place to keep a privacy guarantee — it expires silently the first time
someone bumps the dependency. Manual image attachment is unaffected. - ScreenshotCapture.captureExcludingReporter() is now public. Hosts with
their own reporting UI hit the identical problem: capture() while their
sheet is up photographs the sheet. On macOS it also scopes the capture to
the host application's windows. - ScreenshotCapture.diagnosticMessage(for:) is now public, for hosts logging
their own capture failures.
Unchanged:
- ScreenshotCapture.capture() still captures everything on screen. It is for
capturing BEFORE presenting a reporting surface. - The SDK still never captures without a direct user action, and a failed
capture never blocks submission.
Verified before tagging:
- Local: swift build 0 warnings; swift test 319 executed, 0 failures.
- CI run 30233193246 on e278469, both jobs green:
macOS 319 executed / 6 skipped / 0 failures;
iOS 307 executed / 30 skipped / 0 failures.
Full changelog: https://github.com/awizemann/GitTickets/blob/main/CHANGELOG.md
GitTickets 2.4.0
Additive minor. The built-in report form can finally add a screenshot.
No public API removed or changed in signature. Platform floor unchanged at
macOS 14 / iOS 18. An existing upToNextMajorVersion pin from 2.x resolves
to this release automatically.
Added:
- An "Add screenshot" button in the form, beside "Add image".
GitTicketsView already held the screenshot state, rendered a thumbnail
for it, offered Remove and submitted it — but the state was only ever
assigned nil and no control existed to set it. The feature was present
everywhere except where a user could reach it. - It captures the app BEHIND the form, not the form. A naive wiring would
have been worse than none: macOS captures the whole display and iOS
renders the key window, so the user taps it to show us a problem and
gets a picture of the form covering that problem. macOS excludes the
report window from the ScreenCaptureKit content filter; iOS renders the
root view rather than the window, since a modally presented form lives
in a sibling transition view.
Unchanged:
- Public ScreenshotCapture.capture() still captures everything on screen.
It is for hosts capturing BEFORE they present their own reporting UI,
which is how existing adopters use it.
Behavior:
- A failed capture never blocks submission. One informational line points
at manual image attachment and the form carries on. A missing Screen
Recording permission on macOS is treated as a shrug rather than an
incident: the SDK does not ask for the permission, and the user-facing
copy does not mention permissions or send anyone to System Settings. The
real cause is logged through Configuration.logger at .info, because the
adopter needs it and the user does not.
Verified before tagging:
- Local: swift build 0 warnings; swift test 315 executed, 0 failures.
- CI run 30231115307 on ba0413f, both jobs green:
macOS 315 executed / 6 skipped / 0 failures;
iOS 303 executed / 30 skipped / 0 failures.
Full changelog: https://github.com/awizemann/GitTickets/blob/main/CHANGELOG.md
GitTickets 2.3.1
Patch. Fixes both halves of how "My Reports" handled submissions that do
not come back — one half lied, the other stayed silent.
No public API added, removed, or changed in signature. Platform floor
unchanged at macOS 14 / iOS 18. An existing upToNextMajorVersion pin from
2.x resolves to this release automatically.
Fixed:
- The "reports not showing up" state claimed a cause the SDK cannot know.
Issues are found by label, so one is absent from the result whether it
was DELETED or merely lost its label, and those are indistinguishable
without a per-issue existence probe the backend does not expose. 2.3.0
told a user whose issues had been deleted that they "haven't been lost"
and to try again. The screen now states only what is known, offers both
explanations, and does not imply the situation is temporary. - The .warning log names deletion FIRST, so an adopter rules that out
before chasing label permissions. - A partial shortfall was invisible. With 3 reports filed and 1 missing,
the screen rendered an ordinary list of 2 and said nothing — the missing
one looked exactly like one never filed. Only a total miss got a state,
which made the threshold arbitrary: 3-of-3 took over the screen, 2-of-3
was silent. There is now a non-blocking inline notice above the list.
Deliberately not the full-screen state: a deleted issue produces a
partial shortfall legitimately.
MyIssuesRefresh.allMissing is unchanged in behavior. It reports THAT
nothing came back, which is still worth distinguishing from an empty
history; it never reported WHY, and now nothing claims it does. Its
documentation no longer calls it "almost always a configuration fault".
Closed issues were never a cause and still are not — the backend lists
with state=all.
Verified before tagging:
- Local: swift build 0 warnings; swift test 311 executed, 0 failures.
- CI run 30226965672 on 7d0fb5a, both jobs green:
macOS 311 executed / 6 skipped / 0 failures;
iOS 299 executed / 30 skipped / 0 failures.
Full changelog: https://github.com/awizemann/GitTickets/blob/main/CHANGELOG.md
GitTickets 2.3.0
Additive minor. Closes a silent-failure path in "My Reports" reported by
the ShabuBox integration.
No public API removed or changed in signature. Platform floor unchanged at
macOS 14 / iOS 18. An existing upToNextMajorVersion pin from 2.x resolves
to this release automatically.
Fixed:
- "My Reports" could go permanently empty with no error. The screen narrows
twice: the backend lists issues carrying the configured label, then
matches embedded submission-ID markers against the requested IDs. An
issue whose label was never applied, or was removed later, fails the
first narrowing and can never match the second. The backend answers 200
with zero matches, so the view showed "No reports yet" while the reports
still existed on GitHub. - SubmittedIssue.missingLabels catches this at submit time and still does,
but cannot see a label removed in bulk, a changed backend label, or a
swapped repo — cases where nobody files anything new yet every past
report disappears. Comparing requested against returned catches all. - A refresh no longer blanks the list to a spinner. The three triggers
added in 2.2.0 all called reload(), which dropped to .loading every
time and flickered on an interval when polling was enabled.
Added:
- MyIssuesRefresh (issues, requestedCount, unmatchedCount, allMissing) and
GitTickets.refreshMyIssuesDetailed(). refreshMyIssues() is unchanged and
delegates to it, so nothing is required of existing adopters. - Shortfall logging via Configuration.logger at two severities: a total
miss at .warning naming the label and likely causes, a partial miss at
.info, since a deleted issue produces a partial miss legitimately. - A distinct "Can't find your reports" state, shown only when cached
submissions exist but none came back. - GitTicketsMyIssuesView(loadDetailed:) for hosts with their own loader.
requestedCount == 0 is deliberately not a fault — a device that has filed
nothing has nothing to show.
Verified before tagging:
- Local: swift build 0 warnings; swift test 306 executed, 0 failures.
- CI run 30221091919 on 09080e2, both jobs green:
macOS 306 executed / 6 skipped / 0 failures;
iOS 294 executed / 30 skipped / 0 failures.
Full changelog: https://github.com/awizemann/GitTickets/blob/main/CHANGELOG.md
GitTickets 2.2.0
Additive minor. Fixes a macOS gap where an open "My Reports" or Issue
Detail window could not be refreshed at all.
No public API removed or changed in signature. Platform floor unchanged at
macOS 14 / iOS 18. An existing upToNextMajorVersion pin from 2.x resolves
to this release automatically.
Fixed:
ScrollView { }.refreshable { }installs nothing on macOS — the AppKit
hierarchy is identical to applying no modifier and the refresh
environment action is not even propagated. Both screens used that
construction, so closing and reopening the window (re-running .task) was
the only way to see a new report or reply. Measured against the shipped
views; the harnesses are kept under Harnesses/.- iOS was never affected: .refreshable does install a UIRefreshControl on
a plain ScrollView there. Pull-to-refresh is unchanged.
Added:
- Toolbar Refresh control with a Command-R shortcut and an accessibility
label — the only affordance a macOS user can reach directly. - Automatic re-fetch when the scene becomes active again. The first
activation is ignored, since the screen's own .task has already loaded. - Harnesses/RefreshAffordance: re-runnable proof of the platform behavior
on both macOS and iOS.
Changed:
- MyIssuesPolicy.pollInterval now drives a re-fetch loop. It has been
public since Phase 2 but nothing read it. Default stays 0 (off), so
adopters on defaults see no new network traffic; a negative value is
treated as 0 rather than spinning.
Also corrects two doc comments that described behavior that did not exist:
GitTicketsMyIssuesView claimed the .refreshable gesture worked on macOS,
and pollInterval claimed a Command-R shortcut nothing implemented.
Verified before tagging:
- Local: swift build 0 warnings; swift test 301 executed, 0 failures.
- CI run 30220693396 on b2f4d3b, both jobs green:
macOS 301 executed / 6 skipped / 0 failures;
iOS 289 executed / 30 skipped / 0 failures.
Full changelog: https://github.com/awizemann/GitTickets/blob/main/CHANGELOG.md
GitTickets 2.1.0
Additive minor driven by the ShabuBox integration — a privacy-first macOS
document vault whose in-app reports file to a public repository.
No public API removed or changed in signature. Platform floor unchanged at
macOS 14 / iOS 18. An existing upToNextMajorVersion pin from 2.0.0 resolves
to this release automatically.
Added:
- PrivacyPolicy.attachmentNames (.generic) keeps user filenames out of
public issue bodies. - SharedSecret(infoPlistKey:encoding:bundle:) loads the relay secret from
the bundle instead of a source literal. Keeps it out of git, not out of
an attacker's hands. - DiagnosticsRedactor.recommended exposes the ordered built-in set.
- Full-size preview of a pending attachment before an irreversible public
submission.
Changed:
- DiagnosticsRedactor.absolutePath is in the default redactor array, so
adopters on defaults will see absolute paths — including the trailing
filename — replaced with [path redacted]. Opt out with an explicit array.
Fixed:
- SharedSecret(hex:) and (base64:) rejected degenerate input that had
produced a usable-but-wrong HMAC key since 1.x. - Attachment link text can no longer break out of its markdown link via
newlines in a filename.
Verified before tagging:
- Local: swift build 0 warnings; swift test 290 executed, 0 failures.
- CI run 30214507209 on 0041739, both jobs green:
macOS 290 executed / 6 skipped / 0 failures;
iOS 278 executed / 30 skipped / 0 failures.
Full changelog: https://github.com/awizemann/GitTickets/blob/main/CHANGELOG.md
GitTickets 2.0.0
Breaking release: the supported-platform floor moves to macOS 14 (Sonoma)
and iOS 18. On iOS this drops two releases — 17 is excluded as well as 16.
No public API was removed, renamed, or changed in signature; the major
version is driven entirely by the platform floor.
Removed
- The OneShotStream macOS 13 screenshot fallback (net -90 lines). This was
dead-code deletion: the capture path already called
SCScreenshotManager.captureImage behind an availability check with the
identical filter and configuration, so every macOS 14+ user was already
on that path. Its removal also deletes the Swift 6.0 actor-isolation
error that had kept CI red. - 62 @available annotations that became no-ops at the new floor. Zero
executable lines changed; API stability checked with swift-api-digester.
Changed
- CI retargeted to macos-15 with Xcode pinned to 26.3 (was latest-stable,
which silently moved the compiler and is how the Swift 6.0 breakage went
unnoticed). Snapshot tests now skip on CI, where their baselines cannot
be machine-portable.
Toolchain
- Verified green on CI with Xcode 26.3 on macos-15: macOS 210 tests
executed / 6 skipped, iOS 198 executed / 30 skipped, with the iOS job
resolving a real iOS 18.6 simulator. Built and tested locally on
Xcode 26.6 / Swift 6.3.3. - NO minimum Xcode version is claimed. Older toolchains are untested in
both directions. The v1.1.0 tag asserted a Swift 6.0 / Xcode 16+ floor
that was never verified and was false; this release states what was
actually built and run instead.
Upgrading
- A upToNextMajorVersion pin from 1.x resolves [1.0.0, 2.0.0) and will NOT
pick this up. Change the requirement to 2.0.0 deliberately. - Still below macOS 14 / iOS 18? Pin 1.0.0.
Relay templates version independently and are unchanged at
relay-vercel-v1.0.0 / relay-cloudflare-v1.0.0.
Full changelog: https://github.com/awizemann/GitTickets/blob/main/CHANGELOG.md
GitTickets 1.1.0
Swift 6 language-mode migration. No runtime-behavior change — only
concurrency annotations, one deprecated-API rename, and build config.
- swift-tools-version 5.9 -> 6.0, package-level swiftLanguageModes [.v6];
library and tests compile under the Swift 6 language mode. - Minimum toolchain is now Swift 6.0 (Xcode 16+). Runtime deployment
floor unchanged (macOS 13 / iOS 16). Pin 1.0.0 for Swift 5.9. - GitTicketsMenuItemFactory is now @mainactor (source-compatible for the
documented usage). - Internal: nonisolated(unsafe) on RelaySubmitter's parse-only ISO8601
statics; String(validatingCString:) replaces the deprecated
String(validatingUTF8:).
Relay templates version independently and are unchanged at
relay-vercel-v1.0.0 / relay-cloudflare-v1.0.0.
Full changelog: https://github.com/awizemann/GitTickets/blob/main/CHANGELOG.md
GitTickets 1.0.0
Drop-in Swift package (macOS 13+ / iOS 16+) for "Report an Issue / My
Reports" backed by an app's own GitHub repository.
Two production auth modes (HMAC-signed relay + OAuth Device Flow),
SwiftUI form + AppKit factory + UIKit container, Phase 2 My Reports
list with comment threads, full diagnostics + redaction pipeline,
privacy manifest, and reference Examples.
Companion relay templates ship as separate tags against this HEAD:
- relay-vercel-v1.0.0
- relay-cloudflare-v1.0.0
Full changelog: https://github.com/awizemann/GitTickets/blob/main/CHANGELOG.md