@mmerterden/multi-agent-pipeline 20.35.0 → 20.37.0

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.
Files changed (207) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +6 -5
  3. package/README.tr.md +6 -5
  4. package/docs/architecture.md +3 -3
  5. package/docs/ecosystem.md +5 -5
  6. package/docs/facts.json +4 -4
  7. package/install/catalog-history.json +1 -1
  8. package/manifest.json +210 -136
  9. package/package.json +5 -1
  10. package/pipeline/commands/multi-agent/SKILL.md +33 -154
  11. package/pipeline/commands/multi-agent/analysis/SKILL.md +14 -68
  12. package/pipeline/commands/multi-agent/analysis-jira/SKILL.md +5 -8
  13. package/pipeline/commands/multi-agent/autopilot-on/SKILL.md +38 -109
  14. package/pipeline/commands/multi-agent/channels/SKILL.md +38 -167
  15. package/pipeline/commands/multi-agent/complaint-analysis/SKILL.md +37 -144
  16. package/pipeline/commands/multi-agent/design-check/SKILL.md +27 -131
  17. package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +22 -48
  18. package/pipeline/commands/multi-agent/ios-coding-standard/SKILL.md +37 -180
  19. package/pipeline/commands/multi-agent/jira/SKILL.md +16 -46
  20. package/pipeline/commands/multi-agent/office-pair/SKILL.md +66 -0
  21. package/pipeline/commands/multi-agent/office-status/SKILL.md +1 -1
  22. package/pipeline/commands/multi-agent/refactor/SKILL.md +23 -184
  23. package/pipeline/commands/multi-agent/resume/SKILL.md +30 -136
  24. package/pipeline/commands/multi-agent/review/SKILL.md +24 -199
  25. package/pipeline/commands/multi-agent/setup/SKILL.md +25 -181
  26. package/pipeline/commands/multi-agent/stack/SKILL.md +9 -53
  27. package/pipeline/commands/multi-agent/status/SKILL.md +13 -2
  28. package/pipeline/commands/multi-agent/store-ready/SKILL.md +27 -226
  29. package/pipeline/commands/multi-agent/sync/SKILL.md +38 -167
  30. package/pipeline/commands/multi-agent/test-gen/SKILL.md +2 -4
  31. package/pipeline/commands/multi-agent/update/SKILL.md +18 -60
  32. package/pipeline/contract/CHANGELOG.md +9 -0
  33. package/pipeline/contract/fixtures/error-invalid-request.json +1 -1
  34. package/pipeline/contract/fixtures/error-unauthorized.json +1 -1
  35. package/pipeline/contract/fixtures/error-unsigned.json +1 -1
  36. package/pipeline/contract/fixtures/runs-awaiting-question.json +1 -1
  37. package/pipeline/contract/fixtures/runs-empty.json +1 -1
  38. package/pipeline/contract/fixtures/runs-failed.json +1 -1
  39. package/pipeline/contract/fixtures/runs-pr-opened-redacted.json +1 -1
  40. package/pipeline/contract/fixtures/runs-pr-opened.json +1 -1
  41. package/pipeline/contract/fixtures/runs-running.json +1 -1
  42. package/pipeline/contract/manifest.json +5 -5
  43. package/pipeline/contract/types/index.d.ts +3 -2
  44. package/pipeline/lib/qr-code.mjs +26 -0
  45. package/pipeline/multi-agent-refs/autopilot-on/details.md +148 -0
  46. package/pipeline/multi-agent-refs/channels/generator.md +14 -0
  47. package/pipeline/multi-agent-refs/channels/preview.md +13 -0
  48. package/pipeline/multi-agent-refs/channels/reference.md +46 -0
  49. package/pipeline/multi-agent-refs/complaint-analysis/phases.md +159 -0
  50. package/pipeline/multi-agent-refs/cross-cli-contract.md +4 -4
  51. package/pipeline/multi-agent-refs/design-check/export.md +1 -0
  52. package/pipeline/multi-agent-refs/design-check/init-inventory.md +1 -1
  53. package/pipeline/multi-agent-refs/design-check/scope-and-ledger.md +64 -0
  54. package/pipeline/multi-agent-refs/features/analysis-command-notes.md +53 -0
  55. package/pipeline/multi-agent-refs/garbage-collect/phases.md +60 -0
  56. package/pipeline/multi-agent-refs/help/en.md +1 -0
  57. package/pipeline/multi-agent-refs/help/tr.md +1 -0
  58. package/pipeline/multi-agent-refs/ios-coding-standard/plan.md +71 -0
  59. package/pipeline/multi-agent-refs/ios-coding-standard/resolve-and-scan.md +135 -0
  60. package/pipeline/multi-agent-refs/jira/picker-detail.md +71 -0
  61. package/pipeline/multi-agent-refs/orchestrator/copilot-pipeline.md +88 -0
  62. package/pipeline/multi-agent-refs/orchestrator/dispatcher.md +96 -1
  63. package/pipeline/multi-agent-refs/refactor/sweep.md +190 -0
  64. package/pipeline/multi-agent-refs/resume/details.md +115 -2
  65. package/pipeline/multi-agent-refs/review/inputs.md +33 -1
  66. package/pipeline/multi-agent-refs/review/module-guides.md +9 -1
  67. package/pipeline/multi-agent-refs/review/panel.md +75 -0
  68. package/pipeline/multi-agent-refs/review/valven.md +5 -1
  69. package/pipeline/multi-agent-refs/setup/hooks-and-plugins.md +4 -0
  70. package/pipeline/multi-agent-refs/setup/token-save-flow.md +13 -0
  71. package/pipeline/multi-agent-refs/stack/background.md +72 -0
  72. package/pipeline/multi-agent-refs/store-ready/gates.md +139 -0
  73. package/pipeline/multi-agent-refs/store-ready/report.md +40 -2
  74. package/pipeline/multi-agent-refs/sync/office.md +10 -0
  75. package/pipeline/multi-agent-refs/sync/overview.md +61 -0
  76. package/pipeline/multi-agent-refs/sync/repo.md +91 -0
  77. package/pipeline/multi-agent-refs/update/details.md +83 -0
  78. package/pipeline/schemas/runs-index.schema.json +2 -1
  79. package/pipeline/scripts/contract-server.mjs +1 -1
  80. package/pipeline/scripts/office-pair.mjs +40 -9
  81. package/pipeline/scripts/runs-index.mjs +34 -7
  82. package/pipeline/scripts/status-overview.mjs +401 -0
  83. package/pipeline/skills/.skill-manifest.json +69 -65
  84. package/pipeline/skills/.skills-index.json +15 -4
  85. package/pipeline/skills/shared/README.md +4 -3
  86. package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +8 -71
  87. package/pipeline/skills/shared/core/apple-archive-compliance/references/examples.md +67 -0
  88. package/pipeline/skills/shared/core/apple-archive-compliance/references/version-history.md +8 -0
  89. package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +11 -73
  90. package/pipeline/skills/shared/core/google-play-compliance/references/examples.md +69 -0
  91. package/pipeline/skills/shared/core/google-play-compliance/references/notes.md +7 -0
  92. package/pipeline/skills/shared/core/google-play-compliance/references/version-history.md +5 -0
  93. package/pipeline/skills/shared/core/multi-agent/SKILL.md +39 -262
  94. package/pipeline/skills/shared/core/multi-agent-autopilot-on/SKILL.md +35 -73
  95. package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +37 -337
  96. package/pipeline/skills/shared/core/multi-agent-design-check/SKILL.md +27 -122
  97. package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +8 -340
  98. package/pipeline/skills/shared/core/multi-agent-ios-coding-standard/SKILL.md +37 -180
  99. package/pipeline/skills/shared/core/multi-agent-office-pair/SKILL.md +19 -0
  100. package/pipeline/skills/shared/core/multi-agent-office-status/SKILL.md +1 -1
  101. package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +23 -184
  102. package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +14 -82
  103. package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +25 -277
  104. package/pipeline/skills/shared/core/multi-agent-status/SKILL.md +13 -2
  105. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +75 -219
  106. package/pipeline/skills/shared/external/alarmkit/SKILL.md +11 -162
  107. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-code.md +257 -0
  108. package/pipeline/skills/shared/external/android-architecture/SKILL.md +7 -58
  109. package/pipeline/skills/shared/external/android-architecture/references/code-examples.md +68 -0
  110. package/pipeline/skills/shared/external/app-intents/SKILL.md +3 -45
  111. package/pipeline/skills/shared/external/app-intents/references/code-examples.md +54 -0
  112. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +5 -81
  113. package/pipeline/skills/shared/external/app-store-optimization/references/engagement-and-localization.md +96 -0
  114. package/pipeline/skills/shared/external/app-store-review/SKILL.md +6 -112
  115. package/pipeline/skills/shared/external/app-store-review/references/monetization-and-submission.md +138 -0
  116. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +10 -117
  117. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models-code.md +186 -0
  118. package/pipeline/skills/shared/external/authentication/SKILL.md +3 -50
  119. package/pipeline/skills/shared/external/authentication/references/code-examples.md +59 -0
  120. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +3 -84
  121. package/pipeline/skills/shared/external/callkit-voip/references/code-examples.md +93 -0
  122. package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +7 -263
  123. package/pipeline/skills/shared/external/ci-cd-pipelines/references/pipeline-examples.md +281 -0
  124. package/pipeline/skills/shared/external/clean-code/SKILL.md +8 -41
  125. package/pipeline/skills/shared/external/clean-code/references/code-examples.md +56 -0
  126. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +8 -146
  127. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-code.md +214 -0
  128. package/pipeline/skills/shared/external/compose-components/SKILL.md +6 -80
  129. package/pipeline/skills/shared/external/compose-components/references/code-examples.md +89 -0
  130. package/pipeline/skills/shared/external/compose-navigation/SKILL.md +5 -64
  131. package/pipeline/skills/shared/external/compose-navigation/references/code-examples.md +70 -0
  132. package/pipeline/skills/shared/external/core-data/SKILL.md +9 -157
  133. package/pipeline/skills/shared/external/core-data/references/core-data-code.md +221 -0
  134. package/pipeline/skills/shared/external/core-nfc/SKILL.md +3 -89
  135. package/pipeline/skills/shared/external/core-nfc/references/code-examples.md +98 -0
  136. package/pipeline/skills/shared/external/coreml/SKILL.md +17 -133
  137. package/pipeline/skills/shared/external/coreml/references/coreml-code.md +208 -0
  138. package/pipeline/skills/shared/external/css-modern/SKILL.md +8 -131
  139. package/pipeline/skills/shared/external/css-modern/references/code-examples.md +142 -0
  140. package/pipeline/skills/shared/external/database-patterns/SKILL.md +6 -103
  141. package/pipeline/skills/shared/external/database-patterns/references/orm-examples.md +112 -0
  142. package/pipeline/skills/shared/external/html-semantic/SKILL.md +7 -48
  143. package/pipeline/skills/shared/external/html-semantic/references/code-examples.md +54 -0
  144. package/pipeline/skills/shared/external/humanizer/SKILL.md +6 -19
  145. package/pipeline/skills/shared/external/humanizer/references/voice.md +24 -0
  146. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +13 -170
  147. package/pipeline/skills/shared/external/ios-accessibility/references/assistive-tech-review.md +224 -0
  148. package/pipeline/skills/shared/external/ios-localization/SKILL.md +2 -24
  149. package/pipeline/skills/shared/external/ios-localization/references/code-examples.md +30 -0
  150. package/pipeline/skills/shared/external/ios-networking/SKILL.md +3 -58
  151. package/pipeline/skills/shared/external/ios-networking/references/code-examples.md +67 -0
  152. package/pipeline/skills/shared/external/ios-security/SKILL.md +4 -64
  153. package/pipeline/skills/shared/external/ios-security/references/code-examples.md +74 -0
  154. package/pipeline/skills/shared/external/live-activities/SKILL.md +4 -90
  155. package/pipeline/skills/shared/external/live-activities/references/code-examples.md +108 -0
  156. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +9 -23
  157. package/pipeline/skills/shared/external/localization-reuse-map/references/project-settings.md +22 -0
  158. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +5 -95
  159. package/pipeline/skills/shared/external/mapkit-location/references/code-examples.md +117 -0
  160. package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +7 -106
  161. package/pipeline/skills/shared/external/nextjs-app-router/references/app-router-examples.md +124 -0
  162. package/pipeline/skills/shared/external/permissionkit/SKILL.md +2 -31
  163. package/pipeline/skills/shared/external/permissionkit/references/code-examples.md +37 -0
  164. package/pipeline/skills/shared/external/play-store-review/SKILL.md +6 -74
  165. package/pipeline/skills/shared/external/play-store-review/references/signing-and-policies.md +83 -0
  166. package/pipeline/skills/shared/external/push-notifications/SKILL.md +8 -125
  167. package/pipeline/skills/shared/external/push-notifications/references/notification-code.md +176 -0
  168. package/pipeline/skills/shared/external/python-patterns/SKILL.md +7 -158
  169. package/pipeline/skills/shared/external/python-patterns/references/python-examples.md +176 -0
  170. package/pipeline/skills/shared/external/rest-api-design/SKILL.md +7 -157
  171. package/pipeline/skills/shared/external/rest-api-design/references/api-examples.md +175 -0
  172. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +11 -230
  173. package/pipeline/skills/shared/external/swift-architecture/references/pattern-examples.md +295 -0
  174. package/pipeline/skills/shared/external/swift-codable/SKILL.md +17 -149
  175. package/pipeline/skills/shared/external/swift-codable/references/codable-recipes.md +207 -0
  176. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +12 -99
  177. package/pipeline/skills/shared/external/swift-concurrency/references/code-examples.md +100 -0
  178. package/pipeline/skills/shared/external/swift-concurrency/references/swift-6-2-additions.md +18 -0
  179. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +9 -78
  180. package/pipeline/skills/shared/external/swift-formatstyle/references/formatstyle-examples.md +113 -0
  181. package/pipeline/skills/shared/external/swift-language/SKILL.md +3 -56
  182. package/pipeline/skills/shared/external/swift-language/references/code-examples.md +65 -0
  183. package/pipeline/skills/shared/external/swift-testing-pro/SKILL.md +1 -0
  184. package/pipeline/skills/shared/external/swiftdata/SKILL.md +6 -122
  185. package/pipeline/skills/shared/external/swiftdata/references/code-examples.md +140 -0
  186. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +12 -139
  187. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/interop-code.md +198 -0
  188. package/pipeline/skills/shared/external/tailwind-css/SKILL.md +9 -81
  189. package/pipeline/skills/shared/external/tailwind-css/references/code-examples.md +91 -0
  190. package/pipeline/skills/shared/external/testing-backend/SKILL.md +7 -207
  191. package/pipeline/skills/shared/external/testing-backend/references/testing-examples.md +225 -0
  192. package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +8 -89
  193. package/pipeline/skills/shared/external/typescript-patterns/references/code-examples.md +100 -0
  194. package/pipeline/skills/shared/external/vision-framework/SKILL.md +2 -20
  195. package/pipeline/skills/shared/external/vision-framework/references/code-examples.md +26 -0
  196. package/pipeline/skills/shared/external/vue-composition/SKILL.md +7 -169
  197. package/pipeline/skills/shared/external/vue-composition/references/vue-examples.md +187 -0
  198. package/pipeline/skills/shared/external/web-accessibility/SKILL.md +7 -174
  199. package/pipeline/skills/shared/external/web-accessibility/references/a11y-examples.md +192 -0
  200. package/pipeline/skills/shared/external/web-performance/SKILL.md +8 -66
  201. package/pipeline/skills/shared/external/web-performance/references/code-examples.md +77 -0
  202. package/pipeline/skills/shared/external/web-testing/SKILL.md +11 -186
  203. package/pipeline/skills/shared/external/web-testing/references/testing-examples.md +213 -0
  204. package/pipeline/skills/skills-index.md +2 -1
  205. /package/pipeline/skills/shared/external/localization-reuse-map/{reference → references}/format-and-output.md +0 -0
  206. /package/pipeline/skills/shared/external/localization-reuse-map/{reference → references}/publish-and-snapshot.md +0 -0
  207. /package/pipeline/skills/shared/external/localization-reuse-map/{reference → references}/sources-and-recipes.md +0 -0
