appstore-precheck 1.1.1 → 1.5.1

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 CHANGED
@@ -3,6 +3,124 @@
3
3
  All notable changes to this project are documented here. Versioning follows
4
4
  [SemVer](https://semver.org/). Released as git tags.
5
5
 
6
+ ## [1.5.1] - 2026-06-30
7
+
8
+ ### Changed
9
+
10
+ - Plugin manifest descriptions no longer embed drifting check counts
11
+ - README uninstall: Codex uses /plugins UI
12
+ - cross-tool-verification.md plugin install paths documented
13
+ - GitHub release v1.5.0 notes amended; npm 1.5.1 published
14
+
15
+ ## [1.5.0] - 2026-06-30
16
+
17
+ ### Added
18
+ - **Tier B v1 — 6 heuristic Pierre deep-review checks** (28 total, up from 22). New Phase 4 items
19
+ in guideline order: **2.1** review notes / demo account quality, **2.2** beta/test language,
20
+ **2.3.4** app preview consistency, **2.3.9** incentivized review copy, **4.5.1–4.5.3** push /
21
+ HomeKit abuse patterns, **5.6.4–5.6.7** rating manipulation dark patterns. Marked † in docs;
22
+ higher false-positive risk — advisory `REVIEW-FINDING: WARN` only.
23
+ - Expanded `covered_by_pierre_deep_review` in `guidelines-baseline.json` with 2.2, 2.3.4, 2.3.9,
24
+ 4.5.1–4.5.3, 5.6.4–5.6.7.
25
+
26
+ ### Changed
27
+ - Phase 4 checklist 22 → **28** across `pierre-deep-review.md`, `SKILL.md`, `methodology.md`, README
28
+ (full guideline-ordered table with † Tier B labels), plugin manifest, and social preview
29
+ (`41 static + 28 Pierre deep checks`).
30
+
31
+ ## [1.4.0] - 2026-06-30
32
+
33
+ ### Added
34
+ - **Phase 4: Pierre deep review — 22 semantic checks.** After Phase 3 (explaining every scan
35
+ FAIL/WARN), Pierre runs a read-only Review Simulator: fetches privacy/support URLs, reads
36
+ screenshots, compares metadata claims to Swift code, validates paywall disclosure quality, and
37
+ cross-checks permissions vs policy. Each check emits `REVIEW-PASS:` or advisory
38
+ `REVIEW-FINDING: … WARN` (does not change GREEN/YELLOW/RED counts). Full checklist in
39
+ [`references/pierre-deep-review.md`](skills/appstore-precheck/references/pierre-deep-review.md).
40
+ - **`covered_by_pierre_deep_review`** in `guidelines-baseline.json` (26 guideline numbers across
41
+ the 22 checks). Consolidation moves to **Phase 5** (6 phases total: 0–5).
42
+ - [`examples/pierre-deep-review.md`](examples/pierre-deep-review.md) showing `REVIEW-FINDING` output.
43
+
44
+ ### Changed
45
+ - Flow is now **6 phases (0–5)**: Phase 3 = scan commentary, Phase 4 = deep review, Phase 5 =
46
+ verdict + token. Updated `SKILL.md`, `methodology.md`, README (static table + deep-review table
47
+ in guideline order), examples, plugin manifest, and social preview copy (`41 static + 22 Pierre
48
+ deep checks`).
49
+
50
+ ## [1.3.1] - 2026-06-30
51
+
52
+ ### Changed
53
+ - **Phase 3 (Pierre) now explains every FAIL and WARN** from Phases 0–2 in **2–3 sentences
54
+ each** — no more random 5-guideline sampling. Pierre repeats each machine line verbatim,
55
+ then explains why Apple cares, what the scan found, and what to fix. Updated `SKILL.md`,
56
+ `methodology.md`, the README example, `examples/red-reject.md`, and behavioral eval
57
+ assertions in lockstep.
58
+ - Phase 4 presentation order clarified: trilingual verdict block → Pierre commentary → verbatim
59
+ scan lines + `file:line` fixes → verdict/token.
60
+ - **Trilingual verdict block format:** each language in its own **bold label + blockquote**, separated
61
+ by horizontal rules (`---`) under a `### Pierre` heading — never FR/EN/user-lang compressed on one line.
62
+
63
+ ## [1.3.0] - 2026-06-30
64
+
65
+ ### Added
66
+ - **Eleven new signal-gated advisory checks (30 → 41 rejection vectors), all WARN-only:**
67
+ - **2.1** a login-gated app with no demo account / credentials for App Review (fastlane
68
+ `review_information` or `.reviewPrepNotes`).
69
+ - **2.5.2** executable-code download / native hot-patching (JSPatch, Rollout, DynamicCocoa).
70
+ Allowed JS-bundle OTA (React Native CodePush) is deliberately **not** flagged.
71
+ - **2.5.4** a background mode declared in `UIBackgroundModes` with no matching API used in Swift.
72
+ - **3.1.5(a)** a cryptocurrency wallet / exchange / mining signal.
73
+ - **4.2.3** a thin WKWebView wrapper around a website (heuristic: WKWebView + very few Swift files).
74
+ - **4.2.7** a remote-desktop / host-mirroring signal.
75
+ - **4.4.2** a Safari content-blocker / web extension.
76
+ - **5.1.1(v)** account creation offered without an in-app account-deletion path (the real
77
+ 5.1.1(v) Account Sign-In rule).
78
+ - **5.1.4** metadata targeting a child audience while a third-party ads/analytics SDK is linked.
79
+ - **5.3.4** real-money gambling language in metadata.
80
+ - **5.5** a Mobile Device Management (MDM) signal.
81
+ - `tests/fixtures/risky-app-2` (advisory §31–§41 except web-wrapper) and `tests/fixtures/webview-app`
82
+ (the 4.2.3 heuristic), with assertions in `tests/run.sh`. Both are advisory-only (no FAIL).
83
+
84
+ ### Changed
85
+ - **Corrected the Required Reason API label from `5.1.1(v)` to `5.1.1`.** Apple documents the
86
+ Required Reason API rules under 5.1.1 + the privacy-manifest developer docs; sub-item **(v)** is
87
+ "Account Sign-In", a different rule. The `(v)` label now belongs to the new account-deletion
88
+ check (vector 38). Updated `scan.sh` output, the methodology table, the README table, the
89
+ examples, and the field-test notes in lockstep.
90
+ - §18 (support / privacy URL) now also cites the guidelines it satisfies: **1.5** (developer
91
+ contact via the support URL) and **5.1.1(i)** (privacy policy link).
92
+ - Expanded `guidelines-baseline.json` `covered_by_scan` with 1.5, 2.5.2, 2.5.4, 3.1.5, 4.2.3,
93
+ 4.2.7, 4.4.2, 5.1.4, 5.3.4, and 5.5.
94
+
95
+ ## [1.2.0] - 2026-06-30
96
+
97
+ ### Added
98
+ - **Ten new signal-gated advisory checks (20 → 30 rejection vectors), all WARN-only:**
99
+ - **3.1.1** third-party payment SDK (Stripe, Braintree, PayPal, Square, Adyen, …) linked for
100
+ digital goods instead of in-app purchase.
101
+ - **1.2** user-generated content detected without a report / block / moderation affordance.
102
+ - **1.6** App Transport Security disabled app-wide (`NSAllowsArbitraryLoads=true`).
103
+ - **4.9** recurring Apple Pay without the renewal / cancel disclosure.
104
+ - **5.6.1** a direct App Store write-review link/prompt without the system `requestReview` API.
105
+ - **2.3.1** misleading marketing claims (iOS virus / malware scanners, fake speed boosters) in metadata.
106
+ - **2.3.8** "For Kids" / "For Children" wording outside the Kids Category.
107
+ - **4.4.1** keyboard extension requiring full access (`RequestsOpenAccess=true`).
108
+ - **5.1.3** HealthKit used together with an iCloud / CloudKit sync path.
109
+ - **5.4** VPN / NetworkExtension (`NEVPNManager`) usage.
110
+ - `tests/fixtures/risky-app` plus assertions in `tests/run.sh` exercising all ten new vectors
111
+ (advisory only — the fixture is YELLOW, never RED).
112
+
113
+ ### Changed
114
+ - **YELLOW threshold raised from 3+ to 5+ WARN.** The ten new advisory checks are signal-gated
115
+ (most apps trip only one or two), but the bump keeps a normal submission from sliding into
116
+ YELLOW on advisory noise alone. GREEN is now 0 FAIL and ≤4 WARN; YELLOW is 0 FAIL and ≥5 WARN.
117
+ Updated `verdict.sh`, the verdict tests, the output-contract tables, and the docs in lockstep.
118
+ - Corrected the minimum-functionality check's label from `4.0` to `4.2` (its real guideline
119
+ number) in the scanner output, the methodology table, and the README.
120
+ - Reconciled `guidelines-baseline.json` against the live guidelines (Last Updated June 8, 2026):
121
+ no structural section drift; expanded `covered_by_scan` to reflect every guideline the scan now
122
+ touches (adds 1.2, 1.6, 2.1, 2.3, 2.3.8, 3.1.1, 4.4.1, 4.8, 4.9, 5.1.3, 5.4, 5.6.1; 4.0 → 4.2).
123
+
6
124
  ## [1.1.1] - 2026-06-30
