@outlit/cli 0.1.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +455 -84
  2. package/package.json +4 -2
package/dist/cli.js CHANGED
@@ -104,7 +104,7 @@ var package_default;
104
104
  var init_package = __esm(() => {
105
105
  package_default = {
106
106
  name: "@outlit/cli",
107
- version: "0.1.0",
107
+ version: "1.0.1",
108
108
  description: "CLI for Outlit customer intelligence platform",
109
109
  license: "Apache-2.0",
110
110
  repository: {
@@ -117,7 +117,9 @@ var init_package = __esm(() => {
117
117
  access: "public"
118
118
  },
119
119
  type: "module",
120
- bin: { outlit: "./dist/cli.js" },
120
+ bin: {
121
+ outlit: "./dist/cli.js"
122
+ },
121
123
  files: ["dist"],
122
124
  scripts: {
123
125
  dev: "bun run src/cli.ts",
@@ -155,6 +157,10 @@ function isInteractive() {
155
157
  return false;
156
158
  return true;
157
159
  }
160
+ var isUnicodeSupported;
161
+ var init_tty = __esm(() => {
162
+ isUnicodeSupported = process.platform !== "win32" || Boolean(process.env.WT_SESSION) || process.env.TERM_PROGRAM === "vscode";
163
+ });
158
164
 
159
165
  // src/lib/output.ts
160
166
  function isJsonMode(json) {
@@ -179,7 +185,9 @@ function outputError(error, json) {
179
185
  function errorMessage(err, fallback) {
180
186
  return err instanceof Error ? err.message : fallback;
181
187
  }
182
- var init_output = () => {};
188
+ var init_output = __esm(() => {
189
+ init_tty();
190
+ });
183
191
 
184
192
  // ../../node_modules/.bun/citty@0.2.1/node_modules/citty/dist/index.mjs
185
193
  function defineCommand2(def) {
@@ -1303,6 +1311,7 @@ var init_signup = __esm(() => {
1303
1311
  init_dist();
1304
1312
  init_output2();
1305
1313
  init_output();
1314
+ init_tty();
1306
1315
  signup_default = defineCommand2({
1307
1316
  meta: {
1308
1317
  name: "signup",
@@ -1324,7 +1333,7 @@ var init_signup = __esm(() => {
1324
1333
  return outputResult({ url: OUTLIT_SIGNUP_URL });
1325
1334
  }
1326
1335
  if (isInteractive()) {
1327
- We("Outlit CLI Sign Up");
1336
+ We("Outlit CLI -- Sign Up");
1328
1337
  }
1329
1338
  try {
1330
1339
  if (process.platform === "win32") {
@@ -1435,11 +1444,13 @@ function storeApiKey(apiKey) {
1435
1444
  writeFileSync(credPath, JSON.stringify({ apiKey }, null, 2), { mode: 384 });
1436
1445
  return credPath;
1437
1446
  }
1438
- 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", TICK = "\x1B[32m✓\x1B[0m";
1447
+ var CLI_VERSION2, DEFAULT_MCP_URL = "https://mcp.outlit.ai/mcp", DEFAULT_API_URL = "https://app.outlit.ai", OUTLIT_DASHBOARD_URL = "https://app.outlit.ai/workspace-profile", TICK2;
1439
1448
  var init_config = __esm(() => {
1440
1449
  init_package();
1441
1450
  init_output();
1451
+ init_tty();
1442
1452
  CLI_VERSION2 = package_default.version;
1453
+ TICK2 = `\x1B[32m${isUnicodeSupported ? String.fromCodePoint(10003) : String.fromCodePoint(8730)}\x1B[0m`;
1443
1454
  });
1444
1455
 
1445
1456
  // src/lib/client.ts
@@ -1521,30 +1532,62 @@ function createSpinner(message) {
1521
1532
  }
1522
1533
  let frameIndex = 0;
1523
1534
  let text = message;
1535
+ let stopped = false;
1536
+ process.stderr.write(HIDE_CURSOR);
1537
+ const removeSignalHandlers = () => {
1538
+ process.off("SIGINT", onSigint);
1539
+ process.off("SIGTERM", onSigterm);
1540
+ };
1541
+ const cleanup = () => {
1542
+ if (stopped)
1543
+ return;
1544
+ stopped = true;
1545
+ clearInterval(timer);
1546
+ removeSignalHandlers();
1547
+ process.stderr.write(SHOW_CURSOR);
1548
+ };
1549
+ const onSigint = () => {
1550
+ cleanup();
1551
+ process.exit(130);
1552
+ };
1553
+ const onSigterm = () => {
1554
+ cleanup();
1555
+ process.exit(143);
1556
+ };
1557
+ process.on("SIGINT", onSigint);
1558
+ process.on("SIGTERM", onSigterm);
1524
1559
  const timer = setInterval(() => {
1525
1560
  const frame = FRAMES[frameIndex % FRAMES.length];
1526
1561
  process.stderr.write(`\r\x1B[2K ${frame} ${text}`);
1527
1562
  frameIndex++;
1528
1563
  }, INTERVAL_MS);
1564
+ const finish = (symbol, color, msg) => {
1565
+ if (stopped)
1566
+ return;
1567
+ cleanup();
1568
+ process.stderr.write(`\r\x1B[2K ${color}${symbol}\x1B[0m ${msg}
1569
+ `);
1570
+ };
1529
1571
  return {
1530
1572
  update(msg) {
1531
1573
  text = msg;
1532
1574
  },
1533
1575
  stop(msg) {
1534
- clearInterval(timer);
1535
- process.stderr.write(`\r\x1B[2K \x1B[32m✔\x1B[0m ${msg}
1536
- `);
1576
+ finish(SUCCESS_SYMBOL, "\x1B[32m", msg);
1537
1577
  },
1538
1578
  fail(msg) {
1539
- clearInterval(timer);
1540
- process.stderr.write(`\r\x1B[2K \x1B[31m✗\x1B[0m ${msg}
1541
- `);
1579
+ finish(FAIL_SYMBOL, "\x1B[31m", msg);
1542
1580
  }
1543
1581
  };
1544
1582
  }
1545
- var FRAMES, INTERVAL_MS = 80;
1583
+ var UNICODE_FRAMES, ASCII_FRAMES, FRAMES, INTERVAL_MS = 80, SUCCESS_SYMBOL, FAIL_SYMBOL, HIDE_CURSOR = "\x1B[?25l", SHOW_CURSOR = "\x1B[?25h";
1546
1584
  var init_spinner = __esm(() => {
1547
- FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
1585
+ init_tty();
1586
+ UNICODE_FRAMES = [10251, 10265, 10297, 10296, 10300, 10292, 10278, 10279, 10247, 10255].map((cp) => String.fromCodePoint(cp));
1587
+ ASCII_FRAMES = ["-", "\\", "|", "/"];
1588
+ FRAMES = isUnicodeSupported ? UNICODE_FRAMES : ASCII_FRAMES;
1589
+ SUCCESS_SYMBOL = isUnicodeSupported ? String.fromCodePoint(10003) : String.fromCodePoint(8730);
1590
+ FAIL_SYMBOL = isUnicodeSupported ? String.fromCodePoint(10007) : "x";
1548
1591
  });
1549
1592
 
1550
1593
  // src/lib/table.ts
@@ -1552,14 +1595,14 @@ function renderTable(headers, rows, emptyMessage = "(no results)") {
1552
1595
  if (rows.length === 0)
1553
1596
  return emptyMessage;
1554
1597
  const widths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => (r[i] ?? "").length)));
1555
- const border = (left, mid, right) => `${left}${widths.map((w) => "─".repeat(w + 2)).join(mid)}${right}`;
1556
- const formatRow = (cells) => `│${cells.map((c, i) => ` ${(c ?? "").padEnd(widths[i] ?? 0)} `).join("│")}│`;
1598
+ const border = (left, mid, right) => `${left}${widths.map((w) => BOX.h.repeat(w + 2)).join(mid)}${right}`;
1599
+ const formatRow = (cells) => `${BOX.v}${cells.map((c, i) => ` ${(c ?? "").padEnd(widths[i] ?? 0)} `).join(BOX.v)}${BOX.v}`;
1557
1600
  return [
1558
- border("┌", "┬", "┐"),
1601
+ border(BOX.tl, BOX.tt, BOX.tr),
1559
1602
  formatRow(headers),
1560
- border("├", "┼", "┤"),
1603
+ border(BOX.lt, BOX.cr, BOX.rt),
1561
1604
  ...rows.map(formatRow),
1562
- border("└", "┴", "┘")
1605
+ border(BOX.bl, BOX.bt, BOX.br)
1563
1606
  ].join(`
1564
1607
  `);
1565
1608
  }
@@ -1571,6 +1614,35 @@ function renderPaginationHint(pagination, itemCount) {
1571
1614
  }
1572
1615
  return `Showing all ${pagination.total} results.`;
1573
1616
  }
1617
+ var BOX;
1618
+ var init_table = __esm(() => {
1619
+ init_tty();
1620
+ BOX = isUnicodeSupported ? {
1621
+ h: String.fromCodePoint(9472),
1622
+ v: String.fromCodePoint(9474),
1623
+ tl: String.fromCodePoint(9484),
1624
+ tr: String.fromCodePoint(9488),
1625
+ bl: String.fromCodePoint(9492),
1626
+ br: String.fromCodePoint(9496),
1627
+ lt: String.fromCodePoint(9500),
1628
+ rt: String.fromCodePoint(9508),
1629
+ tt: String.fromCodePoint(9516),
1630
+ bt: String.fromCodePoint(9524),
1631
+ cr: String.fromCodePoint(9532)
1632
+ } : {
1633
+ h: "-",
1634
+ v: "|",
1635
+ tl: "+",
1636
+ tr: "+",
1637
+ bl: "+",
1638
+ br: "+",
1639
+ lt: "+",
1640
+ rt: "+",
1641
+ tt: "+",
1642
+ bt: "+",
1643
+ cr: "+"
1644
+ };
1645
+ });
1574
1646
 
1575
1647
  // src/lib/api.ts
1576
1648
  async function getClientOrExit(flagApiKey, json) {
@@ -1632,6 +1704,7 @@ var init_api = __esm(() => {
1632
1704
  init_client();
1633
1705
  init_output();
1634
1706
  init_spinner();
1707
+ init_table();
1635
1708
  });
1636
1709
 
1637
1710
  // src/commands/auth/login.ts
@@ -1648,6 +1721,7 @@ var init_login = __esm(() => {
1648
1721
  init_api();
1649
1722
  init_config();
1650
1723
  init_output();
1724
+ init_tty();
1651
1725
  login_default = defineCommand2({
1652
1726
  meta: {
1653
1727
  name: "login",
@@ -1680,7 +1754,7 @@ Format: ok_ followed by 32+ alphanumeric characters.`
1680
1754
  if (!isInteractive()) {
1681
1755
  return outputError({ message: "--key <apiKey> is required in non-interactive mode", code: "missing_key" }, json);
1682
1756
  }
1683
- We("Outlit CLI Login");
1757
+ We("Outlit CLI -- Login");
1684
1758
  const existing = resolveApiKey();
1685
1759
  if (existing) {
1686
1760
  R2.info(`A key from ${existing.source} is already active. Enter a new key to replace it.`);
@@ -1779,7 +1853,7 @@ var init_logout = __esm(() => {
1779
1853
  "Remove the stored Outlit API key.",
1780
1854
  "",
1781
1855
  "Deletes ~/.config/outlit/credentials.json.",
1782
- "Idempotent safe to run even if not logged in.",
1856
+ "Idempotent -- safe to run even if not logged in.",
1783
1857
  "",
1784
1858
  "Note: If OUTLIT_API_KEY env var is set, it continues to work after logout."
1785
1859
  ].join(`
@@ -1806,7 +1880,7 @@ var init_logout = __esm(() => {
1806
1880
  if (isJsonMode(json)) {
1807
1881
  return outputResult({ success: true });
1808
1882
  }
1809
- process.stdout.write(`${TICK} Logged out. Credentials removed from ${credPath}
1883
+ process.stdout.write(`${TICK2} Logged out. Credentials removed from ${credPath}
1810
1884
  `);
1811
1885
  }
1812
1886
  });
@@ -1865,7 +1939,7 @@ var init_status = __esm(() => {
1865
1939
  if (isJsonMode(json)) {
1866
1940
  return outputResult({ authenticated: true, source: credential.source, key: masked });
1867
1941
  }
1868
- console.log(`${TICK} Authenticated
1942
+ console.log(`${TICK2} Authenticated
1869
1943
  Key: ${masked}
1870
1944
  Source: ${credential.source}`);
1871
1945
  }
@@ -1892,7 +1966,7 @@ var init_whoami = __esm(() => {
1892
1966
  "Print the active API key (masked) and its source.",
1893
1967
  "",
1894
1968
  "Validates the key against the Outlit API.",
1895
- "Designed for shell scripting outputs a single line in TTY mode.",
1969
+ "Designed for shell scripting -- outputs a single line in TTY mode.",
1896
1970
  "",
1897
1971
  "Examples:",
1898
1972
  " outlit auth whoami",
@@ -1933,11 +2007,11 @@ var init_auth2 = __esm(() => {
1933
2007
  "Manage Outlit CLI authentication.",
1934
2008
  "",
1935
2009
  "Subcommands:",
1936
- " signup create an Outlit account",
1937
- " login store API key",
1938
- " logout remove stored key",
1939
- " status check current auth state",
1940
- " whoami print masked key for scripting"
2010
+ " signup -- create an Outlit account",
2011
+ " login -- store API key",
2012
+ " logout -- remove stored key",
2013
+ " status -- check current auth state",
2014
+ " whoami -- print masked key for scripting"
1941
2015
  ].join(`
1942
2016
  `)
1943
2017
  },
@@ -2012,7 +2086,7 @@ var init_pagination = __esm(() => {
2012
2086
  paginationArgs = {
2013
2087
  limit: {
2014
2088
  type: "string",
2015
- description: "Max results to return (1100). Default: 20.",
2089
+ description: "Max results to return (1-100). Default: 20.",
2016
2090
  default: "20"
2017
2091
  },
2018
2092
  cursor: {
@@ -2059,7 +2133,9 @@ function truncate(value, maxLen) {
2059
2133
  const str = String(value);
2060
2134
  if (str.length <= maxLen)
2061
2135
  return str;
2062
- return `${str.slice(0, maxLen - 1)}…`;
2136
+ if (maxLen <= 3)
2137
+ return "...".slice(0, maxLen);
2138
+ return `${str.slice(0, maxLen - 3)}...`;
2063
2139
  }
2064
2140
 
2065
2141
  // src/commands/customers/list.ts
@@ -2354,9 +2430,9 @@ var init_customers = __esm(() => {
2354
2430
  "Query and filter your customer base.",
2355
2431
  "",
2356
2432
  "Subcommands:",
2357
- " list list customers with filters",
2358
- " get get a specific customer by ID or domain",
2359
- " timeline show activity timeline for a customer",
2433
+ " list -- list customers with filters",
2434
+ " get -- get a specific customer by ID or domain",
2435
+ " timeline -- show activity timeline for a customer",
2360
2436
  "",
2361
2437
  AGENT_JSON_HINT
2362
2438
  ].join(`
@@ -2465,7 +2541,7 @@ var init_users = __esm(() => {
2465
2541
  "Query and filter users across your customer base.",
2466
2542
  "",
2467
2543
  "Subcommands:",
2468
- " list list users with filters",
2544
+ " list -- list users with filters",
2469
2545
  "",
2470
2546
  AGENT_JSON_HINT
2471
2547
  ].join(`
@@ -2490,7 +2566,7 @@ function runMcpCliSetup(key, json, opts, exitOnError = true) {
2490
2566
  DEFAULT_MCP_URL,
2491
2567
  "--header",
2492
2568
  `Authorization: Bearer ${key}`
2493
- ], { stdio: !isJsonMode(json) ? "inherit" : "ignore" });
2569
+ ], { stdio: "pipe" });
2494
2570
  } catch (err) {
2495
2571
  if (exitOnError) {
2496
2572
  if (isEnoentError(err)) {
@@ -2506,7 +2582,7 @@ function runMcpCliSetup(key, json, opts, exitOnError = true) {
2506
2582
  outputResult({ success: true, agent: opts.agentId });
2507
2583
  return { success: true };
2508
2584
  }
2509
- console.log(`${TICK} ${opts.successMessage}`);
2585
+ console.log(`${TICK2} ${opts.successMessage}`);
2510
2586
  }
2511
2587
  return { success: true };
2512
2588
  }
@@ -2528,7 +2604,7 @@ function runMcpFileSetup(key, json, opts, exitOnError = true) {
2528
2604
  outputResult({ success: true, path: opts.configPath, agent: opts.agentId });
2529
2605
  return { success: true };
2530
2606
  }
2531
- console.log(`${TICK} ${opts.successMessage}`);
2607
+ console.log(`${TICK2} ${opts.successMessage}`);
2532
2608
  }
2533
2609
  return { success: true };
2534
2610
  }
@@ -2819,7 +2895,7 @@ var init_openclaw = __esm(() => {
2819
2895
  if (isJsonMode(json)) {
2820
2896
  return outputResult({ success: true, path: skillPath, agent: "openclaw" });
2821
2897
  }
2822
- console.log(`${TICK} Outlit skill written to ${skillPath}. OpenClaw will load it automatically.`);
2898
+ console.log(`${TICK2} Outlit skill written to ${skillPath}. OpenClaw will load it automatically.`);
2823
2899
  }
2824
2900
  });
2825
2901
  });
@@ -2963,7 +3039,7 @@ var init_setup2 = __esm(() => {
2963
3039
  console.log("Detected agents:");
2964
3040
  for (const agentId of detected) {
2965
3041
  const { label, hint } = agentLabels[agentId];
2966
- console.log(` ${TICK} ${label.padEnd(14)} ${hint}`);
3042
+ console.log(` ${TICK2} ${label.padEnd(14)} -- ${hint}`);
2967
3043
  }
2968
3044
  console.log(`
2969
3045
  Configuring...`);
@@ -3039,7 +3115,7 @@ function checkApiKeyPresence(credential) {
3039
3115
  return {
3040
3116
  name: "API key",
3041
3117
  status: "fail",
3042
- message: `Invalid format expected ok_ prefix, got "${credential.key.slice(0, 3)}..."`,
3118
+ message: `Invalid format -- expected ok_ prefix, got "${credential.key.slice(0, 3)}..."`,
3043
3119
  detail: `Get a valid key at ${OUTLIT_DASHBOARD_URL}`
3044
3120
  };
3045
3121
  }
@@ -3148,7 +3224,7 @@ function printChecks(checks) {
3148
3224
  }
3149
3225
  console.log("");
3150
3226
  }
3151
- var STATUS_ICONS, doctor_default, agentChecks;
3227
+ var FAIL_SYMBOL2, STATUS_ICONS, doctor_default, agentChecks;
3152
3228
  var init_doctor = __esm(() => {
3153
3229
  init_dist();
3154
3230
  init_auth();
@@ -3157,10 +3233,12 @@ var init_doctor = __esm(() => {
3157
3233
  init_config();
3158
3234
  init_output();
3159
3235
  init_setup2();
3236
+ init_tty();
3237
+ FAIL_SYMBOL2 = isUnicodeSupported ? String.fromCodePoint(10007) : "x";
3160
3238
  STATUS_ICONS = {
3161
- pass: TICK,
3239
+ pass: TICK2,
3162
3240
  warn: "\x1B[33m!\x1B[0m",
3163
- fail: "\x1B[31m✗\x1B[0m"
3241
+ fail: `\x1B[31m${FAIL_SYMBOL2}\x1B[0m`
3164
3242
  };
3165
3243
  doctor_default = defineCommand2({
3166
3244
  meta: {
@@ -3169,10 +3247,10 @@ var init_doctor = __esm(() => {
3169
3247
  "Check CLI version, API key, connectivity, and agent detection.",
3170
3248
  "",
3171
3249
  "Runs four checks in sequence:",
3172
- " 1. CLI version compares against npm registry",
3173
- " 2. API key checks presence and format (ok_ prefix)",
3174
- " 3. API validation makes a live test call to verify the key works",
3175
- " 4. Agent detection detects OpenClaw, Cursor, Claude Desktop, VS Code",
3250
+ " 1. CLI version -- compares against npm registry",
3251
+ " 2. API key -- checks presence and format (ok_ prefix)",
3252
+ " 3. API validation -- makes a live test call to verify the key works",
3253
+ " 4. Agent detection -- detects OpenClaw, Cursor, Claude Desktop, VS Code",
3176
3254
  "",
3177
3255
  "Exit code: 0 if all checks pass or warn, 1 if any check fails.",
3178
3256
  "",
@@ -3198,7 +3276,7 @@ var init_doctor = __esm(() => {
3198
3276
  if (credential) {
3199
3277
  checks.push(await validateApiKey(credential.key));
3200
3278
  } else {
3201
- checks.push({ name: "API validation", status: "fail", message: "Skipped no API key found" });
3279
+ checks.push({ name: "API validation", status: "fail", message: "Skipped -- no API key found" });
3202
3280
  }
3203
3281
  checks.push(...detectAgents2());
3204
3282
  const hasFail = checks.some((c) => c.status === "fail");
@@ -3500,47 +3578,334 @@ var exports_completions = {};
3500
3578
  __export(exports_completions, {
3501
3579
  default: () => completions_default
3502
3580
  });
3503
- var COMMANDS, cmdNames, BASH_SCRIPT, zshCommands, ZSH_SCRIPT, FISH_SCRIPT, SCRIPTS, completions_default;
3504
- var init_completions = __esm(() => {
3505
- init_dist();
3506
- init_output2();
3507
- init_output();
3508
- COMMANDS = [
3509
- { name: "auth", desc: "Manage authentication" },
3510
- { name: "customers", desc: "Customer operations" },
3511
- { name: "users", desc: "User operations" },
3512
- { name: "facts", desc: "Get customer facts" },
3513
- { name: "search", desc: "Search customer context" },
3514
- { name: "sql", desc: "Execute SQL queries" },
3515
- { name: "schema", desc: "Discover table schemas" },
3516
- { name: "setup", desc: "Configure AI agent tools" },
3517
- { name: "doctor", desc: "Diagnose environment" },
3518
- { name: "completions", desc: "Generate shell completions" }
3519
- ];
3520
- cmdNames = COMMANDS.map((c) => c.name).join(" ");
3521
- BASH_SCRIPT = `_outlit_completions() {
3581
+ function escZsh(s) {
3582
+ return s.replace(/'/g, "'\\''");
3583
+ }
3584
+ function flagNames(flags) {
3585
+ return flags.map((f) => f.name).join(" ");
3586
+ }
3587
+ function generateBash() {
3588
+ const cmdNames = COMMANDS.map((c) => c.name).join(" ");
3589
+ const subCases = cmdsWithSubs.map((c) => {
3590
+ const names = c.subs.map((s) => s.name).join(" ");
3591
+ const parentFlags = c.flags?.length ? ` ${flagNames(c.flags)}` : "";
3592
+ return ` ${c.name}) COMPREPLY=($(compgen -W "${names}${parentFlags}" -- "$cur")) ;;`;
3593
+ }).join(`
3594
+ `);
3595
+ const flagEntries = [];
3596
+ for (const cmd of leafCmds) {
3597
+ flagEntries.push(` ${cmd.name}) COMPREPLY=($(compgen -W "${flagNames(cmd.flags)}" -- "$cur")) ;;`);
3598
+ }
3599
+ for (const cmd of cmdsWithSubs) {
3600
+ for (const sub of cmd.subs) {
3601
+ if (sub.flags?.length) {
3602
+ flagEntries.push(` ${cmd.name}.${sub.name}) COMPREPLY=($(compgen -W "${flagNames(sub.flags)}" -- "$cur")) ;;`);
3603
+ }
3604
+ }
3605
+ }
3606
+ const flagCases = flagEntries.join(`
3607
+ `);
3608
+ return `_outlit_completions() {
3522
3609
  local cur="\${COMP_WORDS[COMP_CWORD]}"
3523
- COMPREPLY=($(compgen -W "${cmdNames}" -- "$cur"))
3610
+ local cmd="\${COMP_WORDS[1]}"
3611
+ local key
3612
+
3613
+ if [[ $COMP_CWORD -eq 1 ]]; then
3614
+ COMPREPLY=($(compgen -W "${cmdNames}" -- "$cur"))
3615
+ return
3616
+ fi
3617
+
3618
+ case $cmd in
3619
+ ${cmdsWithSubs.map((c) => c.name).join("|")})
3620
+ if [[ $COMP_CWORD -eq 2 ]]; then
3621
+ case $cmd in
3622
+ ${subCases}
3623
+ esac
3624
+ return
3625
+ fi
3626
+ key="\${cmd}.\${COMP_WORDS[2]}"
3627
+ ;;
3628
+ *)
3629
+ key=$cmd
3630
+ ;;
3631
+ esac
3632
+
3633
+ case $key in
3634
+ ${flagCases}
3635
+ esac
3524
3636
  }
3525
3637
  complete -F _outlit_completions outlit
3526
3638
  `;
3527
- zshCommands = COMMANDS.map((c) => `'${c.name}:${c.desc.replace(/:/g, "")}'`).join(" ");
3528
- ZSH_SCRIPT = `#compdef outlit
3639
+ }
3640
+ function zshDescribe(items) {
3641
+ return items.map((c) => `'${escZsh(c.name)}:${escZsh(c.desc)}'`).join(" ");
3642
+ }
3643
+ function generateZsh() {
3644
+ const topLevel = zshDescribe(COMMANDS);
3645
+ const subCases = cmdsWithSubs.map((c) => {
3646
+ const items = [...c.subs.map((s) => ({ name: s.name, desc: s.desc })), ...(c.flags ?? []).map((f) => ({ name: f.name, desc: f.desc }))];
3647
+ return ` ${c.name})
3648
+ completions=(${zshDescribe(items)})
3649
+ _describe 'subcommand' completions
3650
+ ;;`;
3651
+ }).join(`
3652
+ `);
3653
+ const flagEntries = [];
3654
+ for (const cmd of leafCmds) {
3655
+ flagEntries.push(` ${cmd.name})
3656
+ completions=(${zshDescribe(cmd.flags)})
3657
+ _describe 'option' completions
3658
+ ;;`);
3659
+ }
3660
+ for (const cmd of cmdsWithSubs) {
3661
+ for (const sub of cmd.subs) {
3662
+ if (sub.flags?.length) {
3663
+ flagEntries.push(` ${cmd.name}.${sub.name})
3664
+ completions=(${zshDescribe(sub.flags)})
3665
+ _describe 'option' completions
3666
+ ;;`);
3667
+ }
3668
+ }
3669
+ }
3670
+ const flagCases = flagEntries.join(`
3671
+ `);
3672
+ return `#compdef outlit
3529
3673
  _outlit() {
3530
- local -a commands
3531
- commands=(${zshCommands})
3532
- _describe 'command' commands
3674
+ local -a completions
3675
+ local cmd=$words[2]
3676
+ local key
3677
+
3678
+ if (( CURRENT == 2 )); then
3679
+ completions=(${topLevel})
3680
+ _describe 'command' completions
3681
+ return
3682
+ fi
3683
+
3684
+ case $cmd in
3685
+ ${cmdsWithSubs.map((c) => c.name).join("|")})
3686
+ if (( CURRENT == 3 )); then
3687
+ case $cmd in
3688
+ ${subCases}
3689
+ esac
3690
+ return
3691
+ fi
3692
+ key="\${cmd}.$words[3]"
3693
+ ;;
3694
+ *)
3695
+ key=$cmd
3696
+ ;;
3697
+ esac
3698
+
3699
+ case $key in
3700
+ ${flagCases}
3701
+ esac
3533
3702
  }
3534
3703
  compdef _outlit outlit
3535
3704
  `;
3536
- FISH_SCRIPT = `# outlit completions for fish shell
3537
- ${COMMANDS.map((c) => `complete -c outlit -f -a ${c.name} -d "${c.desc.replace(/"/g, "\\\"")}"`).join(`
3538
- `)}
3705
+ }
3706
+ function esc(s) {
3707
+ return s.replace(/"/g, "\\\"");
3708
+ }
3709
+ function generateFish() {
3710
+ const lines = [
3711
+ "# outlit completions for fish shell",
3712
+ "",
3713
+ "# Helper: true when commandline starts with the given subcommand path",
3714
+ "function __outlit_using_cmd",
3715
+ " set -l tokens (commandline -opc)",
3716
+ " set -l n (count $argv)",
3717
+ " if test (count $tokens) -le $n",
3718
+ " return 1",
3719
+ " end",
3720
+ " for i in (seq $n)",
3721
+ ' if test "$tokens[(math $i + 1)]" != "$argv[$i]"',
3722
+ " return 1",
3723
+ " end",
3724
+ " end",
3725
+ " return 0",
3726
+ "end",
3727
+ "",
3728
+ "# Top-level commands"
3729
+ ];
3730
+ for (const c of COMMANDS) {
3731
+ lines.push(`complete -c outlit -f -n '__fish_use_subcommand' -a ${c.name} -d "${esc(c.desc)}"`);
3732
+ }
3733
+ for (const cmd of cmdsWithSubs) {
3734
+ lines.push("");
3735
+ lines.push(`# ${cmd.name} subcommands`);
3736
+ for (const sub of cmd.subs) {
3737
+ lines.push(`complete -c outlit -f -n '__outlit_using_cmd ${cmd.name}' -a ${sub.name} -d "${esc(sub.desc)}"`);
3738
+ }
3739
+ }
3740
+ for (const cmd of leafCmds) {
3741
+ lines.push("");
3742
+ lines.push(`# ${cmd.name} flags`);
3743
+ for (const f of cmd.flags) {
3744
+ const long = f.name.replace(/^--/, "");
3745
+ lines.push(`complete -c outlit -n '__outlit_using_cmd ${cmd.name}' -l ${long} -d "${esc(f.desc)}"`);
3746
+ }
3747
+ }
3748
+ for (const cmd of cmdsWithSubs) {
3749
+ if (cmd.flags?.length) {
3750
+ lines.push("");
3751
+ lines.push(`# ${cmd.name} flags`);
3752
+ for (const f of cmd.flags) {
3753
+ const long = f.name.replace(/^--/, "");
3754
+ lines.push(`complete -c outlit -n '__outlit_using_cmd ${cmd.name}' -l ${long} -d "${esc(f.desc)}"`);
3755
+ }
3756
+ }
3757
+ }
3758
+ for (const cmd of cmdsWithSubs) {
3759
+ for (const sub of cmd.subs) {
3760
+ if (sub.flags?.length) {
3761
+ lines.push("");
3762
+ lines.push(`# ${cmd.name} ${sub.name} flags`);
3763
+ for (const f of sub.flags) {
3764
+ const long = f.name.replace(/^--/, "");
3765
+ lines.push(`complete -c outlit -n '__outlit_using_cmd ${cmd.name} ${sub.name}' -l ${long} -d "${esc(f.desc)}"`);
3766
+ }
3767
+ }
3768
+ }
3769
+ }
3770
+ return lines.join(`
3771
+ `) + `
3539
3772
  `;
3773
+ }
3774
+ var JSON_F, API_KEY_F, LIMIT_F, CURSOR_F, COMMON, PAGINATED, ACTIVITY_ORDER, COMMANDS, cmdsWithSubs, leafCmds, SCRIPTS, completions_default;
3775
+ var init_completions = __esm(() => {
3776
+ init_dist();
3777
+ init_output2();
3778
+ init_output();
3779
+ JSON_F = { name: "--json", desc: "Force JSON output" };
3780
+ API_KEY_F = { name: "--api-key", desc: "Outlit API key" };
3781
+ LIMIT_F = { name: "--limit", desc: "Max results (1-100)" };
3782
+ CURSOR_F = { name: "--cursor", desc: "Pagination cursor" };
3783
+ COMMON = [API_KEY_F, JSON_F];
3784
+ PAGINATED = [...COMMON, LIMIT_F, CURSOR_F];
3785
+ ACTIVITY_ORDER = [
3786
+ { name: "--no-activity-in", desc: "No activity in period" },
3787
+ { name: "--has-activity-in", desc: "Activity in period" },
3788
+ { name: "--order-by", desc: "Sort field" },
3789
+ { name: "--order-direction", desc: "Sort direction (asc, desc)" }
3790
+ ];
3791
+ COMMANDS = [
3792
+ {
3793
+ name: "auth",
3794
+ desc: "Manage authentication",
3795
+ subs: [
3796
+ { name: "signup", desc: "Create an Outlit account", flags: [JSON_F] },
3797
+ { name: "login", desc: "Store API key", flags: [JSON_F, { name: "--key", desc: "API key to store" }] },
3798
+ { name: "logout", desc: "Remove stored key", flags: [JSON_F] },
3799
+ { name: "status", desc: "Check auth state", flags: [...COMMON] },
3800
+ { name: "whoami", desc: "Print masked key", flags: [...COMMON] }
3801
+ ]
3802
+ },
3803
+ {
3804
+ name: "customers",
3805
+ desc: "Customer operations",
3806
+ subs: [
3807
+ {
3808
+ name: "list",
3809
+ desc: "List and filter customers",
3810
+ flags: [
3811
+ ...PAGINATED,
3812
+ ...ACTIVITY_ORDER,
3813
+ { name: "--billing-status", desc: "Filter by billing status" },
3814
+ { name: "--mrr-above", desc: "MRR above threshold (cents)" },
3815
+ { name: "--mrr-below", desc: "MRR below threshold (cents)" },
3816
+ { name: "--search", desc: "Search name or domain" },
3817
+ { name: "--status", desc: "Customer status filter" },
3818
+ { name: "--type", desc: "Customer type filter" }
3819
+ ]
3820
+ },
3821
+ {
3822
+ name: "get",
3823
+ desc: "Get customer by ID or domain",
3824
+ flags: [
3825
+ ...COMMON,
3826
+ { name: "--include", desc: "Sections to include" },
3827
+ { name: "--timeframe", desc: "Metrics timeframe" }
3828
+ ]
3829
+ },
3830
+ {
3831
+ name: "timeline",
3832
+ desc: "Show activity timeline",
3833
+ flags: [
3834
+ ...PAGINATED,
3835
+ { name: "--channels", desc: "Filter by channels" },
3836
+ { name: "--event-types", desc: "Filter by event types" },
3837
+ { name: "--timeframe", desc: "Event timeframe" },
3838
+ { name: "--start-date", desc: "Start date (ISO 8601)" },
3839
+ { name: "--end-date", desc: "End date (ISO 8601)" }
3840
+ ]
3841
+ }
3842
+ ]
3843
+ },
3844
+ {
3845
+ name: "users",
3846
+ desc: "User operations",
3847
+ subs: [
3848
+ {
3849
+ name: "list",
3850
+ desc: "List and filter users",
3851
+ flags: [
3852
+ ...PAGINATED,
3853
+ ...ACTIVITY_ORDER,
3854
+ { name: "--journey-stage", desc: "Filter by journey stage" },
3855
+ { name: "--customer-id", desc: "Filter by customer UUID" },
3856
+ { name: "--search", desc: "Search name or email" }
3857
+ ]
3858
+ }
3859
+ ]
3860
+ },
3861
+ {
3862
+ name: "facts",
3863
+ desc: "Get customer facts",
3864
+ flags: [...PAGINATED, { name: "--timeframe", desc: "Lookback window (7d, 30d, 90d)" }]
3865
+ },
3866
+ {
3867
+ name: "search",
3868
+ desc: "Search customer context",
3869
+ flags: [
3870
+ ...COMMON,
3871
+ { name: "--customer", desc: "Scope to customer (UUID or domain)" },
3872
+ { name: "--top-k", desc: "Max results" },
3873
+ { name: "--after", desc: "Events after date (ISO 8601)" },
3874
+ { name: "--before", desc: "Events before date (ISO 8601)" }
3875
+ ]
3876
+ },
3877
+ {
3878
+ name: "sql",
3879
+ desc: "Execute SQL queries",
3880
+ flags: [
3881
+ ...COMMON,
3882
+ { name: "--query-file", desc: "Path to .sql file" },
3883
+ { name: "--limit", desc: "Max rows to return" }
3884
+ ]
3885
+ },
3886
+ { name: "schema", desc: "Discover table schemas", flags: [...COMMON] },
3887
+ {
3888
+ name: "setup",
3889
+ desc: "Configure AI agent tools",
3890
+ flags: [...COMMON, { name: "--yes", desc: "Skip prompts" }],
3891
+ subs: [
3892
+ { name: "cursor", desc: "Configure Cursor", flags: [...COMMON] },
3893
+ { name: "claude-code", desc: "Configure Claude Code", flags: [...COMMON] },
3894
+ { name: "claude-desktop", desc: "Configure Claude Desktop", flags: [...COMMON] },
3895
+ { name: "vscode", desc: "Configure VS Code", flags: [...COMMON] },
3896
+ { name: "gemini", desc: "Configure Gemini CLI", flags: [...COMMON] },
3897
+ { name: "openclaw", desc: "Configure OpenClaw", flags: [...COMMON] }
3898
+ ]
3899
+ },
3900
+ { name: "doctor", desc: "Diagnose environment", flags: [...COMMON] },
3901
+ { name: "completions", desc: "Generate shell completions", flags: [JSON_F] }
3902
+ ];
3903
+ cmdsWithSubs = COMMANDS.filter((c) => c.subs?.length);
3904
+ leafCmds = COMMANDS.filter((c) => !c.subs?.length && c.flags?.length);
3540
3905
  SCRIPTS = {
3541
- bash: BASH_SCRIPT,
3542
- zsh: ZSH_SCRIPT,
3543
- fish: FISH_SCRIPT
3906
+ bash: generateBash,
3907
+ zsh: generateZsh,
3908
+ fish: generateFish
3544
3909
  };
3545
3910
  completions_default = defineCommand2({
3546
3911
  meta: {
@@ -3570,14 +3935,14 @@ ${COMMANDS.map((c) => `complete -c outlit -f -a ${c.name} -d "${c.desc.replace(/
3570
3935
  run({ args }) {
3571
3936
  const json = !!args.json;
3572
3937
  const shell = args.shell;
3573
- const script = SCRIPTS[shell];
3574
- if (!script) {
3938
+ const generate = SCRIPTS[shell];
3939
+ if (!generate) {
3575
3940
  return outputError({
3576
3941
  message: `Unknown shell: ${shell}. Supported: bash, zsh, fish`,
3577
3942
  code: "unknown_shell"
3578
3943
  }, json);
3579
3944
  }
3580
- process.stdout.write(script);
3945
+ process.stdout.write(generate());
3581
3946
  }
3582
3947
  });
3583
3948
  });
@@ -3690,7 +4055,7 @@ var init_setup3 = __esm(() => {
3690
4055
  console.log("Detected agents:");
3691
4056
  for (const agentId of detected) {
3692
4057
  const { label, hint } = agentLabels2[agentId];
3693
- console.log(` ${TICK} ${label.padEnd(14)} ${hint}`);
4058
+ console.log(` ${TICK2} ${label.padEnd(14)} -- ${hint}`);
3694
4059
  }
3695
4060
  console.log(`
3696
4061
  Configuring...`);
@@ -4066,14 +4431,20 @@ async function runMain(cmd, opts = {}) {
4066
4431
  // src/lib/config.ts
4067
4432
  init_package();
4068
4433
  init_output();
4434
+ init_tty();
4069
4435
  var CLI_VERSION = package_default.version;
4436
+ var TICK = `\x1B[32m${isUnicodeSupported ? String.fromCodePoint(10003) : String.fromCodePoint(8730)}\x1B[0m`;
4070
4437
 
4071
4438
  // src/cli.ts
4439
+ if (process.argv.includes("-v")) {
4440
+ console.log(CLI_VERSION);
4441
+ process.exit(0);
4442
+ }
4072
4443
  var main = defineCommand({
4073
4444
  meta: {
4074
4445
  name: "outlit",
4075
4446
  version: CLI_VERSION,
4076
- description: `Outlit CLI \u2014 customer intelligence from the terminal.
4447
+ description: `Outlit CLI -- customer intelligence from the terminal.
4077
4448
 
4078
4449
  Usage examples:
4079
4450
  outlit customers list --billing-status PAYING --no-activity-in 30d
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@outlit/cli",
3
- "version": "0.1.0",
3
+ "version": "1.0.1",
4
4
  "description": "CLI for Outlit customer intelligence platform",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -13,7 +13,9 @@
13
13
  "access": "public"
14
14
  },
15
15
  "type": "module",
16
- "bin": { "outlit": "./dist/cli.js" },
16
+ "bin": {
17
+ "outlit": "./dist/cli.js"
18
+ },
17
19
  "files": ["dist"],
18
20
  "scripts": {
19
21
  "dev": "bun run src/cli.ts",