@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 +133 -0
- package/dist/chunk-Y4JK5AHH.js +109 -0
- package/dist/chunk-Y4JK5AHH.js.map +1 -0
- package/dist/index.js +1176 -217
- package/dist/index.js.map +1 -1
- package/dist/json-MMBOB7YU.js +10 -0
- package/dist/json-MMBOB7YU.js.map +1 -0
- package/package.json +6 -3
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":[]}
|