7
125
 
8
126
  ### Changed
package/README.md CHANGED
@@ -16,8 +16,10 @@
16
16
 
17
17
  `appstore-precheck` is a read-only, pre-submission gate for iOS apps. It statically scans the most
18
18
  common rejection vectors, runs Apple's own metadata linter, watches the App Store Review Guidelines
19
- for drift, and finishes with an adversarial review pass, then hands you a single **GREEN / YELLOW /
20
- RED** verdict. It never edits your code.
19
+ for drift, has Pierre explain every FAIL and WARN, then runs **28 semantic deep-review checks**
20
+ (22 high-confidence Tier A + 6 heuristic Tier B v1 — beta language, review notes quality, app preview,
21
+ incentivized review, push/HomeKit abuse, rating manipulation).
22
+ It hands you a single **GREEN / YELLOW / RED** verdict. It never edits your code.
21
23
 
22
24
  It ships as a portable [Agent Skill](https://agentskills.io): the same `SKILL.md` runs natively in
23
25
  Claude Code, OpenAI Codex, Cursor, and Gemini CLI. The scanner is plain Bash, so you can also run it
@@ -28,43 +30,113 @@ by hand or wire it into CI.
28
30
  <img src="assets/mascot.png" align="right" width="124" alt="Pierre, the French app reviewer">
29
31
 
30
32
  Your verdict is delivered by **Pierre**, a French critic who has seen ten thousand rejections and is
31
- impressed by none of them. He reviews your build harder than Apple would, in private. A GREEN from
33
+ impressed by none of them. He reviews your build harder than Apple would, in private first with a
34
+ fast static scan, then with **28 deep semantic checks** (22 confident + 6 heuristic). A GREEN from
32
35
  Pierre means Apple will wave you through.
33
36
 
34
37
  - 🔴 **RED**: *"Non. Restore Purchases, absent. Guideline 3.1.2. Suivant."*
35
38
  - 🟡 **YELLOW**: *"A few small uglinesses. I would not reject. But I noticed."*
36
39
  - 🟢 **GREEN**: *"Hmf. I find nothing. Acceptable. Do not make me regret this."*
37
40
 
38
- The verdict line is in Pierre's voice. The breakdown beneath it, every `file:line` and fix, stays
39
- plain and surgical.
41
+ The verdict line is in Pierre's voice **three separate language blocks** (bold label + blockquote
42
+ each, divided by horizontal rules), not one compressed sentence. The breakdown beneath it, every
43
+ `file:line` and fix, stays plain and surgical.
40
44
 
