4 Commits

Author SHA1 Message Date
Space-Banane 050c8e5cce ci: suppress SIGPIPE from yes | sdkmanager NDK install
CodexBar Mobile Build / build-android (push) Successful in 21m17s
CodexBar Mobile Build / release (push) Successful in 11s
sdkmanager closes stdin once done; yes keeps writing and gets SIGPIPE
(exit 141), failing the step even though the NDK installed successfully.
Add || true to treat SIGPIPE as success.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 21:57:46 +02:00
Space-Banane 6bf66c0afd ci: pre-install NDK 27.1.12297006 before EAS local build
CodexBar Mobile Build / build-android (push) Failing after 52s
CodexBar Mobile Build / release (push) Has been skipped
Gradle's auto-download of the NDK was failing on the runner with
"Archive is not a ZIP archive" — the download was corrupted/unavailable.
Fix by explicitly installing the NDK via sdkmanager after setup-android
so it is present in $ANDROID_HOME before gradlew runs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 21:54:18 +02:00
Space-Banane 2c63dcfd75 fix: guard expo-notifications against Expo Go crash on import
CodexBar Mobile Build / build-android (push) Failing after 3m21s
CodexBar Mobile Build / release (push) Has been skipped
SDK 53+ removed push notification support from Expo Go, causing the
module to throw at require-time. The static import in notifications.ts
propagated the error to _layout.tsx and both tab screens, making expo-
router report missing default exports and crash the app.

Switch to a try/catch require() so the module initialises safely in
Expo Go (Notifications stays null, all functions become no-ops) while
still working correctly in EAS / development builds.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 21:47:44 +02:00
Space-Banane 487f89699c yes
CodexBar Mobile Build / build-android (push) Successful in 22m24s
CodexBar Mobile Build / release (push) Successful in 23s
2026-06-24 21:13:43 +02:00
3 changed files with 27 additions and 12 deletions
+3
View File
@@ -32,6 +32,9 @@ jobs:
- name: 🏗 Setup Android SDK
uses: android-actions/setup-android@v3
- name: 🏗 Install Android NDK
run: yes | sdkmanager "ndk;27.1.12297006" || true
- name: 🏗 Setup Expo and EAS
uses: expo/expo-github-action@v8
with:
+1 -1
View File
@@ -1,6 +1,6 @@
{
"expo": {
"name": "codexbar.mobile",
"name": "codexbar-mobile",
"slug": "codexbar-mobile",
"scheme": "codexbar",
"version": "1.0.0",
+23 -11
View File
@@ -1,4 +1,4 @@
import * as Notifications from "expo-notifications";
import type * as NotificationsType from "expo-notifications";
import {
loadNotifSettings,
loadNotifThresholdLastFired,
@@ -7,22 +7,32 @@ import {
import type { ClaudeUsageResponse } from "@/types/claude";
import type { CodexUsageResponse } from "@/types/codex";
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldShowBanner: true,
shouldShowList: true,
shouldPlaySound: false,
shouldSetBadge: false,
}),
});
// expo-notifications push notifications were removed from Expo Go in SDK 53.
// Use require() so the initialization error is caught gracefully in Expo Go.
let Notifications: typeof NotificationsType | null = null;
try {
Notifications = require("expo-notifications") as typeof NotificationsType;
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldShowBanner: true,
shouldShowList: true,
shouldPlaySound: false,
shouldSetBadge: false,
}),
});
} catch {
// Running in Expo Go or native module unavailable — notifications disabled.
}
export async function requestPermissions(): Promise<boolean> {
if (!Notifications) return false;
const { status } = await Notifications.requestPermissionsAsync();
return status === "granted";
}
export async function getPermissionStatus(): Promise<string> {
if (!Notifications) return "undetermined";
const { status } = await Notifications.getPermissionsAsync();
return status;
}
@@ -35,6 +45,7 @@ export async function scheduleDailyDigest(
claudeUsage: ClaudeUsageResponse | null,
codexUsage: CodexUsageResponse | null
): Promise<void> {
if (!Notifications) return;
try {
await Notifications.cancelScheduledNotificationAsync(DAILY_ID);
} catch {}
@@ -68,6 +79,7 @@ export async function scheduleDailyDigest(
}
export async function cancelDailyDigest(): Promise<void> {
if (!Notifications) return;
try {
await Notifications.cancelScheduledNotificationAsync(DAILY_ID);
} catch {}
@@ -128,7 +140,7 @@ export async function onUsageDataLoaded(
claudeUsage,
codexUsage
);
if (alerts.length > 0) {
if (alerts.length > 0 && Notifications) {
await Notifications.scheduleNotificationAsync({
content: {
title: "Low quota warning",