@intercom/cli 0.7.0 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +90 -0
- package/README.md +35 -5
- package/dist/{chunk-3V2ONMAU.js → chunk-HMPO42TQ.js} +1 -1
- package/dist/index.js +233 -30
- package/dist/{json-OEUXXCTX.js → json-BJB55URV.js} +2 -2
- package/package.json +8 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the Intercom CLI are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
View it from the CLI with `intercom changelog`.
|
|
9
|
+
|
|
10
|
+
## [0.8.2] - 2026-06-17
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- EU- and AU-hosted workspaces now send API requests to their regional host (`api.eu.intercom.io` / `api.au.intercom.io`) automatically. `intercom auth login` detects the workspace's region from `/me` and stores it, so commands route correctly. This fixes `fin workflows upload` (and `enable`/`disable`) failing with `No file provided` for EU/AU workspaces, which happened because uploads to the US host were proxied cross-region in a way that dropped the file. Existing EU/AU users should run `intercom auth login --token <token>` once to record their region. You can still override the host with `INTERCOM_API_BASE_URL`, or set `INTERCOM_REGION=eu|au|us` when authenticating via the `INTERCOM_TOKEN` environment variable.
|
|
15
|
+
|
|
16
|
+
## [0.8.1] - 2026-06-16
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Show the server's actual error message on failed requests instead of a bare `HTTP <status>`. This covers Fin SDK endpoints like `fin workflows upload` and `fin procedures upload`, which report problems (e.g. `YAML syntax error`, `Invalid file content`, `File too large`) in a different format than the rest of the API. `--verbose` now also prints the response body on errors.
|
|
21
|
+
- `fin workflows enable` and `fin workflows disable` now send the workflow state as the name the server expects (`live`/`paused`) instead of an internal numeric value, which the upload endpoint rejected. Both commands work again.
|
|
22
|
+
|
|
23
|
+
## [0.7.0] - 2026-06-10
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
- `intercom changelog` command to view the CLI's release notes from the terminal
|
|
28
|
+
- `fin data-connectors versions <id>` to view a data connector's version history
|
|
29
|
+
- Auto-enable fin-sdk and retry when a fin command hits the gate (#102)
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- `fin data-connectors list` now shows each connector's state
|
|
34
|
+
- `fin data-connectors get` now shows the full connector definition (method, URL, inputs, outputs)
|
|
35
|
+
- `fin data-connectors create` now takes `--name` and returns the URL to finish configuring the connector in the UI
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- Handle `login_verification` redirect in CLI sign-in (#99)
|
|
40
|
+
|
|
41
|
+
## [0.6.0] - 2026-05-25
|
|
42
|
+
|
|
43
|
+
### Added
|
|
44
|
+
|
|
45
|
+
- `fin workflows upload`, `fin workflows enable`, and `fin workflows disable` (#95)
|
|
46
|
+
- `fin monitor pull-flagged` and `fin conversation bulk-send` (#83)
|
|
47
|
+
|
|
48
|
+
### Changed
|
|
49
|
+
|
|
50
|
+
- Strip internal fields from conversation responses (#97)
|
|
51
|
+
|
|
52
|
+
### Fixed
|
|
53
|
+
|
|
54
|
+
- Target the correct workspace during bootstrap (#96)
|
|
55
|
+
- Parse `fin workflows get` output as YAML, not JSON (#90)
|
|
56
|
+
|
|
57
|
+
## [0.5.0] - 2026-04-27
|
|
58
|
+
|
|
59
|
+
### Added
|
|
60
|
+
|
|
61
|
+
- Emit a Claude Code plugin hint from `--help` and `auth login` (#91)
|
|
62
|
+
|
|
63
|
+
## [0.4.0] - 2026-04-20
|
|
64
|
+
|
|
65
|
+
### Added
|
|
66
|
+
|
|
67
|
+
- `articles search` subcommand (#85)
|
|
68
|
+
- `pricing` command to fetch live pricing information (#67)
|
|
69
|
+
- `fin guidance create` command (#69)
|
|
70
|
+
- `fin` as a binary alias for `intercom` (#66)
|
|
71
|
+
- `intercom config` command (#43)
|
|
72
|
+
- `auth list` and `auth switch` commands (#41)
|
|
73
|
+
- Global `--dry-run` / `-n` flag (#48)
|
|
74
|
+
- `--input` flag on the `api` command and search subcommands (#46)
|
|
75
|
+
- Color output and a `--wide` flag for tables (#44)
|
|
76
|
+
- 5xx retry with exponential backoff (#49)
|
|
77
|
+
|
|
78
|
+
### Changed
|
|
79
|
+
|
|
80
|
+
- Strip article bodies from list/search by default (#86)
|
|
81
|
+
- Default messenger snippets to JWT authentication (#81)
|
|
82
|
+
|
|
83
|
+
### Fixed
|
|
84
|
+
|
|
85
|
+
- Improve `setup` command reliability for greenfield workspaces (#64)
|
|
86
|
+
|
|
87
|
+
[0.7.0]: https://github.com/intercom/cli/releases/tag/v0.7.0
|
|
88
|
+
[0.6.0]: https://github.com/intercom/cli/releases/tag/v0.6.0
|
|
89
|
+
[0.5.0]: https://github.com/intercom/cli/releases/tag/v0.5.0
|
|
90
|
+
[0.4.0]: https://github.com/intercom/cli/releases/tag/v0.4.0
|
package/README.md
CHANGED
|
@@ -73,6 +73,7 @@ intercom setup --company-name "Acme" --articles-from ./docs
|
|
|
73
73
|
| `intercom setup` | Orchestrate full workspace setup |
|
|
74
74
|
| `intercom config get\|set\|list` | Manage CLI configuration |
|
|
75
75
|
| `intercom pricing` | Show current Intercom pricing |
|
|
76
|
+
| `intercom changelog` | Show the CLI's release notes / version history |
|
|
76
77
|
| `intercom completion bash\|zsh\|fish` | Generate shell completions |
|
|
77
78
|
|
|
78
79
|
## Global Flags
|
|
@@ -141,11 +142,11 @@ intercom api /contacts --jq '.data[].email'
|
|
|
141
142
|
```bash
|
|
142
143
|
git clone git@github.com:intercom/cli.git
|
|
143
144
|
cd cli
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
145
|
+
pnpm install
|
|
146
|
+
pnpm build # Build to dist/
|
|
147
|
+
pnpm test # Run tests (~5s)
|
|
148
|
+
pnpm lint # TypeScript typecheck
|
|
149
|
+
pnpm dev # Watch mode
|
|
149
150
|
|
|
150
151
|
# Try it locally
|
|
151
152
|
export INTERCOM_TOKEN="<your-token>"
|
|
@@ -154,6 +155,35 @@ node dist/index.js me
|
|
|
154
155
|
|
|
155
156
|
See [SETUP.md](SETUP.md) for full developer setup guide.
|
|
156
157
|
|
|
158
|
+
## Releasing
|
|
159
|
+
|
|
160
|
+
Publishing `@intercom/cli` to npm runs through `.github/workflows/publish.yml`, which fires when a GitHub Release is published. It uses OIDC trusted publishing (GitHub Actions mints a short-lived token per run, so there is no long-lived `NPM_TOKEN`) and npm staged publishing, which holds every version behind a human 2FA approval before it becomes installable. The org-wide reference is the [Engineering Wiki: Release new npm package versions](https://coda.io/d/Engineering-Wiki_duvlW1VbQXK/Release-new-npm-package-versions_suK1gai4).
|
|
161
|
+
|
|
162
|
+
### Prerequisites (one-time)
|
|
163
|
+
|
|
164
|
+
- **GitHub:** write access to this repo, to bump the version and create Releases.
|
|
165
|
+
- **npm:** to approve a staged release, log in to npmjs.com as `intercom-npm-publisher` (the package owner). Credentials are in the 1Password Engineering Vault.
|
|
166
|
+
|
|
167
|
+
### Cut a stable release
|
|
168
|
+
|
|
169
|
+
1. **Bump the version.** In a PR, set the new `version` in `package.json` and move the unreleased entries in `CHANGELOG.md` under a new `## [X.Y.Z] - YYYY-MM-DD` heading. Merge it to `main` — the workflow refuses any release that is not reachable from the default branch.
|
|
170
|
+
2. **Create a GitHub Release.** From the [Releases page](https://github.com/intercom/cli/releases/new), add a tag `vX.Y.Z` that matches `package.json` exactly (the `v` prefix is required; the workflow asserts `tag == version`). Leave the release label as **None**. Publishing the Release creates the tag and triggers `publish.yml`.
|
|
171
|
+
3. **Wait for the workflow.** It runs the tag and branch guards, builds, then runs `npm stage publish` over OIDC. When the Actions run is green, the version sits in npm's staged queue — uploaded but not yet installable.
|
|
172
|
+
4. **Approve in npm.** Logged in as `intercom-npm-publisher`, open [Staged Packages](https://www.npmjs.com/settings/intercom-npm-publisher/staged-packages), review the version, and **Approve** with 2FA. A stable version publishes to the `latest` dist-tag and is then installable via `npm install -g @intercom/cli`.
|
|
173
|
+
|
|
174
|
+
### Cut a prerelease
|
|
175
|
+
|
|
176
|
+
Same path and same approval gate; a prerelease lands on the `next` dist-tag instead of `latest`.
|
|
177
|
+
|
|
178
|
+
1. Bump `package.json` to a version with a `-` suffix (e.g. `X.Y.Z-beta.1`) and merge to `main` via PR. Prereleases come from the default branch too.
|
|
179
|
+
2. Create a GitHub Release tagged `vX.Y.Z-beta.1` from that commit (the tag must match the version) and tick **Set as a pre-release**.
|
|
180
|
+
3. The workflow detects the `-` suffix and stages to the `next` tag, never `latest`.
|
|
181
|
+
4. Approve the staged version with 2FA as above. Consumers opt in explicitly with `npm install -g @intercom/cli@next`; a plain install still resolves to stable `latest`.
|
|
182
|
+
|
|
183
|
+
### Reject a staged release
|
|
184
|
+
|
|
185
|
+
If a staged version should not ship, choose **Reject** in Staged Packages and it is removed without publishing. Rejecting leaves the git tag and GitHub Release behind, so also delete the Release and tag from the GitHub Releases UI. The version can then be re-staged — only published versions are immutable.
|
|
186
|
+
|
|
157
187
|
## License
|
|
158
188
|
|
|
159
189
|
MIT
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
applyJq,
|
|
10
10
|
detectAuthType,
|
|
11
11
|
formatJson
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-HMPO42TQ.js";
|
|
13
13
|
|
|
14
14
|
// src/index.ts
|
|
15
15
|
import { Command } from "commander";
|
|
@@ -61,6 +61,25 @@ async function fetchWithTimeout(url, init, options) {
|
|
|
61
61
|
|
|
62
62
|
// src/api/client.ts
|
|
63
63
|
var DEFAULT_BASE_URL = "https://api.intercom.io";
|
|
64
|
+
var MAX_RAW_ERROR_LEN = 500;
|
|
65
|
+
function extractApiError(body) {
|
|
66
|
+
if (!body || typeof body !== "object") return {};
|
|
67
|
+
const b = body;
|
|
68
|
+
if (Array.isArray(b.errors) && b.errors.length > 0) {
|
|
69
|
+
const first = b.errors[0];
|
|
70
|
+
return {
|
|
71
|
+
message: typeof first?.message === "string" ? first.message : void 0,
|
|
72
|
+
code: typeof first?.code === "string" ? first.code : void 0
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
if (typeof b.error === "string") return { message: b.error };
|
|
76
|
+
if (b.errors && typeof b.errors === "object") {
|
|
77
|
+
const msgs = Object.values(b.errors).flat().filter((m) => typeof m === "string");
|
|
78
|
+
if (msgs.length > 0) return { message: msgs.join("; ") };
|
|
79
|
+
}
|
|
80
|
+
if (typeof b.message === "string") return { message: b.message };
|
|
81
|
+
return {};
|
|
82
|
+
}
|
|
64
83
|
var _dryRun = false;
|
|
65
84
|
function setDryRun(enabled) {
|
|
66
85
|
_dryRun = enabled;
|
|
@@ -189,9 +208,21 @@ var IntercomClient = class _IntercomClient {
|
|
|
189
208
|
return response.json();
|
|
190
209
|
}
|
|
191
210
|
}
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
211
|
+
const rawBody = await response.text().catch(() => "");
|
|
212
|
+
if (this.verbose && rawBody) {
|
|
213
|
+
console.error(`< Body: ${rawBody}`);
|
|
214
|
+
}
|
|
215
|
+
let parsedBody;
|
|
216
|
+
try {
|
|
217
|
+
parsedBody = rawBody ? JSON.parse(rawBody) : void 0;
|
|
218
|
+
} catch {
|
|
219
|
+
parsedBody = void 0;
|
|
220
|
+
}
|
|
221
|
+
const extracted = extractApiError(parsedBody);
|
|
222
|
+
const trimmedBody = rawBody.trim();
|
|
223
|
+
const rawFallback = trimmedBody.length > MAX_RAW_ERROR_LEN ? `${trimmedBody.slice(0, MAX_RAW_ERROR_LEN)}\u2026` : trimmedBody;
|
|
224
|
+
const errorMsg = extracted.message ?? (rawFallback || `HTTP ${response.status}`);
|
|
225
|
+
const errorCode = extracted.code ?? "";
|
|
195
226
|
if (response.status === 401) {
|
|
196
227
|
throw new AuthError(
|
|
197
228
|
`Authentication expired or invalid: ${errorMsg}. Run "intercom auth login" to re-authenticate.`
|
|
@@ -316,6 +347,43 @@ var IntercomClient = class _IntercomClient {
|
|
|
316
347
|
}
|
|
317
348
|
};
|
|
318
349
|
|
|
350
|
+
// src/api/regions.ts
|
|
351
|
+
var REGION_BASE_URLS = {
|
|
352
|
+
us: "https://api.intercom.io",
|
|
353
|
+
eu: "https://api.eu.intercom.io",
|
|
354
|
+
au: "https://api.au.intercom.io"
|
|
355
|
+
};
|
|
356
|
+
function regionBaseUrl(region) {
|
|
357
|
+
if (!region) return void 0;
|
|
358
|
+
return REGION_BASE_URLS[region];
|
|
359
|
+
}
|
|
360
|
+
function normalizeRegion(value) {
|
|
361
|
+
if (typeof value !== "string") return void 0;
|
|
362
|
+
switch (value.trim().toLowerCase()) {
|
|
363
|
+
case "us":
|
|
364
|
+
case "usa":
|
|
365
|
+
case "united states":
|
|
366
|
+
return "us";
|
|
367
|
+
case "eu":
|
|
368
|
+
case "europe":
|
|
369
|
+
return "eu";
|
|
370
|
+
case "au":
|
|
371
|
+
case "australia":
|
|
372
|
+
return "au";
|
|
373
|
+
default:
|
|
374
|
+
return void 0;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
function detectRegion(me) {
|
|
378
|
+
if (!me || typeof me !== "object") return void 0;
|
|
379
|
+
const m = me;
|
|
380
|
+
const app = m.app;
|
|
381
|
+
return normalizeRegion(app?.region ?? m.region);
|
|
382
|
+
}
|
|
383
|
+
function resolveBaseUrl(region) {
|
|
384
|
+
return process.env.INTERCOM_API_BASE_URL || regionBaseUrl(region) || void 0;
|
|
385
|
+
}
|
|
386
|
+
|
|
319
387
|
// src/auth/store.ts
|
|
320
388
|
import { readFileSync, mkdirSync } from "fs";
|
|
321
389
|
|
|
@@ -552,7 +620,7 @@ async function resolveClient(options = {}) {
|
|
|
552
620
|
token: envToken,
|
|
553
621
|
authType: detectAuthType(envToken),
|
|
554
622
|
appId: process.env.INTERCOM_APP_ID ?? "",
|
|
555
|
-
baseUrl: process.env.
|
|
623
|
+
baseUrl: resolveBaseUrl(normalizeRegion(process.env.INTERCOM_REGION)),
|
|
556
624
|
verbose: options.verbose,
|
|
557
625
|
maxRetries: options.retry === false ? 0 : void 0,
|
|
558
626
|
timeoutMs: options.timeout ? parseInt(options.timeout, 10) * 1e3 : void 0
|
|
@@ -582,7 +650,7 @@ async function resolveClient(options = {}) {
|
|
|
582
650
|
token: cred.token,
|
|
583
651
|
authType: cred.auth_type,
|
|
584
652
|
appId: cred.app_id,
|
|
585
|
-
baseUrl:
|
|
653
|
+
baseUrl: resolveBaseUrl(cred.region),
|
|
586
654
|
verbose: options.verbose,
|
|
587
655
|
maxRetries: options.retry === false ? 0 : void 0,
|
|
588
656
|
timeoutMs: options.timeout ? parseInt(options.timeout, 10) * 1e3 : void 0
|
|
@@ -802,11 +870,13 @@ async function loginWithToken(token) {
|
|
|
802
870
|
const app = me.app;
|
|
803
871
|
const appId = app?.id_code ?? me.id;
|
|
804
872
|
const name = app?.name ?? "Unknown";
|
|
873
|
+
const region = detectRegion(me);
|
|
805
874
|
const configDir2 = process.env.INTERCOM_CONFIG_DIR;
|
|
806
875
|
const store = new CredentialStore(createDefaultBackend(configDir2));
|
|
807
|
-
await store.set(appId, { token, auth_type: authType, app_id: appId });
|
|
808
|
-
await addWorkspace(configDir2, { app_id: appId, name });
|
|
809
|
-
|
|
876
|
+
await store.set(appId, { token, auth_type: authType, app_id: appId, region });
|
|
877
|
+
await addWorkspace(configDir2, { app_id: appId, name, region });
|
|
878
|
+
const regionLabel = region ? ` [${region.toUpperCase()}]` : "";
|
|
879
|
+
console.log(`Authenticated to ${name} (${appId})${regionLabel}`);
|
|
810
880
|
emitClaudeCodeHint();
|
|
811
881
|
}
|
|
812
882
|
|
|
@@ -2545,9 +2615,13 @@ function registerProceduresCommand(fin) {
|
|
|
2545
2615
|
}
|
|
2546
2616
|
|
|
2547
2617
|
// src/commands/fin/data-connectors.ts
|
|
2618
|
+
function summarizeKeys(obj) {
|
|
2619
|
+
if (!obj) return "";
|
|
2620
|
+
return Object.keys(obj).join(", ");
|
|
2621
|
+
}
|
|
2548
2622
|
function registerDataConnectorsCommand(fin) {
|
|
2549
2623
|
const dataConnectors = fin.command("data-connectors").description("Manage Fin SDK data connectors");
|
|
2550
|
-
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() {
|
|
2624
|
+
dataConnectors.command("list").description("List data connectors from the Fin SDK manifest").option("--json", "Output as JSON").option("--jq <expr>", "Filter JSON output with jq expression").option("--verbose", "Show HTTP request/response details").action(async function() {
|
|
2551
2625
|
const opts = this.optsWithGlobals();
|
|
2552
2626
|
const client = await resolveClient(opts);
|
|
2553
2627
|
const result = await client.get("/fin-sdk/manifest");
|
|
@@ -2559,33 +2633,38 @@ function registerDataConnectorsCommand(fin) {
|
|
|
2559
2633
|
}
|
|
2560
2634
|
const rows = items.map((item) => ({
|
|
2561
2635
|
ID: String(item.id ?? ""),
|
|
2562
|
-
NAME: String(item.name ?? "")
|
|
2636
|
+
NAME: String(item.name ?? ""),
|
|
2637
|
+
STATE: String(item.state ?? "")
|
|
2563
2638
|
}));
|
|
2564
|
-
return table({ columns: ["ID", "NAME"], rows });
|
|
2639
|
+
return table({ columns: ["ID", "NAME", "STATE"], rows });
|
|
2565
2640
|
}, items);
|
|
2566
2641
|
});
|
|
2567
|
-
dataConnectors.command("create").description("Create a data connector").requiredOption("
|
|
2642
|
+
dataConnectors.command("create").description("Create a draft data connector (finish configuration in the UI)").requiredOption("--name <name>", "Name for the new data connector").option("--json", "Output as JSON").option("--jq <expr>", "Filter JSON output with jq expression").option("--verbose", "Show HTTP request/response details").addHelpText(
|
|
2643
|
+
"after",
|
|
2644
|
+
`
|
|
2645
|
+
The create endpoint only sets the name \u2014 it returns a web_url where you finish
|
|
2646
|
+
configuring the connector (request, inputs, outputs, auth) in the Intercom UI.
|
|
2647
|
+
|
|
2648
|
+
Example:
|
|
2649
|
+
$ intercom fin data-connectors create --name "Order lookup"`
|
|
2650
|
+
).action(async function() {
|
|
2568
2651
|
const opts = this.optsWithGlobals();
|
|
2569
2652
|
const client = await resolveClient(opts);
|
|
2570
|
-
const
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
const eq = f.indexOf("=");
|
|
2574
|
-
if (eq === -1) throw new Error(`Invalid field format: ${f}. Expected key=value`);
|
|
2575
|
-
body[f.slice(0, eq)] = f.slice(eq + 1);
|
|
2576
|
-
}
|
|
2577
|
-
const result = await client.post("/fin-sdk/data-connectors", body);
|
|
2653
|
+
const result = await client.post("/fin-sdk/data-connectors", {
|
|
2654
|
+
name: opts.name
|
|
2655
|
+
});
|
|
2578
2656
|
render(
|
|
2579
2657
|
result,
|
|
2580
2658
|
opts,
|
|
2581
2659
|
() => detail({
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
"
|
|
2660
|
+
ID: String(result.id ?? ""),
|
|
2661
|
+
Name: String(result.name ?? ""),
|
|
2662
|
+
"Web URL": result.web_url != null ? String(result.web_url) : void 0,
|
|
2663
|
+
"Next step": result.message != null ? String(result.message) : void 0
|
|
2585
2664
|
})
|
|
2586
2665
|
);
|
|
2587
2666
|
});
|
|
2588
|
-
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) {
|
|
2667
|
+
dataConnectors.command("get <id>").description("Download a data connector's full definition 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) {
|
|
2589
2668
|
const opts = this.optsWithGlobals();
|
|
2590
2669
|
const client = await resolveClient(opts);
|
|
2591
2670
|
const result = await client.get(`/fin-sdk/data-connectors/${id}/download`);
|
|
@@ -2593,11 +2672,36 @@ function registerDataConnectorsCommand(fin) {
|
|
|
2593
2672
|
result,
|
|
2594
2673
|
opts,
|
|
2595
2674
|
() => detail({
|
|
2596
|
-
|
|
2597
|
-
|
|
2675
|
+
ID: String(result.id ?? ""),
|
|
2676
|
+
Name: String(result.name ?? ""),
|
|
2677
|
+
State: result.state != null ? String(result.state) : void 0,
|
|
2678
|
+
Description: result.description != null ? String(result.description) : void 0,
|
|
2679
|
+
"Direct Fin usage": result.enable_direct_usage != null ? String(result.enable_direct_usage) : void 0,
|
|
2680
|
+
Method: result.request?.method != null ? String(result.request.method) : void 0,
|
|
2681
|
+
URL: result.request?.url != null ? String(result.request.url) : void 0,
|
|
2682
|
+
Inputs: summarizeKeys(result.inputs) || void 0,
|
|
2683
|
+
Outputs: summarizeKeys(result.outputs) || void 0
|
|
2598
2684
|
})
|
|
2599
2685
|
);
|
|
2600
2686
|
});
|
|
2687
|
+
dataConnectors.command("versions <id>").description("List a data connector's server-side version history").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) {
|
|
2688
|
+
const opts = this.optsWithGlobals();
|
|
2689
|
+
const client = await resolveClient(opts);
|
|
2690
|
+
const result = await client.get(`/fin-sdk/data-connectors/${id}/versions`);
|
|
2691
|
+
const items = result.versions ?? [];
|
|
2692
|
+
render(items, opts, () => {
|
|
2693
|
+
if (items.length === 0) {
|
|
2694
|
+
return "No versions found.";
|
|
2695
|
+
}
|
|
2696
|
+
const rows = items.map((v) => ({
|
|
2697
|
+
STATUS: String(v.status ?? ""),
|
|
2698
|
+
CREATED: String(v.created_at ?? ""),
|
|
2699
|
+
AUTHOR: String(v.author?.name ?? ""),
|
|
2700
|
+
NOTE: String(v.note ?? "")
|
|
2701
|
+
}));
|
|
2702
|
+
return table({ columns: ["STATUS", "CREATED", "AUTHOR", "NOTE"], rows });
|
|
2703
|
+
}, items);
|
|
2704
|
+
});
|
|
2601
2705
|
}
|
|
2602
2706
|
|
|
2603
2707
|
// src/commands/fin/guidance.ts
|
|
@@ -2708,8 +2812,8 @@ function registerAudiencesCommand(fin) {
|
|
|
2708
2812
|
import { readFile as readFile3 } from "fs/promises";
|
|
2709
2813
|
import { basename as basename2 } from "path";
|
|
2710
2814
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
2711
|
-
var STATE_LIVE =
|
|
2712
|
-
var STATE_PAUSED =
|
|
2815
|
+
var STATE_LIVE = "live";
|
|
2816
|
+
var STATE_PAUSED = "paused";
|
|
2713
2817
|
function registerWorkflowsCommand(fin) {
|
|
2714
2818
|
const workflows = fin.command("workflows").description("Manage Fin SDK workflows");
|
|
2715
2819
|
workflows.command("list").description("List Fin SDK workflows").option("--json", "Output as JSON").option("--verbose", "Show HTTP request/response details").action(async function() {
|
|
@@ -4025,7 +4129,7 @@ function registerPricingCommand(program) {
|
|
|
4025
4129
|
}
|
|
4026
4130
|
const markdown = await response.text();
|
|
4027
4131
|
if (opts.json) {
|
|
4028
|
-
const { formatJson: formatJson2 } = await import("./json-
|
|
4132
|
+
const { formatJson: formatJson2 } = await import("./json-BJB55URV.js");
|
|
4029
4133
|
console.log(formatJson2({ url: PRICING_URL, content: markdown }));
|
|
4030
4134
|
} else {
|
|
4031
4135
|
console.log(markdown);
|
|
@@ -4127,6 +4231,104 @@ function registerConfigCommand(program) {
|
|
|
4127
4231
|
});
|
|
4128
4232
|
}
|
|
4129
4233
|
|
|
4234
|
+
// src/commands/changelog.ts
|
|
4235
|
+
import pc2 from "picocolors";
|
|
4236
|
+
|
|
4237
|
+
// src/changelog.ts
|
|
4238
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
4239
|
+
import { fileURLToPath } from "url";
|
|
4240
|
+
var RELEASE_RE = /^##\s+\[?([^\]]+?)\]?(?:\s+-\s+(.+))?$/;
|
|
4241
|
+
var SECTION_RE = /^###\s+(.+)$/;
|
|
4242
|
+
var ENTRY_RE = /^[-*]\s+(.+)$/;
|
|
4243
|
+
function parseChangelog(markdown) {
|
|
4244
|
+
const releases = [];
|
|
4245
|
+
let release = null;
|
|
4246
|
+
let section = null;
|
|
4247
|
+
for (const raw of markdown.split("\n")) {
|
|
4248
|
+
const line = raw.trimEnd();
|
|
4249
|
+
const releaseMatch = line.match(RELEASE_RE);
|
|
4250
|
+
if (releaseMatch) {
|
|
4251
|
+
release = { version: releaseMatch[1].trim(), date: releaseMatch[2]?.trim() ?? "", sections: [] };
|
|
4252
|
+
section = null;
|
|
4253
|
+
releases.push(release);
|
|
4254
|
+
continue;
|
|
4255
|
+
}
|
|
4256
|
+
if (!release) continue;
|
|
4257
|
+
const sectionMatch = line.match(SECTION_RE);
|
|
4258
|
+
if (sectionMatch) {
|
|
4259
|
+
section = { title: sectionMatch[1].trim(), entries: [] };
|
|
4260
|
+
release.sections.push(section);
|
|
4261
|
+
continue;
|
|
4262
|
+
}
|
|
4263
|
+
const entryMatch = line.match(ENTRY_RE);
|
|
4264
|
+
if (entryMatch && section) {
|
|
4265
|
+
section.entries.push(entryMatch[1].trim());
|
|
4266
|
+
}
|
|
4267
|
+
}
|
|
4268
|
+
return releases;
|
|
4269
|
+
}
|
|
4270
|
+
var cached;
|
|
4271
|
+
function loadChangelog() {
|
|
4272
|
+
if (cached) return cached;
|
|
4273
|
+
const path = fileURLToPath(new URL("../CHANGELOG.md", import.meta.url));
|
|
4274
|
+
cached = parseChangelog(readFileSync5(path, "utf8"));
|
|
4275
|
+
return cached;
|
|
4276
|
+
}
|
|
4277
|
+
|
|
4278
|
+
// src/commands/changelog.ts
|
|
4279
|
+
function normalizeVersion(v) {
|
|
4280
|
+
return v.replace(/^v/i, "");
|
|
4281
|
+
}
|
|
4282
|
+
function colorEnabled() {
|
|
4283
|
+
return !!process.stdout.isTTY && !process.env.NO_COLOR;
|
|
4284
|
+
}
|
|
4285
|
+
function renderHuman(releases) {
|
|
4286
|
+
const color = colorEnabled();
|
|
4287
|
+
const out = [];
|
|
4288
|
+
for (const release of releases) {
|
|
4289
|
+
const heading = release.date ? `${release.version} \u2014 ${release.date}` : release.version;
|
|
4290
|
+
out.push(color ? pc2.bold(heading) : heading);
|
|
4291
|
+
for (const section of release.sections) {
|
|
4292
|
+
out.push(` ${color ? pc2.dim(section.title) : section.title}`);
|
|
4293
|
+
for (const entry of section.entries) {
|
|
4294
|
+
out.push(` \u2022 ${entry}`);
|
|
4295
|
+
}
|
|
4296
|
+
}
|
|
4297
|
+
out.push("");
|
|
4298
|
+
}
|
|
4299
|
+
return out.join("\n").trimEnd();
|
|
4300
|
+
}
|
|
4301
|
+
function registerChangelogCommand(program) {
|
|
4302
|
+
program.command("changelog").description("Show the CLI's release notes / version history").argument("[version]", "Show a single version (e.g. 0.7.0)").option("-n, --limit <count>", "Show only the most recent <count> releases").option("--json", "Output as JSON").option("--jq <expr>", "Filter JSON output with jq expression").addHelpText(
|
|
4303
|
+
"after",
|
|
4304
|
+
`
|
|
4305
|
+
Examples:
|
|
4306
|
+
$ intercom changelog Show the full release history
|
|
4307
|
+
$ intercom changelog --limit 1 Show only the latest release
|
|
4308
|
+
$ intercom changelog 0.7.0 Show a specific version
|
|
4309
|
+
$ intercom changelog --json Machine-readable release history`
|
|
4310
|
+
).action(async function(version) {
|
|
4311
|
+
const opts = this.optsWithGlobals();
|
|
4312
|
+
let releases = loadChangelog();
|
|
4313
|
+
if (version) {
|
|
4314
|
+
const wanted = normalizeVersion(version);
|
|
4315
|
+
const match = releases.find((r) => normalizeVersion(r.version) === wanted);
|
|
4316
|
+
if (!match) {
|
|
4317
|
+
const known = releases.map((r) => r.version).join(", ");
|
|
4318
|
+
throw new CLIError(`No changelog entry for version "${version}". Known versions: ${known}`);
|
|
4319
|
+
}
|
|
4320
|
+
releases = [match];
|
|
4321
|
+
} else if (opts.limit !== void 0) {
|
|
4322
|
+
const limit = parseInt(String(opts.limit), 10);
|
|
4323
|
+
if (isNaN(limit) || limit <= 0) {
|
|
4324
|
+
throw new CLIError("--limit must be a positive integer");
|
|
4325
|
+
}
|
|
4326
|
+
releases = releases.slice(0, limit);
|
|
4327
|
+
}
|
|
4328
|
+
render(releases, opts, () => renderHuman(releases), releases);
|
|
4329
|
+
});
|
|
4330
|
+
}
|
|
4331
|
+
|
|
4130
4332
|
// src/index.ts
|
|
4131
4333
|
function detectBinaryName() {
|
|
4132
4334
|
const argv1 = process.argv[1] ?? "";
|
|
@@ -4171,6 +4373,7 @@ Environment: Set INTERCOM_TOKEN to skip login entirely.`;
|
|
|
4171
4373
|
registerPricingCommand(program);
|
|
4172
4374
|
registerCompletionCommand(program);
|
|
4173
4375
|
registerConfigCommand(program);
|
|
4376
|
+
registerChangelogCommand(program);
|
|
4174
4377
|
program.hook("preAction", (thisCommand, actionCommand) => {
|
|
4175
4378
|
const rootOpts = thisCommand.opts();
|
|
4176
4379
|
if (rootOpts.agent && rootOpts.human) {
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intercom/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"description": "CLI tool for managing Intercom workspaces",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"packageManager": "pnpm@10.23.0",
|
|
6
7
|
"bin": {
|
|
7
8
|
"intercom": "dist/index.js",
|
|
8
9
|
"fin": "dist/index.js"
|
|
@@ -20,7 +21,8 @@
|
|
|
20
21
|
},
|
|
21
22
|
"files": [
|
|
22
23
|
"dist",
|
|
23
|
-
"!dist/**/*.map"
|
|
24
|
+
"!dist/**/*.map",
|
|
25
|
+
"CHANGELOG.md"
|
|
24
26
|
],
|
|
25
27
|
"license": "MIT",
|
|
26
28
|
"dependencies": {
|
|
@@ -39,5 +41,9 @@
|
|
|
39
41
|
"tsup": "^8.5.1",
|
|
40
42
|
"typescript": "^5.9.3",
|
|
41
43
|
"vitest": "^4.1.0"
|
|
44
|
+
},
|
|
45
|
+
"pnpm": {
|
|
46
|
+
"overrides": {},
|
|
47
|
+
"onlyBuiltDependencies": []
|
|
42
48
|
}
|
|
43
49
|
}
|