opencode-skills-collection 3.1.0 → 3.1.2
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.
- package/bundled-skills/.antigravity-install-manifest.json +84 -1
- package/bundled-skills/2slides-ppt-generator/SKILL.md +8 -7
- package/bundled-skills/android-cli/SKILL.md +19 -7
- package/bundled-skills/android-ui-journey-testing/SKILL.md +191 -0
- package/bundled-skills/apple-notes-search/SKILL.md +12 -2
- package/bundled-skills/ask-matt/SKILL.md +92 -0
- package/bundled-skills/atlas-ledger/SKILL.md +8 -0
- package/bundled-skills/bugs-are-annoying/SKILL.md +137 -0
- package/bundled-skills/codebase-design/DEEPENING.md +37 -0
- package/bundled-skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
- package/bundled-skills/codebase-design/SKILL.md +145 -0
- package/bundled-skills/codex-fable5/SKILL.md +10 -2
- package/bundled-skills/competitor-analysis/LICENSE.txt +21 -0
- package/bundled-skills/competitor-analysis/SKILL.md +434 -0
- package/bundled-skills/competitor-analysis/references/battle-card-subagent.md +127 -0
- package/bundled-skills/competitor-analysis/references/battle-card.md +91 -0
- package/bundled-skills/competitor-analysis/references/example-research.md +130 -0
- package/bundled-skills/competitor-analysis/references/report-template.html +127 -0
- package/bundled-skills/competitor-analysis/references/research-patterns.md +217 -0
- package/bundled-skills/competitor-analysis/references/workflow.md +434 -0
- package/bundled-skills/competitor-analysis/scripts/capture_screenshots.mjs +142 -0
- package/bundled-skills/competitor-analysis/scripts/compile_report.mjs +929 -0
- package/bundled-skills/competitor-analysis/scripts/extract_vs_names.mjs +140 -0
- package/bundled-skills/competitor-analysis/scripts/gate_candidates.mjs +224 -0
- package/bundled-skills/competitor-analysis/scripts/list_urls.mjs +90 -0
- package/bundled-skills/competitor-analysis/scripts/md_utils.mjs +50 -0
- package/bundled-skills/competitor-analysis/scripts/merge_partials.mjs +291 -0
- package/bundled-skills/competitor-analysis/scripts/package.json +6 -0
- package/bundled-skills/design-it/3d-ui/SKILL.md +259 -0
- package/bundled-skills/design-it/SKILL.md +170 -0
- package/bundled-skills/design-it/ai-native-ui/SKILL.md +295 -0
- package/bundled-skills/design-it/aurora-ui/SKILL.md +307 -0
- package/bundled-skills/design-it/bento-ui/SKILL.md +314 -0
- package/bundled-skills/design-it/brutalism/SKILL.md +270 -0
- package/bundled-skills/design-it/brutalist-typography/SKILL.md +287 -0
- package/bundled-skills/design-it/card-based-design/SKILL.md +262 -0
- package/bundled-skills/design-it/claymorphism/SKILL.md +287 -0
- package/bundled-skills/design-it/color-blocking/SKILL.md +278 -0
- package/bundled-skills/design-it/command-center-ui/SKILL.md +345 -0
- package/bundled-skills/design-it/cyber-y2k/SKILL.md +312 -0
- package/bundled-skills/design-it/cyberpunk-ui/SKILL.md +262 -0
- package/bundled-skills/design-it/dark-mode/SKILL.md +289 -0
- package/bundled-skills/design-it/dashboard-design/SKILL.md +331 -0
- package/bundled-skills/design-it/data-dense-design/SKILL.md +322 -0
- package/bundled-skills/design-it/duotone-design/SKILL.md +248 -0
- package/bundled-skills/design-it/editorial-design/SKILL.md +328 -0
- package/bundled-skills/design-it/flat-design/SKILL.md +221 -0
- package/bundled-skills/design-it/flat-design-2/SKILL.md +240 -0
- package/bundled-skills/design-it/floating-ui/SKILL.md +299 -0
- package/bundled-skills/design-it/frutiger-aero/SKILL.md +274 -0
- package/bundled-skills/design-it/glassmorphism/SKILL.md +272 -0
- package/bundled-skills/design-it/gradient-design/SKILL.md +309 -0
- package/bundled-skills/design-it/high-contrast/SKILL.md +288 -0
- package/bundled-skills/design-it/holographic-ui/SKILL.md +310 -0
- package/bundled-skills/design-it/isometric-design/SKILL.md +228 -0
- package/bundled-skills/design-it/layered-design/SKILL.md +247 -0
- package/bundled-skills/design-it/material-design/SKILL.md +275 -0
- package/bundled-skills/design-it/maximalism/SKILL.md +297 -0
- package/bundled-skills/design-it/minimalism/SKILL.md +267 -0
- package/bundled-skills/design-it/monochromatic-ui/SKILL.md +296 -0
- package/bundled-skills/design-it/neo-brutalism/SKILL.md +270 -0
- package/bundled-skills/design-it/neumorphism/SKILL.md +248 -0
- package/bundled-skills/design-it/retro-design/SKILL.md +283 -0
- package/bundled-skills/design-it/retro-futurism/SKILL.md +259 -0
- package/bundled-skills/design-it/sci-fi-interface/SKILL.md +309 -0
- package/bundled-skills/design-it/skeuomorphism/SKILL.md +280 -0
- package/bundled-skills/design-it/soft-pastel/SKILL.md +307 -0
- package/bundled-skills/design-it/spatial-computing-ui/SKILL.md +300 -0
- package/bundled-skills/design-it/spatial-design/SKILL.md +268 -0
- package/bundled-skills/design-it/swiss-design/SKILL.md +293 -0
- package/bundled-skills/design-it/synthwave/SKILL.md +257 -0
- package/bundled-skills/design-it/tile-design/SKILL.md +297 -0
- package/bundled-skills/design-it/typography-first/SKILL.md +247 -0
- package/bundled-skills/design-it/vaporwave/SKILL.md +331 -0
- package/bundled-skills/design-it/vibrant-maximalism/SKILL.md +291 -0
- package/bundled-skills/design-it/widget-based-design/SKILL.md +274 -0
- package/bundled-skills/design-it/y2k-design/SKILL.md +268 -0
- package/bundled-skills/diagnosing-bugs/SKILL.md +165 -0
- package/bundled-skills/diagnosing-bugs/scripts/hitl-loop.template.sh +41 -0
- package/bundled-skills/docs/contributors/skill-scoring.md +235 -0
- package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
- package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
- package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
- package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
- package/bundled-skills/docs/users/bundles.md +145 -1
- package/bundled-skills/docs/users/claude-code-skills.md +1 -1
- package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
- package/bundled-skills/docs/users/getting-started.md +1 -1
- package/bundled-skills/docs/users/kiro-integration.md +1 -1
- package/bundled-skills/docs/users/specialized-plugin-roadmap.md +11 -4
- package/bundled-skills/docs/users/usage.md +4 -4
- package/bundled-skills/docs/users/visual-guide.md +4 -4
- package/bundled-skills/domain-modeling/ADR-FORMAT.md +47 -0
- package/bundled-skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
- package/bundled-skills/domain-modeling/SKILL.md +105 -0
- package/bundled-skills/dos-verify-done-claims/SKILL.md +16 -4
- package/bundled-skills/ecl-harness-engineer/agents/creator-config.md +1 -1
- package/bundled-skills/ecl-harness-engineer/references/environment-config-guide.md +2 -2
- package/bundled-skills/ecl-harness-engineer/references/environment-detection-guide.md +4 -4
- package/bundled-skills/event-staffing-ordering/SKILL.md +4 -0
- package/bundled-skills/grill-me/SKILL.md +36 -0
- package/bundled-skills/grill-with-docs/SKILL.md +36 -0
- package/bundled-skills/grilling/SKILL.md +39 -0
- package/bundled-skills/handoff/SKILL.md +45 -0
- package/bundled-skills/image-generator/.env.example +7 -0
- package/bundled-skills/image-generator/SKILL.md +509 -0
- package/bundled-skills/improve-codebase-architecture/HTML-REPORT.md +123 -0
- package/bundled-skills/improve-codebase-architecture/SKILL.md +97 -0
- package/bundled-skills/learn/SKILL.md +156 -0
- package/bundled-skills/lesson-generator/SKILL.md +90 -0
- package/bundled-skills/llm-council/.env.example +7 -0
- package/bundled-skills/llm-council/SKILL.md +602 -0
- package/bundled-skills/loop-library/SKILL.md +208 -0
- package/bundled-skills/loop-library/agents/openai.yaml +4 -0
- package/bundled-skills/loop-library/references/catalog.md +270 -0
- package/bundled-skills/lovable-cleanup/SKILL.md +9 -7
- package/bundled-skills/macos-screen-recorder/SKILL.md +9 -1
- package/bundled-skills/mailtrap-managing-contacts/SKILL.md +112 -0
- package/bundled-skills/mailtrap-sending-emails/SKILL.md +167 -0
- package/bundled-skills/mailtrap-setting-up-sending-domain/SKILL.md +77 -0
- package/bundled-skills/mailtrap-testing-with-sandbox/SKILL.md +110 -0
- package/bundled-skills/prototype/LOGIC.md +79 -0
- package/bundled-skills/prototype/SKILL.md +62 -0
- package/bundled-skills/prototype/UI.md +112 -0
- package/bundled-skills/screenstudio-alt/SKILL.md +9 -1
- package/bundled-skills/setup-matt-pocock-skills/SKILL.md +158 -0
- package/bundled-skills/setup-matt-pocock-skills/domain.md +51 -0
- package/bundled-skills/setup-matt-pocock-skills/issue-tracker-github.md +34 -0
- package/bundled-skills/setup-matt-pocock-skills/issue-tracker-gitlab.md +35 -0
- package/bundled-skills/setup-matt-pocock-skills/issue-tracker-local.md +19 -0
- package/bundled-skills/setup-matt-pocock-skills/triage-labels.md +15 -0
- package/bundled-skills/survey-generator/LICENSE +21 -0
- package/bundled-skills/survey-generator/SKILL.md +143 -0
- package/bundled-skills/survey-generator/build_artifact.py +208 -0
- package/bundled-skills/survey-generator/examples/agentic-engineering/research_bundle.json +1196 -0
- package/bundled-skills/survey-generator/examples/agentic-engineering/survey.html +706 -0
- package/bundled-skills/survey-generator/style_spec.json +85 -0
- package/bundled-skills/survey-generator/templates/research_bundle_template.json +69 -0
- package/bundled-skills/tdd/SKILL.md +139 -0
- package/bundled-skills/tdd/mocking.md +59 -0
- package/bundled-skills/tdd/refactoring.md +10 -0
- package/bundled-skills/tdd/tests.md +61 -0
- package/bundled-skills/teach/GLOSSARY-FORMAT.md +35 -0
- package/bundled-skills/teach/LEARNING-RECORD-FORMAT.md +46 -0
- package/bundled-skills/teach/MISSION-FORMAT.md +31 -0
- package/bundled-skills/teach/RESOURCES-FORMAT.md +32 -0
- package/bundled-skills/teach/SKILL.md +169 -0
- package/bundled-skills/to-issues/SKILL.md +115 -0
- package/bundled-skills/to-prd/SKILL.md +104 -0
- package/bundled-skills/tools-page-seo-optimizer/SKILL.md +616 -0
- package/bundled-skills/triage/AGENT-BRIEF.md +207 -0
- package/bundled-skills/triage/OUT-OF-SCOPE.md +105 -0
- package/bundled-skills/triage/SKILL.md +143 -0
- package/bundled-skills/vibecode-production-qa-validator/SKILL.md +371 -141
- package/bundled-skills/wiki-builder/SKILL.md +157 -0
- package/bundled-skills/wiki-builder/agents/openai.yaml +5 -0
- package/bundled-skills/wiki-builder/references/wiki-flavors.md +98 -0
- package/bundled-skills/wiki-builder/scripts/init_wiki.sh +105 -0
- package/bundled-skills/wiki-builder/templates/index.md +20 -0
- package/bundled-skills/wiki-builder/templates/maintenance-log.md +7 -0
- package/bundled-skills/wiki-builder/templates/prompts/compile-concept-page.md +12 -0
- package/bundled-skills/wiki-builder/templates/prompts/compile-index.md +11 -0
- package/bundled-skills/wiki-builder/templates/prompts/compile-source-page.md +12 -0
- package/bundled-skills/wiki-builder/templates/prompts/lint-wiki.md +10 -0
- package/bundled-skills/wiki-builder/templates/prompts/query-and-file.md +11 -0
- package/bundled-skills/wiki-builder/templates/sources.md +9 -0
- package/bundled-skills/wiki-builder/templates/wiki.config.md +53 -0
- package/bundled-skills/writing-great-skills/GLOSSARY.md +181 -0
- package/bundled-skills/writing-great-skills/SKILL.md +111 -0
- package/bundled-skills/yao-meta-skill/SKILL.md +86 -0
- package/bundled-skills/yao-meta-skill/agents/interface.yaml +26 -0
- package/bundled-skills/yao-meta-skill/manifest.json +24 -0
- package/bundled-skills/yao-meta-skill/references/artifact-design-doctrine.md +49 -0
- package/bundled-skills/yao-meta-skill/references/authoring-discipline.md +78 -0
- package/bundled-skills/yao-meta-skill/references/autonomous-adaptation.md +65 -0
- package/bundled-skills/yao-meta-skill/references/distribution-registry-method.md +60 -0
- package/bundled-skills/yao-meta-skill/references/eval-playbook.md +69 -0
- package/bundled-skills/yao-meta-skill/references/gate-selection.md +68 -0
- package/bundled-skills/yao-meta-skill/references/governance.md +134 -0
- package/bundled-skills/yao-meta-skill/references/human-review-template.md +54 -0
- package/bundled-skills/yao-meta-skill/references/intent-dialogue.md +138 -0
- package/bundled-skills/yao-meta-skill/references/iteration-philosophy.md +30 -0
- package/bundled-skills/yao-meta-skill/references/non-skill-decision-tree.md +39 -0
- package/bundled-skills/yao-meta-skill/references/operating-modes.md +107 -0
- package/bundled-skills/yao-meta-skill/references/output-eval-method.md +113 -0
- package/bundled-skills/yao-meta-skill/references/output-quality-risk.md +41 -0
- package/bundled-skills/yao-meta-skill/references/output-visual-quality.md +53 -0
- package/bundled-skills/yao-meta-skill/references/packaging-contracts.md +70 -0
- package/bundled-skills/yao-meta-skill/references/pattern-extraction-doctrine.md +76 -0
- package/bundled-skills/yao-meta-skill/references/platform-capability-matrix.md +49 -0
- package/bundled-skills/yao-meta-skill/references/prompt-engineering-doctrine.md +76 -0
- package/bundled-skills/yao-meta-skill/references/qa-ladder.md +57 -0
- package/bundled-skills/yao-meta-skill/references/reference-scan.md +126 -0
- package/bundled-skills/yao-meta-skill/references/regression-cause-taxonomy.md +80 -0
- package/bundled-skills/yao-meta-skill/references/resource-boundaries.md +120 -0
- package/bundled-skills/yao-meta-skill/references/review-studio-method.md +87 -0
- package/bundled-skills/yao-meta-skill/references/review-waiver-method.md +76 -0
- package/bundled-skills/yao-meta-skill/references/runtime-conformance-method.md +21 -0
- package/bundled-skills/yao-meta-skill/references/skill-archetypes.md +86 -0
- package/bundled-skills/yao-meta-skill/references/skill-atlas-method.md +35 -0
- package/bundled-skills/yao-meta-skill/references/skill-engineering-method.md +210 -0
- package/bundled-skills/yao-meta-skill/references/skill-ir-method.md +41 -0
- package/bundled-skills/yao-meta-skill/references/skillops-decision-policy.md +53 -0
- package/bundled-skills/yao-meta-skill/references/systems-thinking-doctrine.md +75 -0
- package/bundled-skills/yao-meta-skill/references/telemetry-drift-method.md +182 -0
- package/bundled-skills/yao-meta-skill/references/trust-security-method.md +79 -0
- package/bundled-skills/yao-meta-skill/references/user-memory-policy.md +35 -0
- package/bundled-skills/youtube-notetaker/SKILL.md +209 -0
- package/bundled-skills/youtube-notetaker/reference/artifact.html +269 -0
- package/bundled-skills/youtube-notetaker/scripts/contact_sheet.py +53 -0
- package/bundled-skills/youtube-notetaker/scripts/detect_slides.sh +19 -0
- package/bundled-skills/youtube-notetaker/scripts/download.sh +24 -0
- package/bundled-skills/youtube-notetaker/scripts/extract_slides.py +43 -0
- package/bundled-skills/youtube-notetaker/scripts/serve.py +222 -0
- package/bundled-skills/youtube-notetaker/scripts/setup.sh +27 -0
- package/bundled-skills/youtube-notetaker/scripts/verify.sh +31 -0
- package/bundled-skills/youtube-notetaker/scripts/vtt_to_transcript.py +59 -0
- package/bundled-skills/youtube-notetaker/scripts/write_library_item.py +69 -0
- package/package.json +1 -1
- package/skills_index.json +2013 -330
- package/bundled-skills/ai-md/SKILL.md +0 -523
- package/bundled-skills/atlas-contract/SKILL.md +0 -650
- package/bundled-skills/busybox-on-windows/SKILL.md +0 -40
- package/bundled-skills/monte-carlo-prevent/SKILL.md +0 -257
- package/bundled-skills/monte-carlo-prevent/references/TROUBLESHOOTING.md +0 -23
- package/bundled-skills/monte-carlo-prevent/references/parameters.md +0 -32
- package/bundled-skills/monte-carlo-prevent/references/workflows.md +0 -478
- package/bundled-skills/monte-carlo-push-ingestion/SKILL.md +0 -372
- package/bundled-skills/monte-carlo-push-ingestion/references/anomaly-detection.md +0 -87
- package/bundled-skills/monte-carlo-push-ingestion/references/custom-lineage.md +0 -203
- package/bundled-skills/monte-carlo-push-ingestion/references/direct-http-api.md +0 -207
- package/bundled-skills/monte-carlo-push-ingestion/references/prerequisites.md +0 -150
- package/bundled-skills/monte-carlo-push-ingestion/references/push-lineage.md +0 -160
- package/bundled-skills/monte-carlo-push-ingestion/references/push-metadata.md +0 -158
- package/bundled-skills/monte-carlo-push-ingestion/references/push-query-logs.md +0 -219
- package/bundled-skills/monte-carlo-push-ingestion/references/validation.md +0 -257
- package/bundled-skills/monte-carlo-push-ingestion/scripts/sample_verify.py +0 -357
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_and_push_lineage.py +0 -70
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_and_push_metadata.py +0 -65
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_and_push_query_logs.py +0 -70
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_lineage.py +0 -214
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_metadata.py +0 -160
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_query_logs.py +0 -164
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/push_lineage.py +0 -198
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/push_metadata.py +0 -193
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/push_query_logs.py +0 -207
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/collect_and_push_metadata.py +0 -71
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/collect_and_push_query_logs.py +0 -64
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/collect_metadata.py +0 -253
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/collect_query_logs.py +0 -149
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/push_metadata.py +0 -190
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/push_query_logs.py +0 -208
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_and_push_lineage.py +0 -83
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_and_push_metadata.py +0 -77
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_and_push_query_logs.py +0 -83
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_lineage.py +0 -240
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_metadata.py +0 -212
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_query_logs.py +0 -204
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/push_lineage.py +0 -192
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/push_metadata.py +0 -178
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/push_query_logs.py +0 -200
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_and_push_lineage.py +0 -119
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_and_push_metadata.py +0 -119
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_and_push_query_logs.py +0 -117
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_lineage.py +0 -265
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_metadata.py +0 -313
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_query_logs.py +0 -284
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/push_lineage.py +0 -309
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/push_metadata.py +0 -245
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/push_query_logs.py +0 -255
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_and_push_lineage.py +0 -78
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_and_push_metadata.py +0 -80
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_and_push_query_logs.py +0 -88
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_lineage.py +0 -235
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_metadata.py +0 -219
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_query_logs.py +0 -239
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/push_lineage.py +0 -178
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/push_metadata.py +0 -178
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/push_query_logs.py +0 -196
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_and_push_lineage.py +0 -154
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_and_push_metadata.py +0 -137
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_and_push_query_logs.py +0 -137
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_lineage.py +0 -349
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_metadata.py +0 -329
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_query_logs.py +0 -254
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/push_lineage.py +0 -307
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/push_metadata.py +0 -228
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/push_query_logs.py +0 -248
- package/bundled-skills/monte-carlo-push-ingestion/scripts/test_template_sdk_usage.py +0 -340
- package/bundled-skills/skill-optimizer/SKILL.md +0 -271
- package/bundled-skills/using-superpowers/SKILL.md +0 -98
|
@@ -0,0 +1,222 @@
|
|
|
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
|
+
from pathlib import Path
|
|
25
|
+
from tempfile import TemporaryDirectory
|
|
26
|
+
|
|
27
|
+
try:
|
|
28
|
+
import yaml
|
|
29
|
+
except ImportError:
|
|
30
|
+
sys.exit("pip install pyyaml")
|
|
31
|
+
|
|
32
|
+
API = "/api/video-deepdives"
|
|
33
|
+
FM_RE = re.compile(r"^---\n(.*?)\n---\n?(.*)$", re.DOTALL)
|
|
34
|
+
SAFE_SLUG_RE = re.compile(r"^[A-Za-z0-9_-]+$")
|
|
35
|
+
SAFE_MEDIA_RE = re.compile(r"^[A-Za-z0-9_.-]+$")
|
|
36
|
+
SAFE_CTYPE_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*/[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*(?:; charset=[A-Za-z0-9._-]+)?$")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def split_frontmatter(text):
|
|
40
|
+
"""Return (meta_dict, body_str) from a markdown file with YAML frontmatter."""
|
|
41
|
+
m = FM_RE.match(text)
|
|
42
|
+
if not m:
|
|
43
|
+
return {}, text
|
|
44
|
+
meta = yaml.safe_load(m.group(1)) or {}
|
|
45
|
+
return meta, m.group(2)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def dump_file(meta, body):
|
|
49
|
+
out = "---\n" + yaml.safe_dump(meta, sort_keys=False, allow_unicode=True, width=100) + "---\n"
|
|
50
|
+
return out + body
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def library_path(lib, *parts):
|
|
54
|
+
root = Path(lib).resolve()
|
|
55
|
+
candidate = root.joinpath(*parts).resolve()
|
|
56
|
+
try:
|
|
57
|
+
candidate.relative_to(root)
|
|
58
|
+
except ValueError:
|
|
59
|
+
return None
|
|
60
|
+
return candidate
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def safe_content_type(ctype):
|
|
64
|
+
return ctype if isinstance(ctype, str) and SAFE_CTYPE_RE.match(ctype) else "application/octet-stream"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def load_item(lib, slug):
|
|
68
|
+
if not SAFE_SLUG_RE.match(slug):
|
|
69
|
+
return None
|
|
70
|
+
path = library_path(lib, slug + ".md")
|
|
71
|
+
if not path or not path.is_file():
|
|
72
|
+
return None
|
|
73
|
+
meta, body = split_frontmatter(path.read_text(encoding="utf-8"))
|
|
74
|
+
return path, meta, body
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def list_items(lib):
|
|
78
|
+
items = []
|
|
79
|
+
for path in sorted(Path(lib).iterdir()):
|
|
80
|
+
fn = path.name
|
|
81
|
+
if not path.is_file() or not fn.endswith(".md") or fn.startswith("_"):
|
|
82
|
+
continue
|
|
83
|
+
slug = path.stem
|
|
84
|
+
loaded = load_item(lib, slug)
|
|
85
|
+
if not loaded:
|
|
86
|
+
continue
|
|
87
|
+
_, meta, body = loaded
|
|
88
|
+
it = dict(meta)
|
|
89
|
+
it["slug"] = slug
|
|
90
|
+
it["file"] = fn
|
|
91
|
+
it["preview"] = body.strip()[:160]
|
|
92
|
+
items.append(it)
|
|
93
|
+
return items
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class Handler(BaseHTTPRequestHandler):
|
|
97
|
+
lib = None
|
|
98
|
+
artifact = None
|
|
99
|
+
write_token = None
|
|
100
|
+
|
|
101
|
+
def log_message(self, *a):
|
|
102
|
+
pass # quiet
|
|
103
|
+
|
|
104
|
+
def _send(self, code, body, ctype="application/json"):
|
|
105
|
+
ctype = safe_content_type(ctype)
|
|
106
|
+
if isinstance(body, (dict, list)):
|
|
107
|
+
body = json.dumps(body).encode()
|
|
108
|
+
elif isinstance(body, str):
|
|
109
|
+
body = body.encode()
|
|
110
|
+
self.send_response(code)
|
|
111
|
+
self.send_header("Content-Type", ctype)
|
|
112
|
+
self.send_header("Content-Length", str(len(body)))
|
|
113
|
+
self.send_header("Access-Control-Allow-Origin", "*")
|
|
114
|
+
self.send_header("Access-Control-Allow-Methods", "GET, OPTIONS")
|
|
115
|
+
self.send_header("Access-Control-Allow-Headers", "Content-Type, X-Video-Library-Token")
|
|
116
|
+
self.end_headers()
|
|
117
|
+
if self.command != "HEAD":
|
|
118
|
+
self.wfile.write(body)
|
|
119
|
+
|
|
120
|
+
def do_OPTIONS(self):
|
|
121
|
+
self._send(204, b"")
|
|
122
|
+
|
|
123
|
+
def do_GET(self):
|
|
124
|
+
path = self.path.split("?", 1)[0].rstrip("/") or "/"
|
|
125
|
+
if path in ("/", "/index.html"):
|
|
126
|
+
try:
|
|
127
|
+
return self._send(200, open(self.artifact, encoding="utf-8").read(), "text/html; charset=utf-8")
|
|
128
|
+
except OSError:
|
|
129
|
+
return self._send(500, {"error": "artifact not found: " + self.artifact})
|
|
130
|
+
|
|
131
|
+
if path == API:
|
|
132
|
+
items = list_items(self.lib)
|
|
133
|
+
return self._send(200, {"collection": "video-deepdives", "total": len(items), "items": items})
|
|
134
|
+
|
|
135
|
+
if path.startswith(API + "/_media/"):
|
|
136
|
+
fn = posixpath.basename(path) # strip any traversal
|
|
137
|
+
if not SAFE_MEDIA_RE.match(fn):
|
|
138
|
+
return self._send(400, {"error": "bad media name"})
|
|
139
|
+
fp = library_path(self.lib, "_media", fn)
|
|
140
|
+
if not fp or not fp.is_file():
|
|
141
|
+
return self._send(404, {"error": "no such media"})
|
|
142
|
+
ctype = mimetypes.guess_type(str(fp))[0] or "application/octet-stream"
|
|
143
|
+
return self._send(200, fp.read_bytes(), ctype)
|
|
144
|
+
|
|
145
|
+
if path.startswith(API + "/"):
|
|
146
|
+
slug = posixpath.basename(path)
|
|
147
|
+
loaded = load_item(self.lib, slug)
|
|
148
|
+
if not loaded:
|
|
149
|
+
return self._send(404, {"error": "no such item"})
|
|
150
|
+
_, meta, body = loaded
|
|
151
|
+
return self._send(200, {"slug": slug, "type": "video-deepdive", "meta": meta, "body": body.rstrip("\n")})
|
|
152
|
+
|
|
153
|
+
return self._send(404, {"error": "not found"})
|
|
154
|
+
|
|
155
|
+
def do_PATCH(self):
|
|
156
|
+
if not self.write_token:
|
|
157
|
+
return self._send(403, {"error": "writes disabled"})
|
|
158
|
+
if self.headers.get("X-Video-Library-Token") != self.write_token:
|
|
159
|
+
return self._send(403, {"error": "bad write token"})
|
|
160
|
+
path = self.path.split("?", 1)[0].rstrip("/")
|
|
161
|
+
if not path.startswith(API + "/"):
|
|
162
|
+
return self._send(404, {"error": "not found"})
|
|
163
|
+
slug = posixpath.basename(path)
|
|
164
|
+
loaded = load_item(self.lib, slug)
|
|
165
|
+
if not loaded:
|
|
166
|
+
return self._send(404, {"error": "no such item"})
|
|
167
|
+
fp, meta, body = loaded
|
|
168
|
+
try:
|
|
169
|
+
n = int(self.headers.get("Content-Length", 0))
|
|
170
|
+
payload = json.loads(self.rfile.read(n) or b"{}")
|
|
171
|
+
except (ValueError, json.JSONDecodeError):
|
|
172
|
+
return self._send(400, {"error": "bad json"})
|
|
173
|
+
fields = payload.get("fields", payload) # accept {fields:{...}} or a bare dict
|
|
174
|
+
if not isinstance(fields, dict):
|
|
175
|
+
return self._send(400, {"error": "fields must be an object"})
|
|
176
|
+
meta.update(fields)
|
|
177
|
+
fp.write_text(dump_file(meta, body), encoding="utf-8")
|
|
178
|
+
return self._send(200, {"ok": True, "slug": slug, "updated": list(fields.keys())})
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def self_test():
|
|
182
|
+
with TemporaryDirectory() as tmp:
|
|
183
|
+
root = Path(tmp)
|
|
184
|
+
(root / "video_1.md").write_text("---\ntitle: Demo\n---\nBody", encoding="utf-8")
|
|
185
|
+
(root / "_media").mkdir()
|
|
186
|
+
(root / "_media" / "video_1-slide-01.jpg").write_bytes(b"x")
|
|
187
|
+
assert load_item(str(root), "video_1")
|
|
188
|
+
assert load_item(str(root), "../secret") is None
|
|
189
|
+
assert library_path(str(root), "_media", "../video_1.md") == root.resolve() / "video_1.md"
|
|
190
|
+
assert safe_content_type("text/html; charset=utf-8") == "text/html; charset=utf-8"
|
|
191
|
+
assert safe_content_type("text/html\r\nX-Bad: 1") == "application/octet-stream"
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def main():
|
|
195
|
+
ap = argparse.ArgumentParser()
|
|
196
|
+
ap.add_argument("--self-test", action="store_true")
|
|
197
|
+
ap.add_argument("--dir", default=os.path.expanduser(os.environ.get("VIDEO_LIBRARY_DIR", "~/video-deepdives")))
|
|
198
|
+
ap.add_argument("--port", type=int, default=int(os.environ.get("VIDEO_LIBRARY_PORT", "8000")))
|
|
199
|
+
ap.add_argument("--host", default="127.0.0.1")
|
|
200
|
+
ap.add_argument("--write-token", default=os.environ.get("VIDEO_LIBRARY_WRITE_TOKEN"))
|
|
201
|
+
here = os.path.dirname(os.path.abspath(__file__))
|
|
202
|
+
ap.add_argument("--artifact", default=os.path.join(here, "..", "reference", "artifact.html"))
|
|
203
|
+
a = ap.parse_args()
|
|
204
|
+
if a.self_test:
|
|
205
|
+
self_test()
|
|
206
|
+
return
|
|
207
|
+
|
|
208
|
+
lib = os.path.abspath(os.path.expanduser(a.dir))
|
|
209
|
+
os.makedirs(lib, exist_ok=True)
|
|
210
|
+
Handler.lib = lib
|
|
211
|
+
Handler.artifact = os.path.abspath(a.artifact)
|
|
212
|
+
Handler.write_token = a.write_token
|
|
213
|
+
n = len([f for f in os.listdir(lib) if f.endswith(".md") and not f.startswith("_")])
|
|
214
|
+
print(f"Library: {lib} ({n} videos)")
|
|
215
|
+
print(f"Artifact: {Handler.artifact}")
|
|
216
|
+
print("Writes: " + ("enabled with X-Video-Library-Token" if Handler.write_token else "disabled (set VIDEO_LIBRARY_WRITE_TOKEN to enable PATCH)"))
|
|
217
|
+
print(f"Serving on http://{a.host}:{a.port}/ (Ctrl-C to stop)")
|
|
218
|
+
ThreadingHTTPServer((a.host, a.port), Handler).serve_forever()
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
if __name__ == "__main__":
|
|
222
|
+
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()
|
package/package.json
CHANGED