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
6 changes: 4 additions & 2 deletions .github/workflows/android-play-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ jobs:
SCCACHE_REGION: auto
SCCACHE_S3_USE_SSL: "true"
SCCACHE_S3_KEY_PREFIX: ci/android-release-prep
SCCACHE_LOG: info
AWS_ACCESS_KEY_ID: ${{ secrets.SCCACHE_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.SCCACHE_R2_SECRET_ACCESS_KEY }}

Expand Down Expand Up @@ -92,6 +93,7 @@ jobs:
SCCACHE_S3_USE_SSL: "true"
SCCACHE_S3_KEY_PREFIX: ci/android
SCCACHE_LOG: info
SCCACHE_ERROR_LOG: ${{ runner.temp }}/sccache-android.log
AWS_ACCESS_KEY_ID: ${{ secrets.SCCACHE_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.SCCACHE_R2_SECRET_ACCESS_KEY }}

Expand Down Expand Up @@ -152,7 +154,6 @@ jobs:

- name: Prime sccache
run: |
export SCCACHE_ERROR_LOG="$RUNNER_TEMP/sccache-android.log"
rm -f "$SCCACHE_ERROR_LOG"
sccache --stop-server || true
sccache --start-server
Expand Down Expand Up @@ -212,6 +213,8 @@ jobs:
JAVA_HOME: ${{ env.JAVA_HOME }}
ANDROID_SDK_ROOT: ${{ env.ANDROID_HOME }}
ANDROID_NDK_HOME: ${{ env.ANDROID_HOME }}/ndk/30.0.14904198
CARGO_BUILD_JOBS: "2"
GRADLE_MAX_WORKERS: "2"
RUSTC_WRAPPER: sccache
LITTER_UPLOAD_STORE_FILE: ${{ env.LITTER_UPLOAD_STORE_FILE }}
LITTER_UPLOAD_STORE_PASSWORD: ${{ secrets.LITTER_UPLOAD_STORE_PASSWORD }}
Expand All @@ -222,7 +225,6 @@ jobs:
LITTER_VERSION_CODE_OVERRIDE: ${{ env.LITTER_VERSION_CODE_OVERRIDE }}
run: |
set -euo pipefail
export SCCACHE_ERROR_LOG="$RUNNER_TEMP/sccache-android.log"
trap 'status=$?; echo "==> sccache stats"; sccache --show-stats || true; if [ -f "$SCCACHE_ERROR_LOG" ]; then echo "==> sccache error log"; tail -200 "$SCCACHE_ERROR_LOG" || true; fi; exit $status' EXIT
make play-release

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ios-testflight.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ jobs:
SCCACHE_S3_USE_SSL: "true"
SCCACHE_S3_KEY_PREFIX: ci/ios
SCCACHE_LOG: info
SCCACHE_ERROR_LOG: ${{ runner.temp }}/sccache-ios.log
AWS_ACCESS_KEY_ID: ${{ secrets.SCCACHE_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.SCCACHE_R2_SECRET_ACCESS_KEY }}

Expand Down Expand Up @@ -86,7 +87,6 @@ jobs:

- name: Prime sccache
run: |
export SCCACHE_ERROR_LOG="$RUNNER_TEMP/sccache-ios.log"
rm -f "$SCCACHE_ERROR_LOG"
sccache --stop-server || true
sccache --start-server
Expand Down Expand Up @@ -162,6 +162,7 @@ jobs:

- name: Upload to TestFlight
env:
CARGO_BUILD_JOBS: "2"
RUSTC_WRAPPER: sccache
SCHEME: ${{ env.SCHEME }}
APP_BUNDLE_ID: ${{ env.APP_BUNDLE_ID }}
Expand All @@ -176,6 +177,5 @@ jobs:
WAIT_FOR_PROCESSING: ${{ env.WAIT_FOR_PROCESSING }}
run: |
set -euo pipefail
export SCCACHE_ERROR_LOG="$RUNNER_TEMP/sccache-ios.log"
trap 'status=$?; echo "==> sccache stats"; sccache --show-stats || true; if [ -f "$SCCACHE_ERROR_LOG" ]; then echo "==> sccache error log"; tail -200 "$SCCACHE_ERROR_LOG" || true; fi; exit $status' EXIT
make testflight
2 changes: 2 additions & 0 deletions .github/workflows/mobile-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ jobs:
fi

