From f66004df89cfd22ef79a0eeff399d383b8f5e77c Mon Sep 17 00:00:00 2001 From: "Ko Miyatake (Openclaw Bot)" Date: Mon, 18 May 2026 05:40:44 +0000 Subject: [PATCH] fix(research): warn when unsupported --sort or --page/--limit flags are passed historical-token-flow-summary silently dropped --page/--limit; historical-smart-money-balances silently dropped --sort. Both now emit a warning to stderr so callers know their flag had no effect. Co-Authored-By: Claude Sonnet 4.6 --- .changeset/research-warn-unsupported-flags.md | 5 ++++ src/__tests__/research.test.js | 28 +++++++++++++++++++ src/commands/research.js | 18 ++++++++---- 3 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 .changeset/research-warn-unsupported-flags.md diff --git a/.changeset/research-warn-unsupported-flags.md b/.changeset/research-warn-unsupported-flags.md new file mode 100644 index 00000000..77ae010f --- /dev/null +++ b/.changeset/research-warn-unsupported-flags.md @@ -0,0 +1,5 @@ +--- +"nansen-cli": patch +--- + +Warn to stderr when --page/--limit is passed to historical-token-flow-summary or --sort is passed to historical-smart-money-balances, since those endpoints silently ignore those flags. diff --git a/src/__tests__/research.test.js b/src/__tests__/research.test.js index b844e203..de856f9c 100644 --- a/src/__tests__/research.test.js +++ b/src/__tests__/research.test.js @@ -315,6 +315,20 @@ describe('buildResearchCommands handler', () => { expect(mockApi.researchTokenFlowSummary).toHaveBeenCalled(); }); + it('warns to stderr when --page/--limit is passed to historical-token-flow-summary', async () => { + mockApi = makeMockApi(); + const stderrSpy = vi.spyOn(process.stderr, 'write').mockImplementation(() => {}); + try { + await cmds.research(['historical-token-flow-summary'], mockApi, {}, { + 'token-address': TOKENS.solana, 'from-date': FROM, 'to-date': TO, page: 2, limit: 5, + }); + const warned = stderrSpy.mock.calls.some(([msg]) => msg.includes('--page/--limit') && msg.includes('historical-token-flow-summary')); + expect(warned).toBe(true); + } finally { + stderrSpy.mockRestore(); + } + }); + it('dispatches historical-token-quant-scores with --as-of-date', async () => { mockApi = makeMockApi(); await cmds.research(['historical-token-quant-scores'], mockApi, {}, { @@ -356,6 +370,20 @@ describe('buildResearchCommands handler', () => { })); }); + it('warns to stderr when --sort is passed to historical-smart-money-balances', async () => { + mockApi = makeMockApi(); + const stderrSpy = vi.spyOn(process.stderr, 'write').mockImplementation(() => {}); + try { + await cmds.research(['historical-smart-money-balances'], mockApi, {}, { + 'as-of-date': AS_OF, sort: 'value_usd:desc', + }); + const warned = stderrSpy.mock.calls.some(([msg]) => msg.includes('--sort') && msg.includes('historical-smart-money-balances')); + expect(warned).toBe(true); + } finally { + stderrSpy.mockRestore(); + } + }); + it('dispatches historical-token-screener with --timeframe-days and --to-date', async () => { mockApi = makeMockApi(); await cmds.research(['historical-token-screener'], mockApi, {}, { diff --git a/src/commands/research.js b/src/commands/research.js index f6f76af0..f165198f 100644 --- a/src/commands/research.js +++ b/src/commands/research.js @@ -196,11 +196,16 @@ export function buildResearchCommands(deps = {}) { chain: options.chain, fromDate, toDate, filters, orderBy, pagination, }), - 'historical-token-flow-summary': () => apiInstance.researchTokenFlowSummary({ - tokenAddress: options['token-address'] || options.token, - chain: options.chain, - fromDate, toDate, filters, orderBy, - }), + 'historical-token-flow-summary': () => { + if (pagination) { + process.stderr.write('⚠️ warning: --page/--limit is ignored by historical-token-flow-summary (endpoint does not support pagination)\n'); + } + return apiInstance.researchTokenFlowSummary({ + tokenAddress: options['token-address'] || options.token, + chain: options.chain, + fromDate, toDate, filters, orderBy, + }); + }, 'historical-who-bought-sold': () => apiInstance.researchWhoBoughtSold({ tokenAddress: options['token-address'] || options.token, chain: options.chain, @@ -240,6 +245,9 @@ export function buildResearchCommands(deps = {}) { } if (sub === 'historical-smart-money-balances') { + if (options.sort || options['order-by']) { + process.stderr.write('⚠️ warning: --sort is ignored by historical-smart-money-balances (endpoint does not support order_by)\n'); + } requireOptions({ 'as-of-date': asOfDate }, ['as-of-date']); return apiInstance.researchSmartMoneyBalances({ chains: parseChains(options),