@chainpatrol/cli 0.13.0 → 0.14.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 +29 -0
- package/dist/{breakdown-B6QUGYI6.js → breakdown-K5Q6TDKE.js} +1 -1
- package/dist/{check-P5JJJNEX.js → check-NJH7BUIM.js} +1 -1
- package/dist/{chunk-BQDMAEQU.js → chunk-6X5BFFXA.js} +27 -0
- package/dist/{chunk-DJVB73FL.js → chunk-BIKTBRER.js} +1 -1
- package/dist/{chunk-OSRFCVBT.js → chunk-YZEMTNCX.js} +26 -2
- package/dist/cli.js +41 -37
- package/dist/{configs-update-3ZVXGADV.js → configs-update-ON67NMXA.js} +1 -1
- package/dist/{create-DFH2G7RH.js → create-W5S2ZPVC.js} +1 -1
- package/dist/{drift-T74V2C3J.js → drift-ZOLDE24A.js} +1 -1
- package/dist/{found-NXAWEIEK.js → found-M5MX4VXK.js} +1 -1
- package/dist/{healthcheck-HZYEIIOR.js → healthcheck-PFYP6PNW.js} +1 -1
- package/dist/{list-PBAXQSL5.js → list-5TMGSHFC.js} +1 -1
- package/dist/{list-QUFY4IP7.js → list-AHWEE3YZ.js} +1 -1
- package/dist/{list-IYJBKE2F.js → list-B5KLEFHA.js} +1 -1
- package/dist/{list-ZFPML3ZR.js → list-FV5IYCG4.js} +1 -1
- package/dist/{list-23QQYAV5.js → list-GKC7PEU5.js} +1 -1
- package/dist/{list-YCT6DYDI.js → list-HGYBEYOV.js} +1 -1
- package/dist/{list-YRJPN4PI.js → list-ISP5JL4M.js} +1 -1
- package/dist/{list-WX5G3IOF.js → list-LNNIEVB4.js} +2 -2
- package/dist/{list-WJQT2XLE.js → list-TUMVDWIZ.js} +1 -1
- package/dist/{list-I7SBGA52.js → list-VP5IY2SZ.js} +1 -1
- package/dist/{list-EIVPGMWJ.js → list-Z7RJWZH5.js} +1 -1
- package/dist/{list-json-T2Z7NV7G.js → list-json-QC6X25LI.js} +1 -1
- package/dist/{organization-GS5LFIWO.js → organization-VSQQAGBS.js} +40 -23
- package/dist/{run-CJGN6TX4.js → run-HRFJORDS.js} +1 -1
- package/dist/{run-BHEXWBAS.js → run-KDNQIR5E.js} +2 -2
- package/dist/{run-MSO6IXEV.js → run-VHFXOCGS.js} +1 -1
- package/dist/{search-WPSKQGUS.js → search-NOSQW75S.js} +1 -1
- package/dist/{setup-skill-TPMTULHJ.js → setup-skill-Q6PCFIDE.js} +1 -1
- package/dist/{snapshot-ZWAHEG64.js → snapshot-55UV26NQ.js} +1 -1
- package/dist/{summary-CV657J5V.js → summary-QUCLZYX6.js} +1 -1
- package/dist/{validate-SM5DD7I2.js → validate-TPG47SYS.js} +1 -1
- package/dist/{whoami-DH5HVLFN.js → whoami-Y3ZJGN4O.js} +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,34 @@
|
|
|
1
1
|
# @chainpatrol/cli
|
|
2
2
|
|
|
3
|
+
## 0.14.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 339729c: Add an `--include` filter to `chainpatrol metrics organization` (backed
|
|
8
|
+
by a new optional `include` field on `GET /organization/metrics`) so
|
|
9
|
+
callers can ask for just the metrics they care about instead of paying
|
|
10
|
+
for the full ~11-aggregate fan-out.
|
|
11
|
+
|
|
12
|
+
`--include` (or `include: [...]` in the JSON body) accepts a comma list
|
|
13
|
+
of any of: `reports`, `newThreats`, `threatsWatchlisted`,
|
|
14
|
+
`takedownsFiled`, `takedownsCompleted`, `domainThreats`,
|
|
15
|
+
`twitterThreats`, `telegramThreats`, `otherThreats`, `blockedByType`,
|
|
16
|
+
`blockedByDay`. The server runs only those Prisma aggregates;
|
|
17
|
+
unrequested fields come back as `null`. Omitting `--include` (or
|
|
18
|
+
passing an empty list) preserves the existing "compute everything"
|
|
19
|
+
behavior.
|
|
20
|
+
|
|
21
|
+
This is the targeted follow-up to the 3-month-default change for the
|
|
22
|
+
same 503 issue: agents that only need takedown counts can now skip the
|
|
23
|
+
nine other counts entirely, keeping each call well inside the platform
|
|
24
|
+
function cap and cheap enough to run repeatedly per org.
|
|
25
|
+
|
|
26
|
+
The response schema's metric fields and `blockedByType`/`blockedByDay`
|
|
27
|
+
arrays are now nullable to express "not included" — TypeScript callers
|
|
28
|
+
of the CLI's `OrganizationMetricsResult` that previously read
|
|
29
|
+
`result.metrics.reports` as `number` will need `?? 0` (or to opt in to
|
|
30
|
+
`--include` and check for `null` explicitly).
|
|
31
|
+
|
|
3
32
|
## 0.13.0
|
|
4
33
|
|
|
5
34
|
### Minor Changes
|
|
@@ -700,6 +700,33 @@ the full customer-facing dashboard slice (reports, new threats,
|
|
|
700
700
|
watchlisted, takedowns filed/completed, plus per-type and per-day
|
|
701
701
|
breakdowns).
|
|
702
702
|
|
|
703
|
+
#### \`--include\` \u2014 only compute the metrics you actually need
|
|
704
|
+
|
|
705
|
+
\`metrics organization\` runs one Prisma aggregate per requested field.
|
|
706
|
+
By default all 11 are computed in parallel. Pass \`--include\` (or
|
|
707
|
+
\`include: [\u2026]\` in the JSON body) with the comma-separated subset you
|
|
708
|
+
care about to skip the rest \u2014 the unrequested fields come back as
|
|
709
|
+
\`null\` instead of a number, and the server never runs those queries:
|
|
710
|
+
|
|
711
|
+
\`\`\`bash
|
|
712
|
+
# Only takedowns \u2014 one of the cheap shapes
|
|
713
|
+
chainpatrol --json metrics organization --org <slug> \\
|
|
714
|
+
--include takedownsFiled,takedownsCompleted
|
|
715
|
+
|
|
716
|
+
# Time series only, no scalar counts
|
|
717
|
+
chainpatrol --json metrics organization --org <slug> --include blockedByDay
|
|
718
|
+
\`\`\`
|
|
719
|
+
|
|
720
|
+
Allowed values: \`reports\`, \`newThreats\`, \`threatsWatchlisted\`,
|
|
721
|
+
\`takedownsFiled\`, \`takedownsCompleted\`, \`domainThreats\`,
|
|
722
|
+
\`twitterThreats\`, \`telegramThreats\`, \`otherThreats\`,
|
|
723
|
+
\`blockedByType\`, \`blockedByDay\`.
|
|
724
|
+
|
|
725
|
+
Use this whenever the user's question is specific ("how many takedowns
|
|
726
|
+
did we file last month?"). It is the lowest-effort way to make a
|
|
727
|
+
metrics call cheap enough to run repeatedly. Pair it with an explicit
|
|
728
|
+
date window for the best behavior.
|
|
729
|
+
|
|
703
730
|
#### "Across all orgs" via an API key \u2014 what's actually possible
|
|
704
731
|
|
|
705
732
|
A ChainPatrol API key is scoped to a single organization. The
|
|
@@ -45,6 +45,19 @@ var TAKEDOWN_SORT_KEYS = [
|
|
|
45
45
|
"assigneeId",
|
|
46
46
|
"brandId"
|
|
47
47
|
];
|
|
48
|
+
var ORGANIZATION_METRICS_INCLUDE_FIELDS = [
|
|
49
|
+
"reports",
|
|
50
|
+
"newThreats",
|
|
51
|
+
"threatsWatchlisted",
|
|
52
|
+
"takedownsFiled",
|
|
53
|
+
"takedownsCompleted",
|
|
54
|
+
"domainThreats",
|
|
55
|
+
"twitterThreats",
|
|
56
|
+
"telegramThreats",
|
|
57
|
+
"otherThreats",
|
|
58
|
+
"blockedByType",
|
|
59
|
+
"blockedByDay"
|
|
60
|
+
];
|
|
48
61
|
var REQUEST_TIMEOUT_MS = 3e4;
|
|
49
62
|
function defaultGetCredential() {
|
|
50
63
|
const envKey = process.env.CHAINPATROL_API_KEY;
|
|
@@ -71,7 +84,16 @@ function createApiClient(options) {
|
|
|
71
84
|
const headers = buildAuthHeaders();
|
|
72
85
|
const search = new URLSearchParams();
|
|
73
86
|
for (const [key, value] of Object.entries(query)) {
|
|
74
|
-
if (value
|
|
87
|
+
if (value === void 0) continue;
|
|
88
|
+
if (Array.isArray(value)) {
|
|
89
|
+
for (const item of value) {
|
|
90
|
+
if (item !== void 0 && item !== "") {
|
|
91
|
+
search.append(key, item);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (value !== "") {
|
|
75
97
|
search.set(key, value);
|
|
76
98
|
}
|
|
77
99
|
}
|
|
@@ -258,7 +280,8 @@ function createApiClient(options) {
|
|
|
258
280
|
organizationSlug: input.organizationSlug,
|
|
259
281
|
brandSlug: input.brandSlug,
|
|
260
282
|
startDate: parseIsoDateString(input.startDate),
|
|
261
|
-
endDate: parseIsoDateString(input.endDate)
|
|
283
|
+
endDate: parseIsoDateString(input.endDate),
|
|
284
|
+
include: input.include
|
|
262
285
|
});
|
|
263
286
|
},
|
|
264
287
|
listHealthchecks() {
|
|
@@ -378,5 +401,6 @@ export {
|
|
|
378
401
|
TAKEDOWN_STATUSES,
|
|
379
402
|
LIVENESS_STATUSES,
|
|
380
403
|
TAKEDOWN_SORT_KEYS,
|
|
404
|
+
ORGANIZATION_METRICS_INCLUDE_FIELDS,
|
|
381
405
|
createApiClient
|
|
382
406
|
};
|
package/dist/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
getCliVersion,
|
|
14
14
|
isSkillInstalled,
|
|
15
15
|
readInstalledSkillVersion
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-6X5BFFXA.js";
|
|
17
17
|
import "./chunk-NQT77IB7.js";
|
|
18
18
|
import {
|
|
19
19
|
DateTime
|
|
@@ -263,19 +263,21 @@ var HELP = {
|
|
|
263
263
|
]
|
|
264
264
|
},
|
|
265
265
|
"metrics organization": {
|
|
266
|
-
description: "Get organization metrics via the documented GET /organization/metrics endpoint. Works with both API key auth (org derived from key) and session auth (pass --org). Defaults to the trailing 3 months if no date range is given.",
|
|
267
|
-
usage: "chainpatrol metrics organization [--org <slug>] [--from ISO --to ISO|--this-week]",
|
|
266
|
+
description: "Get organization metrics via the documented GET /organization/metrics endpoint. Works with both API key auth (org derived from key) and session auth (pass --org). Defaults to the trailing 3 months if no date range is given. Use --include to skip aggregates the caller doesn't need \u2014 fields not included come back as null.",
|
|
267
|
+
usage: "chainpatrol metrics organization [--org <slug>] [--from ISO --to ISO|--this-week] [--include <list>]",
|
|
268
268
|
options: [
|
|
269
269
|
"--org <slug> Organization slug (omit when using an API key)",
|
|
270
270
|
"--brand-slug <slug> Filter by brand slug (requires brands-metrics flag)",
|
|
271
271
|
"--from <iso> Start date (ISO 8601, e.g. 2026-01-01)",
|
|
272
272
|
"--to <iso> End date (ISO 8601)",
|
|
273
|
-
"--this-week Use the current ISO week (overrides default)"
|
|
273
|
+
"--this-week Use the current ISO week (overrides default)",
|
|
274
|
+
"--include <list> Comma list of fields to compute: reports,newThreats,threatsWatchlisted,takedownsFiled,takedownsCompleted,domainThreats,twitterThreats,telegramThreats,otherThreats,blockedByType,blockedByDay (omit for all)"
|
|
274
275
|
],
|
|
275
276
|
examples: [
|
|
276
|
-
"chainpatrol metrics organization --org acme
|
|
277
|
+
"chainpatrol metrics organization --org acme # defaults to last 3 months, all metrics",
|
|
278
|
+
"chainpatrol metrics organization --org acme --include takedownsFiled,takedownsCompleted",
|
|
277
279
|
"chainpatrol metrics organization --org acme --from 2026-01-01 --to 2026-02-01",
|
|
278
|
-
"CHAINPATROL_API_KEY=... chainpatrol metrics organization --json"
|
|
280
|
+
"CHAINPATROL_API_KEY=... chainpatrol metrics organization --json --include reports"
|
|
279
281
|
]
|
|
280
282
|
},
|
|
281
283
|
"metrics summary": {
|
|
@@ -858,6 +860,7 @@ ${getTopLevelHelp()}
|
|
|
858
860
|
to: { type: "string" },
|
|
859
861
|
thisWeek: { type: "boolean", default: false },
|
|
860
862
|
by: { type: "string" },
|
|
863
|
+
include: { type: "string" },
|
|
861
864
|
brand: { type: "string" },
|
|
862
865
|
enable: { type: "boolean", default: false },
|
|
863
866
|
disable: { type: "boolean", default: false },
|
|
@@ -1031,12 +1034,12 @@ function parseAttachmentUrls() {
|
|
|
1031
1034
|
}
|
|
1032
1035
|
async function handleConfigsList(org) {
|
|
1033
1036
|
if (jsonMode) {
|
|
1034
|
-
const { listConfigsJson } = await import("./list-json-
|
|
1037
|
+
const { listConfigsJson } = await import("./list-json-QC6X25LI.js");
|
|
1035
1038
|
await listConfigsJson({ org });
|
|
1036
1039
|
return;
|
|
1037
1040
|
}
|
|
1038
1041
|
const { render } = await import("ink");
|
|
1039
|
-
const { default: ConfigsList } = await import("./list-
|
|
1042
|
+
const { default: ConfigsList } = await import("./list-B5KLEFHA.js");
|
|
1040
1043
|
const { default: React } = await import("react");
|
|
1041
1044
|
render(React.createElement(ConfigsList, { org }));
|
|
1042
1045
|
}
|
|
@@ -1136,7 +1139,7 @@ async function main() {
|
|
|
1136
1139
|
const positionals = cli.input.slice(2);
|
|
1137
1140
|
const flagAssets = parseAssetInputs();
|
|
1138
1141
|
const contents = [...positionals, ...flagAssets];
|
|
1139
|
-
const { runAssetCheck } = await import("./check-
|
|
1142
|
+
const { runAssetCheck } = await import("./check-NJH7BUIM.js");
|
|
1140
1143
|
await runAssetCheck({
|
|
1141
1144
|
contents,
|
|
1142
1145
|
json: jsonMode,
|
|
@@ -1146,7 +1149,7 @@ async function main() {
|
|
|
1146
1149
|
break;
|
|
1147
1150
|
}
|
|
1148
1151
|
if (subcommand === "list") {
|
|
1149
|
-
const { runAssetList } = await import("./list-
|
|
1152
|
+
const { runAssetList } = await import("./list-5TMGSHFC.js");
|
|
1150
1153
|
await runAssetList({
|
|
1151
1154
|
type: cli.flags.type ?? cli.flags.assetType,
|
|
1152
1155
|
status: cli.flags.assetStatus ?? cli.flags.status,
|
|
@@ -1167,7 +1170,7 @@ async function main() {
|
|
|
1167
1170
|
case "detections": {
|
|
1168
1171
|
const org = await resolveOrg();
|
|
1169
1172
|
if (subcommand === "healthcheck") {
|
|
1170
|
-
const { runDetectionsHealthcheck } = await import("./healthcheck-
|
|
1173
|
+
const { runDetectionsHealthcheck } = await import("./healthcheck-PFYP6PNW.js");
|
|
1171
1174
|
await runDetectionsHealthcheck({
|
|
1172
1175
|
org,
|
|
1173
1176
|
source: cli.flags.source,
|
|
@@ -1182,7 +1185,7 @@ async function main() {
|
|
|
1182
1185
|
break;
|
|
1183
1186
|
}
|
|
1184
1187
|
if (subcommand === "validate") {
|
|
1185
|
-
const { runDetectionsValidate } = await import("./validate-
|
|
1188
|
+
const { runDetectionsValidate } = await import("./validate-TPG47SYS.js");
|
|
1186
1189
|
await runDetectionsValidate({
|
|
1187
1190
|
org,
|
|
1188
1191
|
source: cli.flags.source,
|
|
@@ -1197,7 +1200,7 @@ async function main() {
|
|
|
1197
1200
|
break;
|
|
1198
1201
|
}
|
|
1199
1202
|
if (subcommand === "drift") {
|
|
1200
|
-
const { runDetectionsDrift } = await import("./drift-
|
|
1203
|
+
const { runDetectionsDrift } = await import("./drift-ZOLDE24A.js");
|
|
1201
1204
|
await runDetectionsDrift({
|
|
1202
1205
|
org,
|
|
1203
1206
|
source: cli.flags.source,
|
|
@@ -1211,7 +1214,7 @@ async function main() {
|
|
|
1211
1214
|
break;
|
|
1212
1215
|
}
|
|
1213
1216
|
if (subcommand === "run") {
|
|
1214
|
-
const { runDetectionsRun } = await import("./run-
|
|
1217
|
+
const { runDetectionsRun } = await import("./run-VHFXOCGS.js");
|
|
1215
1218
|
await runDetectionsRun({
|
|
1216
1219
|
org,
|
|
1217
1220
|
configId: cli.flags.configId,
|
|
@@ -1225,7 +1228,7 @@ async function main() {
|
|
|
1225
1228
|
break;
|
|
1226
1229
|
}
|
|
1227
1230
|
if (subcommand === "list") {
|
|
1228
|
-
const { runDetectionsList } = await import("./list-
|
|
1231
|
+
const { runDetectionsList } = await import("./list-AHWEE3YZ.js");
|
|
1229
1232
|
await runDetectionsList({
|
|
1230
1233
|
org,
|
|
1231
1234
|
cursor: cli.flags.cursor,
|
|
@@ -1254,7 +1257,7 @@ async function main() {
|
|
|
1254
1257
|
break;
|
|
1255
1258
|
}
|
|
1256
1259
|
if (action === "run") {
|
|
1257
|
-
const { runDetectionsRun } = await import("./run-
|
|
1260
|
+
const { runDetectionsRun } = await import("./run-VHFXOCGS.js");
|
|
1258
1261
|
await runDetectionsRun({
|
|
1259
1262
|
org,
|
|
1260
1263
|
configId: cli.flags.configId,
|
|
@@ -1272,7 +1275,7 @@ async function main() {
|
|
|
1272
1275
|
throw new Error("detections configs update requires --config-id");
|
|
1273
1276
|
}
|
|
1274
1277
|
const configPatch = getConfigPatchFromSetFlags();
|
|
1275
|
-
const { runDetectionsConfigsUpdate } = await import("./configs-update-
|
|
1278
|
+
const { runDetectionsConfigsUpdate } = await import("./configs-update-ON67NMXA.js");
|
|
1276
1279
|
await runDetectionsConfigsUpdate({
|
|
1277
1280
|
org,
|
|
1278
1281
|
configId: cli.flags.configId,
|
|
@@ -1306,13 +1309,14 @@ async function main() {
|
|
|
1306
1309
|
case "metrics": {
|
|
1307
1310
|
if (subcommand === "organization" || subcommand === "org") {
|
|
1308
1311
|
const org2 = await tryResolveOrg();
|
|
1309
|
-
const { runMetricsOrganization } = await import("./organization-
|
|
1312
|
+
const { runMetricsOrganization } = await import("./organization-VSQQAGBS.js");
|
|
1310
1313
|
await runMetricsOrganization({
|
|
1311
1314
|
org: org2,
|
|
1312
1315
|
brandSlug: cli.flags.brandSlug,
|
|
1313
1316
|
from: cli.flags.from,
|
|
1314
1317
|
to: cli.flags.to,
|
|
1315
1318
|
thisWeek: cli.flags.thisWeek,
|
|
1319
|
+
include: parseCsvList(cli.flags.include),
|
|
1316
1320
|
json: jsonMode,
|
|
1317
1321
|
outputFormat: cliContext.outputFormat
|
|
1318
1322
|
});
|
|
@@ -1320,7 +1324,7 @@ async function main() {
|
|
|
1320
1324
|
}
|
|
1321
1325
|
const org = await resolveOrg();
|
|
1322
1326
|
if (subcommand === "summary") {
|
|
1323
|
-
const { runMetricsSummary } = await import("./summary-
|
|
1327
|
+
const { runMetricsSummary } = await import("./summary-QUCLZYX6.js");
|
|
1324
1328
|
await runMetricsSummary({
|
|
1325
1329
|
org,
|
|
1326
1330
|
from: cli.flags.from,
|
|
@@ -1333,7 +1337,7 @@ async function main() {
|
|
|
1333
1337
|
break;
|
|
1334
1338
|
}
|
|
1335
1339
|
if (subcommand === "found") {
|
|
1336
|
-
const { runMetricsFound } = await import("./found-
|
|
1340
|
+
const { runMetricsFound } = await import("./found-M5MX4VXK.js");
|
|
1337
1341
|
await runMetricsFound({
|
|
1338
1342
|
org,
|
|
1339
1343
|
from: cli.flags.from,
|
|
@@ -1350,7 +1354,7 @@ async function main() {
|
|
|
1350
1354
|
if (!by || !["day", "type", "brand"].includes(by)) {
|
|
1351
1355
|
throw new Error("metrics breakdown requires --by <day|type|brand>");
|
|
1352
1356
|
}
|
|
1353
|
-
const { runMetricsBreakdown } = await import("./breakdown-
|
|
1357
|
+
const { runMetricsBreakdown } = await import("./breakdown-K5Q6TDKE.js");
|
|
1354
1358
|
await runMetricsBreakdown({
|
|
1355
1359
|
org,
|
|
1356
1360
|
by,
|
|
@@ -1371,7 +1375,7 @@ async function main() {
|
|
|
1371
1375
|
case "reports": {
|
|
1372
1376
|
if (subcommand === "list") {
|
|
1373
1377
|
const org = await resolveOrg();
|
|
1374
|
-
const { runReportsList } = await import("./list-
|
|
1378
|
+
const { runReportsList } = await import("./list-FV5IYCG4.js");
|
|
1375
1379
|
await runReportsList({
|
|
1376
1380
|
org,
|
|
1377
1381
|
limit: cli.flags.limit,
|
|
@@ -1399,7 +1403,7 @@ async function main() {
|
|
|
1399
1403
|
}
|
|
1400
1404
|
if (subcommand === "create") {
|
|
1401
1405
|
const org = await tryResolveOrg();
|
|
1402
|
-
const { runReportsCreate } = await import("./create-
|
|
1406
|
+
const { runReportsCreate } = await import("./create-W5S2ZPVC.js");
|
|
1403
1407
|
await runReportsCreate({
|
|
1404
1408
|
org,
|
|
1405
1409
|
title: cli.flags.title,
|
|
@@ -1420,7 +1424,7 @@ async function main() {
|
|
|
1420
1424
|
const positionals = cli.input.slice(2);
|
|
1421
1425
|
const flagAssets = parseAssetInputs();
|
|
1422
1426
|
const assetContents = [...positionals, ...flagAssets];
|
|
1423
|
-
const { runReportsSearch } = await import("./search-
|
|
1427
|
+
const { runReportsSearch } = await import("./search-NOSQW75S.js");
|
|
1424
1428
|
await runReportsSearch({
|
|
1425
1429
|
assetContents,
|
|
1426
1430
|
reportedByCustomer: cli.flags.reportedByCustomer,
|
|
@@ -1436,7 +1440,7 @@ async function main() {
|
|
|
1436
1440
|
}
|
|
1437
1441
|
case "threats": {
|
|
1438
1442
|
if (subcommand === "list") {
|
|
1439
|
-
const { runThreatsList } = await import("./list-
|
|
1443
|
+
const { runThreatsList } = await import("./list-HGYBEYOV.js");
|
|
1440
1444
|
await runThreatsList({
|
|
1441
1445
|
query: cli.flags.query,
|
|
1442
1446
|
from: cli.flags.from,
|
|
@@ -1459,7 +1463,7 @@ async function main() {
|
|
|
1459
1463
|
case "takedowns": {
|
|
1460
1464
|
if (subcommand === "list") {
|
|
1461
1465
|
const org = await tryResolveOrg();
|
|
1462
|
-
const { runTakedownsList } = await import("./list-
|
|
1466
|
+
const { runTakedownsList } = await import("./list-TUMVDWIZ.js");
|
|
1463
1467
|
await runTakedownsList({
|
|
1464
1468
|
org,
|
|
1465
1469
|
query: cli.flags.query,
|
|
@@ -1490,7 +1494,7 @@ async function main() {
|
|
|
1490
1494
|
}
|
|
1491
1495
|
case "queues": {
|
|
1492
1496
|
if (subcommand === "snapshot") {
|
|
1493
|
-
const { runQueuesSnapshot } = await import("./snapshot-
|
|
1497
|
+
const { runQueuesSnapshot } = await import("./snapshot-55UV26NQ.js");
|
|
1494
1498
|
await runQueuesSnapshot({
|
|
1495
1499
|
org: cli.flags.org,
|
|
1496
1500
|
all: cli.flags.all,
|
|
@@ -1508,7 +1512,7 @@ async function main() {
|
|
|
1508
1512
|
}
|
|
1509
1513
|
case "orgs": {
|
|
1510
1514
|
if (subcommand === "list") {
|
|
1511
|
-
const { runOrgsList } = await import("./list-
|
|
1515
|
+
const { runOrgsList } = await import("./list-ISP5JL4M.js");
|
|
1512
1516
|
await runOrgsList({
|
|
1513
1517
|
query: cli.flags.query,
|
|
1514
1518
|
subscriptionStatus: cli.flags.subscriptionStatus,
|
|
@@ -1523,7 +1527,7 @@ async function main() {
|
|
|
1523
1527
|
}
|
|
1524
1528
|
if (subcommand === "assets") {
|
|
1525
1529
|
if (action === "list") {
|
|
1526
|
-
const { runOrgsAssetsList } = await import("./list-
|
|
1530
|
+
const { runOrgsAssetsList } = await import("./list-Z7RJWZH5.js");
|
|
1527
1531
|
await runOrgsAssetsList({
|
|
1528
1532
|
type: cli.flags.type ?? cli.flags.assetType,
|
|
1529
1533
|
groupId: cli.flags.groupId,
|
|
@@ -1539,7 +1543,7 @@ async function main() {
|
|
|
1539
1543
|
}
|
|
1540
1544
|
if (subcommand === "asset-groups") {
|
|
1541
1545
|
if (action === "list") {
|
|
1542
|
-
const { runOrgsAssetGroupsList } = await import("./list-
|
|
1546
|
+
const { runOrgsAssetGroupsList } = await import("./list-VP5IY2SZ.js");
|
|
1543
1547
|
await runOrgsAssetGroupsList({
|
|
1544
1548
|
json: jsonMode,
|
|
1545
1549
|
outputFormat: cliContext.outputFormat
|
|
@@ -1554,7 +1558,7 @@ async function main() {
|
|
|
1554
1558
|
);
|
|
1555
1559
|
}
|
|
1556
1560
|
case "whoami": {
|
|
1557
|
-
const { runWhoami } = await import("./whoami-
|
|
1561
|
+
const { runWhoami } = await import("./whoami-Y3ZJGN4O.js");
|
|
1558
1562
|
await runWhoami({
|
|
1559
1563
|
json: jsonMode,
|
|
1560
1564
|
outputFormat: cliContext.outputFormat
|
|
@@ -1563,7 +1567,7 @@ async function main() {
|
|
|
1563
1567
|
}
|
|
1564
1568
|
case "healthchecks": {
|
|
1565
1569
|
if (subcommand === "list") {
|
|
1566
|
-
const { runHealthchecksList } = await import("./list-
|
|
1570
|
+
const { runHealthchecksList } = await import("./list-GKC7PEU5.js");
|
|
1567
1571
|
await runHealthchecksList({
|
|
1568
1572
|
json: jsonMode,
|
|
1569
1573
|
outputFormat: cliContext.outputFormat
|
|
@@ -1577,7 +1581,7 @@ async function main() {
|
|
|
1577
1581
|
thresholds.minResults = cli.flags.minResults;
|
|
1578
1582
|
if (cli.flags.lookbackHours !== void 0)
|
|
1579
1583
|
thresholds.lookbackHours = cli.flags.lookbackHours;
|
|
1580
|
-
const { runHealthchecksRun } = await import("./run-
|
|
1584
|
+
const { runHealthchecksRun } = await import("./run-HRFJORDS.js");
|
|
1581
1585
|
await runHealthchecksRun({
|
|
1582
1586
|
org,
|
|
1583
1587
|
id: action,
|
|
@@ -1595,7 +1599,7 @@ async function main() {
|
|
|
1595
1599
|
}
|
|
1596
1600
|
case "presets": {
|
|
1597
1601
|
if (subcommand === "list") {
|
|
1598
|
-
const { runPresetsList } = await import("./list-
|
|
1602
|
+
const { runPresetsList } = await import("./list-LNNIEVB4.js");
|
|
1599
1603
|
await runPresetsList({ outputFormat: cliContext.outputFormat });
|
|
1600
1604
|
break;
|
|
1601
1605
|
}
|
|
@@ -1606,7 +1610,7 @@ async function main() {
|
|
|
1606
1610
|
);
|
|
1607
1611
|
}
|
|
1608
1612
|
const org = await resolveOrg();
|
|
1609
|
-
const { runPresetsRun } = await import("./run-
|
|
1613
|
+
const { runPresetsRun } = await import("./run-KDNQIR5E.js");
|
|
1610
1614
|
await runPresetsRun({
|
|
1611
1615
|
presetId: action,
|
|
1612
1616
|
org,
|
|
@@ -1623,12 +1627,12 @@ async function main() {
|
|
|
1623
1627
|
case "setup":
|
|
1624
1628
|
case "install":
|
|
1625
1629
|
case "i": {
|
|
1626
|
-
const { setupSkill } = await import("./setup-skill-
|
|
1630
|
+
const { setupSkill } = await import("./setup-skill-Q6PCFIDE.js");
|
|
1627
1631
|
setupSkill({ json: jsonMode, cloud: cli.flags.cloud });
|
|
1628
1632
|
break;
|
|
1629
1633
|
}
|
|
1630
1634
|
case "uninstall": {
|
|
1631
|
-
const { uninstallSkill } = await import("./setup-skill-
|
|
1635
|
+
const { uninstallSkill } = await import("./setup-skill-Q6PCFIDE.js");
|
|
1632
1636
|
uninstallSkill({ json: jsonMode });
|
|
1633
1637
|
break;
|
|
1634
1638
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PRESETS
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-BIKTBRER.js";
|
|
4
4
|
import "./chunk-E2LAMILJ.js";
|
|
5
5
|
import {
|
|
6
6
|
printOutput,
|
|
7
7
|
toCsvRows
|
|
8
8
|
} from "./chunk-VFT3TD3E.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-YZEMTNCX.js";
|
|
10
10
|
import "./chunk-EGWK6SRQ.js";
|
|
11
11
|
import "./chunk-TFCNKBRC.js";
|
|
12
12
|
import "./chunk-U73SABXK.js";
|
|
@@ -6,13 +6,28 @@ import {
|
|
|
6
6
|
toCsvRows
|
|
7
7
|
} from "./chunk-VFT3TD3E.js";
|
|
8
8
|
import {
|
|
9
|
+
ORGANIZATION_METRICS_INCLUDE_FIELDS,
|
|
9
10
|
createApiClient
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-YZEMTNCX.js";
|
|
11
12
|
import "./chunk-EGWK6SRQ.js";
|
|
12
13
|
import "./chunk-TFCNKBRC.js";
|
|
13
14
|
import "./chunk-U73SABXK.js";
|
|
14
15
|
|
|
15
16
|
// src/commands/metrics/organization.ts
|
|
17
|
+
var INCLUDE_VALUES = new Set(ORGANIZATION_METRICS_INCLUDE_FIELDS);
|
|
18
|
+
function parseIncludeList(raw) {
|
|
19
|
+
if (!raw || raw.length === 0) return void 0;
|
|
20
|
+
const fields = [];
|
|
21
|
+
for (const value of raw) {
|
|
22
|
+
if (!INCLUDE_VALUES.has(value)) {
|
|
23
|
+
throw new Error(
|
|
24
|
+
`Unknown --include value: '${value}'. Allowed: ${ORGANIZATION_METRICS_INCLUDE_FIELDS.join(", ")}`
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
fields.push(value);
|
|
28
|
+
}
|
|
29
|
+
return fields;
|
|
30
|
+
}
|
|
16
31
|
async function runMetricsOrganization(options) {
|
|
17
32
|
const outputFormat = options.outputFormat ?? (options.json ? "json" : "human");
|
|
18
33
|
const client = options.apiClient ?? createApiClient();
|
|
@@ -21,30 +36,37 @@ async function runMetricsOrganization(options) {
|
|
|
21
36
|
to: options.to,
|
|
22
37
|
thisWeek: options.thisWeek
|
|
23
38
|
});
|
|
39
|
+
const include = parseIncludeList(options.include);
|
|
24
40
|
const input = {
|
|
25
41
|
organizationSlug: options.org,
|
|
26
42
|
brandSlug: options.brandSlug,
|
|
27
43
|
startDate: range.startDate,
|
|
28
|
-
endDate: range.endDate
|
|
44
|
+
endDate: range.endDate,
|
|
45
|
+
include
|
|
29
46
|
};
|
|
30
47
|
const result = await client.getOrganizationMetrics(input);
|
|
31
48
|
const label = options.org ?? "your organization";
|
|
49
|
+
const includeLabel = include ? ` (include: ${include.join(", ")})` : "";
|
|
50
|
+
const metricLines = [
|
|
51
|
+
["Reports", result.metrics.reports],
|
|
52
|
+
["New threats", result.metrics.newThreats],
|
|
53
|
+
["Watchlisted threats", result.metrics.threatsWatchlisted],
|
|
54
|
+
["Takedowns filed", result.metrics.takedownsFiled],
|
|
55
|
+
["Takedowns completed", result.metrics.takedownsCompleted],
|
|
56
|
+
["Domain threats", result.metrics.domainThreats],
|
|
57
|
+
["Twitter threats", result.metrics.twitterThreats],
|
|
58
|
+
["Telegram threats", result.metrics.telegramThreats],
|
|
59
|
+
["Other threats", result.metrics.otherThreats]
|
|
60
|
+
];
|
|
61
|
+
const populatedMetricLines = metricLines.filter(([, value]) => value !== null);
|
|
32
62
|
printOutput({
|
|
33
63
|
outputFormat,
|
|
34
|
-
json: { ...result, range },
|
|
64
|
+
json: { ...result, range, include: include ?? null },
|
|
35
65
|
markdown: [
|
|
36
|
-
`# Organization Metrics (${label}) \u2014 ${range.label}`,
|
|
66
|
+
`# Organization Metrics (${label}) \u2014 ${range.label}${includeLabel}`,
|
|
37
67
|
"",
|
|
38
68
|
`- Range: ${range.startDate} \u2192 ${range.endDate}`,
|
|
39
|
-
`-
|
|
40
|
-
`- New threats: ${result.metrics.newThreats}`,
|
|
41
|
-
`- Watchlisted threats: ${result.metrics.threatsWatchlisted}`,
|
|
42
|
-
`- Takedowns filed: ${result.metrics.takedownsFiled}`,
|
|
43
|
-
`- Takedowns completed: ${result.metrics.takedownsCompleted}`,
|
|
44
|
-
`- Domain threats: ${result.metrics.domainThreats}`,
|
|
45
|
-
`- Twitter threats: ${result.metrics.twitterThreats}`,
|
|
46
|
-
`- Telegram threats: ${result.metrics.telegramThreats}`,
|
|
47
|
-
`- Other threats: ${result.metrics.otherThreats}`
|
|
69
|
+
...populatedMetricLines.map(([name, value]) => `- ${name}: ${value}`)
|
|
48
70
|
].join("\n"),
|
|
49
71
|
csv: toCsvRows([
|
|
50
72
|
{
|
|
@@ -63,17 +85,12 @@ async function runMetricsOrganization(options) {
|
|
|
63
85
|
}
|
|
64
86
|
]),
|
|
65
87
|
human: () => {
|
|
66
|
-
console.log(`Organization metrics for ${label} \u2014 ${range.label}`);
|
|
88
|
+
console.log(`Organization metrics for ${label} \u2014 ${range.label}${includeLabel}`);
|
|
67
89
|
console.log(`Range: ${range.startDate} \u2192 ${range.endDate}`);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
console.log(`Takedowns completed: ${result.metrics.takedownsCompleted}`);
|
|
73
|
-
console.log(
|
|
74
|
-
`Threat breakdown: domains=${result.metrics.domainThreats}, twitter=${result.metrics.twitterThreats}, telegram=${result.metrics.telegramThreats}, other=${result.metrics.otherThreats}`
|
|
75
|
-
);
|
|
76
|
-
if (result.blockedByDay.length > 0) {
|
|
90
|
+
for (const [name, value] of populatedMetricLines) {
|
|
91
|
+
console.log(`${name}: ${value}`);
|
|
92
|
+
}
|
|
93
|
+
if (result.blockedByDay && result.blockedByDay.length > 0) {
|
|
77
94
|
console.log("");
|
|
78
95
|
console.log(`Blocked by day (${result.blockedByDay.length} entries):`);
|
|
79
96
|
for (const entry of result.blockedByDay) {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getPresetDefinition,
|
|
3
3
|
runPreset
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BIKTBRER.js";
|
|
5
5
|
import {
|
|
6
6
|
CliExitError,
|
|
7
7
|
ExitCode
|
|
8
8
|
} from "./chunk-E2LAMILJ.js";
|
|
9
9
|
import "./chunk-VFT3TD3E.js";
|
|
10
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-YZEMTNCX.js";
|
|
11
11
|
import "./chunk-EGWK6SRQ.js";
|
|
12
12
|
import "./chunk-TFCNKBRC.js";
|
|
13
13
|
import "./chunk-U73SABXK.js";
|
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.14.0",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"homepage": "https://chainpatrol.com/docs/cli",
|
|
8
8
|
"keywords": [
|