@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,100 @@
1
+ # TypeScript 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
+ ## Discriminated Unions
6
+
7
+ ```typescript
8
+ // API response pattern
9
+ type ApiResult<T> =
10
+ | { status: 'success'; data: T }
11
+ | { status: 'error'; error: { code: string; message: string } }
12
+ | { status: 'loading' };
13
+
14
+ function handleResult<T>(result: ApiResult<T>): string {
15
+ switch (result.status) {
16
+ case 'success':
17
+ return JSON.stringify(result.data);
18
+ case 'error':
19
+ return `Error ${result.error.code}: ${result.error.message}`;
20
+ case 'loading':
21
+ return 'Loading...';
22
+ }
23
+ }
24
+
25
+ // Event system
26
+ type AppEvent =
27
+ | { type: 'USER_LOGIN'; payload: { userId: string } }
28
+ | { type: 'USER_LOGOUT' }
29
+ | { type: 'ITEM_ADDED'; payload: { itemId: string; quantity: number } }
30
+ | { type: 'ITEM_REMOVED'; payload: { itemId: string } };
31
+
32
+ function handleEvent(event: AppEvent): void {
33
+ switch (event.type) {
34
+ case 'USER_LOGIN':
35
+ console.log(`User ${event.payload.userId} logged in`);
36
+ break;
37
+ case 'USER_LOGOUT':
38
+ console.log('User logged out');
39
+ break;
40
+ case 'ITEM_ADDED':
41
+ console.log(`Added ${event.payload.quantity} of ${event.payload.itemId}`);
42
+ break;
43
+ case 'ITEM_REMOVED':
44
+ console.log(`Removed ${event.payload.itemId}`);
45
+ break;
46
+ }
47
+ }
48
+
49
+ // Exhaustive check helper
50
+ function exhaustiveCheck(value: never): never {
51
+ throw new Error(`Unhandled value: ${JSON.stringify(value)}`);
52
+ }
53
+ ```
54
+
55
+ ## Zod for Runtime Validation
56
+
57
+ ```typescript
58
+ import { z } from 'zod';
59
+
60
+ // Define schema
61
+ const UserSchema = z.object({
62
+ id: z.string().uuid(),
63
+ name: z.string().min(1).max(100),
64
+ email: z.string().email(),
65
+ role: z.enum(['admin', 'user', 'viewer']),
66
+ age: z.number().int().min(0).max(150).optional(),
67
+ tags: z.array(z.string()).default([]),
68
+ });
69
+
70
+ // Infer TypeScript type from schema
71
+ type User = z.infer<typeof UserSchema>;
72
+
73
+ // Validate at runtime
74
+ function createUser(input: unknown): User {
75
+ return UserSchema.parse(input); // throws ZodError on failure
76
+ }
77
+
78
+ // Safe parse (no throw)
79
+ function validateUser(input: unknown): ApiResult<User> {
80
+ const result = UserSchema.safeParse(input);
81
+ if (result.success) {
82
+ return { status: 'success', data: result.data };
83
+ }
84
+ return {
85
+ status: 'error',
86
+ error: { code: 'VALIDATION', message: result.error.message },
87
+ };
88
+ }
89
+
90
+ // Schema composition
91
+ const CreateUserSchema = UserSchema.omit({ id: true });
92
+ const UpdateUserSchema = UserSchema.partial().required({ id: true });
93
+
94
+ // API request validation
95
+ const PaginationSchema = z.object({
96
+ page: z.coerce.number().int().min(1).default(1),
97
+ limit: z.coerce.number().int().min(1).max(100).default(20),
98
+ sort: z.enum(['asc', 'desc']).default('desc'),
99
+ });
100
+ ```
@@ -291,26 +291,7 @@ Model loading, compute units, conversion and optimization belong to the
291
291
  `DataScannerViewController` (iOS 16+) is a full-screen live camera that finds
292
292
  text and barcodes and highlights them.
293
293
 
