@chainpatrol/cli 0.21.0 → 0.23.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 (39) hide show
  1. package/CHANGELOG.md +13 -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/{chunk-4N2YKTJ5.js → chunk-LKITFBIG.js} +81 -6
  7. package/dist/cli.js +91 -43
  8. package/dist/{configs-update-MVX7Q5NW.js → configs-update-VDZVBTIF.js} +1 -1
  9. package/dist/{create-ANCO4FXB.js → create-DGCWT2YJ.js} +1 -1
  10. package/dist/{drift-SHPMEJDU.js → drift-YZHCIQ5O.js} +1 -1
  11. package/dist/{found-OPL4HWOW.js → found-6JAOLM6M.js} +1 -1
  12. package/dist/{get-XN752KSL.js → get-RC75EJFC.js} +25 -3
  13. package/dist/{healthcheck-QNLFKAXM.js → healthcheck-7YWSOY6Y.js} +1 -1
  14. package/dist/{list-X4Z3CPO7.js → list-4HX2R7HU.js} +1 -1
  15. package/dist/{list-XSIXAHOG.js → list-4KIZLIVN.js} +1 -1
  16. package/dist/{list-AQ7E23T3.js → list-EJDWUF6W.js} +1 -1
  17. package/dist/{list-WPPNX7G3.js → list-H7NVUX42.js} +1 -1
  18. package/dist/{list-FJBWSGTD.js → list-IDR7WH5J.js} +2 -2
  19. package/dist/{list-SWHKM5R6.js → list-Q3MMBL4Y.js} +1 -1
  20. package/dist/{list-MHICJ2TK.js → list-SRVNEUHC.js} +57 -5
  21. package/dist/{list-FVFF4VW3.js → list-UDT5MDQZ.js} +1 -1
  22. package/dist/{list-QHEFB4KE.js → list-WQFDRXHD.js} +1 -1
  23. package/dist/{list-Q5PRMAN5.js → list-YNQ6VSYV.js} +1 -1
  24. package/dist/{list-4VKMEKZS.js → list-ZARZ72DG.js} +1 -1
  25. package/dist/{list-FWXQUOCP.js → list-ZBC53OYA.js} +1 -1
  26. package/dist/{list-json-B5L5PXKH.js → list-json-7FDHNRYP.js} +1 -1
  27. package/dist/{organization-SOMHMGTM.js → organization-NEZA6JX2.js} +1 -1
  28. package/dist/{run-J5TQ2YC2.js → run-5QV3YD7V.js} +1 -1
  29. package/dist/{run-RV6P2OCD.js → run-CCVJIK7L.js} +1 -1
  30. package/dist/{run-YAAMSWKK.js → run-JLTNFOJK.js} +2 -2
  31. package/dist/{search-FQUR75WR.js → search-JXJLBV43.js} +1 -1
  32. package/dist/search-ZXTJPVM6.js +221 -0
  33. package/dist/{setup-skill-UEOROLCF.js → setup-skill-V3HDWN7T.js} +1 -1
  34. package/dist/{snapshot-2GDJMN3L.js → snapshot-NYOLPGRW.js} +1 -1
  35. package/dist/{summary-LF53KXRR.js → summary-FE6ROSOO.js} +1 -1
  36. package/dist/{types-PTMFLYUV.js → types-M6QMFNUS.js} +2 -1
  37. package/dist/{validate-UYKOMUEI.js → validate-RPQEEQ36.js} +1 -1
  38. package/dist/{whoami-OYOG63BX.js → whoami-ZIWZCBGI.js} +1 -1
  39. package/package.json +1 -1
@@ -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";
@@ -31,6 +31,13 @@ function summarizeObligatoryAdminApproval(org) {
31
31
  const types = org.obligatoryAdminApproval.assetTypes;
32
32
  return types.length === 0 ? "on (all asset types)" : `on (${types.join(", ")})`;
33
33
  }
