mirror of
https://github.com/GMGNAI/gmgn-skills.git
synced 2026-07-27 16:57:44 +00:00
feat(market): hot-searches range filters, flattened params, long-form fields
- Add --min-*/--max-* range flags to `market hot-searches` (same metric names as market trending); flatten filter fields onto each param (no nested filter object) - Document response as long-form RankItem fields (server maps shortcodes); drop the filter_id field from the documented response shape - Sync SKILL.md, cli-usage.md, Readme.md, Readme.zh.md, and OpenApiClient types Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -179,16 +179,18 @@ export interface TokenSignalGroup {
|
||||
max_create_or_open_ts?: string;
|
||||
}
|
||||
|
||||
export interface HotSearchesFilter {
|
||||
filters?: string[];
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
// HotSearchesParam carries its filter fields flattened (no nested `filter` object):
|
||||
// label/interval/chain plus optional `filters` boolean tags, `limit`, and rank-style
|
||||
// numeric range bounds (min_<metric>/max_<metric>) incl. min_created/max_created.
|
||||
// Extra range keys are forwarded verbatim; the service translates metric names per
|
||||
// interval. See `market hot-searches` docs for the supported metric list.
|
||||
export interface HotSearchesParam {
|
||||
label?: string;
|
||||
interval: string; // "1m" | "5m" | "1h" | "6h" | "24h"
|
||||
chain: string; // "sol" | "bsc" | "base" | "eth" | "monad" | "megaeth" | "hyperevm" | "tron"
|
||||
filter?: HotSearchesFilter;
|
||||
filters?: string[];
|
||||
limit?: number;
|
||||
[key: string]: string[] | number | string | undefined;
|
||||
}
|
||||
|
||||
export interface PumpFeeShareInfo {
|
||||
|
||||
+54
-32
@@ -204,47 +204,69 @@ export function registerMarketCommands(program: Command): void {
|
||||
printResult(data, opts["raw"] as boolean | undefined);
|
||||
});
|
||||
|
||||
market
|
||||
const hotSearchesCmd = market
|
||||
.command("hot-searches")
|
||||
.description("Get the hot-search ranking (most-searched tokens) for one or more chains")
|
||||
.option("--chain <chain...>", "Chain(s), repeatable: sol / bsc / base / eth / monad / megaeth / hyperevm / tron (default: all 7 chains)")
|
||||
.option("--interval <interval>", "Time window: 1m / 5m / 1h / 6h / 24h (default 24h)", "24h")
|
||||
.option("--limit <n>", "Max results per chain (default 500)", parseInt)
|
||||
.option("--filter <tag...>", "Filter tags, repeatable. sol defaults: renounced / frozen; EVM defaults: not_honeypot / verified / renounced")
|
||||
.option("--params <json>", "Full params override: JSON array of param objects — overrides --chain/--interval/--limit/--filter when provided")
|
||||
.option("--raw", "Output raw JSON")
|
||||
.action(async (opts) => {
|
||||
const interval = String(opts.interval);
|
||||
if (!HOT_SEARCHES_INTERVALS.has(interval)) {
|
||||
console.error(`[gmgn-cli] Invalid --interval "${interval}". Must be one of: ${[...HOT_SEARCHES_INTERVALS].join(", ")}`);
|
||||
.option("--filter <tag...>", "Boolean filter tags, repeatable. sol defaults: renounced / frozen; EVM defaults: not_honeypot / verified / renounced")
|
||||
.option("--params <json>", "Full params override: JSON array of param objects — overrides --chain/--interval/--limit/--filter and all range flags when provided")
|
||||
.option("--raw", "Output raw JSON");
|
||||
|
||||
// Reuse the same min_*/max_* range flags as `market trending` — the hot_searches
|
||||
// endpoint accepts the identical rank-style metric names inside `filter` and
|
||||
// translates them server-side per interval (min_created/max_created are durations).
|
||||
for (const def of RANK_RANGE_FIELDS) {
|
||||
const flag = def.api.replace(/_/g, "-");
|
||||
if (def.type === "int") {
|
||||
hotSearchesCmd.option(`--${flag} <${def.type}>`, def.desc, parseInt);
|
||||
} else if (def.type === "float") {
|
||||
hotSearchesCmd.option(`--${flag} <${def.type}>`, def.desc, parseFloat);
|
||||
} else if (def.type === "duration") {
|
||||
hotSearchesCmd.option(`--${flag} <duration>`, def.desc, parseDuration);
|
||||
} else {
|
||||
hotSearchesCmd.option(`--${flag} <value>`, def.desc);
|
||||
}
|
||||
}
|
||||
|
||||
hotSearchesCmd.action(async (opts) => {
|
||||
const interval = String(opts.interval);
|
||||
if (!HOT_SEARCHES_INTERVALS.has(interval)) {
|
||||
console.error(`[gmgn-cli] Invalid --interval "${interval}". Must be one of: ${[...HOT_SEARCHES_INTERVALS].join(", ")}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let params: HotSearchesParam[];
|
||||
if (opts.params != null) {
|
||||
try {
|
||||
params = JSON.parse(opts.params as string) as HotSearchesParam[];
|
||||
} catch {
|
||||
console.error(`[gmgn-cli] --params must be a valid JSON array, e.g. '[{"chain":"sol","interval":"24h","filters":["renounced","frozen"],"limit":500,"min_liquidity":1000}]'`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let params: HotSearchesParam[];
|
||||
if (opts.params != null) {
|
||||
try {
|
||||
params = JSON.parse(opts.params as string) as HotSearchesParam[];
|
||||
} catch {
|
||||
console.error(`[gmgn-cli] --params must be a valid JSON array, e.g. '[{"chain":"sol","interval":"24h","filter":{"filters":["renounced","frozen"],"limit":500}}]'`);
|
||||
process.exit(1);
|
||||
} else {
|
||||
// Empty params lets the server apply its default 7-chain config. Filter fields
|
||||
// are flattened directly onto each param (no nested `filter` object).
|
||||
const optsMap = opts as Record<string, unknown>;
|
||||
const chains: string[] = opts.chain?.length ? (opts.chain as string[]) : [];
|
||||
params = chains.map((chain) => {
|
||||
const param: HotSearchesParam = { label: "hot-search", chain, interval };
|
||||
if (opts.filter?.length) param.filters = opts.filter as string[];
|
||||
if (opts.limit != null) param.limit = opts.limit as number;
|
||||
// Fold in any rank-style min_*/max_* range flags (incl. min_created/max_created).
|
||||
for (const def of RANK_RANGE_FIELDS) {
|
||||
const val = optsMap[apiFieldToCliKey(def.api)];
|
||||
if (val != null) param[def.api] = val as number | string;
|
||||
}
|
||||
} else {
|
||||
// Empty params lets the server apply its default 7-chain config.
|
||||
const chains: string[] = opts.chain?.length ? (opts.chain as string[]) : [];
|
||||
params = chains.map((chain) => {
|
||||
const param: HotSearchesParam = { label: "hot-search", chain, interval };
|
||||
const filter: { filters?: string[]; limit?: number } = {};
|
||||
if (opts.filter?.length) filter.filters = opts.filter as string[];
|
||||
if (opts.limit != null) filter.limit = opts.limit as number;
|
||||
if (Object.keys(filter).length) param.filter = filter;
|
||||
return param;
|
||||
});
|
||||
}
|
||||
return param;
|
||||
});
|
||||
}
|
||||
|
||||
const client = new OpenApiClient(getConfig());
|
||||
const data = await client.getHotSearches(params).catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
const client = new OpenApiClient(getConfig());
|
||||
const data = await client.getHotSearches(params).catch(exitOnError);
|
||||
printResult(data, opts.raw);
|
||||
});
|
||||
}
|
||||
|
||||
const HOT_SEARCHES_INTERVALS = new Set(["1m", "5m", "1h", "6h", "24h"]);
|
||||
|
||||
Reference in New Issue
Block a user