cfsa-antigravity 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (378) hide show
  1. package/bin/cli.mjs +324 -0
  2. package/package.json +34 -0
  3. package/template/.agent/instructions/commands.md +48 -0
  4. package/template/.agent/instructions/patterns.md +61 -0
  5. package/template/.agent/instructions/structure.md +29 -0
  6. package/template/.agent/instructions/tech-stack.md +43 -0
  7. package/template/.agent/instructions/workflow.md +41 -0
  8. package/template/.agent/kit-sync.md +15 -0
  9. package/template/.agent/rules/boundary-not-placeholder.md +146 -0
  10. package/template/.agent/rules/completion-checklist.md +48 -0
  11. package/template/.agent/rules/decision-classification.md +103 -0
  12. package/template/.agent/rules/extensibility.md +47 -0
  13. package/template/.agent/rules/question-vs-command.md +81 -0
  14. package/template/.agent/rules/security-first.md +43 -0
  15. package/template/.agent/rules/specificity-standards.md +54 -0
  16. package/template/.agent/rules/tdd-contract-first.md +57 -0
  17. package/template/.agent/rules/vertical-slices.md +42 -0
  18. package/template/.agent/skill-library/MANIFEST.md +480 -0
  19. package/template/.agent/skill-library/README.md +38 -0
  20. package/template/.agent/skill-library/meta/brand-guidelines/SKILL.md +73 -0
  21. package/template/.agent/skill-library/meta/claude-code/README.md +9 -0
  22. package/template/.agent/skill-library/meta/claude-code/agent-development/SKILL.md +415 -0
  23. package/template/.agent/skill-library/meta/claude-code/hook-development/SKILL.md +712 -0
  24. package/template/.agent/skill-library/meta/claude-code/plugin-structure/SKILL.md +476 -0
  25. package/template/.agent/skill-library/meta/git-advanced/SKILL.md +972 -0
  26. package/template/.agent/skill-library/meta/mcp-builder/SKILL.md +236 -0
  27. package/template/.agent/skill-library/meta/product-marketing-context/SKILL.md +241 -0
  28. package/template/.agent/skill-library/meta/regex-patterns/SKILL.md +751 -0
  29. package/template/.agent/skill-library/meta/tmux-processes/SKILL.md +210 -0
  30. package/template/.agent/skill-library/meta/using-tmux-for-interactive-commands/SKILL.md +178 -0
  31. package/template/.agent/skill-library/stack/3d/threejs-pro/SKILL.md +300 -0
  32. package/template/.agent/skill-library/stack/ai/ai-sdk/SKILL.md +77 -0
  33. package/template/.agent/skill-library/stack/ai/langchain/SKILL.md +530 -0
  34. package/template/.agent/skill-library/stack/ai/ollama/SKILL.md +321 -0
  35. package/template/.agent/skill-library/stack/ai/openai-sdk/SKILL.md +549 -0
  36. package/template/.agent/skill-library/stack/analytics/google-analytics/SKILL.md +153 -0
  37. package/template/.agent/skill-library/stack/api/graphql/SKILL.md +1061 -0
  38. package/template/.agent/skill-library/stack/api/trpc/SKILL.md +576 -0
  39. package/template/.agent/skill-library/stack/auth/authjs/SKILL.md +569 -0
  40. package/template/.agent/skill-library/stack/auth/clerk/SKILL.md +590 -0
  41. package/template/.agent/skill-library/stack/auth/firebase-auth/SKILL.md +734 -0
  42. package/template/.agent/skill-library/stack/cms/payload-cms/SKILL.md +573 -0
  43. package/template/.agent/skill-library/stack/cms/shopify/SKILL.md +1193 -0
  44. package/template/.agent/skill-library/stack/cms/wordpress/SKILL.md +1104 -0
  45. package/template/.agent/skill-library/stack/css/sass-scss/SKILL.md +1121 -0
  46. package/template/.agent/skill-library/stack/css/tailwind-css-patterns/SKILL.md +863 -0
  47. package/template/.agent/skill-library/stack/css/tailwind-design-system/SKILL.md +490 -0
  48. package/template/.agent/skill-library/stack/css/vanilla-css/SKILL.md +1078 -0
  49. package/template/.agent/skill-library/stack/databases/clickhouse/SKILL.md +311 -0
  50. package/template/.agent/skill-library/stack/databases/influxdb/SKILL.md +280 -0
  51. package/template/.agent/skill-library/stack/databases/lancedb/SKILL.md +415 -0
  52. package/template/.agent/skill-library/stack/databases/mongodb/SKILL.md +1169 -0
  53. package/template/.agent/skill-library/stack/databases/neo4j/SKILL.md +839 -0
  54. package/template/.agent/skill-library/stack/databases/pgvector/SKILL.md +241 -0
  55. package/template/.agent/skill-library/stack/databases/pinecone/SKILL.md +212 -0
  56. package/template/.agent/skill-library/stack/databases/postgresql/SKILL.md +658 -0
  57. package/template/.agent/skill-library/stack/databases/qdrant/SKILL.md +312 -0
  58. package/template/.agent/skill-library/stack/databases/redis/SKILL.md +1079 -0
  59. package/template/.agent/skill-library/stack/databases/spacetimedb/SKILL.md +532 -0
  60. package/template/.agent/skill-library/stack/databases/sqlite/SKILL.md +1132 -0
  61. package/template/.agent/skill-library/stack/databases/supabase/SKILL.md +640 -0
  62. package/template/.agent/skill-library/stack/databases/surrealdb-expert/SKILL.md +945 -0
  63. package/template/.agent/skill-library/stack/databases/timescaledb/SKILL.md +745 -0
  64. package/template/.agent/skill-library/stack/databases/weaviate/SKILL.md +218 -0
  65. package/template/.agent/skill-library/stack/devops/github-actions/SKILL.md +554 -0
  66. package/template/.agent/skill-library/stack/devops/kubernetes/SKILL.md +950 -0
  67. package/template/.agent/skill-library/stack/devops/nginx/SKILL.md +841 -0
  68. package/template/.agent/skill-library/stack/devops/terraform/SKILL.md +860 -0
  69. package/template/.agent/skill-library/stack/email/resend/SKILL.md +391 -0
  70. package/template/.agent/skill-library/stack/engines/godot/SKILL.md +488 -0
  71. package/template/.agent/skill-library/stack/extensions/chrome-extension/SKILL.md +375 -0
  72. package/template/.agent/skill-library/stack/extensions/vscode-extension/SKILL.md +453 -0
  73. package/template/.agent/skill-library/stack/frameworks/astro-framework/SKILL.md +162 -0
  74. package/template/.agent/skill-library/stack/frameworks/electron/SKILL.md +1286 -0
  75. package/template/.agent/skill-library/stack/frameworks/fastapi/SKILL.md +650 -0
  76. package/template/.agent/skill-library/stack/frameworks/hono/SKILL.md +90 -0
  77. package/template/.agent/skill-library/stack/frameworks/nestjs/SKILL.md +878 -0
  78. package/template/.agent/skill-library/stack/frameworks/nextjs/SKILL.md +635 -0
  79. package/template/.agent/skill-library/stack/frameworks/nuxt/SKILL.md +564 -0
  80. package/template/.agent/skill-library/stack/frameworks/sveltekit/SKILL.md +614 -0
  81. package/template/.agent/skill-library/stack/frameworks/tauri/SKILL.md +920 -0
  82. package/template/.agent/skill-library/stack/gamedev/godot/SKILL.md +1032 -0
  83. package/template/.agent/skill-library/stack/gamedev/unity/SKILL.md +1175 -0
  84. package/template/.agent/skill-library/stack/hosting/aws/SKILL.md +467 -0
  85. package/template/.agent/skill-library/stack/hosting/cloudflare/SKILL.md +201 -0
  86. package/template/.agent/skill-library/stack/hosting/docker-expert/SKILL.md +409 -0
  87. package/template/.agent/skill-library/stack/hosting/vercel/SKILL.md +484 -0
  88. package/template/.agent/skill-library/stack/languages/bash-scripting/SKILL.md +773 -0
  89. package/template/.agent/skill-library/stack/languages/c-cpp/SKILL.md +712 -0
  90. package/template/.agent/skill-library/stack/languages/gdscript/SKILL.md +789 -0
  91. package/template/.agent/skill-library/stack/languages/go/SKILL.md +664 -0
  92. package/template/.agent/skill-library/stack/languages/java/SKILL.md +778 -0
  93. package/template/.agent/skill-library/stack/languages/kotlin/SKILL.md +665 -0
  94. package/template/.agent/skill-library/stack/languages/python/SKILL.md +678 -0
  95. package/template/.agent/skill-library/stack/languages/rust/SKILL.md +673 -0
  96. package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/SKILL.md +141 -0
  97. package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/advanced-generics.md +90 -0
  98. package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/branded-types.md +57 -0
  99. package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/builder-pattern.md +71 -0
  100. package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/common-pitfalls.md +135 -0
  101. package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/conditional-types.md +27 -0
  102. package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/decorators.md +98 -0
  103. package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/discriminated-unions.md +62 -0
  104. package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/mapped-types.md +53 -0
  105. package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/performance-best-practices.md +104 -0
  106. package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/template-literal-types.md +49 -0
  107. package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/testing-types.md +112 -0
  108. package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-guards.md +70 -0
  109. package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-inference.md +101 -0
  110. package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/utility-types.md +98 -0
  111. package/template/.agent/skill-library/stack/languages/vanilla-javascript/SKILL.md +803 -0
  112. package/template/.agent/skill-library/stack/messaging/kafka/SKILL.md +235 -0
  113. package/template/.agent/skill-library/stack/mobile/expo-react-native/SKILL.md +665 -0
  114. package/template/.agent/skill-library/stack/mobile/flutter/SKILL.md +316 -0
  115. package/template/.agent/skill-library/stack/mobile/react-native/SKILL.md +337 -0
  116. package/template/.agent/skill-library/stack/monitoring/posthog/SKILL.md +396 -0
  117. package/template/.agent/skill-library/stack/monitoring/sentry/SKILL.md +509 -0
  118. package/template/.agent/skill-library/stack/observability/datadog/SKILL.md +179 -0
  119. package/template/.agent/skill-library/stack/observability/distributed-tracing/SKILL.md +140 -0
  120. package/template/.agent/skill-library/stack/observability/logging-best-practices/SKILL.md +168 -0
  121. package/template/.agent/skill-library/stack/observability/opentelemetry/SKILL.md +164 -0
  122. package/template/.agent/skill-library/stack/observability/prometheus-grafana/SKILL.md +246 -0
  123. package/template/.agent/skill-library/stack/observability/python-observability/SKILL.md +158 -0
  124. package/template/.agent/skill-library/stack/orm/drizzle-orm/SKILL.md +613 -0
  125. package/template/.agent/skill-library/stack/orm/prisma/SKILL.md +744 -0
  126. package/template/.agent/skill-library/stack/payments/lemonsqueezy/SKILL.md +393 -0
  127. package/template/.agent/skill-library/stack/payments/stripe-integration/SKILL.md +457 -0
  128. package/template/.agent/skill-library/stack/queue/bullmq/SKILL.md +385 -0
  129. package/template/.agent/skill-library/stack/queue/inngest/SKILL.md +438 -0
  130. package/template/.agent/skill-library/stack/realtime/socketio/SKILL.md +595 -0
  131. package/template/.agent/skill-library/stack/search/elasticsearch/SKILL.md +248 -0
  132. package/template/.agent/skill-library/stack/search/meilisearch/SKILL.md +385 -0
  133. package/template/.agent/skill-library/stack/security/crypto-patterns/SKILL.md +437 -0
  134. package/template/.agent/skill-library/stack/security/csp-cors-headers/SKILL.md +588 -0
  135. package/template/.agent/skill-library/stack/security/dependency-auditing/SKILL.md +560 -0
  136. package/template/.agent/skill-library/stack/security/input-sanitization/SKILL.md +430 -0
  137. package/template/.agent/skill-library/stack/security/owasp-web-security/SKILL.md +421 -0
  138. package/template/.agent/skill-library/stack/state/tanstack-query/SKILL.md +637 -0
  139. package/template/.agent/skill-library/stack/state/zustand/SKILL.md +483 -0
  140. package/template/.agent/skill-library/stack/storage/aws-s3/SKILL.md +415 -0
  141. package/template/.agent/skill-library/stack/testing/playwright/SKILL.md +641 -0
  142. package/template/.agent/skill-library/stack/testing/storybook/SKILL.md +923 -0
  143. package/template/.agent/skill-library/stack/testing/testing-library/SKILL.md +872 -0
  144. package/template/.agent/skill-library/stack/testing/vitest/SKILL.md +714 -0
  145. package/template/.agent/skill-library/stack/ui/react-best-practices/SKILL.md +877 -0
  146. package/template/.agent/skill-library/stack/ui/react-composition-patterns/SKILL.md +1107 -0
  147. package/template/.agent/skill-library/stack/ui/react-flow/SKILL.md +425 -0
  148. package/template/.agent/skill-library/stack/ui/shadcn-ui/SKILL.md +703 -0
  149. package/template/.agent/skill-library/surface/api/api-caching/SKILL.md +458 -0
  150. package/template/.agent/skill-library/surface/api/api-documentation-openapi/SKILL.md +697 -0
  151. package/template/.agent/skill-library/surface/api/api-error-handling/SKILL.md +478 -0
  152. package/template/.agent/skill-library/surface/api/api-security-checklist/SKILL.md +147 -0
  153. package/template/.agent/skill-library/surface/api/api-versioning/SKILL.md +420 -0
  154. package/template/.agent/skill-library/surface/api/email-best-practices/SKILL.md +59 -0
  155. package/template/.agent/skill-library/surface/api/rate-limiting-abuse-protection/SKILL.md +147 -0
  156. package/template/.agent/skill-library/surface/api/rest-api-design/SKILL.md +478 -0
  157. package/template/.agent/skill-library/surface/api/webhook-design/SKILL.md +752 -0
  158. package/template/.agent/skill-library/surface/cli/cli-configuration-management/SKILL.md +445 -0
  159. package/template/.agent/skill-library/surface/cli/cli-error-diagnostics/SKILL.md +515 -0
  160. package/template/.agent/skill-library/surface/cli/cli-shell-integration/SKILL.md +479 -0
  161. package/template/.agent/skill-library/surface/cli/cli-ux-design/SKILL.md +477 -0
  162. package/template/.agent/skill-library/surface/desktop/desktop-app-distribution/SKILL.md +416 -0
  163. package/template/.agent/skill-library/surface/desktop/desktop-security-sandboxing/SKILL.md +407 -0
  164. package/template/.agent/skill-library/surface/desktop/desktop-ux-conventions/SKILL.md +361 -0
  165. package/template/.agent/skill-library/surface/desktop/native-os-integration/SKILL.md +563 -0
  166. package/template/.agent/skill-library/surface/extension/browser-extension-patterns/SKILL.md +482 -0
  167. package/template/.agent/skill-library/surface/extension/plugin-architecture-design/SKILL.md +632 -0
  168. package/template/.agent/skill-library/surface/extension/vscode-extension-development/SKILL.md +728 -0
  169. package/template/.agent/skill-library/surface/mobile/app-store-submission/SKILL.md +304 -0
  170. package/template/.agent/skill-library/surface/mobile/mobile-offline-sync/SKILL.md +443 -0
  171. package/template/.agent/skill-library/surface/mobile/mobile-responsive-patterns/SKILL.md +432 -0
  172. package/template/.agent/skill-library/surface/mobile/push-notifications/SKILL.md +495 -0
  173. package/template/.agent/skill-library/surface/web/accessibility-compliance/SKILL.md +827 -0
  174. package/template/.agent/skill-library/surface/web/ai-seo/SKILL.md +398 -0
  175. package/template/.agent/skill-library/surface/web/ai-seo/references/content-patterns.md +285 -0
  176. package/template/.agent/skill-library/surface/web/ai-seo/references/platform-ranking-factors.md +152 -0
  177. package/template/.agent/skill-library/surface/web/analytics-tracking/SKILL.md +309 -0
  178. package/template/.agent/skill-library/surface/web/analytics-tracking/references/event-library.md +260 -0
  179. package/template/.agent/skill-library/surface/web/analytics-tracking/references/ga4-implementation.md +300 -0
  180. package/template/.agent/skill-library/surface/web/analytics-tracking/references/gtm-implementation.md +390 -0
  181. package/template/.agent/skill-library/surface/web/authentication-ui-flows/SKILL.md +530 -0
  182. package/template/.agent/skill-library/surface/web/dark-mode-theming/SKILL.md +516 -0
  183. package/template/.agent/skill-library/surface/web/design-reference-data/SKILL.md +105 -0
  184. package/template/.agent/skill-library/surface/web/design-reference-data/data/charts.csv +26 -0
  185. package/template/.agent/skill-library/surface/web/design-reference-data/data/colors.csv +97 -0
  186. package/template/.agent/skill-library/surface/web/design-reference-data/data/landing.csv +31 -0
  187. package/template/.agent/skill-library/surface/web/design-reference-data/data/styles.csv +59 -0
  188. package/template/.agent/skill-library/surface/web/design-reference-data/data/typography.csv +58 -0
  189. package/template/.agent/skill-library/surface/web/design-reference-data/data/ux-guidelines.csv +100 -0
  190. package/template/.agent/skill-library/surface/web/design-reference-data/scripts/core.py +258 -0
  191. package/template/.agent/skill-library/surface/web/design-reference-data/scripts/design_system.py +1067 -0
  192. package/template/.agent/skill-library/surface/web/design-reference-data/scripts/search.py +106 -0
  193. package/template/.agent/skill-library/surface/web/form-handling-validation/SKILL.md +675 -0
  194. package/template/.agent/skill-library/surface/web/frontend-design/SKILL.md +1393 -0
  195. package/template/.agent/skill-library/surface/web/frontend-design/templates/cppn-hero.tsx +299 -0
  196. package/template/.agent/skill-library/surface/web/frontend-design/templates/wave-hero.tsx +875 -0
  197. package/template/.agent/skill-library/surface/web/frontend-verification/SKILL.md +111 -0
  198. package/template/.agent/skill-library/surface/web/frontend-verification/scripts/ux_audit.py +739 -0
  199. package/template/.agent/skill-library/surface/web/i18n-localization/SKILL.md +154 -0
  200. package/template/.agent/skill-library/surface/web/offline-first-pwa/SKILL.md +657 -0
  201. package/template/.agent/skill-library/surface/web/page-cro/SKILL.md +182 -0
  202. package/template/.agent/skill-library/surface/web/page-cro/references/experiments.md +248 -0
  203. package/template/.agent/skill-library/surface/web/programmatic-seo/SKILL.md +238 -0
  204. package/template/.agent/skill-library/surface/web/programmatic-seo/references/playbooks.md +308 -0
  205. package/template/.agent/skill-library/surface/web/schema-markup/SKILL.md +179 -0
  206. package/template/.agent/skill-library/surface/web/schema-markup/references/schema-examples.md +398 -0
  207. package/template/.agent/skill-library/surface/web/seo-audit/SKILL.md +394 -0
  208. package/template/.agent/skill-library/surface/web/seo-audit/references/ai-writing-detection.md +200 -0
  209. package/template/.agent/skill-library/surface/web/web-performance-optimization/SKILL.md +646 -0
  210. package/template/.agent/skill-library/surface/web/web-scraping/SKILL.md +58 -0
  211. package/template/.agent/skills/accessibility/SKILL.md +522 -0
  212. package/template/.agent/skills/accessibility/references/WCAG.md +162 -0
  213. package/template/.agent/skills/adversarial-review/SKILL.md +90 -0
  214. package/template/.agent/skills/antigravity-workflows/SKILL.md +81 -0
  215. package/template/.agent/skills/antigravity-workflows/resources/implementation-playbook.md +36 -0
  216. package/template/.agent/skills/api-design-principles/SKILL.md +37 -0
  217. package/template/.agent/skills/api-design-principles/assets/api-design-checklist.md +155 -0
  218. package/template/.agent/skills/api-design-principles/assets/rest-api-template.py +182 -0
  219. package/template/.agent/skills/api-design-principles/references/graphql-schema-design.md +583 -0
  220. package/template/.agent/skills/api-design-principles/references/rest-best-practices.md +408 -0
  221. package/template/.agent/skills/api-design-principles/resources/implementation-playbook.md +513 -0
  222. package/template/.agent/skills/api-versioning/SKILL.md +420 -0
  223. package/template/.agent/skills/architecture-mapping/SKILL.md +219 -0
  224. package/template/.agent/skills/bootstrap-agents/SKILL.md +259 -0
  225. package/template/.agent/skills/brainstorming/SKILL.md +236 -0
  226. package/template/.agent/skills/brand-guidelines/SKILL.md +44 -0
  227. package/template/.agent/skills/clean-code/SKILL.md +94 -0
  228. package/template/.agent/skills/code-review-pro/SKILL.md +152 -0
  229. package/template/.agent/skills/concise-planning/SKILL.md +68 -0
  230. package/template/.agent/skills/cross-layer-consistency/SKILL.md +117 -0
  231. package/template/.agent/skills/database-schema-design/SKILL.md +429 -0
  232. package/template/.agent/skills/deployment-procedures/SKILL.md +241 -0
  233. package/template/.agent/skills/design-anti-cliche/SKILL.md +159 -0
  234. package/template/.agent/skills/design-direction/SKILL.md +45 -0
  235. package/template/.agent/skills/error-handling-patterns/SKILL.md +721 -0
  236. package/template/.agent/skills/find-skills/SKILL.md +145 -0
  237. package/template/.agent/skills/git-advanced/SKILL.md +972 -0
  238. package/template/.agent/skills/git-workflow/SKILL.md +420 -0
  239. package/template/.agent/skills/idea-extraction/SKILL.md +271 -0
  240. package/template/.agent/skills/logging-best-practices/SKILL.md +851 -0
  241. package/template/.agent/skills/migration-management/SKILL.md +384 -0
  242. package/template/.agent/skills/minimalist-surgical-development/SKILL.md +69 -0
  243. package/template/.agent/skills/parallel-agents/SKILL.md +165 -0
  244. package/template/.agent/skills/parallel-debugging/SKILL.md +135 -0
  245. package/template/.agent/skills/parallel-feature-development/SKILL.md +166 -0
  246. package/template/.agent/skills/performance-budgeting/SKILL.md +144 -0
  247. package/template/.agent/skills/pipeline-rubrics/SKILL.md +51 -0
  248. package/template/.agent/skills/pipeline-rubrics/references/architecture-rubric.md +19 -0
  249. package/template/.agent/skills/pipeline-rubrics/references/be-rubric.md +21 -0
  250. package/template/.agent/skills/pipeline-rubrics/references/fe-rubric.md +20 -0
  251. package/template/.agent/skills/pipeline-rubrics/references/ia-rubric.md +19 -0
  252. package/template/.agent/skills/pipeline-rubrics/references/scoring.md +28 -0
  253. package/template/.agent/skills/pipeline-rubrics/references/vision-rubric.md +11 -0
  254. package/template/.agent/skills/prd-templates/SKILL.md +88 -0
  255. package/template/.agent/skills/prd-templates/references/architecture-design-template.md +88 -0
  256. package/template/.agent/skills/prd-templates/references/be-spec-template.md +101 -0
  257. package/template/.agent/skills/prd-templates/references/data-placement-template.md +74 -0
  258. package/template/.agent/skills/prd-templates/references/decomposition-templates.md +211 -0
  259. package/template/.agent/skills/prd-templates/references/design-system-decisions.md +198 -0
  260. package/template/.agent/skills/prd-templates/references/engineering-standards-template.md +124 -0
  261. package/template/.agent/skills/prd-templates/references/fe-classification-procedures.md +47 -0
  262. package/template/.agent/skills/prd-templates/references/fe-spec-template.md +84 -0
  263. package/template/.agent/skills/prd-templates/references/infrastructure-report-template.md +71 -0
  264. package/template/.agent/skills/prd-templates/references/operational-templates.md +116 -0
  265. package/template/.agent/skills/prd-templates/references/placeholder-guard-template.md +21 -0
  266. package/template/.agent/skills/prd-templates/references/surface-model.md +61 -0
  267. package/template/.agent/skills/prd-templates/references/vision-template.md +66 -0
  268. package/template/.agent/skills/prompt-engineer/README.md +659 -0
  269. package/template/.agent/skills/prompt-engineer/SKILL.md +249 -0
  270. package/template/.agent/skills/regex-patterns/SKILL.md +751 -0
  271. package/template/.agent/skills/resolve-ambiguity/SKILL.md +278 -0
  272. package/template/.agent/skills/rest-api-design/SKILL.md +478 -0
  273. package/template/.agent/skills/security-scanning-security-hardening/SKILL.md +231 -0
  274. package/template/.agent/skills/session-continuity/SKILL.md +730 -0
  275. package/template/.agent/skills/session-continuity/protocols/01-session-resumption.md +38 -0
  276. package/template/.agent/skills/session-continuity/protocols/02-progress-generation.md +85 -0
  277. package/template/.agent/skills/session-continuity/protocols/03-progress-update.md +70 -0
  278. package/template/.agent/skills/session-continuity/protocols/04-pattern-extraction.md +60 -0
  279. package/template/.agent/skills/session-continuity/protocols/05-session-close.md +37 -0
  280. package/template/.agent/skills/session-continuity/protocols/06-decision-analysis.md +84 -0
  281. package/template/.agent/skills/session-continuity/protocols/07-spec-pipeline-generation.md +48 -0
  282. package/template/.agent/skills/session-continuity/protocols/08-spec-pipeline-update.md +43 -0
  283. package/template/.agent/skills/session-continuity/protocols/09-parallel-claim.md +122 -0
  284. package/template/.agent/skills/session-continuity/protocols/10-placeholder-verification-gate.md +104 -0
  285. package/template/.agent/skills/session-continuity/protocols/ambiguity-gates.md +48 -0
  286. package/template/.agent/skills/skill-creator/LICENSE.txt +202 -0
  287. package/template/.agent/skills/skill-creator/README.md +270 -0
  288. package/template/.agent/skills/skill-creator/SKILL.md +590 -0
  289. package/template/.agent/skills/skill-creator/references/output-patterns.md +82 -0
  290. package/template/.agent/skills/skill-creator/references/workflows.md +28 -0
  291. package/template/.agent/skills/skill-creator/scripts/init_skill.py +303 -0
  292. package/template/.agent/skills/skill-creator/scripts/package_skill.py +110 -0
  293. package/template/.agent/skills/skill-creator/scripts/quick_validate.py +95 -0
  294. package/template/.agent/skills/spec-writing/SKILL.md +110 -0
  295. package/template/.agent/skills/systematic-debugging/CREATION-LOG.md +119 -0
  296. package/template/.agent/skills/systematic-debugging/SKILL.md +297 -0
  297. package/template/.agent/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
  298. package/template/.agent/skills/systematic-debugging/condition-based-waiting.md +115 -0
  299. package/template/.agent/skills/systematic-debugging/defense-in-depth.md +122 -0
  300. package/template/.agent/skills/systematic-debugging/find-polluter.sh +63 -0
  301. package/template/.agent/skills/systematic-debugging/root-cause-tracing.md +169 -0
  302. package/template/.agent/skills/systematic-debugging/test-academic.md +14 -0
  303. package/template/.agent/skills/systematic-debugging/test-pressure-1.md +58 -0
  304. package/template/.agent/skills/systematic-debugging/test-pressure-2.md +68 -0
  305. package/template/.agent/skills/systematic-debugging/test-pressure-3.md +69 -0
  306. package/template/.agent/skills/tdd-workflow/SKILL.md +409 -0
  307. package/template/.agent/skills/tech-stack-catalog/SKILL.md +49 -0
  308. package/template/.agent/skills/tech-stack-catalog/references/constraint-questions.md +21 -0
  309. package/template/.agent/skills/tech-stack-catalog/references/dev-tooling-decisions.md +37 -0
  310. package/template/.agent/skills/tech-stack-catalog/references/surface-decision-tables.md +69 -0
  311. package/template/.agent/skills/technical-writer/SKILL.md +242 -0
  312. package/template/.agent/skills/testing-strategist/SKILL.md +932 -0
  313. package/template/.agent/skills/verification-before-completion/SKILL.md +145 -0
  314. package/template/.agent/skills/workflow-automation/SKILL.md +73 -0
  315. package/template/.agent/workflows/audit-ambiguity-execute.md +165 -0
  316. package/template/.agent/workflows/audit-ambiguity-rubrics.md +83 -0
  317. package/template/.agent/workflows/audit-ambiguity.md +64 -0
  318. package/template/.agent/workflows/bootstrap-agents-fill.md +201 -0
  319. package/template/.agent/workflows/bootstrap-agents-provision.md +197 -0
  320. package/template/.agent/workflows/bootstrap-agents.md +66 -0
  321. package/template/.agent/workflows/create-prd-architecture.md +119 -0
  322. package/template/.agent/workflows/create-prd-compile.md +138 -0
  323. package/template/.agent/workflows/create-prd-design-system.md +135 -0
  324. package/template/.agent/workflows/create-prd-security.md +113 -0
  325. package/template/.agent/workflows/create-prd-stack.md +91 -0
  326. package/template/.agent/workflows/create-prd.md +168 -0
  327. package/template/.agent/workflows/decompose-architecture-structure.md +82 -0
  328. package/template/.agent/workflows/decompose-architecture-validate.md +119 -0
  329. package/template/.agent/workflows/decompose-architecture.md +111 -0
  330. package/template/.agent/workflows/evolve-contract.md +98 -0
  331. package/template/.agent/workflows/evolve-feature-cascade.md +140 -0
  332. package/template/.agent/workflows/evolve-feature-classify.md +116 -0
  333. package/template/.agent/workflows/evolve-feature.md +56 -0
  334. package/template/.agent/workflows/ideate-discover.md +144 -0
  335. package/template/.agent/workflows/ideate-extract.md +129 -0
  336. package/template/.agent/workflows/ideate-validate.md +117 -0
  337. package/template/.agent/workflows/ideate.md +113 -0
  338. package/template/.agent/workflows/implement-slice-setup.md +113 -0
  339. package/template/.agent/workflows/implement-slice-tdd.md +198 -0
  340. package/template/.agent/workflows/implement-slice.md +50 -0
  341. package/template/.agent/workflows/plan-phase.md +202 -0
  342. package/template/.agent/workflows/propagate-decision-apply.md +135 -0
  343. package/template/.agent/workflows/propagate-decision-scan.md +147 -0
  344. package/template/.agent/workflows/propagate-decision.md +56 -0
  345. package/template/.agent/workflows/remediate-pipeline-assess.md +138 -0
  346. package/template/.agent/workflows/remediate-pipeline-execute.md +135 -0
  347. package/template/.agent/workflows/remediate-pipeline.md +55 -0
  348. package/template/.agent/workflows/resolve-ambiguity.md +82 -0
  349. package/template/.agent/workflows/sync-kit.md +209 -0
  350. package/template/.agent/workflows/update-architecture-map.md +74 -0
  351. package/template/.agent/workflows/validate-phase.md +219 -0
  352. package/template/.agent/workflows/verify-infrastructure.md +207 -0
  353. package/template/.agent/workflows/write-architecture-spec-deepen.md +139 -0
  354. package/template/.agent/workflows/write-architecture-spec-design.md +202 -0
  355. package/template/.agent/workflows/write-architecture-spec.md +63 -0
  356. package/template/.agent/workflows/write-be-spec-classify.md +165 -0
  357. package/template/.agent/workflows/write-be-spec-write.md +98 -0
  358. package/template/.agent/workflows/write-be-spec.md +76 -0
  359. package/template/.agent/workflows/write-fe-spec-classify.md +170 -0
  360. package/template/.agent/workflows/write-fe-spec-write.md +94 -0
  361. package/template/.agent/workflows/write-fe-spec.md +71 -0
  362. package/template/AGENTS.md +176 -0
  363. package/template/GEMINI.md +177 -0
  364. package/template/docs/README.md +187 -0
  365. package/template/docs/audits/.gitkeep +0 -0
  366. package/template/docs/audits/README.md +10 -0
  367. package/template/docs/plans/.gitkeep +0 -0
  368. package/template/docs/plans/README.md +21 -0
  369. package/template/docs/plans/be/.gitkeep +0 -0
  370. package/template/docs/plans/be/README.md +11 -0
  371. package/template/docs/plans/fe/.gitkeep +0 -0
  372. package/template/docs/plans/fe/README.md +11 -0
  373. package/template/docs/plans/ia/.gitkeep +0 -0
  374. package/template/docs/plans/ia/README.md +17 -0
  375. package/template/docs/plans/ia/deep-dives/.gitkeep +0 -0
  376. package/template/docs/plans/ia/deep-dives/README.md +5 -0
  377. package/template/docs/plans/phases/.gitkeep +0 -0
  378. package/template/docs/plans/phases/README.md +11 -0