34
+ function summarizePendingApprovals(org) {
35
+ if (org.pendingServiceApprovals.length === 0) return "none";
36
+ const labels = Array.from(
37
+ new Set(org.pendingServiceApprovals.map((approval) => approval.serviceName))
38
+ );
39
+ return labels.join(", ");
40
+ }
34
41
  async function runOrgsGet(options) {
35
42
  const slug = options.slug?.trim();
36
43
  if (!slug) {
@@ -49,14 +56,17 @@ async function runOrgsGet(options) {
49
56
  markdown: [
50
57
  `# ${organization.name} (\`${organization.slug}\`)`,
51
58
  "",
59
+ `- Contact URL: ${organization.contactUrl ?? "(not set)"}`,
52
60
  `- Subscription status: ${organization.subscriptionStatus}`,
53
61
  `- Services: ${summarizeServices(organization)}`,
54
- `- Obligatory admin approval: ${summarizeObligatoryAdminApproval(organization)}`
62
+ `- Obligatory admin approval: ${summarizeObligatoryAdminApproval(organization)}`,
63
+ `- Pending service approvals: ${summarizePendingApprovals(organization)}`
55
64
  ].join("\n"),
56
65
  csv: toCsvRows([
57
66
  {
58
67
  slug: organization.slug,
59
68
  name: organization.name,
69
+ contactUrl: organization.contactUrl ?? "",
60
70
  subscriptionStatus: organization.subscriptionStatus,
61
71
  reportingActive: organization.services.reporting.active,
62
72
  reviewingActive: organization.services.reviewing.active,
@@ -69,16 +79,28 @@ async function runOrgsGet(options) {
69
79
  obligatoryAdminApprovalActive: organization.obligatoryAdminApproval.active,
70
80
  // Empty list + active=true means "applies to all asset types" — read
71
81
  // the active column alongside this one to interpret.
72
- obligatoryAdminApprovalAssetTypes: organization.obligatoryAdminApproval.assetTypes.join("|")
82
+ obligatoryAdminApprovalAssetTypes: organization.obligatoryAdminApproval.assetTypes.join("|"),
83
+ // Pending staff requests to enable Wallet Blocking / Takedowns that a
84
+ // higher-up has not yet approved. Raw `serviceType` enum values,
85
+ // de-duplicated; an empty cell means nothing is awaiting approval.
86
+ pendingServiceApprovals: Array.from(
87
+ new Set(
88
+ organization.pendingServiceApprovals.map((approval) => approval.serviceType)
89
+ )
90
+ ).join("|")
73
91
  }
74
92
  ]),
75
93
  human: () => {
76
94
  console.log(`${organization.name} (slug: ${organization.slug})`);
95
+ console.log(` contactUrl: ${organization.contactUrl ?? "(not set)"}`);
77
96
  console.log(` subscriptionStatus: ${organization.subscriptionStatus}`);
78
97
  console.log(` services: ${summarizeServices(organization)}`);
79
98
  console.log(
80
99
  ` obligatoryAdminApproval: ${summarizeObligatoryAdminApproval(organization)}`
81
100
  );
101
+ console.log(
102
+ ` pendingServiceApprovals: ${summarizePendingApprovals(organization)}`
103
+ );
82
104
  }
83
105
  });
84
106
  }
@@ -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";
@@ -29,6 +29,7 @@ var SINGLE_SERVICES = [
29
29
  "darkWebMonitoring"
30
30
  ];
31
31
  var ALL_SERVICES = [...DUAL_SERVICES, ...SINGLE_SERVICES];
32
+ var PENDING_APPROVAL_SERVICES = ["protection", "takedowns"];
32
33
  function splitCsv(value) {
33
34
  if (!value) return [];
34
35
  return value.split(",").map((part) => part.trim()).filter(Boolean);
@@ -155,6 +156,47 @@ function buildObligatoryAdminApprovalFilter(options) {
155
156
  if (assetTypeStrings.length > 0) filter.assetTypes = assetTypeStrings;
156
157
  return Object.keys(filter).length > 0 ? filter : void 0;
157
158
  }
159
+ function parsePendingApprovalServices(raw) {
160
+ const parts = splitCsv(raw);
161
+ const result = [];
162
+ for (const part of parts) {
163
+ if (!PENDING_APPROVAL_SERVICES.includes(part)) {
164
+ throw new CliExitError(
165
+ `Unknown service '${part}' in --pending-approval-service. Only ${PENDING_APPROVAL_SERVICES.join(", ")} can require approval.`,
166
+ ExitCode.USAGE
167
+ );
168
+ }
169
+ result.push(part);
170
+ }
171
+ return result;
172
+ }
173
+ function buildPendingServiceApprovalFilter(options) {
174
+ if (options.pendingApprovalActive && options.pendingApprovalInactive) {
175
+ throw new CliExitError(
176
+ "Conflicting flags: --pending-approval-active and --pending-approval-inactive can't both be passed.",
177
+ ExitCode.USAGE
178
+ );
179
+ }
180
+ const services = parsePendingApprovalServices(options.pendingApprovalService);
181
+ if (services.length > 0 && options.pendingApprovalInactive) {
182
+ throw new CliExitError(
183
+ "Conflicting flags: --pending-approval-service implies a pending approval exists, so it can't be combined with --pending-approval-inactive.",
184
+ ExitCode.USAGE
185
+ );
186
+ }
187
+ const filter = {};
188
+ if (options.pendingApprovalActive) filter.active = true;
189
+ if (options.pendingApprovalInactive) filter.active = false;
190
+ if (services.length > 0) filter.services = services;
191
+ return Object.keys(filter).length > 0 ? filter : void 0;
192
+ }
193
+ function summarizePendingApprovals(org) {
194
+ if (org.pendingServiceApprovals.length === 0) return "none";
195
+ const labels = Array.from(
196
+ new Set(org.pendingServiceApprovals.map((approval) => approval.serviceName))
197
+ );
198
+ return labels.join(", ");
199
+ }
158
200
  async function runOrgsList(options) {
159
201
  const client = options.apiClient ?? createApiClient();
160
202
  const outputFormat = options.outputFormat ?? (options.json ? "json" : "human");
@@ -162,7 +204,8 @@ async function runOrgsList(options) {
162
204
  query: options.query ?? "",
163
205
  subscriptionStatus: parseSubscriptionStatuses(options.subscriptionStatus),
164
206
  services: buildServicesFilter(options),
165
- obligatoryAdminApproval: buildObligatoryAdminApprovalFilter(options)
207
+ obligatoryAdminApproval: buildObligatoryAdminApprovalFilter(options),
208
+ pendingServiceApproval: buildPendingServiceApprovalFilter(options)
166
209
  };
167
210
  const result = await client.getUserOrgs(input);
168
211
  const organizations = result.organizations;
@@ -173,13 +216,14 @@ async function runOrgsList(options) {
173
216
  `# Organizations (${organizations.length})`,
174
217
  "",
175
218
  ...organizations.map(
176
- (org) => `- \`${org.slug}\` \u2014 ${org.name} \u2014 ${org.subscriptionStatus} \u2014 ${summarizeServices(org)} \u2014 admin-approval: ${summarizeObligatoryAdminApproval(org)}`
219
+ (org) => `- \`${org.slug}\` \u2014 ${org.name} \u2014 ${org.subscriptionStatus} \u2014 contact: ${org.contactUrl ?? "(not set)"} \u2014 ${summarizeServices(org)} \u2014 admin-approval: ${summarizeObligatoryAdminApproval(org)} \u2014 pending-approval: ${summarizePendingApprovals(org)}`
177
220
  )
178
221
  ].join("\n"),
179
222
  csv: toCsvRows(
180
223
  organizations.map((org) => ({
181
224
  slug: org.slug,
182
225
  name: org.name,
226
+ contactUrl: org.contactUrl ?? "",
183
227
  subscriptionStatus: org.subscriptionStatus,
184
228
  reportingActive: org.services.reporting.active,
185
229
  reviewingActive: org.services.reviewing.active,
@@ -193,7 +237,14 @@ async function runOrgsList(options) {
193
237
  // Empty list + active means "applies to all asset types"; we keep
194
238
  // the cell empty in CSV so spreadsheets render it as the natural
195
239
  // "no narrowing" value — pair it with the active column.
196
- obligatoryAdminApprovalAssetTypes: org.obligatoryAdminApproval.assetTypes.join("|")
240
+ obligatoryAdminApprovalAssetTypes: org.obligatoryAdminApproval.assetTypes.join("|"),
241
+ // Pending staff requests to enable Wallet Blocking / Takedowns that
242
+ // a higher-up has not yet approved. We emit the raw `serviceType`
243
+ // enum values (de-duplicated) so the column is machine-filterable;
244
+ // an empty cell means nothing is awaiting approval.
245
+ pendingServiceApprovals: Array.from(
246
+ new Set(org.pendingServiceApprovals.map((approval) => approval.serviceType))
247
+ ).join("|")
197
248
  }))
198
249
  ),
199
250
  human: () => {
@@ -205,8 +256,9 @@ async function runOrgsList(options) {
205
256
  const slugWidth = Math.max(...organizations.map((org) => org.slug.length), 4);
206
257
  const nameWidth = Math.max(...organizations.map((org) => org.name.length), 4);
207
258
  for (const org of organizations) {
259
+ const contact = org.contactUrl ?? "(no contact)";
208
260
  console.log(
209
- ` ${org.slug.padEnd(slugWidth)} ${org.name.padEnd(nameWidth)} ${org.subscriptionStatus.padEnd(11)} ${summarizeServices(org)} admin-approval=${summarizeObligatoryAdminApproval(org)}`
261
+ ` ${org.slug.padEnd(slugWidth)} ${org.name.padEnd(nameWidth)} ${org.subscriptionStatus.padEnd(11)} ${contact} ${summarizeServices(org)} admin-approval=${summarizeObligatoryAdminApproval(org)} pending-approval=${summarizePendingApprovals(org)}`
210
262
  );
211
263
  }
212
264
  }
@@ -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
+ };
@@ -6,7 +6,7 @@ import {
6
6
  readInstalledSkillVersion,
7
7
  setupSkill,
8
8
  uninstallSkill
9
- } from "./chunk-4N2YKTJ5.js";
9
+ } from "./chunk-LKITFBIG.js";
10
10
  import "./chunk-6VTWWGNV.js";
11
11
  export {
12
12
  getBundledSkillContent,
@@ -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";