diff --git a/README.md b/README.md
index e6aecbe..3e60766 100644
--- a/README.md
+++ b/README.md
@@ -24,6 +24,7 @@ message meets a specified criterion.
- **Context menu** – apply AI rules from the message list or the message display action button.
- **Status icons** – toolbar icons show when classification is in progress and briefly display success or error states.
- **Packaging script** – `build-xpi.ps1` builds an XPI ready for installation.
+- **Maintenance tab** – view rule counts, cache entries and clear cached results from the options page.
### Cache Storage
diff --git a/modules/AiClassifier.js b/modules/AiClassifier.js
index a546fcd..de267b6 100644
--- a/modules/AiClassifier.js
+++ b/modules/AiClassifier.js
@@ -312,6 +312,17 @@ async function removeCacheEntries(keys = []) {
}
}
+async function clearCache() {
+ if (!gCacheLoaded) {
+ await loadCache();
+ }
+ if (gCache.size > 0) {
+ gCache.clear();
+ await saveCache();
+ aiLog(`[AiClassifier] Cleared cache`, {debug: true});
+ }
+}
+
function classifyTextSync(text, criterion, cacheKey = null) {
if (!Services?.tm?.spinEventLoopUntil) {
throw new Error("classifyTextSync requires Services");
@@ -396,4 +407,4 @@ async function init() {
await loadCache();
}
-export { classifyText, classifyTextSync, setConfig, removeCacheEntries, getReason, getCachedResult, buildCacheKey, buildCacheKeySync, init };
+export { classifyText, classifyTextSync, setConfig, removeCacheEntries, clearCache, getReason, getCachedResult, buildCacheKey, buildCacheKeySync, init };
diff --git a/options/options.html b/options/options.html
index da9744d..f776fa2 100644
--- a/options/options.html
+++ b/options/options.html
@@ -46,6 +46,7 @@
@@ -171,6 +172,17 @@
+
+
+
Maintenance
+
+
+ Rule count | |
+ Cache entries | |
+
+
+
+
diff --git a/options/options.js b/options/options.js
index 9bcf9dd..5536ad5 100644
--- a/options/options.js
+++ b/options/options.js
@@ -9,7 +9,8 @@ document.addEventListener('DOMContentLoaded', async () => {
'customSystemPrompt',
'aiParams',
'debugLogging',
- 'aiRules'
+ 'aiRules',
+ 'aiCache'
]);
const tabButtons = document.querySelectorAll('#main-tabs li');
const tabs = document.querySelectorAll('.tab-content');
@@ -300,6 +301,15 @@ document.addEventListener('DOMContentLoaded', async () => {
if (r.stopProcessing) rule.stopProcessing = true;
return rule;
}));
+
+ const ruleCountEl = document.getElementById('rule-count');
+ const cacheCountEl = document.getElementById('cache-count');
+ ruleCountEl.textContent = (defaults.aiRules || []).length;
+ cacheCountEl.textContent = defaults.aiCache ? Object.keys(defaults.aiCache).length : 0;
+ document.getElementById('clear-cache').addEventListener('click', async () => {
+ await AiClassifier.clearCache();
+ cacheCountEl.textContent = '0';
+ });
initialized = true;
document.getElementById('save').addEventListener('click', async () => {