# ─── Oppi iOS + macOS ───
# Fork setup: change bundleIdPrefix and DEVELOPMENT_TEAM to your own values.
# See CONTRIBUTING.md for full setup instructions.
name: Oppi
packages:
  swift-markdown:
    url: https://github.com/apple/swift-markdown
    from: "0.7.0"
  swift-cmark:
    url: https://github.com/swiftlang/swift-cmark.git
    from: "0.7.1"
  sentry-cocoa:
    url: https://github.com/getsentry/sentry-cocoa
    from: "8.0.0"
  Sparkle:
    url: https://github.com/sparkle-project/Sparkle
    from: "2.9.0"
options:
  bundleIdPrefix: dev.chenda
  deploymentTarget:
    iOS: "26.0"
    macOS: "15.0"
  xcodeVersion: "26.2"
  generateEmptyDirectories: true
  defaultLocalization: en
configFiles:
  Debug: Base.xcconfig
  Release: Base.xcconfig
settings:
  base:
    SWIFT_VERSION: "6.0"
    SWIFT_STRICT_CONCURRENCY: complete
    TARGETED_DEVICE_FAMILY: 1
    INFOPLIST_KEY_UISupportedInterfaceOrientations: "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"
    INFOPLIST_KEY_UILaunchScreen_Generation: true
    ENABLE_USER_SCRIPT_SANDBOXING: true
    OPPI_TELEMETRY_MODE: "internal"
    APP_GROUP_IDENTIFIER: group.oppi
    DEBUG_INFORMATION_FORMAT: "dwarf-with-dsym"
  configs:
    Release:
      OPPI_TELEMETRY_MODE: "public"
