opencode-skills-collection 2.0.0 → 2.0.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.
Files changed (90) hide show
  1. package/bundled-skills/.antigravity-install-manifest.json +6 -1
  2. package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
  3. package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
  4. package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
  5. package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
  6. package/bundled-skills/docs/users/bundles.md +1 -1
  7. package/bundled-skills/docs/users/claude-code-skills.md +1 -1
  8. package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
  9. package/bundled-skills/docs/users/getting-started.md +1 -1
  10. package/bundled-skills/docs/users/kiro-integration.md +1 -1
  11. package/bundled-skills/docs/users/usage.md +4 -4
  12. package/bundled-skills/docs/users/visual-guide.md +4 -4
  13. package/bundled-skills/manage-skills/SKILL.md +187 -0
  14. package/bundled-skills/monte-carlo-monitor-creation/SKILL.md +222 -0
  15. package/bundled-skills/monte-carlo-monitor-creation/references/comparison-monitor.md +426 -0
  16. package/bundled-skills/monte-carlo-monitor-creation/references/custom-sql-monitor.md +207 -0
  17. package/bundled-skills/monte-carlo-monitor-creation/references/metric-monitor.md +292 -0
  18. package/bundled-skills/monte-carlo-monitor-creation/references/table-monitor.md +231 -0
  19. package/bundled-skills/monte-carlo-monitor-creation/references/validation-monitor.md +404 -0
  20. package/bundled-skills/monte-carlo-prevent/SKILL.md +252 -0
  21. package/bundled-skills/monte-carlo-prevent/references/TROUBLESHOOTING.md +23 -0
  22. package/bundled-skills/monte-carlo-prevent/references/parameters.md +32 -0
  23. package/bundled-skills/monte-carlo-prevent/references/workflows.md +478 -0
  24. package/bundled-skills/monte-carlo-push-ingestion/SKILL.md +363 -0
  25. package/bundled-skills/monte-carlo-push-ingestion/references/anomaly-detection.md +87 -0
  26. package/bundled-skills/monte-carlo-push-ingestion/references/custom-lineage.md +203 -0
  27. package/bundled-skills/monte-carlo-push-ingestion/references/direct-http-api.md +207 -0
  28. package/bundled-skills/monte-carlo-push-ingestion/references/prerequisites.md +150 -0
  29. package/bundled-skills/monte-carlo-push-ingestion/references/push-lineage.md +160 -0
  30. package/bundled-skills/monte-carlo-push-ingestion/references/push-metadata.md +158 -0
  31. package/bundled-skills/monte-carlo-push-ingestion/references/push-query-logs.md +219 -0
  32. package/bundled-skills/monte-carlo-push-ingestion/references/validation.md +257 -0
  33. package/bundled-skills/monte-carlo-push-ingestion/scripts/sample_verify.py +357 -0
  34. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_and_push_lineage.py +70 -0
  35. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_and_push_metadata.py +65 -0
  36. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_and_push_query_logs.py +70 -0
  37. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_lineage.py +214 -0
  38. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_metadata.py +160 -0
  39. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_query_logs.py +164 -0
  40. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/push_lineage.py +198 -0
  41. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/push_metadata.py +193 -0
  42. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/push_query_logs.py +207 -0
  43. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/collect_and_push_metadata.py +71 -0
  44. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/collect_and_push_query_logs.py +64 -0
  45. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/collect_metadata.py +253 -0
  46. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/collect_query_logs.py +149 -0
  47. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/push_metadata.py +190 -0
  48. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/push_query_logs.py +208 -0
  49. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_and_push_lineage.py +83 -0
  50. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_and_push_metadata.py +77 -0
  51. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_and_push_query_logs.py +83 -0
  52. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_lineage.py +240 -0
  53. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_metadata.py +212 -0
  54. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_query_logs.py +204 -0
  55. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/push_lineage.py +192 -0
  56. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/push_metadata.py +178 -0
  57. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/push_query_logs.py +200 -0
  58. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_and_push_lineage.py +119 -0
  59. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_and_push_metadata.py +119 -0
  60. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_and_push_query_logs.py +117 -0
  61. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_lineage.py +265 -0
  62. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_metadata.py +313 -0
  63. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_query_logs.py +284 -0
  64. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/push_lineage.py +309 -0
  65. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/push_metadata.py +245 -0
  66. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/push_query_logs.py +255 -0
  67. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_and_push_lineage.py +78 -0
  68. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_and_push_metadata.py +80 -0
  69. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_and_push_query_logs.py +88 -0
  70. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_lineage.py +235 -0
  71. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_metadata.py +219 -0
  72. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_query_logs.py +239 -0
  73. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/push_lineage.py +178 -0
  74. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/push_metadata.py +178 -0
  75. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/push_query_logs.py +196 -0
  76. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_and_push_lineage.py +154 -0
  77. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_and_push_metadata.py +137 -0
  78. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_and_push_query_logs.py +137 -0
  79. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_lineage.py +349 -0
  80. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_metadata.py +329 -0
  81. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_query_logs.py +254 -0
  82. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/push_lineage.py +307 -0
  83. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/push_metadata.py +228 -0
  84. package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/push_query_logs.py +248 -0
  85. package/bundled-skills/monte-carlo-push-ingestion/scripts/test_template_sdk_usage.py +340 -0
  86. package/bundled-skills/monte-carlo-validation-notebook/SKILL.md +685 -0
  87. package/bundled-skills/monte-carlo-validation-notebook/scripts/generate_notebook_url.py +141 -0
  88. package/bundled-skills/monte-carlo-validation-notebook/scripts/resolve_dbt_schema.py +161 -0
  89. package/package.json +1 -1
  90. package/skills_index.json +503 -61
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Encode a notebook YAML file into a base64 import URL and open it in the browser.
4
+
5
+ Usage:
6
+ python3 generate_notebook_url.py <notebook_yaml_path> [--mc-base-url URL]
7
+ """
8
+
9
+ import argparse
10
+ import base64
11
+ import os
12
+ import re
13
+ import subprocess
14
+ import sys
15
+
16
+ import yaml
17
+
18
+
19
+ def sanitize_yaml(content: str) -> str:
20
+ """Replace non-ASCII characters with ASCII equivalents."""
21
+ replacements = {
22
+ "\u2014": "-",
23
+ "\u2013": "-",
24
+ "\u2018": "'",
25
+ "\u2019": "'",
26
+ "\u201c": '"',
27
+ "\u201d": '"',
28
+ "\u2026": "...",
29
+ "\u00a0": " ",
30
+ }
31
+ for char, replacement in replacements.items():
32
+ content = content.replace(char, replacement)
33
+ content = re.sub(r"[^\x00-\x7F]", "?", content)
34
+ return content
35
+
36
+
37
+ def validate_yaml(content: str) -> None:
38
+ """Parse YAML, validate notebook schema, and exit with context on failure."""
39
+ try:
40
+ doc = yaml.safe_load(content)
41
+ except yaml.YAMLError as e:
42
+ print(f"YAML validation failed: {e}", file=sys.stderr)
43
+ sys.exit(1)
44
+
45
+ errors: list[str] = []
46
+
47
+ # Top-level structure
48
+ if not isinstance(doc, dict):
49
+ errors.append("Root must be a mapping")
50
+ else:
51
+ if "version" not in doc:
52
+ errors.append("Missing top-level 'version'")
53
+ metadata = doc.get("metadata")
54
+ if not isinstance(metadata, dict):
55
+ errors.append("Missing or invalid 'metadata' mapping")
56
+ else:
57
+ for field in ("id", "name", "created_at", "updated_at"):
58
+ if field not in metadata:
59
+ errors.append(f"metadata.{field}: missing required field")
60
+ for bad_field in ("title", "description", "pr_number", "generated_by"):
61
+ if bad_field in metadata:
62
+ errors.append(
63
+ f"metadata.{bad_field}: unexpected field (use 'name' for the notebook title)"
64
+ )
65
+
66
+ cells = doc.get("cells")
67
+ if not isinstance(cells, list):
68
+ errors.append("Missing or invalid 'cells' list")
69
+ else:
70
+ for i, cell in enumerate(cells):
71
+ prefix = f"cells[{i}]"
72
+ if not isinstance(cell, dict):
73
+ errors.append(f"{prefix}: must be a mapping")
74
+ continue
75
+ if "id" not in cell:
76
+ errors.append(f"{prefix}: missing 'id'")
77
+ if "type" not in cell:
78
+ errors.append(f"{prefix}: missing 'type'")
79
+ cell_type = cell.get("type")
80
+ if cell_type not in ("sql", "markdown", "parameter"):
81
+ errors.append(
82
+ f"{prefix}: invalid type '{cell_type}' (must be sql, markdown, or parameter)"
83
+ )
84
+ if "display_type" not in cell:
85
+ errors.append(f"{prefix}: missing 'display_type'")
86
+ if cell_type == "parameter":
87
+ content_val = cell.get("content")
88
+ if not isinstance(content_val, dict):
89
+ errors.append(f"{prefix}: parameter cell 'content' must be a mapping with 'name' and 'config'")
90
+ else:
91
+ if "name" not in content_val:
92
+ errors.append(f"{prefix}: parameter content missing 'name'")
93
+ if "config" not in content_val:
94
+ errors.append(f"{prefix}: parameter content missing 'config'")
95
+
96
+ if errors:
97
+ print("Invalid notebook:", file=sys.stderr)
98
+ for err in errors:
99
+ print(f" - {err}", file=sys.stderr)
100
+ sys.exit(1)
101
+
102
+
103
+ def main() -> None:
104
+ parser = argparse.ArgumentParser(description="Encode notebook YAML to import URL")
105
+ parser.add_argument("yaml_path", help="Path to notebook YAML file")
106
+ parser.add_argument(
107
+ "--mc-base-url",
108
+ default="https://getmontecarlo.com",
109
+ help="MC Bridge base URL",
110
+ )
111
+ args = parser.parse_args()
112
+
113
+ with open(args.yaml_path) as f:
114
+ notebook_yaml = f.read()
115
+
116
+ yaml_content = sanitize_yaml(notebook_yaml.strip())
117
+ validate_yaml(yaml_content)
118
+
119
+ encoded = base64.b64encode(yaml_content.encode()).decode()
120
+ url = f"{args.mc_base_url}/notebooks/import#{encoded}"
121
+
122
+ print(f"URL length: {len(url)} chars")
123
+
124
+ # Save URL to file alongside the YAML
125
+ url_file = os.path.join(os.path.dirname(os.path.abspath(args.yaml_path)), "notebook_url.txt")
126
+ with open(url_file, "w") as f:
127
+ f.write(url)
128
+ print(f"URL saved to: {url_file}")
129
+
130
+ print("\n" + "=" * 60)
131
+ print("NOTEBOOK URL:")
132
+ print("=" * 60)
133
+ print(url)
134
+ print("=" * 60 + "\n")
135
+
136
+ print("Opening notebook in browser...")
137
+ subprocess.run(["open", url])
138
+
139
+
140
+ if __name__ == "__main__":
141
+ main()
@@ -0,0 +1,161 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Resolve the output schema for a dbt model.
4
+
5
+ Usage:
6
+ python3 resolve_dbt_schema.py <dbt_project_yml_path> <model_sql_path>
7
+
8
+ Returns the resolved schema name (uppercase), e.g., "PROD", "PROD_STAGE", "PROD_LINEAGE"
9
+ """
10
+
11
+ import argparse
12
+ import re
13
+ import sys
14
+ from pathlib import Path
15
+ from typing import Dict, List, Optional, Tuple, Union
16
+
17
+ import yaml
18
+
19
+
20
+ def parse_model_config_schema(model_content: str) -> Optional[str]:
21
+ """Extract schema from model's config block."""
22
+ pattern = r"\{\{\s*config\s*\([^)]*\bschema\s*=\s*['\"]([^'\"]+)['\"][^)]*\)\s*\}\}"
23
+ match = re.search(pattern, model_content, re.IGNORECASE | re.DOTALL)
24
+ if match:
25
+ return match.group(1).upper()
26
+
27
+ snapshot_pattern = r"target_schema\s*=\s*generate_schema_name\s*\(\s*['\"]([^'\"]+)['\"]"
28
+ match = re.search(snapshot_pattern, model_content, re.IGNORECASE | re.DOTALL)
29
+ if match:
30
+ return match.group(1).upper()
31
+
32
+ return None
33
+
34
+
35
+ def parse_dbt_project_routing(
36
+ dbt_project: dict, project_name: str
37
+ ) -> Tuple[Dict[str, str], Dict[str, str]]:
38
+ """Extract schema and database routing rules from dbt_project.yml."""
39
+ schema_routing = {} # type: Dict[str, str]
40
+ database_routing = {} # type: Dict[str, str]
41
+
42
+ models_config = dbt_project.get("models", {})
43
+ project_config = models_config.get(project_name, {})
44
+
45
+ def extract_routing(config: dict, current_path: str = "") -> None:
46
+ for key, value in config.items():
47
+ if key.startswith("+"):
48
+ continue
49
+ if not isinstance(value, dict):
50
+ continue
51
+ new_path = f"{current_path}/{key}" if current_path else key
52
+ schema = value.get("schema") or value.get("+schema")
53
+ if schema:
54
+ if "{{" not in schema:
55
+ schema_routing[new_path] = schema.upper()
56
+ database = value.get("database") or value.get("+database")
57
+ if database:
58
+ if "{{" not in database:
59
+ database_routing[new_path] = database.upper()
60
+ extract_routing(value, new_path)
61
+
62
+ extract_routing(project_config)
63
+ return schema_routing, database_routing
64
+
65
+
66
+ def parse_dbt_project_schema_routing(dbt_project: dict, project_name: str) -> Dict[str, str]:
67
+ schema_routing, _ = parse_dbt_project_routing(dbt_project, project_name)
68
+ return schema_routing
69
+
70
+
71
+ def get_model_relative_path(dbt_project_path: Path, model_path: Path) -> str:
72
+ dbt_project_dir = dbt_project_path.parent
73
+ model_relative = model_path.relative_to(dbt_project_dir)
74
+ parts = model_relative.parts
75
+ if parts and parts[0] == "models":
76
+ return str(Path(*parts[1:]))
77
+ return str(model_relative)
78
+
79
+
80
+ def find_matching_schema(
81
+ model_relative_path: str, routing: Dict[str, str]
82
+ ) -> Optional[str]:
83
+ model_dir = str(Path(model_relative_path).parent)
84
+ matches = [] # type: List[Tuple[str, str]]
85
+ for route_path, schema in routing.items():
86
+ if model_dir == route_path or model_dir.startswith(route_path + "/"):
87
+ matches.append((route_path, schema))
88
+ if not matches:
89
+ return None
90
+ matches.sort(key=lambda x: len(x[0]), reverse=True)
91
+ return matches[0][1]
92
+
93
+
94
+ def apply_schema_prefix(schema: str, target_schema: str = "PROD") -> str:
95
+ if not schema or schema.upper() == target_schema.upper():
96
+ return target_schema.upper()
97
+ return f"{target_schema.upper()}_{schema.upper()}"
98
+
99
+
100
+ def resolve_schema(
101
+ dbt_project_path: Union[str, Path],
102
+ model_path: Union[str, Path],
103
+ default_schema: str = "PROD",
104
+ apply_prefix: bool = True,
105
+ ) -> str:
106
+ dbt_project_path = Path(dbt_project_path)
107
+ model_path = Path(model_path)
108
+
109
+ model_content = model_path.read_text()
110
+
111
+ config_schema = parse_model_config_schema(model_content)
112
+ if config_schema:
113
+ if apply_prefix:
114
+ return apply_schema_prefix(config_schema, default_schema)
115
+ return config_schema
116
+
117
+ with open(dbt_project_path) as f:
118
+ dbt_project = yaml.safe_load(f)
119
+
120
+ project_name = dbt_project.get("name", "")
121
+
122
+ routing = parse_dbt_project_schema_routing(dbt_project, project_name)
123
+ model_relative = get_model_relative_path(dbt_project_path, model_path)
124
+ matched_schema = find_matching_schema(model_relative, routing)
125
+ if matched_schema:
126
+ if apply_prefix:
127
+ return apply_schema_prefix(matched_schema, default_schema)
128
+ return matched_schema
129
+
130
+ return default_schema.upper()
131
+
132
+
133
+ def main() -> None:
134
+ parser = argparse.ArgumentParser(
135
+ description="Resolve the output schema for a dbt model"
136
+ )
137
+ parser.add_argument("dbt_project_path", help="Path to dbt_project.yml")
138
+ parser.add_argument("model_path", help="Path to the model SQL file")
139
+ parser.add_argument("--default", default="PROD", help="Default schema (default: PROD)")
140
+ parser.add_argument("--no-prefix", action="store_true", help="Don't apply PROD_ prefix")
141
+
142
+ args = parser.parse_args()
143
+
144
+ dbt_project_path = Path(args.dbt_project_path)
145
+ model_path = Path(args.model_path)
146
+
147
+ if not dbt_project_path.exists():
148
+ print(f"Error: dbt_project.yml not found: {dbt_project_path}", file=sys.stderr)
149
+ sys.exit(1)
150
+
151
+ if not model_path.exists():
152
+ print(f"Error: Model file not found: {model_path}", file=sys.stderr)
153
+ sys.exit(1)
154
+
155
+ apply_prefix = not args.no_prefix
156
+ schema = resolve_schema(dbt_project_path, model_path, args.default, apply_prefix)
157
+ print(schema)
158
+
159
+
160
+ if __name__ == "__main__":
161
+ main()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-skills-collection",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "OpenCode CLI plugin that automatically downloads and keeps skills up to date.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",