@outlit/cli 1.6.1 → 1.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +423 -80
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -104,7 +104,7 @@ var package_default;
104
104
  var init_package = __esm(() => {
105
105
  package_default = {
106
106
  name: "@outlit/cli",
107
- version: "1.6.1",
107
+ version: "1.6.3",
108
108
  description: "CLI for Outlit customer intelligence platform",
109
109
  license: "Apache-2.0",
110
110
  repository: {
@@ -135,7 +135,7 @@ var init_package = __esm(() => {
135
135
  },
136
136
  dependencies: {
137
137
  "@clack/prompts": "^1.0.1",
138
- "@outlit/tools": "^0.1.0",
138
+ "@outlit/tools": "^0.1.2",
139
139
  citty: "^0.2.1"
140
140
  },
141
141
  devDependencies: {
@@ -1493,6 +1493,12 @@ var init_signup = __esm(() => {
1493
1493
  function isCustomerToolName(value) {
1494
1494
  return customerToolNameSet.has(value);
1495
1495
  }
1496
+ function normalizeCustomerSourceType(value) {
1497
+ if (customerSourceTypeSet.has(value)) {
1498
+ return value;
1499
+ }
1500
+ return customerSourceTypeAliasMap.get(value) ?? null;
1501
+ }
1496
1502
  function resolveCustomerContextSearchInput(value) {
1497
1503
  if (!value.query) {
1498
1504
  return {
@@ -1539,6 +1545,14 @@ function resolveCustomerContextSearchInput(value) {
1539
1545
  message: "--after must be before or equal to --before"
1540
1546
  };
1541
1547
  }
1548
+ const invalidSourceTypes = value.sourceTypes?.filter((sourceType) => !normalizeCustomerSourceType(sourceType)) ?? [];
1549
+ if (invalidSourceTypes.length > 0) {
1550
+ return {
1551
+ ok: false,
1552
+ message: `Unknown source types: ${invalidSourceTypes.join(", ")}. Allowed: ${customerSourceTypeInputs.join(", ")}`
1553
+ };
1554
+ }
1555
+ const normalizedSourceTypes = value.sourceTypes ? Array.from(new Set(value.sourceTypes.map((sourceType) => normalizeCustomerSourceType(sourceType)))).filter((sourceType) => sourceType !== null) : undefined;
1542
1556
  return {
1543
1557
  ok: true,
1544
1558
  request: {
@@ -1547,7 +1561,7 @@ function resolveCustomerContextSearchInput(value) {
1547
1561
  topK: value.topK,
1548
1562
  after: value.after,
1549
1563
  before: value.before,
1550
- sourceTypes: value.sourceTypes
1564
+ sourceTypes: normalizedSourceTypes
1551
1565
  }
1552
1566
  };
1553
1567
  }
@@ -1587,7 +1601,7 @@ function createOutlitClient(options) {
1587
1601
  }
1588
1602
  };
1589
1603
  }
1590
- var customerToolNames, customerToolContracts, customerBillingStatuses, customerFactStatuses, customerFactTypes, unsupportedCustomerFactTypes, customerFactCategories, customerIncludeSections, customerSourceTypes, customerTimeframes, timelineChannels, timelineTimeframes, userJourneyStages, schemaTables, customerToolNameSet, iso8601UtcDateTimeRegex, DEFAULT_OUTLIT_API_URL = "https://app.outlit.ai", defaultAgentToolNames, sqlToolNames, analyticalAgentToolNames;
1604
+ var customerToolNames, customerSourceTypes, customerSourceTypeAliases, customerSourceTypeInputs, customerToolContracts, customerBillingStatuses, customerFactStatuses, customerFactTypes, unsupportedCustomerFactTypes, customerFactCategories, customerIncludeSections, customerTimeframes, notificationSeverityValues, timelineChannels, timelineTimeframes, userJourneyStages, customerToolNameSet, customerSourceTypeSet, customerSourceTypeAliasMap, iso8601UtcDateTimeRegex, DEFAULT_OUTLIT_API_URL = "https://app.outlit.ai", actionToolNames, defaultAgentToolNames, sqlToolNames, analyticalAgentToolNames;
1591
1605
  var init_dist4 = __esm(() => {
1592
1606
  customerToolNames = [
1593
1607
  "outlit_list_customers",
@@ -1599,7 +1613,25 @@ var init_dist4 = __esm(() => {
1599
1613
  "outlit_get_source",
1600
1614
  "outlit_search_customer_context",
1601
1615
  "outlit_query",
1602
- "outlit_schema"
1616
+ "outlit_schema",
1617
+ "outlit_send_notification"
1618
+ ];
1619
+ customerSourceTypes = [
1620
+ "EMAIL",
1621
+ "CALL",
1622
+ "CALENDAR_EVENT",
1623
+ "SUPPORT_TICKET",
1624
+ "OPPORTUNITY"
1625
+ ];
1626
+ customerSourceTypeAliases = ["CRM", "CRM_OPPORTUNITY"];
1627
+ customerSourceTypeInputs = [
1628
+ "EMAIL",
1629
+ "CALL",
1630
+ "CALENDAR_EVENT",
1631
+ "SUPPORT_TICKET",
1632
+ "OPPORTUNITY",
1633
+ "CRM",
1634
+ "CRM_OPPORTUNITY"
1603
1635
  ];
1604
1636
  customerToolContracts = {
1605
1637
  outlit_list_customers: {
@@ -1811,11 +1843,21 @@ var init_dist4 = __esm(() => {
1811
1843
  description: "Customer ID or domain"
1812
1844
  },
1813
1845
  channels: {
1814
- description: "Filter by event channel (e.g., EMAIL, SLACK, CALL)",
1846
+ description: "Filter by event channel (e.g., EMAIL, SLACK, CALL, CALENDAR)",
1815
1847
  type: "array",
1816
1848
  items: {
1817
1849
  type: "string",
1818
- enum: ["SDK", "EMAIL", "SLACK", "CALL", "CRM", "BILLING", "SUPPORT", "INTERNAL"]
1850
+ enum: [
1851
+ "SDK",
1852
+ "EMAIL",
1853
+ "SLACK",
1854
+ "CALL",
1855
+ "CALENDAR",
1856
+ "CRM",
1857
+ "BILLING",
1858
+ "SUPPORT",
1859
+ "INTERNAL"
1860
+ ]
1819
1861
  }
1820
1862
  },
1821
1863
  eventTypes: {
@@ -1882,7 +1924,7 @@ var init_dist4 = __esm(() => {
1882
1924
  type: "array",
1883
1925
  items: {
1884
1926
  type: "string",
1885
- enum: ["EMAIL", "CALL", "CALENDAR_EVENT", "SUPPORT_TICKET"]
1927
+ enum: customerSourceTypeInputs
1886
1928
  }
1887
1929
  },
1888
1930
  factTypes: {
@@ -1983,7 +2025,7 @@ var init_dist4 = __esm(() => {
1983
2025
  properties: {
1984
2026
  sourceType: {
1985
2027
  type: "string",
1986
- enum: ["EMAIL", "CALL", "CALENDAR_EVENT", "SUPPORT_TICKET"]
2028
+ enum: customerSourceTypeInputs
1987
2029
  },
1988
2030
  sourceId: {
1989
2031
  type: "string",
@@ -2044,7 +2086,7 @@ var init_dist4 = __esm(() => {
2044
2086
  type: "array",
2045
2087
  items: {
2046
2088
  type: "string",
2047
- enum: ["EMAIL", "CALL", "CALENDAR_EVENT", "SUPPORT_TICKET"]
2089
+ enum: customerSourceTypeInputs
2048
2090
  }
2049
2091
  }
2050
2092
  },
@@ -2054,21 +2096,22 @@ var init_dist4 = __esm(() => {
2054
2096
  },
2055
2097
  outlit_query: {
2056
2098
  toolName: "outlit_query",
2057
- description: `Execute raw SQL queries against your analytics data.
2099
+ description: `Execute read-only SQL queries against your analytics views.
2058
2100
 
2059
- Available tables:
2060
- - events: Customer activity events (event_type, event_channel, customer_id, occurred_at, properties, ...)
2061
- - customer_dimensions: Customer attributes (customer_id, domain, name, billing_status, plan, mrr_cents, ...)
2062
- - user_dimensions: User attributes (user_id, email, name, customer_id, ...)
2063
- - mrr_snapshots: Revenue snapshots over time (customer_id, snapshot_date, mrr_cents, ...)
2101
+ Available views:
2102
+ - activity: Customer activity events (event_name, event_type, event_channel, customer_id, occurred_at, properties, ...)
2103
+ - customers: Customer attributes (customer_id, domain, name, billing_status, plan, mrr_cents, traits, ...)
2104
+ - users: User attributes (user_id, email, name, customer_id, traits, ...)
2105
+ - revenue: Revenue snapshots over time (customer_id, snapshot_date, mrr_cents, ...)
2064
2106
 
2065
2107
  All queries are automatically filtered to your organization's data.
2066
2108
  Only SELECT queries are allowed.
2109
+ Properties and traits are JSON strings; inspect schemas and examples before filtering nested values.
2067
2110
 
2068
2111
  Example queries:
2069
- - SELECT event_type, count(*) FROM events GROUP BY 1 ORDER BY 2 DESC LIMIT 10
2070
- - SELECT billing_status, sum(mrr_cents)/100 as mrr FROM customer_dimensions GROUP BY 1
2071
- - SELECT * FROM events WHERE customer_id = 'cust_123' ORDER BY occurred_at DESC LIMIT 50`,
2112
+ - SELECT event_name, count(*) FROM activity GROUP BY 1 ORDER BY 2 DESC LIMIT 10
2113
+ - SELECT billing_status, sum(mrr_cents)/100 as mrr FROM customers GROUP BY 1
2114
+ - SELECT * FROM activity WHERE customer_id = 'cust_123' ORDER BY occurred_at DESC LIMIT 50`,
2072
2115
  inputSchema: {
2073
2116
  $schema: "https://json-schema.org/draft/2020-12/schema",
2074
2117
  type: "object",
@@ -2080,7 +2123,8 @@ Example queries:
2080
2123
  limit: {
2081
2124
  description: "Max rows to return (default 1000, max 10000)",
2082
2125
  default: 1000,
2083
- type: "number",
2126
+ type: "integer",
2127
+ minimum: 1,
2084
2128
  maximum: 1e4
2085
2129
  }
2086
2130
  },
@@ -2090,22 +2134,129 @@ Example queries:
2090
2134
  },
2091
2135
  outlit_schema: {
2092
2136
  toolName: "outlit_schema",
2093
- description: `Get table schemas for available analytics tables.
2137
+ description: `Get schemas for available analytics views.
2094
2138
 
2095
2139
  Use this to discover column names, types, and descriptions before writing SQL queries.
2096
- Returns column definitions and example queries for each table.`,
2140
+ Returns column definitions and example queries for each view.`,
2097
2141
  inputSchema: {
2098
2142
  $schema: "https://json-schema.org/draft/2020-12/schema",
2099
2143
  type: "object",
2100
2144
  properties: {
2101
2145
  table: {
2102
- description: "Specific table to describe, or omit for all tables",
2146
+ description: "Specific analytics view to describe. Omit to list all views.",
2103
2147
  type: "string",
2104
- enum: ["events", "customer_dimensions", "user_dimensions", "mrr_snapshots"]
2148
+ enum: ["activity", "customers", "users", "revenue"]
2105
2149
  }
2106
2150
  },
2107
2151
  additionalProperties: false
2108
2152
  }
2153
+ },
2154
+ outlit_send_notification: {
2155
+ toolName: "outlit_send_notification",
2156
+ description: "Send or post a Slack notification. Use only when the user explicitly asks you to send, post, or notify. The payload is rendered as a Slack code block.",
2157
+ inputSchema: {
2158
+ $schema: "https://json-schema.org/draft/2020-12/schema",
2159
+ type: "object",
2160
+ properties: {
2161
+ title: {
2162
+ type: "string",
2163
+ minLength: 1,
2164
+ maxLength: 160,
2165
+ description: "Notification title"
2166
+ },
2167
+ payload: {
2168
+ description: "JSON-compatible payload rendered in Slack as a code block. Serialized size must be 100,000 characters or fewer.",
2169
+ anyOf: [
2170
+ {
2171
+ type: "string"
2172
+ },
2173
+ {
2174
+ type: "number"
2175
+ },
2176
+ {
2177
+ type: "boolean"
2178
+ },
2179
+ {
2180
+ type: "null"
2181
+ },
2182
+ {
2183
+ type: "array",
2184
+ items: {
2185
+ $ref: "#/$defs/__schema0"
2186
+ }
2187
+ },
2188
+ {
2189
+ type: "object",
2190
+ propertyNames: {
2191
+ type: "string"
2192
+ },
2193
+ additionalProperties: {
2194
+ $ref: "#/$defs/__schema0"
2195
+ }
2196
+ }
2197
+ ],
2198
+ $ref: "#/$defs/__schema0"
2199
+ },
2200
+ message: {
2201
+ description: "Optional Slack message",
2202
+ type: "string",
2203
+ minLength: 1,
2204
+ maxLength: 1200
2205
+ },
2206
+ severity: {
2207
+ description: "Optional notification severity",
2208
+ type: "string",
2209
+ enum: ["low", "medium", "high"]
2210
+ },
2211
+ source: {
2212
+ description: "Optional source label",
2213
+ type: "string",
2214
+ minLength: 1,
2215
+ maxLength: 120
2216
+ },
2217
+ subject: {
2218
+ description: "Optional subject line",
2219
+ type: "string",
2220
+ minLength: 1,
2221
+ maxLength: 240
2222
+ }
2223
+ },
2224
+ required: ["title", "payload"],
2225
+ additionalProperties: false,
2226
+ $defs: {
2227
+ __schema0: {
2228
+ anyOf: [
2229
+ {
2230
+ type: "string"
2231
+ },
2232
+ {
2233
+ type: "number"
2234
+ },
2235
+ {
2236
+ type: "boolean"
2237
+ },
2238
+ {
2239
+ type: "null"
2240
+ },
2241
+ {
2242
+ type: "array",
2243
+ items: {
2244
+ $ref: "#/$defs/__schema0"
2245
+ }
2246
+ },
2247
+ {
2248
+ type: "object",
2249
+ propertyNames: {
2250
+ type: "string"
2251
+ },
2252
+ additionalProperties: {
2253
+ $ref: "#/$defs/__schema0"
2254
+ }
2255
+ }
2256
+ ]
2257
+ }
2258
+ }
2259
+ }
2109
2260
  }
2110
2261
  };
2111
2262
  customerBillingStatuses = [
@@ -2160,13 +2311,14 @@ Returns column definitions and example queries for each table.`,
2160
2311
  "recentTimeline",
2161
2312
  "behaviorMetrics"
2162
2313
  ];
2163
- customerSourceTypes = ["EMAIL", "CALL", "CALENDAR_EVENT", "SUPPORT_TICKET"];
2164
2314
  customerTimeframes = ["7d", "14d", "30d", "90d"];
2315
+ notificationSeverityValues = ["low", "medium", "high"];
2165
2316
  timelineChannels = [
2166
2317
  "SDK",
2167
2318
  "EMAIL",
2168
2319
  "SLACK",
2169
2320
  "CALL",
2321
+ "CALENDAR",
2170
2322
  "CRM",
2171
2323
  "BILLING",
2172
2324
  "SUPPORT",
@@ -2180,14 +2332,16 @@ Returns column definitions and example queries for each table.`,
2180
2332
  "ENGAGED",
2181
2333
  "INACTIVE"
2182
2334
  ];
2183
- schemaTables = [
2184
- "events",
2185
- "customer_dimensions",
2186
- "user_dimensions",
2187
- "mrr_snapshots"
2188
- ];
2189
2335
  customerToolNameSet = new Set(customerToolNames);
2336
+ customerSourceTypeSet = new Set(customerSourceTypes);
2337
+ customerSourceTypeAliasMap = /* @__PURE__ */ new Map([
2338
+ ["CRM", "OPPORTUNITY"],
2339
+ ["CRM_OPPORTUNITY", "OPPORTUNITY"]
2340
+ ]);
2190
2341
  iso8601UtcDateTimeRegex = /^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$/;
2342
+ actionToolNames = [
2343
+ "outlit_send_notification"
2344
+ ];
2191
2345
  defaultAgentToolNames = [
2192
2346
  "outlit_list_customers",
2193
2347
  "outlit_list_users",
@@ -2196,7 +2350,8 @@ Returns column definitions and example queries for each table.`,
2196
2350
  "outlit_list_facts",
2197
2351
  "outlit_get_fact",
2198
2352
  "outlit_get_source",
2199
- "outlit_search_customer_context"
2353
+ "outlit_search_customer_context",
2354
+ ...actionToolNames
2200
2355
  ];
2201
2356
  sqlToolNames = [
2202
2357
  "outlit_schema",
@@ -4371,7 +4526,12 @@ function invalidValues(values, allowed) {
4371
4526
  return [];
4372
4527
  return values.filter((value) => !allowed.includes(value));
4373
4528
  }
4374
- var list_default3;
4529
+ function normalizeSourceTypes(values) {
4530
+ if (!values)
4531
+ return;
4532
+ return Array.from(new Set(values.map((value) => normalizeCustomerSourceType(value)))).filter((sourceType) => sourceType !== null);
4533
+ }
4534
+ var sourceTypeDescription, list_default3;
4375
4535
  var init_list3 = __esm(() => {
4376
4536
  init_dist4();
4377
4537
  init_dist();
@@ -4381,6 +4541,7 @@ var init_list3 = __esm(() => {
4381
4541
  init_api();
4382
4542
  init_config();
4383
4543
  init_output();
4544
+ sourceTypeDescription = `${customerSourceTypes.join(", ")} (aliases: ${customerSourceTypeAliases.join(", ")})`;
4384
4545
  list_default3 = defineCommand2({
4385
4546
  meta: {
4386
4547
  name: "list",
@@ -4393,11 +4554,11 @@ var init_list3 = __esm(() => {
4393
4554
  " outlit facts list acme.com",
4394
4555
  " outlit facts list acme.com --status ACTIVE",
4395
4556
  " outlit facts list acme.com --fact-types CHURN_RISK,EXPANSION",
4396
- " outlit facts list acme.com --source-types CALL,EMAIL --after 2025-01-01T00:00:00Z",
4557
+ " outlit facts list acme.com --source-types CALL,OPPORTUNITY --after 2025-01-01T00:00:00Z",
4397
4558
  " outlit facts list acme.com --limit 50 --json",
4398
4559
  "",
4399
4560
  `Statuses: ${customerFactStatuses.join(", ")}`,
4400
- `Source types: ${customerSourceTypes.join(", ")}`,
4561
+ `Source types: ${sourceTypeDescription}`,
4401
4562
  `Fact categories: ${customerFactCategories.join(", ")}`,
4402
4563
  "",
4403
4564
  AGENT_JSON_HINT
@@ -4419,7 +4580,7 @@ var init_list3 = __esm(() => {
4419
4580
  },
4420
4581
  "source-types": {
4421
4582
  type: "string",
4422
- description: `Comma-separated generic source type filter (${customerSourceTypes.join(", ")})`
4583
+ description: `Comma-separated generic source type filter (${sourceTypeDescription})`
4423
4584
  },
4424
4585
  "fact-types": {
4425
4586
  type: "string",
@@ -4451,13 +4612,14 @@ var init_list3 = __esm(() => {
4451
4612
  code: "invalid_input"
4452
4613
  }, json);
4453
4614
  }
4454
- const invalidSourceTypes = invalidValues(sourceTypes, customerSourceTypes);
4615
+ const invalidSourceTypes = sourceTypes?.filter((value) => !normalizeCustomerSourceType(value)) ?? [];
4455
4616
  if (invalidSourceTypes.length > 0) {
4456
4617
  return outputError({
4457
- message: `Unknown source types: ${invalidSourceTypes.join(", ")}. Allowed: ${customerSourceTypes.join(", ")}`,
4618
+ message: `Unknown source types: ${invalidSourceTypes.join(", ")}. Allowed: ${customerSourceTypeInputs.join(", ")}`,
4458
4619
  code: "invalid_input"
4459
4620
  }, json);
4460
4621
  }
4622
+ const normalizedSourceTypes = normalizeSourceTypes(sourceTypes);
4461
4623
  const invalidFactTypes = invalidValues(factTypes, customerFactTypes);
4462
4624
  if (invalidFactTypes.length > 0) {
4463
4625
  const anomalyFactTypes = invalidFactTypes.filter((value) => unsupportedCustomerFactTypes.includes(value));
@@ -4507,8 +4669,8 @@ var init_list3 = __esm(() => {
4507
4669
  };
4508
4670
  if (statuses)
4509
4671
  params.status = statuses;
4510
- if (sourceTypes)
4511
- params.sourceTypes = sourceTypes;
4672
+ if (normalizedSourceTypes)
4673
+ params.sourceTypes = normalizedSourceTypes;
4512
4674
  if (factTypes)
4513
4675
  params.factTypes = factTypes;
4514
4676
  if (factCategories)
@@ -4620,7 +4782,7 @@ var exports_get3 = {};
4620
4782
  __export(exports_get3, {
4621
4783
  default: () => get_default3
4622
4784
  });
4623
- var get_default3;
4785
+ var sourceTypeDescription2, get_default3;
4624
4786
  var init_get3 = __esm(() => {
4625
4787
  init_dist4();
4626
4788
  init_dist();
@@ -4628,6 +4790,7 @@ var init_get3 = __esm(() => {
4628
4790
  init_output2();
4629
4791
  init_api();
4630
4792
  init_output();
4793
+ sourceTypeDescription2 = `${customerSourceTypes.join(", ")} (aliases: ${customerSourceTypeAliases.join(", ")})`;
4631
4794
  get_default3 = defineCommand2({
4632
4795
  meta: {
4633
4796
  name: "get",
@@ -4636,9 +4799,10 @@ var init_get3 = __esm(() => {
4636
4799
  "",
4637
4800
  "Examples:",
4638
4801
  " outlit sources get --source-type CALL --source-id call_123",
4802
+ " outlit sources get --source-type OPPORTUNITY --source-id opp_123",
4639
4803
  " outlit sources get --source-type SUPPORT_TICKET --source-id ticket_456 --json",
4640
4804
  "",
4641
- `Source types: ${customerSourceTypes.join(", ")}`,
4805
+ `Source types: ${sourceTypeDescription2}`,
4642
4806
  "",
4643
4807
  AGENT_JSON_HINT
4644
4808
  ].join(`
@@ -4649,7 +4813,7 @@ var init_get3 = __esm(() => {
4649
4813
  ...outputArgs,
4650
4814
  "source-type": {
4651
4815
  type: "string",
4652
- description: "Canonical source type",
4816
+ description: `Source type (${sourceTypeDescription2})`,
4653
4817
  required: true
4654
4818
  },
4655
4819
  "source-id": {
@@ -4660,15 +4824,16 @@ var init_get3 = __esm(() => {
4660
4824
  },
4661
4825
  async run({ args }) {
4662
4826
  const json = !!args.json;
4663
- if (!customerSourceTypes.includes(args["source-type"])) {
4827
+ const sourceType = normalizeCustomerSourceType(args["source-type"]);
4828
+ if (!sourceType) {
4664
4829
  return outputError({
4665
- message: `--source-type must be one of ${customerSourceTypes.join(", ")}`,
4830
+ message: `--source-type must be one of ${customerSourceTypeInputs.join(", ")}`,
4666
4831
  code: "invalid_input"
4667
4832
  }, json);
4668
4833
  }
4669
4834
  const client = await getClientOrExit(args["api-key"], json);
4670
4835
  return runTool(client, customerToolContracts.outlit_get_source.toolName, {
4671
- sourceType: args["source-type"],
4836
+ sourceType,
4672
4837
  sourceId: args["source-id"]
4673
4838
  }, json);
4674
4839
  }
@@ -4708,7 +4873,7 @@ var exports_search = {};
4708
4873
  __export(exports_search, {
4709
4874
  default: () => search_default
4710
4875
  });
4711
- var search_default;
4876
+ var sourceTypeDescription3, search_default;
4712
4877
  var init_search = __esm(() => {
4713
4878
  init_dist4();
4714
4879
  init_dist();
@@ -4717,6 +4882,7 @@ var init_search = __esm(() => {
4717
4882
  init_api();
4718
4883
  init_config();
4719
4884
  init_output();
4885
+ sourceTypeDescription3 = `${customerSourceTypes.join(", ")} (aliases: ${customerSourceTypeAliases.join(", ")})`;
4720
4886
  search_default = defineCommand2({
4721
4887
  meta: {
4722
4888
  name: "search",
@@ -4731,7 +4897,7 @@ var init_search = __esm(() => {
4731
4897
  " outlit search 'churn risk signals' --customer acme.com",
4732
4898
  " outlit search 'expansion opportunities' --top-k 50 --json",
4733
4899
  " outlit search 'support escalations' --after 2025-01-01T00:00:00Z --before 2025-03-31T23:59:59Z",
4734
- " outlit search 'onboarding issues' --source-types CALL,EMAIL",
4900
+ " outlit search 'renewal opportunities' --source-types CALL,OPPORTUNITY",
4735
4901
  "",
4736
4902
  AGENT_JSON_HINT
4737
4903
  ].join(`
@@ -4763,7 +4929,7 @@ var init_search = __esm(() => {
4763
4929
  },
4764
4930
  "source-types": {
4765
4931
  type: "string",
4766
- description: `Comma-separated generic source type filter (${customerSourceTypes.join(", ")})`
4932
+ description: `Comma-separated generic source type filter (${sourceTypeDescription3})`
4767
4933
  }
4768
4934
  },
4769
4935
  async run({ args }) {
@@ -4773,13 +4939,6 @@ var init_search = __esm(() => {
4773
4939
  return outputError({ message: "--top-k must be an integer between 1 and 50", code: "invalid_input" }, json);
4774
4940
  }
4775
4941
  const sourceTypes = args["source-types"] ? splitCsv(args["source-types"]).map((item) => item.trim()).filter(Boolean) : undefined;
4776
- const invalidSourceTypes = sourceTypes?.filter((value) => !customerSourceTypes.includes(value));
4777
- if (invalidSourceTypes && invalidSourceTypes.length > 0) {
4778
- return outputError({
4779
- message: `Unknown source types: ${invalidSourceTypes.join(", ")}. Allowed: ${customerSourceTypes.join(", ")}`,
4780
- code: "invalid_input"
4781
- }, json);
4782
- }
4783
4942
  const resolved = resolveCustomerContextSearchInput({
4784
4943
  query: args.query,
4785
4944
  customer: args.customer,
@@ -4806,7 +4965,7 @@ __export(exports_sql, {
4806
4965
  default: () => sql_default
4807
4966
  });
4808
4967
  import { readFileSync as readFileSync4 } from "node:fs";
4809
- var sql_default;
4968
+ var publicSqlViews, sql_default;
4810
4969
  var init_sql = __esm(() => {
4811
4970
  init_dist4();
4812
4971
  init_dist();
@@ -4814,21 +4973,22 @@ var init_sql = __esm(() => {
4814
4973
  init_output2();
4815
4974
  init_api();
4816
4975
  init_output();
4976
+ publicSqlViews = ["activity", "customers", "users", "revenue"];
4817
4977
  sql_default = defineCommand2({
4818
4978
  meta: {
4819
4979
  name: "sql",
4820
4980
  description: [
4821
- "Run a SQL query against Outlit's analytics database.",
4981
+ "Run a SQL query against Outlit analytics views.",
4822
4982
  "",
4823
4983
  "Provide the query as a positional argument or via --query-file.",
4824
4984
  "When both are provided, --query-file takes precedence.",
4825
4985
  "",
4826
- `Available tables: ${schemaTables.join(", ")}`,
4986
+ `Available views: ${publicSqlViews.join(", ")}`,
4827
4987
  "",
4828
4988
  "Examples:",
4829
- " outlit sql 'SELECT * FROM events LIMIT 10'",
4989
+ " outlit sql 'SELECT * FROM activity LIMIT 10'",
4830
4990
  " outlit sql --query-file ./my-query.sql",
4831
- " outlit sql 'SELECT count(*) FROM events' --limit 1 --json",
4991
+ " outlit sql 'SELECT count(*) FROM activity' --limit 1 --json",
4832
4992
  "",
4833
4993
  AGENT_JSON_HINT
4834
4994
  ].join(`
@@ -4871,41 +5031,221 @@ var init_sql = __esm(() => {
4871
5031
  return outputError({ message: "Provide a SQL query or --query-file", code: "missing_input" }, json);
4872
5032
  }
4873
5033
  const limit = Number(args.limit);
4874
- if (!Number.isFinite(limit) || limit <= 0) {
4875
- return outputError({ message: "--limit must be a positive number", code: "invalid_input" }, json);
5034
+ if (!Number.isInteger(limit) || limit < 1 || limit > 1e4) {
5035
+ return outputError({ message: "--limit must be an integer between 1 and 10000", code: "invalid_input" }, json);
4876
5036
  }
4877
5037
  return runTool(client, customerToolContracts.outlit_query.toolName, { sql, limit }, json);
4878
5038
  }
4879
5039
  });
4880
5040
  });
4881
5041
 
5042
+ // src/commands/notify.ts
5043
+ var exports_notify = {};
5044
+ __export(exports_notify, {
5045
+ default: () => notify_default
5046
+ });
5047
+ import { readFileSync as readFileSync5 } from "node:fs";
5048
+ function parsePayload(raw) {
5049
+ try {
5050
+ return JSON.parse(raw);
5051
+ } catch {
5052
+ return raw;
5053
+ }
5054
+ }
5055
+ function validateTrimmedText(value, maxLength) {
5056
+ if (value === undefined) {
5057
+ return;
5058
+ }
5059
+ const trimmed = value.trim();
5060
+ if (trimmed.length === 0 || trimmed.length > maxLength) {
5061
+ return null;
5062
+ }
5063
+ return trimmed;
5064
+ }
5065
+ function normalizeSeverity(severity) {
5066
+ const normalized = severity.trim().toLowerCase();
5067
+ return notificationSeverityValues.includes(normalized) ? normalized : null;
5068
+ }
5069
+ function payloadSizeIsValid(payload) {
5070
+ const serialized = JSON.stringify(payload);
5071
+ return typeof serialized === "string" && serialized.length <= 1e5;
5072
+ }
5073
+ var notify_default;
5074
+ var init_notify = __esm(() => {
5075
+ init_dist4();
5076
+ init_dist();
5077
+ init_auth();
5078
+ init_output2();
5079
+ init_api();
5080
+ init_output();
5081
+ notify_default = defineCommand2({
5082
+ meta: {
5083
+ name: "notify",
5084
+ description: [
5085
+ "Send a Slack notification through Outlit.",
5086
+ "",
5087
+ "Provide the payload as a positional argument or via --payload-file.",
5088
+ "When both are provided, --payload-file takes precedence.",
5089
+ "",
5090
+ "Examples:",
5091
+ ` outlit notify --title 'Risk found' '{"customer":"acme.com"}'`,
5092
+ " outlit notify --title 'Risk found' --payload-file ./payload.json",
5093
+ ` outlit notify --title 'Escalation' --severity HIGH --message 'Check this account' '{"customer":"acme.com"}'`,
5094
+ "",
5095
+ AGENT_JSON_HINT
5096
+ ].join(`
5097
+ `)
5098
+ },
5099
+ args: {
5100
+ ...authArgs,
5101
+ ...outputArgs,
5102
+ title: {
5103
+ type: "string",
5104
+ description: "Notification title",
5105
+ required: false
5106
+ },
5107
+ payload: {
5108
+ type: "positional",
5109
+ description: "Notification payload as JSON or raw string",
5110
+ required: false
5111
+ },
5112
+ "payload-file": {
5113
+ type: "string",
5114
+ description: "Path to a payload file to read (takes precedence over positional payload)"
5115
+ },
5116
+ message: {
5117
+ type: "string",
5118
+ description: "Optional Slack message"
5119
+ },
5120
+ severity: {
5121
+ type: "string",
5122
+ description: `Optional notification severity (${notificationSeverityValues.join(", ")})`
5123
+ },
5124
+ source: {
5125
+ type: "string",
5126
+ description: "Optional source label"
5127
+ },
5128
+ subject: {
5129
+ type: "string",
5130
+ description: "Optional subject line"
5131
+ }
5132
+ },
5133
+ async run({ args }) {
5134
+ const json = !!args.json;
5135
+ const title = args.title?.trim();
5136
+ if (!title) {
5137
+ return outputError({ message: "Provide --title", code: "missing_input" }, json);
5138
+ }
5139
+ if (title.length > 160) {
5140
+ return outputError({
5141
+ message: "--title must be 160 characters or fewer after trimming",
5142
+ code: "invalid_input"
5143
+ }, json);
5144
+ }
5145
+ const message = validateTrimmedText(args.message, 1200);
5146
+ if (message === null) {
5147
+ return outputError({
5148
+ message: "--message must be between 1 and 1200 characters after trimming",
5149
+ code: "invalid_input"
5150
+ }, json);
5151
+ }
5152
+ const source = validateTrimmedText(args.source, 120);
5153
+ if (source === null) {
5154
+ return outputError({
5155
+ message: "--source must be between 1 and 120 characters after trimming",
5156
+ code: "invalid_input"
5157
+ }, json);
5158
+ }
5159
+ const subject = validateTrimmedText(args.subject, 240);
5160
+ if (subject === null) {
5161
+ return outputError({
5162
+ message: "--subject must be between 1 and 240 characters after trimming",
5163
+ code: "invalid_input"
5164
+ }, json);
5165
+ }
5166
+ let severity;
5167
+ if (args.severity) {
5168
+ const normalized = normalizeSeverity(args.severity);
5169
+ if (!normalized) {
5170
+ return outputError({
5171
+ message: `--severity must be one of: ${notificationSeverityValues.join(", ")}`,
5172
+ code: "invalid_input"
5173
+ }, json);
5174
+ }
5175
+ severity = normalized;
5176
+ }
5177
+ let payloadInput;
5178
+ if (args["payload-file"]) {
5179
+ try {
5180
+ payloadInput = readFileSync5(args["payload-file"], "utf-8");
5181
+ } catch (err) {
5182
+ return outputError({
5183
+ message: `Cannot read file: ${errorMessage(err, "unknown error")}`,
5184
+ code: "file_error"
5185
+ }, json);
5186
+ }
5187
+ } else if (typeof args.payload === "string" && args.payload.trim().length > 0) {
5188
+ payloadInput = args.payload;
5189
+ } else {
5190
+ return outputError({ message: "Provide a payload or --payload-file", code: "missing_input" }, json);
5191
+ }
5192
+ const payload = parsePayload(payloadInput);
5193
+ if (!payloadSizeIsValid(payload)) {
5194
+ return outputError({
5195
+ message: "Payload must serialize to 100000 characters or fewer",
5196
+ code: "invalid_input"
5197
+ }, json);
5198
+ }
5199
+ const client = await getClientOrExit(args["api-key"], json);
5200
+ const params = {
5201
+ title,
5202
+ payload
5203
+ };
5204
+ if (message !== undefined) {
5205
+ params.message = message;
5206
+ }
5207
+ if (severity) {
5208
+ params.severity = severity;
5209
+ }
5210
+ if (source !== undefined) {
5211
+ params.source = source;
5212
+ }
5213
+ if (subject !== undefined) {
5214
+ params.subject = subject;
5215
+ }
5216
+ return runTool(client, customerToolContracts.outlit_send_notification.toolName, params, json);
5217
+ }
5218
+ });
5219
+ });
5220
+
4882
5221
  // src/commands/schema.ts
4883
5222
  var exports_schema = {};
4884
5223
  __export(exports_schema, {
4885
5224
  default: () => schema_default
4886
5225
  });
4887
- var schema_default;
5226
+ var publicSqlViews2, schema_default;
4888
5227
  var init_schema = __esm(() => {
4889
5228
  init_dist4();
4890
5229
  init_dist();
4891
5230
  init_auth();
4892
5231
  init_output2();
4893
5232
  init_api();
5233
+ publicSqlViews2 = ["activity", "customers", "users", "revenue"];
4894
5234
  schema_default = defineCommand2({
4895
5235
  meta: {
4896
5236
  name: "schema",
4897
5237
  description: [
4898
- "Describe the analytics database schema.",
5238
+ "Describe the available analytics views.",
4899
5239
  "",
4900
- "Without a table name, returns the full schema for all tables.",
4901
- "With a table name, returns detailed column info for that table.",
5240
+ "Without a view name, returns the full schema for all views.",
5241
+ "With a view name, returns detailed column info for that view.",
4902
5242
  "",
4903
- `Available tables: ${schemaTables.join(", ")}`,
5243
+ `Available views: ${publicSqlViews2.join(", ")}`,
4904
5244
  "",
4905
5245
  "Examples:",
4906
5246
  " outlit schema",
4907
- " outlit schema events",
4908
- " outlit schema customer_dimensions --json",
5247
+ " outlit schema activity",
5248
+ " outlit schema customers --json",
4909
5249
  "",
4910
5250
  AGENT_JSON_HINT
4911
5251
  ].join(`
@@ -4914,9 +5254,9 @@ var init_schema = __esm(() => {
4914
5254
  args: {
4915
5255
  ...authArgs,
4916
5256
  ...outputArgs,
4917
- table: {
5257
+ view: {
4918
5258
  type: "positional",
4919
- description: `Table to describe (${schemaTables.join(", ")}). Optional.`,
5259
+ description: `View to describe (${publicSqlViews2.join(", ")}). Optional.`,
4920
5260
  required: false
4921
5261
  }
4922
5262
  },
@@ -4924,8 +5264,9 @@ var init_schema = __esm(() => {
4924
5264
  const json = !!args.json;
4925
5265
  const client = await getClientOrExit(args["api-key"], json);
4926
5266
  const params = {};
4927
- if (args.table)
4928
- params.table = args.table;
5267
+ const view = args.view ?? args.table;
5268
+ if (view)
5269
+ params.table = view;
4929
5270
  return runTool(client, customerToolContracts.outlit_schema.toolName, params, json);
4930
5271
  }
4931
5272
  });
@@ -5822,7 +6163,7 @@ var init_completions = __esm(() => {
5822
6163
  desc: "Get one exact source record",
5823
6164
  flags: [
5824
6165
  ...COMMON,
5825
- { name: "--source-type", desc: "Canonical source type" },
6166
+ { name: "--source-type", desc: "Source type" },
5826
6167
  { name: "--source-id", desc: "Exact source ID" }
5827
6168
  ]
5828
6169
  }
@@ -5849,7 +6190,7 @@ var init_completions = __esm(() => {
5849
6190
  { name: "--limit", desc: "Max rows to return" }
5850
6191
  ]
5851
6192
  },
5852
- { name: "schema", desc: "Discover table schemas", flags: [...COMMON] },
6193
+ { name: "schema", desc: "Discover analytics view schemas", flags: [...COMMON] },
5853
6194
  {
5854
6195
  name: "integrations",
5855
6196
  desc: "Manage platform integrations",
@@ -6673,10 +7014,11 @@ Usage examples:
6673
7014
  outlit users list --journey-stage CHAMPION
6674
7015
  outlit facts list acme.com --fact-types CHURN_RISK,EXPANSION
6675
7016
  outlit facts get --fact-id fact_123 --include evidence
6676
- outlit sources get --source-type CALL --source-id call_123
6677
- outlit search 'pricing objections last quarter' --source-types CALL,EMAIL
6678
- outlit sql 'SELECT * FROM events LIMIT 10'
6679
- outlit schema events
7017
+ outlit sources get --source-type OPPORTUNITY --source-id opp_123
7018
+ outlit search 'pricing objections last quarter' --source-types CALL,OPPORTUNITY
7019
+ outlit sql 'SELECT * FROM activity LIMIT 10'
7020
+ outlit notify --title 'Risk found' '{"customer":"acme.com"}'
7021
+ outlit schema activity
6680
7022
  outlit doctor --json
6681
7023
 
6682
7024
  For AI agents: commands auto-output JSON when stdout is piped. No --json flag needed.`
@@ -6691,6 +7033,7 @@ For AI agents: commands auto-output JSON when stdout is piped. No --json flag ne
6691
7033
  sources: () => Promise.resolve().then(() => (init_sources(), exports_sources)).then((m) => m.default),
6692
7034
  search: () => Promise.resolve().then(() => (init_search(), exports_search)).then((m) => m.default),
6693
7035
  sql: () => Promise.resolve().then(() => (init_sql(), exports_sql)).then((m) => m.default),
7036
+ notify: () => Promise.resolve().then(() => (init_notify(), exports_notify)).then((m) => m.default),
6694
7037
  schema: () => Promise.resolve().then(() => (init_schema(), exports_schema)).then((m) => m.default),
6695
7038
  integrations: () => Promise.resolve().then(() => (init_integrations(), exports_integrations)).then((m) => m.default),
6696
7039
  completions: () => Promise.resolve().then(() => (init_completions(), exports_completions)).then((m) => m.default),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@outlit/cli",
3
- "version": "1.6.1",
3
+ "version": "1.6.3",
4
4
  "description": "CLI for Outlit customer intelligence platform",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@clack/prompts": "^1.0.1",
34
- "@outlit/tools": "^0.1.0",
34
+ "@outlit/tools": "^0.1.2",
35
35
  "citty": "^0.2.1"
36
36
  },
37
37
  "devDependencies": {