moai-adk 0.4.5__py3-none-any.whl → 0.20.1__py3-none-any.whl

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.

Potentially problematic release.


This version of moai-adk might be problematic. Click here for more details.

Files changed (433) hide show
  1. moai_adk/__init__.py +1 -1
  2. moai_adk/__main__.py +74 -1
  3. moai_adk/cli/commands/__init__.py +1 -1
  4. moai_adk/cli/commands/analyze.py +119 -0
  5. moai_adk/cli/commands/backup.py +25 -1
  6. moai_adk/cli/commands/doctor.py +31 -5
  7. moai_adk/cli/commands/improve_user_experience.py +307 -0
  8. moai_adk/cli/commands/init.py +111 -10
  9. moai_adk/cli/commands/status.py +33 -3
  10. moai_adk/cli/commands/update.py +921 -130
  11. moai_adk/cli/commands/validate_links.py +120 -0
  12. moai_adk/cli/prompts/init_prompts.py +22 -87
  13. moai_adk/core/analysis/__init__.py +9 -0
  14. moai_adk/core/analysis/session_analyzer.py +388 -0
  15. moai_adk/core/analysis/tag_chain_analyzer.py +344 -0
  16. moai_adk/core/analysis/tag_chain_repair.py +879 -0
  17. moai_adk/core/config/__init__.py +19 -0
  18. moai_adk/core/config/migration.py +235 -0
  19. moai_adk/core/git/__init__.py +1 -1
  20. moai_adk/core/git/branch.py +1 -1
  21. moai_adk/core/git/commit.py +1 -1
  22. moai_adk/core/git/manager.py +1 -1
  23. moai_adk/core/issue_creator.py +313 -0
  24. moai_adk/core/mcp/setup.py +56 -0
  25. moai_adk/core/mcp/setup_old.py +296 -0
  26. moai_adk/core/project/backup_utils.py +1 -1
  27. moai_adk/core/project/checker.py +2 -2
  28. moai_adk/core/project/detector.py +211 -12
  29. moai_adk/core/project/initializer.py +85 -15
  30. moai_adk/core/project/phase_executor.py +76 -13
  31. moai_adk/core/project/validator.py +13 -13
  32. moai_adk/core/quality/__init__.py +1 -1
  33. moai_adk/core/quality/trust_checker.py +1 -1
  34. moai_adk/core/quality/validators/__init__.py +1 -1
  35. moai_adk/core/quality/validators/base_validator.py +1 -1
  36. moai_adk/core/tags/__init__.py +86 -0
  37. moai_adk/core/tags/auto_corrector.py +693 -0
  38. moai_adk/core/tags/ci_validator.py +463 -0
  39. moai_adk/core/tags/cli.py +283 -0
  40. moai_adk/core/tags/generator.py +109 -0
  41. moai_adk/core/tags/inserter.py +99 -0
  42. moai_adk/core/tags/mapper.py +126 -0
  43. moai_adk/core/tags/parser.py +76 -0
  44. moai_adk/core/tags/policy_validator.py +580 -0
  45. moai_adk/core/tags/pre_commit_validator.py +421 -0
  46. moai_adk/core/tags/reporter.py +956 -0
  47. moai_adk/core/tags/rollback_manager.py +525 -0
  48. moai_adk/core/tags/tags.py +149 -0
  49. moai_adk/core/tags/validator.py +897 -0
  50. moai_adk/core/template/__init__.py +1 -1
  51. moai_adk/core/template/backup.py +1 -1
  52. moai_adk/core/template/merger.py +50 -1
  53. moai_adk/core/template/processor.py +119 -13
  54. moai_adk/core/template_engine.py +268 -0
  55. moai_adk/templates/.claude/agents/alfred/backend-expert.md +348 -0
  56. moai_adk/templates/.claude/agents/alfred/cc-manager.md +209 -944
  57. moai_adk/templates/.claude/agents/alfred/database-expert.md +352 -0
  58. moai_adk/templates/.claude/agents/alfred/debug-helper.md +34 -5
  59. moai_adk/templates/.claude/agents/alfred/devops-expert.md +464 -0
  60. moai_adk/templates/.claude/agents/alfred/doc-syncer.md +38 -8
  61. moai_adk/templates/.claude/agents/alfred/format-expert.md +469 -0
  62. moai_adk/templates/.claude/agents/alfred/frontend-expert.md +357 -0
  63. moai_adk/templates/.claude/agents/alfred/git-manager.md +128 -9
  64. moai_adk/templates/.claude/agents/alfred/implementation-planner.md +104 -6
  65. moai_adk/templates/.claude/agents/alfred/project-manager.md +88 -16
  66. moai_adk/templates/.claude/agents/alfred/quality-gate.md +36 -9
  67. moai_adk/templates/.claude/agents/alfred/security-expert.md +270 -0
  68. moai_adk/templates/.claude/agents/alfred/skill-factory.md +865 -0
  69. moai_adk/templates/.claude/agents/alfred/spec-builder.md +214 -43
  70. moai_adk/templates/.claude/agents/alfred/tag-agent.md +111 -9
  71. moai_adk/templates/.claude/agents/alfred/tdd-implementer.md +309 -160
  72. moai_adk/templates/.claude/agents/alfred/trust-checker.md +36 -7
  73. moai_adk/templates/.claude/agents/alfred/ui-ux-expert.md +605 -0
  74. moai_adk/templates/.claude/commands/alfred/0-project.md +393 -966
  75. moai_adk/templates/.claude/commands/alfred/1-plan.md +651 -367
  76. moai_adk/templates/.claude/commands/alfred/2-run.md +388 -241
  77. moai_adk/templates/.claude/commands/alfred/3-sync.md +1921 -410
  78. moai_adk/templates/.claude/commands/alfred/9-feedback.md +153 -0
  79. moai_adk/templates/.claude/commands/alfred/release-new.md +3604 -0
  80. moai_adk/templates/.claude/hooks/alfred/core/project.py +484 -20
  81. moai_adk/templates/.claude/hooks/alfred/core/timeout.py +136 -0
  82. moai_adk/templates/.claude/hooks/alfred/core/ttl_cache.py +108 -0
  83. moai_adk/templates/.claude/hooks/alfred/core/version_cache.py +198 -0
  84. moai_adk/templates/.claude/hooks/alfred/handlers/__init__.py +14 -6
  85. moai_adk/templates/.claude/hooks/alfred/post_tool__enable_streaming_ui.py +50 -0
  86. moai_adk/templates/.claude/hooks/alfred/post_tool__log_changes.py +93 -0
  87. moai_adk/templates/.claude/hooks/alfred/post_tool__tag_auto_corrector.py +407 -0
  88. moai_adk/templates/.claude/hooks/alfred/pre_tool__auto_checkpoint.py +99 -0
  89. moai_adk/templates/.claude/hooks/alfred/pre_tool__realtime_tag_monitor.py +335 -0
  90. moai_adk/templates/.claude/hooks/alfred/pre_tool__tag_policy_validator.py +325 -0
  91. moai_adk/templates/.claude/hooks/alfred/session_end__cleanup.py +93 -0
  92. moai_adk/templates/.claude/hooks/alfred/session_start__auto_cleanup.py +580 -0
  93. moai_adk/templates/.claude/hooks/alfred/session_start__show_project_info.py +298 -0
  94. moai_adk/templates/.claude/hooks/alfred/shared/core/__init__.py +170 -0
  95. moai_adk/templates/.claude/hooks/alfred/{core → shared/core}/checkpoint.py +3 -3
  96. moai_adk/templates/.claude/hooks/alfred/{core → shared/core}/context.py +5 -5
  97. moai_adk/templates/.claude/hooks/alfred/shared/core/project.py +749 -0
  98. moai_adk/templates/.claude/hooks/alfred/shared/core/tags.py +230 -0
  99. moai_adk/templates/.claude/hooks/alfred/shared/core/version_cache.py +198 -0
  100. moai_adk/templates/.claude/hooks/alfred/shared/handlers/__init__.py +21 -0
  101. moai_adk/templates/.claude/hooks/alfred/shared/handlers/daily_analysis.py +351 -0
  102. moai_adk/templates/.claude/hooks/alfred/shared/handlers/notification.py +154 -0
  103. moai_adk/templates/.claude/hooks/alfred/shared/handlers/session.py +174 -0
  104. moai_adk/templates/.claude/hooks/alfred/shared/handlers/tool.py +87 -0
  105. moai_adk/templates/.claude/hooks/alfred/shared/handlers/user.py +61 -0
  106. moai_adk/templates/.claude/hooks/alfred/user_prompt__jit_load_docs.py +111 -0
  107. moai_adk/templates/.claude/hooks/alfred/utils/__init__.py +1 -0
  108. moai_adk/templates/.claude/hooks/alfred/utils/hook_config.py +94 -0
  109. moai_adk/templates/.claude/hooks/alfred/utils/timeout.py +161 -0
  110. moai_adk/templates/.claude/output-styles/alfred/alfred-moai-adk-beginner.md +267 -0
  111. moai_adk/templates/.claude/output-styles/alfred/keating-personal-tutor.md +440 -0
  112. moai_adk/templates/.claude/output-styles/alfred/r2d2-agentic-coding.md +583 -0
  113. moai_adk/templates/.claude/settings.json +96 -14
  114. moai_adk/templates/.claude/skills/moai-alfred-agent-guide/SKILL.md +70 -0
  115. moai_adk/templates/.claude/skills/moai-alfred-agent-guide/examples.md +62 -0
  116. moai_adk/templates/.claude/skills/moai-alfred-agent-guide/reference.md +242 -0
  117. moai_adk/templates/.claude/skills/moai-alfred-ask-user-questions/SKILL.md +237 -0
  118. moai_adk/templates/.claude/skills/moai-alfred-ask-user-questions/examples.md +871 -0
  119. moai_adk/templates/.claude/skills/moai-alfred-ask-user-questions/reference.md +653 -0
  120. moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/README.md +162 -0
  121. moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/SKILL.md +227 -0
  122. moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/examples.md +354 -0
  123. moai_adk/templates/.claude/skills/moai-alfred-clone-pattern/reference.md +158 -0
  124. moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/SKILL.md +179 -79
  125. moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/examples.md +117 -0
  126. moai_adk/templates/.claude/skills/moai-alfred-code-reviewer/scripts/pre-review-check.sh +62 -0
  127. moai_adk/templates/.claude/skills/moai-alfred-config-schema/SKILL.md +132 -0
  128. moai_adk/templates/.claude/skills/moai-alfred-config-schema/examples.md +28 -0
  129. moai_adk/templates/.claude/skills/moai-alfred-config-schema/reference.md +444 -0
  130. moai_adk/templates/.claude/skills/moai-alfred-context-budget/SKILL.md +62 -0
  131. moai_adk/templates/.claude/skills/moai-alfred-context-budget/examples.md +28 -0
  132. moai_adk/templates/.claude/skills/moai-alfred-context-budget/reference.md +405 -0
  133. moai_adk/templates/.claude/skills/moai-alfred-dev-guide/SKILL.md +51 -0
  134. moai_adk/templates/.claude/skills/moai-alfred-dev-guide/examples.md +355 -0
  135. moai_adk/templates/.claude/skills/moai-alfred-dev-guide/reference.md +239 -0
  136. moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/SKILL.md +323 -0
  137. moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/examples.md +286 -0
  138. moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/reference.md +126 -0
  139. moai_adk/templates/.claude/skills/moai-alfred-issue-labels/SKILL.md +229 -0
  140. moai_adk/templates/.claude/skills/moai-alfred-issue-labels/examples.md +4 -0
  141. moai_adk/templates/.claude/skills/moai-alfred-issue-labels/reference.md +150 -0
  142. moai_adk/templates/.claude/skills/moai-alfred-language-detection/SKILL.md +87 -73
  143. moai_adk/templates/.claude/skills/moai-alfred-language-detection/examples.md +29 -0
  144. moai_adk/templates/.claude/skills/moai-alfred-language-detection/reference.md +28 -0
  145. moai_adk/templates/.claude/skills/moai-alfred-personas/README.md +42 -0
  146. moai_adk/templates/.claude/skills/moai-alfred-personas/SKILL.md +429 -0
  147. moai_adk/templates/.claude/skills/moai-alfred-personas/examples.md +520 -0
  148. moai_adk/templates/.claude/skills/moai-alfred-personas/reference.md +405 -0
  149. moai_adk/templates/.claude/skills/moai-alfred-practices/SKILL.md +89 -0
  150. moai_adk/templates/.claude/skills/moai-alfred-practices/examples.md +122 -0
  151. moai_adk/templates/.claude/skills/moai-alfred-practices/reference.md +369 -0
  152. moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/SKILL.md +508 -0
  153. moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/examples.md +481 -0
  154. moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/reference.md +100 -0
  155. moai_adk/templates/.claude/skills/moai-alfred-rules/SKILL.md +77 -0
  156. moai_adk/templates/.claude/skills/moai-alfred-rules/examples.md +265 -0
  157. moai_adk/templates/.claude/skills/moai-alfred-rules/reference.md +539 -0
  158. moai_adk/templates/.claude/skills/moai-alfred-session-state/SKILL.md +320 -0
  159. moai_adk/templates/.claude/skills/moai-alfred-session-state/examples.md +4 -0
  160. moai_adk/templates/.claude/skills/moai-alfred-session-state/reference.md +84 -0
  161. moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/README.md +137 -0
  162. moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/SKILL.md +219 -0
  163. moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/examples/validate-spec.sh +161 -0
  164. moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/examples.md +541 -0
  165. moai_adk/templates/.claude/skills/moai-alfred-spec-authoring/reference.md +622 -0
  166. moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/SKILL.md +19 -0
  167. moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/examples.md +4 -0
  168. moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/reference.md +211 -0
  169. moai_adk/templates/.claude/skills/moai-alfred-workflow/SKILL.md +288 -0
  170. moai_adk/templates/.claude/skills/moai-cc-agents/SKILL.md +269 -0
  171. moai_adk/templates/.claude/skills/moai-cc-agents/templates/agent-template.md +32 -0
  172. moai_adk/templates/.claude/skills/moai-cc-claude-md/SKILL.md +298 -0
  173. moai_adk/templates/.claude/skills/moai-cc-claude-md/templates/CLAUDE-template.md +26 -0
  174. moai_adk/templates/.claude/skills/moai-cc-commands/SKILL.md +307 -0
  175. moai_adk/templates/.claude/skills/moai-cc-commands/templates/command-template.md +21 -0
  176. moai_adk/templates/.claude/skills/moai-cc-hooks/SKILL.md +252 -0
  177. moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/pre-bash-check.sh +19 -0
  178. moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/preserve-permissions.sh +19 -0
  179. moai_adk/templates/.claude/skills/moai-cc-hooks/scripts/validate-bash-command.py +24 -0
  180. moai_adk/templates/.claude/skills/moai-cc-mcp-plugins/SKILL.md +199 -0
  181. moai_adk/templates/.claude/skills/moai-cc-mcp-plugins/templates/settings-mcp-template.json +39 -0
  182. moai_adk/templates/.claude/skills/moai-cc-memory/SKILL.md +316 -0
  183. moai_adk/templates/.claude/skills/moai-cc-memory/templates/session-summary-template.md +18 -0
  184. moai_adk/templates/.claude/skills/moai-cc-settings/SKILL.md +263 -0
  185. moai_adk/templates/.claude/skills/moai-cc-settings/templates/settings-complete-template.json +30 -0
  186. moai_adk/templates/.claude/skills/moai-cc-skill-factory/CHECKLIST.md +482 -0
  187. moai_adk/templates/.claude/skills/moai-cc-skill-factory/EXAMPLES.md +303 -0
  188. moai_adk/templates/.claude/skills/moai-cc-skill-factory/INTERACTIVE-DISCOVERY.md +524 -0
  189. moai_adk/templates/.claude/skills/moai-cc-skill-factory/METADATA.md +477 -0
  190. moai_adk/templates/.claude/skills/moai-cc-skill-factory/PARALLEL-ANALYSIS-REPORT.md +429 -0
  191. moai_adk/templates/.claude/skills/moai-cc-skill-factory/PYTHON-VERSION-MATRIX.md +391 -0
  192. moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL-FACTORY-WORKFLOW.md +431 -0
  193. moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL-UPDATE-ADVISOR.md +577 -0
  194. moai_adk/templates/.claude/skills/moai-cc-skill-factory/SKILL.md +273 -0
  195. moai_adk/templates/.claude/skills/moai-cc-skill-factory/STEP-BY-STEP-GUIDE.md +466 -0
  196. moai_adk/templates/.claude/skills/moai-cc-skill-factory/STRUCTURE.md +583 -0
  197. moai_adk/templates/.claude/skills/moai-cc-skill-factory/WEB-RESEARCH.md +526 -0
  198. moai_adk/templates/.claude/skills/moai-cc-skill-factory/reference.md +608 -0
  199. moai_adk/templates/.claude/skills/moai-cc-skill-factory/scripts/generate-structure.sh +328 -0
  200. moai_adk/templates/.claude/skills/moai-cc-skill-factory/scripts/validate-skill.sh +312 -0
  201. moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/SKILL_TEMPLATE.md +245 -0
  202. moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/examples-template.md +285 -0
  203. moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/reference-template.md +278 -0
  204. moai_adk/templates/.claude/skills/moai-cc-skill-factory/templates/scripts-template.sh +303 -0
  205. moai_adk/templates/.claude/skills/moai-cc-skills/SKILL.md +291 -0
  206. moai_adk/templates/.claude/skills/moai-cc-skills/templates/SKILL-template.md +15 -0
  207. moai_adk/templates/.claude/skills/moai-change-logger/SKILL.md +563 -0
  208. moai_adk/templates/.claude/skills/moai-design-systems/SKILL.md +802 -0
  209. moai_adk/templates/.claude/skills/moai-design-systems/examples.md +1238 -0
  210. moai_adk/templates/.claude/skills/moai-design-systems/reference.md +673 -0
  211. moai_adk/templates/.claude/skills/moai-domain-backend/SKILL.md +234 -43
  212. moai_adk/templates/.claude/skills/moai-domain-backend/examples.md +1633 -0
  213. moai_adk/templates/.claude/skills/moai-domain-backend/reference.md +660 -0
  214. moai_adk/templates/.claude/skills/moai-domain-cli-tool/SKILL.md +97 -69
  215. moai_adk/templates/.claude/skills/moai-domain-cli-tool/examples.md +29 -0
  216. moai_adk/templates/.claude/skills/moai-domain-cli-tool/reference.md +30 -0
  217. moai_adk/templates/.claude/skills/moai-domain-data-science/SKILL.md +97 -72
  218. moai_adk/templates/.claude/skills/moai-domain-data-science/examples.md +29 -0
  219. moai_adk/templates/.claude/skills/moai-domain-data-science/reference.md +30 -0
  220. moai_adk/templates/.claude/skills/moai-domain-database/SKILL.md +97 -74
  221. moai_adk/templates/.claude/skills/moai-domain-database/examples.md +29 -0
  222. moai_adk/templates/.claude/skills/moai-domain-database/reference.md +30 -0
  223. moai_adk/templates/.claude/skills/moai-domain-devops/SKILL.md +98 -74
  224. moai_adk/templates/.claude/skills/moai-domain-devops/examples.md +29 -0
  225. moai_adk/templates/.claude/skills/moai-domain-devops/reference.md +31 -0
  226. moai_adk/templates/.claude/skills/moai-domain-frontend/SKILL.md +102 -73
  227. moai_adk/templates/.claude/skills/moai-domain-frontend/examples.md +29 -0
  228. moai_adk/templates/.claude/skills/moai-domain-frontend/reference.md +31 -0
  229. moai_adk/templates/.claude/skills/moai-domain-ml/SKILL.md +97 -73
  230. moai_adk/templates/.claude/skills/moai-domain-ml/examples.md +29 -0
  231. moai_adk/templates/.claude/skills/moai-domain-ml/reference.md +30 -0
  232. moai_adk/templates/.claude/skills/moai-domain-mobile-app/SKILL.md +97 -67
  233. moai_adk/templates/.claude/skills/moai-domain-mobile-app/examples.md +29 -0
  234. moai_adk/templates/.claude/skills/moai-domain-mobile-app/reference.md +30 -0
  235. moai_adk/templates/.claude/skills/moai-domain-security/SKILL.md +97 -79
  236. moai_adk/templates/.claude/skills/moai-domain-security/examples.md +29 -0
  237. moai_adk/templates/.claude/skills/moai-domain-security/reference.md +30 -0
  238. moai_adk/templates/.claude/skills/moai-domain-web-api/SKILL.md +97 -71
  239. moai_adk/templates/.claude/skills/moai-domain-web-api/examples.md +29 -0
  240. moai_adk/templates/.claude/skills/moai-domain-web-api/reference.md +30 -0
  241. moai_adk/templates/.claude/skills/moai-essentials-debug/SKILL.md +265 -64
  242. moai_adk/templates/.claude/skills/moai-essentials-debug/examples.md +1064 -0
  243. moai_adk/templates/.claude/skills/moai-essentials-debug/reference.md +1047 -0
  244. moai_adk/templates/.claude/skills/moai-essentials-perf/SKILL.md +87 -78
  245. moai_adk/templates/.claude/skills/moai-essentials-perf/examples.md +29 -0
  246. moai_adk/templates/.claude/skills/moai-essentials-perf/reference.md +28 -0
  247. moai_adk/templates/.claude/skills/moai-essentials-refactor/SKILL.md +87 -70
  248. moai_adk/templates/.claude/skills/moai-essentials-refactor/examples.md +29 -0
  249. moai_adk/templates/.claude/skills/moai-essentials-refactor/reference.md +28 -0
  250. moai_adk/templates/.claude/skills/moai-essentials-review/SKILL.md +87 -86
  251. moai_adk/templates/.claude/skills/moai-essentials-review/examples.md +29 -0
  252. moai_adk/templates/.claude/skills/moai-essentials-review/reference.md +28 -0
  253. moai_adk/templates/.claude/skills/moai-foundation-ears/SKILL.md +80 -62
  254. moai_adk/templates/.claude/skills/moai-foundation-ears/examples.md +29 -0
  255. moai_adk/templates/.claude/skills/moai-foundation-ears/reference.md +28 -0
  256. moai_adk/templates/.claude/skills/moai-foundation-git/SKILL.md +207 -50
  257. moai_adk/templates/.claude/skills/moai-foundation-git/examples.md +29 -0
  258. moai_adk/templates/.claude/skills/moai-foundation-git/reference.md +29 -0
  259. moai_adk/templates/.claude/skills/moai-foundation-langs/SKILL.md +90 -71
  260. moai_adk/templates/.claude/skills/moai-foundation-langs/examples.md +29 -0
  261. moai_adk/templates/.claude/skills/moai-foundation-langs/reference.md +28 -0
  262. moai_adk/templates/.claude/skills/moai-foundation-specs/SKILL.md +78 -58
  263. moai_adk/templates/.claude/skills/moai-foundation-specs/examples.md +29 -0
  264. moai_adk/templates/.claude/skills/moai-foundation-specs/reference.md +28 -0
  265. moai_adk/templates/.claude/skills/moai-foundation-tags/SKILL.md +78 -51
  266. moai_adk/templates/.claude/skills/moai-foundation-tags/examples.md +29 -0
  267. moai_adk/templates/.claude/skills/moai-foundation-tags/reference.md +28 -0
  268. moai_adk/templates/.claude/skills/moai-foundation-trust/.!11330!examples.md +0 -0
  269. moai_adk/templates/.claude/skills/moai-foundation-trust/SKILL.md +253 -32
  270. moai_adk/templates/.claude/skills/moai-foundation-trust/examples.md +0 -0
  271. moai_adk/templates/.claude/skills/moai-foundation-trust/reference.md +1099 -0
  272. moai_adk/templates/.claude/skills/moai-jit-docs-enhanced/SKILL.md +460 -0
  273. moai_adk/templates/.claude/skills/moai-lang-c/SKILL.md +98 -74
  274. moai_adk/templates/.claude/skills/moai-lang-c/examples.md +29 -0
  275. moai_adk/templates/.claude/skills/moai-lang-c/reference.md +31 -0
  276. moai_adk/templates/.claude/skills/moai-lang-cpp/SKILL.md +98 -76
  277. moai_adk/templates/.claude/skills/moai-lang-cpp/examples.md +29 -0
  278. moai_adk/templates/.claude/skills/moai-lang-cpp/reference.md +31 -0
  279. moai_adk/templates/.claude/skills/moai-lang-csharp/SKILL.md +2358 -70
  280. moai_adk/templates/.claude/skills/moai-lang-csharp/examples.md +29 -0
  281. moai_adk/templates/.claude/skills/moai-lang-csharp/reference.md +30 -0
  282. moai_adk/templates/.claude/skills/moai-lang-dart/SKILL.md +2962 -68
  283. moai_adk/templates/.claude/skills/moai-lang-dart/examples.md +29 -0
  284. moai_adk/templates/.claude/skills/moai-lang-dart/reference.md +30 -0
  285. moai_adk/templates/.claude/skills/moai-lang-go/SKILL.md +1898 -70
  286. moai_adk/templates/.claude/skills/moai-lang-go/examples.md +29 -0
  287. moai_adk/templates/.claude/skills/moai-lang-go/reference.md +31 -0
  288. moai_adk/templates/.claude/skills/moai-lang-java/SKILL.md +1465 -68
  289. moai_adk/templates/.claude/skills/moai-lang-java/examples.md +29 -0
  290. moai_adk/templates/.claude/skills/moai-lang-java/reference.md +31 -0
  291. moai_adk/templates/.claude/skills/moai-lang-javascript/SKILL.md +2364 -66
  292. moai_adk/templates/.claude/skills/moai-lang-javascript/examples.md +29 -0
  293. moai_adk/templates/.claude/skills/moai-lang-javascript/reference.md +32 -0
  294. moai_adk/templates/.claude/skills/moai-lang-kotlin/SKILL.md +1630 -69
  295. moai_adk/templates/.claude/skills/moai-lang-kotlin/examples.md +29 -0
  296. moai_adk/templates/.claude/skills/moai-lang-kotlin/reference.md +31 -0
  297. moai_adk/templates/.claude/skills/moai-lang-php/SKILL.md +89 -61
  298. moai_adk/templates/.claude/skills/moai-lang-php/examples.md +29 -0
  299. moai_adk/templates/.claude/skills/moai-lang-php/reference.md +30 -0
  300. moai_adk/templates/.claude/skills/moai-lang-python/SKILL.md +735 -66
  301. moai_adk/templates/.claude/skills/moai-lang-python/examples.md +624 -0
  302. moai_adk/templates/.claude/skills/moai-lang-python/reference.md +316 -0
  303. moai_adk/templates/.claude/skills/moai-lang-r/SKILL.md +97 -73
  304. moai_adk/templates/.claude/skills/moai-lang-r/examples.md +29 -0
  305. moai_adk/templates/.claude/skills/moai-lang-r/reference.md +30 -0
  306. moai_adk/templates/.claude/skills/moai-lang-ruby/SKILL.md +98 -73
  307. moai_adk/templates/.claude/skills/moai-lang-ruby/examples.md +29 -0
  308. moai_adk/templates/.claude/skills/moai-lang-ruby/reference.md +31 -0
  309. moai_adk/templates/.claude/skills/moai-lang-rust/SKILL.md +1834 -70
  310. moai_adk/templates/.claude/skills/moai-lang-rust/examples.md +29 -0
  311. moai_adk/templates/.claude/skills/moai-lang-rust/reference.md +31 -0
  312. moai_adk/templates/.claude/skills/moai-lang-scala/SKILL.md +99 -74
  313. moai_adk/templates/.claude/skills/moai-lang-scala/examples.md +29 -0
  314. moai_adk/templates/.claude/skills/moai-lang-scala/reference.md +30 -0
  315. moai_adk/templates/.claude/skills/moai-lang-shell/SKILL.md +97 -74
  316. moai_adk/templates/.claude/skills/moai-lang-shell/examples.md +29 -0
  317. moai_adk/templates/.claude/skills/moai-lang-shell/reference.md +30 -0
  318. moai_adk/templates/.claude/skills/moai-lang-sql/SKILL.md +98 -74
  319. moai_adk/templates/.claude/skills/moai-lang-sql/examples.md +29 -0
  320. moai_adk/templates/.claude/skills/moai-lang-sql/reference.md +31 -0
  321. moai_adk/templates/.claude/skills/moai-lang-swift/SKILL.md +1959 -69
  322. moai_adk/templates/.claude/skills/moai-lang-swift/examples.md +29 -0
  323. moai_adk/templates/.claude/skills/moai-lang-swift/reference.md +30 -0
  324. moai_adk/templates/.claude/skills/moai-lang-template/SKILL.md +348 -0
  325. moai_adk/templates/.claude/skills/moai-lang-template/VARIABLES.md +98 -0
  326. moai_adk/templates/.claude/skills/moai-lang-typescript/SKILL.md +1230 -66
  327. moai_adk/templates/.claude/skills/moai-lang-typescript/examples.md +29 -0
  328. moai_adk/templates/.claude/skills/moai-lang-typescript/reference.md +34 -0
  329. moai_adk/templates/.claude/skills/moai-learning-optimizer/SKILL.md +575 -0
  330. moai_adk/templates/.claude/skills/moai-project-batch-questions/README.md +50 -0
  331. moai_adk/templates/.claude/skills/moai-project-batch-questions/SKILL.md +304 -0
  332. moai_adk/templates/.claude/skills/moai-project-batch-questions/examples.md +417 -0
  333. moai_adk/templates/.claude/skills/moai-project-batch-questions/reference.md +704 -0
  334. moai_adk/templates/.claude/skills/moai-project-config-manager/README.md +87 -0
  335. moai_adk/templates/.claude/skills/moai-project-config-manager/SKILL.md +552 -0
  336. moai_adk/templates/.claude/skills/moai-project-config-manager/examples.md +1109 -0
  337. moai_adk/templates/.claude/skills/moai-project-config-manager/reference.md +514 -0
  338. moai_adk/templates/.claude/skills/moai-project-config-manager/validate.py +106 -0
  339. moai_adk/templates/.claude/skills/moai-project-documentation/README.md +11 -0
  340. moai_adk/templates/.claude/skills/moai-project-documentation/SKILL.md +622 -0
  341. moai_adk/templates/.claude/skills/moai-project-documentation/examples.md +20 -0
  342. moai_adk/templates/.claude/skills/moai-project-documentation/reference.md +12 -0
  343. moai_adk/templates/.claude/skills/moai-project-language-initializer/README.md +152 -0
  344. moai_adk/templates/.claude/skills/moai-project-language-initializer/SKILL.md +285 -0
  345. moai_adk/templates/.claude/skills/moai-project-language-initializer/examples.md +333 -0
  346. moai_adk/templates/.claude/skills/moai-project-language-initializer/reference.md +386 -0
  347. moai_adk/templates/.claude/skills/moai-project-template-optimizer/README.md +49 -0
  348. moai_adk/templates/.claude/skills/moai-project-template-optimizer/SKILL.md +319 -0
  349. moai_adk/templates/.claude/skills/moai-project-template-optimizer/examples.md +58 -0
  350. moai_adk/templates/.claude/skills/moai-project-template-optimizer/reference.md +123 -0
  351. moai_adk/templates/.claude/skills/moai-session-info/SKILL.md +314 -0
  352. moai_adk/templates/.claude/skills/moai-streaming-ui/SKILL.md +552 -0
  353. moai_adk/templates/.claude/skills/moai-tag-policy-validator/SKILL.md +570 -0
  354. moai_adk/templates/.git-hooks/pre-commit +66 -0
  355. moai_adk/templates/.git-hooks/pre-push +255 -0
  356. moai_adk/templates/.github/workflows/c-tag-validation.yml +11 -0
  357. moai_adk/templates/.github/workflows/cpp-tag-validation.yml +11 -0
  358. moai_adk/templates/.github/workflows/csharp-tag-validation.yml +11 -0
  359. moai_adk/templates/.github/workflows/dart-tag-validation.yml +11 -0
  360. moai_adk/templates/.github/workflows/go-tag-validation.yml +130 -0
  361. moai_adk/templates/.github/workflows/java-tag-validation.yml +11 -0
  362. moai_adk/templates/.github/workflows/javascript-tag-validation.yml +135 -0
  363. moai_adk/templates/.github/workflows/kotlin-tag-validation.yml +11 -0
  364. moai_adk/templates/.github/workflows/moai-gitflow.yml +166 -3
  365. moai_adk/templates/.github/workflows/moai-release-create.yml +100 -0
  366. moai_adk/templates/.github/workflows/moai-release-pipeline.yml +188 -0
  367. moai_adk/templates/.github/workflows/php-tag-validation.yml +11 -0
  368. moai_adk/templates/.github/workflows/python-tag-validation.yml +118 -0
  369. moai_adk/templates/.github/workflows/release.yml +118 -0
  370. moai_adk/templates/.github/workflows/ruby-tag-validation.yml +11 -0
  371. moai_adk/templates/.github/workflows/rust-tag-validation.yml +11 -0
  372. moai_adk/templates/.github/workflows/shell-tag-validation.yml +11 -0
  373. moai_adk/templates/.github/workflows/spec-issue-sync.yml +338 -0
  374. moai_adk/templates/.github/workflows/swift-tag-validation.yml +11 -0
  375. moai_adk/templates/.github/workflows/tag-report.yml +269 -0
  376. moai_adk/templates/.github/workflows/tag-validation.yml +186 -0
  377. moai_adk/templates/.github/workflows/typescript-tag-validation.yml +154 -0
  378. moai_adk/templates/.mcp.json +31 -0
  379. moai_adk/templates/.moai/config.json +80 -7
  380. moai_adk/templates/CLAUDE.md +562 -546
  381. moai_adk/utils/banner.py +5 -5
  382. moai_adk/utils/common.py +294 -0
  383. moai_adk/utils/link_validator.py +235 -0
  384. moai_adk/utils/logger.py +8 -8
  385. moai_adk/utils/user_experience.py +451 -0
  386. moai_adk-0.20.1.dist-info/METADATA +233 -0
  387. moai_adk-0.20.1.dist-info/RECORD +404 -0
  388. moai_adk/templates/.claude/hooks/alfred/README.md +0 -230
  389. moai_adk/templates/.claude/hooks/alfred/alfred_hooks.py +0 -156
  390. moai_adk/templates/.claude/hooks/alfred/core/__init__.py +0 -85
  391. moai_adk/templates/.claude/hooks/alfred/handlers/notification.py +0 -25
  392. moai_adk/templates/.claude/hooks/alfred/handlers/session.py +0 -92
  393. moai_adk/templates/.claude/hooks/alfred/handlers/tool.py +0 -70
  394. moai_adk/templates/.claude/hooks/alfred/handlers/user.py +0 -41
  395. moai_adk/templates/.claude/output-styles/alfred/agentic-coding.md +0 -636
  396. moai_adk/templates/.claude/output-styles/alfred/moai-adk-learning.md +0 -692
  397. moai_adk/templates/.claude/output-styles/alfred/study-with-alfred.md +0 -470
  398. moai_adk/templates/.claude/skills/moai-alfred-debugger-pro/SKILL.md +0 -103
  399. moai_adk/templates/.claude/skills/moai-alfred-ears-authoring/SKILL.md +0 -103
  400. moai_adk/templates/.claude/skills/moai-alfred-git-workflow/SKILL.md +0 -95
  401. moai_adk/templates/.claude/skills/moai-alfred-performance-optimizer/SKILL.md +0 -105
  402. moai_adk/templates/.claude/skills/moai-alfred-refactoring-coach/SKILL.md +0 -97
  403. moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-validation/SKILL.md +0 -97
  404. moai_adk/templates/.claude/skills/moai-alfred-tag-scanning/SKILL.md +0 -90
  405. moai_adk/templates/.claude/skills/moai-alfred-trust-validation/SKILL.md +0 -99
  406. moai_adk/templates/.claude/skills/moai-alfred-tui-survey/SKILL.md +0 -87
  407. moai_adk/templates/.claude/skills/moai-alfred-tui-survey/examples.md +0 -62
  408. moai_adk/templates/.claude/skills/moai-claude-code/SKILL.md +0 -94
  409. moai_adk/templates/.claude/skills/moai-claude-code/examples.md +0 -513
  410. moai_adk/templates/.claude/skills/moai-claude-code/reference.md +0 -433
  411. moai_adk/templates/.claude/skills/moai-claude-code/templates/agent-full.md +0 -332
  412. moai_adk/templates/.claude/skills/moai-claude-code/templates/command-full.md +0 -384
  413. moai_adk/templates/.claude/skills/moai-claude-code/templates/plugin-full.json +0 -363
  414. moai_adk/templates/.claude/skills/moai-claude-code/templates/settings-full.json +0 -595
  415. moai_adk/templates/.claude/skills/moai-claude-code/templates/skill-full.md +0 -496
  416. moai_adk/templates/.claude/skills/moai-lang-clojure/SKILL.md +0 -100
  417. moai_adk/templates/.claude/skills/moai-lang-elixir/SKILL.md +0 -99
  418. moai_adk/templates/.claude/skills/moai-lang-haskell/SKILL.md +0 -100
  419. moai_adk/templates/.claude/skills/moai-lang-julia/SKILL.md +0 -98
  420. moai_adk/templates/.claude/skills/moai-lang-lua/SKILL.md +0 -98
  421. moai_adk/templates/.github/PULL_REQUEST_TEMPLATE.md +0 -69
  422. moai_adk/templates/.moai/memory/development-guide.md +0 -344
  423. moai_adk/templates/.moai/memory/gitflow-protection-policy.md +0 -220
  424. moai_adk/templates/.moai/memory/spec-metadata.md +0 -356
  425. moai_adk/templates/.moai/project/product.md +0 -161
  426. moai_adk/templates/.moai/project/structure.md +0 -156
  427. moai_adk/templates/.moai/project/tech.md +0 -227
  428. moai_adk/templates/__init__.py +0 -2
  429. moai_adk-0.4.5.dist-info/METADATA +0 -369
  430. moai_adk-0.4.5.dist-info/RECORD +0 -152
  431. {moai_adk-0.4.5.dist-info → moai_adk-0.20.1.dist-info}/WHEEL +0 -0
  432. {moai_adk-0.4.5.dist-info → moai_adk-0.20.1.dist-info}/entry_points.txt +0 -0
  433. {moai_adk-0.4.5.dist-info → moai_adk-0.20.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,99 +1,1989 @@
1
1
  ---
2
-
3
2
  name: moai-lang-swift
4
- description: Swift best practices with XCTest, SwiftLint, and iOS/macOS development patterns. Use when writing or reviewing Swift code in project workflows.
3
+ version: 2.0.0
4
+ created: 2025-11-06
5
+ updated: 2025-11-06
6
+ status: active
7
+ description: "Swift best practices with SwiftUI, iOS development, Swift Concurrency, and server-side Swift for 2025"
8
+ keywords: [swift, programming, ios, swiftui, server-side, concurrency, vapor, mobile]
5
9
  allowed-tools:
6
10
  - Read
11
+ - Write
12
+ - Edit
7
13
  - Bash
14
+ - WebFetch
15
+ - WebSearch
8
16
  ---
9
17
 
10
- # Swift Expert
18
+ # Swift Development Mastery
19
+
20
+ **Modern Swift Development with 2025 Best Practices**
21
+
22
+ > Comprehensive Swift development guidance covering iOS/macOS applications with SwiftUI, Swift Concurrency, server-side development with Vapor, and cross-platform Swift applications using the latest tools and frameworks.
23
+
24
+ ## What It Does
25
+
26
+ ### iOS/macOS Development
27
+ - **Mobile App Development**: SwiftUI with modern declarative UI patterns, MVVM architecture
28
+ - **Platform Integration**: Core Data, Core Location, Camera, Push Notifications, Background Tasks
29
+ - **Performance Optimization**: Memory management, battery optimization, SwiftUI performance
30
+ - **Testing**: Unit tests, UI tests, performance tests with XCTest framework
11
31
 
12
- ## Skill Metadata
13
- | Field | Value |
14
- | ----- | ----- |
15
- | Allowed tools | Read (read_file), Bash (terminal) |
16
- | Auto-load | On demand when language keywords are detected |
17
- | Trigger cues | Swift code discussions, framework guidance, or file extensions such as .swift. |
18
- | Tier | 3 |
32
+ ### Server-Side Development
33
+ - **API Development**: Vapor 4, Hummingbird, or Perfect for backend services
34
+ - **Database Integration**: Fluent ORM, PostgreSQL, MongoDB with async/await
35
+ - **Real-time Communication**: WebSockets, Server-Sent Events with Swift Concurrency
36
+ - **Testing**: XCTVapor, Mocking libraries, integration testing
19
37
 
20
- ## What it does
38
+ ### Cross-Platform Development
39
+ - **SwiftUI for Multiple Platforms**: iOS, iPadOS, macOS, watchOS, visionOS
40
+ - **Shared Codebases**: Swift Package Manager, custom frameworks
41
+ - **Platform-Specific Optimizations**: Conditional compilation, platform APIs
21
42
 
22
- Provides Swift-specific expertise for TDD development, including XCTest framework, SwiftLint linting, Swift Package Manager, and iOS/macOS platform patterns.
43
+ ## When to Use
23
44
 
24
- ## When to use
45
+ ### Perfect Scenarios
46
+ - **Building iOS and iPadOS applications with SwiftUI**
47
+ - **Developing macOS applications with modern Swift patterns**
48
+ - **Creating server-side APIs with Swift**
49
+ - **Implementing cross-platform Swift applications**
50
+ - **Building real-time applications with Swift Concurrency**
51
+ - **Developing watchOS and visionOS applications**
52
+ - **Creating Swift frameworks and libraries**
25
53
 
26
- - Engages when the conversation references Swift work, frameworks, or files like .swift.
27
- - “Writing Swift tests”, “How to use XCTest”, “iOS patterns”
28
- - Automatically invoked when working with Swift/iOS projects
29
- - Swift SPEC implementation (`/alfred:2-run`)
54
+ ### Common Triggers
55
+ - "Create iOS app with Swift"
56
+ - "Build SwiftUI application"
57
+ - "Develop Swift backend API"
58
+ - "Implement Swift Concurrency"
59
+ - "Optimize Swift performance"
60
+ - "Test Swift application"
61
+ - "Swift best practices"
30
62
 
31
- ## How it works
63
+ ## Tool Version Matrix (2025-11-06)
32
64
 
33
- **TDD Framework**:
34
- - **XCTest**: Apple's native testing framework
35
- - **Quick/Nimble**: BDD-style testing (alternative)
36
- - **XCUITest**: UI testing for iOS/macOS apps
37
- - Test coverage with Xcode Code Coverage
65
+ ### Core Swift
66
+ - **Swift**: 6.0 (current) / 5.10 (LTS)
67
+ - **Xcode**: 16.1 (current) / 15.4 (LTS)
68
+ - **Swift Package Manager**: Built-in with Swift 6.0
69
+ - **Platforms**: iOS 18+, iPadOS 18+, macOS 15+, watchOS 11+, visionOS 2+
38
70
 
39
- **Code Quality**:
40
- - **SwiftLint**: Swift linter and style checker
41
- - **SwiftFormat**: Code formatting tool
42
- - **Xcode Analyzer**: Static code analysis
71
+ ### UI Frameworks
72
+ - **SwiftUI**: iOS 18.0, macOS 15.0
73
+ - **UIKit**: iOS 17.0+ (legacy support)
74
+ - **AppKit**: macOS 14.0+ (legacy support)
75
+ - **Combine**: iOS 13.0+, macOS 10.15+
43
76
 
44
- **Package Management**:
45
- - **Swift Package Manager (SPM)**: Dependency management
46
- - **CocoaPods**: Alternative package manager (legacy)
47
- - **Carthage**: Decentralized dependency manager
77
+ ### Server-Side Frameworks
78
+ - **Vapor**: 4.93.x - Web framework
79
+ - **Hummingbird**: 2.2.x - Lightweight web framework
80
+ - **Fluent**: 4.8.x - ORM for Vapor
81
+ - **PostgresNIO**: 2.12.x - PostgreSQL driver
82
+ - **MongoKitten**: 7.0.x - MongoDB driver
48
83
 
49
- **Swift Patterns**:
50
- - **Optionals**: Safe handling of nil values (?, !)
51
- - **Guard statements**: Early exit patterns
52
- - **Protocol-oriented programming**: Protocols over inheritance
53
- - **Value types**: Prefer structs over classes
54
- - **Closures**: First-class functions
84
+ ### Testing Tools
85
+ - **XCTest**: Built-in testing framework
86
+ - **XCUITest**: UI testing framework
87
+ - **Quick/Nimble**: BDD-style testing
88
+ - **XCTVapor**: Vapor testing utilities
55
89
 
56
- **iOS/macOS Patterns**:
57
- - **SwiftUI**: Declarative UI framework
58
- - **Combine**: Reactive programming
59
- - **UIKit/AppKit**: Traditional UI frameworks
60
- - **MVVM/MVC**: Architecture patterns
90
+ ### Development Tools
91
+ - **SwiftLint**: 0.54.x - Code style enforcement
92
+ - **SwiftFormat**: 0.53.x - Code formatting
93
+ - **Periphery**: 2.10.x - Unused code detection
94
+
95
+ ## Ecosystem Overview
96
+
97
+ ### Package Management
61
98
 
62
- ## Examples
63
99
  ```bash
64
- swift test && swift-format --lint --recursive Sources
100
+ # Swift Package Manager initialization
101
+ swift package init --type executable
102
+ swift package init --type library
103
+
104
+ # Adding dependencies
105
+ swift package add dependency https://github.com/vapor/vapor.git --from 4.93.0
106
+ swift package add dependency https://github.com/Alamofire/Alamofire.git --from 5.9.0
107
+
108
+ # Building and testing
109
+ swift build
110
+ swift test
111
+ swift run
112
+
113
+ # Xcode project generation
114
+ swift package generate-xcodeproj
115
+ ```
116
+
117
+ ### Project Structure (2025 Best Practice)
118
+
119
+ ```
120
+ SwiftProject/
121
+ ├── Package.swift # SPM configuration
122
+ ├── Sources/
123
+ │ ├── App/ # Main application
124
+ │ │ ├── App.swift # Entry point
125
+ │ │ ├── ContentView.swift # Main view
126
+ │ │ └── AppState.swift # App state management
127
+ │ ├── Features/ # Feature modules
128
+ │ │ ├── Authentication/
129
+ │ │ │ ├── Models/
130
+ │ │ │ ├── Views/
131
+ │ │ │ ├── ViewModels/
132
+ │ │ │ └── Services/
133
+ │ │ └── UserProfile/
134
+ │ ├── Core/ # Core utilities
135
+ │ │ ├── Extensions/
136
+ │ │ ├── Protocols/
137
+ │ │ └── Utilities/
138
+ │ └── Shared/ # Shared code
139
+ │ ├── Models/
140
+ │ ├── Networking/
141
+ │ └── Database/
142
+ ├── Tests/
143
+ │ ├── AppTests/
144
+ │ ├── FeaturesTests/
145
+ │ └── IntegrationTests/
146
+ ├── Resources/ # Resources
147
+ │ ├── Assets.xcassets
148
+ │ ├── Localizable.strings
149
+ │ └── Configuration.plist
150
+ ├── .swiftlint.yml # SwiftLint configuration
151
+ ├── .swiftformat # SwiftFormat configuration
152
+ └── Package.resolved # Resolved dependencies
153
+ ```
154
+
155
+ ## Modern Development Patterns
156
+
157
+ ### Swift 6.0 Concurrency Patterns
158
+
159
+ ```swift
160
+ import Foundation
161
+ import SwiftConcurrency
162
+
163
+ // Async/await with structured concurrency
164
+ actor UserManager {
165
+ private var users: [String: User] = [:]
166
+
167
+ func addUser(_ user: User) async throws {
168
+ // Actor ensures thread-safe access
169
+ users[user.id] = user
170
+ }
171
+
172
+ func getUser(id: String) async -> User? {
173
+ return users[id]
174
+ }
175
+
176
+ func updateProfile(id: String, profile: UserProfile) async throws -> User {
177
+ guard var user = users[id] else {
178
+ throw UserError.notFound
179
+ }
180
+ user.profile = profile
181
+ users[id] = user
182
+ return user
183
+ }
184
+
185
+ // Async sequence for real-time updates
186
+ func userUpdates() -> AsyncStream<UserUpdate> {
187
+ AsyncStream { continuation in
188
+ let task = Task {
189
+ for await update in userUpdateChannel {
190
+ continuation.yield(update)
191
+ }
192
+ }
193
+
194
+ continuation.onTermination = { _ in
195
+ task.cancel()
196
+ }
197
+ }
198
+ }
199
+ }
200
+
201
+ // TaskGroup for concurrent operations
202
+ class DataProcessor {
203
+ func processItems(_ items: [DataItem]) async throws -> [ProcessedItem] {
204
+ return try await withThrowingTaskGroup(of: ProcessedItem.self) { group in
205
+ for item in items {
206
+ group.addTask {
207
+ return await self.processSingleItem(item)
208
+ }
209
+ }
210
+
211
+ var results: [ProcessedItem] = []
212
+ for try await result in group {
213
+ results.append(result)
214
+ }
215
+ return results
216
+ }
217
+ }
218
+
219
+ private func processSingleItem(_ item: DataItem) async -> ProcessedItem {
220
+ // Processing logic
221
+ return ProcessedItem(from: item)
222
+ }
223
+ }
224
+
225
+ // AsyncImage with SwiftUI
226
+ struct UserAvatarView: View {
227
+ let user: User
228
+
229
+ var body: some View {
230
+ AsyncImage(url: user.avatarURL) { image in
231
+ image
232
+ .resizable()
233
+ .aspectRatio(contentMode: .fill)
234
+ } placeholder: {
235
+ ProgressView()
236
+ .frame(width: 100, height: 100)
237
+ }
238
+ .frame(width: 100, height: 100)
239
+ .clipShape(Circle())
240
+ .overlay(
241
+ Circle()
242
+ .stroke(Color.blue, lineWidth: 2)
243
+ )
244
+ }
245
+ }
246
+
247
+ // AsyncStream for real-time data
248
+ class RealtimeDataService {
249
+ private let continuation: AsyncStream<DataUpdate>.Continuation
250
+
251
+ init() {
252
+ let (stream, continuation) = AsyncStream<DataUpdate>.makeStream()
253
+ self.continuation = continuation
254
+ }
255
+
256
+ var updates: AsyncStream<DataUpdate> {
257
+ AsyncStream { continuation in
258
+ let task = Task {
259
+ for await update in dataChannel {
260
+ continuation.yield(update)
261
+ }
262
+ }
263
+
264
+ continuation.onTermination = { _ in
265
+ task.cancel()
266
+ }
267
+ }
268
+ }
269
+
270
+ func sendUpdate(_ update: DataUpdate) {
271
+ continuation.yield(update)
272
+ }
273
+ }
274
+ ```
275
+
276
+ ### Modern SwiftUI Patterns
277
+
278
+ ```swift
279
+ import SwiftUI
280
+ import Combine
281
+
282
+ // MVVM with Observable macro
283
+ @Observable
284
+ class UserProfileViewModel {
285
+ var user: User?
286
+ var isLoading = false
287
+ var errorMessage: String?
288
+
289
+ private let userService: UserService
290
+ private var cancellables = Set<AnyCancellable>()
291
+
292
+ init(userService: UserService) {
293
+ self.userService = userService
294
+ }
295
+
296
+ func loadUser(id: String) async {
297
+ isLoading = true
298
+ errorMessage = nil
299
+
300
+ defer { isLoading = false }
301
+
302
+ do {
303
+ user = try await userService.getUser(id: id)
304
+ } catch {
305
+ errorMessage = error.localizedDescription
306
+ }
307
+ }
308
+
309
+ func updateUserProfile(_ profile: UserProfile) async {
310
+ guard let user = user else { return }
311
+
312
+ isLoading = true
313
+ errorMessage = nil
314
+
315
+ defer { isLoading = false }
316
+
317
+ do {
318
+ let updatedUser = try await userService.updateUser(id: user.id, profile: profile)
319
+ self.user = updatedUser
320
+ } catch {
321
+ errorMessage = error.localizedDescription
322
+ }
323
+ }
324
+ }
325
+
326
+ // Modern SwiftUI view with navigation
327
+ struct UserProfileView: View {
328
+ @State private var viewModel: UserProfileViewModel
329
+ @State private var showingEditSheet = false
330
+
331
+ init(userId: String, userService: UserService = .shared) {
332
+ _viewModel = State(initialValue: UserProfileViewModel(userService: userService))
333
+ }
334
+
335
+ var body: some View {
336
+ NavigationStack {
337
+ Group {
338
+ if let user = viewModel.user {
339
+ UserProfileContent(user: user, viewModel: viewModel)
340
+ } else if viewModel.isLoading {
341
+ LoadingView()
342
+ } else if let errorMessage = viewModel.errorMessage {
343
+ ErrorView(message: errorMessage) {
344
+ Task {
345
+ await viewModel.loadUser(id: userId)
346
+ }
347
+ }
348
+ } else {
349
+ EmptyStateView()
350
+ }
351
+ }
352
+ .navigationTitle("Profile")
353
+ .navigationBarTitleDisplayMode(.inline)
354
+ .toolbar {
355
+ ToolbarItem(placement: .navigationBarTrailing) {
356
+ Button("Edit") {
357
+ showingEditSheet = true
358
+ }
359
+ .disabled(viewModel.user == nil || viewModel.isLoading)
360
+ }
361
+ }
362
+ .sheet(isPresented: $showingEditSheet) {
363
+ if let user = viewModel.user {
364
+ EditProfileView(user: user) { profile in
365
+ Task {
366
+ await viewModel.updateUserProfile(profile)
367
+ }
368
+ }
369
+ }
370
+ }
371
+ .task {
372
+ if viewModel.user == nil {
373
+ await viewModel.loadUser(id: userId)
374
+ }
375
+ }
376
+ }
377
+ }
378
+ }
379
+
380
+ // Reusable view components
381
+ struct UserProfileContent: View {
382
+ let user: User
383
+ let viewModel: UserProfileViewModel
384
+
385
+ var body: some View {
386
+ ScrollView {
387
+ VStack(spacing: 24) {
388
+ // Avatar section
389
+ UserAvatarSection(user: user)
390
+
391
+ // Profile information
392
+ ProfileInfoSection(user: user)
393
+
394
+ // Statistics
395
+ UserStatsSection(user: user)
396
+
397
+ // Actions
398
+ UserActionsSection(user: user, viewModel: viewModel)
399
+ }
400
+ .padding()
401
+ }
402
+ }
403
+ }
404
+
405
+ struct UserAvatarSection: View {
406
+ let user: User
407
+
408
+ var body: some View {
409
+ VStack(spacing: 16) {
410
+ UserAvatarView(user: user)
411
+ .frame(width: 120, height: 120)
412
+
413
+ Text(user.name)
414
+ .font(.title2)
415
+ .fontWeight(.semibold)
416
+
417
+ Text("@\(user.username)")
418
+ .font(.body)
419
+ .foregroundColor(.secondary)
420
+ }
421
+ }
422
+ }
423
+
424
+ // Custom modifiers
425
+ struct ProfileCardStyle: ViewModifier {
426
+ func body(content: Content) -> some View {
427
+ content
428
+ .padding()
429
+ .background(Color(.systemBackground))
430
+ .cornerRadius(12)
431
+ .shadow(color: .black.opacity(0.1), radius: 4, x: 0, y: 2)
432
+ }
433
+ }
434
+
435
+ extension View {
436
+ func profileCardStyle() -> some View {
437
+ modifier(ProfileCardStyle())
438
+ }
439
+ }
440
+
441
+ // State management with Environment
442
+ @main
443
+ struct MyApp: App {
444
+ @State private var appState = AppState()
445
+
446
+ var body: some Scene {
447
+ WindowGroup {
448
+ ContentView()
449
+ .environment(appState)
450
+ }
451
+ }
452
+ }
453
+
454
+ // Observable app state
455
+ @Observable
456
+ class AppState {
457
+ var currentUser: User?
458
+ var isAuthenticated = false
459
+ var theme: Theme = .system
460
+
461
+ func login(user: User) {
462
+ currentUser = user
463
+ isAuthenticated = true
464
+ }
465
+
466
+ func logout() {
467
+ currentUser = nil
468
+ isAuthenticated = false
469
+ }
470
+ }
65
471
  ```
66
472
 
67
- ## Inputs
68
- - Language-specific source directories (e.g. `src/`, `app/`).
69
- - Language-specific build/test configuration files (e.g. `package.json`, `pyproject.toml`, `go.mod`).
70
- - Relevant test suites and sample data.
473
+ ### Server-Side Swift with Vapor
71
474
 
72
- ## Outputs
73
- - Test/lint execution plan tailored to the selected language.
74
- - List of key language idioms and review checkpoints.
475
+ ```swift
476
+ import Vapor
477
+ import Fluent
478
+ import PostgresNIO
75
479
 
76
- ## Failure Modes
77
- - When the language runtime or package manager is not installed.
78
- - When the main language cannot be determined in a multilingual project.
480
+ // User model with Fluent
481
+ final class User: Model, Content {
482
+ static let schema = "users"
483
+
484
+ @ID(key: .id)
485
+ var id: UUID?
486
+
487
+ @Field(key: "username")
488
+ var username: String
489
+
490
+ @Field(key: "email")
491
+ var email: String
492
+
493
+ @Field(key: "password_hash")
494
+ var passwordHash: String
495
+
496
+ @Timestamp(key: "created_at", on: .create)
497
+ var createdAt: Date?
498
+
499
+ @Timestamp(key: "updated_at", on: .update)
500
+ var updatedAt: Date?
501
+
502
+ @Children(for: \.$user)
503
+ var posts: [Post]
504
+
505
+ init() { }
506
+
507
+ init(id: UUID? = nil, username: String, email: String, passwordHash: String) {
508
+ self.id = id
509
+ self.username = username
510
+ self.email = email
511
+ self.passwordHash = passwordHash
512
+ }
513
+
514
+ // Public representation
515
+ struct Public: Content {
516
+ var id: UUID
517
+ var username: String
518
+ var email: String
519
+ var createdAt: Date?
520
+ var updatedAt: Date?
521
+ }
522
+
523
+ func convertToPublic() -> Public {
524
+ return Public(
525
+ id: id!,
526
+ username: username,
527
+ email: email,
528
+ createdAt: createdAt,
529
+ updatedAt: updatedAt
530
+ )
531
+ }
532
+ }
533
+
534
+ // Repository pattern with async/await
535
+ struct UserRepository {
536
+ let database: Database
537
+
538
+ func create(_ user: User) async throws -> User {
539
+ try await user.save(on: database)
540
+ return user
541
+ }
542
+
543
+ func findByID(_ id: UUID) async throws -> User? {
544
+ try await User.query(on: database)
545
+ .filter(\.$id == id)
546
+ .first()
547
+ }
548
+
549
+ func findByUsername(_ username: String) async throws -> User? {
550
+ try await User.query(on: database)
551
+ .filter(\.$username == username)
552
+ .first()
553
+ }
554
+
555
+ func findAll(page: Int, per: Int = 10) async throws -> [User] {
556
+ try await User.query(on: database)
557
+ .range(page * per ..< (page + 1) * per)
558
+ .all()
559
+ }
560
+ }
561
+
562
+ // Controllers with async routes
563
+ struct UserController: RouteCollection {
564
+ func boot(routes: RoutesBuilder) throws {
565
+ let users = routes.grouped("api/users")
566
+
567
+ users.get(use: index)
568
+ users.post(use: create)
569
+ users.get(":userID", use: show)
570
+ users.put(":userID", use: update)
571
+ users.delete(":userID", use: delete)
572
+ }
573
+
574
+ @Sendable
575
+ func index(req: Request) async throws -> [User.Public] {
576
+ let users = try await User.query(on: req.db).all()
577
+ return users.map { $0.convertToPublic() }
578
+ }
579
+
580
+ @Sendable
581
+ func create(req: Request) async throws -> User.Public {
582
+ let createUserData = try req.content.decode(CreateUser.self)
583
+
584
+ guard let passwordHash = try? await req.password.hash(createUserData.password) else {
585
+ throw Abort(.badRequest, reason: "Failed to hash password")
586
+ }
587
+
588
+ let user = User(
589
+ username: createUserData.username,
590
+ email: createUserData.email,
591
+ passwordHash: passwordHash
592
+ )
593
+
594
+ try await user.save(on: req.db)
595
+ return user.convertToPublic()
596
+ }
597
+
598
+ @Sendable
599
+ func show(req: Request) async throws -> User.Public {
600
+ guard let user = try await User.find(req.parameters.get("userID"), on: req.db) else {
601
+ throw Abort(.notFound)
602
+ }
603
+ return user.convertToPublic()
604
+ }
605
+
606
+ @Sendable
607
+ func update(req: Request) async throws -> User.Public {
608
+ guard let user = try await User.find(req.parameters.get("userID"), on: req.db) else {
609
+ throw Abort(.notFound)
610
+ }
611
+
612
+ let updateData = try req.content.decode(UpdateUser.self)
613
+ user.username = updateData.username ?? user.username
614
+ user.email = updateData.email ?? user.email
615
+
616
+ try await user.save(on: req.db)
617
+ return user.convertToPublic()
618
+ }
619
+
620
+ @Sendable
621
+ func delete(req: Request) async throws -> HTTPStatus {
622
+ guard let user = try await User.find(req.parameters.get("userID"), on: req.db) else {
623
+ throw Abort(.notFound)
624
+ }
625
+
626
+ try await user.delete(on: req.db)
627
+ return .noContent
628
+ }
629
+ }
630
+
631
+ // DTOs for request/response
632
+ struct CreateUser: Content {
633
+ var username: String
634
+ var email: String
635
+ var password: String
636
+ }
637
+
638
+ struct UpdateUser: Content {
639
+ var username: String?
640
+ var email: String?
641
+ }
642
+
643
+ // WebSocket support
644
+ struct WebSocketController: RouteCollection {
645
+ func boot(routes: RoutesBuilder) throws {
646
+ let websockets = routes.grouped("ws")
647
+ websockets.webSocket("chat", onUpgrade: handleChat)
648
+ }
649
+
650
+ func handleChat(req: Request, ws: WebSocket) async {
651
+ ws.onText { ws, text in
652
+ // Handle incoming message
653
+ do {
654
+ let message = try JSONDecoder().decode(ChatMessage.self, from: text.data(using: .utf8)!)
655
+
656
+ // Broadcast to all connected clients
657
+ await broadcastMessage(message)
658
+ } catch {
659
+ ws.close(code: .invalidData)
660
+ }
661
+ }
662
+
663
+ ws.onBinary { ws, data in
664
+ // Handle binary data
665
+ }
666
+
667
+ ws.onClose.whenComplete { _ in
668
+ // Handle connection close
669
+ }
670
+ }
671
+
672
+ private func broadcastMessage(_ message: ChatMessage) async {
673
+ // Implementation for broadcasting to all clients
674
+ }
675
+ }
676
+ ```
677
+
678
+ ### Swift Package Manager Configuration
679
+
680
+ ```swift
681
+ // Package.swift
682
+ // swift-tools-version: 6.0
683
+
684
+ import PackageDescription
685
+
686
+ let package = Package(
687
+ name: "MySwiftApp",
688
+ platforms: [
689
+ .iOS(.v18),
690
+ .macOS(.v15),
691
+ .watchOS(.v11),
692
+ .visionOS(.v2)
693
+ ],
694
+ products: [
695
+ .library(name: "MySwiftApp", targets: ["MySwiftApp"]),
696
+ .executable(name: "MyServer", targets: ["MyServer"])
697
+ ],
698
+ dependencies: [
699
+ // Networking
700
+ .package(url: "https://github.com/Alamofire/Alamofire.git", from: "5.9.0"),
701
+ .package(url: "https://github.com/vapor/vapor.git", from: "4.93.0"),
702
+
703
+ // Utilities
704
+ .package(url: "https://github.com/apple/swift-async-algorithms", from: "1.0.0"),
705
+ .package(url: "https://github.com/apple/swift-log.git", from: "1.6.0"),
706
+
707
+ // Testing
708
+ .package(url: "https://github.com/Quick/Quick.git", from: "7.3.0"),
709
+ .package(url: "https://github.com/Quick/Nimble.git", from: "13.3.0")
710
+ ],
711
+ targets: [
712
+ .target(
713
+ name: "MySwiftApp",
714
+ dependencies: [
715
+ .product(name: "Alamofire", package: "Alamofire"),
716
+ .product(name: "AsyncAlgorithms", package: "swift-async-algorithms"),
717
+ .product(name: "Logging", package: "swift-log")
718
+ ],
719
+ path: "Sources/MySwiftApp"
720
+ ),
721
+ .target(
722
+ name: "MyServer",
723
+ dependencies: [
724
+ .product(name: "Vapor", package: "vapor"),
725
+ .product(name: "Fluent", package: "vapor"),
726
+ .product(name: "FluentPostgresDriver", package: "vapor")
727
+ ],
728
+ path: "Sources/MyServer"
729
+ ),
730
+ .testTarget(
731
+ name: "MySwiftAppTests",
732
+ dependencies: [
733
+ "MySwiftApp",
734
+ "Quick",
735
+ "Nimble"
736
+ ],
737
+ path: "Tests/MySwiftAppTests"
738
+ ),
739
+ .testTarget(
740
+ name: "MyServerTests",
741
+ dependencies: [
742
+ "MyServer",
743
+ .product(name: "XCTVapor", package: "vapor")
744
+ ],
745
+ path: "Tests/MyServerTests"
746
+ )
747
+ ]
748
+ )
749
+ ```
750
+
751
+ ## Performance Considerations
752
+
753
+ ### Memory Management
754
+
755
+ ```swift
756
+ // Efficient memory usage with weak references
757
+ class ImageCache {
758
+ private var cache: [String: UIImage] = [:]
759
+ private let queue = DispatchQueue(label: "com.app.imagecache", attributes: .concurrent)
760
+
761
+ func setImage(_ image: UIImage, for key: String) {
762
+ queue.async(flags: .barrier) {
763
+ self.cache[key] = image
764
+ }
765
+ }
766
+
767
+ func getImage(for key: String) -> UIImage? {
768
+ return queue.sync {
769
+ return cache[key]
770
+ }
771
+ }
772
+
773
+ func clearCache() {
774
+ queue.async(flags: .barrier) {
775
+ self.cache.removeAll()
776
+ }
777
+ }
778
+ }
779
+
780
+ // Lazy loading and memory optimization
781
+ class DataViewController: UIViewController {
782
+ private lazy var dataLoader: DataLoader = {
783
+ return DataLoader(configuration: .default)
784
+ }()
785
+
786
+ private lazy var imageCache: NSCache<NSString, UIImage> = {
787
+ let cache = NSCache<NSString, UIImage>()
788
+ cache.countLimit = 100
789
+ cache.totalCostLimit = 1024 * 1024 * 50 // 50MB
790
+ return cache
791
+ }()
792
+
793
+ func loadImage(from url: URL) async -> UIImage? {
794
+ let key = url.absoluteString as NSString
795
+
796
+ if let cachedImage = imageCache.object(forKey: key) {
797
+ return cachedImage
798
+ }
799
+
800
+ do {
801
+ let (data, _) = try await dataLoader.data(from: url)
802
+ if let image = UIImage(data: data) {
803
+ imageCache.setObject(image, forKey: key)
804
+ return image
805
+ }
806
+ } catch {
807
+ print("Failed to load image: \(error)")
808
+ }
809
+
810
+ return nil
811
+ }
812
+ }
813
+
814
+ // Efficient data structures
815
+ class EfficientDataProcessor {
816
+ private var observations: [Observation] = []
817
+ private var processedData: ProcessedData?
818
+
819
+ // Use lazy evaluation for expensive computations
820
+ private lazy var statistics: Statistics = {
821
+ calculateStatistics(from: observations)
822
+ }()
823
+
824
+ func addObservation(_ observation: Observation) {
825
+ observations.append(observation)
826
+ // Invalidate cached data when underlying data changes
827
+ processedData = nil
828
+ }
829
+
830
+ var data: ProcessedData {
831
+ if let cached = processedData {
832
+ return cached
833
+ }
834
+
835
+ let result = processData(observations)
836
+ processedData = result
837
+ return result
838
+ }
839
+
840
+ var stats: Statistics {
841
+ return statistics
842
+ }
843
+
844
+ private func calculateStatistics(from observations: [Observation]) -> Statistics {
845
+ // Expensive calculation
846
+ return Statistics(observations: observations)
847
+ }
848
+
849
+ private func processData(_ observations: [Observation]) -> ProcessedData {
850
+ // Data processing logic
851
+ return ProcessedData(observations: observations)
852
+ }
853
+ }
854
+ ```
855
+
856
+ ### SwiftUI Performance Optimization
857
+
858
+ ```swift
859
+ // Performance optimizations for SwiftUI
860
+ struct OptimizedListView: View {
861
+ @State private var items: [Item] = []
862
+
863
+ var body: some View {
864
+ // Use OnAppear for data loading instead of init
865
+ List(items) { item in
866
+ ItemRow(item: item)
867
+ .id(item.id) // Stable identity for view recycling
868
+ }
869
+ .listStyle(.plain)
870
+ .onAppear {
871
+ loadItems()
872
+ }
873
+ }
874
+
875
+ private func loadItems() {
876
+ // Load data asynchronously
877
+ Task {
878
+ let loadedItems = await loadItemsFromAPI()
879
+
880
+ // Update UI on main thread
881
+ await MainActor.run {
882
+ items = loadedItems
883
+ }
884
+ }
885
+ }
886
+ }
887
+
888
+ struct ItemRow: View {
889
+ let item: Item
890
+
891
+ var body: some View {
892
+ HStack {
893
+ AsyncImage(url: item.imageURL) { image in
894
+ image
895
+ .resizable()
896
+ .aspectRatio(contentMode: .fill)
897
+ } placeholder: {
898
+ Color.gray.opacity(0.3)
899
+ }
900
+ .frame(width: 50, height: 50)
901
+ .clipped()
902
+
903
+ VStack(alignment: .leading, spacing: 4) {
904
+ Text(item.title)
905
+ .font(.headline)
906
+ .lineLimit(1)
907
+
908
+ Text(item.description)
909
+ .font(.body)
910
+ .foregroundColor(.secondary)
911
+ .lineLimit(2)
912
+ }
913
+
914
+ Spacer()
915
+ }
916
+ .padding(.vertical, 8)
917
+ }
918
+ }
919
+
920
+ // Efficient state management
921
+ @Observable
922
+ class PerformanceOptimizedViewModel {
923
+ // Use @Published sparingly and only when UI needs to react
924
+ @Published private(set) var items: [Item] = []
925
+ @Published var isLoading = false
926
+ @Published var error: Error?
927
+
928
+ private let service: APIService
929
+ private var currentPage = 0
930
+ private var hasMorePages = true
931
+
932
+ init(service: APIService) {
933
+ self.service = service
934
+ }
935
+
936
+ func loadMoreItems() async {
937
+ guard !isLoading, hasMorePages else { return }
938
+
939
+ isLoading = true
940
+
941
+ defer { isLoading = false }
942
+
943
+ do {
944
+ let newItems = try await service.fetchItems(page: currentPage + 1)
945
+
946
+ await MainActor.run {
947
+ items.append(contentsOf: newItems)
948
+ currentPage += 1
949
+ hasMorePages = !newItems.isEmpty
950
+ }
951
+ } catch {
952
+ await MainActor.run {
953
+ self.error = error
954
+ }
955
+ }
956
+ }
957
+
958
+ func refresh() async {
959
+ currentPage = 0
960
+ hasMorePages = true
961
+ items = []
962
+ error = nil
963
+
964
+ await loadMoreItems()
965
+ }
966
+ }
967
+ ```
968
+
969
+ ### Server-Side Performance
970
+
971
+ ```swift
972
+ // Connection pooling and optimization
973
+ final class DatabaseService {
974
+ private let pool: EventLoopGroupConnectionPool<PostgresConnectionSource>
975
+
976
+ init(configuration: PostgresConfiguration) {
977
+ let source = PostgresConnectionSource(configuration: configuration)
978
+ pool = EventLoopGroupConnectionPool(
979
+ source: source,
980
+ maxConnectionsPerEventLoop: 10,
981
+ on: MultiThreadedEventLoopGroup(numberOfThreads: 4)
982
+ )
983
+ }
984
+
985
+ func execute<T>(_ query: SQLQuery, on eventLoop: EventLoop) async throws -> [T] {
986
+ return try await withThrowingCheckedContinuation { continuation in
987
+ pool.withConnection(on: eventLoop) { connection in
988
+ connection.query(query)
989
+ .eachRow { row in
990
+ // Process each row
991
+ }
992
+ .flatMapThrowing { rows in
993
+ // Convert rows to result type
994
+ return rows.map { self.convertRow($0) }
995
+ }
996
+ .map { continuation.resume(returning: $0) }
997
+ .recover { continuation.resume(throwing: $0) }
998
+ }
999
+ }
1000
+ }
1001
+ }
1002
+
1003
+ // Caching with async/await
1004
+ actor CacheService {
1005
+ private var cache: [String: CacheEntry] = [:]
1006
+ private let cleanupTimer: Timer
1007
+
1008
+ init() {
1009
+ cleanupTimer = Timer.scheduledTimer(withTimeInterval: 300, repeats: true) { [weak self] _ in
1010
+ Task {
1011
+ await self?.cleanup()
1012
+ }
1013
+ }
1014
+ }
1015
+
1016
+ func get(_ key: String) async -> Data? {
1017
+ guard let entry = cache[key], !entry.isExpired else {
1018
+ return nil
1019
+ }
1020
+ return entry.data
1021
+ }
1022
+
1023
+ func set(_ data: Data, forKey key: String, ttl: TimeInterval = 3600) async {
1024
+ cache[key] = CacheEntry(data: data, expiresAt: Date().addingTimeInterval(ttl))
1025
+ }
1026
+
1027
+ private func cleanup() async {
1028
+ let expiredKeys = cache.compactMapValues { entry in
1029
+ entry.isExpired ? nil : entry
1030
+ }.keys
1031
+
1032
+ for key in expiredKeys {
1033
+ cache.removeValue(forKey: key)
1034
+ }
1035
+ }
1036
+
1037
+ struct CacheEntry {
1038
+ let data: Data
1039
+ let expiresAt: Date
1040
+
1041
+ var isExpired: Bool {
1042
+ Date() > expiresAt
1043
+ }
1044
+ }
1045
+ }
1046
+ ```
1047
+
1048
+ ## Testing Strategy
1049
+
1050
+ ### XCTest Configuration
1051
+
1052
+ ```swift
1053
+ // XCTest-based testing
1054
+ class UserServiceTests: XCTestCase {
1055
+ var userService: UserService!
1056
+ var mockAPIClient: MockAPIClient!
1057
+
1058
+ override func setUpWithError() throws {
1059
+ mockAPIClient = MockAPIClient()
1060
+ userService = UserService(apiClient: mockAPIClient)
1061
+ }
1062
+
1063
+ override func tearDownWithError() throws {
1064
+ userService = nil
1065
+ mockAPIClient = nil
1066
+ }
1067
+
1068
+ func testCreateUser_Success() async throws {
1069
+ // Given
1070
+ let userData = CreateUserData(username: "testuser", email: "test@example.com")
1071
+ let expectedUser = User(id: UUID(), username: "testuser", email: "test@example.com")
1072
+
1073
+ mockAPIClient.createUserResult = .success(expectedUser)
1074
+
1075
+ // When
1076
+ let result = try await userService.createUser(userData)
1077
+
1078
+ // Then
1079
+ XCTAssertEqual(result.id, expectedUser.id)
1080
+ XCTAssertEqual(result.username, expectedUser.username)
1081
+ XCTAssertEqual(result.email, expectedUser.email)
1082
+ XCTAssertEqual(mockAPIClient.createUserCallCount, 1)
1083
+ }
1084
+
1085
+ func testCreateUser_Failure() async {
1086
+ // Given
1087
+ let userData = CreateUserData(username: "testuser", email: "test@example.com")
1088
+ mockAPIClient.createUserResult = .failure(APIError.networkError)
1089
+
1090
+ // When & Then
1091
+ do {
1092
+ _ = try await userService.createUser(userData)
1093
+ XCTFail("Expected error to be thrown")
1094
+ } catch {
1095
+ XCTAssertTrue(error is APIError)
1096
+ }
1097
+ }
1098
+
1099
+ func testPerformanceLoadUsers() async throws {
1100
+ // Given
1101
+ let users = (0..<1000).map { User(id: UUID(), username: "user\($0)", email: "user\($0)@example.com") }
1102
+ mockAPIClient.loadUsersResult = .success(users)
1103
+
1104
+ // Measure performance
1105
+ measure {
1106
+ Task {
1107
+ _ = try! await userService.loadUsers()
1108
+ }
1109
+ }
1110
+ }
1111
+ }
1112
+
1113
+ // Mock objects for testing
1114
+ class MockAPIClient: APIClientProtocol {
1115
+ var createUserResult: Result<User, APIError>!
1116
+ var loadUsersResult: Result<[User], APIError>!
1117
+ var createUserCallCount = 0
1118
+
1119
+ func createUser(_ data: CreateUserData) async throws -> User {
1120
+ createUserCallCount += 1
1121
+ switch createUserResult {
1122
+ case .success(let user):
1123
+ return user
1124
+ case .failure(let error):
1125
+ throw error
1126
+ }
1127
+ }
1128
+
1129
+ func loadUsers() async throws -> [User] {
1130
+ switch loadUsersResult {
1131
+ case .success(let users):
1132
+ return users
1133
+ case .failure(let error):
1134
+ throw error
1135
+ }
1136
+ }
1137
+ }
1138
+
1139
+ // Quick/Nimble BDD-style testing
1140
+ import Quick
1141
+ import Nimble
1142
+
1143
+ class UserServiceSpec: QuickSpec {
1144
+ override func spec() {
1145
+ var userService: UserService!
1146
+ var mockAPIClient: MockAPIClient!
1147
+
1148
+ beforeEach {
1149
+ mockAPIClient = MockAPIClient()
1150
+ userService = UserService(apiClient: mockAPIClient)
1151
+ }
1152
+
1153
+ describe("createUser") {
1154
+ context("when API call succeeds") {
1155
+ it("should return the created user") {
1156
+ let userData = CreateUserData(username: "testuser", email: "test@example.com")
1157
+ let expectedUser = User(id: UUID(), username: "testuser", email: "test@example.com")
1158
+ mockAPIClient.createUserResult = .success(expectedUser)
1159
+
1160
+ waitUntil { done in
1161
+ Task {
1162
+ do {
1163
+ let result = try await userService.createUser(userData)
1164
+ expect(result.username).to(equal(expectedUser.username))
1165
+ expect(result.email).to(equal(expectedUser.email))
1166
+ done()
1167
+ } catch {
1168
+ fail("Unexpected error: \(error)")
1169
+ }
1170
+ }
1171
+ }
1172
+ }
1173
+ }
1174
+
1175
+ context("when API call fails") {
1176
+ it("should throw an error") {
1177
+ let userData = CreateUserData(username: "testuser", email: "test@example.com")
1178
+ mockAPIClient.createUserResult = .failure(APIError.networkError)
1179
+
1180
+ waitUntil { done in
1181
+ Task {
1182
+ do {
1183
+ _ = try await userService.createUser(userData)
1184
+ fail("Expected error to be thrown")
1185
+ } catch {
1186
+ expect(error).to(beAKindOf(APIError.self))
1187
+ done()
1188
+ }
1189
+ }
1190
+ }
1191
+ }
1192
+ }
1193
+ }
1194
+ }
1195
+ }
1196
+ ```
79
1197
 
80
- ## Dependencies
81
- - Access to the project file is required using the Read/Grep tool.
82
- - When used with `Skill("moai-foundation-langs")`, it is easy to share cross-language conventions.
1198
+ ### SwiftUI Testing
83
1199
 
84
- ## References
85
- - Apple. "Swift Programming Language Guide." https://docs.swift.org/swift-book/ (accessed 2025-03-29).
86
- - Apple. "Swift Package Manager." https://developer.apple.com/documentation/swift_packages (accessed 2025-03-29).
1200
+ ```swift
1201
+ import XCTest
1202
+ import SwiftUI
1203
+ @testable import MySwiftApp
87
1204
 
88
- ## Changelog
89
- - 2025-03-29: Input/output/failure response/reference information for each language has been specified.
1205
+ class UserProfileViewTests: XCTestCase {
1206
+
1207
+ func testUserProfileView_DisplaysUserInfo() {
1208
+ // Given
1209
+ let user = User(id: UUID(), username: "testuser", name: "Test User", email: "test@example.com")
1210
+ let userService = MockUserService()
1211
+ userService.mockUser = user
1212
+
1213
+ // When
1214
+ let view = UserProfileView(userId: user.id.uuidString, userService: userService)
1215
+
1216
+ // Then
1217
+ let hostingController = UIHostingController(rootView: view)
1218
+ hostingController.loadViewIfNeeded()
1219
+
1220
+ // Test view content
1221
+ // Note: This is a simplified example - in practice, you'd use view inspection or snapshot testing
1222
+ XCTAssertNotNil(hostingController.view)
1223
+ }
1224
+ }
90
1225
 
91
- ## Works well with
1226
+ // ViewInspector for SwiftUI testing (third-party library)
1227
+ import ViewInspector
1228
+
1229
+ extension UserProfileView: Inspectable { }
1230
+
1231
+ class UserProfileViewInspectorTests: XCTestCase {
1232
+
1233
+ func testUserProfileView_WhenLoaded_ShowsUserData() throws {
1234
+ // Given
1235
+ let user = User(id: UUID(), username: "testuser", name: "Test User", email: "test@example.com")
1236
+ let userService = MockUserService()
1237
+ userService.mockUser = user
1238
+
1239
+ // When
1240
+ let view = UserProfileView(userId: user.id.uuidString, userService: userService)
1241
+ let inspectedView = try view.inspect()
1242
+
1243
+ // Then
1244
+ let navigationStack = try inspectedView.navigationStack()
1245
+ let navigationTitle = try navigationStack.navigationBarTitleLabel().string()
1246
+ XCTAssertEqual(navigationTitle, "Profile")
1247
+ }
1248
+ }
1249
+ ```
1250
+
1251
+ ### Server-Side Testing
1252
+
1253
+ ```swift
1254
+ import XCTVapor
1255
+ import XCTest
1256
+ @testable import MyServer
1257
+
1258
+ final class UserControllerTests: XCTestCase {
1259
+
1260
+ func testCreateUser() async throws {
1261
+ let app = Application(.testing)
1262
+ try configure(app)
1263
+
1264
+ // Test data
1265
+ let userData = CreateUserData(username: "testuser", email: "test@example.com", password: "password123")
1266
+
1267
+ try app.test(.POST, "/api/users", beforeRequest: { req in
1268
+ try req.content.encode(userData)
1269
+ }, afterResponse: { res in
1270
+ XCTAssertEqual(res.status, .ok)
1271
+ let user = try res.content.decode(User.Public.self)
1272
+ XCTAssertEqual(user.username, "testuser")
1273
+ XCTAssertEqual(user.email, "test@example.com")
1274
+ })
1275
+ }
1276
+
1277
+ func testGetUser() async throws {
1278
+ let app = Application(.testing)
1279
+ try configure(app)
1280
+
1281
+ // Create a user first
1282
+ let userData = CreateUserData(username: "testuser", email: "test@example.com", password: "password123")
1283
+
1284
+ try app.test(.POST, "/api/users", beforeRequest: { req in
1285
+ try req.content.encode(userData)
1286
+ }, afterResponse: { createRes in
1287
+ XCTAssertEqual(createRes.status, .ok)
1288
+ let createdUser = try createRes.content.decode(User.Public.self)
1289
+
1290
+ // Test getting the user
1291
+ try app.test(.GET, "/api/users/\(createdUser.id)", afterResponse: { getRes in
1292
+ XCTAssertEqual(getRes.status, .ok)
1293
+ let user = try getRes.content.decode(User.Public.self)
1294
+ XCTAssertEqual(user.id, createdUser.id)
1295
+ XCTAssertEqual(user.username, "testuser")
1296
+ })
1297
+ })
1298
+ }
1299
+
1300
+ func testWebSocketConnection() async throws {
1301
+ let app = Application(.testing)
1302
+ try configure(app)
1303
+
1304
+ try app.test(.websocket, "/ws/chat") { conn in
1305
+ try conn.send("Hello, server!")
1306
+ try conn.expectString(text: "Hello, client!")
1307
+ try conn.close()
1308
+ }
1309
+ }
1310
+ }
1311
+ ```
1312
+
1313
+ ## Security Best Practices
1314
+
1315
+ ### Input Validation and Sanitization
1316
+
1317
+ ```swift
1318
+ // Input validation with property wrappers
1319
+ @propertyWrapper
1320
+ struct ValidatedEmail: Decodable {
1321
+ private let _value: String
1322
+
1323
+ var wrappedValue: String {
1324
+ return _value
1325
+ }
1326
+
1327
+ init(wrappedValue: String) throws {
1328
+ guard Self.isValidEmail(wrappedValue) else {
1329
+ throw ValidationError.invalidEmail
1330
+ }
1331
+ _value = wrappedValue.lowercased()
1332
+ }
1333
+
1334
+ init(from decoder: Decoder) throws {
1335
+ let container = try decoder.singleValueContainer()
1336
+ let value = try container.decode(String.self)
1337
+ try self.init(wrappedValue: value)
1338
+ }
1339
+
1340
+ private static func isValidEmail(_ email: String) -> Bool {
1341
+ let emailRegex = #"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"#
1342
+ return email.range(of: emailRegex, options: .regularExpression) != nil
1343
+ }
1344
+ }
1345
+
1346
+ struct CreateUserRequest: Decodable {
1347
+ @ValidatedEmail var email: String
1348
+ @ValidatedUsername var username: String
1349
+ @SecurePassword var password: String
1350
+ }
1351
+
1352
+ @propertyWrapper
1353
+ struct SecurePassword: Decodable {
1354
+ private let _value: String
1355
+
1356
+ var wrappedValue: String {
1357
+ return _value
1358
+ }
1359
+
1360
+ init(wrappedValue: String) throws {
1361
+ guard Self.isValidPassword(wrappedValue) else {
1362
+ throw ValidationError.weakPassword
1363
+ }
1364
+ _value = wrappedValue
1365
+ }
1366
+
1367
+ init(from decoder: Decoder) throws {
1368
+ let container = try decoder.singleValueContainer()
1369
+ let value = try container.decode(String.self)
1370
+ try self.init(wrappedValue: value)
1371
+ }
1372
+
1373
+ private static func isValidPassword(_ password: String) -> Bool {
1374
+ // At least 8 characters, one uppercase, one lowercase, one digit, one special character
1375
+ let passwordRegex = #"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$"#
1376
+ return password.range(of: passwordRegex, options: .regularExpression) != nil
1377
+ }
1378
+ }
1379
+
1380
+ enum ValidationError: Error, LocalizedError {
1381
+ case invalidEmail
1382
+ case weakPassword
1383
+
1384
+ var errorDescription: String? {
1385
+ switch self {
1386
+ case .invalidEmail:
1387
+ return "Invalid email format"
1388
+ case .weakPassword:
1389
+ return "Password must be at least 8 characters and contain uppercase, lowercase, digit, and special character"
1390
+ }
1391
+ }
1392
+ }
1393
+ ```
1394
+
1395
+ ### Authentication and Authorization
1396
+
1397
+ ```swift
1398
+ // JWT authentication middleware
1399
+ struct JWTMiddleware: AsyncMiddleware {
1400
+ let jwtSecret: String
1401
+
1402
+ func respond(to request: Request, chainingTo next: AsyncResponder) async throws -> Response {
1403
+ guard let token = request.headers.bearerAuthorization?.token else {
1404
+ throw Abort(.unauthorized, reason: "Missing authorization token")
1405
+ }
1406
+
1407
+ do {
1408
+ let payload = try JWT<AuthPayload>(from: token, verifiedUsing: .hs256(key: jwtSecret))
1409
+ request.auth.login(payload.user)
1410
+ return try await next.respond(to: request)
1411
+ } catch {
1412
+ throw Abort(.unauthorized, reason: "Invalid token")
1413
+ }
1414
+ }
1415
+ }
1416
+
1417
+ struct AuthPayload: JWTPayload {
1418
+ var user: User
1419
+ var expirationTime: ExpirationClaim
1420
+
1421
+ func verify(using algorithm: some JWTAlgorithm) throws {
1422
+ try expirationTime.verifyNotExpired()
1423
+ }
1424
+ }
1425
+
1426
+ // Role-based access control
1427
+ enum UserRole: String, Codable {
1428
+ case admin
1429
+ case moderator
1430
+ case user
1431
+ case guest
1432
+ }
1433
+
1434
+ extension User {
1435
+ func hasRole(_ role: UserRole) -> Bool {
1436
+ return self.role == role
1437
+ }
1438
+
1439
+ func canAccessResource(_ resource: Resource) -> Bool {
1440
+ switch resource.type {
1441
+ case .adminOnly:
1442
+ return hasRole(.admin)
1443
+ case .moderatorAndAbove:
1444
+ return hasRole(.admin) || hasRole(.moderator)
1445
+ case .userAndAbove:
1446
+ return hasRole(.admin) || hasRole(.moderator) || hasRole(.user)
1447
+ case .public:
1448
+ return true
1449
+ }
1450
+ }
1451
+ }
1452
+
1453
+ // Request extension for authentication
1454
+ extension Request {
1455
+ var authenticatedUser: User? {
1456
+ return auth.get(User.self)
1457
+ }
1458
+
1459
+ func requireAuthentication() throws -> User {
1460
+ guard let user = authenticatedUser else {
1461
+ throw Abort(.unauthorized, reason: "Authentication required")
1462
+ }
1463
+ return user
1464
+ }
1465
+
1466
+ func requireRole(_ role: UserRole) throws -> User {
1467
+ let user = try requireAuthentication()
1468
+ guard user.hasRole(role) else {
1469
+ throw Abort(.forbidden, reason: "Insufficient permissions")
1470
+ }
1471
+ return user
1472
+ }
1473
+ }
1474
+ ```
1475
+
1476
+ ### Security Headers and CORS
1477
+
1478
+ ```swift
1479
+ // Security headers middleware
1480
+ struct SecurityHeadersMiddleware: AsyncMiddleware {
1481
+ func respond(to request: Request, chainingTo next: AsyncResponder) async throws -> Response {
1482
+ let response = try await next.respond(to: request)
1483
+
1484
+ // Add security headers
1485
+ response.headers.add(name: .xContentTypeOptions, value: "nosniff")
1486
+ response.headers.add(name: .xFrameOptions, value: "DENY")
1487
+ response.headers.add(name: .xXSSProtection, value: "1; mode=block")
1488
+ response.headers.add(name: .strictTransportSecurity, value: "max-age=31536000; includeSubDomains")
1489
+ response.headers.add(name: .contentSecurityPolicy, value: "default-src 'self'")
1490
+
1491
+ return response
1492
+ }
1493
+ }
1494
+
1495
+ // CORS configuration
1496
+ struct CORSMiddleware: AsyncMiddleware {
1497
+ private let allowedOrigins: [String]
1498
+ private let allowedMethods: [HTTPMethod]
1499
+ private let allowedHeaders: [String]
1500
+
1501
+ init(allowedOrigins: [String] = ["*"], allowedMethods: [HTTPMethod] = [.GET, .POST, .PUT, .DELETE], allowedHeaders: [String] = ["Content-Type", "Authorization"]) {
1502
+ self.allowedOrigins = allowedOrigins
1503
+ self.allowedMethods = allowedMethods
1504
+ self.allowedHeaders = allowedHeaders
1505
+ }
1506
+
1507
+ func respond(to request: Request, chainingTo next: AsyncResponder) async throws -> Response {
1508
+ let response = try await next.respond(to: request)
1509
+
1510
+ // Add CORS headers
1511
+ if let origin = request.headers.first(name: .origin) {
1512
+ if allowedOrigins.contains("*") || allowedOrigins.contains(origin) {
1513
+ response.headers.add(name: .accessControlAllowOrigin, value: origin)
1514
+ }
1515
+ }
1516
+
1517
+ response.headers.add(name: .accessControlAllowMethods, value: allowedMethods.map { $0.string }.joined(separator: ", "))
1518
+ response.headers.add(name: .accessControlAllowHeaders, value: allowedHeaders.joined(separator: ", "))
1519
+
1520
+ return response
1521
+ }
1522
+ }
1523
+ ```
1524
+
1525
+ ## Integration Patterns
1526
+
1527
+ ### Core Data Integration
1528
+
1529
+ ```swift
1530
+ import CoreData
1531
+ import SwiftUI
1532
+
1533
+ // Core Data manager with async/await
1534
+ actor CoreDataManager {
1535
+ static let shared = CoreDataManager()
1536
+
1537
+ lazy var persistentContainer: NSPersistentContainer = {
1538
+ let container = NSPersistentContainer(name: "DataModel")
1539
+ container.loadPersistentStores { _, error in
1540
+ if let error = error {
1541
+ fatalError("Core Data error: \(error.localizedDescription)")
1542
+ }
1543
+ }
1544
+ container.viewContext.automaticallyMergesChangesFromParent = true
1545
+ return container
1546
+ }()
1547
+
1548
+ var viewContext: NSManagedObjectContext {
1549
+ persistentContainer.viewContext
1550
+ }
1551
+
1552
+ private var backgroundContext: NSManagedObjectContext {
1553
+ persistentContainer.newBackgroundContext()
1554
+ }
1555
+
1556
+ func fetchUsers() async -> [User] {
1557
+ return await withCheckedContinuation { continuation in
1558
+ let request: NSFetchRequest<User> = User.fetchRequest()
1559
+
1560
+ backgroundContext.perform {
1561
+ do {
1562
+ let users = try self.backgroundContext.fetch(request)
1563
+ continuation.resume(returning: users)
1564
+ } catch {
1565
+ continuation.resume(returning: [])
1566
+ }
1567
+ }
1568
+ }
1569
+ }
1570
+
1571
+ func saveUser(_ user: User) async {
1572
+ await withCheckedContinuation { (continuation: CheckedContinuation<Void, Never>) in
1573
+ backgroundContext.perform {
1574
+ do {
1575
+ try self.backgroundContext.save()
1576
+ continuation.resume()
1577
+ } catch {
1578
+ print("Failed to save user: \(error)")
1579
+ continuation.resume()
1580
+ }
1581
+ }
1582
+ }
1583
+ }
1584
+
1585
+ func deleteUser(_ user: User) async {
1586
+ await withCheckedContinuation { (continuation: CheckedContinuation<Void, Never>) in
1587
+ backgroundContext.perform {
1588
+ self.backgroundContext.delete(user)
1589
+ do {
1590
+ try self.backgroundContext.save()
1591
+ continuation.resume()
1592
+ } catch {
1593
+ print("Failed to delete user: \(error)")
1594
+ continuation.resume()
1595
+ }
1596
+ }
1597
+ }
1598
+ }
1599
+ }
1600
+
1601
+ // SwiftUI Core Data integration
1602
+ struct CoreDataUserListView: View {
1603
+ @Environment(\.managedObjectContext) private var viewContext
1604
+ @FetchRequest(
1605
+ sortDescriptors: [NSSortDescriptor(keyPath: \User.createdAt, ascending: true)],
1606
+ animation: .default)
1607
+ private var users: FetchedResults<User>
1608
+
1609
+ var body: some View {
1610
+ List {
1611
+ ForEach(users, id: \.objectID) { user in
1612
+ UserRow(user: user)
1613
+ }
1614
+ .onDelete(perform: deleteUsers)
1615
+ }
1616
+ .toolbar {
1617
+ ToolbarItem(placement: .navigationBarTrailing) {
1618
+ Button(action: addUser) {
1619
+ Label("Add User", systemImage: "plus")
1620
+ }
1621
+ }
1622
+ }
1623
+ }
1624
+
1625
+ private func addUser() {
1626
+ withAnimation {
1627
+ let newUser = User(context: viewContext)
1628
+ newUser.name = "New User"
1629
+ newUser.createdAt = Date()
1630
+
1631
+ saveContext()
1632
+ }
1633
+ }
1634
+
1635
+ private func deleteUsers(offsets: IndexSet) {
1636
+ withAnimation {
1637
+ offsets.map { users[$0] }.forEach(viewContext.delete)
1638
+ saveContext()
1639
+ }
1640
+ }
1641
+
1642
+ private func saveContext() {
1643
+ do {
1644
+ try viewContext.save()
1645
+ } catch {
1646
+ let nsError = error as NSError
1647
+ fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
1648
+ }
1649
+ }
1650
+ }
1651
+ ```
1652
+
1653
+ ### Networking with Async/Await
1654
+
1655
+ ```swift
1656
+ import Foundation
1657
+
1658
+ // Modern networking client
1659
+ class APIClient: APIClientProtocol {
1660
+ private let session: URLSession
1661
+ private let baseURL: URL
1662
+ private let decoder: JSONDecoder
1663
+
1664
+ init(baseURL: URL = URL(string: "https://api.example.com")!) {
1665
+ self.baseURL = baseURL
1666
+ self.decoder = JSONDecoder()
1667
+ self.decoder.dateDecodingStrategy = .iso8601
1668
+ self.decoder.keyDecodingStrategy = .convertFromSnakeCase
1669
+
1670
+ let config = URLSessionConfiguration.default
1671
+ config.timeoutIntervalForRequest = 30
1672
+ config.timeoutIntervalForResource = 60
1673
+ config.waitsForConnectivity = true
1674
+
1675
+ self.session = URLSession(configuration: config)
1676
+ }
1677
+
1678
+ func request<T: Decodable>(_ endpoint: APIEndpoint, responseType: T.Type) async throws -> T {
1679
+ let request = try buildRequest(for: endpoint)
1680
+
1681
+ let (data, response) = try await session.data(for: request)
1682
+
1683
+ guard let httpResponse = response as? HTTPURLResponse else {
1684
+ throw APIError.invalidResponse
1685
+ }
1686
+
1687
+ guard 200...299 ~= httpResponse.statusCode else {
1688
+ throw APIError.serverError(statusCode: httpResponse.statusCode)
1689
+ }
1690
+
1691
+ do {
1692
+ return try decoder.decode(T.self, from: data)
1693
+ } catch {
1694
+ throw APIError.decodingError(error)
1695
+ }
1696
+ }
1697
+
1698
+ func uploadData<T: Decodable>(_ data: Data, to endpoint: APIEndpoint, responseType: T.Type) async throws -> T {
1699
+ var request = try buildRequest(for: endpoint)
1700
+ request.httpMethod = "POST"
1701
+ request.setValue("application/octet-stream", forHTTPHeaderField: "Content-Type")
1702
+ request.httpBody = data
1703
+
1704
+ let (responseData, response) = try await session.upload(for: request, from: data)
1705
+
1706
+ guard let httpResponse = response as? HTTPURLResponse else {
1707
+ throw APIError.invalidResponse
1708
+ }
1709
+
1710
+ guard 200...299 ~= httpResponse.statusCode else {
1711
+ throw APIError.serverError(statusCode: httpResponse.statusCode)
1712
+ }
1713
+
1714
+ do {
1715
+ return try decoder.decode(T.self, from: responseData)
1716
+ } catch {
1717
+ throw APIError.decodingError(error)
1718
+ }
1719
+ }
1720
+
1721
+ private func buildRequest(for endpoint: APIEndpoint) throws -> URLRequest {
1722
+ var components = URLComponents(url: baseURL.appendingPathComponent(endpoint.path), resolvingAgainstBaseURL: false)!
1723
+
1724
+ if !endpoint.parameters.isEmpty {
1725
+ components.queryItems = endpoint.parameters.map { key, value in
1726
+ URLQueryItem(name: key, value: "\(value)")
1727
+ }
1728
+ }
1729
+
1730
+ var request = URLRequest(url: components.url!)
1731
+ request.httpMethod = endpoint.method.rawValue
1732
+ request.setValue("application/json", forHTTPHeaderField: "Content-Type")
1733
+
1734
+ if let body = endpoint.body {
1735
+ request.httpBody = try JSONSerialization.data(withJSONObject: body)
1736
+ }
1737
+
1738
+ return request
1739
+ }
1740
+ }
1741
+
1742
+ // API endpoint configuration
1743
+ enum APIEndpoint {
1744
+ case getUser(id: String)
1745
+ case getUsers(page: Int, limit: Int)
1746
+ case createUser(CreateUserData)
1747
+ case updateUser(id: String, UpdateUserData)
1748
+ case deleteUser(id: String)
1749
+
1750
+ var path: String {
1751
+ switch self {
1752
+ case .getUser(let id):
1753
+ return "users/\(id)"
1754
+ case .getUsers:
1755
+ return "users"
1756
+ case .createUser:
1757
+ return "users"
1758
+ case .updateUser(let id, _):
1759
+ return "users/\(id)"
1760
+ case .deleteUser(let id):
1761
+ return "users/\(id)"
1762
+ }
1763
+ }
1764
+
1765
+ var method: HTTPMethod {
1766
+ switch self {
1767
+ case .getUser, .getUsers:
1768
+ return .GET
1769
+ case .createUser:
1770
+ return .POST
1771
+ case .updateUser:
1772
+ return .PUT
1773
+ case .deleteUser:
1774
+ return .DELETE
1775
+ }
1776
+ }
1777
+
1778
+ var parameters: [String: Any] {
1779
+ switch self {
1780
+ case .getUsers(let page, let limit):
1781
+ return ["page": page, "limit": limit]
1782
+ default:
1783
+ return [:]
1784
+ }
1785
+ }
1786
+
1787
+ var body: [String: Any]? {
1788
+ switch self {
1789
+ case .createUser(let userData):
1790
+ return try? userData.asDictionary()
1791
+ case .updateUser(_, let userData):
1792
+ return try? userData.asDictionary()
1793
+ default:
1794
+ return nil
1795
+ }
1796
+ }
1797
+ }
1798
+
1799
+ enum HTTPMethod: String {
1800
+ case GET = "GET"
1801
+ case POST = "POST"
1802
+ case PUT = "PUT"
1803
+ case DELETE = "DELETE"
1804
+ }
1805
+
1806
+ enum APIError: Error, LocalizedError {
1807
+ case invalidURL
1808
+ case invalidResponse
1809
+ case serverError(statusCode: Int)
1810
+ case decodingError(Error)
1811
+ case networkError(Error)
1812
+
1813
+ var errorDescription: String? {
1814
+ switch self {
1815
+ case .invalidURL:
1816
+ return "Invalid URL"
1817
+ case .invalidResponse:
1818
+ return "Invalid response"
1819
+ case .serverError(let statusCode):
1820
+ return "Server error with status code: \(statusCode)"
1821
+ case .decodingError(let error):
1822
+ return "Decoding error: \(error.localizedDescription)"
1823
+ case .networkError(let error):
1824
+ return "Network error: \(error.localizedDescription)"
1825
+ }
1826
+ }
1827
+ }
1828
+ ```
1829
+
1830
+ ## Modern Development Workflow
1831
+
1832
+ ### Xcode Configuration
1833
+
1834
+ ```swift
1835
+ // Project-level configuration for modern Swift development
1836
+
1837
+ // Info.plist additions for security and privacy
1838
+ <key>NSAppTransportSecurity</key>
1839
+ <dict>
1840
+ <key>NSAllowsArbitraryLoads</key>
1841
+ <false/>
1842
+ <key>NSExceptionDomains</key>
1843
+ <dict>
1844
+ <key>api.example.com</key>
1845
+ <dict>
1846
+ <key>NSExceptionAllowsInsecureHTTPLoads</key>
1847
+ <true/>
1848
+ <key>NSExceptionMinimumTLSVersion</key>
1849
+ <string>TLSv1.2</string>
1850
+ </dict>
1851
+ </dict>
1852
+ </dict>
1853
+
1854
+ <key>NSCameraUsageDescription</key>
1855
+ <string>This app needs camera access for profile photos</string>
1856
+
1857
+ <key>NSLocationWhenInUseUsageDescription</key>
1858
+ <string>This app needs location access for location-based features</string>
1859
+
1860
+ <key>NSUserTrackingUsageDescription</key>
1861
+ <string>This app uses tracking for personalized advertising</string>
1862
+ ```
1863
+
1864
+ ### SwiftLint Configuration
1865
+
1866
+ ```yaml
1867
+ # .swiftlint.yml
1868
+ excluded:
1869
+ - Carthage
1870
+ - Pods
1871
+ - build
1872
+ - .build
1873
+
1874
+ opt_in_rules:
1875
+ - empty_count
1876
+ - force_unwrapping
1877
+ - implicitly_unwrapped_optional
1878
+
1879
+ disabled_rules:
1880
+ - trailing_whitespace
1881
+ - line_length
1882
+
1883
+ line_length:
1884
+ warning: 120
1885
+ error: 150
1886
+
1887
+ function_body_length:
1888
+ warning: 50
1889
+ error: 100
1890
+
1891
+ type_body_length:
1892
+ warning: 300
1893
+ error: 500
1894
+
1895
+ file_length:
1896
+ warning: 400
1897
+ error: 800
1898
+
1899
+ cyclomatic_complexity:
1900
+ warning: 10
1901
+ error: 20
1902
+
1903
+ custom_rules:
1904
+ no_console_log:
1905
+ name: "No Console Logging"
1906
+ regex: '(print|NSLog|debugPrint)\('
1907
+ message: "Console logging should be removed in production."
1908
+ severity: warning
1909
+ ```
1910
+
1911
+ ### CI/CD Configuration
1912
+
1913
+ ```yaml
1914
+ # .github/workflows/swift.yml
1915
+ name: Swift CI
1916
+
1917
+ on:
1918
+ push:
1919
+ branches: [ main, develop ]
1920
+ pull_request:
1921
+ branches: [ main, develop ]
1922
+
1923
+ jobs:
1924
+ test:
1925
+ runs-on: macos-latest
1926
+
1927
+ steps:
1928
+ - uses: actions/checkout@v4
1929
+
1930
+ - name: Select Xcode
1931
+ uses: maxim-lobanov/setup-xcode@v1
1932
+ with:
1933
+ xcode-version: latest-stable
1934
+
1935
+ - name: Cache Swift Package Manager
1936
+ uses: actions/cache@v3
1937
+ with:
1938
+ path: .build
1939
+ key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}
1940
+
1941
+ - name: Build
1942
+ run: swift build
1943
+
1944
+ - name: Run tests
1945
+ run: swift test --enable-code-coverage
1946
+
1947
+ - name: Generate code coverage report
1948
+ run: xcrun llvm-cov report -build-path .build -use-llvm --json > coverage.json
1949
+
1950
+ - name: Upload coverage to Codecov
1951
+ uses: codecov/codecov-action@v3
1952
+ with:
1953
+ file: ./coverage.json
1954
+
1955
+ - name: Run SwiftLint
1956
+ run: |
1957
+ mint run swiftlint/swiftlint swiftlint
1958
+ mint run swiftlint/swiftlint swiftlint --strict
1959
+
1960
+ - name: Run SwiftFormat
1961
+ run: |
1962
+ mint run swiftformat/swiftformat swiftformat --lint --strict .
1963
+
1964
+ ios_test:
1965
+ runs-on: macos-latest
1966
+
1967
+ steps:
1968
+ - uses: actions/checkout@v4
1969
+
1970
+ - name: Select Xcode
1971
+ uses: maxim-lobanov/setup-xcode@v1
1972
+ with:
1973
+ xcode-version: latest-stable
1974
+
1975
+ - name: Build iOS App
1976
+ run: xcodebuild -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 15,OS=latest' clean build
1977
+
1978
+ - name: Run iOS Tests
1979
+ run: xcodebuild -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 15,OS=latest' test
1980
+ ```
1981
+
1982
+ ---
92
1983
 
93
- - alfred-trust-validation (coverage verification)
94
- - alfred-code-reviewer (Swift-specific review)
95
- - mobile-app-expert (iOS app development)
1984
+ **Created by**: MoAI Language Skill Factory
1985
+ **Last Updated**: 2025-11-06
1986
+ **Version**: 2.0.0
1987
+ **Swift Target**: 6.0 with modern SwiftUI, Swift Concurrency, and server-side Swift
96
1988
 
97
- ## Best Practices
98
- - Enable automatic validation by matching your linter with the language's official style guide.
99
- - Fix test/build pipelines with reproducible commands in CI.
1989
+ This skill provides comprehensive Swift development guidance with 2025 best practices, covering everything from iOS/macOS applications with SwiftUI to server-side development with Vapor and modern concurrency patterns.