@intercom/cli 0.1.1 → 0.3.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,133 @@
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\|logout\|status\|list\|switch` | Manage authentication |
36
+ | `intercom auth bootstrap\|signup\|verify-email` | Workspace provisioning |
37
+ | `intercom me` | Show current admin and workspace |
38
+ | `intercom articles list\|get\|create\|update\|delete` | Manage help center articles |
39
+ | `intercom contacts list\|get\|create\|update\|delete\|search` | Manage contacts |
40
+ | `intercom conversations list\|get\|reply\|search` | Manage conversations |
41
+ | `intercom help-center list\|get\|create` | Manage help center collections |
42
+ | `intercom messenger get\|update\|snippet` | Configure Messenger |
43
+ | `intercom fin manifest\|enable\|download` | Fin AI Agent core |
44
+ | `intercom fin procedures list\|get\|validate\|test\|publish` | Fin procedures |
45
+ | `intercom fin guidance\|attributes\|audiences\|workflows\|simulations` | Fin SDK resources |
46
+ | `intercom fin data-connectors list\|get` | Fin data connectors |
47
+ | `intercom setup` | Orchestrate full workspace setup |
48
+ | `intercom config get\|set\|list` | Manage CLI configuration |
49
+ | `intercom pricing` | Show current Intercom pricing |
50
+ | `intercom completion bash\|zsh\|fish` | Generate shell completions |
51
+
52
+ ## Global Flags
53
+
54
+ | Flag | Description |
55
+ |---|---|
56
+ | `--json` | Output as pretty-printed JSON |
57
+ | `--jq <expr>` | Filter JSON output (subset of jq) |
58
+ | `--workspace <id>` | Override default workspace |
59
+ | `--verbose` | Show HTTP request/response details |
60
+ | `--no-retry` | Disable automatic rate limit retry |
61
+ | `--timeout <seconds>` | Request timeout in seconds |
62
+ | `--agent` | Force machine-readable output (JSON/NDJSON) |
63
+ | `--human` | Force human-readable output even when piped |
64
+ | `--wide` | Show all columns with wider truncation |
65
+ | `--version` | Print CLI version |
66
+
67
+ ## Agent / Pipe Mode
68
+
69
+ When stdout is not a TTY (piped to another program), the CLI automatically outputs compact NDJSON — one JSON object per line. No flag needed:
70
+
71
+ ```bash
72
+ # Automatic NDJSON when piped
73
+ intercom articles list | jq '.title'
74
+
75
+ # Force JSON with flag
76
+ intercom articles list --json
77
+
78
+ # Filter inline
79
+ intercom articles list --jq '.data[].title'
80
+ ```
81
+
82
+ ## Raw API Access
83
+
84
+ The `intercom api` command provides direct access to any Intercom API endpoint:
85
+
86
+ ```bash
87
+ # GET request (default)
88
+ intercom api /me
89
+
90
+ # POST with fields
91
+ intercom api /articles -f title="Hello" -f author_id=123
92
+
93
+ # Typed fields (booleans, numbers, file reads)
94
+ intercom api /articles -F draft:=true -F body=@article.html
95
+
96
+ # Auto-paginate
97
+ intercom api /articles --paginate
98
+
99
+ # Use jq to filter
100
+ intercom api /contacts --jq '.data[].email'
101
+ ```
102
+
103
+ ## Environment Variables
104
+
105
+ | Variable | Description |
106
+ |---|---|
107
+ | `INTERCOM_TOKEN` | API token (bypasses credential store) |
108
+ | `INTERCOM_API_BASE_URL` | Override API base URL |
109
+ | `INTERCOM_APP_BASE_URL` | Override app base URL |
110
+ | `INTERCOM_CONFIG_DIR` | Override config directory |
111
+ | `INTERCOM_PASSWORD` | Password for signup/bootstrap |
112
+
113
+ ## Development
114
+
115
+ ```bash
116
+ git clone git@github.com:intercom/cli.git
117
+ cd cli
118
+ npm ci
119
+ npm run build # Build to dist/
120
+ npm test # Run tests (~5s)
121
+ npm run lint # TypeScript typecheck
122
+ npm run dev # Watch mode
123
+
124
+ # Try it locally
125
+ export INTERCOM_TOKEN="<your-token>"
126
+ node dist/index.js me
127
+ ```
128
+
129
+ See [SETUP.md](SETUP.md) for full developer setup guide.
130
+
131
+ ## License
132
+
133
+ 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-Y4JK5AHH.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 timeout?: number;\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":[]}