tar -xzf "$SHARED_PREP_ROOT/generated-mobile-sources.tgz" -C .
mkdir -p .build-stamps
touch .build-stamps/sync .build-stamps/bindings-swift

- name: Build Rust for iOS simulator
env:
Expand Down
12 changes: 8 additions & 4 deletions .github/workflows/mobile-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ jobs:
SCCACHE_REGION: auto
SCCACHE_S3_USE_SSL: "true"
SCCACHE_S3_KEY_PREFIX: ci/mobile-release-prep
SCCACHE_LOG: info
AWS_ACCESS_KEY_ID: ${{ secrets.SCCACHE_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.SCCACHE_R2_SECRET_ACCESS_KEY }}

Expand Down Expand Up @@ -198,6 +199,7 @@ jobs:
SCCACHE_S3_USE_SSL: "true"
SCCACHE_S3_KEY_PREFIX: ci/android
SCCACHE_LOG: info
SCCACHE_ERROR_LOG: ${{ runner.temp }}/sccache-android.log
AWS_ACCESS_KEY_ID: ${{ secrets.SCCACHE_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.SCCACHE_R2_SECRET_ACCESS_KEY }}

Expand Down Expand Up @@ -258,7 +260,6 @@ jobs:

- name: Prime sccache
run: |
export SCCACHE_ERROR_LOG="$RUNNER_TEMP/sccache-android.log"
rm -f "$SCCACHE_ERROR_LOG"
sccache --stop-server || true
sccache --start-server
Expand Down Expand Up @@ -318,6 +319,8 @@ jobs:
JAVA_HOME: ${{ env.JAVA_HOME }}
ANDROID_SDK_ROOT: ${{ env.ANDROID_HOME }}
ANDROID_NDK_HOME: ${{ env.ANDROID_HOME }}/ndk/30.0.14904198
CARGO_BUILD_JOBS: "2"
GRADLE_MAX_WORKERS: "2"
RUSTC_WRAPPER: sccache
LITTER_UPLOAD_STORE_FILE: ${{ env.LITTER_UPLOAD_STORE_FILE }}
LITTER_UPLOAD_STORE_PASSWORD: ${{ secrets.LITTER_UPLOAD_STORE_PASSWORD }}
Expand All @@ -328,7 +331,6 @@ jobs:
LITTER_VERSION_CODE_OVERRIDE: ${{ env.LITTER_VERSION_CODE_OVERRIDE }}
run: |
set -euo pipefail
export SCCACHE_ERROR_LOG="$RUNNER_TEMP/sccache-android.log"
trap 'status=$?; echo "==> sccache stats"; sccache --show-stats || true; if [ -f "$SCCACHE_ERROR_LOG" ]; then echo "==> sccache error log"; tail -200 "$SCCACHE_ERROR_LOG" || true; fi; exit $status' EXIT
make play-release

Expand Down Expand Up @@ -365,6 +367,7 @@ jobs:
SCCACHE_S3_USE_SSL: "true"
SCCACHE_S3_KEY_PREFIX: ci/ios
SCCACHE_LOG: info
SCCACHE_ERROR_LOG: ${{ runner.temp }}/sccache-ios.log
AWS_ACCESS_KEY_ID: ${{ secrets.SCCACHE_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.SCCACHE_R2_SECRET_ACCESS_KEY }}

Expand Down Expand Up @@ -421,7 +424,6 @@ jobs:

- name: Prime sccache
run: |
export SCCACHE_ERROR_LOG="$RUNNER_TEMP/sccache-ios.log"
rm -f "$SCCACHE_ERROR_LOG"
sccache --stop-server || true
sccache --start-server
Expand All @@ -441,6 +443,8 @@ jobs:
fi

