@chainpatrol/cli 0.15.1 → 0.16.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 +52 -0
- package/dist/{breakdown-27PMFEWQ.js → breakdown-PQXHY2VO.js} +1 -1
- package/dist/{check-M5U2CSWK.js → check-5B4EPWOZ.js} +1 -1
- package/dist/{chunk-FOTFWUOX.js → chunk-CJPWEWGS.js} +1 -1
- package/dist/{chunk-UZDSNWGL.js → chunk-JEBZIBRI.js} +3 -0
- package/dist/{chunk-IPN6O3N4.js → chunk-TTLGCRRR.js} +65 -42
- package/dist/cli.js +53 -45
- package/dist/{configs-update-YMPRYXKZ.js → configs-update-6BYB7M37.js} +1 -1
- package/dist/{create-DQYNYD6G.js → create-Y6Z4L656.js} +1 -1
- package/dist/{drift-T4AF6Y3X.js → drift-5EZK2JA5.js} +1 -1
- package/dist/{found-XEGMO6YY.js → found-XRJZ4SSY.js} +1 -1
- package/dist/{healthcheck-FORGIJWP.js → healthcheck-47MU5AZ7.js} +1 -1
- package/dist/{list-N4TTNR6N.js → list-2JCBA3Q2.js} +1 -1
- package/dist/{list-OWJLAWMP.js → list-AYXZG3I6.js} +1 -1
- package/dist/{list-RMD4NKVB.js → list-FGDMMAPM.js} +1 -1
- package/dist/{list-VOWXWXHY.js → list-G2F2IFEU.js} +1 -1
- package/dist/{list-ZTMCEG56.js → list-GPWZ52JD.js} +1 -1
- package/dist/{list-WPXNCBT3.js → list-IA2LRT4X.js} +1 -1
- package/dist/{list-XHBQMP6P.js → list-JD4U2SBV.js} +1 -1
- package/dist/{list-COJ5BLQV.js → list-KFFNLKZK.js} +1 -1
- package/dist/{list-63HPS2RE.js → list-QC7DUKFD.js} +1 -1
- package/dist/{list-BJMP3QEV.js → list-WBZIULUS.js} +2 -2
- package/dist/{list-DVPEMSVH.js → list-ZIM2MR2Q.js} +1 -1
- package/dist/{list-json-X6QHIRE5.js → list-json-DXPR3UEY.js} +1 -1
- package/dist/{organization-HD6LRAZP.js → organization-NR6JCD5I.js} +35 -4
- package/dist/{run-BHAH7DUC.js → run-ANHA5JFB.js} +2 -2
- package/dist/{run-G5J77GZD.js → run-EJBBPBOR.js} +1 -1
- package/dist/{run-V7QJBNLF.js → run-HDEKIP4L.js} +1 -1
- package/dist/{search-ME6KFCEV.js → search-PBVQ7473.js} +1 -1
- package/dist/{setup-skill-6SDQXFTR.js → setup-skill-2RKWIVGS.js} +1 -1
- package/dist/{snapshot-B6TQCFQ3.js → snapshot-U53T5Q2M.js} +1 -1
- package/dist/{summary-NYHIQ5DP.js → summary-2IXOMOIA.js} +1 -1
- package/dist/{validate-I3YHZDZR.js → validate-LXE3JPET.js} +1 -1
- package/dist/{whoami-6KU4LOJS.js → whoami-4XDWPKVV.js} +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,57 @@
|
|
|
1
1
|
# @chainpatrol/cli
|
|
2
2
|
|
|
3
|
+
## 0.16.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- c1af664: Add `--all-my-orgs` to `chainpatrol metrics organization` and raise
|
|
8
|
+
the `--slugs` cap from 50 → 500.
|
|
9
|
+
|
|
10
|
+
`--all-my-orgs` is the shortest path to answer "how many takedowns
|
|
11
|
+
across all clients in the last 7 days?" — no `orgs list` round-trip,
|
|
12
|
+
no client-side slug stitching. The server resolves the org set using
|
|
13
|
+
the same logic as `/user/orgs` (so an agent already familiar with
|
|
14
|
+
that filter shape can reuse it), runs the per-org metric fan-out
|
|
15
|
+
with bounded concurrency, and rolls up totals + per-day /
|
|
16
|
+
per-org-per-day averages + the per-org breakdown in one HTTP call.
|
|
17
|
+
|
|
18
|
+
Pair with `--subscription-status` and/or `--service-active` to
|
|
19
|
+
narrow to the org set the question is actually about — e.g.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
chainpatrol --json metrics organization \
|
|
23
|
+
--all-my-orgs \
|
|
24
|
+
--subscription-status ACTIVE \
|
|
25
|
+
--service-active takedowns \
|
|
26
|
+
--include takedownsCompleted \
|
|
27
|
+
--from 2026-05-12 --to 2026-05-19
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The `--slugs` form still works for cases where the caller wants a
|
|
31
|
+
specific named subset; both forms cap at 500 orgs per call (previously
|
|
32
|
+
50). The cap remains a backstop — `--all-my-orgs` returns a 413 with
|
|
33
|
+
a clear "narrow with filters" hint if the resolved set exceeds it.
|
|
34
|
+
|
|
35
|
+
Auth:
|
|
36
|
+
|
|
37
|
+
- Org-scoped API keys are rejected for `--all-my-orgs` (they're pinned
|
|
38
|
+
to a single org by design — the default form already covers that
|
|
39
|
+
org).
|
|
40
|
+
- User API keys (inherit owning user's memberships) and Bearer
|
|
41
|
+
sessions can use it; the resolved org set matches what `orgs list`
|
|
42
|
+
would return for the same caller.
|
|
43
|
+
- Staff users still get every active org (subject to the filters).
|
|
44
|
+
|
|
45
|
+
Response now includes `scope.resolvedFrom` (`"api-key" |
|
|
46
|
+
"organizationSlug" | "slugs" | "allMyOrgs"`) so agents can see how
|
|
47
|
+
the server interpreted their request and report it accurately to the
|
|
48
|
+
end user.
|
|
49
|
+
|
|
50
|
+
Skill content is rewritten to lead with `--all-my-orgs` for cross-org
|
|
51
|
+
questions, with `--slugs` repositioned as "use this for an explicit
|
|
52
|
+
subset." Existing `--slugs` examples and the `orgs list` + `--slugs`
|
|
53
|
+
recipe are updated to call out the new single-call alternative.
|
|
54
|
+
|
|
3
55
|
## 0.15.1
|
|
4
56
|
|
|
5
57
|
### Patch Changes
|
|
@@ -279,6 +279,9 @@ function createApiClient(options) {
|
|
|
279
279
|
return requestGet("/organization/metrics", {
|
|
280
280
|
organizationSlug: input.organizationSlug,
|
|
281
281
|
slugs: input.slugs,
|
|
282
|
+
allMyOrgs: input.allMyOrgs ? "true" : void 0,
|
|
283
|
+
subscriptionStatus: input.subscriptionStatus,
|
|
284
|
+
services: input.services ? JSON.stringify(input.services) : void 0,
|
|
282
285
|
brandSlug: input.brandSlug,
|
|
283
286
|
startDate: parseIsoDateString(input.startDate),
|
|
284
287
|
endDate: parseIsoDateString(input.endDate),
|
|
@@ -674,21 +674,25 @@ When the user asks for a number that **spans more than one customer/org/brand**
|
|
|
674
674
|
"across all brands", "company-wide", "total takedowns", "total threats",
|
|
675
675
|
"average takedowns per day across customers", "rollup across customers",
|
|
676
676
|
"how many takedowns in the last 7 days?" (no org named) \u2014 the answer is
|
|
677
|
-
**\`chainpatrol metrics organization --
|
|
678
|
-
|
|
679
|
-
single-org commands and have no \`--slugs
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
677
|
+
**\`chainpatrol metrics organization --all-my-orgs\`** (or \`--slugs\`
|
|
678
|
+
if you want a specific subset). \`summary\`, \`found\`, and \`breakdown\`
|
|
679
|
+
are single-org commands and have **no** \`--slugs\`/\`--all-my-orgs\`
|
|
680
|
+
form; only \`organization\` does. The multi-org form rolls totals +
|
|
681
|
+
per-day / per-org-per-day averages + a per-org breakdown server-side
|
|
682
|
+
in **one** HTTP call.
|
|
683
683
|
|
|
684
684
|
**Anti-patterns to avoid:**
|
|
685
685
|
|
|
686
|
-
- \u274C "There's no cross-org aggregation in the CLI." There is \u2014
|
|
687
|
-
organization --slugs
|
|
688
|
-
|
|
686
|
+
- \u274C "There's no cross-org aggregation in the CLI." There is \u2014
|
|
687
|
+
\`metrics organization --all-my-orgs\` (or \`--slugs\`). Don't bail
|
|
688
|
+
out citing the docs without trying these flags.
|
|
689
689
|
- \u274C Looping \`metrics summary --org X\` once per customer to sum
|
|
690
|
-
client-side.
|
|
691
|
-
the endpoint 503-prone in the first place.
|
|
690
|
+
client-side. The multi-org form is one round-trip; the loop is what
|
|
691
|
+
made the endpoint 503-prone in the first place.
|
|
692
|
+
- \u274C Calling \`orgs list\` to build a slug list when you just want
|
|
693
|
+
"everything." Use \`--all-my-orgs\` and skip the enumeration entirely \u2014
|
|
694
|
+
the server resolves the same set via shared logic. Save \`orgs list\`
|
|
695
|
+
+ \`--slugs\` for cases where the user asked for a specific subset.
|
|
692
696
|
- \u274C Routing the user to Metabase / the data warehouse for a question
|
|
693
697
|
the CLI can answer. Reach for Metabase only when the metric isn't
|
|
694
698
|
in the \`--include\` list (\`reports\`, \`newThreats\`,
|
|
@@ -696,35 +700,46 @@ section below.
|
|
|
696
700
|
\`domainThreats\`, \`twitterThreats\`, \`telegramThreats\`,
|
|
697
701
|
\`otherThreats\`, \`blockedByType\`, \`blockedByDay\`).
|
|
698
702
|
- \u274C "Iterating 100+ orgs one-by-one isn't practical here." Right \u2014
|
|
699
|
-
that's why you don't iterate.
|
|
700
|
-
|
|
701
|
-
|
|
703
|
+
that's why you don't iterate. \`--all-my-orgs\` covers up to 500
|
|
704
|
+
orgs in a single call; for larger fleets, narrow with
|
|
705
|
+
\`--subscription-status\` / \`--service-active\`, or split an
|
|
706
|
+
explicit \`--slugs\` list into batches and sum.
|
|
702
707
|
|
|
703
708
|
#### Common cross-org recipe (copy and run)
|
|
704
709
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
chainpatrol --json orgs list \\
|
|
708
|
-
--subscription-status ACTIVE \\
|
|
709
|
-
--service-active takedowns
|
|
710
|
+
The shortest answer to "how many takedowns across all customers in the
|
|
711
|
+
last 7 days?" is a single call \u2014 no \`orgs list\` step needed:
|
|
710
712
|
|
|
711
|
-
|
|
713
|
+
\`\`\`bash
|
|
712
714
|
chainpatrol --json metrics organization \\
|
|
713
|
-
--
|
|
715
|
+
--all-my-orgs \\
|
|
716
|
+
--subscription-status ACTIVE \\
|
|
717
|
+
--service-active takedowns \\
|
|
714
718
|
--include takedownsCompleted \\
|
|
715
719
|
--from <YYYY-MM-DD 7 days ago> --to <YYYY-MM-DD today>
|
|
716
720
|
|
|
717
721
|
# Read these fields from the JSON:
|
|
718
|
-
# .
|
|
719
|
-
# .
|
|
720
|
-
# .averages.
|
|
721
|
-
# .
|
|
722
|
+
# .scope.orgs \u2190 which orgs the server resolved
|
|
723
|
+
# .metrics.takedownsCompleted \u2190 grand total across all orgs
|
|
724
|
+
# .averages.perDay.takedownsCompleted \u2190 total / windowDays
|
|
725
|
+
# .averages.perOrgPerDay.takedownsCompleted \u2190 total / numOrgs / windowDays
|
|
726
|
+
# .perOrg[slug].metrics.takedownsCompleted \u2190 per-customer breakdown
|
|
722
727
|
\`\`\`
|
|
723
728
|
|
|
724
729
|
Replace \`takedownsCompleted\` with whatever metric the user asked about.
|
|
725
730
|
Replace the date range with whatever window they asked about (default
|
|
726
731
|
3 months if they didn't say).
|
|
727
732
|
|
|
733
|
+
If the user *asked* for a specific subset of customers ("how many for
|
|
734
|
+
acme, beta, gamma combined?"), use \`--slugs acme,beta,gamma\` instead
|
|
735
|
+
of \`--all-my-orgs\`. \`--slugs\` accepts up to 500 entries.
|
|
736
|
+
|
|
737
|
+
**Auth note for \`--all-my-orgs\`:** requires a user session or a
|
|
738
|
+
user-scoped API key (it inherits your memberships). Org-scoped API
|
|
739
|
+
keys are rejected \u2014 they're pinned to a single org by design. If
|
|
740
|
+
\`whoami\` shows an org-scoped key, use a Bearer session instead or
|
|
741
|
+
ask the user to provision a user API key.
|
|
742
|
+
|
|
728
743
|
#### Single-org examples
|
|
729
744
|
|
|
730
745
|
\`\`\`bash
|
|
@@ -826,36 +841,44 @@ The response shape switches to multi-org:
|
|
|
826
841
|
}
|
|
827
842
|
\`\`\`
|
|
828
843
|
|
|
829
|
-
To answer **"across all of our customers"**,
|
|
844
|
+
To answer **"across all of our customers"**, prefer \`--all-my-orgs\` \u2014
|
|
845
|
+
it lets the server resolve the org set in one round-trip, no \`orgs
|
|
846
|
+
list\` step needed:
|
|
830
847
|
|
|
831
848
|
\`\`\`bash
|
|
832
|
-
chainpatrol --json orgs list --subscription-status ACTIVE # \u2190 get slugs
|
|
833
849
|
chainpatrol --json metrics organization \\
|
|
834
|
-
--
|
|
850
|
+
--all-my-orgs \\
|
|
851
|
+
--subscription-status ACTIVE \\
|
|
852
|
+
--service-active takedowns \\
|
|
835
853
|
--include takedownsCompleted \\
|
|
836
854
|
--from 2026-05-12 --to 2026-05-19
|
|
837
855
|
\`\`\`
|
|
838
856
|
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
857
|
+
Use \`--slugs <comma-list>\` only when the user asked for a *specific*
|
|
858
|
+
subset of customers ("how many for acme, beta, gamma combined?"); the
|
|
859
|
+
two flags are mutually exclusive. Both forms cap at 500 orgs per call;
|
|
860
|
+
if a real fleet exceeds that, narrow with
|
|
861
|
+
\`--subscription-status\`/\`--service-active\` filters or split an
|
|
862
|
+
explicit \`--slugs\` list into batches and sum. **Do not loop
|
|
863
|
+
\`metrics organization\` once per org** \u2014 N HTTP round-trips is what
|
|
864
|
+
made the old code 503.
|
|
843
865
|
|
|
844
|
-
Always pair
|
|
845
|
-
what the user actually asked about. "How many takedowns did
|
|
846
|
-
complete?" \u2192 \`--include takedownsCompleted\`; "average reports
|
|
847
|
-
day per customer?" \u2192 \`--include reports\`. Skipping \`--include\`
|
|
848
|
-
~11 aggregates per org which is rarely necessary.
|
|
866
|
+
Always pair the multi-org form with \`--include\` to narrow the metric
|
|
867
|
+
set to what the user actually asked about. "How many takedowns did
|
|
868
|
+
we complete?" \u2192 \`--include takedownsCompleted\`; "average reports
|
|
869
|
+
per day per customer?" \u2192 \`--include reports\`. Skipping \`--include\`
|
|
870
|
+
runs ~11 aggregates per org which is rarely necessary.
|
|
849
871
|
|
|
850
|
-
#### Auth: which credential can use \`--slugs\`
|
|
872
|
+
#### Auth: which credential can use \`--slugs\` / \`--all-my-orgs\`
|
|
851
873
|
|
|
852
874
|
- **Org-scoped API key** (the most common production key): can only
|
|
853
|
-
query its own org. If \`--slugs\` contains
|
|
854
|
-
returns 403. Use the \`--org\`
|
|
875
|
+
query its own org. If \`--slugs\` contains foreign orgs the server
|
|
876
|
+
returns 403; \`--all-my-orgs\` is also rejected. Use the \`--org\`
|
|
877
|
+
form (or omit both) instead.
|
|
855
878
|
- **User API key**: inherits the user's org memberships, so it can
|
|
856
879
|
query any org the user is a member of (or any org for staff
|
|
857
|
-
users)
|
|
858
|
-
from automated agents.
|
|
880
|
+
users) via \`--slugs\` or \`--all-my-orgs\`. This is the credential
|
|
881
|
+
you want for cross-org rollups from automated agents.
|
|
859
882
|
- **Session auth** (Bearer token, e.g. \`chainpatrol login\`): same
|
|
860
883
|
membership rules as the user. Staff users can query any org.
|
|
861
884
|
|
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-TTLGCRRR.js";
|
|
17
17
|
import "./chunk-NQT77IB7.js";
|
|
18
18
|
import {
|
|
19
19
|
DateTime
|
|
@@ -263,22 +263,25 @@ var HELP = {
|
|
|
263
263
|
]
|
|
264
264
|
},
|
|
265
265
|
"metrics organization": {
|
|
266
|
-
description: "Get organization metrics via the documented GET /organization/metrics endpoint. Works with org-scoped API keys (
|
|
267
|
-
usage: "chainpatrol metrics organization [--org <slug>|--slugs <list
|
|
266
|
+
description: "Get organization metrics via the documented GET /organization/metrics endpoint. Works with org-scoped API keys (single-org only), user API keys (inherits user permissions, multi-org allowed), and session auth. Defaults to the trailing 3 months if no date range is given. Use --include to skip aggregates; use --slugs OR --all-my-orgs for multi-org rollups (totals + per-day / per-org-per-day averages + per-org breakdown). Fields not included come back as null.",
|
|
267
|
+
usage: "chainpatrol metrics organization [--org <slug>|--slugs <list>|--all-my-orgs] [--from ISO --to ISO|--this-week] [--include <list>]",
|
|
268
268
|
options: [
|
|
269
|
-
"--org <slug>
|
|
270
|
-
"--slugs <list>
|
|
271
|
-
"--
|
|
272
|
-
"--
|
|
273
|
-
"--
|
|
274
|
-
"--
|
|
275
|
-
"--
|
|
269
|
+
"--org <slug> Single org. Mutually exclusive with --slugs and --all-my-orgs.",
|
|
270
|
+
"--slugs <list> Comma list of org slugs (cap 500). Response is the rollup across these orgs.",
|
|
271
|
+
"--all-my-orgs Shortcut for 'every org I can see'. Server resolves via the same logic as `orgs list` (org-scoped API keys are rejected). Cap 500 \u2014 narrow with --subscription-status / --service-active if you have more.",
|
|
272
|
+
"--subscription-status <list> With --all-my-orgs: only ACTIVE / TRIAL / PROSPECT / INTEGRATION (default: same set as `orgs list`).",
|
|
273
|
+
"--service-active <list> With --all-my-orgs: only orgs with the listed service(s) active. Allowed: reporting, reviewing, protection, takedowns, detection, darkWebMonitoring.",
|
|
274
|
+
"--brand-slug <slug> Filter by brand slug (requires brands-metrics flag; single-org only).",
|
|
275
|
+
"--from <iso> Start date (ISO 8601, e.g. 2026-01-01)",
|
|
276
|
+
"--to <iso> End date (ISO 8601)",
|
|
277
|
+
"--this-week Use the current ISO week (overrides default)",
|
|
278
|
+
"--include <list> Comma list of fields to compute: reports,newThreats,threatsWatchlisted,takedownsFiled,takedownsCompleted,domainThreats,twitterThreats,telegramThreats,otherThreats,blockedByType,blockedByDay (omit for all)"
|
|
276
279
|
],
|
|
277
280
|
examples: [
|
|
278
|
-
"chainpatrol metrics organization --org acme # defaults to last 3 months
|
|
281
|
+
"chainpatrol metrics organization --org acme # defaults to last 3 months",
|
|
279
282
|
"chainpatrol metrics organization --org acme --include takedownsFiled,takedownsCompleted",
|
|
280
|
-
"chainpatrol metrics organization --
|
|
281
|
-
"chainpatrol metrics organization --
|
|
283
|
+
"chainpatrol metrics organization --slugs acme,beta,gamma --include takedownsCompleted --from 2026-05-12 --to 2026-05-19",
|
|
284
|
+
"chainpatrol metrics organization --all-my-orgs --service-active takedowns --subscription-status ACTIVE --include takedownsCompleted --from 2026-05-12 --to 2026-05-19 # cross-customer total in one call",
|
|
282
285
|
"CHAINPATROL_API_KEY=... chainpatrol metrics organization --json --include reports"
|
|
283
286
|
]
|
|
284
287
|
},
|
|
@@ -864,6 +867,7 @@ ${getTopLevelHelp()}
|
|
|
864
867
|
by: { type: "string" },
|
|
865
868
|
include: { type: "string" },
|
|
866
869
|
slugs: { type: "string" },
|
|
870
|
+
allMyOrgs: { type: "boolean", default: false },
|
|
867
871
|
brand: { type: "string" },
|
|
868
872
|
enable: { type: "boolean", default: false },
|
|
869
873
|
disable: { type: "boolean", default: false },
|
|
@@ -1037,12 +1041,12 @@ function parseAttachmentUrls() {
|
|
|
1037
1041
|
}
|
|
1038
1042
|
async function handleConfigsList(org) {
|
|
1039
1043
|
if (jsonMode) {
|
|
1040
|
-
const { listConfigsJson } = await import("./list-json-
|
|
1044
|
+
const { listConfigsJson } = await import("./list-json-DXPR3UEY.js");
|
|
1041
1045
|
await listConfigsJson({ org });
|
|
1042
1046
|
return;
|
|
1043
1047
|
}
|
|
1044
1048
|
const { render } = await import("ink");
|
|
1045
|
-
const { default: ConfigsList } = await import("./list-
|
|
1049
|
+
const { default: ConfigsList } = await import("./list-GPWZ52JD.js");
|
|
1046
1050
|
const { default: React } = await import("react");
|
|
1047
1051
|
render(React.createElement(ConfigsList, { org }));
|
|
1048
1052
|
}
|
|
@@ -1142,7 +1146,7 @@ async function main() {
|
|
|
1142
1146
|
const positionals = cli.input.slice(2);
|
|
1143
1147
|
const flagAssets = parseAssetInputs();
|
|
1144
1148
|
const contents = [...positionals, ...flagAssets];
|
|
1145
|
-
const { runAssetCheck } = await import("./check-
|
|
1149
|
+
const { runAssetCheck } = await import("./check-5B4EPWOZ.js");
|
|
1146
1150
|
await runAssetCheck({
|
|
1147
1151
|
contents,
|
|
1148
1152
|
json: jsonMode,
|
|
@@ -1152,7 +1156,7 @@ async function main() {
|
|
|
1152
1156
|
break;
|
|
1153
1157
|
}
|
|
1154
1158
|
if (subcommand === "list") {
|
|
1155
|
-
const { runAssetList } = await import("./list-
|
|
1159
|
+
const { runAssetList } = await import("./list-G2F2IFEU.js");
|
|
1156
1160
|
await runAssetList({
|
|
1157
1161
|
type: cli.flags.type ?? cli.flags.assetType,
|
|
1158
1162
|
status: cli.flags.assetStatus ?? cli.flags.status,
|
|
@@ -1173,7 +1177,7 @@ async function main() {
|
|
|
1173
1177
|
case "detections": {
|
|
1174
1178
|
const org = await resolveOrg();
|
|
1175
1179
|
if (subcommand === "healthcheck") {
|
|
1176
|
-
const { runDetectionsHealthcheck } = await import("./healthcheck-
|
|
1180
|
+
const { runDetectionsHealthcheck } = await import("./healthcheck-47MU5AZ7.js");
|
|
1177
1181
|
await runDetectionsHealthcheck({
|
|
1178
1182
|
org,
|
|
1179
1183
|
source: cli.flags.source,
|
|
@@ -1188,7 +1192,7 @@ async function main() {
|
|
|
1188
1192
|
break;
|
|
1189
1193
|
}
|
|
1190
1194
|
if (subcommand === "validate") {
|
|
1191
|
-
const { runDetectionsValidate } = await import("./validate-
|
|
1195
|
+
const { runDetectionsValidate } = await import("./validate-LXE3JPET.js");
|
|
1192
1196
|
await runDetectionsValidate({
|
|
1193
1197
|
org,
|
|
1194
1198
|
source: cli.flags.source,
|
|
@@ -1203,7 +1207,7 @@ async function main() {
|
|
|
1203
1207
|
break;
|
|
1204
1208
|
}
|
|
1205
1209
|
if (subcommand === "drift") {
|
|
1206
|
-
const { runDetectionsDrift } = await import("./drift-
|
|
1210
|
+
const { runDetectionsDrift } = await import("./drift-5EZK2JA5.js");
|
|
1207
1211
|
await runDetectionsDrift({
|
|
1208
1212
|
org,
|
|
1209
1213
|
source: cli.flags.source,
|
|
@@ -1217,7 +1221,7 @@ async function main() {
|
|
|
1217
1221
|
break;
|
|
1218
1222
|
}
|
|
1219
1223
|
if (subcommand === "run") {
|
|
1220
|
-
const { runDetectionsRun } = await import("./run-
|
|
1224
|
+
const { runDetectionsRun } = await import("./run-HDEKIP4L.js");
|
|
1221
1225
|
await runDetectionsRun({
|
|
1222
1226
|
org,
|
|
1223
1227
|
configId: cli.flags.configId,
|
|
@@ -1231,7 +1235,7 @@ async function main() {
|
|
|
1231
1235
|
break;
|
|
1232
1236
|
}
|
|
1233
1237
|
if (subcommand === "list") {
|
|
1234
|
-
const { runDetectionsList } = await import("./list-
|
|
1238
|
+
const { runDetectionsList } = await import("./list-FGDMMAPM.js");
|
|
1235
1239
|
await runDetectionsList({
|
|
1236
1240
|
org,
|
|
1237
1241
|
cursor: cli.flags.cursor,
|
|
@@ -1260,7 +1264,7 @@ async function main() {
|
|
|
1260
1264
|
break;
|
|
1261
1265
|
}
|
|
1262
1266
|
if (action === "run") {
|
|
1263
|
-
const { runDetectionsRun } = await import("./run-
|
|
1267
|
+
const { runDetectionsRun } = await import("./run-HDEKIP4L.js");
|
|
1264
1268
|
await runDetectionsRun({
|
|
1265
1269
|
org,
|
|
1266
1270
|
configId: cli.flags.configId,
|
|
@@ -1278,7 +1282,7 @@ async function main() {
|
|
|
1278
1282
|
throw new Error("detections configs update requires --config-id");
|
|
1279
1283
|
}
|
|
1280
1284
|
const configPatch = getConfigPatchFromSetFlags();
|
|
1281
|
-
const { runDetectionsConfigsUpdate } = await import("./configs-update-
|
|
1285
|
+
const { runDetectionsConfigsUpdate } = await import("./configs-update-6BYB7M37.js");
|
|
1282
1286
|
await runDetectionsConfigsUpdate({
|
|
1283
1287
|
org,
|
|
1284
1288
|
configId: cli.flags.configId,
|
|
@@ -1312,11 +1316,15 @@ async function main() {
|
|
|
1312
1316
|
case "metrics": {
|
|
1313
1317
|
if (subcommand === "organization" || subcommand === "org") {
|
|
1314
1318
|
const slugs = parseCsvList(cli.flags.slugs);
|
|
1315
|
-
const
|
|
1316
|
-
const
|
|
1319
|
+
const allMyOrgs = cli.flags.allMyOrgs;
|
|
1320
|
+
const org2 = slugs && slugs.length > 0 || allMyOrgs ? void 0 : await tryResolveOrg();
|
|
1321
|
+
const { runMetricsOrganization } = await import("./organization-NR6JCD5I.js");
|
|
1317
1322
|
await runMetricsOrganization({
|
|
1318
1323
|
org: org2,
|
|
1319
1324
|
slugs,
|
|
1325
|
+
allMyOrgs: allMyOrgs || void 0,
|
|
1326
|
+
subscriptionStatus: parseCsvList(cli.flags.subscriptionStatus),
|
|
1327
|
+
serviceActive: parseCsvList(cli.flags.serviceActive),
|
|
1320
1328
|
brandSlug: cli.flags.brandSlug,
|
|
1321
1329
|
from: cli.flags.from,
|
|
1322
1330
|
to: cli.flags.to,
|
|
@@ -1329,7 +1337,7 @@ async function main() {
|
|
|
1329
1337
|
}
|
|
1330
1338
|
const org = await resolveOrg();
|
|
1331
1339
|
if (subcommand === "summary") {
|
|
1332
|
-
const { runMetricsSummary } = await import("./summary-
|
|
1340
|
+
const { runMetricsSummary } = await import("./summary-2IXOMOIA.js");
|
|
1333
1341
|
await runMetricsSummary({
|
|
1334
1342
|
org,
|
|
1335
1343
|
from: cli.flags.from,
|
|
@@ -1342,7 +1350,7 @@ async function main() {
|
|
|
1342
1350
|
break;
|
|
1343
1351
|
}
|
|
1344
1352
|
if (subcommand === "found") {
|
|
1345
|
-
const { runMetricsFound } = await import("./found-
|
|
1353
|
+
const { runMetricsFound } = await import("./found-XRJZ4SSY.js");
|
|
1346
1354
|
await runMetricsFound({
|
|
1347
1355
|
org,
|
|
1348
1356
|
from: cli.flags.from,
|
|
@@ -1359,7 +1367,7 @@ async function main() {
|
|
|
1359
1367
|
if (!by || !["day", "type", "brand"].includes(by)) {
|
|
1360
1368
|
throw new Error("metrics breakdown requires --by <day|type|brand>");
|
|
1361
1369
|
}
|
|
1362
|
-
const { runMetricsBreakdown } = await import("./breakdown-
|
|
1370
|
+
const { runMetricsBreakdown } = await import("./breakdown-PQXHY2VO.js");
|
|
1363
1371
|
await runMetricsBreakdown({
|
|
1364
1372
|
org,
|
|
1365
1373
|
by,
|
|
@@ -1380,7 +1388,7 @@ async function main() {
|
|
|
1380
1388
|
case "reports": {
|
|
1381
1389
|
if (subcommand === "list") {
|
|
1382
1390
|
const org = await resolveOrg();
|
|
1383
|
-
const { runReportsList } = await import("./list-
|
|
1391
|
+
const { runReportsList } = await import("./list-2JCBA3Q2.js");
|
|
1384
1392
|
await runReportsList({
|
|
1385
1393
|
org,
|
|
1386
1394
|
limit: cli.flags.limit,
|
|
@@ -1408,7 +1416,7 @@ async function main() {
|
|
|
1408
1416
|
}
|
|
1409
1417
|
if (subcommand === "create") {
|
|
1410
1418
|
const org = await tryResolveOrg();
|
|
1411
|
-
const { runReportsCreate } = await import("./create-
|
|
1419
|
+
const { runReportsCreate } = await import("./create-Y6Z4L656.js");
|
|
1412
1420
|
await runReportsCreate({
|
|
1413
1421
|
org,
|
|
1414
1422
|
title: cli.flags.title,
|
|
@@ -1429,7 +1437,7 @@ async function main() {
|
|
|
1429
1437
|
const positionals = cli.input.slice(2);
|
|
1430
1438
|
const flagAssets = parseAssetInputs();
|
|
1431
1439
|
const assetContents = [...positionals, ...flagAssets];
|
|
1432
|
-
const { runReportsSearch } = await import("./search-
|
|
1440
|
+
const { runReportsSearch } = await import("./search-PBVQ7473.js");
|
|
1433
1441
|
await runReportsSearch({
|
|
1434
1442
|
assetContents,
|
|
1435
1443
|
reportedByCustomer: cli.flags.reportedByCustomer,
|
|
@@ -1445,7 +1453,7 @@ async function main() {
|
|
|
1445
1453
|
}
|
|
1446
1454
|
case "threats": {
|
|
1447
1455
|
if (subcommand === "list") {
|
|
1448
|
-
const { runThreatsList } = await import("./list-
|
|
1456
|
+
const { runThreatsList } = await import("./list-JD4U2SBV.js");
|
|
1449
1457
|
await runThreatsList({
|
|
1450
1458
|
query: cli.flags.query,
|
|
1451
1459
|
from: cli.flags.from,
|
|
@@ -1468,7 +1476,7 @@ async function main() {
|
|
|
1468
1476
|
case "takedowns": {
|
|
1469
1477
|
if (subcommand === "list") {
|
|
1470
1478
|
const org = await tryResolveOrg();
|
|
1471
|
-
const { runTakedownsList } = await import("./list-
|
|
1479
|
+
const { runTakedownsList } = await import("./list-ZIM2MR2Q.js");
|
|
1472
1480
|
await runTakedownsList({
|
|
1473
1481
|
org,
|
|
1474
1482
|
query: cli.flags.query,
|
|
@@ -1499,7 +1507,7 @@ async function main() {
|
|
|
1499
1507
|
}
|
|
1500
1508
|
case "queues": {
|
|
1501
1509
|
if (subcommand === "snapshot") {
|
|
1502
|
-
const { runQueuesSnapshot } = await import("./snapshot-
|
|
1510
|
+
const { runQueuesSnapshot } = await import("./snapshot-U53T5Q2M.js");
|
|
1503
1511
|
await runQueuesSnapshot({
|
|
1504
1512
|
org: cli.flags.org,
|
|
1505
1513
|
all: cli.flags.all,
|
|
@@ -1517,7 +1525,7 @@ async function main() {
|
|
|
1517
1525
|
}
|
|
1518
1526
|
case "orgs": {
|
|
1519
1527
|
if (subcommand === "list") {
|
|
1520
|
-
const { runOrgsList } = await import("./list-
|
|
1528
|
+
const { runOrgsList } = await import("./list-KFFNLKZK.js");
|
|
1521
1529
|
await runOrgsList({
|
|
1522
1530
|
query: cli.flags.query,
|
|
1523
1531
|
subscriptionStatus: cli.flags.subscriptionStatus,
|
|
@@ -1532,7 +1540,7 @@ async function main() {
|
|
|
1532
1540
|
}
|
|
1533
1541
|
if (subcommand === "assets") {
|
|
1534
1542
|
if (action === "list") {
|
|
1535
|
-
const { runOrgsAssetsList } = await import("./list-
|
|
1543
|
+
const { runOrgsAssetsList } = await import("./list-QC7DUKFD.js");
|
|
1536
1544
|
await runOrgsAssetsList({
|
|
1537
1545
|
type: cli.flags.type ?? cli.flags.assetType,
|
|
1538
1546
|
groupId: cli.flags.groupId,
|
|
@@ -1548,7 +1556,7 @@ async function main() {
|
|
|
1548
1556
|
}
|
|
1549
1557
|
if (subcommand === "asset-groups") {
|
|
1550
1558
|
if (action === "list") {
|
|
1551
|
-
const { runOrgsAssetGroupsList } = await import("./list-
|
|
1559
|
+
const { runOrgsAssetGroupsList } = await import("./list-IA2LRT4X.js");
|
|
1552
1560
|
await runOrgsAssetGroupsList({
|
|
1553
1561
|
json: jsonMode,
|
|
1554
1562
|
outputFormat: cliContext.outputFormat
|
|
@@ -1563,7 +1571,7 @@ async function main() {
|
|
|
1563
1571
|
);
|
|
1564
1572
|
}
|
|
1565
1573
|
case "whoami": {
|
|
1566
|
-
const { runWhoami } = await import("./whoami-
|
|
1574
|
+
const { runWhoami } = await import("./whoami-4XDWPKVV.js");
|
|
1567
1575
|
await runWhoami({
|
|
1568
1576
|
json: jsonMode,
|
|
1569
1577
|
outputFormat: cliContext.outputFormat
|
|
@@ -1572,7 +1580,7 @@ async function main() {
|
|
|
1572
1580
|
}
|
|
1573
1581
|
case "healthchecks": {
|
|
1574
1582
|
if (subcommand === "list") {
|
|
1575
|
-
const { runHealthchecksList } = await import("./list-
|
|
1583
|
+
const { runHealthchecksList } = await import("./list-AYXZG3I6.js");
|
|
1576
1584
|
await runHealthchecksList({
|
|
1577
1585
|
json: jsonMode,
|
|
1578
1586
|
outputFormat: cliContext.outputFormat
|
|
@@ -1586,7 +1594,7 @@ async function main() {
|
|
|
1586
1594
|
thresholds.minResults = cli.flags.minResults;
|
|
1587
1595
|
if (cli.flags.lookbackHours !== void 0)
|
|
1588
1596
|
thresholds.lookbackHours = cli.flags.lookbackHours;
|
|
1589
|
-
const { runHealthchecksRun } = await import("./run-
|
|
1597
|
+
const { runHealthchecksRun } = await import("./run-EJBBPBOR.js");
|
|
1590
1598
|
await runHealthchecksRun({
|
|
1591
1599
|
org,
|
|
1592
1600
|
id: action,
|
|
@@ -1604,7 +1612,7 @@ async function main() {
|
|
|
1604
1612
|
}
|
|
1605
1613
|
case "presets": {
|
|
1606
1614
|
if (subcommand === "list") {
|
|
1607
|
-
const { runPresetsList } = await import("./list-
|
|
1615
|
+
const { runPresetsList } = await import("./list-WBZIULUS.js");
|
|
1608
1616
|
await runPresetsList({ outputFormat: cliContext.outputFormat });
|
|
1609
1617
|
break;
|
|
1610
1618
|
}
|
|
@@ -1615,7 +1623,7 @@ async function main() {
|
|
|
1615
1623
|
);
|
|
1616
1624
|
}
|
|
1617
1625
|
const org = await resolveOrg();
|
|
1618
|
-
const { runPresetsRun } = await import("./run-
|
|
1626
|
+
const { runPresetsRun } = await import("./run-ANHA5JFB.js");
|
|
1619
1627
|
await runPresetsRun({
|
|
1620
1628
|
presetId: action,
|
|
1621
1629
|
org,
|
|
@@ -1632,12 +1640,12 @@ async function main() {
|
|
|
1632
1640
|
case "setup":
|
|
1633
1641
|
case "install":
|
|
1634
1642
|
case "i": {
|
|
1635
|
-
const { setupSkill } = await import("./setup-skill-
|
|
1643
|
+
const { setupSkill } = await import("./setup-skill-2RKWIVGS.js");
|
|
1636
1644
|
setupSkill({ json: jsonMode, cloud: cli.flags.cloud });
|
|
1637
1645
|
break;
|
|
1638
1646
|
}
|
|
1639
1647
|
case "uninstall": {
|
|
1640
|
-
const { uninstallSkill } = await import("./setup-skill-
|
|
1648
|
+
const { uninstallSkill } = await import("./setup-skill-2RKWIVGS.js");
|
|
1641
1649
|
uninstallSkill({ json: jsonMode });
|
|
1642
1650
|
break;
|
|
1643
1651
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PRESETS
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-CJPWEWGS.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-JEBZIBRI.js";
|
|
10
10
|
import "./chunk-EGWK6SRQ.js";
|
|
11
11
|
import "./chunk-TFCNKBRC.js";
|
|
12
12
|
import "./chunk-U73SABXK.js";
|
|
@@ -8,12 +8,34 @@ import {
|
|
|
8
8
|
import {
|
|
9
9
|
ORGANIZATION_METRICS_INCLUDE_FIELDS,
|
|
10
10
|
createApiClient
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-JEBZIBRI.js";
|
|
12
12
|
import "./chunk-EGWK6SRQ.js";
|
|
13
13
|
import "./chunk-TFCNKBRC.js";
|
|
14
14
|
import "./chunk-U73SABXK.js";
|
|
15
15
|
|
|
16
16
|
// src/commands/metrics/organization.ts
|
|
17
|
+
var SERVICE_KEYS = [
|
|
18
|
+
"reporting",
|
|
19
|
+
"reviewing",
|
|
20
|
+
"protection",
|
|
21
|
+
"takedowns",
|
|
22
|
+
"detection",
|
|
23
|
+
"darkWebMonitoring"
|
|
24
|
+
];
|
|
25
|
+
var SERVICE_KEY_SET = new Set(SERVICE_KEYS);
|
|
26
|
+
function buildServicesFilter(raw) {
|
|
27
|
+
if (!raw || raw.length === 0) return void 0;
|
|
28
|
+
const filter = {};
|
|
29
|
+
for (const value of raw) {
|
|
30
|
+
if (!SERVICE_KEY_SET.has(value)) {
|
|
31
|
+
throw new Error(
|
|
32
|
+
`Unknown --service-active value: '${value}'. Allowed: ${SERVICE_KEYS.join(", ")}`
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
filter[value] = { active: true };
|
|
36
|
+
}
|
|
37
|
+
return filter;
|
|
38
|
+
}
|
|
17
39
|
var INCLUDE_VALUES = new Set(ORGANIZATION_METRICS_INCLUDE_FIELDS);
|
|
18
40
|
var METRIC_LABELS = [
|
|
19
41
|
["reports", "Reports"],
|
|
@@ -50,8 +72,13 @@ function populatedMetricRows(metrics, format = (v) => String(v)) {
|
|
|
50
72
|
]);
|
|
51
73
|
}
|
|
52
74
|
async function runMetricsOrganization(options) {
|
|
53
|
-
|
|
54
|
-
|
|
75
|
+
const explicitForms = [
|
|
76
|
+
Boolean(options.org),
|
|
77
|
+
Boolean(options.slugs && options.slugs.length > 0),
|
|
78
|
+
Boolean(options.allMyOrgs)
|
|
79
|
+
].filter(Boolean).length;
|
|
80
|
+
if (explicitForms > 1) {
|
|
81
|
+
throw new Error("Pass at most one of --org, --slugs, or --all-my-orgs.");
|
|
55
82
|
}
|
|
56
83
|
const outputFormat = options.outputFormat ?? (options.json ? "json" : "human");
|
|
57
84
|
const client = options.apiClient ?? createApiClient();
|
|
@@ -61,9 +88,13 @@ async function runMetricsOrganization(options) {
|
|
|
61
88
|
thisWeek: options.thisWeek
|
|
62
89
|
});
|
|
63
90
|
const include = parseIncludeList(options.include);
|
|
91
|
+
const services = buildServicesFilter(options.serviceActive);
|
|
64
92
|
const input = {
|
|
65
93
|
organizationSlug: options.org,
|
|
66
94
|
slugs: options.slugs && options.slugs.length > 0 ? options.slugs : void 0,
|
|
95
|
+
allMyOrgs: options.allMyOrgs || void 0,
|
|
96
|
+
subscriptionStatus: options.subscriptionStatus && options.subscriptionStatus.length > 0 ? options.subscriptionStatus : void 0,
|
|
97
|
+
services,
|
|
67
98
|
brandSlug: options.brandSlug,
|
|
68
99
|
startDate: range.startDate,
|
|
69
100
|
endDate: range.endDate,
|
|
@@ -71,7 +102,7 @@ async function runMetricsOrganization(options) {
|
|
|
71
102
|
};
|
|
72
103
|
const result = await client.getOrganizationMetrics(input);
|
|
73
104
|
const isMulti = result.scope.mode === "multi";
|
|
74
|
-
const scopeLabel = isMulti ? `${result.scope.orgs.length} orgs (${result.scope.orgs.join(", ")})` : result.scope.orgs[0] ?? options.org ?? "your organization";
|
|
105
|
+
const scopeLabel = isMulti ? `${result.scope.orgs.length} orgs${result.scope.resolvedFrom === "allMyOrgs" ? " (--all-my-orgs)" : ` (${result.scope.orgs.slice(0, 10).join(", ")}${result.scope.orgs.length > 10 ? ", \u2026" : ""})`}` : result.scope.orgs[0] ?? options.org ?? "your organization";
|
|
75
106
|
const includeLabel = include ? ` (include: ${include.join(", ")})` : "";
|
|
76
107
|
const totalsRows = populatedMetricRows(result.metrics);
|
|
77
108
|
const perDayRows = result.averages.perDay ? populatedMetricRows(result.averages.perDay, formatAverage) : [];
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getPresetDefinition,
|
|
3
3
|
runPreset
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-CJPWEWGS.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-JEBZIBRI.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.16.0",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"homepage": "https://chainpatrol.com/docs/cli",
|
|
8
8
|
"keywords": [
|