@chainpatrol/cli 0.5.0 → 0.6.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 +13 -0
- package/dist/{breakdown-EBSACUST.js → breakdown-AX6QNTQH.js} +1 -1
- package/dist/{chunk-PIYOWGBZ.js → chunk-AGXMZFUU.js} +1 -1
- package/dist/{chunk-MXUZR2BV.js → chunk-LLWKCA3H.js} +3 -0
- package/dist/{chunk-BSK4YHFA.js → chunk-XOXQPUR6.js} +48 -1
- package/dist/cli.js +74 -21
- package/dist/{configs-update-RPN32YTL.js → configs-update-VROBC2HI.js} +1 -1
- package/dist/{create-QP3M7EZM.js → create-XTCUNT2C.js} +1 -1
- package/dist/{drift-DZ6A7JL5.js → drift-VOKQJ36G.js} +1 -1
- package/dist/{found-AOPBSLRD.js → found-A5HRTJCJ.js} +1 -1
- package/dist/{healthcheck-KAONRGSS.js → healthcheck-AQUXVKAO.js} +1 -1
- package/dist/{list-GEMCFDD5.js → list-5ENZAOFL.js} +1 -1
- package/dist/list-CGRHTFAS.js +182 -0
- package/dist/{list-MWDFCHMJ.js → list-CVFXTKNX.js} +1 -1
- package/dist/{list-LN6NOZIJ.js → list-EYRN5JYC.js} +2 -2
- package/dist/{list-UW63DIKX.js → list-PLZ67PNY.js} +1 -1
- package/dist/{list-json-WTMYLZGY.js → list-json-LEKCCWQU.js} +1 -1
- package/dist/{run-64SBCL4R.js → run-MS5SA5YL.js} +1 -1
- package/dist/{run-43CC5AXR.js → run-OT2X46GT.js} +1 -1
- package/dist/{run-MH5RYPWA.js → run-YHDUUP66.js} +2 -2
- package/dist/{setup-skill-NQIZBJMR.js → setup-skill-BTR2IZ4E.js} +1 -1
- package/dist/{snapshot-E3TPZOKT.js → snapshot-4QR4I67P.js} +1 -1
- package/dist/{summary-6NCA7PDP.js → summary-JOCABBCO.js} +1 -1
- package/dist/{validate-BJFEKI2N.js → validate-27RUCN7R.js} +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @chainpatrol/cli
|
|
2
2
|
|
|
3
|
+
## 0.6.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 575b671: Add `chainpatrol orgs list` — lists organizations accessible to the caller along with each org's subscription status and active/automated service flags (reporting, reviewing, protection, takedowns, detection, dark web monitoring). Filter flags compose with AND and are applied server-side:
|
|
8
|
+
|
|
9
|
+
- `--subscription-status <list>` — comma-separated `PROSPECT`, `TRIAL`, `ACTIVE`, `INTEGRATION` (`INACTIVE` is intentionally not reachable through this filter)
|
|
10
|
+
- `--service-active <list>` / `--service-inactive <list>` — services that must be active / inactive
|
|
11
|
+
- `--service-automated <list>` / `--service-manual <list>` — services whose automation must be on / off (`reporting`, `reviewing`, `protection`, `takedowns`)
|
|
12
|
+
- `--query <text>` — partial name match
|
|
13
|
+
|
|
14
|
+
Use cases: "which ACTIVE customers have takedowns enabled but automation off", "which prospects don't have detection turned on yet". The bundled CLI skill gets a new `orgs list` section under the `queues snapshot` heading.
|
|
15
|
+
|
|
3
16
|
## 0.5.0
|
|
4
17
|
|
|
5
18
|
### Minor Changes
|
|
@@ -82,7 +82,9 @@ description: |
|
|
|
82
82
|
"am I logged in", "list configs", "use the cli", "list reports",
|
|
83
83
|
"customer reports", "reports reported by customer", "find detection gaps",
|
|
84
84
|
"org healthcheck", "organization health check", "audit my org",
|
|
85
|
-
"what's wrong with org", "review org setup"
|
|
85
|
+
"what's wrong with org", "review org setup", "list orgs", "list organizations",
|
|
86
|
+
"orgs with takedowns off", "automation off across orgs",
|
|
87
|
+
"which customers have X enabled", "service toggles by org".
|
|
86
88
|
allowed-tools:
|
|
87
89
|
- Bash
|
|
88
90
|
- Read
|
|
@@ -443,6 +445,51 @@ Guide. Key signals in the response:
|
|
|
443
445
|
|
|
444
446
|
Use \`--all\` to snapshot every org you have access to instead of a single slug.
|
|
445
447
|
|
|
448
|
+
### \`orgs list\` \u2014 List organizations with subscription status and service toggles
|
|
449
|
+
|
|
450
|
+
Returns every organization the caller can see, with each org's
|
|
451
|
+
subscription status (\`PROSPECT\`, \`TRIAL\`, \`ACTIVE\`, \`INTEGRATION\`) and
|
|
452
|
+
which services are active and automated. Use it to answer questions like
|
|
453
|
+
"which customers have takedowns enabled but automation off?" or "which
|
|
454
|
+
prospects don't have detection turned on yet?" \u2014 filters compose with AND
|
|
455
|
+
and are applied server-side, so one call returns the final list.
|
|
456
|
+
|
|
457
|
+
\`\`\`bash
|
|
458
|
+
chainpatrol --json orgs list \\
|
|
459
|
+
--subscription-status ACTIVE \\
|
|
460
|
+
--service-active takedowns \\
|
|
461
|
+
--service-manual takedowns
|
|
462
|
+
\`\`\`
|
|
463
|
+
|
|
464
|
+
Filter flags (all optional, all comma-separated lists):
|
|
465
|
+
|
|
466
|
+
- \`--query <text>\` partial name match (substring, case-insensitive)
|
|
467
|
+
- \`--subscription-status <list>\` one or more of \`PROSPECT\`, \`TRIAL\`,
|
|
468
|
+
\`ACTIVE\`, \`INTEGRATION\`. \`INACTIVE\` is intentionally not reachable
|
|
469
|
+
through this filter \u2014 \`orgs list\` only ever returns live customers.
|
|
470
|
+
- \`--service-active <list>\` services that must be active
|
|
471
|
+
- \`--service-inactive <list>\` services that must be inactive
|
|
472
|
+
- \`--service-automated <list>\` services whose automation must be ON
|
|
473
|
+
(\`reporting\`, \`reviewing\`, \`protection\`, \`takedowns\` \u2014 the four
|
|
474
|
+
with an automation toggle)
|
|
475
|
+
- \`--service-manual <list>\` services whose automation must be OFF
|
|
476
|
+
(same four)
|
|
477
|
+
|
|
478
|
+
Service names: \`reporting\`, \`reviewing\`, \`protection\`, \`takedowns\`,
|
|
479
|
+
\`detection\`, \`darkWebMonitoring\`.
|
|
480
|
+
|
|
481
|
+
Customers see only orgs they're a member of. Staff/superuser sessions see
|
|
482
|
+
every matching org. The response is the same in both cases; visibility is
|
|
483
|
+
enforced server-side.
|
|
484
|
+
|
|
485
|
+
#### Use case: finding service configuration gaps across the customer base
|
|
486
|
+
|
|
487
|
+
When the user asks something like "which customers are paying us but don't
|
|
488
|
+
have takedowns automated yet?" or "any orgs running detection without
|
|
489
|
+
takedowns?", reach for \`orgs list\` \u2014 it's the only command that exposes
|
|
490
|
+
service flags across multiple orgs in one call. Run it in \`--json\` mode
|
|
491
|
+
and summarize patterns by service or by subscription tier.
|
|
492
|
+
|
|
446
493
|
### \`metrics summary | found | breakdown\` \u2014 Org metrics for spike/drop analysis
|
|
447
494
|
|
|
448
495
|
\`\`\`bash
|
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-XOXQPUR6.js";
|
|
17
17
|
import "./chunk-IUZB3DQW.js";
|
|
18
18
|
import {
|
|
19
19
|
DateTime
|
|
@@ -281,6 +281,31 @@ var HELP = {
|
|
|
281
281
|
"--window-hours <n> Hours used for staleness windows"
|
|
282
282
|
]
|
|
283
283
|
},
|
|
284
|
+
orgs: {
|
|
285
|
+
description: "List organizations accessible to you with subscription status and service toggles.",
|
|
286
|
+
usage: "chainpatrol orgs list [filters]",
|
|
287
|
+
examples: [
|
|
288
|
+
"chainpatrol orgs list",
|
|
289
|
+
"chainpatrol orgs list --subscription-status ACTIVE --service-active takedowns --service-manual takedowns"
|
|
290
|
+
]
|
|
291
|
+
},
|
|
292
|
+
"orgs list": {
|
|
293
|
+
description: "List organizations with their subscription status and per-service active/automated flags. All filters compose with AND.",
|
|
294
|
+
usage: "chainpatrol orgs list [filters]",
|
|
295
|
+
options: [
|
|
296
|
+
"--query <text> Partial name match (substring, case-insensitive)",
|
|
297
|
+
"--subscription-status <l> Comma-separated list (PROSPECT,TRIAL,ACTIVE,INTEGRATION)",
|
|
298
|
+
"--service-active <l> Comma-separated services that must be active",
|
|
299
|
+
"--service-inactive <l> Comma-separated services that must be inactive",
|
|
300
|
+
"--service-automated <l> Services whose automation must be ON (reporting,reviewing,protection,takedowns)",
|
|
301
|
+
"--service-manual <l> Services whose automation must be OFF (reporting,reviewing,protection,takedowns)"
|
|
302
|
+
],
|
|
303
|
+
examples: [
|
|
304
|
+
"chainpatrol orgs list --subscription-status ACTIVE",
|
|
305
|
+
"chainpatrol orgs list --service-active takedowns --service-manual takedowns",
|
|
306
|
+
"chainpatrol --json orgs list --subscription-status ACTIVE,TRIAL --service-active detection"
|
|
307
|
+
]
|
|
308
|
+
},
|
|
284
309
|
healthchecks: {
|
|
285
310
|
description: "Run organization healthchecks via the public API. Use `list` to see every available check (including planned ones not yet implemented on the backend) and `run` to execute one or all implemented checks.",
|
|
286
311
|
usage: "chainpatrol healthchecks <list|run <id>|run --all>",
|
|
@@ -369,6 +394,7 @@ function getTopLevelHelp() {
|
|
|
369
394
|
" metrics Query organization metrics and breakdowns",
|
|
370
395
|
" reports Create and list reports from terminal",
|
|
371
396
|
" queues Snapshot operations review/takedown queues",
|
|
397
|
+
" orgs List organizations and filter by status/services",
|
|
372
398
|
" presets Run saved workflows for common jobs",
|
|
373
399
|
" setup Install Claude Code skill and shell completions",
|
|
374
400
|
" uninstall Remove Claude Code skill and shell completions",
|
|
@@ -538,6 +564,7 @@ var COMMANDS = [
|
|
|
538
564
|
"metrics",
|
|
539
565
|
"reports",
|
|
540
566
|
"queues",
|
|
567
|
+
"orgs",
|
|
541
568
|
"presets",
|
|
542
569
|
"setup",
|
|
543
570
|
"uninstall",
|
|
@@ -614,6 +641,12 @@ ${getTopLevelHelp()}
|
|
|
614
641
|
contactInfo: { type: "string" },
|
|
615
642
|
externalSubmissionLink: { type: "string" },
|
|
616
643
|
payloadFile: { type: "string" },
|
|
644
|
+
subscriptionStatus: { type: "string" },
|
|
645
|
+
serviceActive: { type: "string" },
|
|
646
|
+
serviceInactive: { type: "string" },
|
|
647
|
+
serviceAutomated: { type: "string" },
|
|
648
|
+
serviceManual: { type: "string" },
|
|
649
|
+
query: { type: "string" },
|
|
617
650
|
help: { type: "boolean", shortFlag: "h" },
|
|
618
651
|
version: { type: "boolean", shortFlag: "V" },
|
|
619
652
|
quiet: { type: "boolean", default: false, shortFlag: "q" },
|
|
@@ -717,12 +750,12 @@ function parseAttachmentUrls() {
|
|
|
717
750
|
}
|
|
718
751
|
async function handleConfigsList(org) {
|
|
719
752
|
if (jsonMode) {
|
|
720
|
-
const { listConfigsJson } = await import("./list-json-
|
|
753
|
+
const { listConfigsJson } = await import("./list-json-LEKCCWQU.js");
|
|
721
754
|
await listConfigsJson({ org });
|
|
722
755
|
return;
|
|
723
756
|
}
|
|
724
757
|
const { render } = await import("ink");
|
|
725
|
-
const { default: ConfigsList } = await import("./list-
|
|
758
|
+
const { default: ConfigsList } = await import("./list-5ENZAOFL.js");
|
|
726
759
|
const { default: React } = await import("react");
|
|
727
760
|
render(React.createElement(ConfigsList, { org }));
|
|
728
761
|
}
|
|
@@ -820,7 +853,7 @@ async function main() {
|
|
|
820
853
|
case "detections": {
|
|
821
854
|
const org = await resolveOrg();
|
|
822
855
|
if (subcommand === "healthcheck") {
|
|
823
|
-
const { runDetectionsHealthcheck } = await import("./healthcheck-
|
|
856
|
+
const { runDetectionsHealthcheck } = await import("./healthcheck-AQUXVKAO.js");
|
|
824
857
|
await runDetectionsHealthcheck({
|
|
825
858
|
org,
|
|
826
859
|
source: cli.flags.source,
|
|
@@ -835,7 +868,7 @@ async function main() {
|
|
|
835
868
|
break;
|
|
836
869
|
}
|
|
837
870
|
if (subcommand === "validate") {
|
|
838
|
-
const { runDetectionsValidate } = await import("./validate-
|
|
871
|
+
const { runDetectionsValidate } = await import("./validate-27RUCN7R.js");
|
|
839
872
|
await runDetectionsValidate({
|
|
840
873
|
org,
|
|
841
874
|
source: cli.flags.source,
|
|
@@ -850,7 +883,7 @@ async function main() {
|
|
|
850
883
|
break;
|
|
851
884
|
}
|
|
852
885
|
if (subcommand === "drift") {
|
|
853
|
-
const { runDetectionsDrift } = await import("./drift-
|
|
886
|
+
const { runDetectionsDrift } = await import("./drift-VOKQJ36G.js");
|
|
854
887
|
await runDetectionsDrift({
|
|
855
888
|
org,
|
|
856
889
|
source: cli.flags.source,
|
|
@@ -864,7 +897,7 @@ async function main() {
|
|
|
864
897
|
break;
|
|
865
898
|
}
|
|
866
899
|
if (subcommand === "run") {
|
|
867
|
-
const { runDetectionsRun } = await import("./run-
|
|
900
|
+
const { runDetectionsRun } = await import("./run-OT2X46GT.js");
|
|
868
901
|
await runDetectionsRun({
|
|
869
902
|
org,
|
|
870
903
|
configId: cli.flags.configId,
|
|
@@ -883,7 +916,7 @@ async function main() {
|
|
|
883
916
|
break;
|
|
884
917
|
}
|
|
885
918
|
if (action === "run") {
|
|
886
|
-
const { runDetectionsRun } = await import("./run-
|
|
919
|
+
const { runDetectionsRun } = await import("./run-OT2X46GT.js");
|
|
887
920
|
await runDetectionsRun({
|
|
888
921
|
org,
|
|
889
922
|
configId: cli.flags.configId,
|
|
@@ -901,7 +934,7 @@ async function main() {
|
|
|
901
934
|
throw new Error("detections configs update requires --config-id");
|
|
902
935
|
}
|
|
903
936
|
const configPatch = getConfigPatchFromSetFlags();
|
|
904
|
-
const { runDetectionsConfigsUpdate } = await import("./configs-update-
|
|
937
|
+
const { runDetectionsConfigsUpdate } = await import("./configs-update-VROBC2HI.js");
|
|
905
938
|
await runDetectionsConfigsUpdate({
|
|
906
939
|
org,
|
|
907
940
|
configId: cli.flags.configId,
|
|
@@ -928,7 +961,7 @@ async function main() {
|
|
|
928
961
|
case "metrics": {
|
|
929
962
|
const org = await resolveOrg();
|
|
930
963
|
if (subcommand === "summary") {
|
|
931
|
-
const { runMetricsSummary } = await import("./summary-
|
|
964
|
+
const { runMetricsSummary } = await import("./summary-JOCABBCO.js");
|
|
932
965
|
await runMetricsSummary({
|
|
933
966
|
org,
|
|
934
967
|
from: cli.flags.from,
|
|
@@ -940,7 +973,7 @@ async function main() {
|
|
|
940
973
|
break;
|
|
941
974
|
}
|
|
942
975
|
if (subcommand === "found") {
|
|
943
|
-
const { runMetricsFound } = await import("./found-
|
|
976
|
+
const { runMetricsFound } = await import("./found-A5HRTJCJ.js");
|
|
944
977
|
await runMetricsFound({
|
|
945
978
|
org,
|
|
946
979
|
from: cli.flags.from,
|
|
@@ -957,7 +990,7 @@ async function main() {
|
|
|
957
990
|
if (!by || !["day", "type", "brand"].includes(by)) {
|
|
958
991
|
throw new Error("metrics breakdown requires --by <day|type|brand>");
|
|
959
992
|
}
|
|
960
|
-
const { runMetricsBreakdown } = await import("./breakdown-
|
|
993
|
+
const { runMetricsBreakdown } = await import("./breakdown-AX6QNTQH.js");
|
|
961
994
|
await runMetricsBreakdown({
|
|
962
995
|
org,
|
|
963
996
|
by,
|
|
@@ -977,7 +1010,7 @@ async function main() {
|
|
|
977
1010
|
case "reports": {
|
|
978
1011
|
if (subcommand === "list") {
|
|
979
1012
|
const org = await resolveOrg();
|
|
980
|
-
const { runReportsList } = await import("./list-
|
|
1013
|
+
const { runReportsList } = await import("./list-CVFXTKNX.js");
|
|
981
1014
|
await runReportsList({
|
|
982
1015
|
org,
|
|
983
1016
|
limit: cli.flags.limit,
|
|
@@ -993,7 +1026,7 @@ async function main() {
|
|
|
993
1026
|
}
|
|
994
1027
|
if (subcommand === "create") {
|
|
995
1028
|
const org = await tryResolveOrg();
|
|
996
|
-
const { runReportsCreate } = await import("./create-
|
|
1029
|
+
const { runReportsCreate } = await import("./create-XTCUNT2C.js");
|
|
997
1030
|
await runReportsCreate({
|
|
998
1031
|
org,
|
|
999
1032
|
title: cli.flags.title,
|
|
@@ -1017,7 +1050,7 @@ async function main() {
|
|
|
1017
1050
|
}
|
|
1018
1051
|
case "queues": {
|
|
1019
1052
|
if (subcommand === "snapshot") {
|
|
1020
|
-
const { runQueuesSnapshot } = await import("./snapshot-
|
|
1053
|
+
const { runQueuesSnapshot } = await import("./snapshot-4QR4I67P.js");
|
|
1021
1054
|
await runQueuesSnapshot({
|
|
1022
1055
|
org: cli.flags.org,
|
|
1023
1056
|
all: cli.flags.all,
|
|
@@ -1033,9 +1066,29 @@ async function main() {
|
|
|
1033
1066
|
subcommand ? `Unknown subcommand: queues ${subcommand}${hint ? `. Did you mean "queues ${hint}"?` : ""}` : "Usage: chainpatrol queues snapshot [--org <slug>|--all]"
|
|
1034
1067
|
);
|
|
1035
1068
|
}
|
|
1069
|
+
case "orgs": {
|
|
1070
|
+
if (subcommand === "list") {
|
|
1071
|
+
const { runOrgsList } = await import("./list-CGRHTFAS.js");
|
|
1072
|
+
await runOrgsList({
|
|
1073
|
+
query: cli.flags.query,
|
|
1074
|
+
subscriptionStatus: cli.flags.subscriptionStatus,
|
|
1075
|
+
serviceActive: cli.flags.serviceActive,
|
|
1076
|
+
serviceInactive: cli.flags.serviceInactive,
|
|
1077
|
+
serviceAutomated: cli.flags.serviceAutomated,
|
|
1078
|
+
serviceManual: cli.flags.serviceManual,
|
|
1079
|
+
json: jsonMode,
|
|
1080
|
+
outputFormat: cliContext.outputFormat
|
|
1081
|
+
});
|
|
1082
|
+
break;
|
|
1083
|
+
}
|
|
1084
|
+
const hint = subcommand ? suggest(subcommand, ["list"]) : null;
|
|
1085
|
+
throw new Error(
|
|
1086
|
+
subcommand ? `Unknown subcommand: orgs ${subcommand}${hint ? `. Did you mean "orgs ${hint}"?` : ""}` : "Usage: chainpatrol orgs list [--subscription-status <list>] [--service-active <list>] [--service-automated <list>] ..."
|
|
1087
|
+
);
|
|
1088
|
+
}
|
|
1036
1089
|
case "healthchecks": {
|
|
1037
1090
|
if (subcommand === "list") {
|
|
1038
|
-
const { runHealthchecksList } = await import("./list-
|
|
1091
|
+
const { runHealthchecksList } = await import("./list-PLZ67PNY.js");
|
|
1039
1092
|
await runHealthchecksList({
|
|
1040
1093
|
json: jsonMode,
|
|
1041
1094
|
outputFormat: cliContext.outputFormat
|
|
@@ -1049,7 +1102,7 @@ async function main() {
|
|
|
1049
1102
|
thresholds.minResults = cli.flags.minResults;
|
|
1050
1103
|
if (cli.flags.lookbackHours !== void 0)
|
|
1051
1104
|
thresholds.lookbackHours = cli.flags.lookbackHours;
|
|
1052
|
-
const { runHealthchecksRun } = await import("./run-
|
|
1105
|
+
const { runHealthchecksRun } = await import("./run-MS5SA5YL.js");
|
|
1053
1106
|
await runHealthchecksRun({
|
|
1054
1107
|
org,
|
|
1055
1108
|
id: action,
|
|
@@ -1067,7 +1120,7 @@ async function main() {
|
|
|
1067
1120
|
}
|
|
1068
1121
|
case "presets": {
|
|
1069
1122
|
if (subcommand === "list") {
|
|
1070
|
-
const { runPresetsList } = await import("./list-
|
|
1123
|
+
const { runPresetsList } = await import("./list-EYRN5JYC.js");
|
|
1071
1124
|
await runPresetsList({ outputFormat: cliContext.outputFormat });
|
|
1072
1125
|
break;
|
|
1073
1126
|
}
|
|
@@ -1078,7 +1131,7 @@ async function main() {
|
|
|
1078
1131
|
);
|
|
1079
1132
|
}
|
|
1080
1133
|
const org = await resolveOrg();
|
|
1081
|
-
const { runPresetsRun } = await import("./run-
|
|
1134
|
+
const { runPresetsRun } = await import("./run-YHDUUP66.js");
|
|
1082
1135
|
await runPresetsRun({
|
|
1083
1136
|
presetId: action,
|
|
1084
1137
|
org,
|
|
@@ -1095,12 +1148,12 @@ async function main() {
|
|
|
1095
1148
|
case "setup":
|
|
1096
1149
|
case "install":
|
|
1097
1150
|
case "i": {
|
|
1098
|
-
const { setupSkill } = await import("./setup-skill-
|
|
1151
|
+
const { setupSkill } = await import("./setup-skill-BTR2IZ4E.js");
|
|
1099
1152
|
setupSkill({ json: jsonMode });
|
|
1100
1153
|
break;
|
|
1101
1154
|
}
|
|
1102
1155
|
case "uninstall": {
|
|
1103
|
-
const { uninstallSkill } = await import("./setup-skill-
|
|
1156
|
+
const { uninstallSkill } = await import("./setup-skill-BTR2IZ4E.js");
|
|
1104
1157
|
uninstallSkill({ json: jsonMode });
|
|
1105
1158
|
break;
|
|
1106
1159
|
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CliExitError,
|
|
3
|
+
ExitCode
|
|
4
|
+
} from "./chunk-E2LAMILJ.js";
|
|
5
|
+
import {
|
|
6
|
+
printOutput,
|
|
7
|
+
toCsvRows
|
|
8
|
+
} from "./chunk-VFT3TD3E.js";
|
|
9
|
+
import {
|
|
10
|
+
createApiClient
|
|
11
|
+
} from "./chunk-LLWKCA3H.js";
|
|
12
|
+
import "./chunk-EEG7T6WT.js";
|
|
13
|
+
import "./chunk-TFCNKBRC.js";
|
|
14
|
+
import "./chunk-U73SABXK.js";
|
|
15
|
+
|
|
16
|
+
// src/commands/orgs/list.ts
|
|
17
|
+
var VALID_SUBSCRIPTION_STATUSES = /* @__PURE__ */ new Set([
|
|
18
|
+
"PROSPECT",
|
|
19
|
+
"TRIAL",
|
|
20
|
+
"ACTIVE",
|
|
21
|
+
"INTEGRATION"
|
|
22
|
+
]);
|
|
23
|
+
var DUAL_SERVICES = ["reporting", "reviewing", "protection", "takedowns"];
|
|
24
|
+
var SINGLE_SERVICES = ["detection", "darkWebMonitoring"];
|
|
25
|
+
var ALL_SERVICES = [...DUAL_SERVICES, ...SINGLE_SERVICES];
|
|
26
|
+
function splitCsv(value) {
|
|
27
|
+
if (!value) return [];
|
|
28
|
+
return value.split(",").map((part) => part.trim()).filter(Boolean);
|
|
29
|
+
}
|
|
30
|
+
function parseSubscriptionStatuses(raw) {
|
|
31
|
+
const parts = splitCsv(raw);
|
|
32
|
+
if (parts.length === 0) return void 0;
|
|
33
|
+
const result = [];
|
|
34
|
+
for (const part of parts) {
|
|
35
|
+
const upper = part.toUpperCase();
|
|
36
|
+
if (!VALID_SUBSCRIPTION_STATUSES.has(upper)) {
|
|
37
|
+
throw new CliExitError(
|
|
38
|
+
`Unknown subscription status: '${part}'. Valid values: ${Array.from(VALID_SUBSCRIPTION_STATUSES).join(", ")}.`,
|
|
39
|
+
ExitCode.USAGE
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
result.push(upper);
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
function parseServiceList(raw, flagName) {
|
|
47
|
+
const parts = splitCsv(raw);
|
|
48
|
+
const result = [];
|
|
49
|
+
for (const part of parts) {
|
|
50
|
+
if (!ALL_SERVICES.includes(part)) {
|
|
51
|
+
throw new CliExitError(
|
|
52
|
+
`Unknown service '${part}' in --${flagName}. Valid services: ${ALL_SERVICES.join(", ")}.`,
|
|
53
|
+
ExitCode.USAGE
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
result.push(part);
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
function requireDualService(service, flagName) {
|
|
61
|
+
if (!DUAL_SERVICES.includes(service)) {
|
|
62
|
+
throw new CliExitError(
|
|
63
|
+
`Service '${service}' does not have an automation toggle and can't be used with --${flagName}. Use --service-active / --service-inactive instead.`,
|
|
64
|
+
ExitCode.USAGE
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
return service;
|
|
68
|
+
}
|
|
69
|
+
function buildServicesFilter(options) {
|
|
70
|
+
const filters = {};
|
|
71
|
+
const activeSetBy = /* @__PURE__ */ new Map();
|
|
72
|
+
const automatedSetBy = /* @__PURE__ */ new Map();
|
|
73
|
+
function setActive(service, active, flagName) {
|
|
74
|
+
const previous = activeSetBy.get(service);
|
|
75
|
+
if (previous && previous !== flagName) {
|
|
76
|
+
throw new CliExitError(
|
|
77
|
+
`Conflicting flags for service '${service}': --${previous} and --${flagName} can't both be passed.`,
|
|
78
|
+
ExitCode.USAGE
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
activeSetBy.set(service, flagName);
|
|
82
|
+
const existing = filters[service] ?? {};
|
|
83
|
+
filters[service] = { ...existing, active };
|
|
84
|
+
}
|
|
85
|
+
function setAutomated(service, automated, flagName) {
|
|
86
|
+
const previous = automatedSetBy.get(service);
|
|
87
|
+
if (previous && previous !== flagName) {
|
|
88
|
+
throw new CliExitError(
|
|
89
|
+
`Conflicting flags for service '${service}': --${previous} and --${flagName} can't both be passed.`,
|
|
90
|
+
ExitCode.USAGE
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
automatedSetBy.set(service, flagName);
|
|
94
|
+
const existing = filters[service] ?? {};
|
|
95
|
+
filters[service] = { ...existing, automated };
|
|
96
|
+
}
|
|
97
|
+
for (const service of parseServiceList(options.serviceActive, "service-active")) {
|
|
98
|
+
setActive(service, true, "service-active");
|
|
99
|
+
}
|
|
100
|
+
for (const service of parseServiceList(options.serviceInactive, "service-inactive")) {
|
|
101
|
+
setActive(service, false, "service-inactive");
|
|
102
|
+
}
|
|
103
|
+
for (const service of parseServiceList(options.serviceAutomated, "service-automated")) {
|
|
104
|
+
setAutomated(
|
|
105
|
+
requireDualService(service, "service-automated"),
|
|
106
|
+
true,
|
|
107
|
+
"service-automated"
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
for (const service of parseServiceList(options.serviceManual, "service-manual")) {
|
|
111
|
+
setAutomated(requireDualService(service, "service-manual"), false, "service-manual");
|
|
112
|
+
}
|
|
113
|
+
return Object.keys(filters).length > 0 ? filters : void 0;
|
|
114
|
+
}
|
|
115
|
+
function summarizeServices(org) {
|
|
116
|
+
const parts = [];
|
|
117
|
+
for (const service of DUAL_SERVICES) {
|
|
118
|
+
const entry = org.services[service];
|
|
119
|
+
if (!entry.active) continue;
|
|
120
|
+
parts.push(`${service}=${entry.automated ? "auto" : "manual"}`);
|
|
121
|
+
}
|
|
122
|
+
for (const service of SINGLE_SERVICES) {
|
|
123
|
+
if (org.services[service].active) parts.push(service);
|
|
124
|
+
}
|
|
125
|
+
return parts.length > 0 ? parts.join(" ") : "(no services enabled)";
|
|
126
|
+
}
|
|
127
|
+
async function runOrgsList(options) {
|
|
128
|
+
const client = options.apiClient ?? createApiClient();
|
|
129
|
+
const outputFormat = options.outputFormat ?? (options.json ? "json" : "human");
|
|
130
|
+
const input = {
|
|
131
|
+
query: options.query ?? "",
|
|
132
|
+
subscriptionStatus: parseSubscriptionStatuses(options.subscriptionStatus),
|
|
133
|
+
services: buildServicesFilter(options)
|
|
134
|
+
};
|
|
135
|
+
const result = await client.getUserOrgs(input);
|
|
136
|
+
const organizations = result.organizations;
|
|
137
|
+
printOutput({
|
|
138
|
+
outputFormat,
|
|
139
|
+
json: result,
|
|
140
|
+
markdown: [
|
|
141
|
+
`# Organizations (${organizations.length})`,
|
|
142
|
+
"",
|
|
143
|
+
...organizations.map(
|
|
144
|
+
(org) => `- \`${org.slug}\` \u2014 ${org.name} \u2014 ${org.subscriptionStatus} \u2014 ${summarizeServices(org)}`
|
|
145
|
+
)
|
|
146
|
+
].join("\n"),
|
|
147
|
+
csv: toCsvRows(
|
|
148
|
+
organizations.map((org) => ({
|
|
149
|
+
slug: org.slug,
|
|
150
|
+
name: org.name,
|
|
151
|
+
subscriptionStatus: org.subscriptionStatus,
|
|
152
|
+
reportingActive: org.services.reporting.active,
|
|
153
|
+
reportingAutomated: org.services.reporting.automated,
|
|
154
|
+
reviewingActive: org.services.reviewing.active,
|
|
155
|
+
reviewingAutomated: org.services.reviewing.automated,
|
|
156
|
+
protectionActive: org.services.protection.active,
|
|
157
|
+
protectionAutomated: org.services.protection.automated,
|
|
158
|
+
takedownsActive: org.services.takedowns.active,
|
|
159
|
+
takedownsAutomated: org.services.takedowns.automated,
|
|
160
|
+
detectionActive: org.services.detection.active,
|
|
161
|
+
darkWebMonitoringActive: org.services.darkWebMonitoring.active
|
|
162
|
+
}))
|
|
163
|
+
),
|
|
164
|
+
human: () => {
|
|
165
|
+
if (organizations.length === 0) {
|
|
166
|
+
console.log("No organizations matched the filter.");
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
console.log(`Found ${organizations.length} organization(s):`);
|
|
170
|
+
const slugWidth = Math.max(...organizations.map((org) => org.slug.length), 4);
|
|
171
|
+
const nameWidth = Math.max(...organizations.map((org) => org.name.length), 4);
|
|
172
|
+
for (const org of organizations) {
|
|
173
|
+
console.log(
|
|
174
|
+
` ${org.slug.padEnd(slugWidth)} ${org.name.padEnd(nameWidth)} ${org.subscriptionStatus.padEnd(11)} ${summarizeServices(org)}`
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
export {
|
|
181
|
+
runOrgsList
|
|
182
|
+
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PRESETS
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-AGXMZFUU.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-LLWKCA3H.js";
|
|
10
10
|
import "./chunk-EEG7T6WT.js";
|
|
11
11
|
import "./chunk-TFCNKBRC.js";
|
|
12
12
|
import "./chunk-U73SABXK.js";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getPresetDefinition,
|
|
3
3
|
runPreset
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-AGXMZFUU.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-LLWKCA3H.js";
|
|
11
11
|
import "./chunk-EEG7T6WT.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.6.0",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"homepage": "https://chainpatrol.com/docs/cli",
|
|
8
8
|
"keywords": [
|