From 0f5236f5f2f88d18810ba492ff198d5137190feb Mon Sep 17 00:00:00 2001 From: agri-base Date: Tue, 14 Apr 2026 19:06:48 +0900 Subject: [PATCH] feat: add --trust flag to show XAIP runtime reliability scores MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a `--trust` option to the search command that displays runtime trust scores alongside server listings. Scores are fetched from the XAIP Trust Score API (powered by Veridict runtime monitoring). When enabled, a TRUST column shows color-coded scores: green (≥0.8), yellow (≥0.6), red (<0.6), gray dash (unscored). The API call is non-blocking with a 5s timeout — search works normally if the trust API is unreachable. Addresses #715 Co-Authored-By: Claude Opus 4.6 --- src/index.ts | 78 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 16 deletions(-) diff --git a/src/index.ts b/src/index.ts index 27d9c3d0..b70ac148 100644 --- a/src/index.ts +++ b/src/index.ts @@ -25,6 +25,7 @@ interface CliOptions { [key: string]: unknown interactive?: boolean verified?: boolean + trust?: boolean limit?: string page?: string config?: string @@ -122,29 +123,73 @@ async function handleSearch(term: string | undefined, options: CliOptions) { console.log(pc.bold("Most popular servers:\n")) } - const data = results.map((server) => ({ - name: server.displayName || server.qualifiedName, - qualifiedName: server.qualifiedName, - description: server.description ?? "", - useCount: server.useCount, - connectionUrl: `https://server.smithery.ai/${server.qualifiedName}`, - })) + // Fetch XAIP trust scores when --trust flag is set + let trustScores: Record = {} + if (options.trust && results.length > 0) { + try { + const slugs = results.map((s) => s.qualifiedName).join(",") + const res = await fetch( + `https://xaip-trust-api.kuma-github.workers.dev/v1/trust?slugs=${encodeURIComponent(slugs)}`, + { signal: AbortSignal.timeout(5000) }, + ) + if (res.ok) { + const body = (await res.json()) as { + results: Array<{ slug: string; trust: number | null; verdict: string }> + } + for (const entry of body.results) { + trustScores[entry.slug] = { trust: entry.trust, verdict: entry.verdict } + } + } + } catch { + // Trust API unreachable — continue without scores + } + } + + const data = results.map((server) => { + const score = trustScores[server.qualifiedName] + return { + name: server.displayName || server.qualifiedName, + qualifiedName: server.qualifiedName, + description: server.description ?? "", + useCount: server.useCount, + trust: score?.trust, + verdict: score?.verdict, + connectionUrl: `https://server.smithery.ai/${server.qualifiedName}`, + } + }) const page = parseInt(options.page ?? "1", 10) || 1 const limit = parseInt(options.limit ?? "10", 10) || 10 const hasMore = results.length >= limit + const columns: Array<{ key: string; header: string; format?: (v: unknown) => string }> = [ + { key: "qualifiedName", header: "SERVER" }, + { + key: "description", + header: "DESCRIPTION", + format: (v) => truncate(String(v ?? "")), + }, + { key: "useCount", header: "USES", format: (v) => String(v ?? 0) }, + ] + + if (options.trust) { + columns.push({ + key: "trust", + header: "TRUST", + format: (v) => { + if (v == null) return pc.gray("—") + const n = Number(v) + const label = n.toFixed(2) + if (n >= 0.8) return pc.green(label) + if (n >= 0.6) return pc.yellow(label) + return pc.red(label) + }, + }) + } + outputTable({ data, - columns: [ - { key: "qualifiedName", header: "SERVER" }, - { - key: "description", - header: "DESCRIPTION", - format: (v) => truncate(String(v ?? "")), - }, - { key: "useCount", header: "USES", format: (v) => String(v ?? 0) }, - ], + columns, json, jsonData: { servers: data, page, hasMore }, pagination: { page, hasMore }, @@ -426,6 +471,7 @@ function withSearchOptions(cmd: InstanceType) { return cmd .option("-i, --interactive", "Interactive search mode") .option("--verified", "Only show verified servers") + .option("--trust", "Show XAIP trust scores") .option("--namespace ", "Filter by namespace") .option("--limit ", "Max results per page", "10") .option("--page ", "Page number", "1")