@chainpatrol/cli 0.22.0 → 0.23.1

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 (37) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/{breakdown-3LJBT3JQ.js → breakdown-XA6UUD3T.js} +1 -1
  3. package/dist/{check-G64UQCEL.js → check-NQZPNAUF.js} +1 -1
  4. package/dist/{chunk-2JZAPTY6.js → chunk-DVNTYW7L.js} +1 -1
  5. package/dist/{chunk-O7TMOF4W.js → chunk-GOQL7UCG.js} +3 -0
  6. package/dist/cli.js +77 -39
  7. package/dist/{configs-update-MVX7Q5NW.js → configs-update-VDZVBTIF.js} +1 -1
  8. package/dist/{create-ANCO4FXB.js → create-DGCWT2YJ.js} +1 -1
  9. package/dist/{drift-SHPMEJDU.js → drift-YZHCIQ5O.js} +1 -1
  10. package/dist/{found-OPL4HWOW.js → found-6JAOLM6M.js} +1 -1
  11. package/dist/{get-GTACVCLE.js → get-RC75EJFC.js} +1 -1
  12. package/dist/{healthcheck-QNLFKAXM.js → healthcheck-7YWSOY6Y.js} +1 -1
  13. package/dist/{list-X4Z3CPO7.js → list-4HX2R7HU.js} +1 -1
  14. package/dist/{list-XSIXAHOG.js → list-4KIZLIVN.js} +1 -1
  15. package/dist/{list-AQ7E23T3.js → list-EJDWUF6W.js} +1 -1
  16. package/dist/{list-WPPNX7G3.js → list-H7NVUX42.js} +1 -1
  17. package/dist/{list-FJBWSGTD.js → list-IDR7WH5J.js} +2 -2
  18. package/dist/{list-SWHKM5R6.js → list-Q3MMBL4Y.js} +1 -1
  19. package/dist/{list-JK4SRMPL.js → list-SRVNEUHC.js} +1 -1
  20. package/dist/{list-FVFF4VW3.js → list-UDT5MDQZ.js} +1 -1
  21. package/dist/{list-QHEFB4KE.js → list-WQFDRXHD.js} +1 -1
  22. package/dist/{list-Q5PRMAN5.js → list-YNQ6VSYV.js} +1 -1
  23. package/dist/{list-4VKMEKZS.js → list-ZARZ72DG.js} +1 -1
  24. package/dist/{list-FWXQUOCP.js → list-ZBC53OYA.js} +1 -1
  25. package/dist/{list-json-B5L5PXKH.js → list-json-7FDHNRYP.js} +1 -1
  26. package/dist/{organization-SOMHMGTM.js → organization-NEZA6JX2.js} +1 -1
  27. package/dist/{run-J5TQ2YC2.js → run-5QV3YD7V.js} +1 -1
  28. package/dist/{run-RV6P2OCD.js → run-CCVJIK7L.js} +1 -1
  29. package/dist/{run-YAAMSWKK.js → run-JLTNFOJK.js} +2 -2
  30. package/dist/{search-FQUR75WR.js → search-JXJLBV43.js} +1 -1
  31. package/dist/search-ZXTJPVM6.js +221 -0
  32. package/dist/{snapshot-2GDJMN3L.js → snapshot-NYOLPGRW.js} +1 -1
  33. package/dist/{summary-LF53KXRR.js → summary-FE6ROSOO.js} +1 -1
  34. package/dist/{types-PTMFLYUV.js → types-M6QMFNUS.js} +2 -1
  35. package/dist/{validate-UYKOMUEI.js → validate-RPQEEQ36.js} +1 -1
  36. package/dist/{whoami-OYOG63BX.js → whoami-ZIWZCBGI.js} +1 -1
  37. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @chainpatrol/cli
2
2
 
3
+ ## 0.23.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 0f1d7d1: Fix `asset search` bulk lookups by ID. The `--id` (and `--asset`) flags are
8
+ documented and handled as repeatable for bulk lookup, but meow rejected the
9
+ second occurrence with `The flag --id can only be set once.`. Mark both flags
10
+ `isMultiple` so `chainpatrol asset search --id 1 --id 2 --id 3` works as
11
+ advertised instead of erroring out.
12
+
13
+ ## 0.23.0
14
+
15
+ ### Minor Changes
16
+
17
+ - 689e094: Adds `chainpatrol asset search` command for looking up assets by content or by numeric ID. Supports bulk ID lookup via repeated `--id` flags in a single API call. Server-side work in @chainpatrol/external-trpc adds `assetIds` array support to the `/asset/search` endpoint.
18
+
3
19
  ## 0.22.0
4
20
 
5
21
  ### Minor Changes
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-VFT3TD3E.js";
8
8
  import {
9
9
  createApiClient
10
- } from "./chunk-O7TMOF4W.js";
10
+ } from "./chunk-GOQL7UCG.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-O7TMOF4W.js";
11
+ } from "./chunk-GOQL7UCG.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-O7TMOF4W.js";
11
+ } from "./chunk-GOQL7UCG.js";
12
12
  import {
13
13
  DateTime
14
14
  } from "./chunk-TFCNKBRC.js";
