@paulojalowyj/openkit 0.1.1

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 (281) hide show
  1. package/.opencode/ARCHITECTURE.md +150 -0
  2. package/.opencode/LICENSE +21 -0
  3. package/.opencode/bin/cli.js +213 -0
  4. package/.opencode/commands/README.md +273 -0
  5. package/.opencode/commands/analyze.md +64 -0
  6. package/.opencode/commands/brainstorm.md +186 -0
  7. package/.opencode/commands/checklist.md +62 -0
  8. package/.opencode/commands/clarify.md +40 -0
  9. package/.opencode/commands/context.md +68 -0
  10. package/.opencode/commands/create.md +70 -0
  11. package/.opencode/commands/debug.md +160 -0
  12. package/.opencode/commands/deploy.md +244 -0
  13. package/.opencode/commands/doc.md +45 -0
  14. package/.opencode/commands/engineer.md +483 -0
  15. package/.opencode/commands/impl.md +242 -0
  16. package/.opencode/commands/plan.md +250 -0
  17. package/.opencode/commands/preview.md +87 -0
  18. package/.opencode/commands/specify.md +66 -0
  19. package/.opencode/commands/status.md +103 -0
  20. package/.opencode/commands/tasks.md +58 -0
  21. package/.opencode/commands/test.md +104 -0
  22. package/.opencode/commands/ui-ux.md +216 -0
  23. package/.opencode/prompts/backend-specialist.md +315 -0
  24. package/.opencode/prompts/chat.md +36 -0
  25. package/.opencode/prompts/database-architect.md +244 -0
  26. package/.opencode/prompts/debugger.md +244 -0
  27. package/.opencode/prompts/devops-engineer.md +259 -0
  28. package/.opencode/prompts/documentation-writer.md +121 -0
  29. package/.opencode/prompts/explorer-agent.md +92 -0
  30. package/.opencode/prompts/frontend-specialist.md +608 -0
  31. package/.opencode/prompts/mobile-developer.md +393 -0
  32. package/.opencode/prompts/orchestrator.md +472 -0
  33. package/.opencode/prompts/penetration-tester.md +205 -0
  34. package/.opencode/prompts/performance-optimizer.md +204 -0
  35. package/.opencode/prompts/product-owner.md +113 -0
  36. package/.opencode/prompts/project-planner.md +413 -0
  37. package/.opencode/prompts/security-auditor.md +187 -0
  38. package/.opencode/prompts/seo-specialist.md +128 -0
  39. package/.opencode/prompts/test-engineer.md +190 -0
  40. package/.opencode/rules/AGENT_TEMPLATE.md +391 -0
  41. package/.opencode/rules/MASTER.md +272 -0
  42. package/.opencode/rules/README.md +266 -0
  43. package/.opencode/rules/TODOLIST_EXAMPLES.md +675 -0
  44. package/.opencode/rules/TODOLIST_PROTOCOL.md +495 -0
  45. package/.opencode/rules/TOOL_USAGE.md +731 -0
  46. package/.opencode/scripts/auto_preview.py +100 -0
  47. package/.opencode/scripts/checklist.py +217 -0
  48. package/.opencode/scripts/session_manager.py +225 -0
  49. package/.opencode/scripts/verify_all.py +403 -0
  50. package/.opencode/skills/api-patterns/SKILL.md +80 -0
  51. package/.opencode/skills/api-patterns/api-style.md +42 -0
  52. package/.opencode/skills/api-patterns/auth.md +24 -0
  53. package/.opencode/skills/api-patterns/documentation.md +26 -0
  54. package/.opencode/skills/api-patterns/graphql.md +41 -0
  55. package/.opencode/skills/api-patterns/rate-limiting.md +31 -0
  56. package/.opencode/skills/api-patterns/response.md +37 -0
  57. package/.opencode/skills/api-patterns/rest.md +40 -0
  58. package/.opencode/skills/api-patterns/scripts/api_validator.py +211 -0
  59. package/.opencode/skills/api-patterns/security-testing.md +122 -0
  60. package/.opencode/skills/api-patterns/trpc.md +41 -0
  61. package/.opencode/skills/api-patterns/versioning.md +22 -0
  62. package/.opencode/skills/app-builder/SKILL.md +101 -0
  63. package/.opencode/skills/app-builder/agent-coordination.md +71 -0
  64. package/.opencode/skills/app-builder/feature-building.md +53 -0
  65. package/.opencode/skills/app-builder/project-detection.md +34 -0
  66. package/.opencode/skills/app-builder/scaffolding.md +116 -0
  67. package/.opencode/skills/app-builder/tech-stack.md +40 -0
  68. package/.opencode/skills/app-builder/templates/SKILL.md +39 -0
  69. package/.opencode/skills/app-builder/templates/astro-static/TEMPLATE.md +76 -0
  70. package/.opencode/skills/app-builder/templates/chrome-extension/TEMPLATE.md +92 -0
  71. package/.opencode/skills/app-builder/templates/cli-tool/TEMPLATE.md +88 -0
  72. package/.opencode/skills/app-builder/templates/electron-desktop/TEMPLATE.md +88 -0
  73. package/.opencode/skills/app-builder/templates/express-api/TEMPLATE.md +83 -0
  74. package/.opencode/skills/app-builder/templates/flutter-app/TEMPLATE.md +90 -0
  75. package/.opencode/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +90 -0
  76. package/.opencode/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +81 -0
  77. package/.opencode/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +100 -0
  78. package/.opencode/skills/app-builder/templates/nextjs-static/TEMPLATE.md +106 -0
  79. package/.opencode/skills/app-builder/templates/nuxt-app/TEMPLATE.md +100 -0
  80. package/.opencode/skills/app-builder/templates/python-fastapi/TEMPLATE.md +82 -0
  81. package/.opencode/skills/app-builder/templates/react-native-app/TEMPLATE.md +93 -0
  82. package/.opencode/skills/architecture/SKILL.md +55 -0
  83. package/.opencode/skills/architecture/context-discovery.md +43 -0
  84. package/.opencode/skills/architecture/examples.md +94 -0
  85. package/.opencode/skills/architecture/pattern-selection.md +68 -0
  86. package/.opencode/skills/architecture/patterns-reference.md +50 -0
  87. package/.opencode/skills/architecture/trade-off-analysis.md +77 -0
  88. package/.opencode/skills/bash-linux/SKILL.md +199 -0
  89. package/.opencode/skills/behavioral-modes/SKILL.md +242 -0
  90. package/.opencode/skills/brainstorming/SKILL.md +163 -0
  91. package/.opencode/skills/brainstorming/dynamic-questioning.md +350 -0
  92. package/.opencode/skills/clean-code/SKILL.md +201 -0
  93. package/.opencode/skills/code-review-checklist/SKILL.md +109 -0
  94. package/.opencode/skills/database-design/SKILL.md +73 -0
  95. package/.opencode/skills/database-design/database-selection.md +43 -0
  96. package/.opencode/skills/database-design/indexing.md +39 -0
  97. package/.opencode/skills/database-design/migrations.md +48 -0
  98. package/.opencode/skills/database-design/optimization.md +36 -0
  99. package/.opencode/skills/database-design/orm-selection.md +30 -0
  100. package/.opencode/skills/database-design/schema-design.md +56 -0
  101. package/.opencode/skills/database-design/scripts/schema_validator.py +172 -0
  102. package/.opencode/skills/deployment-procedures/SKILL.md +241 -0
  103. package/.opencode/skills/documentation-templates/SKILL.md +279 -0
  104. package/.opencode/skills/frontend-design/SKILL.md +446 -0
  105. package/.opencode/skills/frontend-design/animation-guide.md +331 -0
  106. package/.opencode/skills/frontend-design/color-system.md +311 -0
  107. package/.opencode/skills/frontend-design/data/charts.csv +26 -0
  108. package/.opencode/skills/frontend-design/data/colors.csv +97 -0
  109. package/.opencode/skills/frontend-design/data/icons.csv +101 -0
  110. package/.opencode/skills/frontend-design/data/landing.csv +31 -0
  111. package/.opencode/skills/frontend-design/data/products.csv +97 -0
  112. package/.opencode/skills/frontend-design/data/prompts.csv +24 -0
  113. package/.opencode/skills/frontend-design/data/react-performance.csv +45 -0
  114. package/.opencode/skills/frontend-design/data/stacks/flutter.csv +53 -0
  115. package/.opencode/skills/frontend-design/data/stacks/html-tailwind.csv +56 -0
  116. package/.opencode/skills/frontend-design/data/stacks/jetpack-compose.csv +53 -0
  117. package/.opencode/skills/frontend-design/data/stacks/nextjs.csv +53 -0
  118. package/.opencode/skills/frontend-design/data/stacks/nuxt-ui.csv +51 -0
  119. package/.opencode/skills/frontend-design/data/stacks/nuxtjs.csv +59 -0
  120. package/.opencode/skills/frontend-design/data/stacks/react-native.csv +52 -0
  121. package/.opencode/skills/frontend-design/data/stacks/react.csv +54 -0
  122. package/.opencode/skills/frontend-design/data/stacks/shadcn.csv +61 -0
  123. package/.opencode/skills/frontend-design/data/stacks/svelte.csv +54 -0
  124. package/.opencode/skills/frontend-design/data/stacks/swiftui.csv +51 -0
  125. package/.opencode/skills/frontend-design/data/stacks/vue.csv +50 -0
  126. package/.opencode/skills/frontend-design/data/styles.csv +59 -0
  127. package/.opencode/skills/frontend-design/data/typography.csv +58 -0
  128. package/.opencode/skills/frontend-design/data/ui-reasoning.csv +101 -0
  129. package/.opencode/skills/frontend-design/data/ux-guidelines.csv +100 -0
  130. package/.opencode/skills/frontend-design/data/web-interface.csv +31 -0
  131. package/.opencode/skills/frontend-design/decision-trees.md +418 -0
  132. package/.opencode/skills/frontend-design/motion-graphics.md +306 -0
  133. package/.opencode/skills/frontend-design/scripts/accessibility_checker.py +183 -0
  134. package/.opencode/skills/frontend-design/scripts/core.py +258 -0
  135. package/.opencode/skills/frontend-design/scripts/design_system.py +1067 -0
  136. package/.opencode/skills/frontend-design/scripts/search.py +106 -0
  137. package/.opencode/skills/frontend-design/scripts/ux_audit.py +735 -0
  138. package/.opencode/skills/frontend-design/typography-system.md +345 -0
  139. package/.opencode/skills/frontend-design/ux-psychology.md +541 -0
  140. package/.opencode/skills/frontend-design/visual-effects.md +383 -0
  141. package/.opencode/skills/geo-fundamentals/SKILL.md +156 -0
  142. package/.opencode/skills/geo-fundamentals/scripts/geo_checker.py +289 -0
  143. package/.opencode/skills/i18n-localization/SKILL.md +154 -0
  144. package/.opencode/skills/i18n-localization/scripts/i18n_checker.py +241 -0
  145. package/.opencode/skills/intelligent-routing/SKILL.md +335 -0
  146. package/.opencode/skills/lint-and-validate/SKILL.md +45 -0
  147. package/.opencode/skills/lint-and-validate/scripts/lint_runner.py +172 -0
  148. package/.opencode/skills/lint-and-validate/scripts/type_coverage.py +173 -0
  149. package/.opencode/skills/mobile-design/SKILL.md +394 -0
  150. package/.opencode/skills/mobile-design/decision-trees.md +516 -0
  151. package/.opencode/skills/mobile-design/mobile-backend.md +491 -0
  152. package/.opencode/skills/mobile-design/mobile-color-system.md +420 -0
  153. package/.opencode/skills/mobile-design/mobile-debugging.md +122 -0
  154. package/.opencode/skills/mobile-design/mobile-design-thinking.md +357 -0
  155. package/.opencode/skills/mobile-design/mobile-navigation.md +458 -0
  156. package/.opencode/skills/mobile-design/mobile-performance.md +767 -0
  157. package/.opencode/skills/mobile-design/mobile-testing.md +356 -0
  158. package/.opencode/skills/mobile-design/mobile-typography.md +433 -0
  159. package/.opencode/skills/mobile-design/platform-android.md +666 -0
  160. package/.opencode/skills/mobile-design/platform-ios.md +561 -0
  161. package/.opencode/skills/mobile-design/scripts/mobile_audit.py +670 -0
  162. package/.opencode/skills/mobile-design/touch-psychology.md +537 -0
  163. package/.opencode/skills/nextjs-react-expert/1-async-eliminating-waterfalls.md +312 -0
  164. package/.opencode/skills/nextjs-react-expert/2-bundle-bundle-size-optimization.md +240 -0
  165. package/.opencode/skills/nextjs-react-expert/3-server-server-side-performance.md +490 -0
  166. package/.opencode/skills/nextjs-react-expert/4-client-client-side-data-fetching.md +264 -0
  167. package/.opencode/skills/nextjs-react-expert/5-rerender-re-render-optimization.md +581 -0
  168. package/.opencode/skills/nextjs-react-expert/6-rendering-rendering-performance.md +432 -0
  169. package/.opencode/skills/nextjs-react-expert/7-js-javascript-performance.md +684 -0
  170. package/.opencode/skills/nextjs-react-expert/8-advanced-advanced-patterns.md +150 -0
  171. package/.opencode/skills/nextjs-react-expert/SKILL.md +267 -0
  172. package/.opencode/skills/nextjs-react-expert/scripts/convert_rules.py +222 -0
  173. package/.opencode/skills/nextjs-react-expert/scripts/react_performance_checker.py +252 -0
  174. package/.opencode/skills/parallel-agents/SKILL.md +175 -0
  175. package/.opencode/skills/performance-profiling/SKILL.md +143 -0
  176. package/.opencode/skills/performance-profiling/scripts/lighthouse_audit.py +76 -0
  177. package/.opencode/skills/plan-writing/SKILL.md +176 -0
  178. package/.opencode/skills/python-patterns/SKILL.md +462 -0
  179. package/.opencode/skills/red-team-tactics/SKILL.md +199 -0
  180. package/.opencode/skills/seo-fundamentals/SKILL.md +129 -0
  181. package/.opencode/skills/seo-fundamentals/scripts/seo_checker.py +222 -0
  182. package/.opencode/skills/server-management/SKILL.md +161 -0
  183. package/.opencode/skills/stack-selection/SKILL.md +448 -0
  184. package/.opencode/skills/systematic-debugging/SKILL.md +109 -0
  185. package/.opencode/skills/tailwind-patterns/SKILL.md +269 -0
  186. package/.opencode/skills/tdd-workflow/SKILL.md +149 -0
  187. package/.opencode/skills/testing-patterns/SKILL.md +178 -0
  188. package/.opencode/skills/testing-patterns/scripts/test_runner.py +219 -0
  189. package/.opencode/skills/vulnerability-scanner/SKILL.md +276 -0
  190. package/.opencode/skills/vulnerability-scanner/checklists.md +121 -0
  191. package/.opencode/skills/vulnerability-scanner/scripts/security_scan.py +458 -0
  192. package/.opencode/skills/web-design-guidelines/SKILL.md +57 -0
  193. package/.opencode/skills/webapp-testing/SKILL.md +187 -0
  194. package/.opencode/skills/webapp-testing/scripts/playwright_runner.py +173 -0
  195. package/.opencode/templates/DOCS-ACTION_ITEMS.md +5 -0
  196. package/.opencode/templates/DOCS-API.md +11 -0
  197. package/.opencode/templates/DOCS-BACKEND.md +10 -0
  198. package/.opencode/templates/DOCS-CONTEXT.md +25 -0
  199. package/.opencode/templates/DOCS-DATABASE.md +10 -0
  200. package/.opencode/templates/DOCS-FRONTEND.md +11 -0
  201. package/.opencode/templates/DOCS-QUALITY_GATES.md +20 -0
  202. package/.opencode/templates/DOCS-SECURITY.md +17 -0
  203. package/.opencode/templates/SDD-AcceptanceCriteria.md +21 -0
  204. package/.opencode/templates/SDD-Checklist.md +27 -0
  205. package/.opencode/templates/SDD-Contracts.md +21 -0
  206. package/.opencode/templates/SDD-Plan.md +45 -0
  207. package/.opencode/templates/SDD-ProblemStatement.md +25 -0
  208. package/.opencode/templates/SDD-Quickstart.md +23 -0
  209. package/.opencode/templates/SDD-Research.md +24 -0
  210. package/.opencode/templates/SDD-Risks.md +16 -0
  211. package/.opencode/templates/SDD-Tasks.md +41 -0
  212. package/.opencode/templates/SDD-UserStories.md +45 -0
  213. package/.opencode/templates/TechStack.md +111 -0
  214. package/LICENSE +21 -0
  215. package/PACKAGE_STATUS.md +97 -0
  216. package/README.md +251 -0
  217. package/README.pt-BR.md +192 -0
  218. package/bin/cli.js +505 -0
  219. package/blueprints/fullstack/.env.example +15 -0
  220. package/blueprints/fullstack/AGENTS.md +3 -0
  221. package/blueprints/fullstack/README.md +65 -0
  222. package/blueprints/fullstack/backend/.dockerignore +10 -0
  223. package/blueprints/fullstack/backend/.python-version +1 -0
  224. package/blueprints/fullstack/backend/Dockerfile +33 -0
  225. package/blueprints/fullstack/backend/alembic.ini +40 -0
  226. package/blueprints/fullstack/backend/app/__init__.py +0 -0
  227. package/blueprints/fullstack/backend/app/api/README.md +3 -0
  228. package/blueprints/fullstack/backend/app/api/__init__.py +0 -0
  229. package/blueprints/fullstack/backend/app/celery_app.py +5 -0
  230. package/blueprints/fullstack/backend/app/core/README.md +3 -0
  231. package/blueprints/fullstack/backend/app/core/__init__.py +0 -0
  232. package/blueprints/fullstack/backend/app/database.py +14 -0
  233. package/blueprints/fullstack/backend/app/main.py +16 -0
  234. package/blueprints/fullstack/backend/app/models/README.md +3 -0
  235. package/blueprints/fullstack/backend/app/models/__init__.py +3 -0
  236. package/blueprints/fullstack/backend/app/models/item.py +10 -0
  237. package/blueprints/fullstack/backend/app/routers/__init__.py +0 -0
  238. package/blueprints/fullstack/backend/app/routers/items.py +20 -0
  239. package/blueprints/fullstack/backend/app/schemas/README.md +3 -0
  240. package/blueprints/fullstack/backend/app/schemas/__init__.py +0 -0
  241. package/blueprints/fullstack/backend/app/schemas/item.py +15 -0
  242. package/blueprints/fullstack/backend/app/services/item_service.py +23 -0
  243. package/blueprints/fullstack/backend/app/settings.py +36 -0
  244. package/blueprints/fullstack/backend/app/tasks/README.md +3 -0
  245. package/blueprints/fullstack/backend/app/tasks/__init__.py +0 -0
  246. package/blueprints/fullstack/backend/migrations/env.py +47 -0
  247. package/blueprints/fullstack/backend/migrations/versions/0001_initial_sample_data.py +31 -0
  248. package/blueprints/fullstack/backend/pyproject.toml +45 -0
  249. package/blueprints/fullstack/docker-compose.dev.yml +114 -0
  250. package/blueprints/fullstack/docker-compose.prod.yml +90 -0
  251. package/blueprints/fullstack/docs/README.md +29 -0
  252. package/blueprints/fullstack/docs/engineering/api/README.md +3 -0
  253. package/blueprints/fullstack/docs/engineering/architecture/README.md +3 -0
  254. package/blueprints/fullstack/docs/engineering/backend/README.md +3 -0
  255. package/blueprints/fullstack/docs/engineering/frontend/README.md +3 -0
  256. package/blueprints/fullstack/docs/engineering/security/README.md +3 -0
  257. package/blueprints/fullstack/docs/engineering/standards/README.md +3 -0
  258. package/blueprints/fullstack/frontend/.dockerignore +4 -0
  259. package/blueprints/fullstack/frontend/Dockerfile +23 -0
  260. package/blueprints/fullstack/frontend/components.json +17 -0
  261. package/blueprints/fullstack/frontend/index.html +12 -0
  262. package/blueprints/fullstack/frontend/package.json +28 -0
  263. package/blueprints/fullstack/frontend/src/components/README.md +3 -0
  264. package/blueprints/fullstack/frontend/src/components/ui/.keep +4 -0
  265. package/blueprints/fullstack/frontend/src/index.css +57 -0
  266. package/blueprints/fullstack/frontend/src/lib/README.md +3 -0
  267. package/blueprints/fullstack/frontend/src/lib/api.ts +1 -0
  268. package/blueprints/fullstack/frontend/src/lib/utils.ts +6 -0
  269. package/blueprints/fullstack/frontend/src/main.tsx +66 -0
  270. package/blueprints/fullstack/frontend/src/routes/README.md +3 -0
  271. package/blueprints/fullstack/frontend/src/routes/root.tsx +7 -0
  272. package/blueprints/fullstack/frontend/src/vite-env.d.ts +1 -0
  273. package/blueprints/fullstack/frontend/tailwind.config.ts +12 -0
  274. package/blueprints/fullstack/frontend/tsconfig.json +13 -0
  275. package/blueprints/fullstack/frontend/tsconfig.node.json +12 -0
  276. package/blueprints/fullstack/frontend/vite.config.ts +12 -0
  277. package/index.js +14 -0
  278. package/opencode.json +306 -0
  279. package/package.json +57 -0
  280. package/scripts/prepare.js +65 -0
  281. package/scripts/update-version.js +29 -0
