@leejungkiin/awkit 1.0.7 → 1.0.9
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/core/GEMINI.md.bak +168 -181
- package/package.json +2 -2
- package/schemas/brain-snapshot.json +167 -0
- package/skills/CATALOG.md +70 -0
- package/skills/beads-manager/SKILL.md +20 -1
- package/skills/memory-sync/SKILL.md +20 -2
- package/skills/nm-memory-audit/SKILL.md +157 -0
- package/skills/nm-memory-evolution/SKILL.md +202 -0
- package/skills/nm-memory-intake/SKILL.md +135 -0
- package/skills/nm-memory-sync/SKILL.md +184 -0
- package/skills/orchestrator/SKILL.md +41 -50
- package/skills/schemas/brain-snapshot.json +167 -0
- package/skills/skills/nm-memory-audit/SKILL.md +157 -0
- package/skills/skills/nm-memory-evolution/SKILL.md +202 -0
- package/skills/skills/nm-memory-intake/SKILL.md +135 -0
- package/skills/skills/nm-memory-sync/SKILL.md +184 -0
- package/skills/smali-to-kotlin/SKILL.md +331 -85
- package/skills/smali-to-kotlin/phase-0-discovery.md +93 -94
- package/skills/smali-to-kotlin/phase-1-architecture.md +67 -58
- package/skills/smali-to-kotlin/phase-2-blueprint.md +228 -0
- package/skills/smali-to-kotlin/phase-3-build.md +248 -0
- package/skills/smali-to-kotlin/templates/app-map.md +101 -0
- package/skills/smali-to-kotlin/templates/architecture.md +142 -0
- package/skills/smali-to-kotlin/templates/blueprint.md +145 -0
- package/skills/smali-to-swift/SKILL.md +532 -91
- package/skills/smali-to-swift/phase-0-discovery.md +101 -118
- package/skills/smali-to-swift/phase-1-architecture.md +62 -67
- package/skills/smali-to-swift/phase-2-blueprint.md +173 -0
- package/skills/smali-to-swift/phase-3-build.md +257 -0
- package/skills/smali-to-swift/templates/app-map.md +82 -0
- package/skills/smali-to-swift/templates/architecture.md +97 -0
- package/skills/smali-to-swift/templates/blueprint.md +82 -0
- package/skills/workflows/nm-import.md +73 -0
- package/skills/workflows/nm-recall.md +67 -0
- package/skills/workflows/nm-snapshot.md +69 -0
- package/workflows/_uncategorized/nm-import.md +73 -0
- package/workflows/_uncategorized/nm-recall.md +67 -0
- package/workflows/_uncategorized/nm-snapshot.md +69 -0
- package/workflows/_uncategorized/reverse-android-build.md +222 -0
- package/workflows/_uncategorized/reverse-android-design.md +139 -0
- package/workflows/_uncategorized/reverse-android-discover.md +150 -0
- package/workflows/_uncategorized/reverse-android-scan.md +158 -0
- package/workflows/_uncategorized/reverse-android.md +143 -0
- package/workflows/_uncategorized/reverse-ios-build.md +240 -0
- package/workflows/_uncategorized/reverse-ios-design.md +112 -0
- package/workflows/_uncategorized/reverse-ios-discover.md +120 -0
- package/workflows/_uncategorized/reverse-ios-scan.md +155 -0
- package/workflows/_uncategorized/reverse-ios.md +152 -0
- package/skills/adaptive-language/SKILL.md +0 -189
- package/skills/ambient-brain/SKILL.md +0 -314
- package/skills/ambient-brain/brain-router.md +0 -185
- package/skills/ambient-brain/brain-templates.md +0 -201
- package/skills/context-help/SKILL.md +0 -180
- package/skills/error-translator/SKILL.md +0 -153
- package/skills/session-restore/SKILL.md +0 -240
|
@@ -4,10 +4,9 @@ description: >-
|
|
|
4
4
|
iOS Reverse Engineering specialist. Reads decrypted IPA output (class-dump headers,
|
|
5
5
|
Hopper/IDA disassembly, resources, Info.plist) and rebuilds the app from scratch using
|
|
6
6
|
modern Swift + SwiftUI + Clean Architecture (MVVM).
|
|
7
|
-
UI-First approach: design and approve UI visuals before coding logic.
|
|
8
7
|
Includes framework detection to reuse existing dependencies.
|
|
9
8
|
author: Antigravity Team
|
|
10
|
-
version:
|
|
9
|
+
version: 1.0.0
|
|
11
10
|
trigger: conditional
|
|
12
11
|
activation_keywords:
|
|
13
12
|
- "/reverse-ios"
|
|
@@ -25,11 +24,10 @@ platform: ios
|
|
|
25
24
|
sibling_skill: smali-to-kotlin (Android counterpart)
|
|
26
25
|
---
|
|
27
26
|
|
|
28
|
-
# 🍎 Smali-to-Swift Skill
|
|
27
|
+
# 🍎 Smali-to-Swift Skill
|
|
29
28
|
|
|
30
29
|
> **Purpose:** Transform decrypted iOS IPA (class-dump headers, disassembly, resources, plist) into a modern Swift app with SwiftUI, Clean Architecture, and MVVM.
|
|
31
|
-
> **Philosophy:** "
|
|
32
|
-
> **Key Change (v2):** UI is designed and approved BEFORE coding any business logic.
|
|
30
|
+
> **Philosophy:** "Read ObjC headers to understand WHAT and WHY → Write Swift for HOW."
|
|
33
31
|
|
|
34
32
|
---
|
|
35
33
|
|
|
@@ -42,7 +40,7 @@ sibling_skill: smali-to-kotlin (Android counterpart)
|
|
|
42
40
|
| Detect & reuse third-party frameworks | Crack/bypass DRM or jailbreak |
|
|
43
41
|
| Extract only needed resources (on-demand) | Mass-copy assets blindly |
|
|
44
42
|
| Set up Clean Architecture project structure | Handle Android reverse engineering |
|
|
45
|
-
|
|
|
43
|
+
| Scan IPA frameworks for dependency reuse | Submit to App Store |
|
|
46
44
|
|
|
47
45
|
→ For Android reverse engineering → sibling skill: `smali-to-kotlin`
|
|
48
46
|
→ After rebuild complete → use `/test` or `/deploy` workflows
|
|
@@ -57,7 +55,7 @@ When this skill is active, the agent becomes:
|
|
|
57
55
|
> - Master at reading ObjC/Swift class-dump headers and ARM disassembly
|
|
58
56
|
> - Fluent in Clean Architecture + MVVM + SwiftUI
|
|
59
57
|
> - Knows when to reuse vs rewrite third-party frameworks
|
|
60
|
-
> - Enforces
|
|
58
|
+
> - Enforces resource-on-demand principle (zero bloat)
|
|
61
59
|
|
|
62
60
|
---
|
|
63
61
|
|
|
@@ -76,12 +74,17 @@ When this skill is active, the agent becomes:
|
|
|
76
74
|
### What we get from an IPA:
|
|
77
75
|
```
|
|
78
76
|
Payload/App.app/
|
|
79
|
-
├── App # Mach-O binary (need decrypt first)
|
|
80
|
-
├── Info.plist # App metadata
|
|
81
|
-
├── Frameworks/ # Embedded frameworks
|
|
77
|
+
├── App # Mach-O binary (encrypted → need decrypt first)
|
|
78
|
+
├── Info.plist # App metadata (bundle ID, permissions, URL schemes)
|
|
79
|
+
├── Frameworks/ # Embedded frameworks (.framework / .dylib)
|
|
80
|
+
│ ├── SomeSDK.framework/
|
|
81
|
+
│ └── libswiftCore.dylib
|
|
82
82
|
├── Assets.car # Compiled asset catalog
|
|
83
83
|
├── Base.lproj/ # Storyboards / XIBs (compiled)
|
|
84
|
-
├──
|
|
84
|
+
│ ├── Main.storyboardc/
|
|
85
|
+
│ └── LaunchScreen.storyboardc/
|
|
86
|
+
├── *.nib # Compiled XIB files
|
|
87
|
+
├── *.momd # Core Data models (compiled)
|
|
85
88
|
├── embedded.mobileprovision # Provisioning profile
|
|
86
89
|
├── _CodeSignature/ # Code signing
|
|
87
90
|
└── [other resources: json, png, html, js, fonts...]
|
|
@@ -103,10 +106,10 @@ Payload/App.app/
|
|
|
103
106
|
| Purpose | Technology | Replaces |
|
|
104
107
|
|---------|-----------|----------|
|
|
105
108
|
| **Network** | URLSession + async/await | AFNetworking / Alamofire (evaluate) |
|
|
106
|
-
| **JSON** | Codable (Swift built-in) | NSJSONSerialization / Mantle |
|
|
109
|
+
| **JSON** | Codable (Swift built-in) | NSJSONSerialization / Mantle / ObjectMapper |
|
|
107
110
|
| **Local DB** | SwiftData (iOS 17+) or Core Data | Raw SQLite / FMDB / Realm |
|
|
108
111
|
| **Preferences** | UserDefaults / @AppStorage | NSUserDefaults direct |
|
|
109
|
-
| **Keychain** | KeychainAccess (or custom) | Raw Security.framework |
|
|
112
|
+
| **Keychain** | KeychainAccess (or custom wrapper) | Raw Security.framework |
|
|
110
113
|
| **Image Loading** | AsyncImage / Kingfisher / Nuke | SDWebImage (evaluate) |
|
|
111
114
|
| **Async** | Swift Concurrency (async/await, actors) | GCD / NSOperation / PromiseKit |
|
|
112
115
|
|
|
@@ -127,22 +130,33 @@ always_replace:
|
|
|
127
130
|
Mantle/ObjectMapper: "Codable"
|
|
128
131
|
GCD_dispatch_async: "Task { } / async-await"
|
|
129
132
|
NSOperation: "TaskGroup / async let"
|
|
133
|
+
NSTimer: "Timer.publish (Combine) or Task.sleep"
|
|
134
|
+
UIAlertView: "SwiftUI .alert modifier"
|
|
135
|
+
UIActionSheet: "SwiftUI .confirmationDialog"
|
|
130
136
|
UITableView: "List / LazyVStack"
|
|
131
137
|
UICollectionView: "LazyVGrid / LazyHGrid"
|
|
138
|
+
UIPageViewController: "TabView with .page style"
|
|
132
139
|
Storyboard_segues: "NavigationStack + NavigationLink"
|
|
140
|
+
NSNotificationCenter_addObserver: "NotificationCenter.notifications (AsyncSequence)"
|
|
133
141
|
KVO: "@Observable macro"
|
|
134
142
|
Delegate_patterns: "AsyncStream or closures"
|
|
135
143
|
Target_Action: "SwiftUI action closures"
|
|
136
144
|
|
|
137
145
|
evaluate_before_replacing:
|
|
138
|
-
Alamofire: "Keep if deeply used,
|
|
139
|
-
SDWebImage: "
|
|
140
|
-
Realm: "
|
|
141
|
-
RxSwift: "
|
|
142
|
-
SnapKit: "
|
|
146
|
+
Alamofire: "Keep if deeply used for interceptors/retry, otherwise → URLSession"
|
|
147
|
+
SDWebImage: "Replace with AsyncImage + Kingfisher"
|
|
148
|
+
Realm: "Migrate to SwiftData (if iOS 17+)"
|
|
149
|
+
RxSwift: "Migrate to async/await + AsyncSequence (gradual)"
|
|
150
|
+
SnapKit: "Replace with SwiftUI layout"
|
|
151
|
+
Masonry: "Replace with SwiftUI layout"
|
|
152
|
+
MBProgressHUD: "SwiftUI .overlay + ProgressView"
|
|
153
|
+
SVProgressHUD: "SwiftUI .overlay + ProgressView"
|
|
154
|
+
IQKeyboardManager: "SwiftUI handles keyboard automatically"
|
|
143
155
|
|
|
144
156
|
keep_as_is:
|
|
145
157
|
- "Firebase SDKs (use latest via SPM)"
|
|
158
|
+
- "Google Sign-In"
|
|
159
|
+
- "Facebook SDK (latest)"
|
|
146
160
|
- "Apple frameworks (MapKit, CoreLocation, AVFoundation, etc.)"
|
|
147
161
|
- "Native C/C++ libraries (.dylib)"
|
|
148
162
|
- "CryptoKit (Apple native)"
|
|
@@ -150,50 +164,492 @@ keep_as_is:
|
|
|
150
164
|
|
|
151
165
|
---
|
|
152
166
|
|
|
153
|
-
## 📋 EXECUTION PIPELINE (
|
|
167
|
+
## 📋 EXECUTION PIPELINE (6 Steps)
|
|
168
|
+
|
|
169
|
+
> **Rule:** Always complete one step fully before moving to the next.
|
|
170
|
+
> **Rule:** After each step, create a checkpoint summary for the user.
|
|
171
|
+
|
|
172
|
+
### Step 0: Framework Scanner (PRE-STEP — Always First) 🔍
|
|
173
|
+
|
|
174
|
+
**Purpose:** Scan the IPA structure to identify all third-party frameworks before any coding.
|
|
175
|
+
|
|
176
|
+
**Process:**
|
|
177
|
+
1. **Scan `Frameworks/` directory:**
|
|
178
|
+
```
|
|
179
|
+
Frameworks/Alamofire.framework → Alamofire (network)
|
|
180
|
+
Frameworks/SDWebImage.framework → SDWebImage (image loading)
|
|
181
|
+
Frameworks/Realm.framework → Realm (database)
|
|
182
|
+
Frameworks/FBSDKCoreKit.framework → Facebook SDK
|
|
183
|
+
Frameworks/GoogleSignIn.framework → Google Sign-In
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
2. **Scan class-dump headers for imports:**
|
|
187
|
+
```
|
|
188
|
+
#import <AFNetworking/...> → AFNetworking
|
|
189
|
+
#import <Masonry/...> → Masonry (auto-layout)
|
|
190
|
+
#import <MBProgressHUD/...> → MBProgressHUD
|
|
191
|
+
@import Firebase; → Firebase SDK
|
|
192
|
+
@import GoogleMobileAds; → AdMob
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
3. **Check Mach-O linked frameworks:**
|
|
196
|
+
```bash
|
|
197
|
+
otool -L Payload/App.app/App | grep -v /System | grep -v /usr/lib
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
4. **Check embedded dylibs:**
|
|
201
|
+
```bash
|
|
202
|
+
find Payload/App.app -name "*.dylib" -o -name "*.framework" | sort
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
5. **Check for CocoaPods / SPM markers:**
|
|
206
|
+
```
|
|
207
|
+
Pods/ directory presence → was using CocoaPods
|
|
208
|
+
.package.resolved → was using SPM
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
6. **Output: Framework Detection Report**
|
|
212
|
+
```markdown
|
|
213
|
+
## 📦 Framework Detection Report
|
|
214
|
+
|
|
215
|
+
### ✅ Can Reuse (add to Package.swift / Podfile)
|
|
216
|
+
| Framework | Detected | Latest Version | Action |
|
|
217
|
+
|-----------|----------|----------------|--------|
|
|
218
|
+
| Alamofire | Frameworks/Alamofire.framework | 5.9.0 | Evaluate |
|
|
219
|
+
| Kingfisher | (header import) | 7.12.0 | Add via SPM |
|
|
220
|
+
|
|
221
|
+
### 🔄 Must Replace (legacy)
|
|
222
|
+
| Old Framework | Detected | Modern Replacement |
|
|
223
|
+
|---------------|----------|-------------------|
|
|
224
|
+
| AFNetworking | Frameworks/AFNetworking.framework | URLSession async/await |
|
|
225
|
+
| Masonry | header imports | SwiftUI layout |
|
|
226
|
+
|
|
227
|
+
### 🍏 Apple Frameworks Used
|
|
228
|
+
| Framework | Purpose |
|
|
229
|
+
|-----------|---------|
|
|
230
|
+
| MapKit | Maps |
|
|
231
|
+
| CoreLocation | GPS |
|
|
232
|
+
| AVFoundation | Camera/Audio |
|
|
233
|
+
|
|
234
|
+
### 📱 Native (.dylib) — Investigate
|
|
235
|
+
| File | Notes |
|
|
236
|
+
|------|-------|
|
|
237
|
+
| libcrypto.dylib | Custom crypto? |
|
|
238
|
+
|
|
239
|
+
### ❓ Unknown (investigate)
|
|
240
|
+
| Framework/Import | Notes |
|
|
241
|
+
|------------------|-------|
|
|
242
|
+
| CustomSDK.framework | Proprietary? |
|
|
243
|
+
```
|
|
154
244
|
|
|
155
|
-
|
|
156
|
-
> **Rule:** Always complete one phase fully before moving to the next.
|
|
157
|
-
> **Rule:** UI must be approved before coding logic.
|
|
245
|
+
---
|
|
158
246
|
|
|
247
|
+
### Step 1: Info.plist & Entitlements Analysis + Project Bootstrap 📄
|
|
248
|
+
|
|
249
|
+
**Input:** User provides `Info.plist` + entitlements from IPA.
|
|
250
|
+
|
|
251
|
+
**Tasks:**
|
|
252
|
+
1. Extract Bundle ID and display name
|
|
253
|
+
2. List required permissions (Privacy keys):
|
|
254
|
+
```
|
|
255
|
+
NSCameraUsageDescription → Camera
|
|
256
|
+
NSPhotoLibraryUsageDescription → Photo Library
|
|
257
|
+
NSLocationWhenInUseUsageDescription → Location
|
|
258
|
+
NSMicrophoneUsageDescription → Microphone
|
|
259
|
+
```
|
|
260
|
+
3. Identify URL Schemes (deep links)
|
|
261
|
+
4. Check app capabilities from entitlements:
|
|
262
|
+
```
|
|
263
|
+
com.apple.developer.associated-domains → Universal Links
|
|
264
|
+
aps-environment → Push Notifications
|
|
265
|
+
com.apple.developer.in-app-payments → Apple Pay
|
|
266
|
+
```
|
|
267
|
+
5. Analyze class-dump headers for entry points:
|
|
268
|
+
- `AppDelegate` → lifecycle logic
|
|
269
|
+
- Root ViewController → initial screen
|
|
270
|
+
- Tab bar / Navigation structure
|
|
271
|
+
6. **Output:** Propose Clean Architecture project structure
|
|
272
|
+
|
|
273
|
+
**Project Structure Template:**
|
|
159
274
|
```
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
275
|
+
App/
|
|
276
|
+
├── App.swift # @main entry point
|
|
277
|
+
├── AppDelegate.swift # UIKit lifecycle (if needed for SDKs)
|
|
278
|
+
├── Info.plist
|
|
279
|
+
├── Assets.xcassets/
|
|
280
|
+
├── DI/ # Dependency Injection
|
|
281
|
+
│ └── AppContainer.swift
|
|
282
|
+
├── Data/ # Data Layer
|
|
283
|
+
│ ├── Network/
|
|
284
|
+
│ │ ├── APIClient.swift # URLSession wrapper
|
|
285
|
+
│ │ ├── Endpoints/ # API endpoint definitions
|
|
286
|
+
│ │ └── DTOs/ # Codable response models
|
|
287
|
+
│ ├── Local/
|
|
288
|
+
│ │ ├── SwiftDataModels/ # @Model classes
|
|
289
|
+
│ │ ├── KeychainService.swift
|
|
290
|
+
│ │ └── UserDefaultsKeys.swift
|
|
291
|
+
│ └── Repositories/ # Repository implementations
|
|
292
|
+
├── Domain/ # Domain Layer
|
|
293
|
+
│ ├── Models/ # Business models
|
|
294
|
+
│ ├── Repositories/ # Repository protocols
|
|
295
|
+
│ └── UseCases/
|
|
296
|
+
├── Presentation/ # Presentation Layer
|
|
297
|
+
│ ├── Navigation/
|
|
298
|
+
│ │ ├── AppNavigation.swift # NavigationStack + routes
|
|
299
|
+
│ │ └── Route.swift # Deep link routes
|
|
300
|
+
│ ├── Theme/
|
|
301
|
+
│ │ ├── AppTheme.swift # Colors, fonts, spacing
|
|
302
|
+
│ │ └── Components/ # Reusable SwiftUI components
|
|
303
|
+
│ └── Screens/
|
|
304
|
+
│ ├── Launch/
|
|
305
|
+
│ │ └── LaunchScreen.swift
|
|
306
|
+
│ ├── Auth/
|
|
307
|
+
│ │ ├── LoginScreen.swift
|
|
308
|
+
│ │ └── LoginViewModel.swift
|
|
309
|
+
│ ├── Home/
|
|
310
|
+
│ │ ├── HomeScreen.swift
|
|
311
|
+
│ │ └── HomeViewModel.swift
|
|
312
|
+
│ └── ...
|
|
313
|
+
├── Utilities/
|
|
314
|
+
│ ├── Extensions/
|
|
315
|
+
│ ├── Crypto/ # Encryption/hashing utils
|
|
316
|
+
│ └── Helpers/
|
|
317
|
+
└── Resources/
|
|
318
|
+
├── Localizable.xcstrings
|
|
319
|
+
└── Fonts/
|
|
169
320
|
```
|
|
170
321
|
|
|
171
|
-
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
### Step 2: Data Layer Reconstruction 💾
|
|
325
|
+
|
|
326
|
+
**Input:** User provides class-dump headers + Hopper pseudo-code for network/data classes.
|
|
327
|
+
|
|
328
|
+
**Tasks:**
|
|
329
|
+
1. **Models:** Convert ObjC interfaces → Swift structs
|
|
330
|
+
```objc
|
|
331
|
+
// ObjC header (class-dump)
|
|
332
|
+
@interface UserModel : NSObject
|
|
333
|
+
@property (nonatomic, copy) NSString *userId;
|
|
334
|
+
@property (nonatomic, copy) NSString *fullName;
|
|
335
|
+
@property (nonatomic, assign) NSInteger age;
|
|
336
|
+
@end
|
|
337
|
+
```
|
|
338
|
+
```swift
|
|
339
|
+
// Swift
|
|
340
|
+
struct User: Codable, Identifiable {
|
|
341
|
+
let id: String
|
|
342
|
+
let fullName: String
|
|
343
|
+
let age: Int
|
|
344
|
+
|
|
345
|
+
enum CodingKeys: String, CodingKey {
|
|
346
|
+
case id = "user_id"
|
|
347
|
+
case fullName = "full_name"
|
|
348
|
+
case age
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
2. **API Layer:**
|
|
354
|
+
- Extract base URL, endpoints, headers from disassembly
|
|
355
|
+
- Create async URLSession-based API client:
|
|
356
|
+
```swift
|
|
357
|
+
actor APIClient {
|
|
358
|
+
private let session: URLSession
|
|
359
|
+
private let baseURL: URL
|
|
360
|
+
|
|
361
|
+
func request<T: Decodable>(_ endpoint: Endpoint) async throws -> T {
|
|
362
|
+
let (data, response) = try await session.data(for: endpoint.urlRequest(baseURL: baseURL))
|
|
363
|
+
guard let httpResponse = response as? HTTPURLResponse,
|
|
364
|
+
(200...299).contains(httpResponse.statusCode) else {
|
|
365
|
+
throw APIError.invalidResponse
|
|
366
|
+
}
|
|
367
|
+
return try JSONDecoder().decode(T.self, from: data)
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
3. **Local Storage:**
|
|
373
|
+
- CoreData models → SwiftData `@Model` classes
|
|
374
|
+
- NSUserDefaults keys → `@AppStorage` or typed UserDefaults wrapper
|
|
375
|
+
- Keychain items → KeychainAccess wrapper
|
|
376
|
+
|
|
377
|
+
4. **Repository:**
|
|
378
|
+
```swift
|
|
379
|
+
// Domain layer - protocol
|
|
380
|
+
protocol UserRepository: Sendable {
|
|
381
|
+
func getUser(id: String) async throws -> User
|
|
382
|
+
func login(email: String, password: String) async throws -> AuthToken
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Data layer - implementation
|
|
386
|
+
final class UserRepositoryImpl: UserRepository {
|
|
387
|
+
private let apiClient: APIClient
|
|
388
|
+
private let modelContext: ModelContext
|
|
389
|
+
|
|
390
|
+
func getUser(id: String) async throws -> User {
|
|
391
|
+
// offline-first: check local → fetch remote → cache
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
### Step 3: Core Logic & Utils Reconstruction 🧮
|
|
399
|
+
|
|
400
|
+
**Input:** Disassembly/pseudo-code for encryption, hashing, custom utils.
|
|
401
|
+
|
|
402
|
+
**Tasks:**
|
|
403
|
+
1. Translate ObjC/C crypto logic → Swift
|
|
404
|
+
- Use `CryptoKit` for modern crypto (SHA256, AES-GCM, HMAC)
|
|
405
|
+
- Use `CommonCrypto` for legacy-compatible (MD5, AES-CBC)
|
|
406
|
+
- Preserve exact input/output signatures
|
|
407
|
+
|
|
408
|
+
2. Common ObjC → Swift crypto patterns:
|
|
409
|
+
```objc
|
|
410
|
+
// ObjC (class-dump + disassembly)
|
|
411
|
+
+ (NSString *)md5Hash:(NSString *)input;
|
|
412
|
+
+ (NSData *)aesEncrypt:(NSData *)data withKey:(NSString *)key;
|
|
413
|
+
```
|
|
414
|
+
```swift
|
|
415
|
+
// Swift
|
|
416
|
+
import CryptoKit
|
|
417
|
+
import CommonCrypto
|
|
418
|
+
|
|
419
|
+
enum CryptoUtils {
|
|
420
|
+
static func md5Hash(_ input: String) -> String {
|
|
421
|
+
let data = Data(input.utf8)
|
|
422
|
+
var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
|
|
423
|
+
data.withUnsafeBytes { CC_MD5($0.baseAddress, CC_LONG(data.count), &digest) }
|
|
424
|
+
return digest.map { String(format: "%02x", $0) }.joined()
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
static func aesEncrypt(data: Data, key: String) throws -> Data {
|
|
428
|
+
// Implement matching original algorithm exactly
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
3. **Verification:** XCTest unit tests with known input/output pairs
|
|
434
|
+
|
|
435
|
+
**Critical Rule:**
|
|
436
|
+
> ⚠️ Crypto/hash functions MUST produce identical output to the original app.
|
|
437
|
+
> Test with known pairs captured from the running original app.
|
|
172
438
|
|
|
173
|
-
|
|
174
|
-
- `phase-0-discovery.md` — Framework scan, plist analysis, app map
|
|
175
|
-
- `phase-1-architecture.md` — Layer design, feature mapping, build order
|
|
176
|
-
- `phase-2-blueprint-ui.md` — Contracts + UI visual shell + parity check
|
|
177
|
-
- `phase-3-logic-build.md` — Domain, data, DI, ViewModel, wire UI↔logic
|
|
439
|
+
---
|
|
178
440
|
|
|
179
|
-
###
|
|
180
|
-
|
|
181
|
-
|
|
441
|
+
### Step 4: UI & ViewModel Reconstruction (Per Screen) 🎨
|
|
442
|
+
|
|
443
|
+
**Input:** Storyboard analysis + class-dump headers for ViewControllers.
|
|
444
|
+
|
|
445
|
+
**Tasks:**
|
|
446
|
+
1. **Resource Extraction (On-Demand):**
|
|
447
|
+
- Extract only images, colors, strings for current screen
|
|
448
|
+
- Use Asset Catalog for organized resources
|
|
449
|
+
- Map ObjC string tables to `Localizable.xcstrings`
|
|
450
|
+
|
|
451
|
+
2. **UIKit → SwiftUI Migration:**
|
|
452
|
+
```
|
|
453
|
+
UIViewController → SwiftUI View struct
|
|
454
|
+
UINavigationController → NavigationStack
|
|
455
|
+
UITabBarController → TabView
|
|
456
|
+
UITableView → List / LazyVStack
|
|
457
|
+
UICollectionView → LazyVGrid / LazyHGrid
|
|
458
|
+
UIScrollView → ScrollView
|
|
459
|
+
UIImageView → AsyncImage / Image
|
|
460
|
+
UILabel → Text
|
|
461
|
+
UITextField → TextField
|
|
462
|
+
UIButton → Button
|
|
463
|
+
UIActivityIndicatorView → ProgressView
|
|
464
|
+
UIAlertController → .alert / .confirmationDialog modifier
|
|
465
|
+
UIPageViewController → TabView(.page)
|
|
466
|
+
UIStackView → VStack / HStack
|
|
467
|
+
MKMapView → Map (MapKit SwiftUI)
|
|
468
|
+
WKWebView → WebView (custom wrapper)
|
|
469
|
+
UIRefreshControl → .refreshable modifier
|
|
470
|
+
UISearchController → .searchable modifier
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
3. **ViewModel Creation:**
|
|
474
|
+
```swift
|
|
475
|
+
@Observable
|
|
476
|
+
final class LoginViewModel {
|
|
477
|
+
var email = ""
|
|
478
|
+
var password = ""
|
|
479
|
+
var isLoading = false
|
|
480
|
+
var error: String?
|
|
481
|
+
|
|
482
|
+
private let loginUseCase: LoginUseCase
|
|
483
|
+
|
|
484
|
+
init(loginUseCase: LoginUseCase) {
|
|
485
|
+
self.loginUseCase = loginUseCase
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
func login() async {
|
|
489
|
+
isLoading = true
|
|
490
|
+
defer { isLoading = false }
|
|
491
|
+
do {
|
|
492
|
+
try await loginUseCase.execute(email: email, password: password)
|
|
493
|
+
} catch {
|
|
494
|
+
self.error = error.localizedDescription
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
4. **Screen Composable:**
|
|
501
|
+
```swift
|
|
502
|
+
struct LoginScreen: View {
|
|
503
|
+
@State private var viewModel: LoginViewModel
|
|
504
|
+
|
|
505
|
+
init(loginUseCase: LoginUseCase) {
|
|
506
|
+
_viewModel = State(initialValue: LoginViewModel(loginUseCase: loginUseCase))
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
var body: some View {
|
|
510
|
+
Form {
|
|
511
|
+
TextField("Email", text: $viewModel.email)
|
|
512
|
+
.textContentType(.emailAddress)
|
|
513
|
+
.keyboardType(.emailAddress)
|
|
514
|
+
|
|
515
|
+
SecureField("Password", text: $viewModel.password)
|
|
516
|
+
.textContentType(.password)
|
|
517
|
+
|
|
518
|
+
Button("Login") {
|
|
519
|
+
Task { await viewModel.login() }
|
|
520
|
+
}
|
|
521
|
+
.disabled(viewModel.isLoading)
|
|
522
|
+
}
|
|
523
|
+
.overlay { if viewModel.isLoading { ProgressView() } }
|
|
524
|
+
.alert("Error", isPresented: .constant(viewModel.error != nil)) {
|
|
525
|
+
Button("OK") { viewModel.error = nil }
|
|
526
|
+
} message: {
|
|
527
|
+
Text(viewModel.error ?? "")
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
```
|
|
182
532
|
|
|
183
533
|
---
|
|
184
534
|
|
|
185
|
-
|
|
535
|
+
### Step 5: Third-party SDK & Native Library Integration 📦
|
|
536
|
+
|
|
537
|
+
**Input:** Framework Report from Step 0.
|
|
538
|
+
|
|
539
|
+
**Tasks:**
|
|
540
|
+
1. **Swift Package Manager setup:**
|
|
541
|
+
```swift
|
|
542
|
+
// Package.swift dependencies (or Xcode SPM UI)
|
|
543
|
+
dependencies: [
|
|
544
|
+
.package(url: "https://github.com/firebase/firebase-ios-sdk", from: "11.0.0"),
|
|
545
|
+
.package(url: "https://github.com/onevcat/Kingfisher", from: "7.12.0"),
|
|
546
|
+
.package(url: "https://github.com/kishikawakatsumi/KeychainAccess", from: "4.2.2"),
|
|
547
|
+
]
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
2. **Native C/C++ libraries:**
|
|
551
|
+
```swift
|
|
552
|
+
// Bridging header for C libraries
|
|
553
|
+
// App-Bridging-Header.h
|
|
554
|
+
#include "native_crypto.h"
|
|
555
|
+
|
|
556
|
+
// Swift usage
|
|
557
|
+
func callNativeFunction() -> String {
|
|
558
|
+
let result = native_function_name(param)
|
|
559
|
+
return String(cString: result)
|
|
560
|
+
}
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
3. **App lifecycle for SDK init:**
|
|
564
|
+
```swift
|
|
565
|
+
@main
|
|
566
|
+
struct MyApp: App {
|
|
567
|
+
@UIApplicationDelegateAdaptor private var appDelegate: AppDelegate
|
|
568
|
+
|
|
569
|
+
var body: some Scene {
|
|
570
|
+
WindowGroup {
|
|
571
|
+
ContentView()
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
class AppDelegate: NSObject, UIApplicationDelegate {
|
|
577
|
+
func application(_ application: UIApplication,
|
|
578
|
+
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
|
579
|
+
FirebaseApp.configure()
|
|
580
|
+
// Other SDK initialization
|
|
581
|
+
return true
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
---
|
|
587
|
+
|
|
588
|
+
### Step 6: Parity Check & Quality Gate ✅
|
|
589
|
+
|
|
590
|
+
**Per-module checklist:**
|
|
591
|
+
1. **Branch Coverage:** Review all conditional paths from disassembly
|
|
592
|
+
2. **API Parity:** Same requests/responses as original
|
|
593
|
+
3. **Data Parity:** Crypto output matches, local storage compatible
|
|
594
|
+
4. **UI Parity:** Screen-by-screen comparison
|
|
595
|
+
5. **Performance:**
|
|
596
|
+
- Instruments profiling
|
|
597
|
+
- No unnecessary @State re-renders
|
|
598
|
+
- Proper actor isolation (no data races)
|
|
599
|
+
|
|
600
|
+
---
|
|
601
|
+
|
|
602
|
+
## 🔍 ObjC HEADER READING GUIDE
|
|
603
|
+
|
|
604
|
+
### Property Types → Swift
|
|
605
|
+
```objc
|
|
606
|
+
@property (nonatomic, copy) NSString *name; // → let name: String
|
|
607
|
+
@property (nonatomic, strong) NSArray *items; // → let items: [Any] (refine type)
|
|
608
|
+
@property (nonatomic, assign) BOOL isActive; // → let isActive: Bool
|
|
609
|
+
@property (nonatomic, assign) NSInteger count; // → let count: Int
|
|
610
|
+
@property (nonatomic, assign) CGFloat height; // → let height: CGFloat
|
|
611
|
+
@property (nonatomic, strong) NSDictionary *meta; // → let meta: [String: Any]
|
|
612
|
+
@property (nonatomic, strong) NSDate *createdAt; // → let createdAt: Date
|
|
613
|
+
@property (nonatomic, strong) NSURL *imageURL; // → let imageURL: URL?
|
|
614
|
+
@property (nonatomic, strong) NSData *data; // → let data: Data
|
|
615
|
+
@property (nullable, nonatomic, copy) NSString *bio; // → let bio: String?
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
### Method Signatures → Swift
|
|
619
|
+
```objc
|
|
620
|
+
- (void)fetchUserWithId:(NSString *)userId completion:(void (^)(UserModel *, NSError *))completion;
|
|
621
|
+
// → func fetchUser(id: String) async throws -> User
|
|
622
|
+
|
|
623
|
+
+ (instancetype)sharedInstance;
|
|
624
|
+
// → static let shared = ClassName()
|
|
625
|
+
|
|
626
|
+
- (BOOL)validateEmail:(NSString *)email;
|
|
627
|
+
// → func validateEmail(_ email: String) -> Bool
|
|
628
|
+
```
|
|
186
629
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
630
|
+
### Delegate Patterns → Swift
|
|
631
|
+
```objc
|
|
632
|
+
@protocol UserServiceDelegate <NSObject>
|
|
633
|
+
- (void)userServiceDidFetchUser:(UserModel *)user;
|
|
634
|
+
- (void)userServiceDidFailWithError:(NSError *)error;
|
|
635
|
+
@end
|
|
636
|
+
```
|
|
637
|
+
```swift
|
|
638
|
+
// Replace with async/await:
|
|
639
|
+
func fetchUser() async throws -> User
|
|
640
|
+
// Or AsyncStream for multiple values:
|
|
641
|
+
func userUpdates() -> AsyncStream<User>
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
### Blocks → Closures / async
|
|
645
|
+
```objc
|
|
646
|
+
typedef void (^CompletionHandler)(NSData * _Nullable data, NSError * _Nullable error);
|
|
647
|
+
- (void)requestWithCompletion:(CompletionHandler)completion;
|
|
648
|
+
```
|
|
649
|
+
```swift
|
|
650
|
+
// Modern Swift: drop the callback, use async
|
|
651
|
+
func request() async throws -> Data
|
|
652
|
+
```
|
|
197
653
|
|
|
198
654
|
---
|
|
199
655
|
|
|
@@ -202,12 +658,12 @@ Each phase has a detailed instruction file:
|
|
|
202
658
|
```yaml
|
|
203
659
|
triggers_from:
|
|
204
660
|
- "/reverse-ios" workflow command
|
|
205
|
-
- Keywords: "ipa", "class-dump", "objc to swift", "dịch ngược ios"
|
|
661
|
+
- Keywords: "ipa", "class-dump", "objc to swift", "dịch ngược ios", "reverse ios"
|
|
206
662
|
|
|
207
663
|
delegates_to:
|
|
208
664
|
- "/test" — after parity check
|
|
209
665
|
- "/deploy" — when rebuild is complete
|
|
210
|
-
- beads-manager — auto-track progress per
|
|
666
|
+
- beads-manager — auto-track progress per step
|
|
211
667
|
|
|
212
668
|
works_with:
|
|
213
669
|
- memory-sync — saves decisions, patterns, solutions
|
|
@@ -219,58 +675,41 @@ independent_from:
|
|
|
219
675
|
- smali-to-kotlin (sibling, same pattern, different platform)
|
|
220
676
|
```
|
|
221
677
|
|
|
222
|
-
### Session State Tracking
|
|
223
|
-
|
|
224
|
-
```yaml
|
|
225
|
-
session_state:
|
|
226
|
-
current_phase: 0-4
|
|
227
|
-
current_feature: "Auth"
|
|
228
|
-
phase_2_status:
|
|
229
|
-
contracts: approved | pending
|
|
230
|
-
ui_shell: approved | pending
|
|
231
|
-
resources: extracted | pending
|
|
232
|
-
completed_features: ["Launch", "Login"]
|
|
233
|
-
pending_features: ["Home", "Settings"]
|
|
234
|
-
```
|
|
235
|
-
|
|
236
678
|
---
|
|
237
679
|
|
|
238
680
|
## 🚫 ANTI-PATTERNS
|
|
239
681
|
|
|
240
682
|
```yaml
|
|
241
683
|
never_do:
|
|
242
|
-
- Copy all resources blindly from IPA → only on-demand
|
|
243
|
-
- Skip Phase 2 UI gate → jump to logic coding
|
|
244
|
-
- Code ViewModel before UI is approved → UI design might change
|
|
245
|
-
- Modify UI shell significantly in Phase 3 → only wire, don't redesign
|
|
684
|
+
- Copy all resources blindly from IPA → only on-demand
|
|
246
685
|
- Use UIKit when SwiftUI equivalent exists → always prefer SwiftUI
|
|
247
|
-
- Use GCD for new code → use async/await
|
|
686
|
+
- Use GCD dispatch_async for new code → use async/await
|
|
687
|
+
- Use NSJSONSerialization → use Codable
|
|
248
688
|
- Modify encryption output → must match original exactly
|
|
249
|
-
- Create massive ViewController God objects → split into Views + ViewModels
|
|
689
|
+
- Create massive ViewController God objects → split into SwiftUI Views + ViewModels
|
|
250
690
|
- Skip framework scanner step → always detect reusable dependencies first
|
|
251
|
-
- Use ObjC in new code → Swift only (except bridging headers)
|
|
691
|
+
- Use ObjC in new code → Swift only (except bridging headers for C libs)
|
|
252
692
|
- Force unwrap optionals → use guard let / if let / nil coalescing
|
|
253
693
|
|
|
254
694
|
always_do:
|
|
255
|
-
- Run Framework Scanner (
|
|
256
|
-
-
|
|
257
|
-
- Create #Preview for ALL states (normal, loading, error, empty)
|
|
258
|
-
- Get user approval on UI before coding logic
|
|
259
|
-
- Keep stateless View for Preview even after wiring
|
|
695
|
+
- Run Framework Scanner (Step 0) before any coding
|
|
696
|
+
- Present framework report to user for approval
|
|
260
697
|
- Use Swift Concurrency (async/await) for all async operations
|
|
261
698
|
- Use @Observable (iOS 17+) for ViewModels
|
|
262
|
-
- Use
|
|
699
|
+
- Use NavigationStack for navigation
|
|
263
700
|
- Unit test all encryption/hashing utils
|
|
701
|
+
- Follow Clean Architecture layer separation strictly
|
|
702
|
+
- Use SPM for dependency management (not CocoaPods)
|
|
264
703
|
```
|
|
265
704
|
|
|
266
705
|
---
|
|
267
706
|
|
|
268
707
|
## 📊 CHECKPOINT TEMPLATE
|
|
269
708
|
|
|
270
|
-
After each
|
|
709
|
+
After each step, output:
|
|
271
710
|
|
|
272
711
|
```markdown
|
|
273
|
-
## ✅ [
|
|
712
|
+
## ✅ Step [N] Complete: [Step Name]
|
|
274
713
|
|
|
275
714
|
### What was done:
|
|
276
715
|
- [Summary]
|
|
@@ -284,7 +723,7 @@ After each phase/feature, output:
|
|
|
284
723
|
### Decisions made:
|
|
285
724
|
- [Key decisions]
|
|
286
725
|
|
|
287
|
-
### ⏭️ Next: [
|
|
726
|
+
### ⏭️ Next: Step [N+1] — [Step Name]
|
|
288
727
|
- [What user needs to provide]
|
|
289
728
|
```
|
|
290
729
|
|
|
@@ -292,17 +731,19 @@ After each phase/feature, output:
|
|
|
292
731
|
|
|
293
732
|
## 🧩 PLATFORM RE TEMPLATE PATTERN
|
|
294
733
|
|
|
295
|
-
This skill follows the same **
|
|
734
|
+
This skill follows the same **6-step pipeline** as `smali-to-kotlin`:
|
|
296
735
|
|
|
297
|
-
|
|
|
298
|
-
|
|
736
|
+
| Step | Android (smali-to-kotlin) | iOS (smali-to-swift) |
|
|
737
|
+
|------|--------------------------|---------------------|
|
|
299
738
|
| 0 | Library Scanner (Smali packages) | Framework Scanner (Frameworks/ + headers) |
|
|
300
|
-
| 1 | AndroidManifest
|
|
301
|
-
| 2 |
|
|
302
|
-
| 3 |
|
|
303
|
-
| 4 |
|
|
739
|
+
| 1 | AndroidManifest.xml | Info.plist + Entitlements |
|
|
740
|
+
| 2 | Retrofit + Room | URLSession + SwiftData |
|
|
741
|
+
| 3 | Kotlin crypto utils | Swift CryptoKit/CommonCrypto |
|
|
742
|
+
| 4 | Jetpack Compose + StateFlow | SwiftUI + @Observable |
|
|
743
|
+
| 5 | Hilt + JNI | SPM + Bridging Header |
|
|
744
|
+
| 6 | Parity Check | Parity Check |
|
|
304
745
|
|
|
305
746
|
---
|
|
306
747
|
|
|
307
|
-
*smali-to-swift
|
|
748
|
+
*smali-to-swift v1.0.0 — iOS Reverse Engineering Skill for AWF*
|
|
308
749
|
*Created by Antigravity Team*
|