@@ -0,0 +1,117 @@
1
+ # MapKit and Core Location Code Examples
2
+
3
+ <!-- toc -->
4
+ - [SwiftUI Map (iOS 17+)](#swiftui-map-ios-17)
5
+ - [Selection](#selection)
6
+ - [CLLocationUpdate.liveUpdates() (iOS 17+)](#cllocationupdateliveupdates-ios-17)
7
+ - [Authorization](#authorization)
8
+ <!-- /toc -->
9
+
10
+ Full code samples for the SKILL.md sections that link here. The rules and the decision guidance stay in SKILL.md; each heading below matches the SKILL.md section the code belongs to.
11
+
12
+ ## SwiftUI Map (iOS 17+)
13
+
14
+ ```swift
15
+ import SwiftUI
16
+ import MapKit
17
+
18
+ struct TrailheadMap: View {
19
+ @State private var camera: MapCameraPosition = .automatic
20
+
21
+ private let lot = CLLocationCoordinate2D(latitude: 46.852, longitude: -121.760)
22
+ private let summit = CLLocationCoordinate2D(latitude: 46.853, longitude: -121.727)
23
+
24
+ var body: some View {
25
+ Map(position: $camera) {
26
+ Marker("Parking", coordinate: lot)
27
+ Marker("Summit", systemImage: "mountain.2.fill", coordinate: summit)
28
+ }
29
+ .mapStyle(.standard(elevation: .realistic))
30
+ .mapControls {
31
+ MapUserLocationButton()
32
+ MapCompass()
33
+ MapScaleView()
34
+ }
35
+ }
36
+ }
37
+ ```
38
+
39
+ ## Selection
40
+
41
+ ```swift
42
+ struct CampsiteMap: View {
43
+ let sites: [Campsite]
44
+ @State private var chosen: MKMapItem?
45
+ @State private var headline = ""
46
+
47
+ var body: some View {
48
+ Map(selection: $chosen) {
49
+ ForEach(sites) { site in
50
+ Marker(site.name, coordinate: site.coordinate)
51
+ .tag(site.mapItem)
52
+ }
53
+ }
54
+ .onChange(of: chosen) { _, item in
55
+ guard let item else { return }
56
+ headline = item.name ?? ""
57
+ }
58
+ }
59
+ }
60
+ ```
61
+
62
+ ## CLLocationUpdate.liveUpdates() (iOS 17+)
63
+
64
+ ```swift
65
+ import CoreLocation
66
+ import Observation
67
+
68
+ @MainActor
69
+ @Observable
70
+ final class RunTracker {
71
+ private(set) var lastFix: CLLocation?
72
+ private var stream: Task<Void, Never>?
73
+
74
+ func begin() {
75
+ stream?.cancel()
76
+ stream = Task {
77
+ do {
78
+ for try await reading in CLLocationUpdate.liveUpdates() {
79
+ guard let fix = reading.location,
80
+ fix.horizontalAccuracy >= 0,
81
+ fix.horizontalAccuracy < 50 else { continue }
82
+ lastFix = fix
83
+ }
84
+ } catch is CancellationError {
85
+ } catch {
86
+ lastFix = nil
87
+ }
88
+ }
89
+ }
90
+
91
+ func end() {
92
+ stream?.cancel()
93
+ stream = nil
94
+ }
95
+ }
96
+ ```
97
+
98
+ ## Authorization
99
+
100
+ ```swift
101
+ struct LocationOffView: View {
102
+ @Environment(\.openURL) private var openURL
103
+
104
+ var body: some View {
105
+ ContentUnavailableView {
106
+ Label("Location is off", systemImage: "location.slash")
107
+ } description: {
108
+ Text("Allow location access to see trails near you.")
109
+ } actions: {
110
+ Button("Open Settings") {
111
+ guard let settings = URL(string: UIApplication.openSettingsURLString) else { return }
112
+ openURL(settings)
113
+ }
114
+ }
115
+ }
116
+ }
117
+ ```
@@ -98,69 +98,7 @@ export function SearchBar() {
98
98
 
99
99
  ## Server Actions
100
100
 
101
- ```tsx
102
- // app/actions.ts
103
- 'use server';
104
-
105
- import { revalidatePath } from 'next/cache';
106
- import { redirect } from 'next/navigation';
107
- import { z } from 'zod';
108
-
109
- const CreatePostSchema = z.object({
110
- title: z.string().min(1).max(200),
111
- content: z.string().min(1),
112
- });
113
-
114
- export async function createPost(prevState: ActionState, formData: FormData) {
115
- const validated = CreatePostSchema.safeParse({
116
- title: formData.get('title'),
117
- content: formData.get('content'),
118
- });
119
-
120
- if (!validated.success) {
121
- return { errors: validated.error.flatten().fieldErrors };
122
- }
123
-
124
- try {
125
- await db.post.create({ data: validated.data });
126
- } catch (error) {
127
- return { message: 'Database Error: Failed to create post.' };
128
- }
129
-
130
- revalidatePath('/posts');
131
- redirect('/posts');
132
- }
133
- ```
134
-
135
- ```tsx
136
- // app/posts/new/page.tsx
137
- 'use client';
138
-
139
- import { useActionState } from 'react';
140
- import { createPost } from '@/app/actions';
141
-
142
- export default function NewPostPage() {
143
- const [state, formAction, isPending] = useActionState(createPost, { errors: {} });
144
-
145
- return (
146
- <form action={formAction}>
147
- <div>
148
- <label htmlFor="title">Title</label>
149
- <input id="title" name="title" />
150
- {state.errors?.title && <p className="error">{state.errors.title}</p>}
151
- </div>
152
- <div>
153
- <label htmlFor="content">Content</label>
154
- <textarea id="content" name="content" />
155
- {state.errors?.content && <p className="error">{state.errors.content}</p>}
156
- </div>
157
- <button type="submit" disabled={isPending}>
158
- {isPending ? 'Creating...' : 'Create Post'}
159
- </button>
160
- </form>
161
- );
162
- }
163
- ```
101
+ Code for this section: [App Router examples](references/app-router-examples.md).
164
102
 
165
103
  ## Data Fetching Patterns
166
104
 
@@ -293,52 +231,11 @@ export default function Error({
293
231
 
294
232
  ## Middleware
295
233
 
296
- ```tsx
297
- // middleware.ts (project root)
298
- import { NextResponse } from 'next/server';
299
- import type { NextRequest } from 'next/server';
300
-
301
- export function middleware(request: NextRequest) {
302
- const token = request.cookies.get('session')?.value;
303
-
304
- if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
305
- return NextResponse.redirect(new URL('/login', request.url));
306
- }
307
-
308
- const response = NextResponse.next();
309
- response.headers.set('x-request-id', crypto.randomUUID());
310
- return response;
311
- }
312
-
313
- export const config = {
314
- matcher: ['/dashboard/:path*', '/api/:path*'],
315
- };
316
- ```
234
+ Code for this section: [App Router examples](references/app-router-examples.md).
317
235
 
318
236
  ## Route Handlers (API Routes)
319
237
 
320
- ```tsx
321
- // app/api/users/route.ts
322
- import { NextRequest, NextResponse } from 'next/server';
323
-
324
- export async function GET(request: NextRequest) {
325
- const searchParams = request.nextUrl.searchParams;
326
- const page = parseInt(searchParams.get('page') ?? '1');
327
-
328
- const users = await db.user.findMany({
329
- skip: (page - 1) * 10,
330
- take: 10,
331
- });
332
-
333
- return NextResponse.json(users);
334
- }
335
-
336
- export async function POST(request: NextRequest) {
337
- const body = await request.json();
338
- const user = await db.user.create({ data: body });
339
- return NextResponse.json(user, { status: 201 });
340
- }
341
- ```
238
+ Code for this section: [App Router examples](references/app-router-examples.md).
342
239
 
343
240
  ## Rendering Strategies
344
241
 
@@ -419,3 +316,7 @@ export default async function ProfilePage() {
419
316
  | Hydration errors | Server/client HTML mismatch | Check for browser-only APIs; use `useEffect` for client-only logic |
420
317
  | Dynamic route 404 | Missing `generateStaticParams` | Add params generation or set `dynamicParams = true` |
421
318
  | Server Action fails | Not marked with 'use server' | Add 'use server' at top of file or inline function |
319
+
320
+ ## References
321
+
322
+ - [App Router examples](references/app-router-examples.md): open when writing a Server Action, middleware or a route handler.
@@ -0,0 +1,124 @@
1
+ # App Router examples
2
+
3
+ <!-- toc -->
4
+ - [Server Actions](#server-actions)
5
+ - [Middleware](#middleware)
6
+ - [Route Handlers (API Routes)](#route-handlers-api-routes)
7
+ <!-- /toc -->
8
+
9
+ Code for Server Actions, middleware and route handlers. SKILL.md keeps the component model, data fetching, rendering strategies and rules.
10
+
11
+ ## Server Actions
12
+
13
+ ```tsx
14
+ // app/actions.ts
15
+ 'use server';
16
+
17
+ import { revalidatePath } from 'next/cache';
18
+ import { redirect } from 'next/navigation';
19
+ import { z } from 'zod';
20
+
21
+ const CreatePostSchema = z.object({
22
+ title: z.string().min(1).max(200),
23
+ content: z.string().min(1),
24
+ });
25
+
26
+ export async function createPost(prevState: ActionState, formData: FormData) {
27
+ const validated = CreatePostSchema.safeParse({
28
+ title: formData.get('title'),
29
+ content: formData.get('content'),
30
+ });
31
+
32
+ if (!validated.success) {
33
+ return { errors: validated.error.flatten().fieldErrors };
34
+ }
35
+
36
+ try {
37
+ await db.post.create({ data: validated.data });
38
+ } catch (error) {
39
+ return { message: 'Database Error: Failed to create post.' };
40
+ }
41
+
42
+ revalidatePath('/posts');
43
+ redirect('/posts');
44
+ }
45
+ ```
46
+
47
+ ```tsx
48
+ // app/posts/new/page.tsx
49
+ 'use client';
50
+
51
+ import { useActionState } from 'react';
52
+ import { createPost } from '@/app/actions';
53
+
54
+ export default function NewPostPage() {
55
+ const [state, formAction, isPending] = useActionState(createPost, { errors: {} });
56
+
57
+ return (
58
+ <form action={formAction}>
59
+ <div>
60
+ <label htmlFor="title">Title</label>
61
+ <input id="title" name="title" />
62
+ {state.errors?.title && <p className="error">{state.errors.title}</p>}
63
+ </div>
64
+ <div>
65
+ <label htmlFor="content">Content</label>
66
+ <textarea id="content" name="content" />
67
+ {state.errors?.content && <p className="error">{state.errors.content}</p>}
68
+ </div>
69
+ <button type="submit" disabled={isPending}>
70
+ {isPending ? 'Creating...' : 'Create Post'}
71
+ </button>
72
+ </form>
73
+ );
74
+ }
75
+ ```
76
+
77
+ ## Middleware
78
+
79
+ ```tsx
80
+ // middleware.ts (project root)
81
+ import { NextResponse } from 'next/server';
82
+ import type { NextRequest } from 'next/server';
83
+
84
+ export function middleware(request: NextRequest) {
85
+ const token = request.cookies.get('session')?.value;
86
+
87
+ if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
88
+ return NextResponse.redirect(new URL('/login', request.url));
89
+ }
90
+
91
+ const response = NextResponse.next();
92
+ response.headers.set('x-request-id', crypto.randomUUID());
93
+ return response;
94
+ }
95
+
96
+ export const config = {
97
+ matcher: ['/dashboard/:path*', '/api/:path*'],
98
+ };
99
+ ```
100
+
101
+ ## Route Handlers (API Routes)
102
+
103
+ ```tsx
104
+ // app/api/users/route.ts
105
+ import { NextRequest, NextResponse } from 'next/server';
106
+
107
+ export async function GET(request: NextRequest) {
108
+ const searchParams = request.nextUrl.searchParams;
109
+ const page = parseInt(searchParams.get('page') ?? '1');
110
+
111
+ const users = await db.user.findMany({
112
+ skip: (page - 1) * 10,
113
+ take: 10,
114
+ });
115
+
116
+ return NextResponse.json(users);
117
+ }
118
+
119
+ export async function POST(request: NextRequest) {
120
+ const body = await request.json();
121
+ const user = await db.user.create({ data: body });
122
+ return NextResponse.json(user, { status: 201 });
123
+ }
124
+ ```
@@ -245,37 +245,7 @@ both. When the question carries an `expirationDate`, use that date for the
245
245
  local expiry so the app and the parent's window close together. When a flow combines known-handle checks with responses, keep the
246
246
  bundle-identifier guard from the section above.
247
247
 
248
- ```swift
249
- enum RequestState { case pending, approved, denied, expired }
250
-
251
- @MainActor @Observable
252
- final class ContactRequests {
253
- private(set) var states: [UUID: RequestState] = [:]
254
-
255
- func markPending(_ id: UUID) { states[id] = .pending }
256
-
257
- func expire(_ id: UUID) {
258
- guard states[id] == .pending else { return }
259
- states[id] = .expired // lets the child ask again
260
- }
261
-
262
- @available(iOS 26.2, *)
263
- func listen() async {
264
- for await response in AskCenter.shared.responses(for: CommunicationTopic.self) {
265
- let id = response.question.id
266
- switch response.choice.answer {
267
- case .approval: states[id] = .approved
268
- case .denial: states[id] = .denied
269
- @unknown default: states[id] = .denied
270
- }
271
- let people = response.question.topic.personInformation
272
- refreshContacts(people.map(\.handle))
273
- }
274
- }
275
-
276
- private func refreshContacts(_ handles: [CommunicationHandle]) {}
277
- }
278
- ```
248
+ Code: [Handling responses](references/code-examples.md#handling-responses).
279
249
 
280
250
  - `responses(for:)` is an async sequence of `PermissionResponse<Topic>`; each
281
251
  element has `.question` and `.choice`.
@@ -386,3 +356,4 @@ produces no response.
386
356
  - https://developer.apple.com/documentation/permissionkit/significantappupdatetopic
387
357
  - https://developer.apple.com/documentation/permissionkit/askerror
388
358
  - https://developer.apple.com/documentation/permissionkit/creating-a-communication-experience
359
+ - [Code examples](references/code-examples.md): open for the full code behind Handling responses.
@@ -0,0 +1,37 @@
1
+ # PermissionKit Code Examples
2
+
3
+ Full code samples for the SKILL.md sections that link here. The rules and the decision guidance stay in SKILL.md; each heading below matches the SKILL.md section the code belongs to.
4
+
5
+ ## Handling responses
6
+
7
+ ```swift
8
+ enum RequestState { case pending, approved, denied, expired }
9
+
10
+ @MainActor @Observable
11
+ final class ContactRequests {
12
+ private(set) var states: [UUID: RequestState] = [:]
13
+
14
+ func markPending(_ id: UUID) { states[id] = .pending }
15
+
16
+ func expire(_ id: UUID) {
17
+ guard states[id] == .pending else { return }
18
+ states[id] = .expired // lets the child ask again
19
+ }
20
+
21
+ @available(iOS 26.2, *)
22
+ func listen() async {
23
+ for await response in AskCenter.shared.responses(for: CommunicationTopic.self) {
24
+ let id = response.question.id
25
+ switch response.choice.answer {
26
+ case .approval: states[id] = .approved
27
+ case .denial: states[id] = .denied
28
+ @unknown default: states[id] = .denied
29
+ }
30
+ let people = response.question.topic.personInformation
31
+ refreshContacts(people.map(\.handle))
32
+ }
33
+ }
34
+
35
+ private func refreshContacts(_ handles: [CommunicationHandle]) {}
36
+ }
37
+ ```
@@ -207,43 +207,7 @@ of receiving each item type before purchase.
207
207
 
208
208
  ### Play App Signing (Required for New Apps)
209
209
 
210
- Google manages your app signing key. You upload with an upload key.
211
-
212
- ```bash
213
- # Generate upload key
214
- keytool -genkeypair -v -keystore upload-keystore.jks \
215
- -keyalg RSA -keysize 2048 -validity 10000 \
216
- -alias upload-key
217
-
218
- # Build AAB (not APK)
219
- ./gradlew bundleRelease
220
- ```
221
-
222
- ### AAB Requirements
223
-
224
- - New apps must upload AAB (Android App Bundle), not APK
225
- - Maximum download size: 200 MB (on-demand delivery for larger)
226
- - Use Play Feature Delivery for conditional/on-demand modules
227
-
228
- ### Signing Config
229
-
230
- ```kotlin
231
- android {
232
- signingConfigs {
233
- create("release") {
234
- storeFile = file(System.getenv("UPLOAD_KEYSTORE_PATH") ?: "upload.jks")
235
- storePassword = System.getenv("UPLOAD_KEYSTORE_PASSWORD") ?: ""
236
- keyAlias = System.getenv("UPLOAD_KEY_ALIAS") ?: ""
237
- keyPassword = System.getenv("UPLOAD_KEY_PASSWORD") ?: ""
238
- }
239
- }
240
- buildTypes {
241
- release {
242
- signingConfig = signingConfigs.getByName("release")
243
- }
244
- }
245
- }
246
- ```
210
+ Google holds the app signing key; you upload with your own upload key and build an AAB with `bundleRelease`. New apps must upload an AAB, not an APK (200 MB download limit, Play Feature Delivery beyond that), and the release signing config reads keystore values from environment variables. Commands, AAB rules and the Gradle config: [Signing and policy details](references/signing-and-policies.md).
247
211
 
248
212
  ## Common Rejection Reasons
249
213
 
@@ -266,43 +230,7 @@ android {
266
230
 
267
231
  ## Policy Categories
268
232
 
269
- ### Restricted Content
270
-
271
- - No hate speech, violence, or terrorism
272
- - No sexually explicit content (except in apps with IARC rating)
273
- - No gambling without proper licensing
274
- - No marijuana or pharmaceutical sales
275
- - No weapons or dangerous products
276
-
277
- ### Privacy and Security
278
-
279
- - Data collected must match Data Safety declaration
280
- - Sensitive permissions require justification
281
- - Background location requires approval
282
- - QUERY_ALL_PACKAGES requires approved use case
283
- - Apps targeting children must comply with COPPA
284
-
285
- ### Monetization
286
-
287
- - No deceptive subscription flows
288
- - In-app purchase prices must be clear before purchase
289
- - Free trials must state duration and post-trial price
290
- - Refund policy must be accessible
291
-
292
- ### User-Generated Content
293
-
294
- Apps with UGC must include:
295
- - Content moderation
296
- - Reporting mechanism
297
- - User blocking
298
- - Published content policy
299
-
300
- ### Account Deletion
301
-
302
- If your app allows account creation, you must:
303
- - Offer account deletion within the app
304
- - Provide a web-based deletion option
305
- - Delete data within 60 days of request (or explain legal retention)
233
+ Restricted content, privacy and security, monetization, user-generated content (moderation, reporting, blocking, published policy) and account deletion (in-app and web, data deleted within 60 days). Full lists: [Signing and policy details](references/signing-and-policies.md).
306
234
 
307
235
  ## Do's and Don'ts
308
236
 
@@ -350,3 +278,7 @@ If your app allows account creation, you must:
350
278
  - [ ] Monitor ANR rate (target < 0.47%)
351
279
  - [ ] Respond to user reviews promptly
352
280
  - [ ] Set up staged rollout for production releases (10% -> 50% -> 100%)
281
+
282
+ ## References
283
+
284
+ - [Signing and policy details](references/signing-and-policies.md): generating an upload key, configuring release signing and AAB delivery, or checking an app against the restricted content, privacy, monetization, UGC and account deletion policies.
@@ -0,0 +1,83 @@
1
+ # Signing and policy details
2
+
3
+ Play App Signing setup, AAB requirements, the Gradle signing config, and the policy categories. SKILL.md keeps the checklists, data safety, privacy, rating, billing and rejection reasons.
4
+
5
+ ## Play App Signing (Required for New Apps)
6
+
7
+ Google manages your app signing key. You upload with an upload key.
8
+
9
+ ```bash
10
+ # Generate upload key
11
+ keytool -genkeypair -v -keystore upload-keystore.jks \
12
+ -keyalg RSA -keysize 2048 -validity 10000 \
13
+ -alias upload-key
14
+
15
+ # Build AAB (not APK)
16
+ ./gradlew bundleRelease
17
+ ```
18
+
19
+ ## AAB Requirements
20
+
21
+ - New apps must upload AAB (Android App Bundle), not APK
22
+ - Maximum download size: 200 MB (on-demand delivery for larger)
23
+ - Use Play Feature Delivery for conditional/on-demand modules
24
+
25
+ ## Signing Config
26
+
27
+ ```kotlin
28
+ android {
29
+ signingConfigs {
30
+ create("release") {
31
+ storeFile = file(System.getenv("UPLOAD_KEYSTORE_PATH") ?: "upload.jks")
32
+ storePassword = System.getenv("UPLOAD_KEYSTORE_PASSWORD") ?: ""
33
+ keyAlias = System.getenv("UPLOAD_KEY_ALIAS") ?: ""
34
+ keyPassword = System.getenv("UPLOAD_KEY_PASSWORD") ?: ""
35
+ }
36
+ }
37
+ buildTypes {
38
+ release {
39
+ signingConfig = signingConfigs.getByName("release")
40
+ }
41
+ }
42
+ }
43
+ ```
44
+
45
+ ## Policy Categories
46
+
47
+ ### Restricted Content
48
+
49
+ - No hate speech, violence, or terrorism
50
+ - No sexually explicit content (except in apps with IARC rating)
51
+ - No gambling without proper licensing
52
+ - No marijuana or pharmaceutical sales
53
+ - No weapons or dangerous products
54
+
55
+ ### Privacy and Security
56
+
57
+ - Data collected must match Data Safety declaration
58
+ - Sensitive permissions require justification
59
+ - Background location requires approval
60
+ - QUERY_ALL_PACKAGES requires approved use case
61
+ - Apps targeting children must comply with COPPA
62
+
63
+ ### Monetization
64
+
65
+ - No deceptive subscription flows
66
+ - In-app purchase prices must be clear before purchase
67
+ - Free trials must state duration and post-trial price
68
+ - Refund policy must be accessible
69
+
70
+ ### User-Generated Content
71
+
72
+ Apps with UGC must include:
73
+ - Content moderation
74
+ - Reporting mechanism
75
+ - User blocking
76
+ - Published content policy
77
+
78
+ ### Account Deletion
79
+
80
+ If your app allows account creation, you must:
81
+ - Offer account deletion within the app
82
+ - Provide a web-based deletion option
83
+ - Delete data within 60 days of request (or explain legal retention)