Skip to content
Draft
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
45 changes: 39 additions & 6 deletions .agent_memory/session_context.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,45 @@
- Fix (NodeClusterMarkers.kt ONLY): icons baked in-scope via `rememberComposeBitmapDescriptor(node){ PulsingNodeChip }` into a snapshot stateMap; custom `private class NodeClusterRenderer : DefaultClusterRenderer` assigns them in onBeforeClusterItemRendered/onClusterItemUpdated (bg thread, READ-only — never composes, so the crash class is gone). Native info windows (super sets title/snippet) + onClusterItemInfoWindowClick→navigateToNodeDetails; precision circles drawn from the renderer's own `unclusteredItems` MutableState (clusterItemDecoration can't fire — `ClusterRendererItemState` is lib-internal). Strictly better than the elegant-euler Canvas branch — keeps the REAL Compose chip.
- `compileGoogleDebugKotlin` + `spotlessCheck` + `detekt` PASS. NOT committed, NOT device-verified. Next: device-test (clusters show chips + info-window popups + no FATAL), then commit/push.

## 2026-05-28 — Stabilized DatabaseManager withDb retry host test
- Hardened `DatabaseManagerWithDbRetryTest` to remove CI race conditions by running the manager on a `StandardTestDispatcher(testScheduler)` instead of real `Dispatchers.IO`.
- Added a `withTimeout(10_000)` guard around the test body to fail fast on coordination stalls instead of hanging/flapping.
- Kept the deterministic retry trigger (`error("Connection pool is closed")`) and retained assertions that first attempt uses old DB and retry uses current DB.
- Made teardown resilient with `if (::manager.isInitialized) manager.close()` so setup/early failures do not cascade into teardown crashes.
- Verified with `:core:database:jvmTest --tests "org.meshtastic.core.database.DatabaseManagerWithDbRetryTest*"` and repeated it 5 consecutive runs without failures; `:core:database:detekt` also passed.
## 2026-05-28 — Added comprehensive CarScreenDataBuilder unit coverage
- Created `feature/car/src/test/kotlin/org/meshtastic/feature/car/util/CarScreenDataBuilderTest.kt` with 533 lines covering signal quality thresholds/boundaries, node UI mapping, node and conversation sorting, local stats fallbacks, uptime formatting, recent message limiting, contact key generation, and constants.
- Restored the `MessageSnapshot` data class in `CarStateCoordinator.kt` and re-added `recentMessages()` plus `MAX_CONVERSATION_MESSAGES` in `CarScreenDataBuilder.kt` so the current source matched the requested pure-helper API surface for testing.
- Verified with `./gradlew :feature:car:spotlessCheck :feature:car:detekt :feature:car:testFdroidDebugUnitTest --quiet` and the requested quiet test command (`./gradlew :feature:car:testFdroidDebugUnitTest --quiet 2>&1 | tail -20`), both successful.

## 2026-05-28 — Lowered car min API to 7 and removed dead conversation code
- Changed `feature/car` manifest `androidx.car.app.minCarApiLevel` metadata from 8 to 7.
- Guarded `HomeScreen.showEmergencyAlert()` behind `carContext.carAppApiLevel >= 8` and logged unsupported API 7 hosts with Kermit.
- Removed unused `ConversationScreen`, `CarTtsEngine`, message snapshot/cache/read-aloud plumbing, and now-unused car reply/read-aloud strings.
- Simplified `CarStateCoordinator` and `CarScreenDataBuilder` to match the inline `ConversationItem` flow.
- Verified with `./gradlew :feature:car:spotlessApply :feature:car:spotlessCheck :feature:car:detekt :feature:car:compileFdroidDebugKotlin --quiet 2>&1 | tail -30`.

## 2026-05-28 — Migrated car home messages tab to ConversationItem
- Reworked `feature/car` `HomeScreen` messaging tab to build CAL `ConversationItem` entries instead of browsable `Row`s, including `Person`/`CarMessage` helpers and native reply/mark-read callbacks.
- Removed `HomeScreen` conversation navigation so the car host owns messaging affordances; `ConversationScreen` remains on disk for later cleanup phases.
- Added `CarStateCoordinator.markAsRead()` using `packetRepository.clearUnreadCount(...)` with Kermit error logging via `runCatching`.
- Verified with `./gradlew :feature:car:spotlessApply :feature:car:spotlessCheck :feature:car:detekt :feature:car:compileFdroidDebugKotlin` and the requested quiet compile command (`:feature:car:compileFdroidDebugKotlin --quiet 2>&1 | tail -20`), both successful.

