Ctrl K
ComunidadGuías…

project.yml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
name: Echo
options:
  bundleIdPrefix: com.goosehouse
  deploymentTarget:
    iOS: "26.0"
    watchOS: "26.0"
  xcodeVersion: "27.0"
  createIntermediateGroups: true
  developmentLanguage: en
  generateEmptyDirectories: true
# Code from outside Apple and this repository: the terminal's (Echo/Services/Terminal). Pinned:
# SwiftTerm 1.12 onwards compiles a Metal shader (Xcode's separately downloaded Metal toolchain) and
# 1.20 onwards runs a build-tool plugin Xcode wants trusted before every build and archive; 1.11.2
# needs neither. swift-nio-ssh is Apple's, on Apple's CryptoKit. The packages after swift-nio are
# what these need, pinned here too: Package.resolved is inside Echo.xcodeproj, which isn't kept, so
# without them every fresh checkout would take whatever is newest.
packages:
  SwiftTerm:
    url: https://github.com/migueldeicaza/SwiftTerm
    exactVersion: 1.11.2
  swift-nio-ssh:
    url: https://github.com/apple/swift-nio-ssh
    exactVersion: 0.15.0
  swift-nio:
    url: https://github.com/apple/swift-nio
    exactVersion: 2.104.0
  swift-crypto:
    url: https://github.com/apple/swift-crypto.git
    exactVersion: 4.5.2
  swift-asn1:
    url: https://github.com/apple/swift-asn1.git
    exactVersion: 1.7.3
  swift-atomics:
    url: https://github.com/apple/swift-atomics.git
    exactVersion: 1.3.1
  swift-collections:
    url: https://github.com/apple/swift-collections.git
    exactVersion: 1.7.3
  swift-system:
    url: https://github.com/apple/swift-system.git
    exactVersion: 1.8.1
  swift-argument-parser:
    url: https://github.com/apple/swift-argument-parser
    exactVersion: 1.8.2
settings:
  base:
    DEVELOPMENT_TEAM: 579BSQT6J4
    SWIFT_VERSION: "6.2"
    SWIFT_STRICT_CONCURRENCY: complete
    SWIFT_TREAT_WARNINGS_AS_ERRORS: true
    CODE_SIGN_STYLE: Automatic
    MARKETING_VERSION: "2.4"
    CURRENT_PROJECT_VERSION: "293"
    ENABLE_USER_SCRIPT_SANDBOXING: true
    # Translations: every target's text is pulled into the String Catalog beside its code
    # (Localizable.xcstrings in each target's folder), which the build fills with the English.
    SWIFT_EMIT_LOC_STRINGS: true
