prism-mcp-server 19.2.2 → 19.2.5

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
@@ -93,7 +93,7 @@ Every `prism_infer` call tracks which model handled it (local Ollama vs cloud) a
93
93
  synalux-27b: 2 calls, 1,500 tokens, avg 1,100ms
94
94
  ```
95
95
 
96
- Local calls use actual Ollama token counts; cloud calls use estimates. Metrics are aggregated by the Synalux portal Prism is a thin client that forwards per-call data and fetches the summary on demand.
96
+ Local calls use actual Ollama token counts (`prompt_eval_count` / `eval_count` from Ollama); cloud calls use char/4 estimates. Metrics are tracked locally no portal dependency, no env vars, works offline. Per-call data is also forwarded to the Synalux portal as best-effort analytics (independent of the display).
97
97
 
98
98
  ### Session Drift Detection
99
99
 
@@ -363,7 +363,7 @@ All on-device models are free to run locally via Ollama on every tier. A subscri
363
363
  | Cloud Coder (Web IDE) | -- | 100/day | 1,000/day | 100,000/day |
364
364
  | Cloud search | -- | 50/day | 500/day | 100,000/day |
365
365
  | Max output tokens | 512 | 1,024 | 2,048 | 4,096 |
366
- | Cloud fallback | -- | Claude Sonnet 4 | Claude Sonnet 4 | Priority + Sonnet 4 |
366
+ | Cloud fallback | -- | Claude Opus 4.7 | Claude Opus 4.7 | Priority + Opus 4.7 |
367
367
  | Grounding verifier (fact-check AI output) | -- | ✅ | ✅ | ✅ |
368
368
  | Memory sync (cloud) | -- | ✅ | ✅ | ✅ |
369
369
  | Knowledge / session memory | limited | unlimited | unlimited | unlimited |
@@ -389,6 +389,7 @@ Prism exposes 40+ MCP tools. The core memory loop:
389
389
  | `verify_behavior` | Pre-edit scenario challenge — catch bad changes before they happen |
390
390
  | `knowledge_ingest` | Teach Prism a codebase or document |
391
391
  | `prism_infer` | Local-first inference (route/chat/code modes, thinking, cloud escalation) |
392
+ | `inference_metrics` | Session delegation stats on demand (call count, tokens, local/cloud split) |
392
393
 
393
394
  ### `prism_infer` — local-first inference with cloud escalation
394
395
 
@@ -411,6 +412,40 @@ prism_infer({
411
412
 
412
413
  Full TypeScript signatures live in [`src/tools/`](src/tools/); architecture in [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).
413
414
 
415
+ ### `inference_metrics` — see your local-model usage on demand
416
+
417
+ Call `inference_metrics` anytime mid-session to see how many `prism_infer` calls ran locally vs cloud, with actual token counts:
418
+
419
+ ```
420
+ 📊 Inference Metrics — local-model delegation (this session):
421
+ Total calls: 5 — Local: 5 (100%) | Cloud: 0 (0%)
422
+ Tokens: 1,240 in + 380 out = 1,620 total
423
+ Avg latency: 420ms
424
+ By model:
425
+ prism-coder:27b: 3 calls, 1,100 tokens, avg 520ms
426
+ prism-coder:9b: 2 calls, 520 tokens, avg 270ms
427
+ ```
428
+
429
+ The same block also appears automatically in `session_save_ledger` and `session_save_handoff` responses at session end.
430
+
431
+ **Note:** This tracks `prism_infer` delegation only — not your host model's (Claude's) own token spend. For that, use Claude Code's `/cost` command.
432
+
433
+ ### Local-model delegation (opt-in)
434
+
435
+ By default, your AI agent (Claude, Cursor, etc.) handles everything itself. You can optionally enable delegation so the agent offloads cheap, verifiable sub-tasks to local Ollama models at $0:
436
+
437
+ ```bash
438
+ # Enable via Prism config
439
+ prism config set delegation_enabled true
440
+ ```
441
+
442
+ When enabled, the agent's task router may delegate qualifying work — bulk classification, field extraction, mechanical formatting — to `prism_infer` instead of using cloud tokens. The agent always verifies the result and redoes it itself if quality is degraded.
443
+
444
+ **Guardrails:**
445
+ - **Off by default** — enforced in code, not just convention
446
+ - **Never delegates:** code/text that ships to the user, security/safety logic, planning/reasoning, anything where a silent quality drop isn't obvious
447
+ - **Always verifies:** checks `quality_gate_failed` and `used_cloud` before trusting local output
448
+
414
449
  <details>
415
450
  <summary>How Prism survives context compaction</summary>
416
451
 
@@ -553,6 +588,7 @@ Routing is automatic: `9b → 4b → cloud fallback` on desktop/server, `2b →
553
588
  | `PRISM_SYNALUX_API_KEY` | Paid-tier portal key (`synalux_sk_...`) | -- (local if unset) |
