@qverisai/cli 0.4.0 → 0.5.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.
package/README.md CHANGED
@@ -9,12 +9,12 @@ Found 5 capabilities matching your query
9
9
  1. gridpoint_forecast by Weather.gov
10
10
  weather_gov.gridpoints.forecast.retrieve.v1
11
11
  Returns a textual forecast for a 2.5km grid area
12
- relevance: 95% · success: 99.8% · latency: ~180ms · cost: 3 cr
12
+ relevance: 95% · success: 99.8% · latency: ~180ms · billing: 3 credits / request
13
13
 
14
14
  2. current_weather by OpenWeather
15
15
  openweathermap.weather.current.v1
16
16
  Get current weather data for any location
17
- relevance: 87% · success: 99.5% · latency: ~200ms · cost: 2 cr
17
+ relevance: 87% · success: 99.5% · latency: ~200ms · billing: 2 credits / request
18
18
 
19
19
  $ qveris inspect 1
20
20
  gridpoint_forecast
@@ -23,7 +23,7 @@ Returns a textual forecast for a 2.5km grid area
23
23
  Provider: Weather.gov
24
24
  Latency: ~180ms
25
25
  Success: 99.8%
26
- Cost: 3 credits
26
+ Billing: 3 credits / request
27
27
 
28
28
  Parameters:
29
29
  wfo string required
@@ -38,9 +38,13 @@ Returns a textual forecast for a 2.5km grid area
38
38
  {"wfo": "LWX", "x": 90, "y": 90}
39
39
 
40
40
  $ qveris call 1 --params '{"wfo":"LWX","x":90,"y":90}'
41
- ✓ success · 523ms · 10 credits · (1368087.93 remaining)
41
+ ✓ success · 523ms · 10 credits pre-settlement · (1368087.93 remaining)
42
42
  tool: weather_gov... · id: 7ebcaf9d-...
43
43
 
