diff --git a/ios/BUILD_STATE.md b/ios/BUILD_STATE.md
new file mode 100644
index 0000000..622e694
--- /dev/null
+++ b/ios/BUILD_STATE.md
@@ -0,0 +1,47 @@
+# iOS Build State — ChronoMind
+
+## Current Build
+**CURRENT_PROJECT_VERSION = 1**
+Marketing version: 1.0.0
+
+---
+
+## Build History
+
+| Build | Status | Key Changes |
+|-------|--------|-------------|
+| 1 | Pending | Initial TestFlight release — fix theme duplicates, remove App Groups (temp), bundle ID → com.saravana.chronomind |
+
+---
+
+## Bundle IDs (Registered in App Store Connect)
+
+| Target | Bundle ID |
+|--------|-----------|
+| ChronoMind | `com.saravana.chronomind` |
+| ChronoMindWidgets | `com.saravana.chronomind.widgets` |
+| ChronoMindWatch | `com.saravana.chronomind.watchkitapp` |
+| ChronoMindMac | `com.saravana.chronomind.mac` |
+
+## App Store Connect API Key
+
+| Field | Value |
+|-------|-------|
+| Key ID | `PPATU9GL73` |
+| Issuer ID | `1dbc2980-1621-4fb9-940b-e28257e6322c` |
+| Key Path | `~/.appstoreconnect/private_keys/AuthKey_PPATU9GL73.p8` |
+
+## Pre-Release Checklist
+
+- [x] Bundle IDs registered (iOS + widgets)
+- [ ] App record created in App Store Connect
+- [ ] App Group `group.com.chronomind.shared` registered (needed for widget ↔ app data sharing)
+- [ ] First TestFlight upload
+
+---
+
+## Next Steps
+
+1. Create app record in App Store Connect (manual — API key needs Admin role)
+2. Run `bash ios/release-testflight.sh` from home network
+3. After first upload succeeds, register App Group and re-enable entitlements
diff --git a/ios/ChronoMind.xcodeproj/project.pbxproj b/ios/ChronoMind.xcodeproj/project.pbxproj
index 9e72d07..287d8b4 100644
--- a/ios/ChronoMind.xcodeproj/project.pbxproj
+++ b/ios/ChronoMind.xcodeproj/project.pbxproj
@@ -1173,7 +1173,7 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.chronomind.app;
+ PRODUCT_BUNDLE_IDENTIFIER = com.saravana.chronomind;
SDKROOT = iphoneos;
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
@@ -1203,7 +1203,7 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.chronomind.app;
+ PRODUCT_BUNDLE_IDENTIFIER = com.saravana.chronomind;
SDKROOT = iphoneos;
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
@@ -1222,7 +1222,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = com.chronomind.tests;
+ PRODUCT_BUNDLE_IDENTIFIER = com.saravana.chronomind.tests;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ChronoMind.app/ChronoMind";
@@ -1244,7 +1244,7 @@
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.0.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.chronomind.app.watchkitapp.complications;
+ PRODUCT_BUNDLE_IDENTIFIER = com.saravana.chronomind.watchkitapp.complications;
SDKROOT = watchos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = 4;
@@ -1263,7 +1263,7 @@
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
- PRODUCT_BUNDLE_IDENTIFIER = com.chronomind.tests;
+ PRODUCT_BUNDLE_IDENTIFIER = com.saravana.chronomind.tests;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ChronoMind.app/ChronoMind";
@@ -1279,10 +1279,10 @@
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_GENERATION_MODE = GeneratedFile;
INFOPLIST_KEY_CFBundleDisplayName = ChronoMind;
- INFOPLIST_KEY_WKCompanionAppBundleIdentifier = com.chronomind.app;
+ INFOPLIST_KEY_WKCompanionAppBundleIdentifier = com.saravana.chronomind;
INFOPLIST_KEY_WKRunsIndependentlyOfCompanionApp = YES;
MARKETING_VERSION = 1.0.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.chronomind.app.watchkitapp;
+ PRODUCT_BUNDLE_IDENTIFIER = com.saravana.chronomind.watchkitapp;
SDKROOT = watchos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = 4;
@@ -1307,7 +1307,7 @@
);
MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1.0.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.chronomind.mac;
+ PRODUCT_BUNDLE_IDENTIFIER = com.saravana.chronomind.mac;
SDKROOT = macosx;
};
name = Release;
@@ -1327,7 +1327,7 @@
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.0.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.chronomind.app.watchkitapp.complications;
+ PRODUCT_BUNDLE_IDENTIFIER = com.saravana.chronomind.watchkitapp.complications;
SDKROOT = watchos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = 4;
@@ -1351,7 +1351,7 @@
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.0.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.chronomind.app.widgets;
+ PRODUCT_BUNDLE_IDENTIFIER = com.saravana.chronomind.widgets;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
@@ -1426,10 +1426,10 @@
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_GENERATION_MODE = GeneratedFile;
INFOPLIST_KEY_CFBundleDisplayName = ChronoMind;
- INFOPLIST_KEY_WKCompanionAppBundleIdentifier = com.chronomind.app;
+ INFOPLIST_KEY_WKCompanionAppBundleIdentifier = com.saravana.chronomind;
INFOPLIST_KEY_WKRunsIndependentlyOfCompanionApp = YES;
MARKETING_VERSION = 1.0.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.chronomind.app.watchkitapp;
+ PRODUCT_BUNDLE_IDENTIFIER = com.saravana.chronomind.watchkitapp;
SDKROOT = watchos;
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = 4;
@@ -1521,7 +1521,7 @@
);
MACOSX_DEPLOYMENT_TARGET = 14.0;
MARKETING_VERSION = 1.0.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.chronomind.mac;
+ PRODUCT_BUNDLE_IDENTIFIER = com.saravana.chronomind.mac;
SDKROOT = macosx;
};
name = Debug;
@@ -1542,7 +1542,7 @@
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 1.0.0;
- PRODUCT_BUNDLE_IDENTIFIER = com.chronomind.app.widgets;
+ PRODUCT_BUNDLE_IDENTIFIER = com.saravana.chronomind.widgets;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
diff --git a/ios/ChronoMind/ChronoMind.entitlements b/ios/ChronoMind/ChronoMind.entitlements
index cc45b00..6631ffa 100644
--- a/ios/ChronoMind/ChronoMind.entitlements
+++ b/ios/ChronoMind/ChronoMind.entitlements
@@ -2,9 +2,5 @@
- com.apple.security.application-groups
-
- group.com.chronomind.shared
-
diff --git a/ios/ChronoMindWidgets/ChronoMindWidgets.entitlements b/ios/ChronoMindWidgets/ChronoMindWidgets.entitlements
index cc45b00..6631ffa 100644
--- a/ios/ChronoMindWidgets/ChronoMindWidgets.entitlements
+++ b/ios/ChronoMindWidgets/ChronoMindWidgets.entitlements
@@ -2,9 +2,5 @@
- com.apple.security.application-groups
-
- group.com.chronomind.shared
-
diff --git a/ios/README_TESTFLIGHT.md b/ios/README_TESTFLIGHT.md
new file mode 100644
index 0000000..25b5638
--- /dev/null
+++ b/ios/README_TESTFLIGHT.md
@@ -0,0 +1,161 @@
+# ChronoMind — TestFlight Release Guide
+
+## One-Time Setup (Home Laptop)
+
+### 1. Install prerequisites
+
+```bash
+# Xcode (from App Store or xcodereleases.com)
+xcode-select --install
+
+# XcodeGen
+brew install xcodegen
+```
+
+### 2. Clone sibling repos
+
+The iOS app depends on `ByteLystPlatformSDK` from the common platform repo. Both repos must be siblings:
+
+```
+~/code/mygh/
+├── learning_ai_clock/ # This repo
+└── learning_ai_common_plat/ # ByteLystPlatformSDK lives here
+```
+
+```bash
+cd ~/code/mygh
+git clone https://github.com/saravanakumardb1/learning_ai_common_plat.git
+```
+
+### 3. App Store Connect API Key
+
+The key is already created. Copy it from your work machine:
+
+```bash
+mkdir -p ~/.appstoreconnect/private_keys
+# Copy AuthKey_PPATU9GL73.p8 to ~/.appstoreconnect/private_keys/
+chmod 600 ~/.appstoreconnect/private_keys/AuthKey_PPATU9GL73.p8
+```
+
+| Field | Value |
+|-------|-------|
+| Key ID | `PPATU9GL73` |
+| Issuer ID | `1dbc2980-1621-4fb9-940b-e28257e6322c` |
+
+### 4. Create app in App Store Connect (one-time)
+
+1. Go to [App Store Connect → My Apps](https://appstoreconnect.apple.com/apps)
+2. Click **"+"** → **"New App"**
+3. Fill in:
+ - **Platform:** iOS
+ - **Name:** `ChronoMind`
+ - **Primary Language:** English (U.S.)
+ - **Bundle ID:** `com.saravana.chronomind` (already registered)
+ - **SKU:** `chronomind`
+4. Click **Create**
+
+---
+
+## Release to TestFlight
+
+### Quick release (one command)
+
+```bash
+cd ios
+bash release-testflight.sh
+```
+
+This will:
+1. Bump the build number in `project.yml`
+2. Regenerate the Xcode project via `xcodegen`
+3. Verify the debug build compiles
+4. Archive a Release build
+5. Export and upload to App Store Connect
+6. Update `BUILD_STATE.md`
+7. Commit and push
+
+### Re-upload a failed upload
+
+If the archive succeeded but upload failed:
+
+```bash
+bash release-testflight.sh --skip-build
+```
+
+### Custom API key location
+
+```bash
+ASC_KEY_ID=XXXX ASC_ISSUER_ID=yyyy ASC_KEY_PATH=/path/to/key.p8 bash release-testflight.sh
+```
+
+---
+
+## Manual Steps (if script fails)
+
+### Generate Xcode project
+
+```bash
+cd ios
+xcodegen generate
+```
+
+### Build (simulator, no signing)
+
+```bash
+xcodebuild build \
+ -project ChronoMind.xcodeproj \
+ -scheme ChronoMind \
+ -configuration Debug \
+ -destination 'platform=iOS Simulator,name=iPhone 16 Pro' \
+ CODE_SIGN_IDENTITY=- CODE_SIGNING_ALLOWED=NO
+```
+
+### Archive
+
+```bash
+xcodebuild archive \
+ -project ChronoMind.xcodeproj \
+ -scheme ChronoMind \
+ -configuration Release \
+ -archivePath /tmp/ChronoMind_1.xcarchive \
+ -destination 'generic/platform=iOS'
+```
+
+### Export + Upload
+
+```bash
+xcodebuild -exportArchive \
+ -archivePath /tmp/ChronoMind_1.xcarchive \
+ -exportPath /tmp/ChronoMind_export1 \
+ -exportOptionsPlist ExportOptions.plist \
+ -allowProvisioningUpdates \
+ -authenticationKeyPath ~/.appstoreconnect/private_keys/AuthKey_PPATU9GL73.p8 \
+ -authenticationKeyID PPATU9GL73 \
+ -authenticationKeyIssuerID 1dbc2980-1621-4fb9-940b-e28257e6322c
+```
+
+---
+
+## Troubleshooting
+
+| Error | Fix |
+|-------|-----|
+| `xcodegen not found` | `brew install xcodegen` |
+| `ByteLystPlatformSDK not found` | Clone `learning_ai_common_plat` as sibling directory |
+| `Authentication failed` | Check API key path, Key ID, and Issuer ID |
+| `Error Downloading App Information` | Create the app record in App Store Connect first (see Setup §4) |
+| `No signing certificate "iOS Distribution"` | Use `-allowProvisioningUpdates` with API key (script does this) |
+| `App Groups capability` | Register App Group in developer portal, or remove entitlement for initial release |
+| `duplicate 'init(hex:alpha:)'` | Remove duplicate `Color.init(hex:)` from `ChronoMindTheme.generated.swift` |
+
+---
+
+## Project Info
+
+| Field | Value |
+|-------|-------|
+| Bundle ID | `com.saravana.chronomind` |
+| Team ID | `748N7QPX7J` |
+| Min iOS | 17.0 |
+| Xcode | 16.0+ |
+| Swift | 5.9 |
diff --git a/ios/project.yml b/ios/project.yml
index dc3ef3c..a44e901 100644
--- a/ios/project.yml
+++ b/ios/project.yml
@@ -1,6 +1,6 @@
name: ChronoMind
options:
- bundleIdPrefix: com.chronomind
+ bundleIdPrefix: com.saravana.chronomind
deploymentTarget:
iOS: "17.0"
watchOS: "10.0"
@@ -32,7 +32,7 @@ targets:
- "**/.DS_Store"
settings:
base:
- PRODUCT_BUNDLE_IDENTIFIER: com.chronomind.app
+ PRODUCT_BUNDLE_IDENTIFIER: com.saravana.chronomind
INFOPLIST_GENERATION_MODE: GeneratedFile
MARKETING_VERSION: "1.0.0"
CURRENT_PROJECT_VERSION: "1"
@@ -52,9 +52,6 @@ targets:
- package: ByteLystPlatformSDK
entitlements:
path: ChronoMind/ChronoMind.entitlements
- properties:
- com.apple.security.application-groups:
- - group.com.chronomind.shared
ChronoMindTests:
type: bundle.unit-test
@@ -68,7 +65,7 @@ targets:
- target: ChronoMind
settings:
base:
- PRODUCT_BUNDLE_IDENTIFIER: com.chronomind.tests
+ PRODUCT_BUNDLE_IDENTIFIER: com.saravana.chronomind.tests
GENERATE_INFOPLIST_FILE: true
ChronoMindWidgets:
@@ -84,7 +81,7 @@ targets:
- path: ChronoMind/LiveActivity/TimerActivityAttributes.swift
settings:
base:
- PRODUCT_BUNDLE_IDENTIFIER: com.chronomind.app.widgets
+ PRODUCT_BUNDLE_IDENTIFIER: com.saravana.chronomind.widgets
INFOPLIST_GENERATION_MODE: GeneratedFile
GENERATE_INFOPLIST_FILE: true
MARKETING_VERSION: "1.0.0"
@@ -93,9 +90,6 @@ targets:
INFOPLIST_KEY_CFBundleDisplayName: ChronoMind Widgets
entitlements:
path: ChronoMindWidgets/ChronoMindWidgets.entitlements
- properties:
- com.apple.security.application-groups:
- - group.com.chronomind.shared
ChronoMindWatch:
type: application
@@ -110,12 +104,12 @@ targets:
- path: ChronoMind/Shared/AppGroup
settings:
base:
- PRODUCT_BUNDLE_IDENTIFIER: com.chronomind.app.watchkitapp
+ PRODUCT_BUNDLE_IDENTIFIER: com.saravana.chronomind.watchkitapp
INFOPLIST_GENERATION_MODE: GeneratedFile
GENERATE_INFOPLIST_FILE: true
MARKETING_VERSION: "1.0.0"
CURRENT_PROJECT_VERSION: "1"
- INFOPLIST_KEY_WKCompanionAppBundleIdentifier: com.chronomind.app
+ INFOPLIST_KEY_WKCompanionAppBundleIdentifier: com.saravana.chronomind
INFOPLIST_KEY_CFBundleDisplayName: ChronoMind
INFOPLIST_KEY_WKRunsIndependentlyOfCompanionApp: true
dependencies:
@@ -138,7 +132,7 @@ targets:
- path: ChronoMind/Shared/AppGroup
settings:
base:
- PRODUCT_BUNDLE_IDENTIFIER: com.chronomind.app.watchkitapp.complications
+ PRODUCT_BUNDLE_IDENTIFIER: com.saravana.chronomind.watchkitapp.complications
INFOPLIST_GENERATION_MODE: GeneratedFile
GENERATE_INFOPLIST_FILE: true
MARKETING_VERSION: "1.0.0"
@@ -168,7 +162,7 @@ targets:
- package: ByteLystPlatformSDK
settings:
base:
- PRODUCT_BUNDLE_IDENTIFIER: com.chronomind.mac
+ PRODUCT_BUNDLE_IDENTIFIER: com.saravana.chronomind.mac
INFOPLIST_GENERATION_MODE: GeneratedFile
GENERATE_INFOPLIST_FILE: true
MARKETING_VERSION: "1.0.0"
diff --git a/ios/release-testflight.sh b/ios/release-testflight.sh
new file mode 100755
index 0000000..db46c08
--- /dev/null
+++ b/ios/release-testflight.sh
@@ -0,0 +1,186 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+# ── ChronoMind — TestFlight Release Script ──────────────────────────
+# Run from: learning_ai_clock/ios/
+# Prerequisites: Xcode 16+, xcodegen, App Store Connect API key
+# Usage: bash release-testflight.sh
+# bash release-testflight.sh --skip-build # re-upload existing archive
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+cd "$SCRIPT_DIR"
+
+# ── Configuration ────────────────────────────────────────────────────
+SCHEME="ChronoMind"
+PROJECT="ChronoMind.xcodeproj"
+BUNDLE_ID="com.saravana.chronomind"
+TEAM_ID="748N7QPX7J"
+EXPORT_OPTIONS="ExportOptions.plist"
+
+# App Store Connect API Key (create at https://appstoreconnect.apple.com/access/integrations/api)
+ASC_KEY_ID="${ASC_KEY_ID:-PPATU9GL73}"
+ASC_ISSUER_ID="${ASC_ISSUER_ID:-1dbc2980-1621-4fb9-940b-e28257e6322c}"
+ASC_KEY_PATH="${ASC_KEY_PATH:-$HOME/.appstoreconnect/private_keys/AuthKey_${ASC_KEY_ID}.p8}"
+
+# ── Helpers ──────────────────────────────────────────────────────────
+RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
+step() { echo -e "\n${CYAN}▸ $1${NC}"; }
+ok() { echo -e "${GREEN}✅ $1${NC}"; }
+warn() { echo -e "${YELLOW}⚠️ $1${NC}"; }
+fail() { echo -e "${RED}❌ $1${NC}"; exit 1; }
+
+# ── Parse args ───────────────────────────────────────────────────────
+SKIP_BUILD=false
+for arg in "$@"; do
+ case "$arg" in
+ --skip-build) SKIP_BUILD=true ;;
+ --help|-h) echo "Usage: bash release-testflight.sh [--skip-build]"; exit 0 ;;
+ esac
+done
+
+# ── Pre-flight checks ───────────────────────────────────────────────
+step "Pre-flight checks"
+
+command -v xcodebuild >/dev/null 2>&1 || fail "xcodebuild not found — install Xcode"
+command -v xcodegen >/dev/null 2>&1 || fail "xcodegen not found — brew install xcodegen"
+
+[ -f "$ASC_KEY_PATH" ] || fail "API key not found at $ASC_KEY_PATH
+ Create one at https://appstoreconnect.apple.com/access/integrations/api
+ Save as ~/.appstoreconnect/private_keys/AuthKey_.p8
+ Then export ASC_KEY_ID= ASC_ISSUER_ID="
+
+[ -f "$EXPORT_OPTIONS" ] || fail "ExportOptions.plist not found in ios/"
+[ -f "project.yml" ] || fail "project.yml not found — are you in the ios/ directory?"
+
+# Check sibling SDK exists
+SDK_PATH="../../learning_ai_common_plat/packages/swift-platform-sdk/Package.swift"
+[ -f "$SDK_PATH" ] || fail "ByteLystPlatformSDK not found at $SDK_PATH
+ Ensure learning_ai_common_plat is cloned as a sibling directory"
+
+ok "All pre-flight checks passed"
+
+# ── Read current build number ────────────────────────────────────────
+step "Reading current build number"
+
+CURRENT_BUILD=$(grep -m1 "CURRENT_PROJECT_VERSION" project.yml | awk -F'"' '{print $2}')
+[ -z "$CURRENT_BUILD" ] && fail "Could not read CURRENT_PROJECT_VERSION from project.yml"
+
+NEXT_BUILD=$((CURRENT_BUILD + 1))
+echo " Current: $CURRENT_BUILD → Next: $NEXT_BUILD"
+
+if [ "$SKIP_BUILD" = true ]; then
+ ARCHIVE_PATH="/tmp/${SCHEME}_${CURRENT_BUILD}.xcarchive"
+ [ -d "$ARCHIVE_PATH" ] || fail "No archive found at $ARCHIVE_PATH — run without --skip-build first"
+ warn "Skipping build — using existing archive at $ARCHIVE_PATH"
+ NEXT_BUILD=$CURRENT_BUILD
+else
+ # ── Bump build number ────────────────────────────────────────────
+ step "Bumping build number to $NEXT_BUILD"
+
+ sed -i '' "s/CURRENT_PROJECT_VERSION: \"$CURRENT_BUILD\"/CURRENT_PROJECT_VERSION: \"$NEXT_BUILD\"/g" project.yml
+ ok "project.yml updated"
+
+ # ── Regenerate Xcode project ─────────────────────────────────────
+ step "Generating Xcode project"
+ xcodegen generate
+ ok "Xcode project generated"
+
+ # ── Verify build ─────────────────────────────────────────────────
+ step "Verifying debug build"
+ xcodebuild build \
+ -project "$PROJECT" \
+ -scheme "$SCHEME" \
+ -configuration Debug \
+ -destination 'platform=iOS Simulator,name=iPhone 16 Pro' \
+ CODE_SIGN_IDENTITY=- CODE_SIGNING_ALLOWED=NO \
+ 2>&1 | tail -1
+
+ # ── Archive ──────────────────────────────────────────────────────
+ ARCHIVE_PATH="/tmp/${SCHEME}_${NEXT_BUILD}.xcarchive"
+
+ step "Archiving build $NEXT_BUILD"
+ xcodebuild archive \
+ -project "$PROJECT" \
+ -scheme "$SCHEME" \
+ -configuration Release \
+ -archivePath "$ARCHIVE_PATH" \
+ -destination 'generic/platform=iOS' \
+ 2>&1 | tail -1
+
+ [ -d "$ARCHIVE_PATH" ] || fail "Archive not found at $ARCHIVE_PATH"
+ ok "Archive succeeded: $ARCHIVE_PATH"
+
+ # ── Commit ───────────────────────────────────────────────────────
+ step "Committing build number bump"
+ cd "$SCRIPT_DIR/.."
+ git add ios/project.yml ios/ChronoMind.xcodeproj/
+ git commit -m "chore(ios): bump build number to $NEXT_BUILD for TestFlight release" || warn "Nothing to commit"
+ cd "$SCRIPT_DIR"
+fi
+
+# ── Export + Upload ──────────────────────────────────────────────────
+EXPORT_PATH="/tmp/${SCHEME}_export${NEXT_BUILD}"
+
+step "Exporting and uploading build $NEXT_BUILD to TestFlight"
+rm -rf "$EXPORT_PATH"
+
+xcodebuild -exportArchive \
+ -archivePath "$ARCHIVE_PATH" \
+ -exportPath "$EXPORT_PATH" \
+ -exportOptionsPlist "$EXPORT_OPTIONS" \
+ -allowProvisioningUpdates \
+ -authenticationKeyPath "$ASC_KEY_PATH" \
+ -authenticationKeyID "$ASC_KEY_ID" \
+ -authenticationKeyIssuerID "$ASC_ISSUER_ID" \
+ 2>&1 | tail -5
+
+# ── Verify upload ────────────────────────────────────────────────────
+if [ -f "$EXPORT_PATH/${SCHEME}.ipa" ]; then
+ ok "Upload succeeded! Build $NEXT_BUILD sent to TestFlight"
+else
+ # Check if upload succeeded despite no local IPA (destination: upload)
+ if xcodebuild -exportArchive -archivePath "$ARCHIVE_PATH" -exportPath "$EXPORT_PATH" -exportOptionsPlist "$EXPORT_OPTIONS" 2>&1 | grep -q "Upload succeeded"; then
+ ok "Upload succeeded! Build $NEXT_BUILD sent to TestFlight"
+ fi
+fi
+
+# ── Update BUILD_STATE.md ────────────────────────────────────────────
+step "Updating BUILD_STATE.md"
+
+BUILD_STATE="BUILD_STATE.md"
+if [ ! -f "$BUILD_STATE" ]; then
+ cat > "$BUILD_STATE" << 'HEREDOC'
+# iOS Build State — ChronoMind
+
+## Current Build
+**CURRENT_PROJECT_VERSION = 1**
+Marketing version: 1.0.0
+
+---
+
+## Build History
+
+| Build | Status | Key Changes |
+|-------|--------|-------------|
+HEREDOC
+fi
+
+# Update current build number
+sed -i '' "s/CURRENT_PROJECT_VERSION = [0-9]*/CURRENT_PROJECT_VERSION = $NEXT_BUILD/" "$BUILD_STATE"
+
+ok "BUILD_STATE.md updated to build $NEXT_BUILD"
+
+# ── Final commit + push ─────────────────────────────────────────────
+step "Final commit and push"
+cd "$SCRIPT_DIR/.."
+git add ios/BUILD_STATE.md
+git commit -m "docs(ios): update BUILD_STATE.md for build $NEXT_BUILD" || warn "Nothing to commit"
+git push origin main || warn "Push failed — push manually later"
+cd "$SCRIPT_DIR"
+
+echo ""
+echo -e "${GREEN}════════════════════════════════════════════════════════${NC}"
+echo -e "${GREEN} ChronoMind build $NEXT_BUILD uploaded to TestFlight! ${NC}"
+echo -e "${GREEN} It should appear in ~15-30 minutes after processing. ${NC}"
+echo -e "${GREEN}════════════════════════════════════════════════════════${NC}"
+echo ""