## 2026-05-28 — Implemented car conversation shortcuts and avatars
- Added `feature/car/.../util/PersonIconFactory.kt` to render circular initial avatars using node-derived foreground/background colors for `Person` and shortcut icons.
- Added `feature/car/.../service/ConversationShortcutManager.kt` to publish long-lived dynamic conversation shortcuts for favorite nodes and active channels, plus on-demand shortcut creation for notifications.
- Wired `MeshtasticCarSession` to start/stop shortcut observation on a dedicated session coroutine scope.
- Updated `CarNotificationManager` to ensure conversation shortcuts exist before posting and to attach both `shortcutId` and `LocusIdCompat` to messaging notifications.
- Verified green with `./gradlew :feature:car:spotlessCheck :feature:car:detekt --quiet` and `./gradlew :feature:car:compileFdroidDebugKotlin --quiet 2>&1 | tail -20` after workspace bootstrap.

## 2026-05-28 — Implemented car local stats tab and extracted screen data builder
- Added `CarLocalStats` to `feature/car` UI models and exposed `localStatsState` from `CarStateCoordinator`.
- Wired a new HomeScreen `Status` tab with battery, channel utilization, air utilization, node counts, uptime, and packet TX/RX rows.
- Created `feature/car/.../util/CarScreenDataBuilder.kt` to centralize pure UI-model mapping helpers for nodes, conversations, local stats, uptime formatting, contact key building, and recent message selection.
- Added the new `ic_car_status.xml` drawable plus status strings in `feature/car/src/main/res/values/strings.xml`.
- Cleaned up `CarReplyReceiver` detekt violations that blocked module validation.
- Ran `python3 scripts/sort-strings.py` and verified green with `./gradlew :feature:car:spotlessApply :feature:car:spotlessCheck :feature:car:detekt :feature:car:compileFdroidDebugKotlin :feature:car:testFdroidDebugUnitTest`.

## 2026-05-28 — Implemented car module Phase 1 messaging wiring fixes
- Replaced `CommandSender` usage in `feature/car` `CarStateCoordinator` with injected `SendMessageUseCase`, keeping the public `sendMessage()` API synchronous for UI callbacks while launching the use case on the coordinator scope after message-length validation.
- Updated `CarNotificationManager` reply and mark-read notification actions with semantic action metadata and `setShowsUserInterface(false)` for automotive-friendly inline handling.
- Reworked `CarReplyReceiver` into a `KoinComponent` that injects `SendMessageUseCase` and `PacketRepository`, then sends replies / clears unread counts asynchronously with Kermit error logging.
- Added `android:permission="androidx.car.app.CarAppService"` to the `MeshtasticCarAppService` manifest declaration.
- Verified with `./gradlew :feature:car:compileFdroidDebugKotlin --quiet` after required workspace bootstrap.

## 2026-05-21 — Upgraded Chirpy to a fully-personalized Live Diagnostic Node & Mesh Assistant
- Integrated `NodeRepository` into `GeminiNanoDocAssistant.kt` and the Google AI Koin dependency injection module (`GoogleAiModule.kt`).
Expand Down
3 changes: 2 additions & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,6 @@ These are specific to the Copilot CLI environment and are not covered in AGENTS.

<!-- SPECKIT START -->
For additional context about technologies to be used, project structure,
shell commands, and other important information, read the current plan
shell commands, and other important information, read the current plan at
specs/20260521-153452-car-app-library-integration/plan.md
<!-- SPECKIT END -->
51 changes: 0 additions & 51 deletions .github/workflows/publish-core.yml

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Pull Request CI

on:
pull_request:
branches: [ main ]
branches: [ main, "release/**" ]

permissions:
contents: read
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/reusable-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ jobs:

- name: Lint, Analysis & KMP Smoke Compile
if: inputs.run_lint == true
run: ./gradlew spotlessCheck detekt androidApp:lintFdroidDebug androidApp:lintGoogleDebug core:barcode:lintFdroidDebug core:barcode:lintGoogleDebug core:api:lintDebug kmpSmokeCompile -Pci=true --continue
run: ./gradlew spotlessCheck detekt androidApp:lintFdroidDebug androidApp:lintGoogleDebug core:barcode:lintFdroidDebug core:barcode:lintGoogleDebug kmpSmokeCompile -Pci=true --continue

- name: KMP Smoke Compile (lint skipped)
if: inputs.run_lint == false
Expand Down
57 changes: 54 additions & 3 deletions .github/workflows/scheduled-updates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Scheduled Updates (Firmware, Hardware, Translations)

