Skip to content
This repository was archived by the owner on Aug 1, 2026. It is now read-only.
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
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,24 @@ read the receipts. No browser, no terminal.
value); the scoreboard shows observed routing outcomes, not promises. The
read-only training card reports the local run as it is.

## Run it
## Install it

Flywheel ships as a Windows installer: the app and the engine arrive
together, no Python, no PATH setup. Download the latest
`Flywheel-Setup-<version>-x64.exe` from the
[releases page](https://github.com/HarperZ9/flywheel-desktop/releases);
every release is built from its version tag by a public pipeline and ships
with a `SHA256SUMS.txt` receipt. Verify the copy you downloaded:

```
Get-FileHash Flywheel-Setup-0.2.1-x64.exe -Algorithm SHA256
```

The installer is not code-signed yet, so Windows SmartScreen will warn on
first run; the hash is the substitute, proving the file you hold is the file
the pipeline built.

## Run it from source

Install the engine and start it once:

Expand All @@ -72,7 +89,9 @@ Then run the app:
flutter run -d windows --release
```

If the engine is offline the app says so and can start it for you.
If the engine is offline the app says so and can start it for you. An
installed app launches its own bundled engine by absolute path; a dev
checkout falls back to `flywheel` on PATH.

## Design

Expand Down
9 changes: 9 additions & 0 deletions lib/version.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// version.dart — the app's release identity, surfaced in the UI.
//
// One constant, no plugin. The truth lives in pubspec.yaml; a drift gate
// (test/version_truth_test.dart) fails the suite the moment the two
// disagree, so this can never silently lie about what is running.

const String appVersion = '0.2.1';
const String appPublisher = 'ZentropyLabs';
const String appReleases = 'github.com/HarperZ9/flywheel-desktop/releases';
15 changes: 15 additions & 0 deletions lib/widgets/appearance_panel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:flutter/material.dart';

import '../services/settings.dart';
import '../theme/flywheel_theme.dart';
import '../version.dart';
import 'fw.dart';

const kTextChoices = <String?>[
Expand Down Expand Up @@ -121,6 +122,20 @@ class _AppearanceFormState extends State<_AppearanceForm> {
),
],
),
const SizedBox(height: FwLayout.s4),
Divider(height: 1, color: t.hairline),
const SizedBox(height: FwLayout.s3),
// The app's release identity. The version constant is drift-gated
// against pubspec by the test suite, so this line cannot lie.
Text('Flywheel v$appVersion · $appPublisher',
style: fwMono(t, size: 11.5, color: t.inkMuted)),
const SizedBox(height: 3),
SelectableText(appReleases, style: fwMono(t, size: 10.5, color: t.inkFaint)),
const SizedBox(height: 3),
Text(
'Every release ships with a SHA-256 receipt beside the installer; '
'verify your download against it.',
style: TextStyle(fontSize: 11, color: t.inkFaint, height: 1.4)),
],
);
}
Expand Down
19 changes: 19 additions & 0 deletions test/version_truth_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// The drift gate for lib/version.dart: the constant the UI shows must be
// the version pubspec ships. The moment a release bump touches one and not
// the other, this fails, so the About surface can never lie.
import 'dart:io';

import 'package:flutter_test/flutter_test.dart';

import 'package:flywheel_desktop/version.dart';

void main() {
test('appVersion matches pubspec.yaml', () {
final line = File('pubspec.yaml')
.readAsLinesSync()
.firstWhere((l) => l.startsWith('version:'));
final pubspec = line.split(':')[1].trim().split('+')[0];
expect(appVersion, pubspec,
reason: 'bump lib/version.dart together with pubspec.yaml');
});
}
Loading