tar -xzf "$SHARED_PREP_ROOT/generated-mobile-sources.tgz" -C .
mkdir -p .build-stamps
touch .build-stamps/sync .build-stamps/bindings-swift

- name: Decode App Store Connect API key
env:
Expand Down Expand Up @@ -502,6 +506,7 @@ jobs:

- name: Upload to TestFlight
env:
CARGO_BUILD_JOBS: "2"
RUSTC_WRAPPER: sccache
SCHEME: ${{ env.SCHEME }}
APP_BUNDLE_ID: ${{ env.APP_BUNDLE_ID }}
Expand All @@ -516,6 +521,5 @@ jobs:
WAIT_FOR_PROCESSING: ${{ env.WAIT_FOR_PROCESSING }}
run: |
set -euo pipefail
export SCCACHE_ERROR_LOG="$RUNNER_TEMP/sccache-ios.log"
trap 'status=$?; echo "==> sccache stats"; sccache --show-stats || true; if [ -f "$SCCACHE_ERROR_LOG" ]; then echo "==> sccache error log"; tail -200 "$SCCACHE_ERROR_LOG" || true; fi; exit $status' EXIT
make testflight
7 changes: 1 addition & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,12 +170,7 @@ Incremental policy:
- For Xcode project regeneration, use `make xcgen` or `./apps/ios/scripts/regenerate-project.sh`. Do not run `xcodegen generate --spec project.yml --project Litter.xcodeproj` from inside `apps/ios`; that produces a nested `apps/ios/Litter.xcodeproj/Litter.xcodeproj`.
- For Android emulator debugging, build with `make android-emulator-fast`, install with `adb -e install -r apps/android/app/build/outputs/apk/debug/app-debug.apk`, then launch with `adb -e shell am start -n com.sigkitten.litter.android/com.litter.android.MainActivity`.
- Keep both runtimes available when validating shared Rust changes: boot a simulator with `xcrun simctl boot <device>` or through Simulator.app, and verify an emulator is visible with `adb devices -l`.
- Start the collector with `cargo run --manifest-path shared/rust-bridge/Cargo.toml -p mobile-log-collector -- serve --bind 0.0.0.0:8585 --data-dir /tmp/mobile-log-collector-e2e`.
- Query stored logs with either raw HTTP or the CLI: `curl 'http://127.0.0.1:8585/v1/query?limit=20'` or `cargo run --manifest-path shared/rust-bridge/Cargo.toml -p mobile-log-collector -- query --base-url http://127.0.0.1:8585 --device-id <id> --pretty`.
- iOS simulator log config lives under the app container at `.../Library/Application Support/codex/log-spool/config.json`; use `xcrun simctl get_app_container booted com.sigkitten.litter data` to find the current container, then write the config there.
- Android log config lives at `files/codex-home/log-spool/config.json` inside the app sandbox; write it with `adb shell run-as com.sigkitten.litter.android ...`. When the collector runs on the host machine, use `http://10.0.2.2:8585` from the Android emulator and `http://127.0.0.1:8585` from the iOS simulator.
- A minimal debug config should set `enabled: true`, `collector_url`, `min_level: "DEBUG"`, and stable `device_id` / `device_name` fields so batches can be filtered reliably.
- After launch, verify upload by checking that `log-spool/pending` drains, then query the collector for the target `device_id`. If you need direct storage inspection, query `/tmp/mobile-log-collector-e2e/collector.sqlite3` and decompress batch files under `/tmp/mobile-log-collector-e2e/batches/...`.
- Mobile logs now stay local: use Xcode/device console for iOS, Logcat for Android, and normal Rust `tracing` output instead of a collector or spool directory.

