@mmerterden/multi-agent-pipeline 20.8.0 → 20.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -0
- package/docs/facts.json +3 -3
- package/index.js +1 -0
- package/install/_codex-agents.mjs +1 -1
- package/install/_common.mjs +486 -53
- package/install/_mcp-register.mjs +173 -117
- package/install/claude.mjs +281 -220
- package/install/codex.mjs +7 -7
- package/install/copilot.mjs +13 -11
- package/install/index.mjs +92 -27
- package/install/templates/claude-hooks.json +9 -9
- package/manifest.json +112 -114
- package/package.json +5 -2
- package/pipeline/commands/multi-agent/update/SKILL.md +28 -17
- package/pipeline/lib/confusables.json +79 -33
- package/pipeline/lib/extract-conventions.sh +3 -3
- package/pipeline/lib/json-file-lock.mjs +27 -7
- package/pipeline/lib/normalize-text.mjs +86 -17
- package/pipeline/lib/outbound-gate.mjs +13 -4
- package/pipeline/lib/redact.mjs +87 -13
- package/pipeline/multi-agent-refs/analysis/evidence.md +1 -1
- package/pipeline/multi-agent-refs/analysis/synthesis.md +1 -1
- package/pipeline/multi-agent-refs/component-dispatch.md +1 -1
- package/pipeline/multi-agent-refs/conventions-defaults.md +1 -1
- package/pipeline/multi-agent-refs/features/unattended-security.md +2 -2
- package/pipeline/scripts/agent-guard.py +150 -25
- package/pipeline/scripts/audit-log.sh +3 -4
- package/pipeline/scripts/autopilot-runner.mjs +14 -5
- package/pipeline/scripts/doctor.mjs +8 -2
- package/pipeline/scripts/gen-skills-index.mjs +13 -1
- package/pipeline/scripts/log-metric.sh +9 -3
- package/pipeline/scripts/migrate-prefs.mjs +18 -4
- package/pipeline/scripts/pre-commit-check.sh +119 -27
- package/pipeline/scripts/scan-agent-config.sh +9 -9
- package/pipeline/scripts/unattended_policy.py +12 -3
- package/pipeline/scripts/uninstall.mjs +88 -1
- package/pipeline/scripts/usage-identity.mjs +1 -1
- package/pipeline/scripts/usage-register.mjs +1 -1
- package/pipeline/skills/.skill-manifest.json +30 -30
- package/pipeline/skills/shared/README.md +64 -64
- package/pipeline/skills/shared/external/alarmkit/SKILL.md +2 -2
- package/pipeline/skills/shared/external/alarmkit/evals/evals.json +2 -2
- package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +6 -0
- package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +3 -0
- package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +3 -0
- package/pipeline/skills/shared/external/app-store-review/SKILL.md +3 -4
- package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +5 -3
- package/pipeline/skills/shared/external/authentication/SKILL.md +29 -17
- package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +3 -1
- package/pipeline/skills/shared/external/background-processing/SKILL.md +10 -8
- package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +7 -7
- package/pipeline/skills/shared/external/callkit-voip/SKILL.md +6 -3
- package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +43 -0
- package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +4 -2
- package/pipeline/skills/shared/external/core-data/SKILL.md +12 -2
- package/pipeline/skills/shared/external/core-nfc/SKILL.md +31 -0
- package/pipeline/skills/shared/external/coreml/SKILL.md +1 -1
- package/pipeline/skills/shared/external/cryptokit/SKILL.md +1 -1
- package/pipeline/skills/shared/external/device-integrity/SKILL.md +11 -5
- package/pipeline/skills/shared/external/ios-coding-standard/references/rules.yml +2 -2
- package/pipeline/skills/shared/external/ios-module-structure/modules/_TEMPLATE.yml +1 -1
- package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +6 -6
- package/pipeline/skills/shared/external/localization-reuse-map/example-mapping.json +3 -2
- package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +20 -18
- package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +4 -4
- package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +12 -9
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/_shared.py +201 -0
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +64 -30
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +14 -16
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +20 -12
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +7 -7
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +26 -12
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-key-shots.py +4 -3
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +51 -24
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +19 -9
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +26 -19
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +39 -46
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +37 -63
- package/pipeline/skills/shared/external/mapkit-location/SKILL.md +4 -2
- package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +5 -4
- package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +3 -2
- package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +2 -2
- package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +4 -4
- package/pipeline/skills/shared/external/permissionkit/SKILL.md +15 -6
- package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +2 -1
- package/pipeline/skills/shared/external/push-notifications/SKILL.md +8 -4
- package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +1 -1
- package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +25 -6
- package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/skill-creator/template.md +7 -1
- package/pipeline/skills/shared/external/storekit/references/core-patterns.md +6 -1
- package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +3 -2
- package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +1 -1
- package/pipeline/skills/shared/external/swift-security/SKILL.md +10 -8
- package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +8 -5
- package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +13 -9
- package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +7 -6
- package/pipeline/skills/shared/external/swift-testing/SKILL.md +8 -5
- package/pipeline/skills/shared/external/swift-testing/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +3 -2
- package/pipeline/skills/shared/external/swiftdata/SKILL.md +5 -3
- package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +17 -9
- package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +4 -2
- package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +13 -6
- package/pipeline/skills/shared/external/vision-framework/SKILL.md +3 -1
- package/pipeline/skills/shared/external/weatherkit/SKILL.md +8 -5
- package/pipeline/skills/shared/external/widgetkit/SKILL.md +15 -7
- package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +8 -6
- package/pipeline/scripts/gen-ref-toc.mjs +0 -279
- package/pipeline/scripts/make-manifest.mjs +0 -199
- package/pipeline/scripts/scorecard-snapshot.mjs +0 -178
|
@@ -95,27 +95,27 @@ Source layout is logical grouping only - skill discovery at runtime is unchang
|
|
|
95
95
|
| Skill | Group | Description |
|
|
96
96
|
|-------|-------|-------------|
|
|
97
97
|
| [`accessibility-compliance-accessibility-audit`](./external/accessibility-compliance-accessibility-audit/) | `external` | WCAG 2.2 AA audit process for web, iOS and Android: scope, automated scans, screen-reader and keyboard checks, severity, report, retest. Use |
|
|
98
|
-
| [`alarmkit`](./external/alarmkit/) | `external` | AlarmKit alarms and countdown timers on iOS and iPadOS 26: AlarmManager scheduling and authorization, AlarmAttributes, AlarmPresentation
|
|
99
|
-
| [`app-clips`](./external/app-clips/) | `external` |
|
|
100
|
-
| [`app-intents`](./external/app-intents/) | `external` |
|
|
98
|
+
| [`alarmkit`](./external/alarmkit/) | `external` | AlarmKit alarms and countdown timers on iOS and iPadOS 26: AlarmManager scheduling and authorization, AlarmAttributes, AlarmPresentation, Al |
|
|
99
|
+
| [`app-clips`](./external/app-clips/) | `external` | iOS App Clips: target setup, invocation from NFC, App Clip Codes, QR, Messages, Maps and Safari banners, App Store Connect experiences, size |
|
|
100
|
+
| [`app-intents`](./external/app-intents/) | `external` | App Intents for Siri, Shortcuts, Spotlight, widgets, Control Center and Apple Intelligence: AppIntent actions, AppEntity and EntityQuery, Ap |
|
|
101
101
|
| [`app-store-changelog`](./external/app-store-changelog/) | `external` | Generate user-facing App Store release notes from git history since the last tag. Use when release notes have to be written from the commits |
|
|
102
|
-
| [`app-store-optimization`](./external/app-store-optimization/) | `external` | App Store Optimization (ASO) for ranking and conversion: keyword research;
|
|
102
|
+
| [`app-store-optimization`](./external/app-store-optimization/) | `external` | App Store Optimization (ASO) for ranking and conversion: keyword research; app name, subtitle and 100-byte keyword field; description and pr |
|
|
103
103
|
| [`app-store-review`](./external/app-store-review/) | `external` | App Store submission readiness and rejection prevention: Review Guidelines 2.1, 2.3, 2.5.1, 3.1.1, 4.2 and 5.1.2, PrivacyInfo.xcprivacy mani |
|
|
104
|
-
| [`apple-on-device-ai`](./external/apple-on-device-ai/) | `external` |
|
|
105
|
-
| [`authentication`](./external/authentication/) | `external` |
|
|
106
|
-
| [`background-processing`](./external/background-processing/) | `external` |
|
|
107
|
-
| [`callkit-voip`](./external/callkit-voip/) | `external` | CallKit and PushKit VoIP calling
|
|
108
|
-
| [`cloudkit-sync`](./external/cloudkit-sync/) | `external` |
|
|
109
|
-
| [`contacts-framework`](./external/contacts-framework/) | `external` |
|
|
110
|
-
| [`core-bluetooth`](./external/core-bluetooth/) | `external` | Direct
|
|
111
|
-
| [`core-motion`](./external/core-motion/) | `external` |
|
|
112
|
-
| [`core-nfc`](./external/core-nfc/) | `external` | Core NFC on iPhone: reading and writing
|
|
113
|
-
| [`coreml`](./external/coreml/) | `external` | Swift-side Core ML
|
|
114
|
-
| [`device-integrity`](./external/device-integrity/) | `external` |
|
|
115
|
-
| [`energykit`](./external/energykit/) | `external` |
|
|
116
|
-
| [`eventkit-calendar`](./external/eventkit-calendar/) | `external` | EventKit and EventKitUI
|
|
104
|
+
| [`apple-on-device-ai`](./external/apple-on-device-ai/) | `external` | On-device AI on Apple hardware: Foundation Models (SystemLanguageModel, LanguageModelSession, @Generable and @Guide structured output, tool |
|
|
105
|
+
| [`authentication`](./external/authentication/) | `external` | iOS sign-in with AuthenticationServices and LocalAuthentication: Sign in with Apple, passkey (WebAuthn) sign-up and login via ASAuthorizatio |
|
|
106
|
+
| [`background-processing`](./external/background-processing/) | `external` | iOS background work with BGTaskScheduler: BGAppRefreshTask short fetches, BGProcessingTask long maintenance, BGContinuedProcessingTask (iOS |
|
|
107
|
+
| [`callkit-voip`](./external/callkit-voip/) | `external` | CallKit and PushKit VoIP calling: CXProvider and CXCallController, incoming and outgoing call flows, call actions, VoIP push registration an |
|
|
108
|
+
| [`cloudkit-sync`](./external/cloudkit-sync/) | `external` | CloudKit and iCloud sync on iOS and macOS: CKContainer public, private and shared databases, CKRecord, CKQuery, CKSubscription, CKSyncEngine |
|
|
109
|
+
| [`contacts-framework`](./external/contacts-framework/) | `external` | Contacts and ContactsUI: CNContactStore authorization and limited access, fetch and save requests, creating, updating and deleting contacts, |
|
|
110
|
+
| [`core-bluetooth`](./external/core-bluetooth/) | `external` | Direct BLE with Core Bluetooth: central and peripheral GATT communication, CBCentralManager scanning and connecting, service and characteris |
|
|
111
|
+
| [`core-motion`](./external/core-motion/) | `external` | Core Motion on iOS and watchOS: accelerometer, gyroscope, magnetometer, fused device motion and reference frames, CMPedometer steps, distanc |
|
|
112
|
+
| [`core-nfc`](./external/core-nfc/) | `external` | Core NFC on iPhone: reading and writing NDEF tags, ISO7816, ISO15693, FeliCa and MIFARE access, reader session lifecycle, NFC entitlement an |
|
|
113
|
+
| [`coreml`](./external/coreml/) | `external` | Swift-side Core ML: loading .mlmodel, .mlpackage and .mlmodelc, predictions via generated classes and MLFeatureProvider, compute units, asyn |
|
|
114
|
+
| [`device-integrity`](./external/device-integrity/) | `external` | DeviceCheck and App Attest: DCDevice tokens and per-device bits, DCAppAttestService key generation, attestation and assertions. Use when add |
|
|
115
|
+
| [`energykit`](./external/energykit/) | `external` | EnergyKit on iOS 26: grid electricity forecasts via ElectricityGuidance, EnergyVenue, EV and HVAC load events, ElectricityInsightService his |
|
|
116
|
+
| [`eventkit-calendar`](./external/eventkit-calendar/) | `external` | EventKit and EventKitUI: adding events to the user's calendar, creating reminders, recurrence rules, calendar or reminders access, event edi |
|
|
117
117
|
| [`firebase`](./external/firebase/) | `external` | You're a developer who has shipped dozens of Firebase projects. You've seen the easy path lead to security breaches, runaway costs, and impo |
|
|
118
|
-
| [`healthkit`](./external/healthkit/) | `external` |
|
|
118
|
+
| [`healthkit`](./external/healthkit/) | `external` | HealthKit on iOS, iPadOS, watchOS and visionOS: HKHealthStore authorization, sample, statistics and chart-ready collection queries, saving H |
|
|
119
119
|
| [`hig-components-content`](./external/hig-components-content/) | `external` | Apple HIG for content views mapped to SwiftUI: lists, tables, grids, charts, images, text, web views, empty states. Use when choosing or rev |
|
|
120
120
|
| [`hig-components-layout`](./external/hig-components-layout/) | `external` | Apple HIG for app structure mapped to SwiftUI: tab bars, split views, navigation stacks, toolbars, sheets, popovers, alerts, windows, iOS 26 |
|
|
121
121
|
| [`hig-components-status`](./external/hig-components-status/) | `external` | Apple HIG for status UI mapped to SwiftUI: progress views, gauges, placeholders, status bar, activity rings, success and failure feedback. U |
|
|
@@ -125,64 +125,64 @@ Source layout is logical grouping only - skill discovery at runtime is unchang
|
|
|
125
125
|
| [`hig-patterns`](./external/hig-patterns/) | `external` | Apple HIG interaction patterns mapped to SwiftUI: modality, loading, empty and error states, feedback, undo, search, data entry, settings, s |
|
|
126
126
|
| [`hig-platforms`](./external/hig-platforms/) | `external` | Apple HIG per platform: iPhone, iPad, Mac, Watch, TV and Vision Pro conventions, and adapting one SwiftUI codebase across them. Use when a d |
|
|
127
127
|
| [`hig-technologies`](./external/hig-technologies/) | `external` | Apple HIG for system technologies: Sign in with Apple, passkeys, Apple Pay, Wallet, Siri and App Intents, HealthKit, HomeKit, iCloud, Maps, |
|
|
128
|
-
| [`homekit-matter`](./external/homekit-matter/) | `external` |
|
|
129
|
-
| [`ios-accessibility`](./external/ios-accessibility/) | `external` |
|
|
128
|
+
| [`homekit-matter`](./external/homekit-matter/) | `external` | HomeKit and MatterSupport: managing homes, rooms, zones and accessories, reading characteristics, action sets and triggers, Matter commissio |
|
|
129
|
+
| [`ios-accessibility`](./external/ios-accessibility/) | `external` | VoiceOver, Voice Control, Switch Control and Full Keyboard Access in SwiftUI, UIKit and AppKit on iOS, iPadOS and macOS: labels, hints, valu |
|
|
130
130
|
| [`ios-coding-standard`](./external/ios-coding-standard/) | `external` | The iOS coding-standard rule registry: 99 stable-ID rules across readability, security, service layer, business rules, concurrency, testing, |
|
|
131
131
|
| [`ios-debugger-agent`](./external/ios-debugger-agent/) | `external` | Debug the current iOS project on a booted simulator with XcodeBuildMCP. Use when an iOS bug has to be reproduced and diagnosed on a booted s |
|
|
132
|
-
| [`ios-localization`](./external/ios-localization/) | `external` |
|
|
132
|
+
| [`ios-localization`](./external/ios-localization/) | `external` | i18n and l10n for iOS and macOS: String Catalogs (.xcstrings), generated localizable symbols with compile-time-checked keys, stable key nami |
|
|
133
133
|
| [`ios-module-structure`](./external/ios-module-structure/) | `external` | The ios-module-structure rule registry: stable-ID rules over where a declaration lives, what its file is called and what its folder must con |
|
|
134
|
-
| [`ios-networking`](./external/ios-networking/) | `external` |
|
|
134
|
+
| [`ios-networking`](./external/ios-networking/) | `external` | URLSession with async/await and structured concurrency on iOS and macOS: HTTP requests, REST API clients, response validation, error handlin |
|
|
135
135
|
| [`ios-security`](./external/ios-security/) | `external` | Secure iOS apps with Keychain Services, CryptoKit encryption, biometric authentication (Face ID, Touch ID), Secure Enclave key storage, LACo |
|
|
136
|
-
| [`ios-simulator`](./external/ios-simulator/) | `external` |
|
|
137
|
-
| [`live-activities`](./external/live-activities/) | `external` | ActivityKit Live Activities
|
|
136
|
+
| [`ios-simulator`](./external/ios-simulator/) | `external` | xcrun simctl from the command line: create, boot, erase and delete devices, install and launch apps, simulated pushes without APNs, GPS loca |
|
|
137
|
+
| [`live-activities`](./external/live-activities/) | `external` | ActivityKit Live Activities on the Lock Screen and Dynamic Island: ActivityAttributes and ContentState, request/update/end lifecycle, compac |
|
|
138
138
|
| [`macos-menubar-tuist-app`](./external/macos-menubar-tuist-app/) | `external` | Build, refactor, or review SwiftUI macOS menubar apps that use Tuist. Use when building, refactoring or reviewing a SwiftUI macOS menubar ap |
|
|
139
139
|
| [`macos-spm-app-packaging`](./external/macos-spm-app-packaging/) | `external` | Scaffold, build, sign, and package SwiftPM macOS apps without Xcode projects. Use when a SwiftPM macOS app has to be built, signed or packag |
|
|
140
|
-
| [`mapkit-location`](./external/mapkit-location/) | `external` |
|
|
141
|
-
| [`metrickit-diagnostics`](./external/metrickit-diagnostics/) | `external` |
|
|
142
|
-
| [`musickit-audio`](./external/musickit-audio/) | `external` |
|
|
143
|
-
| [`natural-language`](./external/natural-language/) | `external` |
|
|
144
|
-
| [`passkit-wallet`](./external/passkit-wallet/) | `external` |
|
|
145
|
-
| [`pencilkit-drawing`](./external/pencilkit-drawing/) | `external` | Apple Pencil
|
|
146
|
-
| [`permissionkit`](./external/permissionkit/) | `external` | PermissionKit
|
|
147
|
-
| [`photos-camera-media`](./external/photos-camera-media/) | `external` |
|
|
148
|
-
| [`push-notifications`](./external/push-notifications/) | `external` |
|
|
149
|
-
| [`realitykit-ar`](./external/realitykit-ar/) | `external` | RealityKit and ARKit on iOS: RealityView
|
|
150
|
-
| [`shareplay-activities`](./external/shareplay-activities/) | `external` | GroupActivities and SharePlay on iOS, macOS, tvOS and visionOS:
|
|
151
|
-
| [`speech-recognition`](./external/speech-recognition/) | `external` | Speech-to-text
|
|
152
|
-
| [`storekit`](./external/storekit/) | `external` |
|
|
153
|
-
| [`swift-api-design-guidelines`](./external/swift-api-design-guidelines/) | `external` | Swift API Design Guidelines
|
|
154
|
-
| [`swift-architecture`](./external/swift-architecture/) | `external` | App architecture on Apple platforms
|
|
155
|
-
| [`swift-charts`](./external/swift-charts/) | `external` |
|
|
156
|
-
| [`swift-codable`](./external/swift-codable/) | `external` | Codable
|
|
157
|
-
| [`swift-concurrency`](./external/swift-concurrency/) | `external` | Swift
|
|
140
|
+
| [`mapkit-location`](./external/mapkit-location/) | `external` | MapKit and CoreLocation on iOS and macOS: SwiftUI Map, markers, annotations, polylines and overlays, camera control, user location tracking, |
|
|
141
|
+
| [`metrickit-diagnostics`](./external/metrickit-diagnostics/) | `external` | MetricKit field telemetry from shipping apps: MXMetricManager subscribers, MXMetricPayload and MXDiagnosticPayload, crash, hang and disk-wri |
|
|
142
|
+
| [`musickit-audio`](./external/musickit-audio/) | `external` | MusicKit and MediaPlayer on iOS: Apple Music authorization, catalog search, subscription checks and offers, ApplicationMusicPlayer playback |
|
|
143
|
+
| [`natural-language`](./external/natural-language/) | `external` | NaturalLanguage and Translation frameworks: tokenizing, language identification, part-of-speech tagging, named entities, sentiment, word and |
|
|
144
|
+
| [`passkit-wallet`](./external/passkit-wallet/) | `external` | Apple Pay and Wallet passes with PassKit: Apple Pay buttons, payment requests, authorization flow, merchant capabilities, shipping and conta |
|
|
145
|
+
| [`pencilkit-drawing`](./external/pencilkit-drawing/) | `external` | PencilKit drawing with Apple Pencil or finger: PKCanvasView, PKToolPicker and custom items, PKDrawing persistence and export, stroke inspect |
|
|
146
|
+
| [`permissionkit`](./external/permissionkit/) | `external` | PermissionKit parental approval for minors: CommunicationLimits handle checks, PermissionQuestion, AskCenter requests and responses, Permiss |
|
|
147
|
+
| [`photos-camera-media`](./external/photos-camera-media/) | `external` | PhotoKit and AVFoundation media on iOS: PhotosPicker and PHPickerViewController, Transferable loading of images, movies and Live Photos, pho |
|
|
148
|
+
| [`push-notifications`](./external/push-notifications/) | `external` | UserNotifications and APNs on iOS and macOS, local and remote: permission (standard, provisional, critical), device-token registration, trig |
|
|
149
|
+
| [`realitykit-ar`](./external/realitykit-ar/) | `external` | RealityKit and ARKit on iOS: RealityView camera content, AR camera availability and permission, entities and components, USDZ loading, plane |
|
|
150
|
+
| [`shareplay-activities`](./external/shareplay-activities/) | `external` | GroupActivities and SharePlay on iOS, macOS, tvOS and visionOS: GroupActivity, GroupSession lifecycle, messengers, playback sync, file trans |
|
|
151
|
+
| [`speech-recognition`](./external/speech-recognition/) | `external` | Speech framework speech-to-text: live microphone transcription with AVAudioEngine, recorded audio files, speech and microphone permission, o |
|
|
152
|
+
| [`storekit`](./external/storekit/) | `external` | StoreKit 2 in-app purchases and subscriptions: SubscriptionStoreView, StoreView and ProductView paywalls, consumable, non-consumable and aut |
|
|
153
|
+
| [`swift-api-design-guidelines`](./external/swift-api-design-guidelines/) | `external` | Swift API Design Guidelines: call-site clarity over brevity, argument labels and prepositions, method versus property, side-effect naming, m |
|
|
154
|
+
| [`swift-architecture`](./external/swift-architecture/) | `external` | App architecture on Apple platforms (Swift 6.3, SwiftUI, UIKit): MV with @Observable, MVVM, MVI, TCA, Clean Architecture, VIPER, Coordinator |
|
|
155
|
+
| [`swift-charts`](./external/swift-charts/) | `external` | Swift Charts: bar, line, area, point, pie, donut, iOS 26 3D charts (Chart3D, SurfacePlot), axes, scales, legends, annotations, scrolling, se |
|
|
156
|
+
| [`swift-codable`](./external/swift-codable/) | `external` | Codable JSON and property-list models: JSONDecoder, JSONEncoder, CodingKeys, custom init(from:)/encode(to:), nested containers, date, data a |
|
|
157
|
+
| [`swift-concurrency`](./external/swift-concurrency/) | `external` | Swift 6.2+ concurrency: actor isolation, Sendable, sending, approachable concurrency (SE-0466 default MainActor, @concurrent, nonisolated(no |
|
|
158
158
|
| [`swift-concurrency-expert`](./external/swift-concurrency-expert/) | `external` | Review and fix Swift concurrency issues such as actor isolation and Sendable violations. Use when a Swift concurrency problem needs diagnosi |
|
|
159
159
|
| [`swift-concurrency-pro`](./external/swift-concurrency-pro/) | `external` | Reviews Swift code for concurrency correctness, modern API usage, and common async/await pitfalls. Use when reading, writing, or reviewing S |
|
|
160
|
-
| [`swift-formatstyle`](./external/swift-formatstyle/) | `external` | Display formatting
|
|
161
|
-
| [`swift-language`](./external/swift-language/) | `external` | Core Swift 6.3
|
|
162
|
-
| [`swift-security`](./external/swift-security/) | `external` | Apple
|
|
163
|
-
| [`swift-testing`](./external/swift-testing/) | `external` | Writing, migrating and reviewing
|
|
160
|
+
| [`swift-formatstyle`](./external/swift-formatstyle/) | `external` | Display formatting with FormatStyle (iOS 15+): integers, floating point, decimals, currency, percentages, dates, date ranges, relative and a |
|
|
161
|
+
| [`swift-language`](./external/swift-language/) | `external` | Core Swift 6.3 outside concurrency and SwiftUI: if and switch expressions, typed throws, result builders, property wrappers, some vs any, gu |
|
|
162
|
+
| [`swift-security`](./external/swift-security/) | `external` | Apple client security: Keychain (SecItem, kSecClass, OSStatus, iOS, macOS), Face ID/Touch ID keychain items, CryptoKit (AES-GCM, ChaChaPoly, |
|
|
163
|
+
| [`swift-testing`](./external/swift-testing/) | `external` | Writing, migrating and reviewing Swift Testing tests: @Test, @Suite, #expect, #require, confirmation, traits, withKnownIssue, Attachment.rec |
|
|
164
164
|
| [`swift-testing-pro`](./external/swift-testing-pro/) | `external` | Writes, reviews, and improves Swift Testing code using modern APIs and best practices. Use when reading, writing, or reviewing projects that |
|
|
165
165
|
| [`swiftdata`](./external/swiftdata/) | `external` | SwiftData persistence for Apple apps: @Model classes with @Attribute, @Relationship, @Transient, #Unique and #Index; @Query, #Predicate, Fet |
|
|
166
166
|
| [`swiftdata-pro`](./external/swiftdata-pro/) | `external` | Writes, reviews, and improves SwiftData code using modern APIs and best practices. Use when reading, writing, or reviewing projects that use |
|
|
167
|
-
| [`swiftlint`](./external/swiftlint/) | `external` |
|
|
168
|
-
| [`swiftui-animation`](./external/swiftui-animation/) | `external` | SwiftUI motion:
|
|
167
|
+
| [`swiftlint`](./external/swiftlint/) | `external` | SwiftLint setup and enforcement: build tool and command plugins, Xcode run scripts, CI, .swiftlint.yml rule sets (default, opt-in, analyzer) |
|
|
168
|
+
| [`swiftui-animation`](./external/swiftui-animation/) | `external` | SwiftUI motion: withAnimation, scoped implicit .animation(_:body:) and .animation(_:value:), timing curves and springs (.smooth, .snappy, .b |
|
|
169
169
|
| [`swiftui-expert-skill`](./external/swiftui-expert-skill/) | `external` | Write, review, or improve SwiftUI code following best practices for state management, view composition, performance, macOS-specific APIs, an |
|
|
170
|
-
| [`swiftui-gestures`](./external/swiftui-gestures/) | `external` | SwiftUI
|
|
171
|
-
| [`swiftui-layout-components`](./external/swiftui-layout-components/) | `external` | SwiftUI
|
|
172
|
-
| [`swiftui-liquid-glass`](./external/swiftui-liquid-glass/) | `external` | Liquid Glass in SwiftUI
|
|
173
|
-
| [`swiftui-navigation`](./external/swiftui-navigation/) | `external` | SwiftUI navigation: NavigationStack
|
|
174
|
-
| [`swiftui-patterns`](./external/swiftui-patterns/) | `external` |
|
|
175
|
-
| [`swiftui-performance`](./external/swiftui-performance/) | `external` |
|
|
170
|
+
| [`swiftui-gestures`](./external/swiftui-gestures/) | `external` | SwiftUI gestures: tap, spatial tap, long press, drag, magnify, rotate, composition (simultaneously, sequenced, exclusively), @GestureState, |
|
|
171
|
+
| [`swiftui-layout-components`](./external/swiftui-layout-components/) | `external` | SwiftUI layouts: stacks, lazy stacks, LazyVGrid/LazyHGrid, List sections, swipe actions, ScrollView with ScrollPosition, validated Form, Tog |
|
|
172
|
+
| [`swiftui-liquid-glass`](./external/swiftui-liquid-glass/) | `external` | Liquid Glass in SwiftUI (iOS 26+): glassEffect, Glass tint/interactive variants, GlassEffectContainer, glassEffectID morphing, glassEffectUn |
|
|
173
|
+
| [`swiftui-navigation`](./external/swiftui-navigation/) | `external` | SwiftUI navigation: NavigationStack typed paths, routers, NavigationSplitView, sheets, TabView and Tab API, universal links, URL schemes, Ha |
|
|
174
|
+
| [`swiftui-patterns`](./external/swiftui-patterns/) | `external` | SwiftUI Model-View structure: @Observable ownership, @State, @Bindable, @Environment, view decomposition, custom ViewModifiers, .task loadin |
|
|
175
|
+
| [`swiftui-performance`](./external/swiftui-performance/) | `external` | SwiftUI performance: slow rendering, janky scrolling, high CPU/memory, excess updates, layout thrash, costly body, identity churn, lazy load |
|
|
176
176
|
| [`swiftui-performance-audit`](./external/swiftui-performance-audit/) | `external` | Audit SwiftUI performance issues from code review and profiling evidence. Use when a SwiftUI view is slow and the cause has to be found from |
|
|
177
177
|
| [`swiftui-pro`](./external/swiftui-pro/) | `external` | Comprehensively reviews SwiftUI code for best practices on modern APIs, maintainability, and performance. Use when reading, writing, or revi |
|
|
178
178
|
| [`swiftui-ui-patterns`](./external/swiftui-ui-patterns/) | `external` | Apply proven SwiftUI UI patterns for navigation, sheets, async state, and reusable screens. Use when a SwiftUI screen needs a proven pattern |
|
|
179
|
-
| [`swiftui-uikit-interop`](./external/swiftui-uikit-interop/) | `external` |
|
|
179
|
+
| [`swiftui-uikit-interop`](./external/swiftui-uikit-interop/) | `external` | UIKit and SwiftUI interop: UIViewRepresentable, UIViewControllerRepresentable, UIHostingController, UIHostingConfiguration, Coordinator dele |
|
|
180
180
|
| [`swiftui-view-refactor`](./external/swiftui-view-refactor/) | `external` | Refactor SwiftUI views into smaller components with stable, explicit data flow. Use when a SwiftUI view has grown too large and needs splitt |
|
|
181
|
-
| [`swiftui-webkit`](./external/swiftui-webkit/) | `external` |
|
|
182
|
-
| [`tipkit`](./external/tipkit/) | `external` | TipKit in-app tips
|
|
183
|
-
| [`vision-framework`](./external/vision-framework/) | `external` | On-device computer vision with
|
|
184
|
-
| [`weatherkit`](./external/weatherkit/) | `external` | WeatherKit on iOS:
|
|
185
|
-
| [`widgetkit`](./external/widgetkit/) | `external` | WidgetKit
|
|
181
|
+
| [`swiftui-webkit`](./external/swiftui-webkit/) | `external` | Web content in SwiftUI with WebKit for SwiftUI: WebView, WebPage, observable page state, navigation policies, link interception, JavaScript |
|
|
182
|
+
| [`tipkit`](./external/tipkit/) | `external` | TipKit in-app tips (iOS 17+): Tip protocol, TipView, popoverTip, rules, events, TipGroup, styles, CloudKit sync. Use when building or review |
|
|
183
|
+
| [`vision-framework`](./external/vision-framework/) | `external` | On-device computer vision with Vision and VisionKit: OCR, face detection and landmarks, barcode and QR scanning, person and instance segment |
|
|
184
|
+
| [`weatherkit`](./external/weatherkit/) | `external` | WeatherKit on iOS: current, hourly, daily and minute forecasts, alerts, historical statistics, dataset selection, caching. Use when integrat |
|
|
185
|
+
| [`widgetkit`](./external/widgetkit/) | `external` | WidgetKit surfaces on iOS 26+: timeline-driven widgets for the Home Screen, the Lock Screen and StandBy, interactive widgets using Button or |
|
|
186
186
|
|
|
187
187
|
## Android / Kotlin
|
|
188
188
|
|
|
@@ -242,22 +242,22 @@ Source layout is logical grouping only - skill discovery at runtime is unchang
|
|
|
242
242
|
|-------|-------|-------------|
|
|
243
243
|
| [`agent-introspection-debugging`](./external/agent-introspection-debugging/) | `external` | \| |
|
|
244
244
|
| [`architecture`](./external/architecture/) | `external` | Stack-neutral architecture decisions: quality drivers, options with a trade-off matrix, reversibility, ADRs, fitness checks. Use when making |
|
|
245
|
-
| [`avkit`](./external/avkit/) | `external` | AVKit
|
|
245
|
+
| [`avkit`](./external/avkit/) | `external` | AVKit playback UI: AVPlayerViewController, SwiftUI VideoPlayer, Picture-in-Picture, AirPlay routing, transport controls, subtitles and close |
|
|
246
246
|
| [`backlog`](./external/backlog/) | `external` | Registry and routine for approved but postponed engineering work: each item keeps its full spec, origin and unblock condition, and moves thr |
|
|
247
247
|
| [`ci-cd-pipelines`](./external/ci-cd-pipelines/) | `external` | CI/CD pipelines: GitHub Actions workflows, Docker multi-stage builds, environment management, secret management, deployment strategies. Use |
|
|
248
248
|
| [`clean-code`](./external/clean-code/) | `external` | Readability checks for code in any language: names, function focus, control flow, side effects, errors, comments, duplication. Use when writ |
|
|
249
249
|
| [`context-compression`](./external/context-compression/) | `external` | Keeping long LLM agent sessions on track: what a summary must preserve, incremental structured summaries, state in files, compact versus res |
|
|
250
250
|
| [`core-data`](./external/core-data/) | `external` | Create, audit or refine Core Data persistence for apps still on Core Data rather than SwiftData: stack setup, NSManagedObject subclasses, NS |
|
|
251
251
|
| [`council`](./external/council/) | `external` | \| |
|
|
252
|
-
| [`cryptokit`](./external/cryptokit/) | `external` |
|
|
253
|
-
| [`debugging-instruments`](./external/debugging-instruments/) | `external` |
|
|
252
|
+
| [`cryptokit`](./external/cryptokit/) | `external` | CryptoKit in Swift: SHA-2, SHA-3, HMAC, AES-GCM, ChaChaPoly, P256, P384, P521, Curve25519 and ML-DSA signatures, ECDH with HKDF, HPKE, ML-KE |
|
|
253
|
+
| [`debugging-instruments`](./external/debugging-instruments/) | `external` | Xcode debugging and profiling: LLDB, Memory Graph Debugger, Instruments, crashes, leaks and retain cycles, main-thread hangs, slow rendering |
|
|
254
254
|
| [`debugging-strategies`](./external/debugging-strategies/) | `external` | Language-neutral debugging method: reproduce, minimise, falsifiable hypotheses, git bisect, instrumentation, production traces, concurrency |
|
|
255
255
|
| [`evidence-github`](./external/evidence-github/) | `external` | Search GitHub for facts an analysis can cite - a known issue in a dependency, the PR that fixed it, what a release actually changed, prior a |
|
|
256
256
|
| [`evidence-registry`](./external/evidence-registry/) | `external` | Check a package's real version, deprecation status and release notes on npm, PyPI, Maven Central or Swift Package Index. Use when a spec or |
|
|
257
257
|
| [`github-actions-templates`](./external/github-actions-templates/) | `external` | Authoring GitHub Actions workflows: triggers, matrices, caching, concurrency, least-privilege permissions, SHA pinning, OIDC, reusable workf |
|
|
258
258
|
| [`humanizer`](./external/humanizer/) | `external` | \| |
|
|
259
259
|
| [`localization-reuse-map`](./external/localization-reuse-map/) | `external` | Localization reuse map for one redesigned screen on iOS, Android and web: new keys set against each platform's legacy key, legacy values and |
|
|
260
|
-
| [`pdfkit`](./external/pdfkit/) | `external` | PDFKit on iOS:
|
|
260
|
+
| [`pdfkit`](./external/pdfkit/) | `external` | PDFKit on iOS: PDFView display and SwiftUI wrapping, creating and editing PDFDocument and PDFPage, highlight, note, signature and form annot |
|
|
261
261
|
| [`search-first`](./external/search-first/) | `external` | \| |
|
|
262
262
|
| [`security-review`](./external/security-review/) | `external` | Run a defensive, static security review of a diff or a repo: build a run-scoped threat model, find vulnerabilities joined to OWASP + CWE wit |
|
|
263
263
|
| [`signal-community`](./external/signal-community/) | `external` | Check whether other people hit the same problem, via Stack Overflow and Hacker News (keyless) plus opt-in Reddit and X. Use when a bug repor |
|
|
@@ -389,7 +389,7 @@ Hand-offs:
|
|
|
389
389
|
`WidgetCenter` reloads: `widgetkit`.
|
|
390
390
|
- Non-alarm Live Activities (`Activity.request`, `update`, `end`),
|
|
391
391
|
push-to-start and per-activity update tokens, and remote `content-state`
|
|
392
|
-
payloads: `
|
|
392
|
+
payloads: `live-activities`.
|
|
393
393
|
- APNs, `UNUserNotificationCenter`, notification categories and actions,
|
|
394
394
|
custom notification UI: `push-notifications`, unless the code ends up
|
|
395
395
|
calling `AlarmManager`.
|
|
@@ -477,7 +477,7 @@ struct CoachWidgets: WidgetBundle {
|
|
|
477
477
|
- [ ] AlarmKit is credited only with authorization, `AlarmManager` scheduling and state, attributes, presentation, presentation state, sound and system alarm actions
|
|
478
478
|
- [ ] The ringing screen is described as drawn by the system
|
|
479
479
|
- [ ] Custom countdown and paused UI lives in the widget extension with the same attributes and `AlarmPresentationState`
|
|
480
|
-
- [ ] Hand-offs to `widgetkit`, `
|
|
480
|
+
- [ ] Hand-offs to `widgetkit`, `live-activities` and `push-notifications` are explicit
|
|
481
481
|
- [ ] Setup cites only documented requirements; no `com.apple.developer.alarmkit` unless Apple documents it
|
|
482
482
|
- [ ] `tintColor` is set on `AlarmAttributes` so the alarm is recognisable
|
|
483
483
|
- [ ] `AlarmManager.AlarmError.maximumLimitReached` is handled
|
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
{
|
|
32
32
|
"id": 2,
|
|
33
33
|
"prompt": "Product wants AlarmKit to also drive our Smart Stack widget, our delivery-tracking Live Activity and our marketing push notifications, with a fully custom design for the ringing screen. Which parts belong to AlarmKit?",
|
|
34
|
-
"expected_output": "Limits AlarmKit to system alarms and countdowns and their types, explains that the alerting UI is system-managed while countdown and paused UI can be customised in a widget extension, lists Lock Screen, Dynamic Island, StandBy and paired Apple Watch without Smart Stack, and routes widgets to widgetkit, other Live Activities to
|
|
34
|
+
"expected_output": "Limits AlarmKit to system alarms and countdowns and their types, explains that the alerting UI is system-managed while countdown and paused UI can be customised in a widget extension, lists Lock Screen, Dynamic Island, StandBy and paired Apple Watch without Smart Stack, and routes widgets to widgetkit, other Live Activities to live-activities and notifications to push-notifications.",
|
|
35
35
|
"files": [],
|
|
36
36
|
"expectations": [
|
|
37
37
|
"Keeps AlarmKit scope to system alarms and countdown timers and their AlarmKit types",
|
|
38
38
|
"States that the alerting UI is drawn by the system and only countdown and paused UI is customisable",
|
|
39
39
|
"Lists Lock Screen, Dynamic Island, StandBy and paired Apple Watch and does not claim Smart Stack",
|
|
40
40
|
"Routes Smart Stack and Home Screen widgets to widgetkit",
|
|
41
|
-
"Routes the non-alarm Live Activity to
|
|
41
|
+
"Routes the non-alarm Live Activity to live-activities",
|
|
42
42
|
"Routes push notifications to push-notifications"
|
|
43
43
|
]
|
|
44
44
|
}
|
|
@@ -73,6 +73,12 @@ Always state explicitly: popular but irrelevant keywords are rejected; the
|
|
|
73
73
|
custom page allowance is 70 per app; a test has up to three treatments; In-App
|
|
74
74
|
Events and ratings are ASO work.
|
|
75
75
|
|
|
76
|
+
Every App Store Connect number in this skill (field lengths, the 70-page
|
|
77
|
+
allowance, three treatments, the 90-day test limit, event media sizes, the
|
|
78
|
+
review-prompt cap) is as Apple's documentation stated it at the time of
|
|
79
|
+
writing. Apple changes these limits, so check App Store Connect Help before
|
|
80
|
+
quoting one as current.
|
|
81
|
+
|
|
76
82
|
## Name and subtitle
|
|
77
83
|
|
|
78
84
|
Search indexes both the name (30 characters) and the subtitle (30 characters),
|
|
@@ -7,6 +7,9 @@ subtitle, keyword field and primary category, and user behavior such as
|
|
|
7
7
|
downloads, ratings and reviews. The table below is a planning aid, not a list
|
|
8
8
|
of ranking weights.
|
|
9
9
|
|
|
10
|
+
Limits below are App Store Connect values as Apple's documentation stated them
|
|
11
|
+
at the time of writing; confirm them in App Store Connect Help before quoting.
|
|
12
|
+
|
|
10
13
|
| Field | Role in search | Limit | Changing it | Guidance |
|
|
11
14
|
|---|---|---|---|---|
|
|
12
15
|
| App name | Indexed | 30 characters | With a new version, when status allows | Distinctive, and hints at what the app does |
|
|
@@ -12,10 +12,9 @@ privacy declaration that disagrees with what the binary actually sends, a
|
|
|
12
12
|
purchase path that skips StoreKit, or metadata that promises something the app
|
|
13
13
|
does not do. This skill finds those before App Review does.
|
|
14
14
|
|
|
15
|
-
Apple
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
publication before quoting them.
|
|
15
|
+
Apple publishes a yearly App Store fraud-prevention report with the number of
|
|
16
|
+
submissions App Review looked at and turned down. Quote those figures only from
|
|
17
|
+
the current report, never from memory.
|
|
19
18
|
|
|
20
19
|
## Scope and boundaries
|
|
21
20
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: apple-on-device-ai
|
|
3
|
-
description: "On-device AI on Apple hardware: Foundation Models (SystemLanguageModel, LanguageModelSession, @Generable and @Guide structured output, tool calling), coremltools conversion, quantization, palettization, pruning, Neural Engine
|
|
3
|
+
description: "On-device AI on Apple hardware: Foundation Models (SystemLanguageModel, LanguageModelSession, @Generable and @Guide structured output, tool calling), coremltools conversion, quantization, palettization, pruning, Neural Engine, MLX Swift transformer inference on unified memory, llama.cpp GGUF models. Use when building tool-calling AI features, designing guided generation schemas, converting a model or running inference on device. Not for Swift-side Core ML integration (coreml), OCR, sentiment, NER or classifier training."
|
|
4
4
|
metadata:
|
|
5
5
|
source: multi-agent-pipeline
|
|
6
6
|
---
|
|
@@ -320,8 +320,10 @@ Compression at a glance:
|
|
|
320
320
|
|
|
321
321
|
Boundary: this skill decides which framework to use and owns the Python side
|
|
322
322
|
(conversion, compression, profiling). The `coreml` skill owns the Swift side:
|
|
323
|
-
loading models in the app, runtime settings, calling predictions,
|
|
324
|
-
models into Vision requests.
|
|
323
|
+
loading models in the app, runtime settings, calling predictions, `MLTensor`
|
|
324
|
+
pre- and post-processing, and hooking models into Vision requests. The
|
|
325
|
+
[optimization guide](references/coreml-optimization.md#mltensor) keeps a short
|
|
326
|
+
`MLTensor` example.
|
|
325
327
|
|
|
326
328
|
Conversion: [the conversion guide](references/coreml-conversion.md).
|
|
327
329
|
Compression and profiling: [the optimization guide](references/coreml-optimization.md).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: authentication
|
|
3
|
-
description: "iOS sign-in with AuthenticationServices and LocalAuthentication: Sign in with Apple, passkey (WebAuthn)
|
|
3
|
+
description: "iOS sign-in with AuthenticationServices and LocalAuthentication: Sign in with Apple, passkey (WebAuthn) sign-up and login via ASAuthorizationPlatformPublicKeyCredentialProvider, ASAuthorizationController credential state and revocation, ASWebAuthenticationSession OAuth, third-party login, Password AutoFill, server identity-token validation, LAContext biometric re-auth prompts and policy. Use when adding or reviewing account flows."
|
|
4
4
|
metadata:
|
|
5
5
|
source: multi-agent-pipeline
|
|
6
6
|
---
|
|
@@ -44,7 +44,7 @@ extension WelcomeViewController: ASAuthorizationControllerPresentationContextPro
|
|
|
44
44
|
guard let window = view.window else {
|
|
45
45
|
preconditionFailure("Start Sign in with Apple only while this screen is on screen")
|
|
46
46
|
}
|
|
47
|
-
return window // ASPresentationAnchor
|
|
47
|
+
return window // ASPresentationAnchor is UIWindow; UIWindow() is deprecated in iOS 26
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
```
|
|
@@ -104,22 +104,30 @@ People can revoke the app at any time under Settings > Apple Account >
|
|
|
104
104
|
Sign-In & Security, so check on every launch:
|
|
105
105
|
|
|
106
106
|
```swift
|
|
107
|
-
|
|
107
|
+
@MainActor
|
|
108
|
+
func verifyAppleCredential(for userID: String) async {
|
|
108
109
|
let provider = ASAuthorizationAppleIDProvider()
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
110
|
+
let credentialState: ASAuthorizationAppleIDProvider.CredentialState
|
|
111
|
+
do {
|
|
112
|
+
credentialState = try await provider.credentialState(forUserID: userID)
|
|
113
|
+
} catch {
|
|
114
|
+
SessionStore.shared.presentLogin()
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
switch credentialState {
|
|
118
|
+
case .authorized: SessionStore.shared.resume()
|
|
119
|
+
case .revoked: SessionStore.shared.signOutAndWipe()
|
|
120
|
+
case .notFound: SessionStore.shared.presentLogin()
|
|
121
|
+
case .transferred: SessionStore.shared.migrateTransferredUser(userID)
|
|
122
|
+
@unknown default: SessionStore.shared.presentLogin()
|
|
119
123
|
}
|
|
120
124
|
}
|
|
121
125
|
```
|
|
122
126
|
|
|
127
|
+
The function runs on the main actor and awaits the async form of
|
|
128
|
+
`getCredentialState(forUserID:completion:)`, so the session calls need no hop
|
|
129
|
+
back to the main queue.
|
|
130
|
+
|
|
123
131
|
`.transferred` means the app moved to a different developer team and the user
|
|
124
132
|
identifier must be migrated. Also subscribe to
|
|
125
133
|
`ASAuthorizationAppleIDProvider.credentialRevokedNotification` and sign the
|
|
@@ -133,6 +141,7 @@ backend and keep only what it returns:
|
|
|
133
141
|
```swift
|
|
134
142
|
enum SessionAPI {
|
|
135
143
|
struct Session: Decodable { let accessToken: String }
|
|
144
|
+
private static let transport = URLSession(configuration: .ephemeral)
|
|
136
145
|
|
|
137
146
|
static func exchange(token: Data?, code: Data?) async throws {
|
|
138
147
|
guard let token, let code,
|
|
@@ -144,7 +153,7 @@ enum SessionAPI {
|
|
|
144
153
|
call.httpMethod = "POST"
|
|
145
154
|
call.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
146
155
|
let body = try JSONEncoder().encode(["identity_token": jwt, "authorization_code": grant])
|
|
147
|
-
let (bytes, reply) = try await
|
|
156
|
+
let (bytes, reply) = try await transport.upload(for: call, from: body)
|
|
148
157
|
let status = (reply as? HTTPURLResponse)?.statusCode ?? 0
|
|
149
158
|
if status != 200 { throw URLError(.userAuthenticationRequired) }
|
|
150
159
|
|
|
@@ -312,8 +321,11 @@ func confirmOwner() async -> Bool {
|
|
|
312
321
|
}
|
|
313
322
|
```
|
|
314
323
|
|
|
315
|
-
Info.plist must include `NSFaceIDUsageDescription
|
|
316
|
-
|
|
324
|
+
Info.plist must include `NSFaceIDUsageDescription`, the same rule the
|
|
325
|
+
`swift-security` skill sets for biometric keychain items. The `LAContext` header
|
|
326
|
+
asks apps to supply it: its string is shown the first time the app uses Face ID,
|
|
327
|
+
and once the user denies Face ID for the app, evaluations fail with
|
|
328
|
+
`LAError.biometryNotAvailable`.
|
|
317
329
|
|
|
318
330
|
## Security boundaries
|
|
319
331
|
|
|
@@ -326,7 +338,7 @@ Keychain, and `LAContext.evaluatePolicy` on its own must never unlock a
|
|
|
326
338
|
protected secret.
|
|
327
339
|
|
|
328
340
|
Hand off to `swift-security`: Keychain architecture and migration,
|
|
329
|
-
access-control policy
|
|
341
|
+
biometric-gated keychain items and their access-control policy, CryptoKit, Secure Enclave, certificate pinning
|
|
330
342
|
and trust evaluation, sharing items between apps, hardening local storage, and
|
|
331
343
|
mapping against OWASP MASVS/MASTG. App and device attestation belongs to `device-integrity`.
|
|
332
344
|
|
|
@@ -104,7 +104,9 @@ func unlockSettings(reason: String) async throws -> Bool {
|
|
|
104
104
|
### Info.plist
|
|
105
105
|
|
|
106
106
|
Add `NSFaceIDUsageDescription` with a sentence explaining why the app uses
|
|
107
|
-
Face ID.
|
|
107
|
+
Face ID. The `LAContext` header asks for this key; the system shows the string
|
|
108
|
+
the first time the app uses Face ID, and evaluations fail with
|
|
109
|
+
`LAError.biometryNotAvailable` once the user denies Face ID for the app.
|
|
108
110
|
|
|
109
111
|
### Tuning the context
|
|
110
112
|
|
|
@@ -113,10 +113,7 @@ func perform(_ task: BGTask, _ job: @escaping @Sendable () async throws -> Void)
|
|
|
113
113
|
let finished = (try? await job()) != nil
|
|
114
114
|
task.setTaskCompleted(success: finished && !Task.isCancelled)
|
|
115
115
|
}
|
|
116
|
-
task.expirationHandler = {
|
|
117
|
-
work.cancel()
|
|
118
|
-
task.setTaskCompleted(success: false)
|
|
119
|
-
}
|
|
116
|
+
task.expirationHandler = { work.cancel() }
|
|
120
117
|
}
|
|
121
118
|
```
|
|
122
119
|
|
|
@@ -124,7 +121,11 @@ func perform(_ task: BGTask, _ job: @escaping @Sendable () async throws -> Void)
|
|
|
124
121
|
processing example below reuses `perform`. Two habits matter: schedule the
|
|
125
122
|
next run first, so a crash or expiry does not break the chain, and always
|
|
126
123
|
install an `expirationHandler`, because the system can take the time back at
|
|
127
|
-
any moment.
|
|
124
|
+
any moment. The handler only cancels; the work `Task` is the one completion
|
|
125
|
+
path, so `setTaskCompleted(success:)` runs exactly once, with `false` after an
|
|
126
|
+
expiry. That relies on the job honouring cancellation (`URLSession` async calls
|
|
127
|
+
and `Task.checkCancellation()` throw), so the `Task` ends soon after the
|
|
128
|
+
handler fires.
|
|
128
129
|
|
|
129
130
|
`BGTask` is not `Sendable`, yet both the work `Task` and the expiration
|
|
130
131
|
handler need it, and the handler runs on a queue the framework picks. The
|
|
@@ -165,7 +166,7 @@ the app. It differs from the other two types:
|
|
|
165
166
|
- Under resource pressure the system may end it, and tasks reporting little
|
|
166
167
|
progress go first.
|
|
167
168
|
- The user or the system can cancel it; the `expirationHandler` must stop the
|
|
168
|
-
work and remove partial output
|
|
169
|
+
work and remove partial output, and the cancelled work then completes once.
|
|
169
170
|
- Its handler is exempt from the register-at-launch rule. `submit` expects
|
|
170
171
|
an identifier that already has a handler, so register the job's identifier
|
|
171
172
|
right before submitting it.
|
|
@@ -346,7 +347,8 @@ func application(_ app: UIApplication,
|
|
|
346
347
|
- **Skipping `setTaskCompleted(success:)`.** The system schedules the app less
|
|
347
348
|
often afterwards. Complete on every path, errors included.
|
|
348
349
|
- **No expiration handler.** The task is killed abruptly instead of stopping
|
|
349
|
-
cleanly. Cancel the work and
|
|
350
|
+
cleanly. Cancel the work from the handler and let the cancelled work report
|
|
351
|
+
`success: false`, so completion happens once.
|
|
350
352
|
- **Asking too often.** A refresh every minute gets throttled hard. Use 15
|
|
351
353
|
minutes or more, and remember `earliestBeginDate` is a hint.
|
|
352
354
|
- **Too much work per run.** A ten-minute job inside a refresh task will not
|
|
@@ -359,7 +361,7 @@ func application(_ app: UIApplication,
|
|
|
359
361
|
- [ ] `UIBackgroundModes` has `fetch` and/or `processing` as needed
|
|
360
362
|
- [ ] Refresh and processing handlers are registered before launch completes;
|
|
361
363
|
continued processing handlers are registered before their `submit`
|
|
362
|
-
- [ ] `setTaskCompleted(success:)` runs on every path
|
|
364
|
+
- [ ] `setTaskCompleted(success:)` runs exactly once on every path
|
|
363
365
|
- [ ] `expirationHandler` cancels in-flight work
|
|
364
366
|
- [ ] The handler schedules the next task
|
|
365
367
|
- [ ] `earliestBeginDate` is sensible and read as a lower bound only
|
package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md
CHANGED
|
@@ -94,14 +94,14 @@ func backUp(_ task: BGProcessingTask, assets: [PhotoAsset]) {
|
|
|
94
94
|
task.setTaskCompleted(success: false)
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
|
-
task.expirationHandler = {
|
|
98
|
-
work.cancel()
|
|
99
|
-
task.setTaskCompleted(success: false)
|
|
100
|
-
}
|
|
97
|
+
task.expirationHandler = { work.cancel() }
|
|
101
98
|
}
|
|
102
99
|
```
|
|
103
100
|
|
|
104
|
-
When the window closes, the
|
|
101
|
+
When the window closes, the handler cancels the work, `checkCancellation()`
|
|
102
|
+
throws, and the `catch` reports `success: false`: one completion path, as in
|
|
103
|
+
`perform` and `handleExport`. The saved cursor lets the next run skip what is
|
|
104
|
+
done.
|
|
105
105
|
The `nonisolated(unsafe)` copy lets the non-`Sendable` `BGTask` be shared by
|
|
106
106
|
the work `Task` and the expiration handler under Swift 6.
|
|
107
107
|
|
|
@@ -257,8 +257,8 @@ listed. GPU use also depends on the Background GPU Access entitlement.
|
|
|
257
257
|
### Cancellation from the Live Activity
|
|
258
258
|
|
|
259
259
|
The user can stop the job from the system Live Activity. That arrives through
|
|
260
|
-
`expirationHandler`: cancel the work
|
|
261
|
-
`success: false
|
|
260
|
+
`expirationHandler`: cancel the work and delete partial output there; the
|
|
261
|
+
cancelled work then completes with `success: false`, as `handleExport` does.
|
|
262
262
|
|
|
263
263
|
### Progress drives survival
|
|
264
264
|
|
|
@@ -70,9 +70,12 @@ delegate conformance below is `@preconcurrency`, so those callbacks run as
|
|
|
70
70
|
main-actor code and the `Task` each one starts inherits that isolation. That is
|
|
71
71
|
what lets a `Task` hold on to the non-`Sendable` `CXAction` and `CXProvider`
|
|
72
72
|
it was handed; from a nonisolated method Swift 6 rejects the same capture with
|
|
73
|
-
"passing closure as a 'sending' parameter risks causing data races". The
|
|
74
|
-
system shows
|
|
75
|
-
|
|
73
|
+
"passing closure as a 'sending' parameter risks causing data races". The
|
|
74
|
+
system shows the app's bundle display name for the provider. The
|
|
75
|
+
`localizedName` property ("No longer supported") and `init(localizedName:)`
|
|
76
|
+
(replaced by `init()`) are both deprecated as of iOS 14 and Mac Catalyst 14,
|
|
77
|
+
so create the configuration with `CXProviderConfiguration()` and do not set a
|
|
78
|
+
name.
|
|
76
79
|
|
|
77
80
|
## Incoming call flow
|
|
78
81
|
|