44
+ Billing:
45
+ 10 credits per successful request
46
+ Pre-settlement: 10 credits
47
+
44
48
  {
45
49
  "type": "Feature",
46
50
  "properties": {
@@ -96,9 +100,9 @@ qveris call 1 --params '{"wfo": "LWX", "x": 90, "y": 90}'
96
100
 
97
101
  | Command | Description |
98
102
  |---------|-------------|
99
- | `qveris discover <query>` | Find capabilities by natural language. Shows tool ID, provider, description, relevance, success rate, latency, and cost for each result. |
103
+ | `qveris discover <query>` | Find capabilities by natural language. Shows tool ID, provider, description, relevance, success rate, latency, and billing rule when available. |
100
104
  | `qveris inspect <id\|index>` | View full tool details: parameters (type, required, description, enum values), example, provider info, execution history. |
101
- | `qveris call <id\|index>` | Execute a capability. Shows result data, execution time, cost, and remaining credits. |
105
+ | `qveris call <id\|index>` | Execute a capability. Shows result data, execution time, pre-settlement billing, and remaining credits. |
102
106
 
103
107
  ### Account
104
108
 
@@ -108,6 +112,8 @@ qveris call 1 --params '{"wfo": "LWX", "x": 90, "y": 90}'
108
112
  | `qveris logout` | Remove stored key |
109
113
  | `qveris whoami` | Show current auth status, key source, and region |
110
114
  | `qveris credits` | Check credit balance |
115
+ | `qveris usage` | Context-safe usage audit summary/search/export |
116
+ | `qveris ledger` | Context-safe credits ledger summary/search/export |
111
117
 
112
118
  ### Utilities
113
119
 
@@ -146,7 +152,7 @@ qveris inspect 1 2 3
146
152
 
147
153
  ### Call
148
154
 
149
- Execute a tool. Results are automatically truncated for terminal display (4KB). Large results get an OSS download link.
155
+ Execute a tool. Results are automatically truncated for terminal display (4KB). Large results get an OSS download link. Billing shown here is pre-settlement; use `qveris usage` or `qveris ledger` for final charge status.
150
156
 
151
157
  ```bash
152
158
  # Inline params
@@ -178,7 +184,7 @@ For terminal use, results larger than 4KB are automatically truncated. The CLI s
178
184
  - The response schema so you know the data structure
179
185
 
180
186
  ```
181
- ✓ success · 1200ms · 5 credits
187
+ ✓ success · 1200ms · 5 credits pre-settlement
182
188
 
183
189
  Response truncated (32KB → 4KB preview)
184
190
 
@@ -199,6 +205,40 @@ Preview:
199
205
 
200
206
  For agent/script use (`--json` or piped output), the default increases to 20KB (matching the MCP server). Use `--max-size -1` for unlimited.
201
207
 
208
+ ### Usage Audit
209
+
210
+ Use `qveris usage` to answer whether recent calls succeeded, failed, or charged credits. It defaults to `summary` mode to protect Agent context.
211
+ Summary mode requests service-side `summary=true` aggregates when available and falls back to bounded client-side aggregation for older deployments.
212
+
213
+ ```bash
214
+ # Aggregate recent usage by hour/day/week
215
+ qveris usage --mode summary --bucket hour
216
+
217
+ # Check one execution precisely
218
+ qveris usage --mode search --execution-id <execution_id> --json
219
+
220
+ # Find high-cost or suspicious records
221
+ qveris usage --mode search --min-credits 30 --max-credits 100 --json
222
+ qveris usage --mode search --charge-outcome failed_charged_review --json
223
+
224
+ # Export raw matching rows to a local JSONL file instead of stdout
225
+ qveris usage --mode export-file --start-date 2026-05-01 --end-date 2026-05-04
226
+ ```
227
+
228
+ ### Credits Ledger
229
+
230
+ Use `qveris ledger` to explain final credit balance movements. It also defaults to `summary` mode.
231
+ Summary mode requests service-side `summary=true` aggregates when available and falls back to bounded client-side aggregation for older deployments.
232
+
233
+ ```bash
234
+ qveris ledger --mode summary --bucket day
235
+ qveris ledger --mode search --direction consume --min-credits 50 --json
236
+ qveris ledger --mode search --entry-type consume_tool_execute --json
237
+ qveris ledger --mode export-file --start-date 2026-05-01 --end-date 2026-05-04
238
+ ```
239
+
240
+ `summary` and `search` never print full history. Large record sets are written to `.qveris/exports/*.jsonl` with `--mode export-file`.
241
+
202
242
  ### Interactive Mode
203
243
 
204
244
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qverisai/cli",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "QVeris CLI -- discover, inspect, and call 10,000+ capabilities",
5
5
  "type": "module",
6
6
  "bin": {
@@ -36,7 +36,12 @@ async function requestJson(path, { method = "POST", query = {}, body, timeoutMs
36
36
  errorDetail = jsonBody.error_message || jsonBody.message || null;
37
37
  } catch { /* not JSON */ }
38
38
  if (status === 401 || status === 403) throw new CliError("AUTH_INVALID_KEY", errorDetail);
39
- if (status === 402) throw new CliError("CREDITS_INSUFFICIENT", errorDetail);
39
+ if (status === 402) {
40
+ const pricingHost = baseUrl.includes("qveris.cn") ? "https://qveris.cn" : "https://qveris.ai";
41
+ const err = new CliError("CREDITS_INSUFFICIENT", errorDetail);
42
+ err.hint = `Purchase credits at ${pricingHost}/pricing`;
43
+ throw err;
44
+ }
40
45
  if (status === 429) throw new CliError("RATE_LIMITED", errorDetail);
41
46
  const err = new CliError("API_ERROR", `HTTP ${status}: ${errorDetail || rawText}`);
42
47
  if (jsonBody) err.responseData = jsonBody;
@@ -57,6 +62,21 @@ async function requestJson(path, { method = "POST", query = {}, body, timeoutMs
57
62
  }
58
63
  }
59
64
 
65
+ export function unwrapApiResponse(response) {
66
+ if (
67
+ response &&
68
+ typeof response === "object" &&
69
+ Object.prototype.hasOwnProperty.call(response, "status") &&
70
+ Object.prototype.hasOwnProperty.call(response, "data")
71
+ ) {
72
+ if (response.status === "failure") {
73
+ throw new CliError("API_ERROR", response.message || "API request failed");
74
+ }
75
+ return response.data;
76
+ }
77
+ return response;
78
+ }
79
+
60
80
  export async function discoverTools({ apiKey, baseUrl: baseUrlFlag, query, limit = 5, timeoutMs = 30000 }) {
61
81
  const baseUrl = getBaseUrl(baseUrlFlag, apiKey);
62
82
  return requestJson("/search", { apiKey, baseUrl, body: { query, limit }, timeoutMs });
@@ -91,3 +111,45 @@ export async function callTool({
91
111
  timeoutMs,
92
112
  });
93
113
  }
114
+
115
+ export async function getCredits({ apiKey, baseUrl: baseUrlFlag, timeoutMs = 30000 }) {
116
+ const baseUrl = getBaseUrl(baseUrlFlag, apiKey);
117
+ return requestJson("/auth/credits", {
118
+ method: "GET",
119
+ apiKey,
120
+ baseUrl,
121
+ timeoutMs,
122
+ });
123
+ }
124
+
125
+ export async function getUsageHistory({
126
+ apiKey,
127
+ baseUrl: baseUrlFlag,
128
+ query = {},
129
+ timeoutMs = 30000,
130
+ }) {
131
+ const baseUrl = getBaseUrl(baseUrlFlag, apiKey);
132
+ return requestJson("/auth/usage/history/v2", {
133
+ method: "GET",
134
+ apiKey,
135
+ baseUrl,
136
+ query,
137
+ timeoutMs,
138
+ });
139
+ }
140
+
141
+ export async function getCreditsLedger({
142
+ apiKey,
143
+ baseUrl: baseUrlFlag,
144
+ query = {},
145
+ timeoutMs = 30000,
146
+ }) {
147
+ const baseUrl = getBaseUrl(baseUrlFlag, apiKey);
148
+ return requestJson("/auth/credits/ledger", {
149
+ method: "GET",
150
+ apiKey,
151
+ baseUrl,
152
+ query,
153
+ timeoutMs,
154
+ });
155
+ }
@@ -1,6 +1,6 @@
1
1
  const COMMANDS = [
2
2
  "discover", "inspect", "call",
3
- "login", "logout", "whoami", "credits",
3
+ "login", "logout", "whoami", "credits", "usage", "ledger",
4
4
  "config", "interactive", "history", "doctor", "completions",
5
5
  ];
6
6
 
@@ -1,5 +1,5 @@
1
1
  import { resolveApiKey } from "../client/auth.mjs";
2
- import { discoverTools } from "../client/api.mjs";
2
+ import { getCredits, unwrapApiResponse } from "../client/api.mjs";
3
3
  import { resolveBaseUrl, getSiteUrl } from "../config/region.mjs";
4
4
  import { bold, dim, cyan, yellow, green } from "../output/colors.mjs";
5
5
  import { outputJson } from "../output/json.mjs";
@@ -13,16 +13,19 @@ export async function runCredits(flags) {
13
13
  const spinner = flags.json ? { stop() {} } : createSpinner("Checking credits...");
14
14
 
15
15
  try {
16
- // The backend returns remaining_credits in every /search response
17
- const result = await discoverTools({ apiKey, baseUrl: flags.baseUrl, query: "credit balance", limit: 1, timeoutMs: 10000 });
16
+ const result = unwrapApiResponse(await getCredits({ apiKey, baseUrl, timeoutMs: 10000 }));
18
17
  spinner.stop();
19
18
 
20
19
  const credits = result.remaining_credits;
21
20
 
22
21
  if (flags.json) {
23
- outputJson({ remaining_credits: credits ?? null });
22
+ outputJson(result);
24
23
  } else if (credits !== undefined && credits !== null) {
25
24
  console.log(`\n ${green("\u2713")} Credits remaining: ${bold(yellow(String(credits)))}`);
25
+ printBucket("Daily free", result.daily_free, "remaining", "total");
26
+ printBucket("Invite reward", result.invite_reward, "remaining", "total");
27
+ printBucket("Welcome bonus", result.welcome_bonus, "remaining", "initial");
28
+ printBucket("Purchased", result.purchased, "remaining", "total");
26
29
  console.log(` ${dim("Manage at:")} ${cyan(accountUrl)}\n`);
27
30
  } else {
28
31
  console.log(`\n ${dim("Credit balance not available in API response.")}`);
@@ -33,3 +36,14 @@ export async function runCredits(flags) {
33
36
  throw err;
34
37
  }
35
38
  }
39
+
40
+ function printBucket(label, bucket, remainingKey, totalKey) {
41
+ if (!bucket || typeof bucket !== "object") return;
42
+ const remaining = bucket[remainingKey];
43
+ const total = bucket[totalKey];
44
+ if (remaining === undefined && total === undefined) return;
45
+ const parts = [];
46
+ if (remaining !== undefined) parts.push(`remaining ${yellow(String(remaining))}`);
47
+ if (total !== undefined) parts.push(`${dim("of")} ${String(total)}`);
48
+ console.log(` ${dim(label + ":")} ${parts.join(" ")}`);
49
+ }
@@ -8,6 +8,7 @@ import { createSpinner } from "../output/spinner.mjs";
8
8
 
9
9
  export async function runDiscover(query, flags) {
10
10
  const apiKey = resolveApiKey(flags.apiKey);
11
+ const { region, baseUrl: resolvedBaseUrl } = resolveBaseUrl({ baseUrlFlag: flags.baseUrl, apiKey });
11
12
  const limit = parseInt(flags.limit, 10) || 5;
12
13
  const timeoutMs = (parseInt(flags.timeout, 10) || 30) * 1000;
13
14
 
@@ -16,7 +17,7 @@ export async function runDiscover(query, flags) {
16
17
  try {
17
18
  const result = await discoverTools({
18
19
  apiKey,
19
- baseUrl: flags.baseUrl,
20
+ baseUrl: resolvedBaseUrl,
20
21
  query,
21
22
  limit,
22
23
  timeoutMs,
@@ -26,7 +27,6 @@ export async function runDiscover(query, flags) {
26
27
 
27
28
  // Store richer session data for index resolution
28
29
  const tools = result.results ?? [];
29
- const { region, baseUrl: resolvedBaseUrl } = resolveBaseUrl({ baseUrlFlag: flags.baseUrl, apiKey });
30
30
  writeSession({
31
31
  discoveryId: result.search_id,
32
32
  query,
@@ -30,7 +30,7 @@ export async function runDoctor(flags) {
30
30
  // Test connectivity
31
31
  process.stderr.write(` \u2026 Testing API connectivity...\r`);
32
32
  try {
33
- await discoverTools({ apiKey, baseUrl: flags.baseUrl, query: "test", limit: 1, timeoutMs: 10000 });
33
+ await discoverTools({ apiKey, baseUrl, query: "test", limit: 1, timeoutMs: 10000 });
34
34
  console.log(` ${green("\u2713")} API connectivity OK `);
35
35
  } catch (err) {
36
36
  console.log(` ${red("\u2718")} API connectivity failed: ${err.message} `);
@@ -14,8 +14,7 @@ import { createSpinner } from "../output/spinner.mjs";
14
14
 
15
15
  export async function runInteractive(flags) {
16
16
  const apiKey = resolveApiKey(flags.apiKey);
17
- const baseUrl = flags.baseUrl;
18
- const { region, baseUrl: resolvedBaseUrl } = resolveBaseUrl({ baseUrlFlag: baseUrl, apiKey });
17
+ const { region, baseUrl: resolvedBaseUrl } = resolveBaseUrl({ baseUrlFlag: flags.baseUrl, apiKey });
19
18
  const limit = parseInt(flags.limit, 10) || 5;
20
19
  const discoverTimeout = (parseInt(flags.timeout, 10) || 30) * 1000;
21
20
  const callTimeout = (parseInt(flags.timeout, 10) || 60) * 1000;
@@ -58,7 +57,7 @@ export async function runInteractive(flags) {
58
57
  const query = rest.join(" ");
59
58
  if (!query) { console.log(" Usage: discover <query>"); break; }
60
59
  const sp = createSpinner("Discovering...");
61
- const result = await discoverTools({ apiKey, baseUrl, query, limit, timeoutMs: discoverTimeout });
60
+ const result = await discoverTools({ apiKey, baseUrl: resolvedBaseUrl, query, limit, timeoutMs: discoverTimeout });
62
61
  sp.stop();
63
62
  state.discoveryId = result.search_id;
64
63
  state.results = (result.results ?? []).map((t, i) => ({
@@ -73,7 +72,7 @@ export async function runInteractive(flags) {
73
72
  const toolId = resolveId(rest[0], state);
74
73
  if (!toolId) { console.log(" Usage: inspect <index|tool_id>"); break; }
75
74
  const sp2 = createSpinner("Inspecting...");
76
- const result = await inspectToolsByIds({ apiKey, baseUrl, toolIds: [toolId], discoveryId: state.discoveryId, timeoutMs: discoverTimeout });
75
+ const result = await inspectToolsByIds({ apiKey, baseUrl: resolvedBaseUrl, toolIds: [toolId], discoveryId: state.discoveryId, timeoutMs: discoverTimeout });
77
76
  sp2.stop();
78
77
  console.log(formatInspectResult(result));
79
78
  break;
@@ -85,7 +84,7 @@ export async function runInteractive(flags) {
85
84
  const paramsStr = rest.slice(1).join(" ") || "{}";
86
85
  const parameters = resolveParams(paramsStr);
87
86
  const sp3 = createSpinner("Calling...");
88
- const result = await callTool({ apiKey, baseUrl, toolId, discoveryId: state.discoveryId, parameters, timeoutMs: callTimeout });
87
+ const result = await callTool({ apiKey, baseUrl: resolvedBaseUrl, toolId, discoveryId: state.discoveryId, parameters, timeoutMs: callTimeout });
89
88
  sp3.stop();
90
89
  console.log(formatCallResult(result));
91
90
  if (result.success) {
@@ -0,0 +1,186 @@
1
+ import { resolveApiKey } from "../client/auth.mjs";
2
+ import { getCreditsLedger, unwrapApiResponse } from "../client/api.mjs";
3
+ import { outputJson } from "../output/json.mjs";
4
+ import { createSpinner } from "../output/spinner.mjs";
5
+ import {
6
+ DEFAULT_PAGE_SIZE,
7
+ MAX_EXPORT_ROWS,
8
+ MAX_SEARCH_SCAN_ROWS,
9
+ MAX_SUMMARY_ROWS,
10
+ buildLedgerQuery,
11
+ buildLedgerSummary,
12
+ buildLedgerSummaryFromServer,
13
+ chooseBucket,
14
+ clampLimit,
15
+ extractItems,
16
+ extractTotal,
17
+ formatExportMetadata,
18
+ formatLedgerRows,
19
+ formatLedgerSummary,
20
+ matchesLedgerFilters,
21
+ pickLedgerRow,
22
+ resolveDateRange,
23
+ resolveMode,
24
+ writeJsonlExport,
25
+ } from "../output/audit.mjs";
26
+
27
+ export async function runLedger(flags) {
28
+ const apiKey = resolveApiKey(flags.apiKey);
29
+ const mode = resolveMode(flags.mode);
30
+ const timeoutMs = (parseInt(flags.timeout, 10) || 30) * 1000;
31
+ const limit = clampLimit(flags.limit);
32
+ const { startDate, endDate } = resolveDateRange(flags);
33
+ const bucket = chooseBucket(startDate, endDate, flags.bucket);
34
+
35
+ const spinner = flags.json ? { stop() {} } : createSpinner("Querying credits ledger...");
36
+
37
+ try {
38
+ if (mode === "search") {
39
+ const { rows, total, partial } = await collectLedgerRows({
40
+ apiKey,
41
+ flags,
42
+ timeoutMs,
43
+ limit,
44
+ maxRows: MAX_SEARCH_SCAN_ROWS,
45
+ stopWhenLimitReached: true,
46
+ });
47
+ spinner.stop();
48
+ const payload = {
49
+ mode,
50
+ start_date: startDate,
51
+ end_date: endDate,
52
+ shown_records: rows.length,
53
+ matched_records: total,
54
+ truncated: partial,
55
+ items: rows.map(pickLedgerRow),
56
+ };
57
+ if (flags.json) outputJson(payload);
58
+ else console.log(formatLedgerRows(rows, { total, partial }));
59
+ return;
60
+ }
61
+
62
+ if (mode === "export_file") {
63
+ const { rows, total, partial } = await collectLedgerRows({
64
+ apiKey,
65
+ flags,
66
+ timeoutMs,
67
+ limit: MAX_EXPORT_ROWS,
68
+ maxRows: MAX_EXPORT_ROWS,
69
+ stopWhenLimitReached: false,
70
+ });
71
+ spinner.stop();
72
+ const metadata = writeJsonlExport("credits_ledger", rows, {
73
+ start_date: startDate,
74
+ end_date: endDate,
75
+ matched_records: total,
76
+ truncated: partial,
77
+ filters: ledgerFilters(flags),
78
+ });
79
+ if (flags.json) outputJson(metadata);
80
+ else console.log(formatExportMetadata(metadata));
81
+ return;
82
+ }
83
+
84
+ const summaryResponse = unwrapApiResponse(await getCreditsLedger({
85
+ apiKey,
86
+ baseUrl: flags.baseUrl,
87
+ query: buildLedgerQuery(flags, {
88
+ page: 1,
89
+ pageSize: limit,
90
+ mode: "summary",
91
+ }),
92
+ timeoutMs,
93
+ }));
94
+ if (summaryResponse?.summary) {
95
+ spinner.stop();
96
+ const rows = extractItems(summaryResponse);
97
+ const total = extractTotal(summaryResponse, rows.length);
98
+ const summary = buildLedgerSummaryFromServer(summaryResponse.summary, { startDate, endDate, bucket });
99
+ if (flags.json) {
100
+ outputJson({
101
+ mode,
102
+ summary,
103
+ scanned_records: rows.length,
104
+ matched_records: total,
105
+ truncated: false,
106
+ });
107
+ } else {
108
+ console.log(formatLedgerSummary(summary, { scannedRows: rows.length, total, partial: false }));
109
+ }
110
+ return;
111
+ }
112
+
113
+ const { rows, total, partial, scannedRows } = await collectLedgerRows({
114
+ apiKey,
115
+ flags,
116
+ timeoutMs,
117
+ limit: MAX_SUMMARY_ROWS,
118
+ maxRows: MAX_SUMMARY_ROWS,
119
+ stopWhenLimitReached: false,
120
+ });
121
+ spinner.stop();
122
+ const summary = buildLedgerSummary(rows, { startDate, endDate, bucket });
123
+ if (flags.json) {
124
+ outputJson({
125
+ mode,
126
+ summary,
127
+ scanned_records: scannedRows,
128
+ matched_records: total,
129
+ truncated: partial,
130
+ });
131
+ } else {
132
+ console.log(formatLedgerSummary(summary, { scannedRows, total, partial }));
133
+ }
134
+ } catch (err) {
135
+ spinner.stop();
136
+ throw err;
137
+ }
138
+ }
139
+
140
+ async function collectLedgerRows({ apiKey, flags, timeoutMs, limit, maxRows, stopWhenLimitReached }) {
141
+ const rows = [];
142
+ let page = 1;
143
+ let total;
144
+ let scannedRows = 0;
145
+ let partial = false;
146
+
147
+ while (rows.length < limit && scannedRows < maxRows) {
148
+ const query = buildLedgerQuery(flags, { page, pageSize: Math.min(DEFAULT_PAGE_SIZE, maxRows - scannedRows) });
149
+ const response = unwrapApiResponse(await getCreditsLedger({
150
+ apiKey,
151
+ baseUrl: flags.baseUrl,
152
+ query,
153
+ timeoutMs,
154
+ }));
155
+ const items = extractItems(response);
156
+ if (total === undefined) total = extractTotal(response, undefined);
157
+ if (items.length === 0) break;
158
+ scannedRows += items.length;
159
+ for (const item of items) {
160
+ if (!matchesLedgerFilters(item, flags)) continue;
161
+ rows.push(item);
162
+ if (stopWhenLimitReached && rows.length >= limit) break;
163
+ }
164
+ if (stopWhenLimitReached && rows.length >= limit) {
165
+ partial = Boolean(total && total > scannedRows);
166
+ break;
167
+ }
168
+ if (total !== undefined && scannedRows >= total) break;
169
+ if (items.length < DEFAULT_PAGE_SIZE) break;
170
+ page += 1;
171
+ }
172
+
173
+ if (total !== undefined && scannedRows < total) partial = true;
174
+ if (scannedRows >= maxRows && (total === undefined || scannedRows < total)) partial = true;
175
+
176
+ return { rows: rows.slice(0, limit), total, partial, scannedRows };
177
+ }
178
+
179
+ function ledgerFilters(flags) {
180
+ return {
181
+ entry_type: flags.entryType,
182
+ direction: flags.direction,
183
+ min_credits: flags.minCredits,
184
+ max_credits: flags.maxCredits,
185
+ };
186
+ }