feat(plugins): add Anki card-mined event, AnkiConnect invoke, anki-sync

- Add ctx.anki.on('card-mined') fed by polling, proxy, and card creation once enrichment finishes
- Add ctx.anki.invoke to send one AnkiConnect action to the effective url with no retries
- Ship example anki-sync plugin that syncs to AnkiWeb after mining goes quiet or playback ends
- Unload plugins that finish activating after unloadAll gave up on them
- Document the Anki API and anki-sync plugin in docs-site and architecture docs
This commit is contained in:
sudacode committed 2026-10-27 20:04:34 -07:00
1 parent 4bb85f19bc
commit ff012f0497
16 files changed
+309 -7

No files matched your search

+9 -2
View File
@@ -3,9 +3,10 @@ import test from 'node:test';
import { PollingRunner } from './polling';
test('polling runner records newly added cards after initialization', async () => {
test('polling runner records new cards and reports each ready after enrichment', async () => {
const originalDateNow = Date.now;
const recordedCards: number[] = [];
const events: string[] = [];
let tracked = new Set<number>();
const responses = [
[10, 11],
@@ -18,10 +19,15 @@ test('polling runner records newly added cards after initialization', async () =
getPollingRate: () => 250,
findNotes: async () => responses.shift() ?? [],
shouldAutoUpdateNewCards: () => true,
processNewCard: async () => undefined,
processNewCard: async (noteId) => {
events.push(`process ${noteId}`);
},
recordCardsAdded: (count) => {
recordedCards.push(count);
},
onCardsReady: (noteIds) => {
events.push(`ready ${noteIds.join(',')}`);
},
isUpdateInProgress: () => false,
setUpdateInProgress: () => undefined,
getTrackedNoteIds: () => tracked,
@@ -38,6 +44,7 @@ test('polling runner records newly added cards after initialization', async () =
await runner.pollOnce();
assert.deepEqual(recordedCards, [2]);
assert.deepEqual(events, ['process 12', 'ready 12', 'process 13', 'ready 13']);
} finally {
Date.now = originalDateNow;
}