targets:
  Echo:
    type: application
    platform: iOS
    sources:
      - path: Echo
        excludes:
          - Resources/Web
          - Resources/Redde.storekit   # the scheme's local test store only; not shipped
      # Folder reference: keeps Web/fonts/ intact so katex.min.css can find its fonts.
      - path: Echo/Resources/Web
        type: folder
        buildPhase: resources
      - path: Shared
    dependencies:
      - target: EchoControls
      - target: EchoShare
      - target: EchoPush
      - target: EchoWatch
      - package: SwiftTerm
      - package: swift-nio-ssh
        product: NIOSSH
      - package: swift-nio
        product: NIOCore
      - package: swift-nio
        product: NIOPosix
    entitlements:
      path: Echo/Echo.entitlements
      properties:
        com.apple.security.application-groups:
          - group.com.goosehouse.echo
        # CarPlay: voice-based conversational apps (iOS 26.4+), enabled on the App ID.
        com.apple.developer.carplay-voice-based-conversation: true
        # Time-sensitive notifications, so Siri can announce Redde's alerts on AirPods.
        com.apple.developer.usernotifications.time-sensitive: true
        # Setup links, https://redde.goosehouse.org/connect#…, open in the app (universal links).
        # The site names this app in .well-known/apple-app-site-association (companion/website).
        com.apple.developer.associated-domains:
          - applinks:redde.goosehouse.org
        # Remote notifications from the push relay (Push Notifications is enabled on the App ID).
        # "development" is what the source carries; the App Store export rewrites it to production.
        aps-environment: development
        # Sync with iCloud (CloudSync): settings and servers in iCloud's key-value store. Their
        # secrets go in iCloud Keychain, which needs nothing more.
        com.apple.developer.ubiquity-kvstore-identifier: $(TeamIdentifierPrefix)$(CFBundleIdentifier)
        # Health-Aware Days (HealthDays): reads sleep, steps and workouts, off until turned on;
        # Health wakes Redde when new sleep or a workout is saved.
        com.apple.developer.healthkit: true
        com.apple.developer.healthkit.access: []
        com.apple.developer.healthkit.background-delivery: true
        # Phone tools › Apple Home (DeviceHome): the agent sees and controls HomeKit accessories,
        # off until turned on. HomeKit is enabled on the App ID for this.
        com.apple.developer.homekit: true
    info:
      path: Echo/Info.plist
      properties:
        CFBundleDisplayName: Redde
        CFBundleShortVersionString: $(MARKETING_VERSION)
        CFBundleVersion: $(CURRENT_PROJECT_VERSION)
        UILaunchScreen: {}
        # CarPlay scene. Multiple-scene support once stopped echo:// opens from widgets reaching the
        # app; the WindowGroup now routes every external event to the existing window (EchoApp).
        UIApplicationSceneManifest:
          UIApplicationSupportsMultipleScenes: true
          UISceneConfigurations:
            CPTemplateApplicationSceneSessionRoleApplication:
              - UISceneClassName: CPTemplateApplicationScene
                UISceneConfigurationName: CarPlay
                UISceneDelegateClassName: $(PRODUCT_MODULE_NAME).CarPlaySceneDelegate
        NSSupportsLiveActivities: true
        # Bundled fonts (Terminal theme). OFL license alongside in Resources/Fonts.
        UIAppFonts:
          - SourceCodePro-Medium.ttf
          - SourceCodePro-Bold.ttf
          - Inter-Regular.ttf
          - Inter-SemiBold.ttf
          - Inter-Bold.ttf
        CFBundleURLTypes:
          - CFBundleURLName: com.goosehouse.echo
            # echo: the app's own links (controls, share extension). redde: setup links,
            # redde://connect, which people see and type.
            CFBundleURLSchemes: [echo, redde]
        # Landscape too, for an iPhone Duo's outer screen standing like a tent: every other iPhone
        # is kept in portrait at run time (`Foldable.orientations`, from the app delegate).
        UISupportedInterfaceOrientations:
          - UIInterfaceOrientationPortrait
          - UIInterfaceOrientationLandscapeLeft
          - UIInterfaceOrientationLandscapeRight
        UISupportedInterfaceOrientations~ipad:
          - UIInterfaceOrientationPortrait
          - UIInterfaceOrientationPortraitUpsideDown
          - UIInterfaceOrientationLandscapeLeft
          - UIInterfaceOrientationLandscapeRight
        ITSAppUsesNonExemptEncryption: false
        # A reply the person started keeps streaming after the phone locks (BackgroundTurn): an
        # iOS 26 continued-processing task, one identifier per turn under this wildcard. Leave-By
        # Alerts (LeaveByAlerts): a background refresh shortly before the next alert, to move it with the traffic.
        BGTaskSchedulerPermittedIdentifiers:
          - com.goosehouse.echo.turn.*
          - com.goosehouse.echo.leaveby
        # `audio`: a voice conversation goes on when Redde isn't in front — the car screen switched
        # to navigation, the phone locked in a pocket — so listening and the spoken reply aren't
        # cut off with the foreground. Without it iOS stops the microphone and silences playback.
        UIBackgroundModes:
          - audio
          - processing
          # Calls from agents (AgentCalls): a VoIP push wakes Redde to ring with CallKit.
          - voip
          # Leave-By Alerts (LeaveByAlerts): the background refresh above.
          - fetch
        NSRemindersFullAccessUsageDescription: With Phone tools turned on, Redde reads and adds reminders when your assistant asks it to. They go only to the server you connect to.
        NSAlarmKitUsageDescription: With Phone tools turned on, Redde sets an alarm or a timer when your assistant asks it to, once you have said yes to it.
        NSContactsUsageDescription: With Phone tools turned on, Redde looks up a contact when your assistant asks it to. What it finds goes only to the server you connect to.
        NSPhotoLibraryUsageDescription: With Phone tools turned on, Redde finds photos, shows one to your assistant, or deletes the ones you confirm, when your assistant asks it to. A photo goes only to the server you connect to.
        # Places (Settings → Agent → Places): arriving at or leaving a place the person set tells the bot they chose.
        # Current Location (Settings → Agent → Current Location): roughly where the person is, for the agent.
        NSLocationWhenInUseUsageDescription: With Places on, Redde uses where you are to set a place and to notice when you arrive or leave; only "arrived at Home" goes to your server. With Current Location on, your own agent hears roughly where you are when you ask about places, directions or the weather. With Leave-By Alerts on, Redde works out from where you are when to leave for an event; where you are goes only to Apple Maps, for the way there.
        NSLocationAlwaysAndWhenInUseUsageDescription: With Places turned on, Redde notices when you arrive at or leave a place you set, even when Redde is closed, and tells the bot you chose. Where you are stays on your iPhone; only "arrived at Home" goes to your server.
        # Redde's folder in the Files app ("On My iPhone › Redde"): what Phone tools' files read and write.
        UIFileSharingEnabled: true
        LSSupportsOpeningDocumentsInPlace: true
        NSMotionUsageDescription: Redde reads head movement from your AirPods so you can nod to approve, or shake your head to deny, a request from your assistant. It is read on this device and never stored or sent.
        NSMicrophoneUsageDescription: Redde listens so you can talk to your assistant. Speech is transcribed on this device and only your own server receives the text, unless you start a live voice call, which goes to the voice service you chose.
        NSCalendarsFullAccessUsageDescription: Redde can show your next event when you start a conversation, and attach a day's events to a message for your assistant. With Phone tools turned on, your assistant can also look up events and add them. Events go only to your own server. With Leave-By Alerts on, Redde also reads your next events on this device and asks Apple Maps how long the way to their address takes, to tell you when to leave.
        NSCameraUsageDescription: Redde uses the camera when you take a photo to attach to a message, when you show your assistant something in voice mode, and to scan a setup code. A photo goes only to the server you connect to.
        NSFaceIDUsageDescription: Redde uses Face ID to unlock the app, which holds your Hermes credentials.
        NSLocalNetworkUsageDescription: Redde connects to the Hermes gateway or model server you configure, which is often on your local network.
        # Health-Aware Days (Settings → Agent → Health), off until turned on.
        NSHealthShareUsageDescription: Redde reads only the Health data you turn on. With Health-Aware Days, last night's sleep, your steps and your workouts shape your agent's morning ideas and evening wrap-up. With Phone Tools › Health, your agent can read the kinds you choose when it asks. It goes only to your own server.
        # Phone tools › Apple Home, off until turned on.
        NSHomeKitUsageDescription: With Phone Tools › Apple Home on, your agent can see your accessories and scenes and control them when you ask. Locks, garage doors, doors, windows and the alarm always ask you first. What it reads goes only to your own server.
        NSHealthUpdateUsageDescription: Redde doesn't save anything to Health. It only reads the Health data you turn on, for Health-Aware Days and Phone Tools.
        # Lets Siri accept "Hey Siri, ask Hermes" in addition to "ask Echo".
        INAlternativeAppNames:
          - INAlternativeAppName: Hermes
            INAlternativeAppNamePronunciationHint: her-meez
          - INAlternativeAppName: Sol
            INAlternativeAppNamePronunciationHint: sole
        # Echo talks only to servers the user configures (self-hosted Hermes, llama.cpp, Kokoro),
        # frequently on private networks without public certificates. Arbitrary loads are
        # allowed for that reason; HTTPS is used whenever the configured URL provides it.
        NSAppTransportSecurity:
          NSAllowsArbitraryLoads: true
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: com.goosehouse.echo
        TARGETED_DEVICE_FAMILY: "1,2"
        SUPPORTS_MACCATALYST: false
        SWIFT_EMIT_LOC_STRINGS: true
        # Redde Face (the bot face on Matte Mist) is the default; Matte Graphite, the glass Graphite
        # (AppIcon) and the rest are alternates.
        ASSETCATALOG_COMPILER_APPICON_NAME: AppIconFaceMist
        ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES: "AppIconBubbleGreen AppIconBubblePurple AppIconBubbleOrange AppIconBubblePink AppIconBubbleGraphite AppIconBubbleYellow AppIconBubbleGold AppIconStarMist AppIconStarGreen AppIconStarPurple AppIconStarOrange AppIconStarPink AppIconStarGraphite AppIconStarYellow AppIconStarGold AppIconGhostBlue AppIconGhostGreen AppIconGhostPurple AppIconGhostOrange AppIconGhostPink AppIconGhostGraphite AppIconGhostYellow AppIconGhostGold AppIcon AppIconGraphiteBlock AppIconSteelBlock AppIconMist AppIconGraphiteFlat AppIconGraphiteBlockFlat AppIconSteelFlat AppIconMistFlat AppIconNavyBlock AppIconInk AppIconPaperNavy AppIconGold AppIconClassic"
        ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME: AccentColor
        SWIFT_APPROACHABLE_CONCURRENCY: true
        SWIFT_DEFAULT_ACTOR_ISOLATION: MainActor
        SWIFT_OBJC_BRIDGING_HEADER: Echo/App/Echo-Bridging-Header.h
      configs:
        # The personal prefill never rides along in a Release / App Store build.
        Release:
          EXCLUDED_SOURCE_FILE_NAMES: LocalDefaults.json
  # The Apple Watch app. It talks to Hermes itself, with the connection the phone hands over
  # (Shared/WatchSync.swift), through the same transport code as the phone: those files are
  # listed one by one, since the rest of the app assumes iOS.
  EchoWatch:
    type: application
    platform: watchOS
    sources:
      - path: Watch
      - path: Shared/WatchSync.swift
      - path: Shared/WatchRelay.swift
      - path: Shared/Attachment.swift
      - path: Shared/PlainText.swift
      - path: Shared/ReplyMedia.swift
      - path: Echo/Services/Keychain.swift
      - path: Echo/Models/Message.swift
      - path: Echo/Models/ReplyCards.swift
      - path: Echo/Models/ReplyCardsMore.swift
      - path: Echo/Models/MailModels.swift
      - path: Echo/Models/WatchChats.swift
      # The complication's look and its link, shared with the extension that draws it.
      - path: WatchWidgets/AskComplication.swift
      - path: Echo/Models/ReplyLanguage.swift
      - path: Echo/Models/TurnNotes.swift
      - path: Echo/Models/MeasureUnits.swift
      - path: Echo/Models/CalendarChoice.swift
      - path: Echo/Models/CurrentLocation.swift
      - path: Echo/Models/AsideNote.swift
      - path: Echo/Models/Reactions.swift
      - path: Echo/Services/Transport/HermesTransport.swift
      - path: Echo/Services/Transport/HermesSessionsTransport.swift
      - path: Echo/Services/Transport/ChatCompletionsTransport.swift
      - path: Echo/Services/Transport/SSEParser.swift
      - path: Echo/Services/Transport/JSONValue.swift
    info:
      path: Watch/Info.plist
      properties:
        CFBundleDisplayName: Redde
        CFBundleShortVersionString: $(MARKETING_VERSION)
        CFBundleVersion: $(CURRENT_PROJECT_VERSION)
        WKApplication: true
        WKCompanionAppBundleIdentifier: com.goosehouse.echo
        # Setup comes from the phone once; after that the watch asks Hermes on its own.
        WKRunsIndependentlyOfCompanionApp: true
        # A spoken reply keeps playing after the wrist goes down (Speaker). UIBackgroundModes, as
        # on iOS: WKBackgroundModes is for workout and extended runtime sessions, and App Store
        # Connect rejects a bundle that lists `audio` there.
        UIBackgroundModes:
          - audio
        NSAppTransportSecurity:
          NSAllowsArbitraryLoads: true
    dependencies:
      - target: EchoWatchWidgets
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: com.goosehouse.echo.watchkitapp
        SWIFT_DEFAULT_ACTOR_ISOLATION: MainActor
        SWIFT_APPROACHABLE_CONCURRENCY: true
        ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon
        ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME: AccentColor
        SKIP_INSTALL: true
  # The watch app's complications (WidgetKit). They share no data with the app, only a link it
  # opens, so the extension needs no app group.
  EchoWatchWidgets:
    type: app-extension
    platform: watchOS
    sources:
      - path: WatchWidgets
    info:
      path: WatchWidgets/Info.plist
      properties:
        CFBundleDisplayName: Redde
        CFBundleShortVersionString: $(MARKETING_VERSION)
        CFBundleVersion: $(CURRENT_PROJECT_VERSION)
        NSExtension:
          NSExtensionPointIdentifier: com.apple.widgetkit-extension
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: com.goosehouse.echo.watchkitapp.widgets
        SWIFT_DEFAULT_ACTOR_ISOLATION: MainActor
        SKIP_INSTALL: true
  EchoControls:
    type: app-extension
    platform: iOS
    sources:
      - path: EchoControls
      - path: Shared
    entitlements:
      path: EchoControls/EchoControls.entitlements
      properties:
        com.apple.security.application-groups:
          - group.com.goosehouse.echo
    info:
      path: EchoControls/Info.plist
      properties:
        CFBundleDisplayName: Redde Controls
        CFBundleShortVersionString: $(MARKETING_VERSION)
        CFBundleVersion: $(CURRENT_PROJECT_VERSION)
        NSSupportsLiveActivities: true
        NSExtension:
          NSExtensionPointIdentifier: com.apple.widgetkit-extension
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: com.goosehouse.echo.controls
        SWIFT_DEFAULT_ACTOR_ISOLATION: MainActor
        SKIP_INSTALL: true
        ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME: AccentColor
  EchoShare:
    type: app-extension
    platform: iOS
    sources:
      - path: EchoShare
      - path: Shared
    entitlements:
      path: EchoShare/EchoShare.entitlements
      properties:
        com.apple.security.application-groups:
          - group.com.goosehouse.echo
    info:
      path: EchoShare/Info.plist
      properties:
        CFBundleDisplayName: Redde
        CFBundleShortVersionString: $(MARKETING_VERSION)
        CFBundleVersion: $(CURRENT_PROJECT_VERSION)
        NSExtension:
          NSExtensionPointIdentifier: com.apple.share-services
          NSExtensionPrincipalClass: $(PRODUCT_MODULE_NAME).ShareViewController
          NSExtensionAttributes:
            NSExtensionActivationRule:
              NSExtensionActivationSupportsText: true
              NSExtensionActivationSupportsWebURLWithMaxCount: 1
              NSExtensionActivationSupportsImageWithMaxCount: 4
              NSExtensionActivationSupportsFileWithMaxCount: 4
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: com.goosehouse.echo.share
        SWIFT_DEFAULT_ACTOR_ISOLATION: MainActor
        SKIP_INSTALL: true
  # Opens the sealed notifications a paired Hermes sends through the push relay (Shared/PushSeal).
  # Only what that takes is compiled in: an extension that runs for every notification stays small.
  EchoPush:
    type: app-extension
    platform: iOS
    sources:
      - path: EchoPush
      - path: Shared/PushSeal.swift
      # What a note says is waiting on the person goes on the "Needs you" widget.
      - path: Shared/NeedsYou.swift
      # And what the agent sent for its own widget while the phone wasn't following the turn.
      - path: Shared/AgentBoard.swift
      - path: Shared/DeviceDates.swift
      - path: Shared/PlainText.swift
      - path: Shared/ReplyMedia.swift
      - path: Shared/Attachment.swift
      # A muted chat's notification is delivered quietly.
      - path: Shared/MutedChats.swift
      # The agent's ideas, and what its watches saw, kept as they arrive with Redde closed.
      - path: Shared/AgentIdeas.swift
      - path: Shared/AgentWatches.swift
      - path: Shared/AgentGoals.swift
      - path: Shared/AgentBriefings.swift
      - path: Shared/DayBrief.swift
      - path: Shared/WeekPlan.swift
      - path: Shared/AgentActivityLog.swift
      - path: Shared/QuietHours.swift
      - path: Shared/LeaveTime.swift
      # Leave-By Alerts' traffic re-check, woken by the paired Hermes.
      - path: Shared/LeaveCheck.swift
    entitlements:
      path: EchoPush/EchoPush.entitlements
      properties:
        # The pairings' Keychain item is shared through the app group.
        com.apple.security.application-groups:
          - group.com.goosehouse.echo
    info:
      path: EchoPush/Info.plist
      properties:
        CFBundleDisplayName: Redde
        CFBundleShortVersionString: $(MARKETING_VERSION)
        CFBundleVersion: $(CURRENT_PROJECT_VERSION)
        NSExtension:
          NSExtensionPointIdentifier: com.apple.usernotifications.service
          NSExtensionPrincipalClass: $(PRODUCT_MODULE_NAME).NotificationService
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: com.goosehouse.echo.push
        SKIP_INSTALL: true
  # The same for the Mac (asked 2026-10-30, "pair the mac and ipad for push"): EchoPush's code and
  # the same shared files, so a paired Hermes's notes open with Redde closed there too. Sandboxed,
  # as a Mac App Store extension must be; the pairings are in a Keychain group it shares with the
  # app (`PushVault.keychainGroup`): its own id's, which the app lists second.
  EchoPushMac:
    type: app-extension
    platform: macOS
    deploymentTarget: "26.0"
    sources:
      - path: EchoPush
        excludes:
          # The iPhone's: this one's own are in EchoPushMac/.
          - EchoPush.entitlements
          - Info.plist
      - path: Shared/PushSeal.swift
      - path: Shared/NeedsYou.swift
      - path: Shared/AgentBoard.swift
      - path: Shared/DeviceDates.swift
      - path: Shared/PlainText.swift
      - path: Shared/ReplyMedia.swift
      - path: Shared/Attachment.swift
      - path: Shared/MutedChats.swift
      - path: Shared/AgentIdeas.swift
      - path: Shared/AgentWatches.swift
      - path: Shared/AgentGoals.swift
      - path: Shared/AgentBriefings.swift
      - path: Shared/DayBrief.swift
      - path: Shared/WeekPlan.swift
      - path: Shared/AgentActivityLog.swift
      - path: Shared/QuietHours.swift
      - path: Shared/LeaveTime.swift
      - path: Shared/LeaveCheck.swift
    entitlements:
      path: EchoPushMac/EchoPushMac.entitlements
      properties:
        com.apple.security.app-sandbox: true
        # Ideas, briefings, what waits on the person: kept in the app group for the app to show.
        com.apple.security.application-groups:
          - group.com.goosehouse.echo
        # The pairings: this extension's own Keychain group, which the app shares (Mac/Redde.entitlements).
        keychain-access-groups:
          - $(AppIdentifierPrefix)$(PRODUCT_BUNDLE_IDENTIFIER)
        # A heads-up's leaving time asks Apple Maps the way (`LeaveTime.work`), from where the Mac
        # last was (the app keeps it in the app group): the extension never asks for a fix of its own.
        com.apple.security.network.client: true
    info:
      path: EchoPushMac/Info.plist
      properties:
        CFBundleDisplayName: Redde
        CFBundleShortVersionString: $(MARKETING_VERSION)
        CFBundleVersion: $(CURRENT_PROJECT_VERSION)
        NSExtension:
          NSExtensionPointIdentifier: com.apple.usernotifications.service
          NSExtensionPrincipalClass: $(PRODUCT_MODULE_NAME).NotificationService
    settings:
      base:
        # The iPhone extension's id, as the app is the iPhone's (one App ID for both); the Debug
        # app's own id has its own (below), the prefix an extension's id must start with.
        PRODUCT_BUNDLE_IDENTIFIER: com.goosehouse.echo.push
        # No version of its own (UAT 2.3.1, 2026-10-31: a pinned 2.3 (279) sat inside the 2.3.1 (280)
        # app, which App Store Connect refuses): it takes the project's, as every other target does.
        SKIP_INSTALL: true
        ENABLE_HARDENED_RUNTIME: true
        SWIFT_TREAT_WARNINGS_AS_ERRORS: false
      configs:
        Debug:
          PRODUCT_BUNDLE_IDENTIFIER: com.goosehouse.echo.mac.push
  # Redde for the Mac (started 2026-10-27): a native SwiftUI app on the iPhone app's models,
  # services and views (Mac/ReddeMacApp.swift), in the iPad's layout, sandboxed (Mac/Redde.entitlements).
  ReddeMac:
    type: application
    platform: macOS
    deploymentTarget: "26.0"
    sources:
      - path: Mac
      - path: Echo/Models
      - path: Echo/Services
        excludes:
          # Frameworks the Mac doesn't have: CallKit and PushKit (calls), WatchConnectivity,
          # AlarmKit, MessageUI, CarPlay.
          - AgentCalls.swift
          - WatchLink.swift
          - WatchRelayHost.swift
          - DeviceTools/DeviceAlarms.swift
          - DeviceTools/DevicePeople.swift
          - Voice/WakeListener.swift
      - path: Echo/App/DevHooks.swift
      - path: Echo/App/FrameMonitor.swift
      # The app's resources as the iPhone's: pictures and colours, the translations, the fonts,
      # the sounds, the voice words, and the diagram and maths scripts (a folder, kept whole).
      - path: Echo/Resources
        excludes:
          - Web
          - Redde.storekit
          # The iPhone's permission texts in translation: the Mac has its own (Mac/InfoPlist.xcstrings).
          # With the iPhone's, a Mac in German asked for the camera "to scan a setup code" and
          # said things stay "on this iPhone".
          - InfoPlist.xcstrings
      - path: Echo/Resources/Web
        type: folder
        buildPhase: resources
      - path: Echo/Intents
      - path: Echo/Views
        excludes:
          # The iPhone's own: CarPlay's settings, alternate app icons, calls.
          - CarPlayVoiceSettings.swift
          - CarPlayBotSettings.swift
          - CarPlayCardSettings.swift
          - AppIconSettings.swift
          - AgentCallsSettingsView.swift
          # The SSH terminal is SwiftTerm's iPhone view; its Mac view comes later.
          - TerminalScreen.swift
          # The iPhone's side panel and its edge swipe.
          - SwipeToOpen.swift
      - path: Shared
        excludes:
          - AgentAlarm.swift
          - EchoTurnAttributes.swift
          - ApprovalIntents.swift
    dependencies:
      # Opens a paired Hermes's notes with Redde closed (Contents/PlugIns).
      - target: EchoPushMac
      - package: SwiftTerm
      - package: swift-nio-ssh
        product: NIOSSH
      - package: swift-nio
        product: NIOCore
      - package: swift-nio
        product: NIOPosix
    info:
      path: Mac/Info.plist
      properties:
        CFBundleDisplayName: Redde
        CFBundleShortVersionString: $(MARKETING_VERSION)
        CFBundleVersion: $(CURRENT_PROJECT_VERSION)
        LSApplicationCategoryType: public.app-category.productivity
        # As the iPhone's: only Apple's encryption (HTTPS, CryptoKit), no export documents.
        ITSAppUsesNonExemptEncryption: false
        # The bundled fonts (the Terminal theme's), from the app's resources.
        ATSApplicationFontsPath: .
        # The permission texts the Mac can ask with, as the iPhone's say them.
        NSMicrophoneUsageDescription: Redde listens so you can talk to your assistant. Speech is transcribed on this device and only your own server receives the text, unless you start a live voice call, which goes to the voice service you chose.
        NSSpeechRecognitionUsageDescription: Redde turns what you say into text on this Mac, so you can talk to your assistant.
        NSCameraUsageDescription: Redde uses the camera when you show your assistant something in voice mode. A picture goes only to the server you connect to.
        # The AirPods' nod and shake (HeadGestures) is compiled in: App Store processing refused the
        # first upload (278, ITMS-90683) without it.
        NSMotionUsageDescription: Redde reads head movement from your AirPods so you can nod to approve, or shake your head to deny, a request from your assistant. It is read on this Mac and never stored or sent.
        NSCalendarsFullAccessUsageDescription: Redde can show your next event when you start a conversation, and attach a day's events to a message for your assistant. Events go only to your own server. With Leave-By Alerts on, Redde also reads your next events on this device and asks Apple Maps how long the way to their address takes, to tell you when to leave.
        NSRemindersFullAccessUsageDescription: With Phone tools turned on, Redde reads and adds reminders when your assistant asks it to. They go only to the server you connect to.
        NSContactsUsageDescription: With Phone tools turned on, Redde looks up a contact when your assistant asks it to. What it finds goes only to the server you connect to.
        NSPhotoLibraryUsageDescription: With Phone tools turned on, Redde finds photos, shows one to your assistant, or deletes the ones you confirm, when your assistant asks it to. A photo goes only to the server you connect to.
        # Places (Settings → Agent → Places): arriving at or leaving a place the person set tells the bot they chose.
        # Current Location (Settings → Agent → Current Location): roughly where the person is, for the agent.
        NSLocationWhenInUseUsageDescription: With Places on, Redde uses where you are to set a place and to notice when you arrive or leave; only "arrived at Home" goes to your server. With Current Location on, your own agent hears roughly where you are when you ask about places, directions or the weather. With Leave-By Alerts on, Redde works out from where you are when to leave for an event; where you are goes only to Apple Maps, for the way there.
        NSLocationAlwaysAndWhenInUseUsageDescription: With Places turned on, Redde notices when you arrive at or leave a place you set, even when Redde is closed, and tells the bot you chose. Where you are stays on this Mac; only "arrived at Home" goes to your server.
        # Current Location (Settings → Agent → Current Location): what the Mac asks with.
        NSLocationUsageDescription: With Current Location on, your own agent hears roughly where you are when you ask about places, directions or the weather. It goes to your own server and nowhere else. With Leave-By Alerts on, Redde works out from where you are when to leave for an event; where you are goes only to Apple Maps, for the way there.
        NSLocalNetworkUsageDescription: Redde connects to the Hermes gateway or model server you configure, which is often on your local network.
        # Hermes servers are often on a home network, without public certificates.
        NSAppTransportSecurity:
          NSAllowsArbitraryLoads: true
    settings:
      base:
        # Shipped under the iPhone's id: one purchase, one App Store record, and the container of the
        # iPad app a Mac may already run. Debug keeps an id of its own (below), so a build made here
        # never opens that iPad app's data.
        PRODUCT_BUNDLE_IDENTIFIER: com.goosehouse.echo
        PRODUCT_NAME: Redde
        # Redde Face on the Mac's icon grid (Mac/Assets.xcassets), made from the iPhone's default.
        ASSETCATALOG_COMPILER_APPICON_NAME: AppIconMac
        ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME: AccentColor
        SWIFT_EMIT_LOC_STRINGS: true
        SWIFT_DEFAULT_ACTOR_ISOLATION: MainActor
        SWIFT_APPROACHABLE_CONCURRENCY: true
        SWIFT_TREAT_WARNINGS_AS_ERRORS: false
        SWIFT_OBJC_BRIDGING_HEADER: Echo/App/Echo-Bridging-Header.h
        CODE_SIGN_ENTITLEMENTS: Mac/Redde.entitlements
        ENABLE_HARDENED_RUNTIME: true
      configs:
        Debug:
          PRODUCT_BUNDLE_IDENTIFIER: com.goosehouse.echo.mac
        Release:
          EXCLUDED_SOURCE_FILE_NAMES: LocalDefaults.json
  EchoTests:
    type: bundle.unit-test
    platform: iOS
    sources:
      - path: EchoTests
      # The status widgets' views and timelines, compiled in so the tests can draw them
      # (the file imports the app when WIDGET_VIEWS_IN_TESTS is set).
      - path: EchoControls/StatusWidgets.swift
      - path: EchoControls/BoardWidget.swift
      - path: EchoControls/UpNextWidget.swift
    dependencies:
      - target: Echo
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: com.goosehouse.echo.tests
        GENERATE_INFOPLIST_FILE: true
        SWIFT_DEFAULT_ACTOR_ISOLATION: MainActor
        SWIFT_ACTIVE_COMPILATION_CONDITIONS: $(inherited) WIDGET_VIEWS_IN_TESTS
  EchoUITests:
    type: bundle.ui-testing
    platform: iOS
    sources:
      - path: EchoUITests
    dependencies:
      - target: Echo
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: com.goosehouse.echo.uitests
        GENERATE_INFOPLIST_FILE: true
        TEST_TARGET_NAME: Echo
schemes:
  Echo:
    build:
      targets:
        Echo: all
        EchoTests: [test]
    run:
      config: Debug
      # Tips work in the simulator and debug builds before the products exist in App Store Connect.
      storeKitConfiguration: Echo/Resources/Redde.storekit
    test:
      config: Debug
      targets:
        - EchoTests
  EchoUITests:
    build:
      targets:
        Echo: all
        EchoUITests: [test]
    test:
      config: Debug
      targets:
        - EchoUITests
    archive:
      config: Release