@chainpatrol/cli 0.18.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/dist/{breakdown-ETSF2BZ3.js → breakdown-3LJBT3JQ.js} +1 -1
  3. package/dist/{check-EMGFDXUO.js → check-G64UQCEL.js} +1 -1
  4. package/dist/{chunk-HGAQBGGL.js → chunk-2JZAPTY6.js} +1 -1
  5. package/dist/{chunk-MDDC4F6Q.js → chunk-3LJTWYT6.js} +250 -2
  6. package/dist/{chunk-NQT77IB7.js → chunk-6VTWWGNV.js} +2 -1
  7. package/dist/{chunk-DPLUSURP.js → chunk-O7TMOF4W.js} +3 -0
  8. package/dist/cli.js +81 -40
  9. package/dist/{completions-6C6KG5DH.js → completions-ILC76OX5.js} +1 -1
  10. package/dist/{configs-update-EKNLIRA6.js → configs-update-MVX7Q5NW.js} +1 -1
  11. package/dist/{create-M4PV5VVU.js → create-ANCO4FXB.js} +1 -1
  12. package/dist/{drift-RQKTGJWB.js → drift-SHPMEJDU.js} +1 -1
  13. package/dist/{found-LVYBEOS6.js → found-OPL4HWOW.js} +1 -1
  14. package/dist/{get-YFYSJFBC.js → get-K7VHV5X2.js} +1 -1
  15. package/dist/{healthcheck-J6BIZEG7.js → healthcheck-QNLFKAXM.js} +1 -1
  16. package/dist/list-4VKMEKZS.js +64 -0
  17. package/dist/{list-CNF2FGLN.js → list-AQ7E23T3.js} +1 -1
  18. package/dist/{list-JCJHIJM4.js → list-FJBWSGTD.js} +2 -2
  19. package/dist/{list-O36VWTWR.js → list-FVFF4VW3.js} +1 -1
  20. package/dist/{list-S5Y6GW43.js → list-FWXQUOCP.js} +1 -1
  21. package/dist/{list-E2JVJNHV.js → list-Q5PRMAN5.js} +1 -1
  22. package/dist/{list-O62BZKQ5.js → list-QHEFB4KE.js} +1 -1
  23. package/dist/{list-XUYCZG7S.js → list-QXA6GLCV.js} +1 -1
  24. package/dist/{list-LKNCICLT.js → list-SWHKM5R6.js} +1 -1
  25. package/dist/{list-44BQZHJD.js → list-WPPNX7G3.js} +1 -1
  26. package/dist/{list-AEM2KSO4.js → list-X4Z3CPO7.js} +1 -1
  27. package/dist/{list-2ENAEZVP.js → list-XSIXAHOG.js} +1 -1
  28. package/dist/{list-json-ZTS5GXNA.js → list-json-B5L5PXKH.js} +1 -1
  29. package/dist/{organization-PFPBZXJZ.js → organization-SOMHMGTM.js} +1 -1
  30. package/dist/{run-R3RR6XQF.js → run-J5TQ2YC2.js} +1 -1
  31. package/dist/{run-HS2EEOM6.js → run-RV6P2OCD.js} +1 -1
  32. package/dist/{run-LKPKTH3W.js → run-YAAMSWKK.js} +2 -2
  33. package/dist/{search-EBXEP7XC.js → search-FQUR75WR.js} +1 -1
  34. package/dist/{setup-skill-Z6SBI6GC.js → setup-skill-A36WQLMU.js} +2 -2
  35. package/dist/{snapshot-GNZMYTXT.js → snapshot-2GDJMN3L.js} +1 -1
  36. package/dist/{summary-POVQC6B7.js → summary-LF53KXRR.js} +1 -1
  37. package/dist/types-PTMFLYUV.js +271 -0
  38. package/dist/{validate-QE2F4PYY.js → validate-UYKOMUEI.js} +1 -1
  39. package/dist/{whoami-24KUJUN4.js → whoami-OYOG63BX.js} +1 -1
  40. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,83 @@
1
1
  # @chainpatrol/cli
2
2
 
