opencode-skills-collection 3.0.51 → 3.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 (287) hide show
  1. package/README.md +44 -12
  2. package/bundled-skills/.antigravity-install-manifest.json +84 -1
  3. package/bundled-skills/android-ui-journey-testing/SKILL.md +191 -0
  4. package/bundled-skills/ask-matt/SKILL.md +92 -0
  5. package/bundled-skills/bugs-are-annoying/SKILL.md +137 -0
  6. package/bundled-skills/codebase-design/DEEPENING.md +37 -0
  7. package/bundled-skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
  8. package/bundled-skills/codebase-design/SKILL.md +145 -0
  9. package/bundled-skills/competitor-analysis/LICENSE.txt +21 -0
  10. package/bundled-skills/competitor-analysis/SKILL.md +434 -0
  11. package/bundled-skills/competitor-analysis/references/battle-card-subagent.md +127 -0
  12. package/bundled-skills/competitor-analysis/references/battle-card.md +91 -0
  13. package/bundled-skills/competitor-analysis/references/example-research.md +130 -0
  14. package/bundled-skills/competitor-analysis/references/report-template.html +127 -0
  15. package/bundled-skills/competitor-analysis/references/research-patterns.md +217 -0
  16. package/bundled-skills/competitor-analysis/references/workflow.md +434 -0
  17. package/bundled-skills/competitor-analysis/scripts/capture_screenshots.mjs +142 -0
  18. package/bundled-skills/competitor-analysis/scripts/compile_report.mjs +929 -0
  19. package/bundled-skills/competitor-analysis/scripts/extract_vs_names.mjs +140 -0
  20. package/bundled-skills/competitor-analysis/scripts/gate_candidates.mjs +194 -0
  21. package/bundled-skills/competitor-analysis/scripts/list_urls.mjs +90 -0
  22. package/bundled-skills/competitor-analysis/scripts/md_utils.mjs +50 -0
  23. package/bundled-skills/competitor-analysis/scripts/merge_partials.mjs +291 -0
  24. package/bundled-skills/competitor-analysis/scripts/package.json +6 -0
  25. package/bundled-skills/design-it/3d-ui/SKILL.md +259 -0
  26. package/bundled-skills/design-it/SKILL.md +170 -0
  27. package/bundled-skills/design-it/ai-native-ui/SKILL.md +295 -0
  28. package/bundled-skills/design-it/aurora-ui/SKILL.md +307 -0
  29. package/bundled-skills/design-it/bento-ui/SKILL.md +314 -0
  30. package/bundled-skills/design-it/brutalism/SKILL.md +270 -0
  31. package/bundled-skills/design-it/brutalist-typography/SKILL.md +287 -0
  32. package/bundled-skills/design-it/card-based-design/SKILL.md +262 -0
  33. package/bundled-skills/design-it/claymorphism/SKILL.md +287 -0
  34. package/bundled-skills/design-it/color-blocking/SKILL.md +278 -0
  35. package/bundled-skills/design-it/command-center-ui/SKILL.md +345 -0
  36. package/bundled-skills/design-it/cyber-y2k/SKILL.md +312 -0
  37. package/bundled-skills/design-it/cyberpunk-ui/SKILL.md +262 -0
  38. package/bundled-skills/design-it/dark-mode/SKILL.md +289 -0
  39. package/bundled-skills/design-it/dashboard-design/SKILL.md +331 -0
  40. package/bundled-skills/design-it/data-dense-design/SKILL.md +322 -0
  41. package/bundled-skills/design-it/duotone-design/SKILL.md +248 -0
  42. package/bundled-skills/design-it/editorial-design/SKILL.md +328 -0
  43. package/bundled-skills/design-it/flat-design/SKILL.md +221 -0
  44. package/bundled-skills/design-it/flat-design-2/SKILL.md +240 -0
  45. package/bundled-skills/design-it/floating-ui/SKILL.md +299 -0
  46. package/bundled-skills/design-it/frutiger-aero/SKILL.md +274 -0
  47. package/bundled-skills/design-it/glassmorphism/SKILL.md +272 -0
  48. package/bundled-skills/design-it/gradient-design/SKILL.md +309 -0
  49. package/bundled-skills/design-it/high-contrast/SKILL.md +288 -0
  50. package/bundled-skills/design-it/holographic-ui/SKILL.md +310 -0
  51. package/bundled-skills/design-it/isometric-design/SKILL.md +228 -0
  52. package/bundled-skills/design-it/layered-design/SKILL.md +247 -0
  53. package/bundled-skills/design-it/material-design/SKILL.md +275 -0
  54. package/bundled-skills/design-it/maximalism/SKILL.md +297 -0
  55. package/bundled-skills/design-it/minimalism/SKILL.md +267 -0
  56. package/bundled-skills/design-it/monochromatic-ui/SKILL.md +296 -0
  57. package/bundled-skills/design-it/neo-brutalism/SKILL.md +270 -0
  58. package/bundled-skills/design-it/neumorphism/SKILL.md +248 -0
  59. package/bundled-skills/design-it/retro-design/SKILL.md +283 -0
  60. package/bundled-skills/design-it/retro-futurism/SKILL.md +259 -0
  61. package/bundled-skills/design-it/sci-fi-interface/SKILL.md +309 -0
  62. package/bundled-skills/design-it/skeuomorphism/SKILL.md +280 -0
  63. package/bundled-skills/design-it/soft-pastel/SKILL.md +307 -0
  64. package/bundled-skills/design-it/spatial-computing-ui/SKILL.md +300 -0
  65. package/bundled-skills/design-it/spatial-design/SKILL.md +268 -0
  66. package/bundled-skills/design-it/swiss-design/SKILL.md +293 -0
  67. package/bundled-skills/design-it/synthwave/SKILL.md +257 -0
  68. package/bundled-skills/design-it/tile-design/SKILL.md +297 -0
  69. package/bundled-skills/design-it/typography-first/SKILL.md +247 -0
  70. package/bundled-skills/design-it/vaporwave/SKILL.md +331 -0
  71. package/bundled-skills/design-it/vibrant-maximalism/SKILL.md +291 -0
  72. package/bundled-skills/design-it/widget-based-design/SKILL.md +274 -0
  73. package/bundled-skills/design-it/y2k-design/SKILL.md +268 -0
  74. package/bundled-skills/diagnosing-bugs/SKILL.md +165 -0
  75. package/bundled-skills/diagnosing-bugs/scripts/hitl-loop.template.sh +41 -0
  76. package/bundled-skills/docs/contributors/skill-scoring.md +235 -0
  77. package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
  78. package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
  79. package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
  80. package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
  81. package/bundled-skills/docs/users/bundles.md +1 -1
  82. package/bundled-skills/docs/users/claude-code-skills.md +1 -1
  83. package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
  84. package/bundled-skills/docs/users/getting-started.md +1 -1
  85. package/bundled-skills/docs/users/kiro-integration.md +1 -1
  86. package/bundled-skills/docs/users/usage.md +4 -4
  87. package/bundled-skills/docs/users/visual-guide.md +4 -4
  88. package/bundled-skills/domain-modeling/ADR-FORMAT.md +47 -0
  89. package/bundled-skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  90. package/bundled-skills/domain-modeling/SKILL.md +105 -0
  91. package/bundled-skills/grill-me/SKILL.md +36 -0
  92. package/bundled-skills/grill-with-docs/SKILL.md +36 -0
  93. package/bundled-skills/grilling/SKILL.md +39 -0
  94. package/bundled-skills/handoff/SKILL.md +45 -0
  95. package/bundled-skills/image-generator/.env.example +7 -0
  96. package/bundled-skills/image-generator/SKILL.md +509 -0
  97. package/bundled-skills/improve-codebase-architecture/HTML-REPORT.md +123 -0
  98. package/bundled-skills/improve-codebase-architecture/SKILL.md +97 -0
  99. package/bundled-skills/learn/SKILL.md +156 -0
  100. package/bundled-skills/lesson-generator/SKILL.md +90 -0
  101. package/bundled-skills/llm-council/.env.example +7 -0
  102. package/bundled-skills/llm-council/SKILL.md +602 -0
  103. package/bundled-skills/loop-library/SKILL.md +205 -0
  104. package/bundled-skills/loop-library/agents/openai.yaml +4 -0
  105. package/bundled-skills/loop-library/references/catalog.md +270 -0
  106. package/bundled-skills/mailtrap-managing-contacts/SKILL.md +112 -0
  107. package/bundled-skills/mailtrap-sending-emails/SKILL.md +167 -0
  108. package/bundled-skills/mailtrap-setting-up-sending-domain/SKILL.md +77 -0
  109. package/bundled-skills/mailtrap-testing-with-sandbox/SKILL.md +110 -0
  110. package/bundled-skills/prototype/LOGIC.md +79 -0
  111. package/bundled-skills/prototype/SKILL.md +62 -0
  112. package/bundled-skills/prototype/UI.md +112 -0
  113. package/bundled-skills/setup-matt-pocock-skills/SKILL.md +158 -0
  114. package/bundled-skills/setup-matt-pocock-skills/domain.md +51 -0
  115. package/bundled-skills/setup-matt-pocock-skills/issue-tracker-github.md +34 -0
  116. package/bundled-skills/setup-matt-pocock-skills/issue-tracker-gitlab.md +35 -0
  117. package/bundled-skills/setup-matt-pocock-skills/issue-tracker-local.md +19 -0
  118. package/bundled-skills/setup-matt-pocock-skills/triage-labels.md +15 -0
  119. package/bundled-skills/survey-generator/LICENSE +21 -0
  120. package/bundled-skills/survey-generator/SKILL.md +143 -0
  121. package/bundled-skills/survey-generator/build_artifact.py +208 -0
  122. package/bundled-skills/survey-generator/examples/agentic-engineering/research_bundle.json +1196 -0
  123. package/bundled-skills/survey-generator/examples/agentic-engineering/survey.html +706 -0
  124. package/bundled-skills/survey-generator/style_spec.json +85 -0
  125. package/bundled-skills/survey-generator/templates/research_bundle_template.json +69 -0
  126. package/bundled-skills/tdd/SKILL.md +139 -0
  127. package/bundled-skills/tdd/mocking.md +59 -0
  128. package/bundled-skills/tdd/refactoring.md +10 -0
  129. package/bundled-skills/tdd/tests.md +61 -0
  130. package/bundled-skills/teach/GLOSSARY-FORMAT.md +35 -0
  131. package/bundled-skills/teach/LEARNING-RECORD-FORMAT.md +46 -0
  132. package/bundled-skills/teach/MISSION-FORMAT.md +31 -0
  133. package/bundled-skills/teach/RESOURCES-FORMAT.md +32 -0
  134. package/bundled-skills/teach/SKILL.md +169 -0
  135. package/bundled-skills/to-issues/SKILL.md +115 -0
  136. package/bundled-skills/to-prd/SKILL.md +104 -0
  137. package/bundled-skills/tools-page-seo-optimizer/SKILL.md +616 -0
  138. package/bundled-skills/triage/AGENT-BRIEF.md +207 -0
  139. package/bundled-skills/triage/OUT-OF-SCOPE.md +105 -0
  140. package/bundled-skills/triage/SKILL.md +143 -0
  141. package/bundled-skills/vibecode-production-qa-validator/SKILL.md +371 -141
  142. package/bundled-skills/wiki-builder/SKILL.md +157 -0
  143. package/bundled-skills/wiki-builder/agents/openai.yaml +5 -0
  144. package/bundled-skills/wiki-builder/references/wiki-flavors.md +98 -0
  145. package/bundled-skills/wiki-builder/scripts/init_wiki.sh +105 -0
  146. package/bundled-skills/wiki-builder/templates/index.md +20 -0
  147. package/bundled-skills/wiki-builder/templates/maintenance-log.md +7 -0
  148. package/bundled-skills/wiki-builder/templates/prompts/compile-concept-page.md +12 -0
  149. package/bundled-skills/wiki-builder/templates/prompts/compile-index.md +11 -0
  150. package/bundled-skills/wiki-builder/templates/prompts/compile-source-page.md +12 -0
  151. package/bundled-skills/wiki-builder/templates/prompts/lint-wiki.md +10 -0
  152. package/bundled-skills/wiki-builder/templates/prompts/query-and-file.md +11 -0
  153. package/bundled-skills/wiki-builder/templates/sources.md +9 -0
  154. package/bundled-skills/wiki-builder/templates/wiki.config.md +53 -0
  155. package/bundled-skills/writing-great-skills/GLOSSARY.md +181 -0
  156. package/bundled-skills/writing-great-skills/SKILL.md +111 -0
  157. package/bundled-skills/yao-meta-skill/SKILL.md +86 -0
  158. package/bundled-skills/yao-meta-skill/agents/interface.yaml +26 -0
  159. package/bundled-skills/yao-meta-skill/manifest.json +24 -0
  160. package/bundled-skills/yao-meta-skill/references/artifact-design-doctrine.md +49 -0
  161. package/bundled-skills/yao-meta-skill/references/authoring-discipline.md +78 -0
  162. package/bundled-skills/yao-meta-skill/references/autonomous-adaptation.md +65 -0
  163. package/bundled-skills/yao-meta-skill/references/distribution-registry-method.md +60 -0
  164. package/bundled-skills/yao-meta-skill/references/eval-playbook.md +69 -0
  165. package/bundled-skills/yao-meta-skill/references/gate-selection.md +68 -0
  166. package/bundled-skills/yao-meta-skill/references/governance.md +134 -0
  167. package/bundled-skills/yao-meta-skill/references/human-review-template.md +54 -0
  168. package/bundled-skills/yao-meta-skill/references/intent-dialogue.md +138 -0
  169. package/bundled-skills/yao-meta-skill/references/iteration-philosophy.md +30 -0
  170. package/bundled-skills/yao-meta-skill/references/non-skill-decision-tree.md +39 -0
  171. package/bundled-skills/yao-meta-skill/references/operating-modes.md +107 -0
  172. package/bundled-skills/yao-meta-skill/references/output-eval-method.md +113 -0
  173. package/bundled-skills/yao-meta-skill/references/output-quality-risk.md +41 -0
  174. package/bundled-skills/yao-meta-skill/references/output-visual-quality.md +53 -0
  175. package/bundled-skills/yao-meta-skill/references/packaging-contracts.md +70 -0
  176. package/bundled-skills/yao-meta-skill/references/pattern-extraction-doctrine.md +76 -0
  177. package/bundled-skills/yao-meta-skill/references/platform-capability-matrix.md +49 -0
  178. package/bundled-skills/yao-meta-skill/references/prompt-engineering-doctrine.md +76 -0
  179. package/bundled-skills/yao-meta-skill/references/qa-ladder.md +57 -0
  180. package/bundled-skills/yao-meta-skill/references/reference-scan.md +126 -0
  181. package/bundled-skills/yao-meta-skill/references/regression-cause-taxonomy.md +80 -0
  182. package/bundled-skills/yao-meta-skill/references/resource-boundaries.md +120 -0
  183. package/bundled-skills/yao-meta-skill/references/review-studio-method.md +87 -0
  184. package/bundled-skills/yao-meta-skill/references/review-waiver-method.md +76 -0
  185. package/bundled-skills/yao-meta-skill/references/runtime-conformance-method.md +21 -0
  186. package/bundled-skills/yao-meta-skill/references/skill-archetypes.md +86 -0
  187. package/bundled-skills/yao-meta-skill/references/skill-atlas-method.md +35 -0
  188. package/bundled-skills/yao-meta-skill/references/skill-engineering-method.md +210 -0
  189. package/bundled-skills/yao-meta-skill/references/skill-ir-method.md +41 -0
  190. package/bundled-skills/yao-meta-skill/references/skillops-decision-policy.md +53 -0
  191. package/bundled-skills/yao-meta-skill/references/systems-thinking-doctrine.md +75 -0
  192. package/bundled-skills/yao-meta-skill/references/telemetry-drift-method.md +182 -0
  193. package/bundled-skills/yao-meta-skill/references/trust-security-method.md +79 -0
  194. package/bundled-skills/yao-meta-skill/references/user-memory-policy.md +35 -0
  195. package/bundled-skills/youtube-notetaker/SKILL.md +209 -0
  196. package/bundled-skills/youtube-notetaker/reference/artifact.html +269 -0
  197. package/bundled-skills/youtube-notetaker/scripts/contact_sheet.py +53 -0
  198. package/bundled-skills/youtube-notetaker/scripts/detect_slides.sh +19 -0
  199. package/bundled-skills/youtube-notetaker/scripts/download.sh +24 -0
  200. package/bundled-skills/youtube-notetaker/scripts/extract_slides.py +43 -0
  201. package/bundled-skills/youtube-notetaker/scripts/serve.py +173 -0
  202. package/bundled-skills/youtube-notetaker/scripts/setup.sh +27 -0
  203. package/bundled-skills/youtube-notetaker/scripts/verify.sh +31 -0
  204. package/bundled-skills/youtube-notetaker/scripts/vtt_to_transcript.py +59 -0
  205. package/bundled-skills/youtube-notetaker/scripts/write_library_item.py +69 -0
  206. package/dist/skill-pointer/config-loader.d.ts +14 -0
  207. package/dist/skill-pointer/config-loader.js +30 -3
  208. package/dist/skill-pointer/content-scanner.d.ts +38 -0
  209. package/dist/skill-pointer/content-scanner.js +118 -0
  210. package/dist/skill-pointer/index.d.ts +7 -2
  211. package/dist/skill-pointer/index.js +14 -4
  212. package/dist/skill-pointer/pointer-generator.js +2 -0
  213. package/dist/skill-pointer/skill-patcher.d.ts +13 -0
  214. package/dist/skill-pointer/skill-patcher.js +99 -0
  215. package/package.json +1 -1
  216. package/skills_index.json +1956 -286
  217. package/bundled-skills/ai-md/SKILL.md +0 -523
  218. package/bundled-skills/atlas-contract/SKILL.md +0 -650
  219. package/bundled-skills/busybox-on-windows/SKILL.md +0 -40
  220. package/bundled-skills/monte-carlo-prevent/SKILL.md +0 -257
  221. package/bundled-skills/monte-carlo-prevent/references/TROUBLESHOOTING.md +0 -23
  222. package/bundled-skills/monte-carlo-prevent/references/parameters.md +0 -32
  223. package/bundled-skills/monte-carlo-prevent/references/workflows.md +0 -478
  224. package/bundled-skills/monte-carlo-push-ingestion/SKILL.md +0 -372
  225. package/bundled-skills/monte-carlo-push-ingestion/references/anomaly-detection.md +0 -87
  226. package/bundled-skills/monte-carlo-push-ingestion/references/custom-lineage.md +0 -203
  227. package/bundled-skills/monte-carlo-push-ingestion/references/direct-http-api.md +0 -207
  228. package/bundled-skills/monte-carlo-push-ingestion/references/prerequisites.md +0 -150
  229. package/bundled-skills/monte-carlo-push-ingestion/references/push-lineage.md +0 -160
  230. package/bundled-skills/monte-carlo-push-ingestion/references/push-metadata.md +0 -158
  231. package/bundled-skills/monte-carlo-push-ingestion/references/push-query-logs.md +0 -219
  232. package/bundled-skills/monte-carlo-push-ingestion/references/validation.md +0 -257
  233. package/bundled-skills/monte-carlo-push-ingestion/scripts/sample_verify.py +0 -357
  234. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_and_push_lineage.py +0 -70
  235. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_and_push_metadata.py +0 -65
  236. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_and_push_query_logs.py +0 -70
  237. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_lineage.py +0 -214
  238. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_metadata.py +0 -160
  239. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_query_logs.py +0 -164
  240. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/push_lineage.py +0 -198
  241. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/push_metadata.py +0 -193
  242. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/push_query_logs.py +0 -207
  243. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/collect_and_push_metadata.py +0 -71
  244. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/collect_and_push_query_logs.py +0 -64
  245. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/collect_metadata.py +0 -253
  246. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/collect_query_logs.py +0 -149
  247. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/push_metadata.py +0 -190
  248. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/push_query_logs.py +0 -208
  249. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_and_push_lineage.py +0 -83
  250. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_and_push_metadata.py +0 -77
  251. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_and_push_query_logs.py +0 -83
  252. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_lineage.py +0 -240
  253. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_metadata.py +0 -212
  254. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_query_logs.py +0 -204
  255. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/push_lineage.py +0 -192
  256. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/push_metadata.py +0 -178
  257. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/push_query_logs.py +0 -200
  258. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_and_push_lineage.py +0 -119
  259. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_and_push_metadata.py +0 -119
  260. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_and_push_query_logs.py +0 -117
  261. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_lineage.py +0 -265
  262. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_metadata.py +0 -313
  263. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_query_logs.py +0 -284
  264. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/push_lineage.py +0 -309
  265. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/push_metadata.py +0 -245
  266. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/push_query_logs.py +0 -255
  267. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_and_push_lineage.py +0 -78
  268. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_and_push_metadata.py +0 -80
  269. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_and_push_query_logs.py +0 -88
  270. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_lineage.py +0 -235
  271. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_metadata.py +0 -219
  272. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_query_logs.py +0 -239
  273. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/push_lineage.py +0 -178
  274. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/push_metadata.py +0 -178
  275. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/push_query_logs.py +0 -196
  276. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_and_push_lineage.py +0 -154
  277. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_and_push_metadata.py +0 -137
  278. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_and_push_query_logs.py +0 -137
  279. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_lineage.py +0 -349
  280. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_metadata.py +0 -329
  281. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_query_logs.py +0 -254
  282. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/push_lineage.py +0 -307
  283. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/push_metadata.py +0 -228
  284. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/push_query_logs.py +0 -248
  285. package/bundled-skills/monte-carlo-push-ingestion/scripts/test_template_sdk_usage.py +0 -340
  286. package/bundled-skills/skill-optimizer/SKILL.md +0 -271
  287. package/bundled-skills/using-superpowers/SKILL.md +0 -98
