qualmcp 0.1.1 → 0.1.3

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/tools.js +24 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qualmcp",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "qualmcp": "src/cli.js"
package/src/tools.js CHANGED
@@ -31,7 +31,7 @@ function safeLimit(v, max = 200) {
31
31
 
32
32
  export const tools = {
33
33
  analytics_salesRank: {
34
- name: 'analytics.salesRank',
34
+ name: 'analytics_salesRank',
35
35
  description: 'Ranking of products by sales quantity/revenue across orders with flexible filters and grouping. Always returns product names when possible.',
36
36
  schema: z.object({
37
37
  dateFrom: z.string().datetime().optional(),
@@ -169,7 +169,7 @@ export const tools = {
169
169
  },
170
170
 
171
171
  analytics_stockHealth: {
172
- name: 'analytics.stockHealth',
172
+ name: 'analytics_stockHealth',
173
173
  description: 'Stock + sales velocity and days-cover metrics per product (optionally per store). Returns product names and signals; interpretation is left to the agent.',
174
174
  schema: z.object({
175
175
  storeId: z.number().optional(),
@@ -179,8 +179,8 @@ export const tools = {
179
179
  orderScope: OrderScopeSchema,
180
180
  includeZeroSales: z.boolean().default(true),
181
181
  minSalesQty: z.number().default(0),
182
- limit: z.number().optional(),
183
- offset: z.number().optional()
182
+ limit: z.number().default(200),
183
+ offset: z.number().default(0)
184
184
  }),
185
185
  handler: async (input) => {
186
186
  const {
@@ -213,8 +213,8 @@ export const tools = {
213
213
  clauses.push(`o.${field} <= $${params.length}`);
214
214
 
215
215
  const where = clauses.length > 0 ? clauses.join(' AND ') : '1=1';
216
- const lim = safeLimit(limit, 500);
217
- const off = Math.max(0, Math.floor(Number(offset || 0)));
216
+ const lim = safeLimit(limit ?? 200, 2000);
217
+ const off = Math.max(0, Math.floor(Number(offset ?? 0)));
218
218
 
219
219
  const sql = `
220
220
  WITH stock AS (
@@ -288,7 +288,7 @@ export const tools = {
288
288
  LIMIT 1
289
289
  ) pr ON TRUE
290
290
  )
291
- SELECT *
291
+ SELECT *, COUNT(*) OVER()::bigint AS total_count
292
292
  FROM with_product
293
293
  WHERE (sales_qty_window >= $${params.length + 1})
294
294
  ${includeZeroSales ? '' : 'AND sales_qty_window > 0'}
@@ -301,6 +301,15 @@ export const tools = {
301
301
 
302
302
  const res = await query(sql, [...params, Number(minSalesQty || 0)]);
303
303
 
304
+ const rows = (res.rows || []).map((r) => {
305
+ if (!r || typeof r !== 'object') return r;
306
+ const { total_count, ...rest } = r;
307
+ return rest;
308
+ });
309
+
310
+ const total = res.rows && res.rows.length > 0 ? Number(res.rows[0].total_count || 0) : 0;
311
+ const hasMore = off + rows.length < total;
312
+
304
313
  return {
305
314
  window: {
306
315
  from: from.toISOString(),
@@ -308,13 +317,19 @@ export const tools = {
308
317
  days: windowDays,
309
318
  dateField: field
310
319
  },
311
- rows: res.rows || []
320
+ meta: {
321
+ limit: lim,
322
+ offset: off,
323
+ total,
324
+ hasMore
325
+ },
326
+ rows
312
327
  };
313
328
  }
314
329
  },
315
330
 
316
331
  analytics_salesTimeSeries: {
317
- name: 'analytics.salesTimeSeries',
332
+ name: 'analytics_salesTimeSeries',
318
333
  description: 'Time series aggregation of orders and items sold over time buckets (day/week/month) with flexible orderScope.',
319
334
  schema: z.object({
320
335
  dateFrom: z.string().datetime().optional(),