contextos-agents 1.7.0 → 2.0.0-beta.3

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 (313) hide show
  1. package/.agents/AGENTS.md +16 -50
  2. package/.agents/adapters/aider/export.js +117 -99
  3. package/.agents/adapters/claude/export.js +68 -26
  4. package/.agents/adapters/copilot/export.js +90 -53
  5. package/.agents/adapters/cursor/export.js +100 -104
  6. package/.agents/adapters/drift-detector.js +196 -0
  7. package/.agents/adapters/gemini/export.js +76 -45
  8. package/.agents/adapters/pure-compiler.js +443 -0
  9. package/.agents/adapters/zed/export.js +104 -96
  10. package/.agents/compiled/registry.v2.json +504 -0
  11. package/.agents/compiled/registry.v2.sha256 +1 -0
  12. package/.agents/compiler/manifest-compiler.js +963 -0
  13. package/.agents/compiler/vendor/yaml.LICENSE.txt +13 -0
  14. package/.agents/compiler/vendor/yaml.SBOM.json +6 -0
  15. package/.agents/compiler/vendor/yaml.js +139 -0
  16. package/.agents/core/profiles/init.yaml +25 -0
  17. package/.agents/core/skills/context-manager/skill.yaml +3 -5
  18. package/.agents/core/skills/context-os/SKILL.md +3 -6
  19. package/.agents/core/skills/context-os/skill.yaml +3 -8
  20. package/.agents/core/skills/engineering-workflow/skill.yaml +1 -7
  21. package/.agents/core/skills/gemini-precision/skill.yaml +1 -6
  22. package/.agents/core/skills/gstack-roles/skill.yaml +3 -6
  23. package/.agents/core/skills/ponytail-mindset/skill.yaml +1 -7
  24. package/.agents/core/skills/security/skill.yaml +15 -3
  25. package/.agents/ctx.js +537 -112
  26. package/.agents/customization-dx.js +282 -0
  27. package/.agents/doctor.js +855 -66
  28. package/.agents/filesystem/index.js +71 -0
  29. package/.agents/filesystem/journaled-transaction.js +451 -0
  30. package/.agents/filesystem/lockfile-v2.js +275 -0
  31. package/.agents/filesystem/platform-hardening.js +222 -0
  32. package/.agents/filesystem/project-lock.js +218 -0
  33. package/.agents/filesystem/safe-path.js +256 -0
  34. package/.agents/generated/claude/skills/context-os/SKILL.md +1 -1
  35. package/.agents/generated/gemini/skills/context-os/SKILL.md +2 -2
  36. package/.agents/plugins/contextos/plugin.json +1 -1
  37. package/.agents/plugins.js +278 -64
  38. package/.agents/profiles.js +486 -51
  39. package/.agents/resolver/canonical-resolver.js +1348 -0
  40. package/.agents/resolver.js +50 -534
  41. package/.agents/rules/rule-catalog.js +525 -0
  42. package/.agents/schemas/attestation.review.v1.json +111 -0
  43. package/.agents/schemas/attestation.verification.v1.json +85 -0
  44. package/.agents/schemas/lockfile.v2.schema.json +134 -0
  45. package/.agents/schemas/profile.v2.schema.json +114 -0
  46. package/.agents/schemas/runtime.thread.v1.json +192 -0
  47. package/.agents/schemas/skill.manifest.v2.json +177 -0
  48. package/.agents/schemas/verification.spec.v1.json +39 -0
  49. package/.agents/schemas/workspace.graph.schema.json +106 -0
  50. package/.agents/skills-index.json +6 -166
  51. package/.agents/stats.js +9 -9
  52. package/.agents/transaction-core/event-store.js +288 -0
  53. package/.agents/transaction-core/idempotency.js +129 -0
  54. package/.agents/transaction-core/ipc-lock.js +311 -0
  55. package/.agents/transaction-core/plugin-supply-chain-bundle.js +436 -0
  56. package/.agents/validate.js +44 -1
  57. package/.agents/watch.js +354 -102
  58. package/.agents/workspace/workspace-graph.js +778 -0
  59. package/README.md +59 -387
  60. package/benchmarks/v2/analysis/statistics.js +140 -0
  61. package/benchmarks/v2/analysis/stats.js +69 -0
  62. package/benchmarks/v2/arms/arm-definitions.js +79 -0
  63. package/benchmarks/v2/dataset.schema.json +34 -0
  64. package/benchmarks/v2/evaluators/index.js +25 -0
  65. package/benchmarks/v2/evaluators/verified-success.js +116 -0
  66. package/benchmarks/v2/harness/runner.js +88 -0
  67. package/benchmarks/v2/pilot-tasks.json +392 -0
  68. package/bin/commands/recover.js +88 -0
  69. package/bin/commands/update.js +80 -17
  70. package/bin/commands.js +62 -25
  71. package/bin/index.js +138 -81
  72. package/bin/lib/lockfile.js +5 -3
  73. package/bin/lib/safe-writer.js +34 -3
  74. package/package.json +87 -72
  75. package/registry.json +2 -2
  76. package/registry.v2.schema.json +86 -0
  77. package/.agents/core/profiles/backend.yaml +0 -47
  78. package/.agents/core/profiles/enterprise.yaml +0 -46
  79. package/.agents/core/profiles/frontend.yaml +0 -46
  80. package/.agents/core/profiles/hackathon.yaml +0 -45
  81. package/.agents/core/profiles/mvp.yaml +0 -44
  82. package/.agents/core/profiles/startup.yaml +0 -48
  83. package/.agents/core/skills/adapters/EXAMPLES.md +0 -19
  84. package/.agents/core/skills/adapters/SKILL.md +0 -105
  85. package/.agents/core/skills/adapters/TROUBLESHOOTING.md +0 -7
  86. package/.agents/core/skills/adapters/VALIDATION.json +0 -12
  87. package/.agents/core/skills/adapters/skill.yaml +0 -16
  88. package/.agents/core/skills/architecture-diagrams/SKILL.md +0 -108
  89. package/.agents/core/skills/architecture-diagrams/VALIDATION.json +0 -12
  90. package/.agents/core/skills/architecture-diagrams/skill.yaml +0 -12
  91. package/.agents/core/skills/brutalist-design/SKILL.md +0 -150
  92. package/.agents/core/skills/brutalist-design/VALIDATION.json +0 -12
  93. package/.agents/core/skills/brutalist-design/skill.yaml +0 -12
  94. package/.agents/core/skills/database/EXAMPLES.md +0 -74
  95. package/.agents/core/skills/database/SKILL.md +0 -101
  96. package/.agents/core/skills/database/TROUBLESHOOTING.md +0 -18
  97. package/.agents/core/skills/database/VALIDATION.json +0 -11
  98. package/.agents/core/skills/database/skill.yaml +0 -31
  99. package/.agents/core/skills/ddd/EXAMPLES.md +0 -42
  100. package/.agents/core/skills/ddd/SKILL.md +0 -247
  101. package/.agents/core/skills/ddd/TROUBLESHOOTING.md +0 -19
  102. package/.agents/core/skills/ddd/VALIDATION.json +0 -12
  103. package/.agents/core/skills/ddd/ddd.md +0 -178
  104. package/.agents/core/skills/ddd/skill.yaml +0 -17
  105. package/.agents/core/skills/decisions/EXAMPLES.md +0 -35
  106. package/.agents/core/skills/decisions/SKILL.md +0 -90
  107. package/.agents/core/skills/decisions/TROUBLESHOOTING.md +0 -13
  108. package/.agents/core/skills/decisions/VALIDATION.json +0 -12
  109. package/.agents/core/skills/decisions/skill.yaml +0 -16
  110. package/.agents/core/skills/docker/EXAMPLES.md +0 -56
  111. package/.agents/core/skills/docker/SKILL.md +0 -63
  112. package/.agents/core/skills/docker/TROUBLESHOOTING.md +0 -18
  113. package/.agents/core/skills/docker/VALIDATION.json +0 -11
  114. package/.agents/core/skills/docker/skill.yaml +0 -29
  115. package/.agents/core/skills/fastapi/EXAMPLES.md +0 -36
  116. package/.agents/core/skills/fastapi/SKILL.md +0 -148
  117. package/.agents/core/skills/fastapi/TROUBLESHOOTING.md +0 -19
  118. package/.agents/core/skills/fastapi/VALIDATION.json +0 -12
  119. package/.agents/core/skills/fastapi/fastapi.md +0 -112
  120. package/.agents/core/skills/fastapi/skill.yaml +0 -17
  121. package/.agents/core/skills/generators/EXAMPLES.md +0 -19
  122. package/.agents/core/skills/generators/SKILL.md +0 -112
  123. package/.agents/core/skills/generators/TROUBLESHOOTING.md +0 -7
  124. package/.agents/core/skills/generators/VALIDATION.json +0 -12
  125. package/.agents/core/skills/generators/skill.yaml +0 -25
  126. package/.agents/core/skills/generators/templates/API.md +0 -77
  127. package/.agents/core/skills/generators/templates/ARCHITECTURE.md +0 -70
  128. package/.agents/core/skills/generators/templates/DATABASE.md +0 -42
  129. package/.agents/core/skills/generators/templates/DECISION.md +0 -46
  130. package/.agents/core/skills/generators/templates/PRD.md +0 -67
  131. package/.agents/core/skills/generators/templates/PROJECT_GRAPH.md +0 -56
  132. package/.agents/core/skills/generators/templates/ROADMAP.md +0 -51
  133. package/.agents/core/skills/generators/templates/TASKS.md +0 -43
  134. package/.agents/core/skills/generators/templates/UI.md +0 -73
  135. package/.agents/core/skills/graphify/EXAMPLES.md +0 -73
  136. package/.agents/core/skills/graphify/SKILL.md +0 -130
  137. package/.agents/core/skills/graphify/VALIDATION.json +0 -12
  138. package/.agents/core/skills/graphify/skill.yaml +0 -18
  139. package/.agents/core/skills/impeccable-design/EXAMPLES.md +0 -26
  140. package/.agents/core/skills/impeccable-design/SKILL.md +0 -201
  141. package/.agents/core/skills/impeccable-design/TROUBLESHOOTING.md +0 -19
  142. package/.agents/core/skills/impeccable-design/VALIDATION.json +0 -12
  143. package/.agents/core/skills/impeccable-design/skill.yaml +0 -20
  144. package/.agents/core/skills/interview-me/SKILL.md +0 -97
  145. package/.agents/core/skills/interview-me/VALIDATION.json +0 -12
  146. package/.agents/core/skills/interview-me/skill.yaml +0 -12
  147. package/.agents/core/skills/microservices/EXAMPLES.md +0 -38
  148. package/.agents/core/skills/microservices/SKILL.md +0 -164
  149. package/.agents/core/skills/microservices/TROUBLESHOOTING.md +0 -19
  150. package/.agents/core/skills/microservices/VALIDATION.json +0 -12
  151. package/.agents/core/skills/microservices/microservices.md +0 -119
  152. package/.agents/core/skills/microservices/skill.yaml +0 -17
  153. package/.agents/core/skills/minimalist-design/SKILL.md +0 -113
  154. package/.agents/core/skills/minimalist-design/VALIDATION.json +0 -12
  155. package/.agents/core/skills/minimalist-design/skill.yaml +0 -12
  156. package/.agents/core/skills/nestjs/EXAMPLES.md +0 -40
  157. package/.agents/core/skills/nestjs/SKILL.md +0 -139
  158. package/.agents/core/skills/nestjs/TROUBLESHOOTING.md +0 -19
  159. package/.agents/core/skills/nestjs/VALIDATION.json +0 -12
  160. package/.agents/core/skills/nestjs/nestjs.md +0 -103
  161. package/.agents/core/skills/nestjs/skill.yaml +0 -17
  162. package/.agents/core/skills/nextjs/EXAMPLES.md +0 -40
  163. package/.agents/core/skills/nextjs/SKILL.md +0 -163
  164. package/.agents/core/skills/nextjs/TROUBLESHOOTING.md +0 -19
  165. package/.agents/core/skills/nextjs/VALIDATION.json +0 -12
  166. package/.agents/core/skills/nextjs/nextjs.md +0 -67
  167. package/.agents/core/skills/nextjs/skill.yaml +0 -17
  168. package/.agents/core/skills/node/EXAMPLES.md +0 -80
  169. package/.agents/core/skills/node/SKILL.md +0 -128
  170. package/.agents/core/skills/node/TROUBLESHOOTING.md +0 -19
  171. package/.agents/core/skills/node/VALIDATION.json +0 -12
  172. package/.agents/core/skills/node/node.md +0 -87
  173. package/.agents/core/skills/node/skill.yaml +0 -17
  174. package/.agents/core/skills/performance/EXAMPLES.md +0 -30
  175. package/.agents/core/skills/performance/SKILL.md +0 -75
  176. package/.agents/core/skills/performance/TROUBLESHOOTING.md +0 -19
  177. package/.agents/core/skills/performance/VALIDATION.json +0 -12
  178. package/.agents/core/skills/performance/performance.md +0 -52
  179. package/.agents/core/skills/performance/skill.yaml +0 -17
  180. package/.agents/core/skills/react/EXAMPLES.md +0 -79
  181. package/.agents/core/skills/react/SKILL.md +0 -132
  182. package/.agents/core/skills/react/TROUBLESHOOTING.md +0 -19
  183. package/.agents/core/skills/react/VALIDATION.json +0 -12
  184. package/.agents/core/skills/react/react.md +0 -93
  185. package/.agents/core/skills/react/skill.yaml +0 -17
  186. package/.agents/core/skills/react-best-practices/SKILL.md +0 -155
  187. package/.agents/core/skills/react-best-practices/VALIDATION.json +0 -12
  188. package/.agents/core/skills/react-best-practices/skill.yaml +0 -14
  189. package/.agents/core/skills/redesign-audit/SKILL.md +0 -117
  190. package/.agents/core/skills/redesign-audit/VALIDATION.json +0 -12
  191. package/.agents/core/skills/redesign-audit/skill.yaml +0 -12
  192. package/.agents/core/skills/soft-design/SKILL.md +0 -108
  193. package/.agents/core/skills/soft-design/VALIDATION.json +0 -12
  194. package/.agents/core/skills/soft-design/skill.yaml +0 -12
  195. package/.agents/core/skills/state-management/EXAMPLES.md +0 -56
  196. package/.agents/core/skills/state-management/SKILL.md +0 -48
  197. package/.agents/core/skills/state-management/TROUBLESHOOTING.md +0 -18
  198. package/.agents/core/skills/state-management/VALIDATION.json +0 -11
  199. package/.agents/core/skills/state-management/skill.yaml +0 -28
  200. package/.agents/core/skills/subagent-orchestrator/SKILL.md +0 -117
  201. package/.agents/core/skills/subagent-orchestrator/VALIDATION.json +0 -12
  202. package/.agents/core/skills/subagent-orchestrator/skill.yaml +0 -12
  203. package/.agents/core/skills/system-design/EXAMPLES.md +0 -75
  204. package/.agents/core/skills/system-design/SKILL.md +0 -419
  205. package/.agents/core/skills/system-design/TROUBLESHOOTING.md +0 -19
  206. package/.agents/core/skills/system-design/VALIDATION.json +0 -12
  207. package/.agents/core/skills/system-design/skill.yaml +0 -20
  208. package/.agents/core/skills/system-design/system-design.md +0 -112
  209. package/.agents/core/skills/testing/EXAMPLES.md +0 -71
  210. package/.agents/core/skills/testing/SKILL.md +0 -70
  211. package/.agents/core/skills/testing/TROUBLESHOOTING.md +0 -18
  212. package/.agents/core/skills/testing/VALIDATION.json +0 -11
  213. package/.agents/core/skills/testing/skill.yaml +0 -32
  214. package/.agents/core/skills/typescript/EXAMPLES.md +0 -64
  215. package/.agents/core/skills/typescript/SKILL.md +0 -112
  216. package/.agents/core/skills/typescript/TROUBLESHOOTING.md +0 -19
  217. package/.agents/core/skills/typescript/VALIDATION.json +0 -12
  218. package/.agents/core/skills/typescript/skill.yaml +0 -17
  219. package/.agents/core/skills/typescript/typescript.md +0 -71
  220. package/.agents/core/skills/ui-design/EXAMPLES.md +0 -21
  221. package/.agents/core/skills/ui-design/SKILL.md +0 -124
  222. package/.agents/core/skills/ui-design/TROUBLESHOOTING.md +0 -19
  223. package/.agents/core/skills/ui-design/VALIDATION.json +0 -12
  224. package/.agents/core/skills/ui-design/skill.yaml +0 -17
  225. package/.agents/core/skills/ui-design/ui.md +0 -88
  226. package/.agents/core/skills/ui-ux-pro/EXAMPLES.md +0 -62
  227. package/.agents/core/skills/ui-ux-pro/SKILL.md +0 -375
  228. package/.agents/core/skills/ui-ux-pro/TROUBLESHOOTING.md +0 -19
  229. package/.agents/core/skills/ui-ux-pro/VALIDATION.json +0 -12
  230. package/.agents/core/skills/ui-ux-pro/skill.yaml +0 -19
  231. package/.agents/core/skills/ux-design/EXAMPLES.md +0 -36
  232. package/.agents/core/skills/ux-design/SKILL.md +0 -116
  233. package/.agents/core/skills/ux-design/TROUBLESHOOTING.md +0 -19
  234. package/.agents/core/skills/ux-design/VALIDATION.json +0 -12
  235. package/.agents/core/skills/ux-design/skill.yaml +0 -17
  236. package/.agents/core/skills/ux-design/ux.md +0 -80
  237. package/.agents/core/skills/vercel-optimize/SKILL.md +0 -83
  238. package/.agents/core/skills/vercel-optimize/VALIDATION.json +0 -12
  239. package/.agents/core/skills/vercel-optimize/scripts/collect-signals.mjs +0 -131
  240. package/.agents/core/skills/vercel-optimize/scripts/gate-investigations.mjs +0 -142
  241. package/.agents/core/skills/vercel-optimize/scripts/merge-signals.mjs +0 -143
  242. package/.agents/core/skills/vercel-optimize/scripts/scan-codebase.mjs +0 -174
  243. package/.agents/core/skills/vercel-optimize/skill.yaml +0 -18
  244. package/.agents/core/skills/web-accessibility/EXAMPLES.md +0 -39
  245. package/.agents/core/skills/web-accessibility/SKILL.md +0 -170
  246. package/.agents/core/skills/web-accessibility/TROUBLESHOOTING.md +0 -19
  247. package/.agents/core/skills/web-accessibility/VALIDATION.json +0 -12
  248. package/.agents/core/skills/web-accessibility/accessibility.md +0 -63
  249. package/.agents/core/skills/web-accessibility/skill.yaml +0 -17
  250. package/.agents/generated/claude/skills/adapters/SKILL.md +0 -126
  251. package/.agents/generated/claude/skills/architecture-diagrams/SKILL.md +0 -101
  252. package/.agents/generated/claude/skills/brutalist-design/SKILL.md +0 -145
  253. package/.agents/generated/claude/skills/database/SKILL.md +0 -191
  254. package/.agents/generated/claude/skills/ddd/SKILL.md +0 -305
  255. package/.agents/generated/claude/skills/decisions/SKILL.md +0 -134
  256. package/.agents/generated/claude/skills/docker/SKILL.md +0 -135
  257. package/.agents/generated/claude/skills/fastapi/SKILL.md +0 -200
  258. package/.agents/generated/claude/skills/generators/SKILL.md +0 -133
  259. package/.agents/generated/claude/skills/graphify/SKILL.md +0 -198
  260. package/.agents/generated/claude/skills/impeccable-design/SKILL.md +0 -241
  261. package/.agents/generated/claude/skills/interview-me/SKILL.md +0 -90
  262. package/.agents/generated/claude/skills/microservices/SKILL.md +0 -218
  263. package/.agents/generated/claude/skills/minimalist-design/SKILL.md +0 -108
  264. package/.agents/generated/claude/skills/nestjs/SKILL.md +0 -195
  265. package/.agents/generated/claude/skills/nextjs/SKILL.md +0 -219
  266. package/.agents/generated/claude/skills/node/SKILL.md +0 -224
  267. package/.agents/generated/claude/skills/performance/SKILL.md +0 -121
  268. package/.agents/generated/claude/skills/react/SKILL.md +0 -227
  269. package/.agents/generated/claude/skills/react-best-practices/SKILL.md +0 -146
  270. package/.agents/generated/claude/skills/redesign-audit/SKILL.md +0 -112
  271. package/.agents/generated/claude/skills/soft-design/SKILL.md +0 -103
  272. package/.agents/generated/claude/skills/state-management/SKILL.md +0 -120
  273. package/.agents/generated/claude/skills/subagent-orchestrator/SKILL.md +0 -110
  274. package/.agents/generated/claude/skills/system-design/SKILL.md +0 -507
  275. package/.agents/generated/claude/skills/testing/SKILL.md +0 -157
  276. package/.agents/generated/claude/skills/typescript/SKILL.md +0 -192
  277. package/.agents/generated/claude/skills/ui-design/SKILL.md +0 -161
  278. package/.agents/generated/claude/skills/ui-ux-pro/SKILL.md +0 -451
  279. package/.agents/generated/claude/skills/ux-design/SKILL.md +0 -168
  280. package/.agents/generated/claude/skills/vercel-optimize/SKILL.md +0 -76
  281. package/.agents/generated/claude/skills/web-accessibility/SKILL.md +0 -225
  282. package/.agents/generated/gemini/skills/adapters/SKILL.md +0 -135
  283. package/.agents/generated/gemini/skills/architecture-diagrams/SKILL.md +0 -107
  284. package/.agents/generated/gemini/skills/brutalist-design/SKILL.md +0 -151
  285. package/.agents/generated/gemini/skills/database/SKILL.md +0 -200
  286. package/.agents/generated/gemini/skills/ddd/SKILL.md +0 -314
  287. package/.agents/generated/gemini/skills/decisions/SKILL.md +0 -143
  288. package/.agents/generated/gemini/skills/docker/SKILL.md +0 -144
  289. package/.agents/generated/gemini/skills/fastapi/SKILL.md +0 -209
  290. package/.agents/generated/gemini/skills/generators/SKILL.md +0 -142
  291. package/.agents/generated/gemini/skills/graphify/SKILL.md +0 -205
  292. package/.agents/generated/gemini/skills/impeccable-design/SKILL.md +0 -250
  293. package/.agents/generated/gemini/skills/interview-me/SKILL.md +0 -96
  294. package/.agents/generated/gemini/skills/microservices/SKILL.md +0 -227
  295. package/.agents/generated/gemini/skills/minimalist-design/SKILL.md +0 -114
  296. package/.agents/generated/gemini/skills/nestjs/SKILL.md +0 -204
  297. package/.agents/generated/gemini/skills/nextjs/SKILL.md +0 -298
  298. package/.agents/generated/gemini/skills/node/SKILL.md +0 -323
  299. package/.agents/generated/gemini/skills/performance/SKILL.md +0 -185
  300. package/.agents/generated/gemini/skills/react/SKILL.md +0 -332
  301. package/.agents/generated/gemini/skills/react-best-practices/SKILL.md +0 -152
  302. package/.agents/generated/gemini/skills/redesign-audit/SKILL.md +0 -118
  303. package/.agents/generated/gemini/skills/soft-design/SKILL.md +0 -109
  304. package/.agents/generated/gemini/skills/state-management/SKILL.md +0 -129
  305. package/.agents/generated/gemini/skills/subagent-orchestrator/SKILL.md +0 -116
  306. package/.agents/generated/gemini/skills/system-design/SKILL.md +0 -631
  307. package/.agents/generated/gemini/skills/testing/SKILL.md +0 -166
  308. package/.agents/generated/gemini/skills/typescript/SKILL.md +0 -275
  309. package/.agents/generated/gemini/skills/ui-design/SKILL.md +0 -170
  310. package/.agents/generated/gemini/skills/ui-ux-pro/SKILL.md +0 -460
  311. package/.agents/generated/gemini/skills/ux-design/SKILL.md +0 -177
  312. package/.agents/generated/gemini/skills/vercel-optimize/SKILL.md +0 -82
  313. package/.agents/generated/gemini/skills/web-accessibility/SKILL.md +0 -300
