Skip to content

Commit 67b155e

Browse files
i99devclaude
andcommitted
Initial commit: iLINK
A standalone Flutter dashboard for BYD head units (Leopard 8 / DiLink 5.1). Vehicle controls, automations and speech recognition run on the device — no account, no subscription, no hosted API, no MQTT broker, no license check. Every outbound connection sits behind a switch that ships off, and there is no analytics SDK or telemetry. The bundled radio directory (5,166 stations across 212 countries) browses and searches with no network at all; only playing a live stream needs the internet, and only after the driver enables it. Contributors need nothing that is not in this repository: no private submodule, no secrets, no backend access. See docs/ORIENTATION.md to get running on an ordinary Android emulator in about twenty minutes. Host checks: analyzer clean, 1,452 tests passing, debug APK builds, no broken documentation links. Physical head-unit acceptance (fresh install → speech → vehicle execution) has not been completed; docs/offline-first/final-verification.md records what is and is not proven. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AjhsQbfGjJw2V8j2WmRXpN
0 parents  commit 67b155e

1,240 files changed

Lines changed: 199655 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Keep the existing release identity; provide an absolute external path.
2+
DASH_KEYSTORE_PATH=
3+
DASH_KEYSTORE_PASSWORD=
4+
DASH_KEY_PASSWORD=
5+
DASH_KEY_ALIAS=dash
6+
DASH_EXPECTED_SIGNER_SHA=2a4700925fe0c230c9bac63ab194ff9500a58a4ac0825c2196ee9ac7f33fc264

.gitattributes

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# 3D model assets — binary glTF. Treat as binary so git-diff doesn't
2+
# attempt textual diffs on multi-MB embedded mesh + texture data.
3+
# We deliberately do NOT use Git LFS today: dev_only assets are
4+
# gitignored, and shipped per-model .glb files are <= 25 MB (per
5+
# docs/3D_FREELANCER_BRIEF.md §4 hard limit). Re-evaluate LFS if the
6+
# shipped catalog grows past ~10 cars.
7+
*.glb binary
8+
*.gltf binary
9+
*.bin binary
10+
*.ktx2 binary
11+
12+
# Source 3D files (.blend, .fbx, .obj) are kept out of the runtime
13+
# repo entirely (artist's deliverable is the .glb), but mark them
14+
# binary in case a stray source file is committed to docs/ or
15+
# similar.
16+
*.blend binary
17+
*.fbx binary
18+
*.obj binary
19+
20+
# Public offline bundles and standard wrapper must survive Windows checkouts.
21+
*.dex binary
22+
*.zip binary
23+
*.jar binary
24+
*.sh text eol=lf
25+
android/gradlew text eol=lf
26+
android/gradlew.bat text eol=crlf

.githooks/install.sh

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!/usr/bin/env bash
2+
# Run once after cloning to point git at the in-repo hooks dir.
3+
# Idempotent — safe to re-run.
4+
set -euo pipefail
5+
cd "$(git rev-parse --show-toplevel)"
6+
git config core.hooksPath .githooks
7+
chmod +x .githooks/pre-commit
8+
echo "✓ hooks installed (core.hooksPath=.githooks)"
9+
echo " pre-commit will block commits on dart format / flutter analyze /"
10+
echo " audit_hex failures."