41
45
  ## What it checks
42
46
 
43
- 20 rejection vectors across code, fastlane metadata, screenshots, `PrivacyInfo.xcprivacy`, and the paywall:
47
+ 41 rejection vectors across code, fastlane metadata, screenshots, `PrivacyInfo.xcprivacy`, and the paywall:
44
48
 
45
49
  | Guideline | Check |
46
50
  |-----------|-------|
47
- | **5.1.1(v)** | Privacy Manifest Required Reason API parity |
48
- | **5.1.1** | A non-empty purpose string for every sensitive framework |
49
- | **5.1.2** | ATT usage `NSUserTrackingUsageDescription` |
50
- | **2.3.10** | No other-platform / competitor names in metadata |
51
+ | **1.2** | User-generated content without a report / block / moderation mechanism |
52
+ | **1.6** | App Transport Security disabled app-wide (`NSAllowsArbitraryLoads`) |
53
+ | **2.1** | No placeholder / dummy copy (lorem ipsum, TODO, `example.com`) in store metadata |
54
+ | **2.1** | A login-gated app ships demo credentials / review notes for App Review |
55
+ | **2.3** | A working support URL and a privacy URL in fastlane metadata (no placeholders) — also satisfies 1.5 and 5.1.1(i) |
51
56
  | **2.3.1** | Metadata length limits (name, subtitle, keywords, promo, description) |