554
589
  | `LOCAL_LLM_URL` | Ollama endpoint | `http://localhost:11434` |
555
590
  | `PRISM_FORCE_LOCAL` | Force local SQLite regardless of credentials | `false` |
591
+ | `TELEMETRY_WRITE_TOKEN` | Portal analytics token (optional — metrics display works without it) | -- |
556
592
 
557
593
  With no variables set, Prism runs fully local. Set `PRISM_SYNALUX_API_KEY` (and leave `PRISM_STORAGE=auto`) to use the cloud backend.
558
594
 
@@ -561,11 +597,11 @@ With no variables set, Prism runs fully local. Set `PRISM_SYNALUX_API_KEY` (and
561
597
  ## Testing
562
598
 
563
599
  ```bash
564
- npm test # full suite (vitest)
600
+ npm test # full suite (vitest) — 95 files, 2841 tests
565
601
  npm test -- --coverage # coverage report
566
602
  ```
567
603
 
568
- Coverage spans HRR retrieval, knowledge ingestion, the inference cascade and grounding verifier, compaction, the model picker, and storage round-trips.
604
+ Coverage spans HRR retrieval, knowledge ingestion, the inference cascade and grounding verifier, inference metrics, telemetry allowlist, delegation gate, compaction, the model picker, and storage round-trips.
569
605
 
570
606
  ---
571
607
 
package/dist/server.js CHANGED
@@ -79,6 +79,7 @@ import { sanitizeMcpOutput } from "./utils/sanitizer.js";
79
79
  import { getTracer, initTelemetry } from "./utils/telemetry.js";
80
80
  import { context as otelContext, trace, SpanStatusCode } from "@opentelemetry/api";
81
81
  import { ddInfo, ddError as ddLogError } from "./utils/ddLogger.js";
82
+ import { inferenceMetricsHandler } from "./utils/inferenceMetrics.js";
82
83
  // ─── Import Tool Definitions (schemas) and Handlers (implementations) ─────
83
84
  import { WEB_SEARCH_TOOL, BRAVE_WEB_SEARCH_CODE_MODE_TOOL, LOCAL_SEARCH_TOOL, BRAVE_LOCAL_SEARCH_CODE_MODE_TOOL, CODE_MODE_TRANSFORM_TOOL, BRAVE_ANSWERS_TOOL, RESEARCH_PAPER_ANALYSIS_TOOL, webSearchHandler, braveWebSearchCodeModeHandler, localSearchHandler, braveLocalSearchCodeModeHandler, codeModeTransformHandler, braveAnswersHandler, researchPaperAnalysisHandler, } from "./tools/index.js";
84
85
  // Session memory tools — only used if Supabase is configured
@@ -112,7 +113,9 @@ VERIFY_BEHAVIOR_TOOL, isVerifyBehaviorArgs,
112
113
  // v12: Developer Onboarding & Enterprise Observability
113
114
  ONBOARDING_WIZARD_TOOL, EXTRACT_ENTITIES_TOOL, API_ANALYTICS_TOOL, BACKUP_DATABASE_TOOL, CONFIGURE_NOTIFICATIONS_TOOL, QUERY_MEMORY_NATURAL_TOOL,
114
115
  // v15.5: Knowledge Ingestion
115
- KNOWLEDGE_INGEST_TOOL, sessionSaveLedgerHandler, sessionSaveHandoffHandler, sessionLoadContextHandler, knowledgeSearchHandler, knowledgeForgetHandler,
116
+ KNOWLEDGE_INGEST_TOOL,
117
+ // v19.2: Inference Metrics
118
+ INFERENCE_METRICS_TOOL, sessionSaveLedgerHandler, sessionSaveHandoffHandler, sessionLoadContextHandler, knowledgeSearchHandler, knowledgeForgetHandler,
116
119
  // ─── v0.4.0: New tool handlers ───
117
120
  compactLedgerHandler, sessionSearchMemoryHandler, backfillEmbeddingsHandler, sessionBackfillLinksHandler, sessionSynthesizeEdgesHandler, sessionCognitiveRouteHandler,
118
121
  // ─── v2.0: Time Travel handlers ───
@@ -246,6 +249,8 @@ function buildSessionMemoryTools(autoloadList) {
246
249
  QUERY_MEMORY_NATURAL_TOOL, // query_memory_natural — NL → structured memory search
247
250
  // ─── v15.5: Knowledge Ingestion ───
248
251
  KNOWLEDGE_INGEST_TOOL, // knowledge_ingest — chunk code, gen Q&A, store in graph
252
+ // ─── v19.2: Inference Metrics ───
253
+ INFERENCE_METRICS_TOOL, // inference_metrics — read-only session delegation stats
249
254
  ];
250
255
  }
