@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 ADDED
@@ -0,0 +1,128 @@
1
+ # Intercom CLI
2
+
3
+ CLI tool for managing Intercom workspaces. Designed for both human operators and AI agents.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g @intercom/cli
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```bash
14
+ # Authenticate with your API token
15
+ export INTERCOM_TOKEN="<your-token>"
16
+
17
+ # Check your identity
18
+ intercom me
19
+
20
+ # List help center articles
21
+ intercom articles list
22
+
23
+ # Get a conversation
24
+ intercom conversations get <conversation-id>
25
+
26
+ # Set up a workspace with articles and Fin
27
+ intercom setup --company-name "Acme" --articles-from ./docs
28
+ ```
29
+
30
+ ## Commands
31
+
32
+ | Command | Description |
33
+ |---|---|
34
+ | `intercom api <endpoint>` | Raw API access (like `gh api`) |
35
+ | `intercom auth login` | Authenticate with token |
36
+ | `intercom auth logout` | Remove stored credentials |
37
+ | `intercom auth status` | Show current auth state |
38
+ | `intercom auth bootstrap` | Bootstrap OAuth via Developer Hub |
39
+ | `intercom me` | Show current admin and workspace |
40
+ | `intercom articles list\|get\|create\|update\|delete` | Manage help center articles |
41
+ | `intercom contacts list\|get\|create\|update\|delete` | Manage contacts |
42
+ | `intercom conversations list\|get\|reply` | Manage conversations |
43
+ | `intercom help-center list\|get\|create` | Manage help center collections |
44
+ | `intercom messenger get\|update\|snippet` | Configure Messenger |
45
+ | `intercom fin manifest` | Show Fin SDK manifest |
46
+ | `intercom fin enable` | Enable Fin AI Agent |
47
+ | `intercom fin guidance list\|get` | Manage Fin guidance |
48
+ | `intercom setup` | Orchestrate full workspace setup |
49
+
50
+ ## Global Flags
51
+
52
+ | Flag | Description |
53
+ |---|---|
54
+ | `--json` | Output as pretty-printed JSON |
55
+ | `--jq <expr>` | Filter JSON output (subset of jq) |
56
+ | `--workspace <id>` | Override default workspace |
57
+ | `--verbose` | Show HTTP request/response details |
58
+ | `--no-retry` | Disable automatic rate limit retry |
59
+ | `--timeout <seconds>` | Request timeout in seconds |
60
+ | `--version` | Print CLI version |
61
+
62
+ ## Agent / Pipe Mode
63
+
64
+ When stdout is not a TTY (piped to another program), the CLI automatically outputs compact NDJSON — one JSON object per line. No flag needed:
65
+
66
+ ```bash
67
+ # Automatic NDJSON when piped
68
+ intercom articles list | jq '.title'
69
+
70
+ # Force JSON with flag
71
+ intercom articles list --json
72
+
73
+ # Filter inline
74
+ intercom articles list --jq '.data[].title'
75
+ ```
76
+
77
+ ## Raw API Access
78
+
79
+ The `intercom api` command provides direct access to any Intercom API endpoint:
80
+
81
+ ```bash
82
+ # GET request (default)
83
+ intercom api /me
84
+
85
+ # POST with fields
86
+ intercom api /articles -f title="Hello" -f author_id=123
87
+
88
+ # Typed fields (booleans, numbers, file reads)
89
+ intercom api /articles -F draft:=true -F body=@article.html
90
+
91
+ # Auto-paginate
92
+ intercom api /articles --paginate
93
+
94
+ # Use jq to filter
95
+ intercom api /contacts --jq '.data[].email'
96
+ ```
97
+
98
+ ## Environment Variables
99
+
100
+ | Variable | Description |
101
+ |---|---|
102
+ | `INTERCOM_TOKEN` | API token (bypasses credential store) |
103
+ | `INTERCOM_API_BASE_URL` | Override API base URL |
104
+ | `INTERCOM_APP_BASE_URL` | Override app base URL |
105
+ | `INTERCOM_CONFIG_DIR` | Override config directory |
106
+ | `INTERCOM_PASSWORD` | Password for signup/bootstrap |
107
+
108
+ ## Development
109
+
110
+ ```bash
111
+ git clone git@github.com:intercom/cli.git
112
+ cd cli
113
+ npm ci
114
+ npm run build # Build to dist/
115
+ npm test # Run tests (~9s)
116
+ npm run lint # TypeScript typecheck
117
+ npm run dev # Watch mode
118
+
119
+ # Try it locally
120
+ export INTERCOM_TOKEN="<your-token>"
121
+ node dist/index.js me
122
+ ```
123
+
124
+ See [SETUP.md](SETUP.md) for full developer setup guide.
125
+
126
+ ## License
127
+
128
+ MIT
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/types.ts
4
+ var CLIError = class extends Error {
5
+ constructor(message, exitCode = 1, error) {
6
+ super(message);
7
+ this.exitCode = exitCode;
8
+ this.error = error;
9
+ this.name = "CLIError";
10
+ }
11
+ };
12
+ var AuthError = class extends CLIError {
13
+ constructor(message) {
14
+ super(message, 2);
15
+ }
16
+ };
17
+ var RateLimitError = class extends CLIError {
18
+ constructor(message, retryAfter) {
19
+ super(message, 3);
20
+ this.retryAfter = retryAfter;
21
+ }
22
+ };
23
+ var NotFoundError = class extends CLIError {
24
+ constructor(message) {
25
+ super(message, 4);
26
+ }
27
+ };
28
+ var PermissionError = class extends CLIError {
29
+ constructor(message) {
30
+ super(message, 5);
31
+ }
32
+ };
33
+ var TimeoutError = class extends CLIError {
34
+ constructor(message) {
35
+ super(message, 6);
36
+ }
37
+ };
38
+ function detectAuthType(token) {
39
+ try {
40
+ const decoded = Buffer.from(token, "base64").toString("utf-8");
41
+ if (decoded.startsWith("tok:")) {
42
+ return "oauth";
43
+ }
44
+ } catch {
45
+ }
46
+ return "api_key";
47
+ }
48
+
49
+ // src/output/json.ts
50
+ function formatJson(data) {
51
+ return JSON.stringify(data, null, 2);
52
+ }
53
+ function applyJq(data, expr) {
54
+ if (expr === ".") return data;
55
+ if (!expr.startsWith(".")) {
56
+ throw new CLIError(
57
+ `Unsupported jq expression: "${expr}". Supported: ".", ".field", ".field.nested", ".field[].nested"`
58
+ );
59
+ }
60
+ if (/[|(){},;]/.test(expr)) {
61
+ throw new CLIError(
62
+ `Unsupported jq expression: "${expr}". Supported: ".", ".field", ".field.nested", ".field[].nested"`
63
+ );
64
+ }
65
+ const parts = expr.replace(/^\.\s*/, "").split(/\./).filter(Boolean);
66
+ for (const part of parts) {
67
+ if (!/^\w+(\[\])?$/.test(part)) {
68
+ throw new CLIError(
69
+ `Unsupported jq expression: "${expr}". Supported: ".", ".field", ".field.nested", ".field[].nested"`
70
+ );
71
+ }
72
+ }
73
+ let current = data;
74
+ for (const part of parts) {
75
+ const arrayMatch = part.match(/^(\w+)\[\]$/);
76
+ if (arrayMatch) {
77
+ const key = arrayMatch[1];
78
+ if (current && typeof current === "object" && key in current) {
79
+ const arr = current[key];
80
+ if (!Array.isArray(arr)) return void 0;
81
+ current = arr;
82
+ } else {
83
+ return void 0;
84
+ }
85
+ } else if (Array.isArray(current)) {
86
+ current = current.map(
87
+ (item) => item && typeof item === "object" ? item[part] : void 0
88
+ );
89
+ } else if (current && typeof current === "object") {
90
+ current = current[part];
91
+ } else {
92
+ return void 0;
93
+ }
94
+ }
95
+ return current;
96
+ }
97
+
98
+ export {
99
+ CLIError,
100
+ AuthError,
101
+ RateLimitError,
102
+ NotFoundError,
103
+ PermissionError,
104
+ TimeoutError,
105
+ detectAuthType,
106
+ formatJson,
107
+ applyJq
108
+ };
109
+ //# sourceMappingURL=chunk-QEXGKXTU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts","../src/output/json.ts"],"sourcesContent":["export interface IntercomError {\n code: string;\n message: string;\n status: number;\n retry_after?: number;\n}\n\nexport class CLIError extends Error {\n constructor(\n message: string,\n public readonly exitCode: number = 1,\n public readonly error?: IntercomError,\n ) {\n super(message);\n this.name = \"CLIError\";\n }\n}\n\nexport class AuthError extends CLIError {\n constructor(message: string) {\n super(message, 2);\n }\n}\n\nexport class RateLimitError extends CLIError {\n constructor(\n message: string,\n public readonly retryAfter: number,\n ) {\n super(message, 3);\n }\n}\n\nexport class NotFoundError extends CLIError {\n constructor(message: string) {\n super(message, 4);\n }\n}\n\nexport class PermissionError extends CLIError {\n constructor(message: string) {\n super(message, 5);\n }\n}\n\nexport class TimeoutError extends CLIError {\n constructor(message: string) {\n super(message, 6);\n }\n}\n\nexport type AuthType = \"oauth\" | \"api_key\";\n\n/**\n * Detect whether a token is an OAuth token or an API key.\n * Eagle OAuth tokens are base64-encoded and decode to \"tok:...\" format.\n */\nexport function detectAuthType(token: string): AuthType {\n try {\n const decoded = Buffer.from(token, \"base64\").toString(\"utf-8\");\n if (decoded.startsWith(\"tok:\")) {\n return \"oauth\";\n }\n } catch {\n // Not valid base64 — assume API key\n }\n return \"api_key\";\n}\n\nexport interface StoredCredential {\n token: string;\n auth_type: AuthType;\n app_id: string;\n workspace_name?: string;\n expires_at?: string;\n}\n\nexport interface WorkspaceConfig {\n app_id: string;\n name: string;\n}\n\nexport interface Config {\n workspaces: Record<string, WorkspaceConfig>;\n default?: string;\n}\n\nexport interface PaginatedResponse<T> {\n type: \"list\";\n data: T[];\n pages?: {\n next?: string;\n page: number;\n per_page: number;\n total_pages: number;\n };\n}\n","import { CLIError } from \"../types.js\";\n\nexport function formatJson(data: unknown): string {\n return JSON.stringify(data, null, 2);\n}\n\nexport function applyJq(data: unknown, expr: string): unknown {\n if (expr === \".\") return data;\n\n // Must start with \".\"\n if (!expr.startsWith(\".\")) {\n throw new CLIError(\n `Unsupported jq expression: \"${expr}\". Supported: \".\", \".field\", \".field.nested\", \".field[].nested\"`,\n );\n }\n\n // Reject pipes, functions, parens, etc.\n if (/[|(){},;]/.test(expr)) {\n throw new CLIError(\n `Unsupported jq expression: \"${expr}\". Supported: \".\", \".field\", \".field.nested\", \".field[].nested\"`,\n );\n }\n\n const parts = expr.replace(/^\\.\\s*/, \"\").split(/\\./).filter(Boolean);\n\n for (const part of parts) {\n if (!/^\\w+(\\[\\])?$/.test(part)) {\n throw new CLIError(\n `Unsupported jq expression: \"${expr}\". Supported: \".\", \".field\", \".field.nested\", \".field[].nested\"`,\n );\n }\n }\n let current: unknown = data;\n\n for (const part of parts) {\n const arrayMatch = part.match(/^(\\w+)\\[\\]$/);\n if (arrayMatch) {\n const key = arrayMatch[1];\n if (current && typeof current === \"object\" && key in current) {\n const arr = (current as Record<string, unknown>)[key];\n if (!Array.isArray(arr)) return undefined;\n current = arr;\n } else {\n return undefined;\n }\n } else if (Array.isArray(current)) {\n current = current.map((item) =>\n item && typeof item === \"object\"\n ? (item as Record<string, unknown>)[part]\n : undefined,\n );\n } else if (current && typeof current === \"object\") {\n current = (current as Record<string, unknown>)[part];\n } else {\n return undefined;\n }\n }\n\n return current;\n}\n"],"mappings":";;;AAOO,IAAM,WAAN,cAAuB,MAAM;AAAA,EAClC,YACE,SACgB,WAAmB,GACnB,OAChB;AACA,UAAM,OAAO;AAHG;AACA;AAGhB,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,YAAN,cAAwB,SAAS;AAAA,EACtC,YAAY,SAAiB;AAC3B,UAAM,SAAS,CAAC;AAAA,EAClB;AACF;AAEO,IAAM,iBAAN,cAA6B,SAAS;AAAA,EAC3C,YACE,SACgB,YAChB;AACA,UAAM,SAAS,CAAC;AAFA;AAAA,EAGlB;AACF;AAEO,IAAM,gBAAN,cAA4B,SAAS;AAAA,EAC1C,YAAY,SAAiB;AAC3B,UAAM,SAAS,CAAC;AAAA,EAClB;AACF;AAEO,IAAM,kBAAN,cAA8B,SAAS;AAAA,EAC5C,YAAY,SAAiB;AAC3B,UAAM,SAAS,CAAC;AAAA,EAClB;AACF;AAEO,IAAM,eAAN,cAA2B,SAAS;AAAA,EACzC,YAAY,SAAiB;AAC3B,UAAM,SAAS,CAAC;AAAA,EAClB;AACF;AAQO,SAAS,eAAe,OAAyB;AACtD,MAAI;AACF,UAAM,UAAU,OAAO,KAAK,OAAO,QAAQ,EAAE,SAAS,OAAO;AAC7D,QAAI,QAAQ,WAAW,MAAM,GAAG;AAC9B,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;;;ACjEO,SAAS,WAAW,MAAuB;AAChD,SAAO,KAAK,UAAU,MAAM,MAAM,CAAC;AACrC;AAEO,SAAS,QAAQ,MAAe,MAAuB;AAC5D,MAAI,SAAS,IAAK,QAAO;AAGzB,MAAI,CAAC,KAAK,WAAW,GAAG,GAAG;AACzB,UAAM,IAAI;AAAA,MACR,+BAA+B,IAAI;AAAA,IACrC;AAAA,EACF;AAGA,MAAI,YAAY,KAAK,IAAI,GAAG;AAC1B,UAAM,IAAI;AAAA,MACR,+BAA+B,IAAI;AAAA,IACrC;AAAA,EACF;AAEA,QAAM,QAAQ,KAAK,QAAQ,UAAU,EAAE,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AAEnE,aAAW,QAAQ,OAAO;AACxB,QAAI,CAAC,eAAe,KAAK,IAAI,GAAG;AAC9B,YAAM,IAAI;AAAA,QACR,+BAA+B,IAAI;AAAA,MACrC;AAAA,IACF;AAAA,EACF;AACA,MAAI,UAAmB;AAEvB,aAAW,QAAQ,OAAO;AACxB,UAAM,aAAa,KAAK,MAAM,aAAa;AAC3C,QAAI,YAAY;AACd,YAAM,MAAM,WAAW,CAAC;AACxB,UAAI,WAAW,OAAO,YAAY,YAAY,OAAO,SAAS;AAC5D,cAAM,MAAO,QAAoC,GAAG;AACpD,YAAI,CAAC,MAAM,QAAQ,GAAG,EAAG,QAAO;AAChC,kBAAU;AAAA,MACZ,OAAO;AACL,eAAO;AAAA,MACT;AAAA,IACF,WAAW,MAAM,QAAQ,OAAO,GAAG;AACjC,gBAAU,QAAQ;AAAA,QAAI,CAAC,SACrB,QAAQ,OAAO,SAAS,WACnB,KAAiC,IAAI,IACtC;AAAA,MACN;AAAA,IACF,WAAW,WAAW,OAAO,YAAY,UAAU;AACjD,gBAAW,QAAoC,IAAI;AAAA,IACrD,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;","names":[]}