52
- | **2.3.7** | Localized metadata parity across every locale |
57
+ | **2.3.1** | Misleading marketing claims (iOS virus / malware scanners, fake speed boosters) in metadata |
53
58
  | **2.3.3** | At least one screenshot per locale |
59
+ | **2.3.7** | Localized metadata parity across every locale |
60
+ | **2.3.8** | "For Kids" / "For Children" wording outside the Kids Category |
61
+ | **2.3.10** | No other-platform / competitor names in metadata |
62
+ | **2.5.1** | No private / banned APIs |
63
+ | **2.5.2** | No executable-code download / native hot-patching (JSPatch, Rollout, …) |
64
+ | **2.5.4** | Background modes declared in `UIBackgroundModes` but never used |
65
+ | **3.1.1** | Third-party payment SDK (Stripe, Braintree, PayPal, …) linked for digital goods instead of in-app purchase |
66
+ | **3.1.1(a)** | External purchase link entitlement + disclosure, when external purchase APIs are used |
54
67
  | **3.1.2** | Trial & auto-renew subscription disclosures |
55
68
  | **3.1.2** | Restore Purchases + Terms (EULA) + Privacy Policy on the paywall |
56
- | **2.5.1** | No private / banned APIs |
57
- | **4.0** | Minimum functionality (real navigation) |
69
+ | **3.1.5(a)** | Cryptocurrency wallet / exchange / mining signal |
70
+ | **4.2** | Minimum functionality (real navigation) |
71
+ | **4.2.3** | Thin WKWebView wrapper around a website |
72
+ | **4.2.7** | Remote-desktop / host-mirroring app |
73
+ | **4.4.1** | Keyboard extension that requires full access (`RequestsOpenAccess`) |
74
+ | **4.4.2** | Safari content-blocker / web extension |
58
75
  | **4.8** | Sign in with Apple offered when a third-party social login is used |
59
- | **3.1.1(a)** | External purchase link entitlement + disclosure, when external purchase APIs are used |
60
- | **5.1.5** | Sensitive-API justification *(opt-in)* |
76
+ | **4.9** | Recurring Apple Pay (`PKRecurringPaymentRequest`) verify the renewal / cancel disclosure |
77
+ | **5.1.1** | A non-empty purpose string for every sensitive framework |
78
+ | **5.1.1** | Analytics SDK present ↔ `PrivacyInfo.xcprivacy` declares collected data / tracking domains |
79
+ | **5.1.1** | Privacy Manifest ↔ Required Reason API parity |
80
+ | **5.1.1(v)** | Account creation offered without an in-app account-deletion path |
81
+ | **5.1.2** | ATT usage ↔ `NSUserTrackingUsageDescription` |
61
82
  | **5.1.2** | Tracking / IDFA SDK (AdMob, AppLovin, AppsFlyer, Adjust, …) shipped without an ATT prompt |
83
+ | **5.1.3** | HealthKit data with an iCloud / CloudKit sync path |
84
+ | **5.1.4** | Kids-audience metadata shipping a third-party ads / analytics SDK |
85
+ | **5.1.5** | Sensitive-API justification *(opt-in)* |
86
+ | **5.3.4** | Real-money gambling language in metadata |
87
+ | **5.4** | VPN / NetworkExtension usage (org account + on-screen data disclosure) |
88
+ | **5.5** | Mobile Device Management (MDM) signal |
89
+ | **5.6.1** | A custom App Store review prompt instead of the system `requestReview` API |
62
90
  | **encryption** | `ITSAppUsesNonExemptEncryption` set, so App Store Connect skips the export-compliance question |
63
- | **2.3** | A working support URL and a privacy URL in fastlane metadata (no placeholders) |
64
- | **5.1.1** | Analytics SDK present ↔ `PrivacyInfo.xcprivacy` declares collected data / tracking domains |
65
- | **2.1** | No placeholder / dummy copy (lorem ipsum, TODO, `example.com`) in store metadata |
66
91
 