@@ -0,0 +1,173 @@
1
+ #!/usr/bin/env python3
2
+ """Standalone viewer + API server for a YouTube deep-dive library.
3
+
4
+ Zero framework dependencies (Python stdlib + PyYAML). It serves the interactive
5
+ artifact and a small read/write API over a plain folder of markdown files, so the
6
+ whole thing runs anywhere with no custom backend.
7
+
8
+ python3 serve.py [--dir LIBRARY] [--port 8000] [--artifact path/to/artifact.html]
9
+
10
+ LIBRARY defaults to $VIDEO_LIBRARY_DIR or ~/video-deepdives. Layout:
11
+ LIBRARY/<YTID>.md one markdown file per video (frontmatter + transcript)
12
+ LIBRARY/_media/<YTID>-slide-NN.jpg slide images
13
+
14
+ Routes (the artifact talks to these; the /api/video-deepdives namespace is
15
+ arbitrary and kept only so the same artifact HTML works unmodified):
16
+ GET / the artifact (single-page app)
17
+ GET /api/video-deepdives list every video (flattened frontmatter)
18
+ GET /api/video-deepdives/<id> one video: {meta, body}
19
+ GET /api/video-deepdives/_media/<f> a slide image
20
+ PATCH /api/video-deepdives/<id> merge {fields:{...}} into frontmatter, rewrite
21
+ """
22
+ import argparse, json, os, sys, re, mimetypes, posixpath
23
+ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
24
+
25
+ try:
26
+ import yaml
27
+ except ImportError:
28
+ sys.exit("pip install pyyaml")
29
+
30
+ API = "/api/video-deepdives"
31
+ FM_RE = re.compile(r"^---\n(.*?)\n---\n?(.*)$", re.DOTALL)
32
+
33
+
34
+ def split_frontmatter(text):
35
+ """Return (meta_dict, body_str) from a markdown file with YAML frontmatter."""
36
+ m = FM_RE.match(text)
37
+ if not m:
38
+ return {}, text
39
+ meta = yaml.safe_load(m.group(1)) or {}
40
+ return meta, m.group(2)
41
+
42
+
43
+ def dump_file(meta, body):
44
+ out = "---\n" + yaml.safe_dump(meta, sort_keys=False, allow_unicode=True, width=100) + "---\n"
45
+ return out + body
46
+
47
+
48
+ def load_item(lib, slug):
49
+ path = os.path.join(lib, slug + ".md")
50
+ if not os.path.isfile(path):
51
+ return None
52
+ meta, body = split_frontmatter(open(path, encoding="utf-8").read())
53
+ return path, meta, body
54
+
55
+
56
+ def list_items(lib):
57
+ items = []
58
+ for fn in sorted(os.listdir(lib)):
59
+ if not fn.endswith(".md") or fn.startswith("_"):
60
+ continue
61
+ slug = fn[:-3]
62
+ loaded = load_item(lib, slug)
63
+ if not loaded:
64
+ continue
65
+ _, meta, body = loaded
66
+ it = dict(meta)
67
+ it["slug"] = slug
68
+ it["file"] = fn
69
+ it["preview"] = body.strip()[:160]
70
+ items.append(it)
71
+ return items
72
+
73
+
74
+ class Handler(BaseHTTPRequestHandler):
75
+ lib = None
76
+ artifact = None
77
+
78
+ def log_message(self, *a):
79
+ pass # quiet
80
+
81
+ def _send(self, code, body, ctype="application/json"):
82
+ if isinstance(body, (dict, list)):
83
+ body = json.dumps(body).encode()
84
+ elif isinstance(body, str):
85
+ body = body.encode()
86
+ self.send_response(code)
87
+ self.send_header("Content-Type", ctype)
88
+ self.send_header("Content-Length", str(len(body)))
89
+ self.send_header("Access-Control-Allow-Origin", "*")
90
+ self.send_header("Access-Control-Allow-Methods", "GET, PATCH, OPTIONS")
91
+ self.send_header("Access-Control-Allow-Headers", "Content-Type")
92
+ self.end_headers()
93
+ if self.command != "HEAD":
94
+ self.wfile.write(body)
95
+
96
+ def do_OPTIONS(self):
97
+ self._send(204, b"")
98
+
99
+ def do_GET(self):
100
+ path = self.path.split("?", 1)[0].rstrip("/") or "/"
101
+ if path in ("/", "/index.html"):
102
+ try:
103
+ return self._send(200, open(self.artifact, encoding="utf-8").read(), "text/html; charset=utf-8")
104
+ except OSError:
105
+ return self._send(500, {"error": "artifact not found: " + self.artifact})
106
+
107
+ if path == API:
108
+ items = list_items(self.lib)
109
+ return self._send(200, {"collection": "video-deepdives", "total": len(items), "items": items})
110
+
111
+ if path.startswith(API + "/_media/"):
112
+ fn = posixpath.basename(path) # strip any traversal
113
+ fp = os.path.join(self.lib, "_media", fn)
114
+ if not os.path.isfile(fp):
115
+ return self._send(404, {"error": "no such media"})
116
+ ctype = mimetypes.guess_type(fp)[0] or "application/octet-stream"
117
+ with open(fp, "rb") as f:
118
+ return self._send(200, f.read(), ctype)
119
+
120
+ if path.startswith(API + "/"):
121
+ slug = posixpath.basename(path)
122
+ loaded = load_item(self.lib, slug)
123
+ if not loaded:
124
+ return self._send(404, {"error": "no such item"})
125
+ _, meta, body = loaded
126
+ return self._send(200, {"slug": slug, "type": "video-deepdive", "meta": meta, "body": body.rstrip("\n")})
127
+
128
+ return self._send(404, {"error": "not found"})
129
+
130
+ def do_PATCH(self):
131
+ path = self.path.split("?", 1)[0].rstrip("/")
132
+ if not path.startswith(API + "/"):
133
+ return self._send(404, {"error": "not found"})
134
+ slug = posixpath.basename(path)
135
+ loaded = load_item(self.lib, slug)
136
+ if not loaded:
137
+ return self._send(404, {"error": "no such item"})
138
+ fp, meta, body = loaded
139
+ try:
140
+ n = int(self.headers.get("Content-Length", 0))
141
+ payload = json.loads(self.rfile.read(n) or b"{}")
142
+ except (ValueError, json.JSONDecodeError):
143
+ return self._send(400, {"error": "bad json"})
144
+ fields = payload.get("fields", payload) # accept {fields:{...}} or a bare dict
145
+ if not isinstance(fields, dict):
146
+ return self._send(400, {"error": "fields must be an object"})
147
+ meta.update(fields)
148
+ open(fp, "w", encoding="utf-8").write(dump_file(meta, body))
149
+ return self._send(200, {"ok": True, "slug": slug, "updated": list(fields.keys())})
150
+
151
+
152
+ def main():
153
+ ap = argparse.ArgumentParser()
154
+ ap.add_argument("--dir", default=os.path.expanduser(os.environ.get("VIDEO_LIBRARY_DIR", "~/video-deepdives")))
155
+ ap.add_argument("--port", type=int, default=int(os.environ.get("VIDEO_LIBRARY_PORT", "8000")))
156
+ ap.add_argument("--host", default="127.0.0.1")
157
+ here = os.path.dirname(os.path.abspath(__file__))
158
+ ap.add_argument("--artifact", default=os.path.join(here, "..", "reference", "artifact.html"))
159
+ a = ap.parse_args()
160
+
161
+ lib = os.path.abspath(os.path.expanduser(a.dir))
162
+ os.makedirs(lib, exist_ok=True)
163
+ Handler.lib = lib
164
+ Handler.artifact = os.path.abspath(a.artifact)
165
+ n = len([f for f in os.listdir(lib) if f.endswith(".md") and not f.startswith("_")])
166
+ print(f"Library: {lib} ({n} videos)")
167
+ print(f"Artifact: {Handler.artifact}")
168
+ print(f"Serving on http://{a.host}:{a.port}/ (Ctrl-C to stop)")
169
+ ThreadingHTTPServer((a.host, a.port), Handler).serve_forever()
170
+
171
+
172
+ if __name__ == "__main__":
173
+ main()
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env bash
2
+ # Resolve a YouTube id from a URL/id, print the scratch dir, and report embeddability.
3
+ # Usage: setup.sh "<youtube_url_or_id>"
4
+ #
5
+ # Library location is configurable via the VIDEO_LIBRARY_DIR env var
6
+ # (default: ~/video-deepdives). One markdown file per video lives there.
7
+ set -euo pipefail
8
+ IN="${1:?usage: setup.sh <youtube_url_or_id>}"
9
+ LIB="${VIDEO_LIBRARY_DIR:-$HOME/video-deepdives}"
10
+
11
+ # Extract 11-char id from common URL shapes, or accept a bare id.
12
+ YTID="$(printf '%s' "$IN" | sed -nE 's#.*(youtu\.be/|v=|/embed/|/shorts/)([A-Za-z0-9_-]{11}).*#\2#p')"
13
+ [ -z "$YTID" ] && [ "${#IN}" -eq 11 ] && YTID="$IN"
14
+ [ -z "$YTID" ] && { echo "Could not parse a YouTube id from: $IN" >&2; exit 1; }
15
+
16
+ SCRATCH="/tmp/ytnote-$YTID"
17
+ mkdir -p "$SCRATCH"
18
+
19
+ # Embeddability: oembed returns 200 if embedding allowed, 401 if the owner disabled it.
20
+ CODE="$(curl -s -o /dev/null -w '%{http_code}' \
21
+ "https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v=$YTID&format=json" || echo "000")"
22
+ if [ "$CODE" = "200" ]; then EMBED="allowed"; else EMBED="BLOCKED (oembed $CODE) — inline player disabled, artifact falls back to YouTube link"; fi
23
+
24
+ echo "YTID: $YTID"
25
+ echo "SCRATCH: $SCRATCH"
26
+ echo "EMBED: $EMBED"
27
+ echo "LIBRARY: $LIB/$YTID.md"
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env bash
2
+ # Verify a video is correctly served by the standalone server + appears in the index.
3
+ # Usage: verify.sh <YTID> [base_url]
4
+ # Start the server first: python3 scripts/serve.py --dir <LIBRARY> --port 8000
5
+ set -uo pipefail
6
+ YTID="${1:?usage: verify.sh <YTID> [base_url]}"
7
+ BASE="${2:-http://127.0.0.1:8000}" # standalone serve.py default port
8
+ COLL="$BASE/api/video-deepdives"
9
+ fail=0
10
+
11
+ code(){ curl -s -o /dev/null -w '%{http_code}' "$1"; }
12
+
13
+ echo "1) collection list:"
14
+ C=$(code "$COLL"); echo " GET $COLL -> $C"; [ "$C" = 200 ] || fail=1
15
+ if curl -s "$COLL" | grep -q "\"$YTID\""; then echo " ✓ $YTID present in index"; else echo " ✗ $YTID NOT in index"; fail=1; fi
16
+
17
+ echo "2) item:"
18
+ C=$(code "$COLL/$YTID"); echo " GET $COLL/$YTID -> $C"; [ "$C" = 200 ] || fail=1
19
+
20
+ echo "3) first slide image:"
21
+ C=$(code "$COLL/_media/$YTID-slide-01.jpg"); echo " GET .../_media/$YTID-slide-01.jpg -> $C"; [ "$C" = 200 ] || fail=1
22
+
23
+ echo "4) artifact shell:"
24
+ C=$(code "$BASE/"); echo " GET / -> $C"; [ "$C" = 200 ] || fail=1
25
+
26
+ if [ "$fail" = 0 ]; then
27
+ echo "ALL GOOD. Open: $BASE/#/$YTID"
28
+ else
29
+ echo "SOME CHECKS FAILED — is serve.py running and pointed at the library that contains $YTID?"
30
+ fi
31
+ exit $fail
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env python3
2
+ """Convert a YouTube .vtt (manual or auto-captions) into clean [HH:MM:SS] transcript lines.
3
+
4
+ Usage: vtt_to_transcript.py <input.vtt> <output.txt>
5
+
6
+ Handles the rolling-duplicate problem in auto-captions: each cue repeats the tail of the
7
+ previous cue, so we keep only newly-added words per cue and emit one line per cue start
8
+ time. Strips inline <00:00:00.000> word-timing tags and HTML tags.
9
+ """
10
+ import sys, re, html
11
+
12
+ TS=re.compile(r'(\d{2}):(\d{2}):(\d{2})\.\d{3}\s*-->\s*(\d{2}):(\d{2}):(\d{2})')
13
+ INLINE=re.compile(r'<[^>]+>')
14
+
15
+ def hhmmss(h,m,s): return f"[{int(h):02d}:{int(m):02d}:{int(s):02d}]"
16
+
17
+ def clean(text):
18
+ text=INLINE.sub('',text)
19
+ text=html.unescape(text)
20
+ return re.sub(r'\s+',' ',text).strip()
21
+
22
+ def main():
23
+ if len(sys.argv)!=3: sys.exit("usage: vtt_to_transcript.py <in.vtt> <out.txt>")
24
+ raw=open(sys.argv[1],encoding='utf-8',errors='replace').read().splitlines()
25
+ cues=[] # (start_label, text)
26
+ i=0; cur=None
27
+ while i<len(raw):
28
+ m=TS.search(raw[i])
29
+ if m:
30
+ if cur: cues.append(cur)
31
+ cur=[hhmmss(*m.groups()[:3]),[]]
32
+ i+=1
33
+ while i<len(raw) and not TS.search(raw[i]) and raw[i].strip()!='':
34
+ if raw[i].strip() and not raw[i].strip().isdigit():
35
+ cur[1].append(clean(raw[i]))
36
+ i+=1
37
+ else:
38
+ i+=1
39
+ if cur: cues.append(cur)
40
+
41
+ # De-duplicate rolling captions: keep only the suffix not already seen.
42
+ out=[]; seen_words=[]
43
+ for label,parts in cues:
44
+ text=clean(' '.join(parts))
45
+ if not text: continue
46
+ words=text.split()
47
+ # find longest overlap of seen tail with this cue's head
48
+ overlap=0; maxk=min(len(words),len(seen_words))
49
+ for k in range(maxk,0,-1):
50
+ if seen_words[-k:]==words[:k]: overlap=k; break
51
+ new=words[overlap:]
52
+ if new:
53
+ out.append(f"{label} {' '.join(new)}")
54
+ seen_words=(seen_words+new)[-40:] # bounded window
55
+ with open(sys.argv[2],'w',encoding='utf-8') as f:
56
+ f.write('\n'.join(out)+'\n')
57
+ print(f"wrote {len(out)} transcript lines -> {sys.argv[2]}")
58
+
59
+ if __name__=="__main__": main()
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env python3
2
+ """Assemble the library markdown file for a video deep-dive.
3
+
4
+ Usage:
5
+ write_library_item.py --id <YTID> --title "..." --speaker "..." \
6
+ --tags a,b,c --slides slides.json --transcript transcript.txt [--created YYYY-MM-DD]
7
+
8
+ slides.json: a JSON array of slide objects. Each:
9
+ {
10
+ "idx": 1, # sequence/original frame number (display only; sorted by t)
11
+ "t": 55.7, # seconds (float ok) — used for video seeking
12
+ "mmss": "00:55", # display label
13
+ "title": "Slide title", # short headline
14
+ "note": "1-3 sentences grounded in the transcript at this timestamp.",
15
+ "img": "/api/video-deepdives/_media/<YTID>-slide-01.jpg"
16
+ }
17
+
18
+ Writes $VIDEO_LIBRARY_DIR/<YTID>.md (default ~/video-deepdives/<YTID>.md)
19
+ with YAML frontmatter + transcript body. No em dashes or arrows in titles/notes.
20
+ """
21
+ import argparse, json, os, sys, datetime
22
+ try:
23
+ import yaml
24
+ except ImportError:
25
+ sys.exit("pip install pyyaml")
26
+
27
+ LIB = os.path.expanduser(os.environ.get("VIDEO_LIBRARY_DIR", "~/video-deepdives"))
28
+
29
+ def main():
30
+ ap=argparse.ArgumentParser()
31
+ ap.add_argument("--id",required=True)
32
+ ap.add_argument("--title",required=True)
33
+ ap.add_argument("--speaker",default="")
34
+ ap.add_argument("--tags",default="")
35
+ ap.add_argument("--slides",required=True)
36
+ ap.add_argument("--transcript",required=True)
37
+ ap.add_argument("--created",default=datetime.date.today().isoformat())
38
+ a=ap.parse_args()
39
+
40
+ slides=json.load(open(a.slides))
41
+ slides=sorted(slides,key=lambda s:s["t"])
42
+ for bad in ("—","→"):
43
+ for s in slides:
44
+ if bad in (s.get("title") or "")+(s.get("note") or ""):
45
+ sys.exit(f"Found forbidden char {bad!r} in slide notes/titles; remove it.")
46
+
47
+ fm={
48
+ "id":a.id,
49
+ "title":a.title,
50
+ "youtube_id":a.id,
51
+ "speaker":a.speaker,
52
+ "source_url":f"https://www.youtube.com/watch?v={a.id}",
53
+ "slide_count":len(slides),
54
+ "created":a.created,
55
+ "tags":[t.strip() for t in a.tags.split(",") if t.strip()],
56
+ "slides":slides,
57
+ }
58
+ body=open(a.transcript,encoding="utf-8").read().strip()
59
+ os.makedirs(LIB,exist_ok=True)
60
+ path=os.path.join(LIB,f"{a.id}.md")
61
+ with open(path,"w",encoding="utf-8") as f:
62
+ f.write("---\n")
63
+ yaml.safe_dump(fm,f,sort_keys=False,allow_unicode=True,width=100)
64
+ f.write("---\n## Transcript\n")
65
+ f.write(body+"\n")
66
+ print(f"wrote {path} ({len(slides)} slides, {len(body.splitlines())} transcript lines)")
67
+ print("Verify with: scripts/verify.sh "+a.id)
68
+
69
+ if __name__=="__main__": main()
@@ -1,7 +1,21 @@
1
1
  import type { RiskLevel } from "./risk-level.js";
