@chainpatrol/cli 0.8.0 → 0.10.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.
Files changed (29) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +26 -0
  3. package/dist/{breakdown-DXSN7KUF.js → breakdown-63FAOVL7.js} +1 -1
  4. package/dist/check-7QDINQPT.js +203 -0
  5. package/dist/{chunk-XIHOCIYM.js → chunk-BJISZ3CY.js} +1 -1
  6. package/dist/{chunk-ZN3VMRWG.js → chunk-R2DZGMGT.js} +59 -2
  7. package/dist/{chunk-F6D645LF.js → chunk-RIKR2WFT.js} +3 -0
  8. package/dist/{chunk-IUZB3DQW.js → chunk-Z76CUWSS.js} +11 -1
  9. package/dist/cli.js +68 -24
  10. package/dist/{completions-EGQIARFC.js → completions-D6SOLU2D.js} +1 -1
  11. package/dist/{configs-update-BBENU2PG.js → configs-update-2IOSKZH5.js} +1 -1
  12. package/dist/{create-SXPAFMPT.js → create-EWS3SFCH.js} +1 -1
  13. package/dist/{drift-WJD2Z5ZB.js → drift-Q3VG3XG3.js} +1 -1
  14. package/dist/{found-4UY3IC5T.js → found-22B7RZT5.js} +1 -1
  15. package/dist/{healthcheck-XTQN64DB.js → healthcheck-C3AIMUJT.js} +1 -1
  16. package/dist/{list-BVUG6RUF.js → list-AYHDFSQG.js} +1 -1
  17. package/dist/{list-2PBVBN5K.js → list-DNRWKM5O.js} +1 -1
  18. package/dist/{list-BGI7IZ55.js → list-HFWSMLGJ.js} +2 -2
  19. package/dist/{list-6ELSECNR.js → list-IA4CSOIY.js} +1 -1
  20. package/dist/{list-IJS66PYW.js → list-SDBLGBVW.js} +1 -1
  21. package/dist/{list-json-DWHMAA6S.js → list-json-CEPGVUGF.js} +1 -1
  22. package/dist/{run-M25F7TWI.js → run-AQMJRFGL.js} +1 -1
  23. package/dist/{run-3W7LSPX2.js → run-WJGHJPXN.js} +2 -2
  24. package/dist/{run-4S244KUM.js → run-YTWNQD5X.js} +1 -1
  25. package/dist/{setup-skill-J7PZYVCE.js → setup-skill-BLJLRCXL.js} +2 -2
  26. package/dist/{snapshot-MEOOARL3.js → snapshot-C5MZWJTW.js} +1 -1
  27. package/dist/{summary-JYDAPBYX.js → summary-NQDZQEOD.js} +1 -1
  28. package/dist/{validate-RI7YKHKH.js → validate-5DVPSXJP.js} +1 -1
  29. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @chainpatrol/cli
2
2
 
3
+ ## 0.10.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 034096d: `chainpatrol asset check` now accepts multiple assets in a single
8
+ invocation — either as positional arguments
9
+ (`chainpatrol asset check a.example b.example c.example`) or via
10
+ repeated `--asset` flags. Lookups run in parallel (concurrency 10) and
11
+ the JSON output for bulk calls is
12
+ `{ results: [...], summary: { checked, blocked, allowed, unknown, errored } }`.
13
+ Single-asset JSON keeps the existing flat shape for back-compat. The
14
+ bundled `/chainpatrol` Claude Code skill is updated to call out the bulk
15
+ form so agents stop falling back to per-asset shell loops (or refusing
16
+ the request) when asked to check many domains at once.
17
+
18
+ ## 0.9.0
19
+
20
+ ### Minor Changes
21
+
22
+ - e2658e3: Add `chainpatrol asset check <content>` — look up a single URL, domain, or
23
+ crypto address against the ChainPatrol blocklist and external feeds and
24
+ return the aggregated status (`BLOCKED`, `ALLOWED`, or `UNKNOWN`) plus a
25
+ per-source breakdown. Supports `--json`, `--output markdown`, and
26
+ `--output csv` for agent/script use, and works with both device-code login
27
+ and `CHAINPATROL_API_KEY` env-var auth. The bundled `/chainpatrol` Claude
28
+ Code skill is updated to document the new command and to trigger on
29
+ phrases like "is this URL blocked" / "check this asset".
30
+
3
31
  ## 0.8.0
4
32
 
5
33
  ### Minor Changes
package/README.md CHANGED
@@ -12,6 +12,7 @@ npm install -g chainpatrol
12
12
 
13
13
  ```bash
14
14
  chainpatrol login
15
+ chainpatrol asset check https://phish.example
15
16
  chainpatrol configs list --org my-org
16
17
  chainpatrol --json configs list --org my-org
17
18
  chainpatrol detections healthcheck --org my-org --run
@@ -38,6 +39,31 @@ chainpatrol detections drift --org my-org --explain --output markdown
38
39
  chainpatrol queues snapshot --all --output csv
39
40
  ```
40
41
 