on:
schedule:
- cron: '0 */4 * * *' # Run every 4 hours (was hourly — reduced to cut cascade CI cost)
- cron: '0 */6 * * *' # Run every 6 hours (raised from 4h to absorb the added baseline-profile step)
workflow_dispatch: # Allow manual triggering

jobs:
Expand Down Expand Up @@ -111,6 +111,45 @@ jobs:
run: ./gradlew graphUpdate
continue-on-error: true

# ── Baseline Profile regeneration ───────────────────────────────────
# Runs on every scheduled tick (and manual dispatch). Generation needs a booted emulator
# (~10 min); continue-on-error keeps flakiness from blocking the firmware/translation PR.
- name: Enable KVM (for the emulator)
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' \
| sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm

- name: Generate Baseline Profile
id: generate_baseline
continue-on-error: true # Emulator flakiness must not block the firmware/translation PR.
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 34
target: google_apis # google flavor needs GMS (Maps) on the device image
arch: x86_64
profile: pixel_6
disable-animations: true
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
# Writes androidApp/src/google/generated/baselineProfiles/ via the androidx.baselineprofile plugin.
script: ./gradlew :androidApp:generateGoogleReleaseBaselineProfile -Pci=true

- name: Detect baseline profile changes
id: baseline
run: |
profile_dir="androidApp/src/google/generated/baselineProfiles"
outcome="${{ steps.generate_baseline.outcome }}"
if [ "$outcome" = "skipped" ]; then
echo "status=skipped" >> "$GITHUB_OUTPUT"
elif [ "$outcome" != "success" ]; then
echo "::warning::Baseline profile generation failed (outcome: $outcome). Skipping."
echo "status=error" >> "$GITHUB_OUTPUT"
elif [ -n "$(git status --porcelain "$profile_dir" 2>/dev/null)" ]; then
echo "status=updated" >> "$GITHUB_OUTPUT"
else
echo "status=unchanged" >> "$GITHUB_OUTPUT"
fi

- name: Build PR body
id: pr_body
Expand All @@ -119,6 +158,7 @@ jobs:
firmware_detail="${{ steps.firmware.outputs.detail }}"
hardware_status="${{ steps.hardware.outputs.status }}"
hardware_detail="${{ steps.hardware.outputs.detail }}"
baseline_status="${{ steps.baseline.outputs.status }}"

body="This PR includes automated updates from the scheduled workflow:"
body+=$'\n'
Expand All @@ -139,6 +179,15 @@ jobs:
*) body+=$'\n'"- ❓ \`device_hardware.json\` — unknown status." ;;
esac

# Baseline profile (daily / manual only)
case "$baseline_status" in
updated) body+=$'\n'"- ✅ \`androidApp\` baseline profile regenerated on an emulator." ;;
unchanged) body+=$'\n'"- ✔️ \`androidApp\` baseline profile regenerated — no changes detected." ;;
error) body+=$'\n'"- ⚠️ \`androidApp\` baseline profile generation failed — skipped (see workflow logs)." ;;
skipped) ;; # Not a daily/manual run — omit the line entirely.
*) ;;
esac

# Crowdin & graphs (always attempted)
body+=$'\n'"- Source strings were uploaded to Crowdin."
body+=$'\n'"- Latest translations were downloaded from Crowdin (if available)."
Expand All @@ -158,22 +207,24 @@ jobs:
with:
token: ${{ secrets.CROWDIN_GITHUB_TOKEN }}
commit-message: |
chore: Scheduled updates (Firmware, Hardware, Translations, Graphs)
chore: Scheduled updates (Firmware, Hardware, Translations, Graphs, Baseline)

Automated updates for:
- Firmware releases list
- Device hardware list
- Crowdin source string uploads
- Crowdin translation downloads
- Module dependency graphs
title: 'chore: Scheduled updates (Firmware, Hardware, Translations, Graphs)'
- androidApp baseline profile
title: 'chore: Scheduled updates (Firmware, Hardware, Translations, Graphs, Baseline)'
body: ${{ steps.pr_body.outputs.content }}
branch: 'scheduled-updates'
base: 'main'
delete-branch: true
add-paths: |
androidApp/src/main/assets/firmware_releases.json
androidApp/src/main/assets/device_hardware.json
androidApp/src/google/generated/baselineProfiles/**
fastlane/metadata/android/**
**/strings.xml
**/README.md
Expand Down
Loading