@outlit/cli 1.4.1 → 1.6.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.
- package/dist/cli.js +2188 -922
- package/package.json +4 -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.6.0",
|
|
108
108
|
description: "CLI for Outlit customer intelligence platform",
|
|
109
109
|
license: "Apache-2.0",
|
|
110
110
|
repository: {
|
|
@@ -134,8 +134,9 @@ var init_package = __esm(() => {
|
|
|
134
134
|
typecheck: "tsc --noEmit"
|
|
135
135
|
},
|
|
136
136
|
dependencies: {
|
|
137
|
-
|
|
138
|
-
"@
|
|
137
|
+
"@clack/prompts": "^1.0.1",
|
|
138
|
+
"@outlit/tools": "^0.1.0",
|
|
139
|
+
citty: "^0.2.1"
|
|
139
140
|
},
|
|
140
141
|
devDependencies: {
|
|
141
142
|
typescript: "^5.9.3",
|
|
@@ -222,6 +223,70 @@ var init_output = __esm(() => {
|
|
|
222
223
|
init_tty();
|
|
223
224
|
});
|
|
224
225
|
|
|
226
|
+
// src/lib/config.ts
|
|
227
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
228
|
+
import { homedir } from "node:os";
|
|
229
|
+
import { dirname, join } from "node:path";
|
|
230
|
+
function isEnoentError(err) {
|
|
231
|
+
return err instanceof Error && err.code === "ENOENT";
|
|
232
|
+
}
|
|
233
|
+
function splitCsv(value) {
|
|
234
|
+
return value.split(",").map((s) => s.trim());
|
|
235
|
+
}
|
|
236
|
+
function getConfigDir() {
|
|
237
|
+
if (process.platform === "win32") {
|
|
238
|
+
return join(process.env.APPDATA ?? join(homedir(), "AppData", "Roaming"), "outlit");
|
|
239
|
+
}
|
|
240
|
+
return join(process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config"), "outlit");
|
|
241
|
+
}
|
|
242
|
+
function resolveApiKey(flagValue) {
|
|
243
|
+
if (flagValue)
|
|
244
|
+
return { key: flagValue, source: "flag" };
|
|
245
|
+
const envKey = process.env.OUTLIT_API_KEY;
|
|
246
|
+
if (envKey)
|
|
247
|
+
return { key: envKey, source: "env" };
|
|
248
|
+
const credPath = join(getConfigDir(), "credentials.json");
|
|
249
|
+
if (existsSync(credPath)) {
|
|
250
|
+
try {
|
|
251
|
+
const raw = readFileSync(credPath, "utf-8");
|
|
252
|
+
const config = JSON.parse(raw);
|
|
253
|
+
if (config.apiKey)
|
|
254
|
+
return { key: config.apiKey, source: "config" };
|
|
255
|
+
} catch {}
|
|
256
|
+
}
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
function maskKey(key) {
|
|
260
|
+
if (key.length <= 9)
|
|
261
|
+
return key;
|
|
262
|
+
return `${key.slice(0, 5)}...${key.slice(-4)}`;
|
|
263
|
+
}
|
|
264
|
+
function requireCredential(flagApiKey, json) {
|
|
265
|
+
const credential = resolveApiKey(flagApiKey);
|
|
266
|
+
if (!credential) {
|
|
267
|
+
return outputError({
|
|
268
|
+
message: "Not authenticated. Run `outlit auth login` or pass --api-key.",
|
|
269
|
+
code: "not_authenticated"
|
|
270
|
+
}, json);
|
|
271
|
+
}
|
|
272
|
+
return credential;
|
|
273
|
+
}
|
|
274
|
+
function storeApiKey(apiKey) {
|
|
275
|
+
const configDir = getConfigDir();
|
|
276
|
+
mkdirSync(configDir, { recursive: true, mode: 448 });
|
|
277
|
+
const credPath = join(configDir, "credentials.json");
|
|
278
|
+
writeFileSync(credPath, JSON.stringify({ apiKey }, null, 2), { mode: 384 });
|
|
279
|
+
return credPath;
|
|
280
|
+
}
|
|
281
|
+
var CLI_VERSION2, 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;
|
|
282
|
+
var init_config = __esm(() => {
|
|
283
|
+
init_package();
|
|
284
|
+
init_output();
|
|
285
|
+
init_tty();
|
|
286
|
+
CLI_VERSION2 = package_default.version;
|
|
287
|
+
TICK2 = `\x1B[32m${isUnicodeSupported ? String.fromCodePoint(10003) : String.fromCodePoint(8730)}\x1B[0m`;
|
|
288
|
+
});
|
|
289
|
+
|
|
225
290
|
// ../../node_modules/.bun/citty@0.2.1/node_modules/citty/dist/index.mjs
|
|
226
291
|
function defineCommand2(def) {
|
|
227
292
|
return def;
|
|
@@ -1375,109 +1440,6 @@ Note: JSON is also auto-enabled when stdout is piped (e.g. in CI, scripts, or AI
|
|
|
1375
1440
|
};
|
|
1376
1441
|
});
|
|
1377
1442
|
|
|
1378
|
-
// src/lib/config.ts
|
|
1379
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
1380
|
-
import { homedir } from "node:os";
|
|
1381
|
-
import { dirname, join } from "node:path";
|
|
1382
|
-
function isEnoentError(err) {
|
|
1383
|
-
return err instanceof Error && err.code === "ENOENT";
|
|
1384
|
-
}
|
|
1385
|
-
function splitCsv(value) {
|
|
1386
|
-
return value.split(",").map((s) => s.trim());
|
|
1387
|
-
}
|
|
1388
|
-
function getClaudeDesktopConfigPath() {
|
|
1389
|
-
const home = homedir();
|
|
1390
|
-
switch (process.platform) {
|
|
1391
|
-
case "win32":
|
|
1392
|
-
return join(process.env.APPDATA ?? join(home, "AppData", "Roaming"), "Claude", "claude_desktop_config.json");
|
|
1393
|
-
case "darwin":
|
|
1394
|
-
return join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
1395
|
-
default:
|
|
1396
|
-
return join(home, ".config", "Claude", "claude_desktop_config.json");
|
|
1397
|
-
}
|
|
1398
|
-
}
|
|
1399
|
-
function getConfigDir() {
|
|
1400
|
-
if (process.platform === "win32") {
|
|
1401
|
-
return join(process.env.APPDATA ?? join(homedir(), "AppData", "Roaming"), "outlit");
|
|
1402
|
-
}
|
|
1403
|
-
return join(process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config"), "outlit");
|
|
1404
|
-
}
|
|
1405
|
-
function resolveApiKey(flagValue) {
|
|
1406
|
-
if (flagValue)
|
|
1407
|
-
return { key: flagValue, source: "flag" };
|
|
1408
|
-
const envKey = process.env.OUTLIT_API_KEY;
|
|
1409
|
-
if (envKey)
|
|
1410
|
-
return { key: envKey, source: "env" };
|
|
1411
|
-
const credPath = join(getConfigDir(), "credentials.json");
|
|
1412
|
-
if (existsSync(credPath)) {
|
|
1413
|
-
try {
|
|
1414
|
-
const raw = readFileSync(credPath, "utf-8");
|
|
1415
|
-
const config = JSON.parse(raw);
|
|
1416
|
-
if (config.apiKey)
|
|
1417
|
-
return { key: config.apiKey, source: "config" };
|
|
1418
|
-
} catch {}
|
|
1419
|
-
}
|
|
1420
|
-
return null;
|
|
1421
|
-
}
|
|
1422
|
-
function maskKey(key) {
|
|
1423
|
-
if (key.length <= 9)
|
|
1424
|
-
return key;
|
|
1425
|
-
return `${key.slice(0, 5)}...${key.slice(-4)}`;
|
|
1426
|
-
}
|
|
1427
|
-
function readJsonConfig(filePath) {
|
|
1428
|
-
if (!existsSync(filePath))
|
|
1429
|
-
return {};
|
|
1430
|
-
try {
|
|
1431
|
-
return JSON.parse(readFileSync(filePath, "utf-8"));
|
|
1432
|
-
} catch {
|
|
1433
|
-
return {};
|
|
1434
|
-
}
|
|
1435
|
-
}
|
|
1436
|
-
function requireCredential(flagApiKey, json) {
|
|
1437
|
-
const credential = resolveApiKey(flagApiKey);
|
|
1438
|
-
if (!credential) {
|
|
1439
|
-
return outputError({
|
|
1440
|
-
message: "Not authenticated. Run `outlit auth login` or pass --api-key.",
|
|
1441
|
-
code: "not_authenticated"
|
|
1442
|
-
}, json);
|
|
1443
|
-
}
|
|
1444
|
-
return credential;
|
|
1445
|
-
}
|
|
1446
|
-
function writeConfigFile(filePath, content, opts) {
|
|
1447
|
-
try {
|
|
1448
|
-
mkdirSync(dirname(filePath), { recursive: true });
|
|
1449
|
-
writeFileSync(filePath, content);
|
|
1450
|
-
return true;
|
|
1451
|
-
} catch (err) {
|
|
1452
|
-
return outputError({ message: errorMessage(err, `Failed to write ${opts.label}`), code: "write_error" }, opts.json);
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
function mergeOutlitMcpConfig(configPath, serversKey, outlitConfig, opts) {
|
|
1456
|
-
const existing = readJsonConfig(configPath);
|
|
1457
|
-
const existingServers = existing[serversKey] ?? {};
|
|
1458
|
-
const merged = {
|
|
1459
|
-
...existing,
|
|
1460
|
-
[serversKey]: { ...existingServers, outlit: outlitConfig }
|
|
1461
|
-
};
|
|
1462
|
-
writeConfigFile(configPath, `${JSON.stringify(merged, null, 2)}
|
|
1463
|
-
`, opts);
|
|
1464
|
-
}
|
|
1465
|
-
function storeApiKey(apiKey) {
|
|
1466
|
-
const configDir = getConfigDir();
|
|
1467
|
-
mkdirSync(configDir, { recursive: true, mode: 448 });
|
|
1468
|
-
const credPath = join(configDir, "credentials.json");
|
|
1469
|
-
writeFileSync(credPath, JSON.stringify({ apiKey }, null, 2), { mode: 384 });
|
|
1470
|
-
return credPath;
|
|
1471
|
-
}
|
|
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;
|
|
1473
|
-
var init_config = __esm(() => {
|
|
1474
|
-
init_package();
|
|
1475
|
-
init_output();
|
|
1476
|
-
init_tty();
|
|
1477
|
-
CLI_VERSION2 = package_default.version;
|
|
1478
|
-
TICK2 = `\x1B[32m${isUnicodeSupported ? String.fromCodePoint(10003) : String.fromCodePoint(8730)}\x1B[0m`;
|
|
1479
|
-
});
|
|
1480
|
-
|
|
1481
1443
|
// src/commands/auth/signup.ts
|
|
1482
1444
|
var exports_signup = {};
|
|
1483
1445
|
__export(exports_signup, {
|
|
@@ -1527,6 +1489,725 @@ var init_signup = __esm(() => {
|
|
|
1527
1489
|
});
|
|
1528
1490
|
});
|
|
1529
1491
|
|
|
1492
|
+
// ../tools/dist/index.js
|
|
1493
|
+
function isCustomerToolName(value) {
|
|
1494
|
+
return customerToolNameSet.has(value);
|
|
1495
|
+
}
|
|
1496
|
+
function resolveCustomerContextSearchInput(value) {
|
|
1497
|
+
if (!value.query) {
|
|
1498
|
+
return {
|
|
1499
|
+
ok: false,
|
|
1500
|
+
message: "A query argument is required"
|
|
1501
|
+
};
|
|
1502
|
+
}
|
|
1503
|
+
const normalizedQuery = value.query.trim();
|
|
1504
|
+
if (normalizedQuery.length < 2) {
|
|
1505
|
+
return {
|
|
1506
|
+
ok: false,
|
|
1507
|
+
message: "Query must be at least 2 non-whitespace characters"
|
|
1508
|
+
};
|
|
1509
|
+
}
|
|
1510
|
+
if (value.after !== undefined && !iso8601UtcDateTimeRegex.test(value.after)) {
|
|
1511
|
+
return {
|
|
1512
|
+
ok: false,
|
|
1513
|
+
message: "--after must be a valid ISO 8601 datetime"
|
|
1514
|
+
};
|
|
1515
|
+
}
|
|
1516
|
+
const afterTime = value.after === undefined ? undefined : new Date(value.after).getTime();
|
|
1517
|
+
if (afterTime !== undefined && Number.isNaN(afterTime)) {
|
|
1518
|
+
return {
|
|
1519
|
+
ok: false,
|
|
1520
|
+
message: "--after must be a valid ISO 8601 datetime"
|
|
1521
|
+
};
|
|
1522
|
+
}
|
|
1523
|
+
if (value.before !== undefined && !iso8601UtcDateTimeRegex.test(value.before)) {
|
|
1524
|
+
return {
|
|
1525
|
+
ok: false,
|
|
1526
|
+
message: "--before must be a valid ISO 8601 datetime"
|
|
1527
|
+
};
|
|
1528
|
+
}
|
|
1529
|
+
const beforeTime = value.before === undefined ? undefined : new Date(value.before).getTime();
|
|
1530
|
+
if (beforeTime !== undefined && Number.isNaN(beforeTime)) {
|
|
1531
|
+
return {
|
|
1532
|
+
ok: false,
|
|
1533
|
+
message: "--before must be a valid ISO 8601 datetime"
|
|
1534
|
+
};
|
|
1535
|
+
}
|
|
1536
|
+
if (afterTime !== undefined && beforeTime !== undefined && afterTime > beforeTime) {
|
|
1537
|
+
return {
|
|
1538
|
+
ok: false,
|
|
1539
|
+
message: "--after must be before or equal to --before"
|
|
1540
|
+
};
|
|
1541
|
+
}
|
|
1542
|
+
return {
|
|
1543
|
+
ok: true,
|
|
1544
|
+
request: {
|
|
1545
|
+
query: normalizedQuery,
|
|
1546
|
+
customer: value.customer,
|
|
1547
|
+
topK: value.topK,
|
|
1548
|
+
after: value.after,
|
|
1549
|
+
before: value.before,
|
|
1550
|
+
sourceTypes: value.sourceTypes
|
|
1551
|
+
}
|
|
1552
|
+
};
|
|
1553
|
+
}
|
|
1554
|
+
function createOutlitClient(options) {
|
|
1555
|
+
const key = options.apiKey.trim();
|
|
1556
|
+
const baseUrl = options.baseUrl ?? DEFAULT_OUTLIT_API_URL;
|
|
1557
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
1558
|
+
if (!key) {
|
|
1559
|
+
throw new Error("apiKey is required");
|
|
1560
|
+
}
|
|
1561
|
+
if (!fetchImpl) {
|
|
1562
|
+
throw new Error("fetch is not available");
|
|
1563
|
+
}
|
|
1564
|
+
return {
|
|
1565
|
+
key,
|
|
1566
|
+
baseUrl,
|
|
1567
|
+
async callTool(toolName, input = {}) {
|
|
1568
|
+
if (!isCustomerToolName(toolName)) {
|
|
1569
|
+
throw new Error(`Unknown customer tool: ${toolName}`);
|
|
1570
|
+
}
|
|
1571
|
+
const response = await fetchImpl(new URL("/api/tools/call", baseUrl).toString(), {
|
|
1572
|
+
method: "POST",
|
|
1573
|
+
headers: {
|
|
1574
|
+
Authorization: `Bearer ${key}`,
|
|
1575
|
+
"Content-Type": "application/json"
|
|
1576
|
+
},
|
|
1577
|
+
body: JSON.stringify({
|
|
1578
|
+
tool: toolName,
|
|
1579
|
+
input
|
|
1580
|
+
})
|
|
1581
|
+
});
|
|
1582
|
+
if (!response.ok) {
|
|
1583
|
+
const text = await response.text();
|
|
1584
|
+
throw new Error(`API error (${response.status}): ${text}`);
|
|
1585
|
+
}
|
|
1586
|
+
return response.json();
|
|
1587
|
+
}
|
|
1588
|
+
};
|
|
1589
|
+
}
|
|
1590
|
+
var customerToolNames, customerToolContracts, customerBillingStatuses, customerFactStatuses, customerFactTypes, unsupportedCustomerFactTypes, customerFactCategories, customerIncludeSections, customerSourceTypes, customerTimeframes, timelineChannels, timelineTimeframes, userJourneyStages, schemaTables, customerToolNameSet, iso8601UtcDateTimeRegex, DEFAULT_OUTLIT_API_URL = "https://app.outlit.ai", defaultAgentToolNames, sqlToolNames, analyticalAgentToolNames;
|
|
1591
|
+
var init_dist4 = __esm(() => {
|
|
1592
|
+
customerToolNames = [
|
|
1593
|
+
"outlit_list_customers",
|
|
1594
|
+
"outlit_list_users",
|
|
1595
|
+
"outlit_get_customer",
|
|
1596
|
+
"outlit_get_timeline",
|
|
1597
|
+
"outlit_list_facts",
|
|
1598
|
+
"outlit_get_fact",
|
|
1599
|
+
"outlit_get_source",
|
|
1600
|
+
"outlit_search_customer_context",
|
|
1601
|
+
"outlit_query",
|
|
1602
|
+
"outlit_schema"
|
|
1603
|
+
];
|
|
1604
|
+
customerToolContracts = {
|
|
1605
|
+
outlit_list_customers: {
|
|
1606
|
+
toolName: "outlit_list_customers",
|
|
1607
|
+
description: "Browse and filter customers. Use this to find customers by billing status, activity recency, revenue, or name. Returns a paginated list with summary info (MRR, last activity, status).",
|
|
1608
|
+
inputSchema: {
|
|
1609
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
1610
|
+
type: "object",
|
|
1611
|
+
properties: {
|
|
1612
|
+
billingStatus: {
|
|
1613
|
+
description: "Filter by billing status",
|
|
1614
|
+
type: "string",
|
|
1615
|
+
enum: ["NONE", "TRIALING", "PAYING", "PAST_DUE", "CHURNED"]
|
|
1616
|
+
},
|
|
1617
|
+
hasActivityInLast: {
|
|
1618
|
+
description: "Filter customers with activity in the last N days",
|
|
1619
|
+
type: "string",
|
|
1620
|
+
enum: ["7d", "14d", "30d", "90d"]
|
|
1621
|
+
},
|
|
1622
|
+
noActivityInLast: {
|
|
1623
|
+
description: "Filter customers with NO activity in the last N days",
|
|
1624
|
+
type: "string",
|
|
1625
|
+
enum: ["7d", "14d", "30d", "90d"]
|
|
1626
|
+
},
|
|
1627
|
+
mrrAbove: {
|
|
1628
|
+
description: "Minimum MRR in cents (e.g., 10000 = $100)",
|
|
1629
|
+
type: "number",
|
|
1630
|
+
minimum: 0
|
|
1631
|
+
},
|
|
1632
|
+
mrrBelow: {
|
|
1633
|
+
description: "Maximum MRR in cents",
|
|
1634
|
+
type: "number",
|
|
1635
|
+
minimum: 0
|
|
1636
|
+
},
|
|
1637
|
+
traitFilters: {
|
|
1638
|
+
description: "Filter by exact trait values using key/value pairs",
|
|
1639
|
+
type: "object",
|
|
1640
|
+
propertyNames: {
|
|
1641
|
+
type: "string",
|
|
1642
|
+
pattern: "^[A-Za-z0-9_-]{1,100}$"
|
|
1643
|
+
},
|
|
1644
|
+
additionalProperties: {
|
|
1645
|
+
anyOf: [
|
|
1646
|
+
{
|
|
1647
|
+
type: "string",
|
|
1648
|
+
maxLength: 500
|
|
1649
|
+
},
|
|
1650
|
+
{
|
|
1651
|
+
type: "number"
|
|
1652
|
+
},
|
|
1653
|
+
{
|
|
1654
|
+
type: "boolean"
|
|
1655
|
+
}
|
|
1656
|
+
]
|
|
1657
|
+
}
|
|
1658
|
+
},
|
|
1659
|
+
search: {
|
|
1660
|
+
description: "Search by customer name or domain (case-insensitive)",
|
|
1661
|
+
type: "string",
|
|
1662
|
+
maxLength: 500
|
|
1663
|
+
},
|
|
1664
|
+
limit: {
|
|
1665
|
+
description: "Results per page (max 1000)",
|
|
1666
|
+
default: 50,
|
|
1667
|
+
type: "number",
|
|
1668
|
+
minimum: 1,
|
|
1669
|
+
maximum: 1000
|
|
1670
|
+
},
|
|
1671
|
+
cursor: {
|
|
1672
|
+
description: "Pagination cursor from previous response",
|
|
1673
|
+
type: "string"
|
|
1674
|
+
},
|
|
1675
|
+
orderBy: {
|
|
1676
|
+
description: "Field to order results by",
|
|
1677
|
+
default: "last_activity_at",
|
|
1678
|
+
type: "string",
|
|
1679
|
+
enum: ["last_activity_at", "first_seen_at", "name", "mrr_cents"]
|
|
1680
|
+
},
|
|
1681
|
+
orderDirection: {
|
|
1682
|
+
description: "Sort direction",
|
|
1683
|
+
default: "desc",
|
|
1684
|
+
type: "string",
|
|
1685
|
+
enum: ["asc", "desc"]
|
|
1686
|
+
}
|
|
1687
|
+
},
|
|
1688
|
+
additionalProperties: false
|
|
1689
|
+
}
|
|
1690
|
+
},
|
|
1691
|
+
outlit_list_users: {
|
|
1692
|
+
toolName: "outlit_list_users",
|
|
1693
|
+
description: "Browse and filter users. Use this to find users by journey stage, activity recency, customer, or email/name. Returns a paginated list with activity info.",
|
|
1694
|
+
inputSchema: {
|
|
1695
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
1696
|
+
type: "object",
|
|
1697
|
+
properties: {
|
|
1698
|
+
journeyStage: {
|
|
1699
|
+
description: "Filter by user journey stage",
|
|
1700
|
+
type: "string",
|
|
1701
|
+
enum: ["DISCOVERED", "SIGNED_UP", "ACTIVATED", "ENGAGED", "INACTIVE"]
|
|
1702
|
+
},
|
|
1703
|
+
customerId: {
|
|
1704
|
+
description: "Filter users by customer ID",
|
|
1705
|
+
type: "string",
|
|
1706
|
+
maxLength: 500
|
|
1707
|
+
},
|
|
1708
|
+
traitFilters: {
|
|
1709
|
+
description: "Filter by exact trait values using key/value pairs",
|
|
1710
|
+
type: "object",
|
|
1711
|
+
propertyNames: {
|
|
1712
|
+
type: "string",
|
|
1713
|
+
pattern: "^[A-Za-z0-9_-]{1,100}$"
|
|
1714
|
+
},
|
|
1715
|
+
additionalProperties: {
|
|
1716
|
+
anyOf: [
|
|
1717
|
+
{
|
|
1718
|
+
type: "string",
|
|
1719
|
+
maxLength: 500
|
|
1720
|
+
},
|
|
1721
|
+
{
|
|
1722
|
+
type: "number"
|
|
1723
|
+
},
|
|
1724
|
+
{
|
|
1725
|
+
type: "boolean"
|
|
1726
|
+
}
|
|
1727
|
+
]
|
|
1728
|
+
}
|
|
1729
|
+
},
|
|
1730
|
+
hasActivityInLast: {
|
|
1731
|
+
description: "Filter users active within this window. Format: Nd, Nh, or Nm (e.g., '7d', '24h', '90m')",
|
|
1732
|
+
type: "string",
|
|
1733
|
+
pattern: "^\\d+(d|h|m)$"
|
|
1734
|
+
},
|
|
1735
|
+
noActivityInLast: {
|
|
1736
|
+
description: "Filter users NOT active within this window. Format: Nd, Nh, or Nm (e.g., '30d', '2h')",
|
|
1737
|
+
type: "string",
|
|
1738
|
+
pattern: "^\\d+(d|h|m)$"
|
|
1739
|
+
},
|
|
1740
|
+
search: {
|
|
1741
|
+
description: "Search by user email or name (case-insensitive)",
|
|
1742
|
+
type: "string",
|
|
1743
|
+
maxLength: 500
|
|
1744
|
+
},
|
|
1745
|
+
limit: {
|
|
1746
|
+
description: "Results per page (max 1000)",
|
|
1747
|
+
default: 50,
|
|
1748
|
+
type: "number",
|
|
1749
|
+
minimum: 1,
|
|
1750
|
+
maximum: 1000
|
|
1751
|
+
},
|
|
1752
|
+
cursor: {
|
|
1753
|
+
description: "Pagination cursor from previous response",
|
|
1754
|
+
type: "string"
|
|
1755
|
+
},
|
|
1756
|
+
orderBy: {
|
|
1757
|
+
description: "Field to order by",
|
|
1758
|
+
default: "last_activity_at",
|
|
1759
|
+
type: "string",
|
|
1760
|
+
enum: ["last_activity_at", "first_seen_at", "email"]
|
|
1761
|
+
},
|
|
1762
|
+
orderDirection: {
|
|
1763
|
+
description: "Sort direction",
|
|
1764
|
+
default: "desc",
|
|
1765
|
+
type: "string",
|
|
1766
|
+
enum: ["asc", "desc"]
|
|
1767
|
+
}
|
|
1768
|
+
},
|
|
1769
|
+
additionalProperties: false
|
|
1770
|
+
}
|
|
1771
|
+
},
|
|
1772
|
+
outlit_get_customer: {
|
|
1773
|
+
toolName: "outlit_get_customer",
|
|
1774
|
+
description: "Get full details for a single customer. Use this when you already know which customer you want to inspect. Optionally include related data (users, revenue, recent activity, engagement metrics).",
|
|
1775
|
+
inputSchema: {
|
|
1776
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
1777
|
+
type: "object",
|
|
1778
|
+
properties: {
|
|
1779
|
+
customer: {
|
|
1780
|
+
type: "string",
|
|
1781
|
+
description: "Customer ID, domain, or name to look up"
|
|
1782
|
+
},
|
|
1783
|
+
include: {
|
|
1784
|
+
description: "Additional data sections to include in the response",
|
|
1785
|
+
type: "array",
|
|
1786
|
+
items: {
|
|
1787
|
+
type: "string",
|
|
1788
|
+
enum: ["users", "revenue", "recentTimeline", "behaviorMetrics"]
|
|
1789
|
+
}
|
|
1790
|
+
},
|
|
1791
|
+
timeframe: {
|
|
1792
|
+
description: "Timeframe for timeline and behavior metrics (default: 30d)",
|
|
1793
|
+
default: "30d",
|
|
1794
|
+
type: "string",
|
|
1795
|
+
enum: ["7d", "14d", "30d", "90d"]
|
|
1796
|
+
}
|
|
1797
|
+
},
|
|
1798
|
+
required: ["customer"],
|
|
1799
|
+
additionalProperties: false
|
|
1800
|
+
}
|
|
1801
|
+
},
|
|
1802
|
+
outlit_get_timeline: {
|
|
1803
|
+
toolName: "outlit_get_timeline",
|
|
1804
|
+
description: "Get the chronological activity timeline for a customer. Use this to see what happened and when — emails, calls, Slack messages, billing events, etc. Supports channel and date filtering.",
|
|
1805
|
+
inputSchema: {
|
|
1806
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
1807
|
+
type: "object",
|
|
1808
|
+
properties: {
|
|
1809
|
+
customer: {
|
|
1810
|
+
type: "string",
|
|
1811
|
+
description: "Customer ID or domain"
|
|
1812
|
+
},
|
|
1813
|
+
channels: {
|
|
1814
|
+
description: "Filter by event channel (e.g., EMAIL, SLACK, CALL)",
|
|
1815
|
+
type: "array",
|
|
1816
|
+
items: {
|
|
1817
|
+
type: "string",
|
|
1818
|
+
enum: ["SDK", "EMAIL", "SLACK", "CALL", "CRM", "BILLING", "SUPPORT", "INTERNAL"]
|
|
1819
|
+
}
|
|
1820
|
+
},
|
|
1821
|
+
eventTypes: {
|
|
1822
|
+
description: "Filter by event type",
|
|
1823
|
+
type: "array",
|
|
1824
|
+
items: {
|
|
1825
|
+
type: "string"
|
|
1826
|
+
}
|
|
1827
|
+
},
|
|
1828
|
+
timeframe: {
|
|
1829
|
+
description: "Relative time window (default: 30d). Cannot be used with startDate/endDate.",
|
|
1830
|
+
type: "string",
|
|
1831
|
+
enum: ["7d", "14d", "30d", "90d", "all"]
|
|
1832
|
+
},
|
|
1833
|
+
startDate: {
|
|
1834
|
+
description: "Start of time window (ISO 8601, e.g. '2025-01-01T00:00:00Z'). Cannot be used with timeframe.",
|
|
1835
|
+
type: "string",
|
|
1836
|
+
format: "date-time",
|
|
1837
|
+
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))$"
|
|
1838
|
+
},
|
|
1839
|
+
endDate: {
|
|
1840
|
+
description: "End of time window (ISO 8601, e.g. '2025-01-31T23:59:59Z'). Cannot be used with timeframe.",
|
|
1841
|
+
type: "string",
|
|
1842
|
+
format: "date-time",
|
|
1843
|
+
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))$"
|
|
1844
|
+
},
|
|
1845
|
+
limit: {
|
|
1846
|
+
description: "Results per page (max 1000)",
|
|
1847
|
+
default: 50,
|
|
1848
|
+
type: "number",
|
|
1849
|
+
minimum: 1,
|
|
1850
|
+
maximum: 1000
|
|
1851
|
+
},
|
|
1852
|
+
cursor: {
|
|
1853
|
+
description: "Pagination cursor from previous response",
|
|
1854
|
+
type: "string"
|
|
1855
|
+
}
|
|
1856
|
+
},
|
|
1857
|
+
required: ["customer"],
|
|
1858
|
+
additionalProperties: false
|
|
1859
|
+
}
|
|
1860
|
+
},
|
|
1861
|
+
outlit_list_facts: {
|
|
1862
|
+
toolName: "outlit_list_facts",
|
|
1863
|
+
description: "List structured facts known about a customer. Use filters like status, sourceTypes, factTypes, factCategories, and date bounds to narrow the result set. For topic-specific retrieval, use outlit_search_customer_context instead.",
|
|
1864
|
+
inputSchema: {
|
|
1865
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
1866
|
+
type: "object",
|
|
1867
|
+
properties: {
|
|
1868
|
+
customer: {
|
|
1869
|
+
type: "string",
|
|
1870
|
+
description: "Customer ID or domain"
|
|
1871
|
+
},
|
|
1872
|
+
status: {
|
|
1873
|
+
description: "Optional fact status filter",
|
|
1874
|
+
type: "array",
|
|
1875
|
+
items: {
|
|
1876
|
+
type: "string",
|
|
1877
|
+
enum: ["ACTIVE", "ACKNOWLEDGED", "RESOLVED", "SNOOZED", "CANDIDATE"]
|
|
1878
|
+
}
|
|
1879
|
+
},
|
|
1880
|
+
sourceTypes: {
|
|
1881
|
+
description: "Optional generic source types to restrict fact results to.",
|
|
1882
|
+
type: "array",
|
|
1883
|
+
items: {
|
|
1884
|
+
type: "string",
|
|
1885
|
+
enum: ["EMAIL", "CALL", "CALENDAR_EVENT", "SUPPORT_TICKET"]
|
|
1886
|
+
}
|
|
1887
|
+
},
|
|
1888
|
+
factTypes: {
|
|
1889
|
+
description: "Optional customer-memory fact type filters, such as CHURN_RISK, EXPANSION, SENTIMENT, or BUDGET. Anomaly detector fact types are not supported.",
|
|
1890
|
+
type: "array",
|
|
1891
|
+
items: {
|
|
1892
|
+
type: "string",
|
|
1893
|
+
enum: [
|
|
1894
|
+
"CUSTOM",
|
|
1895
|
+
"COMPANY_CHANGE",
|
|
1896
|
+
"FUNDING_REVENUE",
|
|
1897
|
+
"TECHNOLOGY",
|
|
1898
|
+
"STRATEGY",
|
|
1899
|
+
"COMPETITIVE",
|
|
1900
|
+
"SENTIMENT",
|
|
1901
|
+
"CHAMPION_RISK",
|
|
1902
|
+
"EXPANSION",
|
|
1903
|
+
"CHURN_RISK",
|
|
1904
|
+
"TIMELINE",
|
|
1905
|
+
"BUDGET",
|
|
1906
|
+
"DECISION_MAKER",
|
|
1907
|
+
"REQUIREMENTS",
|
|
1908
|
+
"PRODUCT_USAGE",
|
|
1909
|
+
"CONTACT_INFO",
|
|
1910
|
+
"CONTACT_PREFERENCE"
|
|
1911
|
+
]
|
|
1912
|
+
}
|
|
1913
|
+
},
|
|
1914
|
+
factCategories: {
|
|
1915
|
+
description: "Optional public fact category filters. Supported values: MEMORY, CUSTOM.",
|
|
1916
|
+
type: "array",
|
|
1917
|
+
items: {
|
|
1918
|
+
type: "string",
|
|
1919
|
+
enum: ["MEMORY", "CUSTOM"]
|
|
1920
|
+
}
|
|
1921
|
+
},
|
|
1922
|
+
after: {
|
|
1923
|
+
description: "ISO 8601 datetime lower bound",
|
|
1924
|
+
type: "string",
|
|
1925
|
+
format: "date-time",
|
|
1926
|
+
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))$"
|
|
1927
|
+
},
|
|
1928
|
+
before: {
|
|
1929
|
+
description: "ISO 8601 datetime upper bound",
|
|
1930
|
+
type: "string",
|
|
1931
|
+
format: "date-time",
|
|
1932
|
+
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))$"
|
|
1933
|
+
},
|
|
1934
|
+
limit: {
|
|
1935
|
+
description: "Results per page (max 100)",
|
|
1936
|
+
default: 50,
|
|
1937
|
+
type: "number",
|
|
1938
|
+
minimum: 1,
|
|
1939
|
+
maximum: 100
|
|
1940
|
+
},
|
|
1941
|
+
cursor: {
|
|
1942
|
+
description: "Pagination cursor from previous response",
|
|
1943
|
+
type: "string"
|
|
1944
|
+
}
|
|
1945
|
+
},
|
|
1946
|
+
required: ["customer"],
|
|
1947
|
+
additionalProperties: false
|
|
1948
|
+
}
|
|
1949
|
+
},
|
|
1950
|
+
outlit_get_fact: {
|
|
1951
|
+
toolName: "outlit_get_fact",
|
|
1952
|
+
description: "Get one exact fact by ID. Returns the canonical fact shape and optionally expands requested related data such as evidence.",
|
|
1953
|
+
inputSchema: {
|
|
1954
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
1955
|
+
type: "object",
|
|
1956
|
+
properties: {
|
|
1957
|
+
factId: {
|
|
1958
|
+
type: "string",
|
|
1959
|
+
minLength: 1,
|
|
1960
|
+
maxLength: 500,
|
|
1961
|
+
description: "Exact fact ID to retrieve"
|
|
1962
|
+
},
|
|
1963
|
+
include: {
|
|
1964
|
+
description: "Optional best-effort expansions. Use include=['evidence'] to request evidence when available; unsupported include values are ignored.",
|
|
1965
|
+
type: "array",
|
|
1966
|
+
items: {
|
|
1967
|
+
type: "string",
|
|
1968
|
+
minLength: 1,
|
|
1969
|
+
maxLength: 100
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
},
|
|
1973
|
+
required: ["factId"],
|
|
1974
|
+
additionalProperties: false
|
|
1975
|
+
}
|
|
1976
|
+
},
|
|
1977
|
+
outlit_get_source: {
|
|
1978
|
+
toolName: "outlit_get_source",
|
|
1979
|
+
description: "Get one exact source record by generic sourceType and sourceId. Use this when you already know the concrete underlying source you want to inspect.",
|
|
1980
|
+
inputSchema: {
|
|
1981
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
1982
|
+
type: "object",
|
|
1983
|
+
properties: {
|
|
1984
|
+
sourceType: {
|
|
1985
|
+
type: "string",
|
|
1986
|
+
enum: ["EMAIL", "CALL", "CALENDAR_EVENT", "SUPPORT_TICKET"]
|
|
1987
|
+
},
|
|
1988
|
+
sourceId: {
|
|
1989
|
+
type: "string",
|
|
1990
|
+
minLength: 1,
|
|
1991
|
+
maxLength: 500
|
|
1992
|
+
}
|
|
1993
|
+
},
|
|
1994
|
+
required: ["sourceType", "sourceId"],
|
|
1995
|
+
additionalProperties: false
|
|
1996
|
+
}
|
|
1997
|
+
},
|
|
1998
|
+
outlit_search_customer_context: {
|
|
1999
|
+
toolName: "outlit_search_customer_context",
|
|
2000
|
+
description: "Search across all known customer context using a natural-language query. Returns grouped artifact-level results for matching sources and facts. Omit customer to search across all customers in the organization.",
|
|
2001
|
+
inputSchema: {
|
|
2002
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
2003
|
+
type: "object",
|
|
2004
|
+
properties: {
|
|
2005
|
+
customer: {
|
|
2006
|
+
description: "Customer ID, domain, or name. Omit to search across all customers.",
|
|
2007
|
+
anyOf: [
|
|
2008
|
+
{
|
|
2009
|
+
type: "string",
|
|
2010
|
+
minLength: 1,
|
|
2011
|
+
maxLength: 500
|
|
2012
|
+
},
|
|
2013
|
+
{
|
|
2014
|
+
type: "null"
|
|
2015
|
+
}
|
|
2016
|
+
]
|
|
2017
|
+
},
|
|
2018
|
+
query: {
|
|
2019
|
+
type: "string",
|
|
2020
|
+
minLength: 2,
|
|
2021
|
+
maxLength: 2000,
|
|
2022
|
+
description: "Natural language query or topic to search for."
|
|
2023
|
+
},
|
|
2024
|
+
topK: {
|
|
2025
|
+
description: "Maximum number of artifact results to return (default 20).",
|
|
2026
|
+
type: "integer",
|
|
2027
|
+
minimum: 1,
|
|
2028
|
+
maximum: 50
|
|
2029
|
+
},
|
|
2030
|
+
after: {
|
|
2031
|
+
description: "ISO 8601 datetime lower bound",
|
|
2032
|
+
type: "string",
|
|
2033
|
+
format: "date-time",
|
|
2034
|
+
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))$"
|
|
2035
|
+
},
|
|
2036
|
+
before: {
|
|
2037
|
+
description: "ISO 8601 datetime upper bound",
|
|
2038
|
+
type: "string",
|
|
2039
|
+
format: "date-time",
|
|
2040
|
+
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))$"
|
|
2041
|
+
},
|
|
2042
|
+
sourceTypes: {
|
|
2043
|
+
description: "Optional generic source types to restrict the search to.",
|
|
2044
|
+
type: "array",
|
|
2045
|
+
items: {
|
|
2046
|
+
type: "string",
|
|
2047
|
+
enum: ["EMAIL", "CALL", "CALENDAR_EVENT", "SUPPORT_TICKET"]
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
},
|
|
2051
|
+
required: ["query"],
|
|
2052
|
+
additionalProperties: false
|
|
2053
|
+
}
|
|
2054
|
+
},
|
|
2055
|
+
outlit_query: {
|
|
2056
|
+
toolName: "outlit_query",
|
|
2057
|
+
description: `Execute raw SQL queries against your analytics data.
|
|
2058
|
+
|
|
2059
|
+
Available tables:
|
|
2060
|
+
- events: Customer activity events (event_type, event_channel, customer_id, occurred_at, properties, ...)
|
|
2061
|
+
- customer_dimensions: Customer attributes (customer_id, domain, name, billing_status, plan, mrr_cents, ...)
|
|
2062
|
+
- user_dimensions: User attributes (user_id, email, name, customer_id, ...)
|
|
2063
|
+
- mrr_snapshots: Revenue snapshots over time (customer_id, snapshot_date, mrr_cents, ...)
|
|
2064
|
+
|
|
2065
|
+
All queries are automatically filtered to your organization's data.
|
|
2066
|
+
Only SELECT queries are allowed.
|
|
2067
|
+
|
|
2068
|
+
Example queries:
|
|
2069
|
+
- SELECT event_type, count(*) FROM events GROUP BY 1 ORDER BY 2 DESC LIMIT 10
|
|
2070
|
+
- SELECT billing_status, sum(mrr_cents)/100 as mrr FROM customer_dimensions GROUP BY 1
|
|
2071
|
+
- SELECT * FROM events WHERE customer_id = 'cust_123' ORDER BY occurred_at DESC LIMIT 50`,
|
|
2072
|
+
inputSchema: {
|
|
2073
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
2074
|
+
type: "object",
|
|
2075
|
+
properties: {
|
|
2076
|
+
sql: {
|
|
2077
|
+
type: "string",
|
|
2078
|
+
description: "SQL SELECT query to execute"
|
|
2079
|
+
},
|
|
2080
|
+
limit: {
|
|
2081
|
+
description: "Max rows to return (default 1000, max 10000)",
|
|
2082
|
+
default: 1000,
|
|
2083
|
+
type: "number",
|
|
2084
|
+
maximum: 1e4
|
|
2085
|
+
}
|
|
2086
|
+
},
|
|
2087
|
+
required: ["sql"],
|
|
2088
|
+
additionalProperties: false
|
|
2089
|
+
}
|
|
2090
|
+
},
|
|
2091
|
+
outlit_schema: {
|
|
2092
|
+
toolName: "outlit_schema",
|
|
2093
|
+
description: `Get table schemas for available analytics tables.
|
|
2094
|
+
|
|
2095
|
+
Use this to discover column names, types, and descriptions before writing SQL queries.
|
|
2096
|
+
Returns column definitions and example queries for each table.`,
|
|
2097
|
+
inputSchema: {
|
|
2098
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
2099
|
+
type: "object",
|
|
2100
|
+
properties: {
|
|
2101
|
+
table: {
|
|
2102
|
+
description: "Specific table to describe, or omit for all tables",
|
|
2103
|
+
type: "string",
|
|
2104
|
+
enum: ["events", "customer_dimensions", "user_dimensions", "mrr_snapshots"]
|
|
2105
|
+
}
|
|
2106
|
+
},
|
|
2107
|
+
additionalProperties: false
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
};
|
|
2111
|
+
customerBillingStatuses = [
|
|
2112
|
+
"NONE",
|
|
2113
|
+
"TRIALING",
|
|
2114
|
+
"PAYING",
|
|
2115
|
+
"PAST_DUE",
|
|
2116
|
+
"CHURNED"
|
|
2117
|
+
];
|
|
2118
|
+
customerFactStatuses = [
|
|
2119
|
+
"ACTIVE",
|
|
2120
|
+
"ACKNOWLEDGED",
|
|
2121
|
+
"RESOLVED",
|
|
2122
|
+
"SNOOZED",
|
|
2123
|
+
"CANDIDATE"
|
|
2124
|
+
];
|
|
2125
|
+
customerFactTypes = [
|
|
2126
|
+
"CUSTOM",
|
|
2127
|
+
"COMPANY_CHANGE",
|
|
2128
|
+
"FUNDING_REVENUE",
|
|
2129
|
+
"TECHNOLOGY",
|
|
2130
|
+
"STRATEGY",
|
|
2131
|
+
"COMPETITIVE",
|
|
2132
|
+
"SENTIMENT",
|
|
2133
|
+
"CHAMPION_RISK",
|
|
2134
|
+
"EXPANSION",
|
|
2135
|
+
"CHURN_RISK",
|
|
2136
|
+
"TIMELINE",
|
|
2137
|
+
"BUDGET",
|
|
2138
|
+
"DECISION_MAKER",
|
|
2139
|
+
"REQUIREMENTS",
|
|
2140
|
+
"PRODUCT_USAGE",
|
|
2141
|
+
"CONTACT_INFO",
|
|
2142
|
+
"CONTACT_PREFERENCE"
|
|
2143
|
+
];
|
|
2144
|
+
unsupportedCustomerFactTypes = [
|
|
2145
|
+
"TRACKING_GAP",
|
|
2146
|
+
"SCHEMA_DRIFT",
|
|
2147
|
+
"INGESTION_LAG",
|
|
2148
|
+
"ACTIVATION_RATE_DROP",
|
|
2149
|
+
"FUNNEL_DROPOFF",
|
|
2150
|
+
"CORE_ACTION_DECAY",
|
|
2151
|
+
"CADENCE_BREAK",
|
|
2152
|
+
"QUIET_ACCOUNT",
|
|
2153
|
+
"CHAMPION_AT_RISK",
|
|
2154
|
+
"SEGMENT_DIVERGENCE"
|
|
2155
|
+
];
|
|
2156
|
+
customerFactCategories = ["MEMORY", "CUSTOM"];
|
|
2157
|
+
customerIncludeSections = [
|
|
2158
|
+
"users",
|
|
2159
|
+
"revenue",
|
|
2160
|
+
"recentTimeline",
|
|
2161
|
+
"behaviorMetrics"
|
|
2162
|
+
];
|
|
2163
|
+
customerSourceTypes = ["EMAIL", "CALL", "CALENDAR_EVENT", "SUPPORT_TICKET"];
|
|
2164
|
+
customerTimeframes = ["7d", "14d", "30d", "90d"];
|
|
2165
|
+
timelineChannels = [
|
|
2166
|
+
"SDK",
|
|
2167
|
+
"EMAIL",
|
|
2168
|
+
"SLACK",
|
|
2169
|
+
"CALL",
|
|
2170
|
+
"CRM",
|
|
2171
|
+
"BILLING",
|
|
2172
|
+
"SUPPORT",
|
|
2173
|
+
"INTERNAL"
|
|
2174
|
+
];
|
|
2175
|
+
timelineTimeframes = ["7d", "14d", "30d", "90d", "all"];
|
|
2176
|
+
userJourneyStages = [
|
|
2177
|
+
"DISCOVERED",
|
|
2178
|
+
"SIGNED_UP",
|
|
2179
|
+
"ACTIVATED",
|
|
2180
|
+
"ENGAGED",
|
|
2181
|
+
"INACTIVE"
|
|
2182
|
+
];
|
|
2183
|
+
schemaTables = [
|
|
2184
|
+
"events",
|
|
2185
|
+
"customer_dimensions",
|
|
2186
|
+
"user_dimensions",
|
|
2187
|
+
"mrr_snapshots"
|
|
2188
|
+
];
|
|
2189
|
+
customerToolNameSet = new Set(customerToolNames);
|
|
2190
|
+
iso8601UtcDateTimeRegex = /^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z))$/;
|
|
2191
|
+
defaultAgentToolNames = [
|
|
2192
|
+
"outlit_list_customers",
|
|
2193
|
+
"outlit_list_users",
|
|
2194
|
+
"outlit_get_customer",
|
|
2195
|
+
"outlit_get_timeline",
|
|
2196
|
+
"outlit_list_facts",
|
|
2197
|
+
"outlit_get_fact",
|
|
2198
|
+
"outlit_get_source",
|
|
2199
|
+
"outlit_search_customer_context"
|
|
2200
|
+
];
|
|
2201
|
+
sqlToolNames = [
|
|
2202
|
+
"outlit_schema",
|
|
2203
|
+
"outlit_query"
|
|
2204
|
+
];
|
|
2205
|
+
analyticalAgentToolNames = [
|
|
2206
|
+
...defaultAgentToolNames,
|
|
2207
|
+
...sqlToolNames
|
|
2208
|
+
];
|
|
2209
|
+
});
|
|
2210
|
+
|
|
1530
2211
|
// src/lib/client.ts
|
|
1531
2212
|
function buildUrl(base, path, params) {
|
|
1532
2213
|
const url = new URL(path, base);
|
|
@@ -1552,11 +2233,18 @@ async function createClient(flagApiKey) {
|
|
|
1552
2233
|
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}`);
|
|
1553
2234
|
}
|
|
1554
2235
|
const baseUrl = process.env.OUTLIT_API_URL ?? DEFAULT_API_URL;
|
|
2236
|
+
const toolsClient = createOutlitClient({
|
|
2237
|
+
apiKey: credential.key,
|
|
2238
|
+
baseUrl
|
|
2239
|
+
});
|
|
1555
2240
|
return {
|
|
1556
2241
|
key: credential.key,
|
|
1557
2242
|
baseUrl,
|
|
1558
2243
|
async callTool(toolName, params) {
|
|
1559
|
-
|
|
2244
|
+
if (isCustomerToolName(toolName)) {
|
|
2245
|
+
return toolsClient.callTool(toolName, params);
|
|
2246
|
+
}
|
|
2247
|
+
const endpoint = CLI_TOOL_ENDPOINTS[toolName];
|
|
1560
2248
|
if (!endpoint) {
|
|
1561
2249
|
throw new Error(`Unknown tool: ${toolName}`);
|
|
1562
2250
|
}
|
|
@@ -1585,29 +2273,22 @@ async function createClient(flagApiKey) {
|
|
|
1585
2273
|
}
|
|
1586
2274
|
};
|
|
1587
2275
|
}
|
|
1588
|
-
var API_KEY_REGEX,
|
|
2276
|
+
var API_KEY_REGEX, CLI_TOOL_ENDPOINTS;
|
|
1589
2277
|
var init_client = __esm(() => {
|
|
2278
|
+
init_dist4();
|
|
1590
2279
|
init_config();
|
|
1591
2280
|
API_KEY_REGEX = /^ok_[A-Za-z0-9_-]{32,}$/;
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
outlit_get_timeline: { method: "POST", path: "/api/internal/mcp/timeline" },
|
|
1597
|
-
outlit_get_facts: { method: "POST", path: "/api/internal/mcp/facts" },
|
|
1598
|
-
outlit_schema: { method: "GET", path: "/api/internal/mcp/sql-schema" },
|
|
1599
|
-
outlit_query: { method: "POST", path: "/api/internal/mcp/sql" },
|
|
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" },
|
|
2281
|
+
CLI_TOOL_ENDPOINTS = {
|
|
2282
|
+
outlit_list_integrations: { method: "GET", path: "/api/integrations" },
|
|
2283
|
+
outlit_connect_integration: { method: "POST", path: "/api/integrations/connect" },
|
|
2284
|
+
outlit_connect_status: { method: "GET", path: "/api/integrations/connect/status" },
|
|
1604
2285
|
outlit_disconnect_integration: {
|
|
1605
2286
|
method: "POST",
|
|
1606
|
-
path: "/api/
|
|
2287
|
+
path: "/api/integrations/disconnect"
|
|
1607
2288
|
},
|
|
1608
2289
|
outlit_integration_sync_status: {
|
|
1609
2290
|
method: "GET",
|
|
1610
|
-
path: "/api/
|
|
2291
|
+
path: "/api/integrations/sync-status"
|
|
1611
2292
|
}
|
|
1612
2293
|
};
|
|
1613
2294
|
});
|
|
@@ -1736,10 +2417,28 @@ async function getClientOrExit(flagApiKey, json) {
|
|
|
1736
2417
|
return createClient(flagApiKey).catch((err) => outputError({ message: errorMessage(err, "Authentication failed"), code: "auth_required" }, json));
|
|
1737
2418
|
}
|
|
1738
2419
|
async function pingApiKey(apiKey) {
|
|
1739
|
-
const
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
2420
|
+
const baseUrl = process.env.OUTLIT_API_URL ?? DEFAULT_API_URL;
|
|
2421
|
+
const url = new URL("/api/validate-api-key", baseUrl).toString();
|
|
2422
|
+
const response = await globalThis.fetch(url, {
|
|
2423
|
+
method: "POST",
|
|
2424
|
+
headers: {
|
|
2425
|
+
Authorization: `Bearer ${apiKey}`
|
|
2426
|
+
}
|
|
2427
|
+
});
|
|
2428
|
+
const text = await response.text();
|
|
2429
|
+
const payload = text.length > 0 ? (() => {
|
|
2430
|
+
try {
|
|
2431
|
+
return JSON.parse(text);
|
|
2432
|
+
} catch {
|
|
2433
|
+
return null;
|
|
2434
|
+
}
|
|
2435
|
+
})() : null;
|
|
2436
|
+
if (!response.ok || !payload?.valid) {
|
|
2437
|
+
const message = payload?.error ?? (text.length > 0 ? text : `API error (${response.status})`);
|
|
2438
|
+
throw new Error(message);
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
async function validateKeyOrExit(apiKey, json) {
|
|
1743
2442
|
try {
|
|
1744
2443
|
await pingApiKey(apiKey);
|
|
1745
2444
|
} catch (err) {
|
|
@@ -1789,6 +2488,7 @@ async function runTool(client, toolName, params, json, opts) {
|
|
|
1789
2488
|
}
|
|
1790
2489
|
var init_api = __esm(() => {
|
|
1791
2490
|
init_client();
|
|
2491
|
+
init_config();
|
|
1792
2492
|
init_output();
|
|
1793
2493
|
init_spinner();
|
|
1794
2494
|
init_table();
|
|
@@ -1922,8 +2622,8 @@ var exports_logout = {};
|
|
|
1922
2622
|
__export(exports_logout, {
|
|
1923
2623
|
default: () => logout_default
|
|
1924
2624
|
});
|
|
1925
|
-
import { rmSync } from "node:fs";
|
|
1926
|
-
import { join as
|
|
2625
|
+
import { rmSync as rmSync2 } from "node:fs";
|
|
2626
|
+
import { join as join3 } from "node:path";
|
|
1927
2627
|
var logout_default;
|
|
1928
2628
|
var init_logout = __esm(() => {
|
|
1929
2629
|
init_dist();
|
|
@@ -1949,13 +2649,13 @@ var init_logout = __esm(() => {
|
|
|
1949
2649
|
async run({ args }) {
|
|
1950
2650
|
const json = !!args.json;
|
|
1951
2651
|
const configDir = getConfigDir();
|
|
1952
|
-
const credPath =
|
|
2652
|
+
const credPath = join3(configDir, "credentials.json");
|
|
1953
2653
|
if (process.env.OUTLIT_API_KEY) {
|
|
1954
2654
|
process.stderr.write(`Warning: OUTLIT_API_KEY env var is still set and will continue to work after logout.
|
|
1955
2655
|
`);
|
|
1956
2656
|
}
|
|
1957
2657
|
try {
|
|
1958
|
-
|
|
2658
|
+
rmSync2(credPath, { force: true });
|
|
1959
2659
|
} catch (err) {
|
|
1960
2660
|
if (!isEnoentError(err)) {
|
|
1961
2661
|
return outputError({ message: errorMessage(err, "Failed to remove credentials file"), code: "unlink_error" }, json);
|
|
@@ -2277,6 +2977,7 @@ __export(exports_list, {
|
|
|
2277
2977
|
});
|
|
2278
2978
|
var list_default;
|
|
2279
2979
|
var init_list = __esm(() => {
|
|
2980
|
+
init_dist4();
|
|
2280
2981
|
init_dist();
|
|
2281
2982
|
init_auth();
|
|
2282
2983
|
init_filters();
|
|
@@ -2300,7 +3001,7 @@ var init_list = __esm(() => {
|
|
|
2300
3001
|
" outlit customers list --mrr-above 10000 --limit 50 # high-value at-risk",
|
|
2301
3002
|
" outlit customers list --json | jq '.items[].domain' # pipe-friendly",
|
|
2302
3003
|
"",
|
|
2303
|
-
|
|
3004
|
+
`Billing statuses: ${customerBillingStatuses.join(", ")}`,
|
|
2304
3005
|
"Activity periods: 7d, 14d, 30d, 90d",
|
|
2305
3006
|
"",
|
|
2306
3007
|
AGENT_JSON_HINT
|
|
@@ -2316,7 +3017,7 @@ var init_list = __esm(() => {
|
|
|
2316
3017
|
...orderArgs,
|
|
2317
3018
|
"billing-status": {
|
|
2318
3019
|
type: "string",
|
|
2319
|
-
description:
|
|
3020
|
+
description: `Filter by billing status (${customerBillingStatuses.join(", ")})`
|
|
2320
3021
|
},
|
|
2321
3022
|
"mrr-above": {
|
|
2322
3023
|
type: "string",
|
|
@@ -2329,14 +3030,6 @@ var init_list = __esm(() => {
|
|
|
2329
3030
|
search: {
|
|
2330
3031
|
type: "string",
|
|
2331
3032
|
description: "Search by customer name or domain"
|
|
2332
|
-
},
|
|
2333
|
-
status: {
|
|
2334
|
-
type: "string",
|
|
2335
|
-
description: "Customer status filter (PROVISIONAL, ACTIVE, CHURNED, MERGED)"
|
|
2336
|
-
},
|
|
2337
|
-
type: {
|
|
2338
|
-
type: "string",
|
|
2339
|
-
description: "Customer type filter (COMPANY, INDIVIDUAL)"
|
|
2340
3033
|
}
|
|
2341
3034
|
},
|
|
2342
3035
|
async run({ args }) {
|
|
@@ -2374,11 +3067,7 @@ var init_list = __esm(() => {
|
|
|
2374
3067
|
}
|
|
2375
3068
|
applyListFilters(params, args);
|
|
2376
3069
|
applyPagination(params, args, json);
|
|
2377
|
-
|
|
2378
|
-
params.status = args.status;
|
|
2379
|
-
if (args.type)
|
|
2380
|
-
params.type = args.type;
|
|
2381
|
-
return runTool(client, "outlit_list_customers", params, json, {
|
|
3070
|
+
return runTool(client, customerToolContracts.outlit_list_customers.toolName, params, json, {
|
|
2382
3071
|
spinnerMessage: "Fetching customers...",
|
|
2383
3072
|
table: {
|
|
2384
3073
|
columns: [
|
|
@@ -2401,6 +3090,7 @@ __export(exports_get, {
|
|
|
2401
3090
|
});
|
|
2402
3091
|
var get_default;
|
|
2403
3092
|
var init_get = __esm(() => {
|
|
3093
|
+
init_dist4();
|
|
2404
3094
|
init_dist();
|
|
2405
3095
|
init_auth();
|
|
2406
3096
|
init_output2();
|
|
@@ -2420,6 +3110,9 @@ var init_get = __esm(() => {
|
|
|
2420
3110
|
'Naming note: --include users returns data under the "contacts" key in',
|
|
2421
3111
|
"the response. This is a server-side naming inconsistency, not a CLI bug.",
|
|
2422
3112
|
"",
|
|
3113
|
+
`Available include sections: ${customerIncludeSections.join(", ")}`,
|
|
3114
|
+
`Timeframes: ${customerTimeframes.join(", ")}`,
|
|
3115
|
+
"",
|
|
2423
3116
|
"Examples:",
|
|
2424
3117
|
" outlit customers get acme.com",
|
|
2425
3118
|
" outlit customers get acme.com --include users,revenue",
|
|
@@ -2441,7 +3134,7 @@ var init_get = __esm(() => {
|
|
|
2441
3134
|
type: "string",
|
|
2442
3135
|
description: [
|
|
2443
3136
|
"Comma-separated sections to include in response.",
|
|
2444
|
-
|
|
3137
|
+
`Available: ${customerIncludeSections.join(", ")}`,
|
|
2445
3138
|
'Note: "users" maps to "contacts" in the response (server naming).'
|
|
2446
3139
|
].join(`
|
|
2447
3140
|
`)
|
|
@@ -2462,7 +3155,7 @@ var init_get = __esm(() => {
|
|
|
2462
3155
|
if (args.include) {
|
|
2463
3156
|
params.include = splitCsv(args.include);
|
|
2464
3157
|
}
|
|
2465
|
-
return runTool(client,
|
|
3158
|
+
return runTool(client, customerToolContracts.outlit_get_customer.toolName, params, json);
|
|
2466
3159
|
}
|
|
2467
3160
|
});
|
|
2468
3161
|
});
|
|
@@ -2474,6 +3167,7 @@ __export(exports_timeline, {
|
|
|
2474
3167
|
});
|
|
2475
3168
|
var timeline_default;
|
|
2476
3169
|
var init_timeline = __esm(() => {
|
|
3170
|
+
init_dist4();
|
|
2477
3171
|
init_dist();
|
|
2478
3172
|
init_auth();
|
|
2479
3173
|
init_output2();
|
|
@@ -2492,12 +3186,14 @@ var init_timeline = __esm(() => {
|
|
|
2492
3186
|
"",
|
|
2493
3187
|
"Timeframe is used when no explicit date range is set.",
|
|
2494
3188
|
"When --start-date or --end-date is provided, --timeframe is ignored.",
|
|
3189
|
+
`Channels: ${timelineChannels.join(", ")}`,
|
|
3190
|
+
`Timeframes: ${timelineTimeframes.join(", ")}`,
|
|
2495
3191
|
"",
|
|
2496
3192
|
"Examples:",
|
|
2497
3193
|
" outlit customers timeline acme.com",
|
|
2498
3194
|
" outlit customers timeline acme.com --timeframe 90d",
|
|
2499
3195
|
" outlit customers timeline acme.com --channels EMAIL,SLACK",
|
|
2500
|
-
" outlit customers timeline acme.com --start-date 2025-01-
|
|
3196
|
+
" outlit customers timeline acme.com --start-date 2025-01-01T00:00:00Z --end-date 2025-03-01T23:59:59Z",
|
|
2501
3197
|
" outlit customers timeline acme.com --event-types PAGE_VIEW,MEETING --limit 50",
|
|
2502
3198
|
"",
|
|
2503
3199
|
AGENT_JSON_HINT
|
|
@@ -2515,7 +3211,7 @@ var init_timeline = __esm(() => {
|
|
|
2515
3211
|
},
|
|
2516
3212
|
channels: {
|
|
2517
3213
|
type: "string",
|
|
2518
|
-
description:
|
|
3214
|
+
description: `Comma-separated list of channels to filter (${timelineChannels.join(", ")})`
|
|
2519
3215
|
},
|
|
2520
3216
|
"event-types": {
|
|
2521
3217
|
type: "string",
|
|
@@ -2523,16 +3219,16 @@ var init_timeline = __esm(() => {
|
|
|
2523
3219
|
},
|
|
2524
3220
|
timeframe: {
|
|
2525
3221
|
type: "string",
|
|
2526
|
-
description:
|
|
3222
|
+
description: `Timeframe for events (${timelineTimeframes.join(", ")}). Ignored when --start-date or --end-date is set.`,
|
|
2527
3223
|
default: "30d"
|
|
2528
3224
|
},
|
|
2529
3225
|
"start-date": {
|
|
2530
3226
|
type: "string",
|
|
2531
|
-
description: "Start
|
|
3227
|
+
description: "Start datetime for the event range (ISO 8601, e.g. 2025-01-01T00:00:00Z). When set, --timeframe is ignored."
|
|
2532
3228
|
},
|
|
2533
3229
|
"end-date": {
|
|
2534
3230
|
type: "string",
|
|
2535
|
-
description: "End
|
|
3231
|
+
description: "End datetime for the event range (ISO 8601, e.g. 2025-03-01T23:59:59Z). When set, --timeframe is ignored."
|
|
2536
3232
|
}
|
|
2537
3233
|
},
|
|
2538
3234
|
async run({ args }) {
|
|
@@ -2555,7 +3251,7 @@ var init_timeline = __esm(() => {
|
|
|
2555
3251
|
params.eventTypes = splitCsv(args["event-types"]);
|
|
2556
3252
|
}
|
|
2557
3253
|
applyPagination(params, args, json);
|
|
2558
|
-
return runTool(client,
|
|
3254
|
+
return runTool(client, customerToolContracts.outlit_get_timeline.toolName, params, json);
|
|
2559
3255
|
}
|
|
2560
3256
|
});
|
|
2561
3257
|
});
|
|
@@ -2599,6 +3295,7 @@ __export(exports_list2, {
|
|
|
2599
3295
|
});
|
|
2600
3296
|
var list_default2;
|
|
2601
3297
|
var init_list2 = __esm(() => {
|
|
3298
|
+
init_dist4();
|
|
2602
3299
|
init_dist();
|
|
2603
3300
|
init_auth();
|
|
2604
3301
|
init_filters();
|
|
@@ -2617,7 +3314,7 @@ var init_list2 = __esm(() => {
|
|
|
2617
3314
|
"",
|
|
2618
3315
|
"Examples:",
|
|
2619
3316
|
" outlit users list # all users",
|
|
2620
|
-
" outlit users list --journey-stage
|
|
3317
|
+
" outlit users list --journey-stage ENGAGED # engaged users only",
|
|
2621
3318
|
" outlit users list --customer-id <uuid> # users for a customer",
|
|
2622
3319
|
" outlit users list --no-activity-in 30d # inactive users",
|
|
2623
3320
|
" outlit users list --search alice --order-by last_activity_at",
|
|
@@ -2634,7 +3331,7 @@ var init_list2 = __esm(() => {
|
|
|
2634
3331
|
...traitFilterArgs,
|
|
2635
3332
|
"journey-stage": {
|
|
2636
3333
|
type: "string",
|
|
2637
|
-
description:
|
|
3334
|
+
description: `Filter by journey stage (${userJourneyStages.join(", ")})`
|
|
2638
3335
|
},
|
|
2639
3336
|
"customer-id": {
|
|
2640
3337
|
type: "string",
|
|
@@ -2670,7 +3367,7 @@ var init_list2 = __esm(() => {
|
|
|
2670
3367
|
}
|
|
2671
3368
|
applyListFilters(params, args);
|
|
2672
3369
|
applyPagination(params, args, json);
|
|
2673
|
-
return runTool(client,
|
|
3370
|
+
return runTool(client, customerToolContracts.outlit_list_users.toolName, params, json, {
|
|
2674
3371
|
spinnerMessage: "Fetching users...",
|
|
2675
3372
|
table: {
|
|
2676
3373
|
columns: [
|
|
@@ -2714,376 +3411,213 @@ var init_users = __esm(() => {
|
|
|
2714
3411
|
});
|
|
2715
3412
|
});
|
|
2716
3413
|
|
|
2717
|
-
// src/lib/
|
|
2718
|
-
import { execFileSync as
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
if (isEnoentError(err)) {
|
|
2734
|
-
return outputError({ message: opts.notFoundMessage, code: opts.notFoundCode }, json);
|
|
2735
|
-
}
|
|
2736
|
-
opts.extraErrorHandler?.(err, json);
|
|
2737
|
-
return outputError({ message: errorMessage(err, `${opts.cliName} mcp add failed`), code: "exec_error" }, json);
|
|
2738
|
-
}
|
|
2739
|
-
return { success: false, error: errorMessage(err, `${opts.cliName} mcp add failed`) };
|
|
2740
|
-
}
|
|
2741
|
-
if (exitOnError) {
|
|
2742
|
-
if (isJsonMode(json)) {
|
|
2743
|
-
outputResult({ success: true, agent: opts.agentId });
|
|
2744
|
-
return { success: true };
|
|
2745
|
-
}
|
|
2746
|
-
console.log(`${TICK2} ${opts.successMessage}`);
|
|
3414
|
+
// src/lib/update.ts
|
|
3415
|
+
import { execFileSync as execFileSync3, spawn as spawn2, spawnSync as spawnSync2 } from "node:child_process";
|
|
3416
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync3, realpathSync as realpathSync2, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
3417
|
+
import { homedir as homedir3 } from "node:os";
|
|
3418
|
+
import { dirname as dirname3, join as join4 } from "node:path";
|
|
3419
|
+
function compareVersions2(a, b) {
|
|
3420
|
+
const aParts = a.split("-")[0]?.split(".").map((part) => Number.parseInt(part, 10) || 0) ?? [];
|
|
3421
|
+
const bParts = b.split("-")[0]?.split(".").map((part) => Number.parseInt(part, 10) || 0) ?? [];
|
|
3422
|
+
const maxLength = Math.max(aParts.length, bParts.length);
|
|
3423
|
+
for (let index = 0;index < maxLength; index++) {
|
|
3424
|
+
const left = aParts[index] ?? 0;
|
|
3425
|
+
const right = bParts[index] ?? 0;
|
|
3426
|
+
if (left > right)
|
|
3427
|
+
return 1;
|
|
3428
|
+
if (left < right)
|
|
3429
|
+
return -1;
|
|
2747
3430
|
}
|
|
2748
|
-
return
|
|
3431
|
+
return 0;
|
|
2749
3432
|
}
|
|
2750
|
-
function
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
3433
|
+
function inferInstallerFromUserAgent2(agent) {
|
|
3434
|
+
if (agent.startsWith("bun/"))
|
|
3435
|
+
return "bun";
|
|
3436
|
+
if (agent.startsWith("npm/"))
|
|
3437
|
+
return "npm";
|
|
3438
|
+
if (agent.startsWith("pnpm/"))
|
|
3439
|
+
return "pnpm";
|
|
3440
|
+
if (agent.startsWith("yarn/"))
|
|
3441
|
+
return "yarn";
|
|
3442
|
+
return null;
|
|
3443
|
+
}
|
|
3444
|
+
function isUnderPath2(path, parent) {
|
|
3445
|
+
const normalizedPath = normalizeInstallerPath2(path);
|
|
3446
|
+
const normalizedParent = normalizeInstallerPath2(parent);
|
|
3447
|
+
return normalizedPath === normalizedParent || normalizedPath.startsWith(`${normalizedParent}/`);
|
|
3448
|
+
}
|
|
3449
|
+
function normalizeInstallerPath2(path) {
|
|
3450
|
+
return path.replace(/^\/private\/tmp\//, "/tmp/");
|
|
3451
|
+
}
|
|
3452
|
+
function inferInstallerFromInstallation2(opts) {
|
|
3453
|
+
const candidatePaths = [opts.argv1, opts.realExecPath].filter((value) => !!value);
|
|
3454
|
+
if (opts.npmGlobalPrefix) {
|
|
3455
|
+
const npmPackageRoots = [
|
|
3456
|
+
join4(opts.npmGlobalPrefix, "node_modules", PACKAGE_NAME2),
|
|
3457
|
+
join4(opts.npmGlobalPrefix, "lib", "node_modules", PACKAGE_NAME2)
|
|
3458
|
+
];
|
|
3459
|
+
if (candidatePaths.some((path) => npmPackageRoots.some((root) => isUnderPath2(path, root)))) {
|
|
3460
|
+
return "npm";
|
|
2760
3461
|
}
|
|
2761
|
-
throw err;
|
|
2762
3462
|
}
|
|
2763
|
-
if (
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
return
|
|
3463
|
+
if (opts.bunGlobalBin) {
|
|
3464
|
+
const bunGlobalBin = opts.bunGlobalBin;
|
|
3465
|
+
if (candidatePaths.some((path) => isUnderPath2(path, bunGlobalBin))) {
|
|
3466
|
+
return "bun";
|
|
2767
3467
|
}
|
|
2768
|
-
console.log(`${TICK2} ${opts.successMessage}`);
|
|
2769
3468
|
}
|
|
2770
|
-
return
|
|
3469
|
+
return null;
|
|
2771
3470
|
}
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
configureSafe: () => configureSafe
|
|
2782
|
-
});
|
|
2783
|
-
function configureSafe(key, json) {
|
|
2784
|
-
return runMcpCliSetup(key, json, getConfig(), false).success;
|
|
2785
|
-
}
|
|
2786
|
-
var getConfig = () => ({
|
|
2787
|
-
cliName: "claude",
|
|
2788
|
-
agentId: "claude-code",
|
|
2789
|
-
notFoundMessage: "claude CLI not found. Install from https://claude.ai/code",
|
|
2790
|
-
notFoundCode: "claude_not_found",
|
|
2791
|
-
successMessage: "Outlit added to Claude Code. Restart Claude Code to apply."
|
|
2792
|
-
}), claude_code_default;
|
|
2793
|
-
var init_claude_code = __esm(() => {
|
|
2794
|
-
init_dist();
|
|
2795
|
-
init_auth();
|
|
2796
|
-
init_output2();
|
|
2797
|
-
init_config();
|
|
2798
|
-
init_setup();
|
|
2799
|
-
claude_code_default = defineCommand2({
|
|
2800
|
-
meta: {
|
|
2801
|
-
name: "claude-code",
|
|
2802
|
-
description: "Register Outlit MCP server with Claude Code via `claude mcp add`."
|
|
2803
|
-
},
|
|
2804
|
-
args: { ...authArgs, ...outputArgs },
|
|
2805
|
-
run({ args }) {
|
|
2806
|
-
const json = !!args.json;
|
|
2807
|
-
const { key } = requireCredential(args["api-key"], json);
|
|
2808
|
-
runMcpCliSetup(key, json, getConfig());
|
|
2809
|
-
}
|
|
2810
|
-
});
|
|
2811
|
-
});
|
|
2812
|
-
|
|
2813
|
-
// src/commands/setup/claude-desktop.ts
|
|
2814
|
-
var exports_claude_desktop = {};
|
|
2815
|
-
__export(exports_claude_desktop, {
|
|
2816
|
-
default: () => claude_desktop_default,
|
|
2817
|
-
configureSafe: () => configureSafe2
|
|
2818
|
-
});
|
|
2819
|
-
function configureSafe2(key, json) {
|
|
2820
|
-
return runMcpFileSetup(key, json, getConfig2(key), false).success;
|
|
3471
|
+
function readCommandOutput2(command, args) {
|
|
3472
|
+
try {
|
|
3473
|
+
return execFileSync3(command, args, {
|
|
3474
|
+
encoding: "utf8",
|
|
3475
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
3476
|
+
}).trim();
|
|
3477
|
+
} catch {
|
|
3478
|
+
return null;
|
|
3479
|
+
}
|
|
2821
3480
|
}
|
|
2822
|
-
|
|
2823
|
-
const
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
init_dist();
|
|
2836
|
-
init_auth();
|
|
2837
|
-
init_output2();
|
|
2838
|
-
init_config();
|
|
2839
|
-
init_setup();
|
|
2840
|
-
claude_desktop_default = defineCommand2({
|
|
2841
|
-
meta: {
|
|
2842
|
-
name: "claude-desktop",
|
|
2843
|
-
description: "Add Outlit MCP server to Claude Desktop config."
|
|
2844
|
-
},
|
|
2845
|
-
args: { ...authArgs, ...outputArgs },
|
|
2846
|
-
run({ args }) {
|
|
2847
|
-
const json = !!args.json;
|
|
2848
|
-
const { key } = requireCredential(args["api-key"], json);
|
|
2849
|
-
runMcpFileSetup(key, json, getConfig2(key));
|
|
2850
|
-
}
|
|
2851
|
-
});
|
|
2852
|
-
});
|
|
2853
|
-
|
|
2854
|
-
// src/commands/setup/cursor.ts
|
|
2855
|
-
var exports_cursor = {};
|
|
2856
|
-
__export(exports_cursor, {
|
|
2857
|
-
default: () => cursor_default,
|
|
2858
|
-
configureSafe: () => configureSafe3
|
|
2859
|
-
});
|
|
2860
|
-
import { homedir as homedir2 } from "node:os";
|
|
2861
|
-
import { join as join3 } from "node:path";
|
|
2862
|
-
function configureSafe3(key, json) {
|
|
2863
|
-
return runMcpFileSetup(key, json, getConfig3(), false).success;
|
|
2864
|
-
}
|
|
2865
|
-
var getConfig3 = () => ({
|
|
2866
|
-
agentId: "cursor",
|
|
2867
|
-
configPath: join3(homedir2(), ".cursor", "mcp.json"),
|
|
2868
|
-
serversKey: "mcpServers",
|
|
2869
|
-
label: "cursor mcp.json",
|
|
2870
|
-
successMessage: `Outlit added to Cursor MCP config. Restart Cursor to apply.
|
|
2871
|
-
Config: ~/.cursor/mcp.json`
|
|
2872
|
-
}), cursor_default;
|
|
2873
|
-
var init_cursor = __esm(() => {
|
|
2874
|
-
init_dist();
|
|
2875
|
-
init_auth();
|
|
2876
|
-
init_output2();
|
|
2877
|
-
init_config();
|
|
2878
|
-
init_setup();
|
|
2879
|
-
cursor_default = defineCommand2({
|
|
2880
|
-
meta: {
|
|
2881
|
-
name: "cursor",
|
|
2882
|
-
description: "Add Outlit MCP server to ~/.cursor/mcp.json."
|
|
2883
|
-
},
|
|
2884
|
-
args: { ...authArgs, ...outputArgs },
|
|
2885
|
-
run({ args }) {
|
|
2886
|
-
const json = !!args.json;
|
|
2887
|
-
const { key } = requireCredential(args["api-key"], json);
|
|
2888
|
-
runMcpFileSetup(key, json, getConfig3());
|
|
2889
|
-
}
|
|
2890
|
-
});
|
|
2891
|
-
});
|
|
2892
|
-
|
|
2893
|
-
// src/commands/setup/gemini.ts
|
|
2894
|
-
var exports_gemini = {};
|
|
2895
|
-
__export(exports_gemini, {
|
|
2896
|
-
default: () => gemini_default,
|
|
2897
|
-
configureSafe: () => configureSafe4
|
|
2898
|
-
});
|
|
2899
|
-
function configureSafe4(key, json) {
|
|
2900
|
-
return runMcpCliSetup(key, json, getConfig4(), false).success;
|
|
2901
|
-
}
|
|
2902
|
-
var getConfig4 = () => ({
|
|
2903
|
-
cliName: "gemini",
|
|
2904
|
-
agentId: "gemini",
|
|
2905
|
-
notFoundMessage: "gemini CLI not found. Install from https://github.com/google-gemini/gemini-cli",
|
|
2906
|
-
notFoundCode: "gemini_not_found",
|
|
2907
|
-
successMessage: "Outlit added to Gemini CLI. Restart Gemini CLI to apply."
|
|
2908
|
-
}), gemini_default;
|
|
2909
|
-
var init_gemini = __esm(() => {
|
|
2910
|
-
init_dist();
|
|
2911
|
-
init_auth();
|
|
2912
|
-
init_output2();
|
|
2913
|
-
init_config();
|
|
2914
|
-
init_output();
|
|
2915
|
-
init_setup();
|
|
2916
|
-
gemini_default = defineCommand2({
|
|
2917
|
-
meta: {
|
|
2918
|
-
name: "gemini",
|
|
2919
|
-
description: "Register Outlit MCP server with Gemini CLI via `gemini mcp add`."
|
|
2920
|
-
},
|
|
2921
|
-
args: { ...authArgs, ...outputArgs },
|
|
2922
|
-
run({ args }) {
|
|
2923
|
-
const json = !!args.json;
|
|
2924
|
-
const { key } = requireCredential(args["api-key"], json);
|
|
2925
|
-
runMcpCliSetup(key, json, {
|
|
2926
|
-
...getConfig4(),
|
|
2927
|
-
extraErrorHandler(err, j2) {
|
|
2928
|
-
const msg = err instanceof Error ? err.message.toLowerCase() : "";
|
|
2929
|
-
if (msg.includes("mcp") && msg.includes("not")) {
|
|
2930
|
-
outputError({
|
|
2931
|
-
message: "Your Gemini CLI version does not support 'mcp add'. Run 'gemini update' or reinstall.",
|
|
2932
|
-
code: "gemini_mcp_unsupported"
|
|
2933
|
-
}, j2);
|
|
2934
|
-
}
|
|
2935
|
-
}
|
|
2936
|
-
});
|
|
2937
|
-
}
|
|
3481
|
+
function inferInstaller2() {
|
|
3482
|
+
const fromAgent = inferInstallerFromUserAgent2(process.env.npm_config_user_agent ?? "");
|
|
3483
|
+
if (fromAgent)
|
|
3484
|
+
return fromAgent;
|
|
3485
|
+
const argv1 = process.argv[1];
|
|
3486
|
+
const realExecPath = argv1 ? readCommandOutput2("realpath", [argv1]) ?? safeRealPath2(argv1) : null;
|
|
3487
|
+
const npmGlobalPrefix = process.env.npm_config_prefix ?? readCommandOutput2("npm", ["prefix", "-g"]);
|
|
3488
|
+
const bunGlobalBin = process.env.BUN_INSTALL ? join4(process.env.BUN_INSTALL, "bin") : readCommandOutput2("bun", ["pm", "bin", "-g"]) ?? join4(homedir3(), ".bun", "bin");
|
|
3489
|
+
return inferInstallerFromInstallation2({
|
|
3490
|
+
argv1,
|
|
3491
|
+
realExecPath,
|
|
3492
|
+
npmGlobalPrefix,
|
|
3493
|
+
bunGlobalBin
|
|
2938
3494
|
});
|
|
2939
|
-
});
|
|
2940
|
-
|
|
2941
|
-
// src/commands/setup/openclaw.ts
|
|
2942
|
-
var exports_openclaw = {};
|
|
2943
|
-
__export(exports_openclaw, {
|
|
2944
|
-
getSkillDir: () => getSkillDir,
|
|
2945
|
-
default: () => openclaw_default,
|
|
2946
|
-
configureSafe: () => configureSafe5,
|
|
2947
|
-
buildSkillContent: () => buildSkillContent
|
|
2948
|
-
});
|
|
2949
|
-
import { homedir as homedir3 } from "node:os";
|
|
2950
|
-
import { join as join4 } from "node:path";
|
|
2951
|
-
function getSkillDir() {
|
|
2952
|
-
const home = homedir3();
|
|
2953
|
-
return join4(home, ".openclaw", "skills", "outlit");
|
|
2954
|
-
}
|
|
2955
|
-
function buildSkillContent(maskedKey) {
|
|
2956
|
-
return `---
|
|
2957
|
-
name: outlit
|
|
2958
|
-
description: Query customer data, revenue metrics, and analytics via the Outlit CLI.
|
|
2959
|
-
metadata:
|
|
2960
|
-
openclaw:
|
|
2961
|
-
requires:
|
|
2962
|
-
bins: ["outlit"]
|
|
2963
|
-
env: ["OUTLIT_API_KEY"]
|
|
2964
|
-
---
|
|
2965
|
-
|
|
2966
|
-
# Outlit Customer Intelligence
|
|
2967
|
-
|
|
2968
|
-
You have access to the \`outlit\` CLI for querying customer data and analytics.
|
|
2969
|
-
The CLI outputs structured JSON automatically in non-TTY contexts.
|
|
2970
|
-
|
|
2971
|
-
## Authentication
|
|
2972
|
-
|
|
2973
|
-
Set the env var before running any command:
|
|
2974
|
-
|
|
2975
|
-
export OUTLIT_API_KEY=${maskedKey}
|
|
2976
|
-
|
|
2977
|
-
## List customers
|
|
2978
|
-
|
|
2979
|
-
outlit customers list --billing-status PAYING --no-activity-in 30d --order-by mrr_cents
|
|
2980
|
-
|
|
2981
|
-
## Get customer details
|
|
2982
|
-
|
|
2983
|
-
outlit customers get acme.com --include users,revenue,recentTimeline
|
|
2984
|
-
|
|
2985
|
-
## Get customer activity timeline
|
|
2986
|
-
|
|
2987
|
-
outlit customers timeline acme.com --channels EMAIL,SLACK --limit 50
|
|
2988
|
-
|
|
2989
|
-
## List users for a customer
|
|
2990
|
-
|
|
2991
|
-
outlit users list --customer-id <uuid> --journey-stage ACTIVATED
|
|
2992
|
-
|
|
2993
|
-
## Search across customer context
|
|
2994
|
-
|
|
2995
|
-
outlit search "budget concerns" --customer acme.com
|
|
2996
|
-
|
|
2997
|
-
## Get facts about a customer
|
|
2998
|
-
|
|
2999
|
-
outlit facts acme.com --timeframe 90d
|
|
3000
|
-
|
|
3001
|
-
## Run custom SQL
|
|
3002
|
-
|
|
3003
|
-
outlit sql "SELECT event_type, count(*) FROM events GROUP BY 1 ORDER BY 2 DESC LIMIT 10"
|
|
3004
|
-
|
|
3005
|
-
## Query with a file (for complex SQL)
|
|
3006
|
-
|
|
3007
|
-
outlit sql --query-file /tmp/query.sql
|
|
3008
|
-
|
|
3009
|
-
## Discover table schemas
|
|
3010
|
-
|
|
3011
|
-
outlit schema
|
|
3012
|
-
outlit schema events
|
|
3013
|
-
|
|
3014
|
-
## Rules
|
|
3015
|
-
- Always parse the JSON response before reporting to the user
|
|
3016
|
-
- Convert monetary values from cents to dollars (divide by 100)
|
|
3017
|
-
- IDs are UUIDs (e.g., "a1b2c3d4-e5f6-...")
|
|
3018
|
-
- Never show the raw API key to the user
|
|
3019
|
-
- Use --query-file for complex SQL to avoid shell escaping issues
|
|
3020
|
-
- All list responses include pagination.hasMore and pagination.nextCursor
|
|
3021
|
-
`;
|
|
3022
3495
|
}
|
|
3023
|
-
function
|
|
3024
|
-
const skillPath = join4(getSkillDir(), "SKILL.md");
|
|
3496
|
+
function safeRealPath2(filePath) {
|
|
3025
3497
|
try {
|
|
3026
|
-
|
|
3027
|
-
return true;
|
|
3498
|
+
return realpathSync2(filePath);
|
|
3028
3499
|
} catch {
|
|
3029
|
-
return
|
|
3500
|
+
return null;
|
|
3030
3501
|
}
|
|
3031
3502
|
}
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3503
|
+
function formatUpdateCommand2(installer = inferInstaller2()) {
|
|
3504
|
+
switch (installer) {
|
|
3505
|
+
case "bun":
|
|
3506
|
+
return "bun add -g @outlit/cli";
|
|
3507
|
+
case "npm":
|
|
3508
|
+
return "npm install -g @outlit/cli";
|
|
3509
|
+
case "pnpm":
|
|
3510
|
+
return "pnpm add -g @outlit/cli";
|
|
3511
|
+
case "yarn":
|
|
3512
|
+
return "yarn global add @outlit/cli";
|
|
3513
|
+
default:
|
|
3514
|
+
return `update ${PACKAGE_NAME2} with your package manager`;
|
|
3515
|
+
}
|
|
3516
|
+
}
|
|
3517
|
+
function getUpgradeCommand(installer = inferInstaller2()) {
|
|
3518
|
+
switch (installer) {
|
|
3519
|
+
case "bun":
|
|
3520
|
+
return {
|
|
3521
|
+
command: "bun",
|
|
3522
|
+
args: ["add", "-g", "@outlit/cli"],
|
|
3523
|
+
displayCommand: "bun add -g @outlit/cli"
|
|
3524
|
+
};
|
|
3525
|
+
case "npm":
|
|
3526
|
+
return {
|
|
3527
|
+
command: "npm",
|
|
3528
|
+
args: ["install", "-g", "@outlit/cli"],
|
|
3529
|
+
displayCommand: "npm install -g @outlit/cli"
|
|
3530
|
+
};
|
|
3531
|
+
case "pnpm":
|
|
3532
|
+
return {
|
|
3533
|
+
command: "pnpm",
|
|
3534
|
+
args: ["add", "-g", "@outlit/cli"],
|
|
3535
|
+
displayCommand: "pnpm add -g @outlit/cli"
|
|
3536
|
+
};
|
|
3537
|
+
case "yarn":
|
|
3538
|
+
return {
|
|
3539
|
+
command: "yarn",
|
|
3540
|
+
args: ["global", "add", "@outlit/cli"],
|
|
3541
|
+
displayCommand: "yarn global add @outlit/cli"
|
|
3542
|
+
};
|
|
3543
|
+
default:
|
|
3544
|
+
return null;
|
|
3545
|
+
}
|
|
3546
|
+
}
|
|
3547
|
+
async function fetchLatestCliVersion2() {
|
|
3548
|
+
const response = await fetch(LATEST_VERSION_URL2, { signal: AbortSignal.timeout(5000) });
|
|
3549
|
+
if (!response.ok)
|
|
3550
|
+
throw new Error("registry unavailable");
|
|
3551
|
+
const data = await response.json();
|
|
3552
|
+
if (!data.version)
|
|
3553
|
+
throw new Error("registry returned no version");
|
|
3554
|
+
return data.version;
|
|
3555
|
+
}
|
|
3556
|
+
function runUpgradeCommand(command) {
|
|
3557
|
+
const result = spawnSync2(command.command, command.args, { stdio: "inherit" });
|
|
3558
|
+
if (result.error)
|
|
3559
|
+
throw result.error;
|
|
3560
|
+
if (result.status !== 0 || result.signal) {
|
|
3561
|
+
throw new Error(`Upgrade command failed: ${command.displayCommand}`);
|
|
3562
|
+
}
|
|
3563
|
+
}
|
|
3564
|
+
var UPDATE_CHECK_INTERVAL_MS2, PACKAGE_NAME2 = "@outlit/cli", LATEST_VERSION_URL2 = "https://registry.npmjs.org/@outlit%2Fcli/latest";
|
|
3565
|
+
var init_update = __esm(() => {
|
|
3037
3566
|
init_config();
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
meta: {
|
|
3041
|
-
name: "openclaw",
|
|
3042
|
-
description: "Write Outlit skill to ~/.openclaw/skills/ for OpenClaw."
|
|
3043
|
-
},
|
|
3044
|
-
args: { ...authArgs, ...outputArgs },
|
|
3045
|
-
run({ args }) {
|
|
3046
|
-
const json = !!args.json;
|
|
3047
|
-
const { key } = requireCredential(args["api-key"], json);
|
|
3048
|
-
const skillPath = join4(getSkillDir(), "SKILL.md");
|
|
3049
|
-
const content = buildSkillContent(maskKey(key));
|
|
3050
|
-
writeConfigFile(skillPath, content, { json, label: "SKILL.md" });
|
|
3051
|
-
if (isJsonMode(json)) {
|
|
3052
|
-
return outputResult({ success: true, path: skillPath, agent: "openclaw" });
|
|
3053
|
-
}
|
|
3054
|
-
console.log(`${TICK2} Outlit skill written to ${skillPath}. OpenClaw will load it automatically.`);
|
|
3055
|
-
}
|
|
3056
|
-
});
|
|
3567
|
+
init_tty();
|
|
3568
|
+
UPDATE_CHECK_INTERVAL_MS2 = 12 * 60 * 60 * 1000;
|
|
3057
3569
|
});
|
|
3058
3570
|
|
|
3059
3571
|
// src/commands/setup/skills.ts
|
|
3060
3572
|
var exports_skills = {};
|
|
3061
3573
|
__export(exports_skills, {
|
|
3062
3574
|
runSkillsInstall: () => runSkillsInstall,
|
|
3575
|
+
runAgentSkillsInstall: () => runAgentSkillsInstall,
|
|
3576
|
+
getSkillAgentId: () => getSkillAgentId,
|
|
3063
3577
|
detectPackageRunner: () => detectPackageRunner,
|
|
3064
|
-
default: () => skills_default
|
|
3578
|
+
default: () => skills_default,
|
|
3579
|
+
SKILLS_REPO_URL: () => SKILLS_REPO_URL
|
|
3065
3580
|
});
|
|
3066
|
-
import { execFileSync as
|
|
3581
|
+
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
3582
|
+
function getSkillAgentId(agent) {
|
|
3583
|
+
return skillAgentMap[agent];
|
|
3584
|
+
}
|
|
3067
3585
|
function detectPackageRunner() {
|
|
3068
3586
|
const whichCmd = process.platform === "win32" ? "where" : "which";
|
|
3069
3587
|
for (const runner of ["npx", "bunx", "pnpx"]) {
|
|
3070
3588
|
try {
|
|
3071
|
-
|
|
3589
|
+
execFileSync4(whichCmd, [runner], { stdio: "ignore" });
|
|
3072
3590
|
return runner;
|
|
3073
3591
|
} catch {}
|
|
3074
3592
|
}
|
|
3075
3593
|
return null;
|
|
3076
3594
|
}
|
|
3077
|
-
function buildRunnerArgs(runner) {
|
|
3595
|
+
function buildRunnerArgs(runner, opts) {
|
|
3078
3596
|
const args = runner === "npx" ? ["-y"] : [];
|
|
3079
3597
|
args.push("skills", "add", SKILLS_REPO_URL);
|
|
3080
|
-
for (const
|
|
3081
|
-
args.push("--skill",
|
|
3598
|
+
for (const skillName of opts.skillNames ?? []) {
|
|
3599
|
+
args.push("--skill", skillName);
|
|
3600
|
+
}
|
|
3601
|
+
for (const agent of opts.agents ?? []) {
|
|
3602
|
+
args.push("--agent", agent);
|
|
3603
|
+
}
|
|
3604
|
+
if (opts.autoConfirm) {
|
|
3605
|
+
args.push("-y");
|
|
3606
|
+
}
|
|
3607
|
+
if (opts.global !== false) {
|
|
3608
|
+
args.push("-g");
|
|
3082
3609
|
}
|
|
3083
|
-
args.push("-y", "-g");
|
|
3084
3610
|
return args;
|
|
3085
3611
|
}
|
|
3086
|
-
function runSkillsInstall(
|
|
3612
|
+
function runSkillsInstall(opts) {
|
|
3613
|
+
const {
|
|
3614
|
+
json,
|
|
3615
|
+
exitOnError = true,
|
|
3616
|
+
agents,
|
|
3617
|
+
skillNames,
|
|
3618
|
+
reportedAgent = "skills",
|
|
3619
|
+
autoConfirm = false
|
|
3620
|
+
} = opts;
|
|
3087
3621
|
const runner = detectPackageRunner();
|
|
3088
3622
|
if (!runner) {
|
|
3089
3623
|
if (exitOnError) {
|
|
@@ -3094,8 +3628,11 @@ function runSkillsInstall(json, exitOnError = true) {
|
|
|
3094
3628
|
}
|
|
3095
3629
|
return { success: false, error: "No package runner found" };
|
|
3096
3630
|
}
|
|
3631
|
+
const isInteractiveInstall = (agents?.length ?? 0) === 0 && (skillNames?.length ?? 0) === 0 && !autoConfirm && !isJsonMode(json);
|
|
3097
3632
|
try {
|
|
3098
|
-
|
|
3633
|
+
execFileSync4(runner, buildRunnerArgs(runner, { agents, skillNames, autoConfirm }), {
|
|
3634
|
+
stdio: isInteractiveInstall ? "inherit" : "pipe"
|
|
3635
|
+
});
|
|
3099
3636
|
} catch (err) {
|
|
3100
3637
|
if (exitOnError) {
|
|
3101
3638
|
if (isEnoentError(err)) {
|
|
@@ -3114,210 +3651,355 @@ function runSkillsInstall(json, exitOnError = true) {
|
|
|
3114
3651
|
}
|
|
3115
3652
|
if (exitOnError) {
|
|
3116
3653
|
if (isJsonMode(json)) {
|
|
3117
|
-
outputResult({ success: true, agent:
|
|
3654
|
+
outputResult({ success: true, agent: reportedAgent, runner });
|
|
3118
3655
|
return { success: true, runner };
|
|
3119
3656
|
}
|
|
3120
|
-
|
|
3657
|
+
if (reportedAgent === "skills") {
|
|
3658
|
+
console.log(`${TICK2} Outlit skills installer completed (${runner})`);
|
|
3659
|
+
} else {
|
|
3660
|
+
console.log(`${TICK2} Outlit skill installed for ${reportedAgent}`);
|
|
3661
|
+
}
|
|
3121
3662
|
}
|
|
3122
3663
|
return { success: true, runner };
|
|
3123
3664
|
}
|
|
3124
|
-
|
|
3665
|
+
function runAgentSkillsInstall(agent, json, exitOnError = true) {
|
|
3666
|
+
return runSkillsInstall({
|
|
3667
|
+
json,
|
|
3668
|
+
exitOnError,
|
|
3669
|
+
agents: [getSkillAgentId(agent)],
|
|
3670
|
+
skillNames: [DEFAULT_SKILL_NAME],
|
|
3671
|
+
reportedAgent: agent,
|
|
3672
|
+
autoConfirm: true
|
|
3673
|
+
});
|
|
3674
|
+
}
|
|
3675
|
+
var SKILLS_REPO_URL = "https://github.com/OutlitAI/outlit-agent-skills", DEFAULT_SKILL_NAME = "outlit", skillAgentMap, skills_default;
|
|
3125
3676
|
var init_skills = __esm(() => {
|
|
3126
3677
|
init_dist();
|
|
3127
3678
|
init_output2();
|
|
3128
3679
|
init_config();
|
|
3129
3680
|
init_output();
|
|
3130
|
-
|
|
3681
|
+
skillAgentMap = {
|
|
3682
|
+
"claude-code": "claude-code",
|
|
3683
|
+
codex: "codex",
|
|
3684
|
+
gemini: "gemini-cli",
|
|
3685
|
+
droid: "droid",
|
|
3686
|
+
opencode: "opencode",
|
|
3687
|
+
pi: "pi",
|
|
3688
|
+
openclaw: "openclaw"
|
|
3689
|
+
};
|
|
3131
3690
|
skills_default = defineCommand2({
|
|
3132
3691
|
meta: {
|
|
3133
3692
|
name: "skills",
|
|
3134
3693
|
description: [
|
|
3135
|
-
"
|
|
3694
|
+
"Launch the interactive Skills installer for Outlit.",
|
|
3136
3695
|
"",
|
|
3137
|
-
"
|
|
3696
|
+
"Uses the Outlit skills repo and lets you choose `outlit` and optional extras like `outlit-sdk`.",
|
|
3138
3697
|
"No API key required."
|
|
3139
3698
|
].join(`
|
|
3140
3699
|
`)
|
|
3141
3700
|
},
|
|
3142
3701
|
args: { ...outputArgs },
|
|
3143
3702
|
run({ args }) {
|
|
3144
|
-
|
|
3145
|
-
runSkillsInstall(json);
|
|
3703
|
+
runSkillsInstall({ json: !!args.json });
|
|
3146
3704
|
}
|
|
3147
3705
|
});
|
|
3148
3706
|
});
|
|
3149
3707
|
|
|
3150
|
-
// src/commands/setup/
|
|
3151
|
-
var
|
|
3152
|
-
__export(
|
|
3153
|
-
default: () =>
|
|
3154
|
-
configureSafe: () => configureSafe6
|
|
3708
|
+
// src/commands/setup/claude-code.ts
|
|
3709
|
+
var exports_claude_code = {};
|
|
3710
|
+
__export(exports_claude_code, {
|
|
3711
|
+
default: () => claude_code_default
|
|
3155
3712
|
});
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
return runMcpFileSetup(key, json, getConfig5(), false).success;
|
|
3159
|
-
}
|
|
3160
|
-
var getConfig5 = () => ({
|
|
3161
|
-
agentId: "vscode",
|
|
3162
|
-
configPath: join5(process.cwd(), ".vscode", "mcp.json"),
|
|
3163
|
-
serversKey: "servers",
|
|
3164
|
-
label: ".vscode/mcp.json",
|
|
3165
|
-
successMessage: "Outlit MCP config written to .vscode/mcp.json. Restart VS Code to apply."
|
|
3166
|
-
}), vscode_default;
|
|
3167
|
-
var init_vscode = __esm(() => {
|
|
3713
|
+
var claude_code_default;
|
|
3714
|
+
var init_claude_code = __esm(() => {
|
|
3168
3715
|
init_dist();
|
|
3169
|
-
init_auth();
|
|
3170
3716
|
init_output2();
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
vscode_default = defineCommand2({
|
|
3717
|
+
init_skills();
|
|
3718
|
+
claude_code_default = defineCommand2({
|
|
3174
3719
|
meta: {
|
|
3175
|
-
name: "
|
|
3176
|
-
description: "
|
|
3720
|
+
name: "claude-code",
|
|
3721
|
+
description: "Install the Outlit skill for Claude Code."
|
|
3177
3722
|
},
|
|
3178
|
-
args: { ...
|
|
3723
|
+
args: { ...outputArgs },
|
|
3179
3724
|
run({ args }) {
|
|
3180
|
-
|
|
3181
|
-
const { key } = requireCredential(args["api-key"], json);
|
|
3182
|
-
runMcpFileSetup(key, json, getConfig5());
|
|
3725
|
+
runAgentSkillsInstall("claude-code", !!args.json);
|
|
3183
3726
|
}
|
|
3184
3727
|
});
|
|
3185
3728
|
});
|
|
3186
3729
|
|
|
3187
|
-
// src/commands/setup/
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
const whichCmd = process.platform === "win32" ? "where" : "which";
|
|
3195
|
-
execFileSync4(whichCmd, [cmd], { stdio: "ignore" });
|
|
3196
|
-
return true;
|
|
3197
|
-
} catch {
|
|
3198
|
-
return false;
|
|
3199
|
-
}
|
|
3200
|
-
}
|
|
3201
|
-
function detectAgents() {
|
|
3202
|
-
const home = homedir4();
|
|
3203
|
-
const detected = [];
|
|
3204
|
-
if (existsSync2(join6(home, ".cursor")))
|
|
3205
|
-
detected.push("cursor");
|
|
3206
|
-
if (isCommandAvailable("claude"))
|
|
3207
|
-
detected.push("claude-code");
|
|
3208
|
-
if (existsSync2(getClaudeDesktopConfigPath()))
|
|
3209
|
-
detected.push("claude-desktop");
|
|
3210
|
-
if (isCommandAvailable("code") || existsSync2(join6(process.cwd(), ".vscode")))
|
|
3211
|
-
detected.push("vscode");
|
|
3212
|
-
if (isCommandAvailable("gemini"))
|
|
3213
|
-
detected.push("gemini");
|
|
3214
|
-
if (existsSync2(join6(home, ".openclaw", "skills")))
|
|
3215
|
-
detected.push("openclaw");
|
|
3216
|
-
return detected;
|
|
3217
|
-
}
|
|
3218
|
-
var agentLabels, configurators, setup_default;
|
|
3219
|
-
var init_setup2 = __esm(() => {
|
|
3730
|
+
// src/commands/setup/codex.ts
|
|
3731
|
+
var exports_codex = {};
|
|
3732
|
+
__export(exports_codex, {
|
|
3733
|
+
default: () => codex_default
|
|
3734
|
+
});
|
|
3735
|
+
var codex_default;
|
|
3736
|
+
var init_codex = __esm(() => {
|
|
3220
3737
|
init_dist();
|
|
3221
|
-
init_auth();
|
|
3222
3738
|
init_output2();
|
|
3223
|
-
init_config();
|
|
3224
|
-
init_output();
|
|
3225
|
-
init_claude_code();
|
|
3226
|
-
init_claude_desktop();
|
|
3227
|
-
init_cursor();
|
|
3228
|
-
init_gemini();
|
|
3229
|
-
init_openclaw();
|
|
3230
3739
|
init_skills();
|
|
3231
|
-
|
|
3232
|
-
agentLabels = {
|
|
3233
|
-
cursor: { label: "Cursor", hint: "~/.cursor/" },
|
|
3234
|
-
"claude-code": { label: "Claude Code", hint: "claude CLI found" },
|
|
3235
|
-
"claude-desktop": { label: "Claude Desktop", hint: "config file found" },
|
|
3236
|
-
vscode: { label: "VS Code", hint: "code CLI or .vscode/ found" },
|
|
3237
|
-
gemini: { label: "Gemini CLI", hint: "gemini CLI found" },
|
|
3238
|
-
openclaw: { label: "OpenClaw", hint: "skills directory found" }
|
|
3239
|
-
};
|
|
3240
|
-
configurators = {
|
|
3241
|
-
cursor: configureSafe3,
|
|
3242
|
-
"claude-code": configureSafe,
|
|
3243
|
-
"claude-desktop": configureSafe2,
|
|
3244
|
-
vscode: configureSafe6,
|
|
3245
|
-
gemini: configureSafe4,
|
|
3246
|
-
openclaw: configureSafe5
|
|
3247
|
-
};
|
|
3248
|
-
setup_default = defineCommand2({
|
|
3740
|
+
codex_default = defineCommand2({
|
|
3249
3741
|
meta: {
|
|
3250
|
-
name: "
|
|
3251
|
-
description:
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3742
|
+
name: "codex",
|
|
3743
|
+
description: "Install the Outlit skill for Codex."
|
|
3744
|
+
},
|
|
3745
|
+
args: { ...outputArgs },
|
|
3746
|
+
run({ args }) {
|
|
3747
|
+
runAgentSkillsInstall("codex", !!args.json);
|
|
3748
|
+
}
|
|
3749
|
+
});
|
|
3750
|
+
});
|
|
3751
|
+
|
|
3752
|
+
// src/commands/setup/gemini.ts
|
|
3753
|
+
var exports_gemini = {};
|
|
3754
|
+
__export(exports_gemini, {
|
|
3755
|
+
default: () => gemini_default
|
|
3756
|
+
});
|
|
3757
|
+
var gemini_default;
|
|
3758
|
+
var init_gemini = __esm(() => {
|
|
3759
|
+
init_dist();
|
|
3760
|
+
init_output2();
|
|
3761
|
+
init_skills();
|
|
3762
|
+
gemini_default = defineCommand2({
|
|
3763
|
+
meta: {
|
|
3764
|
+
name: "gemini",
|
|
3765
|
+
description: "Install the Outlit skill for Gemini CLI."
|
|
3766
|
+
},
|
|
3767
|
+
args: { ...outputArgs },
|
|
3768
|
+
run({ args }) {
|
|
3769
|
+
runAgentSkillsInstall("gemini", !!args.json);
|
|
3770
|
+
}
|
|
3771
|
+
});
|
|
3772
|
+
});
|
|
3773
|
+
|
|
3774
|
+
// src/commands/setup/droid.ts
|
|
3775
|
+
var exports_droid = {};
|
|
3776
|
+
__export(exports_droid, {
|
|
3777
|
+
default: () => droid_default
|
|
3778
|
+
});
|
|
3779
|
+
var droid_default;
|
|
3780
|
+
var init_droid = __esm(() => {
|
|
3781
|
+
init_dist();
|
|
3782
|
+
init_output2();
|
|
3783
|
+
init_skills();
|
|
3784
|
+
droid_default = defineCommand2({
|
|
3785
|
+
meta: {
|
|
3786
|
+
name: "droid",
|
|
3787
|
+
description: "Install the Outlit skill for Droid."
|
|
3788
|
+
},
|
|
3789
|
+
args: { ...outputArgs },
|
|
3790
|
+
run({ args }) {
|
|
3791
|
+
runAgentSkillsInstall("droid", !!args.json);
|
|
3792
|
+
}
|
|
3793
|
+
});
|
|
3794
|
+
});
|
|
3795
|
+
|
|
3796
|
+
// src/commands/setup/opencode.ts
|
|
3797
|
+
var exports_opencode = {};
|
|
3798
|
+
__export(exports_opencode, {
|
|
3799
|
+
default: () => opencode_default
|
|
3800
|
+
});
|
|
3801
|
+
var opencode_default;
|
|
3802
|
+
var init_opencode = __esm(() => {
|
|
3803
|
+
init_dist();
|
|
3804
|
+
init_output2();
|
|
3805
|
+
init_skills();
|
|
3806
|
+
opencode_default = defineCommand2({
|
|
3807
|
+
meta: {
|
|
3808
|
+
name: "opencode",
|
|
3809
|
+
description: "Install the Outlit skill for OpenCode."
|
|
3810
|
+
},
|
|
3811
|
+
args: { ...outputArgs },
|
|
3812
|
+
run({ args }) {
|
|
3813
|
+
runAgentSkillsInstall("opencode", !!args.json);
|
|
3814
|
+
}
|
|
3815
|
+
});
|
|
3816
|
+
});
|
|
3817
|
+
|
|
3818
|
+
// src/commands/setup/pi.ts
|
|
3819
|
+
var exports_pi = {};
|
|
3820
|
+
__export(exports_pi, {
|
|
3821
|
+
default: () => pi_default
|
|
3822
|
+
});
|
|
3823
|
+
var pi_default;
|
|
3824
|
+
var init_pi = __esm(() => {
|
|
3825
|
+
init_dist();
|
|
3826
|
+
init_output2();
|
|
3827
|
+
init_skills();
|
|
3828
|
+
pi_default = defineCommand2({
|
|
3829
|
+
meta: {
|
|
3830
|
+
name: "pi",
|
|
3831
|
+
description: "Install the Outlit skill for Pi."
|
|
3832
|
+
},
|
|
3833
|
+
args: { ...outputArgs },
|
|
3834
|
+
run({ args }) {
|
|
3835
|
+
runAgentSkillsInstall("pi", !!args.json);
|
|
3836
|
+
}
|
|
3837
|
+
});
|
|
3838
|
+
});
|
|
3839
|
+
|
|
3840
|
+
// src/commands/setup/openclaw.ts
|
|
3841
|
+
var exports_openclaw = {};
|
|
3842
|
+
__export(exports_openclaw, {
|
|
3843
|
+
default: () => openclaw_default
|
|
3844
|
+
});
|
|
3845
|
+
var openclaw_default;
|
|
3846
|
+
var init_openclaw = __esm(() => {
|
|
3847
|
+
init_dist();
|
|
3848
|
+
init_output2();
|
|
3849
|
+
init_skills();
|
|
3850
|
+
openclaw_default = defineCommand2({
|
|
3851
|
+
meta: {
|
|
3852
|
+
name: "openclaw",
|
|
3853
|
+
description: "Install the Outlit skill for OpenClaw."
|
|
3854
|
+
},
|
|
3855
|
+
args: { ...outputArgs },
|
|
3856
|
+
run({ args }) {
|
|
3857
|
+
runAgentSkillsInstall("openclaw", !!args.json);
|
|
3858
|
+
}
|
|
3859
|
+
});
|
|
3860
|
+
});
|
|
3861
|
+
|
|
3862
|
+
// src/commands/setup/index.ts
|
|
3863
|
+
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
3864
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
3865
|
+
import { homedir as homedir4 } from "node:os";
|
|
3866
|
+
import { join as join5 } from "node:path";
|
|
3867
|
+
function isCommandAvailable(cmd) {
|
|
3868
|
+
try {
|
|
3869
|
+
const whichCmd = process.platform === "win32" ? "where" : "which";
|
|
3870
|
+
execFileSync5(whichCmd, [cmd], { stdio: "ignore" });
|
|
3871
|
+
return true;
|
|
3872
|
+
} catch {
|
|
3873
|
+
return false;
|
|
3874
|
+
}
|
|
3875
|
+
}
|
|
3876
|
+
function getHomeDir() {
|
|
3877
|
+
return process.env.HOME?.trim() || homedir4();
|
|
3878
|
+
}
|
|
3879
|
+
function detectAgents() {
|
|
3880
|
+
const home = getHomeDir();
|
|
3881
|
+
const configHome = process.env.XDG_CONFIG_HOME?.trim() || join5(home, ".config");
|
|
3882
|
+
const detected = [];
|
|
3883
|
+
if (isCommandAvailable("claude"))
|
|
3884
|
+
detected.push("claude-code");
|
|
3885
|
+
if (isCommandAvailable("codex"))
|
|
3886
|
+
detected.push("codex");
|
|
3887
|
+
if (isCommandAvailable("gemini"))
|
|
3888
|
+
detected.push("gemini");
|
|
3889
|
+
if (existsSync4(join5(home, ".factory")))
|
|
3890
|
+
detected.push("droid");
|
|
3891
|
+
if (existsSync4(join5(configHome, "opencode")))
|
|
3892
|
+
detected.push("opencode");
|
|
3893
|
+
if (existsSync4(join5(home, ".pi", "agent")))
|
|
3894
|
+
detected.push("pi");
|
|
3895
|
+
if (existsSync4(join5(home, ".openclaw")) || existsSync4(join5(home, ".clawdbot")) || existsSync4(join5(home, ".moltbot"))) {
|
|
3896
|
+
detected.push("openclaw");
|
|
3897
|
+
}
|
|
3898
|
+
return detected;
|
|
3899
|
+
}
|
|
3900
|
+
var agentLabels, setupSubcommandNames, setup_default;
|
|
3901
|
+
var init_setup = __esm(() => {
|
|
3902
|
+
init_dist();
|
|
3903
|
+
init_output2();
|
|
3904
|
+
init_config();
|
|
3905
|
+
init_output();
|
|
3906
|
+
init_skills();
|
|
3907
|
+
agentLabels = {
|
|
3908
|
+
"claude-code": { label: "Claude Code", hint: "claude CLI found" },
|
|
3909
|
+
codex: { label: "Codex", hint: "codex CLI found" },
|
|
3910
|
+
gemini: { label: "Gemini CLI", hint: "gemini CLI found" },
|
|
3911
|
+
droid: { label: "Droid", hint: ".factory config found" },
|
|
3912
|
+
opencode: { label: "OpenCode", hint: "opencode config found" },
|
|
3913
|
+
pi: { label: "Pi", hint: ".pi/agent config found" },
|
|
3914
|
+
openclaw: { label: "OpenClaw", hint: "OpenClaw config found" }
|
|
3915
|
+
};
|
|
3916
|
+
setupSubcommandNames = new Set([
|
|
3917
|
+
"claude-code",
|
|
3918
|
+
"codex",
|
|
3919
|
+
"gemini",
|
|
3920
|
+
"droid",
|
|
3921
|
+
"opencode",
|
|
3922
|
+
"pi",
|
|
3923
|
+
"openclaw",
|
|
3924
|
+
"skills"
|
|
3925
|
+
]);
|
|
3926
|
+
setup_default = defineCommand2({
|
|
3927
|
+
meta: {
|
|
3928
|
+
name: "setup",
|
|
3929
|
+
description: [
|
|
3930
|
+
"Install the Outlit skill for coding agents.",
|
|
3931
|
+
"",
|
|
3932
|
+
"Without a subcommand, auto-detects supported coding agents and installs `outlit` for all of them.",
|
|
3933
|
+
"Subcommands: claude-code, codex, gemini, droid, opencode, pi, openclaw, skills"
|
|
3934
|
+
].join(`
|
|
3935
|
+
`)
|
|
3258
3936
|
},
|
|
3259
3937
|
args: {
|
|
3260
|
-
...authArgs,
|
|
3261
3938
|
...outputArgs,
|
|
3262
3939
|
yes: {
|
|
3263
3940
|
type: "boolean",
|
|
3264
|
-
description: "
|
|
3941
|
+
description: "Install for all detected coding agents without prompting."
|
|
3265
3942
|
}
|
|
3266
3943
|
},
|
|
3267
3944
|
subCommands: {
|
|
3268
|
-
cursor: () => Promise.resolve().then(() => (init_cursor(), exports_cursor)).then((m) => m.default),
|
|
3269
3945
|
"claude-code": () => Promise.resolve().then(() => (init_claude_code(), exports_claude_code)).then((m) => m.default),
|
|
3270
|
-
|
|
3271
|
-
vscode: () => Promise.resolve().then(() => (init_vscode(), exports_vscode)).then((m) => m.default),
|
|
3946
|
+
codex: () => Promise.resolve().then(() => (init_codex(), exports_codex)).then((m) => m.default),
|
|
3272
3947
|
gemini: () => Promise.resolve().then(() => (init_gemini(), exports_gemini)).then((m) => m.default),
|
|
3948
|
+
droid: () => Promise.resolve().then(() => (init_droid(), exports_droid)).then((m) => m.default),
|
|
3949
|
+
opencode: () => Promise.resolve().then(() => (init_opencode(), exports_opencode)).then((m) => m.default),
|
|
3950
|
+
pi: () => Promise.resolve().then(() => (init_pi(), exports_pi)).then((m) => m.default),
|
|
3273
3951
|
openclaw: () => Promise.resolve().then(() => (init_openclaw(), exports_openclaw)).then((m) => m.default),
|
|
3274
3952
|
skills: () => Promise.resolve().then(() => (init_skills(), exports_skills)).then((m) => m.default)
|
|
3275
3953
|
},
|
|
3276
|
-
async run({ args }) {
|
|
3954
|
+
async run({ args, rawArgs }) {
|
|
3955
|
+
const setupRawArgs = rawArgs ?? [];
|
|
3956
|
+
const subcommandName = setupRawArgs.find((arg) => !arg.startsWith("-"));
|
|
3957
|
+
if (subcommandName && setupSubcommandNames.has(subcommandName)) {
|
|
3958
|
+
return;
|
|
3959
|
+
}
|
|
3277
3960
|
const json = !!args.json;
|
|
3278
|
-
const credential = requireCredential(args["api-key"], json);
|
|
3279
3961
|
const detected = detectAgents();
|
|
3280
3962
|
if (detected.length === 0) {
|
|
3281
3963
|
if (isJsonMode(json)) {
|
|
3282
|
-
return outputResult({ detected: [], configured: [], failed: [],
|
|
3964
|
+
return outputResult({ detected: [], configured: [], failed: [], runner: null });
|
|
3283
3965
|
}
|
|
3284
|
-
console.log("No supported
|
|
3966
|
+
console.log("No supported coding agents detected.");
|
|
3285
3967
|
return;
|
|
3286
3968
|
}
|
|
3287
3969
|
if (!isJsonMode(json) && !args.yes) {
|
|
3288
|
-
console.log("Detected agents:");
|
|
3970
|
+
console.log("Detected coding agents:");
|
|
3289
3971
|
for (const agentId of detected) {
|
|
3290
3972
|
const { label, hint } = agentLabels[agentId];
|
|
3291
3973
|
console.log(` ${TICK2} ${label.padEnd(14)} -- ${hint}`);
|
|
3292
3974
|
}
|
|
3293
3975
|
console.log(`
|
|
3294
|
-
|
|
3295
|
-
}
|
|
3296
|
-
const configured = [];
|
|
3297
|
-
const failed = [];
|
|
3298
|
-
for (const agentId of detected) {
|
|
3299
|
-
const ok = configurators[agentId](credential.key, json);
|
|
3300
|
-
if (ok) {
|
|
3301
|
-
configured.push(agentId);
|
|
3302
|
-
} else {
|
|
3303
|
-
failed.push(agentId);
|
|
3304
|
-
}
|
|
3305
|
-
}
|
|
3306
|
-
const skills = runSkillsInstall(json, false);
|
|
3307
|
-
if (!isJsonMode(json) && !skills.success) {
|
|
3308
|
-
console.log(`
|
|
3309
|
-
! Agent skills installation failed: ${skills.error ?? "unknown error"}`);
|
|
3310
|
-
console.log(" Run `outlit setup skills` to retry.");
|
|
3976
|
+
Installing Outlit skill...`);
|
|
3311
3977
|
}
|
|
3978
|
+
const install = runSkillsInstall({
|
|
3979
|
+
json,
|
|
3980
|
+
exitOnError: false,
|
|
3981
|
+
agents: detected.map(getSkillAgentId),
|
|
3982
|
+
skillNames: ["outlit"],
|
|
3983
|
+
autoConfirm: true
|
|
3984
|
+
});
|
|
3985
|
+
const configured = install.success ? detected : [];
|
|
3986
|
+
const failed = install.success ? [] : detected;
|
|
3312
3987
|
if (isJsonMode(json)) {
|
|
3313
|
-
return outputResult({
|
|
3988
|
+
return outputResult({
|
|
3989
|
+
detected,
|
|
3990
|
+
configured,
|
|
3991
|
+
failed,
|
|
3992
|
+
runner: install.runner ?? null
|
|
3993
|
+
});
|
|
3314
3994
|
}
|
|
3315
|
-
if (
|
|
3995
|
+
if (!install.success) {
|
|
3316
3996
|
console.log(`
|
|
3317
|
-
|
|
3997
|
+
! Outlit skill install failed: ${install.error ?? "unknown error"}`);
|
|
3998
|
+
console.log(" Run `outlit setup skills` to retry manually.");
|
|
3999
|
+
return;
|
|
3318
4000
|
}
|
|
3319
4001
|
console.log(`
|
|
3320
|
-
Done. ${configured.length}
|
|
4002
|
+
Done. Installed Outlit for ${configured.length} coding agent(s).`);
|
|
3321
4003
|
}
|
|
3322
4004
|
});
|
|
3323
4005
|
});
|
|
@@ -3325,21 +4007,16 @@ Done. ${configured.length}/${detected.length} agent(s) configured successfully.`
|
|
|
3325
4007
|
// src/commands/doctor.ts
|
|
3326
4008
|
var exports_doctor = {};
|
|
3327
4009
|
__export(exports_doctor, {
|
|
3328
|
-
default: () => doctor_default
|
|
4010
|
+
default: () => doctor_default,
|
|
4011
|
+
buildAgentChecks: () => buildAgentChecks
|
|
3329
4012
|
});
|
|
3330
|
-
import { existsSync as
|
|
4013
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
3331
4014
|
import { homedir as homedir5 } from "node:os";
|
|
3332
|
-
import { join as
|
|
4015
|
+
import { join as join6 } from "node:path";
|
|
3333
4016
|
async function checkCliVersion() {
|
|
3334
4017
|
const current = CLI_VERSION2;
|
|
3335
4018
|
try {
|
|
3336
|
-
const
|
|
3337
|
-
signal: AbortSignal.timeout(5000)
|
|
3338
|
-
});
|
|
3339
|
-
if (!res.ok)
|
|
3340
|
-
throw new Error("registry unavailable");
|
|
3341
|
-
const data = await res.json();
|
|
3342
|
-
const latest = data.version ?? "unknown";
|
|
4019
|
+
const latest = await fetchLatestCliVersion2();
|
|
3343
4020
|
if (latest === current) {
|
|
3344
4021
|
return { name: "CLI version", status: "pass", message: `v${current} (latest)` };
|
|
3345
4022
|
}
|
|
@@ -3347,7 +4024,7 @@ async function checkCliVersion() {
|
|
|
3347
4024
|
name: "CLI version",
|
|
3348
4025
|
status: "warn",
|
|
3349
4026
|
message: `v${current} installed, v${latest} available`,
|
|
3350
|
-
detail:
|
|
4027
|
+
detail: `Run \`${formatUpdateCommand2()}\` to update`
|
|
3351
4028
|
};
|
|
3352
4029
|
} catch {
|
|
3353
4030
|
return {
|
|
@@ -3434,8 +4111,42 @@ async function checkIntegrations(apiKey) {
|
|
|
3434
4111
|
};
|
|
3435
4112
|
}
|
|
3436
4113
|
}
|
|
3437
|
-
function
|
|
3438
|
-
|
|
4114
|
+
function getHomeDir2(options) {
|
|
4115
|
+
return options?.homeDir?.trim() || process.env.HOME?.trim() || homedir5();
|
|
4116
|
+
}
|
|
4117
|
+
function getSharedSkillsDir(options) {
|
|
4118
|
+
return join6(getHomeDir2(options), ".agents", "skills");
|
|
4119
|
+
}
|
|
4120
|
+
function getOpenClawHome(options) {
|
|
4121
|
+
const home = getHomeDir2(options);
|
|
4122
|
+
if (existsSync5(join6(home, ".openclaw")))
|
|
4123
|
+
return join6(home, ".openclaw");
|
|
4124
|
+
if (existsSync5(join6(home, ".clawdbot")))
|
|
4125
|
+
return join6(home, ".clawdbot");
|
|
4126
|
+
if (existsSync5(join6(home, ".moltbot")))
|
|
4127
|
+
return join6(home, ".moltbot");
|
|
4128
|
+
return join6(home, ".openclaw");
|
|
4129
|
+
}
|
|
4130
|
+
function getAgentSkillDir(agentId, options) {
|
|
4131
|
+
const home = getHomeDir2(options);
|
|
4132
|
+
switch (agentId) {
|
|
4133
|
+
case "claude-code":
|
|
4134
|
+
return join6(options?.claudeConfigDir?.trim() || process.env.CLAUDE_CONFIG_DIR?.trim() || join6(home, ".claude"), "skills");
|
|
4135
|
+
case "codex":
|
|
4136
|
+
return getSharedSkillsDir(options);
|
|
4137
|
+
case "gemini":
|
|
4138
|
+
return getSharedSkillsDir(options);
|
|
4139
|
+
case "droid":
|
|
4140
|
+
return join6(home, ".factory", "skills");
|
|
4141
|
+
case "opencode":
|
|
4142
|
+
return getSharedSkillsDir(options);
|
|
4143
|
+
case "pi":
|
|
4144
|
+
return join6(home, ".pi", "agent", "skills");
|
|
4145
|
+
case "openclaw":
|
|
4146
|
+
return join6(getOpenClawHome(options), "skills");
|
|
4147
|
+
}
|
|
4148
|
+
}
|
|
4149
|
+
function buildAgentChecks(detected = detectAgents(), options) {
|
|
3439
4150
|
if (detected.length === 0) {
|
|
3440
4151
|
return [
|
|
3441
4152
|
{
|
|
@@ -3446,66 +4157,15 @@ function detectAgents2() {
|
|
|
3446
4157
|
];
|
|
3447
4158
|
}
|
|
3448
4159
|
const results = [];
|
|
3449
|
-
const home = homedir5();
|
|
3450
4160
|
for (const agentId of detected) {
|
|
3451
4161
|
const meta = agentChecks[agentId];
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
detail: hasSkill ? undefined : "Run `clawhub install outlit` to configure"
|
|
3460
|
-
});
|
|
3461
|
-
continue;
|
|
3462
|
-
}
|
|
3463
|
-
if (!meta.configCheck) {
|
|
3464
|
-
results.push({
|
|
3465
|
-
name: meta.name,
|
|
3466
|
-
status: "warn",
|
|
3467
|
-
message: "Installed, but Outlit MCP not verified",
|
|
3468
|
-
detail: `Run \`outlit setup ${agentId}\` to configure`
|
|
3469
|
-
});
|
|
3470
|
-
if (agentId === "claude-code") {
|
|
3471
|
-
const skillsDir = join7(home, ".claude", "skills");
|
|
3472
|
-
const hasSkills = existsSync3(join7(skillsDir, "outlit-cli")) || existsSync3(join7(skillsDir, "outlit-sdk")) || existsSync3(join7(skillsDir, "outlit-mcp"));
|
|
3473
|
-
results.push({
|
|
3474
|
-
name: "Agent Skills",
|
|
3475
|
-
status: hasSkills ? "pass" : "warn",
|
|
3476
|
-
message: hasSkills ? "Outlit agent skills installed" : "Outlit agent skills not found",
|
|
3477
|
-
detail: hasSkills ? undefined : "Run `outlit setup skills` to install deeper AI agent context"
|
|
3478
|
-
});
|
|
3479
|
-
}
|
|
3480
|
-
continue;
|
|
3481
|
-
}
|
|
3482
|
-
const { path, key } = meta.configCheck;
|
|
3483
|
-
if (!existsSync3(path)) {
|
|
3484
|
-
results.push({
|
|
3485
|
-
name: meta.name,
|
|
3486
|
-
status: "warn",
|
|
3487
|
-
message: "Installed, but config file not found",
|
|
3488
|
-
detail: `Run \`outlit setup ${agentId}\` to configure`
|
|
3489
|
-
});
|
|
3490
|
-
continue;
|
|
3491
|
-
}
|
|
3492
|
-
try {
|
|
3493
|
-
const config = readJsonConfig(path);
|
|
3494
|
-
const configured = !!config[key]?.outlit;
|
|
3495
|
-
results.push({
|
|
3496
|
-
name: meta.name,
|
|
3497
|
-
status: configured ? "pass" : "warn",
|
|
3498
|
-
message: configured ? "Installed, Outlit MCP configured" : "Installed, but Outlit MCP not configured",
|
|
3499
|
-
detail: configured ? undefined : `Run \`outlit setup ${agentId}\` to configure`
|
|
3500
|
-
});
|
|
3501
|
-
} catch {
|
|
3502
|
-
results.push({
|
|
3503
|
-
name: meta.name,
|
|
3504
|
-
status: "warn",
|
|
3505
|
-
message: "Installed, but config file is malformed",
|
|
3506
|
-
detail: `Check ${path} for JSON syntax errors`
|
|
3507
|
-
});
|
|
3508
|
-
}
|
|
4162
|
+
const hasSkill = existsSync5(join6(getAgentSkillDir(agentId, options), "outlit", "SKILL.md"));
|
|
4163
|
+
results.push({
|
|
4164
|
+
name: meta.name,
|
|
4165
|
+
status: hasSkill ? "pass" : "warn",
|
|
4166
|
+
message: hasSkill ? "Outlit skill installed" : "Installed, but Outlit skill not found",
|
|
4167
|
+
detail: hasSkill ? undefined : meta.missingDetail
|
|
4168
|
+
});
|
|
3509
4169
|
}
|
|
3510
4170
|
return results;
|
|
3511
4171
|
}
|
|
@@ -3540,7 +4200,8 @@ var init_doctor = __esm(() => {
|
|
|
3540
4200
|
init_config();
|
|
3541
4201
|
init_output();
|
|
3542
4202
|
init_tty();
|
|
3543
|
-
|
|
4203
|
+
init_update();
|
|
4204
|
+
init_setup();
|
|
3544
4205
|
FAIL_SYMBOL2 = isUnicodeSupported ? String.fromCodePoint(10007) : "x";
|
|
3545
4206
|
STATUS_ICONS = {
|
|
3546
4207
|
pass: TICK2,
|
|
@@ -3557,73 +4218,374 @@ var init_doctor = __esm(() => {
|
|
|
3557
4218
|
" 1. CLI version -- compares against npm registry",
|
|
3558
4219
|
" 2. API key -- checks presence and format (ok_ prefix)",
|
|
3559
4220
|
" 3. API validation -- makes a live test call to verify the key works",
|
|
3560
|
-
" 4. Agent detection -- detects
|
|
4221
|
+
" 4. Agent detection -- detects supported coding agents and whether the Outlit skill is installed",
|
|
3561
4222
|
"",
|
|
3562
4223
|
"Exit code: 0 if all checks pass or warn, 1 if any check fails.",
|
|
3563
4224
|
"",
|
|
3564
|
-
"JSON output format:",
|
|
3565
|
-
' { "ok": boolean, "checks": [{ "name", "status", "message", "detail?" }] }',
|
|
4225
|
+
"JSON output format:",
|
|
4226
|
+
' { "ok": boolean, "checks": [{ "name", "status", "message", "detail?" }] }',
|
|
4227
|
+
"",
|
|
4228
|
+
"Examples:",
|
|
4229
|
+
" outlit doctor",
|
|
4230
|
+
" outlit doctor --json",
|
|
4231
|
+
` outlit doctor --json | jq '.checks[] | select(.status == "fail")'`,
|
|
4232
|
+
"",
|
|
4233
|
+
"For AI agents: use outlit doctor --json to get structured diagnostics."
|
|
4234
|
+
].join(`
|
|
4235
|
+
`)
|
|
4236
|
+
},
|
|
4237
|
+
args: { ...authArgs, ...outputArgs },
|
|
4238
|
+
async run({ args }) {
|
|
4239
|
+
const json = !!args.json;
|
|
4240
|
+
const checks = [];
|
|
4241
|
+
checks.push(await checkCliVersion());
|
|
4242
|
+
const credential = resolveApiKey(args["api-key"]);
|
|
4243
|
+
checks.push(checkApiKeyPresence(credential));
|
|
4244
|
+
if (credential) {
|
|
4245
|
+
const apiCheck = await validateApiKey(credential.key);
|
|
4246
|
+
checks.push(apiCheck);
|
|
4247
|
+
if (apiCheck.status !== "fail") {
|
|
4248
|
+
checks.push(await checkIntegrations(credential.key));
|
|
4249
|
+
}
|
|
4250
|
+
} else {
|
|
4251
|
+
checks.push({
|
|
4252
|
+
name: "API validation",
|
|
4253
|
+
status: "fail",
|
|
4254
|
+
message: "Skipped -- no API key found"
|
|
4255
|
+
});
|
|
4256
|
+
}
|
|
4257
|
+
checks.push(...buildAgentChecks());
|
|
4258
|
+
const hasFail = checks.some((c) => c.status === "fail");
|
|
4259
|
+
if (isJsonMode(json)) {
|
|
4260
|
+
outputResult({ ok: !hasFail, checks });
|
|
4261
|
+
} else {
|
|
4262
|
+
printChecks(checks);
|
|
4263
|
+
}
|
|
4264
|
+
if (hasFail)
|
|
4265
|
+
process.exit(1);
|
|
4266
|
+
}
|
|
4267
|
+
});
|
|
4268
|
+
agentChecks = {
|
|
4269
|
+
"claude-code": {
|
|
4270
|
+
name: "Claude Code",
|
|
4271
|
+
missingDetail: "Run `outlit setup claude-code` to install the Outlit skill"
|
|
4272
|
+
},
|
|
4273
|
+
codex: {
|
|
4274
|
+
name: "Codex",
|
|
4275
|
+
missingDetail: "Run `outlit setup codex` to install the Outlit skill"
|
|
4276
|
+
},
|
|
4277
|
+
gemini: {
|
|
4278
|
+
name: "Gemini CLI",
|
|
4279
|
+
missingDetail: "Run `outlit setup gemini` to install the Outlit skill"
|
|
4280
|
+
},
|
|
4281
|
+
droid: {
|
|
4282
|
+
name: "Droid",
|
|
4283
|
+
missingDetail: "Run `outlit setup droid` to install the Outlit skill"
|
|
4284
|
+
},
|
|
4285
|
+
opencode: {
|
|
4286
|
+
name: "OpenCode",
|
|
4287
|
+
missingDetail: "Run `outlit setup opencode` to install the Outlit skill"
|
|
4288
|
+
},
|
|
4289
|
+
pi: {
|
|
4290
|
+
name: "Pi",
|
|
4291
|
+
missingDetail: "Run `outlit setup pi` to install the Outlit skill"
|
|
4292
|
+
},
|
|
4293
|
+
openclaw: {
|
|
4294
|
+
name: "OpenClaw",
|
|
4295
|
+
missingDetail: "Run `outlit setup openclaw` to install the Outlit skill"
|
|
4296
|
+
}
|
|
4297
|
+
};
|
|
4298
|
+
});
|
|
4299
|
+
|
|
4300
|
+
// src/commands/upgrade.ts
|
|
4301
|
+
var exports_upgrade = {};
|
|
4302
|
+
__export(exports_upgrade, {
|
|
4303
|
+
default: () => upgrade_default
|
|
4304
|
+
});
|
|
4305
|
+
var upgrade_default;
|
|
4306
|
+
var init_upgrade = __esm(() => {
|
|
4307
|
+
init_dist();
|
|
4308
|
+
init_config();
|
|
4309
|
+
init_output();
|
|
4310
|
+
init_update();
|
|
4311
|
+
upgrade_default = defineCommand2({
|
|
4312
|
+
meta: {
|
|
4313
|
+
name: "upgrade",
|
|
4314
|
+
description: [
|
|
4315
|
+
"Upgrade the Outlit CLI using the same package manager it was installed with.",
|
|
4316
|
+
"",
|
|
4317
|
+
"Checks npm for the latest published version first.",
|
|
4318
|
+
"If the current version is already latest, no install command is run.",
|
|
4319
|
+
"",
|
|
4320
|
+
"Examples:",
|
|
4321
|
+
" outlit upgrade"
|
|
4322
|
+
].join(`
|
|
4323
|
+
`)
|
|
4324
|
+
},
|
|
4325
|
+
async run() {
|
|
4326
|
+
const upgradeCommand = getUpgradeCommand();
|
|
4327
|
+
if (!upgradeCommand) {
|
|
4328
|
+
return outputError({
|
|
4329
|
+
message: "Could not determine how Outlit CLI was installed. Update it manually with your package manager, for example `bun add -g @outlit/cli` or `npm install -g @outlit/cli`.",
|
|
4330
|
+
code: "unknown_installer"
|
|
4331
|
+
}, false);
|
|
4332
|
+
}
|
|
4333
|
+
let latestVersion;
|
|
4334
|
+
try {
|
|
4335
|
+
latestVersion = await fetchLatestCliVersion2();
|
|
4336
|
+
} catch {
|
|
4337
|
+
return outputError({
|
|
4338
|
+
message: "Could not check for CLI updates. Try again later or update manually.",
|
|
4339
|
+
code: "update_check_failed"
|
|
4340
|
+
}, false);
|
|
4341
|
+
}
|
|
4342
|
+
if (compareVersions2(CLI_VERSION2, latestVersion) >= 0) {
|
|
4343
|
+
console.log(`Outlit CLI is already up to date (v${CLI_VERSION2})`);
|
|
4344
|
+
return;
|
|
4345
|
+
}
|
|
4346
|
+
try {
|
|
4347
|
+
runUpgradeCommand(upgradeCommand);
|
|
4348
|
+
} catch (err) {
|
|
4349
|
+
return outputError({
|
|
4350
|
+
message: errorMessage(err, `Failed to run ${upgradeCommand.displayCommand}`),
|
|
4351
|
+
code: "upgrade_failed"
|
|
4352
|
+
}, false);
|
|
4353
|
+
}
|
|
4354
|
+
}
|
|
4355
|
+
});
|
|
4356
|
+
});
|
|
4357
|
+
|
|
4358
|
+
// src/commands/facts/list.ts
|
|
4359
|
+
var exports_list3 = {};
|
|
4360
|
+
__export(exports_list3, {
|
|
4361
|
+
default: () => list_default3
|
|
4362
|
+
});
|
|
4363
|
+
function parseCsvArg(value) {
|
|
4364
|
+
if (!value)
|
|
4365
|
+
return;
|
|
4366
|
+
const items = splitCsv(value).map((item) => item.trim()).filter(Boolean);
|
|
4367
|
+
return items.length > 0 ? items : undefined;
|
|
4368
|
+
}
|
|
4369
|
+
function invalidValues(values, allowed) {
|
|
4370
|
+
if (!values)
|
|
4371
|
+
return [];
|
|
4372
|
+
return values.filter((value) => !allowed.includes(value));
|
|
4373
|
+
}
|
|
4374
|
+
var list_default3;
|
|
4375
|
+
var init_list3 = __esm(() => {
|
|
4376
|
+
init_dist4();
|
|
4377
|
+
init_dist();
|
|
4378
|
+
init_auth();
|
|
4379
|
+
init_output2();
|
|
4380
|
+
init_pagination();
|
|
4381
|
+
init_api();
|
|
4382
|
+
init_config();
|
|
4383
|
+
init_output();
|
|
4384
|
+
list_default3 = defineCommand2({
|
|
4385
|
+
meta: {
|
|
4386
|
+
name: "list",
|
|
4387
|
+
description: [
|
|
4388
|
+
"List structured facts for a customer.",
|
|
4389
|
+
"",
|
|
4390
|
+
"Filter by fact status, source type, or occurrence date range.",
|
|
4391
|
+
"",
|
|
4392
|
+
"Examples:",
|
|
4393
|
+
" outlit facts list acme.com",
|
|
4394
|
+
" outlit facts list acme.com --status ACTIVE",
|
|
4395
|
+
" outlit facts list acme.com --fact-types CHURN_RISK,EXPANSION",
|
|
4396
|
+
" outlit facts list acme.com --source-types CALL,EMAIL --after 2025-01-01T00:00:00Z",
|
|
4397
|
+
" outlit facts list acme.com --limit 50 --json",
|
|
4398
|
+
"",
|
|
4399
|
+
`Statuses: ${customerFactStatuses.join(", ")}`,
|
|
4400
|
+
`Source types: ${customerSourceTypes.join(", ")}`,
|
|
4401
|
+
`Fact categories: ${customerFactCategories.join(", ")}`,
|
|
4402
|
+
"",
|
|
4403
|
+
AGENT_JSON_HINT
|
|
4404
|
+
].join(`
|
|
4405
|
+
`)
|
|
4406
|
+
},
|
|
4407
|
+
args: {
|
|
4408
|
+
...authArgs,
|
|
4409
|
+
...outputArgs,
|
|
4410
|
+
...paginationArgs,
|
|
4411
|
+
customer: {
|
|
4412
|
+
type: "positional",
|
|
4413
|
+
description: "Customer UUID or domain to retrieve facts for",
|
|
4414
|
+
required: true
|
|
4415
|
+
},
|
|
4416
|
+
status: {
|
|
4417
|
+
type: "string",
|
|
4418
|
+
description: `Comma-separated fact statuses (${customerFactStatuses.join(", ")})`
|
|
4419
|
+
},
|
|
4420
|
+
"source-types": {
|
|
4421
|
+
type: "string",
|
|
4422
|
+
description: `Comma-separated generic source type filter (${customerSourceTypes.join(", ")})`
|
|
4423
|
+
},
|
|
4424
|
+
"fact-types": {
|
|
4425
|
+
type: "string",
|
|
4426
|
+
description: "Comma-separated customer-memory fact type filter, such as CHURN_RISK, EXPANSION, or SENTIMENT"
|
|
4427
|
+
},
|
|
4428
|
+
"fact-categories": {
|
|
4429
|
+
type: "string",
|
|
4430
|
+
description: `Comma-separated fact category filter (${customerFactCategories.join(", ")})`
|
|
4431
|
+
},
|
|
4432
|
+
after: {
|
|
4433
|
+
type: "string",
|
|
4434
|
+
description: "Filter to facts occurring after this ISO 8601 datetime"
|
|
4435
|
+
},
|
|
4436
|
+
before: {
|
|
4437
|
+
type: "string",
|
|
4438
|
+
description: "Filter to facts occurring before this ISO 8601 datetime"
|
|
4439
|
+
}
|
|
4440
|
+
},
|
|
4441
|
+
async run({ args }) {
|
|
4442
|
+
const json = !!args.json;
|
|
4443
|
+
const statuses = parseCsvArg(args.status);
|
|
4444
|
+
const sourceTypes = parseCsvArg(args["source-types"]);
|
|
4445
|
+
const factTypes = parseCsvArg(args["fact-types"]);
|
|
4446
|
+
const factCategories = parseCsvArg(args["fact-categories"]);
|
|
4447
|
+
const invalidStatuses = invalidValues(statuses, customerFactStatuses);
|
|
4448
|
+
if (invalidStatuses.length > 0) {
|
|
4449
|
+
return outputError({
|
|
4450
|
+
message: `Unknown fact statuses: ${invalidStatuses.join(", ")}. Allowed: ${customerFactStatuses.join(", ")}`,
|
|
4451
|
+
code: "invalid_input"
|
|
4452
|
+
}, json);
|
|
4453
|
+
}
|
|
4454
|
+
const invalidSourceTypes = invalidValues(sourceTypes, customerSourceTypes);
|
|
4455
|
+
if (invalidSourceTypes.length > 0) {
|
|
4456
|
+
return outputError({
|
|
4457
|
+
message: `Unknown source types: ${invalidSourceTypes.join(", ")}. Allowed: ${customerSourceTypes.join(", ")}`,
|
|
4458
|
+
code: "invalid_input"
|
|
4459
|
+
}, json);
|
|
4460
|
+
}
|
|
4461
|
+
const invalidFactTypes = invalidValues(factTypes, customerFactTypes);
|
|
4462
|
+
if (invalidFactTypes.length > 0) {
|
|
4463
|
+
const anomalyFactTypes = invalidFactTypes.filter((value) => unsupportedCustomerFactTypes.includes(value));
|
|
4464
|
+
const unknownFactTypes = invalidFactTypes.filter((value) => !unsupportedCustomerFactTypes.includes(value));
|
|
4465
|
+
const messageParts = [];
|
|
4466
|
+
if (anomalyFactTypes.length > 0) {
|
|
4467
|
+
messageParts.push(`Anomaly detector fact types are not supported as public filters: ${anomalyFactTypes.join(", ")}. Use customer-memory fact types such as CHURN_RISK, EXPANSION, SENTIMENT, or PRODUCT_USAGE.`);
|
|
4468
|
+
}
|
|
4469
|
+
if (unknownFactTypes.length > 0) {
|
|
4470
|
+
messageParts.push(`Unknown fact types: ${unknownFactTypes.join(", ")}. Allowed: ${customerFactTypes.join(", ")}`);
|
|
4471
|
+
}
|
|
4472
|
+
return outputError({
|
|
4473
|
+
message: messageParts.join(" "),
|
|
4474
|
+
code: "invalid_input"
|
|
4475
|
+
}, json);
|
|
4476
|
+
}
|
|
4477
|
+
const invalidFactCategories = invalidValues(factCategories, customerFactCategories);
|
|
4478
|
+
if (invalidFactCategories.length > 0) {
|
|
4479
|
+
return outputError({
|
|
4480
|
+
message: `Unsupported fact categories: ${invalidFactCategories.join(", ")}. Allowed: ${customerFactCategories.join(", ")}`,
|
|
4481
|
+
code: "invalid_input"
|
|
4482
|
+
}, json);
|
|
4483
|
+
}
|
|
4484
|
+
const afterDate = args.after ? new Date(args.after) : null;
|
|
4485
|
+
const beforeDate = args.before ? new Date(args.before) : null;
|
|
4486
|
+
if (afterDate && Number.isNaN(afterDate.getTime())) {
|
|
4487
|
+
return outputError({
|
|
4488
|
+
message: "--after must be a valid ISO 8601 datetime",
|
|
4489
|
+
code: "invalid_input"
|
|
4490
|
+
}, json);
|
|
4491
|
+
}
|
|
4492
|
+
if (beforeDate && Number.isNaN(beforeDate.getTime())) {
|
|
4493
|
+
return outputError({
|
|
4494
|
+
message: "--before must be a valid ISO 8601 datetime",
|
|
4495
|
+
code: "invalid_input"
|
|
4496
|
+
}, json);
|
|
4497
|
+
}
|
|
4498
|
+
if (afterDate && beforeDate && afterDate.getTime() > beforeDate.getTime()) {
|
|
4499
|
+
return outputError({
|
|
4500
|
+
message: "--after must be before or equal to --before",
|
|
4501
|
+
code: "invalid_input"
|
|
4502
|
+
}, json);
|
|
4503
|
+
}
|
|
4504
|
+
const client = await getClientOrExit(args["api-key"], json);
|
|
4505
|
+
const params = {
|
|
4506
|
+
customer: args.customer
|
|
4507
|
+
};
|
|
4508
|
+
if (statuses)
|
|
4509
|
+
params.status = statuses;
|
|
4510
|
+
if (sourceTypes)
|
|
4511
|
+
params.sourceTypes = sourceTypes;
|
|
4512
|
+
if (factTypes)
|
|
4513
|
+
params.factTypes = factTypes;
|
|
4514
|
+
if (factCategories)
|
|
4515
|
+
params.factCategories = factCategories;
|
|
4516
|
+
if (args.after)
|
|
4517
|
+
params.after = args.after;
|
|
4518
|
+
if (args.before)
|
|
4519
|
+
params.before = args.before;
|
|
4520
|
+
applyPagination(params, args, json);
|
|
4521
|
+
return runTool(client, customerToolContracts.outlit_list_facts.toolName, params, json);
|
|
4522
|
+
}
|
|
4523
|
+
});
|
|
4524
|
+
});
|
|
4525
|
+
|
|
4526
|
+
// src/commands/facts/get.ts
|
|
4527
|
+
var exports_get2 = {};
|
|
4528
|
+
__export(exports_get2, {
|
|
4529
|
+
default: () => get_default2
|
|
4530
|
+
});
|
|
4531
|
+
function parseCsvArg2(value) {
|
|
4532
|
+
if (!value)
|
|
4533
|
+
return;
|
|
4534
|
+
const items = splitCsv(value).map((item) => item.trim()).filter(Boolean);
|
|
4535
|
+
return items.length > 0 ? items : undefined;
|
|
4536
|
+
}
|
|
4537
|
+
var get_default2;
|
|
4538
|
+
var init_get2 = __esm(() => {
|
|
4539
|
+
init_dist4();
|
|
4540
|
+
init_dist();
|
|
4541
|
+
init_auth();
|
|
4542
|
+
init_output2();
|
|
4543
|
+
init_api();
|
|
4544
|
+
init_config();
|
|
4545
|
+
get_default2 = defineCommand2({
|
|
4546
|
+
meta: {
|
|
4547
|
+
name: "get",
|
|
4548
|
+
description: [
|
|
4549
|
+
"Get one exact fact by ID.",
|
|
4550
|
+
"",
|
|
4551
|
+
"Use --include evidence to request best-effort evidence expansion.",
|
|
3566
4552
|
"",
|
|
3567
4553
|
"Examples:",
|
|
3568
|
-
" outlit
|
|
3569
|
-
" outlit
|
|
3570
|
-
` outlit doctor --json | jq '.checks[] | select(.status == "fail")'`,
|
|
4554
|
+
" outlit facts get --fact-id fact_123",
|
|
4555
|
+
" outlit facts get --fact-id fact_123 --include evidence",
|
|
3571
4556
|
"",
|
|
3572
|
-
|
|
4557
|
+
AGENT_JSON_HINT
|
|
3573
4558
|
].join(`
|
|
3574
4559
|
`)
|
|
3575
4560
|
},
|
|
3576
|
-
args: {
|
|
4561
|
+
args: {
|
|
4562
|
+
...authArgs,
|
|
4563
|
+
...outputArgs,
|
|
4564
|
+
"fact-id": {
|
|
4565
|
+
type: "string",
|
|
4566
|
+
description: "Fact ID to fetch",
|
|
4567
|
+
required: true
|
|
4568
|
+
},
|
|
4569
|
+
include: {
|
|
4570
|
+
type: "string",
|
|
4571
|
+
description: "Comma-separated best-effort expansions (for example: evidence)"
|
|
4572
|
+
}
|
|
4573
|
+
},
|
|
3577
4574
|
async run({ args }) {
|
|
3578
4575
|
const json = !!args.json;
|
|
3579
|
-
const
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
checks.push(await checkIntegrations(credential.key));
|
|
3588
|
-
}
|
|
3589
|
-
} else {
|
|
3590
|
-
checks.push({
|
|
3591
|
-
name: "API validation",
|
|
3592
|
-
status: "fail",
|
|
3593
|
-
message: "Skipped -- no API key found"
|
|
3594
|
-
});
|
|
3595
|
-
}
|
|
3596
|
-
checks.push(...detectAgents2());
|
|
3597
|
-
const hasFail = checks.some((c) => c.status === "fail");
|
|
3598
|
-
if (isJsonMode(json)) {
|
|
3599
|
-
outputResult({ ok: !hasFail, checks });
|
|
3600
|
-
} else {
|
|
3601
|
-
printChecks(checks);
|
|
3602
|
-
}
|
|
3603
|
-
if (hasFail)
|
|
3604
|
-
process.exit(1);
|
|
4576
|
+
const client = await getClientOrExit(args["api-key"], json);
|
|
4577
|
+
const params = {
|
|
4578
|
+
factId: args["fact-id"]
|
|
4579
|
+
};
|
|
4580
|
+
const include = parseCsvArg2(args.include);
|
|
4581
|
+
if (include)
|
|
4582
|
+
params.include = include;
|
|
4583
|
+
return runTool(client, customerToolContracts.outlit_get_fact.toolName, params, json);
|
|
3605
4584
|
}
|
|
3606
4585
|
});
|
|
3607
|
-
agentChecks = {
|
|
3608
|
-
cursor: {
|
|
3609
|
-
name: "Cursor",
|
|
3610
|
-
configCheck: { path: join7(homedir5(), ".cursor", "mcp.json"), key: "mcpServers" }
|
|
3611
|
-
},
|
|
3612
|
-
"claude-code": { name: "Claude Code" },
|
|
3613
|
-
"claude-desktop": {
|
|
3614
|
-
name: "Claude Desktop",
|
|
3615
|
-
configCheck: { path: getClaudeDesktopConfigPath(), key: "mcpServers" }
|
|
3616
|
-
},
|
|
3617
|
-
vscode: {
|
|
3618
|
-
name: "VS Code",
|
|
3619
|
-
configCheck: { path: join7(process.cwd(), ".vscode", "mcp.json"), key: "servers" }
|
|
3620
|
-
},
|
|
3621
|
-
gemini: { name: "Gemini CLI" },
|
|
3622
|
-
openclaw: { name: "OpenClaw" }
|
|
3623
|
-
};
|
|
3624
4586
|
});
|
|
3625
4587
|
|
|
3626
|
-
// src/commands/facts.ts
|
|
4588
|
+
// src/commands/facts/index.ts
|
|
3627
4589
|
var exports_facts = {};
|
|
3628
4590
|
__export(exports_facts, {
|
|
3629
4591
|
default: () => facts_default
|
|
@@ -3631,23 +4593,52 @@ __export(exports_facts, {
|
|
|
3631
4593
|
var facts_default;
|
|
3632
4594
|
var init_facts = __esm(() => {
|
|
3633
4595
|
init_dist();
|
|
3634
|
-
init_auth();
|
|
3635
4596
|
init_output2();
|
|
3636
|
-
init_pagination();
|
|
3637
|
-
init_api();
|
|
3638
4597
|
facts_default = defineCommand2({
|
|
3639
4598
|
meta: {
|
|
3640
4599
|
name: "facts",
|
|
3641
4600
|
description: [
|
|
3642
|
-
"
|
|
4601
|
+
"Query structured customer facts.",
|
|
3643
4602
|
"",
|
|
3644
|
-
"
|
|
3645
|
-
"
|
|
4603
|
+
"Subcommands:",
|
|
4604
|
+
" list -- list facts for a customer with filters",
|
|
4605
|
+
" get -- fetch one exact fact by id",
|
|
4606
|
+
"",
|
|
4607
|
+
AGENT_JSON_HINT
|
|
4608
|
+
].join(`
|
|
4609
|
+
`)
|
|
4610
|
+
},
|
|
4611
|
+
subCommands: {
|
|
4612
|
+
list: () => Promise.resolve().then(() => (init_list3(), exports_list3)).then((m) => m.default),
|
|
4613
|
+
get: () => Promise.resolve().then(() => (init_get2(), exports_get2)).then((m) => m.default)
|
|
4614
|
+
}
|
|
4615
|
+
});
|
|
4616
|
+
});
|
|
4617
|
+
|
|
4618
|
+
// src/commands/sources/get.ts
|
|
4619
|
+
var exports_get3 = {};
|
|
4620
|
+
__export(exports_get3, {
|
|
4621
|
+
default: () => get_default3
|
|
4622
|
+
});
|
|
4623
|
+
var get_default3;
|
|
4624
|
+
var init_get3 = __esm(() => {
|
|
4625
|
+
init_dist4();
|
|
4626
|
+
init_dist();
|
|
4627
|
+
init_auth();
|
|
4628
|
+
init_output2();
|
|
4629
|
+
init_api();
|
|
4630
|
+
init_output();
|
|
4631
|
+
get_default3 = defineCommand2({
|
|
4632
|
+
meta: {
|
|
4633
|
+
name: "get",
|
|
4634
|
+
description: [
|
|
4635
|
+
"Get one exact source by source type and source id.",
|
|
3646
4636
|
"",
|
|
3647
4637
|
"Examples:",
|
|
3648
|
-
" outlit
|
|
3649
|
-
" outlit
|
|
3650
|
-
"
|
|
4638
|
+
" outlit sources get --source-type CALL --source-id call_123",
|
|
4639
|
+
" outlit sources get --source-type SUPPORT_TICKET --source-id ticket_456 --json",
|
|
4640
|
+
"",
|
|
4641
|
+
`Source types: ${customerSourceTypes.join(", ")}`,
|
|
3651
4642
|
"",
|
|
3652
4643
|
AGENT_JSON_HINT
|
|
3653
4644
|
].join(`
|
|
@@ -3656,27 +4647,58 @@ var init_facts = __esm(() => {
|
|
|
3656
4647
|
args: {
|
|
3657
4648
|
...authArgs,
|
|
3658
4649
|
...outputArgs,
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
description: "Customer UUID or domain to retrieve facts for",
|
|
4650
|
+
"source-type": {
|
|
4651
|
+
type: "string",
|
|
4652
|
+
description: "Canonical source type",
|
|
3663
4653
|
required: true
|
|
3664
4654
|
},
|
|
3665
|
-
|
|
4655
|
+
"source-id": {
|
|
3666
4656
|
type: "string",
|
|
3667
|
-
description: "
|
|
3668
|
-
|
|
4657
|
+
description: "Exact source id",
|
|
4658
|
+
required: true
|
|
3669
4659
|
}
|
|
3670
4660
|
},
|
|
3671
4661
|
async run({ args }) {
|
|
3672
4662
|
const json = !!args.json;
|
|
4663
|
+
if (!customerSourceTypes.includes(args["source-type"])) {
|
|
4664
|
+
return outputError({
|
|
4665
|
+
message: `--source-type must be one of ${customerSourceTypes.join(", ")}`,
|
|
4666
|
+
code: "invalid_input"
|
|
4667
|
+
}, json);
|
|
4668
|
+
}
|
|
3673
4669
|
const client = await getClientOrExit(args["api-key"], json);
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
};
|
|
3678
|
-
|
|
3679
|
-
|
|
4670
|
+
return runTool(client, customerToolContracts.outlit_get_source.toolName, {
|
|
4671
|
+
sourceType: args["source-type"],
|
|
4672
|
+
sourceId: args["source-id"]
|
|
4673
|
+
}, json);
|
|
4674
|
+
}
|
|
4675
|
+
});
|
|
4676
|
+
});
|
|
4677
|
+
|
|
4678
|
+
// src/commands/sources/index.ts
|
|
4679
|
+
var exports_sources = {};
|
|
4680
|
+
__export(exports_sources, {
|
|
4681
|
+
default: () => sources_default
|
|
4682
|
+
});
|
|
4683
|
+
var sources_default;
|
|
4684
|
+
var init_sources = __esm(() => {
|
|
4685
|
+
init_dist();
|
|
4686
|
+
init_output2();
|
|
4687
|
+
sources_default = defineCommand2({
|
|
4688
|
+
meta: {
|
|
4689
|
+
name: "sources",
|
|
4690
|
+
description: [
|
|
4691
|
+
"Fetch concrete customer sources by type and id.",
|
|
4692
|
+
"",
|
|
4693
|
+
"Subcommands:",
|
|
4694
|
+
" get -- fetch one exact source by sourceType and sourceId",
|
|
4695
|
+
"",
|
|
4696
|
+
AGENT_JSON_HINT
|
|
4697
|
+
].join(`
|
|
4698
|
+
`)
|
|
4699
|
+
},
|
|
4700
|
+
subCommands: {
|
|
4701
|
+
get: () => Promise.resolve().then(() => (init_get3(), exports_get3)).then((m) => m.default)
|
|
3680
4702
|
}
|
|
3681
4703
|
});
|
|
3682
4704
|
});
|
|
@@ -3688,28 +4710,28 @@ __export(exports_search, {
|
|
|
3688
4710
|
});
|
|
3689
4711
|
var search_default;
|
|
3690
4712
|
var init_search = __esm(() => {
|
|
4713
|
+
init_dist4();
|
|
3691
4714
|
init_dist();
|
|
3692
4715
|
init_auth();
|
|
3693
4716
|
init_output2();
|
|
3694
4717
|
init_api();
|
|
4718
|
+
init_config();
|
|
3695
4719
|
init_output();
|
|
3696
4720
|
search_default = defineCommand2({
|
|
3697
4721
|
meta: {
|
|
3698
4722
|
name: "search",
|
|
3699
4723
|
description: [
|
|
3700
|
-
"Search customer context using natural language
|
|
4724
|
+
"Search customer context using natural language.",
|
|
3701
4725
|
"",
|
|
3702
|
-
"Performs a semantic search over
|
|
4726
|
+
"Performs a semantic search over grouped source and fact results.",
|
|
3703
4727
|
"Optionally scope to a specific customer with --customer.",
|
|
3704
|
-
"Use --source-type and --source-id for direct source lookup (query becomes optional).",
|
|
3705
4728
|
"",
|
|
3706
4729
|
"Examples:",
|
|
3707
4730
|
" outlit search 'pricing objections last quarter'",
|
|
3708
4731
|
" outlit search 'churn risk signals' --customer acme.com",
|
|
3709
4732
|
" outlit search 'expansion opportunities' --top-k 50 --json",
|
|
3710
|
-
" outlit search 'support escalations' --after 2025-01-
|
|
3711
|
-
" outlit search 'onboarding issues' --source-types
|
|
3712
|
-
" outlit search --source-type call_transcript --source-id call_123",
|
|
4733
|
+
" outlit search 'support escalations' --after 2025-01-01T00:00:00Z --before 2025-03-31T23:59:59Z",
|
|
4734
|
+
" outlit search 'onboarding issues' --source-types CALL,EMAIL",
|
|
3713
4735
|
"",
|
|
3714
4736
|
AGENT_JSON_HINT
|
|
3715
4737
|
].join(`
|
|
@@ -3720,8 +4742,8 @@ var init_search = __esm(() => {
|
|
|
3720
4742
|
...outputArgs,
|
|
3721
4743
|
query: {
|
|
3722
4744
|
type: "positional",
|
|
3723
|
-
description: "Natural language search query
|
|
3724
|
-
required:
|
|
4745
|
+
description: "Natural language search query",
|
|
4746
|
+
required: true
|
|
3725
4747
|
},
|
|
3726
4748
|
customer: {
|
|
3727
4749
|
type: "string",
|
|
@@ -3729,75 +4751,51 @@ var init_search = __esm(() => {
|
|
|
3729
4751
|
},
|
|
3730
4752
|
"top-k": {
|
|
3731
4753
|
type: "string",
|
|
3732
|
-
description: "Maximum number of results to return (1–50). Default: 20."
|
|
3733
|
-
default: "20"
|
|
4754
|
+
description: "Maximum number of results to return (1–50). Default: 20."
|
|
3734
4755
|
},
|
|
3735
4756
|
after: {
|
|
3736
4757
|
type: "string",
|
|
3737
|
-
description: "Filter to events occurring after this
|
|
4758
|
+
description: "Filter to events occurring after this datetime (ISO 8601, e.g. 2025-01-01T00:00:00Z)"
|
|
3738
4759
|
},
|
|
3739
4760
|
before: {
|
|
3740
4761
|
type: "string",
|
|
3741
|
-
description: "Filter to events occurring before this
|
|
4762
|
+
description: "Filter to events occurring before this datetime (ISO 8601, e.g. 2025-03-31T23:59:59Z)"
|
|
3742
4763
|
},
|
|
3743
4764
|
"source-types": {
|
|
3744
4765
|
type: "string",
|
|
3745
|
-
description:
|
|
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)"
|
|
4766
|
+
description: `Comma-separated generic source type filter (${customerSourceTypes.join(", ")})`
|
|
3754
4767
|
}
|
|
3755
4768
|
},
|
|
3756
4769
|
async run({ args }) {
|
|
3757
4770
|
const json = !!args.json;
|
|
3758
|
-
const topK = Number(args["top-k"]);
|
|
3759
|
-
if (!Number.isFinite(topK) || topK < 1 || topK > 50) {
|
|
4771
|
+
const topK = args["top-k"] ? Number(args["top-k"]) : undefined;
|
|
4772
|
+
if (topK !== undefined && (!Number.isFinite(topK) || !Number.isInteger(topK) || topK < 1 || topK > 50)) {
|
|
3760
4773
|
return outputError({ message: "--top-k must be an integer between 1 and 50", code: "invalid_input" }, json);
|
|
3761
4774
|
}
|
|
3762
|
-
const
|
|
3763
|
-
const
|
|
3764
|
-
|
|
3765
|
-
if (sourceType && !sourceId || !sourceType && sourceId) {
|
|
4775
|
+
const sourceTypes = args["source-types"] ? splitCsv(args["source-types"]).map((item) => item.trim()).filter(Boolean) : undefined;
|
|
4776
|
+
const invalidSourceTypes = sourceTypes?.filter((value) => !customerSourceTypes.includes(value));
|
|
4777
|
+
if (invalidSourceTypes && invalidSourceTypes.length > 0) {
|
|
3766
4778
|
return outputError({
|
|
3767
|
-
message:
|
|
4779
|
+
message: `Unknown source types: ${invalidSourceTypes.join(", ")}. Allowed: ${customerSourceTypes.join(", ")}`,
|
|
3768
4780
|
code: "invalid_input"
|
|
3769
4781
|
}, json);
|
|
3770
4782
|
}
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
4783
|
+
const resolved = resolveCustomerContextSearchInput({
|
|
4784
|
+
query: args.query,
|
|
4785
|
+
customer: args.customer,
|
|
4786
|
+
topK,
|
|
4787
|
+
after: args.after,
|
|
4788
|
+
before: args.before,
|
|
4789
|
+
sourceTypes
|
|
4790
|
+
});
|
|
4791
|
+
if (!resolved.ok) {
|
|
3778
4792
|
return outputError({
|
|
3779
|
-
message:
|
|
4793
|
+
message: resolved.message,
|
|
3780
4794
|
code: "invalid_input"
|
|
3781
4795
|
}, json);
|
|
3782
4796
|
}
|
|
3783
4797
|
const client = await getClientOrExit(args["api-key"], json);
|
|
3784
|
-
|
|
3785
|
-
const params = { topK };
|
|
3786
|
-
if (args.query)
|
|
3787
|
-
params.query = args.query;
|
|
3788
|
-
if (args.customer)
|
|
3789
|
-
params.customer = args.customer;
|
|
3790
|
-
if (args.after)
|
|
3791
|
-
params.occurredAfter = args.after;
|
|
3792
|
-
if (args.before)
|
|
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;
|
|
3800
|
-
return runTool(client, "outlit_search_customer_context", params, json);
|
|
4798
|
+
return runTool(client, customerToolContracts.outlit_search_customer_context.toolName, resolved.request, json);
|
|
3801
4799
|
}
|
|
3802
4800
|
});
|
|
3803
4801
|
});
|
|
@@ -3807,9 +4805,10 @@ var exports_sql = {};
|
|
|
3807
4805
|
__export(exports_sql, {
|
|
3808
4806
|
default: () => sql_default
|
|
3809
4807
|
});
|
|
3810
|
-
import { readFileSync as
|
|
4808
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
3811
4809
|
var sql_default;
|
|
3812
4810
|
var init_sql = __esm(() => {
|
|
4811
|
+
init_dist4();
|
|
3813
4812
|
init_dist();
|
|
3814
4813
|
init_auth();
|
|
3815
4814
|
init_output2();
|
|
@@ -3824,7 +4823,7 @@ var init_sql = __esm(() => {
|
|
|
3824
4823
|
"Provide the query as a positional argument or via --query-file.",
|
|
3825
4824
|
"When both are provided, --query-file takes precedence.",
|
|
3826
4825
|
"",
|
|
3827
|
-
|
|
4826
|
+
`Available tables: ${schemaTables.join(", ")}`,
|
|
3828
4827
|
"",
|
|
3829
4828
|
"Examples:",
|
|
3830
4829
|
" outlit sql 'SELECT * FROM events LIMIT 10'",
|
|
@@ -3859,7 +4858,7 @@ var init_sql = __esm(() => {
|
|
|
3859
4858
|
let sql;
|
|
3860
4859
|
if (args["query-file"]) {
|
|
3861
4860
|
try {
|
|
3862
|
-
sql =
|
|
4861
|
+
sql = readFileSync4(args["query-file"], "utf-8");
|
|
3863
4862
|
} catch (err) {
|
|
3864
4863
|
return outputError({
|
|
3865
4864
|
message: `Cannot read file: ${errorMessage(err, "unknown error")}`,
|
|
@@ -3875,7 +4874,7 @@ var init_sql = __esm(() => {
|
|
|
3875
4874
|
if (!Number.isFinite(limit) || limit <= 0) {
|
|
3876
4875
|
return outputError({ message: "--limit must be a positive number", code: "invalid_input" }, json);
|
|
3877
4876
|
}
|
|
3878
|
-
return runTool(client,
|
|
4877
|
+
return runTool(client, customerToolContracts.outlit_query.toolName, { sql, limit }, json);
|
|
3879
4878
|
}
|
|
3880
4879
|
});
|
|
3881
4880
|
});
|
|
@@ -3887,6 +4886,7 @@ __export(exports_schema, {
|
|
|
3887
4886
|
});
|
|
3888
4887
|
var schema_default;
|
|
3889
4888
|
var init_schema = __esm(() => {
|
|
4889
|
+
init_dist4();
|
|
3890
4890
|
init_dist();
|
|
3891
4891
|
init_auth();
|
|
3892
4892
|
init_output2();
|
|
@@ -3900,7 +4900,7 @@ var init_schema = __esm(() => {
|
|
|
3900
4900
|
"Without a table name, returns the full schema for all tables.",
|
|
3901
4901
|
"With a table name, returns detailed column info for that table.",
|
|
3902
4902
|
"",
|
|
3903
|
-
|
|
4903
|
+
`Available tables: ${schemaTables.join(", ")}`,
|
|
3904
4904
|
"",
|
|
3905
4905
|
"Examples:",
|
|
3906
4906
|
" outlit schema",
|
|
@@ -3916,7 +4916,7 @@ var init_schema = __esm(() => {
|
|
|
3916
4916
|
...outputArgs,
|
|
3917
4917
|
table: {
|
|
3918
4918
|
type: "positional",
|
|
3919
|
-
description:
|
|
4919
|
+
description: `Table to describe (${schemaTables.join(", ")}). Optional.`,
|
|
3920
4920
|
required: false
|
|
3921
4921
|
}
|
|
3922
4922
|
},
|
|
@@ -3926,7 +4926,7 @@ var init_schema = __esm(() => {
|
|
|
3926
4926
|
const params = {};
|
|
3927
4927
|
if (args.table)
|
|
3928
4928
|
params.table = args.table;
|
|
3929
|
-
return runTool(client,
|
|
4929
|
+
return runTool(client, customerToolContracts.outlit_schema.toolName, params, json);
|
|
3930
4930
|
}
|
|
3931
4931
|
});
|
|
3932
4932
|
});
|
|
@@ -4022,17 +5022,17 @@ var init_providers = __esm(() => {
|
|
|
4022
5022
|
});
|
|
4023
5023
|
|
|
4024
5024
|
// src/commands/integrations/list.ts
|
|
4025
|
-
var
|
|
4026
|
-
__export(
|
|
4027
|
-
default: () =>
|
|
5025
|
+
var exports_list4 = {};
|
|
5026
|
+
__export(exports_list4, {
|
|
5027
|
+
default: () => list_default4
|
|
4028
5028
|
});
|
|
4029
|
-
var
|
|
4030
|
-
var
|
|
5029
|
+
var list_default4;
|
|
5030
|
+
var init_list4 = __esm(() => {
|
|
4031
5031
|
init_dist();
|
|
4032
5032
|
init_auth();
|
|
4033
5033
|
init_output2();
|
|
4034
5034
|
init_api();
|
|
4035
|
-
|
|
5035
|
+
list_default4 = defineCommand2({
|
|
4036
5036
|
meta: {
|
|
4037
5037
|
name: "list",
|
|
4038
5038
|
description: [
|
|
@@ -4486,7 +5486,7 @@ var init_integrations = __esm(() => {
|
|
|
4486
5486
|
`)
|
|
4487
5487
|
},
|
|
4488
5488
|
subCommands: {
|
|
4489
|
-
list: () => Promise.resolve().then(() => (
|
|
5489
|
+
list: () => Promise.resolve().then(() => (init_list4(), exports_list4)).then((m) => m.default),
|
|
4490
5490
|
add: () => Promise.resolve().then(() => (init_add(), exports_add)).then((m) => m.default),
|
|
4491
5491
|
remove: () => Promise.resolve().then(() => (init_remove(), exports_remove)).then((m) => m.default),
|
|
4492
5492
|
status: () => Promise.resolve().then(() => (init_status2(), exports_status2)).then((m) => m.default)
|
|
@@ -4741,9 +5741,7 @@ var init_completions = __esm(() => {
|
|
|
4741
5741
|
{ name: "--billing-status", desc: "Filter by billing status" },
|
|
4742
5742
|
{ name: "--mrr-above", desc: "MRR above threshold (cents)" },
|
|
4743
5743
|
{ name: "--mrr-below", desc: "MRR below threshold (cents)" },
|
|
4744
|
-
{ name: "--search", desc: "Search name or domain" }
|
|
4745
|
-
{ name: "--status", desc: "Customer status filter" },
|
|
4746
|
-
{ name: "--type", desc: "Customer type filter" }
|
|
5744
|
+
{ name: "--search", desc: "Search name or domain" }
|
|
4747
5745
|
]
|
|
4748
5746
|
},
|
|
4749
5747
|
{
|
|
@@ -4790,7 +5788,45 @@ var init_completions = __esm(() => {
|
|
|
4790
5788
|
{
|
|
4791
5789
|
name: "facts",
|
|
4792
5790
|
desc: "Get customer facts",
|
|
4793
|
-
|
|
5791
|
+
subs: [
|
|
5792
|
+
{
|
|
5793
|
+
name: "list",
|
|
5794
|
+
desc: "List customer facts",
|
|
5795
|
+
flags: [
|
|
5796
|
+
...PAGINATED,
|
|
5797
|
+
{ name: "--status", desc: "Filter by fact status" },
|
|
5798
|
+
{ name: "--source-types", desc: "Filter by source types" },
|
|
5799
|
+
{ name: "--fact-types", desc: "Filter by fact types" },
|
|
5800
|
+
{ name: "--fact-categories", desc: "Filter by fact categories" },
|
|
5801
|
+
{ name: "--after", desc: "Facts after date (ISO 8601)" },
|
|
5802
|
+
{ name: "--before", desc: "Facts before date (ISO 8601)" }
|
|
5803
|
+
]
|
|
5804
|
+
},
|
|
5805
|
+
{
|
|
5806
|
+
name: "get",
|
|
5807
|
+
desc: "Get a single fact by ID",
|
|
5808
|
+
flags: [
|
|
5809
|
+
...COMMON,
|
|
5810
|
+
{ name: "--fact-id", desc: "Fact ID to fetch" },
|
|
5811
|
+
{ name: "--include", desc: "Best-effort expansions" }
|
|
5812
|
+
]
|
|
5813
|
+
}
|
|
5814
|
+
]
|
|
5815
|
+
},
|
|
5816
|
+
{
|
|
5817
|
+
name: "sources",
|
|
5818
|
+
desc: "Get a concrete source by type and id",
|
|
5819
|
+
subs: [
|
|
5820
|
+
{
|
|
5821
|
+
name: "get",
|
|
5822
|
+
desc: "Get one exact source record",
|
|
5823
|
+
flags: [
|
|
5824
|
+
...COMMON,
|
|
5825
|
+
{ name: "--source-type", desc: "Canonical source type" },
|
|
5826
|
+
{ name: "--source-id", desc: "Exact source ID" }
|
|
5827
|
+
]
|
|
5828
|
+
}
|
|
5829
|
+
]
|
|
4794
5830
|
},
|
|
4795
5831
|
{
|
|
4796
5832
|
name: "search",
|
|
@@ -4800,7 +5836,8 @@ var init_completions = __esm(() => {
|
|
|
4800
5836
|
{ name: "--customer", desc: "Scope to customer (UUID or domain)" },
|
|
4801
5837
|
{ name: "--top-k", desc: "Max results" },
|
|
4802
5838
|
{ name: "--after", desc: "Events after date (ISO 8601)" },
|
|
4803
|
-
{ name: "--before", desc: "Events before date (ISO 8601)" }
|
|
5839
|
+
{ name: "--before", desc: "Events before date (ISO 8601)" },
|
|
5840
|
+
{ name: "--source-types", desc: "Broad source type filter" }
|
|
4804
5841
|
]
|
|
4805
5842
|
},
|
|
4806
5843
|
{
|
|
@@ -4837,17 +5874,20 @@ var init_completions = __esm(() => {
|
|
|
4837
5874
|
},
|
|
4838
5875
|
{
|
|
4839
5876
|
name: "setup",
|
|
4840
|
-
desc: "
|
|
4841
|
-
flags: [
|
|
5877
|
+
desc: "Install Outlit skills for coding agents",
|
|
5878
|
+
flags: [JSON_F, { name: "--yes", desc: "Skip prompts" }],
|
|
4842
5879
|
subs: [
|
|
4843
|
-
{ name: "
|
|
4844
|
-
{ name: "
|
|
4845
|
-
{ name: "
|
|
4846
|
-
{ name: "
|
|
4847
|
-
{ name: "
|
|
4848
|
-
{ name: "
|
|
5880
|
+
{ name: "claude-code", desc: "Install the Outlit skill for Claude Code", flags: [JSON_F] },
|
|
5881
|
+
{ name: "codex", desc: "Install the Outlit skill for Codex", flags: [JSON_F] },
|
|
5882
|
+
{ name: "gemini", desc: "Install the Outlit skill for Gemini CLI", flags: [JSON_F] },
|
|
5883
|
+
{ name: "droid", desc: "Install the Outlit skill for Droid", flags: [JSON_F] },
|
|
5884
|
+
{ name: "opencode", desc: "Install the Outlit skill for OpenCode", flags: [JSON_F] },
|
|
5885
|
+
{ name: "pi", desc: "Install the Outlit skill for Pi", flags: [JSON_F] },
|
|
5886
|
+
{ name: "openclaw", desc: "Install the Outlit skill for OpenClaw", flags: [JSON_F] },
|
|
5887
|
+
{ name: "skills", desc: "Launch the interactive Outlit skills installer", flags: [JSON_F] }
|
|
4849
5888
|
]
|
|
4850
5889
|
},
|
|
5890
|
+
{ name: "upgrade", desc: "Upgrade the CLI", flags: [] },
|
|
4851
5891
|
{ name: "doctor", desc: "Diagnose environment", flags: [...COMMON] },
|
|
4852
5892
|
{ name: "completions", desc: "Generate shell completions", flags: [] }
|
|
4853
5893
|
];
|
|
@@ -4900,142 +5940,149 @@ var init_completions = __esm(() => {
|
|
|
4900
5940
|
var exports_setup = {};
|
|
4901
5941
|
__export(exports_setup, {
|
|
4902
5942
|
isCommandAvailable: () => isCommandAvailable2,
|
|
4903
|
-
detectAgents: () =>
|
|
5943
|
+
detectAgents: () => detectAgents2,
|
|
4904
5944
|
default: () => setup_default2
|
|
4905
5945
|
});
|
|
4906
|
-
import { execFileSync as
|
|
4907
|
-
import { existsSync as
|
|
5946
|
+
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
5947
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
4908
5948
|
import { homedir as homedir6 } from "node:os";
|
|
4909
|
-
import { join as
|
|
5949
|
+
import { join as join7 } from "node:path";
|
|
4910
5950
|
function isCommandAvailable2(cmd) {
|
|
4911
5951
|
try {
|
|
4912
5952
|
const whichCmd = process.platform === "win32" ? "where" : "which";
|
|
4913
|
-
|
|
5953
|
+
execFileSync6(whichCmd, [cmd], { stdio: "ignore" });
|
|
4914
5954
|
return true;
|
|
4915
5955
|
} catch {
|
|
4916
5956
|
return false;
|
|
4917
5957
|
}
|
|
4918
5958
|
}
|
|
4919
|
-
function
|
|
4920
|
-
|
|
5959
|
+
function getHomeDir3() {
|
|
5960
|
+
return process.env.HOME?.trim() || homedir6();
|
|
5961
|
+
}
|
|
5962
|
+
function detectAgents2() {
|
|
5963
|
+
const home = getHomeDir3();
|
|
5964
|
+
const configHome = process.env.XDG_CONFIG_HOME?.trim() || join7(home, ".config");
|
|
4921
5965
|
const detected = [];
|
|
4922
|
-
if (existsSync4(join8(home, ".cursor")))
|
|
4923
|
-
detected.push("cursor");
|
|
4924
5966
|
if (isCommandAvailable2("claude"))
|
|
4925
5967
|
detected.push("claude-code");
|
|
4926
|
-
if (
|
|
4927
|
-
detected.push("
|
|
4928
|
-
if (isCommandAvailable2("code") || existsSync4(join8(process.cwd(), ".vscode")))
|
|
4929
|
-
detected.push("vscode");
|
|
5968
|
+
if (isCommandAvailable2("codex"))
|
|
5969
|
+
detected.push("codex");
|
|
4930
5970
|
if (isCommandAvailable2("gemini"))
|
|
4931
5971
|
detected.push("gemini");
|
|
4932
|
-
if (
|
|
5972
|
+
if (existsSync6(join7(home, ".factory")))
|
|
5973
|
+
detected.push("droid");
|
|
5974
|
+
if (existsSync6(join7(configHome, "opencode")))
|
|
5975
|
+
detected.push("opencode");
|
|
5976
|
+
if (existsSync6(join7(home, ".pi", "agent")))
|
|
5977
|
+
detected.push("pi");
|
|
5978
|
+
if (existsSync6(join7(home, ".openclaw")) || existsSync6(join7(home, ".clawdbot")) || existsSync6(join7(home, ".moltbot"))) {
|
|
4933
5979
|
detected.push("openclaw");
|
|
5980
|
+
}
|
|
4934
5981
|
return detected;
|
|
4935
5982
|
}
|
|
4936
|
-
var agentLabels2,
|
|
4937
|
-
var
|
|
5983
|
+
var agentLabels2, setupSubcommandNames2, setup_default2;
|
|
5984
|
+
var init_setup2 = __esm(() => {
|
|
4938
5985
|
init_dist();
|
|
4939
|
-
init_auth();
|
|
4940
5986
|
init_output2();
|
|
4941
5987
|
init_config();
|
|
4942
5988
|
init_output();
|
|
4943
|
-
init_claude_code();
|
|
4944
|
-
init_claude_desktop();
|
|
4945
|
-
init_cursor();
|
|
4946
|
-
init_gemini();
|
|
4947
|
-
init_openclaw();
|
|
4948
5989
|
init_skills();
|
|
4949
|
-
init_vscode();
|
|
4950
5990
|
agentLabels2 = {
|
|
4951
|
-
cursor: { label: "Cursor", hint: "~/.cursor/" },
|
|
4952
5991
|
"claude-code": { label: "Claude Code", hint: "claude CLI found" },
|
|
4953
|
-
|
|
4954
|
-
vscode: { label: "VS Code", hint: "code CLI or .vscode/ found" },
|
|
5992
|
+
codex: { label: "Codex", hint: "codex CLI found" },
|
|
4955
5993
|
gemini: { label: "Gemini CLI", hint: "gemini CLI found" },
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
"claude-code": configureSafe,
|
|
4961
|
-
"claude-desktop": configureSafe2,
|
|
4962
|
-
vscode: configureSafe6,
|
|
4963
|
-
gemini: configureSafe4,
|
|
4964
|
-
openclaw: configureSafe5
|
|
5994
|
+
droid: { label: "Droid", hint: ".factory config found" },
|
|
5995
|
+
opencode: { label: "OpenCode", hint: "opencode config found" },
|
|
5996
|
+
pi: { label: "Pi", hint: ".pi/agent config found" },
|
|
5997
|
+
openclaw: { label: "OpenClaw", hint: "OpenClaw config found" }
|
|
4965
5998
|
};
|
|
5999
|
+
setupSubcommandNames2 = new Set([
|
|
6000
|
+
"claude-code",
|
|
6001
|
+
"codex",
|
|
6002
|
+
"gemini",
|
|
6003
|
+
"droid",
|
|
6004
|
+
"opencode",
|
|
6005
|
+
"pi",
|
|
6006
|
+
"openclaw",
|
|
6007
|
+
"skills"
|
|
6008
|
+
]);
|
|
4966
6009
|
setup_default2 = defineCommand2({
|
|
4967
6010
|
meta: {
|
|
4968
6011
|
name: "setup",
|
|
4969
6012
|
description: [
|
|
4970
|
-
"
|
|
6013
|
+
"Install the Outlit skill for coding agents.",
|
|
4971
6014
|
"",
|
|
4972
|
-
"Without a subcommand, auto-detects
|
|
4973
|
-
"Subcommands:
|
|
6015
|
+
"Without a subcommand, auto-detects supported coding agents and installs `outlit` for all of them.",
|
|
6016
|
+
"Subcommands: claude-code, codex, gemini, droid, opencode, pi, openclaw, skills"
|
|
4974
6017
|
].join(`
|
|
4975
6018
|
`)
|
|
4976
6019
|
},
|
|
4977
6020
|
args: {
|
|
4978
|
-
...authArgs,
|
|
4979
6021
|
...outputArgs,
|
|
4980
6022
|
yes: {
|
|
4981
6023
|
type: "boolean",
|
|
4982
|
-
description: "
|
|
6024
|
+
description: "Install for all detected coding agents without prompting."
|
|
4983
6025
|
}
|
|
4984
6026
|
},
|
|
4985
6027
|
subCommands: {
|
|
4986
|
-
cursor: () => Promise.resolve().then(() => (init_cursor(), exports_cursor)).then((m) => m.default),
|
|
4987
6028
|
"claude-code": () => Promise.resolve().then(() => (init_claude_code(), exports_claude_code)).then((m) => m.default),
|
|
4988
|
-
|
|
4989
|
-
vscode: () => Promise.resolve().then(() => (init_vscode(), exports_vscode)).then((m) => m.default),
|
|
6029
|
+
codex: () => Promise.resolve().then(() => (init_codex(), exports_codex)).then((m) => m.default),
|
|
4990
6030
|
gemini: () => Promise.resolve().then(() => (init_gemini(), exports_gemini)).then((m) => m.default),
|
|
6031
|
+
droid: () => Promise.resolve().then(() => (init_droid(), exports_droid)).then((m) => m.default),
|
|
6032
|
+
opencode: () => Promise.resolve().then(() => (init_opencode(), exports_opencode)).then((m) => m.default),
|
|
6033
|
+
pi: () => Promise.resolve().then(() => (init_pi(), exports_pi)).then((m) => m.default),
|
|
4991
6034
|
openclaw: () => Promise.resolve().then(() => (init_openclaw(), exports_openclaw)).then((m) => m.default),
|
|
4992
6035
|
skills: () => Promise.resolve().then(() => (init_skills(), exports_skills)).then((m) => m.default)
|
|
4993
6036
|
},
|
|
4994
|
-
async run({ args }) {
|
|
6037
|
+
async run({ args, rawArgs }) {
|
|
6038
|
+
const setupRawArgs = rawArgs ?? [];
|
|
6039
|
+
const subcommandName = setupRawArgs.find((arg) => !arg.startsWith("-"));
|
|
6040
|
+
if (subcommandName && setupSubcommandNames2.has(subcommandName)) {
|
|
6041
|
+
return;
|
|
6042
|
+
}
|
|
4995
6043
|
const json = !!args.json;
|
|
4996
|
-
const
|
|
4997
|
-
const detected = detectAgents3();
|
|
6044
|
+
const detected = detectAgents2();
|
|
4998
6045
|
if (detected.length === 0) {
|
|
4999
6046
|
if (isJsonMode(json)) {
|
|
5000
|
-
return outputResult({ detected: [], configured: [], failed: [],
|
|
6047
|
+
return outputResult({ detected: [], configured: [], failed: [], runner: null });
|
|
5001
6048
|
}
|
|
5002
|
-
console.log("No supported
|
|
6049
|
+
console.log("No supported coding agents detected.");
|
|
5003
6050
|
return;
|
|
5004
6051
|
}
|
|
5005
6052
|
if (!isJsonMode(json) && !args.yes) {
|
|
5006
|
-
console.log("Detected agents:");
|
|
6053
|
+
console.log("Detected coding agents:");
|
|
5007
6054
|
for (const agentId of detected) {
|
|
5008
6055
|
const { label, hint } = agentLabels2[agentId];
|
|
5009
6056
|
console.log(` ${TICK2} ${label.padEnd(14)} -- ${hint}`);
|
|
5010
6057
|
}
|
|
5011
6058
|
console.log(`
|
|
5012
|
-
|
|
5013
|
-
}
|
|
5014
|
-
const configured = [];
|
|
5015
|
-
const failed = [];
|
|
5016
|
-
for (const agentId of detected) {
|
|
5017
|
-
const ok = configurators2[agentId](credential.key, json);
|
|
5018
|
-
if (ok) {
|
|
5019
|
-
configured.push(agentId);
|
|
5020
|
-
} else {
|
|
5021
|
-
failed.push(agentId);
|
|
5022
|
-
}
|
|
5023
|
-
}
|
|
5024
|
-
const skills = runSkillsInstall(json, false);
|
|
5025
|
-
if (!isJsonMode(json) && !skills.success) {
|
|
5026
|
-
console.log(`
|
|
5027
|
-
! Agent skills installation failed: ${skills.error ?? "unknown error"}`);
|
|
5028
|
-
console.log(" Run `outlit setup skills` to retry.");
|
|
6059
|
+
Installing Outlit skill...`);
|
|
5029
6060
|
}
|
|
6061
|
+
const install = runSkillsInstall({
|
|
6062
|
+
json,
|
|
6063
|
+
exitOnError: false,
|
|
6064
|
+
agents: detected.map(getSkillAgentId),
|
|
6065
|
+
skillNames: ["outlit"],
|
|
6066
|
+
autoConfirm: true
|
|
6067
|
+
});
|
|
6068
|
+
const configured = install.success ? detected : [];
|
|
6069
|
+
const failed = install.success ? [] : detected;
|
|
5030
6070
|
if (isJsonMode(json)) {
|
|
5031
|
-
return outputResult({
|
|
6071
|
+
return outputResult({
|
|
6072
|
+
detected,
|
|
6073
|
+
configured,
|
|
6074
|
+
failed,
|
|
6075
|
+
runner: install.runner ?? null
|
|
6076
|
+
});
|
|
5032
6077
|
}
|
|
5033
|
-
if (
|
|
6078
|
+
if (!install.success) {
|
|
5034
6079
|
console.log(`
|
|
5035
|
-
|
|
6080
|
+
! Outlit skill install failed: ${install.error ?? "unknown error"}`);
|
|
6081
|
+
console.log(" Run `outlit setup skills` to retry manually.");
|
|
6082
|
+
return;
|
|
5036
6083
|
}
|
|
5037
6084
|
console.log(`
|
|
5038
|
-
Done. ${configured.length}
|
|
6085
|
+
Done. Installed Outlit for ${configured.length} coding agent(s).`);
|
|
5039
6086
|
}
|
|
5040
6087
|
});
|
|
5041
6088
|
});
|
|
@@ -5392,11 +6439,226 @@ init_tty();
|
|
|
5392
6439
|
var CLI_VERSION = package_default.version;
|
|
5393
6440
|
var TICK = `\x1B[32m${isUnicodeSupported ? String.fromCodePoint(10003) : String.fromCodePoint(8730)}\x1B[0m`;
|
|
5394
6441
|
|
|
6442
|
+
// src/lib/update.ts
|
|
6443
|
+
init_config();
|
|
6444
|
+
init_tty();
|
|
6445
|
+
import { execFileSync as execFileSync2, spawn, spawnSync } from "node:child_process";
|
|
6446
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, realpathSync, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
6447
|
+
import { homedir as homedir2 } from "node:os";
|
|
6448
|
+
import { dirname as dirname2, join as join2 } from "node:path";
|
|
6449
|
+
var UPDATE_CHECK_INTERVAL_MS = 12 * 60 * 60 * 1000;
|
|
6450
|
+
var PACKAGE_NAME = "@outlit/cli";
|
|
6451
|
+
var LATEST_VERSION_URL = "https://registry.npmjs.org/@outlit%2Fcli/latest";
|
|
6452
|
+
var INTERNAL_UPDATE_FLAG = "--internal-update-check";
|
|
6453
|
+
function getUpdateCachePath() {
|
|
6454
|
+
return join2(getConfigDir(), "update-check.json");
|
|
6455
|
+
}
|
|
6456
|
+
function readCachedUpdateState() {
|
|
6457
|
+
const cachePath = getUpdateCachePath();
|
|
6458
|
+
if (!existsSync2(cachePath))
|
|
6459
|
+
return null;
|
|
6460
|
+
try {
|
|
6461
|
+
return JSON.parse(readFileSync2(cachePath, "utf8"));
|
|
6462
|
+
} catch {
|
|
6463
|
+
return null;
|
|
6464
|
+
}
|
|
6465
|
+
}
|
|
6466
|
+
function writeCachedUpdateState(state) {
|
|
6467
|
+
const cachePath = getUpdateCachePath();
|
|
6468
|
+
mkdirSync2(dirname2(cachePath), { recursive: true });
|
|
6469
|
+
writeFileSync2(cachePath, `${JSON.stringify(state, null, 2)}
|
|
6470
|
+
`);
|
|
6471
|
+
}
|
|
6472
|
+
function isUpdateCheckDue(state) {
|
|
6473
|
+
if (!state?.lastCheckedAt)
|
|
6474
|
+
return true;
|
|
6475
|
+
return Date.now() - state.lastCheckedAt >= UPDATE_CHECK_INTERVAL_MS;
|
|
6476
|
+
}
|
|
6477
|
+
function compareVersions(a, b) {
|
|
6478
|
+
const aParts = a.split("-")[0]?.split(".").map((part) => Number.parseInt(part, 10) || 0) ?? [];
|
|
6479
|
+
const bParts = b.split("-")[0]?.split(".").map((part) => Number.parseInt(part, 10) || 0) ?? [];
|
|
6480
|
+
const maxLength = Math.max(aParts.length, bParts.length);
|
|
6481
|
+
for (let index = 0;index < maxLength; index++) {
|
|
6482
|
+
const left = aParts[index] ?? 0;
|
|
6483
|
+
const right = bParts[index] ?? 0;
|
|
6484
|
+
if (left > right)
|
|
6485
|
+
return 1;
|
|
6486
|
+
if (left < right)
|
|
6487
|
+
return -1;
|
|
6488
|
+
}
|
|
6489
|
+
return 0;
|
|
6490
|
+
}
|
|
6491
|
+
function inferInstallerFromUserAgent(agent) {
|
|
6492
|
+
if (agent.startsWith("bun/"))
|
|
6493
|
+
return "bun";
|
|
6494
|
+
if (agent.startsWith("npm/"))
|
|
6495
|
+
return "npm";
|
|
6496
|
+
if (agent.startsWith("pnpm/"))
|
|
6497
|
+
return "pnpm";
|
|
6498
|
+
if (agent.startsWith("yarn/"))
|
|
6499
|
+
return "yarn";
|
|
6500
|
+
return null;
|
|
6501
|
+
}
|
|
6502
|
+
function isUnderPath(path, parent) {
|
|
6503
|
+
const normalizedPath = normalizeInstallerPath(path);
|
|
6504
|
+
const normalizedParent = normalizeInstallerPath(parent);
|
|
6505
|
+
return normalizedPath === normalizedParent || normalizedPath.startsWith(`${normalizedParent}/`);
|
|
6506
|
+
}
|
|
6507
|
+
function normalizeInstallerPath(path) {
|
|
6508
|
+
return path.replace(/^\/private\/tmp\//, "/tmp/");
|
|
6509
|
+
}
|
|
6510
|
+
function inferInstallerFromInstallation(opts) {
|
|
6511
|
+
const candidatePaths = [opts.argv1, opts.realExecPath].filter((value) => !!value);
|
|
6512
|
+
if (opts.npmGlobalPrefix) {
|
|
6513
|
+
const npmPackageRoots = [
|
|
6514
|
+
join2(opts.npmGlobalPrefix, "node_modules", PACKAGE_NAME),
|
|
6515
|
+
join2(opts.npmGlobalPrefix, "lib", "node_modules", PACKAGE_NAME)
|
|
6516
|
+
];
|
|
6517
|
+
if (candidatePaths.some((path) => npmPackageRoots.some((root) => isUnderPath(path, root)))) {
|
|
6518
|
+
return "npm";
|
|
6519
|
+
}
|
|
6520
|
+
}
|
|
6521
|
+
if (opts.bunGlobalBin) {
|
|
6522
|
+
const bunGlobalBin = opts.bunGlobalBin;
|
|
6523
|
+
if (candidatePaths.some((path) => isUnderPath(path, bunGlobalBin))) {
|
|
6524
|
+
return "bun";
|
|
6525
|
+
}
|
|
6526
|
+
}
|
|
6527
|
+
return null;
|
|
6528
|
+
}
|
|
6529
|
+
function readCommandOutput(command, args) {
|
|
6530
|
+
try {
|
|
6531
|
+
return execFileSync2(command, args, {
|
|
6532
|
+
encoding: "utf8",
|
|
6533
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
6534
|
+
}).trim();
|
|
6535
|
+
} catch {
|
|
6536
|
+
return null;
|
|
6537
|
+
}
|
|
6538
|
+
}
|
|
6539
|
+
function inferInstaller() {
|
|
6540
|
+
const fromAgent = inferInstallerFromUserAgent(process.env.npm_config_user_agent ?? "");
|
|
6541
|
+
if (fromAgent)
|
|
6542
|
+
return fromAgent;
|
|
6543
|
+
const argv1 = process.argv[1];
|
|
6544
|
+
const realExecPath = argv1 ? readCommandOutput("realpath", [argv1]) ?? safeRealPath(argv1) : null;
|
|
6545
|
+
const npmGlobalPrefix = process.env.npm_config_prefix ?? readCommandOutput("npm", ["prefix", "-g"]);
|
|
6546
|
+
const bunGlobalBin = process.env.BUN_INSTALL ? join2(process.env.BUN_INSTALL, "bin") : readCommandOutput("bun", ["pm", "bin", "-g"]) ?? join2(homedir2(), ".bun", "bin");
|
|
6547
|
+
return inferInstallerFromInstallation({
|
|
6548
|
+
argv1,
|
|
6549
|
+
realExecPath,
|
|
6550
|
+
npmGlobalPrefix,
|
|
6551
|
+
bunGlobalBin
|
|
6552
|
+
});
|
|
6553
|
+
}
|
|
6554
|
+
function safeRealPath(filePath) {
|
|
6555
|
+
try {
|
|
6556
|
+
return realpathSync(filePath);
|
|
6557
|
+
} catch {
|
|
6558
|
+
return null;
|
|
6559
|
+
}
|
|
6560
|
+
}
|
|
6561
|
+
function formatUpdateCommand(installer = inferInstaller()) {
|
|
6562
|
+
switch (installer) {
|
|
6563
|
+
case "bun":
|
|
6564
|
+
return "bun add -g @outlit/cli";
|
|
6565
|
+
case "npm":
|
|
6566
|
+
return "npm install -g @outlit/cli";
|
|
6567
|
+
case "pnpm":
|
|
6568
|
+
return "pnpm add -g @outlit/cli";
|
|
6569
|
+
case "yarn":
|
|
6570
|
+
return "yarn global add @outlit/cli";
|
|
6571
|
+
default:
|
|
6572
|
+
return `update ${PACKAGE_NAME} with your package manager`;
|
|
6573
|
+
}
|
|
6574
|
+
}
|
|
6575
|
+
function getCachedUpdateNotice(state = readCachedUpdateState()) {
|
|
6576
|
+
if (!state?.latestVersion)
|
|
6577
|
+
return null;
|
|
6578
|
+
if (compareVersions(CLI_VERSION2, state.latestVersion) >= 0)
|
|
6579
|
+
return null;
|
|
6580
|
+
return {
|
|
6581
|
+
currentVersion: CLI_VERSION2,
|
|
6582
|
+
latestVersion: state.latestVersion,
|
|
6583
|
+
command: formatUpdateCommand(state.installer)
|
|
6584
|
+
};
|
|
6585
|
+
}
|
|
6586
|
+
function shouldCheckForUpdates() {
|
|
6587
|
+
if (process.env.OUTLIT_NO_UPDATE_NOTIFIER)
|
|
6588
|
+
return false;
|
|
6589
|
+
return isInteractive();
|
|
6590
|
+
}
|
|
6591
|
+
function shouldShowUpdateNotice(argv = process.argv) {
|
|
6592
|
+
return shouldCheckForUpdates() && !argv.includes("--json") && !argv.includes(INTERNAL_UPDATE_FLAG);
|
|
6593
|
+
}
|
|
6594
|
+
function printCachedUpdateNotice(argv = process.argv, notify = console.error) {
|
|
6595
|
+
if (!shouldShowUpdateNotice(argv))
|
|
6596
|
+
return false;
|
|
6597
|
+
const notice = getCachedUpdateNotice();
|
|
6598
|
+
if (!notice)
|
|
6599
|
+
return false;
|
|
6600
|
+
notify(`Outlit CLI update available: ${notice.currentVersion} -> ${notice.latestVersion}
|
|
6601
|
+
Update with: ${notice.command}`);
|
|
6602
|
+
return true;
|
|
6603
|
+
}
|
|
6604
|
+
function scheduleBackgroundUpdateCheck(argv = process.argv, spawnProcess = spawn) {
|
|
6605
|
+
if (!shouldShowUpdateNotice(argv))
|
|
6606
|
+
return false;
|
|
6607
|
+
if (!isUpdateCheckDue(readCachedUpdateState()))
|
|
6608
|
+
return false;
|
|
6609
|
+
const runtimePath = argv[0];
|
|
6610
|
+
const scriptPath = argv[1];
|
|
6611
|
+
if (!runtimePath || !scriptPath)
|
|
6612
|
+
return false;
|
|
6613
|
+
const child = spawnProcess(runtimePath, [scriptPath, INTERNAL_UPDATE_FLAG], {
|
|
6614
|
+
detached: true,
|
|
6615
|
+
stdio: "ignore"
|
|
6616
|
+
});
|
|
6617
|
+
child.unref?.();
|
|
6618
|
+
return true;
|
|
6619
|
+
}
|
|
6620
|
+
function initializeUpdateNotifier(opts) {
|
|
6621
|
+
const argv = opts?.argv ?? process.argv;
|
|
6622
|
+
printCachedUpdateNotice(argv, opts?.notify);
|
|
6623
|
+
scheduleBackgroundUpdateCheck(argv, opts?.spawn);
|
|
6624
|
+
}
|
|
6625
|
+
async function fetchLatestCliVersion() {
|
|
6626
|
+
const response = await fetch(LATEST_VERSION_URL, { signal: AbortSignal.timeout(5000) });
|
|
6627
|
+
if (!response.ok)
|
|
6628
|
+
throw new Error("registry unavailable");
|
|
6629
|
+
const data = await response.json();
|
|
6630
|
+
if (!data.version)
|
|
6631
|
+
throw new Error("registry returned no version");
|
|
6632
|
+
return data.version;
|
|
6633
|
+
}
|
|
6634
|
+
async function runInternalUpdateCheck(opts) {
|
|
6635
|
+
const fetchLatestVersion = opts?.fetchLatestVersion ?? fetchLatestCliVersion;
|
|
6636
|
+
const installer = opts?.installer ?? inferInstaller();
|
|
6637
|
+
try {
|
|
6638
|
+
const latestVersion = await fetchLatestVersion();
|
|
6639
|
+
writeCachedUpdateState({
|
|
6640
|
+
lastCheckedAt: Date.now(),
|
|
6641
|
+
latestVersion,
|
|
6642
|
+
...installer ? { installer } : {}
|
|
6643
|
+
});
|
|
6644
|
+
} catch {
|
|
6645
|
+
writeCachedUpdateState({
|
|
6646
|
+
lastCheckedAt: Date.now(),
|
|
6647
|
+
...installer ? { installer } : {}
|
|
6648
|
+
});
|
|
6649
|
+
}
|
|
6650
|
+
}
|
|
6651
|
+
|
|
5395
6652
|
// src/cli.ts
|
|
5396
6653
|
if (process.argv.includes("-v")) {
|
|
5397
6654
|
console.log(CLI_VERSION);
|
|
5398
6655
|
process.exit(0);
|
|
5399
6656
|
}
|
|
6657
|
+
if (process.argv.includes(INTERNAL_UPDATE_FLAG)) {
|
|
6658
|
+
await runInternalUpdateCheck();
|
|
6659
|
+
process.exit(0);
|
|
6660
|
+
}
|
|
6661
|
+
initializeUpdateNotifier();
|
|
5400
6662
|
var main = defineCommand({
|
|
5401
6663
|
meta: {
|
|
5402
6664
|
name: "outlit",
|
|
@@ -5408,8 +6670,10 @@ Usage examples:
|
|
|
5408
6670
|
outlit customers get acme.com --include users,revenue
|
|
5409
6671
|
outlit customers timeline acme.com --timeframe 90d
|
|
5410
6672
|
outlit users list --journey-stage CHAMPION
|
|
5411
|
-
outlit facts acme.com --
|
|
5412
|
-
outlit
|
|
6673
|
+
outlit facts list acme.com --fact-types CHURN_RISK,EXPANSION
|
|
6674
|
+
outlit facts get --fact-id fact_123 --include evidence
|
|
6675
|
+
outlit sources get --source-type CALL --source-id call_123
|
|
6676
|
+
outlit search 'pricing objections last quarter' --source-types CALL,EMAIL
|
|
5413
6677
|
outlit sql 'SELECT * FROM events LIMIT 10'
|
|
5414
6678
|
outlit schema events
|
|
5415
6679
|
outlit doctor --json
|
|
@@ -5421,13 +6685,15 @@ For AI agents: commands auto-output JSON when stdout is piped. No --json flag ne
|
|
|
5421
6685
|
customers: () => Promise.resolve().then(() => (init_customers(), exports_customers)).then((m) => m.default),
|
|
5422
6686
|
users: () => Promise.resolve().then(() => (init_users(), exports_users)).then((m) => m.default),
|
|
5423
6687
|
doctor: () => Promise.resolve().then(() => (init_doctor(), exports_doctor)).then((m) => m.default),
|
|
6688
|
+
upgrade: () => Promise.resolve().then(() => (init_upgrade(), exports_upgrade)).then((m) => m.default),
|
|
5424
6689
|
facts: () => Promise.resolve().then(() => (init_facts(), exports_facts)).then((m) => m.default),
|
|
6690
|
+
sources: () => Promise.resolve().then(() => (init_sources(), exports_sources)).then((m) => m.default),
|
|
5425
6691
|
search: () => Promise.resolve().then(() => (init_search(), exports_search)).then((m) => m.default),
|
|
5426
6692
|
sql: () => Promise.resolve().then(() => (init_sql(), exports_sql)).then((m) => m.default),
|
|
5427
6693
|
schema: () => Promise.resolve().then(() => (init_schema(), exports_schema)).then((m) => m.default),
|
|
5428
6694
|
integrations: () => Promise.resolve().then(() => (init_integrations(), exports_integrations)).then((m) => m.default),
|
|
5429
6695
|
completions: () => Promise.resolve().then(() => (init_completions(), exports_completions)).then((m) => m.default),
|
|
5430
|
-
setup: () => Promise.resolve().then(() => (
|
|
6696
|
+
setup: () => Promise.resolve().then(() => (init_setup2(), exports_setup)).then((m) => m.default)
|
|
5431
6697
|
}
|
|
5432
6698
|
});
|
|
5433
6699
|
runMain(main);
|