@chainpatrol/cli 0.25.0 → 0.27.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/CHANGELOG.md +30 -0
- package/dist/cli.js +3 -3
- package/dist/{get-4YHQ7ZE2.js → get-2PCG3CQN.js} +23 -6
- package/dist/list-FZD2FGJA.js +83 -0
- package/dist/{list-T2YIGGM6.js → list-JG2R7EHK.js} +23 -10
- package/package.json +2 -2
- package/dist/list-33ILIIXB.js +0 -63
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# @chainpatrol/cli
|
|
2
2
|
|
|
3
|
+
## 0.27.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 1346c67: Expose brand configuration fields in the `/organization/brands` API endpoint.
|
|
8
|
+
The response now includes `brandColors`, `includedTerms`, `excludedTerms`,
|
|
9
|
+
`tickers`, `avatarUrl`, `websiteUrl`, and `twitterHandle` for each brand.
|
|
10
|
+
The CLI `brands list` command displays these fields in all output formats.
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Updated dependencies [1346c67]
|
|
15
|
+
- @chainpatrol/sdk@0.11.0
|
|
16
|
+
|
|
17
|
+
## 0.26.0
|
|
18
|
+
|
|
19
|
+
### Minor Changes
|
|
20
|
+
|
|
21
|
+
- 4a3d9fb: Add integration connection status to orgs API and CLI. The `/user/orgs` and
|
|
22
|
+
`/user/orgs/{slug}` endpoints now return an `integrations` object for each
|
|
23
|
+
organization showing which third-party integrations are connected: Slack,
|
|
24
|
+
Discord, Telegram (with group count), Vercel, Intercom, and the Moderation API.
|
|
25
|
+
The CLI `orgs get` and `orgs list` commands display integration status in all
|
|
26
|
+
output formats.
|
|
27
|
+
|
|
28
|
+
### Patch Changes
|
|
29
|
+
|
|
30
|
+
- Updated dependencies [4a3d9fb]
|
|
31
|
+
- @chainpatrol/sdk@0.10.0
|
|
32
|
+
|
|
3
33
|
## 0.25.0
|
|
4
34
|
|
|
5
35
|
### Minor Changes
|
package/dist/cli.js
CHANGED
|
@@ -1606,7 +1606,7 @@ async function main() {
|
|
|
1606
1606
|
}
|
|
1607
1607
|
case "orgs": {
|
|
1608
1608
|
if (subcommand === "list") {
|
|
1609
|
-
const { runOrgsList } = await import("./list-
|
|
1609
|
+
const { runOrgsList } = await import("./list-JG2R7EHK.js");
|
|
1610
1610
|
await runOrgsList({
|
|
1611
1611
|
query: cli.flags.query,
|
|
1612
1612
|
subscriptionStatus: cli.flags.subscriptionStatus,
|
|
@@ -1628,7 +1628,7 @@ async function main() {
|
|
|
1628
1628
|
if (subcommand === "get") {
|
|
1629
1629
|
const positionalSlug = action;
|
|
1630
1630
|
const slug = positionalSlug ?? await tryResolveOrg();
|
|
1631
|
-
const { runOrgsGet } = await import("./get-
|
|
1631
|
+
const { runOrgsGet } = await import("./get-2PCG3CQN.js");
|
|
1632
1632
|
await runOrgsGet({
|
|
1633
1633
|
slug,
|
|
1634
1634
|
json: jsonMode,
|
|
@@ -1676,7 +1676,7 @@ async function main() {
|
|
|
1676
1676
|
"brands list --type must be ORGANIZATION or INDIVIDUAL (case-insensitive)."
|
|
1677
1677
|
);
|
|
1678
1678
|
}
|
|
1679
|
-
const { runBrandsList } = await import("./list-
|
|
1679
|
+
const { runBrandsList } = await import("./list-FZD2FGJA.js");
|
|
1680
1680
|
await runBrandsList({
|
|
1681
1681
|
type: rawType,
|
|
1682
1682
|
json: jsonMode,
|
|
@@ -37,6 +37,20 @@ function summarizePendingApprovals(org) {
|
|
|
37
37
|
);
|
|
38
38
|
return labels.join(", ");
|
|
39
39
|
}
|
|
40
|
+
function summarizeIntegrations(org) {
|
|
41
|
+
const parts = [];
|
|
42
|
+
if (org.integrations.slack) parts.push("slack");
|
|
43
|
+
if (org.integrations.discord) parts.push("discord");
|
|
44
|
+
if (org.integrations.telegram.connected) {
|
|
45
|
+
parts.push(
|
|
46
|
+
org.integrations.telegram.groupCount === 1 ? "telegram" : `telegram(${org.integrations.telegram.groupCount} groups)`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
if (org.integrations.vercel) parts.push("vercel");
|
|
50
|
+
if (org.integrations.intercom) parts.push("intercom");
|
|
51
|
+
if (org.integrations.moderation) parts.push("moderation-api");
|
|
52
|
+
return parts.length > 0 ? parts.join(" ") : "(none)";
|
|
53
|
+
}
|
|
40
54
|
async function runOrgsGet(options) {
|
|
41
55
|
const slug = options.slug?.trim();
|
|
42
56
|
if (!slug) {
|
|
@@ -58,6 +72,7 @@ async function runOrgsGet(options) {
|
|
|
58
72
|
`- Contact URL: ${organization.contactUrl ?? "(not set)"}`,
|
|
59
73
|
`- Subscription status: ${organization.subscriptionStatus}`,
|
|
60
74
|
`- Services: ${summarizeServices(organization)}`,
|
|
75
|
+
`- Integrations: ${summarizeIntegrations(organization)}`,
|
|
61
76
|
`- Obligatory admin approval: ${summarizeObligatoryAdminApproval(organization)}`,
|
|
62
77
|
`- Pending service approvals: ${summarizePendingApprovals(organization)}`
|
|
63
78
|
].join("\n"),
|
|
@@ -71,17 +86,18 @@ async function runOrgsGet(options) {
|
|
|
71
86
|
reviewingActive: organization.services.reviewing.active,
|
|
72
87
|
protectionActive: organization.services.protection.active,
|
|
73
88
|
takedownsActive: organization.services.takedowns.active,
|
|
74
|
-
// `takedowns` is the only service with a meaningful automation flag.
|
|
75
89
|
takedownsAutomated: organization.services.takedowns.automated,
|
|
76
90
|
detectionActive: organization.services.detection.active,
|
|
77
91
|
darkWebMonitoringActive: organization.services.darkWebMonitoring.active,
|
|
92
|
+
slackConnected: organization.integrations.slack,
|
|
93
|
+
discordConnected: organization.integrations.discord,
|
|
94
|
+
telegramConnected: organization.integrations.telegram.connected,
|
|
95
|
+
telegramGroupCount: organization.integrations.telegram.groupCount,
|
|
96
|
+
vercelConnected: organization.integrations.vercel,
|
|
97
|
+
intercomConnected: organization.integrations.intercom,
|
|
98
|
+
moderationApiConnected: organization.integrations.moderation,
|
|
78
99
|
obligatoryAdminApprovalActive: organization.obligatoryAdminApproval.active,
|
|
79
|
-
// Empty list + active=true means "applies to all asset types" — read
|
|
80
|
-
// the active column alongside this one to interpret.
|
|
81
100
|
obligatoryAdminApprovalAssetTypes: organization.obligatoryAdminApproval.assetTypes.join("|"),
|
|
82
|
-
// Pending staff requests to enable Wallet Blocking / Takedowns that a
|
|
83
|
-
// higher-up has not yet approved. Raw `serviceType` enum values,
|
|
84
|
-
// de-duplicated; an empty cell means nothing is awaiting approval.
|
|
85
101
|
pendingServiceApprovals: Array.from(
|
|
86
102
|
new Set(
|
|
87
103
|
organization.pendingServiceApprovals.map((approval) => approval.serviceType)
|
|
@@ -94,6 +110,7 @@ async function runOrgsGet(options) {
|
|
|
94
110
|
console.log(` contactUrl: ${organization.contactUrl ?? "(not set)"}`);
|
|
95
111
|
console.log(` subscriptionStatus: ${organization.subscriptionStatus}`);
|
|
96
112
|
console.log(` services: ${summarizeServices(organization)}`);
|
|
113
|
+
console.log(` integrations: ${summarizeIntegrations(organization)}`);
|
|
97
114
|
console.log(
|
|
98
115
|
` obligatoryAdminApproval: ${summarizeObligatoryAdminApproval(organization)}`
|
|
99
116
|
);
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import {
|
|
2
|
+
printOutput,
|
|
3
|
+
toCsvRows
|
|
4
|
+
} from "./chunk-VFT3TD3E.js";
|
|
5
|
+
import {
|
|
6
|
+
createApiClient
|
|
7
|
+
} from "./chunk-OFUIYMPD.js";
|
|
8
|
+
import "./chunk-EGWK6SRQ.js";
|
|
9
|
+
import "./chunk-U73SABXK.js";
|
|
10
|
+
|
|
11
|
+
// src/commands/brands/list.ts
|
|
12
|
+
function toRow(brand) {
|
|
13
|
+
return {
|
|
14
|
+
id: brand.id,
|
|
15
|
+
slug: brand.slug,
|
|
16
|
+
name: brand.name,
|
|
17
|
+
type: brand.type,
|
|
18
|
+
description: brand.description ?? "",
|
|
19
|
+
avatarUrl: brand.avatarUrl ?? "",
|
|
20
|
+
websiteUrl: brand.websiteUrl ?? "",
|
|
21
|
+
twitterHandle: brand.twitterHandle ?? "",
|
|
22
|
+
brandColors: brand.brandColors.join(", "),
|
|
23
|
+
includedTerms: brand.includedTerms.join(", "),
|
|
24
|
+
excludedTerms: brand.excludedTerms.join(", "),
|
|
25
|
+
tickers: brand.tickers.join(", "),
|
|
26
|
+
brandGroupId: brand.brandGroupId,
|
|
27
|
+
createdAt: brand.createdAt
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
async function runBrandsList(options) {
|
|
31
|
+
const outputFormat = options.outputFormat ?? (options.json ? "json" : "human");
|
|
32
|
+
const client = options.apiClient ?? createApiClient();
|
|
33
|
+
const result = await client.listOrganizationBrands();
|
|
34
|
+
const brands = options.type ? result.brands.filter((brand) => brand.type === options.type) : result.brands;
|
|
35
|
+
const rows = brands.map(toRow);
|
|
36
|
+
printOutput({
|
|
37
|
+
outputFormat,
|
|
38
|
+
json: options.type ? { ...result, brands } : result,
|
|
39
|
+
markdown: [
|
|
40
|
+
"# Organization brands",
|
|
41
|
+
"",
|
|
42
|
+
`- Returned: ${brands.length}${options.type ? ` (filtered to type=${options.type})` : ""}`,
|
|
43
|
+
"",
|
|
44
|
+
...rows.map((row) => {
|
|
45
|
+
const parts = [`slug=${row.slug}`, `type=${row.type}`];
|
|
46
|
+
if (row.brandGroupId !== null) parts.push(`groupId=${row.brandGroupId}`);
|
|
47
|
+
if (row.websiteUrl) parts.push(`website=${row.websiteUrl}`);
|
|
48
|
+
if (row.twitterHandle) parts.push(`twitter=@${row.twitterHandle}`);
|
|
49
|
+
if (row.brandColors) parts.push(`colors=${row.brandColors}`);
|
|
50
|
+
if (row.includedTerms) parts.push(`included=${row.includedTerms}`);
|
|
51
|
+
if (row.excludedTerms) parts.push(`excluded=${row.excludedTerms}`);
|
|
52
|
+
if (row.tickers) parts.push(`tickers=${row.tickers}`);
|
|
53
|
+
return `- #${row.id} ${row.name} (${parts.join(", ")})`;
|
|
54
|
+
})
|
|
55
|
+
].join("\n"),
|
|
56
|
+
csv: toCsvRows(rows),
|
|
57
|
+
human: () => {
|
|
58
|
+
if (brands.length === 0) {
|
|
59
|
+
console.log(
|
|
60
|
+
options.type ? `No brands of type ${options.type} found.` : "No brands found."
|
|
61
|
+
);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
console.log(
|
|
65
|
+
`Organization brands \u2014 returned ${brands.length}${options.type ? ` (type=${options.type})` : ""}`
|
|
66
|
+
);
|
|
67
|
+
for (const row of rows) {
|
|
68
|
+
const parts = [`slug=${row.slug}`, `type=${row.type}`];
|
|
69
|
+
if (row.brandGroupId !== null) parts.push(`groupId=${row.brandGroupId}`);
|
|
70
|
+
if (row.websiteUrl) parts.push(`website=${row.websiteUrl}`);
|
|
71
|
+
if (row.twitterHandle) parts.push(`twitter=@${row.twitterHandle}`);
|
|
72
|
+
if (row.brandColors) parts.push(`colors=${row.brandColors}`);
|
|
73
|
+
if (row.includedTerms) parts.push(`included=${row.includedTerms}`);
|
|
74
|
+
if (row.excludedTerms) parts.push(`excluded=${row.excludedTerms}`);
|
|
75
|
+
if (row.tickers) parts.push(`tickers=${row.tickers}`);
|
|
76
|
+
console.log(`#${row.id} ${row.name} (${parts.join(", ")})`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
export {
|
|
82
|
+
runBrandsList
|
|
83
|
+
};
|
|
@@ -196,6 +196,20 @@ function summarizePendingApprovals(org) {
|
|
|
196
196
|
);
|
|
197
197
|
return labels.join(", ");
|
|
198
198
|
}
|
|
199
|
+
function summarizeIntegrations(org) {
|
|
200
|
+
const parts = [];
|
|
201
|
+
if (org.integrations.slack) parts.push("slack");
|
|
202
|
+
if (org.integrations.discord) parts.push("discord");
|
|
203
|
+
if (org.integrations.telegram.connected) {
|
|
204
|
+
parts.push(
|
|
205
|
+
org.integrations.telegram.groupCount === 1 ? "telegram" : `telegram(${org.integrations.telegram.groupCount} groups)`
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
if (org.integrations.vercel) parts.push("vercel");
|
|
209
|
+
if (org.integrations.intercom) parts.push("intercom");
|
|
210
|
+
if (org.integrations.moderation) parts.push("moderation-api");
|
|
211
|
+
return parts.length > 0 ? parts.join(" ") : "(none)";
|
|
212
|
+
}
|
|
199
213
|
async function runOrgsList(options) {
|
|
200
214
|
const client = options.apiClient ?? createApiClient();
|
|
201
215
|
const outputFormat = options.outputFormat ?? (options.json ? "json" : "human");
|
|
@@ -215,7 +229,7 @@ async function runOrgsList(options) {
|
|
|
215
229
|
`# Organizations (${organizations.length})`,
|
|
216
230
|
"",
|
|
217
231
|
...organizations.map(
|
|
218
|
-
(org) => `- \`${org.slug}\` \u2014 ${org.name} \u2014 ${org.subscriptionStatus} \u2014 contact: ${org.contactUrl ?? "(not set)"} \u2014 ${summarizeServices(org)} \u2014 admin-approval: ${summarizeObligatoryAdminApproval(org)} \u2014 pending-approval: ${summarizePendingApprovals(org)}`
|
|
232
|
+
(org) => `- \`${org.slug}\` \u2014 ${org.name} \u2014 ${org.subscriptionStatus} \u2014 contact: ${org.contactUrl ?? "(not set)"} \u2014 ${summarizeServices(org)} \u2014 integrations: ${summarizeIntegrations(org)} \u2014 admin-approval: ${summarizeObligatoryAdminApproval(org)} \u2014 pending-approval: ${summarizePendingApprovals(org)}`
|
|
219
233
|
)
|
|
220
234
|
].join("\n"),
|
|
221
235
|
csv: toCsvRows(
|
|
@@ -228,19 +242,18 @@ async function runOrgsList(options) {
|
|
|
228
242
|
reviewingActive: org.services.reviewing.active,
|
|
229
243
|
protectionActive: org.services.protection.active,
|
|
230
244
|
takedownsActive: org.services.takedowns.active,
|
|
231
|
-
// `takedowns` is the only service with a meaningful automation flag.
|
|
232
245
|
takedownsAutomated: org.services.takedowns.automated,
|
|
233
246
|
detectionActive: org.services.detection.active,
|
|
234
247
|
darkWebMonitoringActive: org.services.darkWebMonitoring.active,
|
|
248
|
+
slackConnected: org.integrations.slack,
|
|
249
|
+
discordConnected: org.integrations.discord,
|
|
250
|
+
telegramConnected: org.integrations.telegram.connected,
|
|
251
|
+
telegramGroupCount: org.integrations.telegram.groupCount,
|
|
252
|
+
vercelConnected: org.integrations.vercel,
|
|
253
|
+
intercomConnected: org.integrations.intercom,
|
|
254
|
+
moderationApiConnected: org.integrations.moderation,
|
|
235
255
|
obligatoryAdminApprovalActive: org.obligatoryAdminApproval.active,
|
|
236
|
-
// Empty list + active means "applies to all asset types"; we keep
|
|
237
|
-
// the cell empty in CSV so spreadsheets render it as the natural
|
|
238
|
-
// "no narrowing" value — pair it with the active column.
|
|
239
256
|
obligatoryAdminApprovalAssetTypes: org.obligatoryAdminApproval.assetTypes.join("|"),
|
|
240
|
-
// Pending staff requests to enable Wallet Blocking / Takedowns that
|
|
241
|
-
// a higher-up has not yet approved. We emit the raw `serviceType`
|
|
242
|
-
// enum values (de-duplicated) so the column is machine-filterable;
|
|
243
|
-
// an empty cell means nothing is awaiting approval.
|
|
244
257
|
pendingServiceApprovals: Array.from(
|
|
245
258
|
new Set(org.pendingServiceApprovals.map((approval) => approval.serviceType))
|
|
246
259
|
).join("|")
|
|
@@ -257,7 +270,7 @@ async function runOrgsList(options) {
|
|
|
257
270
|
for (const org of organizations) {
|
|
258
271
|
const contact = org.contactUrl ?? "(no contact)";
|
|
259
272
|
console.log(
|
|
260
|
-
` ${org.slug.padEnd(slugWidth)} ${org.name.padEnd(nameWidth)} ${org.subscriptionStatus.padEnd(11)} ${contact} ${summarizeServices(org)} admin-approval=${summarizeObligatoryAdminApproval(org)} pending-approval=${summarizePendingApprovals(org)}`
|
|
273
|
+
` ${org.slug.padEnd(slugWidth)} ${org.name.padEnd(nameWidth)} ${org.subscriptionStatus.padEnd(11)} ${contact} ${summarizeServices(org)} integrations=${summarizeIntegrations(org)} admin-approval=${summarizeObligatoryAdminApproval(org)} pending-approval=${summarizePendingApprovals(org)}`
|
|
261
274
|
);
|
|
262
275
|
}
|
|
263
276
|
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@chainpatrol/cli",
|
|
3
3
|
"description": "The official ChainPatrol CLI — terminal interface for threat detection",
|
|
4
4
|
"author": "Umar Ahmed <umar@chainpatrol.io>",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.27.0",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"homepage": "https://chainpatrol.com/docs/cli",
|
|
8
8
|
"keywords": [
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"lint": "npx oxlint ."
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@chainpatrol/sdk": "0.
|
|
36
|
+
"@chainpatrol/sdk": "0.11.0",
|
|
37
37
|
"ink": "^7.0.1",
|
|
38
38
|
"meow": "^14.1.0",
|
|
39
39
|
"open": "^11.0.0",
|
package/dist/list-33ILIIXB.js
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
printOutput,
|
|
3
|
-
toCsvRows
|
|
4
|
-
} from "./chunk-VFT3TD3E.js";
|
|
5
|
-
import {
|
|
6
|
-
createApiClient
|
|
7
|
-
} from "./chunk-OFUIYMPD.js";
|
|
8
|
-
import "./chunk-EGWK6SRQ.js";
|
|
9
|
-
import "./chunk-U73SABXK.js";
|
|
10
|
-
|
|
11
|
-
// src/commands/brands/list.ts
|
|
12
|
-
function toRow(brand) {
|
|
13
|
-
return {
|
|
14
|
-
id: brand.id,
|
|
15
|
-
slug: brand.slug,
|
|
16
|
-
name: brand.name,
|
|
17
|
-
type: brand.type,
|
|
18
|
-
description: brand.description ?? "",
|
|
19
|
-
brandGroupId: brand.brandGroupId,
|
|
20
|
-
createdAt: brand.createdAt
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
async function runBrandsList(options) {
|
|
24
|
-
const outputFormat = options.outputFormat ?? (options.json ? "json" : "human");
|
|
25
|
-
const client = options.apiClient ?? createApiClient();
|
|
26
|
-
const result = await client.listOrganizationBrands();
|
|
27
|
-
const brands = options.type ? result.brands.filter((brand) => brand.type === options.type) : result.brands;
|
|
28
|
-
const rows = brands.map(toRow);
|
|
29
|
-
printOutput({
|
|
30
|
-
outputFormat,
|
|
31
|
-
json: options.type ? { ...result, brands } : result,
|
|
32
|
-
markdown: [
|
|
33
|
-
"# Organization brands",
|
|
34
|
-
"",
|
|
35
|
-
`- Returned: ${brands.length}${options.type ? ` (filtered to type=${options.type})` : ""}`,
|
|
36
|
-
"",
|
|
37
|
-
...rows.map(
|
|
38
|
-
(row) => `- #${row.id} ${row.name} (slug=${row.slug}, type=${row.type}${row.brandGroupId !== null ? `, groupId=${row.brandGroupId}` : ""})`
|
|
39
|
-
)
|
|
40
|
-
].join("\n"),
|
|
41
|
-
csv: toCsvRows(rows),
|
|
42
|
-
human: () => {
|
|
43
|
-
if (brands.length === 0) {
|
|
44
|
-
console.log(
|
|
45
|
-
options.type ? `No brands of type ${options.type} found.` : "No brands found."
|
|
46
|
-
);
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
console.log(
|
|
50
|
-
`Organization brands \u2014 returned ${brands.length}${options.type ? ` (type=${options.type})` : ""}`
|
|
51
|
-
);
|
|
52
|
-
for (const row of rows) {
|
|
53
|
-
const group = row.brandGroupId !== null ? ` groupId=${row.brandGroupId}` : "";
|
|
54
|
-
console.log(
|
|
55
|
-
`#${row.id} ${row.name} (slug=${row.slug}, type=${row.type}${group})`
|
|
56
|
-
);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
export {
|
|
62
|
-
runBrandsList
|
|
63
|
-
};
|