@outlit/cli 2.0.0 → 3.0.0

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 +3173 -631
  2. package/package.json +5 -4
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: "2.0.0",
107
+ version: "3.0.0",
108
108
  description: "CLI for querying Outlit customer context and installing agent skills",
109
109
  license: "Apache-2.0",
110
110
  repository: {
@@ -147,12 +147,13 @@ var init_package = __esm(() => {
147
147
  },
148
148
  dependencies: {
149
149
  "@clack/prompts": "^1.0.1",
150
- "@outlit/tools": "^1.0.0",
150
+ "@outlit/tools": "^2.0.0",
151
151
  citty: "^0.2.1"
152
152
  },
153
153
  devDependencies: {
154
- typescript: "^5.9.3",
155
- "@types/bun": "latest"
154
+ "@types/bun": "latest",
155
+ "node-pty": "^1.1.0",
156
+ typescript: "^5.9.3"
156
157
  }
157
158
  };
158
159
  });
@@ -772,7 +773,7 @@ var import_picocolors, import_sisteransi, at = (t) => t === 161 || t === 164 ||
772
773
  ` && (r && p && (i += st(r)), n && (i += it(n))), V += h.length, m = A, A = g.next();
773
774
  }
774
775
  return i;
775
- }, At, _, bt, z, rt = (t) => ("columns" in t) && typeof t.columns == "number" ? t.columns : 80, nt = (t) => ("rows" in t) && typeof t.rows == "number" ? t.rows : 20, Vt, yt, Mt, Wt;
776
+ }, At, _, bt, z, rt = (t) => ("columns" in t) && typeof t.columns == "number" ? t.columns : 80, nt = (t) => ("rows" in t) && typeof t.rows == "number" ? t.rows : 20, Vt, kt, yt, Mt, Wt, $t;
776
777
  var init_dist2 = __esm(() => {
777
778
  import_picocolors = __toESM(require_picocolors(), 1);
778
779
  import_sisteransi = __toESM(require_src(), 1);
@@ -851,6 +852,23 @@ var init_dist2 = __esm(() => {
851
852
  }
852
853
  }
853
854
  };
855
+ kt = class kt extends x {
856
+ get cursor() {
857
+ return this.value ? 0 : 1;
858
+ }
859
+ get _value() {
860
+ return this.cursor === 0;
861
+ }
862
+ constructor(e) {
863
+ super(e, false), this.value = !!e.initialValue, this.on("userInput", () => {
864
+ this.value = this._value;
865
+ }), this.on("confirm", (s) => {
866
+ this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = s, this.state = "submit", this.close();
867
+ }), this.on("cursor", () => {
868
+ this.value = !this.value;
869
+ });
870
+ }
871
+ };
854
872
  yt = class yt extends x {
855
873
  options;
856
874
  cursor = 0;
@@ -951,6 +969,27 @@ var init_dist2 = __esm(() => {
951
969
  });
952
970
  }
953
971
  };
972
+ $t = class $t extends x {
973
+ get userInputWithCursor() {
974
+ if (this.state === "submit")
975
+ return this.userInput;
976
+ const e = this.userInput;
977
+ if (this.cursor >= e.length)
978
+ return `${this.userInput}█`;
979
+ const s = e.slice(0, this.cursor), [i, ...r] = e.slice(this.cursor);
980
+ return `${s}${import_picocolors.default.inverse(i)}${r.join("")}`;
981
+ }
982
+ get cursor() {
983
+ return this._cursor;
984
+ }
985
+ constructor(e) {
986
+ super({ ...e, initialUserInput: e.initialUserInput ?? e.initialValue }), this.on("userInput", (s) => {
987
+ this._setValue(s);
988
+ }), this.on("finalize", () => {
989
+ this.value || (this.value = e.defaultValue), this.value === undefined && (this.value = "");
990
+ });
991
+ }
992
+ };
954
993
  });
955
994
 
956
995
  // ../../node_modules/.bun/@clack+prompts@1.0.1/node_modules/@clack/prompts/dist/index.mjs
@@ -1166,6 +1205,32 @@ var import_picocolors2, import_sisteransi2, et2, ct2 = () => process.env.CI ===
1166
1205
  for (const w of A)
1167
1206
  B2.push(w);
1168
1207
  return h && B2.push(g), B2;
1208
+ }, Re = (t) => {
1209
+ const r = t.active ?? "Yes", s = t.inactive ?? "No";
1210
+ return new kt({ active: r, inactive: s, signal: t.signal, input: t.input, output: t.output, initialValue: t.initialValue ?? true, render() {
1211
+ const i = t.withGuide ?? _.withGuide, a = `${i ? `${import_picocolors2.default.gray(d)}
1212
+ ` : ""}${W2(this.state)} ${t.message}
1213
+ `, o = this.value ? r : s;
1214
+ switch (this.state) {
1215
+ case "submit": {
1216
+ const u = i ? `${import_picocolors2.default.gray(d)} ` : "";
1217
+ return `${a}${u}${import_picocolors2.default.dim(o)}`;
1218
+ }
1219
+ case "cancel": {
1220
+ const u = i ? `${import_picocolors2.default.gray(d)} ` : "";
1221
+ return `${a}${u}${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(o))}${i ? `
1222
+ ${import_picocolors2.default.gray(d)}` : ""}`;
1223
+ }
1224
+ default: {
1225
+ const u = i ? `${import_picocolors2.default.cyan(d)} ` : "", l = i ? import_picocolors2.default.cyan(x2) : "";
1226
+ return `${a}${u}${this.value ? `${import_picocolors2.default.green(Q2)} ${r}` : `${import_picocolors2.default.dim(H2)} ${import_picocolors2.default.dim(r)}`}${t.vertical ? i ? `
1227
+ ${import_picocolors2.default.cyan(d)} ` : `
1228
+ ` : ` ${import_picocolors2.default.dim("/")} `}${this.value ? `${import_picocolors2.default.dim(H2)} ${import_picocolors2.default.dim(s)}` : `${import_picocolors2.default.green(Q2)} ${s}`}
1229
+ ${l}
1230
+ `;
1231
+ }
1232
+ }
1233
+ } }).prompt();
1169
1234
  }, R2, Ne = (t = "", r) => {
1170
1235
  (r?.output ?? process.stdout).write(`${import_picocolors2.default.gray(x2)} ${import_picocolors2.default.red(t)}
1171
1236
 
@@ -1305,7 +1370,35 @@ ${n}
1305
1370
  }
1306
1371
  }
1307
1372
  } }).prompt();