251
256
  // ─── v0.4.0: Resource Subscription Tracking ──────────────────────
@@ -960,6 +965,9 @@ export function createServer() {
960
965
  throw new Error("Session memory not configured.");
961
966
  result = await knowledgeIngestHandler(args);
962
967
  break;
968
+ case "inference_metrics":
969
+ result = await inferenceMetricsHandler();
970
+ break;
963
971
  default:
964
972
  result = {
965
973
  content: [{ type: "text", text: `Unknown tool: ${name}` }],
@@ -63,6 +63,7 @@ export { verifyBehaviorHandler } from "./behavioralVerifierHandler.js";
63
63
  // Chunks source code, generates Q&A via Claude Haiku, stores in knowledge graph.
64
64
  // Three entry points: MCP tool, REST API, GitHub webhook.
65
65
  export { KNOWLEDGE_INGEST_TOOL } from "./ingestDefinitions.js";
66
+ export { INFERENCE_METRICS_TOOL } from "./sessionMemoryDefinitions.js";
66
67
  export { knowledgeIngestHandler, handleGitHubWebhook, ingestKnowledge, isIngestArgs } from "./ingestHandler.js";
67
68
  // ── v15.4: prism_infer — local-first inference (RAM-gated cascade) ──
68
69
  // Always available. Saves caller's cloud tokens by routing to local
@@ -40,8 +40,8 @@ isSessionForgetMemoryArgs, // v3.1: TTL retention policy type guard
40
40
  isSessionSaveExperienceArgs, isSessionExportMemoryArgs, normalizeExportFormat, isSessionSaveImageArgs, isSessionViewImageArgs } from "./sessionMemoryDefinitions.js";
41
41
  // v4.2: File system access for knowledge_sync_rules
42
42
  import { writeFile } from "node:fs/promises";
43
- import { existsSync } from "node:fs";
44
- import { join } from "node:path";
43
+ import { existsSync, realpathSync, mkdirSync } from "node:fs";
44
+ import { join, sep } from "node:path";
45
45
  // v3.1: In-memory debounce lock for auto-compaction.
46
46
  // Prevents multiple concurrent Gemini compaction tasks for the same project
47
47
  // when many agents call session_save_ledger at the same time.
@@ -1448,7 +1448,13 @@ export async function sessionExportMemoryHandler(args) {
1448
1448
  // to select the correct .obsidian/.logseq sidecar config.
1449
1449
  const requestedFormat = rawFormat;
1450
1450
  const format = normalizeExportFormat(rawFormat);
1451
- // Validate output directory
1451
+ // Validate output directory — path traversal confinement (v4.3 security)
1452
+ const homeDir = process.env.HOME || process.env.USERPROFILE || "/tmp";
1453
+ const defaultExportDir = join(homeDir, ".prism-mcp", "exports");
1454
+ // Create default export directory if it doesn't exist
1455
+ if (!existsSync(defaultExportDir)) {
1456
+ mkdirSync(defaultExportDir, { recursive: true });
1457
+ }
1452
1458
  if (!existsSync(output_dir)) {
1453
1459
  return {
1454
1460
  content: [{
@@ -1458,6 +1464,72 @@ export async function sessionExportMemoryHandler(args) {
1458
1464
  isError: true,
1459
1465
  };
1460
1466
  }
1467
+ // Resolve symlinks and ".." to get the canonical path
1468
+ const resolvedDir = realpathSync(output_dir);
1469
+ // Build allow-list of safe export roots
1470
+ const allowedRoots = [
1471
+ defaultExportDir,
1472
+ process.cwd(),
1473
+ ];
1474
+ // Scratch root under tmp — but NOT the world-writable tmp root itself.
1475
+ // os.tmpdir() (typically /tmp, mode 1777) is readable and writable by every
1476
+ // local principal: allowing it as an export root would (a) leak unredacted
1477
+ // ledger/handoff contents to other users and (b) let a co-resident attacker
1478
+ // pre-plant a symlink at the predictable export filename and have writeFile
1479
+ // follow it (arbitrary-file overwrite). Confine to an owner-only subdir.
1480
+ const tmpExportDir = join(os.tmpdir(), ".prism-mcp", "exports");
1481
+ if (!existsSync(tmpExportDir)) {
1482
+ mkdirSync(tmpExportDir, { recursive: true, mode: 0o700 });
1483
+ }
1484
+ allowedRoots.push(realpathSync(tmpExportDir));
1485
+ if (process.env.PRISM_EXPORT_ROOT) {
1486
+ const exportRoot = process.env.PRISM_EXPORT_ROOT;
1487
+ if (existsSync(exportRoot)) {
1488
+ allowedRoots.push(realpathSync(exportRoot));
1489
+ }
1490
+ }
1491
+ // Reject sensitive directories (resolve each so macOS /etc → /private/etc matches)
1492
+ const sensitiveRoots = [
1493
+ join(homeDir, ".ssh"),
1494
+ join(homeDir, ".gnupg"),
1495
+ "/etc",
1496
+ "/var",
1497
+ "/etc/cron.d",
1498
+ "/etc/cron.daily",
1499
+ "/etc/sudoers.d",
1500
+ ].map(p => existsSync(p) ? realpathSync(p) : p);
1501
+ // Check allow-list first — explicitly configured roots take precedence
1502
+ const isAllowedRoot = (dir) => allowedRoots.some((root) => {
1503
+ const resolvedRoot = existsSync(root) ? realpathSync(root) : root;
1504
+ return dir === resolvedRoot || dir.startsWith(resolvedRoot + sep);
1505
+ });
1506
+ for (const sensitive of sensitiveRoots) {
1507
+ if (resolvedDir === sensitive || resolvedDir.startsWith(sensitive + sep)) {
1508
+ // Allow explicitly configured roots even under sensitive parents
1509
+ // (e.g. tmpExportDir under /private/var on macOS, or PRISM_EXPORT_ROOT)
1510
+ if (!isAllowedRoot(resolvedDir)) {
1511
+ return {
1512
+ content: [{
1513
+ type: "text",
1514
+ text: `Error: output_dir resolves to a sensitive system directory ("${resolvedDir}"). Export denied.`,
1515
+ }],
1516
+ isError: true,
1517
+ };
1518
+ }
1519
+ }
1520
+ }
1521
+ // Verify resolved path falls under an allowed root
1522
+ if (!isAllowedRoot(resolvedDir)) {
1523
+ return {
1524
+ content: [{
1525
+ type: "text",
1526
+ text: `Error: output_dir "${resolvedDir}" is outside allowed export roots. ` +
1527
+ `Allowed: ${allowedRoots.join(", ")}. ` +
1528
+ `Set PRISM_EXPORT_ROOT env var to add a custom root.`,
1529
+ }],
1530
+ isError: true,
1531
+ };
1532
+ }
1461
1533
  const storage = await getStorage();
1462
1534
  const exportedFiles = [];
1463
1535
  try {
@@ -1527,14 +1599,27 @@ export async function sessionExportMemoryHandler(args) {
1527
1599
  else {
1528
1600
  content = JSON.stringify(exportPayload, null, 2);
1529
1601
  }
1530
- if (format === "vault") {
1531
- await writeFile(outputPath, content);
1602
+ // Exclusive create (flag: "wx") refuses to write if the path already
1603
+ // exists — including a symlink pre-planted at the predictable export
1604
+ // name. On a genuine collision fall back to a timestamped unique name.
1605
+ let finalPath = outputPath;
1606
+ try {
1607
+ await writeFile(finalPath, content, { flag: "wx" });
1532
1608
  }
1533
- else {
1534
- await writeFile(outputPath, content, "utf-8");
1609
+ catch (e) {
1610
+ if (e && e.code === "EEXIST") {
1611
+ const dot = filename.lastIndexOf(".");
1612
+ const stem = dot > 0 ? filename.slice(0, dot) : filename;
1613
+ const extPart = dot > 0 ? filename.slice(dot) : "";
1614
+ finalPath = join(output_dir, `${stem}-${Date.now()}${extPart}`);
1615
+ await writeFile(finalPath, content, { flag: "wx" });
1616
+ }
1617
+ else {
1618
+ throw e;
1619
+ }
1535
1620
  }
1536
- exportedFiles.push(outputPath);
1537
- debugLog(`[session_export_memory] Wrote ${content.length} bytes to ${outputPath}`);
1621
+ exportedFiles.push(finalPath);
1622
+ debugLog(`[session_export_memory] Wrote ${content.length} bytes to ${finalPath}`);
1538
1623
  }
1539
1624
  const plural = exportedFiles.length > 1 ? "files" : "file";
1540
1625
  return {
@@ -1790,3 +1790,15 @@ export function isVerifyBehaviorArgs(a) {
1790
1790
  return false;
1791
1791
  return true;
1792
1792
  }
1793
+ // ─── v19.2: Inference Metrics Tool ──────────────────────────
1794
+ export const INFERENCE_METRICS_TOOL = {
1795
+ name: "inference_metrics",
1796
+ description: "Returns the current session's local-model inference metrics — call count, " +
1797
+ "local vs cloud split, token totals, per-model breakdown, and average latency. " +
1798
+ "Read-only, no arguments. Reflects prism_infer delegation usage only, not the " +
1799
+ "host model's (Claude's) own token spend (use /cost for that).",
1800
+ inputSchema: {
1801
+ type: "object",
1802
+ properties: {},
1803
+ },
1804
+ };
@@ -70,12 +70,21 @@ export function resetInferenceMetrics() {
70
70
  }
71
71
  debugLog("[inference-metrics] Session metrics reset");
72
72
  }
73
+ export async function inferenceMetricsHandler() {
74
+ const block = formatInferenceMetrics();
75
+ return {
76
+ content: [{
77
+ type: "text",
78
+ text: block || "No prism_infer calls this session. Metrics track local-model delegation only — not the host model's (Claude's) token spend.",
79
+ }],
80
+ };
81
+ }
73
82
  export function formatInferenceMetrics() {
74
83
  const snap = getInferenceSnapshot();
75
84
  if (snap.totalCalls === 0)
76
85
  return "";
77
86
  const lines = [
78
- `\n📊 Inference Metrics (this session):`,
87
+ `\n📊 Inference Metrics — local-model delegation (this session):`,
79
88
  ` Total calls: ${snap.totalCalls} — Local: ${snap.localCalls} (${snap.localPct}%) | Cloud: ${snap.cloudCalls} (${snap.cloudPct}%)`,
80
89
  ` Tokens: ${snap.totalPromptTokens.toLocaleString()} in + ${snap.totalCompletionTokens.toLocaleString()} out = ${snap.totalTokens.toLocaleString()} total`,
81
90
  ` Avg latency: ${snap.avgLatencyMs}ms`,
@@ -11,6 +11,7 @@
11
11
  * Zero external dependencies — uses native fetch API.
12
12
  */
13
13
  import { debugLog } from "./logger.js";
14
+ import { lookup } from "node:dns/promises";
14
15
  // ─── Default Config ──────────────────────────────────────────
15
16
  const DEFAULT_CONFIG = {
16
17
  enabled: false,
@@ -99,7 +100,7 @@ function isPrivateIP(ip) {
99
100
  return true;
100
101
  return false;
101
102
  }
102
- function isAllowedUrl(url) {
103
+ async function isAllowedUrl(url) {
103
104
  try {
104
105
  const parsed = new URL(url);
105
106
  // Block non-HTTP(S) schemes
@@ -118,6 +119,18 @@ function isAllowedUrl(url) {
118
119
  // Block bracketed IPv6
119
120
  if (hostname.startsWith("[") && isPrivateIP(hostname))
120
121
  return false;
122
+ // Resolve hostname and reject if ANY address is private (closes
123
+ // attacker.example → 169.254.169.254 / 127.0.0.1 bypass)
124
+ try {
125
+ const addrs = await lookup(hostname, { all: true });
126
+ for (const { address } of addrs) {
127
+ if (isPrivateIP(address))
128
+ return false;
129
+ }
130
+ }
131
+ catch {
132
+ return false;
133
+ }
121
134
  return true;
122
135
  }
123
136
  catch {
@@ -126,7 +139,7 @@ function isAllowedUrl(url) {
126
139
  }
127
140
  // ─── Channel Senders ─────────────────────────────────────────
128
141
  async function sendWebhook(url, payload) {
129
- if (!isAllowedUrl(url)) {
142
+ if (!(await isAllowedUrl(url))) {
130
143
  debugLog(`Webhook URL blocked by SSRF policy: ${url}`);
131
144
  return false;
132
145
  }
@@ -135,6 +148,7 @@ async function sendWebhook(url, payload) {
135
148
  method: "POST",
136
149
  headers: { "Content-Type": "application/json" },
137
150
  body: JSON.stringify(payload),
151
+ redirect: "error",
138
152
  signal: AbortSignal.timeout(10_000),
139
153
  });
140
154
  return response.ok;
@@ -145,7 +159,7 @@ async function sendWebhook(url, payload) {
145
159
  }
146
160
  }
147
161
  async function sendSlack(webhookUrl, payload) {
148
- if (!isAllowedUrl(webhookUrl)) {
162
+ if (!(await isAllowedUrl(webhookUrl))) {
149
163
  debugLog(`Slack webhook URL blocked by SSRF policy: ${webhookUrl}`);
150
164
  return false;
151
165
  }
@@ -191,6 +205,7 @@ async function sendSlack(webhookUrl, payload) {
191
205
  method: "POST",
192
206
  headers: { "Content-Type": "application/json" },
193
207
  body: JSON.stringify(slackPayload),
208
+ redirect: "error",
194
209
  signal: AbortSignal.timeout(10_000),
195
210
  });
196
211
  return response.ok;
@@ -201,7 +216,7 @@ async function sendSlack(webhookUrl, payload) {
201
216
  }
202
217
  }
203
218
  async function sendEmail(endpoint, payload) {
204
- if (!isAllowedUrl(endpoint)) {
219
+ if (!(await isAllowedUrl(endpoint))) {
205
220
  debugLog(`Email endpoint URL blocked by SSRF policy: ${endpoint}`);
206
221
  return false;
207
222
  }
@@ -216,6 +231,7 @@ async function sendEmail(endpoint, payload) {
216
231
  project: payload.project,
217
232
  details: payload.details,
218
233
  }),
234
+ redirect: "error",
219
235
  signal: AbortSignal.timeout(10_000),
220
236
  });
221
237
  return response.ok;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prism-mcp-server",
3
- "version": "19.2.2",
3
+ "version": "19.2.5",
4
4
  "mcpName": "io.github.dcostenco/prism-coder",
5
5
  "description": "Prism Coder — Cognitive memory + tool-calling intelligence for AI agents. Mind Palace persistent memory (BFCL Gold Certified, 100% Tool-Call Accuracy, 114 Agent Skills, PHI Guard, Tier Enforcement, Prompt-Based Skill Routing, Zero-Search HDC/HRR retrieval, HRR Semantic Drift Detection across BCBA/Coding/AAC domains, HIPAA-hardened local-first storage, SLERP-optimized GRPO alignment) plus the prism-coder 1.7B–32B open-weights LLM fleet.",
6
6
  "module": "index.ts",
@@ -129,9 +129,10 @@
129
129
  "@modelcontextprotocol/sdk": "^1.27.1",
130
130
  "@mozilla/readability": "^0.6.0",
131
131
  "@opentelemetry/api": "^1.9.1",
132
- "@opentelemetry/exporter-trace-otlp-http": "^0.214.0",
133
- "@opentelemetry/resources": "^2.6.1",
134
- "@opentelemetry/sdk-trace-node": "^2.6.1",
132
+ "@opentelemetry/core": "^2.8.0",
133
+ "@opentelemetry/exporter-trace-otlp-http": "^0.219.0",
134
+ "@opentelemetry/resources": "^2.8.0",
135
+ "@opentelemetry/sdk-trace-node": "^2.8.0",
135
136
  "@opentelemetry/semantic-conventions": "^1.40.0",
136
137
  "@supabase/supabase-js": "^2.99.3",
137
138
  "cheerio": "^1.2.0",