42
+ ### Asset commands
43
+
44
+ ```bash
45
+ # look up a single asset against the ChainPatrol blocklist and external feeds
46
+ chainpatrol asset check https://phish.example
47
+
48
+ # bulk: check many assets in one call (parallel, concurrency=10)
49
+ chainpatrol asset check a.example b.example c.example
50
+
51
+ # repeated --asset is equivalent to positional args
52
+ chainpatrol asset check --asset a.example --asset b.example
53
+
54
+ # pipe a file of one-domain-per-line via xargs into a single CLI call
55
+ xargs -a domains.txt chainpatrol --json asset check
56
+
57
+ # JSON output for automation (single-asset returns flat shape; bulk returns
58
+ # { results: [...], summary: { checked, blocked, allowed, unknown, errored } })
59
+ chainpatrol --json asset check 0xabc123...
60
+ chainpatrol --json asset check a.example b.example c.example
61
+
62
+ # markdown / csv summary tables
63
+ chainpatrol asset check phish.example --output markdown
64
+ chainpatrol asset check a.example b.example --output csv
65
+ ```
66
+
41
67
  ### Detection commands
42
68
 
43
69
  ```bash
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-VFT3TD3E.js";
5
5
  import {
6
6
  createApiClient
7
- } from "./chunk-F6D645LF.js";
7
+ } from "./chunk-RIKR2WFT.js";
8
8
  import "./chunk-EGWK6SRQ.js";
9
9
  import "./chunk-TFCNKBRC.js";
10
10
  import "./chunk-U73SABXK.js";
@@ -0,0 +1,203 @@
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-RIKR2WFT.js";
12
+ import "./chunk-EGWK6SRQ.js";
13
+ import "./chunk-TFCNKBRC.js";
14
+ import "./chunk-U73SABXK.js";
15
+
16
+ // src/commands/asset/check.ts
17
+ var DEFAULT_CONCURRENCY = 10;
18
+ function statusLine(result) {
19
+ const watchTag = result.watchStatus ? ` watch=${result.watchStatus}` : "";
20
+ const reasonTag = result.reason ? ` reason=${result.reason}` : "";
21
+ return `${result.status} (source=${result.source}${reasonTag}${watchTag})`;
22
+ }
23
+ async function runWithConcurrency(items, worker, concurrency) {
24
+ const results = new Array(items.length);
25
+ let cursor = 0;
26
+ const workers = new Array(Math.min(concurrency, items.length)).fill(null).map(async () => {
27
+ while (true) {
28
+ const index = cursor;
29
+ cursor += 1;
30
+ if (index >= items.length) return;
31
+ results[index] = await worker(items[index]);
32
+ }
33
+ });
34
+ await Promise.all(workers);
35
+ return results;
36
+ }
37
+ async function runAssetCheck(options) {
38
+ const contents = (options.contents ?? []).map((value) => value.trim()).filter((value) => value.length > 0);
39
+ if (contents.length === 0) {
40
+ throw new CliExitError(
41
+ "asset check requires at least one asset. Example: chainpatrol asset check https://example.com",
42
+ ExitCode.USAGE
43
+ );
44
+ }
45
+ const outputFormat = options.outputFormat ?? (options.json ? "json" : "human");
46
+ const client = options.apiClient ?? createApiClient();
47
+ const perAssetResults = await runWithConcurrency(
48
+ contents,
49
+ async (content) => {
50
+ try {
51
+ const result = await client.assetCheck({ content });
52
+ return { content, ok: true, result };
53
+ } catch (err) {
54
+ return {
55
+ content,
56
+ ok: false,
57
+ error: err instanceof Error ? err.message : String(err)
58
+ };
59
+ }
60
+ },
61
+ DEFAULT_CONCURRENCY
62
+ );
63
+ const summary = {
64
+ checked: perAssetResults.length,
65
+ blocked: perAssetResults.filter((r) => r.ok && r.result.status === "BLOCKED").length,
66
+ allowed: perAssetResults.filter((r) => r.ok && r.result.status === "ALLOWED").length,
67
+ unknown: perAssetResults.filter((r) => r.ok && r.result.status === "UNKNOWN").length,
68
+ errored: perAssetResults.filter((r) => !r.ok).length
69
+ };
70
+ const isSingle = contents.length === 1;
71
+ const jsonPayload = isSingle ? buildSingleJsonPayload(perAssetResults[0], options.explain) : {
72
+ results: perAssetResults.map(toJsonRow),
73
+ summary,
74
+ explanation: options.explain ? "Bulk asset check ran the public asset/check endpoint for each input in parallel (concurrency=10). Each row reports the aggregated ChainPatrol status plus the per-source breakdown." : void 0
75
+ };
76
+ const markdown = isSingle ? buildSingleMarkdown(perAssetResults[0]) : [
77
+ `# Asset Check (${summary.checked})`,
78
+ "",
79
+ `- Blocked: ${summary.blocked}`,
80
+ `- Allowed: ${summary.allowed}`,
81
+ `- Unknown: ${summary.unknown}`,
82
+ ...summary.errored > 0 ? [`- Errored: ${summary.errored}`] : [],
83
+ "",
84
+ "| Content | Status | Source | Reason | Watch |",
85
+ "| --- | --- | --- | --- | --- |",
86
+ ...perAssetResults.map(toMarkdownRow)
87
+ ].join("\n");
88
+ const csv = toCsvRows(perAssetResults.map(toCsvRow));
89
+ printOutput({
90
+ outputFormat,
91
+ json: jsonPayload,
92
+ markdown,
93
+ csv,
94
+ human: () => {
95
+ for (const entry of perAssetResults) {
96
+ if (entry.ok) {
97
+ console.log(`${entry.content} -> ${statusLine(entry.result)}`);
98
+ } else {
99
+ console.log(`${entry.content} -> ERROR: ${entry.error}`);
100
+ }
101
+ }
102
+ if (isSingle && perAssetResults[0].ok) {
103
+ const sources = perAssetResults[0].result.sources;
104
+ if (sources.length > 0) {
105
+ console.log("Sources:");
106
+ for (const entry of sources) {
107
+ console.log(` - ${entry.source}: ${entry.status}`);
108
+ }
109
+ }
110
+ if (perAssetResults[0].result.message) {
111
+ console.log(`Message: ${perAssetResults[0].result.message}`);
112
+ }
113
+ if (perAssetResults[0].result.code) {
114
+ console.log(`Code: ${perAssetResults[0].result.code}`);
115
+ }
116
+ } else {
117
+ console.log(
118
+ `Summary: ${summary.checked} checked \u2014 blocked=${summary.blocked} allowed=${summary.allowed} unknown=${summary.unknown}${summary.errored > 0 ? ` errored=${summary.errored}` : ""}`
119
+ );
120
+ }
121
+ if (options.explain) {
122
+ console.log(
123
+ "Status is the aggregated verdict across ChainPatrol and external feeds; see the per-source rows for the underlying signals."
124
+ );
125
+ }
126
+ }
127
+ });
128
+ if (summary.errored > 0) {
129
+ throw new CliExitError(
130
+ `asset check: ${summary.errored} of ${summary.checked} request(s) failed.`,
131
+ ExitCode.UNKNOWN
132
+ );
133
+ }
134
+ }
135
+ function buildSingleJsonPayload(entry, explain) {
136
+ if (!entry.ok) {
137
+ return {
138
+ content: entry.content,
139
+ error: entry.error,
140
+ explanation: explain ? "asset check failed for this asset. Inspect the error message and retry." : void 0
141
+ };
142
+ }
143
+ return {
144
+ content: entry.content,
145
+ ...entry.result,
146
+ explanation: explain ? "Asset check aggregates ChainPatrol records and external sources to classify a domain, URL, or crypto address as BLOCKED, ALLOWED, or UNKNOWN." : void 0
147
+ };
148
+ }
149
+ function buildSingleMarkdown(entry) {
150
+ if (!entry.ok) {
151
+ return [`# Asset Check: ${entry.content}`, "", `- Error: ${entry.error}`].join("\n");
152
+ }
153
+ const result = entry.result;
154
+ return [
155
+ `# Asset Check: ${entry.content}`,
156
+ "",
157
+ `- Status: **${result.status}**`,
158
+ `- Source: ${result.source}`,
159
+ ...result.reason ? [`- Reason: ${result.reason}`] : [],
160
+ ...result.watchStatus ? [`- Watch status: ${result.watchStatus}`] : [],
161
+ ...result.message ? [`- Message: ${result.message}`] : [],
162
+ ...result.code ? [`- Code: ${result.code}`] : [],
163
+ "",
164
+ "## Per-source results",
165
+ "",
166
+ ...result.sources.map((entry2) => `- ${entry2.source}: ${entry2.status}`)
167
+ ].join("\n");
168
+ }
169
+ function toJsonRow(entry) {
170
+ if (!entry.ok) {
171
+ return { content: entry.content, error: entry.error };
172
+ }
173
+ return { content: entry.content, ...entry.result };
174
+ }
175
+ function toMarkdownRow(entry) {
176
+ if (!entry.ok) {
177
+ return `| ${entry.content} | ERROR | \u2014 | ${entry.error.replace(/\|/g, "\\|")} | \u2014 |`;
178
+ }
179
+ const r = entry.result;
180
+ return `| ${entry.content} | ${r.status} | ${r.source} | ${r.reason ?? ""} | ${r.watchStatus ?? ""} |`;
181
+ }
182
+ function toCsvRow(entry) {
183
+ if (!entry.ok) {
184
+ return {
185
+ content: entry.content,
186
+ status: "ERROR",
187
+ source: "",
188
+ reason: entry.error,
189
+ watchStatus: ""
190
+ };
191
+ }
192
+ const r = entry.result;
193
+ return {
194
+ content: entry.content,
195
+ status: r.status,
196
+ source: r.source,
197
+ reason: r.reason ?? "",
198
+ watchStatus: r.watchStatus ?? ""
199
+ };
200
+ }
201
+ export {
202
+ runAssetCheck
203
+ };
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-F6D645LF.js";
11
+ } from "./chunk-RIKR2WFT.js";
12
12
  import {
13
13
  DateTime
14
14
  } from "./chunk-TFCNKBRC.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  installCompletions,