.githooks/pre-commit

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#!/usr/bin/env bash
2+
# ilink (Flutter) pre-commit gate. Mirrors .github/workflows/ci.yml so
3+
# CI-failing changes bounce locally before push.
4+
#
5+
# Policy:
6+
# - dart format → whole repo (matches CI's --set-exit-if-changed).
7+
# - flutter analyze → whole repo (matches CI; fails on info+ by default).
8+
# - audit_hex → ``tool/audit_hex.dart`` — feature-ID hex must
9+
# live in the encrypted dispatch table only.
10+
# - flutter test → full suite (matches CI). Slowest gate (~10s)
11+
# but the only one that catches behaviour
12+
# regressions; cheap enough to run on every
13+
# commit that touches Dart.
14+
#
15+
# Skip with ``git commit --no-verify`` only in genuine emergencies —
16+
# CI still gates. Or set ``SKIP_PRECOMMIT=1`` for a one-off bypass.
17+
set -uo pipefail
18+
19+
cd "$(git rev-parse --show-toplevel)"
20+
21+
if [ "${SKIP_PRECOMMIT:-}" = "1" ]; then
22+
echo "[pre-commit] SKIP_PRECOMMIT=1 — skipping all checks"
23+
exit 0
24+
fi
25+
26+
# Collect staged Dart sources so we can short-circuit when no Dart
27+
# code is touched (e.g. a docs- or workflow-only commit).
28+
STAGED_DART=()
29+
while IFS= read -r f; do
30+
[ -n "$f" ] && STAGED_DART+=("$f")
31+
done < <(git diff --cached --name-only --diff-filter=ACMR | grep -E '\.dart$' || true)
32+
33+
if [ ${#STAGED_DART[@]} -eq 0 ]; then
34+
echo "[pre-commit] no .dart files staged — skipping checks"
35+
exit 0
36+
fi
37+
38+
run_step() {
39+
name="$1"; shift
40+
echo
41+
echo "[pre-commit] ── $name ──"
42+
if ! "$@"; then
43+
echo
44+
echo "[pre-commit] ✗ $name failed — commit blocked."
45+
echo "[pre-commit] Fix the issue above and re-stage, or"
46+
echo "[pre-commit] set SKIP_PRECOMMIT=1 to bypass (CI still gates)."
47+
exit 1
48+
fi
49+
}
50+
51+
# `dart format` walks `build/` recursively if you pass `.`, which on
52+
# Windows trips a PathNotFoundException when Gradle leaves dangling
53+
# symlinks under `build/flutter_inappwebview_android/.transforms/…`.
54+
# Scoping to the staged set is also faster (~50ms vs ~1.5s on cold
55+
# cache) and cross-platform.
56+
run_step "dart format (check, staged Dart files)" \
57+
dart format --set-exit-if-changed --output=none "${STAGED_DART[@]}"
58+
run_step "flutter analyze (whole repo)" flutter analyze
59+
run_step "audit stray feature-ID hex" dart run tool/audit_hex.dart
60+
run_step "flutter test (full suite)" flutter test
61+
62+
echo
63+
echo "[pre-commit] ✓ all checks passed"
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: Bug Report
2+
description: Report a bug in Dash
3+
labels: ["bug", "triage"]
4+
body:
5+
- type: markdown
6+
attributes:
7+
value: |
8+
Thanks for taking the time to file a bug. Please fill in the fields below.
9+
- type: input
10+
id: version
11+
attributes:
12+
label: Dash version
13+
description: Check Settings → Diagnostics.
14+
placeholder: "1.2.3"
15+
validations:
16+
required: true
17+
- type: input
18+
id: car
19+
attributes:
20+
label: Car model + head-unit firmware
21+
placeholder: "Leopard 8 / DiLink 5.1"
22+
validations:
23+
required: true
24+
- type: textarea
25+
id: steps
26+
attributes:
27+
label: Steps to reproduce
28+
placeholder: |
29+
1. Open the app
30+
2. Tap "..."
31+
3. See error
32+
validations:
33+
required: true
34+
- type: textarea
35+
id: expected
36+
attributes:
37+
label: Expected behaviour
38+
validations:
39+
required: true
40+
- type: textarea
41+
id: actual
42+
attributes:
43+
label: Actual behaviour
44+
validations:
45+
required: true
46+
- type: textarea
47+
id: logs
48+
attributes:
49+
label: Logs
50+
description: Paste relevant logcat output or screenshots.
51+
render: shell

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
blank_issues_enabled: false
2+
contact_links:
3+
- name: Release notes
4+
url: https://github.com/i99dev/ilink/releases
5+
about: Looking for what's new? See the Releases page.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: Feature Request
2+
description: Suggest a new capability for Dash
3+
labels: ["enhancement", "triage"]
4+
body:
5+
- type: textarea
6+
id: problem
7+
attributes:
8+
label: What problem does this solve?
9+
description: Describe the situation where the current app falls short.
10+
validations:
11+
required: true
12+
- type: textarea
13+
id: proposal
14+
attributes:
15+
label: Proposed behaviour
16+
validations:
17+
required: true
18+
- type: textarea
19+
id: alternatives
20+
attributes:
21+
label: Alternatives you've considered

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
## Problem and resulting behavior
2+
3+
Explain the concrete problem and what this change does. Link the relevant issue, if any.
4+
5+
## Validation
6+
7+
List checks run and their results. Explain any failures or checks you could not run.
8+
9+
- [ ] Formatting, analyzer and Flutter tests
10+
- [ ] Hex audit and production configuration validator
11+
- [ ] Applicable Android build/native tests, or explain why not applicable
12+
13+
For UI changes, include screenshots. For head-unit changes, identify the tested model/firmware, steps and results; explicitly distinguish emulator/mock checks from physical hardware testing.
14+
15+
## Compatibility and review notes
16+
17+
Describe changes to local data, permission scopes, network access, bundled assets or vehicle behavior. Note migration needs and remaining limitations. Remove private information from evidence; do not attach signing keys or credentials.
18+
19+
- [ ] PR title follows the convention in [Contributing](../CONTRIBUTING.md)

.github/SECRETS.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Release signing secrets
2+
3+
The standalone app has no backend, payment, analytics or account credentials.
4+
Never commit a keystore or password, including encrypted keystores in submodules.
5+
6+
Release Actions require these existing signing values:
7+
8+
| Secret | Purpose |
9+
| --- | --- |
10+
| `DASH_RELEASE_KEYSTORE_B64` | Base64 of the exact existing release keystore, restored only under `RUNNER_TEMP`. |
11+
| `DASH_KEYSTORE_PASSWORD` | Existing keystore password. |
12+
| `DASH_KEY_PASSWORD` | Existing private-key password. |
13+
| `DASH_KEY_ALIAS` | Existing alias, `dash`. |
14+
15+
The release workflow uses the `prod` environment. Keep secrets out of untrusted
16+
pull-request workflows. The signing preflight requires certificate SHA-256
17+
`2a4700925fe0c230c9bac63ab194ff9500a58a4ac0825c2196ee9ac7f33fc264`.
18+
It never generates a replacement key. Signing keeps v1, v2 and v3 enabled.
19+
20+
For local release builds, supply the same environment variables and an absolute
21+
keystore path outside the repository. Run `scripts/prepare-signing.sh` before
22+
building. Verified owner backups exist outside Git; see the standalone cleanup
23+
record. Never rotate this app signing identity as part of secret cleanup.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: Build Flutter APK
2+
description: Build a standalone APK using local configuration and the existing release signer.
3+
inputs:
4+
dart-define-file:
5+
description: Local build configuration.
6+
required: false
7+
default: config/prod.json
8+
flutter-build-mode:
9+
description: apk or appbundle.
10+
required: false
11+
default: apk
12+
outputs:
13+
apk-path:
14+
description: Built release package.
15+
value: ${{ steps.build.outputs.apk-path }}
16+
runs:
17+
using: composite
18+
steps:
19+
- name: Build
20+
id: build
21+
shell: bash
22+
env:
23+
BUILD_MODE: ${{ inputs.flutter-build-mode }}
24+
DEFINE_FILE: ${{ inputs.dart-define-file }}
25+
run: |
26+
test -f "$DEFINE_FILE"
27+
test "$BUILD_MODE" = apk || test "$BUILD_MODE" = appbundle
28+
flutter pub get
29+
flutter build "$BUILD_MODE" --release --dart-define-from-file="$DEFINE_FILE" --dart-define=GITHUB_RELEASE_REPOSITORY="${{ github.repository }}"
30+
if [ "$BUILD_MODE" = appbundle ]; then
31+
echo "apk-path=build/app/outputs/bundle/release/app-release.aab" >> "$GITHUB_OUTPUT"
32+
else
33+
echo "apk-path=build/app/outputs/flutter-apk/app-release.apk" >> "$GITHUB_OUTPUT"
34+
fi

0 commit comments

Comments
 (0)