@intercom/cli 0.1.1 → 0.2.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/index.js CHANGED
@@ -1,105 +1,22 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ AuthError,
4
+ CLIError,
5
+ NotFoundError,
6
+ PermissionError,
7
+ RateLimitError,
8
+ TimeoutError,
9
+ applyJq,
10
+ detectAuthType,
11
+ formatJson
12
+ } from "./chunk-QEXGKXTU.js";
2
13
 
3
14
  // src/index.ts
4
15
  import { Command } from "commander";
5
16
 
6
- // src/types.ts
7
- var CLIError = class extends Error {
8
- constructor(message, exitCode = 1, error) {
9
- super(message);
10
- this.exitCode = exitCode;
11
- this.error = error;
12
- this.name = "CLIError";
13
- }
14
- };
15
- var AuthError = class extends CLIError {
16
- constructor(message) {
17
- super(message, 2);
18
- }
19
- };
20
- var RateLimitError = class extends CLIError {
21
- constructor(message, retryAfter) {
22
- super(message, 3);
23
- this.retryAfter = retryAfter;
24
- }
25
- };
26
- var NotFoundError = class extends CLIError {
27
- constructor(message) {
28
- super(message, 4);
29
- }
30
- };
31
- var PermissionError = class extends CLIError {
32
- constructor(message) {
33
- super(message, 5);
34
- }
35
- };
36
- var TimeoutError = class extends CLIError {
37
- constructor(message) {
38
- super(message, 6);
39
- }
40
- };
41
- function detectAuthType(token) {
42
- try {
43
- const decoded = Buffer.from(token, "base64").toString("utf-8");
44
- if (decoded.startsWith("tok:")) {
45
- return "oauth";
46
- }
47
- } catch {
48
- }
49
- return "api_key";
50
- }
51
-
52
- // src/output/json.ts
53
- function formatJson(data) {
54
- return JSON.stringify(data, null, 2);
55
- }
56
- function applyJq(data, expr) {
57
- if (expr === ".") return data;
58
- if (!expr.startsWith(".")) {
59
- throw new CLIError(
60
- `Unsupported jq expression: "${expr}". Supported: ".", ".field", ".field.nested", ".field[].nested"`
61
- );
62
- }
63
- if (/[|(){},;]/.test(expr)) {
64
- throw new CLIError(
65
- `Unsupported jq expression: "${expr}". Supported: ".", ".field", ".field.nested", ".field[].nested"`
66
- );
67
- }
68
- const parts = expr.replace(/^\.\s*/, "").split(/\./).filter(Boolean);
69
- for (const part of parts) {
70
- if (!/^\w+(\[\])?$/.test(part)) {
71
- throw new CLIError(
72
- `Unsupported jq expression: "${expr}". Supported: ".", ".field", ".field.nested", ".field[].nested"`
73
- );
74
- }
75
- }
76
- let current = data;
77
- for (const part of parts) {
78
- const arrayMatch = part.match(/^(\w+)\[\]$/);
79
- if (arrayMatch) {
80
- const key = arrayMatch[1];
81
- if (current && typeof current === "object" && key in current) {
82
- const arr = current[key];
83
- if (!Array.isArray(arr)) return void 0;
84
- current = arr;
85
- } else {
86
- return void 0;
87
- }
88
- } else if (Array.isArray(current)) {
89
- current = current.map(
90
- (item) => item && typeof item === "object" ? item[part] : void 0
91
- );
92
- } else if (current && typeof current === "object") {
93
- current = current[part];
94
- } else {
95
- return void 0;
96
- }
97
- }
98
- return current;
99
- }
100
-
101
17
  // src/api/timeouts.ts
102
18
  var API_TIMEOUT_MS = 3e4;
19
+ var SIMULATION_POLL_TIMEOUT_MS = 6e5;
103
20
 
104
21
  // src/version.ts
105
22
  import { createRequire } from "module";
@@ -629,6 +546,20 @@ function render(data, opts, humanRenderer, listItems) {
629
546
  console.log(formatJson(data));
630
547
  return;
631
548
  }