@@ -1,142 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * gate-investigations.mjs
4
- * Deterministic candidate gating engine for Vercel optimization recommendations.
5
- *
6
- * Usage:
7
- * node scripts/gate-investigations.mjs <signals-file> [--threshold <n>] [--out <file>] [--help]
8
- */
9
-
10
- import { readFileSync, writeFileSync, existsSync } from 'node:fs';
11
- import { resolve } from 'node:path';
12
-
13
- function printHelp() {
14
- console.log(`
15
- gate-investigations.mjs — Optimization Candidate Gating Engine
16
-
17
- Usage:
18
- node scripts/gate-investigations.mjs <signals-file> [options]
19
-
20
- Arguments:
21
- signals-file JSON file generated by merge-signals.mjs (or collect-signals.mjs)
22
-
23
- Options:
24
- --threshold <n> Invocation volume threshold for candidate evaluation (default: 5000)
25
- --out <file> Output destination file (default: stdout)
26
- --help, -h Show this help message
27
- `);
28
- }
29
-
30
- const args = process.argv.slice(2);
31
- if (args.includes('--help') || args.includes('-h') || args.length === 0) {
32
- printHelp();
33
- process.exit(args.includes('--help') || args.includes('-h') ? 0 : 1);
34
- }
35
-
36
- let signalsFile = null;
37
- let threshold = 5000;
38
- let outFile = null;
39
-
40
- for (let i = 0; i < args.length; i++) {
41
- const arg = args[i];
42
- if (arg === '--threshold' && i + 1 < args.length) {
43
- threshold = parseInt(args[++i], 10) || 5000;
44
- } else if (arg === '--out' && i + 1 < args.length) {
45
- outFile = args[++i];
46
- } else if (!arg.startsWith('-') && !signalsFile) {
47
- signalsFile = arg;
48
- }
49
- }
50
-
51
- if (!signalsFile || !existsSync(signalsFile)) {
52
- console.error(`Error: Signals file not found: ${signalsFile}`);
53
- process.exit(1);
54
- }
55
-
56
- let data = {};
57
- try {
58
- data = JSON.parse(readFileSync(resolve(process.cwd(), signalsFile), 'utf8'));
59
- } catch (e) {
60
- console.error(`Error reading signals file: ${e.message}`);
61
- process.exit(1);
62
- }
63
-
64
- const candidates = [];
65
- const routes = data.routes || [];
66
-
67
- for (const r of routes) {
68
- if (r.invocations < threshold && r.p95DurationMs < 1000) {
69
- continue;
70
- }
71
-
72
- // 1. Caching Opportunity Gate
73
- if (r.method === 'GET' && r.invocations >= threshold && (r.cacheable || r.currentCacheControl === 'no-store' || !r.currentCacheControl)) {
74
- candidates.push({
75
- id: `cache-opp-${r.route.replace(/[^a-zA-Z0-9]/g, '-')}`,
76
- scope: 'code',
77
- category: 'caching',
78
- route: r.route,
79
- file: r.file || null,
80
- priority: r.invocations > 100000 ? 'high' : 'medium',
81
- metric: {
82
- invocations: r.invocations,
83
- p95DurationMs: r.p95DurationMs,
84
- currentCacheControl: r.currentCacheControl
85
- },
86
- reason: `High volume GET route (${r.invocations.toLocaleString()} invocations) lacking edge/CDN cache headers.`
87
- });
88
- }
89
-
90
- // 2. High Latency / Cold Start Gate
91
- if (r.p95DurationMs >= 1000 || r.coldStartRate >= 0.1) {
92
- candidates.push({
93
- id: `latency-coldstart-${r.route.replace(/[^a-zA-Z0-9]/g, '-')}`,
94
- scope: 'code',
95
- category: 'compute-duration',
96
- route: r.route,
97
- file: r.file || null,
98
- priority: r.p95DurationMs > 2000 ? 'high' : 'medium',
99
- metric: {
100
- p95DurationMs: r.p95DurationMs,
101
- coldStartRate: r.coldStartRate,
102
- invocations: r.invocations
103
- },
104
- reason: `P95 execution latency (${r.p95DurationMs}ms) or cold start rate (${Math.round(r.coldStartRate * 100)}%) warrants runtime or bundling optimization.`
105
- });
106
- }
107
- }
108
-
109
- // 3. Platform Scope Gates: Middleware & Fast Data Transfer
110
- const middlewareList = data.middleware || [];
111
- for (const mw of middlewareList) {
112
- if (!mw.hasMatcher) {
113
- candidates.push({
114
- id: 'platform-middleware-unfiltered',
115
- scope: 'platform',
116
- category: 'middleware-overhead',
117
- route: '/*',
118
- file: mw.file,
119
- priority: 'high',
120
- metric: {
121
- hasMatcher: false,
122
- runtime: mw.runtime
123
- },
124
- reason: 'Middleware runs globally across all asset/data requests without a path matcher config.'
125
- });
126
- }
127
- }
128
-
129
- const gatedResult = {
130
- timestamp: new Date().toISOString(),
131
- projectId: data.projectId || 'unknown',
132
- gateThreshold: threshold,
133
- totalCandidates: candidates.length,
134
- candidates
135
- };
136
-
137
- const outputJson = JSON.stringify(gatedResult, null, 2);
138
- if (outFile) {
139
- writeFileSync(resolve(process.cwd(), outFile), outputJson, 'utf8');
140
- } else {
141
- console.log(outputJson);
142
- }
@@ -1,143 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * merge-signals.mjs
4
- * Merges Vercel telemetry production metrics with codebase route scan outputs.
5
- *
6
- * Usage:
7
- * node scripts/merge-signals.mjs <signals-file> <codebase-file> [--out <file>] [--help]
8
- */
9
-
10
- import { readFileSync, writeFileSync, existsSync } from 'node:fs';
11
- import { resolve } from 'node:path';
12
-
13
- function printHelp() {
14
- console.log(`
15
- merge-signals.mjs — Correlates Telemetry Metrics with Codebase Routes
16
-
17
- Usage:
18
- node scripts/merge-signals.mjs <signals-file> <codebase-file> [options]
19
-
20
- Arguments:
21
- signals-file JSON file generated by collect-signals.mjs
22
- codebase-file JSON file generated by scan-codebase.mjs
23
-
24
- Options:
25
- --out <file> Output destination file (default: stdout)
26
- --help, -h Show this help message
27
- `);
28
- }
29
-
30
- const args = process.argv.slice(2);
31
- if (args.includes('--help') || args.includes('-h') || args.length < 2) {
32
- printHelp();
33
- process.exit(args.includes('--help') || args.includes('-h') ? 0 : 1);
34
- }
35
-
36
- const positional = [];
37
- let outFile = null;
38
-
39
- for (let i = 0; i < args.length; i++) {
40
- const arg = args[i];
41
- if (arg === '--out' && i + 1 < args.length) {
42
- outFile = args[++i];
43
- } else if (!arg.startsWith('-')) {
44
- positional.push(arg);
45
- }
46
- }
47
-
48
- if (positional.length < 2) {
49
- console.error('Error: Both <signals-file> and <codebase-file> are required.');
50
- process.exit(1);
51
- }
52
-
53
- const [signalsPath, codebasePath] = positional;
54
- if (!existsSync(signalsPath)) {
55
- console.error(`Error: File not found: ${signalsPath}`);
56
- process.exit(1);
57
- }
58
- if (!existsSync(codebasePath)) {
59
- console.error(`Error: File not found: ${codebasePath}`);
60
- process.exit(1);
61
- }
62
-
63
- let signalsData = {};
64
- let codebaseData = {};
65
-
66
- try {
67
- signalsData = JSON.parse(readFileSync(resolve(process.cwd(), signalsPath), 'utf8'));
68
- } catch (e) {
69
- console.error(`Error parsing signals JSON: ${e.message}`);
70
- process.exit(1);
71
- }
72
-
73
- try {
74
- codebaseData = JSON.parse(readFileSync(resolve(process.cwd(), codebasePath), 'utf8'));
75
- } catch (e) {
76
- console.error(`Error parsing codebase JSON: ${e.message}`);
77
- process.exit(1);
78
- }
79
-
80
- const telemetryRoutes = signalsData.routes || [];
81
- const codeRoutes = codebaseData.routes || [];
82
-
83
- // Correlate metrics with source files
84
- const mergedRoutes = [];
85
-
86
- for (const tr of telemetryRoutes) {
87
- // Find matching route in codebase
88
- const match = codeRoutes.find(cr => {
89
- return cr.route === tr.route || cr.route === tr.route + '/' || tr.route === cr.route + '/';
90
- });
91
-
92
- mergedRoutes.push({
93
- ...tr,
94
- file: match ? match.file : null,
95
- frameworkConfig: match ? {
96
- type: match.type,
97
- dynamic: match.dynamic,
98
- revalidate: match.revalidate,
99
- runtime: match.runtime
100
- } : null
101
- });
102
- }
103
-
104
- // Add codebase routes that had no telemetry records
105
- for (const cr of codeRoutes) {
106
- const existing = mergedRoutes.some(mr => mr.file === cr.file || mr.route === cr.route);
107
- if (!existing) {
108
- mergedRoutes.push({
109
- route: cr.route,
110
- method: 'GET',
111
- invocations: 0,
112
- p95DurationMs: 0,
113
- avgDurationMs: 0,
114
- coldStartRate: 0,
115
- errorRate: 0,
116
- cacheable: cr.dynamic === 'force-static' || cr.revalidate != null,
117
- file: cr.file,
118
- frameworkConfig: {
119
- type: cr.type,
120
- dynamic: cr.dynamic,
121
- revalidate: cr.revalidate,
122
- runtime: cr.runtime
123
- }
124
- });
125
- }
126
- }
127
-
128
- const merged = {
129
- timestamp: new Date().toISOString(),
130
- projectId: signalsData.projectId || 'unknown',
131
- windowDays: signalsData.windowDays || 14,
132
- framework: codebaseData.framework || 'unknown',
133
- metrics: signalsData.metrics || {},
134
- middleware: codebaseData.middleware || [],
135
- routes: mergedRoutes
136
- };
137
-
138
- const outputJson = JSON.stringify(merged, null, 2);
139
- if (outFile) {
140
- writeFileSync(resolve(process.cwd(), outFile), outputJson, 'utf8');
141
- } else {
142
- console.log(outputJson);
143
- }
@@ -1,174 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * scan-codebase.mjs
4
- * Scans repository routes, middleware, and rendering directives for Vercel optimization.
5
- *
6
- * Usage:
7
- * node scripts/scan-codebase.mjs <repo-root> [--out <file>] [--help]
8
- */
9
-
10
- import { readdirSync, statSync, readFileSync, writeFileSync, existsSync } from 'node:fs';
11
- import { resolve, join, relative, basename } from 'node:path';
12
-
13
- function printHelp() {
14
- console.log(`
15
- scan-codebase.mjs — Vercel Codebase Route & Config Scanner
16
-
17
- Usage:
18
- node scripts/scan-codebase.mjs <repo-root> [options]
19
-
20
- Arguments:
21
- repo-root Path to the repository root directory to scan
22
-
23
- Options:
24
- --out <file> Output file path (default: stdout)
25
- --help, -h Show this help message
26
- `);
27
- }
28
-
29
- const args = process.argv.slice(2);
30
- if (args.includes('--help') || args.includes('-h') || args.length === 0) {
31
- printHelp();
32
- process.exit(0);
33
- }
34
-
35
- let repoRoot = null;
36
- let outFile = null;
37
-
38
- for (let i = 0; i < args.length; i++) {
39
- const arg = args[i];
40
- if (arg === '--out' && i + 1 < args.length) {
41
- outFile = args[++i];
42
- } else if (!arg.startsWith('-') && !repoRoot) {
43
- repoRoot = resolve(process.cwd(), arg);
44
- }
45
- }
46
-
47
- if (!repoRoot || !existsSync(repoRoot)) {
48
- console.error(`Error: Repository path not found: ${repoRoot}`);
49
- process.exit(1);
50
- }
51
-
52
- // Detect framework
53
- let framework = 'unknown';
54
- const pkgPath = join(repoRoot, 'package.json');
55
- if (existsSync(pkgPath)) {
56
- try {
57
- const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
58
- const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
59
- if (deps.next) framework = 'nextjs';
60
- else if (deps['@sveltejs/kit']) framework = 'sveltekit';
61
- else if (deps.nuxt) framework = 'nuxt';
62
- else if (deps.astro) framework = 'astro';
63
- else if (deps.react) framework = 'react';
64
- } catch {
65
- // Ignore error
66
- }
67
- }
68
-
69
- const routes = [];
70
- const middleware = [];
71
-
72
- function walk(dir) {
73
- let entries;
74
- try {
75
- entries = readdirSync(dir, { withFileTypes: true });
76
- } catch {
77
- return;
78
- }
79
- for (const entry of entries) {
80
- if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === '.next' || entry.name === 'dist') {
81
- continue;
82
- }
83
- const fullPath = join(dir, entry.name);
84
- if (entry.isDirectory()) {
85
- walk(fullPath);
86
- } else if (entry.isFile()) {
87
- const relPath = relative(repoRoot, fullPath).replace(/\\/g, '/');
88
- const filename = basename(entry.name);
89
-
90
- // Check middleware
91
- if (/^middleware\.(ts|js|mjs)$/.test(filename) || /^src\/middleware\.(ts|js|mjs)$/.test(relPath)) {
92
- try {
93
- const content = readFileSync(fullPath, 'utf8');
94
- middleware.push({
95
- file: relPath,
96
- hasMatcher: content.includes('matcher:'),
97
- runtime: content.includes("runtime = 'edge'") ? 'edge' : 'nodejs'
98
- });
99
- } catch {}
100
- }
101
-
102
- // Check App Router route handlers
103
- if (/^(route|page)\.(ts|tsx|js|jsx)$/.test(filename) && (relPath.includes('app/') || relPath.includes('src/app/'))) {
104
- try {
105
- const content = readFileSync(fullPath, 'utf8');
106
- const isRoute = filename.startsWith('route');
107
- const isDynamic = content.includes("dynamic = 'force-dynamic'") || content.includes('export const dynamic = "force-dynamic"');
108
- const isStatic = content.includes("dynamic = 'force-static'") || content.includes('export const dynamic = "force-static"');
109
- const hasRevalidate = /revalidate\s*=\s*(\d+)/.test(content);
110
- const revalidateVal = hasRevalidate ? parseInt(content.match(/revalidate\s*=\s*(\d+)/)[1], 10) : null;
111
- const runtime = content.includes("runtime = 'edge'") ? 'edge' : 'nodejs';
112
-
113
- // Extract route pattern
114
- let routeUrl = relPath
115
- .replace(/^(src\/)?app/, '')
116
- .replace(/\/(route|page)\.(ts|tsx|js|jsx)$/, '');
117
- if (!routeUrl.startsWith('/')) routeUrl = '/' + routeUrl;
118
- if (routeUrl === '') routeUrl = '/';
119
-
120
- routes.push({
121
- type: isRoute ? 'api-route' : 'page-route',
122
- route: routeUrl,
123
- file: relPath,
124
- dynamic: isDynamic ? 'force-dynamic' : (isStatic ? 'force-static' : 'auto'),
125
- revalidate: revalidateVal,
126
- runtime
127
- });
128
- } catch {}
129
- }
130
-
131
- // Check Pages Router API handlers
132
- if ((relPath.includes('pages/api/') || relPath.includes('src/pages/api/')) && /\.(ts|js)$/.test(filename)) {
133
- try {
134
- const content = readFileSync(fullPath, 'utf8');
135
- let routeUrl = relPath
136
- .replace(/^(src\/)?pages/, '')
137
- .replace(/\.(ts|js)$/, '');
138
- if (routeUrl.endsWith('/index')) routeUrl = routeUrl.slice(0, -6);
139
-
140
- routes.push({
141
- type: 'api-route',
142
- route: routeUrl,
143
- file: relPath,
144
- dynamic: 'pages-api',
145
- runtime: content.includes("runtime = 'edge'") ? 'edge' : 'nodejs'
146
- });
147
- } catch {}
148
- }
149
- }
150
- }
151
- }
152
-
153
- walk(repoRoot);
154
-
155
- const result = {
156
- timestamp: new Date().toISOString(),
157
- repoRoot: relative(process.cwd(), repoRoot).replace(/\\/g, '/') || '.',
158
- framework,
159
- summary: {
160
- totalRoutes: routes.length,
161
- apiRoutes: routes.filter(r => r.type === 'api-route').length,
162
- pageRoutes: routes.filter(r => r.type === 'page-route').length,
163
- middlewareCount: middleware.length
164
- },
165
- middleware,
166
- routes
167
- };
168
-
169
- const outputJson = JSON.stringify(result, null, 2);
170
- if (outFile) {
171
- writeFileSync(resolve(process.cwd(), outFile), outputJson, 'utf8');
172
- } else {
173
- console.log(outputJson);
174
- }
@@ -1,18 +0,0 @@
1
- name: vercel-optimize
2
- type: runtime
3
- description: Observability-first Vercel performance and cost reduction optimization skill.
4
- tags:
5
- - vercel
6
- - nextjs
7
- - performance
8
- - cost
9
- version: 1.2.0
10
- requires:
11
- - nextjs
12
- resources:
13
- - SKILL.md
14
- - VALIDATION.json
15
- - scripts/collect-signals.mjs
16
- - scripts/gate-investigations.mjs
17
- - scripts/merge-signals.mjs
18
- - scripts/scan-codebase.mjs
@@ -1,39 +0,0 @@
1
- # web-accessibility Examples — Anti-patterns vs ContextOS Standard
2
-
3
- ## Example 1: Semantic Buttons vs Clickable Divs
4
-
5
- ### Anti-pattern: Clickable Div
6
-
7
- ```tsx
8
- // BAD: Cannot be focused with Tab, does not respond to Enter or Space, silent to screen readers
9
- <div className="button" onClick={handleSubmit}>Submit</div>
10
- ```
11
-
12
- ### Best practice: ContextOS Standard (Semantic Button Element)
13
-
14
- ```tsx
15
- // GOOD: Keyboard focusable, native Enter/Space handling, properly announced by assistive tech
16
- <button type="button" onClick={handleSubmit} className="btn btn-primary">
17
- Submit
18
- </button>
19
- ```
20
-
21
- ---
22
-
23
- ## Example 2: Icon-only Buttons
24
-
25
- ### Anti-pattern: Unlabelled Icon Button
26
-
27
- ```tsx
28
- // BAD: Screen reader announces "button", user has zero idea what it does
29
- <button onClick={onClose}><XIcon /></button>
30
- ```
31
-
32
- ### Best practice: ContextOS Standard (Accessible Label)
33
-
34
- ```tsx
35
- // GOOD: Explicit aria-label and hidden decorative icon
36
- <button type="button" onClick={onClose} aria-label="Close modal window">
37
- <XIcon aria-hidden="true" />
38
- </button>
39
- ```
@@ -1,170 +0,0 @@
1
- ---
2
- name: Web Accessibility
3
- description: >
4
- ContextOS skill for Web Accessibility (WCAG 2.1 AA/AAA), ARIA dialog patterns, keyboard focus traps, and Web Interface Guidelines.
5
- ---
6
-
7
- # Web Accessibility & Interface Guidelines
8
-
9
- ## Overview
10
-
11
- Enforces universal accessibility compliance (WCAG 2.1 AA / AAA), rigorous semantic markup, keyboard navigability with focus traps, screen reader live regions, and Web Interface Guidelines standards.
12
-
13
- ## When to Use
14
-
15
- Activate whenever building, styling, or reviewing user interfaces, forms, modals, menus, navigation drawers, custom interactive widgets, or media elements.
16
-
17
- ## Negative Constraints (What NOT to Do)
18
-
19
- 1. **NEVER use `outline: none` without a custom `:focus-visible` replacement**: Keyboard users must always have a distinct, high-contrast visual focus ring.
20
- 2. **NEVER use non-semantic elements (`<div onClick>`) for interactive triggers**: Always use native `<button>` or `<a href>`.
21
- 3. **NEVER create modals or dialogs without keyboard focus traps**: Focus must remain trapped inside open dialogs during Tab / Shift-Tab navigation and restore to trigger on close.
22
- 4. **NEVER rely exclusively on color to indicate state or errors**: Always pair colors with text labels, icons, or ARIA attributes (`aria-invalid="true"`).
23
- 5. **NEVER trap screen readers with missing form labels or error associations**: Every input must link to `<label htmlFor="id">` and errors via `aria-describedby`.
24
- 6. **NEVER play animations without honoring `prefers-reduced-motion`**: Respect user OS motion reduction preferences.
25
-
26
- ## Rules & Patterns
27
-
28
- ### 1. Focus Visible & High-Contrast Focus Rings
29
-
30
- ```css
31
- button:focus-visible,
32
- a:focus-visible,
33
- input:focus-visible {
34
- outline: 2px solid #6366f1;
35
- outline-offset: 2px;
36
- border-radius: 4px;
37
- }
38
-
39
- button:focus:not(:focus-visible) {
40
- outline: none;
41
- }
42
- ```
43
-
44
- ### 2. Accessible Modal & Focus Trap Contract
45
-
46
- ```tsx
47
- import React, { useEffect, useRef } from 'react';
48
- import { createPortal } from 'react-dom';
49
-
50
- interface ModalProps {
51
- isOpen: boolean;
52
- onClose: () => void;
53
- titleId: string;
54
- children: React.ReactNode;
55
- }
56
-
57
- export function AccessibleModal({ isOpen, onClose, titleId, children }: ModalProps) {
58
- const dialogRef = useRef<HTMLDivElement>(null);
59
- const triggerRef = useRef<HTMLElement | null>(null);
60
-
61
- useEffect(() => {
62
- if (!isOpen) return;
63
- triggerRef.current = document.activeElement as HTMLElement;
64
-
65
- const handleKeyDown = (e: KeyboardEvent) => {
66
- if (e.key === 'Escape') {
67
- e.preventDefault();
68
- onClose();
69
- }
70
-
71
- if (e.key === 'Tab') {
72
- const focusables = dialogRef.current?.querySelectorAll<HTMLElement>(
73
- 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
74
- ) || [];
75
- if (!focusables.length) return;
76
-
77
- const first = focusables[0];
78
- const last = focusables[focusables.length - 1];
79
-
80
- if (e.shiftKey && document.activeElement === first) {
81
- e.preventDefault();
82
- last.focus();
83
- } else if (!e.shiftKey && document.activeElement === last) {
84
- e.preventDefault();
85
- first.focus();
86
- }
87
- }
88
- };
89
-
90
- document.addEventListener('keydown', handleKeyDown);
91
- return () => {
92
- document.removeEventListener('keydown', handleKeyDown);
93
- triggerRef.current?.focus();
94
- };
95
- }, [isOpen, onClose]);
96
-
97
- if (!isOpen) return null;
98
-
99
- return createPortal(
100
- <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4">
101
- <div
102
- ref={dialogRef}
103
- role="dialog"
104
- aria-modal="true"
105
- aria-labelledby={titleId}
106
- className="w-full max-w-lg rounded-xl bg-background p-6 shadow-2xl border"
107
- >
108
- {children}
109
- </div>
110
- </div>,
111
- document.body
112
- );
113
- }
114
- ```
115
-
116
- ### 3. Accessible Forms & Error Association
117
-
118
- ```tsx
119
- export function EmailInput({ error, ...props }: { error?: string } & React.InputHTMLAttributes<HTMLInputElement>) {
120
- const inputId = 'user-email';
121
- const errorId = 'user-email-error';
122
-
123
- return (
124
- <div className="flex flex-col gap-1.5">
125
- <label htmlFor={inputId} className="text-sm font-medium">
126
- Email Address <span aria-hidden="true" className="text-destructive">*</span>
127
- </label>
128
- <input
129
- id={inputId}
130
- type="email"
131
- autoComplete="email"
132
- required
133
- aria-invalid={Boolean(error)}
134
- aria-describedby={error ? errorId : undefined}
135
- className="rounded-md border p-2 text-sm focus-visible:ring-2"
136
- {...props}
137
- />
138
- {error && (
139
- <p id={errorId} role="alert" className="text-xs text-destructive">
140
- {error}
141
- </p>
142
- )}
143
- </div>
144
- );
145
- }
146
- ```
147
-
148
- ## Code Examples
149
-
150
- See `EXAMPLES.md` for detailed dialog, menu, and form examples.
151
-
152
- ## Validation Checklist
153
-
154
- - [ ] All interactive elements are fully operable via Keyboard (`Tab`, `Enter`, `Space`, `Escape`).
155
- - [ ] Visual `:focus-visible` styling is distinct and high contrast (≥ 3:1).
156
- - [ ] Modals use `role="dialog"`, `aria-modal="true"`, focus trap, and restore focus on close.
157
- - [ ] Text contrast ratios satisfy WCAG AA (≥ 4.5:1 for normal text, ≥ 3:1 for large text).
158
- - [ ] Forms pair inputs with `<label htmlFor>`, valid `autocomplete` tokens, and `aria-invalid`.
159
- - [ ] Non-text media contains descriptive `alt` attributes or `aria-hidden="true"` for decorative icons.
160
-
161
- ## Common Mistakes
162
-
163
- - Hiding outline focus indicators globally without `:focus-visible` fallback.
164
- - Forgetting to trap focus in modal dialogs or not returning focus to trigger when modal closes.
165
- - Missing `aria-expanded` attributes on disclosure buttons and dropdown toggles.
166
-
167
- ## Integration Notes
168
-
169
- - Pairs with `ui-ux-pro` and `impeccable-design` for visual contrast and component standards.
170
- - Pairs with `react` and `nextjs` for accessible dialogs and focus restoration across route transitions.