@elizaos/skills 2.0.0-alpha.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 (371) hide show
  1. package/README.md +126 -0
  2. package/package.json +53 -0
  3. package/skills/1password/SKILL.md +70 -0
  4. package/skills/1password/references/cli-examples.md +29 -0
  5. package/skills/1password/references/get-started.md +17 -0
  6. package/skills/apple-notes/SKILL.md +77 -0
  7. package/skills/apple-reminders/SKILL.md +96 -0
  8. package/skills/bear-notes/SKILL.md +107 -0
  9. package/skills/bird/SKILL.md +224 -0
  10. package/skills/blogwatcher/SKILL.md +69 -0
  11. package/skills/blucli/SKILL.md +47 -0
  12. package/skills/bluebubbles/SKILL.md +131 -0
  13. package/skills/camsnap/SKILL.md +45 -0
  14. package/skills/canvas/SKILL.md +203 -0
  15. package/skills/clawhub/SKILL.md +77 -0
  16. package/skills/coding-agent/SKILL.md +284 -0
  17. package/skills/discord/SKILL.md +578 -0
  18. package/skills/eightctl/SKILL.md +50 -0
  19. package/skills/food-order/SKILL.md +48 -0
  20. package/skills/gemini/SKILL.md +43 -0
  21. package/skills/gifgrep/SKILL.md +79 -0
  22. package/skills/github/SKILL.md +77 -0
  23. package/skills/gog/SKILL.md +116 -0
  24. package/skills/goplaces/SKILL.md +52 -0
  25. package/skills/healthcheck/SKILL.md +245 -0
  26. package/skills/himalaya/SKILL.md +257 -0
  27. package/skills/himalaya/references/configuration.md +184 -0
  28. package/skills/himalaya/references/message-composition.md +199 -0
  29. package/skills/imsg/SKILL.md +74 -0
  30. package/skills/local-places/SERVER_README.md +101 -0
  31. package/skills/local-places/SKILL.md +102 -0
  32. package/skills/local-places/pyproject.toml +21 -0
  33. package/skills/local-places/src/local_places/__init__.py +2 -0
  34. package/skills/local-places/src/local_places/google_places.py +314 -0
  35. package/skills/local-places/src/local_places/main.py +65 -0
  36. package/skills/local-places/src/local_places/schemas.py +107 -0
  37. package/skills/mcporter/SKILL.md +61 -0
  38. package/skills/model-usage/SKILL.md +69 -0
  39. package/skills/model-usage/references/codexbar-cli.md +33 -0
  40. package/skills/model-usage/scripts/model_usage.py +310 -0
  41. package/skills/nano-banana-pro/SKILL.md +58 -0
  42. package/skills/nano-banana-pro/scripts/generate_image.py +184 -0
  43. package/skills/nano-pdf/SKILL.md +38 -0
  44. package/skills/notion/SKILL.md +172 -0
  45. package/skills/obsidian/SKILL.md +81 -0
  46. package/skills/openai-image-gen/SKILL.md +89 -0
  47. package/skills/openai-image-gen/scripts/gen.py +240 -0
  48. package/skills/openai-whisper/SKILL.md +38 -0
  49. package/skills/openai-whisper-api/SKILL.md +52 -0
  50. package/skills/openai-whisper-api/scripts/transcribe.sh +85 -0
  51. package/skills/openhue/SKILL.md +51 -0
  52. package/skills/oracle/SKILL.md +125 -0
  53. package/skills/ordercli/SKILL.md +78 -0
  54. package/skills/peekaboo/SKILL.md +190 -0
  55. package/skills/sag/SKILL.md +87 -0
  56. package/skills/security-ask-questions-if-underspecified/.claude-plugin/plugin.json +10 -0
  57. package/skills/security-ask-questions-if-underspecified/README.md +24 -0
  58. package/skills/security-ask-questions-if-underspecified/skills/ask-questions-if-underspecified/SKILL.md +85 -0
  59. package/skills/security-audit-context-building/.claude-plugin/plugin.json +10 -0
  60. package/skills/security-audit-context-building/README.md +58 -0
  61. package/skills/security-audit-context-building/commands/audit-context.md +21 -0
  62. package/skills/security-audit-context-building/skills/audit-context-building/SKILL.md +297 -0
  63. package/skills/security-audit-context-building/skills/audit-context-building/resources/COMPLETENESS_CHECKLIST.md +47 -0
  64. package/skills/security-audit-context-building/skills/audit-context-building/resources/FUNCTION_MICRO_ANALYSIS_EXAMPLE.md +355 -0
  65. package/skills/security-audit-context-building/skills/audit-context-building/resources/OUTPUT_REQUIREMENTS.md +71 -0
  66. package/skills/security-building-secure-contracts/.claude-plugin/plugin.json +10 -0
  67. package/skills/security-building-secure-contracts/README.md +241 -0
  68. package/skills/security-building-secure-contracts/skills/algorand-vulnerability-scanner/SKILL.md +284 -0
  69. package/skills/security-building-secure-contracts/skills/algorand-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +405 -0
  70. package/skills/security-building-secure-contracts/skills/audit-prep-assistant/SKILL.md +409 -0
  71. package/skills/security-building-secure-contracts/skills/cairo-vulnerability-scanner/SKILL.md +329 -0
  72. package/skills/security-building-secure-contracts/skills/cairo-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +722 -0
  73. package/skills/security-building-secure-contracts/skills/code-maturity-assessor/SKILL.md +218 -0
  74. package/skills/security-building-secure-contracts/skills/code-maturity-assessor/resources/ASSESSMENT_CRITERIA.md +355 -0
  75. package/skills/security-building-secure-contracts/skills/code-maturity-assessor/resources/EXAMPLE_REPORT.md +248 -0
  76. package/skills/security-building-secure-contracts/skills/code-maturity-assessor/resources/REPORT_FORMAT.md +33 -0
  77. package/skills/security-building-secure-contracts/skills/cosmos-vulnerability-scanner/SKILL.md +334 -0
  78. package/skills/security-building-secure-contracts/skills/cosmos-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +740 -0
  79. package/skills/security-building-secure-contracts/skills/guidelines-advisor/SKILL.md +252 -0
  80. package/skills/security-building-secure-contracts/skills/guidelines-advisor/resources/ASSESSMENT_AREAS.md +329 -0
  81. package/skills/security-building-secure-contracts/skills/guidelines-advisor/resources/DELIVERABLES.md +118 -0
  82. package/skills/security-building-secure-contracts/skills/guidelines-advisor/resources/EXAMPLE_REPORT.md +298 -0
  83. package/skills/security-building-secure-contracts/skills/secure-workflow-guide/SKILL.md +161 -0
  84. package/skills/security-building-secure-contracts/skills/secure-workflow-guide/resources/EXAMPLE_REPORT.md +279 -0
  85. package/skills/security-building-secure-contracts/skills/secure-workflow-guide/resources/WORKFLOW_STEPS.md +132 -0
  86. package/skills/security-building-secure-contracts/skills/solana-vulnerability-scanner/SKILL.md +389 -0
  87. package/skills/security-building-secure-contracts/skills/solana-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +669 -0
  88. package/skills/security-building-secure-contracts/skills/substrate-vulnerability-scanner/SKILL.md +298 -0
  89. package/skills/security-building-secure-contracts/skills/substrate-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +791 -0
  90. package/skills/security-building-secure-contracts/skills/token-integration-analyzer/SKILL.md +362 -0
  91. package/skills/security-building-secure-contracts/skills/token-integration-analyzer/resources/ASSESSMENT_CATEGORIES.md +571 -0
  92. package/skills/security-building-secure-contracts/skills/token-integration-analyzer/resources/REPORT_TEMPLATES.md +141 -0
  93. package/skills/security-building-secure-contracts/skills/ton-vulnerability-scanner/SKILL.md +388 -0
  94. package/skills/security-building-secure-contracts/skills/ton-vulnerability-scanner/resources/VULNERABILITY_PATTERNS.md +595 -0
  95. package/skills/security-burpsuite-project-parser/.claude-plugin/plugin.json +10 -0
  96. package/skills/security-burpsuite-project-parser/README.md +103 -0
  97. package/skills/security-burpsuite-project-parser/commands/burp-search.md +18 -0
  98. package/skills/security-burpsuite-project-parser/skills/SKILL.md +358 -0
  99. package/skills/security-burpsuite-project-parser/skills/scripts/burp-search.sh +99 -0
  100. package/skills/security-claude-in-chrome-troubleshooting/.claude-plugin/plugin.json +8 -0
  101. package/skills/security-claude-in-chrome-troubleshooting/README.md +31 -0
  102. package/skills/security-claude-in-chrome-troubleshooting/skills/claude-in-chrome-troubleshooting/SKILL.md +251 -0
  103. package/skills/security-constant-time-analysis/.claude-plugin/plugin.json +9 -0
  104. package/skills/security-constant-time-analysis/README.md +381 -0
  105. package/skills/security-constant-time-analysis/commands/ct-check.md +20 -0
  106. package/skills/security-constant-time-analysis/ct_analyzer/__init__.py +49 -0
  107. package/skills/security-constant-time-analysis/ct_analyzer/analyzer.py +1284 -0
  108. package/skills/security-constant-time-analysis/ct_analyzer/script_analyzers.py +3081 -0
  109. package/skills/security-constant-time-analysis/ct_analyzer/tests/__init__.py +1 -0
  110. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_analyzer.py +1397 -0
  111. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/bn_excerpt.js +205 -0
  112. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/decompose_constant_time.c +181 -0
  113. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/decompose_vulnerable.c +74 -0
  114. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/decompose_vulnerable.go +78 -0
  115. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/decompose_vulnerable.rs +92 -0
  116. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.cs +174 -0
  117. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.java +161 -0
  118. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.kt +181 -0
  119. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.php +140 -0
  120. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.py +252 -0
  121. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.rb +188 -0
  122. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.swift +199 -0
  123. package/skills/security-constant-time-analysis/ct_analyzer/tests/test_samples/vulnerable.ts +154 -0
  124. package/skills/security-constant-time-analysis/pyproject.toml +52 -0
  125. package/skills/security-constant-time-analysis/skills/constant-time-analysis/README.md +90 -0
  126. package/skills/security-constant-time-analysis/skills/constant-time-analysis/SKILL.md +219 -0
  127. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/compiled.md +129 -0
  128. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/javascript.md +136 -0
  129. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/kotlin.md +252 -0
  130. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/php.md +172 -0
  131. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/python.md +179 -0
  132. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/ruby.md +198 -0
  133. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/swift.md +288 -0
  134. package/skills/security-constant-time-analysis/skills/constant-time-analysis/references/vm-compiled.md +354 -0
  135. package/skills/security-constant-time-analysis/uv.lock +8 -0
  136. package/skills/security-culture-index/.claude-plugin/plugin.json +8 -0
  137. package/skills/security-culture-index/README.md +79 -0
  138. package/skills/security-culture-index/skills/interpreting-culture-index/SKILL.md +293 -0
  139. package/skills/security-culture-index/skills/interpreting-culture-index/references/anti-patterns.md +255 -0
  140. package/skills/security-culture-index/skills/interpreting-culture-index/references/conversation-starters.md +408 -0
  141. package/skills/security-culture-index/skills/interpreting-culture-index/references/interview-trait-signals.md +253 -0
  142. package/skills/security-culture-index/skills/interpreting-culture-index/references/motivators.md +158 -0
  143. package/skills/security-culture-index/skills/interpreting-culture-index/references/patterns-archetypes.md +147 -0
  144. package/skills/security-culture-index/skills/interpreting-culture-index/references/primary-traits.md +307 -0
  145. package/skills/security-culture-index/skills/interpreting-culture-index/references/secondary-traits.md +228 -0
  146. package/skills/security-culture-index/skills/interpreting-culture-index/references/team-composition.md +148 -0
  147. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/check_deps.py +108 -0
  148. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/culture_index/__init__.py +20 -0
  149. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/culture_index/constants.py +122 -0
  150. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/culture_index/extract.py +187 -0
  151. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/culture_index/models.py +16 -0
  152. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/culture_index/opencv_extractor.py +520 -0
  153. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/extract_pdf.py +237 -0
  154. package/skills/security-culture-index/skills/interpreting-culture-index/scripts/pyproject.toml +18 -0
  155. package/skills/security-culture-index/skills/interpreting-culture-index/templates/burnout-report.md +113 -0
  156. package/skills/security-culture-index/skills/interpreting-culture-index/templates/comparison-report.md +103 -0
  157. package/skills/security-culture-index/skills/interpreting-culture-index/templates/hiring-profile.md +127 -0
  158. package/skills/security-culture-index/skills/interpreting-culture-index/templates/individual-report.md +85 -0
  159. package/skills/security-culture-index/skills/interpreting-culture-index/templates/predicted-profile.md +165 -0
  160. package/skills/security-culture-index/skills/interpreting-culture-index/templates/team-report.md +109 -0
  161. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/analyze-team.md +188 -0
  162. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/coach-manager.md +267 -0
  163. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/compare-profiles.md +188 -0
  164. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/define-hiring-profile.md +220 -0
  165. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/detect-burnout.md +206 -0
  166. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/extract-from-pdf.md +121 -0
  167. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/interpret-individual.md +183 -0
  168. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/interview-debrief.md +234 -0
  169. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/mediate-conflict.md +306 -0
  170. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/plan-onboarding.md +322 -0
  171. package/skills/security-culture-index/skills/interpreting-culture-index/workflows/predict-from-interview.md +250 -0
  172. package/skills/security-differential-review/.claude-plugin/plugin.json +10 -0
  173. package/skills/security-differential-review/README.md +109 -0
  174. package/skills/security-differential-review/commands/diff-review.md +21 -0
  175. package/skills/security-differential-review/skills/differential-review/SKILL.md +220 -0
  176. package/skills/security-differential-review/skills/differential-review/adversarial.md +203 -0
  177. package/skills/security-differential-review/skills/differential-review/methodology.md +234 -0
  178. package/skills/security-differential-review/skills/differential-review/patterns.md +300 -0
  179. package/skills/security-differential-review/skills/differential-review/reporting.md +369 -0
  180. package/skills/security-dwarf-expert/.claude-plugin/plugin.json +10 -0
  181. package/skills/security-dwarf-expert/README.md +38 -0
  182. package/skills/security-dwarf-expert/skills/dwarf-expert/SKILL.md +93 -0
  183. package/skills/security-dwarf-expert/skills/dwarf-expert/reference/coding.md +31 -0
  184. package/skills/security-dwarf-expert/skills/dwarf-expert/reference/dwarfdump.md +50 -0
  185. package/skills/security-dwarf-expert/skills/dwarf-expert/reference/readelf.md +8 -0
  186. package/skills/security-entry-point-analyzer/.claude-plugin/plugin.json +10 -0
  187. package/skills/security-entry-point-analyzer/README.md +74 -0
  188. package/skills/security-entry-point-analyzer/commands/entry-points.md +18 -0
  189. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/SKILL.md +251 -0
  190. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/cosmwasm.md +182 -0
  191. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/move-aptos.md +107 -0
  192. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/move-sui.md +87 -0
  193. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/solana.md +155 -0
  194. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/solidity.md +135 -0
  195. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/ton.md +185 -0
  196. package/skills/security-entry-point-analyzer/skills/entry-point-analyzer/references/vyper.md +141 -0
  197. package/skills/security-firebase-apk-scanner/.claude-plugin/plugin.json +10 -0
  198. package/skills/security-firebase-apk-scanner/README.md +85 -0
  199. package/skills/security-firebase-apk-scanner/commands/scan-apk.md +18 -0
  200. package/skills/security-firebase-apk-scanner/scanner.sh +1408 -0
  201. package/skills/security-firebase-apk-scanner/skills/firebase-apk-scanner/SKILL.md +197 -0
  202. package/skills/security-firebase-apk-scanner/skills/firebase-apk-scanner/references/vulnerabilities.md +803 -0
  203. package/skills/security-fix-review/.claude-plugin/plugin.json +13 -0
  204. package/skills/security-fix-review/README.md +118 -0
  205. package/skills/security-fix-review/commands/fix-review.md +24 -0
  206. package/skills/security-fix-review/skills/fix-review/SKILL.md +264 -0
  207. package/skills/security-fix-review/skills/fix-review/references/bug-detection.md +408 -0
  208. package/skills/security-fix-review/skills/fix-review/references/finding-matching.md +298 -0
  209. package/skills/security-fix-review/skills/fix-review/references/report-parsing.md +398 -0
  210. package/skills/security-insecure-defaults/.claude-plugin/plugin.json +10 -0
  211. package/skills/security-insecure-defaults/README.md +45 -0
  212. package/skills/security-insecure-defaults/skills/insecure-defaults/SKILL.md +117 -0
  213. package/skills/security-insecure-defaults/skills/insecure-defaults/references/examples.md +409 -0
  214. package/skills/security-modern-python/.claude-plugin/plugin.json +10 -0
  215. package/skills/security-modern-python/README.md +58 -0
  216. package/skills/security-modern-python/hooks/hooks.json +16 -0
  217. package/skills/security-modern-python/hooks/intercept-legacy-python.bats +388 -0
  218. package/skills/security-modern-python/hooks/intercept-legacy-python.sh +109 -0
  219. package/skills/security-modern-python/hooks/test_helper.bash +75 -0
  220. package/skills/security-modern-python/skills/modern-python/SKILL.md +333 -0
  221. package/skills/security-modern-python/skills/modern-python/references/dependabot.md +43 -0
  222. package/skills/security-modern-python/skills/modern-python/references/migration-checklist.md +141 -0
  223. package/skills/security-modern-python/skills/modern-python/references/pep723-scripts.md +259 -0
  224. package/skills/security-modern-python/skills/modern-python/references/prek.md +211 -0
  225. package/skills/security-modern-python/skills/modern-python/references/pyproject.md +254 -0
  226. package/skills/security-modern-python/skills/modern-python/references/ruff-config.md +240 -0
  227. package/skills/security-modern-python/skills/modern-python/references/security-setup.md +255 -0
  228. package/skills/security-modern-python/skills/modern-python/references/testing.md +284 -0
  229. package/skills/security-modern-python/skills/modern-python/references/uv-commands.md +200 -0
  230. package/skills/security-modern-python/skills/modern-python/templates/dependabot.yml +36 -0
  231. package/skills/security-modern-python/skills/modern-python/templates/pre-commit-config.yaml +66 -0
  232. package/skills/security-property-based-testing/.claude-plugin/plugin.json +9 -0
  233. package/skills/security-property-based-testing/README.md +47 -0
  234. package/skills/security-property-based-testing/skills/property-based-testing/README.md +88 -0
  235. package/skills/security-property-based-testing/skills/property-based-testing/SKILL.md +109 -0
  236. package/skills/security-property-based-testing/skills/property-based-testing/references/design.md +191 -0
  237. package/skills/security-property-based-testing/skills/property-based-testing/references/generating.md +200 -0
  238. package/skills/security-property-based-testing/skills/property-based-testing/references/libraries.md +130 -0
  239. package/skills/security-property-based-testing/skills/property-based-testing/references/refactoring.md +181 -0
  240. package/skills/security-property-based-testing/skills/property-based-testing/references/reviewing.md +209 -0
  241. package/skills/security-property-based-testing/skills/property-based-testing/references/strategies.md +124 -0
  242. package/skills/semgrep-rule-creator/.claude-plugin/plugin.json +8 -0
  243. package/skills/semgrep-rule-creator/README.md +43 -0
  244. package/skills/semgrep-rule-creator/commands/semgrep-rule.md +26 -0
  245. package/skills/semgrep-rule-creator/skills/semgrep-rule-creator/SKILL.md +168 -0
  246. package/skills/semgrep-rule-creator/skills/semgrep-rule-creator/references/quick-reference.md +203 -0
  247. package/skills/semgrep-rule-creator/skills/semgrep-rule-creator/references/workflow.md +240 -0
  248. package/skills/semgrep-rule-variant-creator/.claude-plugin/plugin.json +9 -0
  249. package/skills/semgrep-rule-variant-creator/README.md +86 -0
  250. package/skills/semgrep-rule-variant-creator/skills/semgrep-rule-variant-creator/SKILL.md +205 -0
  251. package/skills/semgrep-rule-variant-creator/skills/semgrep-rule-variant-creator/references/applicability-analysis.md +250 -0
  252. package/skills/semgrep-rule-variant-creator/skills/semgrep-rule-variant-creator/references/language-syntax-guide.md +324 -0
  253. package/skills/semgrep-rule-variant-creator/skills/semgrep-rule-variant-creator/references/workflow.md +518 -0
  254. package/skills/session-logs/SKILL.md +115 -0
  255. package/skills/sharp-edges/.claude-plugin/plugin.json +10 -0
  256. package/skills/sharp-edges/README.md +48 -0
  257. package/skills/sharp-edges/skills/sharp-edges/SKILL.md +292 -0
  258. package/skills/sharp-edges/skills/sharp-edges/references/auth-patterns.md +252 -0
  259. package/skills/sharp-edges/skills/sharp-edges/references/case-studies.md +274 -0
  260. package/skills/sharp-edges/skills/sharp-edges/references/config-patterns.md +333 -0
  261. package/skills/sharp-edges/skills/sharp-edges/references/crypto-apis.md +190 -0
  262. package/skills/sharp-edges/skills/sharp-edges/references/lang-c.md +205 -0
  263. package/skills/sharp-edges/skills/sharp-edges/references/lang-csharp.md +285 -0
  264. package/skills/sharp-edges/skills/sharp-edges/references/lang-go.md +270 -0
  265. package/skills/sharp-edges/skills/sharp-edges/references/lang-java.md +263 -0
  266. package/skills/sharp-edges/skills/sharp-edges/references/lang-javascript.md +269 -0
  267. package/skills/sharp-edges/skills/sharp-edges/references/lang-kotlin.md +265 -0
  268. package/skills/sharp-edges/skills/sharp-edges/references/lang-php.md +245 -0
  269. package/skills/sharp-edges/skills/sharp-edges/references/lang-python.md +274 -0
  270. package/skills/sharp-edges/skills/sharp-edges/references/lang-ruby.md +273 -0
  271. package/skills/sharp-edges/skills/sharp-edges/references/lang-rust.md +272 -0
  272. package/skills/sharp-edges/skills/sharp-edges/references/lang-swift.md +287 -0
  273. package/skills/sharp-edges/skills/sharp-edges/references/language-specific.md +588 -0
  274. package/skills/sherpa-onnx-tts/SKILL.md +103 -0
  275. package/skills/sherpa-onnx-tts/bin/sherpa-onnx-tts +178 -0
  276. package/skills/skill-creator/SKILL.md +370 -0
  277. package/skills/skill-creator/license.txt +202 -0
  278. package/skills/skill-creator/scripts/init_skill.py +378 -0
  279. package/skills/skill-creator/scripts/package_skill.py +111 -0
  280. package/skills/skill-creator/scripts/quick_validate.py +101 -0
  281. package/skills/slack/SKILL.md +144 -0
  282. package/skills/songsee/SKILL.md +49 -0
  283. package/skills/sonoscli/SKILL.md +46 -0
  284. package/skills/spec-to-code-compliance/.claude-plugin/plugin.json +10 -0
  285. package/skills/spec-to-code-compliance/README.md +67 -0
  286. package/skills/spec-to-code-compliance/commands/spec-compliance.md +22 -0
  287. package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/SKILL.md +349 -0
  288. package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/resources/COMPLETENESS_CHECKLIST.md +69 -0
  289. package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/resources/IR_EXAMPLES.md +417 -0
  290. package/skills/spec-to-code-compliance/skills/spec-to-code-compliance/resources/OUTPUT_REQUIREMENTS.md +105 -0
  291. package/skills/spotify-player/SKILL.md +64 -0
  292. package/skills/static-analysis/.claude-plugin/plugin.json +8 -0
  293. package/skills/static-analysis/README.md +59 -0
  294. package/skills/static-analysis/skills/codeql/SKILL.md +315 -0
  295. package/skills/static-analysis/skills/sarif-parsing/SKILL.md +479 -0
  296. package/skills/static-analysis/skills/sarif-parsing/resources/jq-queries.md +162 -0
  297. package/skills/static-analysis/skills/sarif-parsing/resources/sarif_helpers.py +331 -0
  298. package/skills/static-analysis/skills/semgrep/SKILL.md +337 -0
  299. package/skills/summarize/SKILL.md +87 -0
  300. package/skills/testing-handbook-skills/.claude-plugin/plugin.json +8 -0
  301. package/skills/testing-handbook-skills/README.md +241 -0
  302. package/skills/testing-handbook-skills/scripts/pyproject.toml +8 -0
  303. package/skills/testing-handbook-skills/scripts/validate-skills.py +657 -0
  304. package/skills/testing-handbook-skills/skills/address-sanitizer/SKILL.md +341 -0
  305. package/skills/testing-handbook-skills/skills/aflpp/SKILL.md +640 -0
  306. package/skills/testing-handbook-skills/skills/atheris/SKILL.md +515 -0
  307. package/skills/testing-handbook-skills/skills/cargo-fuzz/SKILL.md +454 -0
  308. package/skills/testing-handbook-skills/skills/codeql/SKILL.md +549 -0
  309. package/skills/testing-handbook-skills/skills/constant-time-testing/SKILL.md +507 -0
  310. package/skills/testing-handbook-skills/skills/coverage-analysis/SKILL.md +607 -0
  311. package/skills/testing-handbook-skills/skills/fuzzing-dictionary/SKILL.md +297 -0
  312. package/skills/testing-handbook-skills/skills/fuzzing-obstacles/SKILL.md +426 -0
  313. package/skills/testing-handbook-skills/skills/harness-writing/SKILL.md +614 -0
  314. package/skills/testing-handbook-skills/skills/libafl/SKILL.md +625 -0
  315. package/skills/testing-handbook-skills/skills/libfuzzer/SKILL.md +795 -0
  316. package/skills/testing-handbook-skills/skills/ossfuzz/SKILL.md +426 -0
  317. package/skills/testing-handbook-skills/skills/ruzzy/SKILL.md +443 -0
  318. package/skills/testing-handbook-skills/skills/semgrep/SKILL.md +601 -0
  319. package/skills/testing-handbook-skills/skills/testing-handbook-generator/SKILL.md +372 -0
  320. package/skills/testing-handbook-skills/skills/testing-handbook-generator/agent-prompt.md +280 -0
  321. package/skills/testing-handbook-skills/skills/testing-handbook-generator/discovery.md +452 -0
  322. package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/domain-skill.md +504 -0
  323. package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/fuzzer-skill.md +454 -0
  324. package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/technique-skill.md +527 -0
  325. package/skills/testing-handbook-skills/skills/testing-handbook-generator/templates/tool-skill.md +366 -0
  326. package/skills/testing-handbook-skills/skills/testing-handbook-generator/testing.md +482 -0
  327. package/skills/testing-handbook-skills/skills/wycheproof/SKILL.md +533 -0
  328. package/skills/things-mac/SKILL.md +86 -0
  329. package/skills/tmux/SKILL.md +135 -0
  330. package/skills/tmux/scripts/find-sessions.sh +112 -0
  331. package/skills/tmux/scripts/wait-for-text.sh +83 -0
  332. package/skills/trello/SKILL.md +95 -0
  333. package/skills/variant-analysis/.claude-plugin/plugin.json +8 -0
  334. package/skills/variant-analysis/README.md +41 -0
  335. package/skills/variant-analysis/commands/variants.md +23 -0
  336. package/skills/variant-analysis/skills/variant-analysis/METHODOLOGY.md +327 -0
  337. package/skills/variant-analysis/skills/variant-analysis/SKILL.md +142 -0
  338. package/skills/variant-analysis/skills/variant-analysis/resources/codeql/cpp.ql +119 -0
  339. package/skills/variant-analysis/skills/variant-analysis/resources/codeql/go.ql +69 -0
  340. package/skills/variant-analysis/skills/variant-analysis/resources/codeql/java.ql +71 -0
  341. package/skills/variant-analysis/skills/variant-analysis/resources/codeql/javascript.ql +63 -0
  342. package/skills/variant-analysis/skills/variant-analysis/resources/codeql/python.ql +80 -0
  343. package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/cpp.yaml +98 -0
  344. package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/go.yaml +63 -0
  345. package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/java.yaml +61 -0
  346. package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/javascript.yaml +60 -0
  347. package/skills/variant-analysis/skills/variant-analysis/resources/semgrep/python.yaml +72 -0
  348. package/skills/variant-analysis/skills/variant-analysis/resources/variant-report-template.md +75 -0
  349. package/skills/video-frames/SKILL.md +46 -0
  350. package/skills/video-frames/scripts/frame.sh +81 -0
  351. package/skills/voice-call/SKILL.md +45 -0
  352. package/skills/wacli/SKILL.md +72 -0
  353. package/skills/weather/SKILL.md +54 -0
  354. package/skills/yara-authoring/.claude-plugin/plugin.json +9 -0
  355. package/skills/yara-authoring/README.md +131 -0
  356. package/skills/yara-authoring/skills/yara-rule-authoring/SKILL.md +645 -0
  357. package/skills/yara-authoring/skills/yara-rule-authoring/examples/MAL_Mac_ProtonRAT_Jan25.yar +99 -0
  358. package/skills/yara-authoring/skills/yara-rule-authoring/examples/MAL_NPM_SupplyChain_Jan25.yar +170 -0
  359. package/skills/yara-authoring/skills/yara-rule-authoring/examples/MAL_Win_Remcos_Jan25.yar +103 -0
  360. package/skills/yara-authoring/skills/yara-rule-authoring/examples/SUSP_CRX_SuspiciousPermissions.yar +134 -0
  361. package/skills/yara-authoring/skills/yara-rule-authoring/examples/SUSP_JS_Obfuscation_Jan25.yar +185 -0
  362. package/skills/yara-authoring/skills/yara-rule-authoring/references/crx-module.md +214 -0
  363. package/skills/yara-authoring/skills/yara-rule-authoring/references/dex-module.md +383 -0
  364. package/skills/yara-authoring/skills/yara-rule-authoring/references/performance.md +333 -0
  365. package/skills/yara-authoring/skills/yara-rule-authoring/references/strings.md +433 -0
  366. package/skills/yara-authoring/skills/yara-rule-authoring/references/style-guide.md +257 -0
  367. package/skills/yara-authoring/skills/yara-rule-authoring/references/testing.md +399 -0
  368. package/skills/yara-authoring/skills/yara-rule-authoring/scripts/atom_analyzer.py +526 -0
  369. package/skills/yara-authoring/skills/yara-rule-authoring/scripts/pyproject.toml +25 -0
  370. package/skills/yara-authoring/skills/yara-rule-authoring/scripts/yara_lint.py +631 -0
  371. package/skills/yara-authoring/skills/yara-rule-authoring/workflows/rule-development.md +493 -0