549
+ if (opts.agent) {
550
+ if (listItems) {
551
+ for (const item of listItems) {
552
+ console.log(JSON.stringify(item));
553
+ }
554
+ } else {
555
+ console.log(JSON.stringify(data));
556
+ }
557
+ return;
558
+ }
559
+ if (opts.human) {
560
+ console.log(humanRenderer());
561
+ return;
562
+ }
632
563
  if (!process.stdout.isTTY) {
633
564
  if (listItems) {
634
565
  for (const item of listItems) {
@@ -673,7 +604,15 @@ function parseTypedFields(fields, typed) {
673
604
 
674
605
  // src/commands/api.ts
675
606
  function registerApiCommand(program) {
676
- program.command("api").description("Make an authenticated API request (like gh api)").argument("<endpoint>", "API endpoint path (e.g., /articles)").option("-X, --method <method>", "HTTP method").option("-f, --field <key=value...>", "String field").option(
607
+ program.command("api").description("Make an authenticated API request (like gh api)").argument("<endpoint>", "API endpoint path (e.g., /articles)").addHelpText(
608
+ "after",
609
+ `
610
+ Examples:
611
+ intercom api /me
612
+ intercom api /articles --paginate
613
+ intercom api /contacts -X POST -f email=test@example.com -f role=user
614
+ intercom api /articles/123 --jq '.title'`
615
+ ).option("-X, --method <method>", "HTTP method").option("-f, --field <key=value...>", "String field").option(
677
616
  "-F, --typed-field <key=value...>",
678
617
  "Typed field (bools, numbers, file reads)"
679
618
  ).option("--jq <expr>", "Filter response with jq expression").option("--json", "Output as JSON").option("--paginate", "Auto-paginate through all pages").option("--verbose", "Show full HTTP request/response").action(async function(endpoint) {
@@ -828,7 +767,6 @@ async function signup(options) {
828
767
  email_submission: {},
829
768
  sign_up_locale: "en",
830
769
  new_app_feature_flags: [
831
- "synchronously-create-subscription-on-signup",
832
770
  "fin-sdk",
833
771
  "messenger-public-api"
834
772
  ]
@@ -929,6 +867,13 @@ async function findOrCreateAppPackage(baseUrl, cookies, appId, appPackageId, tim
929
867
  { timeoutMs }
930
868
  );
931
869
  if (!listResponse.ok) {
870
+ if (listResponse.status === 403) {
871
+ throw new Error(
872
+ `Developer Hub access denied (403). This usually means the admin email has not been verified.
873
+ Verify your email first: intercom auth verify-email --url <url-from-verification-email>
874
+ Then retry this command.`
875
+ );
876
+ }
932
877
  throw new Error(`Failed to list app packages: ${listResponse.status}`);
933
878
  }
934
879
  const data = await listResponse.json();
@@ -970,6 +915,13 @@ async function findOrCreateAppPackage(baseUrl, cookies, appId, appPackageId, tim
970
915
  { timeoutMs }
971
916
  );
972
917
  if (!createResponse.ok) {
918
+ if (createResponse.status === 403) {
919
+ throw new Error(
920
+ `Developer Hub access denied (403). This usually means the admin email has not been verified.
921
+ Verify your email first: intercom auth verify-email --url <url-from-verification-email>
922
+ Then retry this command.`
923
+ );
924
+ }
973
925
  throw new Error(`Failed to create app package: ${createResponse.status}`);
974
926
  }
975
927
  const created = await createResponse.json();
@@ -1244,7 +1196,14 @@ function registerVerifyEmailCommand(auth) {
1244
1196
 
1245
1197
  // src/commands/auth/index.ts
1246
1198
  function registerAuthCommand(program) {
1247
- const auth = program.command("auth").description("Manage authentication credentials");
1199
+ const auth = program.command("auth").description("Manage authentication credentials").addHelpText(
1200
+ "after",
1201
+ `
1202
+ Examples:
1203
+ intercom auth login --token <api-token>
1204
+ intercom auth status
1205
+ intercom auth logout`
1206
+ );
1248
1207
  registerLoginCommand(auth);
1249
1208
  registerBootstrapCommand(auth);
1250
1209
  registerStatusCommand(auth);
@@ -1286,7 +1245,16 @@ function htmlToText(html) {
1286
1245
 
1287
1246
  // src/commands/articles.ts
1288
1247
  function registerArticlesCommand(program) {
1289
- const articles = program.command("articles").description("Manage help center articles");
1248
+ const articles = program.command("articles").description("Manage help center articles").addHelpText(
1249
+ "after",
1250
+ `
1251
+ Examples:
1252
+ intercom articles list
1253
+ intercom articles get 123
1254
+ intercom articles create -f title="Getting Started" -F body=@article.md
1255
+ intercom articles update 123 -f state=published
1256
+ intercom articles delete 123`
1257
+ );
1290
1258
  articles.command("list").description("List help center articles").option("--json", "Output as JSON").option("--jq <expr>", "Filter JSON output with jq expression").option("--verbose", "Show HTTP request/response details").option("--limit <n>", "Max results to return", "25").option("--all", "Auto-paginate all pages").action(async function() {
1291
1259
  const opts = this.optsWithGlobals();
1292
1260
  const client = await resolveClient(opts);
@@ -1409,7 +1377,15 @@ ${body}` : meta;
1409
1377
 
1410
1378
  // src/commands/contacts.ts
1411
1379
  function registerContactsCommand(program) {
1412
- const contacts = program.command("contacts").description("Manage contacts");
1380
+ const contacts = program.command("contacts").description("Manage contacts").addHelpText(
1381
+ "after",
1382
+ `
1383
+ Examples:
1384
+ intercom contacts list --limit 10
1385
+ intercom contacts get abc123
1386
+ intercom contacts create -f email=user@example.com -f role=user
1387
+ intercom contacts delete abc123`
1388
+ );
1413
1389
  contacts.command("list").description("List contacts").option("--json", "Output as JSON").option("--jq <expr>", "Filter JSON output with jq expression").option("--verbose", "Show HTTP request/response details").option("--limit <n>", "Max results to return", "25").option("--all", "Auto-paginate all pages").action(async function() {
1414
1390
  const opts = this.optsWithGlobals();
1415
1391
  const client = await resolveClient(opts);
@@ -1586,7 +1562,14 @@ function renderConversationStream(result) {
1586
1562
  return parts.join("\n");
1587
1563
  }
1588
1564
  function registerConversationsCommand(program) {
1589
- const conversations = program.command("conversations").description("Manage conversations");
1565
+ const conversations = program.command("conversations").description("Manage conversations").addHelpText(
1566
+ "after",
1567
+ `
1568
+ Examples:
1569
+ intercom conversations list
1570
+ intercom conversations get 123
1571
+ intercom conversations reply 123 -f body="Thanks!" -f message_type=comment -f type=admin -f admin_id=456`
1572
+ );
1590
1573
  conversations.command("list").description("List conversations").option("--json", "Output as JSON").option("--jq <expr>", "Filter JSON output with jq expression").option("--verbose", "Show HTTP request/response details").option("--limit <n>", "Max results to return", "25").option("--all", "Auto-paginate all pages").action(async function() {
1591
1574
  const opts = this.optsWithGlobals();
1592
1575
  const client = await resolveClient(opts);
@@ -1657,7 +1640,14 @@ function registerConversationsCommand(program) {
1657
1640
 
1658
1641
  // src/commands/help-center.ts
1659
1642
  function registerHelpCenterCommand(program) {
1660
- const helpCenter = program.command("help-center").description("Manage help center collections");
1643
+ const helpCenter = program.command("help-center").description("Manage help center collections").addHelpText(
1644
+ "after",
1645
+ `
1646
+ Examples:
1647
+ intercom help-center list
1648
+ intercom help-center get 123
1649
+ intercom help-center create -f name="FAQ"`
1650
+ );
1661
1651
  helpCenter.command("list").description("List help center collections").option("--json", "Output as JSON").option("--jq <expr>", "Filter JSON output with jq expression").option("--verbose", "Show HTTP request/response details").option("--limit <n>", "Max results to return", "25").option("--all", "Auto-paginate all pages").action(async function() {
1662
1652
  const opts = this.optsWithGlobals();
1663
1653
  const client = await resolveClient(opts);
@@ -1752,7 +1742,14 @@ export function IntercomWidget() {
1752
1742
  }`;
1753
1743
  }
1754
1744
  function registerMessengerCommand(program) {
1755
- const messenger = program.command("messenger").description("Manage Intercom Messenger settings");
1745
+ const messenger = program.command("messenger").description("Manage Intercom Messenger settings").addHelpText(
1746
+ "after",
1747
+ `
1748
+ Examples:
1749
+ intercom messenger get
1750
+ intercom messenger update -f alignment=right -f theme_mode=dark
1751
+ intercom messenger snippet --format react`
1752
+ );
1756
1753
  messenger.command("get").description("Get Messenger settings").option("--json", "Output as JSON").option("--jq <expr>", "Filter JSON output with jq expression").option("--verbose", "Show HTTP request/response details").action(async function() {
1757
1754
  const opts = this.optsWithGlobals();
1758
1755
  const client = await resolveClient(opts);
@@ -1819,6 +1816,111 @@ function registerMessengerCommand(program) {
1819
1816
  });
1820
1817
  }
1821
1818
 
1819
+ // src/commands/fin.ts
1820
+ import { writeFile as writeFile2 } from "fs/promises";
1821
+
1822
+ // src/commands/fin/procedures.ts
1823
+ import { readFile as readFile2 } from "fs/promises";
1824
+ import { basename } from "path";
1825
+ import AdmZip from "adm-zip";
1826
+ function registerProceduresCommand(fin) {
1827
+ const procedures = fin.command("procedures").description("Manage Fin SDK procedures");
1828
+ procedures.command("list").description("List procedures from the Fin SDK manifest").option("--json", "Output as JSON").option("--verbose", "Show HTTP request/response details").action(async function() {
1829
+ const opts = this.optsWithGlobals();
1830
+ const client = await resolveClient(opts);
1831
+ const result = await client.get("/fin-sdk/manifest");
1832
+ const manifest = result;
1833
+ const items = manifest.procedures ?? [];
1834
+ render(items, opts, () => {
1835
+ if (items.length === 0) {
1836
+ return "No procedures found.";
1837
+ }
1838
+ const rows = items.map((item) => ({
1839
+ ID: String(item.id ?? ""),
1840
+ NAME: String(item.name ?? "")
1841
+ }));
1842
+ return table({ columns: ["ID", "NAME"], rows });
1843
+ }, items);
1844
+ });
1845
+ procedures.command("get <id>").description("Download a procedure by ID and print its YAML content").option("--verbose", "Show HTTP request/response details").action(async function(id) {
1846
+ const opts = this.optsWithGlobals();
1847
+ const client = await resolveClient(opts);
1848
+ const buffer = await client.getBuffer(`/fin-sdk/procedures/${id}/download`);
1849
+ const zip = new AdmZip(buffer);
1850
+ const entry = zip.getEntries().find((e) => e.entryName.endsWith("procedure.yaml"));
1851
+ if (!entry) {
1852
+ throw new Error("procedure.yaml not found in downloaded ZIP");
1853
+ }
1854
+ console.log(zip.readAsText(entry));
1855
+ });
1856
+ procedures.command("upload <file>").description("Upload a procedure file to Fin SDK").option("--json", "Output as JSON").option("--jq <expr>", "Filter JSON output with jq expression").option("--verbose", "Show HTTP request/response details").action(async function(filePath) {
1857
+ const opts = this.optsWithGlobals();
1858
+ const client = await resolveClient(opts);
1859
+ const fileContent = await readFile2(filePath);
1860
+ const formData = new FormData();
1861
+ const blob = new Blob([fileContent], { type: "application/x-yaml" });
1862
+ formData.append("file_data", blob, basename(filePath));
1863
+ const result = await client.postFormData("/fin-sdk/upload", formData);
1864
+ render(result, opts, () => formatJson(result));
1865
+ });
1866
+ }
1867
+
1868
+ // src/commands/fin/data-connectors.ts
1869
+ function registerDataConnectorsCommand(fin) {
1870
+ const dataConnectors = fin.command("data-connectors").description("Manage Fin SDK data connectors");
1871
+ dataConnectors.command("list").description("List data connectors from the Fin SDK manifest").option("--json", "Output as JSON").option("--verbose", "Show HTTP request/response details").action(async function() {
1872
+ const opts = this.optsWithGlobals();
1873
+ const client = await resolveClient(opts);
1874
+ const result = await client.get("/fin-sdk/manifest");
1875
+ const manifest = result;
1876
+ const items = manifest.data_connectors ?? [];
1877
+ render(items, opts, () => {
1878
+ if (items.length === 0) {
1879
+ return "No data connectors found.";
1880
+ }
1881
+ const rows = items.map((item) => ({
1882
+ ID: String(item.id ?? ""),
1883
+ NAME: String(item.name ?? "")
1884
+ }));
1885
+ return table({ columns: ["ID", "NAME"], rows });
1886
+ }, items);
1887
+ });
1888
+ dataConnectors.command("create").description("Create a data connector").requiredOption("-f, --field <key=value>", "Field to set (e.g. name=<name>)", (v, acc) => [...acc, v], []).option("--json", "Output as JSON").option("--jq <expr>", "Filter JSON output with jq expression").option("--verbose", "Show HTTP request/response details").action(async function() {
1889
+ const opts = this.optsWithGlobals();
1890
+ const client = await resolveClient(opts);
1891
+ const fields = opts.field ?? [];
1892
+ const body = {};
1893
+ for (const f of fields) {
1894
+ const eq = f.indexOf("=");
1895
+ if (eq === -1) throw new Error(`Invalid field format: ${f}. Expected key=value`);
1896
+ body[f.slice(0, eq)] = f.slice(eq + 1);
1897
+ }
1898
+ const result = await client.post("/fin-sdk/data-connectors", body);
1899
+ render(
1900
+ result,
1901
+ opts,
1902
+ () => detail({
1903
+ "ID": String(result.id ?? ""),
1904
+ "Name": String(result.name ?? ""),
1905
+ "Status": result.status != null ? String(result.status) : void 0
1906
+ })
1907
+ );
1908
+ });
1909
+ dataConnectors.command("get <id>").description("Download a data connector by ID").option("--json", "Output as JSON").option("--jq <expr>", "Filter JSON output with jq expression").option("--verbose", "Show HTTP request/response details").action(async function(id) {
1910
+ const opts = this.optsWithGlobals();
1911
+ const client = await resolveClient(opts);
1912
+ const result = await client.get(`/fin-sdk/data-connectors/${id}/download`);
1913
+ render(
1914
+ result,
1915
+ opts,
1916
+ () => detail({
1917
+ "ID": String(result.id ?? ""),
1918
+ "Name": String(result.name ?? "")
1919
+ })
1920
+ );
1921
+ });
1922
+ }
1923
+
1822
1924
  // src/commands/fin/guidance.ts
1823
1925
  function registerGuidanceCommand(fin) {
1824
1926
  const guidance = fin.command("guidance").description("Manage Fin SDK guidance");
@@ -1847,6 +1949,169 @@ function registerGuidanceCommand(fin) {
1847
1949
  });
1848
1950
  }
1849
1951
 
1952
+ // src/commands/fin/attributes.ts
1953
+ function registerAttributesCommand(fin) {
1954
+ const attributes = fin.command("attributes").description("Manage Fin SDK attributes");
1955
+ attributes.command("list").description("List Fin SDK attributes").option("--json", "Output as JSON").option("--verbose", "Show HTTP request/response details").action(async function() {
1956
+ const opts = this.optsWithGlobals();
1957
+ const client = await resolveClient(opts);
1958
+ const result = await client.get("/fin-sdk/attributes");
1959
+ const items = Array.isArray(result) ? result : result.attributes ?? [];
1960
+ render(items, opts, () => {
1961
+ if (items.length === 0) {
1962
+ return "No attributes found.";
1963
+ }
1964
+ const rows = items.map((item) => ({
1965
+ NAME: String(item.name ?? ""),
1966
+ TYPE: String(item.type ?? ""),
1967
+ DESCRIPTION: String(item.description ?? "")
1968
+ }));
1969
+ return table({ columns: ["NAME", "TYPE", "DESCRIPTION"], rows });
1970
+ }, items);
1971
+ });
1972
+ }
1973
+
1974
+ // src/commands/fin/audiences.ts
1975
+ function registerAudiencesCommand(fin) {
1976
+ const audiences = fin.command("audiences").description("Manage Fin SDK audiences");
1977
+ audiences.command("list").description("List Fin SDK audiences").option("--json", "Output as JSON").option("--verbose", "Show HTTP request/response details").action(async function() {
1978
+ const opts = this.optsWithGlobals();
1979
+ const client = await resolveClient(opts);
1980
+ const result = await client.get("/fin-sdk/audiences");
1981
+ const items = Array.isArray(result) ? result : result.audiences ?? [];
1982
+ render(items, opts, () => {
1983
+ if (items.length === 0) {
1984
+ return "No audiences found.";
1985
+ }
1986
+ const rows = items.map((item) => ({
1987
+ ID: String(item.id ?? ""),
1988
+ NAME: String(item.name ?? "")
1989
+ }));
1990
+ return table({ columns: ["ID", "NAME"], rows });
1991
+ }, items);
1992
+ });
1993
+ }
1994
+
1995
+ // src/commands/fin/workflows.ts
1996
+ function registerWorkflowsCommand(fin) {
1997
+ const workflows = fin.command("workflows").description("Manage Fin SDK workflows");
1998
+ workflows.command("list").description("List Fin SDK workflows").option("--json", "Output as JSON").option("--verbose", "Show HTTP request/response details").action(async function() {
1999
+ const opts = this.optsWithGlobals();
2000
+ const client = await resolveClient(opts);
2001
+ const result = await client.get("/fin-sdk/workflows");
2002
+ const items = Array.isArray(result) ? result : result.workflows ?? [];
2003
+ render(items, opts, () => {
2004
+ if (items.length === 0) {
2005
+ return "No workflows found.";
2006
+ }
2007
+ const rows = items.map((item) => ({
2008
+ ID: String(item.id ?? ""),
2009
+ TITLE: String(item.title ?? ""),
2010
+ STATE: String(item.state ?? ""),
2011
+ TRIGGER: String(item.trigger_type ?? "")
2012
+ }));
2013
+ return table({ columns: ["ID", "TITLE", "STATE", "TRIGGER"], rows });
2014
+ }, items);
2015
+ });
2016
+ workflows.command("get <id>").description("Get a workflow by ID").option("--json", "Output as JSON").option("--verbose", "Show HTTP request/response details").action(async function(id) {
2017
+ const opts = this.optsWithGlobals();
2018
+ const client = await resolveClient(opts);
2019
+ const result = await client.get(`/fin-sdk/workflows/${id}`);
2020
+ const r = result;
2021
+ render(
2022
+ result,
2023
+ opts,
2024
+ () => detail({
2025
+ "ID": String(r.id ?? ""),
2026
+ "Title": String(r.title ?? ""),
2027
+ "State": String(r.state ?? ""),
2028
+ "Trigger": r.trigger_type != null ? String(r.trigger_type) : void 0
2029
+ })
2030
+ );
2031
+ });
2032
+ }
2033
+
2034
+ // src/commands/fin/simulations.ts
2035
+ function registerSimulationsCommand(fin) {
2036
+ const simulations = fin.command("simulations").description("Manage Fin SDK simulations");
2037
+ simulations.command("list <procedure_id>").description("List simulations for a procedure (displays YAML)").option("--verbose", "Show HTTP request/response details").action(async function(procedureId) {
2038
+ const opts = this.optsWithGlobals();
2039
+ const client = await resolveClient(opts);
2040
+ const text = await client.getText(`/fin-sdk/procedures/${procedureId}/simulations`);
2041
+ console.log(text);
2042
+ });
2043
+ simulations.command("run <procedure_id> [test_id]").description("Run one or all simulations for a procedure").option("--json", "Output as JSON").option("--verbose", "Show HTTP request/response details").action(async function(procedureId, testId) {
2044
+ const opts = this.optsWithGlobals();
2045
+ const client = await resolveClient(opts);
2046
+ let result;
2047
+ if (testId) {
2048
+ result = await client.post(`/fin-sdk/procedures/${procedureId}/simulations/${testId}/run`, {});
2049
+ } else {
2050
+ result = await client.post(`/fin-sdk/procedures/${procedureId}/simulations/run`, {});
2051
+ }
2052
+ const r = result;
2053
+ render(result, opts, () => {
2054
+ if (r.enqueued && Array.isArray(r.enqueued) && r.enqueued.length > 0) {
2055
+ const rows = r.enqueued.map((e) => ({
2056
+ RUN_ID: String(e.run_id ?? ""),
2057
+ TEST_ID: String(e.test_id ?? ""),
2058
+ NAME: String(e.simulation_name ?? ""),
2059
+ STATUS: String(e.status ?? "")
2060
+ }));
2061
+ return table({ columns: ["RUN_ID", "TEST_ID", "NAME", "STATUS"], rows });
2062
+ } else {
2063
+ const runId = r.run_id;
2064
+ if (runId !== void 0) {
2065
+ return `run_id: ${runId}`;
2066
+ } else {
2067
+ return detail({
2068
+ "Procedure ID": String(r.procedure_id ?? "")
2069
+ });
2070
+ }
2071
+ }
2072
+ });
2073
+ });
2074
+ simulations.command("result <run_id>").description("Get the result of a simulation run").option("--json", "Output as JSON").option("--wait", "Poll until run completes").option("--verbose", "Show HTTP request/response details").action(async function(runId) {
2075
+ const opts = this.optsWithGlobals();
2076
+ const client = await resolveClient(opts);
2077
+ let result = await client.get(`/fin-sdk/runs/${runId}`);
2078
+ if (opts.wait) {
2079
+ const deadline = Date.now() + SIMULATION_POLL_TIMEOUT_MS;
2080
+ while (result.status === "pending" || result.status === "running") {
2081
+ if (Date.now() > deadline) {
2082
+ throw new TimeoutError(
2083
+ `Simulation polling timed out after ${SIMULATION_POLL_TIMEOUT_MS / 1e3}s. Last status: ${result.status}. Run "intercom fin simulations result ${runId}" to check later.`
2084
+ );
2085
+ }
2086
+ await new Promise((r) => setTimeout(r, 2e3));
2087
+ result = await client.get(`/fin-sdk/runs/${runId}`);
2088
+ }
2089
+ }
2090
+ render(
2091
+ result,
2092
+ opts,
2093
+ () => detail({
2094
+ "Run ID": String(result.run_id ?? ""),
2095
+ "Status": String(result.status ?? "")
2096
+ })
2097
+ );
2098
+ });
2099
+ simulations.command("generate <procedure_id>").description("Generate simulations for a procedure").option("--json", "Output as JSON").option("--verbose", "Show HTTP request/response details").action(async function(procedureId) {
2100
+ const opts = this.optsWithGlobals();
2101
+ const client = await resolveClient(opts);
2102
+ const result = await client.post(`/fin-sdk/procedures/${procedureId}/simulations/generate`, {});
2103
+ const r = result;
2104
+ render(
2105
+ result,
2106
+ opts,
2107
+ () => detail({
2108
+ "Status": String(r.status ?? ""),
2109
+ "Procedure ID": String(r.procedure_id ?? "")
2110
+ })
2111
+ );
2112
+ });
2113
+ }
2114
+
1850
2115
  // src/auth/ember-session.ts
1851
2116
  async function getEmberSession(options) {
1852
2117
  const { email, password, appId, verifyEmailUrl, timeoutMs = API_TIMEOUT_MS } = options;
@@ -2017,7 +2282,14 @@ function renderResourceTable(label, items) {
2017
2282
  ${table({ columns: ["ID", "NAME"], rows })}`;
2018
2283
  }
2019
2284
  function registerFinCommand(program) {
2020
- const fin = program.command("fin").description("Manage Fin SDK resources");
2285
+ const fin = program.command("fin").description("Manage Fin AI Agent and SDK resources").addHelpText(
2286
+ "after",
2287
+ `
2288
+ Examples:
2289
+ intercom fin manifest
2290
+ intercom fin enable --email admin@company.com
2291
+ intercom fin guidance list`
2292
+ );
2021
2293
  fin.command("manifest").description("Show the Fin SDK manifest for this workspace").option("--json", "Output as JSON").option("--jq <expr>", "Filter JSON output with jq expression").option("--verbose", "Show HTTP request/response details").action(async function() {
2022
2294
  const opts = this.optsWithGlobals();
2023
2295
  const client = await resolveClient(opts);
@@ -2043,12 +2315,26 @@ function registerFinCommand(program) {
2043
2315
  });
2044
2316
  });
2045
2317
  registerFinEnableCommand(fin);
2318
+ registerProceduresCommand(fin);
2319
+ registerDataConnectorsCommand(fin);
2046
2320
  registerGuidanceCommand(fin);
2321
+ registerAttributesCommand(fin);
2322
+ registerAudiencesCommand(fin);
2323
+ registerWorkflowsCommand(fin);
2324
+ registerSimulationsCommand(fin);
2325
+ fin.command("download").description("Download Fin SDK resources as a ZIP file").option("-o, --output <path>", "Output file path", "./fin-resources.zip").option("--verbose", "Show HTTP request/response details").action(async function() {
2326
+ const opts = this.optsWithGlobals();
2327
+ const outputPath = opts.output ?? "./fin-resources.zip";
2328
+ const client = await resolveClient(opts);
2329
+ const buffer = await client.getBuffer("/fin-sdk/download");
2330
+ await writeFile2(outputPath, buffer);
2331
+ console.log(`Downloaded ${buffer.length} bytes to ${outputPath}`);
2332
+ });
2047
2333
  }
2048
2334
 
2049
2335
  // src/commands/setup.ts
2050
2336
  import { readdirSync, readFileSync as readFileSync3, statSync } from "fs";
2051
- import { join as join3, basename } from "path";
2337
+ import { join as join3, basename as basename2 } from "path";
2052
2338
  function isGreenfield(opts) {
2053
2339
  return !!(opts.email && opts.name && (process.env.INTERCOM_PASSWORD || opts.passwordStdin));
2054
2340
  }
@@ -2056,6 +2342,11 @@ function hasPartialGreenfieldFlags(opts) {
2056
2342
  const hasPassword = !!(process.env.INTERCOM_PASSWORD || opts.passwordStdin);
2057
2343
  return !!(opts.email && hasPassword && !opts.name);
2058
2344
  }
2345
+ async function hasExistingAuth() {
2346
+ const configDir = process.env.INTERCOM_CONFIG_DIR;
2347
+ const config = await readConfig(configDir);
2348
+ return !!config.default;
2349
+ }
2059
2350
  function buildPlan(opts) {
2060
2351
  const steps = [];
2061
2352
  let stepNum = 1;
@@ -2101,8 +2392,8 @@ function buildPlan(opts) {
2101
2392
  }
2102
2393
  if (mdFiles.length > 0) {
2103
2394
  const articleCommands = mdFiles.map((file) => {
2104
- const title = basename(file, ".md").replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
2105
- return `intercom articles create -f title="${title}" -F body=@${join3(opts.articlesFrom, file)}`;
2395
+ const title = basename2(file, ".md").replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
2396
+ return `intercom articles create -f title="${title}" -F body=@${join3(opts.articlesFrom, file)} -f author_id=$(intercom me --json | jq -r .id)`;
2106
2397
  });
2107
2398
  steps.push({
2108
2399
  step: stepNum++,
@@ -2114,7 +2405,7 @@ function buildPlan(opts) {
2114
2405
  step: stepNum++,
2115
2406
  description: `Create articles from ${opts.articlesFrom}`,
2116
2407
  commands: [
2117
- `intercom articles create -f title="<article-title>" -F body=@${opts.articlesFrom}/<file>.md`
2408
+ `intercom articles create -f title="<article-title>" -F body=@${opts.articlesFrom}/<file>.md -f author_id=$(intercom me --json | jq -r .id)`
2118
2409
  ]
2119
2410
  });
2120
2411
  }
@@ -2140,15 +2431,20 @@ function formatPlanText(steps) {
2140
2431
  }
2141
2432
  async function runPostAuthSteps(client, opts, results, appId) {
2142
2433
  results.push(`\u2713 Messenger configured`);
2434
+ const me = await client.get("/me");
2435
+ const authorId = me.id != null ? Number(me.id) : void 0;
2143
2436
  const helpCenterName = opts.companyName ? `${opts.companyName} Help` : "Help Center";
2144
2437
  const collections = await client.paginate("/help_center/collections");
2145
2438
  const existingCollection = collections.find(
2146
2439
  (c) => String(c.name ?? "") === helpCenterName
2147
2440
  );
2441
+ let collectionId;
2148
2442
  if (existingCollection) {
2443
+ collectionId = String(existingCollection.id);
2149
2444
  results.push(`\u2713 Help center already exists (${helpCenterName})`);
2150
2445
  } else {
2151
- await client.post("/help_center/collections", { name: helpCenterName });
2446
+ const created = await client.post("/help_center/collections", { name: helpCenterName });
2447
+ collectionId = created.id != null ? String(created.id) : void 0;
2152
2448
  results.push(`\u2713 Help center created (${helpCenterName})`);
2153
2449
  }
2154
2450
  if (opts.articlesFrom) {
@@ -2163,12 +2459,18 @@ async function runPostAuthSteps(client, opts, results, appId) {
2163
2459
  let created = 0;
2164
2460
  let skipped = 0;
2165
2461
  for (const file of mdFiles) {
2166
- const title = basename(file, ".md").replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
2462
+ const title = basename2(file, ".md").replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
2167
2463
  const body = readFileSync3(join3(opts.articlesFrom, file), "utf-8");
2168
2464
  if (existingTitles.has(title)) {
2169
2465
  skipped++;
2170
2466
  } else {
2171
- await client.post("/articles", { title, body, state: "published" });
2467
+ const articleBody = { title, body, state: "published" };
2468
+ if (authorId != null) articleBody.author_id = authorId;
2469
+ if (collectionId != null) {
2470
+ articleBody.parent_id = collectionId;
2471
+ articleBody.parent_type = "collection";
2472
+ }
2473
+ await client.post("/articles", articleBody);
2172
2474
  created++;
2173
2475
  }
2174
2476
  }
@@ -2270,7 +2572,19 @@ async function runPostAuthSteps(client, opts, results, appId) {
2270
2572
  console.log("Setup complete!");
2271
2573
  }
2272
2574
  function registerSetupCommand(program) {
2273
- program.command("setup").description("Set up a complete Intercom installation").option("--company-name <name>", "Company name for Messenger branding").option("--articles-from <dir>", "Directory of markdown files to create as articles").option("--plan", "Output setup steps as CLI commands without executing").option("--dry-run", "Show what would happen without executing").option("--json", "Output as JSON (for --plan mode)").option("--verbose", "Show HTTP request/response details").option("--email <email>", "Admin email address (for new workspace signup)").option("--password-stdin", "Read password from stdin (or set INTERCOM_PASSWORD env var)").option("--name <name>", "Admin name (for new workspace signup)").option("--plan-tier <tier>", "Trial plan tier: essential, advanced, expert (default: advanced)").option("--enable-fin", "Enable Fin AI Agent (default: true for greenfield setup)", true).option("--no-enable-fin", "Skip Fin enablement").option("--verify-email-url <url>", "Email verification URL (needed for Fin on fresh workspaces)").action(async function() {
2575
+ program.command("setup").description("Set up a complete Intercom installation").addHelpText(
2576
+ "after",
2577
+ `
2578
+ Examples:
2579
+ # Existing workspace (already authenticated)
2580
+ intercom setup --company-name "Acme Inc" --articles-from ./docs
2581
+
2582
+ # New workspace (greenfield)
2583
+ INTERCOM_PASSWORD=*** intercom setup --email admin@acme.com --name "Admin" --company-name "Acme Inc"
2584
+
2585
+ # Preview steps without executing
2586
+ intercom setup --plan`
2587
+ ).option("--company-name <name>", "Company name for Messenger branding").option("--articles-from <dir>", "Directory of markdown files to create as articles").option("--plan", "Output setup steps as CLI commands without executing").option("--dry-run", "Show what would happen without executing").option("--json", "Output as JSON (for --plan mode)").option("--verbose", "Show HTTP request/response details").option("--email <email>", "Admin email address (for new workspace signup)").option("--password-stdin", "Read password from stdin (or set INTERCOM_PASSWORD env var)").option("--name <name>", "Admin name (for new workspace signup)").option("--plan-tier <tier>", "Trial plan tier: essential, advanced, expert (default: advanced)").option("--enable-fin", "Enable Fin AI Agent (default: true for greenfield setup)", true).option("--no-enable-fin", "Skip Fin enablement").option("--verify-email-url <url>", "Email verification URL (needed for Fin on fresh workspaces)").action(async function() {
2274
2588
  const opts = this.optsWithGlobals();
2275
2589
  if (hasPartialGreenfieldFlags(opts)) {
2276
2590
  throw new CLIError(
@@ -2321,7 +2635,8 @@ function registerSetupCommand(program) {
2321
2635
  return;
2322
2636
  }
2323
2637
  const results = [];
2324
- if (isGreenfield(opts)) {
2638
+ const alreadyAuthed = await hasExistingAuth();
2639
+ if (isGreenfield(opts) && !alreadyAuthed) {
2325
2640
  const password = await resolvePassword({ passwordStdin: opts.passwordStdin });
2326
2641
  const baseUrl = getAppBaseUrl();
2327
2642
  const planTier = opts.planTier ?? "advanced";
@@ -2335,6 +2650,13 @@ function registerSetupCommand(program) {
2335
2650
  plan: planTier
2336
2651
  });
2337
2652
  results.push(`\u2713 Workspace created: ${workspace.name} (${workspace.id})`);
2653
+ if (opts.verifyEmailUrl) {
2654
+ try {
2655
+ await fetchWithTimeout(opts.verifyEmailUrl, { redirect: "manual" }, { timeoutMs: API_TIMEOUT_MS });
2656
+ results.push(`\u2713 Email verified`);
2657
+ } catch {
2658
+ }
2659
+ }
2338
2660
  let token;
2339
2661
  try {
2340
2662
  const result = await getToken({
@@ -2349,9 +2671,17 @@ function registerSetupCommand(program) {
2349
2671
  console.error(`\u2713 Workspace created: ${workspace.name} (${workspace.id})`);
2350
2672
  console.error(`
2351
2673
  Authentication failed after workspace creation: ${message}`);
2352
- console.error(`
2674
+ if (message.includes("403")) {
2675
+ console.error(`
2676
+ This is likely because the email has not been verified.`);
2677
+ console.error(`Verify your email first, then bootstrap:`);
2678
+ console.error(` intercom auth verify-email --url <url-from-verification-email>`);
2679
+ } else {
2680
+ console.error(`
2353
2681
  Your workspace exists but credentials were not saved.`);
2354
- console.error(`To complete setup, run:
2682
+ }
2683
+ console.error(`
2684
+ To complete setup, run:
2355
2685
  `);
2356
2686
  console.error(` INTERCOM_PASSWORD=*** intercom auth bootstrap --email ${opts.email} --app-id ${workspace.id}`);
2357
2687
  console.error(`
@@ -2385,20 +2715,246 @@ Then re-run setup without signup flags:
2385
2715
  });
2386
2716
  }
2387
2717
 
2718
+ // src/commands/completion.ts
2719
+ function binName() {
2720
+ const argv1 = process.argv[1] ?? "";
2721
+ if (argv1.endsWith("/fin") || argv1.endsWith("\\fin")) return "fin";
2722
+ return "intercom";
2723
+ }
2724
+ var COMMANDS = {
2725
+ api: [],
2726
+ auth: ["login", "logout", "status", "bootstrap", "signup", "verify-email"],
2727
+ me: [],
2728
+ articles: ["list", "get", "create", "update", "delete"],
2729
+ contacts: ["list", "get", "create", "update", "delete"],
2730
+ conversations: ["list", "get", "reply"],
2731
+ "help-center": ["list", "get", "create"],
2732
+ messenger: ["get", "update", "snippet"],
2733
+ fin: ["manifest", "enable", "guidance"],
2734
+ setup: [],
2735
+ pricing: [],
2736
+ completion: ["bash", "zsh", "fish"]
2737
+ };
2738
+ var GLOBAL_FLAGS = [
2739
+ "--json",
2740
+ "--jq",
2741
+ "--workspace",
2742
+ "--verbose",
2743
+ "--no-retry",
2744
+ "--timeout",
2745
+ "--agent",
2746
+ "--human",
2747
+ "--help",
2748
+ "--version"
2749
+ ];
2750
+ function bashScript(name = binName()) {
2751
+ const commandNames = Object.keys(COMMANDS).join(" ");
2752
+ const fnName = `_${name}`;
2753
+ const subcommandCases = Object.entries(COMMANDS).filter(([, subs]) => subs.length > 0).map(([cmd, subs]) => ` ${cmd}) COMPREPLY=( $(compgen -W "${subs.join(" ")}" -- "$cur") ) ;;`).join("\n");
2754
+ return `# bash completion for ${name} CLI
2755
+ # Add to ~/.bashrc: eval "$(${name} completion bash)"
2756
+
2757
+ ${fnName}() {
2758
+ local cur prev commands
2759
+ COMPREPLY=()
2760
+ cur="\${COMP_WORDS[COMP_CWORD]}"
2761
+ prev="\${COMP_WORDS[COMP_CWORD-1]}"
2762
+ commands="${commandNames}"
2763
+
2764
+ if [[ "$cur" == -* ]]; then
2765
+ COMPREPLY=( $(compgen -W "${GLOBAL_FLAGS.join(" ")}" -- "$cur") )
2766
+ return 0
2767
+ fi
2768
+
2769
+ case "\${COMP_WORDS[1]}" in
2770
+ ${subcommandCases}
2771
+ *)
2772
+ if [[ \${COMP_CWORD} -eq 1 ]]; then
2773
+ COMPREPLY=( $(compgen -W "$commands" -- "$cur") )
2774
+ fi
2775
+ ;;
2776
+ esac
2777
+ return 0
2778
+ }
2779
+
2780
+ complete -F ${fnName} ${name}
2781
+ `;
2782
+ }
2783
+ function zshScript(name = binName()) {
2784
+ const fnName = `_${name}`;
2785
+ const commandDescs = [
2786
+ "api:'Make an authenticated API request'",
2787
+ "auth:'Manage authentication credentials'",
2788
+ "me:'Show current admin and workspace info'",
2789
+ "articles:'Manage help center articles'",
2790
+ "contacts:'Manage contacts'",
2791
+ "conversations:'Manage conversations'",
2792
+ "help-center:'Manage help center collections'",
2793
+ "messenger:'Manage Messenger settings'",
2794
+ "fin:'Manage Fin AI Agent'",
2795
+ "setup:'Set up a complete Intercom installation'",
2796
+ "pricing:'Show current Intercom pricing information'",
2797
+ "completion:'Generate shell completion scripts'"
2798
+ ];
2799
+ const subcommandFunctions = Object.entries(COMMANDS).filter(([, subs]) => subs.length > 0).map(([cmd, subs]) => {
2800
+ const subFnName = cmd.replace(/-/g, "_");
2801
+ const subLines = subs.map((s) => `'${s}'`).join(" ");
2802
+ return `${fnName}_${subFnName}() {
2803
+ local -a subcommands
2804
+ subcommands=(${subLines})
2805
+ _describe 'subcommand' subcommands
2806
+ }`;
2807
+ }).join("\n\n");
2808
+ return `#compdef ${name}
2809
+ # zsh completion for ${name} CLI
2810
+ # Add to ~/.zshrc: eval "$(${name} completion zsh)"
2811
+
2812
+ ${fnName}() {
2813
+ local -a commands global_flags
2814
+ commands=(
2815
+ ${commandDescs.join("\n ")}
2816
+ )
2817
+ global_flags=(
2818
+ ${GLOBAL_FLAGS.map((f) => `'${f}'`).join("\n ")}
2819
+ )
2820
+
2821
+ _arguments -C \\
2822
+ '1:command:->command' \\
2823
+ '*::arg:->args'
2824
+
2825
+ case $state in
2826
+ command)
2827
+ _describe 'command' commands
2828
+ ;;
2829
+ args)
2830
+ case $words[1] in
2831
+ ${Object.entries(COMMANDS).filter(([, subs]) => subs.length > 0).map(([cmd]) => ` ${cmd}) ${fnName}_${cmd.replace(/-/g, "_")} ;;`).join("\n")}
2832
+ esac
2833
+ ;;
2834
+ esac
2835
+ }
2836
+
2837
+ ${subcommandFunctions}
2838
+
2839
+ ${fnName} "$@"
2840
+ `;
2841
+ }
2842
+ function fishScript(name = binName()) {
2843
+ const lines = [
2844
+ `# fish completion for ${name} CLI`,
2845
+ `# Add to fish config: ${name} completion fish | source`,
2846
+ "",
2847
+ "# Disable file completions",
2848
+ `complete -c ${name} -f`,
2849
+ "",
2850
+ "# Top-level commands"
2851
+ ];
2852
+ const commandDescs = {
2853
+ api: "Make an authenticated API request",
2854
+ auth: "Manage authentication credentials",
2855
+ me: "Show current admin and workspace info",
2856
+ articles: "Manage help center articles",
2857
+ contacts: "Manage contacts",
2858
+ conversations: "Manage conversations",
2859
+ "help-center": "Manage help center collections",
2860
+ messenger: "Manage Messenger settings",
2861
+ fin: "Manage Fin AI Agent",
2862
+ setup: "Set up a complete Intercom installation",
2863
+ pricing: "Show current Intercom pricing information",
2864
+ completion: "Generate shell completion scripts"
2865
+ };
2866
+ for (const [cmd, desc] of Object.entries(commandDescs)) {
2867
+ lines.push(
2868
+ `complete -c ${name} -n '__fish_use_subcommand' -a '${cmd}' -d '${desc}'`
2869
+ );
2870
+ }
2871
+ lines.push("");
2872
+ lines.push("# Subcommands");
2873
+ for (const [cmd, subs] of Object.entries(COMMANDS)) {
2874
+ for (const sub of subs) {
2875
+ lines.push(
2876
+ `complete -c ${name} -n '__fish_seen_subcommand_from ${cmd}' -a '${sub}'`
2877
+ );
2878
+ }
2879
+ }
2880
+ lines.push("");
2881
+ lines.push("# Global flags");
2882
+ for (const flag of GLOBAL_FLAGS) {
2883
+ lines.push(`complete -c ${name} -l '${flag.replace(/^--/, "")}'`);
2884
+ }
2885
+ lines.push("");
2886
+ return lines.join("\n");
2887
+ }
2888
+ function registerCompletionCommand(program) {
2889
+ const name = binName();
2890
+ const completion = program.command("completion").description("Generate shell completion scripts").addHelpText(
2891
+ "after",
2892
+ `
2893
+ Examples:
2894
+ # Bash (add to ~/.bashrc)
2895
+ eval "$(${name} completion bash)"
2896
+
2897
+ # Zsh (add to ~/.zshrc)
2898
+ eval "$(${name} completion zsh)"
2899
+
2900
+ # Fish (add to fish config)
2901
+ ${name} completion fish | source`
2902
+ );
2903
+ completion.command("bash").description("Generate bash completion script").action(() => {
2904
+ console.log(bashScript());
2905
+ });
2906
+ completion.command("zsh").description("Generate zsh completion script").action(() => {
2907
+ console.log(zshScript());
2908
+ });
2909
+ completion.command("fish").description("Generate fish completion script").action(() => {
2910
+ console.log(fishScript());
2911
+ });
2912
+ }
2913
+
2914
+ // src/commands/pricing.ts
2915
+ var PRICING_URL = "https://www.intercom.com/pricing.md";
2916
+ function registerPricingCommand(program) {
2917
+ program.command("pricing").description("Show current Intercom pricing information").option("--json", "Output as JSON").option("--jq <expr>", "Filter JSON output with jq expression").option("--verbose", "Show HTTP request/response details").action(async function() {
2918
+ const opts = this.optsWithGlobals();
2919
+ const response = await fetchWithTimeout(
2920
+ PRICING_URL,
2921
+ { headers: { Accept: "text/markdown, text/plain, */*" } },
2922
+ { timeoutMs: API_TIMEOUT_MS, verbose: opts.verbose }
2923
+ );
2924
+ if (!response.ok) {
2925
+ throw new CLIError(`Failed to fetch pricing: ${response.status} ${response.statusText}`);
2926
+ }
2927
+ const markdown = await response.text();
2928
+ if (opts.json) {
2929
+ const { formatJson: formatJson2 } = await import("./json-TDEGGEUF.js");
2930
+ console.log(formatJson2({ url: PRICING_URL, content: markdown }));
2931
+ } else {
2932
+ console.log(markdown);
2933
+ }
2934
+ });
2935
+ }
2936
+
2388
2937
  // src/index.ts
2938
+ function detectBinaryName() {
2939
+ const argv1 = process.argv[1] ?? "";
2940
+ if (argv1.endsWith("/fin") || argv1.endsWith("\\fin")) return "fin";
2941
+ return "intercom";
2942
+ }
2389
2943
  function fullCommandName(cmd) {
2390
2944
  const parts = [];
2945
+ const rootNames = /* @__PURE__ */ new Set(["intercom", "fin"]);
2391
2946
  let current = cmd;
2392
2947
  while (current) {
2393
2948
  const name = current.name();
2394
- if (name && name !== "intercom") parts.unshift(name);
2949
+ if (name && !rootNames.has(name)) parts.unshift(name);
2395
2950
  current = current.parent;
2396
2951
  }
2397
2952
  return parts.join(" ");
2398
2953
  }
2399
2954
  function createProgram() {
2400
2955
  const program = new Command();
2401
- program.name("intercom").description("CLI tool for managing Intercom workspaces").version(VERSION).option("--json", "Output as JSON").option("--jq <expr>", "Filter JSON output").option("--workspace <id>", "Override default workspace").option("--verbose", "Show HTTP request/response details").option("--no-retry", "Disable automatic rate limit retry").option("--timeout <seconds>", "Request timeout in seconds");
2956
+ const binName2 = detectBinaryName();
2957
+ program.name(binName2).description("CLI tool for managing Intercom workspaces").version(VERSION).option("--json", "Output as JSON").option("--jq <expr>", "Filter JSON output").option("--workspace <id>", "Override default workspace").option("--verbose", "Show HTTP request/response details").option("--no-retry", "Disable automatic rate limit retry").option("--timeout <seconds>", "Request timeout in seconds").option("--agent", "Force machine-readable output (JSON/NDJSON)").option("--human", "Force human-readable output even when piped");
2402
2958
  registerApiCommand(program);
2403
2959
  registerAuthCommand(program);
2404
2960
  registerMeCommand(program);
@@ -2409,13 +2965,19 @@ function createProgram() {
2409
2965
  registerMessengerCommand(program);
2410
2966
  registerFinCommand(program);
2411
2967
  registerSetupCommand(program);
2412
- program.hook("preAction", (_, actionCommand) => {
2968
+ registerPricingCommand(program);
2969
+ registerCompletionCommand(program);
2970
+ program.hook("preAction", (thisCommand, actionCommand) => {
2971
+ const rootOpts = thisCommand.opts();
2972
+ if (rootOpts.agent && rootOpts.human) {
2973
+ throw new CLIError("--agent and --human are mutually exclusive");
2974
+ }
2413
2975
  setCliCommand(fullCommandName(actionCommand));
2414
2976
  });
2415
2977
  return program;
2416
2978
  }
2417
2979
  function handleError(err) {
2418
- const isJson = process.argv.includes("--json");
2980
+ const isJson = process.argv.includes("--json") || process.argv.includes("--agent");
2419
2981
  if (err instanceof CLIError) {
2420
2982
  if (isJson) {
2421
2983
  console.error(formatJson({
@@ -2433,7 +2995,7 @@ function handleError(err) {
2433
2995
  console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
2434
2996
  process.exit(1);
2435
2997
  }
2436
- var isMainModule = process.argv[1]?.endsWith("index.js") || process.argv[1]?.endsWith("intercom");
2998
+ var isMainModule = process.argv[1]?.endsWith("index.js") || process.argv[1]?.endsWith("intercom") || process.argv[1]?.endsWith("fin");
2437
2999
  if (isMainModule) {
2438
3000
  const program = createProgram();
2439
3001
  try {