opencode-skills-collection 2.0.0 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundled-skills/.antigravity-install-manifest.json +6 -1
- 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 +1 -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/usage.md +4 -4
- package/bundled-skills/docs/users/visual-guide.md +4 -4
- package/bundled-skills/manage-skills/SKILL.md +187 -0
- package/bundled-skills/monte-carlo-monitor-creation/SKILL.md +222 -0
- package/bundled-skills/monte-carlo-monitor-creation/references/comparison-monitor.md +426 -0
- package/bundled-skills/monte-carlo-monitor-creation/references/custom-sql-monitor.md +207 -0
- package/bundled-skills/monte-carlo-monitor-creation/references/metric-monitor.md +292 -0
- package/bundled-skills/monte-carlo-monitor-creation/references/table-monitor.md +231 -0
- package/bundled-skills/monte-carlo-monitor-creation/references/validation-monitor.md +404 -0
- package/bundled-skills/monte-carlo-prevent/SKILL.md +252 -0
- package/bundled-skills/monte-carlo-prevent/references/TROUBLESHOOTING.md +23 -0
- package/bundled-skills/monte-carlo-prevent/references/parameters.md +32 -0
- package/bundled-skills/monte-carlo-prevent/references/workflows.md +478 -0
- package/bundled-skills/monte-carlo-push-ingestion/SKILL.md +363 -0
- package/bundled-skills/monte-carlo-push-ingestion/references/anomaly-detection.md +87 -0
- package/bundled-skills/monte-carlo-push-ingestion/references/custom-lineage.md +203 -0
- package/bundled-skills/monte-carlo-push-ingestion/references/direct-http-api.md +207 -0
- package/bundled-skills/monte-carlo-push-ingestion/references/prerequisites.md +150 -0
- package/bundled-skills/monte-carlo-push-ingestion/references/push-lineage.md +160 -0
- package/bundled-skills/monte-carlo-push-ingestion/references/push-metadata.md +158 -0
- package/bundled-skills/monte-carlo-push-ingestion/references/push-query-logs.md +219 -0
- package/bundled-skills/monte-carlo-push-ingestion/references/validation.md +257 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/sample_verify.py +357 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_and_push_lineage.py +70 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_and_push_metadata.py +65 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_and_push_query_logs.py +70 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_lineage.py +214 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_metadata.py +160 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/collect_query_logs.py +164 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/push_lineage.py +198 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/push_metadata.py +193 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery/push_query_logs.py +207 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/collect_and_push_metadata.py +71 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/collect_and_push_query_logs.py +64 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/collect_metadata.py +253 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/collect_query_logs.py +149 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/push_metadata.py +190 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/bigquery-iceberg/push_query_logs.py +208 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_and_push_lineage.py +83 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_and_push_metadata.py +77 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_and_push_query_logs.py +83 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_lineage.py +240 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_metadata.py +212 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/collect_query_logs.py +204 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/push_lineage.py +192 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/push_metadata.py +178 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/databricks/push_query_logs.py +200 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_and_push_lineage.py +119 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_and_push_metadata.py +119 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_and_push_query_logs.py +117 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_lineage.py +265 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_metadata.py +313 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/collect_query_logs.py +284 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/push_lineage.py +309 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/push_metadata.py +245 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/hive/push_query_logs.py +255 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_and_push_lineage.py +78 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_and_push_metadata.py +80 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_and_push_query_logs.py +88 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_lineage.py +235 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_metadata.py +219 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/collect_query_logs.py +239 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/push_lineage.py +178 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/push_metadata.py +178 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/redshift/push_query_logs.py +196 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_and_push_lineage.py +154 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_and_push_metadata.py +137 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_and_push_query_logs.py +137 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_lineage.py +349 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_metadata.py +329 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/collect_query_logs.py +254 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/push_lineage.py +307 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/push_metadata.py +228 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/templates/snowflake/push_query_logs.py +248 -0
- package/bundled-skills/monte-carlo-push-ingestion/scripts/test_template_sdk_usage.py +340 -0
- package/bundled-skills/monte-carlo-validation-notebook/SKILL.md +685 -0
- package/bundled-skills/monte-carlo-validation-notebook/scripts/generate_notebook_url.py +141 -0
- package/bundled-skills/monte-carlo-validation-notebook/scripts/resolve_dbt_schema.py +161 -0
- package/package.json +1 -1
- 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