@@ -0,0 +1,101 @@
1
+ # Local Places
2
+
3
+ This repo is a fusion of two pieces:
4
+
5
+ - A FastAPI server that exposes endpoints for searching and resolving places via the Google Maps Places API.
6
+ - A companion agent skill that explains how to use the API and can call it to find places efficiently.
7
+
8
+ Together, the skill and server let an agent turn natural-language place queries into structured results quickly.
9
+
10
+ ## Run locally
11
+
12
+ ```bash
13
+ # copy skill definition into the relevant folder (where the agent looks for it)
14
+ # then run the server
15
+
16
+ uv venv
17
+ uv pip install -e ".[dev]"
18
+ uv run --env-file .env uvicorn local_places.main:app --host 0.0.0.0 --reload
19
+ ```
20
+
21
+ Open the API docs at http://127.0.0.1:8000/docs.
22
+
23
+ ## Places API
24
+
25
+ Set the Google Places API key before running:
26
+
27
+ ```bash
28
+ export GOOGLE_PLACES_API_KEY="your-key"
29
+ ```
30
+
31
+ Endpoints:
32
+
33
+ - `POST /places/search` (free-text query + filters)
34
+ - `GET /places/{place_id}` (place details)
35
+ - `POST /locations/resolve` (resolve a user-provided location string)
36
+
37
+ Example search request:
38
+
39
+ ```json
40
+ {
41
+ "query": "italian restaurant",
42
+ "filters": {
43
+ "types": ["restaurant"],
44
+ "open_now": true,
45
+ "min_rating": 4.0,
46
+ "price_levels": [1, 2]
47
+ },
48
+ "limit": 10
49
+ }
50
+ ```
51
+
52
+ Notes:
53
+
54
+ - `filters.types` supports a single type (mapped to Google `includedType`).
55
+
56
+ Example search request (curl):
57
+
58
+ ```bash
59
+ curl -X POST http://127.0.0.1:8000/places/search \
60
+ -H "Content-Type: application/json" \
61
+ -d '{
62
+ "query": "italian restaurant",
63
+ "location_bias": {
64
+ "lat": 40.8065,
65
+ "lng": -73.9719,
66
+ "radius_m": 3000
67
+ },
68
+ "filters": {
69
+ "types": ["restaurant"],
70
+ "open_now": true,
71
+ "min_rating": 4.0,
72
+ "price_levels": [1, 2, 3]
73
+ },
74
+ "limit": 10
75
+ }'
76
+ ```
77
+
78
+ Example resolve request (curl):
79
+
80
+ ```bash
81
+ curl -X POST http://127.0.0.1:8000/locations/resolve \
82
+ -H "Content-Type: application/json" \
83
+ -d '{
84
+ "location_text": "Riverside Park, New York",
85
+ "limit": 5
86
+ }'
87
+ ```
88
+
89
+ ## Test
90
+
91
+ ```bash
92
+ uv run pytest
93
+ ```
94
+
95
+ ## OpenAPI
96
+
97
+ Generate the OpenAPI schema:
98
+
99
+ ```bash
100
+ uv run python scripts/generate_openapi.py
101
+ ```
@@ -0,0 +1,102 @@
1
+ ---
2
+ name: local-places
3
+ description: Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
4
+ homepage: https://github.com/Hyaxia/local_places
5
+ metadata:
6
+ {
7
+ "otto":
8
+ {
9
+ "emoji": "📍",
10
+ "requires": { "bins": ["uv"], "env": ["GOOGLE_PLACES_API_KEY"] },
11
+ "primaryEnv": "GOOGLE_PLACES_API_KEY",
12
+ },
13
+ }
14
+ ---
15
+
16
+ # 📍 Local Places
17
+
18
+ _Find places, Go fast_
19
+
20
+ Search for nearby places using a local Google Places API proxy. Two-step flow: resolve location first, then search.
21
+
22
+ ## Setup
23
+
24
+ ```bash
25
+ cd {baseDir}
26
+ echo "GOOGLE_PLACES_API_KEY=your-key" > .env
27
+ uv venv && uv pip install -e ".[dev]"
28
+ uv run --env-file .env uvicorn local_places.main:app --host 127.0.0.1 --port 8000
29
+ ```
30
+
31
+ Requires `GOOGLE_PLACES_API_KEY` in `.env` or environment.
32
+
33
+ ## Quick Start
34
+
35
+ 1. **Check server:** `curl http://127.0.0.1:8000/ping`
36
+
37
+ 2. **Resolve location:**
38
+
39
+ ```bash
40
+ curl -X POST http://127.0.0.1:8000/locations/resolve \
41
+ -H "Content-Type: application/json" \
42
+ -d '{"location_text": "Soho, London", "limit": 5}'
43
+ ```
44
+
45
+ 3. **Search places:**
46
+
47
+ ```bash
48
+ curl -X POST http://127.0.0.1:8000/places/search \
49
+ -H "Content-Type: application/json" \
50
+ -d '{
51
+ "query": "coffee shop",
52
+ "location_bias": {"lat": 51.5137, "lng": -0.1366, "radius_m": 1000},
53
+ "filters": {"open_now": true, "min_rating": 4.0},
54
+ "limit": 10
55
+ }'
56
+ ```
57
+
58
+ 4. **Get details:**
59
+
60
+ ```bash
61
+ curl http://127.0.0.1:8000/places/{place_id}
62
+ ```
63
+
64
+ ## Conversation Flow
65
+
66
+ 1. If user says "near me" or gives vague location → resolve it first
67
+ 2. If multiple results → show numbered list, ask user to pick
68
+ 3. Ask for preferences: type, open now, rating, price level
69
+ 4. Search with `location_bias` from chosen location
70
+ 5. Present results with name, rating, address, open status
71
+ 6. Offer to fetch details or refine search
72
+
73
+ ## Filter Constraints
74
+
75
+ - `filters.types`: exactly ONE type (e.g., "restaurant", "cafe", "gym")
76
+ - `filters.price_levels`: integers 0-4 (0=free, 4=very expensive)
77
+ - `filters.min_rating`: 0-5 in 0.5 increments
78
+ - `filters.open_now`: boolean
79
+ - `limit`: 1-20 for search, 1-10 for resolve
80
+ - `location_bias.radius_m`: must be > 0
81
+
82
+ ## Response Format
83
+
84
+ ```json
85
+ {
86
+ "results": [
87
+ {
88
+ "place_id": "ChIJ...",
89
+ "name": "Coffee Shop",
90
+ "address": "123 Main St",
91
+ "location": { "lat": 51.5, "lng": -0.1 },
92
+ "rating": 4.6,
93
+ "price_level": 2,
94
+ "types": ["cafe", "food"],
95
+ "open_now": true
96
+ }
97
+ ],
98
+ "next_page_token": "..."
99
+ }
100
+ ```
101
+
102
+ Use `next_page_token` as `page_token` in next request for more results.
@@ -0,0 +1,21 @@
1
+ [project]
2
+ name = "my-api"
3
+ version = "0.1.0"
4
+ description = "FastAPI server"
5
+ readme = "README.md"
6
+ requires-python = ">=3.11"
7
+ dependencies = ["fastapi>=0.110.0", "httpx>=0.27.0", "uvicorn[standard]>=0.29.0"]
8
+
9
+ [project.optional-dependencies]
10
+ dev = ["pytest>=8.0.0"]
11
+
12
+ [build-system]
13
+ requires = ["hatchling"]
14
+ build-backend = "hatchling.build"
15
+
16
+ [tool.hatch.build.targets.wheel]
17
+ packages = ["src/local_places"]
18
+
19
+ [tool.pytest.ini_options]
20
+ addopts = "-q"
21
+ testpaths = ["tests"]
@@ -0,0 +1,2 @@
1
+ __all__ = ["__version__"]
2
+ __version__ = "0.1.0"
@@ -0,0 +1,314 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ import os
5
+ from typing import Any
6
+
7
+ import httpx
8
+ from fastapi import HTTPException
9
+
10
+ from local_places.schemas import (
11
+ LatLng,
12
+ LocationResolveRequest,
13
+ LocationResolveResponse,
14
+ PlaceDetails,
15
+ PlaceSummary,
16
+ ResolvedLocation,
17
+ SearchRequest,
18
+ SearchResponse,
19
+ )
20
+
21
+ GOOGLE_PLACES_BASE_URL = os.getenv(
22
+ "GOOGLE_PLACES_BASE_URL", "https://places.googleapis.com/v1"
23
+ )
24
+ logger = logging.getLogger("local_places.google_places")
25
+
26
+ _PRICE_LEVEL_TO_ENUM = {
27
+ 0: "PRICE_LEVEL_FREE",
28
+ 1: "PRICE_LEVEL_INEXPENSIVE",
29
+ 2: "PRICE_LEVEL_MODERATE",
30
+ 3: "PRICE_LEVEL_EXPENSIVE",
31
+ 4: "PRICE_LEVEL_VERY_EXPENSIVE",
32
+ }
33
+ _ENUM_TO_PRICE_LEVEL = {value: key for key, value in _PRICE_LEVEL_TO_ENUM.items()}
34
+
35
+ _SEARCH_FIELD_MASK = (
36
+ "places.id,"
37
+ "places.displayName,"
38
+ "places.formattedAddress,"
39
+ "places.location,"
40
+ "places.rating,"
41
+ "places.priceLevel,"
42
+ "places.types,"
43
+ "places.currentOpeningHours,"
44
+ "nextPageToken"
45
+ )
46
+
47
+ _DETAILS_FIELD_MASK = (
48
+ "id,"
49
+ "displayName,"
50
+ "formattedAddress,"
51
+ "location,"
52
+ "rating,"
53
+ "priceLevel,"
54
+ "types,"
55
+ "regularOpeningHours,"
56
+ "currentOpeningHours,"
57
+ "nationalPhoneNumber,"
58
+ "websiteUri"
59
+ )
60
+
61
+ _RESOLVE_FIELD_MASK = (
62
+ "places.id,"
63
+ "places.displayName,"
64
+ "places.formattedAddress,"
65
+ "places.location,"
66
+ "places.types"
67
+ )
68
+
69
+
70
+ class _GoogleResponse:
71
+ def __init__(self, response: httpx.Response):
72
+ self.status_code = response.status_code
73
+ self._response = response
74
+
75
+ def json(self) -> dict[str, Any]:
76
+ return self._response.json()
77
+
78
+ @property
79
+ def text(self) -> str:
80
+ return self._response.text
81
+
82
+
83
+ def _api_headers(field_mask: str) -> dict[str, str]:
84
+ api_key = os.getenv("GOOGLE_PLACES_API_KEY")
85
+ if not api_key:
86
+ raise HTTPException(
87
+ status_code=500,
88
+ detail="GOOGLE_PLACES_API_KEY is not set.",
89
+ )
90
+ return {
91
+ "Content-Type": "application/json",
92
+ "X-Goog-Api-Key": api_key,
93
+ "X-Goog-FieldMask": field_mask,
94
+ }
95
+
96
+
97
+ def _request(
98
+ method: str, url: str, payload: dict[str, Any] | None, field_mask: str
99
+ ) -> _GoogleResponse:
100
+ try:
101
+ with httpx.Client(timeout=10.0) as client:
102
+ response = client.request(
103
+ method=method,
104
+ url=url,
105
+ headers=_api_headers(field_mask),
106
+ json=payload,
107
+ )
108
+ except httpx.HTTPError as exc:
109
+ raise HTTPException(status_code=502, detail="Google Places API unavailable.") from exc
110
+
111
+ return _GoogleResponse(response)
112
+
113
+
114
+ def _build_text_query(request: SearchRequest) -> str:
115
+ keyword = request.filters.keyword if request.filters else None
116
+ if keyword:
117
+ return f"{request.query} {keyword}".strip()
118
+ return request.query
119
+
120
+
121
+ def _build_search_body(request: SearchRequest) -> dict[str, Any]:
122
+ body: dict[str, Any] = {
123
+ "textQuery": _build_text_query(request),
124
+ "pageSize": request.limit,
125
+ }
126
+
127
+ if request.page_token:
128
+ body["pageToken"] = request.page_token
129
+
130
+ if request.location_bias:
131
+ body["locationBias"] = {
132
+ "circle": {
133
+ "center": {
134
+ "latitude": request.location_bias.lat,
135
+ "longitude": request.location_bias.lng,
136
+ },
137
+ "radius": request.location_bias.radius_m,
138
+ }
139
+ }
140
+
141
+ if request.filters:
142
+ filters = request.filters
143
+ if filters.types:
144
+ body["includedType"] = filters.types[0]
145
+ if filters.open_now is not None:
146
+ body["openNow"] = filters.open_now
147
+ if filters.min_rating is not None:
148
+ body["minRating"] = filters.min_rating
149
+ if filters.price_levels:
150
+ body["priceLevels"] = [
151
+ _PRICE_LEVEL_TO_ENUM[level] for level in filters.price_levels
152
+ ]
153
+
154
+ return body
155
+
156
+
157
+ def _parse_lat_lng(raw: dict[str, Any] | None) -> LatLng | None:
158
+ if not raw:
159
+ return None
160
+ latitude = raw.get("latitude")
161
+ longitude = raw.get("longitude")
162
+ if latitude is None or longitude is None:
163
+ return None
164
+ return LatLng(lat=latitude, lng=longitude)
165
+
166
+
167
+ def _parse_display_name(raw: dict[str, Any] | None) -> str | None:
168
+ if not raw:
169
+ return None
170
+ return raw.get("text")
171
+
172
+
173
+ def _parse_open_now(raw: dict[str, Any] | None) -> bool | None:
174
+ if not raw:
175
+ return None
176
+ return raw.get("openNow")
177
+
178
+
179
+ def _parse_hours(raw: dict[str, Any] | None) -> list[str] | None:
180
+ if not raw:
181
+ return None
182
+ return raw.get("weekdayDescriptions")
183
+
184
+
185
+ def _parse_price_level(raw: str | None) -> int | None:
186
+ if not raw:
187
+ return None
188
+ return _ENUM_TO_PRICE_LEVEL.get(raw)
189
+
190
+
191
+ def search_places(request: SearchRequest) -> SearchResponse:
192
+ url = f"{GOOGLE_PLACES_BASE_URL}/places:searchText"
193
+ response = _request("POST", url, _build_search_body(request), _SEARCH_FIELD_MASK)
194
+
195
+ if response.status_code >= 400:
196
+ logger.error(
197
+ "Google Places API error %s. response=%s",
198
+ response.status_code,
199
+ response.text,
200
+ )
201
+ raise HTTPException(
202
+ status_code=502,
203
+ detail=f"Google Places API error ({response.status_code}).",
204
+ )
205
+
206
+ try:
207
+ payload = response.json()
208
+ except ValueError as exc:
209
+ logger.error(
210
+ "Google Places API returned invalid JSON. response=%s",
211
+ response.text,
212
+ )
213
+ raise HTTPException(status_code=502, detail="Invalid Google response.") from exc
214
+
215
+ places = payload.get("places", [])
216
+ results = []
217
+ for place in places:
218
+ results.append(
219
+ PlaceSummary(
220
+ place_id=place.get("id", ""),
221
+ name=_parse_display_name(place.get("displayName")),
222
+ address=place.get("formattedAddress"),
223
+ location=_parse_lat_lng(place.get("location")),
224
+ rating=place.get("rating"),
225
+ price_level=_parse_price_level(place.get("priceLevel")),
226
+ types=place.get("types"),
227
+ open_now=_parse_open_now(place.get("currentOpeningHours")),
228
+ )
229
+ )
230
+
231
+ return SearchResponse(
232
+ results=results,
233
+ next_page_token=payload.get("nextPageToken"),
234
+ )
235
+
236
+
237
+ def get_place_details(place_id: str) -> PlaceDetails:
238
+ url = f"{GOOGLE_PLACES_BASE_URL}/places/{place_id}"
239
+ response = _request("GET", url, None, _DETAILS_FIELD_MASK)
240
+
241
+ if response.status_code >= 400:
242
+ logger.error(
243
+ "Google Places API error %s. response=%s",
244
+ response.status_code,
245
+ response.text,
246
+ )
247
+ raise HTTPException(
248
+ status_code=502,
249
+ detail=f"Google Places API error ({response.status_code}).",
250
+ )
251
+
252
+ try:
253
+ payload = response.json()
254
+ except ValueError as exc:
255
+ logger.error(
256
+ "Google Places API returned invalid JSON. response=%s",
257
+ response.text,
258
+ )
259
+ raise HTTPException(status_code=502, detail="Invalid Google response.") from exc
260
+
261
+ return PlaceDetails(
262
+ place_id=payload.get("id", place_id),
263
+ name=_parse_display_name(payload.get("displayName")),
264
+ address=payload.get("formattedAddress"),
265
+ location=_parse_lat_lng(payload.get("location")),
266
+ rating=payload.get("rating"),
267
+ price_level=_parse_price_level(payload.get("priceLevel")),
268
+ types=payload.get("types"),
269
+ phone=payload.get("nationalPhoneNumber"),
270
+ website=payload.get("websiteUri"),
271
+ hours=_parse_hours(payload.get("regularOpeningHours")),
272
+ open_now=_parse_open_now(payload.get("currentOpeningHours")),
273
+ )
274
+
275
+
276
+ def resolve_locations(request: LocationResolveRequest) -> LocationResolveResponse:
277
+ url = f"{GOOGLE_PLACES_BASE_URL}/places:searchText"
278
+ body = {"textQuery": request.location_text, "pageSize": request.limit}
279
+ response = _request("POST", url, body, _RESOLVE_FIELD_MASK)
280
+
281
+ if response.status_code >= 400:
282
+ logger.error(
283
+ "Google Places API error %s. response=%s",
284
+ response.status_code,
285
+ response.text,
286
+ )
287
+ raise HTTPException(
288
+ status_code=502,
289
+ detail=f"Google Places API error ({response.status_code}).",
290
+ )
291
+
292
+ try:
293
+ payload = response.json()
294
+ except ValueError as exc:
295
+ logger.error(
296
+ "Google Places API returned invalid JSON. response=%s",
297
+ response.text,
298
+ )
299
+ raise HTTPException(status_code=502, detail="Invalid Google response.") from exc
300
+
301
+ places = payload.get("places", [])
302
+ results = []
303
+ for place in places:
304
+ results.append(
305
+ ResolvedLocation(
306
+ place_id=place.get("id", ""),
307
+ name=_parse_display_name(place.get("displayName")),
308
+ address=place.get("formattedAddress"),
309
+ location=_parse_lat_lng(place.get("location")),
310
+ types=place.get("types"),
311
+ )
312
+ )
313
+
314
+ return LocationResolveResponse(results=results)
@@ -0,0 +1,65 @@
1
+ import logging
2
+ import os
3
+
4
+ from fastapi import FastAPI, Request
5
+ from fastapi.encoders import jsonable_encoder
6
+ from fastapi.exceptions import RequestValidationError
7
+ from fastapi.responses import JSONResponse
8
+
9
+ from local_places.google_places import get_place_details, resolve_locations, search_places
10
+ from local_places.schemas import (
11
+ LocationResolveRequest,
12
+ LocationResolveResponse,
13
+ PlaceDetails,
14
+ SearchRequest,
15
+ SearchResponse,
16
+ )
17
+
18
+ app = FastAPI(
19
+ title="My API",
20
+ servers=[{"url": os.getenv("OPENAPI_SERVER_URL", "http://maxims-macbook-air:8000")}],
21
+ )
22
+ logger = logging.getLogger("local_places.validation")
23
+
24
+
25
+ @app.get("/ping")
26
+ def ping() -> dict[str, str]:
27
+ return {"message": "pong"}
28
+
29
+
30
+ @app.exception_handler(RequestValidationError)
31
+ async def validation_exception_handler(
32
+ request: Request, exc: RequestValidationError
33
+ ) -> JSONResponse:
34
+ logger.error(
35
+ "Validation error on %s %s. body=%s errors=%s",
36
+ request.method,
37
+ request.url.path,
38
+ exc.body,
39
+ exc.errors(),
40
+ )
41
+ return JSONResponse(
42
+ status_code=422,
43
+ content=jsonable_encoder({"detail": exc.errors()}),
44
+ )
45
+
46
+
47
+ @app.post("/places/search", response_model=SearchResponse)
48
+ def places_search(request: SearchRequest) -> SearchResponse:
49
+ return search_places(request)
50
+
51
+
52
+ @app.get("/places/{place_id}", response_model=PlaceDetails)
53
+ def places_details(place_id: str) -> PlaceDetails:
54
+ return get_place_details(place_id)
55
+
56
+
57
+ @app.post("/locations/resolve", response_model=LocationResolveResponse)
58
+ def locations_resolve(request: LocationResolveRequest) -> LocationResolveResponse:
59
+ return resolve_locations(request)
60
+
61
+
62
+ if __name__ == "__main__":
63
+ import uvicorn
64
+
65
+ uvicorn.run("local_places.main:app", host="0.0.0.0", port=8000)