3
+ ## 0.20.0
4
+
5
+ ### Minor Changes
6
+
7
+ - e63d269: Add `chainpatrol asset types` — list every supported `AssetType` enum
8
+ value with its human-readable label and a short description.
9
+
10
+ The mapping (e.g. `ARCHIVE_ORG` → "Archive.org" / Wayback snapshot,
11
+ `PAGE` → "Page" / standalone web page tracked independently of its
12
+ parent URL, `FIVE_HUNDRED_PX` → "500px") ships bundled with the CLI as
13
+ a static map, so the command works without auth or a network round
14
+ trip. Output is available in human, JSON, markdown, and CSV formats —
15
+ useful when an agent or script needs to translate enum ↔ display name,
16
+ validate a user-supplied `--asset-type` value, or enumerate the
17
+ available types before constructing a filter for `asset list`,
18
+ `threats list`, `takedowns list`, `detections list`, `reports list`,
19
+ or `orgs assets list`.
20
+
21
+ The Claude Code skill is updated to point at the new command whenever
22
+ a user asks "what is `ARCHIVE_ORG`?", "what does `PAGE` mean?", or
23
+ "what asset types does ChainPatrol support?". Shell completions and
24
+ top-level/per-command help text are updated accordingly.
25
+
26
+ ## 0.19.0
27
+
28
+ ### Minor Changes
29
+
30
+ - 477a431: Add proper brand support across metrics and listings so agents can run a
31
+ real "trend search" on an org.
32
+
33
+ ## New: list brands for an org
34
+
35
+ `GET /organization/brands` (CLI: `chainpatrol brands list`) returns every
36
+ brand belonging to the caller's org — both parent / product brands
37
+ (`type: ORGANIZATION`) and individual / employee brands (`type:
38
+ INDIVIDUAL`) — in one call. Soft-deleted brands are excluded. Use
39
+ `--type INDIVIDUAL` to filter to employee brands only. The endpoint is
40
+ org-scoped via auth, no extra args.
41
+
42
+ ## Fixed: brand filter actually applies on metrics
43
+
44
+ Two server-side bugs the trend-search docs ran into:
45
+
46
+ 1. `GET /organization/metrics` with `brandSlug` was filtering the scalar
47
+ metrics (`reports`, `newThreats`, `takedownsFiled`, ...) but **not**
48
+ `blockedByType` / `blockedByDay`, which silently returned org-wide
49
+ totals. A caller drilling into a single brand would see "this brand
50
+ is being attacked on YouTube" when YouTube was really just an
51
+ org-wide trend.
52
+ 2. `POST /metrics/breakdown` with `by: "brand"` was ignoring the
53
+ `brandIds` input filter — `getThreatsBlockedPerBrand()` always
54
+ returned every brand. The function now accepts `brandIds` and the
55
+ handler passes the input through.
56
+
57
+ Both are now wired through correctly. `metrics organization
58
+ --brand-slug <slug> --include blockedByType,blockedByDay` returns
59
+ real brand-scoped time series, and `metrics breakdown --by brand
60
+ --brand <id>` actually narrows to the requested brand(s).
61
+
62
+ ## Skill: full trend-search guide
63
+
64
+ Documents three trend signals the agent can answer from existing
65
+ commands, with concrete current-vs-baseline recipes:
66
+
67
+ 1. Spike in a specific asset type (`metrics breakdown --by type`).
68
+ 2. Spike in overall threat volume (`metrics breakdown --by day` +
69
+ `metrics organization`).
70
+ 3. Spike on a specific sub-brand (`brands list` → join → `metrics
71
+ breakdown --by brand` → `metrics organization --brand-slug`).
72
+ Employee vs. product distinction now comes straight from the brand
73
+ roster.
74
+
75
+ Server-side procedures + validation schemas live in the private
76
+ `@chainpatrol/external-trpc`, `@chainpatrol/validation`, and
77
+ `@chainpatrol/metrics` packages and ship together with this CLI
78
+ release, but are not listed in the frontmatter because they are
79
+ private.
80
+
3
81
  ## 0.18.0
4
82
 
5
83
  ### Minor Changes
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-VFT3TD3E.js";
8
8
  import {
9
9
  createApiClient
10
- } from "./chunk-DPLUSURP.js";
10
+ } from "./chunk-O7TMOF4W.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-DPLUSURP.js";
11
+ } from "./chunk-O7TMOF4W.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-DPLUSURP.js";
11
+ } from "./chunk-O7TMOF4W.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-NQT77IB7.js";
4
+ } from "./chunk-6VTWWGNV.js";
5
5
 
