secufusion-mcp 1.0.7 → 1.0.9

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/index.js +62 -18
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -49,6 +49,36 @@ function getCurrentBranch(cwd) {
49
49
  }
50
50
  }
51
51
  // ─────────────────────────────────────────────
52
+ // Telemetry & Compression helpers
53
+ // ─────────────────────────────────────────────
54
+ function compressCode(code) {
55
+ return code
56
+ .replace(/\/\*[\s\S]*?\*\//g, "") // Remove multi-line comments
57
+ .replace(/\/\/.*$/gm, "") // Remove single-line comments
58
+ .replace(/^\s*[\r\n]/gm, "") // Remove empty lines
59
+ .replace(/[ \t]+$/gm, ""); // Remove trailing whitespace
60
+ }
61
+ function appendTelemetry(response, inputChars) {
62
+ const inputTokens = Math.ceil(inputChars / 4);
63
+ let outputChars = 0;
64
+ if (response.content && Array.isArray(response.content)) {
65
+ for (const c of response.content) {
66
+ if (c.type === "text" && c.text) {
67
+ outputChars += c.text.length;
68
+ }
69
+ }
70
+ }
71
+ const outputTokens = Math.ceil(outputChars / 4);
72
+ const inputCost = (inputTokens / 1000000) * 3.0;
73
+ const outputCost = (outputTokens / 1000000) * 15.0;
74
+ const totalCost = (inputCost + outputCost).toFixed(4);
75
+ const telemetry = `\n\n> 📊 Telemetry\n> Input Tokens: ~${inputTokens}\n> Output Tokens: ~${outputTokens}\n> Estimated Cost: ${totalCost}`;
76
+ if (response.content && response.content.length > 0 && response.content[0].type === "text") {
77
+ response.content[0].text += telemetry;
78
+ }
79
+ return response;
80
+ }
81
+ // ─────────────────────────────────────────────
52
82
  // run_pre_pr_checks helpers
53
83
  // ─────────────────────────────────────────────
54
84
  const CONSOLE_LOG_REGEX = [
@@ -282,6 +312,7 @@ server.tool("manage_branch_state", "Manage the structured JSON state for the cur
282
312
  .optional()
283
313
  .describe("Explicit actionable instruction for resuming. Required for 'update'."),
284
314
  }, async ({ action, task_description, reference_file_path, pending_acs, completed_acs, next_step }) => {
315
+ const inputChars = JSON.stringify({ action, task_description, reference_file_path, pending_acs, completed_acs, next_step }).length;
285
316
  const cwd = process.cwd();
286
317
  const branch = getCurrentBranch(cwd);
287
318
  const statePath = path.resolve(STATE_FILE);
@@ -297,18 +328,18 @@ server.tool("manage_branch_state", "Manage the structured JSON state for the cur
297
328
  if (action === "read") {
298
329
  const branchState = state[branch];
299
330
  if (!branchState) {
300
- return {
331
+ return appendTelemetry({
301
332
  content: [
302
333
  {
303
334
  type: "text",
304
335
  text: `No state found for branch '${branch}'. Please initialize first.`,
305
336
  },
306
337
  ],
307
- };
338
+ }, inputChars);
308
339
  }
309
- return {
340
+ return appendTelemetry({
310
341
  content: [{ type: "text", text: JSON.stringify(branchState, null, 2) }],
311
- };
342
+ }, inputChars);
312
343
  }
313
344
  if (action === "initialize") {
314
345
  state[branch] = {
@@ -320,31 +351,42 @@ server.tool("manage_branch_state", "Manage the structured JSON state for the cur
320
351
  last_updated: new Date().toISOString()
321
352
  };
322
353
  writeFile(statePath, JSON.stringify(state, null, 2));
323
- return {
354
+ let refText = "";
355
+ if (reference_file_path) {
356
+ const refPath = resolve(reference_file_path);
357
+ const content = readFileSafe(refPath);
358
+ if (content) {
359
+ refText = `\n\n**Reference Code (Compressed):**\n\`\`\`\n${compressCode(content)}\n\`\`\``;
360
+ }
361
+ else {
362
+ refText = `\n\n*(Warning: reference file '${reference_file_path}' not found)*`;
363
+ }
364
+ }
365
+ return appendTelemetry({
324
366
  content: [
325
367
  {
326
368
  type: "text",
327
- text: `✅ Branch state initialized for '${branch}'.\n\nState:\n${JSON.stringify(state[branch], null, 2)}`,
369
+ text: `✅ Branch state initialized for '${branch}'.\n\nState:\n${JSON.stringify(state[branch], null, 2)}${refText}`,
328
370
  },
329
371
  ],
330
- };
372
+ }, inputChars);
331
373
  }
332
374
  if (action === "update") {
333
375
  if (!state[branch]) {
334
- return {
376
+ return appendTelemetry({
335
377
  isError: true,
336
378
  content: [
337
379
  { type: "text", text: `No state found for branch '${branch}'. Initialize first.` },
338
380
  ],
339
- };
381
+ }, inputChars);
340
382
  }
341
383
  if (!next_step) {
342
- return {
384
+ return appendTelemetry({
343
385
  isError: true,
344
386
  content: [
345
387
  { type: "text", text: "ERROR: 'next_step' is required when updating." },
346
388
  ],
347
- };
389
+ }, inputChars);
348
390
  }
349
391
  if (pending_acs)
350
392
  state[branch].pending_acs = pending_acs;
@@ -353,16 +395,16 @@ server.tool("manage_branch_state", "Manage the structured JSON state for the cur
353
395
  state[branch].next_step = next_step;
354
396
  state[branch].last_updated = new Date().toISOString();
355
397
  writeFile(statePath, JSON.stringify(state, null, 2));
356
- return {
398
+ return appendTelemetry({
357
399
  content: [
358
400
  {
359
401
  type: "text",
360
402
  text: `✅ Branch state updated for '${branch}'. Next step recorded:\n> ${next_step}`,
361
403
  },
362
404
  ],
363
- };
405
+ }, inputChars);
364
406
  }
365
- return { content: [{ type: "text", text: "Invalid action." }] };
407
+ return appendTelemetry({ content: [{ type: "text", text: "Invalid action." }] }, inputChars);
366
408
  });
367
409
  // ─── Tool 2: log_rejected_pattern ────────────────────────────────────────────
368
410
  server.tool("log_rejected_pattern", "Record a coding pattern that was rejected by the team so it is never repeated. " +
@@ -390,6 +432,7 @@ server.tool("log_rejected_pattern", "Record a coding pattern that was rejected b
390
432
  .optional()
391
433
  .describe("Optional: the file or code area where this was observed."),
392
434
  }, async ({ pattern, reason, category, file_context }) => {
435
+ const inputChars = JSON.stringify({ pattern, reason, category, file_context }).length;
393
436
  const rejectedPath = resolve(REJECTED_FILE);
394
437
  let records = [];
395
438
  const existing = readFileSafe(rejectedPath);
@@ -411,7 +454,7 @@ server.tool("log_rejected_pattern", "Record a coding pattern that was rejected b
411
454
  };
412
455
  records.push(newEntry);
413
456
  writeFile(rejectedPath, JSON.stringify(records, null, 2));
414
- return {
457
+ return appendTelemetry({
415
458
  content: [
416
459
  {
417
460
  type: "text",
@@ -422,7 +465,7 @@ server.tool("log_rejected_pattern", "Record a coding pattern that was rejected b
422
465
  `This will be checked automatically in all future architectural suggestions.`,
423
466
  },
424
467
  ],
425
- };
468
+ }, inputChars);
426
469
  });
427
470
  // ─── Tool 3: run_pre_pr_checks ───────────────────────────────────────────────
428
471
  server.tool("run_pre_pr_checks", "Run all SecuFusion pre-PR guardrail checks across the workspace. " +
@@ -448,6 +491,7 @@ server.tool("run_pre_pr_checks", "Run all SecuFusion pre-PR guardrail checks acr
448
491
  .optional()
449
492
  .describe("Explicitly skip specific checks. Use sparingly — document the reason in your PR description."),
450
493
  }, async ({ work_item_id, root_dir, skip_checks = [] }) => {
494
+ const inputChars = JSON.stringify({ work_item_id, root_dir, skip_checks }).length;
451
495
  const scanRoot = root_dir ? path.resolve(root_dir) : process.cwd();
452
496
  const errors = [];
453
497
  const warnings = [];
@@ -613,10 +657,10 @@ server.tool("run_pre_pr_checks", "Run all SecuFusion pre-PR guardrail checks acr
613
657
  `- **Ready to raise PR** 🚀\n` +
614
658
  rejectedReminder;
615
659
  }
616
- return {
660
+ return appendTelemetry({
617
661
  content: [{ type: "text", text: report }],
618
662
  isError: hasErrors,
619
- };
663
+ }, inputChars);
620
664
  });
621
665
  // ─────────────────────────────────────────────
622
666
  // Start transport
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "secufusion-mcp",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "type": "module",
5
5
  "description": "SecuFusion MCP server - developer workflow tooling with guardrails",
6
6
  "main": "index.js",