@tmdc-solutions/mcp-beta 0.1.8 → 0.1.9

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/dist/stdio.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
  "use strict"; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var _mcpjs = require('@modelcontextprotocol/sdk/server/mcp.js');var _stdiojs = require('@modelcontextprotocol/sdk/server/stdio.js');var _zod = require('zod'); var _zod2 = _interopRequireDefault(_zod);var _faker = require('@faker-js/faker');var _zodtojsonschema = require('zod-to-json-schema');var pt=_zod2.default.object({fields:_zod2.default.array(_zod2.default.object({fieldName:_zod2.default.string(),defaultValue:_zod2.default.string().or(_zod2.default.number()).optional(),unique:_zod2.default.boolean().optional(),prefix:_zod2.default.string().optional(),suffix:_zod2.default.string().optional(),fakerConfig:_zod2.default.object({module:_zod2.default.enum(Object.keys(_faker.faker)),method:_zod2.default.string(),options:_zod2.default.any().optional(),dependencies:_zod2.default.array(_zod2.default.object({optionName:_zod2.default.string(),fieldName:_zod2.default.string()}),{description:`This is to pass inter related fields to the faker method for producing value that is based on other fields.
3
3
  Make sure to pass the fields with dependencies as the last fields in the fields array.
4
4
  Example:
5
- If you want to generate email that is based on the first name and last name, you can pass the original fieldName of first name and last name fields as fieldName of dependencies and optionName as firstName and lastName.`}).optional()})}),{description:"The fields to generate"}),path:_zod2.default.string({description:"Absolute full path where file needs to be created. Always send full absolute path"}).default("~/tmp/mock-data/"),filename:_zod2.default.string().optional().default("mock-data.csv"),parentMapping:_zod2.default.array(_zod2.default.object({fieldName:_zod2.default.string(),parentFieldName:_zod2.default.string(),parentFieldValue:_zod2.default.string()})).optional().default([]),count:_zod2.default.number({description:"The number of items to generate"}).min(1).max(5e6).default(10)}),we=pt.extend({children:_zod2.default.lazy(()=>we.array()).optional().default([])}),ut={file:we,type:_zod2.default.enum(["csv","json","text"],{description:"The output type of the generated data"}).optional().default("csv"),append:_zod2.default.boolean().optional().default(!1),bufferSize:_zod2.default.number().optional().default(1e4),count:_zod2.default.number({description:"The number of items to generate"}).min(1).max(5e6).default(10)};function Se(i){i.tool("mock-data-pattern-schema","Schema for producing mock data patterns",{},()=>({isError:!1,content:[{type:"text",text:JSON.stringify(_zodtojsonschema.zodToJsonSchema.call(void 0, _zod2.default.object(ut)),null,2)}]}))}var _yaml = require('yaml');var _fs = require('fs');var _path = require('path'); var _path2 = _interopRequireDefault(_path);var yt=`Depot in DataOS is a Resource used to connect different data sources to DataOS by abstracting the complexities associated with the underlying source system (including protocols, credentials, and connection schemas).
5
+ If you want to generate email that is based on the first name and last name, you can pass the original fieldName of first name and last name fields as fieldName of dependencies and optionName as firstName and lastName.`}).optional()})}),{description:"The fields to generate"}),path:_zod2.default.string({description:"Absolute full path where file needs to be created. Always send full absolute path"}).default("~/tmp/mock-data/"),filename:_zod2.default.string().optional().default("mock-data.csv"),parentMapping:_zod2.default.array(_zod2.default.object({fieldName:_zod2.default.string(),parentFieldName:_zod2.default.string(),parentFieldValue:_zod2.default.string()})).optional().default([]),count:_zod2.default.number({description:"The number of items to generate"}).min(1).max(5e6).default(10)}),we=pt.extend({children:_zod2.default.lazy(()=>we.array()).optional().default([])}),ut={file:we,type:_zod2.default.enum(["csv","json","text"],{description:"The output type of the generated data"}).optional().default("csv"),append:_zod2.default.boolean().optional().default(!1),bufferSize:_zod2.default.number().optional().default(1e4),count:_zod2.default.number({description:"The number of items to generate"}).min(1).max(5e6).default(10)};function Se(i){i.tool("mock-data-pattern-schema","Schema for producing mock data patterns",{},()=>({isError:!1,content:[{type:"text",text:JSON.stringify(_zodtojsonschema.zodToJsonSchema.call(void 0, _zod2.default.object(ut)),null,2)}]}))}var _yaml = require('yaml');var _fs = require('fs'); var _fs2 = _interopRequireDefault(_fs);var _path = require('path'); var _path2 = _interopRequireDefault(_path);var yt=`Depot in DataOS is a Resource used to connect different data sources to DataOS by abstracting the complexities associated with the underlying source system (including protocols, credentials, and connection schemas).
6
6
  It enables users to establish connections and retrieve data from various data sources, such as file systems (e.g., AWS S3, Google GCS, Azure Blob Storage), data lake systems, database systems (e.g., Redshift, SnowflakeDB, Bigquery, Postgres), and event systems (e.g., Kafka, Pulsar) without moving the data.
7
7
  `,bt=_zod.z.object({acl:_zod.z.enum(["r","rw"],{description:"Access control level - 'r' for read-only, 'rw' for read-write"}),type:_zod.z.literal("key-value-properties").describe("Type of secret storage"),data:_zod.z.record(_zod.z.string(),_zod.z.string(),{description:"Key-value pairs for authentication credentials (e.g., username, password, access keys)"}),files:_zod.z.record(_zod.z.string(),_zod.z.string(),{description:"File paths for credential files (e.g., JSON key files for GCP)"}).optional()}),vt={description:_zod.z.string({description:"Human-readable description of the depot"}),external:_zod.z.boolean({description:"Whether the depot connects to an external data source"}).default(!0),connectionSecret:_zod.z.array(bt).optional()},wt=i=>{let{type:c,spec:e,s3:n,abfss:d,wasbs:t,redshift:S,elasticsearch:v,opensearch:E,eventhub:y,pulsar:g,bigquery:m,gcs:l,kafka:w,mongodb:s,mysql:b,oracle:u,postgresql:h,snowflake:f,mssql:p}=i;switch(c){case"JDBC":if(!e)return"Error: 'JDBC' type requires 'spec' property with subprotocol, host, port, and database.";if(n||d||t||S||v||E||y||g||m||l||w||s||b||u||h||f||p)return"Error: 'JDBC' type should only have 'spec' property, not other configuration properties.";break;case"S3":if(!n)return"Error: 'S3' type requires 's3' property with scheme, bucket, and relativePath.";if(e||d||t||S||v||E||y||g||m||l||w||s||b||u||h||f||p)return"Error: 'S3' type should only have 's3' property, not other configuration properties.";break;case"ABFSS":if(!d)return"Error: 'ABFSS' type requires 'abfss' property with account, container, and relativePath.";if(e||n||t||S||v||E||y||g||m||l||w||s||b||u||h||f||p)return"Error: 'ABFSS' type should only have 'abfss' property, not other configuration properties.";break;case"WASBS":if(!t)return"Error: 'WASBS' type requires 'wasbs' property with account, container, and relativePath.";if(e||n||d||S||v||E||y||g||m||l||w||s||b||u||h||f||p)return"Error: 'WASBS' type should only have 'wasbs' property, not other configuration properties.";break;case"REDSHIFT":if(!S)return"Error: 'REDSHIFT' type requires 'redshift' property with host, database, bucket, and relativePath.";if(e||n||d||t||v||E||y||g||m||l||w||s||b||u||h||f||p)return"Error: 'REDSHIFT' type should only have 'redshift' property, not other configuration properties.";break;case"ELASTICSEARCH":if(!v)return"Error: 'ELASTICSEARCH' type requires 'elasticsearch' property with nodes.";if(e||n||d||t||S||E||y||g||m||l||w||s||b||u||h||f||p)return"Error: 'ELASTICSEARCH' type should only have 'elasticsearch' property, not other configuration properties.";break;case"OPENSEARCH":if(!E)return"Error: 'OPENSEARCH' type requires 'opensearch' property with nodes.";if(e||n||d||t||S||v||y||g||m||l||w||s||b||u||h||f||p)return"Error: 'OPENSEARCH' type should only have 'opensearch' property, not other configuration properties.";break;case"EVENTHUB":if(!y)return"Error: 'EVENTHUB' type requires 'eventhub' property with endpoint.";if(e||n||d||t||S||v||E||g||m||l||w||s||b||u||h||f||p)return"Error: 'EVENTHUB' type should only have 'eventhub' property, not other configuration properties.";break;case"PULSAR":if(!g)return"Error: 'PULSAR' type requires 'pulsar' property with adminUrl and serviceUrl.";if(e||n||d||t||S||v||E||y||m||l||w||s||b||u||h||f||p)return"Error: 'PULSAR' type should only have 'pulsar' property, not other configuration properties.";break;case"BIGQUERY":if(!m)return"Error: 'BIGQUERY' type requires 'bigquery' property with project.";if(e||n||d||t||S||v||E||y||g||l||w||s||b||u||h||f||p)return"Error: 'BIGQUERY' type should only have 'bigquery' property, not other configuration properties.";break;case"GCS":if(!l)return"Error: 'GCS' type requires 'gcs' property with bucket and relativePath.";if(e||n||d||t||S||v||E||y||g||m||w||s||b||u||h||f||p)return"Error: 'GCS' type should only have 'gcs' property, not other configuration properties.";break;case"KAFKA":if(!w)return"Error: 'KAFKA' type requires 'kafka' property with brokers.";if(e||n||d||t||S||v||E||y||g||m||l||s||b||u||h||f||p)return"Error: 'KAFKA' type should only have 'kafka' property, not other configuration properties.";break;case"MONGODB":if(!s)return"Error: 'MONGODB' type requires 'mongodb' property with subprotocol and nodes.";if(e||n||d||t||S||v||E||y||g||m||l||w||b||u||h||f||p)return"Error: 'MONGODB' type should only have 'mongodb' property, not other configuration properties.";break;case"MYSQL":if(!b)return"Error: 'MYSQL' type requires 'mysql' property with host and port.";if(e||n||d||t||S||v||E||y||g||m||l||w||s||u||h||f||p)return"Error: 'MYSQL' type should only have 'mysql' property, not other configuration properties.";break;case"ORACLE":if(!u)return"Error: 'ORACLE' type requires 'oracle' property with subprotocol, host, port, and service.";if(e||n||d||t||S||v||E||y||g||m||l||w||s||b||h||f||p)return"Error: 'ORACLE' type should only have 'oracle' property, not other configuration properties.";break;case"POSTGRESQL":if(!h)return"Error: 'POSTGRESQL' type requires 'postgresql' property with host, port, and database.";if(e||n||d||t||S||v||E||y||g||m||l||w||s||b||u||f||p)return"Error: 'POSTGRESQL' type should only have 'postgresql' property, not other configuration properties.";break;case"SNOWFLAKE":if(!f)return"Error: 'SNOWFLAKE' type requires 'snowflake' property with warehouse, url, and database.";if(e||n||d||t||S||v||E||y||g||m||l||w||s||b||u||h||p)return"Error: 'SNOWFLAKE' type should only have 'snowflake' property, not other configuration properties.";break;case"MSSQL":if(!p)return"Error: 'MSSQL' type requires 'mssql' property with host, port, and database.";if(e||n||d||t||S||v||E||y||g||m||l||w||s||b||u||h||f)return"Error: 'MSSQL' type should only have 'mssql' property, not other configuration properties.";break;default:return`Error: Invalid depot type '${c}'. Supported types are: JDBC, S3, ABFSS, WASBS, REDSHIFT, ELASTICSEARCH, OPENSEARCH, EVENTHUB, PULSAR, BIGQUERY, GCS, KAFKA, MONGODB, MYSQL, ORACLE, POSTGRESQL, SNOWFLAKE, MSSQL.`}return null},St=_zod.z.array(_zod.z.object({name:_zod.z.string({description:"Depot name - alphanumeric with hyphens, max 48 chars, pattern: [a-z0-9]([-a-z0-9]*[a-z0-9])"}),tags:_zod.z.array(_zod.z.string(),{description:"Tags for categorizing and organizing the depot"}),secrets:_zod.z.array(_zod.z.object({name:_zod.z.string({description:"Reference name for the secret"}),keys:_zod.z.array(_zod.z.string(),{description:"Specific keys to extract from the secret"}).optional(),allkeys:_zod.z.boolean({description:"Whether to use all keys from the secret"})})).optional(),owner:_zod.z.string({description:"Owner of the depot resource"}).optional(),compute:_zod.z.string({description:"Compute resource for the depot (default: runnable-default)"}).optional(),depot:_zod.z.object({type:_zod.z.enum(["JDBC","S3","ABFSS","WASBS","REDSHIFT","ELASTICSEARCH","OPENSEARCH","EVENTHUB","PULSAR","BIGQUERY","GCS","KAFKA","MONGODB","MYSQL","ORACLE","POSTGRESQL","SNOWFLAKE","MSSQL"],{description:"Type of depot connection"}),spec:_zod.z.object({subprotocol:_zod.z.string({description:"JDBC subprotocol (e.g., 'postgresql', 'mysql', 'sqlserver', 'oracle:thin')"}),host:_zod.z.string({description:"Database server hostname or IP address"}),port:_zod.z.number({description:"Database server port number"}),database:_zod.z.string({description:"Database name to connect to"}),params:_zod.z.record(_zod.z.string(),_zod.z.any(),{description:"Additional connection parameters (e.g., SSL settings)"}).optional()}).optional(),s3:_zod.z.object({scheme:_zod.z.enum(["s3a","s3"],{description:"S3 protocol scheme"}),bucket:_zod.z.string({description:"S3 bucket name"}),relativePath:_zod.z.string({description:"Path within the bucket"}),format:_zod.z.string({description:"Data format (e.g., 'ICEBERG', 'PARQUET', 'JSON', 'CSV')"}).optional()}).optional(),abfss:_zod.z.object({account:_zod.z.string({description:"Azure storage account name"}),container:_zod.z.string({description:"Container name within the storage account"}),relativePath:_zod.z.string({description:"Path within the container"}),format:_zod.z.string({description:"Data format (e.g., 'PARQUET', 'JSON', 'CSV')"}).optional()}).optional(),wasbs:_zod.z.object({account:_zod.z.string({description:"Azure storage account name"}),container:_zod.z.string({description:"Container name within the storage account"}),relativePath:_zod.z.string({description:"Path within the container"}),format:_zod.z.string({description:"Data format (e.g., 'PARQUET', 'JSON', 'CSV')"}).optional()}).optional(),redshift:_zod.z.object({host:_zod.z.string({description:"Redshift cluster endpoint"}),subprotocol:_zod.z.string({description:"JDBC subprotocol for Redshift"}).optional(),port:_zod.z.number({description:"Redshift port (default: 5439)"}).default(5439),database:_zod.z.string({description:"Redshift database name"}),bucket:_zod.z.string({description:"S3 bucket for data staging"}),relativePath:_zod.z.string({description:"Path within the S3 bucket"})}).optional(),elasticsearch:_zod.z.object({nodes:_zod.z.array(_zod.z.string(),{description:"List of Elasticsearch nodes (format: 'host:port')"})}).optional(),opensearch:_zod.z.object({nodes:_zod.z.array(_zod.z.string(),{description:"List of OpenSearch nodes (format: 'host:port')"})}).optional(),eventhub:_zod.z.object({endpoint:_zod.z.string({description:"Event Hub namespace endpoint (format: 'sb://namespace.servicebus.windows.net/')"})}).optional(),pulsar:_zod.z.object({adminUrl:_zod.z.string({description:"Pulsar admin API URL"}),serviceUrl:_zod.z.string({description:"Pulsar broker service URL"}),tenant:_zod.z.string({description:"Pulsar tenant name"}).optional()}).optional(),bigquery:_zod.z.object({project:_zod.z.string({description:"Google Cloud project ID"}),params:_zod.z.record(_zod.z.string(),_zod.z.any(),{description:"Additional BigQuery connection parameters"}).optional()}).optional(),gcs:_zod.z.object({bucket:_zod.z.string({description:"GCS bucket name"}),relativePath:_zod.z.string({description:"Path within the bucket"})}).optional(),kafka:_zod.z.object({brokers:_zod.z.array(_zod.z.string(),{description:"List of Kafka broker addresses"}),schemaRegistryUrl:_zod.z.string({description:"Schema Registry URL for Avro/JSON schemas"}).optional()}).optional(),mongodb:_zod.z.object({subprotocol:_zod.z.string({description:"MongoDB connection protocol (e.g., 'mongodb+srv')"}),nodes:_zod.z.array(_zod.z.string(),{description:"MongoDB cluster nodes"})}).optional(),mysql:_zod.z.object({host:_zod.z.string({description:"MySQL server hostname"}),port:_zod.z.number({description:"MySQL server port (default: 3306)"}).default(3306),database:_zod.z.string({description:"MySQL database name"}).optional(),params:_zod.z.record(_zod.z.string(),_zod.z.any(),{description:"Additional connection parameters (e.g., SSL settings)"}).optional()}).optional(),oracle:_zod.z.object({subprotocol:_zod.z.string({description:"Oracle JDBC subprotocol (e.g., 'oracle:thin')"}),host:_zod.z.string({description:"Oracle server hostname"}),port:_zod.z.number({description:"Oracle server port (default: 1521)"}).default(1521),service:_zod.z.string({description:"Oracle service name"})}).optional(),postgresql:_zod.z.object({host:_zod.z.string({description:"PostgreSQL server hostname"}),port:_zod.z.number({description:"PostgreSQL server port (default: 5432)"}).default(5432),database:_zod.z.string({description:"PostgreSQL database name"}),params:_zod.z.record(_zod.z.string(),_zod.z.any(),{description:"Additional connection parameters (e.g., sslmode)"}).optional()}).optional(),snowflake:_zod.z.object({warehouse:_zod.z.string({description:"Snowflake warehouse name"}),url:_zod.z.string({description:"Snowflake account URL"}),database:_zod.z.string({description:"Snowflake database name"})}).optional(),mssql:_zod.z.object({host:_zod.z.string({description:"SQL Server hostname"}),port:_zod.z.number({description:"SQL Server port (default: 1433)"}).default(1433),database:_zod.z.string({description:"SQL Server database name"}),params:_zod.z.record(_zod.z.string(),_zod.z.any(),{description:"Additional connection parameters (e.g., encrypt)"}).optional()}).optional()}),...vt,source:_zod.z.string({description:"Maps the depot to the metadata source name in Metis. Running a scanner job on this depot will save the metadata in Metis DB under the specified 'source' name. If this key-value property is not mentioned, the metadata will surface under the depot name on Metis UI."}).optional(),path:_zod.z.string({description:"Absolute path where the file will be stored. example: ~/Documents/project-name/my-depot.yaml"}),fileName:_zod.z.string({description:"File name for the depot file. example: my-depot.yaml"})}),{description:"Array of depot sources to create. Use this tool to create multiple depot sources at once."}).nonempty(),Ee=i=>{i.tool("create-depot-source",yt,{depots:St},async({depots:c})=>{let e=[];for(let n of c){let{name:d,tags:t,depot:S,owner:v,compute:E,source:y,description:g,external:m,connectionSecret:l,path:w,fileName:s}=n,b=wt(S);if(b)return{content:[{type:"text",text:b}]};let u=_yaml.stringify.call(void 0, {name:d,tags:t,type:"depot",version:"v2alpha",layer:"user",...v&&{owner:v},...E&&{compute:E},...y&&{source:y},description:g,external:m,...l&&{connectionSecret:l},depot:S});try{let h=w.includes(".yaml")||w.includes(".yml")?w:w.endsWith("/")?w+s:`${w}/${s}`,f=_path2.default.dirname(h);_fs.existsSync.call(void 0, f)||_fs.mkdirSync.call(void 0, f,{recursive:!0}),_fs.writeFileSync.call(void 0, h,u),e.push({type:"text",text:`Depot source created successfully at ${h}`}),e.push({type:"text",text:`File content: ${u}`})}catch(h){e.push({type:"text",text:`Error creating depot source: ${h}`})}}return{content:e.flat()}})};var Tt=`Flare Workflow in DataOS is a declarative stack for large-scale data processing using Apache Spark. It provides comprehensive solutions for data ingestion, transformation, enrichment, profiling, quality assessment, and syndication on both batch and incremental data.
8
8
 
@@ -62,7 +62,7 @@ Examples:
62
62
  - Basic checks: row_count between 100 and 1000, missing_count(email) = 0
63
63
  - Advanced checks: values in (city) must exist in cities (name), freshness(updated_at) < 1d
64
64
  - Schema validation: required columns, data types, forbidden columns
65
- `,me=_zod.z.object({title:_zod.z.string({description:"Human-readable title for the check (e.g., 'Customer ID Completeness Check')"}).optional(),category:_zod.z.enum(["Accuracy","Completeness","Consistency","Freshness","Schema","Uniqueness","Validity"],{description:"Category of the data quality check for organization and reporting"}),description:_zod.z.string({description:"Detailed description of what the check validates"}).optional(),tags:_zod.z.array(_zod.z.string(),{description:"Tags for organizing and filtering checks (e.g., ['critical', 'pii', 'financial'])"}).optional()}).describe("Metadata attributes for organizing and documenting quality checks"),fr=_zod.z.object({limit:_zod.z.number({description:"Maximum number of failed row samples to collect for analysis (default: 100)"}).min(1).max(1e3).default(100)}).optional().describe("Configuration for collecting failed row samples for debugging"),gr=_zod.z.object({"valid format":_zod.z.enum(["email","phone number","credit card","uuid","date","url"],{description:"Built-in format validation (e.g., 'email', 'phone number')"}).optional(),"valid regex":_zod.z.string({description:"Custom regex pattern for validation (e.g., '^[A-Z]{2}[0-9]{4}$' for postal codes)"}).optional(),"valid min":_zod.z.number({description:"Minimum valid value for numeric columns"}).optional(),"valid max":_zod.z.number({description:"Maximum valid value for numeric columns"}).optional(),"valid min length":_zod.z.number({description:"Minimum valid length for string columns"}).optional(),"valid max length":_zod.z.number({description:"Maximum valid length for string columns"}).optional(),"valid values":_zod.z.array(_zod.z.union([_zod.z.string(),_zod.z.number()]),{description:"List of valid values (e.g., ['active', 'inactive', 'pending'])"}).optional()}).describe("Validation rules for validity checks"),As=_zod.z.object({name:_zod.z.string({description:"Name identifier for the schema check"}).optional(),warn:_zod.z.object({"when required column missing":_zod.z.array(_zod.z.string(),{description:"Columns that should trigger warnings if missing"}).optional(),"when forbidden column present":_zod.z.array(_zod.z.string(),{description:"Columns that should trigger warnings if present (e.g., ['temp_*', 'old_*'])"}).optional(),"when wrong column type":_zod.z.record(_zod.z.string(),_zod.z.string(),{description:"Expected column types that should trigger warnings if wrong (e.g., {'age': 'integer'})"}).optional(),"when wrong column index":_zod.z.record(_zod.z.string(),_zod.z.number(),{description:"Expected column positions that should trigger warnings if wrong"}).optional()}).optional(),fail:_zod.z.object({"when required column missing":_zod.z.array(_zod.z.string(),{description:"Columns that should trigger failures if missing"}).optional(),"when forbidden column present":_zod.z.array(_zod.z.string(),{description:"Columns that should trigger failures if present (sensitive data)"}).optional(),"when wrong column type":_zod.z.record(_zod.z.string(),_zod.z.string(),{description:"Expected column types that should trigger failures if wrong"}).optional(),"when wrong column index":_zod.z.record(_zod.z.string(),_zod.z.number(),{description:"Expected column positions that should trigger failures if wrong"}).optional()}).optional(),attributes:me}).describe("Schema validation check configuration with warn/fail conditions"),Ts=_zod.z.object({name:_zod.z.string({description:"Custom name for the check (overrides default naming)"}).optional(),filter:_zod.z.string({description:`SQL WHERE clause to filter data for this specific check (e.g., 'status = "active"')`}).optional(),attributes:me}),hr=i=>{let{checkType:c,column:e,operator:n,value:d,compareDataset:t,samples:S,name:v,filter:E,attributes:y,missingValues:g,missingRegex:m,validationRules:l,function:w,percentile:s,lengthType:b,sourceColumn:u,referenceDataset:h,referenceColumn:f,checkPattern:p,warn:k,fail:N,failCondition:P,failQuery:_}=i;if(!c)return"Error: 'checkType' is required for all quality checks.";switch(c){case"row_count":if(!n)return"Error: 'row_count' check requires 'operator' property.";if(d===void 0)return"Error: 'row_count' check requires 'value' property.";if(e||g||m||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'row_count' check should only have 'operator', 'value', 'compareDataset', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"missing_count":if(!e)return"Error: 'missing_count' check requires 'column' property.";if(!n)return"Error: 'missing_count' check requires 'operator' property.";if(d===void 0)return"Error: 'missing_count' check requires 'value' property.";if(t||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'missing_count' check should only have 'column', 'operator', 'value', 'missingValues', 'missingRegex', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"missing_percent":if(!e)return"Error: 'missing_percent' check requires 'column' property.";if(!n)return"Error: 'missing_percent' check requires 'operator' property.";if(d===void 0)return"Error: 'missing_percent' check requires 'value' property.";if(t||g||m||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'missing_percent' check should only have 'column', 'operator', 'value', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"duplicate_count":if(!e)return"Error: 'duplicate_count' check requires 'column' property.";if(!n)return"Error: 'duplicate_count' check requires 'operator' property.";if(d===void 0)return"Error: 'duplicate_count' check requires 'value' property.";if(t||g||m||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'duplicate_count' check should only have 'column', 'operator', 'value', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"duplicate_percent":if(!e)return"Error: 'duplicate_percent' check requires 'column' property.";if(!n)return"Error: 'duplicate_percent' check requires 'operator' property.";if(d===void 0)return"Error: 'duplicate_percent' check requires 'value' property.";if(t||g||m||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'duplicate_percent' check should only have 'column', 'operator', 'value', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"invalid_count":if(!e)return"Error: 'invalid_count' check requires 'column' property.";if(!n)return"Error: 'invalid_count' check requires 'operator' property.";if(d===void 0)return"Error: 'invalid_count' check requires 'value' property.";if(!l)return"Error: 'invalid_count' check requires 'validationRules' property.";if(t||g||m||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'invalid_count' check should only have 'column', 'operator', 'value', 'validationRules', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"invalid_percent":if(!e)return"Error: 'invalid_percent' check requires 'column' property.";if(!n)return"Error: 'invalid_percent' check requires 'operator' property.";if(d===void 0)return"Error: 'invalid_percent' check requires 'value' property.";if(!l)return"Error: 'invalid_percent' check requires 'validationRules' property.";if(t||g||m||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'invalid_percent' check should only have 'column', 'operator', 'value', 'validationRules', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"freshness":if(!e)return"Error: 'freshness' check requires 'column' property.";if(!n)return"Error: 'freshness' check requires 'operator' property.";if(!d)return"Error: 'freshness' check requires 'value' property.";if(t||g||m||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'freshness' check should only have 'column', 'operator', 'value', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"aggregation":if(!w)return"Error: 'aggregation' check requires 'function' property.";if(!e)return"Error: 'aggregation' check requires 'column' property.";if(!n)return"Error: 'aggregation' check requires 'operator' property.";if(d===void 0)return"Error: 'aggregation' check requires 'value' property.";if(t||g||m||l||b||u||h||f||p||k||N||P||_)return"Error: 'aggregation' check should only have 'function', 'column', 'operator', 'value', 'percentile', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"length":if(!b)return"Error: 'length' check requires 'lengthType' property.";if(!e)return"Error: 'length' check requires 'column' property.";if(!n)return"Error: 'length' check requires 'operator' property.";if(d===void 0)return"Error: 'length' check requires 'value' property.";if(t||g||m||l||w||s||u||h||f||p||k||N||P||_)return"Error: 'length' check should only have 'lengthType', 'column', 'operator', 'value', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"reference":if(!u)return"Error: 'reference' check requires 'sourceColumn' property.";if(!h)return"Error: 'reference' check requires 'referenceDataset' property.";if(!f)return"Error: 'reference' check requires 'referenceColumn' property.";if(!p)return"Error: 'reference' check requires 'checkPattern' property.";if(e||n||d||t||g||m||l||w||s||b||k||N||P||_)return"Error: 'reference' check should only have 'sourceColumn', 'referenceDataset', 'referenceColumn', 'checkPattern', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"schema":if(e||n||d||t||g||m||l||w||s||b||u||h||f||p||P||_)return"Error: 'schema' check should only have 'warn', 'fail', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"failed_rows":if(!P&&!_)return"Error: 'failed_rows' check requires either 'failCondition' or 'failQuery' property.";if(e||n||d||t||g||m||l||w||s||b||u||h||f||p||k||N)return"Error: 'failed_rows' check should only have 'failCondition', 'failQuery', 'samples', 'name', 'filter', and 'attributes' properties.";break;default:return`Error: Invalid soda check type '${c}'. Supported types are: row_count, missing_count, missing_percent, duplicate_count, duplicate_percent, invalid_count, invalid_percent, freshness, aggregation, length, reference, schema, failed_rows.`}return null},yr=_zod.z.object({checkType:_zod.z.enum(["row_count","missing_count","missing_percent","duplicate_count","duplicate_percent","invalid_count","invalid_percent","freshness","aggregation","length","reference","schema","failed_rows"],{description:"Type of data quality check to perform"}),name:_zod.z.string({description:"Custom name for the check (overrides default naming)"}).optional(),filter:_zod.z.string({description:`SQL WHERE clause to filter data for this specific check (e.g., 'status = "active"')`}).optional(),attributes:me,samples:fr,compareDataset:_zod.z.string({description:"Reference dataset for comparison (e.g., 'same as reference_table')"}).optional(),column:_zod.z.string({description:"Column name for checks that operate on specific columns"}).optional(),operator:_zod.z.enum(["=","!=",">",">=","<","<=","between"],{description:"Comparison operator for the check"}).optional(),value:_zod.z.union([_zod.z.number(),_zod.z.string()],{description:"Expected value or range for the check"}).optional(),missingValues:_zod.z.array(_zod.z.union([_zod.z.string(),_zod.z.null()]),{description:"Custom missing value indicators (e.g., ['NA', 'n/a', '', null])"}).optional(),missingRegex:_zod.z.string({description:"Regex pattern to identify missing values"}).optional(),validationRules:gr.optional(),function:_zod.z.enum(["min","max","avg","sum","stddev","variance","percentile"],{description:"Aggregation function to apply"}).optional(),percentile:_zod.z.number({description:"Percentile value (0-1) for percentile function"}).min(0).max(1).optional(),lengthType:_zod.z.enum(["min_length","max_length","avg_length"],{description:"Type of length check to perform"}).optional(),sourceColumn:_zod.z.string({description:"Column in current dataset"}).optional(),referenceDataset:_zod.z.string({description:"Reference dataset name (e.g., 'reference_table')"}).optional(),referenceColumn:_zod.z.string({description:"Column in reference dataset"}).optional(),checkPattern:_zod.z.enum(["must exist in","must not exist in"],{description:"Type of reference validation"}).optional(),warn:_zod.z.object({"when required column missing":_zod.z.array(_zod.z.string(),{description:"Columns that should trigger warnings if missing"}).optional(),"when forbidden column present":_zod.z.array(_zod.z.string(),{description:"Columns that should trigger warnings if present (e.g., ['temp_*', 'old_*'])"}).optional(),"when wrong column type":_zod.z.record(_zod.z.string(),_zod.z.string(),{description:"Expected column types that should trigger warnings if wrong (e.g., {'age': 'integer'})"}).optional(),"when wrong column index":_zod.z.record(_zod.z.string(),_zod.z.number(),{description:"Expected column positions that should trigger warnings if wrong"}).optional()}).optional(),fail:_zod.z.object({"when required column missing":_zod.z.array(_zod.z.string(),{description:"Columns that should trigger failures if missing"}).optional(),"when forbidden column present":_zod.z.array(_zod.z.string(),{description:"Columns that should trigger failures if present (sensitive data)"}).optional(),"when wrong column type":_zod.z.record(_zod.z.string(),_zod.z.string(),{description:"Expected column types that should trigger failures if wrong"}).optional(),"when wrong column index":_zod.z.record(_zod.z.string(),_zod.z.number(),{description:"Expected column positions that should trigger failures if wrong"}).optional()}).optional(),failCondition:_zod.z.string({description:"SQL condition for identifying failed rows (e.g., 'age < 0 OR age > 150')"}).optional(),failQuery:_zod.z.string({description:"Custom SQL query for complex failed row detection"}).optional()}).describe("Comprehensive Soda quality check with typed validation"),br=_zod.z.object({columns:_zod.z.array(_zod.z.string(),{description:"Column specifications for profiling: exact names, wildcards (*), includes/excludes (e.g., ['customer_id', 'include address_*', 'exclude temp_*', '*'])"})}).optional().describe("Data profiling configuration for statistical analysis"),vr=_zod.z.object({name:_zod.z.string({description:"Identifier name for the filter"}),where:_zod.z.string({description:`SQL WHERE clause for global filtering across all checks (e.g., 'status = "active" AND created_date > "2023-01-01"')`})}).optional().describe("Global filter applied to all checks on this dataset"),wr=_zod.z.object({engine:_zod.z.enum(["minerva","default"],{description:"Query engine: 'minerva' for Trino-based queries, 'default' for native engine"}).default("default"),clusterName:_zod.z.string({description:"Cluster name for Minerva engine (required when engine is 'minerva')"}).optional(),branchName:_zod.z.string({description:"Branch name for Iceberg datasets (defaults to 'main')"}).default("main").optional()}).optional().describe("Engine and execution options for quality checks"),Sr=_zod.z.object({dataset:_zod.z.string({description:"Dataset specification using DataOS UDL format: dataos://[depot]:[collection]/[dataset] (e.g., 'dataos://icebase:retail/customer')"}),options:wr,filter:vr,profile:br,checks:_zod.z.array(yr,{description:"List of data quality checks to execute on this dataset"})}).describe("Complete dataset configuration with quality checks and profiling"),Er=_zod.z.object({requests:_zod.z.object({cpu:_zod.z.string({description:"CPU resource request (e.g., '500m', '1', '2000m')"}).default("1000m"),memory:_zod.z.string({description:"Memory resource request (e.g., '512Mi', '1Gi', '250Mi')"}).default("250Mi")}),limits:_zod.z.object({cpu:_zod.z.string({description:"CPU resource limit (e.g., '1', '2', '4000m')"}).optional(),memory:_zod.z.string({description:"Memory resource limit (e.g., '1Gi', '2Gi', '500Mi')"}).optional()}).optional()}).optional().describe("Resource allocation for quality check execution"),kr=_zod.z.object({cron:_zod.z.string({description:"Cron expression for scheduling (e.g., '0 2 * * *' for daily at 2 AM, '0 */6 * * *' for every 6 hours)"}),concurrencyPolicy:_zod.z.enum(["Allow","Forbid","Replace"],{description:"Policy for handling concurrent executions"}).default("Allow"),endOn:_zod.z.string({description:"End date for scheduled executions in ISO 8601 format"}).optional(),timezone:_zod.z.string({description:"Timezone for schedule execution (e.g., 'UTC', 'Asia/Kolkata')"}).default("UTC")}).optional().describe("Schedule configuration for recurring quality checks"),xr={name:_zod.z.string({description:"Quality workflow name - alphanumeric with hyphens, max 48 chars"}),tags:_zod.z.array(_zod.z.string(),{description:"Tags for categorizing and organizing the quality workflow"}),description:_zod.z.string({description:"Human-readable description of the quality checks and purpose"}),owner:_zod.z.string({description:"Owner of the quality workflow resource"}).optional(),workspace:_zod.z.string({description:"Workspace where the quality workflow will be deployed"}).default("public")},_r=_zod.z.array(_zod.z.object({...xr,schedule:kr,jobName:_zod.z.string({description:"Name of the quality job within the workflow"}),jobTitle:_zod.z.string({description:"Human-readable title for the job"}).optional(),jobDescription:_zod.z.string({description:"Description of the quality job"}).optional(),jobTags:_zod.z.array(_zod.z.string(),{description:"Tags specific to this quality job"}).optional(),compute:_zod.z.string({description:"Compute resource for the job"}).default("runnable-default"),runAsUser:_zod.z.string({description:"User to run the quality job as"}).optional(),stack:_zod.z.enum(["soda+python:1.0"],{description:"Soda stack version with Python flavor"}).default("soda+python:1.0"),logLevel:_zod.z.enum(["DEBUG","INFO","WARNING","ERROR"],{description:"Logging level for the quality job"}).default("INFO"),resources:Er,inputs:_zod.z.array(Sr,{description:"List of datasets and their associated quality checks"}),path:_zod.z.string({description:"Absolute path where the file will be stored. example: ~/Documents/project-name/my-quality.yaml"}),fileName:_zod.z.string({description:"File name for the quality workflow file. example: my-quality.yaml"})}),{description:"Array of quality workflows to create. Use this tool to create multiple quality workflows at once."}).nonempty(),Ae=i=>{i.tool("create-quality-workflow",mr,{workflows:_r},async({workflows:c})=>{let e=[];for(let n of c){let{name:d,tags:t,description:S,owner:v,workspace:E,schedule:y,jobName:g,jobTitle:m,jobDescription:l,jobTags:w,compute:s,runAsUser:b,stack:u,logLevel:h,resources:f,inputs:p,path:k,fileName:N}=n;for(let M of p)for(let O of M.checks){let G=hr(O);if(G)return{content:[{type:"text",text:G}]}}let P=[{name:g,...m&&{title:m},...l&&{description:l},...w&&{tags:w},spec:{stack:u,compute:s,...b&&{runAsUser:b},...f&&{resources:f},logLevel:h,stackSpec:{inputs:p}}}],_=_yaml.stringify.call(void 0, {name:d,tags:t,type:"workflow",version:"v1",...v&&{owner:v},workspace:E,description:S,...y&&{schedule:y},dag:P});try{let M=k.includes(".yaml")||k.includes(".yml")?k:k.endsWith("/")?k+N:`${k}/${N}`,O=_path2.default.dirname(M);_fs.existsSync.call(void 0, O)||_fs.mkdirSync.call(void 0, O,{recursive:!0}),_fs.writeFileSync.call(void 0, M,_),e.push({type:"text",text:`Quality workflow created successfully at ${M}`}),e.push({type:"text",text:`File content: ${_}`})}catch(M){e.push({type:"text",text:`Error creating quality workflow: ${M}`})}}return{content:e.flat()}})};var _https = require('https'); var _https2 = _interopRequireDefault(_https);var Tr=4;function J(i,c,e,n=!1,d=0){return new Promise((t,S)=>{let v=_https2.default.request(i,c,E=>{let y="";E.on("data",g=>y+=g),E.on("end",()=>{n&&d<Tr&&y.includes("Continue wait")?setTimeout(()=>{J(i,c,e,n,d+1).then(t).catch(S)},1e3):t({status:E.statusCode||500,data:y})})});v.on("error",S),e&&v.write(e),v.end()})}var _dotenv = require('dotenv');_dotenv.config.call(void 0, );var te="",le=process.env.SLUG||"bmx";function Te(i,c=","){return Array.isArray(i)?i.filter(e=>e!=null).map(e=>typeof e=="string"?e:JSON.stringify(e)).join(c):""}function W(i){return i===!0||i==="true"||i===1||i==="1"}function pe(i){return i==null?"":typeof i=="string"?i:typeof i=="number"||typeof i=="boolean"?String(i):JSON.stringify(i)}function U(i){let c=pe(i);return c===""?c:c.includes("|")||c.includes(",")||c.includes('"')?`"${c.replace(/"/g,'"')}"`:c}function Le(i){return Array.isArray(i)?i.map(c=>`"${pe(c)}"`).join(","):""}function se(...i){for(let c of i)if(c!==void 0)return c}function Ce(i,c){let e=i.name||i.slug||c||"",n=i.fullyQualifiedName||e||c||"",d=i.description||"",t=_optionalChain([i, 'access', _2 => _2.owner, 'optionalAccess', _3 => _3.name])||_optionalChain([i, 'access', _4 => _4.owner, 'optionalAccess', _5 => _5.displayName])||Te(i.authors||[],","),S=i.timeZones||i.timezones||[],v=Array.isArray(S)?S:typeof S=="string"?[S]:[],E=W(se(_optionalChain([i, 'access', _6 => _6.cache, 'optionalAccess', _7 => _7.enabled]),i.cache,_optionalChain([i, 'access', _8 => _8.runtime, 'optionalAccess', _9 => _9.cache, 'optionalAccess', _10 => _10.enabled]),_optionalChain([i, 'access', _11 => _11.runtime, 'optionalAccess', _12 => _12.cache]),i.isCacheEnabled)),y=[];y.push(`${n}(${n})`),d&&y.push(d),t&&y.push(t),v.length&&y.push(v.join(",")),y.push(`Cache: ${E}`),y.push("");let g=Array.isArray(i.views)?i.views:[],m=Array.isArray(i.tables)?i.tables:[];g.length===0&&m.length>0&&(g.push(...m.filter(s=>!s.sql)),m=m.filter(s=>s.sql));let l=(s,b,u)=>{let h=[],f=s.title||s.displayName||s.name||`item_${b}`,p=s.name||s.table||s.view||f,k=s.description||_optionalChain([s, 'access', _13 => _13.meta, 'optionalAccess', _14 => _14.description])||"",N=W(se(s.isVisible,s.visible)),P=W(s.public),_=s.connectedComponent,M=s.refs||s.references,O=_optionalChain([s, 'access', _15 => _15.meta, 'optionalAccess', _16 => _16.title])||_optionalChain([s, 'access', _17 => _17.metric, 'optionalAccess', _18 => _18.title])||"",G=_optionalChain([s, 'access', _19 => _19.meta, 'optionalAccess', _20 => _20.tags])||s.tags,K=!!(_optionalChain([s, 'access', _21 => _21.meta, 'optionalAccess', _22 => _22.metric])||s.metric);if(h.push(`${b}. ${f}(${p})`),k&&h.push(k),u==="view"){let C=["view"];K&&C.push("metric"),C.push(`visible: ${N}`),C.push(`public: ${P}`),h.push(C.join(", "))}else{let C=["table"];_!==void 0&&C.push(`connectedComponent: ${_}`),C.push(`visible: ${N}`),C.push(`public: ${P}`),h.push(C.join(", "))}if(O&&h.push(O),Array.isArray(G)&&G.length&&h.push(Le(G)),M&&(Array.isArray(M)&&M.length||typeof M=="string")&&h.push(`refs: ${Array.isArray(M)?M.join(","):M}`),u==="table"&&s.sql&&(h.push("SQL:"),h.push("`"+String(s.sql).trim()+"`")),s.joins&&Array.isArray(s.joins)&&s.joins.length){h.push(""),h.push("Joins:");for(let C of s.joins)h.push(`${C.relationship} - ${C.name}`),h.push(" SQL: `"+pe(C.sql).trim()+"`")}h.push(""),h.push("Dimentions"),u==="table"?h.push("name|title|description|type|sql|suggestFilterValues|isVisible|public|primaryKey|aliasMember|isGoverned|refs"):h.push("name|title|description|type|suggestFilterValues|isVisible|public|primaryKey|aliasMember|isGoverned|refs");let V=Array.isArray(s.dimensions)?s.dimensions:[];for(let C of V){let Q=[U(C.name),U(C.title||C.displayName||""),U(C.description||""),U(C.type||C.dataType||"")];u==="table"&&Q.push(U(C.sql||C.expression||"")),Q.push(U(W(C.suggestFilterValues)),U(W(se(C.isVisible,C.visible))),U(W(C.public)),U(W(C.primaryKey)),U(C.aliasMember||(Array.isArray(C.aliasMembers)?C.aliasMembers.join(","):"")),U(W(C.isGoverned)),U(Array.isArray(C.refs)?C.refs.join(","):C.refs||"")),h.push(Q.join("|"))}h.push(""),h.push("Measures"),h.push("name|title|description|cumulativeTotal|cumulative|type|aggType|isVisible|public|aliasMember|isGoverned|refs");let H=Array.isArray(s.measures)?s.measures:[];for(let C of H){let Q=[U(C.name),U(C.title||C.displayName||""),U(C.description||""),U(W(C.cumulativeTotal)),U(W(C.cumulative)),U(C.type||C.dataType||""),U(C.aggType||C.aggregation||""),U(W(se(C.isVisible,C.visible))),U(W(C.public)),U(C.aliasMember||(Array.isArray(C.aliasMembers)?C.aliasMembers.join(","):"")),U(W(C.isGoverned)),U(Array.isArray(C.refs)?C.refs.join(","):C.refs||"")];h.push(Q.join("|"))}return h},w=1;for(let s of g)y.push(...l(s,w++,"view")),y.push("");for(let s of m)y.push(...l(s,w++,"table")),y.push("");return y.join(`
65
+ `,me=_zod.z.object({title:_zod.z.string({description:"Human-readable title for the check (e.g., 'Customer ID Completeness Check')"}).optional(),category:_zod.z.enum(["Accuracy","Completeness","Consistency","Freshness","Schema","Uniqueness","Validity"],{description:"Category of the data quality check for organization and reporting"}),description:_zod.z.string({description:"Detailed description of what the check validates"}).optional(),tags:_zod.z.array(_zod.z.string(),{description:"Tags for organizing and filtering checks (e.g., ['critical', 'pii', 'financial'])"}).optional()}).describe("Metadata attributes for organizing and documenting quality checks"),fr=_zod.z.object({limit:_zod.z.number({description:"Maximum number of failed row samples to collect for analysis (default: 100)"}).min(1).max(1e3).default(100)}).optional().describe("Configuration for collecting failed row samples for debugging"),gr=_zod.z.object({"valid format":_zod.z.enum(["email","phone number","credit card","uuid","date","url"],{description:"Built-in format validation (e.g., 'email', 'phone number')"}).optional(),"valid regex":_zod.z.string({description:"Custom regex pattern for validation (e.g., '^[A-Z]{2}[0-9]{4}$' for postal codes)"}).optional(),"valid min":_zod.z.number({description:"Minimum valid value for numeric columns"}).optional(),"valid max":_zod.z.number({description:"Maximum valid value for numeric columns"}).optional(),"valid min length":_zod.z.number({description:"Minimum valid length for string columns"}).optional(),"valid max length":_zod.z.number({description:"Maximum valid length for string columns"}).optional(),"valid values":_zod.z.array(_zod.z.union([_zod.z.string(),_zod.z.number()]),{description:"List of valid values (e.g., ['active', 'inactive', 'pending'])"}).optional()}).describe("Validation rules for validity checks"),Cs=_zod.z.object({name:_zod.z.string({description:"Name identifier for the schema check"}).optional(),warn:_zod.z.object({"when required column missing":_zod.z.array(_zod.z.string(),{description:"Columns that should trigger warnings if missing"}).optional(),"when forbidden column present":_zod.z.array(_zod.z.string(),{description:"Columns that should trigger warnings if present (e.g., ['temp_*', 'old_*'])"}).optional(),"when wrong column type":_zod.z.record(_zod.z.string(),_zod.z.string(),{description:"Expected column types that should trigger warnings if wrong (e.g., {'age': 'integer'})"}).optional(),"when wrong column index":_zod.z.record(_zod.z.string(),_zod.z.number(),{description:"Expected column positions that should trigger warnings if wrong"}).optional()}).optional(),fail:_zod.z.object({"when required column missing":_zod.z.array(_zod.z.string(),{description:"Columns that should trigger failures if missing"}).optional(),"when forbidden column present":_zod.z.array(_zod.z.string(),{description:"Columns that should trigger failures if present (sensitive data)"}).optional(),"when wrong column type":_zod.z.record(_zod.z.string(),_zod.z.string(),{description:"Expected column types that should trigger failures if wrong"}).optional(),"when wrong column index":_zod.z.record(_zod.z.string(),_zod.z.number(),{description:"Expected column positions that should trigger failures if wrong"}).optional()}).optional(),attributes:me}).describe("Schema validation check configuration with warn/fail conditions"),qs=_zod.z.object({name:_zod.z.string({description:"Custom name for the check (overrides default naming)"}).optional(),filter:_zod.z.string({description:`SQL WHERE clause to filter data for this specific check (e.g., 'status = "active"')`}).optional(),attributes:me}),hr=i=>{let{checkType:c,column:e,operator:n,value:d,compareDataset:t,samples:S,name:v,filter:E,attributes:y,missingValues:g,missingRegex:m,validationRules:l,function:w,percentile:s,lengthType:b,sourceColumn:u,referenceDataset:h,referenceColumn:f,checkPattern:p,warn:k,fail:N,failCondition:P,failQuery:_}=i;if(!c)return"Error: 'checkType' is required for all quality checks.";switch(c){case"row_count":if(!n)return"Error: 'row_count' check requires 'operator' property.";if(d===void 0)return"Error: 'row_count' check requires 'value' property.";if(e||g||m||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'row_count' check should only have 'operator', 'value', 'compareDataset', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"missing_count":if(!e)return"Error: 'missing_count' check requires 'column' property.";if(!n)return"Error: 'missing_count' check requires 'operator' property.";if(d===void 0)return"Error: 'missing_count' check requires 'value' property.";if(t||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'missing_count' check should only have 'column', 'operator', 'value', 'missingValues', 'missingRegex', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"missing_percent":if(!e)return"Error: 'missing_percent' check requires 'column' property.";if(!n)return"Error: 'missing_percent' check requires 'operator' property.";if(d===void 0)return"Error: 'missing_percent' check requires 'value' property.";if(t||g||m||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'missing_percent' check should only have 'column', 'operator', 'value', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"duplicate_count":if(!e)return"Error: 'duplicate_count' check requires 'column' property.";if(!n)return"Error: 'duplicate_count' check requires 'operator' property.";if(d===void 0)return"Error: 'duplicate_count' check requires 'value' property.";if(t||g||m||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'duplicate_count' check should only have 'column', 'operator', 'value', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"duplicate_percent":if(!e)return"Error: 'duplicate_percent' check requires 'column' property.";if(!n)return"Error: 'duplicate_percent' check requires 'operator' property.";if(d===void 0)return"Error: 'duplicate_percent' check requires 'value' property.";if(t||g||m||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'duplicate_percent' check should only have 'column', 'operator', 'value', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"invalid_count":if(!e)return"Error: 'invalid_count' check requires 'column' property.";if(!n)return"Error: 'invalid_count' check requires 'operator' property.";if(d===void 0)return"Error: 'invalid_count' check requires 'value' property.";if(!l)return"Error: 'invalid_count' check requires 'validationRules' property.";if(t||g||m||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'invalid_count' check should only have 'column', 'operator', 'value', 'validationRules', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"invalid_percent":if(!e)return"Error: 'invalid_percent' check requires 'column' property.";if(!n)return"Error: 'invalid_percent' check requires 'operator' property.";if(d===void 0)return"Error: 'invalid_percent' check requires 'value' property.";if(!l)return"Error: 'invalid_percent' check requires 'validationRules' property.";if(t||g||m||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'invalid_percent' check should only have 'column', 'operator', 'value', 'validationRules', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"freshness":if(!e)return"Error: 'freshness' check requires 'column' property.";if(!n)return"Error: 'freshness' check requires 'operator' property.";if(!d)return"Error: 'freshness' check requires 'value' property.";if(t||g||m||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'freshness' check should only have 'column', 'operator', 'value', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"aggregation":if(!w)return"Error: 'aggregation' check requires 'function' property.";if(!e)return"Error: 'aggregation' check requires 'column' property.";if(!n)return"Error: 'aggregation' check requires 'operator' property.";if(d===void 0)return"Error: 'aggregation' check requires 'value' property.";if(t||g||m||l||b||u||h||f||p||k||N||P||_)return"Error: 'aggregation' check should only have 'function', 'column', 'operator', 'value', 'percentile', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"length":if(!b)return"Error: 'length' check requires 'lengthType' property.";if(!e)return"Error: 'length' check requires 'column' property.";if(!n)return"Error: 'length' check requires 'operator' property.";if(d===void 0)return"Error: 'length' check requires 'value' property.";if(t||g||m||l||w||s||u||h||f||p||k||N||P||_)return"Error: 'length' check should only have 'lengthType', 'column', 'operator', 'value', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"reference":if(!u)return"Error: 'reference' check requires 'sourceColumn' property.";if(!h)return"Error: 'reference' check requires 'referenceDataset' property.";if(!f)return"Error: 'reference' check requires 'referenceColumn' property.";if(!p)return"Error: 'reference' check requires 'checkPattern' property.";if(e||n||d||t||g||m||l||w||s||b||k||N||P||_)return"Error: 'reference' check should only have 'sourceColumn', 'referenceDataset', 'referenceColumn', 'checkPattern', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"schema":if(e||n||d||t||g||m||l||w||s||b||u||h||f||p||P||_)return"Error: 'schema' check should only have 'warn', 'fail', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"failed_rows":if(!P&&!_)return"Error: 'failed_rows' check requires either 'failCondition' or 'failQuery' property.";if(e||n||d||t||g||m||l||w||s||b||u||h||f||p||k||N)return"Error: 'failed_rows' check should only have 'failCondition', 'failQuery', 'samples', 'name', 'filter', and 'attributes' properties.";break;default:return`Error: Invalid soda check type '${c}'. Supported types are: row_count, missing_count, missing_percent, duplicate_count, duplicate_percent, invalid_count, invalid_percent, freshness, aggregation, length, reference, schema, failed_rows.`}return null},yr=_zod.z.object({checkType:_zod.z.enum(["row_count","missing_count","missing_percent","duplicate_count","duplicate_percent","invalid_count","invalid_percent","freshness","aggregation","length","reference","schema","failed_rows"],{description:"Type of data quality check to perform"}),name:_zod.z.string({description:"Custom name for the check (overrides default naming)"}).optional(),filter:_zod.z.string({description:`SQL WHERE clause to filter data for this specific check (e.g., 'status = "active"')`}).optional(),attributes:me,samples:fr,compareDataset:_zod.z.string({description:"Reference dataset for comparison (e.g., 'same as reference_table')"}).optional(),column:_zod.z.string({description:"Column name for checks that operate on specific columns"}).optional(),operator:_zod.z.enum(["=","!=",">",">=","<","<=","between"],{description:"Comparison operator for the check"}).optional(),value:_zod.z.union([_zod.z.number(),_zod.z.string()],{description:"Expected value or range for the check"}).optional(),missingValues:_zod.z.array(_zod.z.union([_zod.z.string(),_zod.z.null()]),{description:"Custom missing value indicators (e.g., ['NA', 'n/a', '', null])"}).optional(),missingRegex:_zod.z.string({description:"Regex pattern to identify missing values"}).optional(),validationRules:gr.optional(),function:_zod.z.enum(["min","max","avg","sum","stddev","variance","percentile"],{description:"Aggregation function to apply"}).optional(),percentile:_zod.z.number({description:"Percentile value (0-1) for percentile function"}).min(0).max(1).optional(),lengthType:_zod.z.enum(["min_length","max_length","avg_length"],{description:"Type of length check to perform"}).optional(),sourceColumn:_zod.z.string({description:"Column in current dataset"}).optional(),referenceDataset:_zod.z.string({description:"Reference dataset name (e.g., 'reference_table')"}).optional(),referenceColumn:_zod.z.string({description:"Column in reference dataset"}).optional(),checkPattern:_zod.z.enum(["must exist in","must not exist in"],{description:"Type of reference validation"}).optional(),warn:_zod.z.object({"when required column missing":_zod.z.array(_zod.z.string(),{description:"Columns that should trigger warnings if missing"}).optional(),"when forbidden column present":_zod.z.array(_zod.z.string(),{description:"Columns that should trigger warnings if present (e.g., ['temp_*', 'old_*'])"}).optional(),"when wrong column type":_zod.z.record(_zod.z.string(),_zod.z.string(),{description:"Expected column types that should trigger warnings if wrong (e.g., {'age': 'integer'})"}).optional(),"when wrong column index":_zod.z.record(_zod.z.string(),_zod.z.number(),{description:"Expected column positions that should trigger warnings if wrong"}).optional()}).optional(),fail:_zod.z.object({"when required column missing":_zod.z.array(_zod.z.string(),{description:"Columns that should trigger failures if missing"}).optional(),"when forbidden column present":_zod.z.array(_zod.z.string(),{description:"Columns that should trigger failures if present (sensitive data)"}).optional(),"when wrong column type":_zod.z.record(_zod.z.string(),_zod.z.string(),{description:"Expected column types that should trigger failures if wrong"}).optional(),"when wrong column index":_zod.z.record(_zod.z.string(),_zod.z.number(),{description:"Expected column positions that should trigger failures if wrong"}).optional()}).optional(),failCondition:_zod.z.string({description:"SQL condition for identifying failed rows (e.g., 'age < 0 OR age > 150')"}).optional(),failQuery:_zod.z.string({description:"Custom SQL query for complex failed row detection"}).optional()}).describe("Comprehensive Soda quality check with typed validation"),br=_zod.z.object({columns:_zod.z.array(_zod.z.string(),{description:"Column specifications for profiling: exact names, wildcards (*), includes/excludes (e.g., ['customer_id', 'include address_*', 'exclude temp_*', '*'])"})}).optional().describe("Data profiling configuration for statistical analysis"),vr=_zod.z.object({name:_zod.z.string({description:"Identifier name for the filter"}),where:_zod.z.string({description:`SQL WHERE clause for global filtering across all checks (e.g., 'status = "active" AND created_date > "2023-01-01"')`})}).optional().describe("Global filter applied to all checks on this dataset"),wr=_zod.z.object({engine:_zod.z.enum(["minerva","default"],{description:"Query engine: 'minerva' for Trino-based queries, 'default' for native engine"}).default("default"),clusterName:_zod.z.string({description:"Cluster name for Minerva engine (required when engine is 'minerva')"}).optional(),branchName:_zod.z.string({description:"Branch name for Iceberg datasets (defaults to 'main')"}).default("main").optional()}).optional().describe("Engine and execution options for quality checks"),Sr=_zod.z.object({dataset:_zod.z.string({description:"Dataset specification using DataOS UDL format: dataos://[depot]:[collection]/[dataset] (e.g., 'dataos://icebase:retail/customer')"}),options:wr,filter:vr,profile:br,checks:_zod.z.array(yr,{description:"List of data quality checks to execute on this dataset"})}).describe("Complete dataset configuration with quality checks and profiling"),Er=_zod.z.object({requests:_zod.z.object({cpu:_zod.z.string({description:"CPU resource request (e.g., '500m', '1', '2000m')"}).default("1000m"),memory:_zod.z.string({description:"Memory resource request (e.g., '512Mi', '1Gi', '250Mi')"}).default("250Mi")}),limits:_zod.z.object({cpu:_zod.z.string({description:"CPU resource limit (e.g., '1', '2', '4000m')"}).optional(),memory:_zod.z.string({description:"Memory resource limit (e.g., '1Gi', '2Gi', '500Mi')"}).optional()}).optional()}).optional().describe("Resource allocation for quality check execution"),kr=_zod.z.object({cron:_zod.z.string({description:"Cron expression for scheduling (e.g., '0 2 * * *' for daily at 2 AM, '0 */6 * * *' for every 6 hours)"}),concurrencyPolicy:_zod.z.enum(["Allow","Forbid","Replace"],{description:"Policy for handling concurrent executions"}).default("Allow"),endOn:_zod.z.string({description:"End date for scheduled executions in ISO 8601 format"}).optional(),timezone:_zod.z.string({description:"Timezone for schedule execution (e.g., 'UTC', 'Asia/Kolkata')"}).default("UTC")}).optional().describe("Schedule configuration for recurring quality checks"),xr={name:_zod.z.string({description:"Quality workflow name - alphanumeric with hyphens, max 48 chars"}),tags:_zod.z.array(_zod.z.string(),{description:"Tags for categorizing and organizing the quality workflow"}),description:_zod.z.string({description:"Human-readable description of the quality checks and purpose"}),owner:_zod.z.string({description:"Owner of the quality workflow resource"}).optional(),workspace:_zod.z.string({description:"Workspace where the quality workflow will be deployed"}).default("public")},_r=_zod.z.array(_zod.z.object({...xr,schedule:kr,jobName:_zod.z.string({description:"Name of the quality job within the workflow"}),jobTitle:_zod.z.string({description:"Human-readable title for the job"}).optional(),jobDescription:_zod.z.string({description:"Description of the quality job"}).optional(),jobTags:_zod.z.array(_zod.z.string(),{description:"Tags specific to this quality job"}).optional(),compute:_zod.z.string({description:"Compute resource for the job"}).default("runnable-default"),runAsUser:_zod.z.string({description:"User to run the quality job as"}).optional(),stack:_zod.z.enum(["soda+python:1.0"],{description:"Soda stack version with Python flavor"}).default("soda+python:1.0"),logLevel:_zod.z.enum(["DEBUG","INFO","WARNING","ERROR"],{description:"Logging level for the quality job"}).default("INFO"),resources:Er,inputs:_zod.z.array(Sr,{description:"List of datasets and their associated quality checks"}),path:_zod.z.string({description:"Absolute path where the file will be stored. example: ~/Documents/project-name/my-quality.yaml"}),fileName:_zod.z.string({description:"File name for the quality workflow file. example: my-quality.yaml"})}),{description:"Array of quality workflows to create. Use this tool to create multiple quality workflows at once."}).nonempty(),Ae=i=>{i.tool("create-quality-workflow",mr,{workflows:_r},async({workflows:c})=>{let e=[];for(let n of c){let{name:d,tags:t,description:S,owner:v,workspace:E,schedule:y,jobName:g,jobTitle:m,jobDescription:l,jobTags:w,compute:s,runAsUser:b,stack:u,logLevel:h,resources:f,inputs:p,path:k,fileName:N}=n;for(let M of p)for(let O of M.checks){let G=hr(O);if(G)return{content:[{type:"text",text:G}]}}let P=[{name:g,...m&&{title:m},...l&&{description:l},...w&&{tags:w},spec:{stack:u,compute:s,...b&&{runAsUser:b},...f&&{resources:f},logLevel:h,stackSpec:{inputs:p}}}],_=_yaml.stringify.call(void 0, {name:d,tags:t,type:"workflow",version:"v1",...v&&{owner:v},workspace:E,description:S,...y&&{schedule:y},dag:P});try{let M=k.includes(".yaml")||k.includes(".yml")?k:k.endsWith("/")?k+N:`${k}/${N}`,O=_path2.default.dirname(M);_fs.existsSync.call(void 0, O)||_fs.mkdirSync.call(void 0, O,{recursive:!0}),_fs.writeFileSync.call(void 0, M,_),e.push({type:"text",text:`Quality workflow created successfully at ${M}`}),e.push({type:"text",text:`File content: ${_}`})}catch(M){e.push({type:"text",text:`Error creating quality workflow: ${M}`})}}return{content:e.flat()}})};var _https = require('https'); var _https2 = _interopRequireDefault(_https);var Tr=4;function J(i,c,e,n=!1,d=0){return new Promise((t,S)=>{let v=_https2.default.request(i,c,E=>{let y="";E.on("data",g=>y+=g),E.on("end",()=>{n&&d<Tr&&y.includes("Continue wait")?setTimeout(()=>{J(i,c,e,n,d+1).then(t).catch(S)},1e3):t({status:E.statusCode||500,data:y})})});v.on("error",S),e&&v.write(e),v.end()})}var _dotenv = require('dotenv');_dotenv.config.call(void 0, );var te="",le=process.env.SLUG||"bmx";function Te(i,c=","){return Array.isArray(i)?i.filter(e=>e!=null).map(e=>typeof e=="string"?e:JSON.stringify(e)).join(c):""}function W(i){return i===!0||i==="true"||i===1||i==="1"}function pe(i){return i==null?"":typeof i=="string"?i:typeof i=="number"||typeof i=="boolean"?String(i):JSON.stringify(i)}function U(i){let c=pe(i);return c===""?c:c.includes("|")||c.includes(",")||c.includes('"')?`"${c.replace(/"/g,'"')}"`:c}function Le(i){return Array.isArray(i)?i.map(c=>`"${pe(c)}"`).join(","):""}function se(...i){for(let c of i)if(c!==void 0)return c}function Ce(i,c){let e=i.name||i.slug||c||"",n=i.fullyQualifiedName||e||c||"",d=i.description||"",t=_optionalChain([i, 'access', _2 => _2.owner, 'optionalAccess', _3 => _3.name])||_optionalChain([i, 'access', _4 => _4.owner, 'optionalAccess', _5 => _5.displayName])||Te(i.authors||[],","),S=i.timeZones||i.timezones||[],v=Array.isArray(S)?S:typeof S=="string"?[S]:[],E=W(se(_optionalChain([i, 'access', _6 => _6.cache, 'optionalAccess', _7 => _7.enabled]),i.cache,_optionalChain([i, 'access', _8 => _8.runtime, 'optionalAccess', _9 => _9.cache, 'optionalAccess', _10 => _10.enabled]),_optionalChain([i, 'access', _11 => _11.runtime, 'optionalAccess', _12 => _12.cache]),i.isCacheEnabled)),y=[];y.push(`${n}(${n})`),d&&y.push(d),t&&y.push(t),v.length&&y.push(v.join(",")),y.push(`Cache: ${E}`),y.push("");let g=Array.isArray(i.views)?i.views:[],m=Array.isArray(i.tables)?i.tables:[];g.length===0&&m.length>0&&(g.push(...m.filter(s=>!s.sql)),m=m.filter(s=>s.sql));let l=(s,b,u)=>{let h=[],f=s.title||s.displayName||s.name||`item_${b}`,p=s.name||s.table||s.view||f,k=s.description||_optionalChain([s, 'access', _13 => _13.meta, 'optionalAccess', _14 => _14.description])||"",N=W(se(s.isVisible,s.visible)),P=W(s.public),_=s.connectedComponent,M=s.refs||s.references,O=_optionalChain([s, 'access', _15 => _15.meta, 'optionalAccess', _16 => _16.title])||_optionalChain([s, 'access', _17 => _17.metric, 'optionalAccess', _18 => _18.title])||"",G=_optionalChain([s, 'access', _19 => _19.meta, 'optionalAccess', _20 => _20.tags])||s.tags,K=!!(_optionalChain([s, 'access', _21 => _21.meta, 'optionalAccess', _22 => _22.metric])||s.metric);if(h.push(`${b}. ${f}(${p})`),k&&h.push(k),u==="view"){let C=["view"];K&&C.push("metric"),C.push(`visible: ${N}`),C.push(`public: ${P}`),h.push(C.join(", "))}else{let C=["table"];_!==void 0&&C.push(`connectedComponent: ${_}`),C.push(`visible: ${N}`),C.push(`public: ${P}`),h.push(C.join(", "))}if(O&&h.push(O),Array.isArray(G)&&G.length&&h.push(Le(G)),M&&(Array.isArray(M)&&M.length||typeof M=="string")&&h.push(`refs: ${Array.isArray(M)?M.join(","):M}`),u==="table"&&s.sql&&(h.push("SQL:"),h.push("`"+String(s.sql).trim()+"`")),s.joins&&Array.isArray(s.joins)&&s.joins.length){h.push(""),h.push("Joins:");for(let C of s.joins)h.push(`${C.relationship} - ${C.name}`),h.push(" SQL: `"+pe(C.sql).trim()+"`")}h.push(""),h.push("Dimentions"),u==="table"?h.push("name|title|description|type|sql|suggestFilterValues|isVisible|public|primaryKey|aliasMember|isGoverned|refs"):h.push("name|title|description|type|suggestFilterValues|isVisible|public|primaryKey|aliasMember|isGoverned|refs");let V=Array.isArray(s.dimensions)?s.dimensions:[];for(let C of V){let Q=[U(C.name),U(C.title||C.displayName||""),U(C.description||""),U(C.type||C.dataType||"")];u==="table"&&Q.push(U(C.sql||C.expression||"")),Q.push(U(W(C.suggestFilterValues)),U(W(se(C.isVisible,C.visible))),U(W(C.public)),U(W(C.primaryKey)),U(C.aliasMember||(Array.isArray(C.aliasMembers)?C.aliasMembers.join(","):"")),U(W(C.isGoverned)),U(Array.isArray(C.refs)?C.refs.join(","):C.refs||"")),h.push(Q.join("|"))}h.push(""),h.push("Measures"),h.push("name|title|description|cumulativeTotal|cumulative|type|aggType|isVisible|public|aliasMember|isGoverned|refs");let H=Array.isArray(s.measures)?s.measures:[];for(let C of H){let Q=[U(C.name),U(C.title||C.displayName||""),U(C.description||""),U(W(C.cumulativeTotal)),U(W(C.cumulative)),U(C.type||C.dataType||""),U(C.aggType||C.aggregation||""),U(W(se(C.isVisible,C.visible))),U(W(C.public)),U(C.aliasMember||(Array.isArray(C.aliasMembers)?C.aliasMembers.join(","):"")),U(W(C.isGoverned)),U(Array.isArray(C.refs)?C.refs.join(","):C.refs||"")];h.push(Q.join("|"))}return h},w=1;for(let s of g)y.push(...l(s,w++,"view")),y.push("");for(let s of m)y.push(...l(s,w++,"table")),y.push("");return y.join(`
66
66
  `)}async function re({slug:i=le,apiKey:c,fqdn:e=te}){let n=`https://${e}/lens2/api/${i.replace("public.","public:")}/v2/meta`,d={method:"GET",headers:{Authorization:`Bearer ${c}`}},{status:t,data:S}=await J(n,d);if(t<200||t>=300)return{content:[{type:"text",text:`Error: API responded with ${t}`}],isError:!0};try{let v=JSON.parse(S);return{content:[{type:"text",text:Ce(v,i)}]}}catch (e2){return{content:[{type:"text",text:"Error: API Response is not a JSON"}],isError:!0}}}async function ue({slug:i=le,payload:c,apiKey:e,fqdn:n=te}){let d=`https://${n}/lens2/api/${i.replace("public.","public:")}/v2/load`,t=JSON.stringify({query:c}),S={method:"POST",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json","Content-Length":Buffer.byteLength(t)}},{status:v,data:E}=await J(d,S,t,!0);if(v<200||v>=300)return{content:[{type:"text",text:JSON.stringify({status:v,data:E})}],isError:!0};try{let y=JSON.parse(E);return{content:[{type:"text",text:JSON.stringify(y.data)}]}}catch(y){return console.log("Error parsing lens data response:",y,E),{content:[{type:"text",text:`Query may be still running. Try again one more time. ${y.message}`}],isError:!0}}}async function oe({apiKey:i,fqdn:c=te}){let e=`https://${c}/dph/discover/api/msearch/query/v2`,n=JSON.stringify({queries:[{indexUid:"data_product_v2_search_index",q:"*",filter:["deleted='false'","tagList NOT IN ['DPTier.Source Aligned']"],offset:0,limit:1e3,attributesToRetrieve:["description","name","fullyQualifiedName","id","tagList","displayName","ports.lens.entityInfo.fullyQualifiedName","owner","purpose","updatedAt"]}]}),d={method:"POST",headers:{Authorization:`Bearer ${i}`,"Content-Type":"application/json","Content-Length":Buffer.byteLength(n)}},{status:t,data:S}=await J(e,d,n);if(t<200||t>=300)return{content:[{type:"text",text:`Error: API responded with ${t}`}],isError:!0};try{let E=JSON.parse(S).hits.filter(m=>_optionalChain([m, 'access', _23 => _23.ports, 'optionalAccess', _24 => _24.lens])),y=[],g=["Semantic model (lens) - fully qualified name","Data product name","Data product description","Purpose","DPDomain","DPUsecase","Owner","Updated At"];return E.forEach(m=>{let l=_optionalChain([m, 'access', _25 => _25.tagList, 'access', _26 => _26.find, 'call', _27 => _27(h=>h.startsWith("DPDomain.")), 'optionalAccess', _28 => _28.replace, 'call', _29 => _29("DPDomain.","")])||"N/A",w=_optionalChain([m, 'access', _30 => _30.tagList, 'access', _31 => _31.find, 'call', _32 => _32(h=>h.startsWith("DPUsecase.")), 'optionalAccess', _33 => _33.replace, 'call', _34 => _34("DPUsecase.","")])||"N/A",s=_optionalChain([m, 'access', _35 => _35.owner, 'optionalAccess', _36 => _36.displayName])||"N/A",b=m.updatedAt?new Date(m.updatedAt).toDateString():"N/A",u=[m.ports.lens.entityInfo.fullyQualifiedName.replace("dataos.",""),m.displayName,m.description,m.purpose||"N/A",l,w,s,b];y.push(u.join("|"))}),{content:[{type:"text",text:`${g.join("|")}
67
67
  `+y.join(`
68
68
  `)}]}}catch (e3){return{content:[{type:"text",text:"Error: API Response is not a JSON"}],isError:!0}}}var Cr=`
@@ -168,7 +168,7 @@ The schema includes:
168
168
  - Provide curated data experiences for specific use cases
169
169
  - Can be entity-first (customer_360) or metrics-first (monthly_revenue)
170
170
 
171
- Keywords: schema, metadata, data structure, dimensions, measures, segments, views, model structure`,Rr=_zod.z.string({description:"Name of the lens (semantic model slug). Alphanumeric with hyphen(-)s allowed. Make sure slug string contains workspace notation. example: public.customer-360"}),Re=({server:i,apiKey:c,fqdn:e,slug:n})=>{i.tool("query-lens-schema",Nr,n?{}:{slug:Rr},async({slug:d})=>re({slug:n||d,payload:{},apiKey:c,fqdn:e}))};var Pe=({server:i,apiKey:c,fqdn:e,slug:n})=>{n?i.resource("sematic-models",`sematic-models://lenses/${n}`,async d=>Ie({slug:n.toString(),href:d.href,apiKey:c,fqdn:e,payload:{}})):i.resource("sematic-models",new (0, _mcpjs.ResourceTemplate)("sematic-models://lenses/{slug}",{list:void 0}),async(d,{slug:t})=>Ie({slug:t.toString(),href:d.href,apiKey:c,fqdn:e,payload:{}}))};async function Ie({slug:i,apiKey:c,fqdn:e,href:n}){let d=await re({slug:i.toString(),payload:{},apiKey:c,fqdn:e});return{isError:d.isError,contents:d.content.map(({text:t})=>({uri:n,text:t}))}}var $e={name:"@tmdc-solutions/mcp-beta",version:"0.1.8",description:"for dataOS related tasks in local",type:"module",sideEffects:!1,main:"dist/stdio.cjs",types:"dist/stdio.d.ts",scripts:{build:"tsc","build:stdio":"tsup --clean","build:modules":"tsup --clean",http:"node dist/src/streamable-http.js -L",compile:"npm run build && npm run build:css && node dist/src/streamable-http.js -L",watch:'nodemon --watch src,views -e ts,pug,json,css --exec "npm run compile"',"build:css":"npx @tailwindcss/cli -i app.css -o public/output.css",test:'echo "Error: no test specified" && exit 1'},files:["dist/studio.cjs","dist/studio.cjs.map"],bin:{mcp:"./dist/stdio.js"},keywords:[],author:"",license:"ISC",packageManager:"pnpm@10.12.4",dependencies:{"@faker-js/faker":"^9.8.0","@modelcontextprotocol/sdk":"^1.12.0",dotenv:"^16.5.0",express:"^5.1.0",keyv:"^5.3.4",pug:"^3.0.3","trino-client":"^0.2.9",yaml:"^2.8.0",zod:"^3.25.67","zod-to-json-schema":"^3.24.5"},devDependencies:{"@tailwindcss/cli":"^4.1.8","@total-typescript/tsconfig":"^1.0.4","@types/express":"^5.0.2","@types/node":"^22.15.21",daisyui:"^5.0.40",nodemon:"^3.1.10",tailwindcss:"^4.1.8",tsup:"^8.5.0",typescript:"^5.8.3"}};var Br=`Bundle in DataOS is a Resource that serves as a declarative and standardized mechanism for deploying a collection of Resources, Data Products, or applications in a single operation.
171
+ Keywords: schema, metadata, data structure, dimensions, measures, segments, views, model structure`,Rr=_zod.z.string({description:"Name of the lens (semantic model slug). Alphanumeric with hyphen(-)s allowed. Make sure slug string contains workspace notation. example: public.customer-360"}),Re=({server:i,apiKey:c,fqdn:e,slug:n})=>{i.tool("query-lens-schema",Nr,n?{}:{slug:Rr},async({slug:d})=>re({slug:n||d,payload:{},apiKey:c,fqdn:e}))};var Pe=({server:i,apiKey:c,fqdn:e,slug:n})=>{n?i.resource("sematic-models",`sematic-models://lenses/${n}`,async d=>Ie({slug:n.toString(),href:d.href,apiKey:c,fqdn:e,payload:{}})):i.resource("sematic-models",new (0, _mcpjs.ResourceTemplate)("sematic-models://lenses/{slug}",{list:void 0}),async(d,{slug:t})=>Ie({slug:t.toString(),href:d.href,apiKey:c,fqdn:e,payload:{}}))};async function Ie({slug:i,apiKey:c,fqdn:e,href:n}){let d=await re({slug:i.toString(),payload:{},apiKey:c,fqdn:e});return{isError:d.isError,contents:d.content.map(({text:t})=>({uri:n,text:t}))}}var $e={name:"@tmdc-solutions/mcp-beta",version:"0.1.8",description:"for dataOS related tasks in local",type:"module",sideEffects:!1,main:"dist/stdio.cjs",types:"dist/stdio.d.ts",scripts:{build:"tsc","build:stdio":"tsup --clean","build:modules":"tsup --clean",http:"node dist/src/streamable-http.js -L",compile:"npm run build && npm run build:css && node dist/src/streamable-http.js -L",watch:'nodemon --watch src,views -e ts,pug,json,css --exec "npm run compile"',"build:css":"npx @tailwindcss/cli -i app.css -o public/output.css",test:'echo "Error: no test specified" && exit 1'},files:["dist/studio.cjs","dist/studio.cjs.map"],bin:{mcp:"./dist/stdio.js"},keywords:[],author:"",license:"ISC",packageManager:"pnpm@10.12.4",dependencies:{"@faker-js/faker":"^9.8.0","@modelcontextprotocol/sdk":"^1.25.2",dotenv:"^16.5.0",express:"^5.1.0",keyv:"^5.3.4",pug:"^3.0.3","trino-client":"^0.2.9",undici:"^6.21.0",yaml:"^2.8.0",zod:"^3.25.67","zod-to-json-schema":"^3.24.5"},devDependencies:{"@tailwindcss/cli":"^4.1.8","@total-typescript/tsconfig":"^1.0.4","@types/express":"^5.0.2","@types/node":"^22.15.21",daisyui:"^5.0.40",nodemon:"^3.1.10",tailwindcss:"^4.1.8",tsup:"^8.5.0",typescript:"^5.8.3"},pnpm:{overrides:{glob:">=10.5.0",qs:">=6.14.1",tar:">=7.5.3","body-parser":">=2.2.1","brace-expansion":">=2.0.2"}}};var Br=`Bundle in DataOS is a Resource that serves as a declarative and standardized mechanism for deploying a collection of Resources, Data Products, or applications in a single operation.
172
172
  It empowers data developers with the capability to programmatically orchestrate the deployment, scheduling, creation, and dismantling of code and infrastructure resources linked to these Data Products and applications in a unified manner.
173
173
 
174
174
  A Bundle aggregates various DataOS Resources into a flattened directed acyclic graph (DAG), where each node represents a distinct DataOS Resource, interconnected through dependency relationships.
@@ -208,7 +208,7 @@ Lens operates as a logical modeling layer for accessing tabular data in data war
208
208
  Examples: Create entity-first views (customer profiles, product analytics) or metrics-first views (conversion rates, revenue tracking) with proper SQL selections and joins.
209
209
 
210
210
  Use this tool to generate multiple SQL view files at once for comprehensive Lens model development.
211
- `,Qe=_zod.z.enum(["string","number","time","boolean","date","timestamp"],{description:"SQL data type for dimensions and measures in Lens models"}),Oo=_zod.z.enum(["count","count_distinct","count_distinct_approx","sum","avg","min","max","string","number","boolean"],{description:"Measure aggregation type - count/sum/avg for numerical aggregations, string/number/boolean for calculated measures"}),Rn=_zod.z.enum(["one_to_one","one_to_many","many_to_one"],{description:"Join relationship type between tables - one_to_one (1:1), one_to_many (1:N), many_to_one (N:1)"}),Uo=_zod.z.enum(["entity_first","metrics_first"],{description:"View modeling approach - entity_first (focus on entity attributes), metrics_first (focus on specific metrics with time dimensions)"}),Fo=_zod.z.object({baseTable:_zod.z.string({description:"Base table name for the join (left side of join). Examples: 'customer', 'sales', 'product'"}),baseColumn:_zod.z.string({description:"Column name in base table for join condition. Examples: 'customer_id', 'product_id', 'order_id'"}),targetTable:_zod.z.string({description:"Target table name for the join (right side of join). Examples: 'orders', 'transactions', 'inventory'"}),targetColumn:_zod.z.string({description:"Column name in target table for join condition. Examples: 'customer_id', 'product_id', 'order_id'"})}),Bo=_zod.z.object({tableName:_zod.z.string({description:"Source table name containing the column. Examples: 'customer', 'sales', 'product'"}),columnName:_zod.z.string({description:"Column name to select from the table. Examples: 'customer_id', 'product_name', 'order_date'"}),alias:_zod.z.string({description:"Optional alias for the column in the view. Examples: 'customer_identifier', 'product_title', 'purchase_date'"}).optional(),dataType:Qe,isPrimaryKey:_zod.z.boolean({description:"Whether this column serves as a primary key for the entity"}).default(!1),isRequired:_zod.z.boolean({description:"Whether this column is required (NOT NULL) in the view"}).default(!0)}),zo=_zod.z.object({name:_zod.z.string({description:"Name of the calculated field. Examples: 'total_revenue', 'customer_lifetime_value', 'avg_order_value'"}),expression:_zod.z.string({description:"SQL expression for the calculation. Examples: 'SUM(order_amount)', 'COUNT(DISTINCT customer_id)', 'AVG(product_price * quantity)'"}),dataType:Qe,measureType:Oo.optional(),description:_zod.z.string({description:"Business description of what this calculated field represents"}).optional()}),We=_zod.z.object({column:_zod.z.string({description:"Column name for the condition. Examples: 'status', 'created_date', 'region'"}),operator:_zod.z.enum(["=","!=","<>","<","<=",">",">=","IN","NOT IN","LIKE","NOT LIKE","IS NULL","IS NOT NULL","BETWEEN","EXISTS","NOT EXISTS"],{description:"SQL comparison operator for the condition"}),value:_zod.z.union([_zod.z.string(),_zod.z.number(),_zod.z.array(_zod.z.union([_zod.z.string(),_zod.z.number()]))],{description:"Value(s) for the condition. Can be single value, array for IN/NOT IN, or range for BETWEEN"}).optional(),logicalOperator:_zod.z.enum(["AND","OR"],{description:"Logical operator to combine with next condition"}).optional()}),Qo=_zod.z.object({columns:_zod.z.array(_zod.z.string(),{description:"Column names to group by. Examples: ['region', 'product_category'], ['customer_segment'], ['date_trunc(\\'month\\', order_date)']"}),having:_zod.z.array(We,{description:"HAVING conditions for filtering grouped results (applied after GROUP BY)"}).optional()}),Wo=_zod.z.object({column:_zod.z.string({description:"Column name to order by. Examples: 'total_revenue', 'customer_name', 'order_date'"}),direction:_zod.z.enum(["ASC","DESC"],{description:"Sort direction - ASC (ascending) or DESC (descending)"}).default("ASC")}),Go=_zod.z.object({viewName:_zod.z.string({description:"Name of the Lens view to create. Examples: 'customer_360', 'sales_metrics', 'product_performance'"}),viewType:Uo,description:_zod.z.string({description:"Business description of the view's purpose and use case"}),baseTables:_zod.z.array(_zod.z.string(),{description:"Primary tables for the view. Examples: ['customer', 'orders'], ['sales', 'product'], ['transactions']"}),joins:_zod.z.array(Fo,{description:"Join conditions between tables. All joins in Lens are LEFT JOINs by default"}).optional(),dimensions:_zod.z.array(Bo,{description:"Dimensional columns (descriptive attributes) to include in the view. Examples: customer_name, product_category, region"}),measures:_zod.z.array(zo,{description:"Calculated measures (aggregated values) for the view. Examples: total_sales, customer_count, avg_order_value"}).optional(),whereConditions:_zod.z.array(We,{description:"WHERE conditions to filter the data. Examples: status = 'active', created_date > '2023-01-01'"}).optional(),groupBy:Qo.optional(),orderBy:_zod.z.array(Wo,{description:"ORDER BY specifications for result sorting"}).optional(),limit:_zod.z.number({description:"Maximum number of rows to return. Examples: 1000, 10000"}).optional(),timeFilter:_zod.z.object({timeColumn:_zod.z.string({description:"Time/date column for filtering. Examples: 'created_date', 'order_timestamp', 'updated_at'"}),granularity:_zod.z.enum(["second","minute","hour","day","week","month","quarter","year"],{description:"Time granularity for grouping time-based data"}).optional(),range:_zod.z.string({description:"Time range filter. Examples: 'last 30 days', 'this month', 'last quarter', '2023-01-01 to 2023-12-31'"}).optional()}).optional(),includeNulls:_zod.z.boolean({description:"Whether to include NULL values in results"}).default(!0),distinct:_zod.z.boolean({description:"Whether to apply DISTINCT to the entire result set"}).default(!1)}),Vo=_zod.z.array(_zod.z.object({viewConfig:Go,path:_zod.z.string({description:"Absolute path where the file will be stored. example: ~/Documents/project-name/my-lens-sql.sql"}),fileName:_zod.z.string({description:"File name for the lens SQL file. example: my-lens-sql.sql"})}),{description:"Array of Lens SQL views to create. Use this tool to create multiple Lens SQL view files at once. Note: For executing SQL queries on data, use the SQL MCP tool instead."}).nonempty();function Ho(i){return i.map(e=>`LEFT JOIN ${e.targetTable} ON ${e.baseTable}.${e.baseColumn} = ${e.targetTable}.${e.targetColumn}`).join(`
211
+ `,Qe=_zod.z.enum(["string","number","time","boolean","date","timestamp"],{description:"SQL data type for dimensions and measures in Lens models"}),Oo=_zod.z.enum(["count","count_distinct","count_distinct_approx","sum","avg","min","max","string","number","boolean"],{description:"Measure aggregation type - count/sum/avg for numerical aggregations, string/number/boolean for calculated measures"}),$n=_zod.z.enum(["one_to_one","one_to_many","many_to_one"],{description:"Join relationship type between tables - one_to_one (1:1), one_to_many (1:N), many_to_one (N:1)"}),Uo=_zod.z.enum(["entity_first","metrics_first"],{description:"View modeling approach - entity_first (focus on entity attributes), metrics_first (focus on specific metrics with time dimensions)"}),Fo=_zod.z.object({baseTable:_zod.z.string({description:"Base table name for the join (left side of join). Examples: 'customer', 'sales', 'product'"}),baseColumn:_zod.z.string({description:"Column name in base table for join condition. Examples: 'customer_id', 'product_id', 'order_id'"}),targetTable:_zod.z.string({description:"Target table name for the join (right side of join). Examples: 'orders', 'transactions', 'inventory'"}),targetColumn:_zod.z.string({description:"Column name in target table for join condition. Examples: 'customer_id', 'product_id', 'order_id'"})}),Bo=_zod.z.object({tableName:_zod.z.string({description:"Source table name containing the column. Examples: 'customer', 'sales', 'product'"}),columnName:_zod.z.string({description:"Column name to select from the table. Examples: 'customer_id', 'product_name', 'order_date'"}),alias:_zod.z.string({description:"Optional alias for the column in the view. Examples: 'customer_identifier', 'product_title', 'purchase_date'"}).optional(),dataType:Qe,isPrimaryKey:_zod.z.boolean({description:"Whether this column serves as a primary key for the entity"}).default(!1),isRequired:_zod.z.boolean({description:"Whether this column is required (NOT NULL) in the view"}).default(!0)}),zo=_zod.z.object({name:_zod.z.string({description:"Name of the calculated field. Examples: 'total_revenue', 'customer_lifetime_value', 'avg_order_value'"}),expression:_zod.z.string({description:"SQL expression for the calculation. Examples: 'SUM(order_amount)', 'COUNT(DISTINCT customer_id)', 'AVG(product_price * quantity)'"}),dataType:Qe,measureType:Oo.optional(),description:_zod.z.string({description:"Business description of what this calculated field represents"}).optional()}),We=_zod.z.object({column:_zod.z.string({description:"Column name for the condition. Examples: 'status', 'created_date', 'region'"}),operator:_zod.z.enum(["=","!=","<>","<","<=",">",">=","IN","NOT IN","LIKE","NOT LIKE","IS NULL","IS NOT NULL","BETWEEN","EXISTS","NOT EXISTS"],{description:"SQL comparison operator for the condition"}),value:_zod.z.union([_zod.z.string(),_zod.z.number(),_zod.z.array(_zod.z.union([_zod.z.string(),_zod.z.number()]))],{description:"Value(s) for the condition. Can be single value, array for IN/NOT IN, or range for BETWEEN"}).optional(),logicalOperator:_zod.z.enum(["AND","OR"],{description:"Logical operator to combine with next condition"}).optional()}),Qo=_zod.z.object({columns:_zod.z.array(_zod.z.string(),{description:"Column names to group by. Examples: ['region', 'product_category'], ['customer_segment'], ['date_trunc(\\'month\\', order_date)']"}),having:_zod.z.array(We,{description:"HAVING conditions for filtering grouped results (applied after GROUP BY)"}).optional()}),Wo=_zod.z.object({column:_zod.z.string({description:"Column name to order by. Examples: 'total_revenue', 'customer_name', 'order_date'"}),direction:_zod.z.enum(["ASC","DESC"],{description:"Sort direction - ASC (ascending) or DESC (descending)"}).default("ASC")}),Go=_zod.z.object({viewName:_zod.z.string({description:"Name of the Lens view to create. Examples: 'customer_360', 'sales_metrics', 'product_performance'"}),viewType:Uo,description:_zod.z.string({description:"Business description of the view's purpose and use case"}),baseTables:_zod.z.array(_zod.z.string(),{description:"Primary tables for the view. Examples: ['customer', 'orders'], ['sales', 'product'], ['transactions']"}),joins:_zod.z.array(Fo,{description:"Join conditions between tables. All joins in Lens are LEFT JOINs by default"}).optional(),dimensions:_zod.z.array(Bo,{description:"Dimensional columns (descriptive attributes) to include in the view. Examples: customer_name, product_category, region"}),measures:_zod.z.array(zo,{description:"Calculated measures (aggregated values) for the view. Examples: total_sales, customer_count, avg_order_value"}).optional(),whereConditions:_zod.z.array(We,{description:"WHERE conditions to filter the data. Examples: status = 'active', created_date > '2023-01-01'"}).optional(),groupBy:Qo.optional(),orderBy:_zod.z.array(Wo,{description:"ORDER BY specifications for result sorting"}).optional(),limit:_zod.z.number({description:"Maximum number of rows to return. Examples: 1000, 10000"}).optional(),timeFilter:_zod.z.object({timeColumn:_zod.z.string({description:"Time/date column for filtering. Examples: 'created_date', 'order_timestamp', 'updated_at'"}),granularity:_zod.z.enum(["second","minute","hour","day","week","month","quarter","year"],{description:"Time granularity for grouping time-based data"}).optional(),range:_zod.z.string({description:"Time range filter. Examples: 'last 30 days', 'this month', 'last quarter', '2023-01-01 to 2023-12-31'"}).optional()}).optional(),includeNulls:_zod.z.boolean({description:"Whether to include NULL values in results"}).default(!0),distinct:_zod.z.boolean({description:"Whether to apply DISTINCT to the entire result set"}).default(!1)}),Vo=_zod.z.array(_zod.z.object({viewConfig:Go,path:_zod.z.string({description:"Absolute path where the file will be stored. example: ~/Documents/project-name/my-lens-sql.sql"}),fileName:_zod.z.string({description:"File name for the lens SQL file. example: my-lens-sql.sql"})}),{description:"Array of Lens SQL views to create. Use this tool to create multiple Lens SQL view files at once. Note: For executing SQL queries on data, use the SQL MCP tool instead."}).nonempty();function Ho(i){return i.map(e=>`LEFT JOIN ${e.targetTable} ON ${e.baseTable}.${e.baseColumn} = ${e.targetTable}.${e.targetColumn}`).join(`
212
212
  `)}function ze(i){return i.length?`WHERE ${i.map((e,n)=>{let d="";switch(n>0&&e.logicalOperator&&(d+=`${e.logicalOperator} `),e.operator){case"IS NULL":case"IS NOT NULL":d+=`${e.column} ${e.operator}`;break;case"IN":case"NOT IN":let S=(Array.isArray(e.value)?e.value:[e.value]).map(E=>typeof E=="string"?`'${E}'`:E).join(", ");d+=`${e.column} ${e.operator} (${S})`;break;case"BETWEEN":Array.isArray(e.value)&&e.value.length===2&&(d+=`${e.column} BETWEEN ${e.value[0]} AND ${e.value[1]}`);break;case"LIKE":case"NOT LIKE":d+=`${e.column} ${e.operator} '${e.value}'`;break;default:let v=typeof e.value=="string"?`'${e.value}'`:e.value;d+=`${e.column} ${e.operator} ${v}`}return d}).join(" ")}`:""}function Ko(i,c){let e=i.map(t=>{let S=`${t.tableName}.${t.columnName}`;return t.alias?`${S} AS ${t.alias}`:S}),n=_optionalChain([c, 'optionalAccess', _42 => _42.map, 'call', _43 => _43(t=>`${t.expression} AS ${t.name}`)])||[];return[...e,...n].join(`,
213
213
  `)}var Ge=i=>{i.tool("create-lens-sql",Mo,{views:Vo},async({views:c})=>{let e=[];for(let n of c){let{viewConfig:d,path:t,fileName:S}=n,{viewName:v,viewType:E,description:y,baseTables:g,joins:m=[],dimensions:l,measures:w=[],whereConditions:s=[],groupBy:b,orderBy:u=[],limit:h,timeFilter:f,includeNulls:p,distinct:k}=d,N=Ko(l,w),P=g[0],_=m.length>0?Ho(m):"",M=s.length>0?ze(s):"",O="";if(b&&(O=`GROUP BY ${b.columns.join(", ")}`,b.having&&b.having.length>0)){let B=ze(b.having).replace("WHERE","HAVING");O+=`
214
214
  ${B}`}let G=u.length>0?`ORDER BY ${u.map(B=>`${B.column} ${B.direction}`).join(", ")}`:"",K=h?`LIMIT ${h}`:"",V="";if(f){let B=[];if(f.range){if(f.range.includes("last")&&f.range.includes("days")){let X=_optionalChain([f, 'access', _44 => _44.range, 'access', _45 => _45.match, 'call', _46 => _46(/\d+/), 'optionalAccess', _47 => _47[0]])||"30";B.push(`${f.timeColumn} >= CURRENT_DATE - INTERVAL '${X}' DAY`)}else if(f.range.includes("this month"))B.push(`${f.timeColumn} >= DATE_TRUNC('month', CURRENT_DATE)`);else if(f.range.includes("last quarter"))B.push(`${f.timeColumn} >= DATE_TRUNC('quarter', CURRENT_DATE) - INTERVAL '3' MONTH`);else if(f.range.includes(" to ")){let[X,at]=f.range.split(" to ");B.push(`${f.timeColumn} BETWEEN '${X.trim()}' AND '${at.trim()}'`)}}B.length>0&&(V=B.join(" AND "))}let H="";M&&V?H=`${M} AND ${V}`:M?H=M:V&&(H=`WHERE ${V}`);let Q=[`-- Lens View: ${v}`,`-- Type: ${E}`,`-- Description: ${y}`,"",`SELECT${k?" DISTINCT":""}`,` ${N}`,`FROM ${P}`,_,H,O,G,K].filter(B=>B.trim()!=="").join(`
@@ -236,7 +236,7 @@ Use segments when you notice the same filter conditions being applied repeatedly
236
236
  - LIKE pattern: "{TABLE}.state LIKE '%York%'"
237
237
  - Complex AND/OR: "{TABLE}.state = 'Illinois' AND {TABLE}.sales > 1000"
238
238
  - Date ranges: "{TABLE}.order_date >= '2023-01-01'"
239
- - Null checks: "{TABLE}.email IS NOT NULL"`}),Un=_zod.z.object({name:_zod.z.string({description:"Segment name - should be descriptive and follow naming conventions (e.g., 'active_customers', 'high_value_orders', 'california_sales')"}),sql:ge,public:_zod.z.boolean({description:"Whether the segment is publicly visible to all users or restricted"}).default(!0),description:_zod.z.string({description:"Human-readable description of what this segment filters (e.g., 'Filters for customers with active status and recent purchases')"}).optional(),meta:oi.optional()}),Ke=_zod.z.enum(["geographic_filter","date_range_filter","status_filter","category_filter","value_range_filter","null_check_filter","pattern_match_filter","custom"],{description:"Predefined templates for common segment patterns. Choose 'custom' for fully custom segments"}),ii=i=>{let{template:c,column:e,values:n,operator:d,startDate:t,endDate:S,minValue:v,maxValue:E,checkType:y,pattern:g,sql:m}=i;switch(c){case"geographic_filter":if(!e)return"Error: 'geographic_filter' template requires 'column' property.";if(!n||n.length===0)return"Error: 'geographic_filter' template requires 'values' property with geographic values.";if(t||S||v||E||y||g||m)return"Error: 'geographic_filter' template should only have 'column', 'values', and 'operator' properties.";break;case"date_range_filter":if(!e)return"Error: 'date_range_filter' template requires 'column' property.";if(!t&&!S)return"Error: 'date_range_filter' template requires either 'startDate' or 'endDate' property.";if(n||v||E||y||g||m)return"Error: 'date_range_filter' template should only have 'column', 'startDate', 'endDate', and 'operator' properties.";break;case"status_filter":if(!e)return"Error: 'status_filter' template requires 'column' property.";if(!n||n.length===0)return"Error: 'status_filter' template requires 'values' property with status values.";if(t||S||v||E||y||g||m)return"Error: 'status_filter' template should only have 'column', 'values', and 'operator' properties.";break;case"category_filter":if(!e)return"Error: 'category_filter' template requires 'column' property.";if(!n||n.length===0)return"Error: 'category_filter' template requires 'values' property with category values.";if(t||S||v||E||y||g||m)return"Error: 'category_filter' template should only have 'column', 'values', and 'operator' properties.";break;case"value_range_filter":if(!e)return"Error: 'value_range_filter' template requires 'column' property.";if(!v&&!E)return"Error: 'value_range_filter' template requires either 'minValue' or 'maxValue' property.";if(n||t||S||y||g||m)return"Error: 'value_range_filter' template should only have 'column', 'minValue', 'maxValue', and 'operator' properties.";break;case"null_check_filter":if(!e)return"Error: 'null_check_filter' template requires 'column' property.";if(!y)return"Error: 'null_check_filter' template requires 'checkType' property.";if(n||d||t||S||v||E||g||m)return"Error: 'null_check_filter' template should only have 'column' and 'checkType' properties.";break;case"pattern_match_filter":if(!e)return"Error: 'pattern_match_filter' template requires 'column' property.";if(!g)return"Error: 'pattern_match_filter' template requires 'pattern' property.";if(n||t||S||v||E||y||m)return"Error: 'pattern_match_filter' template should only have 'column', 'pattern', and 'operator' properties.";break;case"custom":if(!m)return"Error: 'custom' template requires 'sql' property with SQL expression.";if(e||n||d||t||S||v||E||y||g)return"Error: 'custom' template should only have 'sql' property.";break;default:return`Error: Invalid template type '${c}'. Supported types are: geographic_filter, date_range_filter, status_filter, category_filter, value_range_filter, null_check_filter, pattern_match_filter, custom.`}return null},si=_zod.z.object({template:Ke,column:_zod.z.string({description:"Column name for the filter"}).optional(),operator:_zod.z.enum(["=","!=",">",">=","<","<=","BETWEEN","IN","NOT IN","LIKE","NOT LIKE","ILIKE"],{description:"SQL operator to use for filtering"}).optional(),values:_zod.z.array(_zod.z.string(),{description:"Values to filter for (geographic, status, or category values)"}).optional(),startDate:_zod.z.string({description:"Start date in YYYY-MM-DD format (e.g., '2023-01-01')"}).optional(),endDate:_zod.z.string({description:"End date in YYYY-MM-DD format (e.g., '2023-12-31')"}).optional(),minValue:_zod.z.number({description:"Minimum value for the range"}).optional(),maxValue:_zod.z.number({description:"Maximum value for the range"}).optional(),checkType:_zod.z.enum(["IS NULL","IS NOT NULL"],{description:"Type of null check to perform"}).optional(),pattern:_zod.z.string({description:"Pattern to match (e.g., '%@gmail.com', 'Mr.%', '%premium%')"}).optional(),sql:ge.optional()}),He=_zod.z.object({segmentType:_zod.z.enum(["template","custom"],{description:"Whether to use a predefined template or create a custom segment"}).default("custom"),name:_zod.z.string({description:"Segment name - descriptive identifier for the segment"}),description:_zod.z.string({description:"Human-readable description of the segment's purpose"}).optional(),public:_zod.z.boolean({description:"Whether the segment is publicly accessible"}).default(!0),templateConfig:si.optional(),sql:ge.optional(),security:_zod.z.object({enabled:_zod.z.boolean({description:"Whether to enable user group-based security for this segment"}).default(!1),includeGroups:_zod.z.union([_zod.z.literal("*"),_zod.z.array(_zod.z.string())],{description:"User groups to include. Use '*' for all users or specify group names"}).optional(),excludeGroups:_zod.z.array(_zod.z.string(),{description:"User groups to exclude from access"}).optional()}).optional(),meta:_zod.z.object({tags:_zod.z.array(_zod.z.string()).optional(),customProperties:_zod.z.record(_zod.z.string(),_zod.z.any()).optional()}).optional()}),ni={configurationType:_zod.z.enum(["single","multiple","bulk_template"],{description:"Configuration type: 'single' for one segment, 'multiple' for several segments, 'bulk_template' for template-based generation"}),segment:He.optional(),segments:_zod.z.array(He,{description:"Array of segment configurations"}).optional(),bulkTemplate:_zod.z.object({baseTemplate:Ke,variations:_zod.z.array(_zod.z.object({name:_zod.z.string({description:"Name of the segment variation"}),values:_zod.z.array(_zod.z.string(),{description:"Values for this variation"}).optional(),customSql:_zod.z.string({description:"Custom SQL to override template"}).optional()}))}).optional(),outputFormat:_zod.z.enum(["segments_only","full_table_structure"],{description:"Whether to output only segments or include them in a full table structure"}).default("segments_only"),tableName:_zod.z.string({description:"Table name for full table structure output"}).optional(),comments:_zod.z.string({description:"Additional comments or notes about the segment configuration"}).optional(),path:_zod.z.string({description:"Absolute path where the file will be stored. example: ~/Documents/project-name/my-segments.yaml"}),fileName:_zod.z.string({description:"File name for the lens segments file. example: my-segments.yaml"})},Ye=i=>{i.tool("create-lens-segments",ei,ni,async({configurationType:c,segment:e,segments:n,bulkTemplate:d,outputFormat:t,tableName:S,path:v,fileName:E})=>{let y=[],g=l=>{let w=ii(l);if(w)throw new Error(w);let{template:s,column:b,values:u,operator:h,startDate:f,endDate:p,minValue:k,maxValue:N,checkType:P,pattern:_,sql:M}=l;switch(s){case"geographic_filter":return h==="IN"&&u.length>1?`{TABLE}.${b} IN ('${u.join("', '")}')`:h==="LIKE"?u.map(O=>`{TABLE}.${b} LIKE '%${O}%'`).join(" OR "):`{TABLE}.${b} ${h||"="} '${u[0]}'`;case"date_range_filter":if(f&&p)return h==="BETWEEN"?`{TABLE}.${b} BETWEEN '${f}' AND '${p}'`:`{TABLE}.${b} >= '${f}' AND {TABLE}.${b} <= '${p}'`;if(f)return`{TABLE}.${b} ${h||">="} '${f}'`;if(p)return`{TABLE}.${b} ${h||"<="} '${p}'`;break;case"status_filter":return h==="IN"&&u.length>1?`{TABLE}.${b} IN ('${u.join("', '")}')`:h==="NOT IN"?`{TABLE}.${b} NOT IN ('${u.join("', '")}')`:`{TABLE}.${b} ${h||"="} '${u[0]}'`;case"category_filter":return h==="IN"&&u.length>1?`{TABLE}.${b} IN ('${u.join("', '")}')`:h==="LIKE"?u.map(O=>`{TABLE}.${b} LIKE '%${O}%'`).join(" OR "):`{TABLE}.${b} ${h||"="} '${u[0]}'`;case"value_range_filter":if(k!==void 0&&N!==void 0)return h==="BETWEEN"?`{TABLE}.${b} BETWEEN ${k} AND ${N}`:`{TABLE}.${b} >= ${k} AND {TABLE}.${b} <= ${N}`;if(k!==void 0)return`{TABLE}.${b} ${h||">="} ${k}`;if(N!==void 0)return`{TABLE}.${b} ${h||"<="} ${N}`;break;case"null_check_filter":return`{TABLE}.${b} ${P}`;case"pattern_match_filter":return`{TABLE}.${b} ${h||"LIKE"} '${_}'`;case"custom":return M;default:throw new Error(`Unsupported template: ${s}`)}throw new Error(`Unable to generate SQL for template: ${s}`)},m=l=>{let w={name:l.name,public:l.public!==void 0?l.public:!0};if(l.description&&(w.description=l.description),l.segmentType==="template"&&l.templateConfig)w.sql=g(l.templateConfig);else if(l.sql)w.sql=l.sql;else throw new Error(`Segment '${l.name}' must have either templateConfig or custom sql`);if(_optionalChain([l, 'access', _49 => _49.security, 'optionalAccess', _50 => _50.enabled])){let s={};(l.security.includeGroups||l.security.excludeGroups)&&(s.secure={user_groups:{}},l.security.includeGroups&&(s.secure.user_groups.includes=l.security.includeGroups),l.security.excludeGroups&&(s.secure.user_groups.excludes=l.security.excludeGroups)),_optionalChain([l, 'access', _51 => _51.meta, 'optionalAccess', _52 => _52.tags])&&(s.tags=l.meta.tags),_optionalChain([l, 'access', _53 => _53.meta, 'optionalAccess', _54 => _54.customProperties])&&Object.assign(s,l.meta.customProperties),Object.keys(s).length>0&&(w.meta=s)}return w};try{if(c==="single"){if(!e)throw new Error("Segment configuration is required for single type");y.push(m(e))}else if(c==="multiple"){if(!n||n.length===0)throw new Error("Segments array is required for multiple type");y=n.map(m)}else if(c==="bulk_template"){if(!d)throw new Error("Bulk template configuration is required for bulk_template type");let{baseTemplate:u,variations:h}=d;y=h.map(f=>{let p={template:u};return f.values&&(p.values=f.values),f.customSql&&(p.sql=f.customSql,p.template="custom"),m({name:f.name,segmentType:"template",templateConfig:p,public:!0})})}let l=()=>["# Lens Segments Configuration","# Reusable filters for consistent data access patterns","# ","# Segments provide:","# - Reusable filter logic across multiple queries","# - Row-level security and data governance","# - Consistent business rule application","# - Performance optimization through pre-defined filters","# ",`# Configuration Type: ${c}`,`# Number of Segments: ${y.length}`,"# ","# Usage in Lens models:","# - Reference segments in measures and dimensions","# - Apply as default filters in cubes","# - Use for user group-based data access control","# ","# Segment SQL uses {TABLE} placeholder for table reference","# Example: {TABLE}.status = 'active' AND {TABLE}.created_date >= '2023-01-01'",""].join(`
239
+ - Null checks: "{TABLE}.email IS NOT NULL"`}),zn=_zod.z.object({name:_zod.z.string({description:"Segment name - should be descriptive and follow naming conventions (e.g., 'active_customers', 'high_value_orders', 'california_sales')"}),sql:ge,public:_zod.z.boolean({description:"Whether the segment is publicly visible to all users or restricted"}).default(!0),description:_zod.z.string({description:"Human-readable description of what this segment filters (e.g., 'Filters for customers with active status and recent purchases')"}).optional(),meta:oi.optional()}),Ke=_zod.z.enum(["geographic_filter","date_range_filter","status_filter","category_filter","value_range_filter","null_check_filter","pattern_match_filter","custom"],{description:"Predefined templates for common segment patterns. Choose 'custom' for fully custom segments"}),ii=i=>{let{template:c,column:e,values:n,operator:d,startDate:t,endDate:S,minValue:v,maxValue:E,checkType:y,pattern:g,sql:m}=i;switch(c){case"geographic_filter":if(!e)return"Error: 'geographic_filter' template requires 'column' property.";if(!n||n.length===0)return"Error: 'geographic_filter' template requires 'values' property with geographic values.";if(t||S||v||E||y||g||m)return"Error: 'geographic_filter' template should only have 'column', 'values', and 'operator' properties.";break;case"date_range_filter":if(!e)return"Error: 'date_range_filter' template requires 'column' property.";if(!t&&!S)return"Error: 'date_range_filter' template requires either 'startDate' or 'endDate' property.";if(n||v||E||y||g||m)return"Error: 'date_range_filter' template should only have 'column', 'startDate', 'endDate', and 'operator' properties.";break;case"status_filter":if(!e)return"Error: 'status_filter' template requires 'column' property.";if(!n||n.length===0)return"Error: 'status_filter' template requires 'values' property with status values.";if(t||S||v||E||y||g||m)return"Error: 'status_filter' template should only have 'column', 'values', and 'operator' properties.";break;case"category_filter":if(!e)return"Error: 'category_filter' template requires 'column' property.";if(!n||n.length===0)return"Error: 'category_filter' template requires 'values' property with category values.";if(t||S||v||E||y||g||m)return"Error: 'category_filter' template should only have 'column', 'values', and 'operator' properties.";break;case"value_range_filter":if(!e)return"Error: 'value_range_filter' template requires 'column' property.";if(!v&&!E)return"Error: 'value_range_filter' template requires either 'minValue' or 'maxValue' property.";if(n||t||S||y||g||m)return"Error: 'value_range_filter' template should only have 'column', 'minValue', 'maxValue', and 'operator' properties.";break;case"null_check_filter":if(!e)return"Error: 'null_check_filter' template requires 'column' property.";if(!y)return"Error: 'null_check_filter' template requires 'checkType' property.";if(n||d||t||S||v||E||g||m)return"Error: 'null_check_filter' template should only have 'column' and 'checkType' properties.";break;case"pattern_match_filter":if(!e)return"Error: 'pattern_match_filter' template requires 'column' property.";if(!g)return"Error: 'pattern_match_filter' template requires 'pattern' property.";if(n||t||S||v||E||y||m)return"Error: 'pattern_match_filter' template should only have 'column', 'pattern', and 'operator' properties.";break;case"custom":if(!m)return"Error: 'custom' template requires 'sql' property with SQL expression.";if(e||n||d||t||S||v||E||y||g)return"Error: 'custom' template should only have 'sql' property.";break;default:return`Error: Invalid template type '${c}'. Supported types are: geographic_filter, date_range_filter, status_filter, category_filter, value_range_filter, null_check_filter, pattern_match_filter, custom.`}return null},si=_zod.z.object({template:Ke,column:_zod.z.string({description:"Column name for the filter"}).optional(),operator:_zod.z.enum(["=","!=",">",">=","<","<=","BETWEEN","IN","NOT IN","LIKE","NOT LIKE","ILIKE"],{description:"SQL operator to use for filtering"}).optional(),values:_zod.z.array(_zod.z.string(),{description:"Values to filter for (geographic, status, or category values)"}).optional(),startDate:_zod.z.string({description:"Start date in YYYY-MM-DD format (e.g., '2023-01-01')"}).optional(),endDate:_zod.z.string({description:"End date in YYYY-MM-DD format (e.g., '2023-12-31')"}).optional(),minValue:_zod.z.number({description:"Minimum value for the range"}).optional(),maxValue:_zod.z.number({description:"Maximum value for the range"}).optional(),checkType:_zod.z.enum(["IS NULL","IS NOT NULL"],{description:"Type of null check to perform"}).optional(),pattern:_zod.z.string({description:"Pattern to match (e.g., '%@gmail.com', 'Mr.%', '%premium%')"}).optional(),sql:ge.optional()}),He=_zod.z.object({segmentType:_zod.z.enum(["template","custom"],{description:"Whether to use a predefined template or create a custom segment"}).default("custom"),name:_zod.z.string({description:"Segment name - descriptive identifier for the segment"}),description:_zod.z.string({description:"Human-readable description of the segment's purpose"}).optional(),public:_zod.z.boolean({description:"Whether the segment is publicly accessible"}).default(!0),templateConfig:si.optional(),sql:ge.optional(),security:_zod.z.object({enabled:_zod.z.boolean({description:"Whether to enable user group-based security for this segment"}).default(!1),includeGroups:_zod.z.union([_zod.z.literal("*"),_zod.z.array(_zod.z.string())],{description:"User groups to include. Use '*' for all users or specify group names"}).optional(),excludeGroups:_zod.z.array(_zod.z.string(),{description:"User groups to exclude from access"}).optional()}).optional(),meta:_zod.z.object({tags:_zod.z.array(_zod.z.string()).optional(),customProperties:_zod.z.record(_zod.z.string(),_zod.z.any()).optional()}).optional()}),ni={configurationType:_zod.z.enum(["single","multiple","bulk_template"],{description:"Configuration type: 'single' for one segment, 'multiple' for several segments, 'bulk_template' for template-based generation"}),segment:He.optional(),segments:_zod.z.array(He,{description:"Array of segment configurations"}).optional(),bulkTemplate:_zod.z.object({baseTemplate:Ke,variations:_zod.z.array(_zod.z.object({name:_zod.z.string({description:"Name of the segment variation"}),values:_zod.z.array(_zod.z.string(),{description:"Values for this variation"}).optional(),customSql:_zod.z.string({description:"Custom SQL to override template"}).optional()}))}).optional(),outputFormat:_zod.z.enum(["segments_only","full_table_structure"],{description:"Whether to output only segments or include them in a full table structure"}).default("segments_only"),tableName:_zod.z.string({description:"Table name for full table structure output"}).optional(),comments:_zod.z.string({description:"Additional comments or notes about the segment configuration"}).optional(),path:_zod.z.string({description:"Absolute path where the file will be stored. example: ~/Documents/project-name/my-segments.yaml"}),fileName:_zod.z.string({description:"File name for the lens segments file. example: my-segments.yaml"})},Ye=i=>{i.tool("create-lens-segments",ei,ni,async({configurationType:c,segment:e,segments:n,bulkTemplate:d,outputFormat:t,tableName:S,path:v,fileName:E})=>{let y=[],g=l=>{let w=ii(l);if(w)throw new Error(w);let{template:s,column:b,values:u,operator:h,startDate:f,endDate:p,minValue:k,maxValue:N,checkType:P,pattern:_,sql:M}=l;switch(s){case"geographic_filter":return h==="IN"&&u.length>1?`{TABLE}.${b} IN ('${u.join("', '")}')`:h==="LIKE"?u.map(O=>`{TABLE}.${b} LIKE '%${O}%'`).join(" OR "):`{TABLE}.${b} ${h||"="} '${u[0]}'`;case"date_range_filter":if(f&&p)return h==="BETWEEN"?`{TABLE}.${b} BETWEEN '${f}' AND '${p}'`:`{TABLE}.${b} >= '${f}' AND {TABLE}.${b} <= '${p}'`;if(f)return`{TABLE}.${b} ${h||">="} '${f}'`;if(p)return`{TABLE}.${b} ${h||"<="} '${p}'`;break;case"status_filter":return h==="IN"&&u.length>1?`{TABLE}.${b} IN ('${u.join("', '")}')`:h==="NOT IN"?`{TABLE}.${b} NOT IN ('${u.join("', '")}')`:`{TABLE}.${b} ${h||"="} '${u[0]}'`;case"category_filter":return h==="IN"&&u.length>1?`{TABLE}.${b} IN ('${u.join("', '")}')`:h==="LIKE"?u.map(O=>`{TABLE}.${b} LIKE '%${O}%'`).join(" OR "):`{TABLE}.${b} ${h||"="} '${u[0]}'`;case"value_range_filter":if(k!==void 0&&N!==void 0)return h==="BETWEEN"?`{TABLE}.${b} BETWEEN ${k} AND ${N}`:`{TABLE}.${b} >= ${k} AND {TABLE}.${b} <= ${N}`;if(k!==void 0)return`{TABLE}.${b} ${h||">="} ${k}`;if(N!==void 0)return`{TABLE}.${b} ${h||"<="} ${N}`;break;case"null_check_filter":return`{TABLE}.${b} ${P}`;case"pattern_match_filter":return`{TABLE}.${b} ${h||"LIKE"} '${_}'`;case"custom":return M;default:throw new Error(`Unsupported template: ${s}`)}throw new Error(`Unable to generate SQL for template: ${s}`)},m=l=>{let w={name:l.name,public:l.public!==void 0?l.public:!0};if(l.description&&(w.description=l.description),l.segmentType==="template"&&l.templateConfig)w.sql=g(l.templateConfig);else if(l.sql)w.sql=l.sql;else throw new Error(`Segment '${l.name}' must have either templateConfig or custom sql`);if(_optionalChain([l, 'access', _49 => _49.security, 'optionalAccess', _50 => _50.enabled])){let s={};(l.security.includeGroups||l.security.excludeGroups)&&(s.secure={user_groups:{}},l.security.includeGroups&&(s.secure.user_groups.includes=l.security.includeGroups),l.security.excludeGroups&&(s.secure.user_groups.excludes=l.security.excludeGroups)),_optionalChain([l, 'access', _51 => _51.meta, 'optionalAccess', _52 => _52.tags])&&(s.tags=l.meta.tags),_optionalChain([l, 'access', _53 => _53.meta, 'optionalAccess', _54 => _54.customProperties])&&Object.assign(s,l.meta.customProperties),Object.keys(s).length>0&&(w.meta=s)}return w};try{if(c==="single"){if(!e)throw new Error("Segment configuration is required for single type");y.push(m(e))}else if(c==="multiple"){if(!n||n.length===0)throw new Error("Segments array is required for multiple type");y=n.map(m)}else if(c==="bulk_template"){if(!d)throw new Error("Bulk template configuration is required for bulk_template type");let{baseTemplate:u,variations:h}=d;y=h.map(f=>{let p={template:u};return f.values&&(p.values=f.values),f.customSql&&(p.sql=f.customSql,p.template="custom"),m({name:f.name,segmentType:"template",templateConfig:p,public:!0})})}let l=()=>["# Lens Segments Configuration","# Reusable filters for consistent data access patterns","# ","# Segments provide:","# - Reusable filter logic across multiple queries","# - Row-level security and data governance","# - Consistent business rule application","# - Performance optimization through pre-defined filters","# ",`# Configuration Type: ${c}`,`# Number of Segments: ${y.length}`,"# ","# Usage in Lens models:","# - Reference segments in measures and dimensions","# - Apply as default filters in cubes","# - Use for user group-based data access control","# ","# Segment SQL uses {TABLE} placeholder for table reference","# Example: {TABLE}.status = 'active' AND {TABLE}.created_date >= '2023-01-01'",""].join(`
240
240
  `),w;if(t==="full_table_structure"){let u={name:S||"example_table",segments:y};w=l()+`table:
241
241
  `+_yaml.stringify.call(void 0, u).split(`
242
242
  `).map(h=>` ${h}`).join(`
@@ -262,7 +262,7 @@ There are two main approaches for designing views:
262
262
 
263
263
  2. **Metrics-first approach**: Views focused on specific performance metrics, each containing one key measure with relevant dimensions for grouping and filtering. Each view represents a specific business metric over time.
264
264
 
265
- Views reference dimensions, measures, and segments from multiple logical tables but don't have any measures, dimensions, or segments of their own.`,ji=_zod.z.string({description:"Cron expression for scheduling (e.g., '*/5 * * * *' for every 5 minutes, '0 */6 * * *' for every 6 hours)"}).regex(/^(\*|([0-5]?\d)) (\*|([01]?\d|2[0-3])) (\*|([01]?\d|[12]\d|3[01])) (\*|([01]?\d)) (\*|[0-6])$/,"Invalid cron expression format"),Ni=_zod.z.object({expression:ji.describe("Cron expression for metric refresh schedule (e.g., '*/5 * * * *', '0 */6 * * *')"),timezone:_zod.z.string({description:"Timezone for metric calculations in TZ database format (e.g., 'UTC', 'America/Vancouver', 'America/Toronto')"}).default("UTC"),window:_zod.z.enum(["day","week","month","quarter","year"],{description:"Time window for metric aggregation - defines the granularity of metric calculation"}),excludes:_zod.z.array(_zod.z.string(),{description:"List of measures or dimensions to exclude from the metric view (e.g., ['purchases', 'source'])"}).optional()}),Ri=_zod.z.object({timeseries:_zod.z.string({description:"Time dimension for Iris dashboard visualization (format: 'table.column_name', e.g., 'sales.invoice_date')"}),excludes:_zod.z.array(_zod.z.string(),{description:"List of fields to exclude from Iris dashboard (e.g., ['sales.source', 'sales.invoice_date'])"}).optional(),refresh:_zod.z.object({every:_zod.z.string({description:"Refresh interval for Iris dashboard (e.g., '24h', '12h', '6h', '1h')"}).regex(/^\d+[hmd]$/,"Format should be like '24h', '12h', '30m', '15m'")}).optional()}),Ze=_zod.z.object({title:_zod.z.string({description:"Human-readable title for the view/metric (e.g., 'Customer Spending by Product Category')"}).optional(),tags:_zod.z.array(_zod.z.string(),{description:"Tags for categorization and discovery. Common patterns: ['DPDomain.{Domain}', 'DPUsecase.{UseCase}', 'DPTier.{Tier}'] (e.g., ['DPDomain.Sales', 'DPUsecase.Revenue Analysis', 'DPTier.Consumer Aligned'])"}).optional(),export_to_iris:_zod.z.boolean({description:"Whether to export this view to Iris dashboard for visualization (mainly for entity-first views)"}).optional(),iris:Ri.optional(),metric:Ni.optional(),refresh:_zod.z.object({every:_zod.z.string({description:"General refresh interval for the view (e.g., '24h', '12h', '6h')"}).regex(/^\d+[hmd]$/,"Format should be like '24h', '12h', '30m'")}).optional()}),Xe=_zod.z.object({join_path:_zod.z.string({description:"Name of the logical table to include in the view. Must match a table defined in your Lens model (e.g., 'sales', 'customer', 'product', 'marketing_campaign')"}),prefix:_zod.z.boolean({description:"Whether to prefix the included fields with the table name. Set to true to avoid naming conflicts (e.g., 'customer_name' vs 'name')"}).default(!1),includes:_zod.z.array(_zod.z.string(),{description:"List of specific measures, dimensions, or segments to include from this table (e.g., ['customer_id', 'total_revenue', 'invoice_date', 'churn_rate'])"}),excludes:_zod.z.array(_zod.z.string(),{description:"List of fields to exclude from this table (alternative to includes for when you want most fields)"}).optional()}),et=_zod.z.object({name:_zod.z.string({description:"View name - should be descriptive and follow naming conventions. For metrics-first: use metric name (e.g., 'customer_churn_rate', 'monthly_revenue'). For entity-first: use entity name (e.g., 'customer_360', 'product_analysis')"}),description:_zod.z.string({description:"Detailed description of the view's purpose and what insights it provides (e.g., 'This metric tracks customer churn rate over time, helping identify retention trends and at-risk customer segments')"}),public:_zod.z.boolean({description:"Whether the view is publicly accessible to all users or restricted"}).default(!0),meta:Ze.optional(),tables:_zod.z.array(Xe,{description:"List of tables to include in this view with their specific field selections"}).min(1,"At least one table must be included in the view")}),Jn=_zod.z.object({views:_zod.z.array(et,{description:"Array of view definitions - you can define multiple views for different use cases or metrics"}).min(1,"At least one view must be defined")}),Ii={viewType:_zod.z.enum(["single","multiple"],{description:"Whether to create a single view or multiple views in one configuration"}).default("single"),name:_zod.z.string({description:"View name - descriptive identifier for the view (required for single view type)"}).optional(),description:_zod.z.string({description:"Detailed description of the view's purpose (required for single view type)"}).optional(),public:_zod.z.boolean({description:"Whether the view is publicly accessible"}).default(!0),approach:_zod.z.enum(["entity-first","metrics-first"],{description:"Design approach: 'entity-first' for comprehensive entity views, 'metrics-first' for specific business metrics"}).optional(),meta:Ze.optional(),tables:_zod.z.array(Xe,{description:"List of tables to include in this view (required for single view type)"}).optional(),views:_zod.z.array(et,{description:"Array of view definitions (required for multiple view type)"}).optional(),comments:_zod.z.string({description:"Additional comments or notes about the view configuration"}).optional(),path:_zod.z.string({description:"Absolute path where the file will be stored. example: ~/Documents/project-name/my-views.yaml"}),fileName:_zod.z.string({description:"File name for the lens views file. example: my-views.yaml"})},tt=i=>{i.tool("create-lens-views",Di,Ii,async({viewType:c,name:e,description:n,public:d,approach:t,meta:S,tables:v,views:E,comments:y,path:g,fileName:m})=>{let l;if(c==="multiple"){if(!E||E.length===0)throw new Error("Views array is required for multiple view type");l={views:E}}else{if(!e||!n||!v||v.length===0)throw new Error("Name, description, and tables are required for single view type");let u={name:e,description:n,public:d,tables:v};S&&(u.meta=S),l={views:[u]}}let w=()=>{let u=[];return y&&u.push(`# ${y}`),t&&(t==="entity-first"?(u.push("# Entity-first approach: Comprehensive view of entity with related measures and dimensions"),u.push("# Use this for denormalized tables that describe entities fully")):(u.push("# Metrics-first approach: Focused on specific business metrics"),u.push("# Each view represents a key performance indicator with relevant dimensions"))),u.push("# Views reference dimensions, measures, and segments from logical tables"),u.push("# Views don't define their own measures/dimensions - they include them from tables"),c==="multiple"&&u.push("# Multiple views defined for different use cases or metrics"),u.join(`
265
+ Views reference dimensions, measures, and segments from multiple logical tables but don't have any measures, dimensions, or segments of their own.`,ji=_zod.z.string({description:"Cron expression for scheduling (e.g., '*/5 * * * *' for every 5 minutes, '0 */6 * * *' for every 6 hours)"}).regex(/^(\*|([0-5]?\d)) (\*|([01]?\d|2[0-3])) (\*|([01]?\d|[12]\d|3[01])) (\*|([01]?\d)) (\*|[0-6])$/,"Invalid cron expression format"),Ni=_zod.z.object({expression:ji.describe("Cron expression for metric refresh schedule (e.g., '*/5 * * * *', '0 */6 * * *')"),timezone:_zod.z.string({description:"Timezone for metric calculations in TZ database format (e.g., 'UTC', 'America/Vancouver', 'America/Toronto')"}).default("UTC"),window:_zod.z.enum(["day","week","month","quarter","year"],{description:"Time window for metric aggregation - defines the granularity of metric calculation"}),excludes:_zod.z.array(_zod.z.string(),{description:"List of measures or dimensions to exclude from the metric view (e.g., ['purchases', 'source'])"}).optional()}),Ri=_zod.z.object({timeseries:_zod.z.string({description:"Time dimension for Iris dashboard visualization (format: 'table.column_name', e.g., 'sales.invoice_date')"}),excludes:_zod.z.array(_zod.z.string(),{description:"List of fields to exclude from Iris dashboard (e.g., ['sales.source', 'sales.invoice_date'])"}).optional(),refresh:_zod.z.object({every:_zod.z.string({description:"Refresh interval for Iris dashboard (e.g., '24h', '12h', '6h', '1h')"}).regex(/^\d+[hmd]$/,"Format should be like '24h', '12h', '30m', '15m'")}).optional()}),Ze=_zod.z.object({title:_zod.z.string({description:"Human-readable title for the view/metric (e.g., 'Customer Spending by Product Category')"}).optional(),tags:_zod.z.array(_zod.z.string(),{description:"Tags for categorization and discovery. Common patterns: ['DPDomain.{Domain}', 'DPUsecase.{UseCase}', 'DPTier.{Tier}'] (e.g., ['DPDomain.Sales', 'DPUsecase.Revenue Analysis', 'DPTier.Consumer Aligned'])"}).optional(),export_to_iris:_zod.z.boolean({description:"Whether to export this view to Iris dashboard for visualization (mainly for entity-first views)"}).optional(),iris:Ri.optional(),metric:Ni.optional(),refresh:_zod.z.object({every:_zod.z.string({description:"General refresh interval for the view (e.g., '24h', '12h', '6h')"}).regex(/^\d+[hmd]$/,"Format should be like '24h', '12h', '30m'")}).optional()}),Xe=_zod.z.object({join_path:_zod.z.string({description:"Name of the logical table to include in the view. Must match a table defined in your Lens model (e.g., 'sales', 'customer', 'product', 'marketing_campaign')"}),prefix:_zod.z.boolean({description:"Whether to prefix the included fields with the table name. Set to true to avoid naming conflicts (e.g., 'customer_name' vs 'name')"}).default(!1),includes:_zod.z.array(_zod.z.string(),{description:"List of specific measures, dimensions, or segments to include from this table (e.g., ['customer_id', 'total_revenue', 'invoice_date', 'churn_rate'])"}),excludes:_zod.z.array(_zod.z.string(),{description:"List of fields to exclude from this table (alternative to includes for when you want most fields)"}).optional()}),et=_zod.z.object({name:_zod.z.string({description:"View name - should be descriptive and follow naming conventions. For metrics-first: use metric name (e.g., 'customer_churn_rate', 'monthly_revenue'). For entity-first: use entity name (e.g., 'customer_360', 'product_analysis')"}),description:_zod.z.string({description:"Detailed description of the view's purpose and what insights it provides (e.g., 'This metric tracks customer churn rate over time, helping identify retention trends and at-risk customer segments')"}),public:_zod.z.boolean({description:"Whether the view is publicly accessible to all users or restricted"}).default(!0),meta:Ze.optional(),tables:_zod.z.array(Xe,{description:"List of tables to include in this view with their specific field selections"}).min(1,"At least one table must be included in the view")}),ea=_zod.z.object({views:_zod.z.array(et,{description:"Array of view definitions - you can define multiple views for different use cases or metrics"}).min(1,"At least one view must be defined")}),Ii={viewType:_zod.z.enum(["single","multiple"],{description:"Whether to create a single view or multiple views in one configuration"}).default("single"),name:_zod.z.string({description:"View name - descriptive identifier for the view (required for single view type)"}).optional(),description:_zod.z.string({description:"Detailed description of the view's purpose (required for single view type)"}).optional(),public:_zod.z.boolean({description:"Whether the view is publicly accessible"}).default(!0),approach:_zod.z.enum(["entity-first","metrics-first"],{description:"Design approach: 'entity-first' for comprehensive entity views, 'metrics-first' for specific business metrics"}).optional(),meta:Ze.optional(),tables:_zod.z.array(Xe,{description:"List of tables to include in this view (required for single view type)"}).optional(),views:_zod.z.array(et,{description:"Array of view definitions (required for multiple view type)"}).optional(),comments:_zod.z.string({description:"Additional comments or notes about the view configuration"}).optional(),path:_zod.z.string({description:"Absolute path where the file will be stored. example: ~/Documents/project-name/my-views.yaml"}),fileName:_zod.z.string({description:"File name for the lens views file. example: my-views.yaml"})},tt=i=>{i.tool("create-lens-views",Di,Ii,async({viewType:c,name:e,description:n,public:d,approach:t,meta:S,tables:v,views:E,comments:y,path:g,fileName:m})=>{let l;if(c==="multiple"){if(!E||E.length===0)throw new Error("Views array is required for multiple view type");l={views:E}}else{if(!e||!n||!v||v.length===0)throw new Error("Name, description, and tables are required for single view type");let u={name:e,description:n,public:d,tables:v};S&&(u.meta=S),l={views:[u]}}let w=()=>{let u=[];return y&&u.push(`# ${y}`),t&&(t==="entity-first"?(u.push("# Entity-first approach: Comprehensive view of entity with related measures and dimensions"),u.push("# Use this for denormalized tables that describe entities fully")):(u.push("# Metrics-first approach: Focused on specific business metrics"),u.push("# Each view represents a key performance indicator with relevant dimensions"))),u.push("# Views reference dimensions, measures, and segments from logical tables"),u.push("# Views don't define their own measures/dimensions - they include them from tables"),c==="multiple"&&u.push("# Multiple views defined for different use cases or metrics"),u.join(`
266
266
  `)},s=_yaml.stringify.call(void 0, l),b=w()+`
267
267
 
268
268
  `+s;try{let u=g.includes(".yaml")||g.includes(".yml")?g:g.endsWith("/")?g+m:`${g}/${m}`,h=_path2.default.dirname(u);return _fs.existsSync.call(void 0, h)||_fs.mkdirSync.call(void 0, h,{recursive:!0}),_fs.writeFileSync.call(void 0, u,b),{content:[{type:"text",text:`Lens views file created successfully at ${u}`},{type:"text",text:`File content: ${b}`}]}}catch(u){return{content:[{type:"text",text:`Error creating lens views file: ${u}`}]}}})};var Ui=`Lens User Groups are used to manage both data access and API scopes, which control access to specific functionalities and endpoints in the Lens semantic layer. This forms part of the access policy, ensuring users interact only with the data and features they are authorized to use.
@@ -286,7 +286,7 @@ User groups extend governance to the Lens Studio Interface, where access to spec
286
286
  - 'data': Access to data query endpoints (/v2/load, /v2/sql) - retrieve and analyze data
287
287
  - 'graphql': Access to GraphQL endpoint (/v2/graphql) - GraphQL-based queries
288
288
  - 'jobs': Access to job-related endpoints (advanced functionality)
289
- - 'source': Access to source-related endpoints (advanced functionality)`}),ot=_zod.z.union([_zod.z.literal("*"),_zod.z.string().regex(/^users:id:.+$/,"User ID must follow pattern 'users:id:username'")],{description:"User specification pattern: '*' for all users or 'users:id:username' for specific users (e.g., 'users:id:johndoe', 'users:id:iamgroot')"}),ce=_zod.z.union([_zod.z.literal("*"),_zod.z.array(ot,{description:"List of users to include in this group. Use specific user IDs for small groups or '*' for all users"})],{description:"Users to include in this group. Use '*' to include all users or specify individual user IDs"}),ae=_zod.z.array(ot,{description:"List of users to exclude from this group (e.g., ['users:id:tempuser', 'users:id:guest'])"}),oa=_zod.z.object({name:_zod.z.string({description:"Unique group name - should be descriptive and follow naming conventions (e.g., 'data_analyst', 'data_engineer', 'business_user', 'admin')"}),description:_zod.z.string({description:"Brief description of the user group's purpose and the type of users it contains (e.g., 'Data analysts responsible for reporting and visualization tasks')"}).optional(),api_scopes:_zod.z.array(Z,{description:"List of API scopes this group can access. Follow principle of least privilege - grant only necessary access"}).optional(),includes:ce,excludes:ae.optional()}),be=_zod.z.enum(["data_analyst","data_engineer","data_scientist","business_user","admin","viewer","developer","custom"],{description:"Predefined role templates with typical API scope configurations. Choose 'custom' for fully custom groups"}),ia=_zod.z.object({template:be,name:_zod.z.string({description:"Group name - will be used as-is or can override template default"}).optional(),description:_zod.z.string({description:"Custom description for this group"}).optional(),customApiScopes:_zod.z.array(Z,{description:"Override default API scopes for this template"}).optional(),includes:ce,excludes:ae.optional(),additionalProperties:_zod.z.record(_zod.z.string(),_zod.z.any(),{description:"Additional custom properties for the group"}).optional()}),Fi=i=>{let{type:c,group:e}=i;switch(c){case"custom":if(!e)return"Error: 'custom' type requires 'group' property with userGroupSchema configuration.";if(!e.name)return"Error: Custom user group requires 'name' property.";if(!e.includes)return"Error: Custom user group requires 'includes' property.";if(e.template||e.customApiScopes||e.additionalProperties)return"Error: Custom user group should not have template-specific properties ('template', 'customApiScopes', 'additionalProperties').";break;case"template":if(!e)return"Error: 'template' type requires 'group' property with templateUserGroupSchema configuration.";if(!e.template)return"Error: Template user group requires 'template' property.";if(!e.includes)return"Error: Template user group requires 'includes' property.";break;default:return`Error: Invalid user group configuration type '${c}'. Supported types are: custom, template.`}return null},ye=_zod.z.object({type:_zod.z.enum(["custom","template"],{description:"Type of user group configuration: 'custom' for fully custom groups, 'template' for template-based groups"}),group:_zod.z.object({name:_zod.z.string({description:"Group name - will be used as-is or can override template default"}).optional(),description:_zod.z.string({description:"Custom description for this group"}).optional(),includes:ce,excludes:ae.optional(),api_scopes:_zod.z.array(Z,{description:"List of API scopes this group can access. Follow principle of least privilege - grant only necessary access"}).optional(),template:be.optional(),customApiScopes:_zod.z.array(Z,{description:"Override default API scopes for this template"}).optional(),additionalProperties:_zod.z.record(_zod.z.string(),_zod.z.any(),{description:"Additional custom properties for the group"}).optional()})}),sa=_zod.z.object({groups:_zod.z.array(ye,{description:"Array of user group configurations"}).min(1,"At least one user group must be defined")}),Bi=_zod.z.object({baseTemplate:be,variations:_zod.z.array(_zod.z.object({name:_zod.z.string({description:"Name for this variation (e.g., 'marketing_analyst', 'finance_analyst')"}),description:_zod.z.string({description:"Description for this variation"}).optional(),customApiScopes:_zod.z.array(Z).optional(),includes:ce,excludes:ae.optional()}),{description:"Variations of the base template to generate"}).min(1,"At least one variation must be specified"),commonProperties:_zod.z.object({apiScopes:_zod.z.array(Z).optional(),excludes:ae.optional()}).optional()}),zi={configurationType:_zod.z.enum(["single","multiple","bulk_template"],{description:"Type of user group configuration: 'single' for one group, 'multiple' for several groups, 'bulk_template' for generating multiple groups from templates"}).default("single"),userGroup:ye.optional(),userGroups:_zod.z.array(ye,{description:"Array of user group configurations for multiple groups"}).optional(),bulkTemplate:Bi.optional(),includeDefaultGroup:_zod.z.boolean({description:"Whether to include a default group that gives all users basic access"}).default(!0),defaultGroupConfig:_zod.z.object({name:_zod.z.string().default("default"),description:_zod.z.string().default("Default user group with basic access"),api_scopes:_zod.z.array(Z).default(["data","graphql"]),includes:ce.default("*")}).optional(),outputFormat:_zod.z.enum(["user_groups_only","complete_file"],{description:"Whether to output only user groups or include them in a complete user_groups.yaml file structure"}).default("complete_file"),comments:_zod.z.string({description:"Additional comments or notes about the user group configuration"}).optional(),path:_zod.z.string({description:"Absolute path where the file will be stored. example: ~/Documents/project-name/my-user-groups.yaml"}),fileName:_zod.z.string({description:"File name for the lens user groups file. example: my-user-groups.yaml"})},it=i=>{i.tool("create-lens-user-groups",Ui,zi,async({configurationType:c,userGroup:e,userGroups:n,bulkTemplate:d,includeDefaultGroup:t,defaultGroupConfig:S,outputFormat:v,comments:E,path:y,fileName:g})=>{let m=[],l=f=>{switch(f){case"data_analyst":return["meta","data","graphql"];case"data_engineer":return["meta","data","graphql","jobs"];case"data_scientist":return["meta","data","graphql","jobs","source"];case"business_user":return["meta","data"];case"admin":return["meta","data","graphql","jobs","source"];case"viewer":return["meta"];case"developer":return["meta","data","graphql","jobs"];default:return["meta","data"]}},w=f=>f==="custom"?"custom_group":f,s=f=>{switch(f){case"data_analyst":return"Data analysts responsible for reporting, visualization, and business intelligence tasks";case"data_engineer":return"Data engineers who build and maintain data pipelines, transformations, and infrastructure";case"data_scientist":return"Data scientists with full access to data, modeling capabilities, and source management";case"business_user":return"Business users who need access to view and analyze data for decision making";case"admin":return"Administrators with full access to all Lens functionality and management capabilities";case"viewer":return"Read-only users who can view metadata but cannot query data";case"developer":return"Developers who build applications and integrations using Lens APIs";default:return"Custom user group with specific access requirements"}},b=f=>{let p=Fi(f);if(p)throw new Error(p);if(f.type==="template"){let{group:k}=f,N=k.template;return{name:k.name||w(N),description:k.description||s(N),api_scopes:k.customApiScopes||l(N),includes:k.includes,...k.excludes&&{excludes:k.excludes},...k.additionalProperties&&k.additionalProperties}}else{let{group:k}=f;return{name:k.name,...k.description&&{description:k.description},...k.api_scopes&&{api_scopes:k.api_scopes},includes:k.includes,...k.excludes&&{excludes:k.excludes}}}};if(c==="single"){if(!e)throw new Error("User group configuration is required for single type");m.push(b(e))}else if(c==="multiple"){if(!n||n.length===0)throw new Error("User groups array is required for multiple type");m=n.map(b)}else if(c==="bulk_template"){if(!d)throw new Error("Bulk template configuration is required for bulk_template type");let{baseTemplate:f,variations:p,commonProperties:k}=d;m=p.map(N=>({name:N.name,description:N.description||s(f),api_scopes:N.customApiScopes||_optionalChain([k, 'optionalAccess', _58 => _58.apiScopes])||l(f),includes:N.includes,excludes:N.excludes||_optionalChain([k, 'optionalAccess', _59 => _59.excludes])}))}if(t){let f={name:_optionalChain([S, 'optionalAccess', _60 => _60.name])||"default",description:_optionalChain([S, 'optionalAccess', _61 => _61.description])||"Default user group with basic access",api_scopes:_optionalChain([S, 'optionalAccess', _62 => _62.api_scopes])||["data","graphql"],includes:_optionalChain([S, 'optionalAccess', _63 => _63.includes])||"*"};m.unshift(f)}let u=()=>["# Lens User Groups Configuration","# This file defines user groups for access control in Lens semantic layer","# ","# User groups control both API access and data visibility:","# - API Scopes: Control access to specific REST endpoints","# - Data Access: Define who can access what data through inclusion/exclusion","# - Priority: First-listed group takes precedence for users in multiple groups","# ","# API Scopes:","# - meta: Metadata endpoints (/v2/meta) - sources, authors, timezones","# - data: Data query endpoints (/v2/load, /v2/sql) - retrieve and analyze data","# - graphql: GraphQL endpoint (/v2/graphql) - GraphQL-based queries","# - jobs: Job-related endpoints (advanced functionality)","# - source: Source-related endpoints (advanced functionality)","# ","# User Patterns:","# - '*': All users","# - 'users:id:username': Specific user (e.g., 'users:id:johndoe')","# ",...E?["# Additional Notes:",`# ${E}`,"# "]:[]].join(`
289
+ - 'source': Access to source-related endpoints (advanced functionality)`}),ot=_zod.z.union([_zod.z.literal("*"),_zod.z.string().regex(/^users:id:.+$/,"User ID must follow pattern 'users:id:username'")],{description:"User specification pattern: '*' for all users or 'users:id:username' for specific users (e.g., 'users:id:johndoe', 'users:id:iamgroot')"}),ce=_zod.z.union([_zod.z.literal("*"),_zod.z.array(ot,{description:"List of users to include in this group. Use specific user IDs for small groups or '*' for all users"})],{description:"Users to include in this group. Use '*' to include all users or specify individual user IDs"}),ae=_zod.z.array(ot,{description:"List of users to exclude from this group (e.g., ['users:id:tempuser', 'users:id:guest'])"}),na=_zod.z.object({name:_zod.z.string({description:"Unique group name - should be descriptive and follow naming conventions (e.g., 'data_analyst', 'data_engineer', 'business_user', 'admin')"}),description:_zod.z.string({description:"Brief description of the user group's purpose and the type of users it contains (e.g., 'Data analysts responsible for reporting and visualization tasks')"}).optional(),api_scopes:_zod.z.array(Z,{description:"List of API scopes this group can access. Follow principle of least privilege - grant only necessary access"}).optional(),includes:ce,excludes:ae.optional()}),be=_zod.z.enum(["data_analyst","data_engineer","data_scientist","business_user","admin","viewer","developer","custom"],{description:"Predefined role templates with typical API scope configurations. Choose 'custom' for fully custom groups"}),aa=_zod.z.object({template:be,name:_zod.z.string({description:"Group name - will be used as-is or can override template default"}).optional(),description:_zod.z.string({description:"Custom description for this group"}).optional(),customApiScopes:_zod.z.array(Z,{description:"Override default API scopes for this template"}).optional(),includes:ce,excludes:ae.optional(),additionalProperties:_zod.z.record(_zod.z.string(),_zod.z.any(),{description:"Additional custom properties for the group"}).optional()}),Fi=i=>{let{type:c,group:e}=i;switch(c){case"custom":if(!e)return"Error: 'custom' type requires 'group' property with userGroupSchema configuration.";if(!e.name)return"Error: Custom user group requires 'name' property.";if(!e.includes)return"Error: Custom user group requires 'includes' property.";if(e.template||e.customApiScopes||e.additionalProperties)return"Error: Custom user group should not have template-specific properties ('template', 'customApiScopes', 'additionalProperties').";break;case"template":if(!e)return"Error: 'template' type requires 'group' property with templateUserGroupSchema configuration.";if(!e.template)return"Error: Template user group requires 'template' property.";if(!e.includes)return"Error: Template user group requires 'includes' property.";break;default:return`Error: Invalid user group configuration type '${c}'. Supported types are: custom, template.`}return null},ye=_zod.z.object({type:_zod.z.enum(["custom","template"],{description:"Type of user group configuration: 'custom' for fully custom groups, 'template' for template-based groups"}),group:_zod.z.object({name:_zod.z.string({description:"Group name - will be used as-is or can override template default"}).optional(),description:_zod.z.string({description:"Custom description for this group"}).optional(),includes:ce,excludes:ae.optional(),api_scopes:_zod.z.array(Z,{description:"List of API scopes this group can access. Follow principle of least privilege - grant only necessary access"}).optional(),template:be.optional(),customApiScopes:_zod.z.array(Z,{description:"Override default API scopes for this template"}).optional(),additionalProperties:_zod.z.record(_zod.z.string(),_zod.z.any(),{description:"Additional custom properties for the group"}).optional()})}),ca=_zod.z.object({groups:_zod.z.array(ye,{description:"Array of user group configurations"}).min(1,"At least one user group must be defined")}),Bi=_zod.z.object({baseTemplate:be,variations:_zod.z.array(_zod.z.object({name:_zod.z.string({description:"Name for this variation (e.g., 'marketing_analyst', 'finance_analyst')"}),description:_zod.z.string({description:"Description for this variation"}).optional(),customApiScopes:_zod.z.array(Z).optional(),includes:ce,excludes:ae.optional()}),{description:"Variations of the base template to generate"}).min(1,"At least one variation must be specified"),commonProperties:_zod.z.object({apiScopes:_zod.z.array(Z).optional(),excludes:ae.optional()}).optional()}),zi={configurationType:_zod.z.enum(["single","multiple","bulk_template"],{description:"Type of user group configuration: 'single' for one group, 'multiple' for several groups, 'bulk_template' for generating multiple groups from templates"}).default("single"),userGroup:ye.optional(),userGroups:_zod.z.array(ye,{description:"Array of user group configurations for multiple groups"}).optional(),bulkTemplate:Bi.optional(),includeDefaultGroup:_zod.z.boolean({description:"Whether to include a default group that gives all users basic access"}).default(!0),defaultGroupConfig:_zod.z.object({name:_zod.z.string().default("default"),description:_zod.z.string().default("Default user group with basic access"),api_scopes:_zod.z.array(Z).default(["data","graphql"]),includes:ce.default("*")}).optional(),outputFormat:_zod.z.enum(["user_groups_only","complete_file"],{description:"Whether to output only user groups or include them in a complete user_groups.yaml file structure"}).default("complete_file"),comments:_zod.z.string({description:"Additional comments or notes about the user group configuration"}).optional(),path:_zod.z.string({description:"Absolute path where the file will be stored. example: ~/Documents/project-name/my-user-groups.yaml"}),fileName:_zod.z.string({description:"File name for the lens user groups file. example: my-user-groups.yaml"})},it=i=>{i.tool("create-lens-user-groups",Ui,zi,async({configurationType:c,userGroup:e,userGroups:n,bulkTemplate:d,includeDefaultGroup:t,defaultGroupConfig:S,outputFormat:v,comments:E,path:y,fileName:g})=>{let m=[],l=f=>{switch(f){case"data_analyst":return["meta","data","graphql"];case"data_engineer":return["meta","data","graphql","jobs"];case"data_scientist":return["meta","data","graphql","jobs","source"];case"business_user":return["meta","data"];case"admin":return["meta","data","graphql","jobs","source"];case"viewer":return["meta"];case"developer":return["meta","data","graphql","jobs"];default:return["meta","data"]}},w=f=>f==="custom"?"custom_group":f,s=f=>{switch(f){case"data_analyst":return"Data analysts responsible for reporting, visualization, and business intelligence tasks";case"data_engineer":return"Data engineers who build and maintain data pipelines, transformations, and infrastructure";case"data_scientist":return"Data scientists with full access to data, modeling capabilities, and source management";case"business_user":return"Business users who need access to view and analyze data for decision making";case"admin":return"Administrators with full access to all Lens functionality and management capabilities";case"viewer":return"Read-only users who can view metadata but cannot query data";case"developer":return"Developers who build applications and integrations using Lens APIs";default:return"Custom user group with specific access requirements"}},b=f=>{let p=Fi(f);if(p)throw new Error(p);if(f.type==="template"){let{group:k}=f,N=k.template;return{name:k.name||w(N),description:k.description||s(N),api_scopes:k.customApiScopes||l(N),includes:k.includes,...k.excludes&&{excludes:k.excludes},...k.additionalProperties&&k.additionalProperties}}else{let{group:k}=f;return{name:k.name,...k.description&&{description:k.description},...k.api_scopes&&{api_scopes:k.api_scopes},includes:k.includes,...k.excludes&&{excludes:k.excludes}}}};if(c==="single"){if(!e)throw new Error("User group configuration is required for single type");m.push(b(e))}else if(c==="multiple"){if(!n||n.length===0)throw new Error("User groups array is required for multiple type");m=n.map(b)}else if(c==="bulk_template"){if(!d)throw new Error("Bulk template configuration is required for bulk_template type");let{baseTemplate:f,variations:p,commonProperties:k}=d;m=p.map(N=>({name:N.name,description:N.description||s(f),api_scopes:N.customApiScopes||_optionalChain([k, 'optionalAccess', _58 => _58.apiScopes])||l(f),includes:N.includes,excludes:N.excludes||_optionalChain([k, 'optionalAccess', _59 => _59.excludes])}))}if(t){let f={name:_optionalChain([S, 'optionalAccess', _60 => _60.name])||"default",description:_optionalChain([S, 'optionalAccess', _61 => _61.description])||"Default user group with basic access",api_scopes:_optionalChain([S, 'optionalAccess', _62 => _62.api_scopes])||["data","graphql"],includes:_optionalChain([S, 'optionalAccess', _63 => _63.includes])||"*"};m.unshift(f)}let u=()=>["# Lens User Groups Configuration","# This file defines user groups for access control in Lens semantic layer","# ","# User groups control both API access and data visibility:","# - API Scopes: Control access to specific REST endpoints","# - Data Access: Define who can access what data through inclusion/exclusion","# - Priority: First-listed group takes precedence for users in multiple groups","# ","# API Scopes:","# - meta: Metadata endpoints (/v2/meta) - sources, authors, timezones","# - data: Data query endpoints (/v2/load, /v2/sql) - retrieve and analyze data","# - graphql: GraphQL endpoint (/v2/graphql) - GraphQL-based queries","# - jobs: Job-related endpoints (advanced functionality)","# - source: Source-related endpoints (advanced functionality)","# ","# User Patterns:","# - '*': All users","# - 'users:id:username': Specific user (e.g., 'users:id:johndoe')","# ",...E?["# Additional Notes:",`# ${E}`,"# "]:[]].join(`
290
290
  `),h=v==="user_groups_only"?`${u()}
291
291
  user_groups:
292
292
  ${_yaml.stringify.call(void 0, m).split(`
@@ -351,5 +351,5 @@ BEST PRACTICES:
351
351
 
352
352
  Keywords: SQL, Trino, cross-model, JOIN, CTE, window functions, multi-model analytics`;async function nt({server:i,apiKey:c,fqdn:e,userId:n}){i.tool("trino-query",Vi,{sqlQuery:_zod2.default.string({description:"SQL query using two-part table names: semantic_model_name.table_name (e.g., sales_360.orders). Supports full Trino SQL syntax. Example: SELECT customer_name, SUM(revenue) FROM sales_360.orders WHERE order_date >= DATE '2024-01-01' GROUP BY customer_name LIMIT 10"})},async({sqlQuery:d})=>{try{let S=await st({fqdn:e,apiKey:c,userId:n}).query({query:d,catalog:"icebase"}),v=0,E,y;return await S.forEach(g=>{if(v==0){let m=g.columns.map(({name:l,type:w})=>`${l}-${w}`);m.shift(),E=m.join("|")}g.data&&(y=g.data.map(l=>(l.shift(),l.join("|"))).join(`
353
353
  `)),v++}),{content:[{type:"text",text:`${E}
354
- ${y}`}]}}catch(t){return{content:[{type:"text",text:`Error executing query: ${t.message}`}],isError:!0}}})}var{version:Yi}=$e;async function Ji(){let i=process.env.API_KEY,c=process.env.FQDN,e=process.env.SLUG,n=process.env.DEV||!1,d=process.env.USERID,t=new (0, _mcpjs.McpServer)({name:"DataOS",version:Yi,capabilities:{resources:{}}}),S=new _stdiojs.StdioServerTransport;n&&(Se(t),xe(t),Ee(t),ke(t),Ae(t),_e(t),Oe(t),Fe(t),Be(t),Ge(t),Ye(t),Je(t),tt(t),it(t)),i&&(De({server:t,apiKey:i,fqdn:c,slug:e}),e||(je({server:t,apiKey:i,fqdn:c}),Ne({server:t,apiKey:i,fqdn:c})),Re({server:t,apiKey:i,fqdn:c,slug:e}),Pe({server:t,apiKey:i,fqdn:c,slug:e}),nt({server:t,apiKey:i,fqdn:c,userId:d})),await t.connect(S)}Ji().catch(console.error);
354
+ ${y}`}]}}catch(t){return{content:[{type:"text",text:`Error executing query: ${t.message}`}],isError:!0}}})}var _undici = require('undici');if(process.env.NODE_EXTRA_CA_CERTS){let i=new (0, _undici.Agent)({connect:{rejectUnauthorized:!0,ca:_fs2.default.readFileSync(process.env.NODE_EXTRA_CA_CERTS)}});_undici.setGlobalDispatcher.call(void 0, i)}var{version:Xi}=$e;async function es(){let i=process.env.API_KEY,c=process.env.FQDN,e=process.env.SLUG,n=process.env.DEV||!1,d=process.env.USERID,t=new (0, _mcpjs.McpServer)({name:"DataOS",version:Xi}),S=new _stdiojs.StdioServerTransport;n&&(Se(t),xe(t),Ee(t),ke(t),Ae(t),_e(t),Oe(t),Fe(t),Be(t),Ge(t),Ye(t),Je(t),tt(t),it(t)),i&&(De({server:t,apiKey:i,fqdn:c,slug:e}),e||(je({server:t,apiKey:i,fqdn:c}),Ne({server:t,apiKey:i,fqdn:c})),Re({server:t,apiKey:i,fqdn:c,slug:e}),Pe({server:t,apiKey:i,fqdn:c,slug:e}),nt({server:t,apiKey:i,fqdn:c,userId:d})),await t.connect(S)}es().catch(console.error);
355
355
  //# sourceMappingURL=stdio.cjs.map
package/dist/stdio.js CHANGED
@@ -62,7 +62,7 @@ Examples:
62
62
  - Basic checks: row_count between 100 and 1000, missing_count(email) = 0
63
63
  - Advanced checks: values in (city) must exist in cities (name), freshness(updated_at) < 1d
64
64
  - Schema validation: required columns, data types, forbidden columns
65
- `,me=o.object({title:o.string({description:"Human-readable title for the check (e.g., 'Customer ID Completeness Check')"}).optional(),category:o.enum(["Accuracy","Completeness","Consistency","Freshness","Schema","Uniqueness","Validity"],{description:"Category of the data quality check for organization and reporting"}),description:o.string({description:"Detailed description of what the check validates"}).optional(),tags:o.array(o.string(),{description:"Tags for organizing and filtering checks (e.g., ['critical', 'pii', 'financial'])"}).optional()}).describe("Metadata attributes for organizing and documenting quality checks"),fr=o.object({limit:o.number({description:"Maximum number of failed row samples to collect for analysis (default: 100)"}).min(1).max(1e3).default(100)}).optional().describe("Configuration for collecting failed row samples for debugging"),gr=o.object({"valid format":o.enum(["email","phone number","credit card","uuid","date","url"],{description:"Built-in format validation (e.g., 'email', 'phone number')"}).optional(),"valid regex":o.string({description:"Custom regex pattern for validation (e.g., '^[A-Z]{2}[0-9]{4}$' for postal codes)"}).optional(),"valid min":o.number({description:"Minimum valid value for numeric columns"}).optional(),"valid max":o.number({description:"Maximum valid value for numeric columns"}).optional(),"valid min length":o.number({description:"Minimum valid length for string columns"}).optional(),"valid max length":o.number({description:"Maximum valid length for string columns"}).optional(),"valid values":o.array(o.union([o.string(),o.number()]),{description:"List of valid values (e.g., ['active', 'inactive', 'pending'])"}).optional()}).describe("Validation rules for validity checks"),As=o.object({name:o.string({description:"Name identifier for the schema check"}).optional(),warn:o.object({"when required column missing":o.array(o.string(),{description:"Columns that should trigger warnings if missing"}).optional(),"when forbidden column present":o.array(o.string(),{description:"Columns that should trigger warnings if present (e.g., ['temp_*', 'old_*'])"}).optional(),"when wrong column type":o.record(o.string(),o.string(),{description:"Expected column types that should trigger warnings if wrong (e.g., {'age': 'integer'})"}).optional(),"when wrong column index":o.record(o.string(),o.number(),{description:"Expected column positions that should trigger warnings if wrong"}).optional()}).optional(),fail:o.object({"when required column missing":o.array(o.string(),{description:"Columns that should trigger failures if missing"}).optional(),"when forbidden column present":o.array(o.string(),{description:"Columns that should trigger failures if present (sensitive data)"}).optional(),"when wrong column type":o.record(o.string(),o.string(),{description:"Expected column types that should trigger failures if wrong"}).optional(),"when wrong column index":o.record(o.string(),o.number(),{description:"Expected column positions that should trigger failures if wrong"}).optional()}).optional(),attributes:me}).describe("Schema validation check configuration with warn/fail conditions"),Ts=o.object({name:o.string({description:"Custom name for the check (overrides default naming)"}).optional(),filter:o.string({description:`SQL WHERE clause to filter data for this specific check (e.g., 'status = "active"')`}).optional(),attributes:me}),hr=i=>{let{checkType:c,column:e,operator:n,value:d,compareDataset:t,samples:S,name:v,filter:E,attributes:y,missingValues:g,missingRegex:m,validationRules:l,function:w,percentile:s,lengthType:b,sourceColumn:u,referenceDataset:h,referenceColumn:f,checkPattern:p,warn:k,fail:N,failCondition:P,failQuery:_}=i;if(!c)return"Error: 'checkType' is required for all quality checks.";switch(c){case"row_count":if(!n)return"Error: 'row_count' check requires 'operator' property.";if(d===void 0)return"Error: 'row_count' check requires 'value' property.";if(e||g||m||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'row_count' check should only have 'operator', 'value', 'compareDataset', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"missing_count":if(!e)return"Error: 'missing_count' check requires 'column' property.";if(!n)return"Error: 'missing_count' check requires 'operator' property.";if(d===void 0)return"Error: 'missing_count' check requires 'value' property.";if(t||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'missing_count' check should only have 'column', 'operator', 'value', 'missingValues', 'missingRegex', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"missing_percent":if(!e)return"Error: 'missing_percent' check requires 'column' property.";if(!n)return"Error: 'missing_percent' check requires 'operator' property.";if(d===void 0)return"Error: 'missing_percent' check requires 'value' property.";if(t||g||m||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'missing_percent' check should only have 'column', 'operator', 'value', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"duplicate_count":if(!e)return"Error: 'duplicate_count' check requires 'column' property.";if(!n)return"Error: 'duplicate_count' check requires 'operator' property.";if(d===void 0)return"Error: 'duplicate_count' check requires 'value' property.";if(t||g||m||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'duplicate_count' check should only have 'column', 'operator', 'value', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"duplicate_percent":if(!e)return"Error: 'duplicate_percent' check requires 'column' property.";if(!n)return"Error: 'duplicate_percent' check requires 'operator' property.";if(d===void 0)return"Error: 'duplicate_percent' check requires 'value' property.";if(t||g||m||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'duplicate_percent' check should only have 'column', 'operator', 'value', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"invalid_count":if(!e)return"Error: 'invalid_count' check requires 'column' property.";if(!n)return"Error: 'invalid_count' check requires 'operator' property.";if(d===void 0)return"Error: 'invalid_count' check requires 'value' property.";if(!l)return"Error: 'invalid_count' check requires 'validationRules' property.";if(t||g||m||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'invalid_count' check should only have 'column', 'operator', 'value', 'validationRules', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"invalid_percent":if(!e)return"Error: 'invalid_percent' check requires 'column' property.";if(!n)return"Error: 'invalid_percent' check requires 'operator' property.";if(d===void 0)return"Error: 'invalid_percent' check requires 'value' property.";if(!l)return"Error: 'invalid_percent' check requires 'validationRules' property.";if(t||g||m||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'invalid_percent' check should only have 'column', 'operator', 'value', 'validationRules', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"freshness":if(!e)return"Error: 'freshness' check requires 'column' property.";if(!n)return"Error: 'freshness' check requires 'operator' property.";if(!d)return"Error: 'freshness' check requires 'value' property.";if(t||g||m||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'freshness' check should only have 'column', 'operator', 'value', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"aggregation":if(!w)return"Error: 'aggregation' check requires 'function' property.";if(!e)return"Error: 'aggregation' check requires 'column' property.";if(!n)return"Error: 'aggregation' check requires 'operator' property.";if(d===void 0)return"Error: 'aggregation' check requires 'value' property.";if(t||g||m||l||b||u||h||f||p||k||N||P||_)return"Error: 'aggregation' check should only have 'function', 'column', 'operator', 'value', 'percentile', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"length":if(!b)return"Error: 'length' check requires 'lengthType' property.";if(!e)return"Error: 'length' check requires 'column' property.";if(!n)return"Error: 'length' check requires 'operator' property.";if(d===void 0)return"Error: 'length' check requires 'value' property.";if(t||g||m||l||w||s||u||h||f||p||k||N||P||_)return"Error: 'length' check should only have 'lengthType', 'column', 'operator', 'value', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"reference":if(!u)return"Error: 'reference' check requires 'sourceColumn' property.";if(!h)return"Error: 'reference' check requires 'referenceDataset' property.";if(!f)return"Error: 'reference' check requires 'referenceColumn' property.";if(!p)return"Error: 'reference' check requires 'checkPattern' property.";if(e||n||d||t||g||m||l||w||s||b||k||N||P||_)return"Error: 'reference' check should only have 'sourceColumn', 'referenceDataset', 'referenceColumn', 'checkPattern', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"schema":if(e||n||d||t||g||m||l||w||s||b||u||h||f||p||P||_)return"Error: 'schema' check should only have 'warn', 'fail', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"failed_rows":if(!P&&!_)return"Error: 'failed_rows' check requires either 'failCondition' or 'failQuery' property.";if(e||n||d||t||g||m||l||w||s||b||u||h||f||p||k||N)return"Error: 'failed_rows' check should only have 'failCondition', 'failQuery', 'samples', 'name', 'filter', and 'attributes' properties.";break;default:return`Error: Invalid soda check type '${c}'. Supported types are: row_count, missing_count, missing_percent, duplicate_count, duplicate_percent, invalid_count, invalid_percent, freshness, aggregation, length, reference, schema, failed_rows.`}return null},yr=o.object({checkType:o.enum(["row_count","missing_count","missing_percent","duplicate_count","duplicate_percent","invalid_count","invalid_percent","freshness","aggregation","length","reference","schema","failed_rows"],{description:"Type of data quality check to perform"}),name:o.string({description:"Custom name for the check (overrides default naming)"}).optional(),filter:o.string({description:`SQL WHERE clause to filter data for this specific check (e.g., 'status = "active"')`}).optional(),attributes:me,samples:fr,compareDataset:o.string({description:"Reference dataset for comparison (e.g., 'same as reference_table')"}).optional(),column:o.string({description:"Column name for checks that operate on specific columns"}).optional(),operator:o.enum(["=","!=",">",">=","<","<=","between"],{description:"Comparison operator for the check"}).optional(),value:o.union([o.number(),o.string()],{description:"Expected value or range for the check"}).optional(),missingValues:o.array(o.union([o.string(),o.null()]),{description:"Custom missing value indicators (e.g., ['NA', 'n/a', '', null])"}).optional(),missingRegex:o.string({description:"Regex pattern to identify missing values"}).optional(),validationRules:gr.optional(),function:o.enum(["min","max","avg","sum","stddev","variance","percentile"],{description:"Aggregation function to apply"}).optional(),percentile:o.number({description:"Percentile value (0-1) for percentile function"}).min(0).max(1).optional(),lengthType:o.enum(["min_length","max_length","avg_length"],{description:"Type of length check to perform"}).optional(),sourceColumn:o.string({description:"Column in current dataset"}).optional(),referenceDataset:o.string({description:"Reference dataset name (e.g., 'reference_table')"}).optional(),referenceColumn:o.string({description:"Column in reference dataset"}).optional(),checkPattern:o.enum(["must exist in","must not exist in"],{description:"Type of reference validation"}).optional(),warn:o.object({"when required column missing":o.array(o.string(),{description:"Columns that should trigger warnings if missing"}).optional(),"when forbidden column present":o.array(o.string(),{description:"Columns that should trigger warnings if present (e.g., ['temp_*', 'old_*'])"}).optional(),"when wrong column type":o.record(o.string(),o.string(),{description:"Expected column types that should trigger warnings if wrong (e.g., {'age': 'integer'})"}).optional(),"when wrong column index":o.record(o.string(),o.number(),{description:"Expected column positions that should trigger warnings if wrong"}).optional()}).optional(),fail:o.object({"when required column missing":o.array(o.string(),{description:"Columns that should trigger failures if missing"}).optional(),"when forbidden column present":o.array(o.string(),{description:"Columns that should trigger failures if present (sensitive data)"}).optional(),"when wrong column type":o.record(o.string(),o.string(),{description:"Expected column types that should trigger failures if wrong"}).optional(),"when wrong column index":o.record(o.string(),o.number(),{description:"Expected column positions that should trigger failures if wrong"}).optional()}).optional(),failCondition:o.string({description:"SQL condition for identifying failed rows (e.g., 'age < 0 OR age > 150')"}).optional(),failQuery:o.string({description:"Custom SQL query for complex failed row detection"}).optional()}).describe("Comprehensive Soda quality check with typed validation"),br=o.object({columns:o.array(o.string(),{description:"Column specifications for profiling: exact names, wildcards (*), includes/excludes (e.g., ['customer_id', 'include address_*', 'exclude temp_*', '*'])"})}).optional().describe("Data profiling configuration for statistical analysis"),vr=o.object({name:o.string({description:"Identifier name for the filter"}),where:o.string({description:`SQL WHERE clause for global filtering across all checks (e.g., 'status = "active" AND created_date > "2023-01-01"')`})}).optional().describe("Global filter applied to all checks on this dataset"),wr=o.object({engine:o.enum(["minerva","default"],{description:"Query engine: 'minerva' for Trino-based queries, 'default' for native engine"}).default("default"),clusterName:o.string({description:"Cluster name for Minerva engine (required when engine is 'minerva')"}).optional(),branchName:o.string({description:"Branch name for Iceberg datasets (defaults to 'main')"}).default("main").optional()}).optional().describe("Engine and execution options for quality checks"),Sr=o.object({dataset:o.string({description:"Dataset specification using DataOS UDL format: dataos://[depot]:[collection]/[dataset] (e.g., 'dataos://icebase:retail/customer')"}),options:wr,filter:vr,profile:br,checks:o.array(yr,{description:"List of data quality checks to execute on this dataset"})}).describe("Complete dataset configuration with quality checks and profiling"),Er=o.object({requests:o.object({cpu:o.string({description:"CPU resource request (e.g., '500m', '1', '2000m')"}).default("1000m"),memory:o.string({description:"Memory resource request (e.g., '512Mi', '1Gi', '250Mi')"}).default("250Mi")}),limits:o.object({cpu:o.string({description:"CPU resource limit (e.g., '1', '2', '4000m')"}).optional(),memory:o.string({description:"Memory resource limit (e.g., '1Gi', '2Gi', '500Mi')"}).optional()}).optional()}).optional().describe("Resource allocation for quality check execution"),kr=o.object({cron:o.string({description:"Cron expression for scheduling (e.g., '0 2 * * *' for daily at 2 AM, '0 */6 * * *' for every 6 hours)"}),concurrencyPolicy:o.enum(["Allow","Forbid","Replace"],{description:"Policy for handling concurrent executions"}).default("Allow"),endOn:o.string({description:"End date for scheduled executions in ISO 8601 format"}).optional(),timezone:o.string({description:"Timezone for schedule execution (e.g., 'UTC', 'Asia/Kolkata')"}).default("UTC")}).optional().describe("Schedule configuration for recurring quality checks"),xr={name:o.string({description:"Quality workflow name - alphanumeric with hyphens, max 48 chars"}),tags:o.array(o.string(),{description:"Tags for categorizing and organizing the quality workflow"}),description:o.string({description:"Human-readable description of the quality checks and purpose"}),owner:o.string({description:"Owner of the quality workflow resource"}).optional(),workspace:o.string({description:"Workspace where the quality workflow will be deployed"}).default("public")},_r=o.array(o.object({...xr,schedule:kr,jobName:o.string({description:"Name of the quality job within the workflow"}),jobTitle:o.string({description:"Human-readable title for the job"}).optional(),jobDescription:o.string({description:"Description of the quality job"}).optional(),jobTags:o.array(o.string(),{description:"Tags specific to this quality job"}).optional(),compute:o.string({description:"Compute resource for the job"}).default("runnable-default"),runAsUser:o.string({description:"User to run the quality job as"}).optional(),stack:o.enum(["soda+python:1.0"],{description:"Soda stack version with Python flavor"}).default("soda+python:1.0"),logLevel:o.enum(["DEBUG","INFO","WARNING","ERROR"],{description:"Logging level for the quality job"}).default("INFO"),resources:Er,inputs:o.array(Sr,{description:"List of datasets and their associated quality checks"}),path:o.string({description:"Absolute path where the file will be stored. example: ~/Documents/project-name/my-quality.yaml"}),fileName:o.string({description:"File name for the quality workflow file. example: my-quality.yaml"})}),{description:"Array of quality workflows to create. Use this tool to create multiple quality workflows at once."}).nonempty(),Ae=i=>{i.tool("create-quality-workflow",mr,{workflows:_r},async({workflows:c})=>{let e=[];for(let n of c){let{name:d,tags:t,description:S,owner:v,workspace:E,schedule:y,jobName:g,jobTitle:m,jobDescription:l,jobTags:w,compute:s,runAsUser:b,stack:u,logLevel:h,resources:f,inputs:p,path:k,fileName:N}=n;for(let M of p)for(let O of M.checks){let G=hr(O);if(G)return{content:[{type:"text",text:G}]}}let P=[{name:g,...m&&{title:m},...l&&{description:l},...w&&{tags:w},spec:{stack:u,compute:s,...b&&{runAsUser:b},...f&&{resources:f},logLevel:h,stackSpec:{inputs:p}}}],_=cr({name:d,tags:t,type:"workflow",version:"v1",...v&&{owner:v},workspace:E,description:S,...y&&{schedule:y},dag:P});try{let M=k.includes(".yaml")||k.includes(".yml")?k:k.endsWith("/")?k+N:`${k}/${N}`,O=dr.dirname(M);lr(O)||pr(O,{recursive:!0}),ur(M,_),e.push({type:"text",text:`Quality workflow created successfully at ${M}`}),e.push({type:"text",text:`File content: ${_}`})}catch(M){e.push({type:"text",text:`Error creating quality workflow: ${M}`})}}return{content:e.flat()}})};import{z}from"zod";import Ar from"https";var Tr=4;function J(i,c,e,n=!1,d=0){return new Promise((t,S)=>{let v=Ar.request(i,c,E=>{let y="";E.on("data",g=>y+=g),E.on("end",()=>{n&&d<Tr&&y.includes("Continue wait")?setTimeout(()=>{J(i,c,e,n,d+1).then(t).catch(S)},1e3):t({status:E.statusCode||500,data:y})})});v.on("error",S),e&&v.write(e),v.end()})}import{config as Lr}from"dotenv";Lr();var te="",le=process.env.SLUG||"bmx";function Te(i,c=","){return Array.isArray(i)?i.filter(e=>e!=null).map(e=>typeof e=="string"?e:JSON.stringify(e)).join(c):""}function W(i){return i===!0||i==="true"||i===1||i==="1"}function pe(i){return i==null?"":typeof i=="string"?i:typeof i=="number"||typeof i=="boolean"?String(i):JSON.stringify(i)}function U(i){let c=pe(i);return c===""?c:c.includes("|")||c.includes(",")||c.includes('"')?`"${c.replace(/"/g,'"')}"`:c}function Le(i){return Array.isArray(i)?i.map(c=>`"${pe(c)}"`).join(","):""}function se(...i){for(let c of i)if(c!==void 0)return c}function Ce(i,c){let e=i.name||i.slug||c||"",n=i.fullyQualifiedName||e||c||"",d=i.description||"",t=i.owner?.name||i.owner?.displayName||Te(i.authors||[],","),S=i.timeZones||i.timezones||[],v=Array.isArray(S)?S:typeof S=="string"?[S]:[],E=W(se(i.cache?.enabled,i.cache,i.runtime?.cache?.enabled,i.runtime?.cache,i.isCacheEnabled)),y=[];y.push(`${n}(${n})`),d&&y.push(d),t&&y.push(t),v.length&&y.push(v.join(",")),y.push(`Cache: ${E}`),y.push("");let g=Array.isArray(i.views)?i.views:[],m=Array.isArray(i.tables)?i.tables:[];g.length===0&&m.length>0&&(g.push(...m.filter(s=>!s.sql)),m=m.filter(s=>s.sql));let l=(s,b,u)=>{let h=[],f=s.title||s.displayName||s.name||`item_${b}`,p=s.name||s.table||s.view||f,k=s.description||s.meta?.description||"",N=W(se(s.isVisible,s.visible)),P=W(s.public),_=s.connectedComponent,M=s.refs||s.references,O=s.meta?.title||s.metric?.title||"",G=s.meta?.tags||s.tags,K=!!(s.meta?.metric||s.metric);if(h.push(`${b}. ${f}(${p})`),k&&h.push(k),u==="view"){let C=["view"];K&&C.push("metric"),C.push(`visible: ${N}`),C.push(`public: ${P}`),h.push(C.join(", "))}else{let C=["table"];_!==void 0&&C.push(`connectedComponent: ${_}`),C.push(`visible: ${N}`),C.push(`public: ${P}`),h.push(C.join(", "))}if(O&&h.push(O),Array.isArray(G)&&G.length&&h.push(Le(G)),M&&(Array.isArray(M)&&M.length||typeof M=="string")&&h.push(`refs: ${Array.isArray(M)?M.join(","):M}`),u==="table"&&s.sql&&(h.push("SQL:"),h.push("`"+String(s.sql).trim()+"`")),s.joins&&Array.isArray(s.joins)&&s.joins.length){h.push(""),h.push("Joins:");for(let C of s.joins)h.push(`${C.relationship} - ${C.name}`),h.push(" SQL: `"+pe(C.sql).trim()+"`")}h.push(""),h.push("Dimentions"),u==="table"?h.push("name|title|description|type|sql|suggestFilterValues|isVisible|public|primaryKey|aliasMember|isGoverned|refs"):h.push("name|title|description|type|suggestFilterValues|isVisible|public|primaryKey|aliasMember|isGoverned|refs");let V=Array.isArray(s.dimensions)?s.dimensions:[];for(let C of V){let Q=[U(C.name),U(C.title||C.displayName||""),U(C.description||""),U(C.type||C.dataType||"")];u==="table"&&Q.push(U(C.sql||C.expression||"")),Q.push(U(W(C.suggestFilterValues)),U(W(se(C.isVisible,C.visible))),U(W(C.public)),U(W(C.primaryKey)),U(C.aliasMember||(Array.isArray(C.aliasMembers)?C.aliasMembers.join(","):"")),U(W(C.isGoverned)),U(Array.isArray(C.refs)?C.refs.join(","):C.refs||"")),h.push(Q.join("|"))}h.push(""),h.push("Measures"),h.push("name|title|description|cumulativeTotal|cumulative|type|aggType|isVisible|public|aliasMember|isGoverned|refs");let H=Array.isArray(s.measures)?s.measures:[];for(let C of H){let Q=[U(C.name),U(C.title||C.displayName||""),U(C.description||""),U(W(C.cumulativeTotal)),U(W(C.cumulative)),U(C.type||C.dataType||""),U(C.aggType||C.aggregation||""),U(W(se(C.isVisible,C.visible))),U(W(C.public)),U(C.aliasMember||(Array.isArray(C.aliasMembers)?C.aliasMembers.join(","):"")),U(W(C.isGoverned)),U(Array.isArray(C.refs)?C.refs.join(","):C.refs||"")];h.push(Q.join("|"))}return h},w=1;for(let s of g)y.push(...l(s,w++,"view")),y.push("");for(let s of m)y.push(...l(s,w++,"table")),y.push("");return y.join(`
65
+ `,me=o.object({title:o.string({description:"Human-readable title for the check (e.g., 'Customer ID Completeness Check')"}).optional(),category:o.enum(["Accuracy","Completeness","Consistency","Freshness","Schema","Uniqueness","Validity"],{description:"Category of the data quality check for organization and reporting"}),description:o.string({description:"Detailed description of what the check validates"}).optional(),tags:o.array(o.string(),{description:"Tags for organizing and filtering checks (e.g., ['critical', 'pii', 'financial'])"}).optional()}).describe("Metadata attributes for organizing and documenting quality checks"),fr=o.object({limit:o.number({description:"Maximum number of failed row samples to collect for analysis (default: 100)"}).min(1).max(1e3).default(100)}).optional().describe("Configuration for collecting failed row samples for debugging"),gr=o.object({"valid format":o.enum(["email","phone number","credit card","uuid","date","url"],{description:"Built-in format validation (e.g., 'email', 'phone number')"}).optional(),"valid regex":o.string({description:"Custom regex pattern for validation (e.g., '^[A-Z]{2}[0-9]{4}$' for postal codes)"}).optional(),"valid min":o.number({description:"Minimum valid value for numeric columns"}).optional(),"valid max":o.number({description:"Maximum valid value for numeric columns"}).optional(),"valid min length":o.number({description:"Minimum valid length for string columns"}).optional(),"valid max length":o.number({description:"Maximum valid length for string columns"}).optional(),"valid values":o.array(o.union([o.string(),o.number()]),{description:"List of valid values (e.g., ['active', 'inactive', 'pending'])"}).optional()}).describe("Validation rules for validity checks"),Cs=o.object({name:o.string({description:"Name identifier for the schema check"}).optional(),warn:o.object({"when required column missing":o.array(o.string(),{description:"Columns that should trigger warnings if missing"}).optional(),"when forbidden column present":o.array(o.string(),{description:"Columns that should trigger warnings if present (e.g., ['temp_*', 'old_*'])"}).optional(),"when wrong column type":o.record(o.string(),o.string(),{description:"Expected column types that should trigger warnings if wrong (e.g., {'age': 'integer'})"}).optional(),"when wrong column index":o.record(o.string(),o.number(),{description:"Expected column positions that should trigger warnings if wrong"}).optional()}).optional(),fail:o.object({"when required column missing":o.array(o.string(),{description:"Columns that should trigger failures if missing"}).optional(),"when forbidden column present":o.array(o.string(),{description:"Columns that should trigger failures if present (sensitive data)"}).optional(),"when wrong column type":o.record(o.string(),o.string(),{description:"Expected column types that should trigger failures if wrong"}).optional(),"when wrong column index":o.record(o.string(),o.number(),{description:"Expected column positions that should trigger failures if wrong"}).optional()}).optional(),attributes:me}).describe("Schema validation check configuration with warn/fail conditions"),qs=o.object({name:o.string({description:"Custom name for the check (overrides default naming)"}).optional(),filter:o.string({description:`SQL WHERE clause to filter data for this specific check (e.g., 'status = "active"')`}).optional(),attributes:me}),hr=i=>{let{checkType:c,column:e,operator:n,value:d,compareDataset:t,samples:S,name:v,filter:E,attributes:y,missingValues:g,missingRegex:m,validationRules:l,function:w,percentile:s,lengthType:b,sourceColumn:u,referenceDataset:h,referenceColumn:f,checkPattern:p,warn:k,fail:N,failCondition:P,failQuery:_}=i;if(!c)return"Error: 'checkType' is required for all quality checks.";switch(c){case"row_count":if(!n)return"Error: 'row_count' check requires 'operator' property.";if(d===void 0)return"Error: 'row_count' check requires 'value' property.";if(e||g||m||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'row_count' check should only have 'operator', 'value', 'compareDataset', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"missing_count":if(!e)return"Error: 'missing_count' check requires 'column' property.";if(!n)return"Error: 'missing_count' check requires 'operator' property.";if(d===void 0)return"Error: 'missing_count' check requires 'value' property.";if(t||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'missing_count' check should only have 'column', 'operator', 'value', 'missingValues', 'missingRegex', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"missing_percent":if(!e)return"Error: 'missing_percent' check requires 'column' property.";if(!n)return"Error: 'missing_percent' check requires 'operator' property.";if(d===void 0)return"Error: 'missing_percent' check requires 'value' property.";if(t||g||m||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'missing_percent' check should only have 'column', 'operator', 'value', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"duplicate_count":if(!e)return"Error: 'duplicate_count' check requires 'column' property.";if(!n)return"Error: 'duplicate_count' check requires 'operator' property.";if(d===void 0)return"Error: 'duplicate_count' check requires 'value' property.";if(t||g||m||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'duplicate_count' check should only have 'column', 'operator', 'value', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"duplicate_percent":if(!e)return"Error: 'duplicate_percent' check requires 'column' property.";if(!n)return"Error: 'duplicate_percent' check requires 'operator' property.";if(d===void 0)return"Error: 'duplicate_percent' check requires 'value' property.";if(t||g||m||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'duplicate_percent' check should only have 'column', 'operator', 'value', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"invalid_count":if(!e)return"Error: 'invalid_count' check requires 'column' property.";if(!n)return"Error: 'invalid_count' check requires 'operator' property.";if(d===void 0)return"Error: 'invalid_count' check requires 'value' property.";if(!l)return"Error: 'invalid_count' check requires 'validationRules' property.";if(t||g||m||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'invalid_count' check should only have 'column', 'operator', 'value', 'validationRules', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"invalid_percent":if(!e)return"Error: 'invalid_percent' check requires 'column' property.";if(!n)return"Error: 'invalid_percent' check requires 'operator' property.";if(d===void 0)return"Error: 'invalid_percent' check requires 'value' property.";if(!l)return"Error: 'invalid_percent' check requires 'validationRules' property.";if(t||g||m||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'invalid_percent' check should only have 'column', 'operator', 'value', 'validationRules', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"freshness":if(!e)return"Error: 'freshness' check requires 'column' property.";if(!n)return"Error: 'freshness' check requires 'operator' property.";if(!d)return"Error: 'freshness' check requires 'value' property.";if(t||g||m||l||w||s||b||u||h||f||p||k||N||P||_)return"Error: 'freshness' check should only have 'column', 'operator', 'value', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"aggregation":if(!w)return"Error: 'aggregation' check requires 'function' property.";if(!e)return"Error: 'aggregation' check requires 'column' property.";if(!n)return"Error: 'aggregation' check requires 'operator' property.";if(d===void 0)return"Error: 'aggregation' check requires 'value' property.";if(t||g||m||l||b||u||h||f||p||k||N||P||_)return"Error: 'aggregation' check should only have 'function', 'column', 'operator', 'value', 'percentile', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"length":if(!b)return"Error: 'length' check requires 'lengthType' property.";if(!e)return"Error: 'length' check requires 'column' property.";if(!n)return"Error: 'length' check requires 'operator' property.";if(d===void 0)return"Error: 'length' check requires 'value' property.";if(t||g||m||l||w||s||u||h||f||p||k||N||P||_)return"Error: 'length' check should only have 'lengthType', 'column', 'operator', 'value', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"reference":if(!u)return"Error: 'reference' check requires 'sourceColumn' property.";if(!h)return"Error: 'reference' check requires 'referenceDataset' property.";if(!f)return"Error: 'reference' check requires 'referenceColumn' property.";if(!p)return"Error: 'reference' check requires 'checkPattern' property.";if(e||n||d||t||g||m||l||w||s||b||k||N||P||_)return"Error: 'reference' check should only have 'sourceColumn', 'referenceDataset', 'referenceColumn', 'checkPattern', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"schema":if(e||n||d||t||g||m||l||w||s||b||u||h||f||p||P||_)return"Error: 'schema' check should only have 'warn', 'fail', 'samples', 'name', 'filter', and 'attributes' properties.";break;case"failed_rows":if(!P&&!_)return"Error: 'failed_rows' check requires either 'failCondition' or 'failQuery' property.";if(e||n||d||t||g||m||l||w||s||b||u||h||f||p||k||N)return"Error: 'failed_rows' check should only have 'failCondition', 'failQuery', 'samples', 'name', 'filter', and 'attributes' properties.";break;default:return`Error: Invalid soda check type '${c}'. Supported types are: row_count, missing_count, missing_percent, duplicate_count, duplicate_percent, invalid_count, invalid_percent, freshness, aggregation, length, reference, schema, failed_rows.`}return null},yr=o.object({checkType:o.enum(["row_count","missing_count","missing_percent","duplicate_count","duplicate_percent","invalid_count","invalid_percent","freshness","aggregation","length","reference","schema","failed_rows"],{description:"Type of data quality check to perform"}),name:o.string({description:"Custom name for the check (overrides default naming)"}).optional(),filter:o.string({description:`SQL WHERE clause to filter data for this specific check (e.g., 'status = "active"')`}).optional(),attributes:me,samples:fr,compareDataset:o.string({description:"Reference dataset for comparison (e.g., 'same as reference_table')"}).optional(),column:o.string({description:"Column name for checks that operate on specific columns"}).optional(),operator:o.enum(["=","!=",">",">=","<","<=","between"],{description:"Comparison operator for the check"}).optional(),value:o.union([o.number(),o.string()],{description:"Expected value or range for the check"}).optional(),missingValues:o.array(o.union([o.string(),o.null()]),{description:"Custom missing value indicators (e.g., ['NA', 'n/a', '', null])"}).optional(),missingRegex:o.string({description:"Regex pattern to identify missing values"}).optional(),validationRules:gr.optional(),function:o.enum(["min","max","avg","sum","stddev","variance","percentile"],{description:"Aggregation function to apply"}).optional(),percentile:o.number({description:"Percentile value (0-1) for percentile function"}).min(0).max(1).optional(),lengthType:o.enum(["min_length","max_length","avg_length"],{description:"Type of length check to perform"}).optional(),sourceColumn:o.string({description:"Column in current dataset"}).optional(),referenceDataset:o.string({description:"Reference dataset name (e.g., 'reference_table')"}).optional(),referenceColumn:o.string({description:"Column in reference dataset"}).optional(),checkPattern:o.enum(["must exist in","must not exist in"],{description:"Type of reference validation"}).optional(),warn:o.object({"when required column missing":o.array(o.string(),{description:"Columns that should trigger warnings if missing"}).optional(),"when forbidden column present":o.array(o.string(),{description:"Columns that should trigger warnings if present (e.g., ['temp_*', 'old_*'])"}).optional(),"when wrong column type":o.record(o.string(),o.string(),{description:"Expected column types that should trigger warnings if wrong (e.g., {'age': 'integer'})"}).optional(),"when wrong column index":o.record(o.string(),o.number(),{description:"Expected column positions that should trigger warnings if wrong"}).optional()}).optional(),fail:o.object({"when required column missing":o.array(o.string(),{description:"Columns that should trigger failures if missing"}).optional(),"when forbidden column present":o.array(o.string(),{description:"Columns that should trigger failures if present (sensitive data)"}).optional(),"when wrong column type":o.record(o.string(),o.string(),{description:"Expected column types that should trigger failures if wrong"}).optional(),"when wrong column index":o.record(o.string(),o.number(),{description:"Expected column positions that should trigger failures if wrong"}).optional()}).optional(),failCondition:o.string({description:"SQL condition for identifying failed rows (e.g., 'age < 0 OR age > 150')"}).optional(),failQuery:o.string({description:"Custom SQL query for complex failed row detection"}).optional()}).describe("Comprehensive Soda quality check with typed validation"),br=o.object({columns:o.array(o.string(),{description:"Column specifications for profiling: exact names, wildcards (*), includes/excludes (e.g., ['customer_id', 'include address_*', 'exclude temp_*', '*'])"})}).optional().describe("Data profiling configuration for statistical analysis"),vr=o.object({name:o.string({description:"Identifier name for the filter"}),where:o.string({description:`SQL WHERE clause for global filtering across all checks (e.g., 'status = "active" AND created_date > "2023-01-01"')`})}).optional().describe("Global filter applied to all checks on this dataset"),wr=o.object({engine:o.enum(["minerva","default"],{description:"Query engine: 'minerva' for Trino-based queries, 'default' for native engine"}).default("default"),clusterName:o.string({description:"Cluster name for Minerva engine (required when engine is 'minerva')"}).optional(),branchName:o.string({description:"Branch name for Iceberg datasets (defaults to 'main')"}).default("main").optional()}).optional().describe("Engine and execution options for quality checks"),Sr=o.object({dataset:o.string({description:"Dataset specification using DataOS UDL format: dataos://[depot]:[collection]/[dataset] (e.g., 'dataos://icebase:retail/customer')"}),options:wr,filter:vr,profile:br,checks:o.array(yr,{description:"List of data quality checks to execute on this dataset"})}).describe("Complete dataset configuration with quality checks and profiling"),Er=o.object({requests:o.object({cpu:o.string({description:"CPU resource request (e.g., '500m', '1', '2000m')"}).default("1000m"),memory:o.string({description:"Memory resource request (e.g., '512Mi', '1Gi', '250Mi')"}).default("250Mi")}),limits:o.object({cpu:o.string({description:"CPU resource limit (e.g., '1', '2', '4000m')"}).optional(),memory:o.string({description:"Memory resource limit (e.g., '1Gi', '2Gi', '500Mi')"}).optional()}).optional()}).optional().describe("Resource allocation for quality check execution"),kr=o.object({cron:o.string({description:"Cron expression for scheduling (e.g., '0 2 * * *' for daily at 2 AM, '0 */6 * * *' for every 6 hours)"}),concurrencyPolicy:o.enum(["Allow","Forbid","Replace"],{description:"Policy for handling concurrent executions"}).default("Allow"),endOn:o.string({description:"End date for scheduled executions in ISO 8601 format"}).optional(),timezone:o.string({description:"Timezone for schedule execution (e.g., 'UTC', 'Asia/Kolkata')"}).default("UTC")}).optional().describe("Schedule configuration for recurring quality checks"),xr={name:o.string({description:"Quality workflow name - alphanumeric with hyphens, max 48 chars"}),tags:o.array(o.string(),{description:"Tags for categorizing and organizing the quality workflow"}),description:o.string({description:"Human-readable description of the quality checks and purpose"}),owner:o.string({description:"Owner of the quality workflow resource"}).optional(),workspace:o.string({description:"Workspace where the quality workflow will be deployed"}).default("public")},_r=o.array(o.object({...xr,schedule:kr,jobName:o.string({description:"Name of the quality job within the workflow"}),jobTitle:o.string({description:"Human-readable title for the job"}).optional(),jobDescription:o.string({description:"Description of the quality job"}).optional(),jobTags:o.array(o.string(),{description:"Tags specific to this quality job"}).optional(),compute:o.string({description:"Compute resource for the job"}).default("runnable-default"),runAsUser:o.string({description:"User to run the quality job as"}).optional(),stack:o.enum(["soda+python:1.0"],{description:"Soda stack version with Python flavor"}).default("soda+python:1.0"),logLevel:o.enum(["DEBUG","INFO","WARNING","ERROR"],{description:"Logging level for the quality job"}).default("INFO"),resources:Er,inputs:o.array(Sr,{description:"List of datasets and their associated quality checks"}),path:o.string({description:"Absolute path where the file will be stored. example: ~/Documents/project-name/my-quality.yaml"}),fileName:o.string({description:"File name for the quality workflow file. example: my-quality.yaml"})}),{description:"Array of quality workflows to create. Use this tool to create multiple quality workflows at once."}).nonempty(),Ae=i=>{i.tool("create-quality-workflow",mr,{workflows:_r},async({workflows:c})=>{let e=[];for(let n of c){let{name:d,tags:t,description:S,owner:v,workspace:E,schedule:y,jobName:g,jobTitle:m,jobDescription:l,jobTags:w,compute:s,runAsUser:b,stack:u,logLevel:h,resources:f,inputs:p,path:k,fileName:N}=n;for(let M of p)for(let O of M.checks){let G=hr(O);if(G)return{content:[{type:"text",text:G}]}}let P=[{name:g,...m&&{title:m},...l&&{description:l},...w&&{tags:w},spec:{stack:u,compute:s,...b&&{runAsUser:b},...f&&{resources:f},logLevel:h,stackSpec:{inputs:p}}}],_=cr({name:d,tags:t,type:"workflow",version:"v1",...v&&{owner:v},workspace:E,description:S,...y&&{schedule:y},dag:P});try{let M=k.includes(".yaml")||k.includes(".yml")?k:k.endsWith("/")?k+N:`${k}/${N}`,O=dr.dirname(M);lr(O)||pr(O,{recursive:!0}),ur(M,_),e.push({type:"text",text:`Quality workflow created successfully at ${M}`}),e.push({type:"text",text:`File content: ${_}`})}catch(M){e.push({type:"text",text:`Error creating quality workflow: ${M}`})}}return{content:e.flat()}})};import{z}from"zod";import Ar from"https";var Tr=4;function J(i,c,e,n=!1,d=0){return new Promise((t,S)=>{let v=Ar.request(i,c,E=>{let y="";E.on("data",g=>y+=g),E.on("end",()=>{n&&d<Tr&&y.includes("Continue wait")?setTimeout(()=>{J(i,c,e,n,d+1).then(t).catch(S)},1e3):t({status:E.statusCode||500,data:y})})});v.on("error",S),e&&v.write(e),v.end()})}import{config as Lr}from"dotenv";Lr();var te="",le=process.env.SLUG||"bmx";function Te(i,c=","){return Array.isArray(i)?i.filter(e=>e!=null).map(e=>typeof e=="string"?e:JSON.stringify(e)).join(c):""}function W(i){return i===!0||i==="true"||i===1||i==="1"}function pe(i){return i==null?"":typeof i=="string"?i:typeof i=="number"||typeof i=="boolean"?String(i):JSON.stringify(i)}function U(i){let c=pe(i);return c===""?c:c.includes("|")||c.includes(",")||c.includes('"')?`"${c.replace(/"/g,'"')}"`:c}function Le(i){return Array.isArray(i)?i.map(c=>`"${pe(c)}"`).join(","):""}function se(...i){for(let c of i)if(c!==void 0)return c}function Ce(i,c){let e=i.name||i.slug||c||"",n=i.fullyQualifiedName||e||c||"",d=i.description||"",t=i.owner?.name||i.owner?.displayName||Te(i.authors||[],","),S=i.timeZones||i.timezones||[],v=Array.isArray(S)?S:typeof S=="string"?[S]:[],E=W(se(i.cache?.enabled,i.cache,i.runtime?.cache?.enabled,i.runtime?.cache,i.isCacheEnabled)),y=[];y.push(`${n}(${n})`),d&&y.push(d),t&&y.push(t),v.length&&y.push(v.join(",")),y.push(`Cache: ${E}`),y.push("");let g=Array.isArray(i.views)?i.views:[],m=Array.isArray(i.tables)?i.tables:[];g.length===0&&m.length>0&&(g.push(...m.filter(s=>!s.sql)),m=m.filter(s=>s.sql));let l=(s,b,u)=>{let h=[],f=s.title||s.displayName||s.name||`item_${b}`,p=s.name||s.table||s.view||f,k=s.description||s.meta?.description||"",N=W(se(s.isVisible,s.visible)),P=W(s.public),_=s.connectedComponent,M=s.refs||s.references,O=s.meta?.title||s.metric?.title||"",G=s.meta?.tags||s.tags,K=!!(s.meta?.metric||s.metric);if(h.push(`${b}. ${f}(${p})`),k&&h.push(k),u==="view"){let C=["view"];K&&C.push("metric"),C.push(`visible: ${N}`),C.push(`public: ${P}`),h.push(C.join(", "))}else{let C=["table"];_!==void 0&&C.push(`connectedComponent: ${_}`),C.push(`visible: ${N}`),C.push(`public: ${P}`),h.push(C.join(", "))}if(O&&h.push(O),Array.isArray(G)&&G.length&&h.push(Le(G)),M&&(Array.isArray(M)&&M.length||typeof M=="string")&&h.push(`refs: ${Array.isArray(M)?M.join(","):M}`),u==="table"&&s.sql&&(h.push("SQL:"),h.push("`"+String(s.sql).trim()+"`")),s.joins&&Array.isArray(s.joins)&&s.joins.length){h.push(""),h.push("Joins:");for(let C of s.joins)h.push(`${C.relationship} - ${C.name}`),h.push(" SQL: `"+pe(C.sql).trim()+"`")}h.push(""),h.push("Dimentions"),u==="table"?h.push("name|title|description|type|sql|suggestFilterValues|isVisible|public|primaryKey|aliasMember|isGoverned|refs"):h.push("name|title|description|type|suggestFilterValues|isVisible|public|primaryKey|aliasMember|isGoverned|refs");let V=Array.isArray(s.dimensions)?s.dimensions:[];for(let C of V){let Q=[U(C.name),U(C.title||C.displayName||""),U(C.description||""),U(C.type||C.dataType||"")];u==="table"&&Q.push(U(C.sql||C.expression||"")),Q.push(U(W(C.suggestFilterValues)),U(W(se(C.isVisible,C.visible))),U(W(C.public)),U(W(C.primaryKey)),U(C.aliasMember||(Array.isArray(C.aliasMembers)?C.aliasMembers.join(","):"")),U(W(C.isGoverned)),U(Array.isArray(C.refs)?C.refs.join(","):C.refs||"")),h.push(Q.join("|"))}h.push(""),h.push("Measures"),h.push("name|title|description|cumulativeTotal|cumulative|type|aggType|isVisible|public|aliasMember|isGoverned|refs");let H=Array.isArray(s.measures)?s.measures:[];for(let C of H){let Q=[U(C.name),U(C.title||C.displayName||""),U(C.description||""),U(W(C.cumulativeTotal)),U(W(C.cumulative)),U(C.type||C.dataType||""),U(C.aggType||C.aggregation||""),U(W(se(C.isVisible,C.visible))),U(W(C.public)),U(C.aliasMember||(Array.isArray(C.aliasMembers)?C.aliasMembers.join(","):"")),U(W(C.isGoverned)),U(Array.isArray(C.refs)?C.refs.join(","):C.refs||"")];h.push(Q.join("|"))}return h},w=1;for(let s of g)y.push(...l(s,w++,"view")),y.push("");for(let s of m)y.push(...l(s,w++,"table")),y.push("");return y.join(`
66
66
  `)}async function re({slug:i=le,apiKey:c,fqdn:e=te}){let n=`https://${e}/lens2/api/${i.replace("public.","public:")}/v2/meta`,d={method:"GET",headers:{Authorization:`Bearer ${c}`}},{status:t,data:S}=await J(n,d);if(t<200||t>=300)return{content:[{type:"text",text:`Error: API responded with ${t}`}],isError:!0};try{let v=JSON.parse(S);return{content:[{type:"text",text:Ce(v,i)}]}}catch{return{content:[{type:"text",text:"Error: API Response is not a JSON"}],isError:!0}}}async function ue({slug:i=le,payload:c,apiKey:e,fqdn:n=te}){let d=`https://${n}/lens2/api/${i.replace("public.","public:")}/v2/load`,t=JSON.stringify({query:c}),S={method:"POST",headers:{Authorization:`Bearer ${e}`,"Content-Type":"application/json","Content-Length":Buffer.byteLength(t)}},{status:v,data:E}=await J(d,S,t,!0);if(v<200||v>=300)return{content:[{type:"text",text:JSON.stringify({status:v,data:E})}],isError:!0};try{let y=JSON.parse(E);return{content:[{type:"text",text:JSON.stringify(y.data)}]}}catch(y){return console.log("Error parsing lens data response:",y,E),{content:[{type:"text",text:`Query may be still running. Try again one more time. ${y.message}`}],isError:!0}}}async function oe({apiKey:i,fqdn:c=te}){let e=`https://${c}/dph/discover/api/msearch/query/v2`,n=JSON.stringify({queries:[{indexUid:"data_product_v2_search_index",q:"*",filter:["deleted='false'","tagList NOT IN ['DPTier.Source Aligned']"],offset:0,limit:1e3,attributesToRetrieve:["description","name","fullyQualifiedName","id","tagList","displayName","ports.lens.entityInfo.fullyQualifiedName","owner","purpose","updatedAt"]}]}),d={method:"POST",headers:{Authorization:`Bearer ${i}`,"Content-Type":"application/json","Content-Length":Buffer.byteLength(n)}},{status:t,data:S}=await J(e,d,n);if(t<200||t>=300)return{content:[{type:"text",text:`Error: API responded with ${t}`}],isError:!0};try{let E=JSON.parse(S).hits.filter(m=>m.ports?.lens),y=[],g=["Semantic model (lens) - fully qualified name","Data product name","Data product description","Purpose","DPDomain","DPUsecase","Owner","Updated At"];return E.forEach(m=>{let l=m.tagList.find(h=>h.startsWith("DPDomain."))?.replace("DPDomain.","")||"N/A",w=m.tagList.find(h=>h.startsWith("DPUsecase."))?.replace("DPUsecase.","")||"N/A",s=m.owner?.displayName||"N/A",b=m.updatedAt?new Date(m.updatedAt).toDateString():"N/A",u=[m.ports.lens.entityInfo.fullyQualifiedName.replace("dataos.",""),m.displayName,m.description,m.purpose||"N/A",l,w,s,b];y.push(u.join("|"))}),{content:[{type:"text",text:`${g.join("|")}
67
67
  `+y.join(`
68
68
  `)}]}}catch{return{content:[{type:"text",text:"Error: API Response is not a JSON"}],isError:!0}}}var Cr=`
@@ -168,7 +168,7 @@ The schema includes:
168
168
  - Provide curated data experiences for specific use cases
169
169
  - Can be entity-first (customer_360) or metrics-first (monthly_revenue)
170
170
 
171
- Keywords: schema, metadata, data structure, dimensions, measures, segments, views, model structure`,Rr=jr.string({description:"Name of the lens (semantic model slug). Alphanumeric with hyphen(-)s allowed. Make sure slug string contains workspace notation. example: public.customer-360"}),Re=({server:i,apiKey:c,fqdn:e,slug:n})=>{i.tool("query-lens-schema",Nr,n?{}:{slug:Rr},async({slug:d})=>re({slug:n||d,payload:{},apiKey:c,fqdn:e}))};import{ResourceTemplate as Ir}from"@modelcontextprotocol/sdk/server/mcp.js";var Pe=({server:i,apiKey:c,fqdn:e,slug:n})=>{n?i.resource("sematic-models",`sematic-models://lenses/${n}`,async d=>Ie({slug:n.toString(),href:d.href,apiKey:c,fqdn:e,payload:{}})):i.resource("sematic-models",new Ir("sematic-models://lenses/{slug}",{list:void 0}),async(d,{slug:t})=>Ie({slug:t.toString(),href:d.href,apiKey:c,fqdn:e,payload:{}}))};async function Ie({slug:i,apiKey:c,fqdn:e,href:n}){let d=await re({slug:i.toString(),payload:{},apiKey:c,fqdn:e});return{isError:d.isError,contents:d.content.map(({text:t})=>({uri:n,text:t}))}}var $e={name:"@tmdc-solutions/mcp-beta",version:"0.1.8",description:"for dataOS related tasks in local",type:"module",sideEffects:!1,main:"dist/stdio.cjs",types:"dist/stdio.d.ts",scripts:{build:"tsc","build:stdio":"tsup --clean","build:modules":"tsup --clean",http:"node dist/src/streamable-http.js -L",compile:"npm run build && npm run build:css && node dist/src/streamable-http.js -L",watch:'nodemon --watch src,views -e ts,pug,json,css --exec "npm run compile"',"build:css":"npx @tailwindcss/cli -i app.css -o public/output.css",test:'echo "Error: no test specified" && exit 1'},files:["dist/studio.cjs","dist/studio.cjs.map"],bin:{mcp:"./dist/stdio.js"},keywords:[],author:"",license:"ISC",packageManager:"pnpm@10.12.4",dependencies:{"@faker-js/faker":"^9.8.0","@modelcontextprotocol/sdk":"^1.12.0",dotenv:"^16.5.0",express:"^5.1.0",keyv:"^5.3.4",pug:"^3.0.3","trino-client":"^0.2.9",yaml:"^2.8.0",zod:"^3.25.67","zod-to-json-schema":"^3.24.5"},devDependencies:{"@tailwindcss/cli":"^4.1.8","@total-typescript/tsconfig":"^1.0.4","@types/express":"^5.0.2","@types/node":"^22.15.21",daisyui:"^5.0.40",nodemon:"^3.1.10",tailwindcss:"^4.1.8",tsup:"^8.5.0",typescript:"^5.8.3"}};import{z as D}from"zod";import{stringify as $r}from"yaml";import{existsSync as Mr,mkdirSync as Or,writeFileSync as Ur}from"fs";import Fr from"path";var Br=`Bundle in DataOS is a Resource that serves as a declarative and standardized mechanism for deploying a collection of Resources, Data Products, or applications in a single operation.
171
+ Keywords: schema, metadata, data structure, dimensions, measures, segments, views, model structure`,Rr=jr.string({description:"Name of the lens (semantic model slug). Alphanumeric with hyphen(-)s allowed. Make sure slug string contains workspace notation. example: public.customer-360"}),Re=({server:i,apiKey:c,fqdn:e,slug:n})=>{i.tool("query-lens-schema",Nr,n?{}:{slug:Rr},async({slug:d})=>re({slug:n||d,payload:{},apiKey:c,fqdn:e}))};import{ResourceTemplate as Ir}from"@modelcontextprotocol/sdk/server/mcp.js";var Pe=({server:i,apiKey:c,fqdn:e,slug:n})=>{n?i.resource("sematic-models",`sematic-models://lenses/${n}`,async d=>Ie({slug:n.toString(),href:d.href,apiKey:c,fqdn:e,payload:{}})):i.resource("sematic-models",new Ir("sematic-models://lenses/{slug}",{list:void 0}),async(d,{slug:t})=>Ie({slug:t.toString(),href:d.href,apiKey:c,fqdn:e,payload:{}}))};async function Ie({slug:i,apiKey:c,fqdn:e,href:n}){let d=await re({slug:i.toString(),payload:{},apiKey:c,fqdn:e});return{isError:d.isError,contents:d.content.map(({text:t})=>({uri:n,text:t}))}}var $e={name:"@tmdc-solutions/mcp-beta",version:"0.1.8",description:"for dataOS related tasks in local",type:"module",sideEffects:!1,main:"dist/stdio.cjs",types:"dist/stdio.d.ts",scripts:{build:"tsc","build:stdio":"tsup --clean","build:modules":"tsup --clean",http:"node dist/src/streamable-http.js -L",compile:"npm run build && npm run build:css && node dist/src/streamable-http.js -L",watch:'nodemon --watch src,views -e ts,pug,json,css --exec "npm run compile"',"build:css":"npx @tailwindcss/cli -i app.css -o public/output.css",test:'echo "Error: no test specified" && exit 1'},files:["dist/studio.cjs","dist/studio.cjs.map"],bin:{mcp:"./dist/stdio.js"},keywords:[],author:"",license:"ISC",packageManager:"pnpm@10.12.4",dependencies:{"@faker-js/faker":"^9.8.0","@modelcontextprotocol/sdk":"^1.25.2",dotenv:"^16.5.0",express:"^5.1.0",keyv:"^5.3.4",pug:"^3.0.3","trino-client":"^0.2.9",undici:"^6.21.0",yaml:"^2.8.0",zod:"^3.25.67","zod-to-json-schema":"^3.24.5"},devDependencies:{"@tailwindcss/cli":"^4.1.8","@total-typescript/tsconfig":"^1.0.4","@types/express":"^5.0.2","@types/node":"^22.15.21",daisyui:"^5.0.40",nodemon:"^3.1.10",tailwindcss:"^4.1.8",tsup:"^8.5.0",typescript:"^5.8.3"},pnpm:{overrides:{glob:">=10.5.0",qs:">=6.14.1",tar:">=7.5.3","body-parser":">=2.2.1","brace-expansion":">=2.0.2"}}};import{z as D}from"zod";import{stringify as $r}from"yaml";import{existsSync as Mr,mkdirSync as Or,writeFileSync as Ur}from"fs";import Fr from"path";var Br=`Bundle in DataOS is a Resource that serves as a declarative and standardized mechanism for deploying a collection of Resources, Data Products, or applications in a single operation.
172
172
  It empowers data developers with the capability to programmatically orchestrate the deployment, scheduling, creation, and dismantling of code and infrastructure resources linked to these Data Products and applications in a unified manner.
173
173
 
174
174
  A Bundle aggregates various DataOS Resources into a flattened directed acyclic graph (DAG), where each node represents a distinct DataOS Resource, interconnected through dependency relationships.
@@ -208,7 +208,7 @@ Lens operates as a logical modeling layer for accessing tabular data in data war
208
208
  Examples: Create entity-first views (customer profiles, product analytics) or metrics-first views (conversion rates, revenue tracking) with proper SQL selections and joins.
209
209
 
210
210
  Use this tool to generate multiple SQL view files at once for comprehensive Lens model development.
211
- `,Qe=q.enum(["string","number","time","boolean","date","timestamp"],{description:"SQL data type for dimensions and measures in Lens models"}),Oo=q.enum(["count","count_distinct","count_distinct_approx","sum","avg","min","max","string","number","boolean"],{description:"Measure aggregation type - count/sum/avg for numerical aggregations, string/number/boolean for calculated measures"}),Rn=q.enum(["one_to_one","one_to_many","many_to_one"],{description:"Join relationship type between tables - one_to_one (1:1), one_to_many (1:N), many_to_one (N:1)"}),Uo=q.enum(["entity_first","metrics_first"],{description:"View modeling approach - entity_first (focus on entity attributes), metrics_first (focus on specific metrics with time dimensions)"}),Fo=q.object({baseTable:q.string({description:"Base table name for the join (left side of join). Examples: 'customer', 'sales', 'product'"}),baseColumn:q.string({description:"Column name in base table for join condition. Examples: 'customer_id', 'product_id', 'order_id'"}),targetTable:q.string({description:"Target table name for the join (right side of join). Examples: 'orders', 'transactions', 'inventory'"}),targetColumn:q.string({description:"Column name in target table for join condition. Examples: 'customer_id', 'product_id', 'order_id'"})}),Bo=q.object({tableName:q.string({description:"Source table name containing the column. Examples: 'customer', 'sales', 'product'"}),columnName:q.string({description:"Column name to select from the table. Examples: 'customer_id', 'product_name', 'order_date'"}),alias:q.string({description:"Optional alias for the column in the view. Examples: 'customer_identifier', 'product_title', 'purchase_date'"}).optional(),dataType:Qe,isPrimaryKey:q.boolean({description:"Whether this column serves as a primary key for the entity"}).default(!1),isRequired:q.boolean({description:"Whether this column is required (NOT NULL) in the view"}).default(!0)}),zo=q.object({name:q.string({description:"Name of the calculated field. Examples: 'total_revenue', 'customer_lifetime_value', 'avg_order_value'"}),expression:q.string({description:"SQL expression for the calculation. Examples: 'SUM(order_amount)', 'COUNT(DISTINCT customer_id)', 'AVG(product_price * quantity)'"}),dataType:Qe,measureType:Oo.optional(),description:q.string({description:"Business description of what this calculated field represents"}).optional()}),We=q.object({column:q.string({description:"Column name for the condition. Examples: 'status', 'created_date', 'region'"}),operator:q.enum(["=","!=","<>","<","<=",">",">=","IN","NOT IN","LIKE","NOT LIKE","IS NULL","IS NOT NULL","BETWEEN","EXISTS","NOT EXISTS"],{description:"SQL comparison operator for the condition"}),value:q.union([q.string(),q.number(),q.array(q.union([q.string(),q.number()]))],{description:"Value(s) for the condition. Can be single value, array for IN/NOT IN, or range for BETWEEN"}).optional(),logicalOperator:q.enum(["AND","OR"],{description:"Logical operator to combine with next condition"}).optional()}),Qo=q.object({columns:q.array(q.string(),{description:"Column names to group by. Examples: ['region', 'product_category'], ['customer_segment'], ['date_trunc(\\'month\\', order_date)']"}),having:q.array(We,{description:"HAVING conditions for filtering grouped results (applied after GROUP BY)"}).optional()}),Wo=q.object({column:q.string({description:"Column name to order by. Examples: 'total_revenue', 'customer_name', 'order_date'"}),direction:q.enum(["ASC","DESC"],{description:"Sort direction - ASC (ascending) or DESC (descending)"}).default("ASC")}),Go=q.object({viewName:q.string({description:"Name of the Lens view to create. Examples: 'customer_360', 'sales_metrics', 'product_performance'"}),viewType:Uo,description:q.string({description:"Business description of the view's purpose and use case"}),baseTables:q.array(q.string(),{description:"Primary tables for the view. Examples: ['customer', 'orders'], ['sales', 'product'], ['transactions']"}),joins:q.array(Fo,{description:"Join conditions between tables. All joins in Lens are LEFT JOINs by default"}).optional(),dimensions:q.array(Bo,{description:"Dimensional columns (descriptive attributes) to include in the view. Examples: customer_name, product_category, region"}),measures:q.array(zo,{description:"Calculated measures (aggregated values) for the view. Examples: total_sales, customer_count, avg_order_value"}).optional(),whereConditions:q.array(We,{description:"WHERE conditions to filter the data. Examples: status = 'active', created_date > '2023-01-01'"}).optional(),groupBy:Qo.optional(),orderBy:q.array(Wo,{description:"ORDER BY specifications for result sorting"}).optional(),limit:q.number({description:"Maximum number of rows to return. Examples: 1000, 10000"}).optional(),timeFilter:q.object({timeColumn:q.string({description:"Time/date column for filtering. Examples: 'created_date', 'order_timestamp', 'updated_at'"}),granularity:q.enum(["second","minute","hour","day","week","month","quarter","year"],{description:"Time granularity for grouping time-based data"}).optional(),range:q.string({description:"Time range filter. Examples: 'last 30 days', 'this month', 'last quarter', '2023-01-01 to 2023-12-31'"}).optional()}).optional(),includeNulls:q.boolean({description:"Whether to include NULL values in results"}).default(!0),distinct:q.boolean({description:"Whether to apply DISTINCT to the entire result set"}).default(!1)}),Vo=q.array(q.object({viewConfig:Go,path:q.string({description:"Absolute path where the file will be stored. example: ~/Documents/project-name/my-lens-sql.sql"}),fileName:q.string({description:"File name for the lens SQL file. example: my-lens-sql.sql"})}),{description:"Array of Lens SQL views to create. Use this tool to create multiple Lens SQL view files at once. Note: For executing SQL queries on data, use the SQL MCP tool instead."}).nonempty();function Ho(i){return i.map(e=>`LEFT JOIN ${e.targetTable} ON ${e.baseTable}.${e.baseColumn} = ${e.targetTable}.${e.targetColumn}`).join(`
211
+ `,Qe=q.enum(["string","number","time","boolean","date","timestamp"],{description:"SQL data type for dimensions and measures in Lens models"}),Oo=q.enum(["count","count_distinct","count_distinct_approx","sum","avg","min","max","string","number","boolean"],{description:"Measure aggregation type - count/sum/avg for numerical aggregations, string/number/boolean for calculated measures"}),$n=q.enum(["one_to_one","one_to_many","many_to_one"],{description:"Join relationship type between tables - one_to_one (1:1), one_to_many (1:N), many_to_one (N:1)"}),Uo=q.enum(["entity_first","metrics_first"],{description:"View modeling approach - entity_first (focus on entity attributes), metrics_first (focus on specific metrics with time dimensions)"}),Fo=q.object({baseTable:q.string({description:"Base table name for the join (left side of join). Examples: 'customer', 'sales', 'product'"}),baseColumn:q.string({description:"Column name in base table for join condition. Examples: 'customer_id', 'product_id', 'order_id'"}),targetTable:q.string({description:"Target table name for the join (right side of join). Examples: 'orders', 'transactions', 'inventory'"}),targetColumn:q.string({description:"Column name in target table for join condition. Examples: 'customer_id', 'product_id', 'order_id'"})}),Bo=q.object({tableName:q.string({description:"Source table name containing the column. Examples: 'customer', 'sales', 'product'"}),columnName:q.string({description:"Column name to select from the table. Examples: 'customer_id', 'product_name', 'order_date'"}),alias:q.string({description:"Optional alias for the column in the view. Examples: 'customer_identifier', 'product_title', 'purchase_date'"}).optional(),dataType:Qe,isPrimaryKey:q.boolean({description:"Whether this column serves as a primary key for the entity"}).default(!1),isRequired:q.boolean({description:"Whether this column is required (NOT NULL) in the view"}).default(!0)}),zo=q.object({name:q.string({description:"Name of the calculated field. Examples: 'total_revenue', 'customer_lifetime_value', 'avg_order_value'"}),expression:q.string({description:"SQL expression for the calculation. Examples: 'SUM(order_amount)', 'COUNT(DISTINCT customer_id)', 'AVG(product_price * quantity)'"}),dataType:Qe,measureType:Oo.optional(),description:q.string({description:"Business description of what this calculated field represents"}).optional()}),We=q.object({column:q.string({description:"Column name for the condition. Examples: 'status', 'created_date', 'region'"}),operator:q.enum(["=","!=","<>","<","<=",">",">=","IN","NOT IN","LIKE","NOT LIKE","IS NULL","IS NOT NULL","BETWEEN","EXISTS","NOT EXISTS"],{description:"SQL comparison operator for the condition"}),value:q.union([q.string(),q.number(),q.array(q.union([q.string(),q.number()]))],{description:"Value(s) for the condition. Can be single value, array for IN/NOT IN, or range for BETWEEN"}).optional(),logicalOperator:q.enum(["AND","OR"],{description:"Logical operator to combine with next condition"}).optional()}),Qo=q.object({columns:q.array(q.string(),{description:"Column names to group by. Examples: ['region', 'product_category'], ['customer_segment'], ['date_trunc(\\'month\\', order_date)']"}),having:q.array(We,{description:"HAVING conditions for filtering grouped results (applied after GROUP BY)"}).optional()}),Wo=q.object({column:q.string({description:"Column name to order by. Examples: 'total_revenue', 'customer_name', 'order_date'"}),direction:q.enum(["ASC","DESC"],{description:"Sort direction - ASC (ascending) or DESC (descending)"}).default("ASC")}),Go=q.object({viewName:q.string({description:"Name of the Lens view to create. Examples: 'customer_360', 'sales_metrics', 'product_performance'"}),viewType:Uo,description:q.string({description:"Business description of the view's purpose and use case"}),baseTables:q.array(q.string(),{description:"Primary tables for the view. Examples: ['customer', 'orders'], ['sales', 'product'], ['transactions']"}),joins:q.array(Fo,{description:"Join conditions between tables. All joins in Lens are LEFT JOINs by default"}).optional(),dimensions:q.array(Bo,{description:"Dimensional columns (descriptive attributes) to include in the view. Examples: customer_name, product_category, region"}),measures:q.array(zo,{description:"Calculated measures (aggregated values) for the view. Examples: total_sales, customer_count, avg_order_value"}).optional(),whereConditions:q.array(We,{description:"WHERE conditions to filter the data. Examples: status = 'active', created_date > '2023-01-01'"}).optional(),groupBy:Qo.optional(),orderBy:q.array(Wo,{description:"ORDER BY specifications for result sorting"}).optional(),limit:q.number({description:"Maximum number of rows to return. Examples: 1000, 10000"}).optional(),timeFilter:q.object({timeColumn:q.string({description:"Time/date column for filtering. Examples: 'created_date', 'order_timestamp', 'updated_at'"}),granularity:q.enum(["second","minute","hour","day","week","month","quarter","year"],{description:"Time granularity for grouping time-based data"}).optional(),range:q.string({description:"Time range filter. Examples: 'last 30 days', 'this month', 'last quarter', '2023-01-01 to 2023-12-31'"}).optional()}).optional(),includeNulls:q.boolean({description:"Whether to include NULL values in results"}).default(!0),distinct:q.boolean({description:"Whether to apply DISTINCT to the entire result set"}).default(!1)}),Vo=q.array(q.object({viewConfig:Go,path:q.string({description:"Absolute path where the file will be stored. example: ~/Documents/project-name/my-lens-sql.sql"}),fileName:q.string({description:"File name for the lens SQL file. example: my-lens-sql.sql"})}),{description:"Array of Lens SQL views to create. Use this tool to create multiple Lens SQL view files at once. Note: For executing SQL queries on data, use the SQL MCP tool instead."}).nonempty();function Ho(i){return i.map(e=>`LEFT JOIN ${e.targetTable} ON ${e.baseTable}.${e.baseColumn} = ${e.targetTable}.${e.targetColumn}`).join(`
212
212
  `)}function ze(i){return i.length?`WHERE ${i.map((e,n)=>{let d="";switch(n>0&&e.logicalOperator&&(d+=`${e.logicalOperator} `),e.operator){case"IS NULL":case"IS NOT NULL":d+=`${e.column} ${e.operator}`;break;case"IN":case"NOT IN":let S=(Array.isArray(e.value)?e.value:[e.value]).map(E=>typeof E=="string"?`'${E}'`:E).join(", ");d+=`${e.column} ${e.operator} (${S})`;break;case"BETWEEN":Array.isArray(e.value)&&e.value.length===2&&(d+=`${e.column} BETWEEN ${e.value[0]} AND ${e.value[1]}`);break;case"LIKE":case"NOT LIKE":d+=`${e.column} ${e.operator} '${e.value}'`;break;default:let v=typeof e.value=="string"?`'${e.value}'`:e.value;d+=`${e.column} ${e.operator} ${v}`}return d}).join(" ")}`:""}function Ko(i,c){let e=i.map(t=>{let S=`${t.tableName}.${t.columnName}`;return t.alias?`${S} AS ${t.alias}`:S}),n=c?.map(t=>`${t.expression} AS ${t.name}`)||[];return[...e,...n].join(`,
213
213
  `)}var Ge=i=>{i.tool("create-lens-sql",Mo,{views:Vo},async({views:c})=>{let e=[];for(let n of c){let{viewConfig:d,path:t,fileName:S}=n,{viewName:v,viewType:E,description:y,baseTables:g,joins:m=[],dimensions:l,measures:w=[],whereConditions:s=[],groupBy:b,orderBy:u=[],limit:h,timeFilter:f,includeNulls:p,distinct:k}=d,N=Ko(l,w),P=g[0],_=m.length>0?Ho(m):"",M=s.length>0?ze(s):"",O="";if(b&&(O=`GROUP BY ${b.columns.join(", ")}`,b.having&&b.having.length>0)){let B=ze(b.having).replace("WHERE","HAVING");O+=`
214
214
  ${B}`}let G=u.length>0?`ORDER BY ${u.map(B=>`${B.column} ${B.direction}`).join(", ")}`:"",K=h?`LIMIT ${h}`:"",V="";if(f){let B=[];if(f.range){if(f.range.includes("last")&&f.range.includes("days")){let X=f.range.match(/\d+/)?.[0]||"30";B.push(`${f.timeColumn} >= CURRENT_DATE - INTERVAL '${X}' DAY`)}else if(f.range.includes("this month"))B.push(`${f.timeColumn} >= DATE_TRUNC('month', CURRENT_DATE)`);else if(f.range.includes("last quarter"))B.push(`${f.timeColumn} >= DATE_TRUNC('quarter', CURRENT_DATE) - INTERVAL '3' MONTH`);else if(f.range.includes(" to ")){let[X,at]=f.range.split(" to ");B.push(`${f.timeColumn} BETWEEN '${X.trim()}' AND '${at.trim()}'`)}}B.length>0&&(V=B.join(" AND "))}let H="";M&&V?H=`${M} AND ${V}`:M?H=M:V&&(H=`WHERE ${V}`);let Q=[`-- Lens View: ${v}`,`-- Type: ${E}`,`-- Description: ${y}`,"",`SELECT${k?" DISTINCT":""}`,` ${N}`,`FROM ${P}`,_,H,O,G,K].filter(B=>B.trim()!=="").join(`
@@ -236,7 +236,7 @@ Use segments when you notice the same filter conditions being applied repeatedly
236
236
  - LIKE pattern: "{TABLE}.state LIKE '%York%'"
237
237
  - Complex AND/OR: "{TABLE}.state = 'Illinois' AND {TABLE}.sales > 1000"
238
238
  - Date ranges: "{TABLE}.order_date >= '2023-01-01'"
239
- - Null checks: "{TABLE}.email IS NOT NULL"`}),Un=L.object({name:L.string({description:"Segment name - should be descriptive and follow naming conventions (e.g., 'active_customers', 'high_value_orders', 'california_sales')"}),sql:ge,public:L.boolean({description:"Whether the segment is publicly visible to all users or restricted"}).default(!0),description:L.string({description:"Human-readable description of what this segment filters (e.g., 'Filters for customers with active status and recent purchases')"}).optional(),meta:oi.optional()}),Ke=L.enum(["geographic_filter","date_range_filter","status_filter","category_filter","value_range_filter","null_check_filter","pattern_match_filter","custom"],{description:"Predefined templates for common segment patterns. Choose 'custom' for fully custom segments"}),ii=i=>{let{template:c,column:e,values:n,operator:d,startDate:t,endDate:S,minValue:v,maxValue:E,checkType:y,pattern:g,sql:m}=i;switch(c){case"geographic_filter":if(!e)return"Error: 'geographic_filter' template requires 'column' property.";if(!n||n.length===0)return"Error: 'geographic_filter' template requires 'values' property with geographic values.";if(t||S||v||E||y||g||m)return"Error: 'geographic_filter' template should only have 'column', 'values', and 'operator' properties.";break;case"date_range_filter":if(!e)return"Error: 'date_range_filter' template requires 'column' property.";if(!t&&!S)return"Error: 'date_range_filter' template requires either 'startDate' or 'endDate' property.";if(n||v||E||y||g||m)return"Error: 'date_range_filter' template should only have 'column', 'startDate', 'endDate', and 'operator' properties.";break;case"status_filter":if(!e)return"Error: 'status_filter' template requires 'column' property.";if(!n||n.length===0)return"Error: 'status_filter' template requires 'values' property with status values.";if(t||S||v||E||y||g||m)return"Error: 'status_filter' template should only have 'column', 'values', and 'operator' properties.";break;case"category_filter":if(!e)return"Error: 'category_filter' template requires 'column' property.";if(!n||n.length===0)return"Error: 'category_filter' template requires 'values' property with category values.";if(t||S||v||E||y||g||m)return"Error: 'category_filter' template should only have 'column', 'values', and 'operator' properties.";break;case"value_range_filter":if(!e)return"Error: 'value_range_filter' template requires 'column' property.";if(!v&&!E)return"Error: 'value_range_filter' template requires either 'minValue' or 'maxValue' property.";if(n||t||S||y||g||m)return"Error: 'value_range_filter' template should only have 'column', 'minValue', 'maxValue', and 'operator' properties.";break;case"null_check_filter":if(!e)return"Error: 'null_check_filter' template requires 'column' property.";if(!y)return"Error: 'null_check_filter' template requires 'checkType' property.";if(n||d||t||S||v||E||g||m)return"Error: 'null_check_filter' template should only have 'column' and 'checkType' properties.";break;case"pattern_match_filter":if(!e)return"Error: 'pattern_match_filter' template requires 'column' property.";if(!g)return"Error: 'pattern_match_filter' template requires 'pattern' property.";if(n||t||S||v||E||y||m)return"Error: 'pattern_match_filter' template should only have 'column', 'pattern', and 'operator' properties.";break;case"custom":if(!m)return"Error: 'custom' template requires 'sql' property with SQL expression.";if(e||n||d||t||S||v||E||y||g)return"Error: 'custom' template should only have 'sql' property.";break;default:return`Error: Invalid template type '${c}'. Supported types are: geographic_filter, date_range_filter, status_filter, category_filter, value_range_filter, null_check_filter, pattern_match_filter, custom.`}return null},si=L.object({template:Ke,column:L.string({description:"Column name for the filter"}).optional(),operator:L.enum(["=","!=",">",">=","<","<=","BETWEEN","IN","NOT IN","LIKE","NOT LIKE","ILIKE"],{description:"SQL operator to use for filtering"}).optional(),values:L.array(L.string(),{description:"Values to filter for (geographic, status, or category values)"}).optional(),startDate:L.string({description:"Start date in YYYY-MM-DD format (e.g., '2023-01-01')"}).optional(),endDate:L.string({description:"End date in YYYY-MM-DD format (e.g., '2023-12-31')"}).optional(),minValue:L.number({description:"Minimum value for the range"}).optional(),maxValue:L.number({description:"Maximum value for the range"}).optional(),checkType:L.enum(["IS NULL","IS NOT NULL"],{description:"Type of null check to perform"}).optional(),pattern:L.string({description:"Pattern to match (e.g., '%@gmail.com', 'Mr.%', '%premium%')"}).optional(),sql:ge.optional()}),He=L.object({segmentType:L.enum(["template","custom"],{description:"Whether to use a predefined template or create a custom segment"}).default("custom"),name:L.string({description:"Segment name - descriptive identifier for the segment"}),description:L.string({description:"Human-readable description of the segment's purpose"}).optional(),public:L.boolean({description:"Whether the segment is publicly accessible"}).default(!0),templateConfig:si.optional(),sql:ge.optional(),security:L.object({enabled:L.boolean({description:"Whether to enable user group-based security for this segment"}).default(!1),includeGroups:L.union([L.literal("*"),L.array(L.string())],{description:"User groups to include. Use '*' for all users or specify group names"}).optional(),excludeGroups:L.array(L.string(),{description:"User groups to exclude from access"}).optional()}).optional(),meta:L.object({tags:L.array(L.string()).optional(),customProperties:L.record(L.string(),L.any()).optional()}).optional()}),ni={configurationType:L.enum(["single","multiple","bulk_template"],{description:"Configuration type: 'single' for one segment, 'multiple' for several segments, 'bulk_template' for template-based generation"}),segment:He.optional(),segments:L.array(He,{description:"Array of segment configurations"}).optional(),bulkTemplate:L.object({baseTemplate:Ke,variations:L.array(L.object({name:L.string({description:"Name of the segment variation"}),values:L.array(L.string(),{description:"Values for this variation"}).optional(),customSql:L.string({description:"Custom SQL to override template"}).optional()}))}).optional(),outputFormat:L.enum(["segments_only","full_table_structure"],{description:"Whether to output only segments or include them in a full table structure"}).default("segments_only"),tableName:L.string({description:"Table name for full table structure output"}).optional(),comments:L.string({description:"Additional comments or notes about the segment configuration"}).optional(),path:L.string({description:"Absolute path where the file will be stored. example: ~/Documents/project-name/my-segments.yaml"}),fileName:L.string({description:"File name for the lens segments file. example: my-segments.yaml"})},Ye=i=>{i.tool("create-lens-segments",ei,ni,async({configurationType:c,segment:e,segments:n,bulkTemplate:d,outputFormat:t,tableName:S,path:v,fileName:E})=>{let y=[],g=l=>{let w=ii(l);if(w)throw new Error(w);let{template:s,column:b,values:u,operator:h,startDate:f,endDate:p,minValue:k,maxValue:N,checkType:P,pattern:_,sql:M}=l;switch(s){case"geographic_filter":return h==="IN"&&u.length>1?`{TABLE}.${b} IN ('${u.join("', '")}')`:h==="LIKE"?u.map(O=>`{TABLE}.${b} LIKE '%${O}%'`).join(" OR "):`{TABLE}.${b} ${h||"="} '${u[0]}'`;case"date_range_filter":if(f&&p)return h==="BETWEEN"?`{TABLE}.${b} BETWEEN '${f}' AND '${p}'`:`{TABLE}.${b} >= '${f}' AND {TABLE}.${b} <= '${p}'`;if(f)return`{TABLE}.${b} ${h||">="} '${f}'`;if(p)return`{TABLE}.${b} ${h||"<="} '${p}'`;break;case"status_filter":return h==="IN"&&u.length>1?`{TABLE}.${b} IN ('${u.join("', '")}')`:h==="NOT IN"?`{TABLE}.${b} NOT IN ('${u.join("', '")}')`:`{TABLE}.${b} ${h||"="} '${u[0]}'`;case"category_filter":return h==="IN"&&u.length>1?`{TABLE}.${b} IN ('${u.join("', '")}')`:h==="LIKE"?u.map(O=>`{TABLE}.${b} LIKE '%${O}%'`).join(" OR "):`{TABLE}.${b} ${h||"="} '${u[0]}'`;case"value_range_filter":if(k!==void 0&&N!==void 0)return h==="BETWEEN"?`{TABLE}.${b} BETWEEN ${k} AND ${N}`:`{TABLE}.${b} >= ${k} AND {TABLE}.${b} <= ${N}`;if(k!==void 0)return`{TABLE}.${b} ${h||">="} ${k}`;if(N!==void 0)return`{TABLE}.${b} ${h||"<="} ${N}`;break;case"null_check_filter":return`{TABLE}.${b} ${P}`;case"pattern_match_filter":return`{TABLE}.${b} ${h||"LIKE"} '${_}'`;case"custom":return M;default:throw new Error(`Unsupported template: ${s}`)}throw new Error(`Unable to generate SQL for template: ${s}`)},m=l=>{let w={name:l.name,public:l.public!==void 0?l.public:!0};if(l.description&&(w.description=l.description),l.segmentType==="template"&&l.templateConfig)w.sql=g(l.templateConfig);else if(l.sql)w.sql=l.sql;else throw new Error(`Segment '${l.name}' must have either templateConfig or custom sql`);if(l.security?.enabled){let s={};(l.security.includeGroups||l.security.excludeGroups)&&(s.secure={user_groups:{}},l.security.includeGroups&&(s.secure.user_groups.includes=l.security.includeGroups),l.security.excludeGroups&&(s.secure.user_groups.excludes=l.security.excludeGroups)),l.meta?.tags&&(s.tags=l.meta.tags),l.meta?.customProperties&&Object.assign(s,l.meta.customProperties),Object.keys(s).length>0&&(w.meta=s)}return w};try{if(c==="single"){if(!e)throw new Error("Segment configuration is required for single type");y.push(m(e))}else if(c==="multiple"){if(!n||n.length===0)throw new Error("Segments array is required for multiple type");y=n.map(m)}else if(c==="bulk_template"){if(!d)throw new Error("Bulk template configuration is required for bulk_template type");let{baseTemplate:u,variations:h}=d;y=h.map(f=>{let p={template:u};return f.values&&(p.values=f.values),f.customSql&&(p.sql=f.customSql,p.template="custom"),m({name:f.name,segmentType:"template",templateConfig:p,public:!0})})}let l=()=>["# Lens Segments Configuration","# Reusable filters for consistent data access patterns","# ","# Segments provide:","# - Reusable filter logic across multiple queries","# - Row-level security and data governance","# - Consistent business rule application","# - Performance optimization through pre-defined filters","# ",`# Configuration Type: ${c}`,`# Number of Segments: ${y.length}`,"# ","# Usage in Lens models:","# - Reference segments in measures and dimensions","# - Apply as default filters in cubes","# - Use for user group-based data access control","# ","# Segment SQL uses {TABLE} placeholder for table reference","# Example: {TABLE}.status = 'active' AND {TABLE}.created_date >= '2023-01-01'",""].join(`
239
+ - Null checks: "{TABLE}.email IS NOT NULL"`}),zn=L.object({name:L.string({description:"Segment name - should be descriptive and follow naming conventions (e.g., 'active_customers', 'high_value_orders', 'california_sales')"}),sql:ge,public:L.boolean({description:"Whether the segment is publicly visible to all users or restricted"}).default(!0),description:L.string({description:"Human-readable description of what this segment filters (e.g., 'Filters for customers with active status and recent purchases')"}).optional(),meta:oi.optional()}),Ke=L.enum(["geographic_filter","date_range_filter","status_filter","category_filter","value_range_filter","null_check_filter","pattern_match_filter","custom"],{description:"Predefined templates for common segment patterns. Choose 'custom' for fully custom segments"}),ii=i=>{let{template:c,column:e,values:n,operator:d,startDate:t,endDate:S,minValue:v,maxValue:E,checkType:y,pattern:g,sql:m}=i;switch(c){case"geographic_filter":if(!e)return"Error: 'geographic_filter' template requires 'column' property.";if(!n||n.length===0)return"Error: 'geographic_filter' template requires 'values' property with geographic values.";if(t||S||v||E||y||g||m)return"Error: 'geographic_filter' template should only have 'column', 'values', and 'operator' properties.";break;case"date_range_filter":if(!e)return"Error: 'date_range_filter' template requires 'column' property.";if(!t&&!S)return"Error: 'date_range_filter' template requires either 'startDate' or 'endDate' property.";if(n||v||E||y||g||m)return"Error: 'date_range_filter' template should only have 'column', 'startDate', 'endDate', and 'operator' properties.";break;case"status_filter":if(!e)return"Error: 'status_filter' template requires 'column' property.";if(!n||n.length===0)return"Error: 'status_filter' template requires 'values' property with status values.";if(t||S||v||E||y||g||m)return"Error: 'status_filter' template should only have 'column', 'values', and 'operator' properties.";break;case"category_filter":if(!e)return"Error: 'category_filter' template requires 'column' property.";if(!n||n.length===0)return"Error: 'category_filter' template requires 'values' property with category values.";if(t||S||v||E||y||g||m)return"Error: 'category_filter' template should only have 'column', 'values', and 'operator' properties.";break;case"value_range_filter":if(!e)return"Error: 'value_range_filter' template requires 'column' property.";if(!v&&!E)return"Error: 'value_range_filter' template requires either 'minValue' or 'maxValue' property.";if(n||t||S||y||g||m)return"Error: 'value_range_filter' template should only have 'column', 'minValue', 'maxValue', and 'operator' properties.";break;case"null_check_filter":if(!e)return"Error: 'null_check_filter' template requires 'column' property.";if(!y)return"Error: 'null_check_filter' template requires 'checkType' property.";if(n||d||t||S||v||E||g||m)return"Error: 'null_check_filter' template should only have 'column' and 'checkType' properties.";break;case"pattern_match_filter":if(!e)return"Error: 'pattern_match_filter' template requires 'column' property.";if(!g)return"Error: 'pattern_match_filter' template requires 'pattern' property.";if(n||t||S||v||E||y||m)return"Error: 'pattern_match_filter' template should only have 'column', 'pattern', and 'operator' properties.";break;case"custom":if(!m)return"Error: 'custom' template requires 'sql' property with SQL expression.";if(e||n||d||t||S||v||E||y||g)return"Error: 'custom' template should only have 'sql' property.";break;default:return`Error: Invalid template type '${c}'. Supported types are: geographic_filter, date_range_filter, status_filter, category_filter, value_range_filter, null_check_filter, pattern_match_filter, custom.`}return null},si=L.object({template:Ke,column:L.string({description:"Column name for the filter"}).optional(),operator:L.enum(["=","!=",">",">=","<","<=","BETWEEN","IN","NOT IN","LIKE","NOT LIKE","ILIKE"],{description:"SQL operator to use for filtering"}).optional(),values:L.array(L.string(),{description:"Values to filter for (geographic, status, or category values)"}).optional(),startDate:L.string({description:"Start date in YYYY-MM-DD format (e.g., '2023-01-01')"}).optional(),endDate:L.string({description:"End date in YYYY-MM-DD format (e.g., '2023-12-31')"}).optional(),minValue:L.number({description:"Minimum value for the range"}).optional(),maxValue:L.number({description:"Maximum value for the range"}).optional(),checkType:L.enum(["IS NULL","IS NOT NULL"],{description:"Type of null check to perform"}).optional(),pattern:L.string({description:"Pattern to match (e.g., '%@gmail.com', 'Mr.%', '%premium%')"}).optional(),sql:ge.optional()}),He=L.object({segmentType:L.enum(["template","custom"],{description:"Whether to use a predefined template or create a custom segment"}).default("custom"),name:L.string({description:"Segment name - descriptive identifier for the segment"}),description:L.string({description:"Human-readable description of the segment's purpose"}).optional(),public:L.boolean({description:"Whether the segment is publicly accessible"}).default(!0),templateConfig:si.optional(),sql:ge.optional(),security:L.object({enabled:L.boolean({description:"Whether to enable user group-based security for this segment"}).default(!1),includeGroups:L.union([L.literal("*"),L.array(L.string())],{description:"User groups to include. Use '*' for all users or specify group names"}).optional(),excludeGroups:L.array(L.string(),{description:"User groups to exclude from access"}).optional()}).optional(),meta:L.object({tags:L.array(L.string()).optional(),customProperties:L.record(L.string(),L.any()).optional()}).optional()}),ni={configurationType:L.enum(["single","multiple","bulk_template"],{description:"Configuration type: 'single' for one segment, 'multiple' for several segments, 'bulk_template' for template-based generation"}),segment:He.optional(),segments:L.array(He,{description:"Array of segment configurations"}).optional(),bulkTemplate:L.object({baseTemplate:Ke,variations:L.array(L.object({name:L.string({description:"Name of the segment variation"}),values:L.array(L.string(),{description:"Values for this variation"}).optional(),customSql:L.string({description:"Custom SQL to override template"}).optional()}))}).optional(),outputFormat:L.enum(["segments_only","full_table_structure"],{description:"Whether to output only segments or include them in a full table structure"}).default("segments_only"),tableName:L.string({description:"Table name for full table structure output"}).optional(),comments:L.string({description:"Additional comments or notes about the segment configuration"}).optional(),path:L.string({description:"Absolute path where the file will be stored. example: ~/Documents/project-name/my-segments.yaml"}),fileName:L.string({description:"File name for the lens segments file. example: my-segments.yaml"})},Ye=i=>{i.tool("create-lens-segments",ei,ni,async({configurationType:c,segment:e,segments:n,bulkTemplate:d,outputFormat:t,tableName:S,path:v,fileName:E})=>{let y=[],g=l=>{let w=ii(l);if(w)throw new Error(w);let{template:s,column:b,values:u,operator:h,startDate:f,endDate:p,minValue:k,maxValue:N,checkType:P,pattern:_,sql:M}=l;switch(s){case"geographic_filter":return h==="IN"&&u.length>1?`{TABLE}.${b} IN ('${u.join("', '")}')`:h==="LIKE"?u.map(O=>`{TABLE}.${b} LIKE '%${O}%'`).join(" OR "):`{TABLE}.${b} ${h||"="} '${u[0]}'`;case"date_range_filter":if(f&&p)return h==="BETWEEN"?`{TABLE}.${b} BETWEEN '${f}' AND '${p}'`:`{TABLE}.${b} >= '${f}' AND {TABLE}.${b} <= '${p}'`;if(f)return`{TABLE}.${b} ${h||">="} '${f}'`;if(p)return`{TABLE}.${b} ${h||"<="} '${p}'`;break;case"status_filter":return h==="IN"&&u.length>1?`{TABLE}.${b} IN ('${u.join("', '")}')`:h==="NOT IN"?`{TABLE}.${b} NOT IN ('${u.join("', '")}')`:`{TABLE}.${b} ${h||"="} '${u[0]}'`;case"category_filter":return h==="IN"&&u.length>1?`{TABLE}.${b} IN ('${u.join("', '")}')`:h==="LIKE"?u.map(O=>`{TABLE}.${b} LIKE '%${O}%'`).join(" OR "):`{TABLE}.${b} ${h||"="} '${u[0]}'`;case"value_range_filter":if(k!==void 0&&N!==void 0)return h==="BETWEEN"?`{TABLE}.${b} BETWEEN ${k} AND ${N}`:`{TABLE}.${b} >= ${k} AND {TABLE}.${b} <= ${N}`;if(k!==void 0)return`{TABLE}.${b} ${h||">="} ${k}`;if(N!==void 0)return`{TABLE}.${b} ${h||"<="} ${N}`;break;case"null_check_filter":return`{TABLE}.${b} ${P}`;case"pattern_match_filter":return`{TABLE}.${b} ${h||"LIKE"} '${_}'`;case"custom":return M;default:throw new Error(`Unsupported template: ${s}`)}throw new Error(`Unable to generate SQL for template: ${s}`)},m=l=>{let w={name:l.name,public:l.public!==void 0?l.public:!0};if(l.description&&(w.description=l.description),l.segmentType==="template"&&l.templateConfig)w.sql=g(l.templateConfig);else if(l.sql)w.sql=l.sql;else throw new Error(`Segment '${l.name}' must have either templateConfig or custom sql`);if(l.security?.enabled){let s={};(l.security.includeGroups||l.security.excludeGroups)&&(s.secure={user_groups:{}},l.security.includeGroups&&(s.secure.user_groups.includes=l.security.includeGroups),l.security.excludeGroups&&(s.secure.user_groups.excludes=l.security.excludeGroups)),l.meta?.tags&&(s.tags=l.meta.tags),l.meta?.customProperties&&Object.assign(s,l.meta.customProperties),Object.keys(s).length>0&&(w.meta=s)}return w};try{if(c==="single"){if(!e)throw new Error("Segment configuration is required for single type");y.push(m(e))}else if(c==="multiple"){if(!n||n.length===0)throw new Error("Segments array is required for multiple type");y=n.map(m)}else if(c==="bulk_template"){if(!d)throw new Error("Bulk template configuration is required for bulk_template type");let{baseTemplate:u,variations:h}=d;y=h.map(f=>{let p={template:u};return f.values&&(p.values=f.values),f.customSql&&(p.sql=f.customSql,p.template="custom"),m({name:f.name,segmentType:"template",templateConfig:p,public:!0})})}let l=()=>["# Lens Segments Configuration","# Reusable filters for consistent data access patterns","# ","# Segments provide:","# - Reusable filter logic across multiple queries","# - Row-level security and data governance","# - Consistent business rule application","# - Performance optimization through pre-defined filters","# ",`# Configuration Type: ${c}`,`# Number of Segments: ${y.length}`,"# ","# Usage in Lens models:","# - Reference segments in measures and dimensions","# - Apply as default filters in cubes","# - Use for user group-based data access control","# ","# Segment SQL uses {TABLE} placeholder for table reference","# Example: {TABLE}.status = 'active' AND {TABLE}.created_date >= '2023-01-01'",""].join(`
240
240
  `),w;if(t==="full_table_structure"){let u={name:S||"example_table",segments:y};w=l()+`table:
241
241
  `+Ve(u).split(`
242
242
  `).map(h=>` ${h}`).join(`
@@ -262,7 +262,7 @@ There are two main approaches for designing views:
262
262
 
263
263
  2. **Metrics-first approach**: Views focused on specific performance metrics, each containing one key measure with relevant dimensions for grouping and filtering. Each view represents a specific business metric over time.
264
264
 
265
- Views reference dimensions, measures, and segments from multiple logical tables but don't have any measures, dimensions, or segments of their own.`,ji=I.string({description:"Cron expression for scheduling (e.g., '*/5 * * * *' for every 5 minutes, '0 */6 * * *' for every 6 hours)"}).regex(/^(\*|([0-5]?\d)) (\*|([01]?\d|2[0-3])) (\*|([01]?\d|[12]\d|3[01])) (\*|([01]?\d)) (\*|[0-6])$/,"Invalid cron expression format"),Ni=I.object({expression:ji.describe("Cron expression for metric refresh schedule (e.g., '*/5 * * * *', '0 */6 * * *')"),timezone:I.string({description:"Timezone for metric calculations in TZ database format (e.g., 'UTC', 'America/Vancouver', 'America/Toronto')"}).default("UTC"),window:I.enum(["day","week","month","quarter","year"],{description:"Time window for metric aggregation - defines the granularity of metric calculation"}),excludes:I.array(I.string(),{description:"List of measures or dimensions to exclude from the metric view (e.g., ['purchases', 'source'])"}).optional()}),Ri=I.object({timeseries:I.string({description:"Time dimension for Iris dashboard visualization (format: 'table.column_name', e.g., 'sales.invoice_date')"}),excludes:I.array(I.string(),{description:"List of fields to exclude from Iris dashboard (e.g., ['sales.source', 'sales.invoice_date'])"}).optional(),refresh:I.object({every:I.string({description:"Refresh interval for Iris dashboard (e.g., '24h', '12h', '6h', '1h')"}).regex(/^\d+[hmd]$/,"Format should be like '24h', '12h', '30m', '15m'")}).optional()}),Ze=I.object({title:I.string({description:"Human-readable title for the view/metric (e.g., 'Customer Spending by Product Category')"}).optional(),tags:I.array(I.string(),{description:"Tags for categorization and discovery. Common patterns: ['DPDomain.{Domain}', 'DPUsecase.{UseCase}', 'DPTier.{Tier}'] (e.g., ['DPDomain.Sales', 'DPUsecase.Revenue Analysis', 'DPTier.Consumer Aligned'])"}).optional(),export_to_iris:I.boolean({description:"Whether to export this view to Iris dashboard for visualization (mainly for entity-first views)"}).optional(),iris:Ri.optional(),metric:Ni.optional(),refresh:I.object({every:I.string({description:"General refresh interval for the view (e.g., '24h', '12h', '6h')"}).regex(/^\d+[hmd]$/,"Format should be like '24h', '12h', '30m'")}).optional()}),Xe=I.object({join_path:I.string({description:"Name of the logical table to include in the view. Must match a table defined in your Lens model (e.g., 'sales', 'customer', 'product', 'marketing_campaign')"}),prefix:I.boolean({description:"Whether to prefix the included fields with the table name. Set to true to avoid naming conflicts (e.g., 'customer_name' vs 'name')"}).default(!1),includes:I.array(I.string(),{description:"List of specific measures, dimensions, or segments to include from this table (e.g., ['customer_id', 'total_revenue', 'invoice_date', 'churn_rate'])"}),excludes:I.array(I.string(),{description:"List of fields to exclude from this table (alternative to includes for when you want most fields)"}).optional()}),et=I.object({name:I.string({description:"View name - should be descriptive and follow naming conventions. For metrics-first: use metric name (e.g., 'customer_churn_rate', 'monthly_revenue'). For entity-first: use entity name (e.g., 'customer_360', 'product_analysis')"}),description:I.string({description:"Detailed description of the view's purpose and what insights it provides (e.g., 'This metric tracks customer churn rate over time, helping identify retention trends and at-risk customer segments')"}),public:I.boolean({description:"Whether the view is publicly accessible to all users or restricted"}).default(!0),meta:Ze.optional(),tables:I.array(Xe,{description:"List of tables to include in this view with their specific field selections"}).min(1,"At least one table must be included in the view")}),Jn=I.object({views:I.array(et,{description:"Array of view definitions - you can define multiple views for different use cases or metrics"}).min(1,"At least one view must be defined")}),Ii={viewType:I.enum(["single","multiple"],{description:"Whether to create a single view or multiple views in one configuration"}).default("single"),name:I.string({description:"View name - descriptive identifier for the view (required for single view type)"}).optional(),description:I.string({description:"Detailed description of the view's purpose (required for single view type)"}).optional(),public:I.boolean({description:"Whether the view is publicly accessible"}).default(!0),approach:I.enum(["entity-first","metrics-first"],{description:"Design approach: 'entity-first' for comprehensive entity views, 'metrics-first' for specific business metrics"}).optional(),meta:Ze.optional(),tables:I.array(Xe,{description:"List of tables to include in this view (required for single view type)"}).optional(),views:I.array(et,{description:"Array of view definitions (required for multiple view type)"}).optional(),comments:I.string({description:"Additional comments or notes about the view configuration"}).optional(),path:I.string({description:"Absolute path where the file will be stored. example: ~/Documents/project-name/my-views.yaml"}),fileName:I.string({description:"File name for the lens views file. example: my-views.yaml"})},tt=i=>{i.tool("create-lens-views",Di,Ii,async({viewType:c,name:e,description:n,public:d,approach:t,meta:S,tables:v,views:E,comments:y,path:g,fileName:m})=>{let l;if(c==="multiple"){if(!E||E.length===0)throw new Error("Views array is required for multiple view type");l={views:E}}else{if(!e||!n||!v||v.length===0)throw new Error("Name, description, and tables are required for single view type");let u={name:e,description:n,public:d,tables:v};S&&(u.meta=S),l={views:[u]}}let w=()=>{let u=[];return y&&u.push(`# ${y}`),t&&(t==="entity-first"?(u.push("# Entity-first approach: Comprehensive view of entity with related measures and dimensions"),u.push("# Use this for denormalized tables that describe entities fully")):(u.push("# Metrics-first approach: Focused on specific business metrics"),u.push("# Each view represents a key performance indicator with relevant dimensions"))),u.push("# Views reference dimensions, measures, and segments from logical tables"),u.push("# Views don't define their own measures/dimensions - they include them from tables"),c==="multiple"&&u.push("# Multiple views defined for different use cases or metrics"),u.join(`
265
+ Views reference dimensions, measures, and segments from multiple logical tables but don't have any measures, dimensions, or segments of their own.`,ji=I.string({description:"Cron expression for scheduling (e.g., '*/5 * * * *' for every 5 minutes, '0 */6 * * *' for every 6 hours)"}).regex(/^(\*|([0-5]?\d)) (\*|([01]?\d|2[0-3])) (\*|([01]?\d|[12]\d|3[01])) (\*|([01]?\d)) (\*|[0-6])$/,"Invalid cron expression format"),Ni=I.object({expression:ji.describe("Cron expression for metric refresh schedule (e.g., '*/5 * * * *', '0 */6 * * *')"),timezone:I.string({description:"Timezone for metric calculations in TZ database format (e.g., 'UTC', 'America/Vancouver', 'America/Toronto')"}).default("UTC"),window:I.enum(["day","week","month","quarter","year"],{description:"Time window for metric aggregation - defines the granularity of metric calculation"}),excludes:I.array(I.string(),{description:"List of measures or dimensions to exclude from the metric view (e.g., ['purchases', 'source'])"}).optional()}),Ri=I.object({timeseries:I.string({description:"Time dimension for Iris dashboard visualization (format: 'table.column_name', e.g., 'sales.invoice_date')"}),excludes:I.array(I.string(),{description:"List of fields to exclude from Iris dashboard (e.g., ['sales.source', 'sales.invoice_date'])"}).optional(),refresh:I.object({every:I.string({description:"Refresh interval for Iris dashboard (e.g., '24h', '12h', '6h', '1h')"}).regex(/^\d+[hmd]$/,"Format should be like '24h', '12h', '30m', '15m'")}).optional()}),Ze=I.object({title:I.string({description:"Human-readable title for the view/metric (e.g., 'Customer Spending by Product Category')"}).optional(),tags:I.array(I.string(),{description:"Tags for categorization and discovery. Common patterns: ['DPDomain.{Domain}', 'DPUsecase.{UseCase}', 'DPTier.{Tier}'] (e.g., ['DPDomain.Sales', 'DPUsecase.Revenue Analysis', 'DPTier.Consumer Aligned'])"}).optional(),export_to_iris:I.boolean({description:"Whether to export this view to Iris dashboard for visualization (mainly for entity-first views)"}).optional(),iris:Ri.optional(),metric:Ni.optional(),refresh:I.object({every:I.string({description:"General refresh interval for the view (e.g., '24h', '12h', '6h')"}).regex(/^\d+[hmd]$/,"Format should be like '24h', '12h', '30m'")}).optional()}),Xe=I.object({join_path:I.string({description:"Name of the logical table to include in the view. Must match a table defined in your Lens model (e.g., 'sales', 'customer', 'product', 'marketing_campaign')"}),prefix:I.boolean({description:"Whether to prefix the included fields with the table name. Set to true to avoid naming conflicts (e.g., 'customer_name' vs 'name')"}).default(!1),includes:I.array(I.string(),{description:"List of specific measures, dimensions, or segments to include from this table (e.g., ['customer_id', 'total_revenue', 'invoice_date', 'churn_rate'])"}),excludes:I.array(I.string(),{description:"List of fields to exclude from this table (alternative to includes for when you want most fields)"}).optional()}),et=I.object({name:I.string({description:"View name - should be descriptive and follow naming conventions. For metrics-first: use metric name (e.g., 'customer_churn_rate', 'monthly_revenue'). For entity-first: use entity name (e.g., 'customer_360', 'product_analysis')"}),description:I.string({description:"Detailed description of the view's purpose and what insights it provides (e.g., 'This metric tracks customer churn rate over time, helping identify retention trends and at-risk customer segments')"}),public:I.boolean({description:"Whether the view is publicly accessible to all users or restricted"}).default(!0),meta:Ze.optional(),tables:I.array(Xe,{description:"List of tables to include in this view with their specific field selections"}).min(1,"At least one table must be included in the view")}),ea=I.object({views:I.array(et,{description:"Array of view definitions - you can define multiple views for different use cases or metrics"}).min(1,"At least one view must be defined")}),Ii={viewType:I.enum(["single","multiple"],{description:"Whether to create a single view or multiple views in one configuration"}).default("single"),name:I.string({description:"View name - descriptive identifier for the view (required for single view type)"}).optional(),description:I.string({description:"Detailed description of the view's purpose (required for single view type)"}).optional(),public:I.boolean({description:"Whether the view is publicly accessible"}).default(!0),approach:I.enum(["entity-first","metrics-first"],{description:"Design approach: 'entity-first' for comprehensive entity views, 'metrics-first' for specific business metrics"}).optional(),meta:Ze.optional(),tables:I.array(Xe,{description:"List of tables to include in this view (required for single view type)"}).optional(),views:I.array(et,{description:"Array of view definitions (required for multiple view type)"}).optional(),comments:I.string({description:"Additional comments or notes about the view configuration"}).optional(),path:I.string({description:"Absolute path where the file will be stored. example: ~/Documents/project-name/my-views.yaml"}),fileName:I.string({description:"File name for the lens views file. example: my-views.yaml"})},tt=i=>{i.tool("create-lens-views",Di,Ii,async({viewType:c,name:e,description:n,public:d,approach:t,meta:S,tables:v,views:E,comments:y,path:g,fileName:m})=>{let l;if(c==="multiple"){if(!E||E.length===0)throw new Error("Views array is required for multiple view type");l={views:E}}else{if(!e||!n||!v||v.length===0)throw new Error("Name, description, and tables are required for single view type");let u={name:e,description:n,public:d,tables:v};S&&(u.meta=S),l={views:[u]}}let w=()=>{let u=[];return y&&u.push(`# ${y}`),t&&(t==="entity-first"?(u.push("# Entity-first approach: Comprehensive view of entity with related measures and dimensions"),u.push("# Use this for denormalized tables that describe entities fully")):(u.push("# Metrics-first approach: Focused on specific business metrics"),u.push("# Each view represents a key performance indicator with relevant dimensions"))),u.push("# Views reference dimensions, measures, and segments from logical tables"),u.push("# Views don't define their own measures/dimensions - they include them from tables"),c==="multiple"&&u.push("# Multiple views defined for different use cases or metrics"),u.join(`
266
266
  `)},s=Ai(l),b=w()+`
267
267
 
268
268
  `+s;try{let u=g.includes(".yaml")||g.includes(".yml")?g:g.endsWith("/")?g+m:`${g}/${m}`,h=qi.dirname(u);return Ti(h)||Li(h,{recursive:!0}),Ci(u,b),{content:[{type:"text",text:`Lens views file created successfully at ${u}`},{type:"text",text:`File content: ${b}`}]}}catch(u){return{content:[{type:"text",text:`Error creating lens views file: ${u}`}]}}})};import{z as R}from"zod";import{stringify as rt}from"yaml";import{existsSync as Pi,mkdirSync as $i,writeFileSync as Mi}from"fs";import Oi from"path";var Ui=`Lens User Groups are used to manage both data access and API scopes, which control access to specific functionalities and endpoints in the Lens semantic layer. This forms part of the access policy, ensuring users interact only with the data and features they are authorized to use.
@@ -286,7 +286,7 @@ User groups extend governance to the Lens Studio Interface, where access to spec
286
286
  - 'data': Access to data query endpoints (/v2/load, /v2/sql) - retrieve and analyze data
287
287
  - 'graphql': Access to GraphQL endpoint (/v2/graphql) - GraphQL-based queries
288
288
  - 'jobs': Access to job-related endpoints (advanced functionality)
289
- - 'source': Access to source-related endpoints (advanced functionality)`}),ot=R.union([R.literal("*"),R.string().regex(/^users:id:.+$/,"User ID must follow pattern 'users:id:username'")],{description:"User specification pattern: '*' for all users or 'users:id:username' for specific users (e.g., 'users:id:johndoe', 'users:id:iamgroot')"}),ce=R.union([R.literal("*"),R.array(ot,{description:"List of users to include in this group. Use specific user IDs for small groups or '*' for all users"})],{description:"Users to include in this group. Use '*' to include all users or specify individual user IDs"}),ae=R.array(ot,{description:"List of users to exclude from this group (e.g., ['users:id:tempuser', 'users:id:guest'])"}),oa=R.object({name:R.string({description:"Unique group name - should be descriptive and follow naming conventions (e.g., 'data_analyst', 'data_engineer', 'business_user', 'admin')"}),description:R.string({description:"Brief description of the user group's purpose and the type of users it contains (e.g., 'Data analysts responsible for reporting and visualization tasks')"}).optional(),api_scopes:R.array(Z,{description:"List of API scopes this group can access. Follow principle of least privilege - grant only necessary access"}).optional(),includes:ce,excludes:ae.optional()}),be=R.enum(["data_analyst","data_engineer","data_scientist","business_user","admin","viewer","developer","custom"],{description:"Predefined role templates with typical API scope configurations. Choose 'custom' for fully custom groups"}),ia=R.object({template:be,name:R.string({description:"Group name - will be used as-is or can override template default"}).optional(),description:R.string({description:"Custom description for this group"}).optional(),customApiScopes:R.array(Z,{description:"Override default API scopes for this template"}).optional(),includes:ce,excludes:ae.optional(),additionalProperties:R.record(R.string(),R.any(),{description:"Additional custom properties for the group"}).optional()}),Fi=i=>{let{type:c,group:e}=i;switch(c){case"custom":if(!e)return"Error: 'custom' type requires 'group' property with userGroupSchema configuration.";if(!e.name)return"Error: Custom user group requires 'name' property.";if(!e.includes)return"Error: Custom user group requires 'includes' property.";if(e.template||e.customApiScopes||e.additionalProperties)return"Error: Custom user group should not have template-specific properties ('template', 'customApiScopes', 'additionalProperties').";break;case"template":if(!e)return"Error: 'template' type requires 'group' property with templateUserGroupSchema configuration.";if(!e.template)return"Error: Template user group requires 'template' property.";if(!e.includes)return"Error: Template user group requires 'includes' property.";break;default:return`Error: Invalid user group configuration type '${c}'. Supported types are: custom, template.`}return null},ye=R.object({type:R.enum(["custom","template"],{description:"Type of user group configuration: 'custom' for fully custom groups, 'template' for template-based groups"}),group:R.object({name:R.string({description:"Group name - will be used as-is or can override template default"}).optional(),description:R.string({description:"Custom description for this group"}).optional(),includes:ce,excludes:ae.optional(),api_scopes:R.array(Z,{description:"List of API scopes this group can access. Follow principle of least privilege - grant only necessary access"}).optional(),template:be.optional(),customApiScopes:R.array(Z,{description:"Override default API scopes for this template"}).optional(),additionalProperties:R.record(R.string(),R.any(),{description:"Additional custom properties for the group"}).optional()})}),sa=R.object({groups:R.array(ye,{description:"Array of user group configurations"}).min(1,"At least one user group must be defined")}),Bi=R.object({baseTemplate:be,variations:R.array(R.object({name:R.string({description:"Name for this variation (e.g., 'marketing_analyst', 'finance_analyst')"}),description:R.string({description:"Description for this variation"}).optional(),customApiScopes:R.array(Z).optional(),includes:ce,excludes:ae.optional()}),{description:"Variations of the base template to generate"}).min(1,"At least one variation must be specified"),commonProperties:R.object({apiScopes:R.array(Z).optional(),excludes:ae.optional()}).optional()}),zi={configurationType:R.enum(["single","multiple","bulk_template"],{description:"Type of user group configuration: 'single' for one group, 'multiple' for several groups, 'bulk_template' for generating multiple groups from templates"}).default("single"),userGroup:ye.optional(),userGroups:R.array(ye,{description:"Array of user group configurations for multiple groups"}).optional(),bulkTemplate:Bi.optional(),includeDefaultGroup:R.boolean({description:"Whether to include a default group that gives all users basic access"}).default(!0),defaultGroupConfig:R.object({name:R.string().default("default"),description:R.string().default("Default user group with basic access"),api_scopes:R.array(Z).default(["data","graphql"]),includes:ce.default("*")}).optional(),outputFormat:R.enum(["user_groups_only","complete_file"],{description:"Whether to output only user groups or include them in a complete user_groups.yaml file structure"}).default("complete_file"),comments:R.string({description:"Additional comments or notes about the user group configuration"}).optional(),path:R.string({description:"Absolute path where the file will be stored. example: ~/Documents/project-name/my-user-groups.yaml"}),fileName:R.string({description:"File name for the lens user groups file. example: my-user-groups.yaml"})},it=i=>{i.tool("create-lens-user-groups",Ui,zi,async({configurationType:c,userGroup:e,userGroups:n,bulkTemplate:d,includeDefaultGroup:t,defaultGroupConfig:S,outputFormat:v,comments:E,path:y,fileName:g})=>{let m=[],l=f=>{switch(f){case"data_analyst":return["meta","data","graphql"];case"data_engineer":return["meta","data","graphql","jobs"];case"data_scientist":return["meta","data","graphql","jobs","source"];case"business_user":return["meta","data"];case"admin":return["meta","data","graphql","jobs","source"];case"viewer":return["meta"];case"developer":return["meta","data","graphql","jobs"];default:return["meta","data"]}},w=f=>f==="custom"?"custom_group":f,s=f=>{switch(f){case"data_analyst":return"Data analysts responsible for reporting, visualization, and business intelligence tasks";case"data_engineer":return"Data engineers who build and maintain data pipelines, transformations, and infrastructure";case"data_scientist":return"Data scientists with full access to data, modeling capabilities, and source management";case"business_user":return"Business users who need access to view and analyze data for decision making";case"admin":return"Administrators with full access to all Lens functionality and management capabilities";case"viewer":return"Read-only users who can view metadata but cannot query data";case"developer":return"Developers who build applications and integrations using Lens APIs";default:return"Custom user group with specific access requirements"}},b=f=>{let p=Fi(f);if(p)throw new Error(p);if(f.type==="template"){let{group:k}=f,N=k.template;return{name:k.name||w(N),description:k.description||s(N),api_scopes:k.customApiScopes||l(N),includes:k.includes,...k.excludes&&{excludes:k.excludes},...k.additionalProperties&&k.additionalProperties}}else{let{group:k}=f;return{name:k.name,...k.description&&{description:k.description},...k.api_scopes&&{api_scopes:k.api_scopes},includes:k.includes,...k.excludes&&{excludes:k.excludes}}}};if(c==="single"){if(!e)throw new Error("User group configuration is required for single type");m.push(b(e))}else if(c==="multiple"){if(!n||n.length===0)throw new Error("User groups array is required for multiple type");m=n.map(b)}else if(c==="bulk_template"){if(!d)throw new Error("Bulk template configuration is required for bulk_template type");let{baseTemplate:f,variations:p,commonProperties:k}=d;m=p.map(N=>({name:N.name,description:N.description||s(f),api_scopes:N.customApiScopes||k?.apiScopes||l(f),includes:N.includes,excludes:N.excludes||k?.excludes}))}if(t){let f={name:S?.name||"default",description:S?.description||"Default user group with basic access",api_scopes:S?.api_scopes||["data","graphql"],includes:S?.includes||"*"};m.unshift(f)}let u=()=>["# Lens User Groups Configuration","# This file defines user groups for access control in Lens semantic layer","# ","# User groups control both API access and data visibility:","# - API Scopes: Control access to specific REST endpoints","# - Data Access: Define who can access what data through inclusion/exclusion","# - Priority: First-listed group takes precedence for users in multiple groups","# ","# API Scopes:","# - meta: Metadata endpoints (/v2/meta) - sources, authors, timezones","# - data: Data query endpoints (/v2/load, /v2/sql) - retrieve and analyze data","# - graphql: GraphQL endpoint (/v2/graphql) - GraphQL-based queries","# - jobs: Job-related endpoints (advanced functionality)","# - source: Source-related endpoints (advanced functionality)","# ","# User Patterns:","# - '*': All users","# - 'users:id:username': Specific user (e.g., 'users:id:johndoe')","# ",...E?["# Additional Notes:",`# ${E}`,"# "]:[]].join(`
289
+ - 'source': Access to source-related endpoints (advanced functionality)`}),ot=R.union([R.literal("*"),R.string().regex(/^users:id:.+$/,"User ID must follow pattern 'users:id:username'")],{description:"User specification pattern: '*' for all users or 'users:id:username' for specific users (e.g., 'users:id:johndoe', 'users:id:iamgroot')"}),ce=R.union([R.literal("*"),R.array(ot,{description:"List of users to include in this group. Use specific user IDs for small groups or '*' for all users"})],{description:"Users to include in this group. Use '*' to include all users or specify individual user IDs"}),ae=R.array(ot,{description:"List of users to exclude from this group (e.g., ['users:id:tempuser', 'users:id:guest'])"}),na=R.object({name:R.string({description:"Unique group name - should be descriptive and follow naming conventions (e.g., 'data_analyst', 'data_engineer', 'business_user', 'admin')"}),description:R.string({description:"Brief description of the user group's purpose and the type of users it contains (e.g., 'Data analysts responsible for reporting and visualization tasks')"}).optional(),api_scopes:R.array(Z,{description:"List of API scopes this group can access. Follow principle of least privilege - grant only necessary access"}).optional(),includes:ce,excludes:ae.optional()}),be=R.enum(["data_analyst","data_engineer","data_scientist","business_user","admin","viewer","developer","custom"],{description:"Predefined role templates with typical API scope configurations. Choose 'custom' for fully custom groups"}),aa=R.object({template:be,name:R.string({description:"Group name - will be used as-is or can override template default"}).optional(),description:R.string({description:"Custom description for this group"}).optional(),customApiScopes:R.array(Z,{description:"Override default API scopes for this template"}).optional(),includes:ce,excludes:ae.optional(),additionalProperties:R.record(R.string(),R.any(),{description:"Additional custom properties for the group"}).optional()}),Fi=i=>{let{type:c,group:e}=i;switch(c){case"custom":if(!e)return"Error: 'custom' type requires 'group' property with userGroupSchema configuration.";if(!e.name)return"Error: Custom user group requires 'name' property.";if(!e.includes)return"Error: Custom user group requires 'includes' property.";if(e.template||e.customApiScopes||e.additionalProperties)return"Error: Custom user group should not have template-specific properties ('template', 'customApiScopes', 'additionalProperties').";break;case"template":if(!e)return"Error: 'template' type requires 'group' property with templateUserGroupSchema configuration.";if(!e.template)return"Error: Template user group requires 'template' property.";if(!e.includes)return"Error: Template user group requires 'includes' property.";break;default:return`Error: Invalid user group configuration type '${c}'. Supported types are: custom, template.`}return null},ye=R.object({type:R.enum(["custom","template"],{description:"Type of user group configuration: 'custom' for fully custom groups, 'template' for template-based groups"}),group:R.object({name:R.string({description:"Group name - will be used as-is or can override template default"}).optional(),description:R.string({description:"Custom description for this group"}).optional(),includes:ce,excludes:ae.optional(),api_scopes:R.array(Z,{description:"List of API scopes this group can access. Follow principle of least privilege - grant only necessary access"}).optional(),template:be.optional(),customApiScopes:R.array(Z,{description:"Override default API scopes for this template"}).optional(),additionalProperties:R.record(R.string(),R.any(),{description:"Additional custom properties for the group"}).optional()})}),ca=R.object({groups:R.array(ye,{description:"Array of user group configurations"}).min(1,"At least one user group must be defined")}),Bi=R.object({baseTemplate:be,variations:R.array(R.object({name:R.string({description:"Name for this variation (e.g., 'marketing_analyst', 'finance_analyst')"}),description:R.string({description:"Description for this variation"}).optional(),customApiScopes:R.array(Z).optional(),includes:ce,excludes:ae.optional()}),{description:"Variations of the base template to generate"}).min(1,"At least one variation must be specified"),commonProperties:R.object({apiScopes:R.array(Z).optional(),excludes:ae.optional()}).optional()}),zi={configurationType:R.enum(["single","multiple","bulk_template"],{description:"Type of user group configuration: 'single' for one group, 'multiple' for several groups, 'bulk_template' for generating multiple groups from templates"}).default("single"),userGroup:ye.optional(),userGroups:R.array(ye,{description:"Array of user group configurations for multiple groups"}).optional(),bulkTemplate:Bi.optional(),includeDefaultGroup:R.boolean({description:"Whether to include a default group that gives all users basic access"}).default(!0),defaultGroupConfig:R.object({name:R.string().default("default"),description:R.string().default("Default user group with basic access"),api_scopes:R.array(Z).default(["data","graphql"]),includes:ce.default("*")}).optional(),outputFormat:R.enum(["user_groups_only","complete_file"],{description:"Whether to output only user groups or include them in a complete user_groups.yaml file structure"}).default("complete_file"),comments:R.string({description:"Additional comments or notes about the user group configuration"}).optional(),path:R.string({description:"Absolute path where the file will be stored. example: ~/Documents/project-name/my-user-groups.yaml"}),fileName:R.string({description:"File name for the lens user groups file. example: my-user-groups.yaml"})},it=i=>{i.tool("create-lens-user-groups",Ui,zi,async({configurationType:c,userGroup:e,userGroups:n,bulkTemplate:d,includeDefaultGroup:t,defaultGroupConfig:S,outputFormat:v,comments:E,path:y,fileName:g})=>{let m=[],l=f=>{switch(f){case"data_analyst":return["meta","data","graphql"];case"data_engineer":return["meta","data","graphql","jobs"];case"data_scientist":return["meta","data","graphql","jobs","source"];case"business_user":return["meta","data"];case"admin":return["meta","data","graphql","jobs","source"];case"viewer":return["meta"];case"developer":return["meta","data","graphql","jobs"];default:return["meta","data"]}},w=f=>f==="custom"?"custom_group":f,s=f=>{switch(f){case"data_analyst":return"Data analysts responsible for reporting, visualization, and business intelligence tasks";case"data_engineer":return"Data engineers who build and maintain data pipelines, transformations, and infrastructure";case"data_scientist":return"Data scientists with full access to data, modeling capabilities, and source management";case"business_user":return"Business users who need access to view and analyze data for decision making";case"admin":return"Administrators with full access to all Lens functionality and management capabilities";case"viewer":return"Read-only users who can view metadata but cannot query data";case"developer":return"Developers who build applications and integrations using Lens APIs";default:return"Custom user group with specific access requirements"}},b=f=>{let p=Fi(f);if(p)throw new Error(p);if(f.type==="template"){let{group:k}=f,N=k.template;return{name:k.name||w(N),description:k.description||s(N),api_scopes:k.customApiScopes||l(N),includes:k.includes,...k.excludes&&{excludes:k.excludes},...k.additionalProperties&&k.additionalProperties}}else{let{group:k}=f;return{name:k.name,...k.description&&{description:k.description},...k.api_scopes&&{api_scopes:k.api_scopes},includes:k.includes,...k.excludes&&{excludes:k.excludes}}}};if(c==="single"){if(!e)throw new Error("User group configuration is required for single type");m.push(b(e))}else if(c==="multiple"){if(!n||n.length===0)throw new Error("User groups array is required for multiple type");m=n.map(b)}else if(c==="bulk_template"){if(!d)throw new Error("Bulk template configuration is required for bulk_template type");let{baseTemplate:f,variations:p,commonProperties:k}=d;m=p.map(N=>({name:N.name,description:N.description||s(f),api_scopes:N.customApiScopes||k?.apiScopes||l(f),includes:N.includes,excludes:N.excludes||k?.excludes}))}if(t){let f={name:S?.name||"default",description:S?.description||"Default user group with basic access",api_scopes:S?.api_scopes||["data","graphql"],includes:S?.includes||"*"};m.unshift(f)}let u=()=>["# Lens User Groups Configuration","# This file defines user groups for access control in Lens semantic layer","# ","# User groups control both API access and data visibility:","# - API Scopes: Control access to specific REST endpoints","# - Data Access: Define who can access what data through inclusion/exclusion","# - Priority: First-listed group takes precedence for users in multiple groups","# ","# API Scopes:","# - meta: Metadata endpoints (/v2/meta) - sources, authors, timezones","# - data: Data query endpoints (/v2/load, /v2/sql) - retrieve and analyze data","# - graphql: GraphQL endpoint (/v2/graphql) - GraphQL-based queries","# - jobs: Job-related endpoints (advanced functionality)","# - source: Source-related endpoints (advanced functionality)","# ","# User Patterns:","# - '*': All users","# - 'users:id:username': Specific user (e.g., 'users:id:johndoe')","# ",...E?["# Additional Notes:",`# ${E}`,"# "]:[]].join(`
290
290
  `),h=v==="user_groups_only"?`${u()}
291
291
  user_groups:
292
292
  ${rt(m).split(`
@@ -351,5 +351,5 @@ BEST PRACTICES:
351
351
 
352
352
  Keywords: SQL, Trino, cross-model, JOIN, CTE, window functions, multi-model analytics`;async function nt({server:i,apiKey:c,fqdn:e,userId:n}){i.tool("trino-query",Vi,{sqlQuery:Gi.string({description:"SQL query using two-part table names: semantic_model_name.table_name (e.g., sales_360.orders). Supports full Trino SQL syntax. Example: SELECT customer_name, SUM(revenue) FROM sales_360.orders WHERE order_date >= DATE '2024-01-01' GROUP BY customer_name LIMIT 10"})},async({sqlQuery:d})=>{try{let S=await st({fqdn:e,apiKey:c,userId:n}).query({query:d,catalog:"icebase"}),v=0,E,y;return await S.forEach(g=>{if(v==0){let m=g.columns.map(({name:l,type:w})=>`${l}-${w}`);m.shift(),E=m.join("|")}g.data&&(y=g.data.map(l=>(l.shift(),l.join("|"))).join(`
353
353
  `)),v++}),{content:[{type:"text",text:`${E}
354
- ${y}`}]}}catch(t){return{content:[{type:"text",text:`Error executing query: ${t.message}`}],isError:!0}}})}var{version:Yi}=$e;async function Ji(){let i=process.env.API_KEY,c=process.env.FQDN,e=process.env.SLUG,n=process.env.DEV||!1,d=process.env.USERID,t=new Hi({name:"DataOS",version:Yi,capabilities:{resources:{}}}),S=new Ki;n&&(Se(t),xe(t),Ee(t),ke(t),Ae(t),_e(t),Oe(t),Fe(t),Be(t),Ge(t),Ye(t),Je(t),tt(t),it(t)),i&&(De({server:t,apiKey:i,fqdn:c,slug:e}),e||(je({server:t,apiKey:i,fqdn:c}),Ne({server:t,apiKey:i,fqdn:c})),Re({server:t,apiKey:i,fqdn:c,slug:e}),Pe({server:t,apiKey:i,fqdn:c,slug:e}),nt({server:t,apiKey:i,fqdn:c,userId:d})),await t.connect(S)}Ji().catch(console.error);
354
+ ${y}`}]}}catch(t){return{content:[{type:"text",text:`Error executing query: ${t.message}`}],isError:!0}}})}import{setGlobalDispatcher as Yi,Agent as Ji}from"undici";import Zi from"fs";if(process.env.NODE_EXTRA_CA_CERTS){let i=new Ji({connect:{rejectUnauthorized:!0,ca:Zi.readFileSync(process.env.NODE_EXTRA_CA_CERTS)}});Yi(i)}var{version:Xi}=$e;async function es(){let i=process.env.API_KEY,c=process.env.FQDN,e=process.env.SLUG,n=process.env.DEV||!1,d=process.env.USERID,t=new Hi({name:"DataOS",version:Xi}),S=new Ki;n&&(Se(t),xe(t),Ee(t),ke(t),Ae(t),_e(t),Oe(t),Fe(t),Be(t),Ge(t),Ye(t),Je(t),tt(t),it(t)),i&&(De({server:t,apiKey:i,fqdn:c,slug:e}),e||(je({server:t,apiKey:i,fqdn:c}),Ne({server:t,apiKey:i,fqdn:c})),Re({server:t,apiKey:i,fqdn:c,slug:e}),Pe({server:t,apiKey:i,fqdn:c,slug:e}),nt({server:t,apiKey:i,fqdn:c,userId:d})),await t.connect(S)}es().catch(console.error);
355
355
  //# sourceMappingURL=stdio.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tmdc-solutions/mcp-beta",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "for dataOS related tasks in local",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -29,12 +29,13 @@
29
29
  "packageManager": "pnpm@10.12.4",
30
30
  "dependencies": {
31
31
  "@faker-js/faker": "^9.8.0",
32
- "@modelcontextprotocol/sdk": "^1.12.0",
32
+ "@modelcontextprotocol/sdk": "^1.25.2",
33
33
  "dotenv": "^16.5.0",
34
34
  "express": "^5.1.0",
35
35
  "keyv": "^5.3.4",
36
36
  "pug": "^3.0.3",
37
37
  "trino-client": "^0.2.9",
38
+ "undici": "^6.21.0",
38
39
  "yaml": "^2.8.0",
39
40
  "zod": "^3.25.67",
40
41
  "zod-to-json-schema": "^3.24.5"
@@ -49,5 +50,14 @@
49
50
  "tailwindcss": "^4.1.8",
50
51
  "tsup": "^8.5.0",
51
52
  "typescript": "^5.8.3"
53
+ },
54
+ "pnpm": {
55
+ "overrides": {
56
+ "glob": ">=10.5.0",
57
+ "qs": ">=6.14.1",
58
+ "tar": ">=7.5.3",
59
+ "body-parser": ">=2.2.1",
60
+ "brace-expansion": ">=2.0.2"
61
+ }
52
62
  }
53
63
  }