294
- ```swift
295
- import UIKit
296
- import VisionKit
297
-
298
- @MainActor
299
- func presentTicketScanner(from host: UIViewController, delegate: DataScannerViewControllerDelegate) {
300
- guard DataScannerViewController.isSupported, DataScannerViewController.isAvailable else { return }
301
- let scanner = DataScannerViewController(
302
- recognizedDataTypes: [.text(languages: ["en"]), .barcode(symbologies: [.qr, .aztec])],
303
- qualityLevel: .balanced,
304
- recognizesMultipleItems: false,
305
- isHighFrameRateTrackingEnabled: true,
306
- isHighlightingEnabled: true
307
- )
308
- scanner.delegate = delegate
309
- host.present(scanner, animated: true) {
310
- try? scanner.startScanning()
311
- }
312
- }
313
- ```
294
+ Code: [VisionKit live scanning: DataScannerViewController](references/code-examples.md#visionkit-live-scanning-datascannerviewcontroller).
314
295
 
315
296
  `isSupported` checks the hardware (A12 Bionic or later); `isAvailable`
316
297
  additionally requires camera permission. In SwiftUI, wrap the controller in a
@@ -362,3 +343,4 @@ additionally requires camera permission. In SwiftUI, wrap the controller in a
362
343
  - https://developer.apple.com/documentation/visionkit
363
344
  - https://developer.apple.com/documentation/vision/recognizetextrequest
364
345
  - https://developer.apple.com/documentation/visionkit/datascannerviewcontroller
346
+ - [Code examples](references/code-examples.md): open for the full code behind VisionKit live scanning: DataScannerViewController.
@@ -0,0 +1,26 @@
1
+ # Vision Framework 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
+ ## VisionKit live scanning: DataScannerViewController
6
+
7
+ ```swift
8
+ import UIKit
9
+ import VisionKit
10
+
11
+ @MainActor
12
+ func presentTicketScanner(from host: UIViewController, delegate: DataScannerViewControllerDelegate) {
13
+ guard DataScannerViewController.isSupported, DataScannerViewController.isAvailable else { return }
14
+ let scanner = DataScannerViewController(
15
+ recognizedDataTypes: [.text(languages: ["en"]), .barcode(symbologies: [.qr, .aztec])],
16
+ qualityLevel: .balanced,
17
+ recognizesMultipleItems: false,
18
+ isHighFrameRateTrackingEnabled: true,
19
+ isHighlightingEnabled: true
20
+ )
21
+ scanner.delegate = delegate
22
+ host.present(scanner, animated: true) {
23
+ try? scanner.startScanning()
24
+ }
25
+ }
26
+ ```
@@ -164,181 +164,15 @@ watch(
164
164
 
165
165
  ## Composables (useXxx Pattern)
166
166
 
167
- ```typescript
168
- // composables/useFetch.ts
169
- import { ref, type Ref } from 'vue';
170
-
171
- interface UseFetchReturn<T> {
172
- data: Ref<T | null>;
173
- error: Ref<string | null>;
174
- isLoading: Ref<boolean>;
175
- execute: () => Promise<void>;
176
- }
177
-
178
- export function useFetch<T>(url: string | Ref<string>): UseFetchReturn<T> {
179
- const data = ref<T | null>(null) as Ref<T | null>;
180
- const error = ref<string | null>(null);
181
- const isLoading = ref(false);
182
-
183
- async function execute() {
184
- isLoading.value = true;
185
- error.value = null;
186
- try {
187
- const resolvedUrl = typeof url === 'string' ? url : url.value;
188
- const response = await fetch(resolvedUrl);
189
- if (!response.ok) throw new Error(`HTTP ${response.status}`);
190
- data.value = await response.json();
191
- } catch (e) {
192
- error.value = e instanceof Error ? e.message : 'Unknown error';
193
- } finally {
194
- isLoading.value = false;
195
- }
196
- }
197
-
198
- return { data, error, isLoading, execute };
199
- }
200
-
201
- // composables/useLocalStorage.ts
202
- import { ref, watch, type Ref } from 'vue';
203
-
204
- export function useLocalStorage<T>(key: string, defaultValue: T): Ref<T> {
205
- const stored = localStorage.getItem(key);
206
- const data = ref<T>(stored ? JSON.parse(stored) : defaultValue) as Ref<T>;
207
-
208
- watch(data, (newValue) => {
209
- localStorage.setItem(key, JSON.stringify(newValue));
210
- }, { deep: true });
211
-
212
- return data;
213
- }
214
-
215
- // composables/useDebounce.ts
216
- import { ref, watch, type Ref } from 'vue';
217
-
218
- export function useDebounce<T>(source: Ref<T>, delay = 300): Ref<T> {
219
- const debounced = ref(source.value) as Ref<T>;
220
- let timeout: ReturnType<typeof setTimeout>;
221
-
222
- watch(source, (newValue) => {
223
- clearTimeout(timeout);
224
- timeout = setTimeout(() => {
225
- debounced.value = newValue;
226
- }, delay);
227
- });
228
-
229
- return debounced;
230
- }
231
- ```
167
+ Code for this section: [Vue examples](references/vue-examples.md).
232
168
 
233
169
  ## Pinia State Management
234
170
 
235
- ```typescript
236
- // stores/auth.ts
237
- import { defineStore } from 'pinia';
238
- import { ref, computed } from 'vue';
239
-
240
- export const useAuthStore = defineStore('auth', () => {
241
- // State
242
- const user = ref<User | null>(null);
243
- const token = ref<string | null>(null);
244
-
245
- // Getters
246
- const isAuthenticated = computed(() => !!token.value);
247
- const displayName = computed(() => user.value?.name ?? 'Guest');
248
-
249
- // Actions
250
- async function login(credentials: { email: string; password: string }) {
251
- const response = await api.post('/auth/login', credentials);
252
- user.value = response.user;
253
- token.value = response.token;
254
- }
255
-
256
- function logout() {
257
- user.value = null;
258
- token.value = null;
259
- }
260
-
261
- return { user, token, isAuthenticated, displayName, login, logout };
262
- }, {
263
- persist: true, // pinia-plugin-persistedstate
264
- });
265
-
266
- // stores/cart.ts
267
- export const useCartStore = defineStore('cart', () => {
268
- const items = ref<CartItem[]>([]);
269
-
270
- const totalItems = computed(() =>
271
- items.value.reduce((sum, item) => sum + item.quantity, 0)
272
- );
273
-
274
- const totalPrice = computed(() =>
275
- items.value.reduce((sum, item) => sum + item.price * item.quantity, 0)
276
- );
277
-
278
- function addItem(product: Product) {
279
- const existing = items.value.find((i) => i.productId === product.id);
280
- if (existing) {
281
- existing.quantity++;
282
- } else {
283
- items.value.push({ productId: product.id, name: product.name, price: product.price, quantity: 1 });
284
- }
285
- }
286
-
287
- function removeItem(productId: string) {
288
- items.value = items.value.filter((i) => i.productId !== productId);
289
- }
290
-
291
- return { items, totalItems, totalPrice, addItem, removeItem };
292
- });
293
- ```
171
+ Code for this section: [Vue examples](references/vue-examples.md).
294
172
 
295
173
  ## Vue Router 4
296
174
 
297
- ```typescript
298
- // router/index.ts
299
- import { createRouter, createWebHistory } from 'vue-router';
300
- import type { RouteRecordRaw } from 'vue-router';
301
-
302
- const routes: RouteRecordRaw[] = [
303
- {
304
- path: '/',
305
- component: () => import('@/layouts/DefaultLayout.vue'),
306
- children: [
307
- { path: '', name: 'home', component: () => import('@/pages/HomePage.vue') },
308
- { path: 'about', name: 'about', component: () => import('@/pages/AboutPage.vue') },
309
- ],
310
- },
311
- {
312
- path: '/dashboard',
313
- component: () => import('@/layouts/DashboardLayout.vue'),
314
- meta: { requiresAuth: true },
315
- children: [
316
- { path: '', name: 'dashboard', component: () => import('@/pages/DashboardPage.vue') },
317
- { path: 'settings', name: 'settings', component: () => import('@/pages/SettingsPage.vue') },
318
- { path: 'users/:id', name: 'user-detail', component: () => import('@/pages/UserDetailPage.vue'), props: true },
319
- ],
320
- },
321
- { path: '/:pathMatch(.*)*', name: 'not-found', component: () => import('@/pages/NotFoundPage.vue') },
322
- ];
323
-
324
- const router = createRouter({
325
- history: createWebHistory(),
326
- routes,
327
- scrollBehavior(to, from, savedPosition) {
328
- return savedPosition ?? { top: 0 };
329
- },
330
- });
331
-
332
- // Navigation guard
333
- router.beforeEach((to, from) => {
334
- const auth = useAuthStore();
335
- if (to.meta.requiresAuth && !auth.isAuthenticated) {
336
- return { name: 'login', query: { redirect: to.fullPath } };
337
- }
338
- });
339
-
340
- export default router;
341
- ```
175
+ Code for this section: [Vue examples](references/vue-examples.md).
342
176
 
343
177
  ## Do's
344
178
 
@@ -372,3 +206,7 @@ export default router;
372
206
  | Prop mutation warning | Modifying prop directly | Use `defineModel` or emit event with new value |
373
207
  | Template ref is null | Accessed before mount | Use `onMounted` hook or optional chaining |
374
208
  | Pinia state lost on refresh | No persistence plugin | Add `pinia-plugin-persistedstate` |
209
+
210
+ ## References
211
+
212
+ - [Vue examples](references/vue-examples.md): open when writing a composable, a Pinia store or router configuration and guards.
@@ -0,0 +1,187 @@
1
+ # Vue examples
2
+
3
+ <!-- toc -->
4
+ - [Composables (useXxx Pattern)](#composables-usexxx-pattern)
5
+ - [Pinia State Management](#pinia-state-management)
6
+ - [Vue Router 4](#vue-router-4)
7
+ <!-- /toc -->
8
+
9
+ Code for composables, Pinia stores and Vue Router 4. SKILL.md keeps the core concepts, script setup, reactivity and watcher rules.
10
+
11
+ ## Composables (useXxx Pattern)
12
+
13
+ ```typescript
14
+ // composables/useFetch.ts
15
+ import { ref, type Ref } from 'vue';
16
+
17
+ interface UseFetchReturn<T> {
18
+ data: Ref<T | null>;
19
+ error: Ref<string | null>;
20
+ isLoading: Ref<boolean>;
21
+ execute: () => Promise<void>;
22
+ }
23
+
24
+ export function useFetch<T>(url: string | Ref<string>): UseFetchReturn<T> {
25
+ const data = ref<T | null>(null) as Ref<T | null>;
26
+ const error = ref<string | null>(null);
27
+ const isLoading = ref(false);
28
+
29
+ async function execute() {
30
+ isLoading.value = true;
31
+ error.value = null;
32
+ try {
33
+ const resolvedUrl = typeof url === 'string' ? url : url.value;
34
+ const response = await fetch(resolvedUrl);
35
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
36
+ data.value = await response.json();
37
+ } catch (e) {
38
+ error.value = e instanceof Error ? e.message : 'Unknown error';
39
+ } finally {
40
+ isLoading.value = false;
41
+ }
42
+ }
43
+
44
+ return { data, error, isLoading, execute };
45
+ }
46
+
47
+ // composables/useLocalStorage.ts
48
+ import { ref, watch, type Ref } from 'vue';
49
+
50
+ export function useLocalStorage<T>(key: string, defaultValue: T): Ref<T> {
51
+ const stored = localStorage.getItem(key);
52
+ const data = ref<T>(stored ? JSON.parse(stored) : defaultValue) as Ref<T>;
53
+
54
+ watch(data, (newValue) => {
55
+ localStorage.setItem(key, JSON.stringify(newValue));
56
+ }, { deep: true });
57
+
58
+ return data;
59
+ }
60
+
61
+ // composables/useDebounce.ts
62
+ import { ref, watch, type Ref } from 'vue';
63
+
64
+ export function useDebounce<T>(source: Ref<T>, delay = 300): Ref<T> {
65
+ const debounced = ref(source.value) as Ref<T>;
66
+ let timeout: ReturnType<typeof setTimeout>;
67
+
68
+ watch(source, (newValue) => {
69
+ clearTimeout(timeout);
70
+ timeout = setTimeout(() => {
71
+ debounced.value = newValue;
72
+ }, delay);
73
+ });
74
+
75
+ return debounced;
76
+ }
77
+ ```
78
+
79
+ ## Pinia State Management
80
+
81
+ ```typescript
82
+ // stores/auth.ts
83
+ import { defineStore } from 'pinia';
84
+ import { ref, computed } from 'vue';
85
+
86
+ export const useAuthStore = defineStore('auth', () => {
87
+ // State
88
+ const user = ref<User | null>(null);
89
+ const token = ref<string | null>(null);
90
+
91
+ // Getters
92
+ const isAuthenticated = computed(() => !!token.value);
93
+ const displayName = computed(() => user.value?.name ?? 'Guest');
94
+
95
+ // Actions
96
+ async function login(credentials: { email: string; password: string }) {
97
+ const response = await api.post('/auth/login', credentials);
98
+ user.value = response.user;
99
+ token.value = response.token;
100
+ }
101
+
102
+ function logout() {
103
+ user.value = null;
104
+ token.value = null;
105
+ }
106
+
107
+ return { user, token, isAuthenticated, displayName, login, logout };
108
+ }, {
109
+ persist: true, // pinia-plugin-persistedstate
110
+ });
111
+
112
+ // stores/cart.ts
113
+ export const useCartStore = defineStore('cart', () => {
114
+ const items = ref<CartItem[]>([]);
115
+
116
+ const totalItems = computed(() =>
117
+ items.value.reduce((sum, item) => sum + item.quantity, 0)
118
+ );
119
+
120
+ const totalPrice = computed(() =>
121
+ items.value.reduce((sum, item) => sum + item.price * item.quantity, 0)
122
+ );
123
+
124
+ function addItem(product: Product) {
125
+ const existing = items.value.find((i) => i.productId === product.id);
126
+ if (existing) {
127
+ existing.quantity++;
128
+ } else {
129
+ items.value.push({ productId: product.id, name: product.name, price: product.price, quantity: 1 });
130
+ }
131
+ }
132
+
133
+ function removeItem(productId: string) {
134
+ items.value = items.value.filter((i) => i.productId !== productId);
135
+ }
136
+
137
+ return { items, totalItems, totalPrice, addItem, removeItem };
138
+ });
139
+ ```
140
+
141
+ ## Vue Router 4
142
+
143
+ ```typescript
144
+ // router/index.ts
145
+ import { createRouter, createWebHistory } from 'vue-router';
146
+ import type { RouteRecordRaw } from 'vue-router';
147
+
148
+ const routes: RouteRecordRaw[] = [
149
+ {
150
+ path: '/',
151
+ component: () => import('@/layouts/DefaultLayout.vue'),
152
+ children: [
153
+ { path: '', name: 'home', component: () => import('@/pages/HomePage.vue') },
154
+ { path: 'about', name: 'about', component: () => import('@/pages/AboutPage.vue') },
155
+ ],
156
+ },
157
+ {
158
+ path: '/dashboard',
159
+ component: () => import('@/layouts/DashboardLayout.vue'),
160
+ meta: { requiresAuth: true },
161
+ children: [
162
+ { path: '', name: 'dashboard', component: () => import('@/pages/DashboardPage.vue') },
163
+ { path: 'settings', name: 'settings', component: () => import('@/pages/SettingsPage.vue') },
164
+ { path: 'users/:id', name: 'user-detail', component: () => import('@/pages/UserDetailPage.vue'), props: true },
165
+ ],
166
+ },
167
+ { path: '/:pathMatch(.*)*', name: 'not-found', component: () => import('@/pages/NotFoundPage.vue') },
168
+ ];
169
+
170
+ const router = createRouter({
171
+ history: createWebHistory(),
172
+ routes,
173
+ scrollBehavior(to, from, savedPosition) {
174
+ return savedPosition ?? { top: 0 };
175
+ },
176
+ });
177
+
178
+ // Navigation guard
179
+ router.beforeEach((to, from) => {
180
+ const auth = useAuthStore();
181
+ if (to.meta.requiresAuth && !auth.isAuthenticated) {
182
+ return { name: 'login', query: { redirect: to.fullPath } };
183
+ }
184
+ });
185
+
186
+ export default router;
187
+ ```