3
3
  uninstallCompletions
4
- } from "./chunk-IUZB3DQW.js";
4
+ } from "./chunk-Z76CUWSS.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";
@@ -196,7 +196,9 @@ description: |
196
196
  "org healthcheck", "organization health check", "audit my org",
197
197
  "what's wrong with org", "review org setup", "list orgs", "list organizations",
198
198
  "orgs with takedowns off", "automation off across orgs",
199
- "which customers have X enabled", "service toggles by org".
199
+ "which customers have X enabled", "service toggles by org",
200
+ "is this URL blocked", "is this domain blocked", "is this address blocked",
201
+ "check this asset", "asset check", "lookup asset status".
200
202
  allowed-tools:
201
203
  - Bash
202
204
  - Read
@@ -310,6 +312,61 @@ so the same background+tail pattern works without \`--json\`. Prefer
310
312
  chainpatrol logout
311
313
  \`\`\`
312
314
 
315
+ ### \`asset check\` \u2014 Check one or many assets against the blocklist
316
+
317
+ Look up a URL, domain, or crypto address and return its aggregated status
318
+ (\`BLOCKED\`, \`ALLOWED\`, or \`UNKNOWN\`) plus a per-source breakdown
319
+ (ChainPatrol + external feeds like eth-phishing-detect, phishfort, seal,
320
+ polkadot-phishing). Works whether you're authenticated via device-code
321
+ login or via a \`CHAINPATROL_API_KEY\` env var.
322
+
323
+ Single asset:
324
+
325
+ \`\`\`bash
326
+ chainpatrol asset check https://phish.example
327
+ chainpatrol asset check 0xabc123...
328
+ \`\`\`
329
+
330
+ #### Bulk checks (preferred for >1 asset)
331
+
332
+ Pass multiple assets in a single invocation \u2014 the CLI runs them in
333
+ parallel (concurrency 10) and returns one row per asset. **Do this
334
+ instead of looping the CLI in a shell \`for\` loop**: one process, one
335
+ auth handshake, parallel HTTP. Use either positional args or repeated
336
+ \`--asset\`:
337
+
338
+ \`\`\`bash
339
+ # positional form
340
+ chainpatrol asset check a.example b.example c.example
341
+
342
+ # repeated --asset (handy when content has spaces or special chars)
343
+ chainpatrol asset check --asset a.example --asset b.example
344
+
345
+ # from a file of one-asset-per-line (use xargs to splat into one call)
346
+ xargs -a domains.txt chainpatrol asset check
347
+ \`\`\`
348
+
349
+ JSON mode is the agent-friendly default \u2014 single-asset JSON keeps the
350
+ flat \`{ content, status, source, reason?, sources[], watchStatus? }\`
351
+ shape; multi-asset JSON returns \`{ results: [...], summary: { checked,
352
+ blocked, allowed, unknown, errored } }\`:
353
+
354
+ \`\`\`bash
355
+ chainpatrol --json asset check https://phish.example
356
+ chainpatrol --json asset check a.example b.example c.example
357
+ \`\`\`
358
+
359
+ Markdown / CSV are also available for sharing in docs / chat:
360
+
361
+ \`\`\`bash
362
+ chainpatrol asset check phish.example --output markdown
363
+ chainpatrol asset check a.example b.example --output csv
364
+ \`\`\`
365
+
366
+ If any individual lookup fails, the CLI still prints results for the
367
+ successful ones, then exits non-zero so failures aren't silently
368
+ swallowed.
369
+
313
370
  ### \`configs list\` \u2014 List detection configurations
314
371
 
315
372
  Requires authentication and an organization slug.
@@ -95,6 +95,9 @@ function createApiClient(options) {
95
95
  return await res.json();
96
96
  }
97
97
  return {
98
+ assetCheck(input) {
99
+ return request("/asset/check", input);
100
+ },
98
101
  listDetectionConfigs(slug) {
99
102
  return request("/detection/configs/list", { slug });
100
103
  },
@@ -16,6 +16,7 @@ _chainpatrol() {
16
16
  commands=(
17
17
  'login:Authenticate with ChainPatrol'
18
18
  'logout:Clear stored credentials'
19
+ 'asset:Check asset status against ChainPatrol'
19
20
  'configs:Manage detection configs'
20
21
  'detections:Validate and run detection configs'
21
22
  'metrics:Query organization metrics'
@@ -56,6 +57,11 @@ _chainpatrol() {
56
57
  _arguments -s $global_flags
57
58
  elif (( CURRENT == 3 )); then
58
59
  case "\${words[2]}" in
60
+ asset)
61
+ local -a asset_subcommands
62
+ asset_subcommands=('check:Check asset status against ChainPatrol')
63
+ _describe 'subcommand' asset_subcommands
64
+ ;;
59
65
  configs)
60
66
  local -a subcommands
61
67
  subcommands=('list:List detection configurations')
@@ -118,13 +124,17 @@ var BASH_COMPLETION = `_chainpatrol() {
118
124
  COMPREPLY=()
119
125
  cur="\${COMP_WORDS[COMP_CWORD]}"
120
126
  prev="\${COMP_WORDS[COMP_CWORD-1]}"
121
- commands="login logout configs detections metrics reports queues presets setup uninstall completions help"
127
+ commands="login logout asset configs detections metrics reports queues presets setup uninstall completions help"
122
128
 
123
129
  case "\${prev}" in
124
130
  chainpatrol)