## Coding Style & Naming Conventions
- Swift style follows standard Xcode defaults: 4-space indentation, `UpperCamelCase` for types, `lowerCamelCase` for properties/functions.
Expand Down
26 changes: 6 additions & 20 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ ANDROID_RUST_PROFILE ?= android-dev
ANDROID_RELEASE_ABIS ?= arm64-v8a,x86_64
HOST_ARCH := $(shell uname -m)
ANDROID_EMULATOR_ABIS ?= $(if $(filter arm64 aarch64,$(HOST_ARCH)),arm64-v8a,x86_64)
LOG_COLLECTOR_BIND ?= 0.0.0.0:8585
LOG_COLLECTOR_DATA_DIR ?= /tmp/mobile-log-collector-e2e

# Auto-detect Android SDK/NDK/JDK paths (macOS defaults, overridable via env)
ANDROID_SDK_ROOT ?= $(or $(ANDROID_HOME),$(wildcard $(HOME)/Library/Android/sdk))
Expand All @@ -52,11 +50,6 @@ endif

PACKAGE_CARGO_ENV := CARGO_INCREMENTAL=0

# Forward log collector env vars to xcodebuild as build settings
XCODE_EXTRA_SETTINGS :=
ifdef LOG_COLLECTOR_URL
XCODE_EXTRA_SETTINGS += LOG_COLLECTOR_URL='$(LOG_COLLECTOR_URL)'
endif
DEV_CARGO_ENV := env -u CARGO_INCREMENTAL

PATCH_FILES := \
Expand Down Expand Up @@ -96,7 +89,6 @@ $(shell mkdir -p $(STAMPS))
android android-fast android-emulator-fast android-emulator-run android-device-run android-release android-debug android-install android-emulator-install \
rust-ios rust-ios-package rust-ios-device-fast rust-ios-sim-fast rust-android rust-check rust-test rust-host-dev \
bindings bindings-swift bindings-kotlin \
log-collector \
sync patch unpatch xcgen ios-frameworks \
ios-build ios-build-sim ios-build-sim-fast ios-build-device ios-build-device-fast \
test test-rust test-ios test-android \
Expand Down Expand Up @@ -153,7 +145,7 @@ android-emulator-run: android-emulator-fast
adb -s "$$EMU" shell am start -n $(ANDROID_PACKAGE)/$(ANDROID_ACTIVITY)
android-device-run: android-fast
@echo "==> Installing and launching on connected device..."
@DEVICE=$${ANDROID_DEVICE_SERIAL:-$$(adb devices | awk 'NR>1 && $$2=="device" && $$1 !~ /^emulator-/ {print $$1; exit}')} && \
@DEVICE=$${ANDROID_DEVICE_SERIAL:-$$(adb devices | awk -F'\t' 'NR>1 && $$2=="device" && $$1 !~ /^emulator-/ {print $$1; exit}')} && \
if [ -z "$$DEVICE" ]; then echo "ERROR: no connected Android device found (set ANDROID_DEVICE_SERIAL=<serial> to override)"; exit 1; fi && \
echo "==> Using device $$DEVICE..." && \
INSTALL_OUTPUT=$$(adb -s "$$DEVICE" install -r $(ANDROID_APK) 2>&1) && \
Expand Down Expand Up @@ -205,11 +197,6 @@ rust-test:

rust-host-dev: rust-check rust-test

log-collector:
@echo "==> Starting local mobile log collector on $(LOG_COLLECTOR_BIND)..."
@echo "==> Web tail UI will be available at /tail on that server."
@cd $(ROOT) && cargo run --manifest-path $(RUST_DIR)/Cargo.toml -p mobile-log-collector -- serve --bind $(LOG_COLLECTOR_BIND) --data-dir $(LOG_COLLECTOR_DATA_DIR)

rust-android: $(STAMP_RUST_ANDROID)
$(STAMP_RUST_ANDROID): $(STAMP_SYNC) $(STAMP_BINDINGS_K) $(ANDROID_RUST_SOURCES) tools/scripts/build-android-rust.sh Makefile
@echo "==> Building Rust for Android..."
Expand All @@ -231,7 +218,6 @@ help:
'make android-emulator-run fast emulator build + install + launch on emulator' \
'make android-device-run fast Android dev build + install + launch on connected device (override ANDROID_DEVICE_SERIAL; set ANDROID_REINSTALL_ON_SIGNATURE_MISMATCH=0 to keep installed app)' \
'make android-release Android build using release Rust profile and multi-ABI output' \
'make log-collector start local log collector + web tail UI (override LOG_COLLECTOR_BIND / LOG_COLLECTOR_DATA_DIR)' \
'make rust-check host cargo check for shared crates' \
'make rust-test host cargo test for shared crates'

