@oomkapwn/enquire-mcp 3.11.5-rc.4 → 3.11.5-rc.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/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  All notable changes to this project will be documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
4
4
 
5
+ ## [3.11.5-rc.5] — 2026-07-03
6
+
7
+ > **TL;DR:** **a root-cause META-AUDIT of the whole rc.1→rc.4 cascade found a real MED class that all 4 RCs — and 30+ prior audit rounds — missed: a CHAR-BLIND fence toggle.** `opensBlockFence(line)` returns a boolean, so the callers doing `inFence = !inFence` could not tell a ``` delimiter from a `~~~` one — a `~~~` line inside a ``` block (or vice versa) wrongly flipped the in-fence state, **surfacing content that is inside code and dropping the real content after the block**. Confirmed live (reproduced against `dist/`) in **`write.ts` (×2 — the data-affecting `rename_note`/`replace_in_notes` rewriters, which rewrote a `[[link]]` inside the code block AND skipped the real link after it), `read.ts extractHeadings` (readNote map), and `meta.ts getOpenQuestions` (always-on)**. Only `fts5.ts` was correct (it alone tracked the fence-marker char). **Class fix:** a canonical char-aware primitive `advanceFence(line, marker)` in `src/fence.ts` (returns the open-fence char + whether the line is a matching-char delimiter); all five walkers (write ×2, read, meta, fts5) now share it — a mismatched inner fence is treated as literal code, matching CommonMark + the parser's `stripCodeAndInline`. **Structural defenses:** the `fence-toggle-invariant` was upgraded from a presence-check to a **correctness check** (flags any live `= !…fence…` char-blind toggle; asserts every walker uses `advanceFence`); the `parser-desync-invariant` was **broadened** from the two wrappers to also cover the `scanWikilinkInners`/`INLINE_TAG_RE` primitives `validateNoteProposal` uses (the rc.3 invariant's scope-too-narrow gap). **+4 tests (1469 → 1473), all mutation-verified.**
8
+ >
9
+ > **Meta-audit conclusions (why the cascade + prior audits missed this).** A 4-lens root-cause Workflow established: (1) **the deepest cause of the whole fence/parser class is architectural** — `src/parser.ts` exposes only a fixed `{frontmatter, body, wikilinks, embeds, tags}` and has NO canonical *"give me the note's structure"* accessor (no fence-aware line iterator, no headings), so any tool needing those hand-rolls a line walker and can diverge. (2) **~85 % of the CI apparatus is claim/drift-driven or static-grep; not one gate ever fed a code-fenced note to an always-on tool and asserted the output** — the behavioral surface these bugs live on had zero coverage until rc.2/rc.3 began building it, and even those two invariants are static-signature detectors with blind spots (the char-aware dimension was one). The follow-up (rc.6, planned) will add the two highest-leverage hardenings the audit designed: a **generative canonical-parser-agreement behavioral net** (oracle = `parseNote`/`stripCodeAndInline`) and the missing **parser structure accessors**, to make this class impossible-by-construction rather than caught-per-instance.
10
+
5
11
  ## [3.11.5-rc.4] — 2026-07-02
6
12
 
7
13
  > **TL;DR:** **CLOSES the post-rc.2 re-sweep — the 2 independent tail LOWs.** (1) **fts5 indented-fence residual** (of the rc.2 change): `computeBreadcrumbsByLine` gated its fence toggle on `/^(```|~~~)/` (anchored at column 0), so an INDENTED code fence (up to 3 leading spaces, valid CommonMark) was NOT detected — its `#` lines were treated as headings and leaked into the breadcrumb — while `read.ts extractHeadings` (which routes through `opensBlockFence`) IS indent-tolerant. Now `/^\s*(`{3,}|~{3,})/` + fence-CHAR close-matching, consistent with read.ts (empirically: an indented `# Fenced` no longer leaks). (2) **CRL-1 sibling** — `--reranker-top-n`: was validated only inside `buildMcpServer` (one call-frame later), which the stdio `serve` path invokes AFTER `prepareServerDeps` acquired the FTS5 handle / watcher / embed-db / HNSW, so `serve --enable-reranker --reranker-top-n 0` leaked them all; hoisted into `prepareServerDeps`' fail-fast block (serve-http already validated it early via `validateServeHttpRetrievalOpts`). **+2 tests (1467 → 1469, both mutation-verified).** **This CLOSES the entire v3.11.5-rc.1 → rc.4 audit + re-sweep cascade: the full 12-lens project audit (rc.1: 4 findings) → 3 mandatory post-merge re-sweeps (rc.2 fence read-path siblings, rc.3 parser-desync class, rc.4 tail LOWs), 12 confirmed findings total (1 MED write-drop + 4 MED + 5 LOW + 1 INFO + 1 fts5-residual), every one reproduced against `dist/` and closed with a behavioral test, most with an inventory invariant.**
package/README.ar.md CHANGED
@@ -56,7 +56,7 @@ claude mcp add obsidian -- npx -y @oomkapwn/enquire-mcp serve --vault ~/Document
56
56
  > 3. **صفر استدعاءات سحابية أثناء التشغيل.** نموذج التضمين يعمل **على جهازك** ويُفهرس markdown الذي كتبته **أنت** — ولهذا فهو تنزيل محلي لمرة واحدة (~110 ميغابايت)، لا مفتاح API سحابي. الرسوخ والخصوصية لهما ثمن، ولا ندّعي خلاف ذلك: محتوى مكتبتك لا يغادر جهازك أبداً، وهي آمنة للعمل المعزول (air-gap) افتراضياً ([مفروضة بالكود](./SECURITY.md)، لا مجرّد طموح).
57
57
  > 4. **استدعاء واعٍ بالحداثة.** تُبلّغ كل نتيجة عن عمر الملاحظة؛ وإعادة الترتيب الاختيارية بالحداثة تتيح للوكيل تفضيل المعرفة الحديثة ووسم الحقائق القديمة لإعادة التحقق — حدود "الوعي بالنسيان"، مبنيّة على `mtime` الذي تملكه ملفاتك أصلاً.
58
58
 
59
- **46 أداة · 19 موجِّه MCP · 1469+ اختبار وحدة · 50+ لغة · إصدار مستقر v3.11.x · مُقيَّد بالـ semver · MIT · إثبات بناء npm (SLSA L2).**
59
+ **46 أداة · 19 موجِّه MCP · 1473+ اختبار وحدة · 50+ لغة · إصدار مستقر v3.11.x · مُقيَّد بالـ semver · MIT · إثبات بناء npm (SLSA L2).**
60
60
 
61
61
  </div>
62
62
 
@@ -90,7 +90,7 @@ claude mcp add obsidian -- npx -y @oomkapwn/enquire-mcp serve --vault ~/Document
90
90
  | **GraphRAG-light** (كشف مجتمعات Wikilink بمعامل Louvain) | ✅ **حصرياً هنا** | ❌ | ❌ |
91
91
  | **تنفيذ استعلام `.base` مستقل** (يعمل دون تشغيل Obsidian) | ✅ **حصرياً هنا** | ❌ | ❌ يفوّض إلى Obsidian |
92
92
  | **استرجاع HyDE** (Gao et al 2023) + تفكيك الأسئلة الفرعية | ✅ **حصرياً هنا** | ❌ | ❌ |
93
- | **1469 اختبار وحدة · 9 بوابات CI إلزامية + 5 إرشادية لكل PR** | ✅ | غير منطبق | نادر |
93
+ | **1473 اختبار وحدة · 9 بوابات CI إلزامية + 5 إرشادية لكل PR** | ✅ | غير منطبق | نادر |
94
94
  | **إثبات بناء موقَّع** (npm + Sigstore، SLSA Build L2) | ✅ | غير منطبق | ❌ |
