@chainpatrol/cli 0.9.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.
- package/CHANGELOG.md +15 -0
- package/README.md +14 -2
- package/dist/check-7QDINQPT.js +203 -0
- package/dist/{chunk-P4L4N5LM.js → chunk-R2DZGMGT.js} +33 -4
- package/dist/cli.js +19 -12
- package/dist/{setup-skill-DR4KGQMG.js → setup-skill-BLJLRCXL.js} +1 -1
- package/package.json +1 -1
- package/dist/check-YZRIAUOK.js +0 -85
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
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
|
+
|
|
3
18
|
## 0.9.0
|
|
4
19
|
|
|
5
20
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -45,11 +45,23 @@ chainpatrol queues snapshot --all --output csv
|
|
|
45
45
|
# look up a single asset against the ChainPatrol blocklist and external feeds
|
|
46
46
|
chainpatrol asset check https://phish.example
|
|
47
47
|
|
|
48
|
-
#
|
|
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 } })
|
|
49
59
|
chainpatrol --json asset check 0xabc123...
|
|
60
|
+
chainpatrol --json asset check a.example b.example c.example
|
|
50
61
|
|
|
51
|
-
# markdown summary
|
|
62
|
+
# markdown / csv summary tables
|
|
52
63
|
chainpatrol asset check phish.example --output markdown
|
|
64
|
+
chainpatrol asset check a.example b.example --output csv
|
|
53
65
|
```
|
|
54
66
|
|
|
55
67
|
### Detection commands
|
|
@@ -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
|
+
};
|
|
@@ -312,7 +312,7 @@ so the same background+tail pattern works without \`--json\`. Prefer
|
|
|
312
312
|
chainpatrol logout
|
|
313
313
|
\`\`\`
|
|
314
314
|
|
|
315
|
-
### \`asset check\` \u2014 Check
|
|
315
|
+
### \`asset check\` \u2014 Check one or many assets against the blocklist
|
|
316
316
|
|
|
317
317
|
Look up a URL, domain, or crypto address and return its aggregated status
|
|
318
318
|
(\`BLOCKED\`, \`ALLOWED\`, or \`UNKNOWN\`) plus a per-source breakdown
|
|
@@ -320,24 +320,53 @@ Look up a URL, domain, or crypto address and return its aggregated status
|
|
|
320
320
|
polkadot-phishing). Works whether you're authenticated via device-code
|
|
321
321
|
login or via a \`CHAINPATROL_API_KEY\` env var.
|
|
322
322
|
|
|
323
|
+
Single asset:
|
|
324
|
+
|
|
323
325
|
\`\`\`bash
|
|
324
326
|
chainpatrol asset check https://phish.example
|
|
325
327
|
chainpatrol asset check 0xabc123...
|
|
326
328
|
\`\`\`
|
|
327
329
|
|
|
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 } }\`:
|
|
330
353
|
|
|
331
354
|
\`\`\`bash
|
|
332
355
|
chainpatrol --json asset check https://phish.example
|
|
356
|
+
chainpatrol --json asset check a.example b.example c.example
|
|
333
357
|
\`\`\`
|
|
334
358
|
|
|
335
|
-
Markdown
|
|
359
|
+
Markdown / CSV are also available for sharing in docs / chat:
|
|
336
360
|
|
|
337
361
|
\`\`\`bash
|
|
338
362
|
chainpatrol asset check phish.example --output markdown
|
|
363
|
+
chainpatrol asset check a.example b.example --output csv
|
|
339
364
|
\`\`\`
|
|
340
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
|
+
|
|
341
370
|
### \`configs list\` \u2014 List detection configurations
|
|
342
371
|
|
|
343
372
|
Requires authentication and an organization slug.
|
package/dist/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
getCliVersion,
|
|
14
14
|
isSkillInstalled,
|
|
15
15
|
readInstalledSkillVersion
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-R2DZGMGT.js";
|
|
17
17
|
import "./chunk-Z76CUWSS.js";
|
|
18
18
|
import {
|
|
19
19
|
DateTime
|
|
@@ -92,18 +92,24 @@ var HELP = {
|
|
|
92
92
|
usage: "chainpatrol logout"
|
|
93
93
|
},
|
|
94
94
|
asset: {
|
|
95
|
-
description: "Check whether
|
|
96
|
-
usage: "chainpatrol asset check <content>",
|
|
95
|
+
description: "Check whether one or more assets are BLOCKED, ALLOWED, or UNKNOWN.",
|
|
96
|
+
usage: "chainpatrol asset check <content> [<content> ...]",
|
|
97
97
|
examples: [
|
|
98
98
|
"chainpatrol asset check https://phish.example",
|
|
99
|
+
"chainpatrol asset check a.example b.example c.example",
|
|
99
100
|
"chainpatrol --json asset check 0xabc123\u2026"
|
|
100
101
|
]
|
|
101
102
|
},
|
|
102
103
|
"asset check": {
|
|
103
|
-
description: "Look up
|
|
104
|
-
usage: "chainpatrol asset check <content>",
|
|
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
|
+
],
|
|
105
109
|
examples: [
|
|
106
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",
|
|
107
113
|
"chainpatrol asset check phish.example --output markdown",
|
|
108
114
|
"chainpatrol --json asset check 0xabc123\u2026"
|
|
109
115
|
]
|
|
@@ -875,11 +881,12 @@ async function main() {
|
|
|
875
881
|
}
|
|
876
882
|
case "asset": {
|
|
877
883
|
if (subcommand === "check") {
|
|
878
|
-
const
|
|
879
|
-
const
|
|
880
|
-
const
|
|
884
|
+
const positionals = cli.input.slice(2);
|
|
885
|
+
const flagAssets = parseAssetInputs();
|
|
886
|
+
const contents = [...positionals, ...flagAssets];
|
|
887
|
+
const { runAssetCheck } = await import("./check-7QDINQPT.js");
|
|
881
888
|
await runAssetCheck({
|
|
882
|
-
|
|
889
|
+
contents,
|
|
883
890
|
json: jsonMode,
|
|
884
891
|
outputFormat: cliContext.outputFormat,
|
|
885
892
|
explain: cliContext.explain
|
|
@@ -888,7 +895,7 @@ async function main() {
|
|
|
888
895
|
}
|
|
889
896
|
const hint = subcommand ? suggest(subcommand, ["check"]) : null;
|
|
890
897
|
throw new Error(
|
|
891
|
-
subcommand ? `Unknown subcommand: asset ${subcommand}${hint ? `. Did you mean "asset ${hint}"?` : ""}` : "Usage: chainpatrol asset check <content>"
|
|
898
|
+
subcommand ? `Unknown subcommand: asset ${subcommand}${hint ? `. Did you mean "asset ${hint}"?` : ""}` : "Usage: chainpatrol asset check <content> [<content> ...]"
|
|
892
899
|
);
|
|
893
900
|
}
|
|
894
901
|
case "detections": {
|
|
@@ -1189,12 +1196,12 @@ async function main() {
|
|
|
1189
1196
|
case "setup":
|
|
1190
1197
|
case "install":
|
|
1191
1198
|
case "i": {
|
|
1192
|
-
const { setupSkill } = await import("./setup-skill-
|
|
1199
|
+
const { setupSkill } = await import("./setup-skill-BLJLRCXL.js");
|
|
1193
1200
|
setupSkill({ json: jsonMode, cloud: cli.flags.cloud });
|
|
1194
1201
|
break;
|
|
1195
1202
|
}
|
|
1196
1203
|
case "uninstall": {
|
|
1197
|
-
const { uninstallSkill } = await import("./setup-skill-
|
|
1204
|
+
const { uninstallSkill } = await import("./setup-skill-BLJLRCXL.js");
|
|
1198
1205
|
uninstallSkill({ json: jsonMode });
|
|
1199
1206
|
break;
|
|
1200
1207
|
}
|
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.10.0",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"homepage": "https://chainpatrol.com/docs/cli",
|
|
8
8
|
"keywords": [
|
package/dist/check-YZRIAUOK.js
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
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
|
-
function statusLine(result) {
|
|
18
|
-
const watchTag = result.watchStatus ? ` watch=${result.watchStatus}` : "";
|
|
19
|
-
const reasonTag = result.reason ? ` reason=${result.reason}` : "";
|
|
20
|
-
return `${result.status} (source=${result.source}${reasonTag}${watchTag})`;
|
|
21
|
-
}
|
|
22
|
-
async function runAssetCheck(options) {
|
|
23
|
-
const content = options.content?.trim();
|
|
24
|
-
if (!content) {
|
|
25
|
-
throw new CliExitError(
|
|
26
|
-
"asset check requires an asset. Example: chainpatrol asset check https://example.com",
|
|
27
|
-
ExitCode.USAGE
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
const outputFormat = options.outputFormat ?? (options.json ? "json" : "human");
|
|
31
|
-
const client = options.apiClient ?? createApiClient();
|
|
32
|
-
const result = await client.assetCheck({ content });
|
|
33
|
-
printOutput({
|
|
34
|
-
outputFormat,
|
|
35
|
-
json: {
|
|
36
|
-
content,
|
|
37
|
-
...result,
|
|
38
|
-
explanation: options.explain ? "Asset check aggregates ChainPatrol records and external sources to classify a domain, URL, or crypto address as BLOCKED, ALLOWED, or UNKNOWN." : void 0
|
|
39
|
-
},
|
|
40
|
-
markdown: [
|
|
41
|
-
`# Asset Check: ${content}`,
|
|
42
|
-
"",
|
|
43
|
-
`- Status: **${result.status}**`,
|
|
44
|
-
`- Source: ${result.source}`,
|
|
45
|
-
...result.reason ? [`- Reason: ${result.reason}`] : [],
|
|
46
|
-
...result.watchStatus ? [`- Watch status: ${result.watchStatus}`] : [],
|
|
47
|
-
...result.message ? [`- Message: ${result.message}`] : [],
|
|
48
|
-
...result.code ? [`- Code: ${result.code}`] : [],
|
|
49
|
-
"",
|
|
50
|
-
"## Per-source results",
|
|
51
|
-
"",
|
|
52
|
-
...result.sources.map((entry) => `- ${entry.source}: ${entry.status}`)
|
|
53
|
-
].join("\n"),
|
|
54
|
-
csv: toCsvRows(
|
|
55
|
-
result.sources.map((entry) => ({
|
|
56
|
-
content,
|
|
57
|
-
source: entry.source,
|
|
58
|
-
status: entry.status
|
|
59
|
-
}))
|
|
60
|
-
),
|
|
61
|
-
human: () => {
|
|
62
|
-
console.log(`${content} -> ${statusLine(result)}`);
|
|
63
|
-
if (result.message) {
|
|
64
|
-
console.log(`Message: ${result.message}`);
|
|
65
|
-
}
|
|
66
|
-
if (result.code) {
|
|
67
|
-
console.log(`Code: ${result.code}`);
|
|
68
|
-
}
|
|
69
|
-
if (result.sources.length > 0) {
|
|
70
|
-
console.log("Sources:");
|
|
71
|
-
for (const entry of result.sources) {
|
|
72
|
-
console.log(` - ${entry.source}: ${entry.status}`);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
if (options.explain) {
|
|
76
|
-
console.log(
|
|
77
|
-
"Status is the aggregated verdict across ChainPatrol and external feeds; see the per-source rows for the underlying signals."
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
export {
|
|
84
|
-
runAssetCheck
|
|
85
|
-
};
|