6
6
  // src/commands/setup-skill.ts
7
7
  import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, existsSync as existsSync2, readFileSync as readFileSync3, rmSync } from "fs";
@@ -201,12 +201,23 @@ description: |
201
201
  "which customers have X enabled", "service toggles by org",
202
202
  "is this URL blocked", "is this domain blocked", "is this address blocked",
203
203
  "check this asset", "asset check", "lookup asset status",
204
+ "what is ARCHIVE_ORG", "what does PAGE mean", "list asset types",
205
+ "supported asset types", "asset type mapping", "asset type enum",
206
+ "what asset types are there", "human readable asset type",
204
207
  "how many takedowns", "takedowns in the last", "threats taken down",
205
208
  "across all clients", "across all customers", "across all orgs",
206
209
  "across all brands", "company-wide", "total takedowns", "total threats",
207
210
  "total reports", "average takedowns", "average threats", "average per day",
208
211
  "average per customer", "average per org", "rollup across customers",
209
- "sum across orgs", "sum across customers".
212
+ "sum across orgs", "sum across customers",
213
+ "trends in org", "search for trends", "trend search", "look for trends",
214
+ "any trends", "trending threats", "spike in asset type",
215
+ "spike in threat volume", "coordinated attack", "spike check",
216
+ "anything unusual", "anything new for", "what's new for",
217
+ "employee being targeted", "spike on a sub-brand", "spike on a brand",
218
+ "sub-brand spike",
219
+ "list brands", "brands for org", "list sub-brands", "employee brands",
220
+ "individual brands", "brand list", "all brands in org".
210
221
  allowed-tools:
211
222
  - Bash
212
223
  - Read
@@ -375,6 +386,29 @@ If any individual lookup fails, the CLI still prints results for the
375
386
  successful ones, then exits non-zero so failures aren't silently
376
387
  swallowed.
377
388
 
