@customerio/cli 0.0.0-bootstrap → 0.0.1
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/.npm/run.js +73 -0
- package/README.md +221 -2
- package/package.json +75 -10
package/.npm/run.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawnSync } = require("child_process");
|
|
4
|
+
const { existsSync } = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
|
|
7
|
+
const pkgRoot = path.join(__dirname, "..");
|
|
8
|
+
const rootPkg = require(path.join(pkgRoot, "package.json"));
|
|
9
|
+
const optionalDependencies = rootPkg.optionalDependencies || {};
|
|
10
|
+
const platform = (rootPkg.customerioCli?.platforms || []).find(
|
|
11
|
+
(candidate) => candidate.os === process.platform && candidate.cpu === process.arch
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
if (!platform) {
|
|
15
|
+
console.error(
|
|
16
|
+
`Unsupported platform for ${rootPkg.name}: ${process.platform}-${process.arch}`
|
|
17
|
+
);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const platformPackage = Object.keys(optionalDependencies).find((packageName) =>
|
|
22
|
+
packageName.endsWith(`-${platform.npm}`)
|
|
23
|
+
);
|
|
24
|
+
let platformPackageRoot;
|
|
25
|
+
|
|
26
|
+
if (!platformPackage) {
|
|
27
|
+
console.error(
|
|
28
|
+
`Missing optional dependency metadata for ${process.platform}-${process.arch}.`
|
|
29
|
+
);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
platformPackageRoot = path.dirname(
|
|
35
|
+
require.resolve(`${platformPackage}/package.json`, { paths: [pkgRoot] })
|
|
36
|
+
);
|
|
37
|
+
} catch {
|
|
38
|
+
console.error(
|
|
39
|
+
`Missing optional dependency ${platformPackage} for ${process.platform}-${process.arch}.\n` +
|
|
40
|
+
"Reinstall without disabling optional dependencies."
|
|
41
|
+
);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const binPath = path.join(platformPackageRoot, "bin", `cio${platform.ext || ""}`);
|
|
46
|
+
|
|
47
|
+
if (!existsSync(binPath)) {
|
|
48
|
+
console.error(
|
|
49
|
+
`Missing ${rootPkg.name} binary at ${binPath}.\n` +
|
|
50
|
+
"Reinstall without disabling optional dependencies."
|
|
51
|
+
);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const result = spawnSync(binPath, process.argv.slice(2), {
|
|
56
|
+
stdio: "inherit",
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
if (result.error) {
|
|
60
|
+
console.error(result.error.message);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (result.signal) {
|
|
65
|
+
try {
|
|
66
|
+
process.kill(process.pid, result.signal);
|
|
67
|
+
} catch {
|
|
68
|
+
// Some platforms cannot re-raise child signals; use a generic failure below.
|
|
69
|
+
}
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
process.exit(result.status ?? 1);
|
package/README.md
CHANGED
|
@@ -1,3 +1,222 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Customer.io CLI (`cio`)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
An agent-first CLI for Customer.io APIs.
|
|
4
|
+
|
|
5
|
+
**800+ Journeys routes + 100+ CDP Pipelines routes, zero per-endpoint code.** A single `cio api <path>` command covers every endpoint. Every command returns structured JSON to stdout. Every error returns structured JSON to stderr.
|
|
6
|
+
|
|
7
|
+
AI agents are the primary consumer. Use `cio schema` to introspect endpoints before calling them.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm i -g @customerio/cli
|
|
13
|
+
cio --help
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
To build from source instead:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
go install github.com/customerio/cli@latest
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Install the agent skill
|
|
23
|
+
|
|
24
|
+
This repo ships a [SKILL.md](skills/cio/SKILL.md) so Claude Code, Cursor, Codex, Windsurf, and other agents that support [open agent skills](https://github.com/vercel-labs/skills) know how to drive the CLI. Install it with:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx skills add customerio/cli
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Authentication
|
|
31
|
+
|
|
32
|
+
The CLI uses **service account tokens** (`sa_live_...`) for authentication. These are exchanged for short-lived JWTs via OAuth 2.0 client credentials, just like `gh auth`.
|
|
33
|
+
|
|
34
|
+
### Login
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Interactive — prints the browser login URL, then prompts for the minted token
|
|
38
|
+
cio auth login
|
|
39
|
+
|
|
40
|
+
# Read from stdin (for CI/automation; login still auto-discovers region)
|
|
41
|
+
echo "$SA_TOKEN" | cio auth login --with-token
|
|
42
|
+
|
|
43
|
+
# Verify auth works
|
|
44
|
+
cio auth status
|
|
45
|
+
|
|
46
|
+
# Print raw token
|
|
47
|
+
cio auth token
|
|
48
|
+
|
|
49
|
+
# Logout
|
|
50
|
+
cio auth logout
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Token Resolution Order
|
|
54
|
+
|
|
55
|
+
1. `--token` flag (highest priority)
|
|
56
|
+
2. `CIO_TOKEN` environment variable
|
|
57
|
+
3. `~/.cio/config.json` file (lowest priority)
|
|
58
|
+
|
|
59
|
+
When you use `CIO_TOKEN` or `--token` directly on normal commands, you may
|
|
60
|
+
also need `CIO_REGION=us|eu` or `--api-url`.
|
|
61
|
+
|
|
62
|
+
### How It Works
|
|
63
|
+
|
|
64
|
+
1. You provide a `sa_live_...` token (from Customer.io UI → Account Settings → Manage API Credentials → Service Accounts)
|
|
65
|
+
2. The CLI exchanges it for a JWT via `POST /v1/service_accounts/oauth/token`
|
|
66
|
+
3. The JWT is cached locally and refreshed automatically when it expires
|
|
67
|
+
4. All API calls use `Authorization: Bearer <jwt>`
|
|
68
|
+
|
|
69
|
+
### Override per-command
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
cio --token sa_live_xxx api /v1/environments/{environment_id}/campaigns --params '{"environment_id": "123"}'
|
|
73
|
+
CIO_TOKEN=sa_live_xxx cio api /v1/environments/{environment_id}/campaigns --params '{"environment_id": "123"}'
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Usage
|
|
77
|
+
|
|
78
|
+
Use `cio api <path>` for any API endpoint. Path placeholders are resolved from `--params`. The HTTP method defaults to GET (or POST if `--json` is provided); override with `-X`:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# List campaigns in workspace 123
|
|
82
|
+
cio api /v1/environments/{environment_id}/campaigns --params '{"environment_id": "123"}'
|
|
83
|
+
|
|
84
|
+
# Get a specific campaign
|
|
85
|
+
cio api /v1/environments/{environment_id}/campaigns/{campaign_id} \
|
|
86
|
+
--params '{"environment_id": "123", "campaign_id": "456"}'
|
|
87
|
+
|
|
88
|
+
# Create a campaign
|
|
89
|
+
cio api /v1/environments/{environment_id}/campaigns \
|
|
90
|
+
--params '{"environment_id": "123"}' \
|
|
91
|
+
--json '{"campaign": {"name": "Welcome Flow", "type": "none"}}'
|
|
92
|
+
|
|
93
|
+
# Explicit method override
|
|
94
|
+
cio api /v1/environments/{environment_id}/campaigns/{campaign_id} -X DELETE \
|
|
95
|
+
--params '{"environment_id": "123", "campaign_id": "456"}'
|
|
96
|
+
|
|
97
|
+
# Introspect endpoints
|
|
98
|
+
cio schema # list all resources
|
|
99
|
+
cio schema campaigns # list endpoints for a resource
|
|
100
|
+
cio schema campaigns.list # full schema for a method
|
|
101
|
+
cio schema GET /v1/environments/{environment_id}/campaigns # by HTTP method + path
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Account ID fallback
|
|
105
|
+
|
|
106
|
+
Paths that include `{account_id}` auto-fill from the account ID stored during `cio auth login`, so you don't need to pass it on every call:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
cio api /v1/accounts/{account_id}/environments
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Pass `--params '{"account_id": "..."}'` to override, or set `CIO_ACCESS_TOKEN` to disable the fallback (the pre-exchanged JWT may belong to a different account).
|
|
113
|
+
|
|
114
|
+
### Filtering with jq
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# Filter with --jq to save context window
|
|
118
|
+
cio api /v1/environments/{environment_id}/campaigns \
|
|
119
|
+
--params '{"environment_id": "123"}' \
|
|
120
|
+
--jq '.campaigns[] | {id, name, state}'
|
|
121
|
+
|
|
122
|
+
# Complex filtering
|
|
123
|
+
cio api /v1/environments/{environment_id}/campaigns \
|
|
124
|
+
--params '{"environment_id": "123"}' \
|
|
125
|
+
--jq '.campaigns[] | select(.state == "active") | {id, name}'
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Write operations
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# Always dry-run first
|
|
132
|
+
cio api /v1/environments/{environment_id}/campaigns \
|
|
133
|
+
--params '{"environment_id": "123"}' \
|
|
134
|
+
--json '{"campaign": {"name": "Welcome Flow", "type": "none"}}' --dry-run
|
|
135
|
+
|
|
136
|
+
# Then execute (removes --dry-run)
|
|
137
|
+
cio api /v1/environments/{environment_id}/campaigns \
|
|
138
|
+
--params '{"environment_id": "123"}' \
|
|
139
|
+
--json '{"campaign": {"name": "Welcome Flow", "type": "none"}}'
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Pagination
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
cio api /v1/environments/{environment_id}/campaigns \
|
|
146
|
+
--params '{"environment_id": "123"}' --page 2 --limit 50
|
|
147
|
+
|
|
148
|
+
# Auto-paginate (emits NDJSON — one JSON object per line)
|
|
149
|
+
cio api /v1/environments/{environment_id}/campaigns \
|
|
150
|
+
--params '{"environment_id": "123"}' --page-all
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Global Flags
|
|
154
|
+
|
|
155
|
+
| Flag | Env Var | Description |
|
|
156
|
+
|---|---|---|
|
|
157
|
+
| `--token <value>` | `CIO_TOKEN` | Service account token override |
|
|
158
|
+
| `-X, --method` | | HTTP method override (default: GET, or POST if --json) |
|
|
159
|
+
| `--json <payload>` | | Raw JSON request body or `@filename` to read from file |
|
|
160
|
+
| `--params <json>` | | Query parameters as JSON → query string |
|
|
161
|
+
| `--jq <expr>` | | jq expression filter (via gojq) |
|
|
162
|
+
| `--dry-run` | | Validate + print request, skip execution |
|
|
163
|
+
| `--api-url <url>` | | API base URL override |
|
|
164
|
+
| `--timeout <duration>` | `CIO_TIMEOUT` | HTTP request timeout (default: 30s) |
|
|
165
|
+
| `--page <n>` | | Page number |
|
|
166
|
+
| `--limit <n>` | | Page size |
|
|
167
|
+
| `--page-all` | | Auto-paginate, emit NDJSON |
|
|
168
|
+
|
|
169
|
+
## Exit Codes
|
|
170
|
+
|
|
171
|
+
| Code | Meaning |
|
|
172
|
+
|---|---|
|
|
173
|
+
| 0 | Success |
|
|
174
|
+
| 1 | General error |
|
|
175
|
+
| 2 | Validation / input error |
|
|
176
|
+
| 3 | Authentication error |
|
|
177
|
+
| 4 | Authorization error |
|
|
178
|
+
| 5 | API error (4xx/5xx) |
|
|
179
|
+
|
|
180
|
+
## Error Format
|
|
181
|
+
|
|
182
|
+
```json
|
|
183
|
+
{"error":true,"code":"AUTH_ERROR","message":"Not authenticated.","details":{"status_code":401}}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Architecture
|
|
187
|
+
|
|
188
|
+
The CLI uses a **generic `api` command + route registry** architecture:
|
|
189
|
+
|
|
190
|
+
1. `cio api <path>` — a single command that takes any API path with `{placeholder}` params
|
|
191
|
+
2. OpenAPI specs are downloaded from the live API on first use and cached locally under `~/.cio/cache/specs/` (24h TTL, ETag-based conditional refresh). Use `cio schema --refresh` to force re-download.
|
|
192
|
+
3. `internal/routes/enrichment.json` — summaries, param descriptions, query params for routes not yet annotated in the OpenAPI spec
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
# Discover resources
|
|
196
|
+
cio schema
|
|
197
|
+
|
|
198
|
+
# List endpoints for a resource
|
|
199
|
+
cio schema campaigns
|
|
200
|
+
|
|
201
|
+
# Inspect a method's parameters
|
|
202
|
+
cio schema campaigns.list
|
|
203
|
+
|
|
204
|
+
# Make an API call
|
|
205
|
+
cio api /v1/environments/{environment_id}/campaigns --params '{"environment_id": "123"}'
|
|
206
|
+
|
|
207
|
+
# CDP Pipelines (workspace_id = environment_id)
|
|
208
|
+
cio api /cdp/api/workspaces/{workspace_id}/sources --params '{"workspace_id": "123"}'
|
|
209
|
+
cio schema sources
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Development
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
go build -o cio .
|
|
216
|
+
go test ./...
|
|
217
|
+
go test ./... -v -run TestAuthLogin
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## License
|
|
221
|
+
|
|
222
|
+
Licensed under Apache License 2.0 with the Commons Clause Restriction. See [LICENSE](LICENSE).
|
package/package.json
CHANGED
|
@@ -1,20 +1,85 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@customerio/cli",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Agent-first CLI for Customer.io APIs",
|
|
5
|
+
"bin": {
|
|
6
|
+
"cio": ".npm/run.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
".npm/run.js",
|
|
10
|
+
"LICENSE",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"optionalDependencies": {
|
|
14
|
+
"@customerio/cli-darwin-arm64": "0.0.1",
|
|
15
|
+
"@customerio/cli-darwin-x64": "0.0.1",
|
|
16
|
+
"@customerio/cli-linux-arm64": "0.0.1",
|
|
17
|
+
"@customerio/cli-linux-x64": "0.0.1",
|
|
18
|
+
"@customerio/cli-win32-arm64": "0.0.1",
|
|
19
|
+
"@customerio/cli-win32-x64": "0.0.1"
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public",
|
|
23
|
+
"provenance": true
|
|
24
|
+
},
|
|
25
|
+
"customerioCli": {
|
|
26
|
+
"platforms": [
|
|
27
|
+
{
|
|
28
|
+
"goos": "darwin",
|
|
29
|
+
"goarch": "arm64",
|
|
30
|
+
"npm": "darwin-arm64",
|
|
31
|
+
"os": "darwin",
|
|
32
|
+
"cpu": "arm64",
|
|
33
|
+
"ext": ""
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"goos": "darwin",
|
|
37
|
+
"goarch": "amd64",
|
|
38
|
+
"npm": "darwin-x64",
|
|
39
|
+
"os": "darwin",
|
|
40
|
+
"cpu": "x64",
|
|
41
|
+
"ext": ""
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"goos": "linux",
|
|
45
|
+
"goarch": "arm64",
|
|
46
|
+
"npm": "linux-arm64",
|
|
47
|
+
"os": "linux",
|
|
48
|
+
"cpu": "arm64",
|
|
49
|
+
"ext": ""
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"goos": "linux",
|
|
53
|
+
"goarch": "amd64",
|
|
54
|
+
"npm": "linux-x64",
|
|
55
|
+
"os": "linux",
|
|
56
|
+
"cpu": "x64",
|
|
57
|
+
"ext": ""
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"goos": "windows",
|
|
61
|
+
"goarch": "arm64",
|
|
62
|
+
"npm": "win32-arm64",
|
|
63
|
+
"os": "win32",
|
|
64
|
+
"cpu": "arm64",
|
|
65
|
+
"ext": ".exe"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"goos": "windows",
|
|
69
|
+
"goarch": "amd64",
|
|
70
|
+
"npm": "win32-x64",
|
|
71
|
+
"os": "win32",
|
|
72
|
+
"cpu": "x64",
|
|
73
|
+
"ext": ".exe"
|
|
74
|
+
}
|
|
75
|
+
]
|
|
8
76
|
},
|
|
9
|
-
"keywords": [],
|
|
10
|
-
"author": "",
|
|
11
77
|
"license": "SEE LICENSE IN LICENSE",
|
|
12
|
-
"type": "commonjs",
|
|
13
78
|
"repository": {
|
|
14
79
|
"type": "git",
|
|
15
80
|
"url": "git+https://github.com/customerio/cli.git"
|
|
16
81
|
},
|
|
17
|
-
"
|
|
18
|
-
"
|
|
82
|
+
"engines": {
|
|
83
|
+
"node": ">=16"
|
|
19
84
|
}
|
|
20
85
|
}
|