@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/README.md +128 -0
- package/dist/chunk-QEXGKXTU.js +109 -0
- package/dist/chunk-QEXGKXTU.js.map +1 -0
- package/dist/index.js +682 -120
- package/dist/index.js.map +1 -1
- package/dist/json-TDEGGEUF.js +10 -0
- package/dist/json-TDEGGEUF.js.map +1 -0
- package/package.json +5 -3
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)").
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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").
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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 {
|