@chainpatrol/cli 0.19.0 → 0.20.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 CHANGED
@@ -1,5 +1,28 @@
1
1
  # @chainpatrol/cli
2
2
 
3
+ ## 0.20.0
4
+
5
+ ### Minor Changes
6
+
7
+ - e63d269: Add `chainpatrol asset types` — list every supported `AssetType` enum
8
+ value with its human-readable label and a short description.
9
+
10
+ The mapping (e.g. `ARCHIVE_ORG` → "Archive.org" / Wayback snapshot,
11
+ `PAGE` → "Page" / standalone web page tracked independently of its
12
+ parent URL, `FIVE_HUNDRED_PX` → "500px") ships bundled with the CLI as
13
+ a static map, so the command works without auth or a network round
14
+ trip. Output is available in human, JSON, markdown, and CSV formats —
15
+ useful when an agent or script needs to translate enum ↔ display name,
16
+ validate a user-supplied `--asset-type` value, or enumerate the
17
+ available types before constructing a filter for `asset list`,
18
+ `threats list`, `takedowns list`, `detections list`, `reports list`,
19
+ or `orgs assets list`.
20
+
21
+ The Claude Code skill is updated to point at the new command whenever
22
+ a user asks "what is `ARCHIVE_ORG`?", "what does `PAGE` mean?", or
23
+ "what asset types does ChainPatrol support?". Shell completions and
24
+ top-level/per-command help text are updated accordingly.
25
+
3
26
  ## 0.19.0
4
27
 
5
28
  ### Minor Changes
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  installCompletions,
3
3
  uninstallCompletions
4
- } from "./chunk-NQT77IB7.js";
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";
@@ -201,6 +201,9 @@ description: |
201
201
  "which customers have X enabled", "service toggles by org",
202
202
  "is this URL blocked", "is this domain blocked", "is this address blocked",
203
203
  "check this asset", "asset check", "lookup asset status",
204
+ "what is ARCHIVE_ORG", "what does PAGE mean", "list asset types",
205
+ "supported asset types", "asset type mapping", "asset type enum",
206
+ "what asset types are there", "human readable asset type",
204
207
  "how many takedowns", "takedowns in the last", "threats taken down",
205
208
  "across all clients", "across all customers", "across all orgs",
206
209
  "across all brands", "company-wide", "total takedowns", "total threats",
@@ -383,6 +386,29 @@ If any individual lookup fails, the CLI still prints results for the
383
386
  successful ones, then exits non-zero so failures aren't silently
384
387
  swallowed.
385
388
 
389
+ ### \`asset types\` \u2014 List every supported asset type and what it means
390
+
391
+ When a user asks "what is \`ARCHIVE_ORG\`?", "what does \`PAGE\` mean?",
392
+ or "what asset types does ChainPatrol support?" \u2014 don't guess. Run:
393
+
394
+ \`\`\`bash
395
+ chainpatrol asset types
396
+ chainpatrol --json asset types
397
+ \`\`\`
398
+
399
+ The mapping is bundled with the CLI (no API or auth required), so this
400
+ is safe to run anywhere. Each row is \`{ type, label, description }\`:
401
+ \`type\` is the canonical enum value used by every \`--asset-type\` flag
402
+ (\`asset list\`, \`threats list\`, \`takedowns list\`, \`detections list\`,
403
+ \`reports list\`, \`orgs assets list\`); \`label\` is the human-friendly
404
+ display name (\`ARCHIVE_ORG\` \u2192 \`Archive.org\`, \`PAGE\` \u2192 \`Page\`,
405
+ \`FIVE_HUNDRED_PX\` \u2192 \`500px\`); \`description\` is a one-line note for
406
+ unobvious entries.
407
+
408
+ Use this whenever you need to translate between enum and display name,
409
+ validate that a type the user mentioned is real, or enumerate options
410
+ before constructing a filter.
411
+
386
412
  ### \`configs list\` \u2014 List detection configurations
387
413
 
388
414
  Requires authentication and an organization 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-UDGJEN4M.js";
17
- import "./chunk-NQT77IB7.js";
16
+ } from "./chunk-3LJTWYT6.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 or list blocked/allowed assets across the global ChainPatrol blocklist.",
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 in the global ChainPatrol blocklist",
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",
@@ -1183,9 +1194,17 @@ async function main() {
1183
1194
  });
1184
1195
  break;
1185
1196
  }
1186
- const hint = subcommand ? suggest(subcommand, ["check", "list"]) : null;
1197
+ if (subcommand === "types") {
1198
+ const { runAssetTypes } = await import("./types-PTMFLYUV.js");
1199
+ runAssetTypes({
1200
+ json: jsonMode,
1201
+ outputFormat: cliContext.outputFormat
1202
+ });
1203
+ break;
1204
+ }
1205
+ const hint = subcommand ? suggest(subcommand, ["check", "list", "types"]) : null;
1187
1206
  throw new Error(
1188
- subcommand ? `Unknown subcommand: asset ${subcommand}${hint ? `. Did you mean "asset ${hint}"?` : ""}` : "Usage: chainpatrol asset <check|list>"
1207
+ subcommand ? `Unknown subcommand: asset ${subcommand}${hint ? `. Did you mean "asset ${hint}"?` : ""}` : "Usage: chainpatrol asset <check|list|types>"
1189
1208
  );
1190
1209
  }
1191
1210
  case "detections": {
@@ -1686,17 +1705,17 @@ async function main() {
1686
1705
  case "setup":
1687
1706
  case "install":
1688
1707
  case "i": {
1689
- const { setupSkill } = await import("./setup-skill-F7437RT3.js");
1708
+ const { setupSkill } = await import("./setup-skill-A36WQLMU.js");
1690
1709
  setupSkill({ json: jsonMode, cloud: cli.flags.cloud });
1691
1710
  break;
1692
1711
  }
1693
1712
  case "uninstall": {
1694
- const { uninstallSkill } = await import("./setup-skill-F7437RT3.js");
1713
+ const { uninstallSkill } = await import("./setup-skill-A36WQLMU.js");
1695
1714
  uninstallSkill({ json: jsonMode });
1696
1715
  break;
1697
1716
  }
1698
1717
  case "completions": {
1699
- const { printCompletions } = await import("./completions-6C6KG5DH.js");
1718
+ const { printCompletions } = await import("./completions-ILC76OX5.js");
1700
1719
  printCompletions(subcommand);
1701
1720
  break;
1702
1721
  }
@@ -3,7 +3,7 @@ import {
3
3
  installCompletions,
4
4
  printCompletions,
5
5
  uninstallCompletions
6
- } from "./chunk-NQT77IB7.js";
6
+ } from "./chunk-6VTWWGNV.js";
7
7
  export {
8
8
  getCompletionScript,
9
9
  installCompletions,
@@ -6,8 +6,8 @@ import {
6
6
  readInstalledSkillVersion,
7
7
  setupSkill,
8
8
  uninstallSkill
9
- } from "./chunk-UDGJEN4M.js";
10
- import "./chunk-NQT77IB7.js";
9
+ } from "./chunk-3LJTWYT6.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.19.0",
5
+ "version": "0.20.0",
6
6
  "license": "UNLICENSED",
7
7
  "homepage": "https://chainpatrol.com/docs/cli",
8
8
  "keywords": [