2
+ export interface ScanPattern {
3
+ id: string;
4
+ pattern: string;
5
+ description: string;
6
+ severity: "block" | "warn";
7
+ }
8
+ export interface SkillPatch {
9
+ skillId: string;
10
+ find: string;
11
+ replace: string;
12
+ description?: string;
13
+ }
2
14
  export interface SkillRiskFilterConfig {
3
15
  excludedRiskLevels?: RiskLevel[];
4
16
  excludedSkills?: string[];
17
+ scanPatterns?: ScanPattern[];
18
+ skillPatches?: SkillPatch[];
5
19
  }
6
20
  export declare const DEFAULT_FILTER_CONFIG_PATH: string;
7
21
  /**
@@ -1,13 +1,34 @@
1
- import os from "os";
2
- import path from "path";
3
- import fs from "fs";
1
+ import * as os from "node:os";
2
+ import * as path from "node:path";
3
+ import * as fs from "node:fs";
4
4
  import stripJsonComments from "strip-json-comments";
5
5
  const DEFAULT_CONFIG = {
6
6
  excludedRiskLevels: [],
7
7
  excludedSkills: [],
8
+ scanPatterns: [],
9
+ skillPatches: [],
8
10
  };
9
11
  export const DEFAULT_FILTER_CONFIG_PATH = path.join(os.homedir(), ".config", "opencode", "skill-filter.jsonc");
10
12
  const VALID_RISK_LEVELS = ["none", "safe", "critical", "offensive", "unknown"];
13
+ const VALID_SEVERITIES = ["block", "warn"];
14
+ function isValidScanPattern(entry) {
15
+ if (typeof entry !== "object" || entry === null)
16
+ return false;
17
+ const obj = entry;
18
+ return (typeof obj.id === "string" &&
19
+ typeof obj.pattern === "string" &&
20
+ typeof obj.description === "string" &&
21
+ typeof obj.severity === "string" &&
22
+ VALID_SEVERITIES.includes(obj.severity));
23
+ }
24
+ function isValidSkillPatch(entry) {
25
+ if (typeof entry !== "object" || entry === null)
26
+ return false;
27
+ const obj = entry;
28
+ return (typeof obj.skillId === "string" &&
29
+ typeof obj.find === "string" &&
30
+ typeof obj.replace === "string");
31
+ }
11
32
  /**
12
33
  * Loads filter config from skill-filter.jsonc. Missing file or section returns defaults.
13
34
  * @param configPath Optional override (for testing).
@@ -28,6 +49,12 @@ export function loadFilterConfig(configPath) {
28
49
  excludedSkills: Array.isArray(parsed.excludedSkills)
29
50
  ? parsed.excludedSkills
30
51
  : DEFAULT_CONFIG.excludedSkills,
52
+ scanPatterns: Array.isArray(parsed.scanPatterns)
53
+ ? parsed.scanPatterns.filter(isValidScanPattern)
54
+ : DEFAULT_CONFIG.scanPatterns,
55
+ skillPatches: Array.isArray(parsed.skillPatches)
56
+ ? parsed.skillPatches.filter(isValidSkillPatch)
57
+ : DEFAULT_CONFIG.skillPatches,
31
58
  };
32
59
  }
33
60
  catch {
@@ -0,0 +1,38 @@
1
+ import type { ScanPattern } from "./config-loader.js";
2
+ import type { SkillIndexEntry } from "./vault-installer.js";
3
+ export interface ScanResult {
4
+ skillId: string;
5
+ matchedPatterns: {
6
+ id: string;
7
+ severity: "block" | "warn";
8
+ }[];
9
+ blocked: boolean;
10
+ }
11
+ export interface ScanOutput {
12
+ passed: SkillIndexEntry[];
13
+ quarantined: ScanResult[];
14
+ warned: ScanResult[];
15
+ }
16
+ /** Default patterns that detect recursive loop triggers in skill content. */
17
+ export declare const DEFAULT_SCAN_PATTERNS: ScanPattern[];
18
+ /**
19
+ * Merges user-supplied scan patterns with built-in defaults.
20
+ * Config patterns with the same `id` override the default entry,
21
+ * but only if the config pattern has a valid regex. Invalid overrides
22
+ * are rejected and the default is preserved to prevent silently
23
+ * disabling built-in protection.
24
+ */
25
+ export declare function mergePatterns(configPatterns: ScanPattern[]): ScanPattern[];
26
+ /**
27
+ * Tests skill content against a list of scan patterns.
28
+ * Returns the list of matched pattern ids and severities.
29
+ */
30
+ export declare function scanSkillContent(content: string, patterns: ScanPattern[]): {
31
+ id: string;
32
+ severity: "block" | "warn";
33
+ }[];
34
+ /**
35
+ * Scans every skill's SKILL.md for dangerous content patterns.
36
+ * Returns lists of passed, quarantined (blocked), and warned entries.
37
+ */
38
+ export declare function scanSkills(bundledSkillsPath: string, index: SkillIndexEntry[], configPatterns?: ScanPattern[]): ScanOutput;
@@ -0,0 +1,118 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { SKILL_FILENAME } from "../constants/constants.js";
4
+ /** Default patterns that detect recursive loop triggers in skill content. */
5
+ export const DEFAULT_SCAN_PATTERNS = [
6
+ {
7
+ id: "recursive-skill-invocation",
8
+ pattern: String.raw `(invoke|use|check|load)\b.*?\bskills?\b.*?\bbefore\s+(any|every|all)\s+(response|action|message)`,
9
+ description: "Detects instructions mandating skill invocation before every response",
10
+ severity: "block",
11
+ },
12
+ {
13
+ id: "aggressive-match-threshold",
14
+ pattern: String.raw `(even\s+)?(a\s+)?1%\s+chance.*skill`,
15
+ description: "Detects extremely low probability thresholds causing over-triggering",
16
+ severity: "block",
17
+ },
18
+ {
19
+ id: "mandatory-pre-response-skill-check",
20
+ pattern: String.raw `you\s+(absolutely\s+)?must.*invoke.*skill`,
21
+ description: "Detects mandatory skill invocation directives",
22
+ severity: "block",
23
+ },
24
+ ];
25
+ /**
26
+ * Merges user-supplied scan patterns with built-in defaults.
27
+ * Config patterns with the same `id` override the default entry,
28
+ * but only if the config pattern has a valid regex. Invalid overrides
29
+ * are rejected and the default is preserved to prevent silently
30
+ * disabling built-in protection.
31
+ */
32
+ export function mergePatterns(configPatterns) {
33
+ const merged = new Map();
34
+ for (const p of DEFAULT_SCAN_PATTERNS) {
35
+ merged.set(p.id, p);
36
+ }
37
+ for (const p of configPatterns) {
38
+ // Validate regex before allowing override
39
+ try {
40
+ new RegExp(p.pattern, "is");
41
+ merged.set(p.id, p);
42
+ }
43
+ catch {
44
+ // If this would override a default, keep the default — don't silently disable protection
45
+ if (!merged.has(p.id)) {
46
+ // New pattern with invalid regex — just skip it
47
+ console.warn(`Invalid regex for pattern '${p.id}': ${p.pattern}`);
48
+ }
49
+ // Existing default stays in place
50
+ }
51
+ }
52
+ return [...merged.values()];
53
+ }
54
+ /**
55
+ * Tests skill content against a list of scan patterns.
56
+ * Returns the list of matched pattern ids and severities.
57
+ */
58
+ export function scanSkillContent(content, patterns) {
59
+ const matches = [];
60
+ for (const p of patterns) {
61
+ try {
62
+ const re = new RegExp(p.pattern, "is");
63
+ if (re.test(content)) {
64
+ matches.push({ id: p.id, severity: p.severity });
65
+ }
66
+ }
67
+ catch {
68
+ // Invalid regex — skip silently
69
+ }
70
+ }
71
+ return matches;
72
+ }
73
+ /**
74
+ * Scans every skill's SKILL.md for dangerous content patterns.
75
+ * Returns lists of passed, quarantined (blocked), and warned entries.
76
+ */
77
+ export function scanSkills(bundledSkillsPath, index, configPatterns) {
78
+ const patterns = mergePatterns(configPatterns ?? []);
79
+ const passed = [];
80
+ const quarantined = [];
81
+ const warned = [];
82
+ for (const entry of index) {
83
+ // Path traversal guard: quarantine entries whose id escapes the bundled-skills directory
84
+ if (entry.id.includes("..") || entry.id.includes(path.sep) || entry.id.includes("/")) {
85
+ quarantined.push({
86
+ skillId: entry.id,
87
+ matchedPatterns: [{ id: "path-traversal", severity: "block" }],
88
+ blocked: true,
89
+ });
90
+ continue;
91
+ }
92
+ const skillFile = path.join(bundledSkillsPath, entry.id, SKILL_FILENAME);
93
+ if (!fs.existsSync(skillFile)) {
94
+ passed.push(entry);
95
+ continue;
96
+ }
97
+ const content = fs.readFileSync(skillFile, "utf-8");
98
+ const matches = scanSkillContent(content, patterns);
99
+ if (matches.length === 0) {
100
+ passed.push(entry);
101
+ continue;
102
+ }
103
+ const hasBlock = matches.some((m) => m.severity === "block");
104
+ const result = {
105
+ skillId: entry.id,
106
+ matchedPatterns: matches,
107
+ blocked: hasBlock,
108
+ };
109
+ if (hasBlock) {
110
+ quarantined.push(result);
111
+ }
112
+ else {
113
+ warned.push(result);
114
+ passed.push(entry);
115
+ }
116
+ }
117
+ return { passed, quarantined, warned };
118
+ }
@@ -17,10 +17,15 @@ export interface SkillPointerOptions {
17
17
  * Orchestrates the full SkillPointer pipeline:
18
18
  *
19
19
  * 1. Reads skills_index.json bundled alongside the skills snapshot.
20
- * 2. Copies bundled skills directly into the vault, categorised by the index.
21
- * 3. Generates pointer SKILL.md files in activeSkillsDir with full skill
20
+ * 2. Filters by risk level / excluded skills.
21
+ * 3. Copies skills into the vault, categorised by the index.
22
+ * 4. Applies config-driven content patches to installed skills.
23
+ * 5. Generates pointer SKILL.md files in activeSkillsDir with full skill
22
24
  * listings so keyword searches (e.g. "laravel") resolve out of the box.
23
25
  *
26
+ * Content safety scanning is performed at CI time (sync-skills.yml),
27
+ * not at runtime — dangerous skills are removed before npm publish.
28
+ *
24
29
  * The activeSkillsDir is never used as a staging area — user custom
25
30
  * skills already present there are never moved or overwritten.
26
31
  */
@@ -1,11 +1,12 @@
1
- import os from "os";
2
- import path from "path";
1
+ import * as os from "node:os";
2
+ import * as path from "node:path";
3
3
  import { VAULT_DIR_NAME } from "../constants/constants.js";
4
4
  import { ensureDir } from "../utils/fs.utils.js";
5
5
  import { generatePointers } from "./pointer-generator.js";
6
6
  import { installSkillsToVault, loadSkillsIndex } from "./vault-installer.js";
7
7
  import { filterIndex } from "./skill-risk-filter.js";
8
8
  import { loadFilterConfig, DEFAULT_FILTER_CONFIG_PATH } from "./config-loader.js";
9
+ import { applySkillPatches } from "./skill-patcher.js";
9
10
  function resolveDefaultVaultDir() {
10
11
  return path.join(os.homedir(), ".config", "opencode", VAULT_DIR_NAME);
11
12
  }
@@ -13,10 +14,15 @@ function resolveDefaultVaultDir() {
13
14
  * Orchestrates the full SkillPointer pipeline:
14
15
  *
15
16
  * 1. Reads skills_index.json bundled alongside the skills snapshot.
16
- * 2. Copies bundled skills directly into the vault, categorised by the index.
17
- * 3. Generates pointer SKILL.md files in activeSkillsDir with full skill
17
+ * 2. Filters by risk level / excluded skills.
18
+ * 3. Copies skills into the vault, categorised by the index.
19
+ * 4. Applies config-driven content patches to installed skills.
20
+ * 5. Generates pointer SKILL.md files in activeSkillsDir with full skill
18
21
  * listings so keyword searches (e.g. "laravel") resolve out of the box.
19
22
  *
23
+ * Content safety scanning is performed at CI time (sync-skills.yml),
24
+ * not at runtime — dangerous skills are removed before npm publish.
25
+ *
20
26
  * The activeSkillsDir is never used as a staging area — user custom
21
27
  * skills already present there are never moved or overwritten.
22
28
  */
@@ -29,5 +35,9 @@ export function runSkillPointer(options) {
29
35
  const config = loadFilterConfig(configPath);
30
36
  const filteredIndex = filterIndex(index, config);
31
37
  installSkillsToVault(options.bundledSkillsPath, vaultDir, filteredIndex);
38
+ // Apply content patches
39
+ if (config.skillPatches && config.skillPatches.length > 0) {
40
+ applySkillPatches(vaultDir, filteredIndex, config.skillPatches);
41
+ }
32
42
  generatePointers(options.activeSkillsDir, vaultDir, filteredIndex);
33
43
  }
@@ -35,6 +35,8 @@ ${skillList}
35
35
  **Vault path:** \`${normalizedPath}\`
36
36
 
37
37
  > Do not guess best practices — always read from the vault first.
38
+
39
+ > ⚠️ **Anti-loop guard**: Do NOT invoke skills recursively or check for applicable skills before every response. Each skill should be loaded at most once per user request. If you have already identified and loaded the relevant skill for this task, proceed with execution — do not re-scan for skills.
38
40
  `;
39
41
  }
40
42
  /**