1308
- }, Qt;
1373
+ }, Qt, Ze = (t) => new $t({ validate: t.validate, placeholder: t.placeholder, defaultValue: t.defaultValue, initialValue: t.initialValue, output: t.output, signal: t.signal, input: t.input, render() {
1374
+ const r = t?.withGuide ?? _.withGuide, s = `${`${r ? `${import_picocolors2.default.gray(d)}
1375
+ ` : ""}${W2(this.state)} `}${t.message}
1376
+ `, i = t.placeholder ? import_picocolors2.default.inverse(t.placeholder[0]) + import_picocolors2.default.dim(t.placeholder.slice(1)) : import_picocolors2.default.inverse(import_picocolors2.default.hidden("_")), a = this.userInput ? this.userInputWithCursor : i, o = this.value ?? "";
1377
+ switch (this.state) {
1378
+ case "error": {
1379
+ const u = this.error ? ` ${import_picocolors2.default.yellow(this.error)}` : "", l = r ? `${import_picocolors2.default.yellow(d)} ` : "", n = r ? import_picocolors2.default.yellow(x2) : "";
1380
+ return `${s.trim()}
1381
+ ${l}${a}
1382
+ ${n}${u}
1383
+ `;
1384
+ }
1385
+ case "submit": {
1386
+ const u = o ? ` ${import_picocolors2.default.dim(o)}` : "", l = r ? import_picocolors2.default.gray(d) : "";
1387
+ return `${s}${l}${u}`;
1388
+ }
1389
+ case "cancel": {
1390
+ const u = o ? ` ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(o))}` : "", l = r ? import_picocolors2.default.gray(d) : "";
1391
+ return `${s}${l}${u}${o.trim() ? `
1392
+ ${l}` : ""}`;
1393
+ }
1394
+ default: {
1395
+ const u = r ? `${import_picocolors2.default.cyan(d)} ` : "", l = r ? import_picocolors2.default.cyan(x2) : "";
1396
+ return `${s}${u}${a}
1397
+ ${l}
1398
+ `;
1399
+ }
1400
+ }
1401
+ } }).prompt();
1309
1402
  var init_dist3 = __esm(() => {
1310
1403
  init_dist2();
1311
1404
  init_dist2();
@@ -1511,7 +1604,7 @@ function createOutlitClient(options) {
1511
1604
  return {
1512
1605
  key,
1513
1606
  baseUrl,
1514
- async callTool(toolName, input = {}) {
1607
+ async callTool(toolName, input = {}, callOptions) {
1515
1608
  if (!isPublicToolName(toolName)) {
1516
1609
  throw new Error(`Unknown public tool: ${toolName}`);
1517
1610
  }
@@ -1524,7 +1617,8 @@ function createOutlitClient(options) {
1524
1617
  body: JSON.stringify({
1525
1618
  tool: toolName,
1526
1619
  input
1527
- })
1620
+ }),
1621
+ ...callOptions?.signal ? { signal: callOptions.signal } : {}
1528
1622
  });
1529
1623
  if (!response.ok) {
1530
1624
  const text = await response.text();
@@ -1580,17 +1674,28 @@ function matchesGeneratedJsonSchema(value, schema) {
1580
1674
  case "array": {
1581
1675
  if (!Array.isArray(value))
1582
1676
  return false;
1677
+ if (schema.minItems !== undefined && value.length < schema.minItems)
1678
+ return false;
1679
+ if (schema.maxItems !== undefined && value.length > schema.maxItems)
1680
+ return false;
1583
1681
  const itemSchema = schema.items;
1584
1682
  return !itemSchema || value.every((item) => matchesGeneratedJsonSchema(item, itemSchema));
1585
1683
  }
1586
- case "string":
1587
- return typeof value === "string";
1684
+ case "string": {
1685
+ if (typeof value !== "string")
1686
+ return false;
1687
+ if (schema.minLength !== undefined && value.length < schema.minLength)
1688
+ return false;
1689
+ if (schema.maxLength !== undefined && value.length > schema.maxLength)
1690
+ return false;
1691
+ return schema.pattern === undefined || new RegExp(schema.pattern).test(value);
1692
+ }
1588
1693
  case "boolean":
1589
1694
  return typeof value === "boolean";
1590
1695
  case "number":
1591
- return typeof value === "number" && Number.isFinite(value);
1696
+ return matchesNumberBounds(value, schema, false);
1592
1697
  case "integer":
1593
- return typeof value === "number" && Number.isSafeInteger(value);
1698
+ return matchesNumberBounds(value, schema, true);
1594
1699
  case "null":
1595
1700
  return value === null;
1596
1701
  case undefined:
@@ -1599,13 +1704,28 @@ function matchesGeneratedJsonSchema(value, schema) {
1599
1704
  return false;
1600
1705
  }
1601
1706
  }
1602
- var publicToolNames, publicToolContracts, consumerToolPolicies, toolGatewayTransport, apiKeyValidationTransport, apiKeyValidationSuccessSchema, apiKeyValidationFailureSchema, toolGatewayErrorSchema, customerBillingStatuses, customerFactStatuses, customerFactTypes, unsupportedCustomerFactTypes, customerFactCategories, customerIncludeSections, customerSourceTypes, customerSourceTypeAliasMap, customerSourceTypeAliases, customerSourceTypeInputs, customerTimeframes, timelineChannels, timelineTimeframes, userJourneyStages, workspaceUserListOrderFields, publicToolNameSet, customerSourceTypeSet, iso8601UtcDateTimeRegex, DEFAULT_OUTLIT_API_URL = "https://app.outlit.ai", OutlitToolsApiError, defaultToolNames, analyticalToolNames, cliToolNames, defaultToolNameSet, sqlToolNames;
1707
+ function matchesNumberBounds(value, schema, integer) {
1708
+ if (typeof value !== "number" || !Number.isFinite(value))
1709
+ return false;
1710
+ if (integer && !Number.isSafeInteger(value))
1711
+ return false;
1712
+ if (schema.minimum !== undefined && value < schema.minimum)
1713
+ return false;
1714
+ if (schema.maximum !== undefined && value > schema.maximum)
1715
+ return false;
1716
+ return true;
1717
+ }
1718
+ var publicToolNames, publicToolContracts, consumerToolPolicies, toolGatewayTransport, apiKeyValidationTransport, apiKeyValidationSuccessSchema, apiKeyValidationFailureSchema, toolGatewayErrorSchema, customerBillingStatuses, customerFactStatuses, customerFactTypes, unsupportedCustomerFactTypes, customerFactCategories, customerIncludeSections, customerSourceTypes, customerSourceTypeAliasMap, customerSourceTypeAliases, customerSourceTypeInputs, customerTimeframes, timelineChannels, timelineTimeframes, userJourneyStages, workspaceUserListOrderFields, publicToolNameSet, customerSourceTypeSet, iso8601UtcDateTimeRegex, DEFAULT_OUTLIT_API_URL = "https://app.outlit.ai", OutlitToolsApiError, defaultToolNames, analyticalToolNames, piToolNames, cliToolNames, defaultToolNameSet, sqlToolNames;
1603
1719
  var init_dist4 = __esm(() => {
1604
1720
  publicToolNames = [
1605
1721
  "outlit_list_customers",
1606
1722
  "outlit_list_users",
1607
1723
  "outlit_list_workspace_users",
1608
1724
  "outlit_get_customer",
1725
+ "outlit_assign_customer_owner",
1726
+ "outlit_grant_customer_access",
1727
+ "outlit_update_customer_access",
1728
+ "outlit_revoke_customer_access",
1609
1729
  "outlit_get_timeline",
1610
1730
  "outlit_list_facts",
1611
1731
  "outlit_get_fact",
@@ -1621,16 +1741,19 @@ var init_dist4 = __esm(() => {
1621
1741
  "outlit_enable_destination",
1622
1742
  "outlit_disable_destination",
1623
1743
  "outlit_archive_destination",
1624
- "outlit_list_integrations",
1625
1744
  "outlit_get_integration_capabilities",
1626
1745
  "outlit_begin_integration_setup",
1627
1746
  "outlit_get_integration_setup_status",
1628
- "outlit_get_integration_sync_status",
1747
+ "outlit_get_integration_status",
1748
+ "outlit_setup_integration",
1629
1749
  "outlit_get_customer_activation",
1630
1750
  "outlit_preview_customer_activation",
1631
1751
  "outlit_update_customer_activation",
1632
1752
  "outlit_get_workspace_settings",
1633
- "outlit_update_workspace_settings"
1753
+ "outlit_update_workspace_settings",
1754
+ "outlit_list_behavior_metric_sources",
1755
+ "outlit_list_behavior_metric_events",
1756
+ "outlit_create_behavior_metric"
1634
1757
  ];
1635
1758
  publicToolContracts = {
1636
1759
  outlit_list_customers: {
@@ -2195,7 +2318,7 @@ var init_dist4 = __esm(() => {
2195
2318
  commandVersion: 1,
2196
2319
  ownerDomain: "users",
2197
2320
  title: "List Workspace Users",
2198
- description: "Browse internal workspace users such as CSMs, managers, account owners, and admins. Use this to discover who owns customers before composing dynamic reports across account books.",
2321
+ description: "List active workspace members who resolve to local Outlit users. Use this to discover exact user IDs for customer ownership and access commands or to browse account ownership.",
2199
2322
  inputSchema: {
2200
2323
  $schema: "https://json-schema.org/draft/2020-12/schema",
2201
2324
  type: "object",
@@ -2216,7 +2339,7 @@ var init_dist4 = __esm(() => {
2216
2339
  maxLength: 500
2217
2340
  },
2218
2341
  hasOwnedCustomers: {
2219
- description: "When true, return only workspace users who own at least one customer",
2342
+ description: "When true, return only members who own customers; when false, return only members who own none",
2220
2343
  type: "boolean"
2221
2344
  },
2222
2345
  limit: {
@@ -3133,6 +3256,269 @@ var init_dist4 = __esm(() => {
3133
3256
  additionalProperties: false
3134
3257
  }
3135
3258
  },
3259
+ outlit_assign_customer_owner: {
3260
+ toolName: "outlit_assign_customer_owner",
3261
+ commandId: "customer.owner.assign",
3262
+ commandVersion: 1,
3263
+ ownerDomain: "customers",
3264
+ title: "Assign Customer Owner",
3265
+ description: "Assign an active workspace member as this customer’s primary owner. The former owner keeps Editor access.",
3266
+ inputSchema: {
3267
+ $schema: "https://json-schema.org/draft/2020-12/schema",
3268
+ type: "object",
3269
+ properties: {
3270
+ customerId: {
3271
+ type: "string",
3272
+ format: "uuid",
3273
+ pattern: "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
3274
+ },
3275
+ targetUserId: {
3276
+ type: "string",
3277
+ minLength: 1,
3278
+ maxLength: 500
3279
+ }
3280
+ },
3281
+ required: [
3282
+ "customerId",
3283
+ "targetUserId"
3284
+ ]
3285
+ },
3286
+ outputSchema: {
3287
+ $schema: "https://json-schema.org/draft/2020-12/schema",
3288
+ type: "object",
3289
+ properties: {
3290
+ customerId: {
3291
+ type: "string"
3292
+ },
3293
+ ownerId: {
3294
+ type: "string"
3295
+ },
3296
+ previousOwnerId: {
3297
+ anyOf: [
3298
+ {
3299
+ type: "string"
3300
+ },
3301
+ {
3302
+ type: "null"
3303
+ }
3304
+ ]
3305
+ }
3306
+ },
3307
+ required: [
3308
+ "customerId",
3309
+ "ownerId",
3310
+ "previousOwnerId"
3311
+ ],
3312
+ additionalProperties: false
3313
+ }
3314
+ },
3315
+ outlit_grant_customer_access: {
3316
+ toolName: "outlit_grant_customer_access",
3317
+ commandId: "customer.access.grant",
3318
+ commandVersion: 1,
3319
+ ownerDomain: "customers",
3320
+ title: "Grant Customer Access",
3321
+ description: "Share a customer with an active workspace member as a Viewer or Editor. The customer ID must be exact.",
3322
+ inputSchema: {
3323
+ $schema: "https://json-schema.org/draft/2020-12/schema",
3324
+ type: "object",
3325
+ properties: {
3326
+ customerId: {
3327
+ type: "string",
3328
+ format: "uuid",
3329
+ pattern: "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
3330
+ },
3331
+ targetUserId: {
3332
+ type: "string",
3333
+ minLength: 1,
3334
+ maxLength: 500
3335
+ },
3336
+ role: {
3337
+ type: "string",
3338
+ enum: [
3339
+ "VIEWER",
3340
+ "EDITOR"
3341
+ ]
3342
+ }
3343
+ },
3344
+ required: [
3345
+ "customerId",
3346
+ "targetUserId",
3347
+ "role"
3348
+ ]
3349
+ },
3350
+ outputSchema: {
3351
+ $schema: "https://json-schema.org/draft/2020-12/schema",
3352
+ type: "object",
3353
+ properties: {
3354
+ access: {
3355
+ type: "object",
3356
+ properties: {
3357
+ customerId: {
3358
+ type: "string"
3359
+ },
3360
+ userId: {
3361
+ type: "string"
3362
+ },
3363
+ role: {
3364
+ type: "string",
3365
+ enum: [
3366
+ "VIEWER",
3367
+ "EDITOR"
3368
+ ]
3369
+ },
3370
+ grantedById: {
3371
+ anyOf: [
3372
+ {
3373
+ type: "string"
3374
+ },
3375
+ {
3376
+ type: "null"
3377
+ }
3378
+ ]
3379
+ }
3380
+ },
3381
+ required: [
3382
+ "customerId",
3383
+ "userId",
3384
+ "role",
3385
+ "grantedById"
3386
+ ],
3387
+ additionalProperties: false
3388
+ }
3389
+ },
3390
+ required: [
3391
+ "access"
3392
+ ],
3393
+ additionalProperties: false
3394
+ }
3395
+ },
3396
+ outlit_update_customer_access: {
3397
+ toolName: "outlit_update_customer_access",
3398
+ commandId: "customer.access.update",
3399
+ commandVersion: 1,
3400
+ ownerDomain: "customers",
3401
+ title: "Update Customer Access",
3402
+ description: "Change an existing customer collaborator between Viewer and Editor.",
3403
+ inputSchema: {
3404
+ $schema: "https://json-schema.org/draft/2020-12/schema",
3405
+ type: "object",
3406
+ properties: {
3407
+ customerId: {
3408
+ type: "string",
3409
+ format: "uuid",
3410
+ pattern: "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
3411
+ },
3412
+ targetUserId: {
3413
+ type: "string",
3414
+ minLength: 1,
3415
+ maxLength: 500
3416
+ },
3417
+ role: {
3418
+ type: "string",
3419
+ enum: [
3420
+ "VIEWER",
3421
+ "EDITOR"
3422
+ ]
3423
+ }
3424
+ },
3425
+ required: [
3426
+ "customerId",
3427
+ "targetUserId",
3428
+ "role"
3429
+ ]
3430
+ },
3431
+ outputSchema: {
3432
+ $schema: "https://json-schema.org/draft/2020-12/schema",
3433
+ type: "object",
3434
+ properties: {
3435
+ access: {
3436
+ type: "object",
3437
+ properties: {
3438
+ customerId: {
3439
+ type: "string"
3440
+ },
3441
+ userId: {
3442
+ type: "string"
3443
+ },
3444
+ role: {
3445
+ type: "string",
3446
+ enum: [
3447
+ "VIEWER",
3448
+ "EDITOR"
3449
+ ]
3450
+ },
3451
+ grantedById: {
3452
+ anyOf: [
3453
+ {
3454
+ type: "string"
3455
+ },
3456
+ {
3457
+ type: "null"
3458
+ }
3459
+ ]
3460
+ }
3461
+ },
3462
+ required: [
3463
+ "customerId",
3464
+ "userId",
3465
+ "role",
3466
+ "grantedById"
3467
+ ],
3468
+ additionalProperties: false
3469
+ }
3470
+ },
3471
+ required: [
3472
+ "access"
3473
+ ],
3474
+ additionalProperties: false
3475
+ }
3476
+ },
3477
+ outlit_revoke_customer_access: {
3478
+ toolName: "outlit_revoke_customer_access",
3479
+ commandId: "customer.access.revoke",
3480
+ commandVersion: 1,
3481
+ ownerDomain: "customers",
3482
+ title: "Revoke Customer Access",
3483
+ description: "Remove a collaborator’s explicit access to a customer.",
3484
+ inputSchema: {
3485
+ $schema: "https://json-schema.org/draft/2020-12/schema",
3486
+ type: "object",
3487
+ properties: {
3488
+ customerId: {
3489
+ type: "string",
3490
+ format: "uuid",
3491
+ pattern: "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
3492
+ },
3493
+ targetUserId: {
3494
+ type: "string",
3495
+ minLength: 1,
3496
+ maxLength: 500
3497
+ }
3498
+ },
3499
+ required: [
3500
+ "customerId",
3501
+ "targetUserId"
3502
+ ]
3503
+ },
3504
+ outputSchema: {
3505
+ $schema: "https://json-schema.org/draft/2020-12/schema",
3506
+ type: "object",
3507
+ properties: {
3508
+ customerId: {
3509
+ type: "string"
3510
+ },
3511
+ userId: {
3512
+ type: "string"
3513
+ }
3514
+ },
3515
+ required: [
3516
+ "customerId",
3517
+ "userId"
3518
+ ],
3519
+ additionalProperties: false
3520
+ }
3521
+ },
3136
3522
  outlit_get_timeline: {
3137
3523
  toolName: "outlit_get_timeline",
3138
3524
  commandId: "timeline.get",
@@ -8543,118 +8929,13 @@ Returns column definitions and example queries for each view.`,
8543
8929
  additionalProperties: false
8544
8930
  }
8545
8931
  },
8546
- outlit_list_integrations: {
8547
- toolName: "outlit_list_integrations",
8548
- commandId: "integration.list",
8549
- commandVersion: 1,
8932
+ outlit_get_integration_capabilities: {
8933
+ toolName: "outlit_get_integration_capabilities",
8934
+ commandId: "integration.capabilities.get",
8935
+ commandVersion: 2,
8550
8936
  ownerDomain: "integrations",
8551
- title: "List Integrations",
8552
- description: "List available integrations and safe connection health for the current actor.",
8553
- inputSchema: {
8554
- $schema: "https://json-schema.org/draft/2020-12/schema",
8555
- type: "object",
8556
- properties: {
8557
- connectedOnly: {
8558
- default: false,
8559
- type: "boolean"
8560
- }
8561
- },
8562
- additionalProperties: false
8563
- },
8564
- outputSchema: {
8565
- $schema: "https://json-schema.org/draft/2020-12/schema",
8566
- type: "object",
8567
- properties: {
8568
- integrations: {
8569
- type: "array",
8570
- items: {
8571
- type: "object",
8572
- properties: {
8573
- provider: {
8574
- type: "string",
8575
- minLength: 1,
8576
- maxLength: 80
8577
- },
8578
- name: {
8579
- type: "string",
8580
- minLength: 1,
8581
- maxLength: 120
8582
- },
8583
- category: {
8584
- type: "string",
8585
- enum: [
8586
- "crm",
8587
- "communication",
8588
- "storage",
8589
- "calls",
8590
- "calendar",
8591
- "analytics",
8592
- "billing",
8593
- "support"
8594
- ]
8595
- },
8596
- status: {
8597
- type: "string",
8598
- enum: [
8599
- "available",
8600
- "connected",
8601
- "setup_required"
8602
- ]
8603
- },
8604
- lastDataReceivedAt: {
8605
- anyOf: [
8606
- {
8607
- type: "string",
8608
- format: "date-time",
8609
- pattern: "^(?:(?:\\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))$"
8610
- },
8611
- {
8612
- type: "null"
8613
- }
8614
- ]
8615
- },
8616
- syncStatus: {
8617
- anyOf: [
8618
- {
8619
- type: "string",
8620
- minLength: 1,
8621
- maxLength: 80
8622
- },
8623
- {
8624
- type: "null"
8625
- }
8626
- ]
8627
- },
8628
- hasSyncError: {
8629
- type: "boolean"
8630
- }
8631
- },
8632
- required: [
8633
- "provider",
8634
- "name",
8635
- "category",
8636
- "status",
8637
- "lastDataReceivedAt",
8638
- "syncStatus",
8639
- "hasSyncError"
8640
- ],
8641
- additionalProperties: false
8642
- }
8643
- }
8644
- },
8645
- required: [
8646
- "integrations"
8647
- ],
8648
- additionalProperties: false
8649
- }
8650
- },
8651
- outlit_get_integration_capabilities: {
8652
- toolName: "outlit_get_integration_capabilities",
8653
- commandId: "integration.capabilities.get",
8654
- commandVersion: 1,
8655
- ownerDomain: "integrations",
8656
- title: "Get Integration Capabilities",
8657
- description: "Describe safe integration setup modes without exposing credential fields or provider configuration.",
8937
+ title: "Get Integration Capabilities",
8938
+ description: "Describe safe integration setup modes without exposing credential fields or provider configuration.",
8658
8939
  inputSchema: {
8659
8940
  $schema: "https://json-schema.org/draft/2020-12/schema",
8660
8941
  type: "object",
@@ -8728,6 +9009,10 @@ Returns column definitions and example queries for each view.`,
8728
9009
  ],
8729
9010
  additionalProperties: false
8730
9011
  }
9012
+ },
9013
+ preferredSetupVersion: {
9014
+ type: "number",
9015
+ const: 1
8731
9016
  }
8732
9017
  },
8733
9018
  required: [
@@ -8875,159 +9160,965 @@ Returns column definitions and example queries for each view.`,
8875
9160
  additionalProperties: false
8876
9161
  }
8877
9162
  },
8878
- outlit_get_integration_sync_status: {
8879
- toolName: "outlit_get_integration_sync_status",
8880
- commandId: "integration.sync_status.get",
8881
- commandVersion: 1,
9163
+ outlit_get_integration_status: {
9164
+ toolName: "outlit_get_integration_status",
9165
+ commandId: "integration.status.get",
9166
+ commandVersion: 2,
8882
9167
  ownerDomain: "integrations",
8883
- title: "Get Integration Sync Status",
8884
- description: "Get safe model-level sync status for a connection visible to the current actor.",
9168
+ title: "Get Integration Status",
9169
+ description: "Get the configuration-readiness status for one integration or the public integration catalog.",
8885
9170
  inputSchema: {
8886
9171
  $schema: "https://json-schema.org/draft/2020-12/schema",
8887
9172
  type: "object",
8888
9173
  properties: {
8889
9174
  provider: {
8890
9175
  type: "string",
8891
- minLength: 1,
8892
- maxLength: 80
9176
+ enum: [
9177
+ "salesforce",
9178
+ "hubspot",
9179
+ "attio",
9180
+ "slack",
9181
+ "google-calendar",
9182
+ "google-mail",
9183
+ "granola",
9184
+ "gong",
9185
+ "fireflies",
9186
+ "pylon",
9187
+ "stripe",
9188
+ "mixpanel",
9189
+ "posthog",
9190
+ "supabase",
9191
+ "clerk"
9192
+ ]
8893
9193
  }
8894
9194
  },
8895
- required: [
8896
- "provider"
8897
- ],
8898
9195
  additionalProperties: false
8899
9196
  },
8900
9197
  outputSchema: {
8901
9198
  $schema: "https://json-schema.org/draft/2020-12/schema",
8902
9199
  type: "object",
8903
9200
  properties: {
8904
- provider: {
8905
- type: "string",
8906
- minLength: 1,
8907
- maxLength: 80
8908
- },
8909
- name: {
8910
- type: "string",
8911
- minLength: 1,
8912
- maxLength: 120
8913
- },
8914
- category: {
8915
- type: "string",
8916
- enum: [
8917
- "crm",
8918
- "communication",
8919
- "storage",
8920
- "calls",
8921
- "calendar",
8922
- "analytics",
8923
- "billing",
8924
- "support"
8925
- ]
8926
- },
8927
- status: {
8928
- type: "string",
8929
- enum: [
8930
- "not_connected",
8931
- "connected"
8932
- ]
8933
- },
8934
- syncs: {
9201
+ integrations: {
8935
9202
  type: "array",
8936
9203
  items: {
8937
9204
  type: "object",
8938
9205
  properties: {
8939
- model: {
9206
+ provider: {
8940
9207
  type: "string",
8941
9208
  minLength: 1,
8942
- maxLength: 120
9209
+ maxLength: 80
8943
9210
  },
8944
- status: {
9211
+ name: {
8945
9212
  type: "string",
8946
9213
  minLength: 1,
8947
- maxLength: 80
9214
+ maxLength: 120
8948
9215
  },
8949
- lastSyncedAt: {
8950
- anyOf: [
8951
- {
8952
- type: "string",
8953
- format: "date-time",
8954
- pattern: "^(?:(?:\\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))$"
8955
- },
8956
- {
8957
- type: "null"
8958
- }
9216
+ category: {
9217
+ type: "string",
9218
+ enum: [
9219
+ "crm",
9220
+ "communication",
9221
+ "storage",
9222
+ "calls",
9223
+ "calendar",
9224
+ "analytics",
9225
+ "billing",
9226
+ "support"
8959
9227
  ]
8960
9228
  },
8961
- hasError: {
8962
- type: "boolean"
9229
+ status: {
9230
+ type: "string",
9231
+ enum: [
9232
+ "not_connected",
9233
+ "awaiting_auth",
9234
+ "setup_required",
9235
+ "ready",
9236
+ "requires_intervention"
9237
+ ]
8963
9238
  }
8964
9239
  },
8965
9240
  required: [
8966
- "model",
8967
- "status",
8968
- "lastSyncedAt",
8969
- "hasError"
9241
+ "provider",
9242
+ "name",
9243
+ "category",
9244
+ "status"
8970
9245
  ],
8971
9246
  additionalProperties: false
8972
9247
  }
8973
9248
  }
8974
9249
  },
8975
9250
  required: [
8976
- "provider",
8977
- "name",
8978
- "category",
8979
- "status",
8980
- "syncs"
9251
+ "integrations"
8981
9252
  ],
8982
9253
  additionalProperties: false
8983
9254
  }
8984
9255
  },
8985
- outlit_get_customer_activation: {
8986
- toolName: "outlit_get_customer_activation",
8987
- commandId: "customer_activation.get",
9256
+ outlit_setup_integration: {
9257
+ toolName: "outlit_setup_integration",
9258
+ commandId: "integration.setup.run",
8988
9259
  commandVersion: 1,
8989
- ownerDomain: "customer_activation",
8990
- title: "Get Customer Activation",
8991
- description: "Get the product event currently configured to activate customers and users.",
9260
+ ownerDomain: "integrations",
9261
+ title: "Set Up Integration",
9262
+ description: "Continue integration setup through validated credentials, safe configuration, or a trusted browser handoff.",
8992
9263
  inputSchema: {
8993
9264
  $schema: "https://json-schema.org/draft/2020-12/schema",
8994
- type: "object",
8995
- properties: {},
8996
- additionalProperties: false
8997
- },
8998
- outputSchema: {
8999
- $schema: "https://json-schema.org/draft/2020-12/schema",
9000
- type: "object",
9001
- properties: {
9002
- activation: {
9265
+ anyOf: [
9266
+ {
9003
9267
  type: "object",
9004
9268
  properties: {
9005
- eventName: {
9006
- anyOf: [
9007
- {
9269
+ provider: {
9270
+ type: "string",
9271
+ enum: [
9272
+ "salesforce",
9273
+ "hubspot",
9274
+ "attio"
9275
+ ]
9276
+ },
9277
+ configuration: {
9278
+ type: "object",
9279
+ properties: {
9280
+ kind: {
9008
9281
  type: "string",
9009
- minLength: 1,
9010
- maxLength: 191
9282
+ const: "crm_mapping"
9011
9283
  },
9012
- {
9013
- type: "null"
9284
+ mappings: {
9285
+ minItems: 1,
9286
+ type: "array",
9287
+ items: {
9288
+ type: "object",
9289
+ properties: {
9290
+ pipelineId: {
9291
+ type: "string",
9292
+ minLength: 1
9293
+ },
9294
+ pipelineName: {
9295
+ type: "string"
9296
+ },
9297
+ mappings: {
9298
+ type: "array",
9299
+ items: {
9300
+ type: "object",
9301
+ properties: {
9302
+ outlitStage: {
9303
+ type: "string",
9304
+ enum: [
9305
+ "Created",
9306
+ "Quoting",
9307
+ "Negotiation",
9308
+ "Won",
9309
+ "Lost"
9310
+ ]
9311
+ },
9312
+ crmStages: {
9313
+ type: "array",
9314
+ items: {
9315
+ type: "object",
9316
+ properties: {
9317
+ id: {
9318
+ type: "string",
9319
+ minLength: 1
9320
+ },
9321
+ name: {
9322
+ type: "string"
9323
+ }
9324
+ },
9325
+ required: [
9326
+ "id",
9327
+ "name"
9328
+ ],
9329
+ additionalProperties: false
9330
+ }
9331
+ }
9332
+ },
9333
+ required: [
9334
+ "outlitStage",
9335
+ "crmStages"
9336
+ ],
9337
+ additionalProperties: false
9338
+ }
9339
+ }
9340
+ },
9341
+ required: [
9342
+ "pipelineId",
9343
+ "pipelineName",
9344
+ "mappings"
9345
+ ],
9346
+ additionalProperties: false
9347
+ }
9348
+ },
9349
+ confirm: {
9350
+ type: "boolean",
9351
+ const: true
9014
9352
  }
9015
- ]
9353
+ },
9354
+ required: [
9355
+ "kind",
9356
+ "mappings",
9357
+ "confirm"
9358
+ ],
9359
+ additionalProperties: false
9016
9360
  }
9017
9361
  },
9018
9362
  required: [
9019
- "eventName"
9363
+ "provider"
9020
9364
  ],
9021
9365
  additionalProperties: false
9022
- }
9023
- },
9024
- required: [
9025
- "activation"
9026
- ],
9027
- additionalProperties: false
9028
- }
9029
- },
9030
- outlit_preview_customer_activation: {
9366
+ },
9367
+ {
9368
+ type: "object",
9369
+ properties: {
9370
+ provider: {
9371
+ type: "string",
9372
+ enum: [
9373
+ "slack",
9374
+ "google-calendar",
9375
+ "google-mail",
9376
+ "gong"
9377
+ ]
9378
+ }
9379
+ },
9380
+ required: [
9381
+ "provider"
9382
+ ],
9383
+ additionalProperties: false
9384
+ },
9385
+ {
9386
+ type: "object",
9387
+ properties: {
9388
+ provider: {
9389
+ type: "string",
9390
+ const: "stripe"
9391
+ },
9392
+ connectionMode: {
9393
+ type: "string",
9394
+ const: "oauth"
9395
+ }
9396
+ },
9397
+ required: [
9398
+ "provider"
9399
+ ],
9400
+ additionalProperties: false
9401
+ },
9402
+ {
9403
+ type: "object",
9404
+ properties: {
9405
+ provider: {
9406
+ type: "string",
9407
+ const: "stripe"
9408
+ },
9409
+ connectionMode: {
9410
+ type: "string",
9411
+ const: "restricted_key"
9412
+ },
9413
+ credentials: {
9414
+ type: "object",
9415
+ properties: {
9416
+ apiKey: {
9417
+ type: "string",
9418
+ minLength: 1,
9419
+ pattern: "^rk_.*"
9420
+ }
9421
+ },
9422
+ required: [
9423
+ "apiKey"
9424
+ ],
9425
+ additionalProperties: false
9426
+ }
9427
+ },
9428
+ required: [
9429
+ "provider",
9430
+ "connectionMode"
9431
+ ],
9432
+ additionalProperties: false
9433
+ },
9434
+ {
9435
+ type: "object",
9436
+ properties: {
9437
+ provider: {
9438
+ type: "string",
9439
+ const: "granola"
9440
+ },
9441
+ credentials: {
9442
+ type: "object",
9443
+ properties: {
9444
+ apiKey: {
9445
+ type: "string",
9446
+ minLength: 1
9447
+ },
9448
+ authScope: {
9449
+ default: "personal",
9450
+ type: "string",
9451
+ enum: [
9452
+ "personal",
9453
+ "enterprise"
9454
+ ]
9455
+ },
9456
+ enterpriseKeyAcknowledged: {
9457
+ default: false,
9458
+ type: "boolean"
9459
+ }
9460
+ },
9461
+ required: [
9462
+ "apiKey"
9463
+ ],
9464
+ additionalProperties: false
9465
+ }
9466
+ },
9467
+ required: [
9468
+ "provider"
9469
+ ],
9470
+ additionalProperties: false
9471
+ },
9472
+ {
9473
+ type: "object",
9474
+ properties: {
9475
+ provider: {
9476
+ type: "string",
9477
+ const: "fireflies"
9478
+ },
9479
+ credentials: {
9480
+ type: "object",
9481
+ properties: {
9482
+ apiKey: {
9483
+ type: "string",
9484
+ minLength: 1
9485
+ }
9486
+ },
9487
+ required: [
9488
+ "apiKey"
9489
+ ],
9490
+ additionalProperties: false
9491
+ }
9492
+ },
9493
+ required: [
9494
+ "provider"
9495
+ ],
9496
+ additionalProperties: false
9497
+ },
9498
+ {
9499
+ type: "object",
9500
+ properties: {
9501
+ provider: {
9502
+ type: "string",
9503
+ const: "pylon"
9504
+ },
9505
+ credentials: {
9506
+ type: "object",
9507
+ properties: {
9508
+ apiToken: {
9509
+ type: "string",
9510
+ minLength: 1
9511
+ }
9512
+ },
9513
+ required: [
9514
+ "apiToken"
9515
+ ],
9516
+ additionalProperties: false
9517
+ }
9518
+ },
9519
+ required: [
9520
+ "provider"
9521
+ ],
9522
+ additionalProperties: false
9523
+ },
9524
+ {
9525
+ type: "object",
9526
+ properties: {
9527
+ provider: {
9528
+ type: "string",
9529
+ const: "mixpanel"
9530
+ },
9531
+ credentials: {
9532
+ type: "object",
9533
+ properties: {
9534
+ username: {
9535
+ type: "string",
9536
+ minLength: 1
9537
+ },
9538
+ secret: {
9539
+ type: "string",
9540
+ minLength: 1
9541
+ },
9542
+ projectId: {
9543
+ type: "string",
9544
+ minLength: 1,
9545
+ maxLength: 64
9546
+ },
9547
+ region: {
9548
+ type: "string",
9549
+ enum: [
9550
+ "us",
9551
+ "eu",
9552
+ "in"
9553
+ ]
9554
+ }
9555
+ },
9556
+ required: [
9557
+ "username",
9558
+ "secret",
9559
+ "projectId",
9560
+ "region"
9561
+ ],
9562
+ additionalProperties: false
9563
+ },
9564
+ configuration: {
9565
+ type: "object",
9566
+ properties: {
9567
+ kind: {
9568
+ type: "string",
9569
+ const: "mixpanel_mapping"
9570
+ },
9571
+ mapping: {
9572
+ oneOf: [
9573
+ {
9574
+ type: "object",
9575
+ properties: {
9576
+ mode: {
9577
+ type: "string",
9578
+ const: "group_key"
9579
+ },
9580
+ groupKey: {
9581
+ type: "string",
9582
+ minLength: 1
9583
+ }
9584
+ },
9585
+ required: [
9586
+ "mode",
9587
+ "groupKey"
9588
+ ],
9589
+ additionalProperties: false
9590
+ },
9591
+ {
9592
+ type: "object",
9593
+ properties: {
9594
+ mode: {
9595
+ type: "string",
9596
+ const: "event_property"
9597
+ },
9598
+ propertyName: {
9599
+ type: "string",
9600
+ minLength: 1
9601
+ }
9602
+ },
9603
+ required: [
9604
+ "mode",
9605
+ "propertyName"
9606
+ ],
9607
+ additionalProperties: false
9608
+ },
9609
+ {
9610
+ type: "object",
9611
+ properties: {
9612
+ mode: {
9613
+ type: "string",
9614
+ const: "email_domain"
9615
+ }
9616
+ },
9617
+ required: [
9618
+ "mode"
9619
+ ],
9620
+ additionalProperties: false
9621
+ }
9622
+ ]
9623
+ },
9624
+ confirm: {
9625
+ type: "boolean",
9626
+ const: true
9627
+ }
9628
+ },
9629
+ required: [
9630
+ "kind",
9631
+ "mapping",
9632
+ "confirm"
9633
+ ],
9634
+ additionalProperties: false
9635
+ }
9636
+ },
9637
+ required: [
9638
+ "provider"
9639
+ ],
9640
+ additionalProperties: false
9641
+ },
9642
+ {
9643
+ type: "object",
9644
+ properties: {
9645
+ provider: {
9646
+ type: "string",
9647
+ const: "posthog"
9648
+ },
9649
+ credentials: {
9650
+ type: "object",
9651
+ properties: {
9652
+ apiKey: {
9653
+ type: "string",
9654
+ minLength: 10,
9655
+ pattern: "^phx_.*"
9656
+ },
9657
+ region: {
9658
+ type: "string",
9659
+ enum: [
9660
+ "us",
9661
+ "eu"
9662
+ ]
9663
+ },
9664
+ projectId: {
9665
+ type: "string",
9666
+ minLength: 1,
9667
+ pattern: "^\\d+$"
9668
+ }
9669
+ },
9670
+ required: [
9671
+ "apiKey",
9672
+ "region",
9673
+ "projectId"
9674
+ ],
9675
+ additionalProperties: false
9676
+ }
9677
+ },
9678
+ required: [
9679
+ "provider"
9680
+ ],
9681
+ additionalProperties: false
9682
+ },
9683
+ {
9684
+ type: "object",
9685
+ properties: {
9686
+ provider: {
9687
+ type: "string",
9688
+ enum: [
9689
+ "clerk",
9690
+ "supabase"
9691
+ ]
9692
+ }
9693
+ },
9694
+ required: [
9695
+ "provider"
9696
+ ],
9697
+ additionalProperties: false
9698
+ }
9699
+ ]
9700
+ },
9701
+ outputSchema: {
9702
+ $schema: "https://json-schema.org/draft/2020-12/schema",
9703
+ type: "object",
9704
+ properties: {
9705
+ provider: {
9706
+ type: "string",
9707
+ enum: [
9708
+ "salesforce",
9709
+ "hubspot",
9710
+ "attio",
9711
+ "slack",
9712
+ "google-calendar",
9713
+ "google-mail",
9714
+ "granola",
9715
+ "gong",
9716
+ "fireflies",
9717
+ "pylon",
9718
+ "stripe",
9719
+ "mixpanel",
9720
+ "posthog",
9721
+ "supabase",
9722
+ "clerk"
9723
+ ]
9724
+ },
9725
+ name: {
9726
+ type: "string",
9727
+ minLength: 1,
9728
+ maxLength: 120
9729
+ },
9730
+ category: {
9731
+ type: "string",
9732
+ enum: [
9733
+ "crm",
9734
+ "communication",
9735
+ "storage",
9736
+ "calls",
9737
+ "calendar",
9738
+ "analytics",
9739
+ "billing",
9740
+ "support"
9741
+ ]
9742
+ },
9743
+ status: {
9744
+ type: "string",
9745
+ enum: [
9746
+ "not_connected",
9747
+ "awaiting_auth",
9748
+ "setup_required",
9749
+ "ready",
9750
+ "requires_intervention"
9751
+ ]
9752
+ },
9753
+ next: {
9754
+ anyOf: [
9755
+ {
9756
+ anyOf: [
9757
+ {
9758
+ type: "object",
9759
+ properties: {
9760
+ kind: {
9761
+ type: "string",
9762
+ const: "browser_handoff"
9763
+ },
9764
+ purpose: {
9765
+ type: "string",
9766
+ enum: [
9767
+ "authentication",
9768
+ "recovery",
9769
+ "external_setup"
9770
+ ]
9771
+ },
9772
+ url: {
9773
+ type: "string",
9774
+ format: "uri"
9775
+ },
9776
+ sessionId: {
9777
+ anyOf: [
9778
+ {
9779
+ type: "string",
9780
+ format: "uuid",
9781
+ pattern: "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
9782
+ },
9783
+ {
9784
+ type: "null"
9785
+ }
9786
+ ]
9787
+ },
9788
+ expiresAt: {
9789
+ anyOf: [
9790
+ {
9791
+ type: "string",
9792
+ format: "date-time",
9793
+ pattern: "^(?:(?:\\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))$"
9794
+ },
9795
+ {
9796
+ type: "null"
9797
+ }
9798
+ ]
9799
+ }
9800
+ },
9801
+ required: [
9802
+ "kind",
9803
+ "purpose",
9804
+ "url",
9805
+ "sessionId",
9806
+ "expiresAt"
9807
+ ],
9808
+ additionalProperties: false
9809
+ },
9810
+ {
9811
+ type: "object",
9812
+ properties: {
9813
+ kind: {
9814
+ type: "string",
9815
+ const: "crm_mapping"
9816
+ },
9817
+ recommendation: {
9818
+ minItems: 1,
9819
+ type: "array",
9820
+ items: {
9821
+ type: "object",
9822
+ properties: {
9823
+ pipelineId: {
9824
+ type: "string",
9825
+ minLength: 1
9826
+ },
9827
+ pipelineName: {
9828
+ type: "string"
9829
+ },
9830
+ mappings: {
9831
+ type: "array",
9832
+ items: {
9833
+ type: "object",
9834
+ properties: {
9835
+ outlitStage: {
9836
+ type: "string",
9837
+ enum: [
9838
+ "Created",
9839
+ "Quoting",
9840
+ "Negotiation",
9841
+ "Won",
9842
+ "Lost"
9843
+ ]
9844
+ },
9845
+ crmStages: {
9846
+ type: "array",
9847
+ items: {
9848
+ type: "object",
9849
+ properties: {
9850
+ id: {
9851
+ type: "string",
9852
+ minLength: 1
9853
+ },
9854
+ name: {
9855
+ type: "string"
9856
+ }
9857
+ },
9858
+ required: [
9859
+ "id",
9860
+ "name"
9861
+ ],
9862
+ additionalProperties: false
9863
+ }
9864
+ }
9865
+ },
9866
+ required: [
9867
+ "outlitStage",
9868
+ "crmStages"
9869
+ ],
9870
+ additionalProperties: false
9871
+ }
9872
+ }
9873
+ },
9874
+ required: [
9875
+ "pipelineId",
9876
+ "pipelineName",
9877
+ "mappings"
9878
+ ],
9879
+ additionalProperties: false
9880
+ }
9881
+ }
9882
+ },
9883
+ required: [
9884
+ "kind",
9885
+ "recommendation"
9886
+ ],
9887
+ additionalProperties: false
9888
+ },
9889
+ {
9890
+ type: "object",
9891
+ properties: {
9892
+ kind: {
9893
+ type: "string",
9894
+ const: "mixpanel_mapping"
9895
+ },
9896
+ preview: {
9897
+ type: "object",
9898
+ properties: {
9899
+ sampleSize: {
9900
+ type: "integer",
9901
+ minimum: 0,
9902
+ maximum: 9007199254740991
9903
+ },
9904
+ sampleWindowStartAt: {
9905
+ type: "string",
9906
+ format: "date-time",
9907
+ pattern: "^(?:(?:\\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))$"
9908
+ },
9909
+ sampleWindowEndAt: {
9910
+ type: "string",
9911
+ format: "date-time",
9912
+ pattern: "^(?:(?:\\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))$"
9913
+ },
9914
+ accountKeyCoveragePct: {
9915
+ type: "number",
9916
+ minimum: 0,
9917
+ maximum: 100
9918
+ },
9919
+ emailOrDomainCoveragePct: {
9920
+ type: "number",
9921
+ minimum: 0,
9922
+ maximum: 100
9923
+ },
9924
+ unmappedPct: {
9925
+ type: "number",
9926
+ minimum: 0,
9927
+ maximum: 100
9928
+ },
9929
+ matchedCustomerCount: {
9930
+ type: "integer",
9931
+ minimum: 0,
9932
+ maximum: 9007199254740991
9933
+ },
9934
+ opaqueOnlyUnmappedCount: {
9935
+ type: "integer",
9936
+ minimum: 0,
9937
+ maximum: 9007199254740991
9938
+ },
9939
+ candidateAccountKeys: {
9940
+ type: "array",
9941
+ items: {
9942
+ type: "object",
9943
+ properties: {
9944
+ key: {
9945
+ type: "string"
9946
+ },
9947
+ count: {
9948
+ type: "integer",
9949
+ minimum: 0,
9950
+ maximum: 9007199254740991
9951
+ },
9952
+ coveragePct: {
9953
+ type: "number",
9954
+ minimum: 0,
9955
+ maximum: 100
9956
+ }
9957
+ },
9958
+ required: [
9959
+ "key",
9960
+ "count",
9961
+ "coveragePct"
9962
+ ],
9963
+ additionalProperties: false
9964
+ }
9965
+ },
9966
+ unmappedReasons: {
9967
+ type: "array",
9968
+ items: {
9969
+ type: "object",
9970
+ properties: {
9971
+ reason: {
9972
+ type: "string",
9973
+ enum: [
9974
+ "missing_account_key",
9975
+ "missing_email_or_domain",
9976
+ "no_matching_customer"
9977
+ ]
9978
+ },
9979
+ count: {
9980
+ type: "integer",
9981
+ minimum: 0,
9982
+ maximum: 9007199254740991
9983
+ }
9984
+ },
9985
+ required: [
9986
+ "reason",
9987
+ "count"
9988
+ ],
9989
+ additionalProperties: false
9990
+ }
9991
+ },
9992
+ warnings: {
9993
+ type: "array",
9994
+ items: {
9995
+ type: "string"
9996
+ }
9997
+ }
9998
+ },
9999
+ required: [
10000
+ "sampleSize",
10001
+ "sampleWindowStartAt",
10002
+ "sampleWindowEndAt",
10003
+ "accountKeyCoveragePct",
10004
+ "emailOrDomainCoveragePct",
10005
+ "unmappedPct",
10006
+ "matchedCustomerCount",
10007
+ "opaqueOnlyUnmappedCount",
10008
+ "candidateAccountKeys",
10009
+ "unmappedReasons",
10010
+ "warnings"
10011
+ ],
10012
+ additionalProperties: false
10013
+ }
10014
+ },
10015
+ required: [
10016
+ "kind",
10017
+ "preview"
10018
+ ],
10019
+ additionalProperties: false
10020
+ }
10021
+ ]
10022
+ },
10023
+ {
10024
+ type: "null"
10025
+ }
10026
+ ]
10027
+ },
10028
+ error: {
10029
+ anyOf: [
10030
+ {
10031
+ type: "object",
10032
+ properties: {
10033
+ code: {
10034
+ type: "string",
10035
+ enum: [
10036
+ "OWNER_REQUIRED",
10037
+ "CONNECTION_CONFLICT",
10038
+ "CREDENTIAL_REQUIRED",
10039
+ "CREDENTIAL_REJECTED",
10040
+ "LEGACY_CONNECTION_REQUIRED",
10041
+ "HANDOFF_UNAVAILABLE",
10042
+ "TRANSIENT_FAILURE"
10043
+ ]
10044
+ },
10045
+ message: {
10046
+ type: "string"
10047
+ },
10048
+ retryable: {
10049
+ type: "boolean"
10050
+ }
10051
+ },
10052
+ required: [
10053
+ "code",
10054
+ "message",
10055
+ "retryable"
10056
+ ],
10057
+ additionalProperties: false
10058
+ },
10059
+ {
10060
+ type: "null"
10061
+ }
10062
+ ]
10063
+ }
10064
+ },
10065
+ required: [
10066
+ "provider",
10067
+ "name",
10068
+ "category",
10069
+ "status",
10070
+ "next",
10071
+ "error"
10072
+ ],
10073
+ additionalProperties: false
10074
+ }
10075
+ },
10076
+ outlit_get_customer_activation: {
10077
+ toolName: "outlit_get_customer_activation",
10078
+ commandId: "customer_activation.get",
10079
+ commandVersion: 1,
10080
+ ownerDomain: "customer_activation",
10081
+ title: "Get Customer Activation",
10082
+ description: "Get the product event currently configured to activate customers and users.",
10083
+ inputSchema: {
10084
+ $schema: "https://json-schema.org/draft/2020-12/schema",
10085
+ type: "object",
10086
+ properties: {},
10087
+ additionalProperties: false
10088
+ },
10089
+ outputSchema: {
10090
+ $schema: "https://json-schema.org/draft/2020-12/schema",
10091
+ type: "object",
10092
+ properties: {
10093
+ activation: {
10094
+ type: "object",
10095
+ properties: {
10096
+ eventName: {
10097
+ anyOf: [
10098
+ {
10099
+ type: "string",
10100
+ minLength: 1,
10101
+ maxLength: 191
10102
+ },
10103
+ {
10104
+ type: "null"
10105
+ }
10106
+ ]
10107
+ }
10108
+ },
10109
+ required: [
10110
+ "eventName"
10111
+ ],
10112
+ additionalProperties: false
10113
+ }
10114
+ },
10115
+ required: [
10116
+ "activation"
10117
+ ],
10118
+ additionalProperties: false
10119
+ }
10120
+ },
10121
+ outlit_preview_customer_activation: {
9031
10122
  toolName: "outlit_preview_customer_activation",
9032
10123
  commandId: "customer_activation.preview",
9033
10124
  commandVersion: 1,
@@ -9278,67 +10369,393 @@ Returns column definitions and example queries for each view.`,
9278
10369
  }
9279
10370
  },
9280
10371
  required: [
9281
- "activation",
9282
- "changed"
10372
+ "activation",
10373
+ "changed"
10374
+ ],
10375
+ additionalProperties: false
10376
+ }
10377
+ },
10378
+ outlit_get_workspace_settings: {
10379
+ toolName: "outlit_get_workspace_settings",
10380
+ commandId: "settings.get",
10381
+ commandVersion: 1,
10382
+ ownerDomain: "settings",
10383
+ title: "Get Workspace Settings",
10384
+ description: "Get the workspace default timezone used by time-based product behavior.",
10385
+ inputSchema: {
10386
+ $schema: "https://json-schema.org/draft/2020-12/schema",
10387
+ type: "object",
10388
+ properties: {},
10389
+ additionalProperties: false
10390
+ },
10391
+ outputSchema: {
10392
+ $schema: "https://json-schema.org/draft/2020-12/schema",
10393
+ type: "object",
10394
+ properties: {
10395
+ settings: {
10396
+ type: "object",
10397
+ properties: {
10398
+ defaultTimezone: {
10399
+ type: "string",
10400
+ minLength: 1
10401
+ }
10402
+ },
10403
+ required: [
10404
+ "defaultTimezone"
10405
+ ],
10406
+ additionalProperties: false
10407
+ }
10408
+ },
10409
+ required: [
10410
+ "settings"
10411
+ ],
10412
+ additionalProperties: false
10413
+ }
10414
+ },
10415
+ outlit_update_workspace_settings: {
10416
+ toolName: "outlit_update_workspace_settings",
10417
+ commandId: "settings.update",
10418
+ commandVersion: 1,
10419
+ ownerDomain: "settings",
10420
+ title: "Update Workspace Settings",
10421
+ description: "Update the workspace default timezone using a valid IANA timezone.",
10422
+ inputSchema: {
10423
+ $schema: "https://json-schema.org/draft/2020-12/schema",
10424
+ type: "object",
10425
+ properties: {
10426
+ defaultTimezone: {
10427
+ type: "string",
10428
+ minLength: 1
10429
+ }
10430
+ },
10431
+ required: [
10432
+ "defaultTimezone"
10433
+ ],
10434
+ additionalProperties: false
10435
+ },
10436
+ outputSchema: {
10437
+ $schema: "https://json-schema.org/draft/2020-12/schema",
10438
+ type: "object",
10439
+ properties: {
10440
+ settings: {
10441
+ type: "object",
10442
+ properties: {
10443
+ defaultTimezone: {
10444
+ type: "string",
10445
+ minLength: 1
10446
+ }
10447
+ },
10448
+ required: [
10449
+ "defaultTimezone"
10450
+ ],
10451
+ additionalProperties: false
10452
+ }
10453
+ },
10454
+ required: [
10455
+ "settings"
10456
+ ],
10457
+ additionalProperties: false
10458
+ }
10459
+ },
10460
+ outlit_list_behavior_metric_sources: {
10461
+ toolName: "outlit_list_behavior_metric_sources",
10462
+ commandId: "behavior_metric_source.list",
10463
+ commandVersion: 1,
10464
+ ownerDomain: "behavior_metrics",
10465
+ title: "List Behavior Metric Sources",
10466
+ description: "List product-event sources eligible for Behavior Metric discovery.",
10467
+ inputSchema: {
10468
+ $schema: "https://json-schema.org/draft/2020-12/schema",
10469
+ type: "object",
10470
+ properties: {},
10471
+ additionalProperties: false
10472
+ },
10473
+ outputSchema: {
10474
+ $schema: "https://json-schema.org/draft/2020-12/schema",
10475
+ type: "object",
10476
+ properties: {
10477
+ sources: {
10478
+ type: "array",
10479
+ items: {
10480
+ type: "object",
10481
+ properties: {
10482
+ sourceKey: {
10483
+ type: "string",
10484
+ pattern: "^metric_source_v1_[a-f0-9]{32}$"
10485
+ },
10486
+ provider: {
10487
+ type: "string",
10488
+ enum: [
10489
+ "outlit_sdk",
10490
+ "posthog",
10491
+ "mixpanel"
10492
+ ]
10493
+ },
10494
+ label: {
10495
+ type: "string",
10496
+ minLength: 1,
10497
+ maxLength: 255
10498
+ },
10499
+ readiness: {
10500
+ type: "string",
10501
+ enum: [
10502
+ "READY",
10503
+ "WARMING",
10504
+ "BLOCKED"
10505
+ ]
10506
+ }
10507
+ },
10508
+ required: [
10509
+ "sourceKey",
10510
+ "provider",
10511
+ "label",
10512
+ "readiness"
10513
+ ],
10514
+ additionalProperties: false
10515
+ }
10516
+ }
10517
+ },
10518
+ required: [
10519
+ "sources"
9283
10520
  ],
9284
10521
  additionalProperties: false
9285
10522
  }
9286
10523
  },
9287
- outlit_get_workspace_settings: {
9288
- toolName: "outlit_get_workspace_settings",
9289
- commandId: "settings.get",
10524
+ outlit_list_behavior_metric_events: {
10525
+ toolName: "outlit_list_behavior_metric_events",
10526
+ commandId: "behavior_metric_event.list",
9290
10527
  commandVersion: 1,
9291
- ownerDomain: "settings",
9292
- title: "Get Workspace Settings",
9293
- description: "Get the workspace default timezone used by time-based product behavior.",
10528
+ ownerDomain: "behavior_metrics",
10529
+ title: "List Behavior Metric Events",
10530
+ description: "List attributed event candidates for a Behavior Metric source.",
9294
10531
  inputSchema: {
9295
10532
  $schema: "https://json-schema.org/draft/2020-12/schema",
9296
10533
  type: "object",
9297
- properties: {},
10534
+ properties: {
10535
+ sourceKey: {
10536
+ type: "string",
10537
+ pattern: "^metric_source_v1_[a-f0-9]{32}$"
10538
+ },
10539
+ weeks: {
10540
+ default: 12,
10541
+ type: "integer",
10542
+ minimum: 1,
10543
+ maximum: 53
10544
+ },
10545
+ limit: {
10546
+ default: 100,
10547
+ type: "integer",
10548
+ minimum: 1,
10549
+ maximum: 100
10550
+ }
10551
+ },
10552
+ required: [
10553
+ "sourceKey"
10554
+ ],
9298
10555
  additionalProperties: false
9299
10556
  },
9300
10557
  outputSchema: {
9301
10558
  $schema: "https://json-schema.org/draft/2020-12/schema",
9302
10559
  type: "object",
9303
10560
  properties: {
9304
- settings: {
9305
- type: "object",
9306
- properties: {
9307
- defaultTimezone: {
9308
- type: "string",
9309
- minLength: 1
9310
- }
9311
- },
9312
- required: [
9313
- "defaultTimezone"
9314
- ],
9315
- additionalProperties: false
10561
+ events: {
10562
+ type: "array",
10563
+ items: {
10564
+ type: "object",
10565
+ properties: {
10566
+ eventName: {
10567
+ type: "string",
10568
+ minLength: 1,
10569
+ maxLength: 191
10570
+ },
10571
+ eventCount: {
10572
+ type: "integer",
10573
+ minimum: 0,
10574
+ maximum: 9007199254740991
10575
+ },
10576
+ distinctCustomers: {
10577
+ type: "integer",
10578
+ minimum: 0,
10579
+ maximum: 9007199254740991
10580
+ },
10581
+ activeWeeks: {
10582
+ type: "integer",
10583
+ minimum: 1,
10584
+ maximum: 53
10585
+ },
10586
+ propertyKeys: {
10587
+ maxItems: 10,
10588
+ type: "array",
10589
+ items: {
10590
+ type: "string",
10591
+ minLength: 1,
10592
+ maxLength: 191
10593
+ }
10594
+ }
10595
+ },
10596
+ required: [
10597
+ "eventName",
10598
+ "eventCount",
10599
+ "distinctCustomers",
10600
+ "activeWeeks",
10601
+ "propertyKeys"
10602
+ ],
10603
+ additionalProperties: false
10604
+ }
10605
+ },
10606
+ truncated: {
10607
+ type: "boolean"
9316
10608
  }
9317
10609
  },
9318
10610
  required: [
9319
- "settings"
10611
+ "events",
10612
+ "truncated"
9320
10613
  ],
9321
10614
  additionalProperties: false
9322
10615
  }
9323
10616
  },
9324
- outlit_update_workspace_settings: {
9325
- toolName: "outlit_update_workspace_settings",
9326
- commandId: "settings.update",
10617
+ outlit_create_behavior_metric: {
10618
+ toolName: "outlit_create_behavior_metric",
10619
+ commandId: "behavior_metric.create",
9327
10620
  commandVersion: 1,
9328
- ownerDomain: "settings",
9329
- title: "Update Workspace Settings",
9330
- description: "Update the workspace default timezone using a valid IANA timezone.",
10621
+ ownerDomain: "behavior_metrics",
10622
+ title: "Create Behavior Metric",
10623
+ description: "Create or idempotently return an event-based Behavior Metric in ENABLED and SHADOW.",
9331
10624
  inputSchema: {
9332
10625
  $schema: "https://json-schema.org/draft/2020-12/schema",
9333
10626
  type: "object",
9334
10627
  properties: {
9335
- defaultTimezone: {
10628
+ sourceKey: {
9336
10629
  type: "string",
9337
- minLength: 1
10630
+ pattern: "^metric_source_v1_[a-f0-9]{32}$"
10631
+ },
10632
+ eventName: {
10633
+ type: "string",
10634
+ minLength: 1,
10635
+ maxLength: 191
10636
+ },
10637
+ behaviorKey: {
10638
+ type: "string",
10639
+ maxLength: 64,
10640
+ pattern: "^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$"
10641
+ },
10642
+ label: {
10643
+ type: "string",
10644
+ minLength: 1,
10645
+ maxLength: 255
10646
+ },
10647
+ propertyFilters: {
10648
+ default: [],
10649
+ maxItems: 5,
10650
+ type: "array",
10651
+ items: {
10652
+ oneOf: [
10653
+ {
10654
+ type: "object",
10655
+ properties: {
10656
+ property: {
10657
+ type: "string",
10658
+ minLength: 1,
10659
+ maxLength: 191
10660
+ },
10661
+ operator: {
10662
+ type: "string",
10663
+ const: "equals"
10664
+ },
10665
+ value: {
10666
+ oneOf: [
10667
+ {
10668
+ type: "object",
10669
+ properties: {
10670
+ type: {
10671
+ type: "string",
10672
+ const: "string"
10673
+ },
10674
+ value: {
10675
+ type: "string",
10676
+ maxLength: 191
10677
+ }
10678
+ },
10679
+ required: [
10680
+ "type",
10681
+ "value"
10682
+ ],
10683
+ additionalProperties: false
10684
+ },
10685
+ {
10686
+ type: "object",
10687
+ properties: {
10688
+ type: {
10689
+ type: "string",
10690
+ const: "number"
10691
+ },
10692
+ value: {
10693
+ type: "number",
10694
+ minimum: -9007199254740991,
10695
+ maximum: 9007199254740991
10696
+ }
10697
+ },
10698
+ required: [
10699
+ "type",
10700
+ "value"
10701
+ ],
10702
+ additionalProperties: false
10703
+ },
10704
+ {
10705
+ type: "object",
10706
+ properties: {
10707
+ type: {
10708
+ type: "string",
10709
+ const: "boolean"
10710
+ },
10711
+ value: {
10712
+ type: "boolean"
10713
+ }
10714
+ },
10715
+ required: [
10716
+ "type",
10717
+ "value"
10718
+ ],
10719
+ additionalProperties: false
10720
+ }
10721
+ ]
10722
+ }
10723
+ },
10724
+ required: [
10725
+ "property",
10726
+ "operator",
10727
+ "value"
10728
+ ],
10729
+ additionalProperties: false
10730
+ },
10731
+ {
10732
+ type: "object",
10733
+ properties: {
10734
+ property: {
10735
+ type: "string",
10736
+ minLength: 1,
10737
+ maxLength: 191
10738
+ },
10739
+ operator: {
10740
+ type: "string",
10741
+ const: "exists"
10742
+ }
10743
+ },
10744
+ required: [
10745
+ "property",
10746
+ "operator"
10747
+ ],
10748
+ additionalProperties: false
10749
+ }
10750
+ ]
10751
+ }
9338
10752
  }
9339
10753
  },
9340
10754
  required: [
9341
- "defaultTimezone"
10755
+ "sourceKey",
10756
+ "eventName",
10757
+ "behaviorKey",
10758
+ "label"
9342
10759
  ],
9343
10760
  additionalProperties: false
9344
10761
  },
@@ -9346,22 +10763,237 @@ Returns column definitions and example queries for each view.`,
9346
10763
  $schema: "https://json-schema.org/draft/2020-12/schema",
9347
10764
  type: "object",
9348
10765
  properties: {
9349
- settings: {
10766
+ created: {
10767
+ type: "boolean"
10768
+ },
10769
+ metric: {
9350
10770
  type: "object",
9351
10771
  properties: {
9352
- defaultTimezone: {
10772
+ sourceKey: {
9353
10773
  type: "string",
9354
- minLength: 1
10774
+ pattern: "^metric_source_v1_[a-f0-9]{32}$"
10775
+ },
10776
+ behaviorKey: {
10777
+ type: "string",
10778
+ maxLength: 64,
10779
+ pattern: "^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$"
10780
+ },
10781
+ label: {
10782
+ type: "string",
10783
+ minLength: 1,
10784
+ maxLength: 255
10785
+ },
10786
+ eventSelection: {
10787
+ oneOf: [
10788
+ {
10789
+ type: "object",
10790
+ properties: {
10791
+ mode: {
10792
+ type: "string",
10793
+ const: "exact_event_names"
10794
+ },
10795
+ eventNames: {
10796
+ minItems: 1,
10797
+ maxItems: 1,
10798
+ type: "array",
10799
+ items: {
10800
+ type: "string",
10801
+ minLength: 1,
10802
+ maxLength: 191
10803
+ }
10804
+ }
10805
+ },
10806
+ required: [
10807
+ "mode",
10808
+ "eventNames"
10809
+ ],
10810
+ additionalProperties: false
10811
+ },
10812
+ {
10813
+ type: "object",
10814
+ properties: {
10815
+ mode: {
10816
+ type: "string",
10817
+ const: "configured_event"
10818
+ },
10819
+ eventName: {
10820
+ type: "string",
10821
+ minLength: 1,
10822
+ maxLength: 191
10823
+ },
10824
+ propertyFilters: {
10825
+ minItems: 1,
10826
+ maxItems: 5,
10827
+ type: "array",
10828
+ items: {
10829
+ oneOf: [
10830
+ {
10831
+ type: "object",
10832
+ properties: {
10833
+ property: {
10834
+ type: "string",
10835
+ minLength: 1,
10836
+ maxLength: 191
10837
+ },
10838
+ operator: {
10839
+ type: "string",
10840
+ const: "equals"
10841
+ },
10842
+ value: {
10843
+ oneOf: [
10844
+ {
10845
+ type: "object",
10846
+ properties: {
10847
+ type: {
10848
+ type: "string",
10849
+ const: "string"
10850
+ },
10851
+ value: {
10852
+ type: "string",
10853
+ maxLength: 191
10854
+ }
10855
+ },
10856
+ required: [
10857
+ "type",
10858
+ "value"
10859
+ ],
10860
+ additionalProperties: false
10861
+ },
10862
+ {
10863
+ type: "object",
10864
+ properties: {
10865
+ type: {
10866
+ type: "string",
10867
+ const: "number"
10868
+ },
10869
+ value: {
10870
+ type: "number",
10871
+ minimum: -9007199254740991,
10872
+ maximum: 9007199254740991
10873
+ }
10874
+ },
10875
+ required: [
10876
+ "type",
10877
+ "value"
10878
+ ],
10879
+ additionalProperties: false
10880
+ },
10881
+ {
10882
+ type: "object",
10883
+ properties: {
10884
+ type: {
10885
+ type: "string",
10886
+ const: "boolean"
10887
+ },
10888
+ value: {
10889
+ type: "boolean"
10890
+ }
10891
+ },
10892
+ required: [
10893
+ "type",
10894
+ "value"
10895
+ ],
10896
+ additionalProperties: false
10897
+ }
10898
+ ]
10899
+ }
10900
+ },
10901
+ required: [
10902
+ "property",
10903
+ "operator",
10904
+ "value"
10905
+ ],
10906
+ additionalProperties: false
10907
+ },
10908
+ {
10909
+ type: "object",
10910
+ properties: {
10911
+ property: {
10912
+ type: "string",
10913
+ minLength: 1,
10914
+ maxLength: 191
10915
+ },
10916
+ operator: {
10917
+ type: "string",
10918
+ const: "exists"
10919
+ }
10920
+ },
10921
+ required: [
10922
+ "property",
10923
+ "operator"
10924
+ ],
10925
+ additionalProperties: false
10926
+ }
10927
+ ]
10928
+ }
10929
+ }
10930
+ },
10931
+ required: [
10932
+ "mode",
10933
+ "eventName",
10934
+ "propertyFilters"
10935
+ ],
10936
+ additionalProperties: false
10937
+ }
10938
+ ]
10939
+ },
10940
+ status: {
10941
+ type: "string",
10942
+ const: "ENABLED"
10943
+ },
10944
+ evaluationMode: {
10945
+ type: "string",
10946
+ const: "SHADOW"
10947
+ },
10948
+ definitions: {
10949
+ minItems: 2,
10950
+ maxItems: 2,
10951
+ type: "array",
10952
+ items: {
10953
+ type: "object",
10954
+ properties: {
10955
+ id: {
10956
+ type: "string",
10957
+ format: "uuid",
10958
+ pattern: "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
10959
+ },
10960
+ metricKey: {
10961
+ type: "string",
10962
+ minLength: 1,
10963
+ maxLength: 191
10964
+ },
10965
+ aggregation: {
10966
+ type: "string",
10967
+ enum: [
10968
+ "active_days",
10969
+ "event_count"
10970
+ ]
10971
+ }
10972
+ },
10973
+ required: [
10974
+ "id",
10975
+ "metricKey",
10976
+ "aggregation"
10977
+ ],
10978
+ additionalProperties: false
10979
+ }
9355
10980
  }
9356
10981
  },
9357
10982
  required: [
9358
- "defaultTimezone"
10983
+ "sourceKey",
10984
+ "behaviorKey",
10985
+ "label",
10986
+ "eventSelection",
10987
+ "status",
10988
+ "evaluationMode",
10989
+ "definitions"
9359
10990
  ],
9360
10991
  additionalProperties: false
9361
10992
  }
9362
10993
  },
9363
10994
  required: [
9364
- "settings"
10995
+ "created",
10996
+ "metric"
9365
10997
  ],
9366
10998
  additionalProperties: false
9367
10999
  }
@@ -9392,11 +11024,15 @@ Returns column definitions and example queries for each view.`,
9392
11024
  "outlit_query",
9393
11025
  "outlit_schema"
9394
11026
  ],
9395
- cli: [
11027
+ pi: [
9396
11028
  "outlit_list_customers",
9397
11029
  "outlit_list_users",
9398
11030
  "outlit_list_workspace_users",
9399
11031
  "outlit_get_customer",
11032
+ "outlit_assign_customer_owner",
11033
+ "outlit_grant_customer_access",
11034
+ "outlit_update_customer_access",
11035
+ "outlit_revoke_customer_access",
9400
11036
  "outlit_get_timeline",
9401
11037
  "outlit_list_facts",
9402
11038
  "outlit_get_fact",
@@ -9412,16 +11048,54 @@ Returns column definitions and example queries for each view.`,
9412
11048
  "outlit_enable_destination",
9413
11049
  "outlit_disable_destination",
9414
11050
  "outlit_archive_destination",
9415
- "outlit_list_integrations",
9416
11051
  "outlit_get_integration_capabilities",
9417
11052
  "outlit_begin_integration_setup",
9418
11053
  "outlit_get_integration_setup_status",
9419
- "outlit_get_integration_sync_status",
11054
+ "outlit_get_integration_status",
11055
+ "outlit_setup_integration",
9420
11056
  "outlit_get_customer_activation",
9421
11057
  "outlit_preview_customer_activation",
9422
11058
  "outlit_update_customer_activation",
9423
11059
  "outlit_get_workspace_settings",
9424
11060
  "outlit_update_workspace_settings"
11061
+ ],
11062
+ cli: [
11063
+ "outlit_list_customers",
11064
+ "outlit_list_users",
11065
+ "outlit_list_workspace_users",
11066
+ "outlit_get_customer",
11067
+ "outlit_assign_customer_owner",
11068
+ "outlit_grant_customer_access",
11069
+ "outlit_update_customer_access",
11070
+ "outlit_revoke_customer_access",
11071
+ "outlit_get_timeline",
11072
+ "outlit_list_facts",
11073
+ "outlit_get_fact",
11074
+ "outlit_get_source",
11075
+ "outlit_list_sources",
11076
+ "outlit_search_customer_context",
11077
+ "outlit_query",
11078
+ "outlit_schema",
11079
+ "outlit_list_destinations",
11080
+ "outlit_get_destination",
11081
+ "outlit_create_destination",
11082
+ "outlit_update_destination",
11083
+ "outlit_enable_destination",
11084
+ "outlit_disable_destination",
11085
+ "outlit_archive_destination",
11086
+ "outlit_get_integration_capabilities",
11087
+ "outlit_begin_integration_setup",
11088
+ "outlit_get_integration_setup_status",
11089
+ "outlit_get_integration_status",
11090
+ "outlit_setup_integration",
11091
+ "outlit_get_customer_activation",
11092
+ "outlit_preview_customer_activation",
11093
+ "outlit_update_customer_activation",
11094
+ "outlit_get_workspace_settings",
11095
+ "outlit_update_workspace_settings",
11096
+ "outlit_list_behavior_metric_sources",
11097
+ "outlit_list_behavior_metric_events",
11098
+ "outlit_create_behavior_metric"
9425
11099
  ]
9426
11100
  };
9427
11101
  toolGatewayTransport = {
@@ -9574,11 +11248,14 @@ Returns column definitions and example queries for each view.`,
9574
11248
  "workspace_members:read",
9575
11249
  "analytics:read",
9576
11250
  "destinations:manage",
11251
+ "behavior_metrics:manage",
11252
+ "integrations:connect_own",
9577
11253
  "integrations:manage",
9578
11254
  "activation:read",
9579
11255
  "activation:manage",
9580
11256
  "workspace_settings:read",
9581
- "workspace_settings:manage"
11257
+ "workspace_settings:manage",
11258
+ "customer_access:manage"
9582
11259
  ]
9583
11260
  }
9584
11261
  },
@@ -9629,11 +11306,14 @@ Returns column definitions and example queries for each view.`,
9629
11306
  "workspace_members:read",
9630
11307
  "analytics:read",
9631
11308
  "destinations:manage",
11309
+ "behavior_metrics:manage",
11310
+ "integrations:connect_own",
9632
11311
  "integrations:manage",
9633
11312
  "activation:read",
9634
11313
  "activation:manage",
9635
11314
  "workspace_settings:read",
9636
- "workspace_settings:manage"
11315
+ "workspace_settings:manage",
11316
+ "customer_access:manage"
9637
11317
  ]
9638
11318
  }
9639
11319
  }
@@ -9857,6 +11537,7 @@ Returns column definitions and example queries for each view.`,
9857
11537
  };
9858
11538
  defaultToolNames = consumerToolPolicies.default;
9859
11539
  analyticalToolNames = consumerToolPolicies.analytical;
11540
+ piToolNames = consumerToolPolicies.pi;
9860
11541
  cliToolNames = consumerToolPolicies.cli;
9861
11542
  defaultToolNameSet = new Set(defaultToolNames);
9862
11543
  sqlToolNames = analyticalToolNames.filter((toolName) => !defaultToolNameSet.has(toolName));
@@ -9872,18 +11553,37 @@ async function createClient(flagApiKey) {
9872
11553
  throw new Error(`Invalid API key format. Keys must start with "ok_" followed by at least 32 alphanumeric characters. Get one at ${OUTLIT_DASHBOARD_URL}`);
9873
11554
  }
9874
11555
  const baseUrl = process.env.OUTLIT_API_URL ?? DEFAULT_API_URL;
11556
+ validateApiBaseUrl(baseUrl);
9875
11557
  const toolsClient = createOutlitClient({ apiKey: credential.key, baseUrl });
9876
11558
  return {
9877
11559
  key: credential.key,
9878
11560
  baseUrl,
9879
- async callTool(toolName, params) {
11561
+ async callTool(toolName, params, callOptions) {
9880
11562
  if (!isPublicToolName(toolName) || !cliToolNameSet.has(toolName)) {
9881
11563
  throw new Error(`Unknown CLI tool: ${toolName}`);
9882
11564
  }
9883
- return toolsClient.callTool(toolName, params);
11565
+ return toolsClient.callTool(toolName, params, {
11566
+ signal: callOptions?.signal
11567
+ });
9884
11568
  }
9885
11569
  };
9886
11570
  }
11571
+ function validateApiBaseUrl(baseUrl) {
11572
+ let url;
11573
+ try {
11574
+ url = new URL(baseUrl);
11575
+ } catch {
11576
+ throw new Error("OUTLIT_API_URL must be a valid absolute URL");
11577
+ }
11578
+ if (url.protocol === "https:" || url.protocol === "http:" && isLoopbackHost(url.hostname)) {
11579
+ return;
11580
+ }
11581
+ throw new Error("OUTLIT_API_URL must use HTTPS unless it is a loopback development URL");
11582
+ }
11583
+ function isLoopbackHost(hostname) {
11584
+ const normalized = hostname.toLowerCase().replace(/^\[|\]$/g, "");
11585
+ return normalized === "localhost" || normalized === "::1" || /^127(?:\.\d{1,3}){3}$/.test(normalized);
11586
+ }
9887
11587
  var API_KEY_REGEX, cliToolNameSet;
9888
11588
  var init_client = __esm(() => {
9889
11589
  init_dist4();
@@ -10066,6 +11766,17 @@ async function validateKeyOrExit(apiKey, json) {
10066
11766
  }, json);
10067
11767
  }
10068
11768
  }
11769
+ function outputApiError(error, json, fallback) {
11770
+ if (isOutlitToolsApiError(error) && error.envelope) {
11771
+ if (isJsonMode(json)) {
11772
+ process.stderr.write(`${JSON.stringify(error.envelope, null, 2)}
11773
+ `);
11774
+ process.exit(1);
11775
+ }
11776
+ return outputError({ message: error.envelope.message, code: error.envelope.code }, json);
11777
+ }
11778
+ return outputError(fallback, json);
11779
+ }
10069
11780
  function renderApiTable(data, table) {
10070
11781
  const record = typeof data === "object" && data !== null && !Array.isArray(data) ? data : {};
10071
11782
  const itemsKey = table.itemsKey ?? "items";
@@ -10100,7 +11811,7 @@ function readPath(record, path) {
10100
11811
  return current;
10101
11812
  }
10102
11813
  async function runTool(client, toolName, params, json, opts) {
10103
- const spinner = opts?.spinnerMessage ? createSpinner(opts.spinnerMessage) : null;
11814
+ const spinner = opts?.spinnerMessage && !isJsonMode(json) ? createSpinner(opts.spinnerMessage) : null;
10104
11815
  try {
10105
11816
  const rawData = await client.callTool(toolName, params);
10106
11817
  const data = opts?.transform ? opts.transform(rawData) : rawData;
@@ -10112,15 +11823,10 @@ async function runTool(client, toolName, params, json, opts) {
10112
11823
  renderApiTable(data, table);
10113
11824
  } catch (err) {
10114
11825
  spinner?.fail("Failed");
10115
- if (isOutlitToolsApiError(err) && err.envelope) {
10116
- if (isJsonMode(json)) {
10117
- process.stderr.write(`${JSON.stringify(err.envelope, null, 2)}
10118
- `);
10119
- process.exit(1);
10120
- }
10121
- return outputError({ message: err.envelope.message, code: err.envelope.code }, json);
10122
- }
10123
- return outputError({ message: errorMessage(err, "Request failed"), code: "api_error" }, json);
11826
+ return outputApiError(err, json, {
11827
+ message: errorMessage(err, "Request failed"),
11828
+ code: "api_error"
11829
+ });
10124
11830
  }
10125
11831
  }
10126
11832
  var ApiKeyValidationUnavailableError;
@@ -10146,16 +11852,26 @@ async function pollUntil(fn, predicate, opts = {}) {
10146
11852
  const timeoutMs = opts.timeoutMs ?? 300000;
10147
11853
  const start = Date.now();
10148
11854
  while (Date.now() - start < timeoutMs) {
11855
+ const remainingMs = timeoutMs - (Date.now() - start);
11856
+ const controller = new AbortController;
11857
+ const deadline = setTimeout(() => controller.abort(), remainingMs);
10149
11858
  try {
10150
- const result = await fn();
11859
+ const result = await fn(controller.signal);
10151
11860
  if (predicate(result))
10152
11861
  return result;
10153
- } catch {}
11862
+ } catch (error) {
11863
+ if (controller.signal.aborted && Date.now() - start >= timeoutMs)
11864
+ return null;
11865
+ if (opts.shouldRetry?.(error) === false)
11866
+ throw error;
11867
+ } finally {
11868
+ clearTimeout(deadline);
11869
+ }
10154
11870
  if (opts.spinner && opts.spinnerMessage) {
10155
11871
  const elapsed = Math.floor((Date.now() - start) / 1000);
10156
11872
  opts.spinner.update(`${opts.spinnerMessage} (${elapsed}s)`);
10157
11873
  }
10158
- await sleep(intervalMs);
11874
+ await sleep(Math.min(intervalMs, Math.max(0, timeoutMs - (Date.now() - start))));
10159
11875
  }
10160
11876
  return null;
10161
11877
  }
@@ -11115,27 +12831,33 @@ function capitalize(value) {
11115
12831
  return "--";
11116
12832
  return value.charAt(0).toUpperCase() + value.slice(1);
11117
12833
  }
11118
- function formatNumber(value) {
11119
- if (value == null || typeof value !== "number" || Number.isNaN(value))
11120
- return "--";
11121
- return value.toLocaleString("en-US");
11122
- }
11123
12834
 
11124
12835
  // src/lib/platform-input.ts
11125
12836
  function isIso8601DateTime(value) {
11126
12837
  return iso8601DateTimeRegex.test(value) && !Number.isNaN(new Date(value).getTime());
11127
12838
  }
11128
12839
  function requiredTrimmedString(value, flag, json) {
11129
- const trimmed = value?.trim();
11130
- if (!trimmed) {
12840
+ return requiredString(value, flag, json).trim();
12841
+ }
12842
+ function requiredString(value, flag, json) {
12843
+ if (!value?.trim()) {
11131
12844
  return outputError({ message: `Provide ${flag}`, code: "missing_input" }, json);
11132
12845
  }
11133
- return trimmed;
12846
+ return value;
11134
12847
  }
11135
12848
  function optionalTrimmedString(value) {
11136
12849
  const trimmed = value?.trim();
11137
12850
  return trimmed ? trimmed : null;
11138
12851
  }
12852
+ function parseIntegerFlag(value, fallback, flag, json) {
12853
+ if (value === undefined)
12854
+ return fallback;
12855
+ const parsed = typeof value === "number" ? value : Number(value);
12856
+ if (!Number.isInteger(parsed)) {
12857
+ return outputError({ message: `${flag} must be an integer`, code: "invalid_input" }, json);
12858
+ }
12859
+ return parsed;
12860
+ }
11139
12861
  var iso8601DateTimeRegex;
11140
12862
  var init_platform_input = __esm(() => {
11141
12863
  init_output();
@@ -11424,25 +13146,279 @@ var init_timeline = __esm(() => {
11424
13146
  };
11425
13147
  timeline_default = defineCommand2({
11426
13148
  meta: {
11427
- name: "timeline",
13149
+ name: "timeline",
13150
+ description: [
13151
+ "Show the activity timeline for a customer.",
13152
+ "",
13153
+ "The customer argument accepts:",
13154
+ " - Customer domain (acme.com)",
13155
+ " - Customer ID (UUID)",
13156
+ "",
13157
+ "Timeframe is used when no explicit date range is set.",
13158
+ "When --start-date or --end-date is provided, --timeframe is ignored.",
13159
+ `Channels: ${timelineChannels.join(", ")}`,
13160
+ `Timeframes: ${timelineTimeframes.join(", ")}`,
13161
+ "",
13162
+ "Examples:",
13163
+ " outlit customers timeline acme.com",
13164
+ " outlit customers timeline acme.com --timeframe 90d",
13165
+ " outlit customers timeline acme.com --channels COMMUNICATION,MEETING",
13166
+ " outlit customers timeline acme.com --start-date 2025-01-01T00:00:00Z --end-date 2025-03-01T23:59:59Z",
13167
+ " outlit customers timeline acme.com --event-types PAGE_VIEW,MEETING --limit 50",
13168
+ "",
13169
+ AGENT_JSON_HINT
13170
+ ].join(`
13171
+ `)
13172
+ },
13173
+ args: {
13174
+ ...authArgs,
13175
+ ...outputArgs,
13176
+ ...paginationArgs,
13177
+ customer: {
13178
+ type: "positional",
13179
+ description: "Customer ID or domain (acme.com)",
13180
+ required: true
13181
+ },
13182
+ channels: {
13183
+ type: "string",
13184
+ description: `Comma-separated list of channels to filter (${timelineChannels.join(", ")})`
13185
+ },
13186
+ "event-types": {
13187
+ type: "string",
13188
+ description: "Comma-separated list of event types to filter (e.g. PAGE_VIEW,MEETING)"
13189
+ },
13190
+ timeframe: {
13191
+ type: "string",
13192
+ description: `Timeframe for events (${timelineTimeframes.join(", ")}). Ignored when --start-date or --end-date is set.`,
13193
+ default: "30d"
13194
+ },
13195
+ "start-date": {
13196
+ type: "string",
13197
+ description: "Start datetime for the event range (ISO 8601, e.g. 2025-01-01T00:00:00Z). When set, --timeframe is ignored."
13198
+ },
13199
+ "end-date": {
13200
+ type: "string",
13201
+ description: "End datetime for the event range (ISO 8601, e.g. 2025-03-01T23:59:59Z). When set, --timeframe is ignored."
13202
+ }
13203
+ },
13204
+ async run({ args }) {
13205
+ const json = !!args.json;
13206
+ const client = await getClientOrExit(args["api-key"], json);
13207
+ const hasDateRange = !!args["start-date"] || !!args["end-date"];
13208
+ const params = { customer: args.customer };
13209
+ if (hasDateRange) {
13210
+ if (args["start-date"])
13211
+ params.startDate = args["start-date"];
13212
+ if (args["end-date"])
13213
+ params.endDate = args["end-date"];
13214
+ } else {
13215
+ params.timeframe = args.timeframe;
13216
+ }
13217
+ if (args.channels) {
13218
+ params.channels = normalizeTimelineChannels(args.channels);
13219
+ }
13220
+ if (args["event-types"]) {
13221
+ params.eventTypes = splitCsv(args["event-types"]);
13222
+ }
13223
+ applyPagination(params, args, json);
13224
+ return runTool(client, publicToolContracts.outlit_get_timeline.toolName, params, json);
13225
+ }
13226
+ });
13227
+ });
13228
+
13229
+ // src/commands/customers/collaboration-input.ts
13230
+ function parseCustomerCollaborationIds(args, json) {
13231
+ const customerId = requiredString(args["customer-id"], "<customer-id>", json);
13232
+ const customerIdPattern = new RegExp(customerIdSchema.pattern);
13233
+ if (!customerIdPattern.test(customerId)) {
13234
+ return outputError({ message: "<customer-id> must be an exact customer UUID", code: "invalid_input" }, json);
13235
+ }
13236
+ const targetUserId = requiredString(args["target-user-id"], "--target-user-id", json);
13237
+ if (targetUserId.length > targetUserIdSchema.maxLength) {
13238
+ return outputError({
13239
+ message: `--target-user-id must be at most ${targetUserIdSchema.maxLength} characters`,
13240
+ code: "invalid_input"
13241
+ }, json);
13242
+ }
13243
+ return { customerId, targetUserId };
13244
+ }
13245
+ function parseCustomerAccessRole(value, json) {
13246
+ const input = requiredString(value, "--role", json);
13247
+ const role = customerAccessRoles.find((candidate) => candidate === input);
13248
+ if (!role) {
13249
+ return outputError({
13250
+ message: `--role must be one of: ${customerAccessRoles.join(", ")}`,
13251
+ code: "invalid_input"
13252
+ }, json);
13253
+ }
13254
+ return role;
13255
+ }
13256
+ var customerIdSchema, targetUserIdSchema, customerAccessRoles, customerCollaborationIdArgs, customerAccessRoleArg;
13257
+ var init_collaboration_input = __esm(() => {
13258
+ init_dist4();
13259
+ init_output();
13260
+ init_platform_input();
13261
+ customerIdSchema = publicToolContracts.outlit_assign_customer_owner.inputSchema.properties.customerId;
13262
+ targetUserIdSchema = publicToolContracts.outlit_assign_customer_owner.inputSchema.properties.targetUserId;
13263
+ customerAccessRoles = publicToolContracts.outlit_grant_customer_access.inputSchema.properties.role.enum;
13264
+ customerCollaborationIdArgs = {
13265
+ "customer-id": {
13266
+ type: "positional",
13267
+ description: "Exact customer UUID",
13268
+ required: true
13269
+ },
13270
+ "target-user-id": {
13271
+ type: "string",
13272
+ description: "Required exact workspace-user ID from `outlit ws-users list --json`"
13273
+ }
13274
+ };
13275
+ customerAccessRoleArg = {
13276
+ role: {
13277
+ type: "string",
13278
+ description: `Required collaboration role (${customerAccessRoles.join(", ")})`
13279
+ }
13280
+ };
13281
+ });
13282
+
13283
+ // src/commands/customers/owner/set.ts
13284
+ var exports_set = {};
13285
+ __export(exports_set, {
13286
+ default: () => set_default
13287
+ });
13288
+ var set_default;
13289
+ var init_set = __esm(() => {
13290
+ init_dist4();
13291
+ init_dist();
13292
+ init_auth();
13293
+ init_output2();
13294
+ init_api();
13295
+ init_collaboration_input();
13296
+ set_default = defineCommand2({
13297
+ meta: {
13298
+ name: "set",
13299
+ description: [
13300
+ "Assign an active workspace member as a customer's primary owner.",
13301
+ "The former owner keeps Editor access.",
13302
+ "Both IDs must be exact; discover them with customer and workspace-user list commands.",
13303
+ "",
13304
+ "Example:",
13305
+ " outlit customers owner set 10000000-0000-4000-8000-000000000000 --target-user-id user_123 --json",
13306
+ "",
13307
+ AGENT_JSON_HINT
13308
+ ].join(`
13309
+ `)
13310
+ },
13311
+ args: {
13312
+ ...authArgs,
13313
+ ...outputArgs,
13314
+ ...customerCollaborationIdArgs
13315
+ },
13316
+ async run({ args }) {
13317
+ const json = !!args.json;
13318
+ const input = parseCustomerCollaborationIds(args, json);
13319
+ const client = await getClientOrExit(args["api-key"], json);
13320
+ return runTool(client, publicToolContracts.outlit_assign_customer_owner.toolName, input, json, {
13321
+ spinnerMessage: "Assigning customer owner..."
13322
+ });
13323
+ }
13324
+ });
13325
+ });
13326
+
13327
+ // src/commands/customers/owner/index.ts
13328
+ var exports_owner = {};
13329
+ __export(exports_owner, {
13330
+ default: () => owner_default
13331
+ });
13332
+ var owner_default;
13333
+ var init_owner = __esm(() => {
13334
+ init_dist();
13335
+ init_output2();
13336
+ owner_default = defineCommand2({
13337
+ meta: {
13338
+ name: "owner",
13339
+ description: [
13340
+ "Manage a customer's primary owner.",
13341
+ "",
13342
+ "Commands:",
13343
+ " set -- assign or reassign the primary owner",
13344
+ "",
13345
+ AGENT_JSON_HINT
13346
+ ].join(`
13347
+ `)
13348
+ },
13349
+ subCommands: {
13350
+ set: () => Promise.resolve().then(() => (init_set(), exports_set)).then((m) => m.default)
13351
+ }
13352
+ });
13353
+ });
13354
+
13355
+ // src/commands/customers/grant.ts
13356
+ var exports_grant = {};
13357
+ __export(exports_grant, {
13358
+ default: () => grant_default
13359
+ });
13360
+ var grant_default;
13361
+ var init_grant = __esm(() => {
13362
+ init_dist4();
13363
+ init_dist();
13364
+ init_auth();
13365
+ init_output2();
13366
+ init_api();
13367
+ init_collaboration_input();
13368
+ grant_default = defineCommand2({
13369
+ meta: {
13370
+ name: "grant",
13371
+ description: [
13372
+ "Grant or change Viewer or Editor customer access for an active workspace member.",
13373
+ "Re-run this command with a different role to update an existing collaborator.",
13374
+ "Both IDs must be exact; discover them with customer and workspace-user list commands.",
13375
+ "",
13376
+ "Example:",
13377
+ " outlit customers grant 10000000-0000-4000-8000-000000000000 --target-user-id user_123 --role VIEWER --json",
13378
+ "",
13379
+ AGENT_JSON_HINT
13380
+ ].join(`
13381
+ `)
13382
+ },
13383
+ args: {
13384
+ ...authArgs,
13385
+ ...outputArgs,
13386
+ ...customerCollaborationIdArgs,
13387
+ ...customerAccessRoleArg
13388
+ },
13389
+ async run({ args }) {
13390
+ const json = !!args.json;
13391
+ const ids = parseCustomerCollaborationIds(args, json);
13392
+ const role = parseCustomerAccessRole(args.role, json);
13393
+ const client = await getClientOrExit(args["api-key"], json);
13394
+ return runTool(client, publicToolContracts.outlit_grant_customer_access.toolName, { ...ids, role }, json, { spinnerMessage: "Granting customer access..." });
13395
+ }
13396
+ });
13397
+ });
13398
+
13399
+ // src/commands/customers/revoke.ts
13400
+ var exports_revoke = {};
13401
+ __export(exports_revoke, {
13402
+ default: () => revoke_default
13403
+ });
13404
+ var revoke_default;
13405
+ var init_revoke = __esm(() => {
13406
+ init_dist4();
13407
+ init_dist();
13408
+ init_auth();
13409
+ init_output2();
13410
+ init_api();
13411
+ init_collaboration_input();
13412
+ revoke_default = defineCommand2({
13413
+ meta: {
13414
+ name: "revoke",
11428
13415
  description: [
11429
- "Show the activity timeline for a customer.",
11430
- "",
11431
- "The customer argument accepts:",
11432
- " - Customer domain (acme.com)",
11433
- " - Customer ID (UUID)",
11434
- "",
11435
- "Timeframe is used when no explicit date range is set.",
11436
- "When --start-date or --end-date is provided, --timeframe is ignored.",
11437
- `Channels: ${timelineChannels.join(", ")}`,
11438
- `Timeframes: ${timelineTimeframes.join(", ")}`,
13416
+ "Remove a collaborator's explicit access to a customer.",
13417
+ "The primary owner cannot be removed.",
13418
+ "Both IDs must be exact; discover them with customer and workspace-user list commands.",
11439
13419
  "",
11440
- "Examples:",
11441
- " outlit customers timeline acme.com",
11442
- " outlit customers timeline acme.com --timeframe 90d",
11443
- " outlit customers timeline acme.com --channels COMMUNICATION,MEETING",
11444
- " outlit customers timeline acme.com --start-date 2025-01-01T00:00:00Z --end-date 2025-03-01T23:59:59Z",
11445
- " outlit customers timeline acme.com --event-types PAGE_VIEW,MEETING --limit 50",
13420
+ "Example:",
13421
+ " outlit customers revoke 10000000-0000-4000-8000-000000000000 --target-user-id user_123 --json",
11446
13422
  "",
11447
13423
  AGENT_JSON_HINT
11448
13424
  ].join(`
@@ -11451,55 +13427,13 @@ var init_timeline = __esm(() => {
11451
13427
  args: {
11452
13428
  ...authArgs,
11453
13429
  ...outputArgs,
11454
- ...paginationArgs,
11455
- customer: {
11456
- type: "positional",
11457
- description: "Customer ID or domain (acme.com)",
11458
- required: true
11459
- },
11460
- channels: {
11461
- type: "string",
11462
- description: `Comma-separated list of channels to filter (${timelineChannels.join(", ")})`
11463
- },
11464
- "event-types": {
11465
- type: "string",
11466
- description: "Comma-separated list of event types to filter (e.g. PAGE_VIEW,MEETING)"
11467
- },
11468
- timeframe: {
11469
- type: "string",
11470
- description: `Timeframe for events (${timelineTimeframes.join(", ")}). Ignored when --start-date or --end-date is set.`,
11471
- default: "30d"
11472
- },
11473
- "start-date": {
11474
- type: "string",
11475
- description: "Start datetime for the event range (ISO 8601, e.g. 2025-01-01T00:00:00Z). When set, --timeframe is ignored."
11476
- },
11477
- "end-date": {
11478
- type: "string",
11479
- description: "End datetime for the event range (ISO 8601, e.g. 2025-03-01T23:59:59Z). When set, --timeframe is ignored."
11480
- }
13430
+ ...customerCollaborationIdArgs
11481
13431
  },
11482
13432
  async run({ args }) {
11483
13433
  const json = !!args.json;
13434
+ const input = parseCustomerCollaborationIds(args, json);
11484
13435
  const client = await getClientOrExit(args["api-key"], json);
11485
- const hasDateRange = !!args["start-date"] || !!args["end-date"];
11486
- const params = { customer: args.customer };
11487
- if (hasDateRange) {
11488
- if (args["start-date"])
11489
- params.startDate = args["start-date"];
11490
- if (args["end-date"])
11491
- params.endDate = args["end-date"];
11492
- } else {
11493
- params.timeframe = args.timeframe;
11494
- }
11495
- if (args.channels) {
11496
- params.channels = normalizeTimelineChannels(args.channels);
11497
- }
11498
- if (args["event-types"]) {
11499
- params.eventTypes = splitCsv(args["event-types"]);
11500
- }
11501
- applyPagination(params, args, json);
11502
- return runTool(client, publicToolContracts.outlit_get_timeline.toolName, params, json);
13436
+ return runTool(client, publicToolContracts.outlit_revoke_customer_access.toolName, input, json, { spinnerMessage: "Revoking customer access..." });
11503
13437
  }
11504
13438
  });
11505
13439
  });
@@ -11523,6 +13457,9 @@ var init_customers = __esm(() => {
11523
13457
  " list -- list customers with filters",
11524
13458
  " get -- get a specific customer by ID or domain",
11525
13459
  " timeline -- show activity timeline for a customer",
13460
+ " owner set -- assign a primary customer owner",
13461
+ " grant -- grant or change Viewer or Editor access",
13462
+ " revoke -- remove explicit collaborator access",
11526
13463
  "",
11527
13464
  AGENT_JSON_HINT
11528
13465
  ].join(`
@@ -11531,7 +13468,10 @@ var init_customers = __esm(() => {
11531
13468
  subCommands: {
11532
13469
  list: () => Promise.resolve().then(() => (init_list(), exports_list)).then((m) => m.default),
11533
13470
  get: () => Promise.resolve().then(() => (init_get2(), exports_get2)).then((m) => m.default),
11534
- timeline: () => Promise.resolve().then(() => (init_timeline(), exports_timeline)).then((m) => m.default)
13471
+ timeline: () => Promise.resolve().then(() => (init_timeline(), exports_timeline)).then((m) => m.default),
13472
+ owner: () => Promise.resolve().then(() => (init_owner(), exports_owner)).then((m) => m.default),
13473
+ grant: () => Promise.resolve().then(() => (init_grant(), exports_grant)).then((m) => m.default),
13474
+ revoke: () => Promise.resolve().then(() => (init_revoke(), exports_revoke)).then((m) => m.default)
11535
13475
  }
11536
13476
  });
11537
13477
  });
@@ -11696,9 +13636,10 @@ var init_list3 = __esm(() => {
11696
13636
  meta: {
11697
13637
  name: "list",
11698
13638
  description: [
11699
- "List and filter internal workspace users.",
13639
+ "List all active workspace members with local Outlit user records.",
11700
13640
  "",
11701
- "Use this to discover CSMs, managers, and account owners before composing dynamic customer reports.",
13641
+ "By default, customer ownership does not limit results; --has-owned-customers is the only customer-related filter.",
13642
+ "Use JSON output to copy exact user IDs for customer ownership and access commands.",
11702
13643
  "Output is JSON when piped or when --json is passed.",
11703
13644
  "",
11704
13645
  "Examples:",
@@ -11729,7 +13670,7 @@ var init_list3 = __esm(() => {
11729
13670
  },
11730
13671
  "has-owned-customers": {
11731
13672
  type: "boolean",
11732
- description: "Return only workspace users who own at least one customer"
13673
+ description: "Return only members who own customers; omit for all eligible members"
11733
13674
  }
11734
13675
  },
11735
13676
  async run({ args }) {
@@ -11999,14 +13940,14 @@ async function checkIntegrationReadiness(apiKey, checks) {
11999
13940
  status: "pass",
12000
13941
  message: `${providers.length} provider setup capabilities available`
12001
13942
  });
12002
- const integrations = await client.callTool("outlit_list_integrations", {});
13943
+ const integrations = await client.callTool("outlit_get_integration_status", {});
12003
13944
  const items = Array.isArray(integrations.integrations) ? integrations.integrations : [];
12004
- summary.connectedCount = items.filter((item) => item.status === "connected").length;
12005
- summary.errorCount = items.filter((item) => item.status === "error").length;
13945
+ summary.connectedCount = items.filter((item) => item.status === "ready").length;
13946
+ summary.errorCount = items.filter((item) => item.status === "requires_intervention").length;
12006
13947
  checks.push({
12007
13948
  name: "Integrations",
12008
13949
  status: summary.errorCount > 0 ? "warn" : "pass",
12009
- message: summary.errorCount > 0 ? `${summary.connectedCount} connected, ${summary.errorCount} with errors` : `${summary.connectedCount} connected`
13950
+ message: summary.errorCount > 0 ? `${summary.connectedCount} ready, ${summary.errorCount} requiring intervention` : `${summary.connectedCount} ready`
12010
13951
  });
12011
13952
  } catch (err) {
12012
13953
  checks.push({
@@ -12020,7 +13961,6 @@ async function checkIntegrationReadiness(apiKey, checks) {
12020
13961
  function buildNextActions() {
12021
13962
  return [
12022
13963
  "outlit doctor --json",
12023
- "outlit integrations capabilities --json",
12024
13964
  "outlit integrations setup <provider> --json",
12025
13965
  "outlit integrations status --json"
12026
13966
  ];
@@ -12058,7 +13998,7 @@ var init_onboard = __esm(() => {
12058
13998
  "Examples:",
12059
13999
  " outlit onboard --agent codex --json",
12060
14000
  " outlit auth login --browser --json",
12061
- " outlit integrations capabilities --json",
14001
+ " outlit integrations setup <provider> --json",
12062
14002
  "",
12063
14003
  AGENT_JSON_HINT
12064
14004
  ].join(`
@@ -12677,39 +14617,39 @@ async function checkIntegrations(apiKey) {
12677
14617
  const client = await createClient(apiKey);
12678
14618
  const timeout = new Promise((_2, reject) => setTimeout(() => reject(new Error("Integrations check timed out")), 1e4));
12679
14619
  const data = await Promise.race([
12680
- client.callTool("outlit_list_integrations", {}),
14620
+ client.callTool("outlit_get_integration_status", {}),
12681
14621
  timeout
12682
14622
  ]);
12683
- const items = data.items ?? [];
12684
- const connected = items.filter((i) => i.status === "connected").length;
12685
- const errors = items.filter((i) => i.status === "error").length;
12686
- if (errors > 0) {
14623
+ const items = data.integrations ?? [];
14624
+ const ready = items.filter((item) => item.status === "ready").length;
14625
+ const requiringIntervention = items.filter((item) => item.status === "requires_intervention").length;
14626
+ if (requiringIntervention > 0) {
12687
14627
  return {
12688
14628
  name: "Integrations",
12689
14629
  status: "warn",
12690
- message: `${connected} connected, ${errors} with errors`,
14630
+ message: `${ready} ready, ${requiringIntervention} requiring intervention`,
12691
14631
  detail: "Run `outlit integrations status` for details"
12692
14632
  };
12693
14633
  }
12694
- if (connected === 0) {
14634
+ if (ready === 0) {
12695
14635
  return {
12696
14636
  name: "Integrations",
12697
14637
  status: "pass",
12698
- message: "No integrations connected",
12699
- detail: "Run `outlit integrations list` to see available integrations"
14638
+ message: "No integrations ready",
14639
+ detail: "Run `outlit integrations status` to inspect integrations"
12700
14640
  };
12701
14641
  }
12702
14642
  return {
12703
14643
  name: "Integrations",
12704
14644
  status: "pass",
12705
- message: `${connected} integration(s) connected`
14645
+ message: `${ready} integration(s) ready`
12706
14646
  };
12707
14647
  } catch {
12708
14648
  return {
12709
14649
  name: "Integrations",
12710
14650
  status: "warn",
12711
14651
  message: "Could not check integrations",
12712
- detail: "Integration status endpoint may not be available yet"
14652
+ detail: "Integration readiness may not be available yet"
12713
14653
  };
12714
14654
  }
12715
14655
  }
@@ -13308,7 +15248,7 @@ var init_list5 = __esm(() => {
13308
15248
  description: [
13309
15249
  "List concrete source records deterministically.",
13310
15250
  "",
13311
- "Use this when you need enumerated calls, emails, calendar events, support tickets, or opportunities rather than semantic ranking.",
15251
+ "Use this when you need enumerated calls, emails, calendar events, support tickets, opportunities, or Slack conversations rather than semantic ranking.",
13312
15252
  "",
13313
15253
  "Examples:",
13314
15254
  " outlit sources list --customer acme.com --source-type CALL",
@@ -14192,6 +16132,202 @@ var init_destinations = __esm(() => {
14192
16132
  });
14193
16133
  });
14194
16134
 
16135
+ // src/commands/metrics/sources.ts
16136
+ var exports_sources2 = {};
16137
+ __export(exports_sources2, {
16138
+ default: () => sources_default2
16139
+ });
16140
+ var sources_default2;
16141
+ var init_sources2 = __esm(() => {
16142
+ init_dist();
16143
+ init_auth();
16144
+ init_output2();
16145
+ init_api();
16146
+ sources_default2 = defineCommand2({
16147
+ meta: {
16148
+ name: "sources",
16149
+ description: [
16150
+ "List product-event sources eligible for Behavior Metrics.",
16151
+ "",
16152
+ "Use the returned source key with `outlit metrics events --source <source-key>`.",
16153
+ "",
16154
+ AGENT_JSON_HINT
16155
+ ].join(`
16156
+ `)
16157
+ },
16158
+ args: { ...authArgs, ...outputArgs },
16159
+ async run({ args }) {
16160
+ const json = !!args.json;
16161
+ const client = await getClientOrExit(args["api-key"], json);
16162
+ return runTool(client, "outlit_list_behavior_metric_sources", {}, json, {
16163
+ spinnerMessage: "Loading Behavior Metric sources..."
16164
+ });
16165
+ }
16166
+ });
16167
+ });
16168
+
16169
+ // src/commands/metrics/events.ts
16170
+ var exports_events = {};
16171
+ __export(exports_events, {
16172
+ default: () => events_default
16173
+ });
16174
+ function parseBoundedInteger2(value, fallback, flag, min, max, json) {
16175
+ const parsed = parseIntegerFlag(value, fallback, flag, json);
16176
+ if (parsed < min || parsed > max) {
16177
+ return outputError({ message: `${flag} must be an integer from ${min} to ${max}`, code: "invalid_input" }, json);
16178
+ }
16179
+ return parsed;
16180
+ }
16181
+ var events_default;
16182
+ var init_events = __esm(() => {
16183
+ init_dist();
16184
+ init_auth();
16185
+ init_output2();
16186
+ init_api();
16187
+ init_output();
16188
+ init_platform_input();
16189
+ events_default = defineCommand2({
16190
+ meta: {
16191
+ name: "events",
16192
+ description: [
16193
+ "List attributed event candidates for a Behavior Metric source.",
16194
+ "",
16195
+ "Examples:",
16196
+ " outlit metrics events --source metric_source_v1_0123456789abcdef0123456789abcdef --json",
16197
+ " outlit metrics events --source metric_source_v1_0123456789abcdef0123456789abcdef --weeks 4 --limit 20 --json",
16198
+ "",
16199
+ AGENT_JSON_HINT
16200
+ ].join(`
16201
+ `)
16202
+ },
16203
+ args: {
16204
+ ...authArgs,
16205
+ ...outputArgs,
16206
+ source: { type: "string", description: "Behavior Metric source key" },
16207
+ weeks: { type: "string", description: "History window in weeks (1-53, default: 12)" },
16208
+ limit: { type: "string", description: "Maximum event candidates (1-100, default: 100)" }
16209
+ },
16210
+ async run({ args }) {
16211
+ const json = !!args.json;
16212
+ const client = await getClientOrExit(args["api-key"], json);
16213
+ return runTool(client, "outlit_list_behavior_metric_events", {
16214
+ sourceKey: requiredTrimmedString(args.source, "--source", json),
16215
+ weeks: parseBoundedInteger2(args.weeks, 12, "--weeks", 1, 53, json),
16216
+ limit: parseBoundedInteger2(args.limit, 100, "--limit", 1, 100, json)
16217
+ }, json, { spinnerMessage: "Loading Behavior Metric events..." });
16218
+ }
16219
+ });
16220
+ });
16221
+
16222
+ // src/commands/metrics/create.ts
16223
+ var exports_create2 = {};
16224
+ __export(exports_create2, {
16225
+ default: () => create_default2
16226
+ });
16227
+ function parsePropertyFilters(value, json) {
16228
+ if (!value?.trim())
16229
+ return [];
16230
+ try {
16231
+ const parsed = JSON.parse(value);
16232
+ if (!Array.isArray(parsed)) {
16233
+ return outputError({ message: "--property-filters must be a JSON array", code: "invalid_input" }, json);
16234
+ }
16235
+ return parsed;
16236
+ } catch (error) {
16237
+ return outputError({
16238
+ message: `Invalid --property-filters JSON: ${errorMessage(error, "parse failed")}`,
16239
+ code: "invalid_input"
16240
+ }, json);
16241
+ }
16242
+ }
16243
+ var create_default2;
16244
+ var init_create2 = __esm(() => {
16245
+ init_dist();
16246
+ init_auth();
16247
+ init_output2();
16248
+ init_api();
16249
+ init_output();
16250
+ init_platform_input();
16251
+ create_default2 = defineCommand2({
16252
+ meta: {
16253
+ name: "create",
16254
+ description: [
16255
+ "Create an event-based Outlit Behavior Metric.",
16256
+ "",
16257
+ "Examples:",
16258
+ " outlit metrics create --source metric_source_v1_0123456789abcdef0123456789abcdef --event report_exported --key reports_exported --label 'Reports exported' --json",
16259
+ ` outlit metrics create --source metric_source_v1_0123456789abcdef0123456789abcdef --event report_exported --key production_reports_exported --label 'Production reports exported' --property-filters '[{"property":"environment","operator":"equals","value":{"type":"string","value":"production"}}]' --json`,
16260
+ "",
16261
+ AGENT_JSON_HINT
16262
+ ].join(`
16263
+ `)
16264
+ },
16265
+ args: {
16266
+ ...authArgs,
16267
+ ...outputArgs,
16268
+ source: { type: "string", description: "Behavior Metric source key" },
16269
+ event: { type: "string", description: "Exact tracked event name" },
16270
+ key: { type: "string", description: "Stable lower_snake_case metric key" },
16271
+ label: { type: "string", description: "Human-readable metric label" },
16272
+ "property-filters": {
16273
+ type: "string",
16274
+ description: "Optional JSON array of event property filters"
16275
+ }
16276
+ },
16277
+ async run({ args }) {
16278
+ const json = !!args.json;
16279
+ const client = await getClientOrExit(args["api-key"], json);
16280
+ const input = {
16281
+ sourceKey: requiredTrimmedString(args.source, "--source", json),
16282
+ eventName: requiredString(args.event, "--event", json),
16283
+ behaviorKey: requiredTrimmedString(args.key, "--key", json),
16284
+ label: requiredTrimmedString(args.label, "--label", json),
16285
+ propertyFilters: parsePropertyFilters(args["property-filters"], json)
16286
+ };
16287
+ return runTool(client, "outlit_create_behavior_metric", input, json, {
16288
+ spinnerMessage: "Creating Behavior Metric..."
16289
+ });
16290
+ }
16291
+ });
16292
+ });
16293
+
16294
+ // src/commands/metrics/index.ts
16295
+ var exports_metrics = {};
16296
+ __export(exports_metrics, {
16297
+ default: () => metrics_default
16298
+ });
16299
+ var metrics_default;
16300
+ var init_metrics = __esm(() => {
16301
+ init_dist();
16302
+ init_output2();
16303
+ metrics_default = defineCommand2({
16304
+ meta: {
16305
+ name: "metrics",
16306
+ description: [
16307
+ "Configure event-based Outlit Behavior Metrics.",
16308
+ "",
16309
+ "Commands:",
16310
+ " sources List eligible event sources",
16311
+ " events List event candidates for a source",
16312
+ " create Create a Behavior Metric",
16313
+ "",
16314
+ "Examples:",
16315
+ " outlit metrics sources --json",
16316
+ " outlit metrics events --source metric_source_v1_0123456789abcdef0123456789abcdef --json",
16317
+ " outlit metrics create --source metric_source_v1_0123456789abcdef0123456789abcdef --event report_exported --key reports_exported --label 'Reports exported' --json",
16318
+ "",
16319
+ AGENT_JSON_HINT
16320
+ ].join(`
16321
+ `)
16322
+ },
16323
+ subCommands: {
16324
+ sources: () => Promise.resolve().then(() => (init_sources2(), exports_sources2)).then((module) => module.default),
16325
+ events: () => Promise.resolve().then(() => (init_events(), exports_events)).then((module) => module.default),
16326
+ create: () => Promise.resolve().then(() => (init_create2(), exports_create2)).then((module) => module.default)
16327
+ }
16328
+ });
16329
+ });
16330
+
14195
16331
  // src/commands/settings/get.ts
14196
16332
  var exports_get6 = {};
14197
16333
  __export(exports_get6, {
@@ -14309,183 +16445,564 @@ var init_settings = __esm(() => {
14309
16445
  });
14310
16446
  });
14311
16447
 
14312
- // src/commands/integrations/list.ts
14313
- var exports_list7 = {};
14314
- __export(exports_list7, {
14315
- default: () => list_default7
14316
- });
14317
- var list_default7;
14318
- var init_list7 = __esm(() => {
14319
- init_dist();
14320
- init_auth();
14321
- init_output2();
14322
- init_api();
14323
- list_default7 = defineCommand2({
14324
- meta: {
14325
- name: "list",
14326
- description: [
14327
- "List available integrations and their connection status.",
14328
- "",
14329
- "Shows all supported third-party integrations with whether they",
14330
- "are connected, available, or in an error state.",
14331
- "",
14332
- "Examples:",
14333
- " outlit integrations list",
14334
- " outlit integrations list --json",
14335
- "",
14336
- AGENT_JSON_HINT
14337
- ].join(`
14338
- `)
14339
- },
14340
- args: {
14341
- ...authArgs,
14342
- ...outputArgs
14343
- },
14344
- async run({ args }) {
14345
- const json = !!args.json;
14346
- const client = await getClientOrExit(args["api-key"], json);
14347
- return runTool(client, "outlit_list_integrations", {}, json, {
14348
- spinnerMessage: "Fetching integrations...",
14349
- table: {
14350
- itemsKey: "integrations",
14351
- columns: [
14352
- { header: "Name", key: "name", format: (v) => truncate(v, 24) },
14353
- { header: "Category", key: "category", format: capitalize },
14354
- { header: "Status", key: "status" },
14355
- { header: "Last Synced", key: "lastDataReceivedAt", format: relativeDate }
14356
- ]
14357
- }
14358
- });
14359
- }
14360
- });
14361
- });
14362
-
14363
16448
  // src/lib/providers.ts
14364
16449
  function normalizeProviderInput(input) {
14365
- return input.trim().toLowerCase().replace(/[\s_]+/g, "-");
16450
+ const normalized = input.trim().toLowerCase().replace(/[\s_]+/g, "-");
16451
+ return normalized === "gmail" ? "google-mail" : normalized;
14366
16452
  }
14367
16453
 
14368
- // src/commands/integrations/capabilities.ts
14369
- var exports_capabilities = {};
14370
- __export(exports_capabilities, {
14371
- default: () => capabilities_default
14372
- });
14373
- var capabilities_default;
14374
- var init_capabilities = __esm(() => {
14375
- init_dist();
14376
- init_auth();
14377
- init_output2();
14378
- init_api();
14379
- capabilities_default = defineCommand2({
14380
- meta: {
14381
- name: "capabilities",
14382
- description: [
14383
- "Show machine-readable integration setup capabilities.",
14384
- "",
14385
- "Use this before setup to learn whether a safe browser handoff is available",
14386
- "or configuration must continue in the Outlit web app.",
14387
- "",
14388
- "Examples:",
14389
- " outlit integrations capabilities --json",
14390
- " outlit integrations capabilities hubspot --json",
14391
- "",
14392
- AGENT_JSON_HINT
14393
- ].join(`
14394
- `)
14395
- },
14396
- args: {
14397
- ...authArgs,
14398
- ...outputArgs,
14399
- provider: {
14400
- type: "positional",
14401
- description: "Provider name to inspect (optional)",
14402
- required: false
14403
- }
14404
- },
14405
- async run({ args }) {
14406
- const json = !!args.json;
14407
- const client = await getClientOrExit(args["api-key"], json);
14408
- if (args.provider) {
14409
- return runTool(client, "outlit_get_integration_capabilities", { provider: normalizeProviderInput(args.provider) }, json, {
14410
- spinnerMessage: "Fetching integration capabilities..."
14411
- });
16454
+ // src/commands/integrations/setup-input.ts
16455
+ async function readSetupConfigText() {
16456
+ return Bun.stdin.text();
16457
+ }
16458
+ function parseSetupConfig(text, provider) {
16459
+ let parsed;
16460
+ try {
16461
+ parsed = JSON.parse(text);
16462
+ } catch {
16463
+ throw new SetupInputError("--config-stdin requires exactly one valid JSON document.");
16464
+ }
16465
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
16466
+ throw new SetupInputError("--config-stdin must contain a JSON object.");
16467
+ }
16468
+ const config = parsed;
16469
+ const allowedKeys = new Set(["connectionMode", "credentials", "configuration"]);
16470
+ if (Object.keys(config).some((key) => !allowedKeys.has(key))) {
16471
+ throw new SetupInputError("--config-stdin accepts only connectionMode, credentials, and configuration.");
16472
+ }
16473
+ const input = { provider, ...config };
16474
+ const schema = publicToolContracts.outlit_setup_integration.inputSchema;
16475
+ if (!matchesGeneratedJsonSchema(input, schema)) {
16476
+ throw new SetupInputError("--config-stdin does not match this provider's setup contract.");
16477
+ }
16478
+ return input;
16479
+ }
16480
+ function hasCrmConfiguration(input) {
16481
+ const configuration = input.configuration;
16482
+ return typeof configuration === "object" && configuration !== null && !Array.isArray(configuration) && configuration.kind === "crm_mapping";
16483
+ }
16484
+ async function collectProviderCredentials(provider) {
16485
+ switch (provider) {
16486
+ case "stripe":
16487
+ return {
16488
+ provider,
16489
+ connectionMode: "restricted_key",
16490
+ credentials: { apiKey: await secret("Stripe restricted API key") }
16491
+ };
16492
+ case "granola": {
16493
+ const authScope = await choice("Granola key scope", [
16494
+ { value: "personal", label: "Personal" },
16495
+ { value: "enterprise", label: "Enterprise" }
16496
+ ]);
16497
+ const enterpriseKeyAcknowledged = authScope === "enterprise" ? await confirmation("I confirm this is an enterprise Granola key") : false;
16498
+ if (authScope === "enterprise" && !enterpriseKeyAcknowledged) {
16499
+ throw new SetupCancelledError;
14412
16500
  }
14413
- return runTool(client, "outlit_get_integration_capabilities", {}, json, {
14414
- spinnerMessage: "Fetching integration capabilities..."
14415
- });
16501
+ return {
16502
+ provider,
16503
+ credentials: {
16504
+ apiKey: await secret("Granola API key"),
16505
+ authScope,
16506
+ enterpriseKeyAcknowledged
16507
+ }
16508
+ };
14416
16509
  }
16510
+ case "fireflies":
16511
+ return { provider, credentials: { apiKey: await secret("Fireflies API key") } };
16512
+ case "pylon":
16513
+ return { provider, credentials: { apiToken: await secret("Pylon API token") } };
16514
+ case "mixpanel":
16515
+ return {
16516
+ provider,
16517
+ credentials: {
16518
+ username: await visible("Mixpanel service-account username"),
16519
+ secret: await secret("Mixpanel service-account secret"),
16520
+ projectId: await visible("Mixpanel project ID"),
16521
+ region: await choice("Mixpanel region", [
16522
+ { value: "us", label: "US" },
16523
+ { value: "eu", label: "EU" },
16524
+ { value: "in", label: "India" }
16525
+ ])
16526
+ }
16527
+ };
16528
+ case "posthog":
16529
+ return {
16530
+ provider,
16531
+ credentials: {
16532
+ apiKey: await secret("PostHog personal API key"),
16533
+ projectId: await visible("PostHog project ID"),
16534
+ region: await choice("PostHog region", [
16535
+ { value: "us", label: "US" },
16536
+ { value: "eu", label: "EU" }
16537
+ ])
16538
+ }
16539
+ };
16540
+ default:
16541
+ throw new SetupInputError("Core requested credentials for a provider without a CLI credential contract.", "INVALID_SETUP_RESPONSE");
16542
+ }
16543
+ }
16544
+ async function confirmCrmRecommendation() {
16545
+ return confirmation("Apply this exact CRM stage mapping?");
16546
+ }
16547
+ async function collectMixpanelMapping(candidateKeys) {
16548
+ const mode = await choice("How should Mixpanel events map to Outlit customers?", [
16549
+ { value: "group_key", label: "Mixpanel group key" },
16550
+ { value: "event_property", label: "Event property" },
16551
+ { value: "email_domain", label: "Email domain" }
16552
+ ]);
16553
+ if (mode === "email_domain")
16554
+ return { mode };
16555
+ if (mode === "event_property") {
16556
+ return { mode, propertyName: await visible("Mixpanel event property") };
16557
+ }
16558
+ const groupKey = candidateKeys.length > 0 ? await choice("Mixpanel group key", candidateKeys.map(({ key }) => ({ value: key, label: key }))) : await visible("Mixpanel group key");
16559
+ return { mode, groupKey };
16560
+ }
16561
+ async function secret(message) {
16562
+ const value = await He({
16563
+ message,
16564
+ validate: (input) => input?.trim() ? undefined : "A value is required"
14417
16565
  });
16566
+ if (Ct(value))
16567
+ throw new SetupCancelledError;
16568
+ return String(value).trim();
16569
+ }
16570
+ async function visible(message) {
16571
+ const value = await Ze({
16572
+ message,
16573
+ validate: (input) => input?.trim() ? undefined : "A value is required"
16574
+ });
16575
+ if (Ct(value))
16576
+ throw new SetupCancelledError;
16577
+ return String(value).trim();
16578
+ }
16579
+ async function choice(message, options) {
16580
+ const value = await Je({ message, options });
16581
+ if (Ct(value))
16582
+ throw new SetupCancelledError;
16583
+ return value;
16584
+ }
16585
+ async function confirmation(message) {
16586
+ const value = await Re({ message });
16587
+ if (Ct(value))
16588
+ throw new SetupCancelledError;
16589
+ return value;
16590
+ }
16591
+ var SetupInputError, SetupCancelledError;
16592
+ var init_setup_input = __esm(() => {
16593
+ init_dist3();
16594
+ init_dist4();
16595
+ SetupInputError = class SetupInputError extends Error {
16596
+ code;
16597
+ constructor(message, code = "invalid_input") {
16598
+ super(message);
16599
+ this.name = "SetupInputError";
16600
+ this.code = code;
16601
+ }
16602
+ };
16603
+ SetupCancelledError = class SetupCancelledError extends Error {
16604
+ constructor() {
16605
+ super("Integration setup was cancelled.");
16606
+ this.name = "SetupCancelledError";
16607
+ }
16608
+ };
14418
16609
  });
14419
16610
 
14420
16611
  // src/commands/integrations/wait-for-connection.ts
14421
16612
  async function waitForIntegrationConnection({
14422
16613
  client,
14423
16614
  sessionId,
14424
- displayName,
14425
- cliName,
14426
- retryCommand
16615
+ displayName
14427
16616
  }) {
14428
16617
  const spinner = createSpinner(`Waiting for ${displayName} authentication...`);
14429
- const result = await pollUntil(() => client.callTool("outlit_get_integration_setup_status", { sessionId }).then((r) => r), (r) => terminalConnectStatuses.has(r.status ?? ""), {
16618
+ const result = await pollUntil((signal) => client.callTool("outlit_get_integration_setup_status", { sessionId }, { signal }).then((response) => response), (response) => response.status !== "pending", {
14430
16619
  intervalMs: 2000,
14431
16620
  timeoutMs: 300000,
14432
16621
  spinner,
14433
- spinnerMessage: `Waiting for ${displayName} authentication...`
16622
+ spinnerMessage: `Waiting for ${displayName} authentication...`,
16623
+ shouldRetry(error) {
16624
+ if (!isOutlitToolsApiError(error))
16625
+ return true;
16626
+ if (error.envelope)
16627
+ return error.envelope.retryable;
16628
+ return error.status === 408 || error.status === 429 || error.status >= 500;
16629
+ }
14434
16630
  });
14435
- if (!result || result.status === "expired") {
16631
+ if (!result) {
14436
16632
  spinner.fail("Connection timed out");
14437
- console.log(`
14438
- The authentication session expired.`);
14439
- console.log(` Run \`${retryCommand}\` to try again.`);
14440
- process.exit(1);
16633
+ throw new IntegrationAuthTimeoutError;
14441
16634
  }
14442
- if (result.status === "failed") {
14443
- spinner.fail(`${displayName} connection failed`);
14444
- if (result.error)
14445
- console.log(`
14446
- ${result.error}`);
14447
- process.exit(1);
16635
+ if (result.status === "expired" || result.status === "failed") {
16636
+ spinner.fail(`${displayName} authentication ${result.status}`);
16637
+ throw new IntegrationAuthError(result.status);
14448
16638
  }
14449
16639
  if (result.status !== "connected") {
14450
- spinner.fail(`${displayName} connection returned an invalid status`);
14451
- if (result.status)
14452
- console.log(`
14453
- Unexpected status: ${result.status}`);
14454
- process.exit(1);
16640
+ spinner.fail("Connection timed out");
16641
+ throw new IntegrationAuthTimeoutError;
14455
16642
  }
14456
- spinner.stop(`${displayName} connected successfully!`);
14457
- console.log(` Sync will begin automatically.`);
14458
- console.log(` Use \`outlit integrations status ${cliName}\` to check progress.`);
16643
+ spinner.stop(`${displayName} authentication completed`);
14459
16644
  }
14460
- var terminalConnectStatuses;
16645
+ var IntegrationAuthTimeoutError, IntegrationAuthError;
14461
16646
  var init_wait_for_connection = __esm(() => {
16647
+ init_dist4();
14462
16648
  init_spinner();
14463
- terminalConnectStatuses = new Set(["connected", "failed", "expired"]);
16649
+ IntegrationAuthTimeoutError = class IntegrationAuthTimeoutError extends Error {
16650
+ constructor() {
16651
+ super("Integration authentication timed out after 5 minutes.");
16652
+ this.name = "IntegrationAuthTimeoutError";
16653
+ }
16654
+ };
16655
+ IntegrationAuthError = class IntegrationAuthError extends Error {
16656
+ status;
16657
+ constructor(status) {
16658
+ super(`Integration authentication ${status}.`);
16659
+ this.name = "IntegrationAuthError";
16660
+ this.status = status;
16661
+ }
16662
+ };
14464
16663
  });
14465
16664
 
14466
16665
  // src/commands/integrations/setup.ts
14467
16666
  var exports_setup = {};
14468
16667
  __export(exports_setup, {
16668
+ validateHandoffUrl: () => validateHandoffUrl,
14469
16669
  default: () => setup_default2
14470
16670
  });
16671
+ async function runPreferredSetup(options) {
16672
+ const { client, json, machineMode, acceptRecommended, suppliedConfig } = options;
16673
+ const provider = options.input.provider;
16674
+ let input = options.input;
16675
+ let setupCalls = 0;
16676
+ let continuationUsed = false;
16677
+ let mappingUsed = false;
16678
+ const transitions = new Set;
16679
+ while (setupCalls < 3) {
16680
+ let response;
16681
+ try {
16682
+ const raw = await client.callTool("outlit_setup_integration", input);
16683
+ setupCalls += 1;
16684
+ if (!matchesGeneratedJsonSchema(raw, setupOutputSchema)) {
16685
+ return invalidSetupResponse(json);
16686
+ }
16687
+ response = raw;
16688
+ } catch (error) {
16689
+ return outputApiError(error, json, {
16690
+ message: "Integration setup request failed.",
16691
+ code: "api_error"
16692
+ });
16693
+ }
16694
+ if (response.error) {
16695
+ if (response.error.code !== "CREDENTIAL_REQUIRED") {
16696
+ return outputError({ message: response.error.message, code: response.error.code }, json);
16697
+ }
16698
+ if (continuationUsed || transitions.has("credential"))
16699
+ return stalled(json);
16700
+ if (machineMode || suppliedConfig) {
16701
+ return outputError({ message: response.error.message, code: response.error.code }, json);
16702
+ }
16703
+ transitions.add("credential");
16704
+ continuationUsed = true;
16705
+ try {
16706
+ input = await collectProviderCredentials(provider);
16707
+ } catch (error) {
16708
+ if (error instanceof SetupCancelledError || error instanceof SetupInputError) {
16709
+ return outputError({
16710
+ message: error.message,
16711
+ code: error instanceof SetupInputError ? error.code : "SETUP_CANCELLED"
16712
+ }, json);
16713
+ }
16714
+ return outputError({ message: "Could not collect provider credentials.", code: "SETUP_CANCELLED" }, json);
16715
+ }
16716
+ continue;
16717
+ }
16718
+ if (!response.next) {
16719
+ if (response.status === "ready")
16720
+ return finishSetup(response, machineMode);
16721
+ return outputError({
16722
+ message: "Integration setup requires attention before it can continue.",
16723
+ code: "SETUP_INCOMPLETE"
16724
+ }, json);
16725
+ }
16726
+ if (response.next.kind === "browser_handoff") {
16727
+ let handoffUrl;
16728
+ try {
16729
+ handoffUrl = validateHandoffUrl(response.next.url, client.baseUrl);
16730
+ } catch {
16731
+ return invalidSetupResponse(json);
16732
+ }
16733
+ if (machineMode)
16734
+ return finishSetup(response, true);
16735
+ const opened = openBrowser(handoffUrl);
16736
+ if (!opened)
16737
+ console.log(`Open this URL to continue: ${handoffUrl}`);
16738
+ if (response.next.purpose !== "authentication" || response.next.sessionId === null) {
16739
+ return finishSetup(response, false);
16740
+ }
16741
+ if (continuationUsed || transitions.has("authentication"))
16742
+ return stalled(json);
16743
+ transitions.add("authentication");
16744
+ continuationUsed = true;
16745
+ try {
16746
+ await waitForIntegrationConnection({
16747
+ client,
16748
+ sessionId: response.next.sessionId,
16749
+ displayName: response.name
16750
+ });
16751
+ } catch (error) {
16752
+ if (error instanceof IntegrationAuthTimeoutError) {
16753
+ return outputError({
16754
+ message: "Integration authentication timed out after 5 minutes.",
16755
+ code: "AUTH_TIMEOUT"
16756
+ }, json);
16757
+ }
16758
+ if (error instanceof IntegrationAuthError) {
16759
+ return outputError({ message: "Integration authentication failed.", code: "AUTH_FAILED" }, json);
16760
+ }
16761
+ return outputApiError(error, json, {
16762
+ message: "Integration authentication failed.",
16763
+ code: "AUTH_FAILED"
16764
+ });
16765
+ }
16766
+ input = authenticationContinuationInput(input);
16767
+ continue;
16768
+ }
16769
+ if (response.next.kind === "crm_mapping") {
16770
+ printRecommendation(response.next.recommendation, machineMode);
16771
+ if (mappingUsed || transitions.has("crm_mapping"))
16772
+ return stalled(json);
16773
+ let shouldApply = acceptRecommended;
16774
+ if (!acceptRecommended && !machineMode) {
16775
+ try {
16776
+ shouldApply = await confirmCrmRecommendation();
16777
+ } catch (error) {
16778
+ if (error instanceof SetupCancelledError) {
16779
+ return outputError({ message: error.message, code: "SETUP_CANCELLED" }, json);
16780
+ }
16781
+ return outputError({ message: "Could not confirm the CRM mapping.", code: "SETUP_CANCELLED" }, json);
16782
+ }
16783
+ }
16784
+ if (!shouldApply)
16785
+ return finishSetup(response, machineMode);
16786
+ mappingUsed = true;
16787
+ transitions.add("crm_mapping");
16788
+ input = {
16789
+ provider,
16790
+ configuration: {
16791
+ kind: "crm_mapping",
16792
+ mappings: response.next.recommendation,
16793
+ confirm: true
16794
+ }
16795
+ };
16796
+ continue;
16797
+ }
16798
+ if (response.next.kind === "mixpanel_mapping") {
16799
+ if (mappingUsed || transitions.has("mixpanel_mapping"))
16800
+ return stalled(json);
16801
+ printMixpanelPreview(response.next.preview, machineMode);
16802
+ if (machineMode || suppliedConfig)
16803
+ return finishSetup(response, machineMode);
16804
+ let mapping;
16805
+ try {
16806
+ mapping = await collectMixpanelMapping(response.next.preview.candidateAccountKeys ?? []);
16807
+ } catch (error) {
16808
+ if (error instanceof SetupCancelledError) {
16809
+ return outputError({ message: error.message, code: "SETUP_CANCELLED" }, json);
16810
+ }
16811
+ return outputError({ message: "Could not collect the Mixpanel mapping.", code: "SETUP_CANCELLED" }, json);
16812
+ }
16813
+ mappingUsed = true;
16814
+ transitions.add("mixpanel_mapping");
16815
+ input = {
16816
+ provider,
16817
+ configuration: { kind: "mixpanel_mapping", mapping, confirm: true }
16818
+ };
16819
+ continue;
16820
+ }
16821
+ return invalidSetupResponse(json);
16822
+ }
16823
+ return stalled(json);
16824
+ }
16825
+ async function runLegacySetup(client, capability, json, machineMode) {
16826
+ if (!capability.browserHandoffAvailable || capability.setupMode === "human_controlled") {
16827
+ const controlPlaneUrl = validateHandoffUrl("/integrations", client.baseUrl);
16828
+ return outputResult({
16829
+ status: "human_controlled",
16830
+ provider: capability.provider,
16831
+ controlPlaneUrl,
16832
+ capabilities: capability
16833
+ });
16834
+ }
16835
+ const spinner = machineMode ? null : createSpinner(`Starting ${capability.name} setup...`);
16836
+ let setup;
16837
+ try {
16838
+ setup = await client.callTool("outlit_begin_integration_setup", {
16839
+ provider: capability.provider
16840
+ });
16841
+ } catch (error) {
16842
+ spinner?.fail(`Failed to start ${capability.name} setup`);
16843
+ return outputApiError(error, json, {
16844
+ message: "Failed to start setup flow.",
16845
+ code: "api_error"
16846
+ });
16847
+ }
16848
+ if (setup.state === "already_connected") {
16849
+ spinner?.stop(`${capability.name} is already connected`);
16850
+ return outputResult({ status: "already_connected", ...setup, capabilities: capability });
16851
+ }
16852
+ if (!setup.connectUrl) {
16853
+ spinner?.fail(`Failed to start ${capability.name} setup`);
16854
+ return invalidSetupResponse(json);
16855
+ }
16856
+ let connectUrl;
16857
+ try {
16858
+ connectUrl = validateHandoffUrl(setup.connectUrl, client.baseUrl);
16859
+ } catch {
16860
+ spinner?.fail(`Failed to start ${capability.name} setup`);
16861
+ return invalidSetupResponse(json);
16862
+ }
16863
+ if (!machineMode) {
16864
+ const opened = openBrowser(connectUrl);
16865
+ spinner?.stop(opened ? `Browser opened for ${capability.name}` : "Could not open browser");
16866
+ if (!opened)
16867
+ console.log(`Open this URL to continue: ${connectUrl}`);
16868
+ if (setup.sessionId) {
16869
+ try {
16870
+ await waitForIntegrationConnection({
16871
+ client,
16872
+ sessionId: setup.sessionId,
16873
+ displayName: capability.name
16874
+ });
16875
+ } catch (error) {
16876
+ if (error instanceof IntegrationAuthTimeoutError || error instanceof IntegrationAuthError && error.status === "expired") {
16877
+ return outputError({
16878
+ message: "Integration authentication timed out after 5 minutes.",
16879
+ code: "AUTH_TIMEOUT"
16880
+ }, json);
16881
+ }
16882
+ return outputError({ message: "Integration authentication failed.", code: "AUTH_FAILED" }, json);
16883
+ }
16884
+ return;
16885
+ }
16886
+ }
16887
+ return outputResult({
16888
+ status: "awaiting_auth",
16889
+ ...setup,
16890
+ connectUrl,
16891
+ capabilities: capability
16892
+ });
16893
+ }
16894
+ function getUnsupportedSetupArgument(rawArgs) {
16895
+ let foundProvider = false;
16896
+ for (let index = 0;index < rawArgs.length; index += 1) {
16897
+ const argument = rawArgs[index];
16898
+ if (argument === undefined)
16899
+ continue;
16900
+ if (argument === "--api-key") {
16901
+ const value = rawArgs[index + 1];
16902
+ if (!value || value.startsWith("-"))
16903
+ return argument;
16904
+ index += 1;
16905
+ continue;
16906
+ }
16907
+ if (argument.startsWith("--api-key=")) {
16908
+ if (!argument.slice("--api-key=".length))
16909
+ return argument;
16910
+ continue;
16911
+ }
16912
+ if (argument === "--json" || argument === "--no-json" || argument === "--config-stdin" || argument === "--accept-recommended") {
16913
+ continue;
16914
+ }
16915
+ if (argument.startsWith("-"))
16916
+ return argument;
16917
+ if (!foundProvider) {
16918
+ foundProvider = true;
16919
+ continue;
16920
+ }
16921
+ return argument;
16922
+ }
16923
+ return null;
16924
+ }
14471
16925
  async function fetchProviderCapability(client, provider, json) {
14472
16926
  try {
14473
16927
  const result = await client.callTool("outlit_get_integration_capabilities", {
14474
16928
  provider
14475
16929
  });
14476
16930
  const capability = result.providers?.find((candidate) => candidate.provider === provider);
14477
- if (capability)
14478
- return capability;
16931
+ if (capability) {
16932
+ return { capability, preferredSetupVersion: result.preferredSetupVersion };
16933
+ }
14479
16934
  return outputError({ message: `Unknown integration: "${provider}"`, code: "unknown_provider" }, json);
14480
16935
  } catch (error) {
14481
- return outputError({
14482
- message: errorMessage(error, "Failed to fetch integration capabilities"),
16936
+ return outputApiError(error, json, {
16937
+ message: "Failed to fetch integration capabilities.",
14483
16938
  code: "api_error"
14484
- }, json);
16939
+ });
16940
+ }
16941
+ }
16942
+ function validateHandoffUrl(value, configuredBaseUrl) {
16943
+ const configured = new URL(configuredBaseUrl);
16944
+ const url = new URL(value, configured);
16945
+ if (url.origin !== configured.origin)
16946
+ throw new Error("Untrusted integration handoff origin");
16947
+ if (url.protocol !== "https:" && !isLoopbackHostname(url.hostname)) {
16948
+ throw new Error("Integration handoff must use HTTPS");
16949
+ }
16950
+ if (url.username || url.password || url.hash) {
16951
+ throw new Error("Integration handoff contains unsafe URL credentials or fragment");
16952
+ }
16953
+ for (const [key, queryValue] of url.searchParams) {
16954
+ if (/password|secret|credential|token|api[-_]?key|code/i.test(key)) {
16955
+ throw new Error("Integration handoff contains an unsafe query parameter");
16956
+ }
16957
+ if (/^(?:ok_|rk_|phx_|whsec_)/i.test(queryValue)) {
16958
+ throw new Error("Integration handoff contains credential material");
16959
+ }
16960
+ }
16961
+ return url.toString();
16962
+ }
16963
+ function authenticationContinuationInput(input) {
16964
+ const continuation = { provider: input.provider };
16965
+ if (input.connectionMode !== undefined)
16966
+ continuation.connectionMode = input.connectionMode;
16967
+ if (input.configuration !== undefined)
16968
+ continuation.configuration = input.configuration;
16969
+ return continuation;
16970
+ }
16971
+ function isLoopbackHostname(hostname) {
16972
+ const normalized = hostname.toLowerCase().replace(/^\[|\]$/g, "");
16973
+ return normalized === "localhost" || normalized === "::1" || /^127(?:\.\d{1,3}){3}$/.test(normalized);
16974
+ }
16975
+ function printRecommendation(recommendation, machineMode) {
16976
+ if (!machineMode) {
16977
+ console.log(`Recommended CRM mapping:
16978
+ ${JSON.stringify(recommendation, null, 2)}`);
16979
+ }
16980
+ }
16981
+ function printMixpanelPreview(preview, machineMode) {
16982
+ if (!machineMode) {
16983
+ console.log(`Mixpanel mapping preview:
16984
+ ${JSON.stringify(preview, null, 2)}`);
16985
+ }
16986
+ }
16987
+ function finishSetup(response, machineMode) {
16988
+ if (machineMode) {
16989
+ outputResult(response);
16990
+ return;
14485
16991
  }
16992
+ console.log(`${response.name}: ${response.status}`);
14486
16993
  }
14487
- var setup_default2;
16994
+ function invalidSetupResponse(json) {
16995
+ return outputError({
16996
+ message: "Outlit returned an invalid integration setup response.",
16997
+ code: "INVALID_SETUP_RESPONSE"
16998
+ }, json);
16999
+ }
17000
+ function stalled(json) {
17001
+ return outputError({ message: STALLED_MESSAGE, code: "SETUP_STALLED" }, json);
17002
+ }
17003
+ var setupOutputSchema, STALLED_MESSAGE = "Integration setup did not reach a terminal state.", setup_default2;
14488
17004
  var init_setup2 = __esm(() => {
17005
+ init_dist4();
14489
17006
  init_dist();
14490
17007
  init_auth();
14491
17008
  init_output2();
@@ -14493,19 +17010,23 @@ var init_setup2 = __esm(() => {
14493
17010
  init_output();
14494
17011
  init_spinner();
14495
17012
  init_tty();
17013
+ init_setup_input();
14496
17014
  init_wait_for_connection();
17015
+ setupOutputSchema = publicToolContracts.outlit_setup_integration.outputSchema;
14497
17016
  setup_default2 = defineCommand2({
14498
17017
  meta: {
14499
17018
  name: "setup",
14500
17019
  description: [
14501
- "Start a safe browser handoff for an integration.",
17020
+ "Set up or repair an integration through credentials, configuration, or a safe handoff.",
14502
17021
  "",
14503
- "Credential and provider-specific configuration is completed in the Outlit web app.",
14504
- "Providers without browser handoff support return the human control-plane URL.",
17022
+ "Interactive setup prompts for provider secrets only after Core requests them.",
17023
+ "Automation may pass one strict JSON document on stdin with --config-stdin.",
17024
+ "Supported actor-owned setup uses integrations:connect_own; workspace or admin setup uses integrations:manage.",
14505
17025
  "",
14506
17026
  "Examples:",
14507
17027
  " outlit integrations setup slack",
14508
17028
  " outlit integrations setup hubspot --json",
17029
+ " outlit integrations setup fireflies --config-stdin --json",
14509
17030
  "",
14510
17031
  AGENT_JSON_HINT
14511
17032
  ].join(`
@@ -14514,58 +17035,70 @@ var init_setup2 = __esm(() => {
14514
17035
  args: {
14515
17036
  ...authArgs,
14516
17037
  ...outputArgs,
17038
+ "config-stdin": {
17039
+ type: "boolean",
17040
+ description: "Read one strict provider configuration JSON document from stdin"
17041
+ },
17042
+ "accept-recommended": {
17043
+ type: "boolean",
17044
+ description: "Apply the exact CRM mapping recommendation shown by this command"
17045
+ },
14517
17046
  provider: {
14518
17047
  type: "positional",
14519
17048
  description: "Integration provider to set up",
14520
17049
  required: true
14521
17050
  }
14522
17051
  },
14523
- async run({ args }) {
17052
+ async run({ args, rawArgs }) {
14524
17053
  const json = !!args.json;
17054
+ const machineMode = isJsonMode(json);
17055
+ const unsupportedArgument = getUnsupportedSetupArgument(rawArgs ?? []);
17056
+ if (unsupportedArgument) {
17057
+ return outputError({
17058
+ message: "Integration setup accepts provider configuration only through --config-stdin; provider secrets are never CLI flags.",
17059
+ code: "invalid_input"
17060
+ }, json);
17061
+ }
14525
17062
  const provider = normalizeProviderInput(args.provider);
14526
17063
  const client = await getClientOrExit(args["api-key"], json);
14527
- const capability = await fetchProviderCapability(client, provider, json);
14528
- if (!capability.browserHandoffAvailable || capability.setupMode === "human_controlled") {
14529
- return outputResult({
14530
- status: "human_controlled",
14531
- provider: capability.provider,
14532
- controlPlaneUrl: `${client.baseUrl}/integrations`,
14533
- capabilities: capability
14534
- });
17064
+ const { capability, preferredSetupVersion } = await fetchProviderCapability(client, provider, json);
17065
+ if (preferredSetupVersion !== 1) {
17066
+ if (args["config-stdin"] || args["accept-recommended"]) {
17067
+ return outputError({
17068
+ message: "This Outlit deployment does not support negotiated setup; --config-stdin and --accept-recommended are unavailable.",
17069
+ code: "unsupported_core_version"
17070
+ }, json);
17071
+ }
17072
+ return runLegacySetup(client, capability, json, machineMode);
14535
17073
  }
14536
- const spinner = createSpinner(`Starting ${capability.name} setup...`);
14537
- let setup;
14538
- try {
14539
- setup = await client.callTool("outlit_begin_integration_setup", {
14540
- provider: capability.provider
14541
- });
14542
- } catch (error) {
14543
- spinner.fail(`Failed to start ${capability.name} setup`);
14544
- return outputError({ message: errorMessage(error, "Failed to start setup flow"), code: "api_error" }, json);
14545
- }
14546
- if (setup.state === "already_connected") {
14547
- spinner.stop(`${capability.name} is already connected`);
14548
- return outputResult({ status: "already_connected", ...setup, capabilities: capability });
14549
- }
14550
- if (!json && setup.connectUrl) {
14551
- const opened = openBrowser(setup.connectUrl);
14552
- spinner.stop(opened ? `Browser opened for ${capability.name}` : "Could not open browser");
14553
- if (!opened)
14554
- console.log(`Open this URL to continue: ${setup.connectUrl}`);
14555
- if (setup.sessionId) {
14556
- await waitForIntegrationConnection({
14557
- client,
14558
- sessionId: setup.sessionId,
14559
- displayName: capability.name,
14560
- cliName: capability.provider,
14561
- retryCommand: `outlit integrations setup ${capability.provider}`
14562
- });
14563
- return;
17074
+ let initialInput = { provider: capability.provider };
17075
+ if (args["config-stdin"]) {
17076
+ try {
17077
+ initialInput = parseSetupConfig(await readSetupConfigText(), capability.provider);
17078
+ } catch (error) {
17079
+ if (error instanceof SetupInputError) {
17080
+ return outputError({ message: error.message, code: error.code }, json);
17081
+ }
17082
+ return outputError({
17083
+ message: "Could not read integration configuration from stdin.",
17084
+ code: "invalid_input"
17085
+ }, json);
14564
17086
  }
14565
- } else {
14566
- spinner.stop(`Started ${capability.name} setup`);
14567
17087
  }
14568
- return outputResult({ status: "awaiting_auth", ...setup, capabilities: capability });
17088
+ if (args["accept-recommended"] && hasCrmConfiguration(initialInput)) {
17089
+ return outputError({
17090
+ message: "--accept-recommended conflicts with a supplied CRM configuration.",
17091
+ code: "invalid_input"
17092
+ }, json);
17093
+ }
17094
+ return runPreferredSetup({
17095
+ client,
17096
+ input: initialInput,
17097
+ json,
17098
+ machineMode,
17099
+ acceptRecommended: !!args["accept-recommended"],
17100
+ suppliedConfig: !!args["config-stdin"]
17101
+ });
14569
17102
  }
14570
17103
  });
14571
17104
  });
@@ -14575,46 +17108,25 @@ var exports_status2 = {};
14575
17108
  __export(exports_status2, {
14576
17109
  default: () => status_default2
14577
17110
  });
14578
- function hideBlankModelSyncs(data) {
14579
- if (typeof data !== "object" || data === null || Array.isArray(data)) {
14580
- return data;
14581
- }
14582
- const record = data;
14583
- if (!Array.isArray(record.syncs)) {
14584
- return data;
14585
- }
14586
- return {
14587
- ...record,
14588
- syncs: record.syncs.filter((sync) => {
14589
- if (typeof sync !== "object" || sync === null || Array.isArray(sync)) {
14590
- return false;
14591
- }
14592
- const model = sync.model;
14593
- return typeof model === "string" && model.trim().length > 0;
14594
- })
14595
- };
14596
- }
14597
17111
  var status_default2;
14598
17112
  var init_status2 = __esm(() => {
14599
17113
  init_dist();
14600
17114
  init_auth();
14601
17115
  init_output2();
14602
17116
  init_api();
14603
- init_output();
14604
17117
  status_default2 = defineCommand2({
14605
17118
  meta: {
14606
17119
  name: "status",
14607
17120
  description: [
14608
- "Show sync status for connected integrations.",
17121
+ "Show canonical integration readiness for agents and operators.",
14609
17122
  "",
14610
- "Without a provider name, shows a summary of all connected integrations.",
14611
- "With a provider name, shows detailed per-model sync status.",
14612
- "With --session, checks a browser-auth setup session returned by `integrations setup`.",
17123
+ "Without a provider name, shows the status of every available integration.",
17124
+ "With a provider name, returns its single canonical readiness status.",
17125
+ "Status reports configuration readiness, not sync, backfill, or data availability.",
14613
17126
  "",
14614
17127
  "Examples:",
14615
- " outlit integrations status # summary of all",
14616
- " outlit integrations status stripe # detailed Stripe sync status",
14617
- " outlit integrations status --session 550e8400-e29b-41d4-a716-446655440000 --json",
17128
+ " outlit integrations status",
17129
+ " outlit integrations status stripe --json",
14618
17130
  "",
14619
17131
  AGENT_JSON_HINT
14620
17132
  ].join(`
@@ -14625,49 +17137,22 @@ var init_status2 = __esm(() => {
14625
17137
  ...outputArgs,
14626
17138
  provider: {
14627
17139
  type: "positional",
14628
- description: "Provider name to show detailed status for (optional)",
17140
+ description: "Provider name to inspect (optional)",
14629
17141
  required: false
14630
- },
14631
- session: {
14632
- type: "string",
14633
- description: "Browser-auth setup session ID returned by `outlit integrations setup <provider>`."
14634
17142
  }
14635
17143
  },
14636
17144
  async run({ args }) {
14637
17145
  const json = !!args.json;
14638
17146
  const client = await getClientOrExit(args["api-key"], json);
14639
- if (args.session && args.provider) {
14640
- return outputError({ message: "Use either a provider name or --session, not both.", code: "invalid_input" }, json);
14641
- }
14642
- if (args.session) {
14643
- return runTool(client, "outlit_get_integration_setup_status", { sessionId: args.session }, json, {
14644
- spinnerMessage: "Checking setup session..."
14645
- });
14646
- }
14647
- if (args.provider) {
14648
- return runTool(client, "outlit_get_integration_sync_status", { provider: normalizeProviderInput(args.provider) }, json, {
14649
- spinnerMessage: "Fetching sync status...",
14650
- transform: hideBlankModelSyncs,
14651
- table: {
14652
- columns: [
14653
- { header: "Model", key: "model" },
14654
- { header: "Status", key: "status" },
14655
- { header: "Records", key: "recordCount", format: formatNumber },
14656
- { header: "Last Synced", key: "lastSyncedAt", format: relativeDate }
14657
- ],
14658
- itemsKey: "syncs"
14659
- }
14660
- });
14661
- }
14662
- return runTool(client, "outlit_list_integrations", { connectedOnly: true }, json, {
17147
+ const provider = args.provider ? normalizeProviderInput(args.provider) : undefined;
17148
+ return runTool(client, "outlit_get_integration_status", provider ? { provider } : {}, json, {
14663
17149
  spinnerMessage: "Fetching integration status...",
14664
17150
  table: {
14665
17151
  itemsKey: "integrations",
14666
17152
  columns: [
14667
- { header: "Name", key: "name", format: (v) => truncate(v, 24) },
17153
+ { header: "Name", key: "name", format: (value) => truncate(value, 24) },
14668
17154
  { header: "Category", key: "category", format: capitalize },
14669
- { header: "Sync Status", key: "syncStatus" },
14670
- { header: "Last Synced", key: "lastDataReceivedAt", format: relativeDate }
17155
+ { header: "Status", key: "status" }
14671
17156
  ]
14672
17157
  }
14673
17158
  });
@@ -14687,26 +17172,19 @@ var init_integrations = __esm(() => {
14687
17172
  meta: {
14688
17173
  name: "integrations",
14689
17174
  description: [
14690
- "Manage platform integrations (communication, analytics, billing, etc.).",
17175
+ "Set up actor-owned integrations and inspect canonical readiness.",
14691
17176
  "",
14692
- "Inspect integrations, start safe browser handoffs, and check sync status.",
17177
+ "Supported actor-owned setup uses integrations:connect_own; workspace or admin setup uses integrations:manage.",
14693
17178
  "",
14694
17179
  "Commands:",
14695
- " list List available integrations and connection status",
14696
- " capabilities [provider]",
14697
- " Show safe setup mode and browser-handoff availability",
14698
- " setup <provider> Start a browser handoff when supported",
14699
- " status --session <id>",
14700
- " Poll browser-auth setup status returned by setup JSON output",
14701
- " status [provider] Show sync status for connected integrations",
14702
- "",
14703
- "Credential and provider-specific configuration remains in the Outlit web app."
17180
+ " setup <provider> Run bounded provider setup when authorized",
17181
+ " status [provider] Show canonical integration readiness",
17182
+ "",
17183
+ "Core determines whether the requested setup is actor-owned or workspace/admin scoped."
14704
17184
  ].join(`
14705
17185
  `)
14706
17186
  },
14707
17187
  subCommands: {
14708
- list: () => Promise.resolve().then(() => (init_list7(), exports_list7)).then((m) => m.default),
14709
- capabilities: () => Promise.resolve().then(() => (init_capabilities(), exports_capabilities)).then((m) => m.default),
14710
17188
  setup: () => Promise.resolve().then(() => (init_setup2(), exports_setup)).then((m) => m.default),
14711
17189
  status: () => Promise.resolve().then(() => (init_status2(), exports_status2)).then((m) => m.default)
14712
17190
  }
@@ -14935,6 +17413,31 @@ var init_completions = __esm(() => {
14935
17413
  { name: "--start-date", desc: "Start date (ISO 8601)" },
14936
17414
  { name: "--end-date", desc: "End date (ISO 8601)" }
14937
17415
  ]
17416
+ },
17417
+ {
17418
+ name: "owner",
17419
+ desc: "Manage the primary customer owner",
17420
+ subs: [
17421
+ {
17422
+ name: "set",
17423
+ desc: "Assign the primary customer owner",
17424
+ flags: [...COMMON, { name: "--target-user-id", desc: "Required workspace-user ID" }]
17425
+ }
17426
+ ]
17427
+ },
17428
+ {
17429
+ name: "grant",
17430
+ desc: "Grant or change Viewer or Editor customer access",
17431
+ flags: [
17432
+ ...COMMON,
17433
+ { name: "--target-user-id", desc: "Required workspace-user ID" },
17434
+ { name: "--role", desc: "Required access role (VIEWER, EDITOR)" }
17435
+ ]
17436
+ },
17437
+ {
17438
+ name: "revoke",
17439
+ desc: "Revoke explicit customer access",
17440
+ flags: [...COMMON, { name: "--target-user-id", desc: "Required workspace-user ID" }]
14938
17441
  }
14939
17442
  ]
14940
17443
  },
@@ -14993,13 +17496,13 @@ var init_completions = __esm(() => {
14993
17496
  subs: [
14994
17497
  {
14995
17498
  name: "list",
14996
- desc: "List and filter internal workspace users",
17499
+ desc: "List eligible active workspace members",
14997
17500
  flags: [
14998
17501
  ...PAGINATED,
14999
17502
  { name: "--search", desc: "Search name, email, title, role, or territory" },
15000
17503
  { name: "--role", desc: "Filter by role metadata" },
15001
17504
  { name: "--manager-email", desc: "Filter by manager email" },
15002
- { name: "--has-owned-customers", desc: "Only users who own customers" },
17505
+ { name: "--has-owned-customers", desc: "Only members who own customers" },
15003
17506
  { name: "--order-by", desc: "Sort field" },
15004
17507
  { name: "--order-direction", desc: "Sort direction (asc, desc)" }
15005
17508
  ]
@@ -15089,17 +17592,19 @@ var init_completions = __esm(() => {
15089
17592
  name: "integrations",
15090
17593
  desc: "Manage platform integrations",
15091
17594
  subs: [
15092
- { name: "list", desc: "List integrations and status", flags: [...COMMON] },
15093
- { name: "capabilities", desc: "Show setup capabilities", flags: [JSON_F] },
15094
17595
  {
15095
17596
  name: "setup",
15096
- desc: "Start a safe browser setup handoff",
15097
- flags: [...COMMON]
17597
+ desc: "Set up or repair an integration",
17598
+ flags: [
17599
+ ...COMMON,
17600
+ { name: "--config-stdin", desc: "Read provider configuration JSON from stdin" },
17601
+ { name: "--accept-recommended", desc: "Apply the exact CRM recommendation" }
17602
+ ]
15098
17603
  },
15099
17604
  {
15100
17605
  name: "status",
15101
- desc: "Show sync or setup-session status",
15102
- flags: [...COMMON, { name: "--session", desc: "Browser-auth setup session ID" }]
17606
+ desc: "Show configuration readiness",
17607
+ flags: [...COMMON]
15103
17608
  }
15104
17609
  ]
15105
17610
  },
@@ -15150,6 +17655,39 @@ var init_completions = __esm(() => {
15150
17655
  }
15151
17656
  ]
15152
17657
  },
17658
+ {
17659
+ name: "metrics",
17660
+ desc: "Configure Behavior Metrics",
17661
+ subs: [
17662
+ {
17663
+ name: "sources",
17664
+ desc: "List product-event sources eligible for Behavior Metrics",
17665
+ flags: [...COMMON]
17666
+ },
17667
+ {
17668
+ name: "events",
17669
+ desc: "List attributed event candidates for a Behavior Metric source",
17670
+ flags: [
17671
+ ...COMMON,
17672
+ { name: "--source", desc: "Behavior Metric source key" },
17673
+ { name: "--weeks", desc: "History window in weeks (1-53, default: 12)" },
17674
+ { name: "--limit", desc: "Maximum event candidates (1-100, default: 100)" }
17675
+ ]
17676
+ },
17677
+ {
17678
+ name: "create",
17679
+ desc: "Create an event-based Behavior Metric",
17680
+ flags: [
17681
+ ...COMMON,
17682
+ { name: "--source", desc: "Behavior Metric source key" },
17683
+ { name: "--event", desc: "Exact tracked event name" },
17684
+ { name: "--key", desc: "Stable lower_snake_case metric key" },
17685
+ { name: "--label", desc: "Human-readable metric label" },
17686
+ { name: "--property-filters", desc: "Optional JSON event property filters" }
17687
+ ]
17688
+ }
17689
+ ]
17690
+ },
15153
17691
  {
15154
17692
  name: "onboard",
15155
17693
  desc: "Prepare a coding agent for Outlit",
@@ -15966,6 +18504,9 @@ Usage examples:
15966
18504
  outlit activation get --json
15967
18505
  outlit activation preview --event integration_connected --json
15968
18506
  outlit destinations disable 10000000-0000-4000-8000-000000000003 --json
18507
+ outlit metrics sources --json
18508
+ outlit metrics events --source metric_source_v1_0123456789abcdef0123456789abcdef --json
18509
+ outlit metrics create --source metric_source_v1_0123456789abcdef0123456789abcdef --event report_exported --key reports_exported --label 'Reports exported' --json
15969
18510
  outlit doctor --json
15970
18511
 
15971
18512
  For AI agents: commands auto-output JSON when stdout is piped. No --json flag needed.`
@@ -15985,6 +18526,7 @@ For AI agents: commands auto-output JSON when stdout is piped. No --json flag ne
15985
18526
  sql: () => Promise.resolve().then(() => (init_sql(), exports_sql)).then((m) => m.default),
15986
18527
  schema: () => Promise.resolve().then(() => (init_schema(), exports_schema)).then((m) => m.default),
15987
18528
  destinations: () => Promise.resolve().then(() => (init_destinations(), exports_destinations)).then((m) => m.default),
18529
+ metrics: () => Promise.resolve().then(() => (init_metrics(), exports_metrics)).then((module) => module.default),
15988
18530
  settings: () => Promise.resolve().then(() => (init_settings(), exports_settings)).then((m) => m.default),
15989
18531
  integrations: () => Promise.resolve().then(() => (init_integrations(), exports_integrations)).then((m) => m.default),
15990
18532
  completions: () => Promise.resolve().then(() => (init_completions(), exports_completions)).then((m) => m.default),