@@ -0,0 +1,675 @@
1
+ ---
2
+ name: form-handling-validation
3
+ description: "Comprehensive form patterns including client+server validation with shared Zod schemas, react-hook-form integration, multi-step wizards, file uploads, accessible error handling, and dirty state tracking. Use when building forms, validation flows, or form UX."
4
+ version: 1.0.0
5
+ ---
6
+
7
+ # Form Handling & Validation
8
+
9
+ Build forms that validate correctly on both client and server, communicate errors clearly, and handle edge cases like file uploads, multi-step flows, and unsaved changes.
10
+
11
+ ## Core Principle: Single Schema, Shared Validation
12
+
13
+ Define the validation schema once in Zod. Derive TypeScript types from it. Use the same schema on client and server.
14
+
15
+ ```typescript
16
+ // src/schemas/contact.schema.ts
17
+ import { z } from 'zod';
18
+
19
+ export const ContactFormSchema = z.object({
20
+ name: z.string().min(1, 'Name is required').max(100, 'Name must be under 100 characters'),
21
+ email: z.string().email('Please enter a valid email address'),
22
+ subject: z.enum(['support', 'sales', 'feedback'], {
23
+ errorMap: () => ({ message: 'Please select a subject' }),
24
+ }),
25
+ message: z.string()
26
+ .min(10, 'Message must be at least 10 characters')
27
+ .max(2000, 'Message must be under 2000 characters'),
28
+ attachments: z.array(z.instanceof(File)).max(3, 'Maximum 3 files allowed').optional(),
29
+ });
30
+
31
+ export type ContactFormData = z.infer<typeof ContactFormSchema>;
32
+ ```
33
+
34
+ **Server-side validation (API route):**
35
+ ```typescript
36
+ // src/pages/api/contact.ts
37
+ import { ContactFormSchema } from '@/schemas/contact.schema';
38
+
39
+ export async function POST({ request }: APIContext) {
40
+ const body = await request.json();
41
+ const result = ContactFormSchema.safeParse(body);
42
+
43
+ if (!result.success) {
44
+ return new Response(JSON.stringify({
45
+ error: 'Validation failed',
46
+ fields: result.error.flatten().fieldErrors,
47
+ }), { status: 422 });
48
+ }
49
+
50
+ // result.data is typed as ContactFormData
51
+ await sendContactEmail(result.data);
52
+ return new Response(JSON.stringify({ success: true }), { status: 200 });
53
+ }
54
+ ```
55
+
56
+ ---
57
+
58
+ ## react-hook-form Patterns
59
+
60
+ ### Basic Form with Zod Resolver
61
+
62
+ ```tsx
63
+ import { useForm } from 'react-hook-form';
64
+ import { zodResolver } from '@hookform/resolvers/zod';
65
+ import { ContactFormSchema, type ContactFormData } from '@/schemas/contact.schema';
66
+
67
+ function ContactForm() {
68
+ const {
69
+ register,
70
+ handleSubmit,
71
+ formState: { errors, isSubmitting, isDirty, isValid },
72
+ reset,
73
+ setError,
74
+ } = useForm<ContactFormData>({
75
+ resolver: zodResolver(ContactFormSchema),
76
+ defaultValues: {
77
+ name: '',
78
+ email: '',
79
+ subject: undefined,
80
+ message: '',
81
+ },
82
+ mode: 'onBlur', // Validate on blur, not on every keystroke
83
+ });
84
+
85
+ const onSubmit = async (data: ContactFormData) => {
86
+ const response = await fetch('/api/contact', {
87
+ method: 'POST',
88
+ headers: { 'Content-Type': 'application/json' },
89
+ body: JSON.stringify(data),
90
+ });
91
+
92
+ if (!response.ok) {
93
+ const body = await response.json();
94
+ // Map server errors back to fields
95
+ if (body.fields) {
96
+ for (const [field, messages] of Object.entries(body.fields)) {
97
+ setError(field as keyof ContactFormData, {
98
+ message: (messages as string[])[0],
99
+ });
100
+ }
101
+ } else {
102
+ setError('root', { message: body.error ?? 'Submission failed' });
103
+ }
104
+ return;
105
+ }
106
+
107
+ reset();
108
+ };
109
+
110
+ return (
111
+ <form onSubmit={handleSubmit(onSubmit)} noValidate>
112
+ {errors.root && (
113
+ <div role="alert" className="form-error-banner">
114
+ {errors.root.message}
115
+ </div>
116
+ )}
117
+
118
+ <div className="field-group">
119
+ <label htmlFor="name">Name</label>
120
+ <input
121
+ id="name"
122
+ type="text"
123
+ aria-invalid={!!errors.name}
124
+ aria-describedby={errors.name ? 'name-error' : undefined}
125
+ {...register('name')}
126
+ />
127
+ {errors.name && (
128
+ <p id="name-error" className="field-error" role="alert">
129
+ {errors.name.message}
130
+ </p>
131
+ )}
132
+ </div>
133
+
134
+ <button type="submit" disabled={isSubmitting}>
135
+ {isSubmitting ? 'Sending...' : 'Send Message'}
136
+ </button>
137
+ </form>
138
+ );
139
+ }
140
+ ```
141
+
142
+ ### Controller for Custom Components
143
+
144
+ Use `Controller` for components that do not expose a standard `ref` (selects, date pickers, rich text editors).
145
+
146
+ ```tsx
147
+ import { Controller, useForm } from 'react-hook-form';
148
+
149
+ function FormWithCustomSelect() {
150
+ const { control, handleSubmit } = useForm<ContactFormData>({
151
+ resolver: zodResolver(ContactFormSchema),
152
+ });
153
+
154
+ return (
155
+ <form onSubmit={handleSubmit(onSubmit)}>
156
+ <Controller
157
+ name="subject"
158
+ control={control}
159
+ render={({ field, fieldState }) => (
160
+ <div className="field-group">
161
+ <label htmlFor="subject">Subject</label>
162
+ <CustomSelect
163
+ id="subject"
164
+ options={subjectOptions}
165
+ value={field.value}
166
+ onChange={field.onChange}
167
+ onBlur={field.onBlur}
168
+ aria-invalid={!!fieldState.error}
169
+ aria-describedby={fieldState.error ? 'subject-error' : undefined}
170
+ />
171
+ {fieldState.error && (
172
+ <p id="subject-error" className="field-error" role="alert">
173
+ {fieldState.error.message}
174
+ </p>
175
+ )}
176
+ </div>
177
+ )}
178
+ />
179
+ </form>
180
+ );
181
+ }
182
+ ```
183
+
184
+ ---
185
+
186
+ ## Error Messaging UX
187
+
188
+ ### Timing
189
+
190
+ | Strategy | When to Validate | Best For |
191
+ |----------|-----------------|----------|
192
+ | `onBlur` | When field loses focus | Most forms --- gives user time to finish typing |
193
+ | `onChange` | Every keystroke after first blur | Password strength, character counters |
194
+ | `onSubmit` | Only on submit | Simple forms, less noise |
195
+ | `onTouched` | After first blur, then onChange | Recommended default for complex forms |
196
+
197
+ ### Inline Errors
198
+
199
+ ```tsx
200
+ // Reusable field error component
201
+ function FieldError({ id, error }: { id: string; error?: string }) {
202
+ if (!error) return null;
203
+
204
+ return (
205
+ <p id={id} className="field-error" role="alert">
206
+ <svg aria-hidden="true" className="error-icon">{/* icon */}</svg>
207
+ {error}
208
+ </p>
209
+ );
210
+ }
211
+ ```
212
+
213
+ ### Error Summary
214
+
215
+ Show an error summary at the top of the form on submit. Focus it so screen readers announce it.
216
+
217
+ ```tsx
218
+ function ErrorSummary({ errors }: { errors: Record<string, { message?: string }> }) {
219
+ const summaryRef = useRef<HTMLDivElement>(null);
220
+ const errorEntries = Object.entries(errors).filter(([, e]) => e.message);
221
+
222
+ useEffect(() => {
223
+ if (errorEntries.length > 0) {
224
+ summaryRef.current?.focus();
225
+ }
226
+ }, [errorEntries.length]);
227
+
228
+ if (errorEntries.length === 0) return null;
229
+
230
+ return (
231
+ <div ref={summaryRef} role="alert" tabIndex={-1} className="error-summary">
232
+ <h2>There {errorEntries.length === 1 ? 'is 1 error' : `are ${errorEntries.length} errors`}</h2>
233
+ <ul>
234
+ {errorEntries.map(([field, error]) => (
235
+ <li key={field}>
236
+ <a href={`#${field}`}>{error.message}</a>
237
+ </li>
238
+ ))}
239
+ </ul>
240
+ </div>
241
+ );
242
+ }
243
+ ```
244
+
245
+ ---
246
+
247
+ ## Multi-Step Forms (Wizard Pattern)
248
+
249
+ ### Schema Per Step
250
+
251
+ ```typescript
252
+ // Step schemas
253
+ export const PersonalInfoSchema = z.object({
254
+ firstName: z.string().min(1, 'First name is required'),
255
+ lastName: z.string().min(1, 'Last name is required'),
256
+ email: z.string().email('Please enter a valid email'),
257
+ });
258
+
259
+ export const AddressSchema = z.object({
260
+ street: z.string().min(1, 'Street is required'),
261
+ city: z.string().min(1, 'City is required'),
262
+ postalCode: z.string().regex(/^\d{5}$/, 'Enter a valid 5-digit postal code'),
263
+ });
264
+
265
+ export const PreferencesSchema = z.object({
266
+ newsletter: z.boolean(),
267
+ theme: z.enum(['light', 'dark', 'system']),
268
+ });
269
+
270
+ // Combined schema for final submission
271
+ export const RegistrationSchema = PersonalInfoSchema
272
+ .merge(AddressSchema)
273
+ .merge(PreferencesSchema);
274
+ ```
275
+
276
+ ### Multi-Step State Management
277
+
278
+ ```tsx
279
+ type WizardState = z.infer<typeof RegistrationSchema>;
280
+
281
+ function RegistrationWizard() {
282
+ const [step, setStep] = useState(0);
283
+ const [formData, setFormData] = useState<Partial<WizardState>>({});
284
+
285
+ const steps = [
286
+ { schema: PersonalInfoSchema, title: 'Personal Info', component: PersonalInfoStep },
287
+ { schema: AddressSchema, title: 'Address', component: AddressStep },
288
+ { schema: PreferencesSchema, title: 'Preferences', component: PreferencesStep },
289
+ ];
290
+
291
+ const currentStep = steps[step];
292
+
293
+ function handleStepComplete(stepData: Record<string, unknown>) {
294
+ const merged = { ...formData, ...stepData };
295
+ setFormData(merged);
296
+
297
+ if (step < steps.length - 1) {
298
+ setStep(step + 1);
299
+ } else {
300
+ // Final submission
301
+ const result = RegistrationSchema.safeParse(merged);
302
+ if (result.success) {
303
+ submitRegistration(result.data);
304
+ }
305
+ }
306
+ }
307
+
308
+ return (
309
+ <div>
310
+ {/* Progress indicator */}
311
+ <nav aria-label="Registration progress">
312
+ <ol>
313
+ {steps.map((s, i) => (
314
+ <li key={s.title} aria-current={i === step ? 'step' : undefined}>
315
+ <span className={i < step ? 'completed' : i === step ? 'current' : 'upcoming'}>
316
+ {s.title}
317
+ </span>
318
+ </li>
319
+ ))}
320
+ </ol>
321
+ </nav>
322
+
323
+ <h2>{currentStep.title}</h2>
324
+ <currentStep.component
325
+ defaultValues={formData}
326
+ schema={currentStep.schema}
327
+ onComplete={handleStepComplete}
328
+ onBack={step > 0 ? () => setStep(step - 1) : undefined}
329
+ />
330
+ </div>
331
+ );
332
+ }
333
+ ```
334
+
335
+ ### Persist State Across Page Reloads
336
+
337
+ ```typescript
338
+ function useFormPersistence<T>(key: string, defaultValues: T) {
339
+ const [state, setState] = useState<T>(() => {
340
+ if (typeof window === 'undefined') return defaultValues;
341
+ const saved = sessionStorage.getItem(key);
342
+ return saved ? JSON.parse(saved) : defaultValues;
343
+ });
344
+
345
+ useEffect(() => {
346
+ sessionStorage.setItem(key, JSON.stringify(state));
347
+ }, [key, state]);
348
+
349
+ function clear() {
350
+ sessionStorage.removeItem(key);
351
+ setState(defaultValues);
352
+ }
353
+
354
+ return [state, setState, clear] as const;
355
+ }
356
+ ```
357
+
358
+ ---
359
+
360
+ ## File Upload Handling
361
+
362
+ ### Zod Schema for Files
363
+
364
+ ```typescript
365
+ const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
366
+ const ACCEPTED_TYPES = ['image/jpeg', 'image/png', 'image/webp', 'application/pdf'];
367
+
368
+ export const FileUploadSchema = z.object({
369
+ files: z
370
+ .array(
371
+ z.instanceof(File)
372
+ .refine((file) => file.size <= MAX_FILE_SIZE, 'File must be under 5MB')
373
+ .refine((file) => ACCEPTED_TYPES.includes(file.type), 'Unsupported file type')
374
+ )
375
+ .min(1, 'At least one file is required')
376
+ .max(5, 'Maximum 5 files'),
377
+ });
378
+ ```
379
+
380
+ ### Drag-and-Drop Upload Component
381
+
382
+ ```tsx
383
+ function FileDropzone({ onFiles, maxFiles = 5 }: { onFiles: (files: File[]) => void; maxFiles?: number }) {
384
+ const [isDragging, setIsDragging] = useState(false);
385
+ const inputRef = useRef<HTMLInputElement>(null);
386
+
387
+ function handleDrop(event: React.DragEvent) {
388
+ event.preventDefault();
389
+ setIsDragging(false);
390
+ const files = Array.from(event.dataTransfer.files).slice(0, maxFiles);
391
+ onFiles(files);
392
+ }
393
+
394
+ function handleDragOver(event: React.DragEvent) {
395
+ event.preventDefault();
396
+ setIsDragging(true);
397
+ }
398
+
399
+ return (
400
+ <div
401
+ onDrop={handleDrop}
402
+ onDragOver={handleDragOver}
403
+ onDragLeave={() => setIsDragging(false)}
404
+ className={`dropzone ${isDragging ? 'dropzone--active' : ''}`}
405
+ role="button"
406
+ tabIndex={0}
407
+ aria-label="Upload files. Click or drag and drop."
408
+ onKeyDown={(e) => {
409
+ if (e.key === 'Enter' || e.key === ' ') {
410
+ e.preventDefault();
411
+ inputRef.current?.click();
412
+ }
413
+ }}
414
+ >
415
+ <input
416
+ ref={inputRef}
417
+ type="file"
418
+ multiple
419
+ accept={ACCEPTED_TYPES.join(',')}
420
+ onChange={(e) => onFiles(Array.from(e.target.files ?? []))}
421
+ className="visually-hidden"
422
+ aria-hidden="true"
423
+ tabIndex={-1}
424
+ />
425
+ <p>{isDragging ? 'Drop files here' : 'Drag files here or click to browse'}</p>
426
+ <p className="hint">Max {maxFiles} files, up to 5MB each. JPEG, PNG, WebP, or PDF.</p>
427
+ </div>
428
+ );
429
+ }
430
+ ```
431
+
432
+ ### Upload Progress
433
+
434
+ ```typescript
435
+ async function uploadWithProgress(
436
+ file: File,
437
+ url: string,
438
+ onProgress: (percent: number) => void
439
+ ): Promise<Response> {
440
+ return new Promise((resolve, reject) => {
441
+ const xhr = new XMLHttpRequest();
442
+ xhr.open('POST', url);
443
+
444
+ xhr.upload.addEventListener('progress', (event) => {
445
+ if (event.lengthComputable) {
446
+ onProgress(Math.round((event.loaded / event.total) * 100));
447
+ }
448
+ });
449
+
450
+ xhr.addEventListener('load', () => {
451
+ resolve(new Response(xhr.response, { status: xhr.status }));
452
+ });
453
+ xhr.addEventListener('error', () => reject(new Error('Upload failed')));
454
+
455
+ const formData = new FormData();
456
+ formData.append('file', file);
457
+ xhr.send(formData);
458
+ });
459
+ }
460
+ ```
461
+
462
+ ---
463
+
464
+ ## Autofill and Autocomplete
465
+
466
+ Use correct `autocomplete` attributes so browsers and password managers can assist users.
467
+
468
+ ```html
469
+ <!-- Login form -->
470
+ <input type="email" autocomplete="username" />
471
+ <input type="password" autocomplete="current-password" />
472
+
473
+ <!-- Registration form -->
474
+ <input type="text" autocomplete="given-name" />
475
+ <input type="text" autocomplete="family-name" />
476
+ <input type="email" autocomplete="email" />
477
+ <input type="password" autocomplete="new-password" />
478
+
479
+ <!-- Address form -->
480
+ <input type="text" autocomplete="street-address" />
481
+ <input type="text" autocomplete="address-level2" /> <!-- city -->
482
+ <input type="text" autocomplete="postal-code" />
483
+ <select autocomplete="country">...</select>
484
+
485
+ <!-- Payment form -->
486
+ <input type="text" autocomplete="cc-name" />
487
+ <input type="text" autocomplete="cc-number" inputmode="numeric" />
488
+ <input type="text" autocomplete="cc-exp" />
489
+ <input type="text" autocomplete="cc-csc" />
490
+
491
+ <!-- One-time codes (MFA) -->
492
+ <input type="text" autocomplete="one-time-code" inputmode="numeric" />
493
+ ```
494
+
495
+ ---
496
+
497
+ ## Double-Submission Prevention
498
+
499
+ ```tsx
500
+ function SubmitButton({ isSubmitting, label = 'Submit' }: { isSubmitting: boolean; label?: string }) {
501
+ return (
502
+ <button type="submit" disabled={isSubmitting} aria-busy={isSubmitting}>
503
+ {isSubmitting ? (
504
+ <>
505
+ <span className="spinner" aria-hidden="true" />
506
+ <span>Submitting...</span>
507
+ </>
508
+ ) : (
509
+ label
510
+ )}
511
+ </button>
512
+ );
513
+ }
514
+ ```
515
+
516
+ **Server-side idempotency:**
517
+ ```typescript
518
+ // Include an idempotency key in the form
519
+ const idempotencyKey = crypto.randomUUID();
520
+
521
+ // Server checks: if this key was already processed, return the cached response
522
+ ```
523
+
524
+ ---
525
+
526
+ ## Dirty State and Unsaved Changes Warning
527
+
528
+ ```tsx
529
+ function useUnsavedChangesWarning(isDirty: boolean): void {
530
+ useEffect(() => {
531
+ if (!isDirty) return;
532
+
533
+ function handleBeforeUnload(event: BeforeUnloadEvent) {
534
+ event.preventDefault();
535
+ // Modern browsers ignore custom messages but still show the prompt
536
+ event.returnValue = '';
537
+ }
538
+
539
+ window.addEventListener('beforeunload', handleBeforeUnload);
540
+ return () => window.removeEventListener('beforeunload', handleBeforeUnload);
541
+ }, [isDirty]);
542
+ }
543
+
544
+ // Usage in form component
545
+ function EditProfileForm() {
546
+ const { formState: { isDirty }, handleSubmit, reset } = useForm(/* ... */);
547
+
548
+ useUnsavedChangesWarning(isDirty);
549
+
550
+ // For SPA navigation, also intercept route changes:
551
+ // - React Router: useBlocker() or <Prompt />
552
+ // - Next.js: router.events.on('routeChangeStart', handler)
553
+ }
554
+ ```
555
+
556
+ ---
557
+
558
+ ## Dynamic Form Fields
559
+
560
+ ### Field Arrays
561
+
562
+ ```tsx
563
+ import { useFieldArray, useForm } from 'react-hook-form';
564
+
565
+ const InvoiceSchema = z.object({
566
+ lineItems: z.array(z.object({
567
+ description: z.string().min(1, 'Description required'),
568
+ quantity: z.number().min(1, 'Minimum 1'),
569
+ unitPrice: z.number().min(0, 'Price cannot be negative'),
570
+ })).min(1, 'At least one line item is required'),
571
+ });
572
+
573
+ function InvoiceForm() {
574
+ const { control, register, handleSubmit } = useForm({
575
+ resolver: zodResolver(InvoiceSchema),
576
+ defaultValues: { lineItems: [{ description: '', quantity: 1, unitPrice: 0 }] },
577
+ });
578
+
579
+ const { fields, append, remove } = useFieldArray({ control, name: 'lineItems' });
580
+
581
+ return (
582
+ <form onSubmit={handleSubmit(onSubmit)}>
583
+ <fieldset>
584
+ <legend>Line Items</legend>
585
+ {fields.map((field, index) => (
586
+ <div key={field.id} className="line-item-row">
587
+ <input {...register(`lineItems.${index}.description`)}
588
+ aria-label={`Item ${index + 1} description`} />
589
+ <input {...register(`lineItems.${index}.quantity`, { valueAsNumber: true })}
590
+ type="number" aria-label={`Item ${index + 1} quantity`} />
591
+ <input {...register(`lineItems.${index}.unitPrice`, { valueAsNumber: true })}
592
+ type="number" step="0.01" aria-label={`Item ${index + 1} unit price`} />
593
+ <button type="button" onClick={() => remove(index)}
594
+ aria-label={`Remove item ${index + 1}`}>
595
+ Remove
596
+ </button>
597
+ </div>
598
+ ))}
599
+ <button type="button" onClick={() => append({ description: '', quantity: 1, unitPrice: 0 })}>
600
+ Add line item
601
+ </button>
602
+ </fieldset>
603
+ </form>
604
+ );
605
+ }
606
+ ```
607
+
608
+ ### Conditional Fields
609
+
610
+ ```typescript
611
+ // Schema with conditional validation
612
+ const EventSchema = z.discriminatedUnion('type', [
613
+ z.object({
614
+ type: z.literal('in-person'),
615
+ venue: z.string().min(1, 'Venue is required for in-person events'),
616
+ capacity: z.number().min(1),
617
+ }),
618
+ z.object({
619
+ type: z.literal('virtual'),
620
+ meetingUrl: z.string().url('Please enter a valid URL'),
621
+ }),
622
+ ]);
623
+ ```
624
+
625
+ ```tsx
626
+ function EventForm() {
627
+ const { watch, register } = useForm({ resolver: zodResolver(EventSchema) });
628
+ const eventType = watch('type');
629
+
630
+ return (
631
+ <form>
632
+ <select {...register('type')}>
633
+ <option value="in-person">In-Person</option>
634
+ <option value="virtual">Virtual</option>
635
+ </select>
636
+
637
+ {eventType === 'in-person' && (
638
+ <>
639
+ <input {...register('venue')} placeholder="Venue name" />
640
+ <input {...register('capacity', { valueAsNumber: true })} type="number" />
641
+ </>
642
+ )}
643
+
644
+ {eventType === 'virtual' && (
645
+ <input {...register('meetingUrl')} placeholder="https://meet.example.com/..." />
646
+ )}
647
+ </form>
648
+ );
649
+ }
650
+ ```
651
+
652
+ ---
653
+
654
+ ## Common Anti-Patterns
655
+
656
+ | Anti-Pattern | Why It Is Wrong | Correct Approach |
657
+ |-------------|-----------------|------------------|
658
+ | Validate only on client | Server receives unvalidated data | Use the same Zod schema on both client and server |
659
+ | Validate only on submit | User discovers all errors at once | Validate on blur, show errors inline |
660
+ | `placeholder` as label | Disappears on input, fails a11y | Use `<label>`, placeholder is a hint only |
661
+ | Alert on every keystroke | Noisy, especially for screen readers | Debounce validation, validate on blur |
662
+ | Reset form on error | User loses all input | Keep values, highlight errors |
663
+ | Disable submit until valid | User cannot discover what is wrong | Keep button enabled, show errors on submit |
664
+ | Generic "Something went wrong" | User cannot fix the problem | Show field-level errors with corrective guidance |
665
+ | No loading state on submit | User clicks multiple times | Disable button + show spinner during submission |
666
+ | Custom validation before Zod | Two sources of truth | Put all validation in the Zod schema |
667
+ | `required` without `aria-required` | Screen readers may not announce | Use both `required` and `aria-required="true"` |
668
+
669
+ ## References
670
+
671
+ - [react-hook-form docs](https://react-hook-form.com/)
672
+ - [Zod docs](https://zod.dev/)
673
+ - [@hookform/resolvers](https://github.com/react-hook-form/resolvers)
674
+ - [WAI Forms Tutorial](https://www.w3.org/WAI/tutorials/forms/)
675
+ - [GOV.UK Form Design Patterns](https://design-system.service.gov.uk/patterns/)