67
- Paywall checks are skipped automatically when no in-app-purchase signals are present.
92
+ Paywall checks are skipped automatically when no in-app-purchase signals are present, and the
93
+ signal-gated advisory checks stay silent unless their triggering signal is found.
94
+
95
+ ### Pierre deep review (28 semantic checks)
96
+
97
+ After the static scan, Pierre reads your project end-to-end and runs **28 evidence-based checks**
98
+ the grep layer cannot fully judge. These emit advisory `REVIEW-FINDING:` lines (they do **not**
99
+ change the GREEN/YELLOW/RED verdict). Full procedure:
100
+ [`references/pierre-deep-review.md`](skills/appstore-precheck/references/pierre-deep-review.md).
101
+
102
+ **22 checks (Tier A)** are high-confidence cross-reads (privacy policy fetch, claims vs code,
103
+ screenshots, paywall copy). **6 checks (Tier B v1, marked †)** are heuristic — useful pre-submit
104
+ signals with a higher false-positive rate; Pierre prefers `not applicable` when no signal is present.
105
+
106
+ | Guideline | Deep check |
107
+ |-----------|------------|
108
+ | **1.2.1** | User-generated content → is there a real report / block / moderation UI flow? |
109
+ | **1.4.1** | Health or medical claims in metadata/UI without appropriate disclaimers? |
110
+ | **2.1** | Store metadata claims match features actually implemented in code |
111
+ | **2.1** † | App Review demo account / review notes actionable (credentials, steps — not placeholder) |
112
+ | **2.2** † | Beta, test, preview, or work-in-progress language in store-facing copy or UI |
113
+ | **2.3.2** | Primary App Store category fits the app type |
114
+ | **2.3.4** † | App preview video/assets (if in-repo) match shipped features and metadata |
115
+ | **2.3.5** | Screenshot images match shipped features (no misleading frames or missing UI) |
116
+ | **2.3.6** | Metadata pricing / subscription language matches the paywall |
117
+ | **2.3.9** † | Incentivized review copy ("rate 5 stars", "review for reward") in metadata or UI |
118
+ | **2.3.11–2.3.13** | Cross-locale metadata materially consistent (trial terms, features, URLs) |
119
+ | **3.1.1** | Digital goods unlocked via external purchase links (web checkout in WebView, etc.) |
120
+ | **3.1.2** | Trial, auto-renew, and cancel disclosures are legible sentences — not keyword stubs |
121
+ | **4.2.1–4.2.2** | Minimum functionality beyond a thin WebView shell or template app |
122
+ | **4.5.1–4.5.3** † | Push notification or HomeKit entitlement used as intended (no spam-push / HomeKit without home UI) |
123
+ | **4.8** | Third-party login → Sign in with Apple offered, or a valid exempt case |
124
+ | **5.1.1(i)** | Privacy policy text (fetched live) matches code, PrivacyInfo, and SDK usage |
125
+ | **5.1.1(ii)** | Purpose strings are specific and tied to a visible feature |
126
+ | **5.1.1(iii)** | Permissions and SDKs proportionate to the app's stated purpose |
127
+ | **5.1.1(iv)** | Permission denial handled without forced re-prompt loops |
128
+ | **5.1.2** | ATT prompt, tracking description, privacy policy, and ad SDK usage align |
129
+ | **5.1.3** | HealthKit data not used for advertising or marketing |
130
+ | **5.1.4** | Kids-audience signals → parental gate before external links / IAP / account areas |
131
+ | **5.4** | VPN / NetworkExtension → on-screen disclosure copy visible in UI strings |
132
+ | **5.2.1–5.2.3** | Obvious third-party trademark or brand misuse in metadata or UI copy |
133
+ | **5.3.1–5.3.3** | Contest / sweepstakes copy includes official rules and eligibility |
134
+ | **5.6.2–5.6.3** | Developer identity consistent (app name, support URL content, domains) |
135
+ | **5.6.4–5.6.7** † | Rating / review manipulation dark patterns (withhold features until 5 stars, write-review links without `requestReview`) |
136
+
137
+ Pierre runs **all 28 every time** and reports each as `REVIEW-PASS:` or `REVIEW-FINDING:`. When the
138
+ static scan already flagged a guideline, the deep check adds semantic context the scanner could not see.
139
+ † Tier B v1 items are heuristic — treat findings as "verify before submit", not automatic blockers.
68
140
 
69
141
  ### Supported app types
70
142
 
@@ -74,46 +146,109 @@ how the app is built:
74
146
 
75
147
  | App type | Coverage |
76
148
  |----------|----------|
77
- | 🟢 **Native Swift / SwiftUI** | **Full.** All 20 vectors apply. |
149
+ | 🟢 **Native Swift / SwiftUI** | **Full.** All 41 vectors apply. |
78
150
  | 🟡 **React Native / Flutter** | Metadata, privacy manifest, screenshots, and export compliance apply in full. The Swift-source checks (ATT, paywall links, private API, SDK detection, navigation) **under-detect rather than misfire**: that logic lives in JS/Dart, so they stay quiet instead of blocking. |