389
+ ### \`asset types\` \u2014 List every supported asset type and what it means
390
+
391
+ When a user asks "what is \`ARCHIVE_ORG\`?", "what does \`PAGE\` mean?",
392
+ or "what asset types does ChainPatrol support?" \u2014 don't guess. Run:
393
+
394
+ \`\`\`bash
395
+ chainpatrol asset types
396
+ chainpatrol --json asset types
397
+ \`\`\`
398
+
399
+ The mapping is bundled with the CLI (no API or auth required), so this
400
+ is safe to run anywhere. Each row is \`{ type, label, description }\`:
401
+ \`type\` is the canonical enum value used by every \`--asset-type\` flag
402
+ (\`asset list\`, \`threats list\`, \`takedowns list\`, \`detections list\`,
403
+ \`reports list\`, \`orgs assets list\`); \`label\` is the human-friendly
404
+ display name (\`ARCHIVE_ORG\` \u2192 \`Archive.org\`, \`PAGE\` \u2192 \`Page\`,
405
+ \`FIVE_HUNDRED_PX\` \u2192 \`500px\`); \`description\` is a one-line note for
406
+ unobvious entries.
407
+
408
+ Use this whenever you need to translate between enum and display name,
409
+ validate that a type the user mentioned is real, or enumerate options
410
+ before constructing a filter.
411
+
378
412
  ### \`configs list\` \u2014 List detection configurations
379
413
 
380
414
  Requires authentication and an organization slug.
@@ -732,6 +766,36 @@ takedowns?", reach for \`orgs list\` \u2014 it's the only command that exposes
732
766
  service flags across multiple orgs in one call. Run it in \`--json\` mode
733
767
  and summarize patterns by service or by subscription tier.
734
768
 
769
+ ### \`brands list\` \u2014 List the brands (sub-brands) belonging to an org
770
+
771
+ Returns every brand for the org the caller is authenticated as, both
772
+ parent / product brands (\`type: "ORGANIZATION"\`) and individual /
773
+ employee brands (\`type: "INDIVIDUAL"\`). Soft-deleted brands are excluded.
774
+ The endpoint is org-scoped and inferred from auth \u2014 there's no \`--org\`
775
+ flag \u2014 so org-scoped API keys, user API keys, and user sessions all work
776
+ without extra arguments.
777
+
778
+ \`\`\`bash
779
+ chainpatrol brands list # all brands
780
+ chainpatrol brands list --type INDIVIDUAL # employee / person brands only
781
+ chainpatrol brands list --type ORGANIZATION # product / parent brands only
782
+ chainpatrol --json brands list # machine-readable
783
+ \`\`\`
784
+
785
+ Each entry has \`{ id, slug, name, type, description, brandGroupId, createdAt }\`.
786
+ Use this when you need to:
787
+
788
+ - Distinguish employee vs. product brands ahead of time \u2014 e.g. while
789
+ running a trend search and you want to highlight which spiking
790
+ sub-brands are employees so the user gets a direct heads-up to the
791
+ person involved.
792
+ - Resolve a brand name the user mentions to its \`slug\` for use with
793
+ \`metrics organization --brand-slug <slug>\` or as a \`brandId\` for
794
+ \`takedowns list --brand <id>\`.
795
+ - Audit a customer's setup \u2014 "how many employee brands does this org
796
+ protect?" or "are there brands the org set up but never wired into a
797
+ detection config?"
798
+
735
799
  ### \`metrics summary | found | breakdown | organization\` \u2014 Org metrics for spike/drop analysis
736
800
 
737
801
  #### Decision rule \u2014 read this before picking a metrics subcommand
@@ -1416,6 +1480,190 @@ Until a dedicated probe command exists:
1416
1480
  In both cases, if liveness looks miscalibrated for a class of assets,
1417
1481
  notify ChainPatrol engineering \u2014 the checker likely needs a tuning pass for
1418
1482
  that platform.
1483
+
1484
+ ## Organization Trend Search Guide
1485
+
1486
+ Trend search asks "what's changed recently for this org?" \u2014 the answer can
1487
+ surface coordinated attacks, new attack channels, or campaigns targeting
1488
+ specific people, **before** they show up as a healthcheck failure. Unlike
1489
+ the HealthCheck Guide above (which grades single signals against
1490
+ thresholds), trend search compares a recent window to a baseline window
1491
+ and flags ratios, not absolute counts. A trend is interesting even when
1492
+ the pipeline is keeping up with it \u2014 the user usually wants to know.
1493
+
1494
+ When the user asks something like:
1495
+
1496
+ - "are there any trends in org X?"
1497
+ - "search for trends in <org>"
1498
+ - "anything unusual happening with <org> lately?"
1499
+ - "any spikes for <org>?"
1500
+ - "what's new for <org> this week?"
1501
+ - "is anyone targeting <org>'s employees more than usual?"
1502
+ - "are we seeing more YouTube/Telegram/etc. threats for <org>?"
1503
+
1504
+ \u2026run the three trend checks below in parallel (single message, multiple
1505
+ Bash calls) and surface anything where the current rate is \u2265 2\xD7 the
1506
+ baseline AND clears a small absolute floor.
1507
+
1508
+ ### How to compute "current vs. baseline" rates
1509
+
1510
+ Pick two non-overlapping windows: a **current** window the user cares about
1511
+ (default last 7 days) and a **baseline** window ending where the current
1512
+ one starts (default the prior ~90 days, i.e. \`current_start - 90d\` \u2192
1513
+ \`current_start - 1d\`). For any breakdown bucket, compute:
1514
+
1515
+ \`\`\`
1516
+ current_per_day = current_count / current_window_days
1517
+ baseline_per_day = baseline_count / baseline_window_days
1518
+ ratio = current_per_day / max(baseline_per_day, epsilon)
1519
+ \`\`\`
1520
+
1521
+ Flag a bucket if \`ratio >= 2\` AND \`current_count >= 5\`. The floor
1522
+ suppresses noise on orgs with near-zero baseline activity (a single new
1523
+ YouTube report jumping the rate from 0 to 1/day shouldn't trigger). If
1524
+ the user gives a different window ("last 3 days", "this month"), adjust
1525
+ both windows proportionally and keep the same ratio threshold.
1526
+
1527
+ ### Trend 1 \u2014 Spike in a specific asset type
1528
+
1529
+ A sudden jump in threats on a platform the org doesn't usually see
1530
+ traffic on ("normally you don't get targeted on YouTube much, but now
1531
+ there's a spike there") is worth flagging \u2014 it usually means an attacker
1532
+ has discovered a new channel that works for them. Even when the absolute
1533
+ number is small, the *ratio* against the org's normal mix is what
1534
+ matters.
1535
+
1536
+ Use \`metrics breakdown --by type\` over both windows:
1537
+
1538
+ \`\`\`bash
1539
+ # Current window \u2014 last 7 days, broken out by asset type
1540
+ chainpatrol --json metrics breakdown --org <slug> --by type \\
1541
+ --from <YYYY-MM-DD 7d ago> --to <YYYY-MM-DD today>
1542
+
1543
+ # Baseline window \u2014 prior ~90 days ending where the current window starts
1544
+ chainpatrol --json metrics breakdown --org <slug> --by type \\
1545
+ --from <YYYY-MM-DD 97d ago> --to <YYYY-MM-DD 8d ago>
1546
+ \`\`\`
1547
+
1548
+ Each entry in \`.points\` has \`{ type, count }\`. Join the two windows on
1549
+ \`type\`, apply the ratio rule above, and report each flagged type.
1550
+
1551
+ Cross-reference any flagged type with \`configs list --org <slug>\` \u2014 if
1552
+ the spike is on Twitter / X but \`twitter_post_search\` is disabled, the
1553
+ detection source for that channel isn't even running for this org and
1554
+ the spike is being caught by something else (likely customer reports);
1555
+ suggest turning it on.
1556
+
1557
+ ### Trend 2 \u2014 Spike in overall threat volume
1558
+
1559
+ A sharp rise in total threats across the org \u2014 regardless of type or
1560
+ brand \u2014 usually means a coordinated attack or campaign is underway. This
1561
+ isn't a healthcheck (reviewing and takedowns may be keeping up just
1562
+ fine), but the security team still wants to know so they can warn
1563
+ customers / employees / partners.
1564
+
1565
+ \`\`\`bash
1566
+ # Daily volume for the last ~6 weeks \u2014 enough to eyeball a baseline AND
1567
+ # see the spike on the right edge of the series.
1568
+ chainpatrol --json metrics breakdown --org <slug> --by day \\
1569
+ --from <YYYY-MM-DD 42d ago> --to <YYYY-MM-DD today>
1570
+ \`\`\`
1571
+
1572
+ Read \`.points\` (one entry per day). Take the trailing 7-day average and
1573
+ compare against the prior ~5 weeks (the same 2\xD7 / floor rule). For round
1574
+ totals to quote to the user, also pull:
1575
+
1576
+ \`\`\`bash
1577
+ # Two calls \u2014 current and baseline windows \u2014 using --include to skip
1578
+ # the per-type / per-day series and keep the call cheap.
1579
+ chainpatrol --json metrics organization --org <slug> \\
1580
+ --include reports,newThreats,threatsWatchlisted \\
1581
+ --from <current_from> --to <current_to>
1582
+
1583
+ chainpatrol --json metrics organization --org <slug> \\
1584
+ --include reports,newThreats,threatsWatchlisted \\
1585
+ --from <baseline_from> --to <baseline_to>
1586
+ \`\`\`
1587
+
1588
+ When volume spikes broadly, also skim \`reports list --reported-by-customer\`
1589
+ for the same window \u2014 a wave of customer reports often arrives a few hours
1590
+ ahead of automated detection on a real coordinated push.
1591
+
1592
+ ### Trend 3 \u2014 Spike on a specific sub-brand (especially employee brands)
1593
+
1594
+ Sub-brands the org has set up for individual people \u2014 employees,
1595
+ executives, public figures \u2014 are high-signal targets. A sudden spike on
1596
+ one usually means an attacker is impersonating that person specifically,
1597
+ which is materially different from a generic phishing wave and usually
1598
+ warrants a direct heads-up to the person involved. In the database these
1599
+ are \`Brand\` rows with \`type: INDIVIDUAL\` (vs. \`ORGANIZATION\` for
1600
+ product / parent brands).
1601
+
1602
+ **Step 1: Pull the brand roster** so you can label each spike as
1603
+ "employee" or "product" without asking the user.
1604
+
1605
+ \`\`\`bash
1606
+ chainpatrol --json brands list
1607
+ \`\`\`
1608
+
1609
+ Build a map of \`slug \u2192 type\` from the response so the next step's
1610
+ findings can be tagged \`(employee)\` or \`(product)\` automatically.
1611
+
1612
+ **Step 2: Run the breakdown over both windows.**
1613
+
1614
+ \`\`\`bash
1615
+ # Current window \u2014 last 7 days, broken out by sub-brand
1616
+ chainpatrol --json metrics breakdown --org <slug> --by brand \\
1617
+ --from <YYYY-MM-DD 7d ago> --to <YYYY-MM-DD today>
1618
+
1619
+ # Baseline window \u2014 prior ~90 days
1620
+ chainpatrol --json metrics breakdown --org <slug> --by brand \\
1621
+ --from <YYYY-MM-DD 97d ago> --to <YYYY-MM-DD 8d ago>
1622
+ \`\`\`
1623
+
1624
+ Each entry in \`.points\` has \`{ brandId, brandSlug, brandName, count }\`.
1625
+ Apply the ratio rule, join against the \`slug \u2192 type\` map from Step 1,
1626
+ and report each spiking sub-brand by name plus its type.
1627
+
1628
+ **Step 3: Drill into the flagged brand** with \`metrics organization
1629
+ --brand-slug <slug>\` for a per-day / per-type breakdown scoped to that
1630
+ brand only. The server applies the brand filter to the scalar metrics
1631
+ (\`newThreats\`, \`takedownsFiled\`, etc.) AND to \`blockedByType\` /
1632
+ \`blockedByDay\`, so the time series and per-asset-type counts are real
1633
+ brand-only data:
1634
+
1635
+ \`\`\`bash
1636
+ chainpatrol --json metrics organization --org <slug> \\
1637
+ --brand-slug <brand-slug> \\
1638
+ --include newThreats,blockedByType,blockedByDay \\
1639
+ --from <YYYY-MM-DD 7d ago> --to <YYYY-MM-DD today>
1640
+ \`\`\`
1641
+
1642
+ If multiple \`INDIVIDUAL\` brands are spiking at the same time, treat that
1643
+ as a stronger signal than a single one \u2014 likely a campaign targeting the
1644
+ company's people rather than a single impersonation. Prioritize those
1645
+ findings over single-brand spikes when summarizing.
1646
+
1647
+ ### Reporting trend findings
1648
+
1649
+ Report each spiking bucket as its own finding with: the trend it falls
1650
+ under (asset type / overall volume / sub-brand), the current vs. baseline
1651
+ rate (e.g. "youtube: 12/day last 7d vs. 1.2/day prior 90d, \xD710
1652
+ baseline"), and a one-line follow-up:
1653
+
1654
+ - Asset-type spike \u2192 check \`configs list\` for the matching detection
1655
+ source and turn it on if it's off.
1656
+ - Overall-volume spike \u2192 flag a possible coordinated campaign; suggest
1657
+ the security team look at the recent \`reports list\` for shared
1658
+ infrastructure (sender, registrar, hosting).
1659
+ - Sub-brand spike \u2192 look up \`type\` via \`brands list\`; if
1660
+ \`INDIVIDUAL\`, suggest a direct heads-up to that person; if
1661
+ \`ORGANIZATION\`, suggest a product-team alert.
1662
+
1663
+ If none of the three trends fire above the 2\xD7 / floor thresholds, say so
1664
+ explicitly ("no significant trends in the last 7 days vs. the prior 90")
1665
+ rather than dumping every breakdown number \u2014 the absence is the
1666
+ finding.
1419
1667
  `;
1420
1668
  }
1421
1669
  function getBundledSkillVersion() {
@@ -66,6 +66,7 @@ _chainpatrol() {
66
66
  asset_subcommands=(
67
67
  'check:Check asset status against ChainPatrol'
68
68
  'list:List assets in the global ChainPatrol blocklist'
69
+ 'types:List supported asset types and their human-readable labels'
69
70
  )
70
71
  _describe 'subcommand' asset_subcommands
71
72
  ;;
@@ -161,7 +162,7 @@ var BASH_COMPLETION = `_chainpatrol() {
161
162
  return 0
162
163
  ;;
163
164
  asset)
164
- COMPREPLY=( $(compgen -W "check list" -- "\${cur}") )
165
+ COMPREPLY=( $(compgen -W "check list types" -- "\${cur}") )
165
166
  return 0
166
167
  ;;
167
168
  configs)
@@ -392,6 +392,9 @@ function createApiClient(options) {
392
392
  {}
393
393
  );
394
394
  },
395
+ listOrganizationBrands() {
396
+ return requestGet("/organization/brands", {});
397
+ },
395
398
  getCurrentUser() {
396
399
  return request("/user/me", {});
397
400
  },