@dollhousemcp/mcp-server
Version:
DollhouseMCP - A Model Context Protocol (MCP) server that enables dynamic AI persona management from markdown files, allowing Claude and other compatible AI assistants to activate and switch between different behavioral personas.
121 lines • 15.7 kB
JavaScript
/**
* In-memory ring buffer sink for metric snapshots.
*
* Stores snapshots in an EvictingQueue and provides a query interface
* for the MCP query_metrics tool. Follows the same query pattern as
* MemoryLogSink (see src/logging/sinks/MemoryLogSink.ts).
*/
import { EvictingQueue } from '../../utils/EvictingQueue.js';
export class MemoryMetricsSink {
name = 'MemoryMetricsSink';
queue;
constructor(maxSnapshots = 240) {
this.queue = new EvictingQueue(maxSnapshots);
}
onSnapshot(snapshot) {
this.queue.push(snapshot);
}
async flush() {
// No-op — in-memory, nothing to flush.
}
async close() {
this.queue.clear();
}
query(options) {
const latest = options?.latest ?? true;
const limit = Math.min(Math.max(options?.limit ?? 1, 0), 100);
const offset = Math.max(options?.offset ?? 0, 0);
const allSnapshots = this.queue.toArray();
// Compute availability bounds BEFORE filtering
const oldestAvailable = allSnapshots.length > 0 ? allSnapshots[0].timestamp : '';
const newestAvailable = allSnapshots.length > 0 ? allSnapshots.at(-1).timestamp : '';
// If limit is 0, return empty result with bounds
if (limit === 0) {
return {
snapshots: [],
total: 0,
hasMore: false,
limit,
offset,
oldestAvailable,
newestAvailable,
};
}
// 1. Select snapshots based on latest flag
let snapshots;
if (latest) {
snapshots = allSnapshots.length > 0 ? [allSnapshots.at(-1)] : [];
}
else {
snapshots = [...allSnapshots];
}
// 2. Filter by time range
if (options?.since) {
const since = options.since;
snapshots = snapshots.filter(s => s.timestamp > since);
}
if (options?.until) {
const until = options.until;
snapshots = snapshots.filter(s => s.timestamp < until);
}
// 3. Filter metrics within each snapshot by name/source/type
if (options?.names || options?.source || options?.type) {
const filtered = [];
for (const snapshot of snapshots) {
const matchedMetrics = snapshot.metrics.filter(metric => matchesMetricFilters(metric, options));
if (matchedMetrics.length > 0) {
filtered.push({ ...snapshot, metrics: matchedMetrics });
}
}
snapshots = filtered;
}
// 4. Sort newest-first (descending timestamp)
snapshots.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
// 5. Count total before pagination
const total = snapshots.length;
// 6. Paginate
snapshots = snapshots.slice(offset, offset + limit);
return {
snapshots,
total,
hasMore: offset + limit < total,
limit,
offset,
oldestAvailable,
newestAvailable,
};
}
getStats() {
return { size: this.queue.size, capacity: this.queue.capacity };
}
}
// ---------------------------------------------------------------------------
// Internal helpers
// ---------------------------------------------------------------------------
function matchesMetricFilters(metric, options) {
// Name filter: prefix match if ends with '.' or '.*', else exact match
if (options.names && options.names.length > 0) {
const matched = options.names.some(name => {
if (name.endsWith('.') || name.endsWith('.*')) {
const prefix = name.endsWith('.*') ? name.slice(0, -1) : name;
return metric.name.startsWith(prefix);
}
return metric.name === name;
});
if (!matched)
return false;
}
// Source filter: case-insensitive substring match
if (options.source) {
const needle = options.source.toLowerCase();
if (!metric.source.toLowerCase().includes(needle))
return false;
}
// Type filter: exact match
if (options.type) {
if (metric.type !== options.type)
return false;
}
return true;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWVtb3J5TWV0cmljc1NpbmsuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbWV0cmljcy9zaW5rcy9NZW1vcnlNZXRyaWNzU2luay50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7QUFFSCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFTN0QsTUFBTSxPQUFPLGlCQUFpQjtJQUNuQixJQUFJLEdBQUcsbUJBQW1CLENBQUM7SUFDbkIsS0FBSyxDQUFnQztJQUV0RCxZQUFZLGVBQXVCLEdBQUc7UUFDcEMsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLGFBQWEsQ0FBaUIsWUFBWSxDQUFDLENBQUM7SUFDL0QsQ0FBQztJQUVELFVBQVUsQ0FBQyxRQUF3QjtRQUNqQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUM1QixDQUFDO0lBRUQsS0FBSyxDQUFDLEtBQUs7UUFDVCx1Q0FBdUM7SUFDekMsQ0FBQztJQUVELEtBQUssQ0FBQyxLQUFLO1FBQ1QsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztJQUNyQixDQUFDO0lBRUQsS0FBSyxDQUFDLE9BQTRCO1FBQ2hDLE1BQU0sTUFBTSxHQUFHLE9BQU8sRUFBRSxNQUFNLElBQUksSUFBSSxDQUFDO1FBQ3ZDLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsS0FBSyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUM5RCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxNQUFNLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBRWpELE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUM7UUFFMUMsK0NB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SUFDbEQsSUFBSSxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDbkIsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUM1QyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxXQUFXLEVBQUUsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDO1lBQUUsT0FBTyxLQUFLLENBQUM7SUFDbEUsQ0FBQztJQUVELDJCQUEyQjtJQUMzQixJQUFJLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNqQixJQUFJLE1BQU0sQ0FBQyxJQUFJLEtBQUssT0FBTyxDQUFDLElBQUk7WUFBRSxPQUFPLEtBQUssQ0FBQztJQUNqRCxDQUFDO0lBRUQsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBJbi1tZW1vcnkgcmluZyBidWZmZXIgc2luayBmb3IgbWV0cmljIHNuYXBzaG90cy5cbiAqXG4gKiBTdG9yZXMgc25hcHNob3RzIGluIGFuIEV2aWN0aW5nUXVldWUgYW5kIHByb3ZpZGVzIGEgcXVlcnkgaW50ZXJmYWNlXG4gKiBmb3IgdGhlIE1DUCBxdWVyeV9tZXRyaWNzIHRvb2wuIEZvbGxvd3MgdGhlIHNhbWUgcXVlcnkgcGF0dGVybiBhc1xuICogTWVtb3J5TG9nU2luayAoc2VlIHNyYy9sb2dnaW5nL3NpbmtzL01lbW9yeUxvZ1NpbmsudHMpLlxuICovXG5cbmltcG9ydCB7IEV2aWN0aW5nUXVldWUgfSBmcm9tICcuLi8uLi91dGlscy9FdmljdGluZ1F1ZXVlLmpzJztcbmltcG9ydCB0eXBlIHtcbiAgSU1ldHJpY3NTaW5rLFxuICBNZXRyaWNFbnRyeSxcbiAgTWV0cmljUXVlcnlPcHRpb25zLFxuICBNZXRyaWNRdWVyeVJlc3VsdCxcbiAgTWV0cmljU25hcHNob3QsXG59IGZyb20gJy4uL3R5cGVzLmpzJztcblxuZXhwb3J0IGNsYXNzIE1lbW9yeU1ldHJpY3NTaW5rIGltcGxlbWVudHMgSU1ldHJpY3NTaW5rIHtcbiAgcmVhZG9ubHkgbmFtZSA9ICdNZW1vcnlNZXRyaWNzU2luayc7XG4gIHByaXZhdGUgcmVhZG9ubHkgcXVldWU6IEV2aWN0aW5nUXVldWU8TWV0cmljU25hcHNob3Q+O1xuXG4gIGNvbnN0cnVjdG9yKG1heFNuYXBzaG90czogbnVtYmVyID0gMjQwKSB7XG4gICAgdGhpcy5xdWV1ZSA9IG5ldyBFdmljdGluZ1F1ZXVlPE1ldHJpY1NuYXBzaG90PihtYXhTbmFwc2hvdHMpO1xuICB9XG5cbiAgb25TbmFwc2hvdChzbmFwc2hvdDogTWV0cmljU25hcHNob3QpOiB2b2lkIHtcbiAgICB0aGlzLnF1ZXVlLnB1c2goc25hcHNob3QpO1xuICB9XG5cbiAgYXN5bmMgZmx1c2goKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgLy8gTm8tb3Ag4oCUIGluLW1lbW9yeSwgbm90aGluZyB0byBmbHVzaC5cbiAgfVxuXG4gIGFzeW5jIGNsb3NlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIHRoaXMucXVldWUuY2xlYXIoKTtcbiAgfVxuXG4gIHF1ZXJ5KG9wdGlvbnM/OiBNZXRyaWNRdWVyeU9wdGlvbnMpOiBNZXRyaWNRdWVyeVJlc3VsdCB7XG4gICAgY29uc3QgbGF0ZXN0ID0gb3B0aW9ucz8ubGF0ZXN0ID8/IHRydWU7XG4gICAgY29uc3QgbGltaXQgPSBNYXRoLm1pbihNYXRoLm1heChvcHRpb25zPy5saW1pdCA/PyAxLCAwKSwgMTAwKTtcbiAgICBjb25zdCBvZmZzZXQgPSBNYXRoLm1heChvcHRpb25zPy5vZmZzZXQgPz8gMCwgMCk7XG5cbiAgICBjb25zdCBhbGxTbmFwc2hvdHMgPSB0aGlzLnF1ZXVlLnRvQXJyYXkoKTtcblxuICAgIC8vIENvbXB1dGUgYXZhaWxhYmlsaXR5IGJvdW5kcyBCRUZPUkUgZmlsdGVyaW5nXG4gICAgY29uc3Qgb2xkZXN0QXZhaWxhYmxlID0gYWxsU25hcHNob3RzLmxlbmd0aCA+IDAgPyBhbGxTbmFwc2hvdHNbMF0udGltZXN0YW1wIDogJyc7XG4gICAgY29uc3QgbmV3ZXN0QXZhaWxhYmxlID0gYWxsU25hcHNob3RzLmxlbmd0aCA+IDAgPyBhbGxTbmFwc2hvdHMuYXQoLTEpIS50aW1lc3RhbXAgOiAnJztcblxuICAgIC8vIElmIGxpbWl0IGlzIDAsIHJldHVybiBlbXB0eSByZXN1bHQgd2l0aCBib3VuZHNcbiAgICBpZiAobGltaXQgPT09IDApIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHNuYXBzaG90czogW10sXG4gICAgICAgIHRvdGFsOiAwLFxuICAgICAgICBoYXNNb3JlOiBmYWxzZSxcbiAgICAgICAgbGltaXQsXG4gICAgICAgIG9mZnNldCxcbiAgICAgICAgb2xkZXN0QXZhaWxhYmxlLFxuICAgICAgICBuZXdlc3RBdmFpbGFibGUsXG4gICAgICB9O1xuICAgIH1cblxuICAgIC8vIDEuIFNlbGVjdCBzbmFwc2hvdHMgYmFzZWQgb24gbGF0ZXN0IGZsYWdcbiAgICBsZXQgc25hcHNob3RzOiBNZXRyaWNTbmFwc2hvdFtdO1xuICAgIGlmIChsYXRlc3QpIHtcbiAgICAgIHNuYXBzaG90cyA9IGFsbFNuYXBzaG90cy5sZW5ndGggPiAwID8gW2FsbFNuYXBzaG90cy5hdCgtMSkhXSA6IFtdO1xuICAgIH0gZWxzZSB7XG4gICAgICBzbmFwc2hvdHMgPSBbLi4uYWxsU25hcHNob3RzXTtcbiAgICB9XG5cbiAgICAvLyAyLiBGaWx0ZXIgYnkgdGltZSByYW5nZVxuICAgIGlmIChvcHRpb25zPy5zaW5jZSkge1xuICAgICAgY29uc3Qgc2luY2UgPSBvcHRpb25zLnNpbmNlO1xuICAgICAgc25hcHNob3RzID0gc25hcHNob3RzLmZpbHRlcihzID0+IHMudGltZXN0YW1wID4gc2luY2UpO1xuICAgIH1cbiAgICBpZiAob3B0aW9ucz8udW50aWwpIHtcbiAgICAgIGNvbnN0IHVudGlsID0gb3B0aW9ucy51bnRpbDtcbiAgICAgIHNuYXBzaG90cyA9IHNuYXBzaG90cy5maWx0ZXIocyA9PiBzLnRpbWVzdGFtcCA8IHVudGlsKTtcbiAgICB9XG5cbiAgICAvLyAzLiBGaWx0ZXIgbWV0cmljcyB3aXRoaW4gZWFjaCBzbmFwc2hvdCBieSBuYW1lL3NvdXJjZS90eXBlXG4gICAgaWYgKG9wdGlvbnM/Lm5hbWVzIHx8IG9wdGlvbnM/LnNvdXJjZSB8fCBvcHRpb25zPy50eXBlKSB7XG4gICAgICBjb25zdCBmaWx0ZXJlZDogTWV0cmljU25hcHNob3RbXSA9IFtdO1xuICAgICAgZm9yIChjb25zdCBzbmFwc2hvdCBvZiBzbmFwc2hvdHMpIHtcbiAgICAgICAgY29uc3QgbWF0Y2hlZE1ldHJpY3MgPSBzbmFwc2hvdC5tZXRyaWNzLmZpbHRlcihtZXRyaWMgPT5cbiAgICAgICAgICBtYXRjaGVzTWV0cmljRmlsdGVycyhtZXRyaWMsIG9wdGlvbnMpLFxuICAgICAgICApO1xuICAgICAgICBpZiAobWF0Y2hlZE1ldHJpY3MubGVuZ3RoID4gMCkge1xuICAgICAgICAgIGZpbHRlcmVkLnB1c2goeyAuLi5zbmFwc2hvdCwgbWV0cmljczogbWF0Y2hlZE1ldHJpY3MgfSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHNuYXBzaG90cyA9IGZpbHRlcmVkO1xuICAgIH1cblxuICAgIC8vIDQuIFNvcnQgbmV3ZXN0LWZpcnN0IChkZXNjZW5kaW5nIHRpbWVzdGFtcClcbiAgICBzbmFwc2hvdHMuc29ydCgoYSwgYikgPT4gYi50aW1lc3RhbXAubG9jYWxlQ29tcGFyZShhLnRpbWVzdGFtcCkpO1xuXG4gICAgLy8gNS4gQ291bnQgdG90YWwgYmVmb3JlIHBhZ2luYXRpb25cbiAgICBjb25zdCB0b3RhbCA9IHNuYXBzaG90cy5sZW5ndGg7XG5cbiAgICAvLyA2LiBQYWdpbmF0ZVxuICAgIHNuYXBzaG90cyA9IHNuYXBzaG90cy5zbGljZShvZmZzZXQsIG9mZnNldCArIGxpbWl0KTtcblxuICAgIHJldHVybiB7XG4gICAgICBzbmFwc2hvdHMsXG4gICAgICB0b3RhbCxcbiAgICAgIGhhc01vcmU6IG9mZnNldCArIGxpbWl0IDwgdG90YWwsXG4gICAgICBsaW1pdCxcbiAgICAgIG9mZnNldCxcbiAgICAgIG9sZGVzdEF2YWlsYWJsZSxcbiAgICAgIG5ld2VzdEF2YWlsYWJsZSxcbiAgICB9O1xuICB9XG5cbiAgZ2V0U3RhdHMoKTogeyBzaXplOiBudW1iZXI7IGNhcGFjaXR5OiBudW1iZXIgfSB7XG4gICAgcmV0dXJuIHsgc2l6ZTogdGhpcy5xdWV1ZS5zaXplLCBjYXBhY2l0eTogdGhpcy5xdWV1ZS5jYXBhY2l0eSB9O1xuICB9XG59XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gSW50ZXJuYWwgaGVscGVyc1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbmZ1bmN0aW9uIG1hdGNoZXNNZXRyaWNGaWx0ZXJzKFxuICBtZXRyaWM6IE1ldHJpY0VudHJ5LFxuICBvcHRpb25zOiBNZXRyaWNRdWVyeU9wdGlvbnMsXG4pOiBib29sZWFuIHtcbiAgLy8gTmFtZSBmaWx0ZXI6IHByZWZpeCBtYXRjaCBpZiBlbmRzIHdpdGggJy4nIG9yICcuKicsIGVsc2UgZXhhY3QgbWF0Y2hcbiAgaWYgKG9wdGlvbnMubmFtZXMgJiYgb3B0aW9ucy5uYW1lcy5sZW5ndGggPiAwKSB7XG4gICAgY29uc3QgbWF0Y2hlZCA9IG9wdGlvbnMubmFtZXMuc29tZShuYW1lID0+IHtcbiAgICAgIGlmIChuYW1lLmVuZHNXaXRoKCcuJykgfHwgbmFtZS5lbmRzV2l0aCgnLionKSkge1xuICAgICAgICBjb25zdCBwcmVmaXggPSBuYW1lLmVuZHNXaXRoKCcuKicpID8gbmFtZS5zbGljZSgwLCAtMSkgOiBuYW1lO1xuICAgICAgICByZXR1cm4gbWV0cmljLm5hbWUuc3RhcnRzV2l0aChwcmVmaXgpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG1ldHJpYy5uYW1lID09PSBuYW1lO1xuICAgIH0pO1xuICAgIGlmICghbWF0Y2hlZCkgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLy8gU291cmNlIGZpbHRlcjogY2FzZS1pbnNlbnNpdGl2ZSBzdWJzdHJpbmcgbWF0Y2hcbiAgaWYgKG9wdGlvbnMuc291cmNlKSB7XG4gICAgY29uc3QgbmVlZGxlID0gb3B0aW9ucy5zb3VyY2UudG9Mb3dlckNhc2UoKTtcbiAgICBpZiAoIW1ldHJpYy5zb3VyY2UudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyhuZWVkbGUpKSByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvLyBUeXBlIGZpbHRlcjogZXhhY3QgbWF0Y2hcbiAgaWYgKG9wdGlvbnMudHlwZSkge1xuICAgIGlmIChtZXRyaWMudHlwZSAhPT0gb3B0aW9ucy50eXBlKSByZXR1cm4gZmFsc2U7XG4gIH1cblxuICByZXR1cm4gdHJ1ZTtcbn1cbiJdfQ==