125
131
  COMPREPLY=( $(compgen -W "\${commands}" -- "\${cur}") )
126
132
  return 0
127
133
  ;;
134
+ asset)
135
+ COMPREPLY=( $(compgen -W "check" -- "\${cur}") )
136
+ return 0
137
+ ;;
128
138
  configs)
129
139
  COMPREPLY=( $(compgen -W "list" -- "\${cur}") )
130
140
  return 0
package/dist/cli.js CHANGED
@@ -13,8 +13,8 @@ import {
13
13
  getCliVersion,
14
14
  isSkillInstalled,
15
15
  readInstalledSkillVersion
16
- } from "./chunk-ZN3VMRWG.js";
17
- import "./chunk-IUZB3DQW.js";
16
+ } from "./chunk-R2DZGMGT.js";
17
+ import "./chunk-Z76CUWSS.js";
18
18
  import {
19
19
  DateTime
20
20
  } from "./chunk-TFCNKBRC.js";
@@ -91,6 +91,29 @@ var HELP = {
91
91
  description: "Clear stored credentials from this machine.",
92
92
  usage: "chainpatrol logout"
93
93
  },
94
+ asset: {
95
+ description: "Check whether one or more assets are BLOCKED, ALLOWED, or UNKNOWN.",
96
+ usage: "chainpatrol asset check <content> [<content> ...]",
97
+ examples: [
98
+ "chainpatrol asset check https://phish.example",
99
+ "chainpatrol asset check a.example b.example c.example",
100
+ "chainpatrol --json asset check 0xabc123\u2026"
101
+ ]
102
+ },
103
+ "asset check": {
104
+ description: "Look up one or more assets (URL, domain, or crypto address) against the ChainPatrol blocklist and external feeds. Returns the aggregated status plus a per-source breakdown. Multiple assets can be passed as positional arguments or via repeated --asset; they are checked in parallel (concurrency 10).",
105
+ usage: "chainpatrol asset check <content> [<content> ...]",
106
+ options: [
107
+ "--asset <content> Asset content (repeatable; alternative to positional args)"
108
+ ],
109
+ examples: [
110
+ "chainpatrol asset check https://phish.example",
111
+ "chainpatrol asset check a.example b.example c.example --json",
112
+ "chainpatrol asset check --asset a.example --asset b.example --output csv",
113
+ "chainpatrol asset check phish.example --output markdown",
114
+ "chainpatrol --json asset check 0xabc123\u2026"
115
+ ]
116
+ },
94
117
  configs: {
95
118
  description: "Manage detection configs for an organization.",
96
119
  usage: "chainpatrol configs <list>",
@@ -391,6 +414,7 @@ function getTopLevelHelp() {
391
414
  " Commands",
392
415
  " login Authenticate with ChainPatrol",
393
416
  " logout Clear stored credentials",
417
+ " asset Check asset status against ChainPatrol",
394
418
  " configs Manage detection configs",
395
419
  " detections Validate, run, update detection configs",
396
420
  " healthchecks List and run organization healthchecks",
@@ -561,6 +585,7 @@ function printVersionMessages(messages) {
561
585
  var COMMANDS = [
562
586
  "login",
563
587
  "logout",
588
+ "asset",
564
589
  "configs",
565
590
  "detections",
566
591
  "healthchecks",
@@ -754,12 +779,12 @@ function parseAttachmentUrls() {
754
779
  }
755
780
  async function handleConfigsList(org) {
756
781
  if (jsonMode) {
757
- const { listConfigsJson } = await import("./list-json-DWHMAA6S.js");
782
+ const { listConfigsJson } = await import("./list-json-CEPGVUGF.js");
758
783
  await listConfigsJson({ org });
759
784
  return;
760
785
  }
761
786
  const { render } = await import("ink");
762
- const { default: ConfigsList } = await import("./list-6ELSECNR.js");
787
+ const { default: ConfigsList } = await import("./list-IA4CSOIY.js");
763
788
  const { default: React } = await import("react");
764
789
  render(React.createElement(ConfigsList, { org }));
765
790
  }
@@ -854,10 +879,29 @@ async function main() {
854
879
  }
855
880
  throw new Error("Usage: chainpatrol configs list");
856
881
  }
882
+ case "asset": {
883
+ if (subcommand === "check") {
884
+ const positionals = cli.input.slice(2);
885
+ const flagAssets = parseAssetInputs();
886
+ const contents = [...positionals, ...flagAssets];
887
+ const { runAssetCheck } = await import("./check-7QDINQPT.js");
888
+ await runAssetCheck({
889
+ contents,
890
+ json: jsonMode,
891
+ outputFormat: cliContext.outputFormat,
892
+ explain: cliContext.explain
893
+ });
894
+ break;
895
+ }
896
+ const hint = subcommand ? suggest(subcommand, ["check"]) : null;
897
+ throw new Error(
898
+ subcommand ? `Unknown subcommand: asset ${subcommand}${hint ? `. Did you mean "asset ${hint}"?` : ""}` : "Usage: chainpatrol asset check <content> [<content> ...]"
899
+ );
900
+ }
857
901
  case "detections": {
858
902
  const org = await resolveOrg();
859
903
  if (subcommand === "healthcheck") {
860
- const { runDetectionsHealthcheck } = await import("./healthcheck-XTQN64DB.js");
904
+ const { runDetectionsHealthcheck } = await import("./healthcheck-C3AIMUJT.js");
861
905
  await runDetectionsHealthcheck({
862
906
  org,
863
907
  source: cli.flags.source,
@@ -872,7 +916,7 @@ async function main() {
872
916
  break;
873
917
  }
874
918
  if (subcommand === "validate") {
875
- const { runDetectionsValidate } = await import("./validate-RI7YKHKH.js");
919
+ const { runDetectionsValidate } = await import("./validate-5DVPSXJP.js");
876
920
  await runDetectionsValidate({
877
921
  org,
878
922
  source: cli.flags.source,
@@ -887,7 +931,7 @@ async function main() {
887
931
  break;
888
932
  }
889
933
  if (subcommand === "drift") {
890
- const { runDetectionsDrift } = await import("./drift-WJD2Z5ZB.js");
934
+ const { runDetectionsDrift } = await import("./drift-Q3VG3XG3.js");
891
935
  await runDetectionsDrift({
892
936
  org,
893
937
  source: cli.flags.source,
@@ -901,7 +945,7 @@ async function main() {
901
945
  break;
902
946
  }
903
947
  if (subcommand === "run") {
904
- const { runDetectionsRun } = await import("./run-4S244KUM.js");
948
+ const { runDetectionsRun } = await import("./run-YTWNQD5X.js");
905
949
  await runDetectionsRun({
906
950
  org,
907
951
  configId: cli.flags.configId,
@@ -920,7 +964,7 @@ async function main() {
920
964
  break;
921
965
  }
922
966
  if (action === "run") {
923
- const { runDetectionsRun } = await import("./run-4S244KUM.js");
967
+ const { runDetectionsRun } = await import("./run-YTWNQD5X.js");
924
968
  await runDetectionsRun({
925
969
  org,
926
970
  configId: cli.flags.configId,
@@ -938,7 +982,7 @@ async function main() {
938
982
  throw new Error("detections configs update requires --config-id");
939
983
  }
940
984
  const configPatch = getConfigPatchFromSetFlags();
941
- const { runDetectionsConfigsUpdate } = await import("./configs-update-BBENU2PG.js");
985
+ const { runDetectionsConfigsUpdate } = await import("./configs-update-2IOSKZH5.js");
942
986
  await runDetectionsConfigsUpdate({
943
987
  org,
944
988
  configId: cli.flags.configId,
@@ -965,7 +1009,7 @@ async function main() {
965
1009
  case "metrics": {
966
1010
  const org = await resolveOrg();
967
1011
  if (subcommand === "summary") {
968
- const { runMetricsSummary } = await import("./summary-JYDAPBYX.js");
1012
+ const { runMetricsSummary } = await import("./summary-NQDZQEOD.js");
969
1013
  await runMetricsSummary({
970
1014
  org,
971
1015
  from: cli.flags.from,
@@ -977,7 +1021,7 @@ async function main() {
977
1021
  break;
978
1022
  }
979
1023
  if (subcommand === "found") {
980
- const { runMetricsFound } = await import("./found-4UY3IC5T.js");
1024
+ const { runMetricsFound } = await import("./found-22B7RZT5.js");
981
1025
  await runMetricsFound({
982
1026
  org,
983
1027
  from: cli.flags.from,
@@ -994,7 +1038,7 @@ async function main() {
994
1038
  if (!by || !["day", "type", "brand"].includes(by)) {
995
1039
  throw new Error("metrics breakdown requires --by <day|type|brand>");
996
1040
  }
997
- const { runMetricsBreakdown } = await import("./breakdown-DXSN7KUF.js");
1041
+ const { runMetricsBreakdown } = await import("./breakdown-63FAOVL7.js");
998
1042
  await runMetricsBreakdown({
999
1043
  org,
1000
1044
  by,
@@ -1014,7 +1058,7 @@ async function main() {
1014
1058
  case "reports": {
1015
1059
  if (subcommand === "list") {
1016
1060
  const org = await resolveOrg();
1017
- const { runReportsList } = await import("./list-BVUG6RUF.js");
1061
+ const { runReportsList } = await import("./list-AYHDFSQG.js");
1018
1062
  await runReportsList({
1019
1063
  org,
1020
1064
  limit: cli.flags.limit,
@@ -1030,7 +1074,7 @@ async function main() {
1030
1074
  }
1031
1075
  if (subcommand === "create") {
1032
1076
  const org = await tryResolveOrg();
1033
- const { runReportsCreate } = await import("./create-SXPAFMPT.js");
1077
+ const { runReportsCreate } = await import("./create-EWS3SFCH.js");
1034
1078
  await runReportsCreate({
1035
1079
  org,
1036
1080
  title: cli.flags.title,
@@ -1054,7 +1098,7 @@ async function main() {
1054
1098
  }
1055
1099
  case "queues": {
1056
1100
  if (subcommand === "snapshot") {
1057
- const { runQueuesSnapshot } = await import("./snapshot-MEOOARL3.js");
1101
+ const { runQueuesSnapshot } = await import("./snapshot-C5MZWJTW.js");
1058
1102
  await runQueuesSnapshot({
1059
1103
  org: cli.flags.org,
1060
1104
  all: cli.flags.all,
@@ -1072,7 +1116,7 @@ async function main() {
1072
1116
  }
1073
1117
  case "orgs": {
1074
1118
  if (subcommand === "list") {
1075
- const { runOrgsList } = await import("./list-IJS66PYW.js");
1119
+ const { runOrgsList } = await import("./list-SDBLGBVW.js");
1076
1120
  await runOrgsList({
1077
1121
  query: cli.flags.query,
1078
1122
  subscriptionStatus: cli.flags.subscriptionStatus,
@@ -1092,7 +1136,7 @@ async function main() {
1092
1136
  }
1093
1137
  case "healthchecks": {
1094
1138
  if (subcommand === "list") {
1095
- const { runHealthchecksList } = await import("./list-2PBVBN5K.js");
1139
+ const { runHealthchecksList } = await import("./list-DNRWKM5O.js");
1096
1140
  await runHealthchecksList({
1097
1141
  json: jsonMode,
1098
1142
  outputFormat: cliContext.outputFormat
@@ -1106,7 +1150,7 @@ async function main() {
1106
1150
  thresholds.minResults = cli.flags.minResults;
1107
1151
  if (cli.flags.lookbackHours !== void 0)
1108
1152
  thresholds.lookbackHours = cli.flags.lookbackHours;
1109
- const { runHealthchecksRun } = await import("./run-M25F7TWI.js");
1153
+ const { runHealthchecksRun } = await import("./run-AQMJRFGL.js");
1110
1154
  await runHealthchecksRun({
1111
1155
  org,
1112
1156
  id: action,
@@ -1124,7 +1168,7 @@ async function main() {
1124
1168
  }
1125
1169
  case "presets": {
1126
1170
  if (subcommand === "list") {
1127
- const { runPresetsList } = await import("./list-BGI7IZ55.js");
1171
+ const { runPresetsList } = await import("./list-HFWSMLGJ.js");
1128
1172
  await runPresetsList({ outputFormat: cliContext.outputFormat });
1129
1173
  break;
1130
1174
  }
@@ -1135,7 +1179,7 @@ async function main() {
1135
1179
  );
1136
1180
  }
1137
1181
  const org = await resolveOrg();
1138
- const { runPresetsRun } = await import("./run-3W7LSPX2.js");
1182
+ const { runPresetsRun } = await import("./run-WJGHJPXN.js");
1139
1183
  await runPresetsRun({
1140
1184
  presetId: action,
1141
1185
  org,
@@ -1152,17 +1196,17 @@ async function main() {
1152
1196
  case "setup":
1153
1197
  case "install":
1154
1198
  case "i": {
1155
- const { setupSkill } = await import("./setup-skill-J7PZYVCE.js");
1199
+ const { setupSkill } = await import("./setup-skill-BLJLRCXL.js");
1156
1200
  setupSkill({ json: jsonMode, cloud: cli.flags.cloud });
1157
1201
  break;
1158
1202
  }
1159
1203
  case "uninstall": {
1160
- const { uninstallSkill } = await import("./setup-skill-J7PZYVCE.js");
1204
+ const { uninstallSkill } = await import("./setup-skill-BLJLRCXL.js");
1161
1205
  uninstallSkill({ json: jsonMode });
1162
1206
  break;
1163
1207
  }
1164
1208
  case "completions": {
1165
- const { printCompletions } = await import("./completions-EGQIARFC.js");
1209
+ const { printCompletions } = await import("./completions-D6SOLU2D.js");
1166
1210
  printCompletions(subcommand);
1167
1211
  break;
1168
1212
  }
@@ -3,7 +3,7 @@ import {
3
3
  installCompletions,
4
4
  printCompletions,
5
5
  uninstallCompletions
6
- } from "./chunk-IUZB3DQW.js";
6
+ } from "./chunk-Z76CUWSS.js";
7
7
  export {
8
8
  getCompletionScript,
9
9
  installCompletions,
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-VFT3TD3E.js";
8
8
  import {
9
9
  createApiClient
10
- } from "./chunk-F6D645LF.js";
10
+ } from "./chunk-RIKR2WFT.js";
11
11
  import "./chunk-EGWK6SRQ.js";
12
12
  import "./chunk-TFCNKBRC.js";
13
13
  import "./chunk-U73SABXK.js";
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-F6D645LF.js";
11
+ } from "./chunk-RIKR2WFT.js";
12
12
  import "./chunk-EGWK6SRQ.js";
13
13
  import "./chunk-TFCNKBRC.js";
14
14
  import "./chunk-U73SABXK.js";
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-F6D645LF.js";
11
+ } from "./chunk-RIKR2WFT.js";
12
12
  import "./chunk-EGWK6SRQ.js";
13
13
  import "./chunk-TFCNKBRC.js";
14
14
  import "./chunk-U73SABXK.js";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-VFT3TD3E.js";
5
5
  import {
6
6
  createApiClient
7
- } from "./chunk-F6D645LF.js";
7
+ } from "./chunk-RIKR2WFT.js";
8
8
  import "./chunk-EGWK6SRQ.js";
9
9
  import {
10
10
  DateTime
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-F6D645LF.js";
11
+ } from "./chunk-RIKR2WFT.js";
12
12
  import "./chunk-EGWK6SRQ.js";
13
13
  import "./chunk-TFCNKBRC.js";
14
14
  import "./chunk-U73SABXK.js";
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-F6D645LF.js";
11
+ } from "./chunk-RIKR2WFT.js";
12
12
  import "./chunk-EGWK6SRQ.js";
13
13
  import "./chunk-TFCNKBRC.js";
14
14
  import "./chunk-U73SABXK.js";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-VFT3TD3E.js";
5
5
  import {
6
6
  createApiClient
7
- } from "./chunk-F6D645LF.js";
7
+ } from "./chunk-RIKR2WFT.js";
8
8
  import "./chunk-EGWK6SRQ.js";
9
9
  import "./chunk-TFCNKBRC.js";
10
10
  import "./chunk-U73SABXK.js";
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  PRESETS
3
- } from "./chunk-XIHOCIYM.js";
3
+ } from "./chunk-BJISZ3CY.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-F6D645LF.js";
9
+ import "./chunk-RIKR2WFT.js";
10
10
  import "./chunk-EGWK6SRQ.js";
11
11
  import "./chunk-TFCNKBRC.js";
12
12
  import "./chunk-U73SABXK.js";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-JCMWDZYY.js";
5
5
  import {
6
6
  createApiClient
7
- } from "./chunk-F6D645LF.js";
7
+ } from "./chunk-RIKR2WFT.js";
8
8
  import {
9
9
  AuthCorruptedError,
10
10
  AuthExpiredError,
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-F6D645LF.js";
11
+ } from "./chunk-RIKR2WFT.js";
12
12
  import "./chunk-EGWK6SRQ.js";
13
13
  import "./chunk-TFCNKBRC.js";
14
14
  import "./chunk-U73SABXK.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createApiClient
3
- } from "./chunk-F6D645LF.js";
3
+ } from "./chunk-RIKR2WFT.js";
4
4
  import "./chunk-EGWK6SRQ.js";
5
5
  import "./chunk-TFCNKBRC.js";
6
6
  import "./chunk-U73SABXK.js";
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-F6D645LF.js";
11
+ } from "./chunk-RIKR2WFT.js";
12
12
  import "./chunk-EGWK6SRQ.js";
13
13
  import "./chunk-TFCNKBRC.js";
14
14
  import "./chunk-U73SABXK.js";
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  getPresetDefinition,
3
3
  runPreset
4
- } from "./chunk-XIHOCIYM.js";
4
+ } from "./chunk-BJISZ3CY.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-F6D645LF.js";
10
+ import "./chunk-RIKR2WFT.js";
11
11
  import "./chunk-EGWK6SRQ.js";
12
12
  import "./chunk-TFCNKBRC.js";
13
13
  import "./chunk-U73SABXK.js";
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-F6D645LF.js";
11
+ } from "./chunk-RIKR2WFT.js";
12
12
  import "./chunk-EGWK6SRQ.js";
13
13
  import "./chunk-TFCNKBRC.js";
14
14
  import "./chunk-U73SABXK.js";
@@ -6,8 +6,8 @@ import {
6
6
  readInstalledSkillVersion,
7
7
  setupSkill,
8
8
  uninstallSkill
9
- } from "./chunk-ZN3VMRWG.js";
10
- import "./chunk-IUZB3DQW.js";
9
+ } from "./chunk-R2DZGMGT.js";
10
+ import "./chunk-Z76CUWSS.js";
11
11
  export {
12
12
  getBundledSkillContent,
13
13
  getBundledSkillVersion,
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-F6D645LF.js";
11
+ } from "./chunk-RIKR2WFT.js";
12
12
  import "./chunk-EGWK6SRQ.js";
13
13
  import "./chunk-TFCNKBRC.js";
14
14
  import "./chunk-U73SABXK.js";
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-VFT3TD3E.js";
5
5
  import {
6
6
  createApiClient
7
- } from "./chunk-F6D645LF.js";
7
+ } from "./chunk-RIKR2WFT.js";
8
8
  import "./chunk-EGWK6SRQ.js";
9
9
  import "./chunk-TFCNKBRC.js";
10
10
  import "./chunk-U73SABXK.js";
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-F6D645LF.js";
11
+ } from "./chunk-RIKR2WFT.js";
12
12
  import "./chunk-EGWK6SRQ.js";
13
13
  import "./chunk-TFCNKBRC.js";
14
14
  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.8.0",
5
+ "version": "0.10.0",
6
6
  "license": "UNLICENSED",
7
7
  "homepage": "https://chainpatrol.com/docs/cli",
8
8
  "keywords": [