@outlit/cli 3.2.0 → 3.2.2

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 +192 -50
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -104,7 +104,7 @@ var package_default;
104
104
  var init_package = __esm(() => {
105
105
  package_default = {
106
106
  name: "@outlit/cli",
107
- version: "3.2.0",
107
+ version: "3.2.2",
108
108
  description: "CLI for querying Outlit customer context and installing agent skills",
109
109
  license: "Apache-2.0",
110
110
  repository: {
@@ -147,7 +147,7 @@ var init_package = __esm(() => {
147
147
  },
148
148
  dependencies: {
149
149
  "@clack/prompts": "^1.0.1",
150
- "@outlit/tools": "^2.2.0",
150
+ "@outlit/tools": "^2.2.1",
151
151
  citty: "^0.2.1"
152
152
  },
153
153
  devDependencies: {
@@ -15776,6 +15776,7 @@ Returns column definitions and example queries for each view.`,
15776
15776
  "TOOL_BINDING_MISSING",
15777
15777
  "TOOL_IMPLEMENTATION_ERROR",
15778
15778
  "TOOL_OUTPUT_INVALID",
15779
+ "TOOL_RESOURCE_NOT_FOUND",
15779
15780
  "TOOL_RESULT_TOO_LARGE",
15780
15781
  "TOOL_GATEWAY_ERROR",
15781
15782
  "plan_api_limit_exceeded",
@@ -19251,6 +19252,15 @@ function readCommandOutput2(command, args) {
19251
19252
  return null;
19252
19253
  }
19253
19254
  }
19255
+ function isStandaloneInstall2(argv = process.argv) {
19256
+ const scriptPath = argv[1];
19257
+ if (!scriptPath)
19258
+ return true;
19259
+ if (scriptPath.startsWith("/$bunfs/") || scriptPath.startsWith("~bunfs"))
19260
+ return true;
19261
+ const resolved = safeRealPath2(scriptPath) ?? scriptPath;
19262
+ return !/\.(?:cjs|mjs|jsx?|tsx?)$/.test(resolved);
19263
+ }
19254
19264
  function inferInstaller2() {
19255
19265
  const fromAgent = inferInstallerFromUserAgent2(process.env.npm_config_user_agent ?? "");
19256
19266
  if (fromAgent)
@@ -19273,8 +19283,11 @@ function safeRealPath2(filePath) {
19273
19283
  return null;
19274
19284
  }
19275
19285
  }
19276
- function formatUpdateCommand2(installer = inferInstaller2()) {
19277
- switch (installer) {
19286
+ function formatUpdateCommand2(installer, argv = process.argv) {
19287
+ if (isStandaloneInstall2(argv))
19288
+ return STANDALONE_UPDATE_HINT2;
19289
+ const resolved = installer === undefined ? inferInstaller2() : installer;
19290
+ switch (resolved) {
19278
19291
  case "bun":
19279
19292
  return "bun add -g @outlit/cli";
19280
19293
  case "npm":
@@ -19326,15 +19339,16 @@ async function fetchLatestCliVersion2() {
19326
19339
  throw new Error("registry returned no version");
19327
19340
  return data.version;
19328
19341
  }
19329
- function runUpgradeCommand(command) {
19330
- const result = spawnSync2(command.command, command.args, { stdio: "inherit" });
19342
+ function runUpgradeCommand(command, opts) {
19343
+ const stdio = opts?.stdoutToStderr ? ["ignore", process.stderr, process.stderr] : "inherit";
19344
+ const result = spawnSync2(command.command, command.args, { stdio });
19331
19345
  if (result.error)
19332
19346
  throw result.error;
19333
19347
  if (result.status !== 0 || result.signal) {
19334
19348
  throw new Error(`Upgrade command failed: ${command.displayCommand}`);
19335
19349
  }
19336
19350
  }
19337
- var UPDATE_CHECK_INTERVAL_MS2, PACKAGE_NAME2 = "@outlit/cli", LATEST_VERSION_URL2 = "https://registry.npmjs.org/@outlit%2Fcli/latest";
19351
+ var UPDATE_CHECK_INTERVAL_MS2, PACKAGE_NAME2 = "@outlit/cli", LATEST_VERSION_URL2 = "https://registry.npmjs.org/@outlit%2Fcli/latest", STANDALONE_UPDATE_HINT2 = "re-run your original install method (for example `curl -fsSL https://outlit.ai/install.sh | bash` or `brew upgrade outlitai/tap/outlit`), or download the latest release from https://github.com/OutlitAI/outlit-sdk/releases";
19338
19352
  var init_update2 = __esm(() => {
19339
19353
  init_config();
19340
19354
  init_tty();
@@ -19695,26 +19709,77 @@ function checkApiKeyPresence(credential) {
19695
19709
  }
19696
19710
  async function validateApiKey(apiKey) {
19697
19711
  try {
19698
- await pingApiKey(apiKey);
19699
- return { name: "API validation", status: "pass", message: "Key is valid" };
19712
+ const validation = await pingApiKey(apiKey);
19713
+ const org = validation.organization?.name ?? validation.organization?.slug ?? validation.organizationId;
19714
+ const keyDetail = validation.apiKey ? ` · key "${validation.apiKey.name}" (${validation.apiKey.keyType})` : "";
19715
+ return {
19716
+ check: {
19717
+ name: "API validation",
19718
+ status: "pass",
19719
+ message: "Key is valid",
19720
+ detail: `Org: ${org}${keyDetail}`
19721
+ },
19722
+ validation
19723
+ };
19700
19724
  } catch (err) {
19701
19725
  if (isApiKeyValidationUnavailableError(err)) {
19702
19726
  return {
19703
- name: "API validation",
19704
- status: "warn",
19705
- message: "API validation is temporarily unavailable",
19706
- detail: "Try again shortly"
19727
+ check: {
19728
+ name: "API validation",
19729
+ status: "warn",
19730
+ message: "API validation is temporarily unavailable",
19731
+ detail: "Try again shortly"
19732
+ },
19733
+ validation: null
19707
19734
  };
19708
19735
  }
19709
19736
  return {
19710
- name: "API validation",
19711
- status: "fail",
19712
- message: `API rejected key: ${errorMessage(err, "unknown error")}`,
19713
- detail: `Check your key at ${OUTLIT_DASHBOARD_URL}`
19737
+ check: {
19738
+ name: "API validation",
19739
+ status: "fail",
19740
+ message: `API rejected key: ${errorMessage(err, "unknown error")}`,
19741
+ detail: `Check your key at ${OUTLIT_DASHBOARD_URL}`
19742
+ },
19743
+ validation: null
19714
19744
  };
19715
19745
  }
19716
19746
  }
19717
- async function checkIntegrations(apiKey) {
19747
+ function grantUsable(grant, grants, createdById) {
19748
+ if (!grants.includes(grant))
19749
+ return false;
19750
+ if (grant === "integrations:connect_own" && !createdById)
19751
+ return false;
19752
+ return true;
19753
+ }
19754
+ function checkPermissions(validation) {
19755
+ const grants = validation.authorization.grants;
19756
+ const createdById = validation.createdById?.trim() || null;
19757
+ const unavailable = COMMAND_GRANTS.filter((family) => !family.anyOf.some((grant) => grantUsable(grant, grants, createdById)));
19758
+ const detail = [
19759
+ grants.length > 0 ? `grants: ${grants.join(", ")}` : null,
19760
+ unavailable.length > 0 ? `unavailable to this key: ${unavailable.map((family) => family.commands).join("; ")}` : null
19761
+ ].filter((part) => part !== null).join(" · ");
19762
+ return {
19763
+ name: "Permissions",
19764
+ status: unavailable.length > 0 ? "warn" : "pass",
19765
+ message: `${grants.length} key grant${grants.length === 1 ? "" : "s"}`,
19766
+ detail: detail || undefined
19767
+ };
19768
+ }
19769
+ async function checkIntegrations(apiKey, validation) {
19770
+ const grants = validation?.authorization.grants;
19771
+ if (grants) {
19772
+ const createdById = validation?.createdById?.trim() || null;
19773
+ const canRead = grantUsable("integrations:manage", grants, createdById) || grantUsable("integrations:connect_own", grants, createdById);
19774
+ if (!canRead) {
19775
+ return {
19776
+ name: "Integrations",
19777
+ status: "warn",
19778
+ message: "API key does not grant integrations access",
19779
+ detail: "Requires the integrations:manage grant, or integrations:connect_own on a user-created key"
19780
+ };
19781
+ }
19782
+ }
19718
19783
  try {
19719
19784
  const client = await createClient(apiKey);
19720
19785
  const timeout = new Promise((_2, reject) => setTimeout(() => reject(new Error("Integrations check timed out")), 1e4));
@@ -19746,7 +19811,15 @@ async function checkIntegrations(apiKey) {
19746
19811
  status: "pass",
19747
19812
  message: `${ready} integration(s) ready`
19748
19813
  };
19749
- } catch {
19814
+ } catch (err) {
19815
+ if (isOutlitToolsApiError(err) && err.envelope?.code === "TOOL_CALL_FORBIDDEN") {
19816
+ return {
19817
+ name: "Integrations",
19818
+ status: "warn",
19819
+ message: "API key was denied integrations access",
19820
+ detail: "Requires the integrations:manage grant, or integrations:connect_own on a user-created key"
19821
+ };
19822
+ }
19750
19823
  return {
19751
19824
  name: "Integrations",
19752
19825
  status: "warn",
@@ -19834,8 +19907,9 @@ function printChecks(checks) {
19834
19907
  }
19835
19908
  console.log("");
19836
19909
  }
19837
- var FAIL_SYMBOL2, STATUS_ICONS, doctor_default, agentChecks;
19910
+ var FAIL_SYMBOL2, STATUS_ICONS, doctor_default, COMMAND_GRANTS, agentChecks;
19838
19911
  var init_doctor = __esm(() => {
19912
+ init_dist4();
19839
19913
  init_dist();
19840
19914
  init_auth();
19841
19915
  init_output2();
@@ -19858,11 +19932,13 @@ var init_doctor = __esm(() => {
19858
19932
  description: [
19859
19933
  "Check CLI version, API key, connectivity, and agent detection.",
19860
19934
  "",
19861
- "Runs four checks in sequence:",
19935
+ "Runs six checks in sequence:",
19862
19936
  " 1. CLI version -- compares against npm registry",
19863
19937
  " 2. API key -- checks presence and format (ok_ prefix)",
19864
19938
  " 3. API validation -- makes a live test call to verify the key works",
19865
- " 4. Agent detection -- detects supported coding agents and whether the Outlit skill is installed",
19939
+ " 4. Permissions -- shows key grants and unavailable commands",
19940
+ " 5. Integrations -- checks integration readiness or explains missing access",
19941
+ " 6. Agent detection -- detects supported coding agents and whether the Outlit skill is installed",
19866
19942
  "",
19867
19943
  "Exit code: 0 if all checks pass or warn, 1 if any check fails.",
19868
19944
  "",
@@ -19887,9 +19963,12 @@ var init_doctor = __esm(() => {
19887
19963
  checks.push(checkApiKeyPresence(credential));
19888
19964
  if (credential) {
19889
19965
  const apiCheck = await validateApiKey(credential.key);
19890
- checks.push(apiCheck);
19891
- if (apiCheck.status !== "fail") {
19892
- checks.push(await checkIntegrations(credential.key));
19966
+ checks.push(apiCheck.check);
19967
+ if (apiCheck.validation) {
19968
+ checks.push(checkPermissions(apiCheck.validation));
19969
+ }
19970
+ if (apiCheck.check.status !== "fail") {
19971
+ checks.push(await checkIntegrations(credential.key, apiCheck.validation));
19893
19972
  }
19894
19973
  } else {
19895
19974
  checks.push({
@@ -19909,6 +19988,38 @@ var init_doctor = __esm(() => {
19909
19988
  process.exit(1);
19910
19989
  }
19911
19990
  });
19991
+ COMMAND_GRANTS = [
19992
+ {
19993
+ commands: "customers (read), users, facts, sources, search, attention",
19994
+ anyOf: ["customer_intelligence:read"]
19995
+ },
19996
+ { commands: "ws-users", anyOf: ["workspace_members:read"] },
19997
+ { commands: "sql, schema", anyOf: ["analytics:read"] },
19998
+ { commands: "destinations", anyOf: ["destinations:manage"] },
19999
+ { commands: "features", anyOf: ["behavior_metrics:manage"] },
20000
+ {
20001
+ commands: "integrations",
20002
+ anyOf: ["integrations:manage", "integrations:connect_own"]
20003
+ },
20004
+ { commands: "activation get, preview", anyOf: ["activation:read"] },
20005
+ { commands: "activation update, disable", anyOf: ["activation:manage"] },
20006
+ { commands: "settings get", anyOf: ["workspace_settings:read"] },
20007
+ { commands: "settings update", anyOf: ["workspace_settings:manage"] },
20008
+ { commands: "customers grant, revoke, owner", anyOf: ["customer_access:manage"] },
20009
+ {
20010
+ commands: "identity suggestions list",
20011
+ anyOf: ["customer_intelligence:read"]
20012
+ },
20013
+ {
20014
+ commands: "identity suggestions reject",
20015
+ anyOf: ["customer_identity:review"]
20016
+ },
20017
+ {
20018
+ commands: "customers merge (preview), customers merge-status",
20019
+ anyOf: ["customer_intelligence:read"]
20020
+ },
20021
+ { commands: "customers merge --execute", anyOf: ["customer_identity:merge"] }
20022
+ ];
19912
20023
  agentChecks = {
19913
20024
  "claude-code": {
19914
20025
  name: "Claude Code",
@@ -19949,6 +20060,7 @@ __export(exports_upgrade, {
19949
20060
  var upgrade_default;
19950
20061
  var init_upgrade = __esm(() => {
19951
20062
  init_dist();
20063
+ init_output2();
19952
20064
  init_config();
19953
20065
  init_output();
19954
20066
  init_update2();
@@ -19960,20 +20072,16 @@ var init_upgrade = __esm(() => {
19960
20072
  "",
19961
20073
  "Checks npm for the latest published version first.",
19962
20074
  "If the current version is already latest, no install command is run.",
20075
+ "Standalone binaries cannot self-update; they get manual-update guidance instead.",
19963
20076
  "",
19964
20077
  "Examples:",
19965
20078
  " outlit upgrade"
19966
20079
  ].join(`
19967
20080
  `)
19968
20081
  },
19969
- async run() {
19970
- const upgradeCommand = getUpgradeCommand();
19971
- if (!upgradeCommand) {
19972
- return outputError({
19973
- 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`.",
19974
- code: "unknown_installer"
19975
- }, false);
19976
- }
20082
+ args: { ...outputArgs },
20083
+ async run({ args }) {
20084
+ const json = !!args.json;
19977
20085
  let latestVersion;
19978
20086
  try {
19979
20087
  latestVersion = await fetchLatestCliVersion2();
@@ -19981,20 +20089,38 @@ var init_upgrade = __esm(() => {
19981
20089
  return outputError({
19982
20090
  message: "Could not check for CLI updates. Try again later or update manually.",
19983
20091
  code: "update_check_failed"
19984
- }, false);
20092
+ }, json);
19985
20093
  }
19986
20094
  if (compareVersions2(CLI_VERSION2, latestVersion) >= 0) {
20095
+ const result2 = { status: "current", currentVersion: CLI_VERSION2, latestVersion };
20096
+ if (isJsonMode(json))
20097
+ return outputResult(result2);
19987
20098
  console.log(`Outlit CLI is already up to date (v${CLI_VERSION2})`);
19988
20099
  return;
19989
20100
  }
20101
+ const standalone = isStandaloneInstall2();
20102
+ const upgradeCommand = standalone ? null : getUpgradeCommand();
20103
+ if (!upgradeCommand) {
20104
+ const message = standalone ? `Outlit CLI v${latestVersion} is available. This standalone binary cannot update itself — ${STANDALONE_UPDATE_HINT2}.` : `Outlit CLI v${latestVersion} is available. 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\`.`;
20105
+ return outputError({ message, code: standalone ? "manual_update_required" : "unknown_installer" }, json);
20106
+ }
19990
20107
  try {
19991
- runUpgradeCommand(upgradeCommand);
20108
+ runUpgradeCommand(upgradeCommand, { stdoutToStderr: isJsonMode(json) });
19992
20109
  } catch (err) {
19993
20110
  return outputError({
19994
20111
  message: errorMessage(err, `Failed to run ${upgradeCommand.displayCommand}`),
19995
20112
  code: "upgrade_failed"
19996
- }, false);
20113
+ }, json);
19997
20114
  }
20115
+ const result = {
20116
+ status: "updated",
20117
+ currentVersion: CLI_VERSION2,
20118
+ latestVersion,
20119
+ command: upgradeCommand.displayCommand
20120
+ };
20121
+ if (isJsonMode(json))
20122
+ return outputResult(result);
20123
+ console.log(`Updated Outlit CLI to v${latestVersion}`);
19998
20124
  }
19999
20125
  });
20000
20126
  });
@@ -23452,6 +23578,7 @@ var UPDATE_CHECK_INTERVAL_MS = 12 * 60 * 60 * 1000;
23452
23578
  var PACKAGE_NAME = "@outlit/cli";
23453
23579
  var LATEST_VERSION_URL = "https://registry.npmjs.org/@outlit%2Fcli/latest";
23454
23580
  var INTERNAL_UPDATE_FLAG = "--internal-update-check";
23581
+ var STANDALONE_UPDATE_HINT = "re-run your original install method (for example `curl -fsSL https://outlit.ai/install.sh | bash` or `brew upgrade outlitai/tap/outlit`), or download the latest release from https://github.com/OutlitAI/outlit-sdk/releases";
23455
23582
  function getUpdateCachePath() {
23456
23583
  return join2(getConfigDir(), "update-check.json");
23457
23584
  }
@@ -23538,6 +23665,15 @@ function readCommandOutput(command, args) {
23538
23665
  return null;
23539
23666
  }
23540
23667
  }
23668
+ function isStandaloneInstall(argv = process.argv) {
23669
+ const scriptPath = argv[1];
23670
+ if (!scriptPath)
23671
+ return true;
23672
+ if (scriptPath.startsWith("/$bunfs/") || scriptPath.startsWith("~bunfs"))
23673
+ return true;
23674
+ const resolved = safeRealPath(scriptPath) ?? scriptPath;
23675
+ return !/\.(?:cjs|mjs|jsx?|tsx?)$/.test(resolved);
23676
+ }
23541
23677
  function inferInstaller() {
23542
23678
  const fromAgent = inferInstallerFromUserAgent(process.env.npm_config_user_agent ?? "");
23543
23679
  if (fromAgent)
@@ -23560,8 +23696,11 @@ function safeRealPath(filePath) {
23560
23696
  return null;
23561
23697
  }
23562
23698
  }
23563
- function formatUpdateCommand(installer = inferInstaller()) {
23564
- switch (installer) {
23699
+ function formatUpdateCommand(installer, argv = process.argv) {
23700
+ if (isStandaloneInstall(argv))
23701
+ return STANDALONE_UPDATE_HINT;
23702
+ const resolved = installer === undefined ? inferInstaller() : installer;
23703
+ switch (resolved) {
23565
23704
  case "bun":
23566
23705
  return "bun add -g @outlit/cli";
23567
23706
  case "npm":
@@ -23603,26 +23742,29 @@ function printCachedUpdateNotice(argv = process.argv, notify = console.error) {
23603
23742
  Update with: ${notice.command}`);
23604
23743
  return true;
23605
23744
  }
23606
- function scheduleBackgroundUpdateCheck(argv = process.argv, spawnProcess = spawn) {
23745
+ function scheduleBackgroundUpdateCheck(argv = process.argv, spawnProcess = spawn, execPath = process.execPath) {
23607
23746
  if (!shouldShowUpdateNotice(argv))
23608
23747
  return false;
23609
23748
  if (!isUpdateCheckDue(readCachedUpdateState()))
23610
23749
  return false;
23611
- const runtimePath = argv[0];
23612
- const scriptPath = argv[1];
23613
- if (!runtimePath || !scriptPath)
23750
+ const standalone = isStandaloneInstall(argv);
23751
+ const command = standalone ? execPath : argv[0];
23752
+ const scriptPath = standalone ? null : argv[1];
23753
+ if (!command || !standalone && !scriptPath)
23614
23754
  return false;
23615
- const child = spawnProcess(runtimePath, [scriptPath, INTERNAL_UPDATE_FLAG], {
23616
- detached: true,
23617
- stdio: "ignore"
23618
- });
23619
- child.unref?.();
23620
- return true;
23755
+ try {
23756
+ const child = spawnProcess(command, [...scriptPath ? [scriptPath] : [], INTERNAL_UPDATE_FLAG], { detached: true, stdio: "ignore" });
23757
+ child.on?.("error", () => {});
23758
+ child.unref?.();
23759
+ return true;
23760
+ } catch {
23761
+ return false;
23762
+ }
23621
23763
  }
23622
23764
  function initializeUpdateNotifier(opts) {
23623
23765
  const argv = opts?.argv ?? process.argv;
23624
23766
  printCachedUpdateNotice(argv, opts?.notify);
23625
- scheduleBackgroundUpdateCheck(argv, opts?.spawn);
23767
+ scheduleBackgroundUpdateCheck(argv, opts?.spawn, opts?.execPath);
23626
23768
  }
23627
23769
  async function fetchLatestCliVersion() {
23628
23770
  const response = await fetch(LATEST_VERSION_URL, { signal: AbortSignal.timeout(5000) });
@@ -23635,7 +23777,7 @@ async function fetchLatestCliVersion() {
23635
23777
  }
23636
23778
  async function runInternalUpdateCheck(opts) {
23637
23779
  const fetchLatestVersion = opts?.fetchLatestVersion ?? fetchLatestCliVersion;
23638
- const installer = opts?.installer ?? inferInstaller();
23780
+ const installer = isStandaloneInstall() ? null : opts?.installer ?? inferInstaller();
23639
23781
  try {
23640
23782
  const latestVersion = await fetchLatestVersion();
23641
23783
  writeCachedUpdateState({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@outlit/cli",
3
- "version": "3.2.0",
3
+ "version": "3.2.2",
4
4
  "description": "CLI for querying Outlit customer context and installing agent skills",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -43,7 +43,7 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "@clack/prompts": "^1.0.1",
46
- "@outlit/tools": "^2.2.0",
46
+ "@outlit/tools": "^2.2.1",
47
47
  "citty": "^0.2.1"
48
48
  },
49
49
  "devDependencies": {