zephyr-enterprise-tools 1.2.1 → 1.2.2

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/mcp-server.js CHANGED
@@ -167,6 +167,23 @@ const TOOLS = [
167
167
  required: ['projectId', 'releaseId'],
168
168
  },
169
169
  },
170
+ {
171
+ name: 'user_trend',
172
+ description: 'Get full audit log activity for a user — every action they performed across the system. Filter by date range and optionally by entity type (project or release).',
173
+ inputSchema: {
174
+ type: 'object',
175
+ properties: {
176
+ userName: { type: 'string', description: 'Username to look up (e.g. "dylan.garcia")' },
177
+ fromDate: { type: 'string', description: 'Start date YYYY-MM-DD (e.g. "2026-08-01")' },
178
+ toDate: { type: 'string', description: 'End date YYYY-MM-DD (e.g. "2026-08-18")' },
179
+ entity: { type: 'string', description: 'Filter by entity type: "project", "release", or "" for all', enum: ['project', 'release', ''] },
180
+ operation: { type: 'string', description: 'Filter by operation (e.g. "CREATE", "UPDATE"). Omit for all.' },
181
+ offset: { type: 'number', description: 'Pagination offset (default 0)' },
182
+ pageSize: { type: 'number', description: 'Records per page (default 25)' },
183
+ },
184
+ required: ['userName'],
185
+ },
186
+ },
170
187
  {
171
188
  name: 'list_projects',
172
189
  description: 'List all available Zephyr projects.',
@@ -282,6 +299,18 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
282
299
  case 'user_activity':
283
300
  result = await tools.getUserActivity(projectId, releaseId, { days: args.days || 30 });
284
301
  break;
302
+
303
+ case 'user_trend':
304
+ result = await tools.getUserTrend({
305
+ userName: args.userName,
306
+ fromDate: args.fromDate || null,
307
+ toDate: args.toDate || null,
308
+ entity: args.entity || '',
309
+ operation: args.operation || null,
310
+ offset: args.offset || 0,
311
+ pageSize: args.pageSize || 25,
312
+ });
313
+ break;
285
314
 
286
315
  case 'list_projects':
287
316
  const projects = await tools.GET('/project');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zephyr-enterprise-tools",
3
- "version": "1.2.1",
3
+ "version": "1.2.2",
4
4
  "description": "Comprehensive Zephyr Enterprise Tools - Release Readiness, Project Health, Test Analytics & More",
5
5
  "main": "zephyr-enterprise-tools.js",
6
6
  "types": "zephyr-enterprise-tools.d.ts",
@@ -1285,6 +1285,99 @@ export class QualityGates {
1285
1285
  topExecutors: executors.slice(0, 5),
1286
1286
  };
1287
1287
  }
1288
+
1289
+ // ─── User Trend (Audit Logs) ─────────────────────────────────────────────────
1290
+
1291
+ async getUserTrend(options = {}) {
1292
+ const {
1293
+ userName = "",
1294
+ fromDate = null, // "YYYY-MM-DD"
1295
+ toDate = null, // "YYYY-MM-DD"
1296
+ entity = "", // "project", "release", or "" for all
1297
+ operation = null, // specific operation or null for all
1298
+ offset = 0,
1299
+ pageSize = 25,
1300
+ } = options;
1301
+
1302
+ const v3BaseUrl = this.baseUrl.replace('/latest', '/v3');
1303
+ const url = new URL(`${v3BaseUrl}/ui/auditLogs`);
1304
+ url.searchParams.set("offset", String(offset));
1305
+ url.searchParams.set("pagesize", String(pageSize));
1306
+ url.searchParams.set("isascorder", "false");
1307
+ url.searchParams.set("order", "id");
1308
+ url.searchParams.set("isExport", "false");
1309
+
1310
+ const body = { entity, operation, userName };
1311
+
1312
+ if (fromDate) {
1313
+ body.fromDate = fromDate;
1314
+ body.fromDateVal = `${fromDate}T00:00:00.000Z`;
1315
+ }
1316
+ if (toDate) {
1317
+ body.toDate = toDate;
1318
+ body.toDateVal = `${toDate}T00:00:00.000Z`;
1319
+ }
1320
+
1321
+ const res = await fetch(url.toString(), {
1322
+ method: "POST",
1323
+ headers: {
1324
+ Accept: "application/json",
1325
+ "Content-Type": "application/json",
1326
+ ...this.authHeader(),
1327
+ },
1328
+ body: JSON.stringify(body),
1329
+ });
1330
+
1331
+ if (!res.ok) {
1332
+ const text = await res.text().catch(() => "");
1333
+ throw new Error(`Zephyr audit logs API ${res.status}: ${text}`);
1334
+ }
1335
+
1336
+ const data = await res.json();
1337
+ const logs = data.results || data || [];
1338
+
1339
+ // Summarise by operation and entity type
1340
+ const byOperation = {};
1341
+ const byEntity = {};
1342
+ for (const log of logs) {
1343
+ const op = log.operation || "Unknown";
1344
+ const ent = log.entity || "Unknown";
1345
+ byOperation[op] = (byOperation[op] || 0) + 1;
1346
+ byEntity[ent] = (byEntity[ent] || 0) + 1;
1347
+ }
1348
+
1349
+ return {
1350
+ tool: "User Trend",
1351
+ userName,
1352
+ dateRange: { from: fromDate || "all", to: toDate || "all" },
1353
+ entity: entity || "all",
1354
+ timestamp: new Date().toISOString(),
1355
+ totalRecords: data.totalCount ?? logs.length,
1356
+ offset,
1357
+ pageSize,
1358
+ operationSummary: Object.entries(byOperation)
1359
+ .map(([operation, count]) => ({ operation, count }))
1360
+ .sort((a, b) => b.count - a.count),
1361
+ entitySummary: Object.entries(byEntity)
1362
+ .map(([entity, count]) => ({ entity, count }))
1363
+ .sort((a, b) => b.count - a.count),
1364
+ auditLogs: logs.map(log => ({
1365
+ id: log.id,
1366
+ userName: log.userName,
1367
+ entity: log.entity,
1368
+ entityName: log.entityName,
1369
+ operation: log.operation,
1370
+ description: log.description,
1371
+ detail: log.detail,
1372
+ projectId: log.projectId,
1373
+ projectName: log.projectName,
1374
+ releaseId: log.releaseId,
1375
+ releaseName: log.releaseName,
1376
+ createdOn: log.createdOn,
1377
+ ipAddress: log.ipAddress,
1378
+ })),
1379
+ };
1380
+ }
1288
1381
  }
1289
1382
 
1290
1383
  // Export with both names for backward compatibility