UNPKG

@ankimcp/anki-mcp-server

Version:

Model Context Protocol server for Anki - enables AI assistants to interact with your Anki flashcards

151 lines • 4.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.READ_ONLY_HINT = void 0; exports.cleanHtml = cleanHtml; exports.extractRenderedCardContent = extractRenderedCardContent; exports.getCardType = getCardType; exports.getNoteType = getNoteType; exports.getRatingDescription = getRatingDescription; exports.createSuccessResponse = createSuccessResponse; exports.createErrorResponse = createErrorResponse; exports.formatInterval = formatInterval; exports.parseDeckStats = parseDeckStats; const anki_types_1 = require("../types/anki.types"); const anki_connect_client_1 = require("../clients/anki-connect.client"); exports.READ_ONLY_HINT = "The server is running in read-only mode, which blocks this operation. " + "Read-only mode is set by the READ_ONLY environment variable or the --read-only flag."; const ANSWER_SEPARATOR_REGEX = /<hr\b[^>]*\bid=["']?answer["']?[^>]*>/i; function cleanHtml(html) { if (!html) { return ""; } return (html .replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, "") .replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "") .replace(/<br\s*\/?>/gi, "\n") .replace(/<\/(?:div|p)>/gi, "\n") .replace(/<[^>]*>/g, "") .replace(/&nbsp;/g, " ") .replace(/&lt;/g, "<") .replace(/&gt;/g, ">") .replace(/&quot;/g, '"') .replace(/&#39;/g, "'") .replace(/&amp;/g, "&") .replace(/[ \t]+/g, " ") .replace(/ *\n */g, "\n") .replace(/\n{2,}/g, "\n") .trim()); } function extractRenderedCardContent(card) { const question = card.question ?? ""; const answer = card.answer ?? ""; const separatorMatch = answer.match(ANSWER_SEPARATOR_REGEX); const backHtml = separatorMatch && separatorMatch.index !== undefined ? answer.slice(separatorMatch.index + separatorMatch[0].length) : answer; return { front: cleanHtml(question), back: cleanHtml(backHtml), }; } function getCardType(type) { switch (type) { case anki_types_1.CardType.New: return "new"; case anki_types_1.CardType.Learning: return "learning"; case anki_types_1.CardType.Review: return "review"; case anki_types_1.CardType.Relearning: return "relearning"; default: return "unknown"; } } function getNoteType(modelName) { const lowerName = modelName.toLowerCase(); if (lowerName.includes("basic")) { if (lowerName.includes("reverse")) { return "Basic (and reversed card)"; } return "Basic"; } if (lowerName.includes("cloze")) { return "Cloze"; } return "Custom"; } function getRatingDescription(rating) { switch (rating) { case anki_types_1.CardRating.Again: return "Again (failed to recall)"; case anki_types_1.CardRating.Hard: return "Hard (recalled with difficulty)"; case anki_types_1.CardRating.Good: return "Good (recalled with some effort)"; case anki_types_1.CardRating.Easy: return "Easy (recalled instantly)"; default: return "Unknown"; } } function createSuccessResponse(data) { return { content: [ { type: "text", text: JSON.stringify(data, null, 2), }, ], }; } function createErrorResponse(error, context) { const errorData = { success: false, error: error instanceof Error ? error.message : "Unknown error occurred", }; if (error instanceof anki_connect_client_1.AnkiConnectError) { if (error.action) { errorData.action = error.action; } } if (context) { Object.assign(errorData, context); } if (error instanceof anki_connect_client_1.ReadOnlyModeError) { errorData.hint = exports.READ_ONLY_HINT; } return { content: [ { type: "text", text: JSON.stringify(errorData, null, 2), }, ], isError: true, }; } function formatInterval(days) { if (days < 1) { const hours = Math.round(days * 24); return `${hours} hour${hours !== 1 ? "s" : ""}`; } if (days < 30) { return `${Math.round(days)} day${days !== 1 ? "s" : ""}`; } if (days < 365) { const months = Math.round(days / 30); return `${months} month${months !== 1 ? "s" : ""}`; } const years = Math.round((days / 365) * 10) / 10; return `${years} year${years !== 1 ? "s" : ""}`; } function parseDeckStats(stats) { return { new_count: stats.new_count || 0, learn_count: stats.lrn_count || 0, review_count: stats.rev_count || 0, total_cards: stats.total || 0, }; } //# sourceMappingURL=anki.utils.js.map