@@ -0,0 +1,289 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ GEO Checker - Generative Engine Optimization Audit
4
+ Checks PUBLIC WEB CONTENT for AI citation readiness.
5
+
6
+ PURPOSE:
7
+ - Analyze pages that will be INDEXED by AI engines (ChatGPT, Perplexity, etc.)
8
+ - Check for structured data, author info, dates, FAQ sections
9
+ - Help content rank in AI-generated answers
10
+
11
+ WHAT IT CHECKS:
12
+ - HTML files (actual web pages)
13
+ - JSX/TSX files (React page components)
14
+ - NOT markdown files (those are developer docs, not public content)
15
+
16
+ Usage:
17
+ python geo_checker.py <project_path>
18
+ """
19
+ import sys
20
+ import re
21
+ import json
22
+ from pathlib import Path
23
+
24
+ # Fix Windows console encoding
25
+ try:
26
+ sys.stdout.reconfigure(encoding='utf-8', errors='replace')
27
+ sys.stderr.reconfigure(encoding='utf-8', errors='replace')
28
+ except AttributeError:
29
+ pass
30
+
31
+
32
+ # Directories to skip (not public content)
33
+ SKIP_DIRS = {
34
+ 'node_modules', '.next', 'dist', 'build', '.git', '.github',
35
+ '__pycache__', '.vscode', '.idea', 'coverage', 'test', 'tests',
36
+ '__tests__', 'spec', 'docs', 'documentation'
37
+ }
38
+
39
+ # Files to skip (not public pages)
40
+ SKIP_FILES = {
41
+ 'jest.config', 'webpack.config', 'vite.config', 'tsconfig',
42
+ 'package.json', 'package-lock', 'yarn.lock', '.eslintrc',
43
+ 'tailwind.config', 'postcss.config', 'next.config'
44
+ }
45
+
46
+
47
+ def is_page_file(file_path: Path) -> bool:
48
+ """Check if this file is likely a public-facing page."""
49
+ name = file_path.stem.lower()
50
+
51
+ # Skip config/utility files
52
+ if any(skip in name for skip in SKIP_FILES):
53
+ return False
54
+
55
+ # Skip test files
56
+ if name.endswith('.test') or name.endswith('.spec'):
57
+ return False
58
+ if name.startswith('test_') or name.startswith('spec_'):
59
+ return False
60
+
61
+ # Likely page indicators
62
+ page_indicators = ['page', 'index', 'home', 'about', 'contact', 'blog',
63
+ 'post', 'article', 'product', 'service', 'landing']
64
+
65
+ # Check if it's in a pages/app directory (Next.js, etc.)
66
+ parts = [p.lower() for p in file_path.parts]
67
+ if 'pages' in parts or 'app' in parts or 'routes' in parts:
68
+ return True
69
+
70
+ # Check filename indicators
71
+ if any(ind in name for ind in page_indicators):
72
+ return True
73
+
74
+ # HTML files are usually pages
75
+ if file_path.suffix.lower() == '.html':
76
+ return True
77
+
78
+ return False
79
+
80
+
81
+ def find_web_pages(project_path: Path) -> list:
82
+ """Find public-facing web pages only."""
83
+ patterns = ['**/*.html', '**/*.htm', '**/*.jsx', '**/*.tsx']
84
+
85
+ files = []
86
+ for pattern in patterns:
87
+ for f in project_path.glob(pattern):
88
+ # Skip excluded directories
89
+ if any(skip in f.parts for skip in SKIP_DIRS):
90
+ continue
91
+
92
+ # Check if it's likely a page
93
+ if is_page_file(f):
94
+ files.append(f)
95
+
96
+ return files[:30] # Limit to 30 pages
97
+
98
+
99
+ def check_page(file_path: Path) -> dict:
100
+ """Check a single web page for GEO elements."""
101
+ try:
102
+ content = file_path.read_text(encoding='utf-8', errors='ignore')
103
+ except Exception as e:
104
+ return {'file': str(file_path.name), 'passed': [], 'issues': [f"Error: {e}"], 'score': 0}
105
+
106
+ issues = []
107
+ passed = []
108
+
109
+ # 1. JSON-LD Structured Data (Critical for AI)
110
+ if 'application/ld+json' in content:
111
+ passed.append("JSON-LD structured data found")
112
+ if '"@type"' in content:
113
+ if 'Article' in content:
114
+ passed.append("Article schema present")
115
+ if 'FAQPage' in content:
116
+ passed.append("FAQ schema present")
117
+ if 'Organization' in content or 'Person' in content:
118
+ passed.append("Entity schema present")
119
+ else:
120
+ issues.append("No JSON-LD structured data (AI engines prefer structured content)")
121
+
122
+ # 2. Heading Structure
123
+ h1_count = len(re.findall(r'<h1[^>]*>', content, re.I))
124
+ h2_count = len(re.findall(r'<h2[^>]*>', content, re.I))
125
+
126
+ if h1_count == 1:
127
+ passed.append("Single H1 heading (clear topic)")
128
+ elif h1_count == 0:
129
+ issues.append("No H1 heading - page topic unclear")
130
+ else:
131
+ issues.append(f"Multiple H1 headings ({h1_count}) - confusing for AI")
132
+
133
+ if h2_count >= 2:
134
+ passed.append(f"{h2_count} H2 subheadings (good structure)")
135
+ else:
136
+ issues.append("Add more H2 subheadings for scannable content")
137
+
138
+ # 3. Author Attribution (E-E-A-T signal)
139
+ author_patterns = ['author', 'byline', 'written-by', 'contributor', 'rel="author"']
140
+ has_author = any(p in content.lower() for p in author_patterns)
141
+ if has_author:
142
+ passed.append("Author attribution found")
143
+ else:
144
+ issues.append("No author info (AI prefers attributed content)")
145
+
146
+ # 4. Publication Date (Freshness signal)
147
+ date_patterns = ['datePublished', 'dateModified', 'datetime=', 'pubdate', 'article:published']
148
+ has_date = any(re.search(p, content, re.I) for p in date_patterns)
149
+ if has_date:
150
+ passed.append("Publication date found")
151
+ else:
152
+ issues.append("No publication date (freshness matters for AI)")
153
+
154
+ # 5. FAQ Section (Highly citable)
155
+ faq_patterns = [r'<details', r'faq', r'frequently.?asked', r'"FAQPage"']
156
+ has_faq = any(re.search(p, content, re.I) for p in faq_patterns)
157
+ if has_faq:
158
+ passed.append("FAQ section detected (highly citable)")
159
+
160
+ # 6. Lists (Structured content)
161
+ list_count = len(re.findall(r'<(ul|ol)[^>]*>', content, re.I))
162
+ if list_count >= 2:
163
+ passed.append(f"{list_count} lists (structured content)")
164
+
165
+ # 7. Tables (Comparison data)
166
+ table_count = len(re.findall(r'<table[^>]*>', content, re.I))
167
+ if table_count >= 1:
168
+ passed.append(f"{table_count} table(s) (comparison data)")
169
+
170
+ # 8. Entity Recognition (E-E-A-T signal) - NEW 2025
171
+ entity_patterns = [
172
+ r'"@type"\s*:\s*"Organization"',
173
+ r'"@type"\s*:\s*"LocalBusiness"',
174
+ r'"@type"\s*:\s*"Brand"',
175
+ r'itemtype.*schema\.org/(Organization|Person|Brand)',
176
+ r'rel="author"'
177
+ ]
178
+ has_entity = any(re.search(p, content, re.I) for p in entity_patterns)
179
+ if has_entity:
180
+ passed.append("Entity/Brand recognition (E-E-A-T)")
181
+
182
+ # 9. Original Statistics/Data (AI citation magnet) - NEW 2025
183
+ stat_patterns = [
184
+ r'\d+%', # Percentages
185
+ r'\$[\d,]+', # Dollar amounts
186
+ r'study\s+(shows|found)', # Research citations
187
+ r'according to', # Source attribution
188
+ r'data\s+(shows|reveals)', # Data-backed claims
189
+ r'\d+x\s+(faster|better|more)', # Comparison stats
190
+ r'(million|billion|trillion)', # Large numbers
191
+ ]
192
+ stat_matches = sum(1 for p in stat_patterns if re.search(p, content, re.I))
193
+ if stat_matches >= 2:
194
+ passed.append("Original statistics/data (citation magnet)")
195
+
196
+ # 10. Conversational/Direct answers - NEW 2025
197
+ direct_answer_patterns = [
198
+ r'is defined as',
199
+ r'refers to',
200
+ r'means that',
201
+ r'the answer is',
202
+ r'in short,',
203
+ r'simply put,',
204
+ r'<dfn'
205
+ ]
206
+ has_direct = any(re.search(p, content, re.I) for p in direct_answer_patterns)
207
+ if has_direct:
208
+ passed.append("Direct answer patterns (LLM-friendly)")
209
+
210
+ # Calculate score
211
+ total = len(passed) + len(issues)
212
+ score = (len(passed) / total * 100) if total > 0 else 0
213
+
214
+ return {
215
+ 'file': str(file_path.name),
216
+ 'passed': passed,
217
+ 'issues': issues,
218
+ 'score': round(score)
219
+ }
220
+
221
+
222
+ def main():
223
+ target = sys.argv[1] if len(sys.argv) > 1 else "."
224
+ target_path = Path(target).resolve()
225
+
226
+ print("\n" + "=" * 60)
227
+ print(" GEO CHECKER - AI Citation Readiness Audit")
228
+ print("=" * 60)
229
+ print(f"Project: {target_path}")
230
+ print("-" * 60)
231
+
232
+ # Find web pages only
233
+ pages = find_web_pages(target_path)
234
+
235
+ if not pages:
236
+ print("\n[!] No public web pages found.")
237
+ print(" Looking for: HTML, JSX, TSX files in pages/app directories")
238
+ print(" Skipping: docs, tests, config files, node_modules")
239
+ output = {"script": "geo_checker", "pages_found": 0, "passed": True}
240
+ print("\n" + json.dumps(output, indent=2))
241
+ sys.exit(0)
242
+
243
+ print(f"Found {len(pages)} public pages to analyze\n")
244
+
245
+ # Check each page
246
+ results = []
247
+ for page in pages:
248
+ result = check_page(page)
249
+ results.append(result)
250
+
251
+ # Print results
252
+ for result in results:
253
+ status = "[OK]" if result['score'] >= 60 else "[!]"
254
+ print(f"{status} {result['file']}: {result['score']}%")
255
+ if result['issues'] and result['score'] < 60:
256
+ for issue in result['issues'][:2]: # Show max 2 issues
257
+ print(f" - {issue}")
258
+
259
+ # Average score
260
+ avg_score = sum(r['score'] for r in results) / len(results) if results else 0
261
+
262
+ print("\n" + "=" * 60)
263
+ print(f"AVERAGE GEO SCORE: {avg_score:.0f}%")
264
+ print("=" * 60)
265
+
266
+ if avg_score >= 80:
267
+ print("[OK] Excellent - Content well-optimized for AI citations")
268
+ elif avg_score >= 60:
269
+ print("[OK] Good - Some improvements recommended")
270
+ elif avg_score >= 40:
271
+ print("[!] Needs work - Add structured elements")
272
+ else:
273
+ print("[X] Poor - Content needs GEO optimization")
274
+
275
+ # JSON output
276
+ output = {
277
+ "script": "geo_checker",
278
+ "project": str(target_path),
279
+ "pages_checked": len(results),
280
+ "average_score": round(avg_score),
281
+ "passed": avg_score >= 60
282
+ }
283
+ print("\n" + json.dumps(output, indent=2))
284
+
285
+ sys.exit(0 if avg_score >= 60 else 1)
286
+
287
+
288
+ if __name__ == "__main__":
289
+ main()
@@ -0,0 +1,154 @@
1
+ ---
2
+ name: i18n-localization
3
+ description: Internationalization and localization patterns. Detecting hardcoded strings, managing translations, locale files, RTL support.
4
+ allowed-tools: Read, Glob, Grep
5
+ ---
6
+
7
+ # i18n & Localization
8
+
9
+ > Internationalization (i18n) and Localization (L10n) best practices.
10
+
11
+ ---
12
+
13
+ ## 1. Core Concepts
14
+
15
+ | Term | Meaning |
16
+ |------|---------|
17
+ | **i18n** | Internationalization - making app translatable |
18
+ | **L10n** | Localization - actual translations |
19
+ | **Locale** | Language + Region (en-US, tr-TR) |
20
+ | **RTL** | Right-to-left languages (Arabic, Hebrew) |
21
+
22
+ ---
23
+
24
+ ## 2. When to Use i18n
25
+
26
+ | Project Type | i18n Needed? |
27
+ |--------------|--------------|
28
+ | Public web app | Yes |
29
+ | SaaS product | Yes |
30
+ | Internal tool | Maybe |
31
+ | Single-region app | Consider future |
32
+ | Personal project | Optional |
33
+
34
+ ---
35
+
36
+ ## 3. Implementation Patterns
37
+
38
+ ### React (react-i18next)
39
+
40
+ ```tsx
41
+ import { useTranslation } from 'react-i18next';
42
+
43
+ function Welcome() {
44
+ const { t } = useTranslation();
45
+ return <h1>{t('welcome.title')}</h1>;
46
+ }
47
+ ```
48
+
49
+ ### Next.js (next-intl)
50
+
51
+ ```tsx
52
+ import { useTranslations } from 'next-intl';
53
+
54
+ export default function Page() {
55
+ const t = useTranslations('Home');
56
+ return <h1>{t('title')}</h1>;
57
+ }
58
+ ```
59
+
60
+ ### Python (gettext)
61
+
62
+ ```python
63
+ from gettext import gettext as _
64
+
65
+ print(_("Welcome to our app"))
66
+ ```
67
+
68
+ ---
69
+
70
+ ## 4. File Structure
71
+
72
+ ```
73
+ locales/
74
+ ├── en/
75
+ │ ├── common.json
76
+ │ ├── auth.json
77
+ │ └── errors.json
78
+ ├── tr/
79
+ │ ├── common.json
80
+ │ ├── auth.json
81
+ │ └── errors.json
82
+ └── ar/ # RTL
83
+ └── ...
84
+ ```
85
+
86
+ ---
87
+
88
+ ## 5. Best Practices
89
+
90
+ ### DO
91
+
92
+ - Use translation keys, not raw text
93
+ - Namespace translations by feature
94
+ - Support pluralization
95
+ - Handle date/number formats per locale
96
+ - Plan for RTL from the start
97
+ - Use ICU message format for complex strings
98
+
99
+ ### DON'T
100
+
101
+ - Hardcode strings in components
102
+ - Concatenate translated strings
103
+ - Assume text length (German is 30% longer)
104
+ - Forget about RTL layout
105
+ - Mix languages in same file
106
+
107
+ ---
108
+
109
+ ## 6. Common Issues
110
+
111
+ | Issue | Solution |
112
+ |-------|----------|
113
+ | Missing translation | Fallback to default language |
114
+ | Hardcoded strings | Use linter/checker script |
115
+ | Date format | Use Intl.DateTimeFormat |
116
+ | Number format | Use Intl.NumberFormat |
117
+ | Pluralization | Use ICU message format |
118
+
119
+ ---
120
+
121
+ ## 7. RTL Support
122
+
123
+ ```css
124
+ /* CSS Logical Properties */
125
+ .container {
126
+ margin-inline-start: 1rem; /* Not margin-left */
127
+ padding-inline-end: 1rem; /* Not padding-right */
128
+ }
129
+
130
+ [dir="rtl"] .icon {
131
+ transform: scaleX(-1);
132
+ }
133
+ ```
134
+
135
+ ---
136
+
137
+ ## 8. Checklist
138
+
139
+ Before shipping:
140
+
141
+ - [ ] All user-facing strings use translation keys
142
+ - [ ] Locale files exist for all supported languages
143
+ - [ ] Date/number formatting uses Intl API
144
+ - [ ] RTL layout tested (if applicable)
145
+ - [ ] Fallback language configured
146
+ - [ ] No hardcoded strings in components
147
+
148
+ ---
149
+
150
+ ## Script
151
+
152
+ | Script | Purpose | Command |
153
+ |--------|---------|---------|
154
+ | `scripts/i18n_checker.py` | Detect hardcoded strings & missing translations | `python scripts/i18n_checker.py <project_path>` |
@@ -0,0 +1,241 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ i18n Checker - Detects hardcoded strings and missing translations.
4
+ Scans for untranslated text in React, Vue, and Python files.
5
+ """
6
+ import sys
7
+ import re
8
+ import json
9
+ from pathlib import Path
10
+
11
+ # Fix Windows console encoding for Unicode output
12
+ try:
13
+ sys.stdout.reconfigure(encoding='utf-8', errors='replace')
14
+ sys.stderr.reconfigure(encoding='utf-8', errors='replace')
15
+ except AttributeError:
16
+ pass # Python < 3.7
17
+
18
+ # Patterns that indicate hardcoded strings (should be translated)
19
+ HARDCODED_PATTERNS = {
20
+ 'jsx': [
21
+ # Text directly in JSX: <div>Hello World</div>
22
+ r'>\s*[A-Z][a-zA-Z\s]{3,30}\s*</',
23
+ # JSX attribute strings: title="Welcome"
24
+ r'(title|placeholder|label|alt|aria-label)="[A-Z][a-zA-Z\s]{2,}"',
25
+ # Button/heading text
26
+ r'<(button|h[1-6]|p|span|label)[^>]*>\s*[A-Z][a-zA-Z\s!?.,]{3,}\s*</',
27
+ ],
28
+ 'vue': [
29
+ # Vue template text
30
+ r'>\s*[A-Z][a-zA-Z\s]{3,30}\s*</',
31
+ r'(placeholder|label|title)="[A-Z][a-zA-Z\s]{2,}"',
32
+ ],
33
+ 'python': [
34
+ # print/raise with string literals
35
+ r'(print|raise\s+\w+)\s*\(\s*["\'][A-Z][^"\']{5,}["\']',
36
+ # Flask flash messages
37
+ r'flash\s*\(\s*["\'][A-Z][^"\']{5,}["\']',
38
+ ]
39
+ }
40
+
41
+ # Patterns that indicate proper i18n usage
42
+ I18N_PATTERNS = [
43
+ r't\(["\']', # t('key') - react-i18next
44
+ r'useTranslation', # React hook
45
+ r'\$t\(', # Vue i18n
46
+ r'_\(["\']', # Python gettext
47
+ r'gettext\(', # Python gettext
48
+ r'useTranslations', # next-intl
49
+ r'FormattedMessage', # react-intl
50
+ r'i18n\.', # Generic i18n
51
+ ]
52
+
53
+ def find_locale_files(project_path: Path) -> list:
54
+ """Find translation/locale files."""
55
+ patterns = [
56
+ "**/locales/**/*.json",
57
+ "**/translations/**/*.json",
58
+ "**/lang/**/*.json",
59
+ "**/i18n/**/*.json",
60
+ "**/messages/*.json",
61
+ "**/*.po", # gettext
62
+ ]
63
+
64
+ files = []
65
+ for pattern in patterns:
66
+ files.extend(project_path.glob(pattern))
67
+
68
+ return [f for f in files if 'node_modules' not in str(f)]
69
+
70
+ def check_locale_completeness(locale_files: list) -> dict:
71
+ """Check if all locales have the same keys."""
72
+ issues = []
73
+ passed = []
74
+
75
+ if not locale_files:
76
+ return {'passed': [], 'issues': ["[!] No locale files found"]}
77
+
78
+ # Group by parent folder (language)
79
+ locales = {}
80
+ for f in locale_files:
81
+ if f.suffix == '.json':
82
+ try:
83
+ lang = f.parent.name
84
+ content = json.loads(f.read_text(encoding='utf-8'))
85
+ if lang not in locales:
86
+ locales[lang] = {}
87
+ locales[lang][f.stem] = set(flatten_keys(content))
88
+ except:
89
+ continue
90
+
91
+ if len(locales) < 2:
92
+ passed.append(f"[OK] Found {len(locale_files)} locale file(s)")
93
+ return {'passed': passed, 'issues': issues}
94
+
95
+ passed.append(f"[OK] Found {len(locales)} language(s): {', '.join(locales.keys())}")
96
+
97
+ # Compare keys across locales
98
+ all_langs = list(locales.keys())
99
+ base_lang = all_langs[0]
100
+
101
+ for namespace in locales.get(base_lang, {}):
102
+ base_keys = locales[base_lang].get(namespace, set())
103
+
104
+ for lang in all_langs[1:]:
105
+ other_keys = locales.get(lang, {}).get(namespace, set())
106
+
107
+ missing = base_keys - other_keys
108
+ if missing:
109
+ issues.append(f"[X] {lang}/{namespace}: Missing {len(missing)} keys")
110
+
111
+ extra = other_keys - base_keys
112
+ if extra:
113
+ issues.append(f"[!] {lang}/{namespace}: {len(extra)} extra keys")
114
+
115
+ if not issues:
116
+ passed.append("[OK] All locales have matching keys")
117
+
118
+ return {'passed': passed, 'issues': issues}
119
+
120
+ def flatten_keys(d, prefix=''):
121
+ """Flatten nested dict keys."""
122
+ keys = set()
123
+ for k, v in d.items():
124
+ new_key = f"{prefix}.{k}" if prefix else k
125
+ if isinstance(v, dict):
126
+ keys.update(flatten_keys(v, new_key))
127
+ else:
128
+ keys.add(new_key)
129
+ return keys
130
+
131
+ def check_hardcoded_strings(project_path: Path) -> dict:
132
+ """Check for hardcoded strings in code files."""
133
+ issues = []
134
+ passed = []
135
+
136
+ # Find code files
137
+ extensions = {
138
+ '.tsx': 'jsx', '.jsx': 'jsx', '.ts': 'jsx', '.js': 'jsx',
139
+ '.vue': 'vue',
140
+ '.py': 'python'
141
+ }
142
+
143
+ code_files = []
144
+ for ext in extensions:
145
+ code_files.extend(project_path.rglob(f"*{ext}"))
146
+
147
+ code_files = [f for f in code_files if not any(x in str(f) for x in
148
+ ['node_modules', '.git', 'dist', 'build', '__pycache__', 'venv', 'test', 'spec'])]
149
+
150
+ if not code_files:
151
+ return {'passed': ["[!] No code files found"], 'issues': []}
152
+
153
+ files_with_i18n = 0
154
+ files_with_hardcoded = 0
155
+ hardcoded_examples = []
156
+
157
+ for file_path in code_files[:50]: # Limit
158
+ try:
159
+ content = file_path.read_text(encoding='utf-8', errors='ignore')
160
+ ext = file_path.suffix
161
+ file_type = extensions.get(ext, 'jsx')
162
+
163
+ # Check for i18n usage
164
+ has_i18n = any(re.search(p, content) for p in I18N_PATTERNS)
165
+ if has_i18n:
166
+ files_with_i18n += 1
167
+
168
+ # Check for hardcoded strings
169
+ patterns = HARDCODED_PATTERNS.get(file_type, [])
170
+ hardcoded_found = False
171
+
172
+ for pattern in patterns:
173
+ matches = re.findall(pattern, content)
174
+ if matches and not has_i18n:
175
+ hardcoded_found = True
176
+ if len(hardcoded_examples) < 5:
177
+ hardcoded_examples.append(f"{file_path.name}: {str(matches[0])[:40]}...")
178
+
179
+ if hardcoded_found:
180
+ files_with_hardcoded += 1
181
+
182
+ except:
183
+ continue
184
+
185
+ passed.append(f"[OK] Analyzed {len(code_files)} code files")
186
+
187
+ if files_with_i18n > 0:
188
+ passed.append(f"[OK] {files_with_i18n} files use i18n")
189
+
190
+ if files_with_hardcoded > 0:
191
+ issues.append(f"[X] {files_with_hardcoded} files may have hardcoded strings")
192
+ for ex in hardcoded_examples:
193
+ issues.append(f" → {ex}")
194
+ else:
195
+ passed.append("[OK] No obvious hardcoded strings detected")
196
+
197
+ return {'passed': passed, 'issues': issues}
198
+
199
+ def main():
200
+ target = sys.argv[1] if len(sys.argv) > 1 else "."
201
+ project_path = Path(target)
202
+
203
+ print("\n" + "=" * 60)
204
+ print(" i18n CHECKER - Internationalization Audit")
205
+ print("=" * 60 + "\n")
206
+
207
+ # Check locale files
208
+ locale_files = find_locale_files(project_path)
209
+ locale_result = check_locale_completeness(locale_files)
210
+
211
+ # Check hardcoded strings
212
+ code_result = check_hardcoded_strings(project_path)
213
+
214
+ # Print results
215
+ print("[LOCALE FILES]")
216
+ print("-" * 40)
217
+ for item in locale_result['passed']:
218
+ print(f" {item}")
219
+ for item in locale_result['issues']:
220
+ print(f" {item}")
221
+
222
+ print("\n[CODE ANALYSIS]")
223
+ print("-" * 40)
224
+ for item in code_result['passed']:
225
+ print(f" {item}")
226
+ for item in code_result['issues']:
227
+ print(f" {item}")
228
+
229
+ # Summary
230
+ critical_issues = sum(1 for i in locale_result['issues'] + code_result['issues'] if i.startswith("[X]"))
231
+
232
+ print("\n" + "=" * 60)
233
+ if critical_issues == 0:
234
+ print("[OK] i18n CHECK: PASSED")
235
+ sys.exit(0)
236
+ else:
237
+ print(f"[X] i18n CHECK: {critical_issues} issues found")
238
+ sys.exit(1)
239
+
240
+ if __name__ == "__main__":
241
+ main()