95
95
  | **سطح عام مُقيَّد بالـ semver** ([STABILITY.md](./STABILITY.md)) | ✅ | غير منطبق | ❌ |
96
96
  | تشغيل مستقل (لا حاجة لإضافة Obsidian) | ✅ | ❌ يتطلب Obsidian | متفاوت |
@@ -409,7 +409,7 @@ graph LR
409
409
  ```bash
410
410
  git clone https://github.com/oomkapwn/enquire-mcp.git
411
411
  cd enquire-mcp && npm install
412
- npm test # full suite (1469 tests, ~12s)
412
+ npm test # full suite (1473 tests, ~12s)
413
413
  npm run lint # zero warnings
414
414
  npm run build # tsc → dist/
415
415
  ```
package/README.de.md CHANGED
@@ -17,7 +17,7 @@
17
17
  [![CI](https://github.com/oomkapwn/enquire-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/oomkapwn/enquire-mcp/actions/workflows/ci.yml)
18
18
  [![npm](https://img.shields.io/npm/v/@oomkapwn/enquire-mcp.svg?label=npm&color=cb3837)](https://www.npmjs.com/package/@oomkapwn/enquire-mcp)
19
19
  [![downloads](https://img.shields.io/npm/dm/@oomkapwn/enquire-mcp.svg?color=cb3837)](https://www.npmjs.com/package/@oomkapwn/enquire-mcp)
20
- [![tests](https://img.shields.io/badge/tests-1469%20passing-brightgreen.svg)](#️-vertrauen)
20
+ [![tests](https://img.shields.io/badge/tests-1473%20passing-brightgreen.svg)](#️-vertrauen)
21
21
  [![stable](https://img.shields.io/badge/v3.11.x-stable-brightgreen.svg)](./STABILITY.md)
22
22
  [![build provenance](https://img.shields.io/badge/build_provenance-SLSA_L2-blue.svg)](https://slsa.dev/spec/v1.0/levels#build-l2)
23
23
  [![MCP](https://img.shields.io/badge/MCP-1.29-8A2BE2.svg)](https://modelcontextprotocol.io/)
@@ -55,7 +55,7 @@ Ihr Obsidian-Vault wird zum **persistenten, abfragbaren Langzeitgedächtnis** f
55
55
  > 3. **Null Cloud-Aufrufe während des Servings.** Das Embedding-Modell läuft **auf Ihrem Rechner** und indexiert das von **Ihnen** geschriebene Markdown — deshalb ist es ein einmaliger lokaler Download (~110 MB), kein Cloud-API-Schlüssel. Verankert + privat gibt es nicht umsonst, und wir tun nicht so: Der Inhalt Ihres Vaults verlässt niemals Ihren Rechner, standardmäßig air-gap-sicher ([erzwungen](./SECURITY.md), nicht nur angestrebt).
56
56
  > 4. **Frischebewusster Abruf.** Jeder Treffer meldet, wie alt die Notiz ist; das optionale Reranking nach Aktualität erlaubt es einem Agenten, frisches Wissen zu bevorzugen und veraltete Fakten zur erneuten Überprüfung zu markieren — die vergessensbewusste Front, aufgebaut auf der `mtime`, die Ihre Dateien bereits besitzen.
57
57
 
58
- **46 Tools · 19 MCP-Prompts · 1469+ Unit-Tests · 50+ Sprachen · v3.11.x stable · semver-gebunden · MIT · npm-Build-Provenienz (SLSA L2).**
58
+ **46 Tools · 19 MCP-Prompts · 1473+ Unit-Tests · 50+ Sprachen · v3.11.x stable · semver-gebunden · MIT · npm-Build-Provenienz (SLSA L2).**
59
59
 
60
60
  ---
61
61
 
@@ -83,7 +83,7 @@ Ihr Obsidian-Vault wird zum **persistenten, abfragbaren Langzeitgedächtnis** f
83
83
  | **GraphRAG-light** (Wikilink-Community-Erkennung via Louvain-Modularität) | ✅ **nur hier** | ❌ | ❌ |
84
84
  | **Eigenständige `.base`-Abfrageausführung** (funktioniert ohne laufendes Obsidian) | ✅ **nur hier** | ❌ | ❌ delegiert an Obsidian |
85
85
  | **HyDE-Retrieval** (Gao et al. 2023) + Teilfragen-Zerlegung | ✅ **nur hier** | ❌ | ❌ |
86
- | **1469 Unit-Tests · 9 erforderliche + 5 beratende CI-Gates pro PR** | ✅ | n. z. | selten |
86
+ | **1473 Unit-Tests · 9 erforderliche + 5 beratende CI-Gates pro PR** | ✅ | n. z. | selten |
87
87
  | **Signierte Build-Provenienz** (npm + Sigstore, SLSA Build L2) | ✅ | n. z. | ❌ |
88
88
  | **Semver-gebundene öffentliche Oberfläche** ([STABILITY.md](./STABILITY.md)) | ✅ | n. z. | ❌ |
89
89
  | Eigenständig (kein Obsidian-Plugin nötig) | ✅ | ❌ erfordert Obsidian | variiert |
@@ -322,7 +322,7 @@ Kanal: `npm install @oomkapwn/enquire-mcp` → neueste stabile Version (`@latest
322
322
  ```bash
323
323
  git clone https://github.com/oomkapwn/enquire-mcp.git
324
324
  cd enquire-mcp && npm install
325
- npm test # vollständige Suite (1469 Tests, ~12 s)
325
+ npm test # vollständige Suite (1473 Tests, ~12 s)
326
326
  npm run lint # null Warnungen
327
327
  npm run build # tsc → dist/
328
328
  ```
package/README.es.md CHANGED
@@ -48,7 +48,7 @@ Tu bóveda de Obsidian se convierte en **memoria a largo plazo persistente y con
48
48
  > 3. **Cero llamadas a la nube durante el servicio.** El modelo de embeddings se ejecuta **en tu máquina** e indexa el markdown que **tú** escribiste: por eso es una descarga local única (~110 MB), no una clave de API en la nube. Estar anclado y ser privado no sale gratis, y no fingimos que sí: el contenido de tu bóveda nunca sale de tu máquina, seguro para entornos aislados por defecto ([garantizado](./SECURITY.md), no aspiracional).
49
49
  > 4. **Recuperación consciente de la frescura.** Cada resultado informa de la antigüedad de la nota; el reordenamiento por recencia opcional permite que un agente prefiera el conocimiento reciente y marque los hechos obsoletos para reverificación: la frontera consciente del olvido, construida sobre el `mtime` que tus archivos ya tienen.
50
50
 
51
- **46 herramientas · 19 prompts MCP · 1469+ pruebas unitarias · 50+ idiomas · v3.11.x estable · ligado a semver · MIT · procedencia de compilación en npm (SLSA L2).**
51
+ **46 herramientas · 19 prompts MCP · 1473+ pruebas unitarias · 50+ idiomas · v3.11.x estable · ligado a semver · MIT · procedencia de compilación en npm (SLSA L2).**
52
52
 
53
53
  ---
54
54
 
@@ -76,7 +76,7 @@ Tu bóveda de Obsidian se convierte en **memoria a largo plazo persistente y con
76
76
  | **GraphRAG-light** (detección de comunidades de wikilinks por modularidad de Louvain) | ✅ **solo aquí** | ❌ | ❌ |
77
77
  | **Ejecución autónoma de consultas `.base`** (funciona sin Obsidian abierto) | ✅ **solo aquí** | ❌ | ❌ delega en Obsidian |
78
78
  | **Recuperación HyDE** (Gao et al. 2023) + descomposición en subpreguntas | ✅ **solo aquí** | ❌ | ❌ |
79
- | **1469 pruebas unitarias · 9 puertas de CI requeridas + 5 indicativas por PR** | ✅ | n/d | raro |
79
+ | **1473 pruebas unitarias · 9 puertas de CI requeridas + 5 indicativas por PR** | ✅ | n/d | raro |
80
80
  | **Procedencia de compilación firmada** (npm + Sigstore, SLSA Build L2) | ✅ | n/d | ❌ |
81
81
  | **Superficie pública ligada a semver** ([STABILITY.md](./STABILITY.md)) | ✅ | n/d | ❌ |
82
82
  | Autónomo (sin necesidad de plugin de Obsidian) | ✅ | ❌ requiere Obsidian | varía |
package/README.fr.md CHANGED
@@ -15,7 +15,7 @@
15
15
  [![CI](https://github.com/oomkapwn/enquire-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/oomkapwn/enquire-mcp/actions/workflows/ci.yml)
16
16
  [![npm](https://img.shields.io/npm/v/@oomkapwn/enquire-mcp.svg?label=npm&color=cb3837)](https://www.npmjs.com/package/@oomkapwn/enquire-mcp)
17
17
  [![downloads](https://img.shields.io/npm/dm/@oomkapwn/enquire-mcp.svg?color=cb3837)](https://www.npmjs.com/package/@oomkapwn/enquire-mcp)
18
- [![tests](https://img.shields.io/badge/tests-1469%20passing-brightgreen.svg)](#️-confiance)
18
+ [![tests](https://img.shields.io/badge/tests-1473%20passing-brightgreen.svg)](#️-confiance)
19
19
  [![stable](https://img.shields.io/badge/v3.11.x-stable-brightgreen.svg)](./STABILITY.md)
20
20
  [![build provenance](https://img.shields.io/badge/build_provenance-SLSA_L2-blue.svg)](https://slsa.dev/spec/v1.0/levels#build-l2)
21
21
  [![MCP](https://img.shields.io/badge/MCP-1.29-8A2BE2.svg)](https://modelcontextprotocol.io/)
@@ -53,7 +53,7 @@ Votre coffre Obsidian devient une **mémoire à long terme persistante et interr
53
53
  > 3. **Zéro appel au cloud pendant le service.** Modèles mis en cache localement (téléchargement unique depuis HuggingFace). Le contenu de votre coffre ne quitte jamais votre machine. Sûr en environnement isolé par défaut.
54
54
  > 4. **Rappel conscient de la fraîcheur.** Chaque résultat indique l'âge de la note ; le reclassement par récence optionnel permet à un agent de préférer le savoir frais et de signaler les faits périmés à revérifier — la frontière consciente de l'oubli, bâtie sur le `mtime` que vos fichiers possèdent déjà.
55
55
 
56
- **46 outils · 19 prompts MCP · 1469+ tests unitaires · 50+ langues · v3.11.x stable · lié au semver · MIT · provenance de build npm (SLSA L2).**
56
+ **46 outils · 19 prompts MCP · 1473+ tests unitaires · 50+ langues · v3.11.x stable · lié au semver · MIT · provenance de build npm (SLSA L2).**
57
57
 
58
58
  ---
59
59
 
@@ -81,7 +81,7 @@ Votre coffre Obsidian devient une **mémoire à long terme persistante et interr
81
81
  | **GraphRAG-light** (détection de communautés de wikilinks par modularité de Louvain) | ✅ **uniquement ici** | ❌ | ❌ |
82
82
  | **Exécution autonome de requêtes `.base`** (fonctionne sans Obsidian ouvert) | ✅ **uniquement ici** | ❌ | ❌ délègue à Obsidian |
83
83
  | **Récupération HyDE** (Gao et al. 2023) + décomposition en sous-questions | ✅ **uniquement ici** | ❌ | ❌ |
84
- | **1469 tests unitaires · 9 portes CI requises + 5 indicatives par PR** | ✅ | s.o. | rare |
84
+ | **1473 tests unitaires · 9 portes CI requises + 5 indicatives par PR** | ✅ | s.o. | rare |
85
85
  | **Provenance de build signée** (npm + Sigstore, SLSA Build L2) | ✅ | s.o. | ❌ |
86
86
  | **Surface publique liée au semver** ([STABILITY.md](./STABILITY.md)) | ✅ | s.o. | ❌ |
87
87
  | Autonome (aucun plugin Obsidian requis) | ✅ | ❌ requiert Obsidian | variable |
@@ -320,7 +320,7 @@ Canal : `npm install @oomkapwn/enquire-mcp` → dernière version stable (`@late
320
320
  ```bash
321
321
  git clone https://github.com/oomkapwn/enquire-mcp.git
322
322
  cd enquire-mcp && npm install
323
- npm test # suite complète (1469 tests, ~12 s)
323
+ npm test # suite complète (1473 tests, ~12 s)
324
324
  npm run lint # zéro avertissement
325
325
  npm run build # tsc → dist/
326
326
  ```
package/README.hi.md CHANGED
@@ -50,7 +50,7 @@ claude mcp add obsidian -- npx -y @oomkapwn/enquire-mcp serve --vault ~/Document
50
50
  > 3. **serve के दौरान शून्य क्लाउड कॉल।** embedding मॉडल **आपकी मशीन पर** चलता है और उसी markdown को अनुक्रमित करता है जो **आपने** लिखी — इसीलिए यह एक-बार का स्थानीय डाउनलोड (~110 MB) है, न कि कोई क्लाउड API key। मूल-आधारित + निजी होना मुफ़्त नहीं है, और हम इसका दिखावा नहीं करते: आपके vault की सामग्री कभी आपकी मशीन नहीं छोड़ती, डिफ़ॉल्ट रूप से एयर-गैप-सुरक्षित ([प्रवर्तित](./SECURITY.md), केवल आकांक्षात्मक नहीं)।
51
51
  > 4. **ताज़गी-सजग recall।** हर परिणाम बताता है कि नोट कितना पुराना है; वैकल्पिक recency re-ranking एजेंट को ताज़ा ज्ञान को प्राथमिकता देने और बासी तथ्यों को पुनः-सत्यापन हेतु चिह्नित करने देता है — भूलने-के-प्रति-सजग सीमांत, जो आपकी फ़ाइलों में पहले से मौजूद `mtime` पर बना है।
52
52
 
53
- **46 टूल · 19 MCP प्रॉम्प्ट · 1469+ यूनिट टेस्ट · 50+ भाषाएँ · v3.11.x स्थिर · semver-बाध्य · MIT · npm बिल्ड प्रोवेनेंस (SLSA L2)।**
53
+ **46 टूल · 19 MCP प्रॉम्प्ट · 1473+ यूनिट टेस्ट · 50+ भाषाएँ · v3.11.x स्थिर · semver-बाध्य · MIT · npm बिल्ड प्रोवेनेंस (SLSA L2)।**
54
54
 
55
55
  ---
56
56
 
@@ -78,7 +78,7 @@ claude mcp add obsidian -- npx -y @oomkapwn/enquire-mcp serve --vault ~/Document
78
78
  | **GraphRAG-light** (Louvain modularity wikilink समुदाय-पहचान) | ✅ **केवल यहीं** | ❌ | ❌ |
79
79
  | **स्वतंत्र `.base` क्वेरी निष्पादन** (Obsidian चले बिना काम करता है) | ✅ **केवल यहीं** | ❌ | ❌ Obsidian को सौंपता है |
80
80
  | **HyDE retrieval** (Gao et al 2023) + उप-प्रश्न विघटन | ✅ **केवल यहीं** | ❌ | ❌ |
81
- | **1469 यूनिट टेस्ट · प्रति PR 9 आवश्यक + 5 सलाहकारी CI गेट** | ✅ | लागू नहीं | विरल |
81
+ | **1473 यूनिट टेस्ट · प्रति PR 9 आवश्यक + 5 सलाहकारी CI गेट** | ✅ | लागू नहीं | विरल |
82
82
  | **साइन्ड बिल्ड प्रोवेनेंस** (npm + Sigstore, SLSA Build L2) | ✅ | लागू नहीं | ❌ |
83
83
  | **semver-बाध्य सार्वजनिक सतह** ([STABILITY.md](./STABILITY.md)) | ✅ | लागू नहीं | ❌ |
84
84
  | स्वतंत्र (कोई Obsidian प्लगइन ज़रूरी नहीं) | ✅ | ❌ Obsidian ज़रूरी | भिन्न |
@@ -319,7 +319,7 @@ graph LR
319
319
  ```bash
320
320
  git clone https://github.com/oomkapwn/enquire-mcp.git
321
321
  cd enquire-mcp && npm install
322
- npm test # पूर्ण सूट (1469 टेस्ट, ~12s)
322
+ npm test # पूर्ण सूट (1473 टेस्ट, ~12s)
323
323
  npm run lint # ज़ीरो वॉर्निंग
324
324
  npm run build # tsc → dist/
325
325
  ```
package/README.ja.md CHANGED
@@ -48,7 +48,7 @@ claude mcp add obsidian -- npx -y @oomkapwn/enquire-mcp serve --vault ~/Document
48
48
  > 3. **serve 中はクラウド呼び出しがゼロ。** モデルはローカルにキャッシュ(HuggingFace から一度だけダウンロード)。あなたのボールトの内容はマシンから決して出ていきません。デフォルトでエアギャップ安全。
49
49
  > 4. **鮮度を意識した呼び戻し。** すべてのヒットが、そのノートがどれくらい古いかを報告します。オプトインの鮮度リランキングにより、エージェントは新しい知識を優先し、古くなった事実を再検証対象としてフラグ付けできます——これは忘却を意識したフロンティアであり、あなたのファイルがもともと持っている `mtime` の上に構築されています。
50
50
 
51
- **46 ツール · 19 MCP プロンプト · 1469+ ユニットテスト · 50+ 言語 · v3.11.x 安定版 · semver 準拠 · MIT · npm ビルドプロベナンス(SLSA L2)。**
51
+ **46 ツール · 19 MCP プロンプト · 1473+ ユニットテスト · 50+ 言語 · v3.11.x 安定版 · semver 準拠 · MIT · npm ビルドプロベナンス(SLSA L2)。**
52
52
 
53
53
  ---
54
54
 
@@ -76,7 +76,7 @@ claude mcp add obsidian -- npx -y @oomkapwn/enquire-mcp serve --vault ~/Document
76
76
  | **GraphRAG-light**(Louvain モジュラリティによる wikilink コミュニティ検出) | ✅ **ここだけ** | ❌ | ❌ |
77
77
  | **スタンドアロンの `.base` クエリ実行**(Obsidian を起動せずに動作) | ✅ **ここだけ** | ❌ | ❌ Obsidian に委譲 |
78
78
  | **HyDE 検索**(Gao et al 2023)+ サブクエスチョン分解 | ✅ **ここだけ** | ❌ | ❌ |
79
- | **1469 ユニットテスト · PR ごとに 9 個の必須 + 5 個のアドバイザリ CI ゲート** | ✅ | 該当なし | まれ |
79
+ | **1473 ユニットテスト · PR ごとに 9 個の必須 + 5 個のアドバイザリ CI ゲート** | ✅ | 該当なし | まれ |
80
80
  | **署名付きビルドプロベナンス**(npm + Sigstore、SLSA Build L2) | ✅ | 該当なし | ❌ |
81
81
  | **semver 準拠の公開サーフェス**([STABILITY.md](./STABILITY.md)) | ✅ | 該当なし | ❌ |
82
82
  | スタンドアロン(Obsidian プラグイン不要) | ✅ | ❌ Obsidian が必要 | まちまち |
@@ -315,7 +315,7 @@ graph LR
315
315
  ```bash
316
316
  git clone https://github.com/oomkapwn/enquire-mcp.git
317
317
  cd enquire-mcp && npm install
318
- npm test # フルスイート(1469 テスト、約 12 秒)
318
+ npm test # フルスイート(1473 テスト、約 12 秒)
319
319
  npm run lint # 警告ゼロ
320
320
  npm run build # tsc → dist/
321
321
  ```
package/README.ko.md CHANGED
@@ -17,7 +17,7 @@
17
17
  [![CI](https://github.com/oomkapwn/enquire-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/oomkapwn/enquire-mcp/actions/workflows/ci.yml)
18
18
  [![npm](https://img.shields.io/npm/v/@oomkapwn/enquire-mcp.svg?label=npm&color=cb3837)](https://www.npmjs.com/package/@oomkapwn/enquire-mcp)
19
19
  [![downloads](https://img.shields.io/npm/dm/@oomkapwn/enquire-mcp.svg?color=cb3837)](https://www.npmjs.com/package/@oomkapwn/enquire-mcp)
20
- [![tests](https://img.shields.io/badge/tests-1469%20passing-brightgreen.svg)](#️-신뢰)
20
+ [![tests](https://img.shields.io/badge/tests-1473%20passing-brightgreen.svg)](#️-신뢰)
21
21
  [![stable](https://img.shields.io/badge/v3.11.x-stable-brightgreen.svg)](./STABILITY.md)
22
22
  [![build provenance](https://img.shields.io/badge/build_provenance-SLSA_L2-blue.svg)](https://slsa.dev/spec/v1.0/levels#build-l2)
23
23
  [![MCP](https://img.shields.io/badge/MCP-1.29-8A2BE2.svg)](https://modelcontextprotocol.io/)
@@ -55,7 +55,7 @@ claude mcp add obsidian -- npx -y @oomkapwn/enquire-mcp serve --vault ~/Document
55
55
  > 3. **serve 중 클라우드 호출 0건.** 임베딩 모델은 **당신의 머신에서** 실행되어 **당신이** 작성한 마크다운을 인덱싱합니다 — 그래서 클라우드 API 키가 아니라 일회성 로컬 다운로드(~110 MB)입니다. 근거 기반 + 프라이버시는 공짜가 아니며, 우리는 그런 척하지 않습니다. 당신의 Vault 콘텐츠는 당신의 머신을 결코 떠나지 않으며, 기본적으로 에어갭(air-gap) 안전합니다([강제됨](./SECURITY.md), 희망 사항이 아님).
56
56
  > 4. **신선도를 인식하는 회상.** 모든 결과는 노트가 얼마나 오래되었는지 보고합니다. 선택형 최신성 재순위는 에이전트가 신선한 지식을 선호하고 재검증이 필요한 오래된 사실을 표시하도록 합니다 — 망각을 인식하는 최전선이, 당신의 파일이 이미 가진 `mtime` 위에 구축됩니다.
57
57
 
58
- **도구 46개 · MCP 프롬프트 19개 · 단위 테스트 1469+개 · 50+ 개 언어 · v3.11.x stable · semver 결속 · MIT · npm 빌드 출처 증명(SLSA L2).**
58
+ **도구 46개 · MCP 프롬프트 19개 · 단위 테스트 1473+개 · 50+ 개 언어 · v3.11.x stable · semver 결속 · MIT · npm 빌드 출처 증명(SLSA L2).**
59
59
 
60
60
  ---
61
61
 
@@ -83,7 +83,7 @@ claude mcp add obsidian -- npx -y @oomkapwn/enquire-mcp serve --vault ~/Document
83
83
  | **GraphRAG-light** (Louvain 모듈성을 통한 위키링크 커뮤니티 탐지) | ✅ **여기에만 있음** | ❌ | ❌ |
84
84
  | **독립 실행형 `.base` 쿼리 실행** (Obsidian 실행 없이 동작) | ✅ **여기에만 있음** | ❌ | ❌ Obsidian에 위임 |
85
85
  | **HyDE 검색** (Gao et al 2023) + 하위 질문 분해 | ✅ **여기에만 있음** | ❌ | ❌ |
86
- | **단위 테스트 1469개 · PR당 필수 9개 + 권고 5개 CI 게이트** | ✅ | 해당 없음 | 드묾 |
86
+ | **단위 테스트 1473개 · PR당 필수 9개 + 권고 5개 CI 게이트** | ✅ | 해당 없음 | 드묾 |
87
87
  | **서명된 빌드 출처 증명** (npm + Sigstore, SLSA Build L2) | ✅ | 해당 없음 | ❌ |
88
88
  | **semver로 결속된 공개 표면** ([STABILITY.md](./STABILITY.md)) | ✅ | 해당 없음 | ❌ |
89
89
  | 독립 실행형 (Obsidian 플러그인 불필요) | ✅ | ❌ Obsidian 필요 | 제각각 |
@@ -322,7 +322,7 @@ graph LR
322
322
  ```bash
323
323
  git clone https://github.com/oomkapwn/enquire-mcp.git
324
324
  cd enquire-mcp && npm install
325
- npm test # 전체 스위트 (1469개 테스트, ~12초)
325
+ npm test # 전체 스위트 (1473개 테스트, ~12초)
326
326
  npm run lint # 경고 0건
327
327
  npm run build # tsc → dist/
328
328
  ```
package/README.md CHANGED
@@ -17,7 +17,7 @@
17
17
  [![CI](https://github.com/oomkapwn/enquire-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/oomkapwn/enquire-mcp/actions/workflows/ci.yml)
18
18
  [![npm](https://img.shields.io/npm/v/@oomkapwn/enquire-mcp.svg?label=npm&color=cb3837)](https://www.npmjs.com/package/@oomkapwn/enquire-mcp)
19
19
  [![downloads](https://img.shields.io/npm/dm/@oomkapwn/enquire-mcp.svg?color=cb3837)](https://www.npmjs.com/package/@oomkapwn/enquire-mcp)
20
- [![tests](https://img.shields.io/badge/tests-1469%20passing-brightgreen.svg)](#️-trust)
20
+ [![tests](https://img.shields.io/badge/tests-1473%20passing-brightgreen.svg)](#️-trust)
21
21
  [![stable](https://img.shields.io/badge/v3.11.x-stable-brightgreen.svg)](./STABILITY.md)
22
22
  [![build provenance](https://img.shields.io/badge/build_provenance-SLSA_L2-blue.svg)](https://slsa.dev/spec/v1.0/levels#build-l2)
23
23
  [![MCP](https://img.shields.io/badge/MCP-1.29-8A2BE2.svg)](https://modelcontextprotocol.io/)
@@ -53,7 +53,7 @@ Your Obsidian vault becomes **persistent, queryable long-term memory** for any M
53
53
  > 3. **Zero cloud calls during serve.** The embedding model runs **on your machine** and indexes the markdown **you** wrote — that's why it's a one-time local download (~110 MB), not a cloud API key. Grounded + private isn't free, and we don't pretend it is: your vault content never leaves your machine, air-gap-safe by default ([enforced](./SECURITY.md), not aspirational).
54
54
  > 4. **Freshness-aware recall.** Every hit reports how old the note is; opt-in recency re-ranking lets an agent prefer fresh knowledge and flag stale facts for re-verification — the forgetting-aware frontier, built on the `mtime` your files already have.
55
55
 
56
- **46 tools · 19 MCP prompts · 1469 unit tests · 50+ languages · v3.11.x stable · semver-bound · MIT · npm build provenance (SLSA L2).**
56
+ **46 tools · 19 MCP prompts · 1473 unit tests · 50+ languages · v3.11.x stable · semver-bound · MIT · npm build provenance (SLSA L2).**
57
57
 
58
58
  ---
59
59
 
@@ -81,7 +81,7 @@ Your Obsidian vault becomes **persistent, queryable long-term memory** for any M
81
81
  | **GraphRAG-light** (wikilink community detection via Louvain modularity) | ✅ **only here** | ❌ | ❌ |
82
82
  | **Standalone `.base` query execution** (works without Obsidian running) | ✅ **only here** | ❌ | ❌ delegates to Obsidian |
83
83
  | **HyDE retrieval** (Gao et al 2023) + sub-question decomposition | ✅ **only here** | ❌ | ❌ |
84
- | **1469 unit tests · 9 required + 5 advisory CI gates per PR** | ✅ | n/a | rare |
84
+ | **1473 unit tests · 9 required + 5 advisory CI gates per PR** | ✅ | n/a | rare |
85
85
  | **Signed build provenance** (npm + Sigstore, SLSA Build L2) | ✅ | n/a | ❌ |
86
86
  | **Semver-bound public surface** ([STABILITY.md](./STABILITY.md)) | ✅ | n/a | ❌ |
87
87
  | Standalone (no Obsidian plugin needed) | ✅ | ❌ requires Obsidian | varies |
@@ -320,7 +320,7 @@ Channel: `npm install @oomkapwn/enquire-mcp` → latest stable (`@latest` = v3.1
320
320
  ```bash
321
321
  git clone https://github.com/oomkapwn/enquire-mcp.git
322
322
  cd enquire-mcp && npm install
323
- npm test # full suite (1469 tests, ~12s)
323
+ npm test # full suite (1473 tests, ~12s)
324
324
  npm run lint # zero warnings
325
325
  npm run build # tsc → dist/
326
326
  ```
package/README.pt.md CHANGED
@@ -15,7 +15,7 @@
15
15
  [![CI](https://github.com/oomkapwn/enquire-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/oomkapwn/enquire-mcp/actions/workflows/ci.yml)
16
16
  [![npm](https://img.shields.io/npm/v/@oomkapwn/enquire-mcp.svg?label=npm&color=cb3837)](https://www.npmjs.com/package/@oomkapwn/enquire-mcp)
17
17
  [![downloads](https://img.shields.io/npm/dm/@oomkapwn/enquire-mcp.svg?color=cb3837)](https://www.npmjs.com/package/@oomkapwn/enquire-mcp)
18
- [![tests](https://img.shields.io/badge/tests-1469%20passing-brightgreen.svg)](#️-confiança)
18
+ [![tests](https://img.shields.io/badge/tests-1473%20passing-brightgreen.svg)](#️-confiança)
19
19
  [![stable](https://img.shields.io/badge/v3.11.x-stable-brightgreen.svg)](./STABILITY.md)
20
20
  [![build provenance](https://img.shields.io/badge/build_provenance-SLSA_L2-blue.svg)](https://slsa.dev/spec/v1.0/levels#build-l2)
21
21
  [![MCP](https://img.shields.io/badge/MCP-1.29-8A2BE2.svg)](https://modelcontextprotocol.io/)
@@ -53,7 +53,7 @@ Seu vault do Obsidian se torna **memória de longo prazo persistente e consultá
53
53
  > 3. **Zero chamadas à nuvem durante o serve.** Modelos em cache local (download único do HuggingFace). O conteúdo do seu vault nunca sai da sua máquina. Seguro para ambientes isolados (air-gap) por padrão.
54
54
  > 4. **Recuperação consciente da atualidade.** Cada resultado informa quão antiga é a nota; o reranqueamento por recência opcional permite que um agente prefira conhecimento recente e sinalize fatos desatualizados para reverificação — a fronteira consciente do esquecimento, construída sobre o `mtime` que seus arquivos já têm.
55
55
 
56
- **46 ferramentas · 19 prompts MCP · 1469+ testes unitários · 50+ idiomas · v3.11.x estável · vinculado a semver · MIT · proveniência de build no npm (SLSA L2).**
56
+ **46 ferramentas · 19 prompts MCP · 1473+ testes unitários · 50+ idiomas · v3.11.x estável · vinculado a semver · MIT · proveniência de build no npm (SLSA L2).**
57
57
 
58
58
  ---
59
59
 
@@ -81,7 +81,7 @@ Seu vault do Obsidian se torna **memória de longo prazo persistente e consultá
81
81
  | **GraphRAG-light** (detecção de comunidades de wikilinks via modularidade de Louvain) | ✅ **só aqui** | ❌ | ❌ |
82
82
  | **Execução autônoma de consultas `.base`** (funciona sem o Obsidian em execução) | ✅ **só aqui** | ❌ | ❌ delega ao Obsidian |
83
83
  | **Recuperação HyDE** (Gao et al. 2023) + decomposição em sub-perguntas | ✅ **só aqui** | ❌ | ❌ |
84
- | **1469 testes unitários · 9 gates obrigatórios + 5 consultivos de CI por PR** | ✅ | n/d | raro |
84
+ | **1473 testes unitários · 9 gates obrigatórios + 5 consultivos de CI por PR** | ✅ | n/d | raro |
85
85
  | **Proveniência de build assinada** (npm + Sigstore, SLSA Build L2) | ✅ | n/d | ❌ |
86
86
  | **Superfície pública vinculada a semver** ([STABILITY.md](./STABILITY.md)) | ✅ | n/d | ❌ |
87
87
  | Autônomo (sem necessidade de plugin do Obsidian) | ✅ | ❌ exige Obsidian | varia |
@@ -320,7 +320,7 @@ Canal: `npm install @oomkapwn/enquire-mcp` → último estável (`@latest` = v3.
320
320
  ```bash
321
321
  git clone https://github.com/oomkapwn/enquire-mcp.git
322
322
  cd enquire-mcp && npm install
323
- npm test # suíte completa (1469 testes, ~12s)
323
+ npm test # suíte completa (1473 testes, ~12s)
324
324
  npm run lint # zero avisos
325
325
  npm run build # tsc → dist/
326
326
  ```
package/README.ru.md CHANGED
@@ -15,7 +15,7 @@
15
15
  [![CI](https://github.com/oomkapwn/enquire-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/oomkapwn/enquire-mcp/actions/workflows/ci.yml)
16
16
  [![npm](https://img.shields.io/npm/v/@oomkapwn/enquire-mcp.svg?label=npm&color=cb3837)](https://www.npmjs.com/package/@oomkapwn/enquire-mcp)
17
17
  [![downloads](https://img.shields.io/npm/dm/@oomkapwn/enquire-mcp.svg?color=cb3837)](https://www.npmjs.com/package/@oomkapwn/enquire-mcp)
18
- [![tests](https://img.shields.io/badge/tests-1469%20passing-brightgreen.svg)](#️-доверие)
18
+ [![tests](https://img.shields.io/badge/tests-1473%20passing-brightgreen.svg)](#️-доверие)
19
19
  [![stable](https://img.shields.io/badge/v3.11.x-stable-brightgreen.svg)](./STABILITY.md)
20
20
  [![build provenance](https://img.shields.io/badge/build_provenance-SLSA_L2-blue.svg)](https://slsa.dev/spec/v1.0/levels#build-l2)
21
21
  [![MCP](https://img.shields.io/badge/MCP-1.29-8A2BE2.svg)](https://modelcontextprotocol.io/)
@@ -53,7 +53,7 @@ claude mcp add obsidian -- npx -y @oomkapwn/enquire-mcp serve --vault ~/Document
53
53
  > 3. **Ноль обращений в облако в режиме serve.** Модели кешируются локально (однократная загрузка с HuggingFace). Содержимое вашего хранилища никогда не покидает вашу машину. По умолчанию безопасно для изолированных сред.
54
54
  > 4. **Поиск с учётом свежести.** Каждый результат сообщает, насколько стара заметка; опциональное переранжирование по давности позволяет агенту предпочитать свежие знания и помечать устаревшие факты для повторной проверки — рубеж «осознания забывания», построенный на `mtime`, который ваши файлы уже имеют.
55
55
 
56
- **46 инструментов · 19 MCP-промптов · 1469+ модульных тестов · 50+ языков · стабильная ветка v3.11.x · с гарантиями semver · MIT · подтверждённая сборка в npm (SLSA L2).**
56
+ **46 инструментов · 19 MCP-промптов · 1473+ модульных тестов · 50+ языков · стабильная ветка v3.11.x · с гарантиями semver · MIT · подтверждённая сборка в npm (SLSA L2).**
57
57
 
58
58
  ---
59
59
 
@@ -81,7 +81,7 @@ claude mcp add obsidian -- npx -y @oomkapwn/enquire-mcp serve --vault ~/Document
81
81
  | **GraphRAG-light** (детекция сообществ по wikilink-графу через модулярность Лувена) | ✅ **только здесь** | ❌ | ❌ |
82
82
  | **Автономное выполнение `.base`-запросов** (работает без запущенного Obsidian) | ✅ **только здесь** | ❌ | ❌ делегирует Obsidian |
83
83
  | **HyDE-поиск** (Gao et al 2023) + декомпозиция на подвопросы | ✅ **только здесь** | ❌ | ❌ |
84
- | **1469 модульных тестов · 9 обязательных + 5 совещательных CI-гейтов на каждый PR** | ✅ | н/д | редко |
84
+ | **1473 модульных тестов · 9 обязательных + 5 совещательных CI-гейтов на каждый PR** | ✅ | н/д | редко |
85
85
  | **Подтверждённое происхождение сборки** (npm + Sigstore, SLSA Build L2) | ✅ | н/д | ❌ |
86
86
  | **Публичная поверхность с гарантиями semver** ([STABILITY.md](./STABILITY.md)) | ✅ | н/д | ❌ |
87
87
  | Автономность (плагин Obsidian не нужен) | ✅ | ❌ требует Obsidian | по-разному |
@@ -320,7 +320,7 @@ graph LR
320
320
  ```bash
321
321
  git clone https://github.com/oomkapwn/enquire-mcp.git
322
322
  cd enquire-mcp && npm install
323
- npm test # полный набор (1469 тестов, ~12с)
323
+ npm test # полный набор (1473 тестов, ~12с)
324
324
  npm run lint # ноль предупреждений
325
325
  npm run build # tsc → dist/
326
326
  ```
package/README.zh.md CHANGED
@@ -48,7 +48,7 @@ claude mcp add obsidian -- npx -y @oomkapwn/enquire-mcp serve --vault ~/Document
48
48
  > 3. **serve 期间零云端调用。** 向量嵌入模型**在你的机器上**运行,索引的是**你**亲手写下的 markdown——正因如此,它是一次性的本地下载(约 110 MB),而不是一个云端 API 密钥。扎根 + 隐私并非没有代价,我们也不假装它免费:你的仓库内容永不离开本机,默认即可隔离(air-gap)安全运行([已强制执行](./SECURITY.md),而非纸面承诺)。
49
49
  > 4. **时效感知召回。** 每条结果都报告笔记有多旧;可选的时效重排让智能体优先采用新知识,并把陈旧事实标记出来等待复核——这是"遗忘感知"前沿,建立在你的文件本就拥有的 `mtime` 之上。
50
50
 
51
- **46 个工具 · 19 个 MCP 提示词 · 1469+ 单元测试 · 50+ 语言 · v3.11.x 稳定版 · 语义化版本约束 · MIT · npm 构建溯源(SLSA L2)。**
51
+ **46 个工具 · 19 个 MCP 提示词 · 1473+ 单元测试 · 50+ 语言 · v3.11.x 稳定版 · 语义化版本约束 · MIT · npm 构建溯源(SLSA L2)。**
52
52
 
53
53
  ---
54
54
 
@@ -76,7 +76,7 @@ claude mcp add obsidian -- npx -y @oomkapwn/enquire-mcp serve --vault ~/Document
76
76
  | **GraphRAG-light**(Louvain 模块度社群检测) | ✅ **独有** | ❌ | ❌ |
77
77
  | **独立 `.base` 查询执行**(无需运行 Obsidian) | ✅ **独有** | ❌ | ❌ 委托给 Obsidian |
78
78
  | **HyDE 检索**(Gao et al. 2023)+ 子问题分解 | ✅ **独有** | ❌ | ❌ |
79
- | **1469 单元测试 · 每个 PR 9 项必需 + 5 项指导性 CI 门禁** | ✅ | 不适用 | 罕见 |
79
+ | **1473 单元测试 · 每个 PR 9 项必需 + 5 项指导性 CI 门禁** | ✅ | 不适用 | 罕见 |
80
80
  | **签名构建溯源**(npm + Sigstore,SLSA Build L2) | ✅ | 不适用 | ❌ |
81
81
  | **语义化版本约束的公开接口**([STABILITY.md](./STABILITY.md)) | ✅ | 不适用 | ❌ |
82
82
  | 独立运行(无需 Obsidian 插件) | ✅ | ❌ 需 Obsidian | 不一 |
@@ -315,7 +315,7 @@ graph LR
315
315
  ```bash
316
316
  git clone https://github.com/oomkapwn/enquire-mcp.git
317
317
  cd enquire-mcp && npm install
318
- npm test # 完整套件(1469 个测试,约 12s)
318
+ npm test # 完整套件(1473 个测试,约 12s)
319
319
  npm run lint # 零警告
320
320
  npm run build # tsc → dist/
321
321
  ```
package/dist/fence.d.ts CHANGED
@@ -17,4 +17,26 @@
17
17
  * opensBlockFence("plain text"); // false
18
18
  */
19
19
  export declare function opensBlockFence(line: string): boolean;
20
+ /** The fence character (`` ` `` or `~`) if `line` is a BLOCK code-fence delimiter, else null.
21
+ * A leading run closed by another same-char run on the SAME line is an inline span → null. */
22
+ export type FenceChar = "`" | "~";
23
+ export declare function blockFenceDelimiter(line: string): FenceChar | null;
24
+ /**
25
+ * Advance a CHAR-AWARE fence state machine by one line. Returns the new open-fence
26
+ * marker (the char that opened the current block, or null when outside) and whether
27
+ * this line is a block-fence DELIMITER (an open, or a CLOSE whose char matches the open).
28
+ *
29
+ * v3.11.5-rc.5 (meta-audit) — the correct pattern to replace the char-BLIND `inFence =
30
+ * !inFence` toggle: a `` ``` `` line inside a `~~~` block (or vice versa) is LITERAL code,
31
+ * NOT a delimiter, so it must not flip the state — matching CommonMark + the parser's
32
+ * `stripCodeAndInline` (which pairs ``` with ``` and ~~~ with ~~~ independently). Only
33
+ * fts5's breadcrumb walker tracked this; write.ts/read.ts/meta.ts used the blind toggle,
34
+ * so a mismatched inner fence corrupted rename/replace edits, the heading map, and
35
+ * open-questions. Callers: `const s = advanceFence(line, marker); marker = s.marker; if
36
+ * (s.delimiter) {…continue…} if (marker !== null) {…in-fence…}`.
37
+ */
38
+ export declare function advanceFence(line: string, marker: FenceChar | null): {
39
+ marker: FenceChar | null;
40
+ delimiter: boolean;
41
+ };
20
42
  //# sourceMappingURL=fence.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fence.d.ts","sourceRoot":"","sources":["../src/fence.ts"],"names":[],"mappings":"AAWA;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAQrD"}
1
+ {"version":3,"file":"fence.d.ts","sourceRoot":"","sources":["../src/fence.ts"],"names":[],"mappings":"AAWA;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;+FAC+F;AAC/F,MAAM,MAAM,SAAS,GAAG,GAAG,GAAG,GAAG,CAAC;AAClC,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAOlE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI,GAAG;IAAE,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAMrH"}
package/dist/fence.js CHANGED
@@ -27,13 +27,39 @@
27
27
  * opensBlockFence("plain text"); // false
28
28
  */
29
29
  export function opensBlockFence(line) {
30
+ return blockFenceDelimiter(line) !== null;
31
+ }
32
+ export function blockFenceDelimiter(line) {
30
33
  const m = /^\s*(`{3,}|~{3,})/.exec(line);
31
34
  if (!m?.[1])
32
- return false;
33
- const fenceChar = m[1][0] ?? "`";
35
+ return null;
36
+ const ch = m[1][0] === "~" ? "~" : "`";
34
37
  const rest = line.slice(m.index + m[0].length);
35
- // A later run of the SAME fence char on this line closes it inline → an inline
36
- // span, not a block-fence delimiter.
37
- return !rest.includes(fenceChar.repeat(3));
38
+ // A later run of the SAME fence char on this line closes it inline → an inline span.
39
+ return rest.includes(ch.repeat(3)) ? null : ch;
40
+ }
41
+ /**
42
+ * Advance a CHAR-AWARE fence state machine by one line. Returns the new open-fence
43
+ * marker (the char that opened the current block, or null when outside) and whether
44
+ * this line is a block-fence DELIMITER (an open, or a CLOSE whose char matches the open).
45
+ *
46
+ * v3.11.5-rc.5 (meta-audit) — the correct pattern to replace the char-BLIND `inFence =
47
+ * !inFence` toggle: a `` ``` `` line inside a `~~~` block (or vice versa) is LITERAL code,
48
+ * NOT a delimiter, so it must not flip the state — matching CommonMark + the parser's
49
+ * `stripCodeAndInline` (which pairs ``` with ``` and ~~~ with ~~~ independently). Only
50
+ * fts5's breadcrumb walker tracked this; write.ts/read.ts/meta.ts used the blind toggle,
51
+ * so a mismatched inner fence corrupted rename/replace edits, the heading map, and
52
+ * open-questions. Callers: `const s = advanceFence(line, marker); marker = s.marker; if
53
+ * (s.delimiter) {…continue…} if (marker !== null) {…in-fence…}`.
54
+ */
55
+ export function advanceFence(line, marker) {
56
+ const d = blockFenceDelimiter(line);
57
+ if (!d)
58
+ return { marker, delimiter: false };
59
+ if (marker === null)
60
+ return { marker: d, delimiter: true }; // opens a block
61
+ if (d === marker)
62
+ return { marker: null, delimiter: true }; // closes it (matching char)
63
+ return { marker, delimiter: false }; // different-char fence inside a block = literal content
38
64
  }
39
65
  //# sourceMappingURL=fence.js.map
package/dist/fence.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"fence.js","sourceRoot":"","sources":["../src/fence.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,oFAAoF;AACpF,sFAAsF;AACtF,4EAA4E;AAC5E,yCAAyC;AACzC,EAAE;AACF,wFAAwF;AACxF,yFAAyF;AACzF,wFAAwF;AACxF,0FAA0F;AAE1F;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,MAAM,CAAC,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1B,MAAM,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;IACjC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC/C,+EAA+E;IAC/E,qCAAqC;IACrC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7C,CAAC"}
1
+ {"version":3,"file":"fence.js","sourceRoot":"","sources":["../src/fence.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,oFAAoF;AACpF,sFAAsF;AACtF,4EAA4E;AAC5E,yCAAyC;AACzC,EAAE;AACF,wFAAwF;AACxF,yFAAyF;AACzF,wFAAwF;AACxF,0FAA0F;AAE1F;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAO,mBAAmB,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC;AAC5C,CAAC;AAKD,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,MAAM,CAAC,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,EAAE,GAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAClD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC/C,qFAAqF;IACrF,OAAO,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;AACjD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,MAAwB;IACjE,MAAM,CAAC,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAC5C,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,gBAAgB;IAC5E,IAAI,CAAC,KAAK,MAAM;QAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,4BAA4B;IACxF,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,wDAAwD;AAC/F,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"fts5.d.ts","sourceRoot":"","sources":["../src/fts5.ts"],"names":[],"mappings":"AAoCA;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,SAAS,CAAC;AAEnD,oEAAoE;AACpE,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,KAAK,CAAC;AAErC;kEACkE;AAClE,MAAM,WAAW,YAAY;IAC3B,oDAAoD;IACpD,QAAQ,EAAE,MAAM,CAAC;IACjB,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;IAChB;+DAC2D;IAC3D,KAAK,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,IAAI,EAAE,SAAS,CAAC;CACjB;AAED,wEAAwE;AACxE,MAAM,WAAW,aAAa;IAC5B,uDAAuD;IACvD,KAAK,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,YAAY,EAAE,MAAM,CAAC;CACtB;AAiED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,EAAE,CAAmB;IAC7B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;IACxC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,YAAY,CAAA;KAAE;IAM9E;;;;;;;OAOG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAwC3B,iEAAiE;IAC3D,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAcrC;6BACyB;IACzB,KAAK,IAAI,IAAI;IAOb,OAAO,CAAC,eAAe;IAsEvB,OAAO,CAAC,QAAQ;IAQhB,OAAO,CAAC,SAAS;IAejB,OAAO,CAAC,SAAS;IAKjB;;;;;;;;;;;OAWG;IACH,IAAI,CACF,WAAW,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,EACxD,IAAI,CAAC,EAAE,SAAS,GACf;QACD,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,OAAO,EAAE,MAAM,EAAE,CAAC;QAClB,SAAS,EAAE,MAAM,EAAE,CAAC;KACrB;IA0BD;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAS/B;;;;;;;;OAQG;IACH,WAAW,CACT,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,eAAe,GAAE,MAAM,EAAO,EAC9B,IAAI,GAAE,MAAM,EAAO,GAClB,MAAM;IAiCT;;;;;;;;;;;OAWG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,MAAM;IA2BpH;;;;;;;;;;;;;;;OAeG;IACH,MAAM,CACJ,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAO,GAClF,YAAY,EAAE;IAgFjB;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAQ/G,kEAAkE;IAClE,WAAW,IAAI,MAAM;IAMrB;yEACqE;IACrE,UAAU,IAAI,MAAM;CAKrB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAyB/C;AAED,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB;;;;+EAI2E;IAC3E,UAAU,EAAE,MAAM,CAAC;CACpB;AAID;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,SAAkB,GAAG,YAAY,EAAE,CAmExF;AAED;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CA4DlE;AAuBD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAM1D;AA8BD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAErF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,YAAY,CAAC;CAC9B,GAAG,IAAI,CAAC,CAmCR"}
1
+ {"version":3,"file":"fts5.d.ts","sourceRoot":"","sources":["../src/fts5.ts"],"names":[],"mappings":"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"}
package/dist/fts5.js CHANGED
@@ -14,7 +14,7 @@ import { createHash } from "node:crypto";
14
14
  import { promises as fs } from "node:fs";
15
15
  import * as os from "node:os";
16
16
  import * as path from "node:path";
17
- import { opensBlockFence } from "./fence.js";
17
+ import { advanceFence } from "./fence.js";
18
18
  import { optionalDepDetail } from "./optional-dep.js";
19
19
  import { countLineBreaks, splitLines, stripTrailingHashes, stripTrailingLineEnds, stripTrailingSlashes } from "./wildcard-match.js";
20
20
  const SCHEMA_VERSION = 4;
@@ -638,35 +638,17 @@ export function computeBreadcrumbsByLine(content) {
638
638
  const lines = splitLines(content);
639
639
  const out = new Array(lines.length).fill("");
640
640
  const stack = []; // index = depth-1, value = heading text
641
- let inFence = false;
642
- let fenceMarker = "";
641
+ let fenceMarker = null;
643
642
  for (let i = 0; i < lines.length; i++) {
644
643
  const ln = lines[i] ?? "";
645
- // v3.11.5-rc.2 (post-rc.1 re-sweep, WRITE-FENCE sibling) gate the marker logic
646
- // on the shared `opensBlockFence` so a line-leading self-contained inline span
647
- // (`` ```code``` ``) is NOT mistaken for a block-fence open; pre-rc.2 the naive
648
- // `/^(```|~~~)/` match flipped `inFence` on such a line, freezing every following
649
- // line's breadcrumb to the wrong heading stack.
650
- // v3.11.5-rc.4 (post-rc.3 re-sweep) — allow leading whitespace + a variable-length
651
- // fence run (`` `{3,} `` / `~{3,}`), so an INDENTED code fence (up to 3 spaces, valid
652
- // CommonMark) is detected matching read.ts extractHeadings, which routes through
653
- // opensBlockFence (indent-tolerant). Close-matching keys on the fence CHAR (``` closes
654
- // only ```, ~~~ only ~~~) so it is robust across differing run lengths.
655
- const fenceMatch = /^\s*(`{3,}|~{3,})/.exec(ln);
656
- const fenceChar = fenceMatch?.[1]?.[0];
657
- if (fenceChar && opensBlockFence(ln)) {
658
- if (!inFence) {
659
- inFence = true;
660
- fenceMarker = fenceChar;
661
- }
662
- else if (fenceChar === fenceMarker) {
663
- inFence = false;
664
- fenceMarker = "";
665
- }
666
- out[i] = stack.join(" > ");
667
- continue;
668
- }
669
- if (inFence) {
644
+ // v3.11.5-rc.5 (meta-audit) the canonical char-aware fence walk lives in fence.ts's
645
+ // advanceFence: an inline span isn't a block fence (rc.2), an indented fence IS detected
646
+ // (rc.4), and a `~~~` line inside a ``` block is literal content, not a close (this walker
647
+ // pioneered the char-aware close-match; all walkers now share the one implementation).
648
+ const st = advanceFence(ln, fenceMarker);
649
+ fenceMarker = st.marker;
650
+ if (st.delimiter || fenceMarker !== null) {
651
+ // a fence delimiter, or any line inside the fence → breadcrumb stays the current stack
670
652
  out[i] = stack.join(" > ");
671
653
  continue;
672
654
  }