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
16 changes: 9 additions & 7 deletions docs/product-contract.md

Large diffs are not rendered by default.

26 changes: 13 additions & 13 deletions docs/release-runbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This runbook covers desktop downloads and source archives on GitHub. The package

## release candidate

The candidate is **2.2.4**, with [release notes](releases/2.2.4.md). It adds the in-app network explorer, profile pictures, nearby help, scan ETA and responsive cancellation. **2.2.3** remains the published release until this candidate passes review and native package checks. **2.2.1** was withdrawn; its tag remains fixed. Do not reuse either tag.
The candidate is **2.2.5**, with [release notes](releases/2.2.5.md). It improves graph image quality, hover stability, contextual help and Results navigation, and compacts the History toolbar. **2.2.4** remains the published release until this candidate passes review and native package checks. **2.2.1** was withdrawn; its tag remains fixed. Do not reuse either tag.

Use the existing tag convention without a `v` prefix. Desktop installers start at `2.0.1`; `2.0.0` contains source archives only, and `1.0.2` contains the legacy Python executable. Publish only after authorization, resolved review findings and green CI on the pinned main commit.

Expand All @@ -27,8 +27,8 @@ Use the existing tag convention without a `v` prefix. Desktop installers start a
5. Confirm that the intended tag does not already exist locally or remotely. Never move an existing release tag.

```sh
git tag --list 2.2.4
git ls-remote --tags origin refs/tags/2.2.4
git tag --list 2.2.5
git ls-remote --tags origin refs/tags/2.2.5
gh release list --repo Microck/vapora
```

Expand All @@ -43,8 +43,8 @@ For a committed candidate, create an archive from its exact commit:
```sh
VAPORA_RELEASE_COMMIT=REPLACE_WITH_REVIEWED_MAIN_COMMIT

git archive --format=tar.gz --prefix=vapora-2.2.4/ \
--output=/tmp/vapora-2.2.4-source.tar.gz "$VAPORA_RELEASE_COMMIT"
git archive --format=tar.gz --prefix=vapora-2.2.5/ \
--output=/tmp/vapora-2.2.5-source.tar.gz "$VAPORA_RELEASE_COMMIT"
```

Extract it into a fresh directory and run:
Expand Down Expand Up @@ -81,21 +81,21 @@ Proceed only after explicit approval of the tag and notes, all findings are reso
4. Create an annotated tag at the pinned commit. Git is used here because Jujutsu does not create annotated tags:

```sh
git -c user.name=Microck -c user.email=contact@micr.dev tag -a 2.2.4 \
"$VAPORA_RELEASE_COMMIT" -F docs/releases/2.2.4.md
git push origin refs/tags/2.2.4
git -c user.name=Microck -c user.email=contact@micr.dev tag -a 2.2.5 \
"$VAPORA_RELEASE_COMMIT" -F docs/releases/2.2.5.md
git push origin refs/tags/2.2.5
```

5. Wait for core CI and Desktop packages CI triggered by the new tag to pass on the pinned commit. Download that tag run's verified artifacts into `/tmp/vapora-desktop-downloads`. Compute `SHA256SUMS.txt` from the exact EXE, AppImage and DMG bytes, using their basenames. Confirm there are four tested downloads: Windows x64 installer and portable EXEs, Linux x64 AppImage, and macOS ARM64 DMG. Publish a normal GitHub release with those files attached from the start:

```sh
gh release create 2.2.4 \
gh release create 2.2.5 \
/tmp/vapora-desktop-downloads/*/*.exe \
/tmp/vapora-desktop-downloads/*/*.AppImage \
/tmp/vapora-desktop-downloads/*/*.dmg \
/tmp/vapora-desktop-downloads/SHA256SUMS.txt \
--repo Microck/vapora --verify-tag \
--title 'vapora 2.2.4' --notes-file docs/releases/2.2.4.md --latest
--title 'vapora 2.2.5' --notes-file docs/releases/2.2.5.md --latest
```

6. GitHub also provides the source ZIP and tar.gz. Do not publish an empty source-only release while waiting for desktop builds. Do not attach the legacy executable, replace existing public assets with `--clobber`, publish to npm or mark the release as a prerelease.
Expand All @@ -105,15 +105,15 @@ Proceed only after explicit approval of the tag and notes, all findings are reso
1. Confirm the release is published, not a draft, and points to the intended tag:

```sh
gh release view 2.2.4 --repo Microck/vapora \
gh release view 2.2.5 --repo Microck/vapora \
--json url,tagName,isDraft,isPrerelease,publishedAt,assets
git ls-remote --tags origin refs/tags/2.2.4 'refs/tags/2.2.4^{}'
git ls-remote --tags origin refs/tags/2.2.5 'refs/tags/2.2.5^{}'
```

2. Verify the annotated tag's peeled commit equals `VAPORA_RELEASE_COMMIT`.
3. Download a public source archive for the tag into a fresh directory. Repeat the source checks above against the actual public download.
4. Confirm both core and desktop tag CI passed. Download each attached installer and verify its checksum against `SHA256SUMS.txt` and the tested CI artifact. Check the release has both installer and portable EXEs, an AppImage and a DMG before calling it complete. Report a failed or incomplete platform check honestly.
5. Verify main and the historical `legacy`, `feature/gui-and-analysis` and `rewrite/typescript-effect` branches remain at their expected commits.
5. Verify main points to the released commit and the protected historical `legacy` branch remains at `a42279957cebe997a609f19da77bc13167be7205`. Previously removed feature branches must not be recreated.
6. Report the release URL, tagged commit, completed checks and outstanding platform limits.

## recover from a publishing problem
Expand Down
15 changes: 15 additions & 0 deletions docs/releases/2.2.5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# vapora 2.2.5

Graph images now export with a 4,096-pixel long edge, independent of the window size. Geometry and labels render at export resolution, using loaded original profile pictures. Camera position, filters and selection stay unchanged.

- Network arranges automatically. Pause and Resume control the layout; hover no longer resizes or reorders circles.
- Help uses headings and short points beside its control, without covering the control itself. Scrollbars keep the square classic Steam bevels.
- Friends search sits directly above the table. The Obsidian vault download is also available in the main Results actions.
- Attached history stays in a Results tab. The standalone viewer remains available from the rail, with account states kept separate. Failed refreshes retain the saved capture and retry guidance when reopened.
- History uses a compact account/date toolbar and grouped actions. Coverage notices show counts, with details in contextual help.

Image resolution does not add detail absent from an original avatar. Dense graphs can still take time to arrange and render.

Windows downloads include an installer and a portable EXE. The portable app keeps data in `Vapora-data` beside the EXE and needs about 1 GB free in Windows TEMP, plus space for scan data. Move the EXE and data folder together. Downloads are unsigned and not notarized; verify them against `SHA256SUMS.txt`.

Native package tests use local provider fixtures. This release does not change live Steam or history fetching behavior.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/ui-refinements/friends-after.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/ui-refinements/history-after.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vapora",
"version": "2.2.4",
"version": "2.2.5",
"private": true,
"description": "Explore public Steam friend networks",
"type": "module",
Expand Down
5 changes: 3 additions & 2 deletions scripts/history-worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ async def navigate():
if __name__ == "__main__":
try:
asyncio.run(serve())
except Exception:
except Exception as error:
# Browser paths, cookies, challenge URLs and private page content stay out of IPC.
emit({"id": 0, "error": "History's browser could not load the profile. Retry or import a saved capture."})
# The exception class gives support a safe failure code without exposing the provider response.
emit({"id": 0, "error": f"History's browser could not load the profile ({type(error).__name__}). Retry or import a saved capture."})
sys.exit(1)
8 changes: 6 additions & 2 deletions src/history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,18 @@ const captureTime = (capturedAt: string) => {
export function diagnosticText(message: string): string {
return message.replace(/\bSteamHistory(?:\.net)?\b/gi, "History");
}
export function coverageError(bundle: Bundle): string | null {
/** Select coverage by parsed capture time, keeping undated sources behind dated captures. */
export function latestCoverageSource(bundle: Bundle) {
let latest: Bundle["sources"][number] | undefined; let latestDate = -Infinity;
for (const source of bundle.sources) {
if (!source.coverage.length) continue;
const date = captureTime(source.capturedAt);
if (!latest || date > latestDate) { latest = source; latestDate = date; }
}
const issues = latest?.coverage.flatMap((section) => section.error ? [section.error] : []) ?? [];
return latest;
}
export function coverageError(bundle: Bundle): string | null {
const issues = latestCoverageSource(bundle)?.coverage.flatMap((section) => section.error ? [section.error] : []) ?? [];
return issues.length ? diagnosticText(issues.join("\n")) : null;
}

Expand Down
Loading
Loading