Expand Down Expand Up @@ -304,31 +290,31 @@ ios-build-sim: verify-ios-project
-scheme $(IOS_SCHEME) \
-configuration $(XCODE_CONFIG) \
-destination 'platform=iOS Simulator,name=$(IOS_SIM_DEVICE)' \
$(XCODE_EXTRA_SETTINGS) build
build

ios-build-sim-fast: verify-ios-project
@echo "==> Building iOS ($(XCODE_CONFIG), fast simulator)..."
@xcodebuild -project $(IOS_DIR)/Litter.xcodeproj \
-scheme $(IOS_SCHEME) \
-configuration $(XCODE_CONFIG) \
-destination 'platform=iOS Simulator,name=$(IOS_SIM_DEVICE)' \
$(XCODE_EXTRA_SETTINGS) build
build

ios-build-device: verify-ios-project
@echo "==> Building iOS ($(XCODE_CONFIG), device)..."
@xcodebuild -project $(IOS_DIR)/Litter.xcodeproj \
-scheme $(IOS_SCHEME) \
-configuration $(XCODE_CONFIG) \
-destination 'generic/platform=iOS' \
$(XCODE_EXTRA_SETTINGS) build
build

ios-build-device-fast: verify-ios-project
@echo "==> Building iOS ($(XCODE_CONFIG), fast device)..."
@xcodebuild -project $(IOS_DIR)/Litter.xcodeproj \
-scheme $(IOS_SCHEME) \
-configuration $(XCODE_CONFIG) \
-destination 'generic/platform=iOS' \
$(XCODE_EXTRA_SETTINGS) build
build

ios-build: ios-build-sim

Expand All @@ -338,7 +324,7 @@ android-debug:

android-install: android-debug
@echo "==> Installing APK to device..."
@DEVICE=$${ANDROID_DEVICE_SERIAL:-$$(adb devices | awk 'NR>1 && $$2=="device" && $$1 !~ /^emulator-/ {print $$1; exit}')} && \
@DEVICE=$${ANDROID_DEVICE_SERIAL:-$$(adb devices | awk -F'\t' 'NR>1 && $$2=="device" && $$1 !~ /^emulator-/ {print $$1; exit}')} && \
if [ -z "$$DEVICE" ]; then echo "ERROR: no connected Android device found (set ANDROID_DEVICE_SERIAL=<serial> to override)"; exit 1; fi && \
echo "==> Using device $$DEVICE..." && \
INSTALL_OUTPUT=$$(adb -s "$$DEVICE" install -r $(ANDROID_DIR)/app/build/outputs/apk/debug/app-debug.apk 2>&1) && \
Expand Down
1 change: 0 additions & 1 deletion apps/android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ android {
buildConfigField("boolean", "ENABLE_ON_DEVICE_BRIDGE", "true")
buildConfigField("String", "RUNTIME_STARTUP_MODE", "\"hybrid\"")
buildConfigField("String", "APP_RUNTIME_TRANSPORT", "\"app_bridge_rpc_transport\"")
buildConfigField("String", "LOG_COLLECTOR_URL", "\"${System.getenv("LOG_COLLECTOR_URL") ?: ""}\"")
manifestPlaceholders["runtimeStartupMode"] = "hybrid"
manifestPlaceholders["enableOnDeviceBridge"] = "true"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ class MainActivity : ComponentActivity() {
archived = false, cwd = null, searchTerm = null,
),
)
appModel.refreshSnapshot()
LLog.i("MainActivity", "Local in-process server connected")
} catch (e: Exception) {
LLog.w("MainActivity", "Local server failed", fields = mapOf("error" to e.message))
Expand Down
Loading
Loading