@chainpatrol/cli 0.19.0 → 0.21.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 +49 -0
- package/dist/{chunk-UDGJEN4M.js → chunk-4N2YKTJ5.js} +108 -14
- package/dist/{chunk-NQT77IB7.js → chunk-6VTWWGNV.js} +2 -1
- package/dist/cli.js +37 -12
- package/dist/{completions-6C6KG5DH.js → completions-ILC76OX5.js} +1 -1
- package/dist/{get-K7VHV5X2.js → get-XN752KSL.js} +15 -2
- package/dist/{list-QXA6GLCV.js → list-MHICJ2TK.js} +37 -4
- package/dist/{setup-skill-F7437RT3.js → setup-skill-UEOROLCF.js} +2 -2
- package/dist/types-PTMFLYUV.js +271 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,54 @@
|
|
|
1
1
|
# @chainpatrol/cli
|
|
2
2
|
|
|
3
|
+
## 0.21.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- b3e77eb: `orgs list` and `orgs get` now surface each organization's "Obligatory
|
|
8
|
+
Organization Admin Approval" state (`Organization.requiresCustomerReview`)
|
|
9
|
+
alongside its per-asset-type scope. The new response field is
|
|
10
|
+
`obligatoryAdminApproval: { active, assetTypes }` — an empty `assetTypes`
|
|
11
|
+
list with `active: true` means approval applies to every asset type
|
|
12
|
+
(matches the in-app UI's behaviour when no narrowing has been configured).
|
|
13
|
+
|
|
14
|
+
`orgs list` also accepts three new filters that compose with the
|
|
15
|
+
existing ones via AND:
|
|
16
|
+
|
|
17
|
+
- `--obligatory-approval-active` / `--obligatory-approval-inactive` —
|
|
18
|
+
filter on the toggle itself.
|
|
19
|
+
- `--obligatory-approval-asset-type <csv>` — return only orgs whose
|
|
20
|
+
approval scope covers every listed asset type (an org's empty
|
|
21
|
+
per-asset-type list still counts as "all types"). Passing this flag
|
|
22
|
+
implies the feature is on, so it can't be combined with
|
|
23
|
+
`--obligatory-approval-inactive`.
|
|
24
|
+
|
|
25
|
+
Server-side work in `@chainpatrol/external-trpc` and `@chainpatrol/validation`
|
|
26
|
+
extends the `/user/orgs` and `/user/orgs/{slug}` schemas accordingly; both
|
|
27
|
+
are private packages and don't need version bumps.
|
|
28
|
+
|
|
29
|
+
## 0.20.0
|
|
30
|
+
|
|
31
|
+
### Minor Changes
|
|
32
|
+
|
|
33
|
+
- e63d269: Add `chainpatrol asset types` — list every supported `AssetType` enum
|
|
34
|
+
value with its human-readable label and a short description.
|
|
35
|
+
|
|
36
|
+
The mapping (e.g. `ARCHIVE_ORG` → "Archive.org" / Wayback snapshot,
|
|
37
|
+
`PAGE` → "Page" / standalone web page tracked independently of its
|
|
38
|
+
parent URL, `FIVE_HUNDRED_PX` → "500px") ships bundled with the CLI as
|
|
39
|
+
a static map, so the command works without auth or a network round
|
|
40
|
+
trip. Output is available in human, JSON, markdown, and CSV formats —
|
|
41
|
+
useful when an agent or script needs to translate enum ↔ display name,
|
|
42
|
+
validate a user-supplied `--asset-type` value, or enumerate the
|
|
43
|
+
available types before constructing a filter for `asset list`,
|
|
44
|
+
`threats list`, `takedowns list`, `detections list`, `reports list`,
|
|
45
|
+
or `orgs assets list`.
|
|
46
|
+
|
|
47
|
+
The Claude Code skill is updated to point at the new command whenever
|
|
48
|
+
a user asks "what is `ARCHIVE_ORG`?", "what does `PAGE` mean?", or
|
|
49
|
+
"what asset types does ChainPatrol support?". Shell completions and
|
|
50
|
+
top-level/per-command help text are updated accordingly.
|
|
51
|
+
|
|
3
52
|
## 0.19.0
|
|
4
53
|
|
|
5
54
|
### Minor Changes
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
installCompletions,
|
|
3
3
|
uninstallCompletions
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-6VTWWGNV.js";
|
|
5
5
|
|
|
6
6
|
// src/commands/setup-skill.ts
|
|
7
7
|
import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, existsSync as existsSync2, readFileSync as readFileSync3, rmSync } from "fs";
|
|
@@ -199,8 +199,17 @@ description: |
|
|
|
199
199
|
"fetch org details", "org info",
|
|
200
200
|
"orgs with takedowns off", "automation off across orgs",
|
|
201
201
|
"which customers have X enabled", "service toggles by org",
|
|
202
|
+
"obligatory admin approval", "obligatory organization admin approval",
|
|
203
|
+
"obligatory approval", "admin approval enabled", "admin approval orgs",
|
|
204
|
+
"requires customer review", "requires admin approval",
|
|
205
|
+
"orgs that require admin approval", "orgs requiring approval",
|
|
206
|
+
"which orgs require approval for twitter", "approval scope",
|
|
207
|
+
"admin approval asset types", "approval per asset type",
|
|
202
208
|
"is this URL blocked", "is this domain blocked", "is this address blocked",
|
|
203
209
|
"check this asset", "asset check", "lookup asset status",
|
|
210
|
+
"what is ARCHIVE_ORG", "what does PAGE mean", "list asset types",
|
|
211
|
+
"supported asset types", "asset type mapping", "asset type enum",
|
|
212
|
+
"what asset types are there", "human readable asset type",
|
|
204
213
|
"how many takedowns", "takedowns in the last", "threats taken down",
|
|
205
214
|
"across all clients", "across all customers", "across all orgs",
|
|
206
215
|
"across all brands", "company-wide", "total takedowns", "total threats",
|
|
@@ -383,6 +392,29 @@ If any individual lookup fails, the CLI still prints results for the
|
|
|
383
392
|
successful ones, then exits non-zero so failures aren't silently
|
|
384
393
|
swallowed.
|
|
385
394
|
|
|
395
|
+
### \`asset types\` \u2014 List every supported asset type and what it means
|
|
396
|
+
|
|
397
|
+
When a user asks "what is \`ARCHIVE_ORG\`?", "what does \`PAGE\` mean?",
|
|
398
|
+
or "what asset types does ChainPatrol support?" \u2014 don't guess. Run:
|
|
399
|
+
|
|
400
|
+
\`\`\`bash
|
|
401
|
+
chainpatrol asset types
|
|
402
|
+
chainpatrol --json asset types
|
|
403
|
+
\`\`\`
|
|
404
|
+
|
|
405
|
+
The mapping is bundled with the CLI (no API or auth required), so this
|
|
406
|
+
is safe to run anywhere. Each row is \`{ type, label, description }\`:
|
|
407
|
+
\`type\` is the canonical enum value used by every \`--asset-type\` flag
|
|
408
|
+
(\`asset list\`, \`threats list\`, \`takedowns list\`, \`detections list\`,
|
|
409
|
+
\`reports list\`, \`orgs assets list\`); \`label\` is the human-friendly
|
|
410
|
+
display name (\`ARCHIVE_ORG\` \u2192 \`Archive.org\`, \`PAGE\` \u2192 \`Page\`,
|
|
411
|
+
\`FIVE_HUNDRED_PX\` \u2192 \`500px\`); \`description\` is a one-line note for
|
|
412
|
+
unobvious entries.
|
|
413
|
+
|
|
414
|
+
Use this whenever you need to translate between enum and display name,
|
|
415
|
+
validate that a type the user mentioned is real, or enumerate options
|
|
416
|
+
before constructing a filter.
|
|
417
|
+
|
|
386
418
|
### \`configs list\` \u2014 List detection configurations
|
|
387
419
|
|
|
388
420
|
Requires authentication and an organization slug.
|
|
@@ -630,14 +662,17 @@ Guide. Key signals in the response:
|
|
|
630
662
|
|
|
631
663
|
Use \`--all\` to snapshot every org you have access to instead of a single slug.
|
|
632
664
|
|
|
633
|
-
### \`orgs list\` \u2014 List organizations with subscription status and
|
|
665
|
+
### \`orgs list\` \u2014 List organizations with subscription status, service toggles, and admin-approval scope
|
|
634
666
|
|
|
635
667
|
Returns every organization the caller can see, with each org's
|
|
636
|
-
subscription status (\`PROSPECT\`, \`TRIAL\`, \`ACTIVE\`, \`INTEGRATION\`)
|
|
637
|
-
which services are active
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
668
|
+
subscription status (\`PROSPECT\`, \`TRIAL\`, \`ACTIVE\`, \`INTEGRATION\`),
|
|
669
|
+
which services are active, and the per-org "Obligatory Organization
|
|
670
|
+
Admin Approval" toggle (with its asset-type scope). Use it to answer
|
|
671
|
+
questions like "which customers have takedowns enabled but automation
|
|
672
|
+
off?", "which prospects don't have detection turned on yet?", or "which
|
|
673
|
+
orgs require admin approval before adding Twitter assets to the
|
|
674
|
+
blocklist?" \u2014 filters compose with AND and are applied server-side, so
|
|
675
|
+
one call returns the final list.
|
|
641
676
|
|
|
642
677
|
\`\`\`bash
|
|
643
678
|
chainpatrol --json orgs list \\
|
|
@@ -660,6 +695,34 @@ misleading filters like "reporting.automated=true" that don't mean
|
|
|
660
695
|
anything. \`detection\` and \`darkWebMonitoring\` have always been
|
|
661
696
|
single-flag services.
|
|
662
697
|
|
|
698
|
+
#### Obligatory Organization Admin Approval
|
|
699
|
+
|
|
700
|
+
Each org also has a separate "Obligatory Organization Admin Approval"
|
|
701
|
+
toggle (\`Organization.requiresCustomerReview\` in the schema, surfaced
|
|
702
|
+
on the Services settings page in the app) that gates customer-side
|
|
703
|
+
review of proposals ChainPatrol staff have already approved before
|
|
704
|
+
they're added to the blocklist. It is NOT one of the operational
|
|
705
|
+
services above \u2014 it is an org-policy toggle with its own per-asset-type
|
|
706
|
+
scope.
|
|
707
|
+
|
|
708
|
+
Each org's response includes:
|
|
709
|
+
|
|
710
|
+
\`\`\`json
|
|
711
|
+
{
|
|
712
|
+
"obligatoryAdminApproval": {
|
|
713
|
+
"active": true,
|
|
714
|
+
"assetTypes": ["TWITTER", "URL"]
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
\`\`\`
|
|
718
|
+
|
|
719
|
+
- \`active=true\` + empty \`assetTypes\` means approval applies to
|
|
720
|
+
**all** asset types \u2014 the org has not narrowed the scope.
|
|
721
|
+
- \`active=true\` + a non-empty \`assetTypes\` list means approval is
|
|
722
|
+
required only for those asset types.
|
|
723
|
+
- \`active=false\` means no approval is required; \`assetTypes\` is
|
|
724
|
+
always empty in that case.
|
|
725
|
+
|
|
663
726
|
So per-org JSON looks like:
|
|
664
727
|
|
|
665
728
|
\`\`\`json
|
|
@@ -671,7 +734,8 @@ So per-org JSON looks like:
|
|
|
671
734
|
"takedowns": { "active": true, "automated": false },
|
|
672
735
|
"detection": { "active": true },
|
|
673
736
|
"darkWebMonitoring": { "active": false }
|
|
674
|
-
}
|
|
737
|
+
},
|
|
738
|
+
"obligatoryAdminApproval": { "active": true, "assetTypes": ["TWITTER"] }
|
|
675
739
|
}
|
|
676
740
|
\`\`\`
|
|
677
741
|
|
|
@@ -680,7 +744,7 @@ explain that the flag exists in the DB but has no operational effect and
|
|
|
680
744
|
isn't exposed by the public API \u2014 only \`takedowns.automated\` carries a
|
|
681
745
|
real meaning.
|
|
682
746
|
|
|
683
|
-
Filter flags (all optional, all comma-separated lists):
|
|
747
|
+
Filter flags (all optional, all comma-separated lists where noted):
|
|
684
748
|
|
|
685
749
|
- \`--query <text>\` partial name match (substring, case-insensitive)
|
|
686
750
|
- \`--subscription-status <list>\` one or more of \`PROSPECT\`, \`TRIAL\`,
|
|
@@ -693,6 +757,16 @@ Filter flags (all optional, all comma-separated lists):
|
|
|
693
757
|
meaningful automation toggle. Passing any other service name errors out.
|
|
694
758
|
- \`--service-manual <list>\` services whose automation must be OFF.
|
|
695
759
|
Same restriction \u2014 only \`takedowns\`.
|
|
760
|
+
- \`--obligatory-approval-active\` \u2014 only orgs with admin approval on
|
|
761
|
+
- \`--obligatory-approval-inactive\` \u2014 only orgs with admin approval off
|
|
762
|
+
- \`--obligatory-approval-asset-type <list>\` \u2014 only orgs whose admin
|
|
763
|
+
approval scope covers EVERY listed asset type. The match treats an
|
|
764
|
+
org's empty per-asset-type list as "applies to all asset types", so a
|
|
765
|
+
fully-broad org matches every value passed here. Passing this flag
|
|
766
|
+
implies the feature is on, so it can't be combined with
|
|
767
|
+
\`--obligatory-approval-inactive\`. Use the canonical asset-type enum
|
|
768
|
+
names (\`TWITTER\`, \`URL\`, \`PAGE\`, \u2026); run \`chainpatrol asset types\`
|
|
769
|
+
to see them all.
|
|
696
770
|
|
|
697
771
|
Service names: \`reporting\`, \`reviewing\`, \`protection\`, \`takedowns\`,
|
|
698
772
|
\`detection\`, \`darkWebMonitoring\`.
|
|
@@ -701,16 +775,36 @@ Customers see only orgs they're a member of. Staff/superuser sessions see
|
|
|
701
775
|
every matching org. The response is the same in both cases; visibility is
|
|
702
776
|
enforced server-side.
|
|
703
777
|
|
|
778
|
+
#### Use case: finding which orgs require admin approval for an asset type
|
|
779
|
+
|
|
780
|
+
When a user asks "which orgs require admin approval before blocking
|
|
781
|
+
Twitter assets?", reach straight for the filter \u2014 no client-side
|
|
782
|
+
post-processing needed:
|
|
783
|
+
|
|
784
|
+
\`\`\`bash
|
|
785
|
+
chainpatrol --json orgs list --obligatory-approval-asset-type TWITTER
|
|
786
|
+
\`\`\`
|
|
787
|
+
|
|
788
|
+
To audit just the broad opt-ins ("which orgs require approval for
|
|
789
|
+
everything?"), filter on the toggle and inspect \`assetTypes\` in the
|
|
790
|
+
output \u2014 an empty array means "all":
|
|
791
|
+
|
|
792
|
+
\`\`\`bash
|
|
793
|
+
chainpatrol --json orgs list --obligatory-approval-active \\
|
|
794
|
+
| jq '.organizations[] | select(.obligatoryAdminApproval.assetTypes | length == 0) | .slug'
|
|
795
|
+
\`\`\`
|
|
796
|
+
|
|
704
797
|
### \`orgs get\` \u2014 Get a single organization by slug
|
|
705
798
|
|
|
706
799
|
Look up one organization the caller has access to. Returns the same per-org
|
|
707
800
|
shape as a single row from \`orgs list\` \u2014 \`active\` for every service,
|
|
708
801
|
plus \`automated\` on \`takedowns\` only (see the note above on why other
|
|
709
|
-
services don't expose an automation flag)
|
|
710
|
-
\`
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
802
|
+
services don't expose an automation flag), plus \`obligatoryAdminApproval\`
|
|
803
|
+
(\`active\` + \`assetTypes\`). Anything you could read from \`orgs list\` you
|
|
804
|
+
can also read here without paging or filtering. Use it when the user
|
|
805
|
+
names a specific customer ("show me acme's setup", "is takedowns
|
|
806
|
+
automation on for morpho?", "does this org require admin approval for
|
|
807
|
+
Twitter?") and you don't need the rest of the catalogue.
|
|
714
808
|
|
|
715
809
|
\`\`\`bash
|
|
716
810
|
chainpatrol orgs get <slug>
|
|
@@ -66,6 +66,7 @@ _chainpatrol() {
|
|
|
66
66
|
asset_subcommands=(
|
|
67
67
|
'check:Check asset status against ChainPatrol'
|
|
68
68
|
'list:List assets in the global ChainPatrol blocklist'
|
|
69
|
+
'types:List supported asset types and their human-readable labels'
|
|
69
70
|
)
|
|
70
71
|
_describe 'subcommand' asset_subcommands
|
|
71
72
|
;;
|
|
@@ -161,7 +162,7 @@ var BASH_COMPLETION = `_chainpatrol() {
|
|
|
161
162
|
return 0
|
|
162
163
|
;;
|
|
163
164
|
asset)
|
|
164
|
-
COMPREPLY=( $(compgen -W "check list" -- "\${cur}") )
|
|
165
|
+
COMPREPLY=( $(compgen -W "check list types" -- "\${cur}") )
|
|
165
166
|
return 0
|
|
166
167
|
;;
|
|
167
168
|
configs)
|
package/dist/cli.js
CHANGED
|
@@ -13,8 +13,8 @@ import {
|
|
|
13
13
|
getCliVersion,
|
|
14
14
|
isSkillInstalled,
|
|
15
15
|
readInstalledSkillVersion
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
import "./chunk-
|
|
16
|
+
} from "./chunk-4N2YKTJ5.js";
|
|
17
|
+
import "./chunk-6VTWWGNV.js";
|
|
18
18
|
import {
|
|
19
19
|
DateTime
|
|
20
20
|
} from "./chunk-TFCNKBRC.js";
|
|
@@ -92,14 +92,25 @@ var HELP = {
|
|
|
92
92
|
usage: "chainpatrol logout"
|
|
93
93
|
},
|
|
94
94
|
asset: {
|
|
95
|
-
description: "Check asset status
|
|
96
|
-
usage: "chainpatrol asset <check|list>",
|
|
95
|
+
description: "Check asset status, list blocked/allowed assets across the global ChainPatrol blocklist, or list every supported asset type.",
|
|
96
|
+
usage: "chainpatrol asset <check|list|types>",
|
|
97
97
|
examples: [
|
|
98
98
|
"chainpatrol asset check https://phish.example",
|
|
99
99
|
"chainpatrol asset list --asset-type URL --from 2026-05-01",
|
|
100
|
+
"chainpatrol asset types",
|
|
100
101
|
"chainpatrol --json asset check 0xabc123\u2026"
|
|
101
102
|
]
|
|
102
103
|
},
|
|
104
|
+
"asset types": {
|
|
105
|
+
description: "List every asset type supported by ChainPatrol and what each enum value means (e.g. ARCHIVE_ORG \u2192 Archive.org Wayback snapshot, PAGE \u2192 standalone web page). Reads from a static map bundled with the CLI \u2014 no API or auth required. Useful for picking the right --asset-type value for `asset list`, `threats list`, `takedowns list`, etc.",
|
|
106
|
+
usage: "chainpatrol asset types",
|
|
107
|
+
examples: [
|
|
108
|
+
"chainpatrol asset types",
|
|
109
|
+
"chainpatrol --json asset types",
|
|
110
|
+
"chainpatrol asset types --output markdown",
|
|
111
|
+
"chainpatrol asset types --output csv > asset-types.csv"
|
|
112
|
+
]
|
|
113
|
+
},
|
|
103
114
|
"asset list": {
|
|
104
115
|
description: "List assets in the global ChainPatrol blocklist for a given asset type. Defaults to BLOCKED assets updated in the last day. Use --from and --to to widen the window.",
|
|
105
116
|
usage: "chainpatrol asset list --asset-type <type> [--from ISO --to ISO] [filters]",
|
|
@@ -636,7 +647,7 @@ function getTopLevelHelp() {
|
|
|
636
647
|
" login Authenticate with ChainPatrol",
|
|
637
648
|
" logout Clear stored credentials",
|
|
638
649
|
" whoami Show the current authenticated identity",
|
|
639
|
-
" asset Check or list assets
|
|
650
|
+
" asset Check or list assets, or list supported asset types",
|
|
640
651
|
" configs Manage detection configs",
|
|
641
652
|
" detections Validate, run, list, update detection configs and results",
|
|
642
653
|
" healthchecks List and run organization healthchecks",
|
|
@@ -905,6 +916,9 @@ ${getTopLevelHelp()}
|
|
|
905
916
|
serviceInactive: { type: "string" },
|
|
906
917
|
serviceAutomated: { type: "string" },
|
|
907
918
|
serviceManual: { type: "string" },
|
|
919
|
+
obligatoryApprovalActive: { type: "boolean" },
|
|
920
|
+
obligatoryApprovalInactive: { type: "boolean" },
|
|
921
|
+
obligatoryApprovalAssetType: { type: "string" },
|
|
908
922
|
query: { type: "string" },
|
|
909
923
|
assetType: { type: "string" },
|
|
910
924
|
takedownStatus: { type: "string" },
|
|
@@ -1183,9 +1197,17 @@ async function main() {
|
|
|
1183
1197
|
});
|
|
1184
1198
|
break;
|
|
1185
1199
|
}
|
|
1186
|
-
|
|
1200
|
+
if (subcommand === "types") {
|
|
1201
|
+
const { runAssetTypes } = await import("./types-PTMFLYUV.js");
|
|
1202
|
+
runAssetTypes({
|
|
1203
|
+
json: jsonMode,
|
|
1204
|
+
outputFormat: cliContext.outputFormat
|
|
1205
|
+
});
|
|
1206
|
+
break;
|
|
1207
|
+
}
|
|
1208
|
+
const hint = subcommand ? suggest(subcommand, ["check", "list", "types"]) : null;
|
|
1187
1209
|
throw new Error(
|
|
1188
|
-
subcommand ? `Unknown subcommand: asset ${subcommand}${hint ? `. Did you mean "asset ${hint}"?` : ""}` : "Usage: chainpatrol asset <check|list>"
|
|
1210
|
+
subcommand ? `Unknown subcommand: asset ${subcommand}${hint ? `. Did you mean "asset ${hint}"?` : ""}` : "Usage: chainpatrol asset <check|list|types>"
|
|
1189
1211
|
);
|
|
1190
1212
|
}
|
|
1191
1213
|
case "detections": {
|
|
@@ -1539,7 +1561,7 @@ async function main() {
|
|
|
1539
1561
|
}
|
|
1540
1562
|
case "orgs": {
|
|
1541
1563
|
if (subcommand === "list") {
|
|
1542
|
-
const { runOrgsList } = await import("./list-
|
|
1564
|
+
const { runOrgsList } = await import("./list-MHICJ2TK.js");
|
|
1543
1565
|
await runOrgsList({
|
|
1544
1566
|
query: cli.flags.query,
|
|
1545
1567
|
subscriptionStatus: cli.flags.subscriptionStatus,
|
|
@@ -1547,6 +1569,9 @@ async function main() {
|
|
|
1547
1569
|
serviceInactive: cli.flags.serviceInactive,
|
|
1548
1570
|
serviceAutomated: cli.flags.serviceAutomated,
|
|
1549
1571
|
serviceManual: cli.flags.serviceManual,
|
|
1572
|
+
obligatoryApprovalActive: cli.flags.obligatoryApprovalActive,
|
|
1573
|
+
obligatoryApprovalInactive: cli.flags.obligatoryApprovalInactive,
|
|
1574
|
+
obligatoryApprovalAssetType: cli.flags.obligatoryApprovalAssetType,
|
|
1550
1575
|
json: jsonMode,
|
|
1551
1576
|
outputFormat: cliContext.outputFormat
|
|
1552
1577
|
});
|
|
@@ -1555,7 +1580,7 @@ async function main() {
|
|
|
1555
1580
|
if (subcommand === "get") {
|
|
1556
1581
|
const positionalSlug = action;
|
|
1557
1582
|
const slug = positionalSlug ?? await tryResolveOrg();
|
|
1558
|
-
const { runOrgsGet } = await import("./get-
|
|
1583
|
+
const { runOrgsGet } = await import("./get-XN752KSL.js");
|
|
1559
1584
|
await runOrgsGet({
|
|
1560
1585
|
slug,
|
|
1561
1586
|
json: jsonMode,
|
|
@@ -1686,17 +1711,17 @@ async function main() {
|
|
|
1686
1711
|
case "setup":
|
|
1687
1712
|
case "install":
|
|
1688
1713
|
case "i": {
|
|
1689
|
-
const { setupSkill } = await import("./setup-skill-
|
|
1714
|
+
const { setupSkill } = await import("./setup-skill-UEOROLCF.js");
|
|
1690
1715
|
setupSkill({ json: jsonMode, cloud: cli.flags.cloud });
|
|
1691
1716
|
break;
|
|
1692
1717
|
}
|
|
1693
1718
|
case "uninstall": {
|
|
1694
|
-
const { uninstallSkill } = await import("./setup-skill-
|
|
1719
|
+
const { uninstallSkill } = await import("./setup-skill-UEOROLCF.js");
|
|
1695
1720
|
uninstallSkill({ json: jsonMode });
|
|
1696
1721
|
break;
|
|
1697
1722
|
}
|
|
1698
1723
|
case "completions": {
|
|
1699
|
-
const { printCompletions } = await import("./completions-
|
|
1724
|
+
const { printCompletions } = await import("./completions-ILC76OX5.js");
|
|
1700
1725
|
printCompletions(subcommand);
|
|
1701
1726
|
break;
|
|
1702
1727
|
}
|
|
@@ -26,6 +26,11 @@ function summarizeServices(org) {
|
|
|
26
26
|
if (org.services.darkWebMonitoring.active) parts.push("darkWebMonitoring");
|
|
27
27
|
return parts.length > 0 ? parts.join(" ") : "(no services enabled)";
|
|
28
28
|
}
|
|
29
|
+
function summarizeObligatoryAdminApproval(org) {
|
|
30
|
+
if (!org.obligatoryAdminApproval.active) return "off";
|
|
31
|
+
const types = org.obligatoryAdminApproval.assetTypes;
|
|
32
|
+
return types.length === 0 ? "on (all asset types)" : `on (${types.join(", ")})`;
|
|
33
|
+
}
|
|
29
34
|
async function runOrgsGet(options) {
|
|
30
35
|
const slug = options.slug?.trim();
|
|
31
36
|
if (!slug) {
|
|
@@ -45,7 +50,8 @@ async function runOrgsGet(options) {
|
|
|
45
50
|
`# ${organization.name} (\`${organization.slug}\`)`,
|
|
46
51
|
"",
|
|
47
52
|
`- Subscription status: ${organization.subscriptionStatus}`,
|
|
48
|
-
`- Services: ${summarizeServices(organization)}
|
|
53
|
+
`- Services: ${summarizeServices(organization)}`,
|
|
54
|
+
`- Obligatory admin approval: ${summarizeObligatoryAdminApproval(organization)}`
|
|
49
55
|
].join("\n"),
|
|
50
56
|
csv: toCsvRows([
|
|
51
57
|
{
|
|
@@ -59,13 +65,20 @@ async function runOrgsGet(options) {
|
|
|
59
65
|
// `takedowns` is the only service with a meaningful automation flag.
|
|
60
66
|
takedownsAutomated: organization.services.takedowns.automated,
|
|
61
67
|
detectionActive: organization.services.detection.active,
|
|
62
|
-
darkWebMonitoringActive: organization.services.darkWebMonitoring.active
|
|
68
|
+
darkWebMonitoringActive: organization.services.darkWebMonitoring.active,
|
|
69
|
+
obligatoryAdminApprovalActive: organization.obligatoryAdminApproval.active,
|
|
70
|
+
// Empty list + active=true means "applies to all asset types" — read
|
|
71
|
+
// the active column alongside this one to interpret.
|
|
72
|
+
obligatoryAdminApprovalAssetTypes: organization.obligatoryAdminApproval.assetTypes.join("|")
|
|
63
73
|
}
|
|
64
74
|
]),
|
|
65
75
|
human: () => {
|
|
66
76
|
console.log(`${organization.name} (slug: ${organization.slug})`);
|
|
67
77
|
console.log(` subscriptionStatus: ${organization.subscriptionStatus}`);
|
|
68
78
|
console.log(` services: ${summarizeServices(organization)}`);
|
|
79
|
+
console.log(
|
|
80
|
+
` obligatoryAdminApproval: ${summarizeObligatoryAdminApproval(organization)}`
|
|
81
|
+
);
|
|
69
82
|
}
|
|
70
83
|
});
|
|
71
84
|
}
|
|
@@ -128,13 +128,41 @@ function summarizeServices(org) {
|
|
|
128
128
|
}
|
|
129
129
|
return parts.length > 0 ? parts.join(" ") : "(no services enabled)";
|
|
130
130
|
}
|
|
131
|
+
function summarizeObligatoryAdminApproval(org) {
|
|
132
|
+
if (!org.obligatoryAdminApproval.active) return "off";
|
|
133
|
+
const types = org.obligatoryAdminApproval.assetTypes;
|
|
134
|
+
return types.length === 0 ? "on (all asset types)" : `on (${types.join(", ")})`;
|
|
135
|
+
}
|
|
136
|
+
function buildObligatoryAdminApprovalFilter(options) {
|
|
137
|
+
if (options.obligatoryApprovalActive && options.obligatoryApprovalInactive) {
|
|
138
|
+
throw new CliExitError(
|
|
139
|
+
"Conflicting flags: --obligatory-approval-active and --obligatory-approval-inactive can't both be passed.",
|
|
140
|
+
ExitCode.USAGE
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
const assetTypeStrings = splitCsv(options.obligatoryApprovalAssetType).map(
|
|
144
|
+
(value) => value.toUpperCase()
|
|
145
|
+
);
|
|
146
|
+
if (assetTypeStrings.length > 0 && options.obligatoryApprovalInactive) {
|
|
147
|
+
throw new CliExitError(
|
|
148
|
+
"Conflicting flags: --obligatory-approval-asset-type implies the feature is on, so it can't be combined with --obligatory-approval-inactive.",
|
|
149
|
+
ExitCode.USAGE
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
const filter = {};
|
|
153
|
+
if (options.obligatoryApprovalActive) filter.active = true;
|
|
154
|
+
if (options.obligatoryApprovalInactive) filter.active = false;
|
|
155
|
+
if (assetTypeStrings.length > 0) filter.assetTypes = assetTypeStrings;
|
|
156
|
+
return Object.keys(filter).length > 0 ? filter : void 0;
|
|
157
|
+
}
|
|
131
158
|
async function runOrgsList(options) {
|
|
132
159
|
const client = options.apiClient ?? createApiClient();
|
|
133
160
|
const outputFormat = options.outputFormat ?? (options.json ? "json" : "human");
|
|
134
161
|
const input = {
|
|
135
162
|
query: options.query ?? "",
|
|
136
163
|
subscriptionStatus: parseSubscriptionStatuses(options.subscriptionStatus),
|
|
137
|
-
services: buildServicesFilter(options)
|
|
164
|
+
services: buildServicesFilter(options),
|
|
165
|
+
obligatoryAdminApproval: buildObligatoryAdminApprovalFilter(options)
|
|
138
166
|
};
|
|
139
167
|
const result = await client.getUserOrgs(input);
|
|
140
168
|
const organizations = result.organizations;
|
|
@@ -145,7 +173,7 @@ async function runOrgsList(options) {
|
|
|
145
173
|
`# Organizations (${organizations.length})`,
|
|
146
174
|
"",
|
|
147
175
|
...organizations.map(
|
|
148
|
-
(org) => `- \`${org.slug}\` \u2014 ${org.name} \u2014 ${org.subscriptionStatus} \u2014 ${summarizeServices(org)}`
|
|
176
|
+
(org) => `- \`${org.slug}\` \u2014 ${org.name} \u2014 ${org.subscriptionStatus} \u2014 ${summarizeServices(org)} \u2014 admin-approval: ${summarizeObligatoryAdminApproval(org)}`
|
|
149
177
|
)
|
|
150
178
|
].join("\n"),
|
|
151
179
|
csv: toCsvRows(
|
|
@@ -160,7 +188,12 @@ async function runOrgsList(options) {
|
|
|
160
188
|
// `takedowns` is the only service with a meaningful automation flag.
|
|
161
189
|
takedownsAutomated: org.services.takedowns.automated,
|
|
162
190
|
detectionActive: org.services.detection.active,
|
|
163
|
-
darkWebMonitoringActive: org.services.darkWebMonitoring.active
|
|
191
|
+
darkWebMonitoringActive: org.services.darkWebMonitoring.active,
|
|
192
|
+
obligatoryAdminApprovalActive: org.obligatoryAdminApproval.active,
|
|
193
|
+
// Empty list + active means "applies to all asset types"; we keep
|
|
194
|
+
// the cell empty in CSV so spreadsheets render it as the natural
|
|
195
|
+
// "no narrowing" value — pair it with the active column.
|
|
196
|
+
obligatoryAdminApprovalAssetTypes: org.obligatoryAdminApproval.assetTypes.join("|")
|
|
164
197
|
}))
|
|
165
198
|
),
|
|
166
199
|
human: () => {
|
|
@@ -173,7 +206,7 @@ async function runOrgsList(options) {
|
|
|
173
206
|
const nameWidth = Math.max(...organizations.map((org) => org.name.length), 4);
|
|
174
207
|
for (const org of organizations) {
|
|
175
208
|
console.log(
|
|
176
|
-
` ${org.slug.padEnd(slugWidth)} ${org.name.padEnd(nameWidth)} ${org.subscriptionStatus.padEnd(11)} ${summarizeServices(org)}`
|
|
209
|
+
` ${org.slug.padEnd(slugWidth)} ${org.name.padEnd(nameWidth)} ${org.subscriptionStatus.padEnd(11)} ${summarizeServices(org)} admin-approval=${summarizeObligatoryAdminApproval(org)}`
|
|
177
210
|
);
|
|
178
211
|
}
|
|
179
212
|
}
|
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
readInstalledSkillVersion,
|
|
7
7
|
setupSkill,
|
|
8
8
|
uninstallSkill
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-4N2YKTJ5.js";
|
|
10
|
+
import "./chunk-6VTWWGNV.js";
|
|
11
11
|
export {
|
|
12
12
|
getBundledSkillContent,
|
|
13
13
|
getBundledSkillVersion,
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import {
|
|
2
|
+
printOutput,
|
|
3
|
+
toCsvRows
|
|
4
|
+
} from "./chunk-VFT3TD3E.js";
|
|
5
|
+
|
|
6
|
+
// src/lib/asset-types.ts
|
|
7
|
+
var ASSET_TYPES = [
|
|
8
|
+
{
|
|
9
|
+
type: "URL",
|
|
10
|
+
label: "URL",
|
|
11
|
+
description: "A full URL or domain (web page). The most common asset type for phishing sites."
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
type: "PAGE",
|
|
15
|
+
label: "Page",
|
|
16
|
+
description: "A standalone web page tracked independently of its parent URL (e.g. a hosted phishing kit deployed on a shared platform)."
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
type: "ADDRESS",
|
|
20
|
+
label: "Address",
|
|
21
|
+
description: "A blockchain address (EVM, Bitcoin, Solana, etc.) used by a threat."
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
type: "DISCORD",
|
|
25
|
+
label: "Discord",
|
|
26
|
+
description: "A Discord server invite or guild."
|
|
27
|
+
},
|
|
28
|
+
{ type: "LINKEDIN", label: "LinkedIn", description: "A LinkedIn profile or page." },
|
|
29
|
+
{ type: "TWITTER", label: "Twitter", description: "An X (formerly Twitter) account." },
|
|
30
|
+
{ type: "FACEBOOK", label: "Facebook", description: "A Facebook page or profile." },
|
|
31
|
+
{ type: "YOUTUBE", label: "YouTube", description: "A YouTube channel or video." },
|
|
32
|
+
{ type: "REDDIT", label: "Reddit", description: "A Reddit user or subreddit." },
|
|
33
|
+
{
|
|
34
|
+
type: "TELEGRAM",
|
|
35
|
+
label: "Telegram",
|
|
36
|
+
description: "A Telegram channel, group, or user."
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
type: "GOOGLE_APP_STORE",
|
|
40
|
+
label: "Google Play Store",
|
|
41
|
+
description: "An Android app on Google Play."
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
type: "APPLE_APP_STORE",
|
|
45
|
+
label: "Apple App Store",
|
|
46
|
+
description: "An iOS app on the Apple App Store."
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
type: "AMAZON_APP_STORE",
|
|
50
|
+
label: "Amazon App Store",
|
|
51
|
+
description: "An Android app on the Amazon Appstore."
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
type: "MICROSOFT_APP_STORE",
|
|
55
|
+
label: "Microsoft App Store",
|
|
56
|
+
description: "An app in the Microsoft Store."
|
|
57
|
+
},
|
|
58
|
+
{ type: "TIKTOK", label: "TikTok", description: "A TikTok account or video." },
|
|
59
|
+
{ type: "INSTAGRAM", label: "Instagram", description: "An Instagram account." },
|
|
60
|
+
{ type: "THREADS", label: "Threads", description: "A Threads (Meta) account." },
|
|
61
|
+
{ type: "MEDIUM", label: "Medium", description: "A Medium blog or post." },
|
|
62
|
+
{
|
|
63
|
+
type: "CHROME_WEB_STORE",
|
|
64
|
+
label: "Chrome Web Store",
|
|
65
|
+
description: "A Chrome browser extension."
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
type: "MOZILLA_ADDONS",
|
|
69
|
+
label: "Mozilla Firefox Addons",
|
|
70
|
+
description: "A Firefox browser add-on."
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
type: "OPERA_ADDONS",
|
|
74
|
+
label: "Opera Addons",
|
|
75
|
+
description: "An Opera browser add-on."
|
|
76
|
+
},
|
|
77
|
+
{ type: "EMAIL", label: "Email", description: "An email address." },
|
|
78
|
+
{ type: "PATREON", label: "Patreon", description: "A Patreon page." },
|
|
79
|
+
{ type: "OPENSEA", label: "OpenSea", description: "An OpenSea collection or account." },
|
|
80
|
+
{ type: "FARCASTER", label: "Farcaster", description: "A Farcaster account." },
|
|
81
|
+
{
|
|
82
|
+
type: "IPFS",
|
|
83
|
+
label: "IPFS",
|
|
84
|
+
description: "An IPFS-hosted resource (CID or gateway URL)."
|
|
85
|
+
},
|
|
86
|
+
{ type: "GOOGLE_FORM", label: "Google Form", description: "A Google Forms form." },
|
|
87
|
+
{
|
|
88
|
+
type: "WHATSAPP",
|
|
89
|
+
label: "WhatsApp",
|
|
90
|
+
description: "A WhatsApp number, group, or channel."
|
|
91
|
+
},
|
|
92
|
+
{ type: "DISCORD_USER", label: "Discord User", description: "A Discord user account." },
|
|
93
|
+
{ type: "QUORA", label: "Quora", description: "A Quora user or space." },
|
|
94
|
+
{
|
|
95
|
+
type: "GITHUB",
|
|
96
|
+
label: "GitHub",
|
|
97
|
+
description: "A GitHub account, repository, or page."
|
|
98
|
+
},
|
|
99
|
+
{ type: "TEACHABLE", label: "Teachable", description: "A Teachable course or school." },
|
|
100
|
+
{ type: "SUBSTACK", label: "Substack", description: "A Substack publication." },
|
|
101
|
+
{ type: "DEBANK", label: "Debank", description: "A Debank profile." },
|
|
102
|
+
{ type: "TAWK_TO", label: "Tawk.to Chat", description: "A Tawk.to live-chat widget." },
|
|
103
|
+
{ type: "JOTFORM", label: "Jotform", description: "A Jotform form." },
|
|
104
|
+
{ type: "PRIMAL", label: "Primal", description: "A Primal (Nostr) profile." },
|
|
105
|
+
{ type: "BLUESKY", label: "Bluesky", description: "A Bluesky account." },
|
|
106
|
+
{ type: "SNAPCHAT", label: "Snapchat", description: "A Snapchat account." },
|
|
107
|
+
{ type: "DESO", label: "DeSo", description: "A DeSo profile." },
|
|
108
|
+
{ type: "PINTEREST", label: "Pinterest", description: "A Pinterest account or board." },
|
|
109
|
+
{ type: "FLICKR", label: "Flickr", description: "A Flickr account." },
|
|
110
|
+
{ type: "GALXE", label: "Galxe", description: "A Galxe campaign or space." },
|
|
111
|
+
{ type: "VELOG", label: "Velog", description: "A Velog blog or post." },
|
|
112
|
+
{ type: "NPM", label: "npm", description: "An npm package." },
|
|
113
|
+
{ type: "PYPI", label: "PyPI", description: "A PyPI Python package." },
|
|
114
|
+
{ type: "HEX", label: "Hex", description: "A Hex Erlang/Elixir package." },
|
|
115
|
+
{ type: "DOCKER_HUB", label: "Docker Hub", description: "A Docker Hub image." },
|
|
116
|
+
{
|
|
117
|
+
type: "VOCAL_MEDIA",
|
|
118
|
+
label: "Vocal Media",
|
|
119
|
+
description: "A Vocal Media profile or story."
|
|
120
|
+
},
|
|
121
|
+
{ type: "TECKFINE", label: "Teckfine", description: "A Teckfine listing." },
|
|
122
|
+
{
|
|
123
|
+
type: "TENDERLY",
|
|
124
|
+
label: "Tenderly",
|
|
125
|
+
description: "A Tenderly dashboard or simulation."
|
|
126
|
+
},
|
|
127
|
+
{ type: "HACKMD", label: "HackMD", description: "A HackMD note." },
|
|
128
|
+
{ type: "ETSY", label: "Etsy", description: "An Etsy shop or listing." },
|
|
129
|
+
{ type: "ZAZZLE", label: "Zazzle", description: "A Zazzle shop or product." },
|
|
130
|
+
{ type: "BASENAME", label: "Basename", description: "A Base ENS (basename) record." },
|
|
131
|
+
{
|
|
132
|
+
type: "BILIBILI_TV",
|
|
133
|
+
label: "Bilibili TV",
|
|
134
|
+
description: "A Bilibili TV channel or video."
|
|
135
|
+
},
|
|
136
|
+
{ type: "VIMEO", label: "Vimeo", description: "A Vimeo video or channel." },
|
|
137
|
+
{
|
|
138
|
+
type: "DAILYMOTION",
|
|
139
|
+
label: "Dailymotion",
|
|
140
|
+
description: "A Dailymotion video or channel."
|
|
141
|
+
},
|
|
142
|
+
{ type: "PHONE_NUMBER", label: "Phone Number", description: "A phone number." },
|
|
143
|
+
{ type: "SLACK", label: "Slack", description: "A Slack workspace invite." },
|
|
144
|
+
{ type: "CALENDLY", label: "Calendly", description: "A Calendly scheduling page." },
|
|
145
|
+
{
|
|
146
|
+
type: "NGROK",
|
|
147
|
+
label: "Ngrok",
|
|
148
|
+
description: "An ngrok tunnel (often used to host short-lived phishing endpoints)."
|
|
149
|
+
},
|
|
150
|
+
{ type: "RARIBLE", label: "Rarible", description: "A Rarible collection or profile." },
|
|
151
|
+
{
|
|
152
|
+
type: "RUST_PACKAGE",
|
|
153
|
+
label: "Rust Package",
|
|
154
|
+
description: "A crates.io Rust package."
|
|
155
|
+
},
|
|
156
|
+
{ type: "FLATHUB", label: "Flathub", description: "A Flathub Linux app listing." },
|
|
157
|
+
{ type: "VIDLII", label: "VidLii", description: "A VidLii video or channel." },
|
|
158
|
+
{ type: "VEVIOZ", label: "Vevioz", description: "A Vevioz listing." },
|
|
159
|
+
{ type: "ISSUU", label: "Issuu", description: "An Issuu publication." },
|
|
160
|
+
{
|
|
161
|
+
type: "SOUNDCLOUD",
|
|
162
|
+
label: "SoundCloud",
|
|
163
|
+
description: "A SoundCloud account or track."
|
|
164
|
+
},
|
|
165
|
+
{ type: "ZAPPER", label: "Zapper", description: "A Zapper profile or bundle." },
|
|
166
|
+
{ type: "REDNOTE", label: "RedNote", description: "A RedNote (Xiaohongshu) account." },
|
|
167
|
+
{
|
|
168
|
+
type: "SAMSUNG_APP_STORE",
|
|
169
|
+
label: "Samsung Galaxy Store",
|
|
170
|
+
description: "An app on Samsung Galaxy Store."
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
type: "HUAWEI_APP_STORE",
|
|
174
|
+
label: "Huawei AppGallery",
|
|
175
|
+
description: "An app on Huawei AppGallery."
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
type: "XIAOMI_APP_STORE",
|
|
179
|
+
label: "Xiaomi GetApps",
|
|
180
|
+
description: "An app on Xiaomi GetApps."
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
type: "TENCENT_APP_STORE",
|
|
184
|
+
label: "Tencent App Store",
|
|
185
|
+
description: "An app on the Tencent App Store."
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
type: "OPPO_APP_STORE",
|
|
189
|
+
label: "OPPO App Market",
|
|
190
|
+
description: "An app on OPPO App Market."
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
type: "VIVO_APP_STORE",
|
|
194
|
+
label: "Vivo App Store",
|
|
195
|
+
description: "An app on Vivo App Store."
|
|
196
|
+
},
|
|
197
|
+
{ type: "F_DROID", label: "F-Droid", description: "An app on F-Droid." },
|
|
198
|
+
{ type: "GOOGLE_AD", label: "Google Ad", description: "A Google Ads advertisement." },
|
|
199
|
+
{ type: "BING_AD", label: "Bing Ad", description: "A Microsoft Bing advertisement." },
|
|
200
|
+
{ type: "TWITCH", label: "Twitch", description: "A Twitch channel." },
|
|
201
|
+
{ type: "BEHANCE", label: "Behance", description: "A Behance profile or project." },
|
|
202
|
+
{ type: "ZORA", label: "Zora", description: "A Zora collection or profile." },
|
|
203
|
+
{
|
|
204
|
+
type: "META_AD",
|
|
205
|
+
label: "Meta Ad",
|
|
206
|
+
description: "A Facebook/Instagram (Meta) advertisement."
|
|
207
|
+
},
|
|
208
|
+
{ type: "SIGNAL", label: "Signal", description: "A Signal group invite or contact." },
|
|
209
|
+
{ type: "DEVIANTART", label: "DeviantArt", description: "A DeviantArt profile." },
|
|
210
|
+
{ type: "BANDCAMP", label: "Bandcamp", description: "A Bandcamp page." },
|
|
211
|
+
{
|
|
212
|
+
type: "ARCHIVE_ORG",
|
|
213
|
+
label: "Archive.org",
|
|
214
|
+
description: "An Internet Archive (archive.org) snapshot \u2014 typically a Wayback Machine URL preserving a phishing page."
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
type: "FIVE_HUNDRED_PX",
|
|
218
|
+
label: "500px",
|
|
219
|
+
description: "A 500px photographer profile."
|
|
220
|
+
}
|
|
221
|
+
];
|
|
222
|
+
var ASSET_TYPE_LABELS = Object.freeze(
|
|
223
|
+
Object.fromEntries(ASSET_TYPES.map((entry) => [entry.type, entry.label]))
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
// src/commands/asset/types.ts
|
|
227
|
+
function toRow(entry) {
|
|
228
|
+
return {
|
|
229
|
+
type: entry.type,
|
|
230
|
+
label: entry.label,
|
|
231
|
+
description: entry.description ?? ""
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function runAssetTypes(options) {
|
|
235
|
+
const outputFormat = options.outputFormat ?? (options.json ? "json" : "human");
|
|
236
|
+
const rows = ASSET_TYPES.map(toRow);
|
|
237
|
+
const escapeMarkdownCell = (value) => value.replaceAll("|", "\\|");
|
|
238
|
+
printOutput({
|
|
239
|
+
outputFormat,
|
|
240
|
+
json: { assetTypes: ASSET_TYPES, count: ASSET_TYPES.length },
|
|
241
|
+
markdown: [
|
|
242
|
+
"# ChainPatrol asset types",
|
|
243
|
+
"",
|
|
244
|
+
`Total: ${ASSET_TYPES.length}`,
|
|
245
|
+
"",
|
|
246
|
+
"| Type | Label | Description |",
|
|
247
|
+
"| --- | --- | --- |",
|
|
248
|
+
...rows.map(
|
|
249
|
+
(row) => `| \`${row.type}\` | ${escapeMarkdownCell(row.label)} | ${escapeMarkdownCell(row.description)} |`
|
|
250
|
+
)
|
|
251
|
+
].join("\n"),
|
|
252
|
+
csv: toCsvRows(rows),
|
|
253
|
+
human: () => {
|
|
254
|
+
const typeColumnWidth = Math.max(...ASSET_TYPES.map((entry) => entry.type.length));
|
|
255
|
+
const labelColumnWidth = Math.max(
|
|
256
|
+
...ASSET_TYPES.map((entry) => entry.label.length)
|
|
257
|
+
);
|
|
258
|
+
console.log(`ChainPatrol asset types (${ASSET_TYPES.length})`);
|
|
259
|
+
console.log("");
|
|
260
|
+
for (const entry of ASSET_TYPES) {
|
|
261
|
+
const type = entry.type.padEnd(typeColumnWidth);
|
|
262
|
+
const label = entry.label.padEnd(labelColumnWidth);
|
|
263
|
+
const description = entry.description ? ` ${entry.description}` : "";
|
|
264
|
+
console.log(`${type} ${label}${description}`);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
export {
|
|
270
|
+
runAssetTypes
|
|
271
|
+
};
|
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.21.0",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"homepage": "https://chainpatrol.com/docs/cli",
|
|
8
8
|
"keywords": [
|