@intercom/cli 0.10.0 → 0.12.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/CHANGELOG.md +14 -0
- package/dist/index.js +414 -13
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
View it from the CLI with `intercom changelog`.
|
|
9
9
|
|
|
10
|
+
## [0.12.0] - 2026-08-26
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `intercom internal-articles` manages the private knowledge Fin reads: `list`, `get`, `create`, `update` and `delete`. Previously internal articles could only be reached through raw `intercom api` calls. Pass `--unstable` to include each article's `folder_id` in the output.
|
|
15
|
+
- `intercom internal-articles folders list` and `folders get <id>` read the internal article folder tree. Walk `parent_folder_id` to rebuild the hierarchy and match each article to a folder by its `folder_id`. These always send `Intercom-Version: Unstable`, because the folders API is not generally available yet.
|
|
16
|
+
- `intercom internal-articles folders articles <folder-id>` lists the articles in a folder and every folder below it.
|
|
17
|
+
|
|
18
|
+
## [0.11.0] - 2026-08-17
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- `fin workflows versions <id>` lists a workflow's server-side version history, showing which version is live, which is draft, and who saved it. `fin workflows get <id> --version <version_id>` downloads any of those versions as re-uploadable YAML, so a local file can be diffed against what Fin is actually running.
|
|
23
|
+
|
|
10
24
|
## [0.10.0] - 2026-08-17
|
|
11
25
|
|
|
12
26
|
### Added
|
package/dist/index.js
CHANGED
|
@@ -327,9 +327,9 @@ ${await value.text()}`);
|
|
|
327
327
|
async postFormData(path, formData) {
|
|
328
328
|
return this.request("POST", path, formData);
|
|
329
329
|
}
|
|
330
|
-
async paginate(path, params, dataKey = "data") {
|
|
330
|
+
async paginate(path, params, dataKey = "data", headers) {
|
|
331
331
|
const allData = [];
|
|
332
|
-
const firstResponse = await this.get(path, { ...params });
|
|
332
|
+
const firstResponse = await this.get(path, { ...params }, headers);
|
|
333
333
|
const firstData = firstResponse[dataKey];
|
|
334
334
|
if (firstData) allData.push(...firstData);
|
|
335
335
|
const pages = firstResponse.pages;
|
|
@@ -337,10 +337,11 @@ ${await value.text()}`);
|
|
|
337
337
|
if (startingAfter) {
|
|
338
338
|
let cursor = startingAfter;
|
|
339
339
|
while (cursor) {
|
|
340
|
-
const response = await this.get(
|
|
341
|
-
|
|
342
|
-
starting_after: cursor
|
|
343
|
-
|
|
340
|
+
const response = await this.get(
|
|
341
|
+
path,
|
|
342
|
+
{ ...params, starting_after: cursor },
|
|
343
|
+
headers
|
|
344
|
+
);
|
|
344
345
|
const data = response[dataKey];
|
|
345
346
|
if (data) allData.push(...data);
|
|
346
347
|
const p = response.pages;
|
|
@@ -350,7 +351,11 @@ ${await value.text()}`);
|
|
|
350
351
|
}
|
|
351
352
|
const totalPages = pages?.total_pages ?? 1;
|
|
352
353
|
for (let page = 2; page <= totalPages; page++) {
|
|
353
|
-
const response = await this.get(
|
|
354
|
+
const response = await this.get(
|
|
355
|
+
path,
|
|
356
|
+
{ ...params, page: String(page) },
|
|
357
|
+
headers
|
|
358
|
+
);
|
|
354
359
|
const data = response[dataKey];
|
|
355
360
|
if (data) allData.push(...data);
|
|
356
361
|
}
|
|
@@ -1790,6 +1795,356 @@ Use -F for typed values (numbers, booleans) and @file reads.`
|
|
|
1790
1795
|
});
|
|
1791
1796
|
}
|
|
1792
1797
|
|
|
1798
|
+
// src/commands/internal-articles.ts
|
|
1799
|
+
var UNSTABLE_HEADERS = { "Intercom-Version": "Unstable" };
|
|
1800
|
+
var BODY_KEY = "internal_article";
|
|
1801
|
+
var INTEGER_FIELDS = ["owner_id", "author_id", "folder_id"];
|
|
1802
|
+
function stripBody2(items) {
|
|
1803
|
+
return items.map(({ body: _body, json_blocks: _blocks, ...rest }) => rest);
|
|
1804
|
+
}
|
|
1805
|
+
function headersFor(opts) {
|
|
1806
|
+
return opts.unstable ? UNSTABLE_HEADERS : void 0;
|
|
1807
|
+
}
|
|
1808
|
+
function buildBody(opts) {
|
|
1809
|
+
const attrs = {
|
|
1810
|
+
...parseFieldArgs(opts.field ?? []),
|
|
1811
|
+
...parseTypedFields(opts.typedField ?? [], true)
|
|
1812
|
+
};
|
|
1813
|
+
for (const key of INTEGER_FIELDS) {
|
|
1814
|
+
if (typeof attrs[key] === "string") {
|
|
1815
|
+
const parsed = parseInt(attrs[key], 10);
|
|
1816
|
+
if (!isNaN(parsed)) attrs[key] = parsed;
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
return { [BODY_KEY]: attrs };
|
|
1820
|
+
}
|
|
1821
|
+
function articleRows(items) {
|
|
1822
|
+
return items.map((a) => ({
|
|
1823
|
+
ID: String(a.id ?? ""),
|
|
1824
|
+
TITLE: String(a.title ?? ""),
|
|
1825
|
+
FOLDER: a.folder_id != null ? String(a.folder_id) : "",
|
|
1826
|
+
LOCALE: String(a.locale ?? ""),
|
|
1827
|
+
UPDATED: formatTimestamp(a.updated_at)
|
|
1828
|
+
}));
|
|
1829
|
+
}
|
|
1830
|
+
var ARTICLE_COLUMNS = ["ID", "TITLE", "FOLDER", "LOCALE", "UPDATED"];
|
|
1831
|
+
function articleDetail(result) {
|
|
1832
|
+
const meta = detail({
|
|
1833
|
+
ID: String(result.id ?? ""),
|
|
1834
|
+
Title: String(result.title ?? ""),
|
|
1835
|
+
Locale: String(result.locale ?? ""),
|
|
1836
|
+
"Folder ID": result.folder_id != null ? String(result.folder_id) : void 0,
|
|
1837
|
+
"Owner ID": result.owner_id != null ? String(result.owner_id) : void 0,
|
|
1838
|
+
"Author ID": result.author_id != null ? String(result.author_id) : void 0,
|
|
1839
|
+
Updated: formatTimestamp(result.updated_at),
|
|
1840
|
+
Created: formatTimestamp(result.created_at)
|
|
1841
|
+
});
|
|
1842
|
+
const body = typeof result.body === "string" ? htmlToText(result.body) : "";
|
|
1843
|
+
return body ? `${meta}
|
|
1844
|
+
|
|
1845
|
+
${body}` : meta;
|
|
1846
|
+
}
|
|
1847
|
+
function addCommonOptions(cmd) {
|
|
1848
|
+
return cmd.option("--json", "Output as JSON").option("--jq <expr>", "Filter JSON output with jq expression").option("--verbose", "Show HTTP request/response details");
|
|
1849
|
+
}
|
|
1850
|
+
function addFieldOptions(cmd) {
|
|
1851
|
+
return cmd.option(
|
|
1852
|
+
"-f, --field <key=value>",
|
|
1853
|
+
"Field to set (repeatable)",
|
|
1854
|
+
(v, acc) => [...acc, v],
|
|
1855
|
+
[]
|
|
1856
|
+
).option(
|
|
1857
|
+
"-F, --typed-field <key=value>",
|
|
1858
|
+
"Typed field: bools, numbers, @file reads (repeatable)",
|
|
1859
|
+
(v, acc) => [...acc, v],
|
|
1860
|
+
[]
|
|
1861
|
+
);
|
|
1862
|
+
}
|
|
1863
|
+
function registerInternalArticlesCommand(program) {
|
|
1864
|
+
const internalArticles = program.command("internal-articles").description(
|
|
1865
|
+
"Manage internal articles (list, get, create, update, delete, folders)"
|
|
1866
|
+
).addHelpText(
|
|
1867
|
+
"after",
|
|
1868
|
+
`
|
|
1869
|
+
Internal articles are the private knowledge Fin reads but end users never see.
|
|
1870
|
+
They are separate from "intercom articles", which manages public help center content.
|
|
1871
|
+
|
|
1872
|
+
Examples:
|
|
1873
|
+
intercom internal-articles list
|
|
1874
|
+
intercom internal-articles list --unstable # include folder_id
|
|
1875
|
+
intercom internal-articles get 123
|
|
1876
|
+
intercom internal-articles create -f title='Refunds' -f owner_id=1 -f author_id=1 -F body_markdown=@refunds.md
|
|
1877
|
+
intercom internal-articles update 123 -f title='Refunds (2026)'
|
|
1878
|
+
intercom internal-articles delete 123
|
|
1879
|
+
intercom internal-articles folders list # folder hierarchy`
|
|
1880
|
+
);
|
|
1881
|
+
addCommonOptions(
|
|
1882
|
+
internalArticles.command("list").description("List internal articles").option("--limit <n>", "Max results to return", "25").option("--all", "Auto-paginate all pages").option(
|
|
1883
|
+
"--body",
|
|
1884
|
+
"Include the body and json_blocks fields (omitted by default to keep output small)"
|
|
1885
|
+
).option(
|
|
1886
|
+
"--unstable",
|
|
1887
|
+
"Send Intercom-Version: Unstable, which adds folder_id to each article"
|
|
1888
|
+
)
|
|
1889
|
+
).addHelpText(
|
|
1890
|
+
"after",
|
|
1891
|
+
`
|
|
1892
|
+
Examples:
|
|
1893
|
+
$ intercom internal-articles list --json
|
|
1894
|
+
$ intercom internal-articles list --all --jq '.[].title'
|
|
1895
|
+
$ intercom internal-articles list --unstable --json # include folder_id
|
|
1896
|
+
$ intercom internal-articles list --body --json # include full body`
|
|
1897
|
+
).action(async function() {
|
|
1898
|
+
const opts = this.optsWithGlobals();
|
|
1899
|
+
const client = await resolveClient(opts);
|
|
1900
|
+
const headers = headersFor(opts);
|
|
1901
|
+
let result;
|
|
1902
|
+
if (opts.all) {
|
|
1903
|
+
const allItems = await client.paginate(
|
|
1904
|
+
"/internal_articles",
|
|
1905
|
+
{ per_page: "50" },
|
|
1906
|
+
"data",
|
|
1907
|
+
headers
|
|
1908
|
+
);
|
|
1909
|
+
result = {
|
|
1910
|
+
type: "list",
|
|
1911
|
+
data: opts.body ? allItems : stripBody2(allItems)
|
|
1912
|
+
};
|
|
1913
|
+
} else {
|
|
1914
|
+
const raw = await client.get(
|
|
1915
|
+
"/internal_articles",
|
|
1916
|
+
{ per_page: opts.limit ?? "25" },
|
|
1917
|
+
headers
|
|
1918
|
+
);
|
|
1919
|
+
if (!opts.body && Array.isArray(raw.data)) {
|
|
1920
|
+
raw.data = stripBody2(raw.data);
|
|
1921
|
+
}
|
|
1922
|
+
result = raw;
|
|
1923
|
+
}
|
|
1924
|
+
const items = result.data ?? [];
|
|
1925
|
+
render(
|
|
1926
|
+
result,
|
|
1927
|
+
opts,
|
|
1928
|
+
() => table({ columns: ARTICLE_COLUMNS, rows: articleRows(items) }),
|
|
1929
|
+
items
|
|
1930
|
+
);
|
|
1931
|
+
});
|
|
1932
|
+
addCommonOptions(
|
|
1933
|
+
internalArticles.command("get <id>").description("Get an internal article by ID").option(
|
|
1934
|
+
"--unstable",
|
|
1935
|
+
"Send Intercom-Version: Unstable, which adds folder_id to the article"
|
|
1936
|
+
)
|
|
1937
|
+
).action(async function(id) {
|
|
1938
|
+
const opts = this.optsWithGlobals();
|
|
1939
|
+
const client = await resolveClient(opts);
|
|
1940
|
+
const result = await client.get(
|
|
1941
|
+
`/internal_articles/${id}`,
|
|
1942
|
+
void 0,
|
|
1943
|
+
headersFor(opts)
|
|
1944
|
+
);
|
|
1945
|
+
render(result, opts, () => articleDetail(result));
|
|
1946
|
+
});
|
|
1947
|
+
addCommonOptions(
|
|
1948
|
+
addFieldOptions(
|
|
1949
|
+
internalArticles.command("create").description("Create an internal article").option(
|
|
1950
|
+
"--unstable",
|
|
1951
|
+
"Send Intercom-Version: Unstable, needed to set folder_id"
|
|
1952
|
+
)
|
|
1953
|
+
)
|
|
1954
|
+
).addHelpText(
|
|
1955
|
+
"after",
|
|
1956
|
+
`
|
|
1957
|
+
Examples:
|
|
1958
|
+
$ intercom internal-articles create -f title='Refund policy' -f owner_id=1 -f author_id=1 -F body_markdown=@refunds.md
|
|
1959
|
+
$ intercom internal-articles create -f title='Escalations' -f owner_id=1 -f author_id=1 -f folder_id=7 --unstable
|
|
1960
|
+
|
|
1961
|
+
Required fields: title, owner_id, author_id
|
|
1962
|
+
Content: pass body (HTML) or body_markdown (Markdown), not both.
|
|
1963
|
+
Use -F for typed values (numbers, booleans) and @file reads.`
|
|
1964
|
+
).action(async function() {
|
|
1965
|
+
const opts = this.optsWithGlobals();
|
|
1966
|
+
const client = await resolveClient(opts);
|
|
1967
|
+
const result = await client.post(
|
|
1968
|
+
"/internal_articles",
|
|
1969
|
+
buildBody(opts),
|
|
1970
|
+
headersFor(opts)
|
|
1971
|
+
);
|
|
1972
|
+
render(
|
|
1973
|
+
result,
|
|
1974
|
+
opts,
|
|
1975
|
+
() => articleDetail(result)
|
|
1976
|
+
);
|
|
1977
|
+
});
|
|
1978
|
+
addCommonOptions(
|
|
1979
|
+
addFieldOptions(
|
|
1980
|
+
internalArticles.command("update <id>").description("Update an internal article").option(
|
|
1981
|
+
"--unstable",
|
|
1982
|
+
"Send Intercom-Version: Unstable, needed to set folder_id"
|
|
1983
|
+
)
|
|
1984
|
+
)
|
|
1985
|
+
).addHelpText(
|
|
1986
|
+
"after",
|
|
1987
|
+
`
|
|
1988
|
+
Examples:
|
|
1989
|
+
$ intercom internal-articles update 123 -f title='Refund policy (2026)'
|
|
1990
|
+
$ intercom internal-articles update 123 -F body_markdown=@refunds.md
|
|
1991
|
+
$ intercom internal-articles update 123 -f folder_id=7 --unstable`
|
|
1992
|
+
).action(async function(id) {
|
|
1993
|
+
const opts = this.optsWithGlobals();
|
|
1994
|
+
const client = await resolveClient(opts);
|
|
1995
|
+
const result = await client.put(
|
|
1996
|
+
`/internal_articles/${id}`,
|
|
1997
|
+
buildBody(opts),
|
|
1998
|
+
headersFor(opts)
|
|
1999
|
+
);
|
|
2000
|
+
render(
|
|
2001
|
+
result,
|
|
2002
|
+
opts,
|
|
2003
|
+
() => articleDetail(result)
|
|
2004
|
+
);
|
|
2005
|
+
});
|
|
2006
|
+
addCommonOptions(
|
|
2007
|
+
internalArticles.command("delete <id>").description("Delete an internal article")
|
|
2008
|
+
).action(async function(id) {
|
|
2009
|
+
const opts = this.optsWithGlobals();
|
|
2010
|
+
const client = await resolveClient(opts);
|
|
2011
|
+
const result = await client.delete(`/internal_articles/${id}`);
|
|
2012
|
+
const deleted = result;
|
|
2013
|
+
render(result, opts, () => `Deleted internal article ${deleted.id ?? id}`);
|
|
2014
|
+
});
|
|
2015
|
+
const folders = internalArticles.command("folders").description("List and inspect internal article folders").addHelpText(
|
|
2016
|
+
"after",
|
|
2017
|
+
`
|
|
2018
|
+
Folders are served only on the Unstable API version until the folders API is
|
|
2019
|
+
released, so these subcommands always send Intercom-Version: Unstable.
|
|
2020
|
+
|
|
2021
|
+
Reconstruct the hierarchy by walking parent_folder_id, then match articles to
|
|
2022
|
+
folders with the folder_id from "internal-articles list --unstable".
|
|
2023
|
+
|
|
2024
|
+
Examples:
|
|
2025
|
+
intercom internal-articles folders list
|
|
2026
|
+
intercom internal-articles folders list --parent-folder-id 7
|
|
2027
|
+
intercom internal-articles folders get 7
|
|
2028
|
+
intercom internal-articles folders articles 7`
|
|
2029
|
+
);
|
|
2030
|
+
addCommonOptions(
|
|
2031
|
+
folders.command("list").description("List internal article folders").option("--limit <n>", "Max results to return", "25").option("--all", "Auto-paginate all pages").option(
|
|
2032
|
+
"--parent-folder-id <id>",
|
|
2033
|
+
"Only return folders directly inside this folder"
|
|
2034
|
+
)
|
|
2035
|
+
).action(async function() {
|
|
2036
|
+
const opts = this.optsWithGlobals();
|
|
2037
|
+
const client = await resolveClient(opts);
|
|
2038
|
+
const params = {};
|
|
2039
|
+
if (opts.parentFolderId) params.parent_folder_id = opts.parentFolderId;
|
|
2040
|
+
let result;
|
|
2041
|
+
if (opts.all) {
|
|
2042
|
+
const allItems = await client.paginate(
|
|
2043
|
+
"/folders",
|
|
2044
|
+
{ ...params, per_page: "50" },
|
|
2045
|
+
"data",
|
|
2046
|
+
UNSTABLE_HEADERS
|
|
2047
|
+
);
|
|
2048
|
+
result = { type: "list", data: allItems };
|
|
2049
|
+
} else {
|
|
2050
|
+
result = await client.get(
|
|
2051
|
+
"/folders",
|
|
2052
|
+
{ ...params, per_page: opts.limit ?? "25" },
|
|
2053
|
+
UNSTABLE_HEADERS
|
|
2054
|
+
);
|
|
2055
|
+
}
|
|
2056
|
+
const items = result.data ?? [];
|
|
2057
|
+
render(
|
|
2058
|
+
result,
|
|
2059
|
+
opts,
|
|
2060
|
+
() => {
|
|
2061
|
+
if (items.length === 0) return "No folders found.";
|
|
2062
|
+
const rows = items.map((f) => ({
|
|
2063
|
+
ID: String(f.id ?? ""),
|
|
2064
|
+
NAME: String(f.name ?? ""),
|
|
2065
|
+
PARENT: f.parent_folder_id != null ? String(f.parent_folder_id) : "",
|
|
2066
|
+
ITEMS: f.content_count != null ? String(f.content_count) : ""
|
|
2067
|
+
}));
|
|
2068
|
+
return table({ columns: ["ID", "NAME", "PARENT", "ITEMS"], rows });
|
|
2069
|
+
},
|
|
2070
|
+
items
|
|
2071
|
+
);
|
|
2072
|
+
});
|
|
2073
|
+
addCommonOptions(
|
|
2074
|
+
folders.command("get <id>").description("Get an internal article folder by ID")
|
|
2075
|
+
).action(async function(id) {
|
|
2076
|
+
const opts = this.optsWithGlobals();
|
|
2077
|
+
const client = await resolveClient(opts);
|
|
2078
|
+
const result = await client.get(`/folders/${id}`, void 0, UNSTABLE_HEADERS);
|
|
2079
|
+
render(
|
|
2080
|
+
result,
|
|
2081
|
+
opts,
|
|
2082
|
+
() => detail({
|
|
2083
|
+
ID: String(result.id ?? ""),
|
|
2084
|
+
Name: String(result.name ?? ""),
|
|
2085
|
+
Description: result.description != null ? String(result.description) : void 0,
|
|
2086
|
+
Emoji: result.emoji != null ? String(result.emoji) : void 0,
|
|
2087
|
+
"Parent folder ID": result.parent_folder_id != null ? String(result.parent_folder_id) : void 0,
|
|
2088
|
+
Items: result.content_count != null ? String(result.content_count) : void 0,
|
|
2089
|
+
Updated: formatTimestamp(result.updated_at),
|
|
2090
|
+
Created: formatTimestamp(result.created_at)
|
|
2091
|
+
})
|
|
2092
|
+
);
|
|
2093
|
+
});
|
|
2094
|
+
addCommonOptions(
|
|
2095
|
+
folders.command("articles <folder-id>").description("List the articles in a folder and everything below it").option("--limit <n>", "Max results to return", "25").option("--all", "Auto-paginate all pages").option(
|
|
2096
|
+
"--body",
|
|
2097
|
+
"Include the body and json_blocks fields (omitted by default to keep output small)"
|
|
2098
|
+
)
|
|
2099
|
+
).addHelpText(
|
|
2100
|
+
"after",
|
|
2101
|
+
`
|
|
2102
|
+
This walks the folder tree, so it returns the articles in every descendant
|
|
2103
|
+
folder too, not just the ones directly inside.
|
|
2104
|
+
|
|
2105
|
+
Examples:
|
|
2106
|
+
$ intercom internal-articles folders articles 7
|
|
2107
|
+
$ intercom internal-articles folders articles 7 --all --jq '.[].title'`
|
|
2108
|
+
).action(async function(folderId) {
|
|
2109
|
+
const opts = this.optsWithGlobals();
|
|
2110
|
+
const client = await resolveClient(opts);
|
|
2111
|
+
const params = { folder_id: folderId };
|
|
2112
|
+
let result;
|
|
2113
|
+
if (opts.all) {
|
|
2114
|
+
const allItems = await client.paginate(
|
|
2115
|
+
"/internal_articles/search",
|
|
2116
|
+
{ ...params, per_page: "50" },
|
|
2117
|
+
"internal_articles",
|
|
2118
|
+
UNSTABLE_HEADERS
|
|
2119
|
+
);
|
|
2120
|
+
result = {
|
|
2121
|
+
type: "list",
|
|
2122
|
+
internal_articles: opts.body ? allItems : stripBody2(allItems)
|
|
2123
|
+
};
|
|
2124
|
+
} else {
|
|
2125
|
+
const raw = await client.get(
|
|
2126
|
+
"/internal_articles/search",
|
|
2127
|
+
{ ...params, per_page: opts.limit ?? "25" },
|
|
2128
|
+
UNSTABLE_HEADERS
|
|
2129
|
+
);
|
|
2130
|
+
if (!opts.body && Array.isArray(raw.internal_articles)) {
|
|
2131
|
+
raw.internal_articles = stripBody2(raw.internal_articles);
|
|
2132
|
+
}
|
|
2133
|
+
result = raw;
|
|
2134
|
+
}
|
|
2135
|
+
const items = result.internal_articles ?? [];
|
|
2136
|
+
render(
|
|
2137
|
+
result,
|
|
2138
|
+
opts,
|
|
2139
|
+
() => {
|
|
2140
|
+
if (items.length === 0) return "No internal articles found.";
|
|
2141
|
+
return table({ columns: ARTICLE_COLUMNS, rows: articleRows(items) });
|
|
2142
|
+
},
|
|
2143
|
+
items
|
|
2144
|
+
);
|
|
2145
|
+
});
|
|
2146
|
+
}
|
|
2147
|
+
|
|
1793
2148
|
// src/commands/contacts.ts
|
|
1794
2149
|
function registerContactsCommand(program) {
|
|
1795
2150
|
const contacts = program.command("contacts").description("Manage contacts (list, get, create, update, delete, search)").addHelpText(
|
|
@@ -2258,7 +2613,7 @@ Examples:
|
|
|
2258
2613
|
}
|
|
2259
2614
|
|
|
2260
2615
|
// src/commands/messenger.ts
|
|
2261
|
-
var
|
|
2616
|
+
var UNSTABLE_HEADERS2 = { "Intercom-Version": "Unstable" };
|
|
2262
2617
|
var WIDGET_LOADER = (appId) => `(function(){var w=window;var ic=w.Intercom;if(typeof ic==="function"){ic('reattach_activator');}else{var d=document;var i=function(){i.c(arguments);};i.q=[];i.c=function(args){i.q.push(args);};w.Intercom=i;var l=function(){var s=d.createElement('script');s.type='text/javascript';s.async=true;s.src='https://widget.intercom.io/widget/${appId}';var x=d.getElementsByTagName('script')[0];x.parentNode.insertBefore(s,x);};if(document.readyState==='complete'){l();}else if(w.attachEvent){w.attachEvent('onload',l);}else{w.addEventListener('load',l,false);}}})();`;
|
|
2263
2618
|
function generateHtmlJwtSnippet(appId) {
|
|
2264
2619
|
return `<!--
|
|
@@ -2491,7 +2846,7 @@ Examples:
|
|
|
2491
2846
|
).action(async function() {
|
|
2492
2847
|
const opts = this.optsWithGlobals();
|
|
2493
2848
|
const client = await resolveClient(opts);
|
|
2494
|
-
const result = await client.get("/messenger", void 0,
|
|
2849
|
+
const result = await client.get("/messenger", void 0, UNSTABLE_HEADERS2);
|
|
2495
2850
|
const r = result;
|
|
2496
2851
|
render(
|
|
2497
2852
|
result,
|
|
@@ -2518,7 +2873,7 @@ Examples:
|
|
|
2518
2873
|
const opts = this.optsWithGlobals();
|
|
2519
2874
|
const client = await resolveClient(opts);
|
|
2520
2875
|
const body = parseFieldArgs(opts.field ?? []);
|
|
2521
|
-
const result = await client.put("/messenger", body,
|
|
2876
|
+
const result = await client.put("/messenger", body, UNSTABLE_HEADERS2);
|
|
2522
2877
|
const r = result;
|
|
2523
2878
|
render(
|
|
2524
2879
|
result,
|
|
@@ -3183,20 +3538,26 @@ function registerWorkflowsCommand(fin) {
|
|
|
3183
3538
|
return table({ columns: ["ID", "TITLE", "STATE", "TRIGGER"], rows });
|
|
3184
3539
|
}, items);
|
|
3185
3540
|
});
|
|
3186
|
-
workflows.command("get <id> [output]").description("Get a workflow by ID as YAML (writes to [output] file, or stdout)").option("--json", "Output as parsed JSON instead of YAML").option("--jq <expr>", "Filter parsed-JSON output with a jq expression").option("--verbose", "Show HTTP request/response details").addHelpText(
|
|
3541
|
+
workflows.command("get <id> [output]").description("Get a workflow by ID as YAML (writes to [output] file, or stdout)").option("--json", "Output as parsed JSON instead of YAML").option("--jq <expr>", "Filter parsed-JSON output with a jq expression").option("--version <version_id>", "Download a historical version instead of the current one").option("--verbose", "Show HTTP request/response details").addHelpText(
|
|
3187
3542
|
"after",
|
|
3188
3543
|
`
|
|
3189
3544
|
Examples:
|
|
3190
3545
|
$ intercom fin workflows get 42 workflow.yaml # write YAML to a file
|
|
3191
3546
|
$ intercom fin workflows get 42 > workflow.yaml # or redirect stdout
|
|
3192
3547
|
$ intercom fin workflows get 42 --json | jq .state
|
|
3548
|
+
$ intercom fin workflows versions 42 # find a version ID
|
|
3549
|
+
$ intercom fin workflows get 42 --version 4821 # print that version's YAML
|
|
3193
3550
|
|
|
3194
3551
|
The YAML it prints is ready to edit and re-upload with
|
|
3195
|
-
\`intercom fin workflows upload
|
|
3552
|
+
\`intercom fin workflows upload\`.
|
|
3553
|
+
|
|
3554
|
+
--version downloads the re-uploadable YAML of a historical version, so you can
|
|
3555
|
+
diff a local file against what is live (\`intercom fin workflows versions <id>\`
|
|
3556
|
+
shows which version that is).`
|
|
3196
3557
|
).action(async function(id, output) {
|
|
3197
3558
|
const opts = this.optsWithGlobals();
|
|
3198
3559
|
const client = await resolveClient(opts);
|
|
3199
|
-
const text = await client.getText(`/fin-sdk/workflows/${id}`);
|
|
3560
|
+
const text = opts.version ? await getVersionYaml2(client, id, opts.version) : await client.getText(`/fin-sdk/workflows/${id}`);
|
|
3200
3561
|
if (opts.json || opts.jq || opts.agent) {
|
|
3201
3562
|
const parsed = parseYaml3(text);
|
|
3202
3563
|
render(parsed, opts, () => formatJson(parsed));
|
|
@@ -3314,6 +3675,45 @@ overwritten (the server does not expose a concurrency token).`
|
|
|
3314
3675
|
})
|
|
3315
3676
|
);
|
|
3316
3677
|
});
|
|
3678
|
+
workflows.command("versions <id>").description("List a workflow's server-side version history (which one is live)").option("--json", "Output as JSON").option("--jq <expr>", "Filter JSON output with jq expression").option("--verbose", "Show HTTP request/response details").addHelpText(
|
|
3679
|
+
"after",
|
|
3680
|
+
`
|
|
3681
|
+
Examples:
|
|
3682
|
+
$ intercom fin workflows versions 42
|
|
3683
|
+
$ intercom fin workflows versions 42 --jq '.entity_version_id'
|
|
3684
|
+
|
|
3685
|
+
STATUS is the server's own vocabulary: live is what Fin is running now, draft is
|
|
3686
|
+
unpublished, previously_live is superseded. Download any of them with
|
|
3687
|
+
\`intercom fin workflows get <id> --version <VERSION>\`.`
|
|
3688
|
+
).action(async function(id) {
|
|
3689
|
+
const opts = this.optsWithGlobals();
|
|
3690
|
+
const client = await resolveClient(opts);
|
|
3691
|
+
const result = await client.get(`/fin-sdk/workflows/${id}/versions`);
|
|
3692
|
+
const items = result.versions ?? [];
|
|
3693
|
+
render(items, opts, () => {
|
|
3694
|
+
if (items.length === 0) {
|
|
3695
|
+
return "No versions found.";
|
|
3696
|
+
}
|
|
3697
|
+
const rows = items.map((v) => ({
|
|
3698
|
+
VERSION: String(v.entity_version_id ?? ""),
|
|
3699
|
+
STATUS: String(v.status ?? ""),
|
|
3700
|
+
CREATED: String(v.created_at ?? ""),
|
|
3701
|
+
AUTHOR: String(v.author?.name ?? ""),
|
|
3702
|
+
NOTE: String(v.note ?? "")
|
|
3703
|
+
}));
|
|
3704
|
+
return table({ columns: ["VERSION", "STATUS", "CREATED", "AUTHOR", "NOTE"], rows });
|
|
3705
|
+
}, items);
|
|
3706
|
+
});
|
|
3707
|
+
}
|
|
3708
|
+
async function getVersionYaml2(client, id, versionId) {
|
|
3709
|
+
const result = await client.get(
|
|
3710
|
+
`/fin-sdk/workflows/${id}/versions/${versionId}`
|
|
3711
|
+
);
|
|
3712
|
+
const content = result.content;
|
|
3713
|
+
if (content == null) {
|
|
3714
|
+
throw new CLIError(`Workflow version ${versionId} returned no content`);
|
|
3715
|
+
}
|
|
3716
|
+
return typeof content === "string" ? content : stringifyYaml3(content);
|
|
3317
3717
|
}
|
|
3318
3718
|
|
|
3319
3719
|
// src/commands/fin/simulations.ts
|
|
@@ -4776,6 +5176,7 @@ Environment: Set INTERCOM_TOKEN to skip login entirely.`;
|
|
|
4776
5176
|
registerAuthCommand(program);
|
|
4777
5177
|
registerMeCommand(program);
|
|
4778
5178
|
registerArticlesCommand(program);
|
|
5179
|
+
registerInternalArticlesCommand(program);
|
|
4779
5180
|
registerContactsCommand(program);
|
|
4780
5181
|
registerConversationsCommand(program);
|
|
4781
5182
|
registerHelpCenterCommand(program);
|