targets:
  Oppi:
    type: application
    platform: iOS
    sources:
      - path: Oppi
        type: group
        excludes:
          - "Resources/AppIcon.icon"
      - path: Oppi/Resources/AppIcon.icon
        type: folder
        buildPhase: resources
      - path: Shared
        type: group
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: dev.chenda.Oppi
        PRODUCT_NAME: Oppi
        MARKETING_VERSION: "1.1.0"
        CURRENT_PROJECT_VERSION: 25
        ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon
        CODE_SIGN_STYLE: Automatic
        DEVELOPMENT_TEAM: AZAQMY4SPZ
        INFOPLIST_KEY_NSSupportsLiveActivities: true
        ENABLE_USER_SCRIPT_SANDBOXING: false
    entitlements:
      path: Oppi/Resources/Oppi.entitlements
      properties:
        com.apple.security.application-groups:
          - $(APP_GROUP_IDENTIFIER)
    info:
      path: Oppi/Resources/Info.plist
      properties:
        UISupportedInterfaceOrientations:
          - UIInterfaceOrientationPortrait
          - UIInterfaceOrientationPortraitUpsideDown
          - UIInterfaceOrientationLandscapeLeft
          - UIInterfaceOrientationLandscapeRight
        CFBundleDisplayName: Oppi
        CFBundleURLTypes:
          - CFBundleTypeRole: Editor
            CFBundleURLName: dev.chenda.oppi.invite
            CFBundleURLSchemes:
              - oppi
              - pi
        UILaunchScreen: {}
        UIBackgroundModes:
          - remote-notification
        NSSupportsLiveActivities: true
        NSCameraUsageDescription: "Oppi uses the camera to take photos for agent conversations."
        NSPhotoLibraryAddUsageDescription: "Oppi saves images from agent conversations to your photo library."
        NSPhotoLibraryUsageDescription: "Oppi accesses your photo library to attach images to agent conversations."
        NSLocalNetworkUsageDescription: "Oppi needs local network access to connect to your Mac server."
        NSBonjourServices:
          - "_oppi._tcp"
        NSMicrophoneUsageDescription: "Oppi uses the microphone to transcribe your voice into text prompts."
        NSSpeechRecognitionUsageDescription: "Oppi uses on-device speech recognition to convert your voice into text."
        NSFaceIDUsageDescription: "Oppi uses Face ID to confirm approval of high-risk agent actions like sudo, force push, and recursive deletes."
        CFBundleShortVersionString: "$(MARKETING_VERSION)"
        CFBundleVersion: "$(CURRENT_PROJECT_VERSION)"
        UIAppFonts:
          - FiraCode-Regular.ttf
          - FiraCode-SemiBold.ttf
          - FiraCode-Bold.ttf
          - JetBrainsMono-Regular.ttf
          - JetBrainsMono-SemiBold.ttf
          - JetBrainsMono-Bold.ttf
          - CascadiaCode-Regular.ttf
          - CascadiaCode-SemiBold.ttf
          - CascadiaCode-Bold.ttf
          - SourceCodePro-Regular.otf
          - SourceCodePro-Semibold.otf
          - SourceCodePro-Bold.otf
          - MonaspaceNeon-Regular.otf
          - MonaspaceNeon-SemiBold.otf
          - MonaspaceNeon-Bold.otf
        ITSAppUsesNonExemptEncryption: false
        SentryDSN: "$(SENTRY_DSN)"
        OPPITelemetryMode: "$(OPPI_TELEMETRY_MODE)"
        NSAppTransportSecurity:
          NSAllowsLocalNetworking: true
          NSExceptionDomains:
            ts.net:
              NSIncludesSubdomains: true
              NSExceptionAllowsInsecureHTTPLoads: true
    preBuildScripts:
      - script: |
          if command -v swiftlint >/dev/null 2>&1; then
            swiftlint lint --config "$SRCROOT/.swiftlint.yml" --quiet
          else
            echo "warning: SwiftLint not installed — brew install swiftlint"
          fi
        name: SwiftLint
        basedOnDependencyAnalysis: false
        shell: /bin/bash
        showEnvVars: false
      - script: |
          if command -v node >/dev/null 2>&1; then
            bun "$SRCROOT/../../server/scripts/check-architecture-boundaries.ts" --scope ios --format xcode
          else
            echo "error: Node.js is required for architecture boundary checks (.internal/ARCHITECTURE.md#ios-layers)"
            exit 1
          fi
        name: ArchitectureBoundaries
        basedOnDependencyAnalysis: false
        shell: /bin/bash
        showEnvVars: false
    postBuildScripts:
      - script: |
          if [ "$SENTRY_DSN" = "" ] || [[ "$SENTRY_DSN" == *'$('* ]]; then
            echo "note: Sentry dSYM upload skipped (no DSN configured)"
            exit 0
          fi
          SENTRY_CLI="/opt/homebrew/bin/sentry-cli"
          if [ ! -x "$SENTRY_CLI" ]; then
            echo "warning: sentry-cli not found — brew install getsentry/tools/sentry-cli"
            exit 0
          fi
          DSYM_PATH="$DWARF_DSYM_FOLDER_PATH/$DWARF_DSYM_FILE_NAME"
          if [ ! -d "$DSYM_PATH" ]; then
            echo "warning: dSYM not found at $DSYM_PATH"
            exit 0
          fi
          echo "Uploading dSYMs to Sentry ($SENTRY_ORG/$SENTRY_PROJECT)..."
          "$SENTRY_CLI" debug-files upload \
            --org "$SENTRY_ORG" \
            --project "$SENTRY_PROJECT" \
            --include-sources \
            "$DSYM_PATH" &
          echo "note: Sentry dSYM upload started in background"
        name: SentryDSYMUpload
        basedOnDependencyAnalysis: false
        shell: /bin/bash
        showEnvVars: false
    dependencies:
      - package: swift-markdown
        product: Markdown
      - package: swift-cmark
        product: cmark-gfm
      - package: swift-cmark
        product: cmark-gfm-extensions
      - package: sentry-cocoa
        product: Sentry
      - target: OppiActivityExtension
        embed: true
      - target: OppiControlWidget
        embed: true

  OppiActivityExtension:
    type: app-extension
    platform: iOS
    sources:
      - path: OppiActivityExtension
        type: group
      - path: Shared
        type: group
    entitlements:
      path: OppiActivityExtension/OppiActivityExtension.entitlements
      properties:
        com.apple.security.application-groups:
          - $(APP_GROUP_IDENTIFIER)
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: dev.chenda.Oppi.ActivityExtension
        MARKETING_VERSION: "1.1.0"
        CURRENT_PROJECT_VERSION: 25
        CODE_SIGN_STYLE: Automatic
        DEVELOPMENT_TEAM: AZAQMY4SPZ
        GENERATE_INFOPLIST_FILE: true
        INFOPLIST_KEY_CFBundleDisplayName: Oppi
        INFOPLIST_KEY_NSExtension_NSExtensionPointIdentifier: com.apple.widgetkit-extension
        INFOPLIST_KEY_NSSupportsLiveActivities: true

  OppiControlWidget:
    type: app-extension
    platform: iOS
    sources:
      - path: OppiControlWidget
        type: group
      - path: Shared
        type: group
    entitlements:
      path: OppiControlWidget/OppiControlWidget.entitlements
      properties:
        com.apple.security.application-groups:
          - $(APP_GROUP_IDENTIFIER)
    info:
      path: OppiControlWidget/Info.plist
      properties:
        CFBundleDisplayName: Oppi
        NSExtension:
          NSExtensionPointIdentifier: com.apple.widgetkit-extension
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: dev.chenda.Oppi.ControlWidget
        MARKETING_VERSION: "1.1.0"
        CURRENT_PROJECT_VERSION: 25
        CODE_SIGN_STYLE: Automatic
        DEVELOPMENT_TEAM: AZAQMY4SPZ
        CODE_SIGN_ALLOW_ENTITLEMENTS_MODIFICATION: "YES"

  OppiTests:
    type: bundle.unit-test
    platform: iOS
    sources:
      - path: OppiTests
        type: group
    dependencies:
      - target: Oppi
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: dev.chenda.OppiTests
        CODE_SIGN_IDENTITY: ""
        CODE_SIGNING_ALLOWED: "NO"

  OppiPerfTests:
    type: bundle.unit-test
    platform: iOS
    sources:
      - path: OppiPerfTests
        type: group
    dependencies:
      - target: Oppi
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: dev.chenda.OppiPerfTests
        CODE_SIGN_IDENTITY: ""
        CODE_SIGNING_ALLOWED: "NO"

  OppiUITests:
    type: bundle.ui-testing
    platform: iOS
    sources:
      - path: OppiUITests
        type: group
    dependencies:
      - target: Oppi
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: dev.chenda.OppiUITests
        CODE_SIGN_IDENTITY: ""
        CODE_SIGNING_ALLOWED: "NO"

  OppiE2ETests:
    type: bundle.ui-testing
    platform: iOS
    sources:
      - path: OppiE2ETests
        type: group
    dependencies:
      - target: Oppi
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: dev.chenda.OppiE2ETests
        CODE_SIGN_IDENTITY: ""
        CODE_SIGNING_ALLOWED: "NO"

  OppiMacTests:
    type: bundle.unit-test
    platform: macOS
    deploymentTarget: "26.0"
    sources:
      - path: OppiMacTests
        type: group
    dependencies:
      - target: OppiMac
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: dev.chenda.OppiMacTests
        CODE_SIGN_IDENTITY: ""
        CODE_SIGNING_ALLOWED: "NO"
        TEST_HOST: "$(BUILT_PRODUCTS_DIR)/Oppi.app/Contents/MacOS/Oppi"
        BUNDLE_LOADER: "$(TEST_HOST)"

  OppiMac:
    type: application
    platform: macOS
    deploymentTarget: "26.0"
    sources:
      - path: OppiMac
        type: group
      - path: Shared
        type: group
        excludes:
          - "PiSessionAttributes.swift"
          - "LiveActivityPresentation.swift"
          - "PermissionLiveActivityIntents.swift"
          - "SharedConstants.swift"
    dependencies:
      - package: Sparkle
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: dev.chenda.OppiMac
        PRODUCT_NAME: Oppi
        MARKETING_VERSION: "0.1.1"
        CURRENT_PROJECT_VERSION: 2
        CODE_SIGN_IDENTITY: "Developer ID Application"
        CODE_SIGN_STYLE: Manual
        DEVELOPMENT_TEAM: AZAQMY4SPZ
        ENABLE_HARDENED_RUNTIME: true
        CODE_SIGN_ENTITLEMENTS: OppiMac/OppiMac.entitlements
    info:
      path: OppiMac/Resources/Info.plist
      properties:
        CFBundleDisplayName: Oppi
        LSUIElement: true
        SUFeedURL: "https://github.com/duh17/oppi/releases/download/appcast/appcast.xml"
        SUPublicEDKey: "wnLCIfY048anOcj7/J/Iv6Lp9Fmba4zQ0EjCL7k/M+E="
        SUEnableAutomaticChecks: true
        SUScheduledCheckInterval: 86400
        NSAppTransportSecurity:
          NSAllowsLocalNetworking: true

schemes:
  Oppi:
    build:
      targets:
        Oppi: all
        OppiActivityExtension: all
        OppiControlWidget: all
        OppiTests: [test]
        OppiPerfTests: [test]
        OppiUITests: [test]
        OppiE2ETests: [test]
    test:
      targets:
        - name: OppiTests
          randomExecutionOrder: true
        - name: OppiPerfTests
        - name: OppiUITests
        - name: OppiE2ETests

  OppiMac:
    build:
      targets:
        OppiMac: all
        OppiMacTests: [test]
    test:
      targets:
        - name: OppiMacTests
          parallelizable: true
          randomExecutionOrder: true
