@outlit/cli 1.3.1 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +959 -122
- package/package.json +5 -3
package/dist/cli.js
CHANGED
|
@@ -104,7 +104,7 @@ var package_default;
|
|
|
104
104
|
var init_package = __esm(() => {
|
|
105
105
|
package_default = {
|
|
106
106
|
name: "@outlit/cli",
|
|
107
|
-
version: "1.
|
|
107
|
+
version: "1.4.1",
|
|
108
108
|
description: "CLI for Outlit customer intelligence platform",
|
|
109
109
|
license: "Apache-2.0",
|
|
110
110
|
repository: {
|
|
@@ -120,7 +120,9 @@ var init_package = __esm(() => {
|
|
|
120
120
|
bin: {
|
|
121
121
|
outlit: "./dist/cli.js"
|
|
122
122
|
},
|
|
123
|
-
files: [
|
|
123
|
+
files: [
|
|
124
|
+
"dist"
|
|
125
|
+
],
|
|
124
126
|
scripts: {
|
|
125
127
|
dev: "bun run src/cli.ts",
|
|
126
128
|
"dev:watch": "bun --watch src/cli.ts",
|
|
@@ -136,15 +138,46 @@ var init_package = __esm(() => {
|
|
|
136
138
|
"@clack/prompts": "^1.0.1"
|
|
137
139
|
},
|
|
138
140
|
devDependencies: {
|
|
139
|
-
typescript: "^5.
|
|
141
|
+
typescript: "^5.9.3",
|
|
140
142
|
"@types/bun": "latest"
|
|
141
143
|
}
|
|
142
144
|
};
|
|
143
145
|
});
|
|
144
146
|
|
|
145
147
|
// src/lib/tty.ts
|
|
148
|
+
import { execFileSync } from "node:child_process";
|
|
149
|
+
import { createInterface } from "node:readline";
|
|
146
150
|
function openBrowserCmd() {
|
|
147
|
-
return process.platform === "darwin" ? "open" :
|
|
151
|
+
return process.platform === "darwin" ? "open" : "xdg-open";
|
|
152
|
+
}
|
|
153
|
+
function openBrowser(url) {
|
|
154
|
+
try {
|
|
155
|
+
if (process.platform === "win32") {
|
|
156
|
+
execFileSync("cmd", ["/c", "start", "", url.replace(/&/g, "^&")], { stdio: "ignore" });
|
|
157
|
+
} else {
|
|
158
|
+
execFileSync(openBrowserCmd(), [url], { stdio: "ignore" });
|
|
159
|
+
}
|
|
160
|
+
return true;
|
|
161
|
+
} catch {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function promptInput(label, opts) {
|
|
166
|
+
return new Promise((resolve) => {
|
|
167
|
+
const rl = createInterface({
|
|
168
|
+
input: process.stdin,
|
|
169
|
+
output: opts?.secret ? undefined : process.stderr,
|
|
170
|
+
terminal: !opts?.secret
|
|
171
|
+
});
|
|
172
|
+
process.stderr.write(`${label}: `);
|
|
173
|
+
rl.question("", (answer) => {
|
|
174
|
+
rl.close();
|
|
175
|
+
if (opts?.secret)
|
|
176
|
+
process.stderr.write(`
|
|
177
|
+
`);
|
|
178
|
+
resolve(answer.trim());
|
|
179
|
+
});
|
|
180
|
+
});
|
|
148
181
|
}
|
|
149
182
|
function isInteractive() {
|
|
150
183
|
if (!process.stdin.isTTY || !process.stdout.isTTY)
|
|
@@ -679,7 +712,7 @@ var import_picocolors, import_sisteransi, at = (t) => t === 161 || t === 164 ||
|
|
|
679
712
|
` && (r && p && (i += st(r)), n && (i += it(n))), V += h.length, m = A, A = g.next();
|
|
680
713
|
}
|
|
681
714
|
return i;
|
|
682
|
-
}, 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;
|
|
715
|
+
}, 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;
|
|
683
716
|
var init_dist2 = __esm(() => {
|
|
684
717
|
import_picocolors = __toESM(require_picocolors(), 1);
|
|
685
718
|
import_sisteransi = __toESM(require_src(), 1);
|
|
@@ -758,6 +791,23 @@ var init_dist2 = __esm(() => {
|
|
|
758
791
|
}
|
|
759
792
|
}
|
|
760
793
|
};
|
|
794
|
+
kt = class kt extends x {
|
|
795
|
+
get cursor() {
|
|
796
|
+
return this.value ? 0 : 1;
|
|
797
|
+
}
|
|
798
|
+
get _value() {
|
|
799
|
+
return this.cursor === 0;
|
|
800
|
+
}
|
|
801
|
+
constructor(e) {
|
|
802
|
+
super(e, false), this.value = !!e.initialValue, this.on("userInput", () => {
|
|
803
|
+
this.value = this._value;
|
|
804
|
+
}), this.on("confirm", (s) => {
|
|
805
|
+
this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = s, this.state = "submit", this.close();
|
|
806
|
+
}), this.on("cursor", () => {
|
|
807
|
+
this.value = !this.value;
|
|
808
|
+
});
|
|
809
|
+
}
|
|
810
|
+
};
|
|
761
811
|
yt = class yt extends x {
|
|
762
812
|
options;
|
|
763
813
|
cursor = 0;
|
|
@@ -1073,6 +1123,32 @@ var import_picocolors2, import_sisteransi2, et2, ct2 = () => process.env.CI ===
|
|
|
1073
1123
|
for (const w of A)
|
|
1074
1124
|
B2.push(w);
|
|
1075
1125
|
return h && B2.push(g), B2;
|
|
1126
|
+
}, Re = (t) => {
|
|
1127
|
+
const r = t.active ?? "Yes", s = t.inactive ?? "No";
|
|
1128
|
+
return new kt({ active: r, inactive: s, signal: t.signal, input: t.input, output: t.output, initialValue: t.initialValue ?? true, render() {
|
|
1129
|
+
const i = t.withGuide ?? _.withGuide, a = `${i ? `${import_picocolors2.default.gray(d)}
|
|
1130
|
+
` : ""}${W2(this.state)} ${t.message}
|
|
1131
|
+
`, o = this.value ? r : s;
|
|
1132
|
+
switch (this.state) {
|
|
1133
|
+
case "submit": {
|
|
1134
|
+
const u = i ? `${import_picocolors2.default.gray(d)} ` : "";
|
|
1135
|
+
return `${a}${u}${import_picocolors2.default.dim(o)}`;
|
|
1136
|
+
}
|
|
1137
|
+
case "cancel": {
|
|
1138
|
+
const u = i ? `${import_picocolors2.default.gray(d)} ` : "";
|
|
1139
|
+
return `${a}${u}${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(o))}${i ? `
|
|
1140
|
+
${import_picocolors2.default.gray(d)}` : ""}`;
|
|
1141
|
+
}
|
|
1142
|
+
default: {
|
|
1143
|
+
const u = i ? `${import_picocolors2.default.cyan(d)} ` : "", l = i ? import_picocolors2.default.cyan(x2) : "";
|
|
1144
|
+
return `${a}${u}${this.value ? `${import_picocolors2.default.green(Q2)} ${r}` : `${import_picocolors2.default.dim(H2)} ${import_picocolors2.default.dim(r)}`}${t.vertical ? i ? `
|
|
1145
|
+
${import_picocolors2.default.cyan(d)} ` : `
|
|
1146
|
+
` : ` ${import_picocolors2.default.dim("/")} `}${this.value ? `${import_picocolors2.default.dim(H2)} ${import_picocolors2.default.dim(s)}` : `${import_picocolors2.default.green(Q2)} ${s}`}
|
|
1147
|
+
${l}
|
|
1148
|
+
`;
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
} }).prompt();
|
|
1076
1152
|
}, R2, Ne = (t = "", r) => {
|
|
1077
1153
|
(r?.output ?? process.stdout).write(`${import_picocolors2.default.gray(x2)} ${import_picocolors2.default.red(t)}
|
|
1078
1154
|
|
|
@@ -1299,57 +1375,6 @@ Note: JSON is also auto-enabled when stdout is piped (e.g. in CI, scripts, or AI
|
|
|
1299
1375
|
};
|
|
1300
1376
|
});
|
|
1301
1377
|
|
|
1302
|
-
// src/commands/auth/signup.ts
|
|
1303
|
-
var exports_signup = {};
|
|
1304
|
-
__export(exports_signup, {
|
|
1305
|
-
default: () => signup_default
|
|
1306
|
-
});
|
|
1307
|
-
import { execFileSync } from "node:child_process";
|
|
1308
|
-
var OUTLIT_SIGNUP_URL = "https://app.outlit.ai/sign-up", signup_default;
|
|
1309
|
-
var init_signup = __esm(() => {
|
|
1310
|
-
init_dist3();
|
|
1311
|
-
init_dist();
|
|
1312
|
-
init_output2();
|
|
1313
|
-
init_output();
|
|
1314
|
-
init_tty();
|
|
1315
|
-
signup_default = defineCommand2({
|
|
1316
|
-
meta: {
|
|
1317
|
-
name: "signup",
|
|
1318
|
-
description: [
|
|
1319
|
-
"Create an Outlit account.",
|
|
1320
|
-
"",
|
|
1321
|
-
"Opens the Outlit sign-up page in your default browser.",
|
|
1322
|
-
"",
|
|
1323
|
-
"Examples:",
|
|
1324
|
-
" outlit auth signup # opens browser",
|
|
1325
|
-
" outlit auth signup --json # outputs URL as JSON"
|
|
1326
|
-
].join(`
|
|
1327
|
-
`)
|
|
1328
|
-
},
|
|
1329
|
-
args: { ...outputArgs },
|
|
1330
|
-
async run({ args }) {
|
|
1331
|
-
const json = !!args.json;
|
|
1332
|
-
if (isJsonMode(json)) {
|
|
1333
|
-
return outputResult({ url: OUTLIT_SIGNUP_URL });
|
|
1334
|
-
}
|
|
1335
|
-
if (isInteractive()) {
|
|
1336
|
-
We("Outlit CLI -- Sign Up");
|
|
1337
|
-
}
|
|
1338
|
-
try {
|
|
1339
|
-
if (process.platform === "win32") {
|
|
1340
|
-
execFileSync("cmd", ["/c", "start", "", OUTLIT_SIGNUP_URL], { stdio: "ignore" });
|
|
1341
|
-
} else {
|
|
1342
|
-
execFileSync(openBrowserCmd(), [OUTLIT_SIGNUP_URL], { stdio: "ignore" });
|
|
1343
|
-
}
|
|
1344
|
-
} catch {}
|
|
1345
|
-
if (isInteractive()) {
|
|
1346
|
-
R2.info(`Opening ${OUTLIT_SIGNUP_URL}`);
|
|
1347
|
-
Le("Once you've signed up, run `outlit auth login` to store your API key.");
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
});
|
|
1351
|
-
});
|
|
1352
|
-
|
|
1353
1378
|
// src/lib/config.ts
|
|
1354
1379
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
1355
1380
|
import { homedir } from "node:os";
|
|
@@ -1444,7 +1469,7 @@ function storeApiKey(apiKey) {
|
|
|
1444
1469
|
writeFileSync(credPath, JSON.stringify({ apiKey }, null, 2), { mode: 384 });
|
|
1445
1470
|
return credPath;
|
|
1446
1471
|
}
|
|
1447
|
-
var CLI_VERSION2, DEFAULT_MCP_URL = "https://mcp.outlit.ai/mcp", DEFAULT_API_URL = "https://app.outlit.ai", OUTLIT_DASHBOARD_URL = "https://app.outlit.ai/workspace-profile", TICK2;
|
|
1472
|
+
var CLI_VERSION2, DEFAULT_MCP_URL = "https://mcp.outlit.ai/mcp", DEFAULT_API_URL = "https://app.outlit.ai", OUTLIT_DASHBOARD_URL = "https://app.outlit.ai/workspace-profile", OUTLIT_SIGNUP_URL = "https://app.outlit.ai/sign-up", TICK2;
|
|
1448
1473
|
var init_config = __esm(() => {
|
|
1449
1474
|
init_package();
|
|
1450
1475
|
init_output();
|
|
@@ -1453,6 +1478,55 @@ var init_config = __esm(() => {
|
|
|
1453
1478
|
TICK2 = `\x1B[32m${isUnicodeSupported ? String.fromCodePoint(10003) : String.fromCodePoint(8730)}\x1B[0m`;
|
|
1454
1479
|
});
|
|
1455
1480
|
|
|
1481
|
+
// src/commands/auth/signup.ts
|
|
1482
|
+
var exports_signup = {};
|
|
1483
|
+
__export(exports_signup, {
|
|
1484
|
+
default: () => signup_default
|
|
1485
|
+
});
|
|
1486
|
+
var signup_default;
|
|
1487
|
+
var init_signup = __esm(() => {
|
|
1488
|
+
init_dist3();
|
|
1489
|
+
init_dist();
|
|
1490
|
+
init_output2();
|
|
1491
|
+
init_config();
|
|
1492
|
+
init_output();
|
|
1493
|
+
init_tty();
|
|
1494
|
+
signup_default = defineCommand2({
|
|
1495
|
+
meta: {
|
|
1496
|
+
name: "signup",
|
|
1497
|
+
description: [
|
|
1498
|
+
"Create an Outlit account.",
|
|
1499
|
+
"",
|
|
1500
|
+
"Opens the Outlit sign-up page in your default browser.",
|
|
1501
|
+
"",
|
|
1502
|
+
"Examples:",
|
|
1503
|
+
" outlit auth signup # opens browser",
|
|
1504
|
+
" outlit auth signup --json # outputs URL as JSON"
|
|
1505
|
+
].join(`
|
|
1506
|
+
`)
|
|
1507
|
+
},
|
|
1508
|
+
args: { ...outputArgs },
|
|
1509
|
+
async run({ args }) {
|
|
1510
|
+
const json = !!args.json;
|
|
1511
|
+
if (isJsonMode(json)) {
|
|
1512
|
+
return outputResult({ url: OUTLIT_SIGNUP_URL });
|
|
1513
|
+
}
|
|
1514
|
+
if (isInteractive()) {
|
|
1515
|
+
We("Outlit CLI -- Sign Up");
|
|
1516
|
+
}
|
|
1517
|
+
const opened = openBrowser(OUTLIT_SIGNUP_URL);
|
|
1518
|
+
if (isInteractive()) {
|
|
1519
|
+
if (opened) {
|
|
1520
|
+
R2.info(`Opening ${OUTLIT_SIGNUP_URL}`);
|
|
1521
|
+
} else {
|
|
1522
|
+
R2.info(`Could not open browser. Visit ${OUTLIT_SIGNUP_URL}`);
|
|
1523
|
+
}
|
|
1524
|
+
Le("Once you've signed up, run `outlit auth login` to store your API key.");
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
});
|
|
1528
|
+
});
|
|
1529
|
+
|
|
1456
1530
|
// src/lib/client.ts
|
|
1457
1531
|
function buildUrl(base, path, params) {
|
|
1458
1532
|
const url = new URL(path, base);
|
|
@@ -1461,6 +1535,8 @@ function buildUrl(base, path, params) {
|
|
|
1461
1535
|
continue;
|
|
1462
1536
|
if (Array.isArray(value)) {
|
|
1463
1537
|
url.searchParams.set(key, value.join(","));
|
|
1538
|
+
} else if (typeof value === "object") {
|
|
1539
|
+
url.searchParams.set(key, JSON.stringify(value));
|
|
1464
1540
|
} else {
|
|
1465
1541
|
url.searchParams.set(key, String(value));
|
|
1466
1542
|
}
|
|
@@ -1521,7 +1597,18 @@ var init_client = __esm(() => {
|
|
|
1521
1597
|
outlit_get_facts: { method: "POST", path: "/api/internal/mcp/facts" },
|
|
1522
1598
|
outlit_schema: { method: "GET", path: "/api/internal/mcp/sql-schema" },
|
|
1523
1599
|
outlit_query: { method: "POST", path: "/api/internal/mcp/sql" },
|
|
1524
|
-
outlit_search_customer_context: { method: "POST", path: "/api/internal/mcp/context-search" }
|
|
1600
|
+
outlit_search_customer_context: { method: "POST", path: "/api/internal/mcp/context-search" },
|
|
1601
|
+
outlit_list_integrations: { method: "GET", path: "/api/internal/mcp/integrations" },
|
|
1602
|
+
outlit_connect_integration: { method: "POST", path: "/api/internal/mcp/integrations/connect" },
|
|
1603
|
+
outlit_connect_status: { method: "GET", path: "/api/internal/mcp/integrations/connect/status" },
|
|
1604
|
+
outlit_disconnect_integration: {
|
|
1605
|
+
method: "POST",
|
|
1606
|
+
path: "/api/internal/mcp/integrations/disconnect"
|
|
1607
|
+
},
|
|
1608
|
+
outlit_integration_sync_status: {
|
|
1609
|
+
method: "GET",
|
|
1610
|
+
path: "/api/internal/mcp/integrations/sync-status"
|
|
1611
|
+
}
|
|
1525
1612
|
};
|
|
1526
1613
|
});
|
|
1527
1614
|
|
|
@@ -1712,7 +1799,6 @@ var exports_login = {};
|
|
|
1712
1799
|
__export(exports_login, {
|
|
1713
1800
|
default: () => login_default
|
|
1714
1801
|
});
|
|
1715
|
-
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
1716
1802
|
var login_default;
|
|
1717
1803
|
var init_login = __esm(() => {
|
|
1718
1804
|
init_dist3();
|
|
@@ -1773,14 +1859,12 @@ Format: ok_ followed by 32+ alphanumeric characters.`
|
|
|
1773
1859
|
if (Ct(method))
|
|
1774
1860
|
cancelLogin();
|
|
1775
1861
|
if (method === "browser") {
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
} catch {}
|
|
1783
|
-
R2.info("Opening browser... paste your key once you have it.");
|
|
1862
|
+
const opened = openBrowser(OUTLIT_DASHBOARD_URL);
|
|
1863
|
+
if (opened) {
|
|
1864
|
+
R2.info("Opening browser... paste your key once you have it.");
|
|
1865
|
+
} else {
|
|
1866
|
+
R2.info(`Could not open browser. Visit ${OUTLIT_DASHBOARD_URL} manually.`);
|
|
1867
|
+
}
|
|
1784
1868
|
}
|
|
1785
1869
|
const result = await He({
|
|
1786
1870
|
message: "Paste your Outlit API key:",
|
|
@@ -2026,6 +2110,38 @@ var init_auth2 = __esm(() => {
|
|
|
2026
2110
|
});
|
|
2027
2111
|
|
|
2028
2112
|
// src/args/filters.ts
|
|
2113
|
+
function parseTraitFilterValue(value) {
|
|
2114
|
+
if (value === "true")
|
|
2115
|
+
return true;
|
|
2116
|
+
if (value === "false")
|
|
2117
|
+
return false;
|
|
2118
|
+
const parsed = Number(value);
|
|
2119
|
+
if (value.trim() !== "" && Number.isFinite(parsed)) {
|
|
2120
|
+
return parsed;
|
|
2121
|
+
}
|
|
2122
|
+
return value;
|
|
2123
|
+
}
|
|
2124
|
+
function parseTraitFilters(input) {
|
|
2125
|
+
if (!input)
|
|
2126
|
+
return;
|
|
2127
|
+
const entries = input.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
2128
|
+
if (entries.length === 0)
|
|
2129
|
+
return;
|
|
2130
|
+
const filters = {};
|
|
2131
|
+
for (const entry of entries) {
|
|
2132
|
+
const separatorIndex = entry.indexOf("=");
|
|
2133
|
+
if (separatorIndex <= 0 || separatorIndex === entry.length - 1) {
|
|
2134
|
+
throw new Error(`Invalid trait filter "${entry}". Expected key=value.`);
|
|
2135
|
+
}
|
|
2136
|
+
const key = entry.slice(0, separatorIndex).trim();
|
|
2137
|
+
const rawValue = entry.slice(separatorIndex + 1).trim();
|
|
2138
|
+
if (!/^[A-Za-z0-9_-]{1,100}$/.test(key)) {
|
|
2139
|
+
throw new Error(`Invalid trait filter key "${key}". Keys may only contain letters, numbers, underscores, and dashes.`);
|
|
2140
|
+
}
|
|
2141
|
+
filters[key] = parseTraitFilterValue(rawValue);
|
|
2142
|
+
}
|
|
2143
|
+
return filters;
|
|
2144
|
+
}
|
|
2029
2145
|
function applyListFilters(params, args) {
|
|
2030
2146
|
if (args["no-activity-in"])
|
|
2031
2147
|
params.noActivityInLast = args["no-activity-in"];
|
|
@@ -2038,7 +2154,7 @@ function applyListFilters(params, args) {
|
|
|
2038
2154
|
if (args["order-direction"])
|
|
2039
2155
|
params.orderDirection = args["order-direction"];
|
|
2040
2156
|
}
|
|
2041
|
-
var activityFilterArgs, orderArgs;
|
|
2157
|
+
var activityFilterArgs, orderArgs, traitFilterArgs;
|
|
2042
2158
|
var init_filters = __esm(() => {
|
|
2043
2159
|
activityFilterArgs = {
|
|
2044
2160
|
"no-activity-in": {
|
|
@@ -2062,6 +2178,12 @@ var init_filters = __esm(() => {
|
|
|
2062
2178
|
default: "desc"
|
|
2063
2179
|
}
|
|
2064
2180
|
};
|
|
2181
|
+
traitFilterArgs = {
|
|
2182
|
+
trait: {
|
|
2183
|
+
type: "string",
|
|
2184
|
+
description: "Filter by traits using key=value pairs. Separate multiple filters with commas (e.g. role=admin,active=true)"
|
|
2185
|
+
}
|
|
2186
|
+
};
|
|
2065
2187
|
});
|
|
2066
2188
|
|
|
2067
2189
|
// src/args/pagination.ts
|
|
@@ -2137,6 +2259,16 @@ function truncate(value, maxLen) {
|
|
|
2137
2259
|
return "...".slice(0, maxLen);
|
|
2138
2260
|
return `${str.slice(0, maxLen - 3)}...`;
|
|
2139
2261
|
}
|
|
2262
|
+
function capitalize(value) {
|
|
2263
|
+
if (value == null || typeof value !== "string")
|
|
2264
|
+
return "--";
|
|
2265
|
+
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
2266
|
+
}
|
|
2267
|
+
function formatNumber(value) {
|
|
2268
|
+
if (value == null || typeof value !== "number" || Number.isNaN(value))
|
|
2269
|
+
return "--";
|
|
2270
|
+
return value.toLocaleString("en-US");
|
|
2271
|
+
}
|
|
2140
2272
|
|
|
2141
2273
|
// src/commands/customers/list.ts
|
|
2142
2274
|
var exports_list = {};
|
|
@@ -2180,6 +2312,7 @@ var init_list = __esm(() => {
|
|
|
2180
2312
|
...outputArgs,
|
|
2181
2313
|
...paginationArgs,
|
|
2182
2314
|
...activityFilterArgs,
|
|
2315
|
+
...traitFilterArgs,
|
|
2183
2316
|
...orderArgs,
|
|
2184
2317
|
"billing-status": {
|
|
2185
2318
|
type: "string",
|
|
@@ -2226,6 +2359,19 @@ var init_list = __esm(() => {
|
|
|
2226
2359
|
}
|
|
2227
2360
|
params.mrrBelow = value;
|
|
2228
2361
|
}
|
|
2362
|
+
if (args.trait) {
|
|
2363
|
+
try {
|
|
2364
|
+
const traitFilters = parseTraitFilters(args.trait);
|
|
2365
|
+
if (traitFilters) {
|
|
2366
|
+
params.traitFilters = traitFilters;
|
|
2367
|
+
}
|
|
2368
|
+
} catch (error) {
|
|
2369
|
+
return outputError({
|
|
2370
|
+
message: error instanceof Error ? error.message : "Invalid --trait filter",
|
|
2371
|
+
code: "invalid_input"
|
|
2372
|
+
}, json);
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2229
2375
|
applyListFilters(params, args);
|
|
2230
2376
|
applyPagination(params, args, json);
|
|
2231
2377
|
if (args.status)
|
|
@@ -2459,6 +2605,7 @@ var init_list2 = __esm(() => {
|
|
|
2459
2605
|
init_output2();
|
|
2460
2606
|
init_pagination();
|
|
2461
2607
|
init_api();
|
|
2608
|
+
init_output();
|
|
2462
2609
|
list_default2 = defineCommand2({
|
|
2463
2610
|
meta: {
|
|
2464
2611
|
name: "list",
|
|
@@ -2484,6 +2631,7 @@ var init_list2 = __esm(() => {
|
|
|
2484
2631
|
...authArgs,
|
|
2485
2632
|
...outputArgs,
|
|
2486
2633
|
...paginationArgs,
|
|
2634
|
+
...traitFilterArgs,
|
|
2487
2635
|
"journey-stage": {
|
|
2488
2636
|
type: "string",
|
|
2489
2637
|
description: "Filter by journey stage (e.g. CHAMPION, AT_RISK, CHURNED)"
|
|
@@ -2507,6 +2655,19 @@ var init_list2 = __esm(() => {
|
|
|
2507
2655
|
params.journeyStage = args["journey-stage"];
|
|
2508
2656
|
if (args["customer-id"])
|
|
2509
2657
|
params.customerId = args["customer-id"];
|
|
2658
|
+
if (args.trait) {
|
|
2659
|
+
try {
|
|
2660
|
+
const traitFilters = parseTraitFilters(args.trait);
|
|
2661
|
+
if (traitFilters) {
|
|
2662
|
+
params.traitFilters = traitFilters;
|
|
2663
|
+
}
|
|
2664
|
+
} catch (error) {
|
|
2665
|
+
return outputError({
|
|
2666
|
+
message: error instanceof Error ? error.message : "Invalid --trait filter",
|
|
2667
|
+
code: "invalid_input"
|
|
2668
|
+
}, json);
|
|
2669
|
+
}
|
|
2670
|
+
}
|
|
2510
2671
|
applyListFilters(params, args);
|
|
2511
2672
|
applyPagination(params, args, json);
|
|
2512
2673
|
return runTool(client, "outlit_list_users", params, json, {
|
|
@@ -2554,10 +2715,10 @@ var init_users = __esm(() => {
|
|
|
2554
2715
|
});
|
|
2555
2716
|
|
|
2556
2717
|
// src/lib/setup.ts
|
|
2557
|
-
import { execFileSync as
|
|
2718
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
2558
2719
|
function runMcpCliSetup(key, json, opts, exitOnError = true) {
|
|
2559
2720
|
try {
|
|
2560
|
-
|
|
2721
|
+
execFileSync2(opts.cliName, [
|
|
2561
2722
|
"mcp",
|
|
2562
2723
|
"add",
|
|
2563
2724
|
"--transport",
|
|
@@ -2785,20 +2946,15 @@ __export(exports_openclaw, {
|
|
|
2785
2946
|
configureSafe: () => configureSafe5,
|
|
2786
2947
|
buildSkillContent: () => buildSkillContent
|
|
2787
2948
|
});
|
|
2788
|
-
import { existsSync as existsSync2 } from "node:fs";
|
|
2789
2949
|
import { homedir as homedir3 } from "node:os";
|
|
2790
2950
|
import { join as join4 } from "node:path";
|
|
2791
2951
|
function getSkillDir() {
|
|
2792
2952
|
const home = homedir3();
|
|
2793
|
-
|
|
2794
|
-
if (existsSync2(clawdDir)) {
|
|
2795
|
-
return join4(clawdDir, "skills", "outlit-intelligence");
|
|
2796
|
-
}
|
|
2797
|
-
return join4(home, ".openclaw", "skills", "outlit-intelligence");
|
|
2953
|
+
return join4(home, ".openclaw", "skills", "outlit");
|
|
2798
2954
|
}
|
|
2799
2955
|
function buildSkillContent(maskedKey) {
|
|
2800
2956
|
return `---
|
|
2801
|
-
name: outlit
|
|
2957
|
+
name: outlit
|
|
2802
2958
|
description: Query customer data, revenue metrics, and analytics via the Outlit CLI.
|
|
2803
2959
|
metadata:
|
|
2804
2960
|
openclaw:
|
|
@@ -2883,7 +3039,7 @@ var init_openclaw = __esm(() => {
|
|
|
2883
3039
|
openclaw_default = defineCommand2({
|
|
2884
3040
|
meta: {
|
|
2885
3041
|
name: "openclaw",
|
|
2886
|
-
description: "Write Outlit
|
|
3042
|
+
description: "Write Outlit skill to ~/.openclaw/skills/ for OpenClaw."
|
|
2887
3043
|
},
|
|
2888
3044
|
args: { ...authArgs, ...outputArgs },
|
|
2889
3045
|
run({ args }) {
|
|
@@ -2907,12 +3063,12 @@ __export(exports_skills, {
|
|
|
2907
3063
|
detectPackageRunner: () => detectPackageRunner,
|
|
2908
3064
|
default: () => skills_default
|
|
2909
3065
|
});
|
|
2910
|
-
import { execFileSync as
|
|
3066
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
2911
3067
|
function detectPackageRunner() {
|
|
2912
3068
|
const whichCmd = process.platform === "win32" ? "where" : "which";
|
|
2913
3069
|
for (const runner of ["npx", "bunx", "pnpx"]) {
|
|
2914
3070
|
try {
|
|
2915
|
-
|
|
3071
|
+
execFileSync3(whichCmd, [runner], { stdio: "ignore" });
|
|
2916
3072
|
return runner;
|
|
2917
3073
|
} catch {}
|
|
2918
3074
|
}
|
|
@@ -2939,7 +3095,7 @@ function runSkillsInstall(json, exitOnError = true) {
|
|
|
2939
3095
|
return { success: false, error: "No package runner found" };
|
|
2940
3096
|
}
|
|
2941
3097
|
try {
|
|
2942
|
-
|
|
3098
|
+
execFileSync3(runner, buildRunnerArgs(runner), { stdio: "pipe" });
|
|
2943
3099
|
} catch (err) {
|
|
2944
3100
|
if (exitOnError) {
|
|
2945
3101
|
if (isEnoentError(err)) {
|
|
@@ -3029,14 +3185,14 @@ var init_vscode = __esm(() => {
|
|
|
3029
3185
|
});
|
|
3030
3186
|
|
|
3031
3187
|
// src/commands/setup/index.ts
|
|
3032
|
-
import { execFileSync as
|
|
3033
|
-
import { existsSync as
|
|
3188
|
+
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
3189
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
3034
3190
|
import { homedir as homedir4 } from "node:os";
|
|
3035
3191
|
import { join as join6 } from "node:path";
|
|
3036
3192
|
function isCommandAvailable(cmd) {
|
|
3037
3193
|
try {
|
|
3038
3194
|
const whichCmd = process.platform === "win32" ? "where" : "which";
|
|
3039
|
-
|
|
3195
|
+
execFileSync4(whichCmd, [cmd], { stdio: "ignore" });
|
|
3040
3196
|
return true;
|
|
3041
3197
|
} catch {
|
|
3042
3198
|
return false;
|
|
@@ -3045,17 +3201,17 @@ function isCommandAvailable(cmd) {
|
|
|
3045
3201
|
function detectAgents() {
|
|
3046
3202
|
const home = homedir4();
|
|
3047
3203
|
const detected = [];
|
|
3048
|
-
if (
|
|
3204
|
+
if (existsSync2(join6(home, ".cursor")))
|
|
3049
3205
|
detected.push("cursor");
|
|
3050
3206
|
if (isCommandAvailable("claude"))
|
|
3051
3207
|
detected.push("claude-code");
|
|
3052
|
-
if (
|
|
3208
|
+
if (existsSync2(getClaudeDesktopConfigPath()))
|
|
3053
3209
|
detected.push("claude-desktop");
|
|
3054
|
-
if (isCommandAvailable("code") ||
|
|
3210
|
+
if (isCommandAvailable("code") || existsSync2(join6(process.cwd(), ".vscode")))
|
|
3055
3211
|
detected.push("vscode");
|
|
3056
3212
|
if (isCommandAvailable("gemini"))
|
|
3057
3213
|
detected.push("gemini");
|
|
3058
|
-
if (
|
|
3214
|
+
if (existsSync2(join6(home, ".openclaw", "skills")))
|
|
3059
3215
|
detected.push("openclaw");
|
|
3060
3216
|
return detected;
|
|
3061
3217
|
}
|
|
@@ -3171,7 +3327,7 @@ var exports_doctor = {};
|
|
|
3171
3327
|
__export(exports_doctor, {
|
|
3172
3328
|
default: () => doctor_default
|
|
3173
3329
|
});
|
|
3174
|
-
import { existsSync as
|
|
3330
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
3175
3331
|
import { homedir as homedir5 } from "node:os";
|
|
3176
3332
|
import { join as join7 } from "node:path";
|
|
3177
3333
|
async function checkCliVersion() {
|
|
@@ -3237,6 +3393,47 @@ async function validateApiKey(apiKey) {
|
|
|
3237
3393
|
};
|
|
3238
3394
|
}
|
|
3239
3395
|
}
|
|
3396
|
+
async function checkIntegrations(apiKey) {
|
|
3397
|
+
try {
|
|
3398
|
+
const client = await createClient(apiKey);
|
|
3399
|
+
const timeout = new Promise((_2, reject) => setTimeout(() => reject(new Error("Integrations check timed out")), 1e4));
|
|
3400
|
+
const data = await Promise.race([
|
|
3401
|
+
client.callTool("outlit_list_integrations", {}),
|
|
3402
|
+
timeout
|
|
3403
|
+
]);
|
|
3404
|
+
const items = data.items ?? [];
|
|
3405
|
+
const connected = items.filter((i) => i.status === "connected").length;
|
|
3406
|
+
const errors = items.filter((i) => i.status === "error").length;
|
|
3407
|
+
if (errors > 0) {
|
|
3408
|
+
return {
|
|
3409
|
+
name: "Integrations",
|
|
3410
|
+
status: "warn",
|
|
3411
|
+
message: `${connected} connected, ${errors} with errors`,
|
|
3412
|
+
detail: "Run `outlit integrations status` for details"
|
|
3413
|
+
};
|
|
3414
|
+
}
|
|
3415
|
+
if (connected === 0) {
|
|
3416
|
+
return {
|
|
3417
|
+
name: "Integrations",
|
|
3418
|
+
status: "pass",
|
|
3419
|
+
message: "No integrations connected",
|
|
3420
|
+
detail: "Run `outlit integrations list` to see available integrations"
|
|
3421
|
+
};
|
|
3422
|
+
}
|
|
3423
|
+
return {
|
|
3424
|
+
name: "Integrations",
|
|
3425
|
+
status: "pass",
|
|
3426
|
+
message: `${connected} integration(s) connected`
|
|
3427
|
+
};
|
|
3428
|
+
} catch {
|
|
3429
|
+
return {
|
|
3430
|
+
name: "Integrations",
|
|
3431
|
+
status: "warn",
|
|
3432
|
+
message: "Could not check integrations",
|
|
3433
|
+
detail: "Integration status endpoint may not be available yet"
|
|
3434
|
+
};
|
|
3435
|
+
}
|
|
3436
|
+
}
|
|
3240
3437
|
function detectAgents2() {
|
|
3241
3438
|
const detected = detectAgents();
|
|
3242
3439
|
if (detected.length === 0) {
|
|
@@ -3253,13 +3450,13 @@ function detectAgents2() {
|
|
|
3253
3450
|
for (const agentId of detected) {
|
|
3254
3451
|
const meta = agentChecks[agentId];
|
|
3255
3452
|
if (agentId === "openclaw") {
|
|
3256
|
-
const openclawBase =
|
|
3257
|
-
const hasSkill =
|
|
3453
|
+
const openclawBase = join7(home, ".openclaw", "skills");
|
|
3454
|
+
const hasSkill = existsSync3(join7(openclawBase, "outlit", "SKILL.md"));
|
|
3258
3455
|
results.push({
|
|
3259
3456
|
name: meta.name,
|
|
3260
3457
|
status: hasSkill ? "pass" : "warn",
|
|
3261
3458
|
message: hasSkill ? "Installed, Outlit skill configured" : "Installed, but Outlit skill not found",
|
|
3262
|
-
detail: hasSkill ? undefined : "Run `
|
|
3459
|
+
detail: hasSkill ? undefined : "Run `clawhub install outlit` to configure"
|
|
3263
3460
|
});
|
|
3264
3461
|
continue;
|
|
3265
3462
|
}
|
|
@@ -3272,7 +3469,7 @@ function detectAgents2() {
|
|
|
3272
3469
|
});
|
|
3273
3470
|
if (agentId === "claude-code") {
|
|
3274
3471
|
const skillsDir = join7(home, ".claude", "skills");
|
|
3275
|
-
const hasSkills =
|
|
3472
|
+
const hasSkills = existsSync3(join7(skillsDir, "outlit-cli")) || existsSync3(join7(skillsDir, "outlit-sdk")) || existsSync3(join7(skillsDir, "outlit-mcp"));
|
|
3276
3473
|
results.push({
|
|
3277
3474
|
name: "Agent Skills",
|
|
3278
3475
|
status: hasSkills ? "pass" : "warn",
|
|
@@ -3283,7 +3480,7 @@ function detectAgents2() {
|
|
|
3283
3480
|
continue;
|
|
3284
3481
|
}
|
|
3285
3482
|
const { path, key } = meta.configCheck;
|
|
3286
|
-
if (!
|
|
3483
|
+
if (!existsSync3(path)) {
|
|
3287
3484
|
results.push({
|
|
3288
3485
|
name: meta.name,
|
|
3289
3486
|
status: "warn",
|
|
@@ -3339,6 +3536,7 @@ var init_doctor = __esm(() => {
|
|
|
3339
3536
|
init_auth();
|
|
3340
3537
|
init_output2();
|
|
3341
3538
|
init_api();
|
|
3539
|
+
init_client();
|
|
3342
3540
|
init_config();
|
|
3343
3541
|
init_output();
|
|
3344
3542
|
init_tty();
|
|
@@ -3383,7 +3581,11 @@ var init_doctor = __esm(() => {
|
|
|
3383
3581
|
const credential = resolveApiKey(args["api-key"]);
|
|
3384
3582
|
checks.push(checkApiKeyPresence(credential));
|
|
3385
3583
|
if (credential) {
|
|
3386
|
-
|
|
3584
|
+
const apiCheck = await validateApiKey(credential.key);
|
|
3585
|
+
checks.push(apiCheck);
|
|
3586
|
+
if (apiCheck.status !== "fail") {
|
|
3587
|
+
checks.push(await checkIntegrations(credential.key));
|
|
3588
|
+
}
|
|
3387
3589
|
} else {
|
|
3388
3590
|
checks.push({
|
|
3389
3591
|
name: "API validation",
|
|
@@ -3398,7 +3600,8 @@ var init_doctor = __esm(() => {
|
|
|
3398
3600
|
} else {
|
|
3399
3601
|
printChecks(checks);
|
|
3400
3602
|
}
|
|
3401
|
-
|
|
3603
|
+
if (hasFail)
|
|
3604
|
+
process.exit(1);
|
|
3402
3605
|
}
|
|
3403
3606
|
});
|
|
3404
3607
|
agentChecks = {
|
|
@@ -3494,16 +3697,19 @@ var init_search = __esm(() => {
|
|
|
3494
3697
|
meta: {
|
|
3495
3698
|
name: "search",
|
|
3496
3699
|
description: [
|
|
3497
|
-
"Search customer context using natural language.",
|
|
3700
|
+
"Search customer context using natural language or direct source lookup.",
|
|
3498
3701
|
"",
|
|
3499
|
-
"Performs a semantic search over customer
|
|
3702
|
+
"Performs a semantic search over customer facts, emails, and transcripts.",
|
|
3500
3703
|
"Optionally scope to a specific customer with --customer.",
|
|
3704
|
+
"Use --source-type and --source-id for direct source lookup (query becomes optional).",
|
|
3501
3705
|
"",
|
|
3502
3706
|
"Examples:",
|
|
3503
3707
|
" outlit search 'pricing objections last quarter'",
|
|
3504
3708
|
" outlit search 'churn risk signals' --customer acme.com",
|
|
3505
3709
|
" outlit search 'expansion opportunities' --top-k 50 --json",
|
|
3506
3710
|
" outlit search 'support escalations' --after 2025-01-01 --before 2025-03-31",
|
|
3711
|
+
" outlit search 'onboarding issues' --source-types call_transcript,email",
|
|
3712
|
+
" outlit search --source-type call_transcript --source-id call_123",
|
|
3507
3713
|
"",
|
|
3508
3714
|
AGENT_JSON_HINT
|
|
3509
3715
|
].join(`
|
|
@@ -3514,8 +3720,8 @@ var init_search = __esm(() => {
|
|
|
3514
3720
|
...outputArgs,
|
|
3515
3721
|
query: {
|
|
3516
3722
|
type: "positional",
|
|
3517
|
-
description: "Natural language search query",
|
|
3518
|
-
required:
|
|
3723
|
+
description: "Natural language search query. Optional when --source-type and --source-id are provided.",
|
|
3724
|
+
required: false
|
|
3519
3725
|
},
|
|
3520
3726
|
customer: {
|
|
3521
3727
|
type: "string",
|
|
@@ -3523,7 +3729,7 @@ var init_search = __esm(() => {
|
|
|
3523
3729
|
},
|
|
3524
3730
|
"top-k": {
|
|
3525
3731
|
type: "string",
|
|
3526
|
-
description: "Maximum number of results to return. Default: 20.",
|
|
3732
|
+
description: "Maximum number of results to return (1–50). Default: 20.",
|
|
3527
3733
|
default: "20"
|
|
3528
3734
|
},
|
|
3529
3735
|
after: {
|
|
@@ -3533,25 +3739,64 @@ var init_search = __esm(() => {
|
|
|
3533
3739
|
before: {
|
|
3534
3740
|
type: "string",
|
|
3535
3741
|
description: "Filter to events occurring before this date (ISO 8601, e.g. 2025-03-31)"
|
|
3742
|
+
},
|
|
3743
|
+
"source-types": {
|
|
3744
|
+
type: "string",
|
|
3745
|
+
description: "Comma-separated broad source type filter"
|
|
3746
|
+
},
|
|
3747
|
+
"source-type": {
|
|
3748
|
+
type: "string",
|
|
3749
|
+
description: "Exact source type for direct lookup (must pair with --source-id)"
|
|
3750
|
+
},
|
|
3751
|
+
"source-id": {
|
|
3752
|
+
type: "string",
|
|
3753
|
+
description: "Exact source ID for direct lookup (must pair with --source-type)"
|
|
3536
3754
|
}
|
|
3537
3755
|
},
|
|
3538
3756
|
async run({ args }) {
|
|
3539
3757
|
const json = !!args.json;
|
|
3540
|
-
const client = await getClientOrExit(args["api-key"], json);
|
|
3541
3758
|
const topK = Number(args["top-k"]);
|
|
3542
|
-
if (!Number.isFinite(topK) || topK
|
|
3543
|
-
return outputError({ message: "--top-k must be
|
|
3759
|
+
if (!Number.isFinite(topK) || topK < 1 || topK > 50) {
|
|
3760
|
+
return outputError({ message: "--top-k must be an integer between 1 and 50", code: "invalid_input" }, json);
|
|
3544
3761
|
}
|
|
3545
|
-
const
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3762
|
+
const sourceType = args["source-type"];
|
|
3763
|
+
const sourceId = args["source-id"];
|
|
3764
|
+
const sourceTypes = args["source-types"];
|
|
3765
|
+
if (sourceType && !sourceId || !sourceType && sourceId) {
|
|
3766
|
+
return outputError({
|
|
3767
|
+
message: "--source-type and --source-id must be provided together",
|
|
3768
|
+
code: "invalid_input"
|
|
3769
|
+
}, json);
|
|
3770
|
+
}
|
|
3771
|
+
if (!args.query && !sourceType) {
|
|
3772
|
+
return outputError({
|
|
3773
|
+
message: "A query argument or --source-type and --source-id are required",
|
|
3774
|
+
code: "invalid_input"
|
|
3775
|
+
}, json);
|
|
3776
|
+
}
|
|
3777
|
+
if (sourceTypes && sourceType) {
|
|
3778
|
+
return outputError({
|
|
3779
|
+
message: "--source-types cannot be combined with --source-type/--source-id",
|
|
3780
|
+
code: "invalid_input"
|
|
3781
|
+
}, json);
|
|
3782
|
+
}
|
|
3783
|
+
const client = await getClientOrExit(args["api-key"], json);
|
|
3784
|
+
const parseCsv = (value) => value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
3785
|
+
const params = { topK };
|
|
3786
|
+
if (args.query)
|
|
3787
|
+
params.query = args.query;
|
|
3549
3788
|
if (args.customer)
|
|
3550
3789
|
params.customer = args.customer;
|
|
3551
3790
|
if (args.after)
|
|
3552
3791
|
params.occurredAfter = args.after;
|
|
3553
3792
|
if (args.before)
|
|
3554
3793
|
params.occurredBefore = args.before;
|
|
3794
|
+
if (sourceTypes)
|
|
3795
|
+
params.sourceTypes = parseCsv(sourceTypes);
|
|
3796
|
+
if (sourceType)
|
|
3797
|
+
params.sourceType = sourceType;
|
|
3798
|
+
if (sourceId)
|
|
3799
|
+
params.sourceId = sourceId;
|
|
3555
3800
|
return runTool(client, "outlit_search_customer_context", params, json);
|
|
3556
3801
|
}
|
|
3557
3802
|
});
|
|
@@ -3686,6 +3931,569 @@ var init_schema = __esm(() => {
|
|
|
3686
3931
|
});
|
|
3687
3932
|
});
|
|
3688
3933
|
|
|
3934
|
+
// src/lib/providers.ts
|
|
3935
|
+
function resolveProvider(input) {
|
|
3936
|
+
const normalized = input.toLowerCase().trim();
|
|
3937
|
+
const provider = INTEGRATION_PROVIDERS[normalized];
|
|
3938
|
+
if (provider)
|
|
3939
|
+
return { provider, cliName: normalized };
|
|
3940
|
+
const suggestion = findClosestMatch(normalized);
|
|
3941
|
+
const base = `Unknown integration: "${input}". Available: ${PROVIDER_NAMES.join(", ")}`;
|
|
3942
|
+
if (suggestion) {
|
|
3943
|
+
return { error: `${base}
|
|
3944
|
+
|
|
3945
|
+
Did you mean "${suggestion}"?`, suggestion };
|
|
3946
|
+
}
|
|
3947
|
+
return { error: base };
|
|
3948
|
+
}
|
|
3949
|
+
function resolveProviderOrExit(input, json) {
|
|
3950
|
+
const result = resolveProvider(input);
|
|
3951
|
+
if ("error" in result) {
|
|
3952
|
+
return outputError({ message: result.error, code: "unknown_provider" }, json);
|
|
3953
|
+
}
|
|
3954
|
+
return result;
|
|
3955
|
+
}
|
|
3956
|
+
function findClosestMatch(input) {
|
|
3957
|
+
return PROVIDER_NAMES.find((name) => name.startsWith(input) || input.startsWith(name)) ?? null;
|
|
3958
|
+
}
|
|
3959
|
+
var INTEGRATION_PROVIDERS, PROVIDER_NAMES;
|
|
3960
|
+
var init_providers = __esm(() => {
|
|
3961
|
+
init_output();
|
|
3962
|
+
INTEGRATION_PROVIDERS = {
|
|
3963
|
+
slack: { id: "slack", name: "Slack", category: "communication", authType: "oauth" },
|
|
3964
|
+
gmail: { id: "google-mail", name: "Gmail", category: "communication", authType: "oauth" },
|
|
3965
|
+
"google-calendar": {
|
|
3966
|
+
id: "google-calendar",
|
|
3967
|
+
name: "Google Calendar",
|
|
3968
|
+
category: "calendar",
|
|
3969
|
+
authType: "oauth"
|
|
3970
|
+
},
|
|
3971
|
+
pylon: {
|
|
3972
|
+
id: "pylon",
|
|
3973
|
+
name: "Pylon",
|
|
3974
|
+
category: "support",
|
|
3975
|
+
authType: "api_key",
|
|
3976
|
+
configFields: [{ key: "apiKey", label: "API Key", secret: true }]
|
|
3977
|
+
},
|
|
3978
|
+
stripe: {
|
|
3979
|
+
id: "brex-api-key",
|
|
3980
|
+
name: "Stripe",
|
|
3981
|
+
category: "billing",
|
|
3982
|
+
authType: "api_key",
|
|
3983
|
+
configFields: [{ key: "apiKey", label: "API Key", secret: true }]
|
|
3984
|
+
},
|
|
3985
|
+
fireflies: {
|
|
3986
|
+
id: "fireflies",
|
|
3987
|
+
name: "Fireflies",
|
|
3988
|
+
category: "calls",
|
|
3989
|
+
authType: "api_key",
|
|
3990
|
+
configFields: [{ key: "apiKey", label: "API Key", secret: true }]
|
|
3991
|
+
},
|
|
3992
|
+
posthog: {
|
|
3993
|
+
id: "posthog",
|
|
3994
|
+
name: "PostHog",
|
|
3995
|
+
category: "analytics",
|
|
3996
|
+
authType: "api_key",
|
|
3997
|
+
configFields: [
|
|
3998
|
+
{ key: "apiKey", label: "API Key", secret: true },
|
|
3999
|
+
{ key: "region", label: "Region (us or eu)" },
|
|
4000
|
+
{ key: "projectId", label: "Project ID" }
|
|
4001
|
+
]
|
|
4002
|
+
},
|
|
4003
|
+
supabase: {
|
|
4004
|
+
id: "supabase",
|
|
4005
|
+
name: "Supabase",
|
|
4006
|
+
category: "data",
|
|
4007
|
+
authType: "api_key",
|
|
4008
|
+
configFields: [
|
|
4009
|
+
{ key: "projectUrl", label: "Project URL" },
|
|
4010
|
+
{ key: "serviceRoleKey", label: "Service Role Key", secret: true }
|
|
4011
|
+
]
|
|
4012
|
+
},
|
|
4013
|
+
clerk: {
|
|
4014
|
+
id: "clerk",
|
|
4015
|
+
name: "Clerk",
|
|
4016
|
+
category: "auth",
|
|
4017
|
+
authType: "api_key",
|
|
4018
|
+
configFields: [{ key: "secretKey", label: "Secret Key", secret: true }]
|
|
4019
|
+
}
|
|
4020
|
+
};
|
|
4021
|
+
PROVIDER_NAMES = Object.keys(INTEGRATION_PROVIDERS).sort();
|
|
4022
|
+
});
|
|
4023
|
+
|
|
4024
|
+
// src/commands/integrations/list.ts
|
|
4025
|
+
var exports_list3 = {};
|
|
4026
|
+
__export(exports_list3, {
|
|
4027
|
+
default: () => list_default3
|
|
4028
|
+
});
|
|
4029
|
+
var list_default3;
|
|
4030
|
+
var init_list3 = __esm(() => {
|
|
4031
|
+
init_dist();
|
|
4032
|
+
init_auth();
|
|
4033
|
+
init_output2();
|
|
4034
|
+
init_api();
|
|
4035
|
+
list_default3 = defineCommand2({
|
|
4036
|
+
meta: {
|
|
4037
|
+
name: "list",
|
|
4038
|
+
description: [
|
|
4039
|
+
"List available integrations and their connection status.",
|
|
4040
|
+
"",
|
|
4041
|
+
"Shows all supported third-party integrations with whether they",
|
|
4042
|
+
"are connected, available, or in an error state.",
|
|
4043
|
+
"",
|
|
4044
|
+
"Examples:",
|
|
4045
|
+
" outlit integrations list",
|
|
4046
|
+
" outlit integrations list --json",
|
|
4047
|
+
"",
|
|
4048
|
+
AGENT_JSON_HINT
|
|
4049
|
+
].join(`
|
|
4050
|
+
`)
|
|
4051
|
+
},
|
|
4052
|
+
args: {
|
|
4053
|
+
...authArgs,
|
|
4054
|
+
...outputArgs
|
|
4055
|
+
},
|
|
4056
|
+
async run({ args }) {
|
|
4057
|
+
const json = !!args.json;
|
|
4058
|
+
const client = await getClientOrExit(args["api-key"], json);
|
|
4059
|
+
return runTool(client, "outlit_list_integrations", {}, json, {
|
|
4060
|
+
spinnerMessage: "Fetching integrations...",
|
|
4061
|
+
table: {
|
|
4062
|
+
columns: [
|
|
4063
|
+
{ header: "Name", key: "name", format: (v) => truncate(v, 24) },
|
|
4064
|
+
{ header: "Category", key: "category", format: capitalize },
|
|
4065
|
+
{ header: "Status", key: "status" },
|
|
4066
|
+
{ header: "Last Synced", key: "lastDataReceivedAt", format: relativeDate }
|
|
4067
|
+
]
|
|
4068
|
+
}
|
|
4069
|
+
});
|
|
4070
|
+
}
|
|
4071
|
+
});
|
|
4072
|
+
});
|
|
4073
|
+
|
|
4074
|
+
// src/lib/poll.ts
|
|
4075
|
+
async function pollUntil(fn, predicate, opts = {}) {
|
|
4076
|
+
const intervalMs = opts.intervalMs ?? 2000;
|
|
4077
|
+
const timeoutMs = opts.timeoutMs ?? 300000;
|
|
4078
|
+
const start = Date.now();
|
|
4079
|
+
while (Date.now() - start < timeoutMs) {
|
|
4080
|
+
try {
|
|
4081
|
+
const result = await fn();
|
|
4082
|
+
if (predicate(result))
|
|
4083
|
+
return result;
|
|
4084
|
+
} catch {}
|
|
4085
|
+
if (opts.spinner && opts.spinnerMessage) {
|
|
4086
|
+
const elapsed = Math.floor((Date.now() - start) / 1000);
|
|
4087
|
+
opts.spinner.update(`${opts.spinnerMessage} (${elapsed}s)`);
|
|
4088
|
+
}
|
|
4089
|
+
await sleep(intervalMs);
|
|
4090
|
+
}
|
|
4091
|
+
return null;
|
|
4092
|
+
}
|
|
4093
|
+
function sleep(ms) {
|
|
4094
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4095
|
+
}
|
|
4096
|
+
|
|
4097
|
+
// src/commands/integrations/add.ts
|
|
4098
|
+
var exports_add = {};
|
|
4099
|
+
__export(exports_add, {
|
|
4100
|
+
default: () => add_default
|
|
4101
|
+
});
|
|
4102
|
+
async function addApiKeyProvider(client, provider, cliName, json, rawConfig) {
|
|
4103
|
+
const fields = provider.configFields ?? [];
|
|
4104
|
+
let config;
|
|
4105
|
+
if (rawConfig) {
|
|
4106
|
+
try {
|
|
4107
|
+
const parsed = JSON.parse(rawConfig);
|
|
4108
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
4109
|
+
return outputError({ message: "Invalid JSON in --config. Expected a JSON object.", code: "invalid_config" }, json);
|
|
4110
|
+
}
|
|
4111
|
+
config = parsed;
|
|
4112
|
+
} catch {
|
|
4113
|
+
return outputError({ message: "Invalid JSON in --config. Expected a JSON object.", code: "invalid_config" }, json);
|
|
4114
|
+
}
|
|
4115
|
+
const missing = fields.filter((f) => !config[f.key]);
|
|
4116
|
+
if (missing.length > 0) {
|
|
4117
|
+
return outputError({
|
|
4118
|
+
message: `Missing required fields: ${missing.map((f) => f.key).join(", ")}`,
|
|
4119
|
+
code: "invalid_config"
|
|
4120
|
+
}, json);
|
|
4121
|
+
}
|
|
4122
|
+
} else if (isInteractive() && !isJsonMode(json)) {
|
|
4123
|
+
console.log(`
|
|
4124
|
+
Configure ${provider.name}:
|
|
4125
|
+
`);
|
|
4126
|
+
config = {};
|
|
4127
|
+
for (const field of fields) {
|
|
4128
|
+
config[field.key] = await promptInput(` ${field.label}`, { secret: field.secret });
|
|
4129
|
+
}
|
|
4130
|
+
console.log();
|
|
4131
|
+
} else {
|
|
4132
|
+
return outputResult({
|
|
4133
|
+
status: "config_required",
|
|
4134
|
+
provider: cliName,
|
|
4135
|
+
message: `${provider.name} requires API key configuration. Pass --config with the required fields.`,
|
|
4136
|
+
requiredFields: fields.map((f) => ({ key: f.key, label: f.label }))
|
|
4137
|
+
});
|
|
4138
|
+
}
|
|
4139
|
+
const spinner = createSpinner(`Connecting ${provider.name}...`);
|
|
4140
|
+
try {
|
|
4141
|
+
await client.callTool("outlit_connect_integration", {
|
|
4142
|
+
provider: provider.id,
|
|
4143
|
+
config
|
|
4144
|
+
});
|
|
4145
|
+
spinner.stop(`${provider.name} connected successfully!`);
|
|
4146
|
+
if (isJsonMode(json)) {
|
|
4147
|
+
return outputResult({
|
|
4148
|
+
status: "connected",
|
|
4149
|
+
provider: cliName
|
|
4150
|
+
});
|
|
4151
|
+
}
|
|
4152
|
+
console.log(` Use \`outlit integrations status ${cliName}\` to check sync progress.`);
|
|
4153
|
+
} catch (err) {
|
|
4154
|
+
spinner.fail(`Failed to connect ${provider.name}`);
|
|
4155
|
+
return outputError({ message: errorMessage(err, "Failed to connect integration"), code: "api_error" }, json);
|
|
4156
|
+
}
|
|
4157
|
+
}
|
|
4158
|
+
async function addOAuthProvider(client, provider, cliName, json, force) {
|
|
4159
|
+
const spinner = createSpinner(`Connecting ${provider.name}...`);
|
|
4160
|
+
let connectData;
|
|
4161
|
+
try {
|
|
4162
|
+
connectData = await client.callTool("outlit_connect_integration", {
|
|
4163
|
+
provider: provider.id
|
|
4164
|
+
});
|
|
4165
|
+
} catch (err) {
|
|
4166
|
+
spinner.fail(`Failed to initiate ${provider.name} connection`);
|
|
4167
|
+
return outputError({ message: errorMessage(err, "Failed to start connection flow"), code: "api_error" }, json);
|
|
4168
|
+
}
|
|
4169
|
+
if (connectData.alreadyConnected && !force) {
|
|
4170
|
+
spinner.stop(`${provider.name} is already connected`);
|
|
4171
|
+
if (isJsonMode(json)) {
|
|
4172
|
+
return outputResult({
|
|
4173
|
+
status: "already_connected",
|
|
4174
|
+
provider: cliName,
|
|
4175
|
+
message: `${provider.name} is already connected. Use --force to reconnect.`
|
|
4176
|
+
});
|
|
4177
|
+
}
|
|
4178
|
+
console.log(`
|
|
4179
|
+
${provider.name} is already connected.`);
|
|
4180
|
+
console.log(` To reconnect, run: outlit integrations add ${cliName} --force`);
|
|
4181
|
+
return;
|
|
4182
|
+
}
|
|
4183
|
+
const integrationsUrl = `${client.baseUrl}/integrations`;
|
|
4184
|
+
spinner.update(`Opening browser for ${provider.name} authentication...`);
|
|
4185
|
+
const opened = openBrowser(integrationsUrl);
|
|
4186
|
+
if (!opened) {
|
|
4187
|
+
spinner.stop("Could not open browser automatically");
|
|
4188
|
+
if (isJsonMode(json)) {
|
|
4189
|
+
return outputResult({
|
|
4190
|
+
status: "browser_failed",
|
|
4191
|
+
provider: cliName,
|
|
4192
|
+
url: integrationsUrl,
|
|
4193
|
+
sessionId: connectData.sessionId
|
|
4194
|
+
});
|
|
4195
|
+
}
|
|
4196
|
+
console.log(`
|
|
4197
|
+
Open this URL in your browser to connect ${provider.name}:`);
|
|
4198
|
+
console.log(` ${integrationsUrl}
|
|
4199
|
+
`);
|
|
4200
|
+
} else {
|
|
4201
|
+
spinner.stop(`Browser opened for ${provider.name} authentication`);
|
|
4202
|
+
}
|
|
4203
|
+
if (isJsonMode(json)) {
|
|
4204
|
+
return outputResult({
|
|
4205
|
+
status: "awaiting_auth",
|
|
4206
|
+
provider: cliName,
|
|
4207
|
+
sessionId: connectData.sessionId
|
|
4208
|
+
});
|
|
4209
|
+
}
|
|
4210
|
+
await waitForConnection(client, connectData.sessionId, provider, cliName);
|
|
4211
|
+
}
|
|
4212
|
+
async function waitForConnection(client, sessionId, provider, cliName) {
|
|
4213
|
+
const spinner = createSpinner(`Waiting for ${provider.name} authentication...`);
|
|
4214
|
+
const result = await pollUntil(() => client.callTool("outlit_connect_status", { sessionId }).then((r) => r), (r) => r.status !== "pending", {
|
|
4215
|
+
intervalMs: 2000,
|
|
4216
|
+
timeoutMs: 300000,
|
|
4217
|
+
spinner,
|
|
4218
|
+
spinnerMessage: `Waiting for ${provider.name} authentication...`
|
|
4219
|
+
});
|
|
4220
|
+
if (!result || result.status === "expired") {
|
|
4221
|
+
spinner.fail("Connection timed out");
|
|
4222
|
+
console.log(`
|
|
4223
|
+
The authentication session expired.`);
|
|
4224
|
+
console.log(` Run \`outlit integrations add ${cliName}\` to try again.`);
|
|
4225
|
+
process.exit(1);
|
|
4226
|
+
}
|
|
4227
|
+
if (result.status === "failed") {
|
|
4228
|
+
spinner.fail(`${provider.name} connection failed`);
|
|
4229
|
+
if (result.error)
|
|
4230
|
+
console.log(`
|
|
4231
|
+
${result.error}`);
|
|
4232
|
+
process.exit(1);
|
|
4233
|
+
}
|
|
4234
|
+
spinner.stop(`${provider.name} connected successfully!`);
|
|
4235
|
+
console.log(` Sync will begin automatically.`);
|
|
4236
|
+
console.log(` Use \`outlit integrations status ${cliName}\` to check progress.`);
|
|
4237
|
+
}
|
|
4238
|
+
var add_default;
|
|
4239
|
+
var init_add = __esm(() => {
|
|
4240
|
+
init_dist();
|
|
4241
|
+
init_auth();
|
|
4242
|
+
init_output2();
|
|
4243
|
+
init_api();
|
|
4244
|
+
init_output();
|
|
4245
|
+
init_providers();
|
|
4246
|
+
init_spinner();
|
|
4247
|
+
init_tty();
|
|
4248
|
+
add_default = defineCommand2({
|
|
4249
|
+
meta: {
|
|
4250
|
+
name: "add",
|
|
4251
|
+
description: [
|
|
4252
|
+
"Connect a new integration.",
|
|
4253
|
+
"",
|
|
4254
|
+
"For OAuth providers (Slack, Gmail, etc.), opens the browser for authentication.",
|
|
4255
|
+
"For API-key providers (Stripe, PostHog, etc.), accepts credentials via --config or interactive prompts.",
|
|
4256
|
+
"",
|
|
4257
|
+
"Examples:",
|
|
4258
|
+
" outlit integrations add slack",
|
|
4259
|
+
` outlit integrations add stripe --config '{"apiKey": "rk_xxx"}'`,
|
|
4260
|
+
" outlit integrations add posthog --json # outputs required fields as JSON",
|
|
4261
|
+
" outlit integrations add slack --force # reconnect if already connected",
|
|
4262
|
+
"",
|
|
4263
|
+
`Providers: ${PROVIDER_NAMES.join(", ")}`,
|
|
4264
|
+
"",
|
|
4265
|
+
AGENT_JSON_HINT
|
|
4266
|
+
].join(`
|
|
4267
|
+
`)
|
|
4268
|
+
},
|
|
4269
|
+
args: {
|
|
4270
|
+
...authArgs,
|
|
4271
|
+
...outputArgs,
|
|
4272
|
+
provider: {
|
|
4273
|
+
type: "positional",
|
|
4274
|
+
description: "Integration provider to connect",
|
|
4275
|
+
required: true
|
|
4276
|
+
},
|
|
4277
|
+
force: {
|
|
4278
|
+
type: "boolean",
|
|
4279
|
+
description: "Reconnect even if the integration is already connected."
|
|
4280
|
+
},
|
|
4281
|
+
config: {
|
|
4282
|
+
type: "string",
|
|
4283
|
+
description: `JSON configuration for API-key integrations (e.g. '{"apiKey": "sk_xxx"}')`
|
|
4284
|
+
}
|
|
4285
|
+
},
|
|
4286
|
+
async run({ args }) {
|
|
4287
|
+
const json = !!args.json;
|
|
4288
|
+
const client = await getClientOrExit(args["api-key"], json);
|
|
4289
|
+
const { provider, cliName } = resolveProviderOrExit(args.provider, json);
|
|
4290
|
+
if (provider.authType === "api_key") {
|
|
4291
|
+
await addApiKeyProvider(client, provider, cliName, json, args.config);
|
|
4292
|
+
} else {
|
|
4293
|
+
await addOAuthProvider(client, provider, cliName, json, !!args.force);
|
|
4294
|
+
}
|
|
4295
|
+
}
|
|
4296
|
+
});
|
|
4297
|
+
});
|
|
4298
|
+
|
|
4299
|
+
// src/commands/integrations/remove.ts
|
|
4300
|
+
var exports_remove = {};
|
|
4301
|
+
__export(exports_remove, {
|
|
4302
|
+
default: () => remove_default
|
|
4303
|
+
});
|
|
4304
|
+
var remove_default;
|
|
4305
|
+
var init_remove = __esm(() => {
|
|
4306
|
+
init_dist3();
|
|
4307
|
+
init_dist();
|
|
4308
|
+
init_auth();
|
|
4309
|
+
init_output2();
|
|
4310
|
+
init_api();
|
|
4311
|
+
init_output();
|
|
4312
|
+
init_providers();
|
|
4313
|
+
init_spinner();
|
|
4314
|
+
init_tty();
|
|
4315
|
+
remove_default = defineCommand2({
|
|
4316
|
+
meta: {
|
|
4317
|
+
name: "remove",
|
|
4318
|
+
description: [
|
|
4319
|
+
"Disconnect an integration and remove all synced data.",
|
|
4320
|
+
"",
|
|
4321
|
+
"This permanently deletes all data that was synced from the integration",
|
|
4322
|
+
"(e.g., opportunities, contacts, messages). The action cannot be undone.",
|
|
4323
|
+
"",
|
|
4324
|
+
"Examples:",
|
|
4325
|
+
" outlit integrations remove posthog",
|
|
4326
|
+
" outlit integrations remove slack --yes # skip confirmation prompt",
|
|
4327
|
+
"",
|
|
4328
|
+
AGENT_JSON_HINT
|
|
4329
|
+
].join(`
|
|
4330
|
+
`)
|
|
4331
|
+
},
|
|
4332
|
+
args: {
|
|
4333
|
+
...authArgs,
|
|
4334
|
+
...outputArgs,
|
|
4335
|
+
provider: {
|
|
4336
|
+
type: "positional",
|
|
4337
|
+
description: "Integration provider to disconnect",
|
|
4338
|
+
required: true
|
|
4339
|
+
},
|
|
4340
|
+
yes: {
|
|
4341
|
+
type: "boolean",
|
|
4342
|
+
description: "Skip confirmation prompt (required in non-interactive mode)."
|
|
4343
|
+
}
|
|
4344
|
+
},
|
|
4345
|
+
async run({ args }) {
|
|
4346
|
+
const json = !!args.json;
|
|
4347
|
+
const { provider, cliName } = resolveProviderOrExit(args.provider, json);
|
|
4348
|
+
const client = await getClientOrExit(args["api-key"], json);
|
|
4349
|
+
if (!args.yes) {
|
|
4350
|
+
if (!isInteractive() || json) {
|
|
4351
|
+
return outputError({
|
|
4352
|
+
message: `Disconnecting ${provider.name} requires confirmation. Use --yes to confirm in non-interactive or JSON mode.`,
|
|
4353
|
+
code: "confirmation_required"
|
|
4354
|
+
}, json);
|
|
4355
|
+
}
|
|
4356
|
+
R2.warn(`This will disconnect ${provider.name} and delete all synced data.
|
|
4357
|
+
This action cannot be undone.`);
|
|
4358
|
+
const confirmed = await Re({ message: `Disconnect ${provider.name}?` });
|
|
4359
|
+
if (Ct(confirmed) || !confirmed) {
|
|
4360
|
+
Ne("Cancelled.");
|
|
4361
|
+
return;
|
|
4362
|
+
}
|
|
4363
|
+
}
|
|
4364
|
+
const spinner = createSpinner(`Disconnecting ${provider.name}...`);
|
|
4365
|
+
try {
|
|
4366
|
+
const result = await client.callTool("outlit_disconnect_integration", {
|
|
4367
|
+
provider: provider.id
|
|
4368
|
+
});
|
|
4369
|
+
if (result.success) {
|
|
4370
|
+
spinner.stop(`${provider.name} disconnected. All synced data has been removed.`);
|
|
4371
|
+
if (isJsonMode(json)) {
|
|
4372
|
+
return outputResult({ success: true, provider: cliName });
|
|
4373
|
+
}
|
|
4374
|
+
} else {
|
|
4375
|
+
spinner.fail(`Failed to disconnect ${provider.name}`);
|
|
4376
|
+
return outputError({
|
|
4377
|
+
message: result.message ?? `Failed to disconnect ${provider.name}`,
|
|
4378
|
+
code: "disconnect_failed"
|
|
4379
|
+
}, json);
|
|
4380
|
+
}
|
|
4381
|
+
} catch (err) {
|
|
4382
|
+
spinner.fail(`Failed to disconnect ${provider.name}`);
|
|
4383
|
+
return outputError({ message: errorMessage(err, "Disconnect request failed"), code: "api_error" }, json);
|
|
4384
|
+
}
|
|
4385
|
+
}
|
|
4386
|
+
});
|
|
4387
|
+
});
|
|
4388
|
+
|
|
4389
|
+
// src/commands/integrations/status.ts
|
|
4390
|
+
var exports_status2 = {};
|
|
4391
|
+
__export(exports_status2, {
|
|
4392
|
+
default: () => status_default2
|
|
4393
|
+
});
|
|
4394
|
+
var status_default2;
|
|
4395
|
+
var init_status2 = __esm(() => {
|
|
4396
|
+
init_dist();
|
|
4397
|
+
init_auth();
|
|
4398
|
+
init_output2();
|
|
4399
|
+
init_api();
|
|
4400
|
+
init_providers();
|
|
4401
|
+
status_default2 = defineCommand2({
|
|
4402
|
+
meta: {
|
|
4403
|
+
name: "status",
|
|
4404
|
+
description: [
|
|
4405
|
+
"Show sync status for connected integrations.",
|
|
4406
|
+
"",
|
|
4407
|
+
"Without a provider name, shows a summary of all connected integrations.",
|
|
4408
|
+
"With a provider name, shows detailed per-model sync status.",
|
|
4409
|
+
"",
|
|
4410
|
+
"Examples:",
|
|
4411
|
+
" outlit integrations status # summary of all",
|
|
4412
|
+
" outlit integrations status stripe # detailed Stripe sync status",
|
|
4413
|
+
"",
|
|
4414
|
+
AGENT_JSON_HINT
|
|
4415
|
+
].join(`
|
|
4416
|
+
`)
|
|
4417
|
+
},
|
|
4418
|
+
args: {
|
|
4419
|
+
...authArgs,
|
|
4420
|
+
...outputArgs,
|
|
4421
|
+
provider: {
|
|
4422
|
+
type: "positional",
|
|
4423
|
+
description: "Provider name to show detailed status for (optional)",
|
|
4424
|
+
required: false
|
|
4425
|
+
}
|
|
4426
|
+
},
|
|
4427
|
+
async run({ args }) {
|
|
4428
|
+
const json = !!args.json;
|
|
4429
|
+
const client = await getClientOrExit(args["api-key"], json);
|
|
4430
|
+
if (args.provider) {
|
|
4431
|
+
const { provider } = resolveProviderOrExit(args.provider, json);
|
|
4432
|
+
return runTool(client, "outlit_integration_sync_status", { provider: provider.id }, json, {
|
|
4433
|
+
spinnerMessage: "Fetching sync status...",
|
|
4434
|
+
table: {
|
|
4435
|
+
columns: [
|
|
4436
|
+
{ header: "Model", key: "model" },
|
|
4437
|
+
{ header: "Status", key: "status" },
|
|
4438
|
+
{ header: "Records", key: "recordCount", format: formatNumber },
|
|
4439
|
+
{ header: "Last Synced", key: "lastSyncedAt", format: relativeDate }
|
|
4440
|
+
],
|
|
4441
|
+
itemsKey: "syncs"
|
|
4442
|
+
}
|
|
4443
|
+
});
|
|
4444
|
+
}
|
|
4445
|
+
return runTool(client, "outlit_list_integrations", { connectedOnly: true }, json, {
|
|
4446
|
+
spinnerMessage: "Fetching integration status...",
|
|
4447
|
+
table: {
|
|
4448
|
+
columns: [
|
|
4449
|
+
{ header: "Name", key: "name", format: (v) => truncate(v, 24) },
|
|
4450
|
+
{ header: "Category", key: "category", format: capitalize },
|
|
4451
|
+
{ header: "Sync Status", key: "syncStatus" },
|
|
4452
|
+
{ header: "Last Synced", key: "lastDataReceivedAt", format: relativeDate }
|
|
4453
|
+
]
|
|
4454
|
+
}
|
|
4455
|
+
});
|
|
4456
|
+
}
|
|
4457
|
+
});
|
|
4458
|
+
});
|
|
4459
|
+
|
|
4460
|
+
// src/commands/integrations/index.ts
|
|
4461
|
+
var exports_integrations = {};
|
|
4462
|
+
__export(exports_integrations, {
|
|
4463
|
+
default: () => integrations_default
|
|
4464
|
+
});
|
|
4465
|
+
var integrations_default;
|
|
4466
|
+
var init_integrations = __esm(() => {
|
|
4467
|
+
init_dist();
|
|
4468
|
+
init_providers();
|
|
4469
|
+
integrations_default = defineCommand2({
|
|
4470
|
+
meta: {
|
|
4471
|
+
name: "integrations",
|
|
4472
|
+
description: [
|
|
4473
|
+
"Manage platform integrations (communication, analytics, billing, etc.).",
|
|
4474
|
+
"",
|
|
4475
|
+
"Connect third-party services like Slack, Stripe, and PostHog",
|
|
4476
|
+
"to sync data into your Outlit workspace.",
|
|
4477
|
+
"",
|
|
4478
|
+
"Commands:",
|
|
4479
|
+
" list List available integrations and connection status",
|
|
4480
|
+
" add <provider> Connect a new integration (opens browser for OAuth)",
|
|
4481
|
+
" remove <provider> Disconnect an integration and remove synced data",
|
|
4482
|
+
" status [provider] Show sync status for connected integrations",
|
|
4483
|
+
"",
|
|
4484
|
+
`Providers: ${PROVIDER_NAMES.join(", ")}`
|
|
4485
|
+
].join(`
|
|
4486
|
+
`)
|
|
4487
|
+
},
|
|
4488
|
+
subCommands: {
|
|
4489
|
+
list: () => Promise.resolve().then(() => (init_list3(), exports_list3)).then((m) => m.default),
|
|
4490
|
+
add: () => Promise.resolve().then(() => (init_add(), exports_add)).then((m) => m.default),
|
|
4491
|
+
remove: () => Promise.resolve().then(() => (init_remove(), exports_remove)).then((m) => m.default),
|
|
4492
|
+
status: () => Promise.resolve().then(() => (init_status2(), exports_status2)).then((m) => m.default)
|
|
4493
|
+
}
|
|
4494
|
+
});
|
|
4495
|
+
});
|
|
4496
|
+
|
|
3689
4497
|
// src/commands/completions.ts
|
|
3690
4498
|
var exports_completions = {};
|
|
3691
4499
|
__export(exports_completions, {
|
|
@@ -3756,7 +4564,10 @@ function zshDescribe(items) {
|
|
|
3756
4564
|
function generateZsh() {
|
|
3757
4565
|
const topLevel = zshDescribe(COMMANDS);
|
|
3758
4566
|
const subCases = cmdsWithSubs.map((c) => {
|
|
3759
|
-
const items = [
|
|
4567
|
+
const items = [
|
|
4568
|
+
...c.subs.map((s) => ({ name: s.name, desc: s.desc })),
|
|
4569
|
+
...(c.flags ?? []).map((f) => ({ name: f.name, desc: f.desc }))
|
|
4570
|
+
];
|
|
3760
4571
|
return ` ${c.name})
|
|
3761
4572
|
completions=(${zshDescribe(items)})
|
|
3762
4573
|
_describe 'subcommand' completions
|
|
@@ -3887,7 +4698,6 @@ function generateFish() {
|
|
|
3887
4698
|
var JSON_F, API_KEY_F, LIMIT_F, CURSOR_F, COMMON, PAGINATED, ACTIVITY_ORDER, COMMANDS, cmdsWithSubs, leafCmds, SCRIPTS, completions_default;
|
|
3888
4699
|
var init_completions = __esm(() => {
|
|
3889
4700
|
init_dist();
|
|
3890
|
-
init_output2();
|
|
3891
4701
|
init_output();
|
|
3892
4702
|
JSON_F = { name: "--json", desc: "Force JSON output" };
|
|
3893
4703
|
API_KEY_F = { name: "--api-key", desc: "Outlit API key" };
|
|
@@ -3907,7 +4717,11 @@ var init_completions = __esm(() => {
|
|
|
3907
4717
|
desc: "Manage authentication",
|
|
3908
4718
|
subs: [
|
|
3909
4719
|
{ name: "signup", desc: "Create an Outlit account", flags: [JSON_F] },
|
|
3910
|
-
{
|
|
4720
|
+
{
|
|
4721
|
+
name: "login",
|
|
4722
|
+
desc: "Store API key",
|
|
4723
|
+
flags: [JSON_F, { name: "--key", desc: "API key to store" }]
|
|
4724
|
+
},
|
|
3911
4725
|
{ name: "logout", desc: "Remove stored key", flags: [JSON_F] },
|
|
3912
4726
|
{ name: "status", desc: "Check auth state", flags: [...COMMON] },
|
|
3913
4727
|
{ name: "whoami", desc: "Print masked key", flags: [...COMMON] }
|
|
@@ -3923,6 +4737,7 @@ var init_completions = __esm(() => {
|
|
|
3923
4737
|
flags: [
|
|
3924
4738
|
...PAGINATED,
|
|
3925
4739
|
...ACTIVITY_ORDER,
|
|
4740
|
+
{ name: "--trait", desc: "Filter by trait key=value pairs" },
|
|
3926
4741
|
{ name: "--billing-status", desc: "Filter by billing status" },
|
|
3927
4742
|
{ name: "--mrr-above", desc: "MRR above threshold (cents)" },
|
|
3928
4743
|
{ name: "--mrr-below", desc: "MRR below threshold (cents)" },
|
|
@@ -3964,6 +4779,7 @@ var init_completions = __esm(() => {
|
|
|
3964
4779
|
flags: [
|
|
3965
4780
|
...PAGINATED,
|
|
3966
4781
|
...ACTIVITY_ORDER,
|
|
4782
|
+
{ name: "--trait", desc: "Filter by trait key=value pairs" },
|
|
3967
4783
|
{ name: "--journey-stage", desc: "Filter by journey stage" },
|
|
3968
4784
|
{ name: "--customer-id", desc: "Filter by customer UUID" },
|
|
3969
4785
|
{ name: "--search", desc: "Search name or email" }
|
|
@@ -3997,6 +4813,28 @@ var init_completions = __esm(() => {
|
|
|
3997
4813
|
]
|
|
3998
4814
|
},
|
|
3999
4815
|
{ name: "schema", desc: "Discover table schemas", flags: [...COMMON] },
|
|
4816
|
+
{
|
|
4817
|
+
name: "integrations",
|
|
4818
|
+
desc: "Manage platform integrations",
|
|
4819
|
+
subs: [
|
|
4820
|
+
{ name: "list", desc: "List integrations and status", flags: [...COMMON] },
|
|
4821
|
+
{
|
|
4822
|
+
name: "add",
|
|
4823
|
+
desc: "Connect an integration",
|
|
4824
|
+
flags: [
|
|
4825
|
+
...COMMON,
|
|
4826
|
+
{ name: "--config", desc: "JSON config for API-key providers" },
|
|
4827
|
+
{ name: "--force", desc: "Reconnect if already connected" }
|
|
4828
|
+
]
|
|
4829
|
+
},
|
|
4830
|
+
{
|
|
4831
|
+
name: "remove",
|
|
4832
|
+
desc: "Disconnect an integration",
|
|
4833
|
+
flags: [...COMMON, { name: "--yes", desc: "Skip confirmation" }]
|
|
4834
|
+
},
|
|
4835
|
+
{ name: "status", desc: "Show sync status", flags: [...COMMON] }
|
|
4836
|
+
]
|
|
4837
|
+
},
|
|
4000
4838
|
{
|
|
4001
4839
|
name: "setup",
|
|
4002
4840
|
desc: "Configure AI agent tools",
|
|
@@ -4011,7 +4849,7 @@ var init_completions = __esm(() => {
|
|
|
4011
4849
|
]
|
|
4012
4850
|
},
|
|
4013
4851
|
{ name: "doctor", desc: "Diagnose environment", flags: [...COMMON] },
|
|
4014
|
-
{ name: "completions", desc: "Generate shell completions", flags: [
|
|
4852
|
+
{ name: "completions", desc: "Generate shell completions", flags: [] }
|
|
4015
4853
|
];
|
|
4016
4854
|
cmdsWithSubs = COMMANDS.filter((c) => c.subs?.length);
|
|
4017
4855
|
leafCmds = COMMANDS.filter((c) => !c.subs?.length && c.flags?.length);
|
|
@@ -4038,7 +4876,6 @@ var init_completions = __esm(() => {
|
|
|
4038
4876
|
`)
|
|
4039
4877
|
},
|
|
4040
4878
|
args: {
|
|
4041
|
-
...outputArgs,
|
|
4042
4879
|
shell: {
|
|
4043
4880
|
type: "positional",
|
|
4044
4881
|
description: "Shell to generate completions for (bash, zsh, fish)",
|
|
@@ -4046,14 +4883,13 @@ var init_completions = __esm(() => {
|
|
|
4046
4883
|
}
|
|
4047
4884
|
},
|
|
4048
4885
|
run({ args }) {
|
|
4049
|
-
const json = !!args.json;
|
|
4050
4886
|
const shell = args.shell;
|
|
4051
4887
|
const generate = SCRIPTS[shell];
|
|
4052
4888
|
if (!generate) {
|
|
4053
4889
|
return outputError({
|
|
4054
4890
|
message: `Unknown shell: ${shell}. Supported: bash, zsh, fish`,
|
|
4055
4891
|
code: "unknown_shell"
|
|
4056
|
-
},
|
|
4892
|
+
}, false);
|
|
4057
4893
|
}
|
|
4058
4894
|
process.stdout.write(generate());
|
|
4059
4895
|
}
|
|
@@ -4067,14 +4903,14 @@ __export(exports_setup, {
|
|
|
4067
4903
|
detectAgents: () => detectAgents3,
|
|
4068
4904
|
default: () => setup_default2
|
|
4069
4905
|
});
|
|
4070
|
-
import { execFileSync as
|
|
4071
|
-
import { existsSync as
|
|
4906
|
+
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
4907
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
4072
4908
|
import { homedir as homedir6 } from "node:os";
|
|
4073
4909
|
import { join as join8 } from "node:path";
|
|
4074
4910
|
function isCommandAvailable2(cmd) {
|
|
4075
4911
|
try {
|
|
4076
4912
|
const whichCmd = process.platform === "win32" ? "where" : "which";
|
|
4077
|
-
|
|
4913
|
+
execFileSync5(whichCmd, [cmd], { stdio: "ignore" });
|
|
4078
4914
|
return true;
|
|
4079
4915
|
} catch {
|
|
4080
4916
|
return false;
|
|
@@ -4083,17 +4919,17 @@ function isCommandAvailable2(cmd) {
|
|
|
4083
4919
|
function detectAgents3() {
|
|
4084
4920
|
const home = homedir6();
|
|
4085
4921
|
const detected = [];
|
|
4086
|
-
if (
|
|
4922
|
+
if (existsSync4(join8(home, ".cursor")))
|
|
4087
4923
|
detected.push("cursor");
|
|
4088
4924
|
if (isCommandAvailable2("claude"))
|
|
4089
4925
|
detected.push("claude-code");
|
|
4090
|
-
if (
|
|
4926
|
+
if (existsSync4(getClaudeDesktopConfigPath()))
|
|
4091
4927
|
detected.push("claude-desktop");
|
|
4092
|
-
if (isCommandAvailable2("code") ||
|
|
4928
|
+
if (isCommandAvailable2("code") || existsSync4(join8(process.cwd(), ".vscode")))
|
|
4093
4929
|
detected.push("vscode");
|
|
4094
4930
|
if (isCommandAvailable2("gemini"))
|
|
4095
4931
|
detected.push("gemini");
|
|
4096
|
-
if (
|
|
4932
|
+
if (existsSync4(join8(home, ".openclaw", "skills")))
|
|
4097
4933
|
detected.push("openclaw");
|
|
4098
4934
|
return detected;
|
|
4099
4935
|
}
|
|
@@ -4589,6 +5425,7 @@ For AI agents: commands auto-output JSON when stdout is piped. No --json flag ne
|
|
|
4589
5425
|
search: () => Promise.resolve().then(() => (init_search(), exports_search)).then((m) => m.default),
|
|
4590
5426
|
sql: () => Promise.resolve().then(() => (init_sql(), exports_sql)).then((m) => m.default),
|
|
4591
5427
|
schema: () => Promise.resolve().then(() => (init_schema(), exports_schema)).then((m) => m.default),
|
|
5428
|
+
integrations: () => Promise.resolve().then(() => (init_integrations(), exports_integrations)).then((m) => m.default),
|
|
4592
5429
|
completions: () => Promise.resolve().then(() => (init_completions(), exports_completions)).then((m) => m.default),
|
|
4593
5430
|
setup: () => Promise.resolve().then(() => (init_setup3(), exports_setup)).then((m) => m.default)
|
|
4594
5431
|
}
|