79
151
 
80
152
  ## Quick start
81
153
 
82
- **Claude Code**: install as a plugin:
154
+ One `SKILL.md`, every host. **Claude Code, Cursor, and Codex** install as native **plugins** from
155
+ this GitHub repo. **Gemini CLI** installs the same skill with `gemini skills install` (no plugin
156
+ marketplace yet). [`install.sh`](install.sh) remains the fallback for vendoring into a project.
157
+
158
+ ### Install the full skill (Pierre + all phases)
159
+
160
+ | Host | Install method |
161
+ |------|----------------|
162
+ | **Claude Code** | Plugin (recommended) |
163
+ | **Cursor** | Plugin (recommended) |
164
+ | **OpenAI Codex** | Plugin (recommended) |
165
+ | **Gemini CLI** | `gemini skills install` one-liner |
166
+
167
+ **Claude Code:**
83
168
 
84
169
  ```
85
170
  /plugin marketplace add berkayturk/appstore-precheck
86
171
  /plugin install appstore-precheck@appstore-precheck
87
172
  ```
88
173
 
89
- **Run instantly with npx** (no clone, no install):
174
+ **Cursor** import this repo as a marketplace, then install the plugin:
175
+
176
+ 1. **Customize → Plugins → Import marketplace**
177
+ 2. Repo URL: `https://github.com/berkayturk/appstore-precheck`
178
+ 3. Install **appstore-precheck**
179
+
180
+ After the plugin is listed on the [Cursor Marketplace](https://cursor.com/marketplace), you can
181
+ install from **Customize → Plugins** without importing the repo.
182
+
183
+ **OpenAI Codex:**
90
184
 
91
185
  ```bash
92
- npx appstore-precheck # scans the current directory, prints the verdict
93
- npx appstore-precheck --fail-on YELLOW
186
+ codex plugin marketplace add berkayturk/appstore-precheck
187
+ ```
188
+
189
+ Then run `codex`, open `/plugins`, select the **appstore-precheck** marketplace tab, and install
190
+ **appstore-precheck**. Start a new thread after install.
191
+
192
+ On newer Codex builds you may also be able to run:
193
+
194
+ ```bash
195
+ codex plugin add appstore-precheck@appstore-precheck
94
196
  ```
95
197
 
96
- It runs the static scan over the current directory and exits non-zero on RED (or on YELLOW with
97
- `--fail-on YELLOW`). Read-only, like everything else here.
198
+ Refresh after repo updates:
199
+
200
+ ```bash
201
+ codex plugin marketplace upgrade appstore-precheck
202
+ ```
98
203
 
99
- **Codex, Cursor, Gemini, Claude**: clone, then run the installer from inside your iOS project:
204
+ **Gemini CLI** (native skill install no plugin marketplace):
205
+
206
+ ```bash
207
+ gemini skills install https://github.com/berkayturk/appstore-precheck.git \
208
+ --path skills/appstore-precheck --scope workspace
209
+ ```
210
+
211
+ Use `--scope user` for a global install. Verify with `gemini skills list`.
212
+
213
+ **Fallback — `install.sh`** (vendors the skill into `.claude/skills/` and/or `.agents/skills/`):
100
214
 
101
215
  ```bash
102
216
  git clone https://github.com/berkayturk/appstore-precheck.git
103
- /path/to/appstore-precheck/install.sh # → ./.claude/skills and ./.agents/skills
217
+ cd your-ios-app
218
+ /path/to/appstore-precheck/install.sh # all hosts → .claude/skills + .agents/skills
219
+ /path/to/appstore-precheck/install.sh cursor # Cursor only
220
+ /path/to/appstore-precheck/install.sh codex # Codex only
221
+ /path/to/appstore-precheck/install.sh gemini # Gemini only
222
+ /path/to/appstore-precheck/install.sh claude user # Claude Code user-wide → ~/.claude/skills
223
+ ```
224
+
225
+ Then ask your agent to run the precheck before you submit. See [Cross-tool support](#cross-tool-support)
226
+ for which directory each host reads. Maintainer notes for marketplace submission:
227
+ [`docs/publishing-plugins.md`](docs/publishing-plugins.md).
228
+
229
+ ### Scan only (no agent skill install)
230
+
231
+ **npx** — static scan + verdict in the terminal; no clone, no skill vendoring (Phases 3–4 Pierre
232
+ commentary require an agent with the skill installed):
233
+
234
+ ```bash
235
+ npx appstore-precheck # scans the current directory, prints the verdict
236
+ npx appstore-precheck --fail-on YELLOW
104
237
  ```
105
238
 
106
- **Standalone**: the scanner is just Bash:
239
+ **Standalone Bash** same static scan, run by hand or in CI:
107
240
 
108
241
  ```bash
109
- bash skills/appstore-precheck/scripts/scan.sh
242
+ bash skills/appstore-precheck/scripts/scan.sh # from a clone of this repo
110
243
  ```
111
244
 
112
- **CI**: drop the static scan into a workflow with the bundled composite action. It fails the
245
+ ### CI
246
+
247
+ Drop the static scan into a workflow with the bundled composite action. It fails the
113
248
  job on a RED verdict; set `fail-on: YELLOW` to be stricter:
114
249
 
115
250
  ```yaml
116
- - uses: berkayturk/appstore-precheck@v1.1.0
251
+ - uses: berkayturk/appstore-precheck@v1.5.0
117
252
  with:
118
253
  working-directory: . # optional, default: . (repo root)
119
254
  fail-on: RED # optional, default: RED (RED | YELLOW)
@@ -127,10 +262,11 @@ a RED verdict. No App Store Connect credentials are needed; the action runs the
127
262
  | Phase | Step |
128
263
  |-------|------|
129
264
  | **0** | **Guideline drift**: diff the live App Store Review Guidelines against a tracked baseline. Never blocks. |
130
- | **1** | **Static scan**: `scan.sh` over the 20 vectors above. |
265
+ | **1** | **Static scan**: `scan.sh` over the 41 vectors above. |
131
266
  | **2** | **`fastlane precheck`**: Apple's own metadata rule engine. |
132
- | **3** | **Adversarial review**: Pierre role-plays a skeptical reviewer and drafts realistic rejection notices. |
133
- | **4** | **Verdict**: GREEN / YELLOW / RED, and a `.precheck-pass` token the upload guard gates on. |
267
+ | **3** | **Pierre commentary**: explains **every** FAIL and WARN from Phases 0–2 in 2–3 sentences each. |
268
+ | **4** | **Pierre deep review**: 28 semantic checks (22 Tier A + 6 Tier B v1 heuristic). Advisory only. |
269
+ | **5** | **Verdict**: GREEN / YELLOW / RED from Phases 0–2 counts, plus `.precheck-pass` token the upload guard gates on. |
134
270
 
135
271
  ## Demo
136
272
 
@@ -143,25 +279,45 @@ counts are deterministic ([`verdict.sh`](skills/appstore-precheck/scripts/verdic
143
279
 
144
280
  ## Example
145
281
 
282
+ ### Pierre
283
+
284
+ **Français**
285
+ > *Non. Trois fautes. Apple en aurait trouvé moins. Suivant.*
286
+
287
+ ---
288
+
289
+ **English**
290
+ > *No. Three faults. Apple would have found fewer. Next.*
291
+
292
+ ---
293
+
294
+ **Türkçe**
295
+ > *Hayır. Üç hata. Apple daha azını bulurdu. Sıradaki.*
296
+
297
+ **RED — 3 FAIL** · submission blocked
298
+
146
299
  ```
147
- 🔴 Pierre: "Non. Three faults. Apple would have found one. Suivant."
300
+ FAIL: 3.1.2 Restore Purchases not found in SubscriptionView.swift
301
+ Pierre: Apple requires a Restore Purchases control on every subscription paywall …
302
+ ```
303
+
304
+ **Phase 4 (deep review, excerpt):**
148
305
 
149
- RED: 3 FAIL
150
- 3.1.2 Restore Purchases missing SubscriptionView.swift:14 add restorePurchases()
151
- 2.3.10 "Android" in metadata en-US/description.txt:1 remove the reference
152
- • 5.1.1(v) FileTimestamp undeclared PrivacyInfo.xcprivacy → declare the reason
153
- Submission blocked.
306
+ ```
307
+ REVIEW-FINDING: 5.1.1(i) WARN privacy policy says "no location data" but ContentView.swift uses CLLocationManager
308
+ Pierre: Apple compares your privacy policy to actual SDK and permission usage under 5.1.1(i) …
154
309
  ```
155
310
 
156
- See [`examples/`](examples/) for full [GREEN](examples/green-pass.md) and [RED](examples/red-reject.md) runs,
157
- plus real [Phase 0 drift-check](examples/drift-check.md) and [Phase 2 `fastlane precheck`](examples/fastlane-precheck.md) results.
311
+ See [`examples/`](examples/) for full [GREEN](examples/green-pass.md), [RED](examples/red-reject.md), and
312
+ [deep-review](examples/pierre-deep-review.md) runs, plus real [Phase 0 drift-check](examples/drift-check.md)
313
+ and [Phase 2 `fastlane precheck`](examples/fastlane-precheck.md) results.
158
314
 
159
315
  ## Output
160
316
 
161
317
  | State | Meaning | Token | Upload guard |
162
318
  |-------|---------|-------|--------------|
163
- | 🟢 **GREEN** | 0 FAIL, ≤2 WARN | written (60 min) | allowed |
164
- | 🟡 **YELLOW** | 0 FAIL, 3+ WARN | not written | blocked; needs confirmation |
319
+ | 🟢 **GREEN** | 0 FAIL, ≤4 WARN | written (60 min) | allowed |
320
+ | 🟡 **YELLOW** | 0 FAIL, 5+ WARN | not written | blocked; needs confirmation |
165
321
  | 🔴 **RED** | ≥1 FAIL | removed | blocked; shows the FAIL list |
166
322
 
167
323
  ## Configuration
@@ -205,16 +361,22 @@ Everything else works without one.
205
361
  ## Uninstall
206
362
 
207
363
  ```bash
208
- /plugin uninstall appstore-precheck@appstore-precheck # Claude Code plugin
209
- rm -rf .claude/skills/appstore-precheck .agents/skills/appstore-precheck # manual install
210
- rm -f .precheck-pass # runtime token
364
+ /plugin uninstall appstore-precheck@appstore-precheck # Claude Code plugin
365
+ # Codex: run `codex`, open `/plugins`, uninstall appstore-precheck (CLI 0.125.x has no `plugin remove`)
366
+ # Cursor: Customize → Plugins → appstore-precheck Uninstall
367
+ gemini skills uninstall appstore-precheck # Gemini (if installed via gemini skills)
368
+ rm -rf .claude/skills/appstore-precheck # install.sh (Claude Code / Cursor)
369
+ rm -rf .agents/skills/appstore-precheck # install.sh (Codex / Cursor / Gemini)
370
+ rm -rf .cursor/skills/appstore-precheck # if you mirrored there manually
371
+ rm -rf .gemini/skills/appstore-precheck # if installed to workspace scope manually
372
+ rm -f .precheck-pass # runtime token
211
373
  ```
212
374
 
213
375
  ## Development
214
376
 
215
377
  ```bash
216
378
  npm run lint # bash -n on every script
217
- npm run check-versions # plugin.json / package.json / SKILL.md in lockstep
379
+ npm run check-versions # plugin manifests / package.json / SKILL.md in lockstep
218
380
  npm test # run scan.sh against fixture projects and assert
219
381
  claude plugin validate .
220
382
  ```
@@ -223,9 +385,11 @@ CI runs ShellCheck, JSON validation, the version-consistency guard, and the fixt
223
385
 
224
386
  ## Disclaimer
225
387
 
226
- This is a static heuristic tool. A GREEN result **lowers but does not eliminate** rejection risk;
227
- Apple's guidelines change frequently and reviewer decisions are judgment calls. It performs no runtime
228
- crash testing; always do a final manual review before you submit. Not affiliated with Apple.
388
+ This is a static heuristic tool plus Pierre's semantic deep review. A GREEN result **lowers but does
389
+ not eliminate** rejection risk; Apple's guidelines change frequently and reviewer decisions are
390
+ judgment calls. `REVIEW-FINDING` lines are advisory and do not block the token by themselves. It
391
+ performs no runtime crash testing; always do a final manual review before you submit. Not affiliated
392
+ with Apple.
229
393
 
230
394
  ## Star History
231
395
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "appstore-precheck",
3
- "version": "1.1.1",
4
- "description": "Read-only iOS App Store pre-submission check, packaged as a portable Agent Skill / Claude Code plugin and an npx CLI.",
3
+ "version": "1.5.1",
4
+ "description": "Read-only iOS App Store pre-submission check, packaged as a portable Agent Skill with native Claude Code, Cursor, and Codex plugins, plus an npx CLI.",
5
5
  "license": "MIT",
6
6
  "author": "Berkay Turk (https://github.com/berkayturk)",
7
7
  "homepage": "https://github.com/berkayturk/appstore-precheck",