@@ -184,6 +184,9 @@ function createApiClient(options) {
184
184
  assetCheck(input) {
185
185
  return request("/asset/check", input);
186
186
  },
187
+ assetSearch(input) {
188
+ return request("/asset/search", input);
189
+ },
187
190
  listDetectionConfigs(slug) {
188
191
  return request("/detection/configs/list", { slug });
189
192
  },
package/dist/cli.js CHANGED
@@ -92,10 +92,11 @@ var HELP = {
92
92
  usage: "chainpatrol logout"
93
93
  },
94
94
  asset: {
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>",
95
+ description: "Check asset status, search assets by content or ID, list blocked/allowed assets across the global ChainPatrol blocklist, or list every supported asset type.",
96
+ usage: "chainpatrol asset <check|list|search|types>",
97
97
  examples: [
98
98
  "chainpatrol asset check https://phish.example",
99
+ "chainpatrol asset search --id 12345",
99
100
  "chainpatrol asset list --asset-type URL --from 2026-05-01",
100
101
  "chainpatrol asset types",
101
102
  "chainpatrol --json asset check 0xabc123\u2026"
@@ -142,6 +143,21 @@ var HELP = {
142
143
  "chainpatrol --json asset check 0xabc123\u2026"
143
144
  ]
144
145
  },
146
+ "asset search": {
147
+ description: "Search for assets by content or by numeric ID. Returns detailed asset information including status, associated reports, takedown details, and which platforms have consumed (blocked) the asset. Supports bulk lookup by passing multiple --id flags. Unlike `asset check` (which queries the public blocklist aggregation), `asset search` queries the internal asset database directly and returns richer context.",
148
+ usage: "chainpatrol asset search [<content> ...] [--id <id> ...]",
149
+ options: [
150
+ "--id <number> Asset ID (repeatable for bulk lookup)",
151
+ "--asset <content> Asset content (repeatable; alternative to positional args)"
152
+ ],
153
+ examples: [
154
+ "chainpatrol asset search https://phish.example",
155
+ "chainpatrol asset search --id 4175269",
156
+ "chainpatrol asset search --id 4175269 --id 4144496 --id 4642520",
157
+ "chainpatrol --json asset search --id 4175269 --id 4144496 --id 4642520",
158
+ "chainpatrol asset search --id 12345 --output markdown"
159
+ ]
160
+ },
145
161
  configs: {
146
162
  description: "Manage detection configs for an organization.",
147
163
  usage: "chainpatrol configs <list>",
@@ -651,7 +667,7 @@ function getTopLevelHelp() {
651
667
  " login Authenticate with ChainPatrol",
652
668
  " logout Clear stored credentials",
653
669
  " whoami Show the current authenticated identity",
654
- " asset Check or list assets, or list supported asset types",
670
+ " asset Check, search, or list assets, or list supported asset types",
655
671
  " configs Manage detection configs",
656
672
  " detections Validate, run, list, update detection configs and results",
657
673
  " healthchecks List and run organization healthchecks",
@@ -905,7 +921,7 @@ ${getTopLevelHelp()}
905
921
  description: { type: "string" },
906
922
  cron: { type: "string" },
907
923
  mergeConfig: { type: "boolean", default: true },
908
- asset: { type: "string" },
924
+ asset: { type: "string", isMultiple: true },
909
925
  limit: { type: "number" },
910
926
  cursor: { type: "number" },
911
927
  status: { type: "string" },
@@ -961,7 +977,8 @@ ${getTopLevelHelp()}
961
977
  quiet: { type: "boolean", default: false, shortFlag: "q" },
962
978
  noInput: { type: "boolean", default: false },
963
979
  noColor: { type: "boolean", default: false },
964
- cloud: { type: "boolean", default: false }
980
+ cloud: { type: "boolean", default: false },
981
+ id: { type: "string", isMultiple: true }
965
982
  }
966
983
  });
967
984
  var [command, subcommand, action] = cli.input;
@@ -1076,12 +1093,12 @@ function parseAttachmentUrls() {
1076
1093
  }
1077
1094
  async function handleConfigsList(org) {
1078
1095
  if (jsonMode) {
1079
- const { listConfigsJson } = await import("./list-json-B5L5PXKH.js");
1096
+ const { listConfigsJson } = await import("./list-json-7FDHNRYP.js");
1080
1097
  await listConfigsJson({ org });
1081
1098
  return;
1082
1099
  }
1083
1100
  const { render } = await import("ink");
1084
- const { default: ConfigsList } = await import("./list-X4Z3CPO7.js");
1101
+ const { default: ConfigsList } = await import("./list-4HX2R7HU.js");
1085
1102
  const { default: React } = await import("react");
1086
1103
  render(React.createElement(ConfigsList, { org }));
1087
1104
  }
@@ -1181,7 +1198,7 @@ async function main() {
1181
1198
  const positionals = cli.input.slice(2);
1182
1199
  const flagAssets = parseAssetInputs();
1183
1200
  const contents = [...positionals, ...flagAssets];
1184
- const { runAssetCheck } = await import("./check-G64UQCEL.js");
1201
+ const { runAssetCheck } = await import("./check-NQZPNAUF.js");
1185
1202
  await runAssetCheck({
1186
1203
  contents,
1187
1204
  json: jsonMode,
@@ -1191,7 +1208,7 @@ async function main() {
1191
1208
  break;
1192
1209
  }
1193
1210
  if (subcommand === "list") {
1194
- const { runAssetList } = await import("./list-XSIXAHOG.js");
1211
+ const { runAssetList } = await import("./list-4KIZLIVN.js");
1195
1212
  await runAssetList({
1196
1213
  type: cli.flags.type ?? cli.flags.assetType,
1197
1214
  status: cli.flags.assetStatus ?? cli.flags.status,
@@ -1204,23 +1221,44 @@ async function main() {
1204
1221
  });
1205
1222
  break;
1206
1223
  }
1224
+ if (subcommand === "search") {
1225
+ const positionals = cli.input.slice(2);
1226
+ const flagAssets = parseAssetInputs();
1227
+ const contents = [...positionals, ...flagAssets];
1228
+ const rawIds = getRepeatedFlag("id");
1229
+ const ids = rawIds.map((v) => {
1230
+ const n = Number(v);
1231
+ if (!Number.isInteger(n) || n <= 0) {
1232
+ throw new Error(`Invalid asset ID: ${v}. IDs must be positive integers.`);
1233
+ }
1234
+ return n;
1235
+ });
1236
+ const { runAssetSearch } = await import("./search-ZXTJPVM6.js");
1237
+ await runAssetSearch({
1238
+ contents: contents.length > 0 ? contents : void 0,
1239
+ ids: ids.length > 0 ? ids : void 0,
1240
+ json: jsonMode,
1241
+ outputFormat: cliContext.outputFormat
1242
+ });
1243
+ break;
1244
+ }
1207
1245
  if (subcommand === "types") {
1208
- const { runAssetTypes } = await import("./types-PTMFLYUV.js");
1246
+ const { runAssetTypes } = await import("./types-M6QMFNUS.js");
1209
1247
  runAssetTypes({
1210
1248
  json: jsonMode,
1211
1249
  outputFormat: cliContext.outputFormat
1212
1250
  });
1213
1251
  break;
1214
1252
  }
1215
- const hint = subcommand ? suggest(subcommand, ["check", "list", "types"]) : null;
1253
+ const hint = subcommand ? suggest(subcommand, ["check", "list", "search", "types"]) : null;
1216
1254
  throw new Error(
1217
- subcommand ? `Unknown subcommand: asset ${subcommand}${hint ? `. Did you mean "asset ${hint}"?` : ""}` : "Usage: chainpatrol asset <check|list|types>"
1255
+ subcommand ? `Unknown subcommand: asset ${subcommand}${hint ? `. Did you mean "asset ${hint}"?` : ""}` : "Usage: chainpatrol asset <check|list|search|types>"
1218
1256
  );
1219
1257
  }
1220
1258
  case "detections": {
1221
1259
  const org = await resolveOrg();
1222
1260
  if (subcommand === "healthcheck") {
1223
- const { runDetectionsHealthcheck } = await import("./healthcheck-QNLFKAXM.js");
1261
+ const { runDetectionsHealthcheck } = await import("./healthcheck-7YWSOY6Y.js");
1224
1262
  await runDetectionsHealthcheck({
1225
1263
  org,
1226
1264
  source: cli.flags.source,
@@ -1235,7 +1273,7 @@ async function main() {
1235
1273
  break;
1236
1274
  }
1237
1275
  if (subcommand === "validate") {
1238
- const { runDetectionsValidate } = await import("./validate-UYKOMUEI.js");
1276
+ const { runDetectionsValidate } = await import("./validate-RPQEEQ36.js");
1239
1277
  await runDetectionsValidate({
1240
1278
  org,
1241
1279
  source: cli.flags.source,
@@ -1250,7 +1288,7 @@ async function main() {
1250
1288
  break;
1251
1289
  }
1252
1290
  if (subcommand === "drift") {
1253
- const { runDetectionsDrift } = await import("./drift-SHPMEJDU.js");
1291
+ const { runDetectionsDrift } = await import("./drift-YZHCIQ5O.js");
1254
1292
  await runDetectionsDrift({
1255
1293
  org,
1256
1294
  source: cli.flags.source,
@@ -1264,7 +1302,7 @@ async function main() {
1264
1302
  break;
1265
1303
  }
1266
1304
  if (subcommand === "run") {
1267
- const { runDetectionsRun } = await import("./run-RV6P2OCD.js");
1305
+ const { runDetectionsRun } = await import("./run-CCVJIK7L.js");
1268
1306
  await runDetectionsRun({
1269
1307
  org,
1270
1308
  configId: cli.flags.configId,
@@ -1278,7 +1316,7 @@ async function main() {
1278
1316
  break;
1279
1317
  }
1280
1318
  if (subcommand === "list") {
1281
- const { runDetectionsList } = await import("./list-SWHKM5R6.js");
1319
+ const { runDetectionsList } = await import("./list-Q3MMBL4Y.js");
1282
1320
  await runDetectionsList({
1283
1321
  org,
1284
1322
  cursor: cli.flags.cursor,
@@ -1307,7 +1345,7 @@ async function main() {
1307
1345
  break;
1308
1346
  }
1309
1347
  if (action === "run") {
1310
- const { runDetectionsRun } = await import("./run-RV6P2OCD.js");
1348
+ const { runDetectionsRun } = await import("./run-CCVJIK7L.js");
1311
1349
  await runDetectionsRun({
1312
1350
  org,
1313
1351
  configId: cli.flags.configId,
@@ -1325,7 +1363,7 @@ async function main() {
1325
1363
  throw new Error("detections configs update requires --config-id");
1326
1364
  }
1327
1365
  const configPatch = getConfigPatchFromSetFlags();
1328
- const { runDetectionsConfigsUpdate } = await import("./configs-update-MVX7Q5NW.js");
1366
+ const { runDetectionsConfigsUpdate } = await import("./configs-update-VDZVBTIF.js");
1329
1367
  await runDetectionsConfigsUpdate({
1330
1368
  org,
1331
1369
  configId: cli.flags.configId,
@@ -1361,7 +1399,7 @@ async function main() {
1361
1399
  const slugs = parseCsvList(cli.flags.slugs);
1362
1400
  const allMyOrgs = cli.flags.allMyOrgs;
1363
1401
  const org2 = slugs && slugs.length > 0 || allMyOrgs ? void 0 : await tryResolveOrg();
1364
- const { runMetricsOrganization } = await import("./organization-SOMHMGTM.js");
1402
+ const { runMetricsOrganization } = await import("./organization-NEZA6JX2.js");
1365
1403
  await runMetricsOrganization({
1366
1404
  org: org2,
1367
1405
  slugs,
@@ -1380,7 +1418,7 @@ async function main() {
1380
1418
  }
1381
1419
  const org = await resolveOrg();
1382
1420
  if (subcommand === "summary") {
1383
- const { runMetricsSummary } = await import("./summary-LF53KXRR.js");
1421
+ const { runMetricsSummary } = await import("./summary-FE6ROSOO.js");
1384
1422
  await runMetricsSummary({
1385
1423
  org,
1386
1424
  from: cli.flags.from,
@@ -1393,7 +1431,7 @@ async function main() {
1393
1431
  break;
1394
1432
  }
1395
1433
  if (subcommand === "found") {
1396
- const { runMetricsFound } = await import("./found-OPL4HWOW.js");
1434
+ const { runMetricsFound } = await import("./found-6JAOLM6M.js");
1397
1435
  await runMetricsFound({
1398
1436
  org,
1399
1437
  from: cli.flags.from,
@@ -1410,7 +1448,7 @@ async function main() {
1410
1448
  if (!by || !["day", "type", "brand"].includes(by)) {
1411
1449
  throw new Error("metrics breakdown requires --by <day|type|brand>");
1412
1450
  }
1413
- const { runMetricsBreakdown } = await import("./breakdown-3LJBT3JQ.js");
1451
+ const { runMetricsBreakdown } = await import("./breakdown-XA6UUD3T.js");
1414
1452
  await runMetricsBreakdown({
1415
1453
  org,
1416
1454
  by,
@@ -1431,7 +1469,7 @@ async function main() {
1431
1469
  case "reports": {
1432
1470
  if (subcommand === "list") {
1433
1471
  const org = await resolveOrg();
1434
- const { runReportsList } = await import("./list-WPPNX7G3.js");
1472
+ const { runReportsList } = await import("./list-H7NVUX42.js");
1435
1473
  await runReportsList({
1436
1474
  org,
1437
1475
  limit: cli.flags.limit,
@@ -1459,7 +1497,7 @@ async function main() {
1459
1497
  }
1460
1498
  if (subcommand === "create") {
1461
1499
  const org = await tryResolveOrg();
1462
- const { runReportsCreate } = await import("./create-ANCO4FXB.js");
1500
+ const { runReportsCreate } = await import("./create-DGCWT2YJ.js");
1463
1501
  await runReportsCreate({
1464
1502
  org,
1465
1503
  title: cli.flags.title,
@@ -1480,7 +1518,7 @@ async function main() {
1480
1518
  const positionals = cli.input.slice(2);
1481
1519
  const flagAssets = parseAssetInputs();
1482
1520
  const assetContents = [...positionals, ...flagAssets];
1483
- const { runReportsSearch } = await import("./search-FQUR75WR.js");
1521
+ const { runReportsSearch } = await import("./search-JXJLBV43.js");
1484
1522
  await runReportsSearch({
1485
1523
  assetContents,
1486
1524
  reportedByCustomer: cli.flags.reportedByCustomer,
@@ -1496,7 +1534,7 @@ async function main() {
1496
1534
  }
1497
1535
  case "threats": {
1498
1536
  if (subcommand === "list") {
1499
- const { runThreatsList } = await import("./list-Q5PRMAN5.js");
1537
+ const { runThreatsList } = await import("./list-YNQ6VSYV.js");
1500
1538
  await runThreatsList({
1501
1539
  query: cli.flags.query,
1502
1540
  from: cli.flags.from,
@@ -1519,7 +1557,7 @@ async function main() {
1519
1557
  case "takedowns": {
1520
1558
  if (subcommand === "list") {
1521
1559
  const org = await tryResolveOrg();
1522
- const { runTakedownsList } = await import("./list-FWXQUOCP.js");
1560
+ const { runTakedownsList } = await import("./list-ZBC53OYA.js");
1523
1561
  await runTakedownsList({
1524
1562
  org,
1525
1563
  query: cli.flags.query,
@@ -1550,7 +1588,7 @@ async function main() {
1550
1588
  }
1551
1589
  case "queues": {
1552
1590
  if (subcommand === "snapshot") {
1553
- const { runQueuesSnapshot } = await import("./snapshot-2GDJMN3L.js");
1591
+ const { runQueuesSnapshot } = await import("./snapshot-NYOLPGRW.js");
1554
1592
  await runQueuesSnapshot({
1555
1593
  org: cli.flags.org,
1556
1594
  all: cli.flags.all,
@@ -1568,7 +1606,7 @@ async function main() {
1568
1606
  }
1569
1607
  case "orgs": {
1570
1608
  if (subcommand === "list") {
1571
- const { runOrgsList } = await import("./list-JK4SRMPL.js");
1609
+ const { runOrgsList } = await import("./list-SRVNEUHC.js");
1572
1610
  await runOrgsList({
1573
1611
  query: cli.flags.query,
1574
1612
  subscriptionStatus: cli.flags.subscriptionStatus,
@@ -1590,7 +1628,7 @@ async function main() {
1590
1628
  if (subcommand === "get") {
1591
1629
  const positionalSlug = action;
1592
1630
  const slug = positionalSlug ?? await tryResolveOrg();
1593
- const { runOrgsGet } = await import("./get-GTACVCLE.js");
1631
+ const { runOrgsGet } = await import("./get-RC75EJFC.js");
1594
1632
  await runOrgsGet({
1595
1633
  slug,
1596
1634
  json: jsonMode,
@@ -1600,7 +1638,7 @@ async function main() {
1600
1638
  }
1601
1639
  if (subcommand === "assets") {
1602
1640
  if (action === "list") {
1603
- const { runOrgsAssetsList } = await import("./list-QHEFB4KE.js");
1641
+ const { runOrgsAssetsList } = await import("./list-WQFDRXHD.js");
1604
1642
  await runOrgsAssetsList({
1605
1643
  type: cli.flags.type ?? cli.flags.assetType,
1606
1644
  groupId: cli.flags.groupId,
@@ -1616,7 +1654,7 @@ async function main() {
1616
1654
  }
1617
1655
  if (subcommand === "asset-groups") {
1618
1656
  if (action === "list") {
1619
- const { runOrgsAssetGroupsList } = await import("./list-FVFF4VW3.js");
1657
+ const { runOrgsAssetGroupsList } = await import("./list-UDT5MDQZ.js");
1620
1658
  await runOrgsAssetGroupsList({
1621
1659
  json: jsonMode,
1622
1660
  outputFormat: cliContext.outputFormat
@@ -1638,7 +1676,7 @@ async function main() {
1638
1676
  "brands list --type must be ORGANIZATION or INDIVIDUAL (case-insensitive)."
1639
1677
  );
1640
1678
  }
1641
- const { runBrandsList } = await import("./list-4VKMEKZS.js");
1679
+ const { runBrandsList } = await import("./list-ZARZ72DG.js");
1642
1680
  await runBrandsList({
1643
1681
  type: rawType,
1644
1682
  json: jsonMode,
@@ -1652,7 +1690,7 @@ async function main() {
1652
1690
  );
1653
1691
  }
1654
1692
  case "whoami": {
1655
- const { runWhoami } = await import("./whoami-OYOG63BX.js");
1693
+ const { runWhoami } = await import("./whoami-ZIWZCBGI.js");
1656
1694
  await runWhoami({
1657
1695
  json: jsonMode,
1658
1696
  outputFormat: cliContext.outputFormat
@@ -1661,7 +1699,7 @@ async function main() {
1661
1699
  }
1662
1700
  case "healthchecks": {
1663
1701
  if (subcommand === "list") {
1664
- const { runHealthchecksList } = await import("./list-AQ7E23T3.js");
1702
+ const { runHealthchecksList } = await import("./list-EJDWUF6W.js");
1665
1703
  await runHealthchecksList({
1666
1704
  json: jsonMode,
1667
1705
  outputFormat: cliContext.outputFormat
@@ -1675,7 +1713,7 @@ async function main() {
1675
1713
  thresholds.minResults = cli.flags.minResults;
1676
1714
  if (cli.flags.lookbackHours !== void 0)
1677
1715
  thresholds.lookbackHours = cli.flags.lookbackHours;
1678
- const { runHealthchecksRun } = await import("./run-J5TQ2YC2.js");
1716
+ const { runHealthchecksRun } = await import("./run-5QV3YD7V.js");
1679
1717
  await runHealthchecksRun({
1680
1718
  org,
1681
1719
  id: action,
@@ -1693,7 +1731,7 @@ async function main() {
1693
1731
  }
1694
1732
  case "presets": {
1695
1733
  if (subcommand === "list") {
1696
- const { runPresetsList } = await import("./list-FJBWSGTD.js");
1734
+ const { runPresetsList } = await import("./list-IDR7WH5J.js");
1697
1735
  await runPresetsList({ outputFormat: cliContext.outputFormat });
1698
1736
  break;
1699
1737
  }
@@ -1704,7 +1742,7 @@ async function main() {
1704
1742
  );
1705
1743
  }
1706
1744
  const org = await resolveOrg();
1707
- const { runPresetsRun } = await import("./run-YAAMSWKK.js");
1745
+ const { runPresetsRun } = await import("./run-JLTNFOJK.js");
1708
1746
  await runPresetsRun({
1709
1747
  presetId: action,
1710
1748
  org,
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-VFT3TD3E.js";
8
8
  import {
9
9
  createApiClient
10
- } from "./chunk-O7TMOF4W.js";
10
+ } from "./chunk-GOQL7UCG.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-O7TMOF4W.js";
11
+ } from "./chunk-GOQL7UCG.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-O7TMOF4W.js";
11
+ } from "./chunk-GOQL7UCG.js";
12
12
  import "./chunk-EGWK6SRQ.js";
13
13
  import "./chunk-TFCNKBRC.js";
14
14
  import "./chunk-U73SABXK.js";
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-VFT3TD3E.js";
8
8
  import {
9
9
  createApiClient
10
- } from "./chunk-O7TMOF4W.js";
10
+ } from "./chunk-GOQL7UCG.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-O7TMOF4W.js";
11
+ } from "./chunk-GOQL7UCG.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-O7TMOF4W.js";
11
+ } from "./chunk-GOQL7UCG.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-JCMWDZYY.js";
5
5
  import {
6
6
  createApiClient
7
- } from "./chunk-O7TMOF4W.js";
7
+ } from "./chunk-GOQL7UCG.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-O7TMOF4W.js";
11
+ } from "./chunk-GOQL7UCG.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-O7TMOF4W.js";
7
+ } from "./chunk-GOQL7UCG.js";
8
8
  import "./chunk-EGWK6SRQ.js";
9
9
  import "./chunk-TFCNKBRC.js";
10
10
  import "./chunk-U73SABXK.js";
@@ -10,7 +10,7 @@ import {
10
10
  REPORT_REVIEW_DECISIONS,
11
11
  REPORT_STATUSES,
12
12
  createApiClient
13
- } from "./chunk-O7TMOF4W.js";
13
+ } from "./chunk-GOQL7UCG.js";
14
14
  import "./chunk-EGWK6SRQ.js";
15
15
  import "./chunk-TFCNKBRC.js";
16
16
  import "./chunk-U73SABXK.js";
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  PRESETS
3
- } from "./chunk-2JZAPTY6.js";
3
+ } from "./chunk-DVNTYW7L.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-O7TMOF4W.js";
9
+ import "./chunk-GOQL7UCG.js";
10
10
  import "./chunk-EGWK6SRQ.js";
11
11
  import "./chunk-TFCNKBRC.js";
12
12
  import "./chunk-U73SABXK.js";
@@ -12,7 +12,7 @@ import {
12
12
  LIVENESS_FILTER_VALUES,
13
13
  WATCHLIST_FILTER_VALUES,
14
14
  createApiClient
15
- } from "./chunk-O7TMOF4W.js";
15
+ } from "./chunk-GOQL7UCG.js";
16
16
  import "./chunk-EGWK6SRQ.js";
17
17
  import "./chunk-TFCNKBRC.js";
18
18
  import "./chunk-U73SABXK.js";
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-O7TMOF4W.js";
11
+ } from "./chunk-GOQL7UCG.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-O7TMOF4W.js";
7
+ } from "./chunk-GOQL7UCG.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-O7TMOF4W.js";
11
+ } from "./chunk-GOQL7UCG.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-O7TMOF4W.js";
11
+ } from "./chunk-GOQL7UCG.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-O7TMOF4W.js";
7
+ } from "./chunk-GOQL7UCG.js";
8
8
  import "./chunk-EGWK6SRQ.js";
9
9
  import "./chunk-TFCNKBRC.js";
10
10
  import "./chunk-U73SABXK.js";
@@ -11,7 +11,7 @@ import {
11
11
  TAKEDOWN_SORT_KEYS,
12
12
  TAKEDOWN_STATUSES,
13
13
  createApiClient
14
- } from "./chunk-O7TMOF4W.js";
14
+ } from "./chunk-GOQL7UCG.js";
15
15
  import "./chunk-EGWK6SRQ.js";
16
16
  import "./chunk-TFCNKBRC.js";
17
17
  import "./chunk-U73SABXK.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createApiClient
3
- } from "./chunk-O7TMOF4W.js";
3
+ } from "./chunk-GOQL7UCG.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
  import {
9
9
  ORGANIZATION_METRICS_INCLUDE_FIELDS,
10
10
  createApiClient
11
- } from "./chunk-O7TMOF4W.js";
11
+ } from "./chunk-GOQL7UCG.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-O7TMOF4W.js";
11
+ } from "./chunk-GOQL7UCG.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-O7TMOF4W.js";
11
+ } from "./chunk-GOQL7UCG.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-2JZAPTY6.js";
4
+ } from "./chunk-DVNTYW7L.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-O7TMOF4W.js";
10
+ import "./chunk-GOQL7UCG.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-O7TMOF4W.js";
11
+ } from "./chunk-GOQL7UCG.js";
12
12
  import "./chunk-EGWK6SRQ.js";
13
13
  import "./chunk-TFCNKBRC.js";
14
14
  import "./chunk-U73SABXK.js";
@@ -0,0 +1,221 @@
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-GOQL7UCG.js";
12
+ import "./chunk-EGWK6SRQ.js";
13
+ import "./chunk-TFCNKBRC.js";
14
+ import "./chunk-U73SABXK.js";
15
+
16
+ // src/commands/asset/search.ts
17
+ function formatAssetRow(item) {
18
+ if (!item.asset) {
19
+ return " (not found)";
20
+ }
21
+ const a = item.asset;
22
+ const lines = [
23
+ ` [${a.status}] ${a.content} (id=${a.id}, type=${a.type}, watch=${a.watchStatus})`
24
+ ];
25
+ if (item.reports.length > 0) {
26
+ lines.push(` Reports: ${item.reports.length}`);
27
+ }
28
+ if (item.takedown) {
29
+ lines.push(
30
+ ` Takedown: ${item.takedown.status} (${item.takedown.tasks.length} task(s))`
31
+ );
32
+ }
33
+ if (item.blockedBy.length > 0) {
34
+ lines.push(` Blocked by: ${item.blockedBy.map((b) => b.consumer).join(", ")}`);
35
+ }
36
+ return lines.join("\n");
37
+ }
38
+ function toMarkdownRow(item, label) {
39
+ if (!item.asset) {
40
+ return `| ${label ?? "unknown"} | \u2014 | \u2014 | \u2014 | not found |`;
41
+ }
42
+ const a = item.asset;
43
+ return `| ${a.id} | ${a.content} | ${a.type} | ${a.status} | ${a.watchStatus} |`;
44
+ }
45
+ function toCsvRow(item, label) {
46
+ if (!item.asset) {
47
+ return {
48
+ id: label ?? "",
49
+ content: label ?? "",
50
+ type: "",
51
+ status: "NOT_FOUND",
52
+ watchStatus: "",
53
+ reports: 0,
54
+ takedownStatus: "",
55
+ blockedByCount: 0
56
+ };
57
+ }
58
+ const a = item.asset;
59
+ return {
60
+ id: a.id,
61
+ content: a.content,
62
+ type: a.type,
63
+ status: a.status,
64
+ watchStatus: a.watchStatus,
65
+ reports: item.reports.length,
66
+ takedownStatus: item.takedown?.status ?? "",
67
+ blockedByCount: item.blockedBy.length
68
+ };
69
+ }
70
+ async function runAssetSearch(options) {
71
+ const contents = (options.contents ?? []).map((v) => v.trim()).filter((v) => v.length > 0);
72
+ const ids = options.ids ?? [];
73
+ if (contents.length === 0 && ids.length === 0) {
74
+ throw new CliExitError(
75
+ "asset search requires at least one asset content or --id. Example: chainpatrol asset search https://example.com or chainpatrol asset search --id 12345",
76
+ ExitCode.USAGE
77
+ );
78
+ }
79
+ if (contents.length > 0 && ids.length > 0) {
80
+ throw new CliExitError(
81
+ "asset search does not support mixing content and --id in the same call. Use one or the other.",
82
+ ExitCode.USAGE
83
+ );
84
+ }
85
+ const outputFormat = options.outputFormat ?? (options.json ? "json" : "human");
86
+ const client = options.apiClient ?? createApiClient();
87
+ let items;
88
+ let labels = [];
89
+ if (ids.length > 0) {
90
+ labels = ids.map((id) => `ID ${id}`);
91
+ const result = await client.assetSearch({ assetIds: ids });
92
+ items = result.results ?? [result];
93
+ } else if (contents.length === 1) {
94
+ labels = [contents[0]];
95
+ const result = await client.assetSearch({ content: contents[0] });
96
+ items = [result];
97
+ } else {
98
+ labels = contents;
99
+ const settled = await Promise.allSettled(
100
+ contents.map((content) => client.assetSearch({ content }))
101
+ );
102
+ let errored = 0;
103
+ items = settled.map((r, i) => {
104
+ if (r.status === "fulfilled") return r.value;
105
+ errored += 1;
106
+ console.error(
107
+ `Error searching ${contents[i]}: ${r.reason instanceof Error ? r.reason.message : String(r.reason)}`
108
+ );
109
+ return { asset: null, reports: [], takedown: null, blockedBy: [] };
110
+ });
111
+ if (errored === contents.length) {
112
+ throw new CliExitError(
113
+ `asset search: all ${errored} request(s) failed.`,
114
+ ExitCode.UNKNOWN
115
+ );
116
+ }
117
+ }
118
+ const found = items.filter((i) => i.asset !== null).length;
119
+ const notFound = items.length - found;
120
+ const jsonPayload = items.length === 1 ? items[0] : {
121
+ results: items,
122
+ summary: { total: items.length, found, notFound }
123
+ };
124
+ const markdown = items.length === 1 && items[0].asset ? buildSingleMarkdown(items[0]) : [
125
+ `# Asset Search (${items.length})`,
126
+ "",
127
+ `- Found: ${found}`,
128
+ `- Not found: ${notFound}`,
129
+ "",
130
+ "| ID | Content | Type | Status | Watch |",
131
+ "| --- | --- | --- | --- | --- |",
132
+ ...items.map((item, i) => toMarkdownRow(item, labels[i]))
133
+ ].join("\n");
134
+ const csv = toCsvRows(items.map((item, i) => toCsvRow(item, labels[i])));
135
+ printOutput({
136
+ outputFormat,
137
+ json: jsonPayload,
138
+ markdown,
139
+ csv,
140
+ human: () => {
141
+ if (items.length === 1) {
142
+ const item = items[0];
143
+ if (!item.asset) {
144
+ console.log(`${labels[0] ?? "Asset"} not found.`);
145
+ return;
146
+ }
147
+ console.log(formatAssetRow(item));
148
+ if (item.reports.length > 0) {
149
+ console.log(" Reports:");
150
+ for (const r of item.reports) {
151
+ console.log(
152
+ ` #${r.id} [${r.status}] ${r.title ?? "(untitled)"} \u2014 ${r.createdAt}`
153
+ );
154
+ }
155
+ }
156
+ if (item.takedown) {
157
+ console.log(` Takedown #${item.takedown.id} [${item.takedown.status}]`);
158
+ for (const t of item.takedown.tasks) {
159
+ console.log(
160
+ ` Task #${t.id} [${t.status}] ${t.takedownProvider?.name ?? "unknown provider"}`
161
+ );
162
+ }
163
+ }
164
+ return;
165
+ }
166
+ console.log(
167
+ `Asset Search \u2014 ${found} found, ${notFound} not found (${items.length} total)`
168
+ );
169
+ for (let i = 0; i < items.length; i++) {
170
+ const item = items[i];
171
+ if (!item.asset) {
172
+ console.log(`${labels[i] ?? "unknown"} -> NOT FOUND`);
173
+ } else {
174
+ console.log(formatAssetRow(item));
175
+ }
176
+ }
177
+ }
178
+ });
179
+ }
180
+ function buildSingleMarkdown(item) {
181
+ if (!item.asset) {
182
+ return "# Asset Search\n\nAsset not found.";
183
+ }
184
+ const a = item.asset;
185
+ const lines = [
186
+ `# Asset Search: ${a.content}`,
187
+ "",
188
+ `- ID: ${a.id}`,
189
+ `- Type: ${a.type}`,
190
+ `- Status: **${a.status}**`,
191
+ `- Watch: ${a.watchStatus}`,
192
+ `- Created: ${a.createdAt}`,
193
+ `- Updated: ${a.updatedAt}`
194
+ ];
195
+ if (item.reports.length > 0) {
196
+ lines.push("", "## Reports", "");
197
+ for (const r of item.reports) {
198
+ lines.push(`- #${r.id} [${r.status}] ${r.title ?? "(untitled)"} \u2014 ${r.createdAt}`);
199
+ }
200
+ }
201
+ if (item.takedown) {
202
+ lines.push("", `## Takedown #${item.takedown.id} [${item.takedown.status}]`, "");
203
+ for (const t of item.takedown.tasks) {
204
+ lines.push(
205
+ `- Task #${t.id} [${t.status}] ${t.takedownProvider?.name ?? "unknown provider"}`
206
+ );
207
+ }
208
+ }
209
+ if (item.blockedBy.length > 0) {
210
+ lines.push("", "## Blocked By", "");
211
+ for (const b of item.blockedBy) {
212
+ lines.push(
213
+ `- ${b.consumer}${b.name ? ` (${b.name})` : ""} \u2014 since ${b.consumedAt}`
214
+ );
215
+ }
216
+ }
217
+ return lines.join("\n");
218
+ }
219
+ export {
220
+ runAssetSearch
221
+ };
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-O7TMOF4W.js";
11
+ } from "./chunk-GOQL7UCG.js";
12
12
  import "./chunk-EGWK6SRQ.js";
13
13
  import "./chunk-TFCNKBRC.js";
14
14
  import "./chunk-U73SABXK.js";
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-VFT3TD3E.js";
8
8
  import {
9
9
  createApiClient
10
- } from "./chunk-O7TMOF4W.js";
10
+ } from "./chunk-GOQL7UCG.js";
11
11
  import "./chunk-EGWK6SRQ.js";
12
12
  import "./chunk-TFCNKBRC.js";
13
13
  import "./chunk-U73SABXK.js";
@@ -217,7 +217,8 @@ var ASSET_TYPES = [
217
217
  type: "FIVE_HUNDRED_PX",
218
218
  label: "500px",
219
219
  description: "A 500px photographer profile."
220
- }
220
+ },
221
+ { type: "LUMA", label: "Luma", description: "A Luma page or profile." }
221
222
  ];
222
223
  var ASSET_TYPE_LABELS = Object.freeze(
223
224
  Object.fromEntries(ASSET_TYPES.map((entry) => [entry.type, entry.label]))
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-VFT3TD3E.js";
9
9
  import {
10
10
  createApiClient
11
- } from "./chunk-O7TMOF4W.js";
11
+ } from "./chunk-GOQL7UCG.js";
12
12
  import "./chunk-EGWK6SRQ.js";
13
13
  import "./chunk-TFCNKBRC.js";
14
14
  import "./chunk-U73SABXK.js";
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-VFT3TD3E.js";
4
4
  import {
5
5
  createApiClient
6
- } from "./chunk-O7TMOF4W.js";
6
+ } from "./chunk-GOQL7UCG.js";
7
7
  import "./chunk-EGWK6SRQ.js";
8
8
  import "./chunk-TFCNKBRC.js";
9
9
  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.22.0",
5
+ "version": "0.23.1",
6
6
  "license": "UNLICENSED",
7
7
  "homepage": "https://chainpatrol.com/docs/cli",
8
8
  "keywords": [