living-documentation 8.15.0 → 8.17.0
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/dist/src/frontend/confirm-modal.js +10 -1
- package/dist/src/frontend/documents.js +4 -0
- package/dist/src/frontend/i18n/en.json +8 -0
- package/dist/src/frontend/i18n/fr.json +8 -0
- package/dist/src/frontend/index.html +21 -0
- package/dist/src/frontend/metadata.js +27 -1
- package/dist/src/frontend/validate.js +107 -0
- package/dist/src/lib/status.d.ts +9 -0
- package/dist/src/lib/status.d.ts.map +1 -0
- package/dist/src/lib/status.js +72 -0
- package/dist/src/lib/status.js.map +1 -0
- package/dist/src/mcp/tools/metadata.d.ts.map +1 -1
- package/dist/src/mcp/tools/metadata.js +4 -0
- package/dist/src/mcp/tools/metadata.js.map +1 -1
- package/dist/src/routes/metadata.d.ts.map +1 -1
- package/dist/src/routes/metadata.js +24 -0
- package/dist/src/routes/metadata.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
// ── Generic confirmation modal ──────────────────────────────────────────────
|
|
2
2
|
// Promise-based replacement for window.confirm(). Any module can call:
|
|
3
|
-
// const ok = await showConfirm({ title, message, detail, confirmLabel, danger });
|
|
3
|
+
// const ok = await showConfirm({ title, message, detail, confirmLabel, danger, detailTone });
|
|
4
4
|
// The modal sits at z-[60] so it stacks above other app modals (z-50).
|
|
5
|
+
// `detailTone: "warning"` renders the detail block as an amber callout when the
|
|
6
|
+
// secondary message carries a consequence the user should not miss.
|
|
5
7
|
|
|
6
8
|
let _confirmResolve = null;
|
|
7
9
|
|
|
10
|
+
const _DETAIL_NEUTRAL_CLS =
|
|
11
|
+
"text-xs text-gray-500 dark:text-gray-400 italic break-all";
|
|
12
|
+
const _DETAIL_WARNING_CLS =
|
|
13
|
+
"text-xs text-amber-800 dark:text-amber-200 break-all bg-amber-50 dark:bg-amber-900/30 border-l-4 border-amber-500 rounded-r px-3 py-2";
|
|
14
|
+
|
|
8
15
|
function _confirmT(key, fallback) {
|
|
9
16
|
return window.t ? window.t(key) : fallback;
|
|
10
17
|
}
|
|
@@ -49,6 +56,8 @@ function showConfirm(opts) {
|
|
|
49
56
|
messageEl.style.display = o.message ? "" : "none";
|
|
50
57
|
detailEl.textContent = o.detail || "";
|
|
51
58
|
detailEl.style.display = o.detail ? "" : "none";
|
|
59
|
+
detailEl.className =
|
|
60
|
+
o.detailTone === "warning" ? _DETAIL_WARNING_CLS : _DETAIL_NEUTRAL_CLS;
|
|
52
61
|
|
|
53
62
|
cancelBtn.textContent = o.cancelLabel || _confirmT("common.cancel", "Cancel");
|
|
54
63
|
okBtn.textContent = o.confirmLabel || _confirmT("common.confirm", "Confirm");
|
|
@@ -322,6 +322,10 @@ async function openDocument(id, skipHistory = false, fromLink = false, anchor =
|
|
|
322
322
|
_lastDocIdRendered = id;
|
|
323
323
|
_wireDocContent(doc.html);
|
|
324
324
|
|
|
325
|
+
if (typeof updateValidateButtonForCurrentDoc === "function") {
|
|
326
|
+
updateValidateButtonForCurrentDoc();
|
|
327
|
+
}
|
|
328
|
+
|
|
325
329
|
// Load annotations for this document
|
|
326
330
|
loadAnnotations(id);
|
|
327
331
|
|
|
@@ -66,6 +66,14 @@
|
|
|
66
66
|
"sidebar.file_attachment_badge": "attachment",
|
|
67
67
|
"sidebar.file_attached_docs_badge": "document with attachments",
|
|
68
68
|
|
|
69
|
+
"doc.validate_mode": "Validate document — flip frontmatter status from \"To be validated\" to \"Accepted\"",
|
|
70
|
+
"doc.validate_btn": "Validate",
|
|
71
|
+
"doc.validate_title": "Validate this document?",
|
|
72
|
+
"doc.validate_message": "The frontmatter status will change from \"To be validated\" to \"Accepted\".",
|
|
73
|
+
"doc.validate_detail_low_accuracy": "Reliability is currently {accuracy}. Confirming will also re-baseline source-file hashes, bringing reliability back to 100%.",
|
|
74
|
+
"doc.validate_confirm": "Validate",
|
|
75
|
+
"doc.validate_failed": "Validation failed: ",
|
|
76
|
+
"metadata.readonly_banner": "Read-only — this document is SuperSeeded. Source metadata can still be viewed but not edited.",
|
|
69
77
|
"doc.marker_mode": "Marker mode — highlight to annotate",
|
|
70
78
|
"doc.marker_btn": "Marker",
|
|
71
79
|
"doc.toggle_width": "Toggle full width",
|
|
@@ -66,6 +66,14 @@
|
|
|
66
66
|
"sidebar.file_attachment_badge": "pièce jointe",
|
|
67
67
|
"sidebar.file_attached_docs_badge": "document contenant des pièces jointes",
|
|
68
68
|
|
|
69
|
+
"doc.validate_mode": "Valider le document — passer le statut frontmatter de « To be validated » à « Accepted »",
|
|
70
|
+
"doc.validate_btn": "Valider",
|
|
71
|
+
"doc.validate_title": "Valider ce document ?",
|
|
72
|
+
"doc.validate_message": "Le statut frontmatter va passer de « To be validated » à « Accepted ».",
|
|
73
|
+
"doc.validate_detail_low_accuracy": "La fiabilité actuelle est de {accuracy}. Confirmer va aussi réinitialiser les hashes des fichiers source, ramenant la fiabilité à 100 %.",
|
|
74
|
+
"doc.validate_confirm": "Valider",
|
|
75
|
+
"doc.validate_failed": "Échec de la validation : ",
|
|
76
|
+
"metadata.readonly_banner": "Lecture seule — ce document est SuperSeeded. Les métadonnées source peuvent être consultées mais pas modifiées.",
|
|
69
77
|
"doc.marker_mode": "Mode Marqueur — surligner pour annoter",
|
|
70
78
|
"doc.marker_btn": "Marqueur",
|
|
71
79
|
"doc.toggle_width": "Basculer la largeur",
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
<script defer src="/annotations.js"></script>
|
|
52
52
|
<script defer src="/metadata.js"></script>
|
|
53
53
|
<script defer src="/accuracy-gauge.js"></script>
|
|
54
|
+
<script defer src="/validate.js"></script>
|
|
54
55
|
<script defer src="/export.js"></script>
|
|
55
56
|
<script defer src="/diagram-link-modal.js"></script>
|
|
56
57
|
<script defer src="/new-folder-modal.js"></script>
|
|
@@ -620,6 +621,16 @@
|
|
|
620
621
|
<div class="flex items-center gap-2 flex-wrap ml-auto">
|
|
621
622
|
<!-- View mode actions -->
|
|
622
623
|
<div id="view-actions" class="flex items-center gap-2">
|
|
624
|
+
<button
|
|
625
|
+
onclick="validateCurrentDoc()"
|
|
626
|
+
id="validate-btn"
|
|
627
|
+
data-i18n-title="doc.validate_mode"
|
|
628
|
+
title="Validate document"
|
|
629
|
+
class="hidden no-print text-sm px-3 py-1.5 rounded-lg border border-green-700 bg-green-600 text-white font-semibold hover:bg-green-700 transition-colors"
|
|
630
|
+
>
|
|
631
|
+
<i class="fa-solid fa-check" aria-hidden="true" style="margin-right: 4px"></i>
|
|
632
|
+
<span data-i18n="doc.validate_btn">Validate</span>
|
|
633
|
+
</button>
|
|
623
634
|
<button
|
|
624
635
|
onclick="toggleMarker()"
|
|
625
636
|
id="stabilo-btn"
|
|
@@ -900,6 +911,15 @@
|
|
|
900
911
|
class="text-xs text-gray-600 dark:text-gray-300 bg-gray-50 dark:bg-gray-800 rounded-lg px-3 py-2"
|
|
901
912
|
></div>
|
|
902
913
|
|
|
914
|
+
<!-- Read-only banner (SuperSeeded documents) -->
|
|
915
|
+
<div
|
|
916
|
+
id="metadata-readonly-banner"
|
|
917
|
+
data-i18n="metadata.readonly_banner"
|
|
918
|
+
class="hidden text-xs text-amber-800 dark:text-amber-200 bg-amber-50 dark:bg-amber-900/30 border-l-4 border-amber-500 rounded-r px-3 py-2"
|
|
919
|
+
>
|
|
920
|
+
Read-only — this document is SuperSeeded. Source metadata can still be viewed but not edited.
|
|
921
|
+
</div>
|
|
922
|
+
|
|
903
923
|
<!-- List -->
|
|
904
924
|
<div class="border border-gray-200 dark:border-gray-700 rounded-lg overflow-hidden">
|
|
905
925
|
<div
|
|
@@ -919,6 +939,7 @@
|
|
|
919
939
|
<div class="flex items-center gap-2 flex-wrap">
|
|
920
940
|
<button
|
|
921
941
|
onclick="metadataToggleBrowser()"
|
|
942
|
+
id="metadata-add-btn"
|
|
922
943
|
class="text-sm px-3 py-1.5 rounded-lg border border-blue-200 dark:border-blue-700 text-blue-600 dark:text-blue-400 hover:bg-blue-50 dark:hover:bg-blue-900/30 transition-colors"
|
|
923
944
|
>
|
|
924
945
|
<i class="fa-solid fa-plus"></i> <span data-i18n="metadata.add">Add source file</span>
|
|
@@ -75,7 +75,7 @@ function renderMetadataList() {
|
|
|
75
75
|
onclick="metadataRemovePath('${safePath.replace(/'/g, "\\'")}')"
|
|
76
76
|
data-i18n-title="metadata.remove"
|
|
77
77
|
title="Remove"
|
|
78
|
-
class="text-xs px-2 py-1 rounded-lg border border-red-200 dark:border-red-700 text-red-500 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/40 transition-colors"
|
|
78
|
+
class="metadata-row-remove text-xs px-2 py-1 rounded-lg border border-red-200 dark:border-red-700 text-red-500 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/40 transition-colors"
|
|
79
79
|
>
|
|
80
80
|
<i class="fa-solid fa-trash"></i>
|
|
81
81
|
</button>
|
|
@@ -84,8 +84,33 @@ function renderMetadataList() {
|
|
|
84
84
|
.join("");
|
|
85
85
|
|
|
86
86
|
if (typeof window.applyI18n === "function") window.applyI18n();
|
|
87
|
+
applyMetadataReadOnlyMode();
|
|
87
88
|
}
|
|
88
89
|
|
|
90
|
+
// Hide the three metadata-mutation controls (and the row-level trash icons)
|
|
91
|
+
// when the current document's frontmatter status is `SuperSeeded`. The server
|
|
92
|
+
// also rejects these mutations independently — this is purely UX. Re-applied
|
|
93
|
+
// after every list re-render so dynamically generated rows stay consistent.
|
|
94
|
+
function applyMetadataReadOnlyMode() {
|
|
95
|
+
const readOnly =
|
|
96
|
+
typeof window.getDocStatus === "function" &&
|
|
97
|
+
window.getDocStatus(
|
|
98
|
+
typeof currentDocContent !== "undefined" ? currentDocContent : "",
|
|
99
|
+
) === "SuperSeeded";
|
|
100
|
+
|
|
101
|
+
const refreshBtn = document.getElementById("metadata-refresh-btn");
|
|
102
|
+
const addBtn = document.getElementById("metadata-add-btn");
|
|
103
|
+
const banner = document.getElementById("metadata-readonly-banner");
|
|
104
|
+
if (refreshBtn) refreshBtn.classList.toggle("hidden", readOnly);
|
|
105
|
+
if (addBtn) addBtn.classList.toggle("hidden", readOnly);
|
|
106
|
+
if (banner) banner.classList.toggle("hidden", !readOnly);
|
|
107
|
+
document
|
|
108
|
+
.querySelectorAll("#metadata-list .metadata-row-remove")
|
|
109
|
+
.forEach((el) => el.classList.toggle("hidden", readOnly));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
window.applyMetadataReadOnlyMode = applyMetadataReadOnlyMode;
|
|
113
|
+
|
|
89
114
|
function renderMetadataSummary() {
|
|
90
115
|
const el = document.getElementById("metadata-summary");
|
|
91
116
|
if (!el) return;
|
|
@@ -110,6 +135,7 @@ async function openMetadataModal() {
|
|
|
110
135
|
metadataBrowseCurrent = "";
|
|
111
136
|
metadataBrowseCache = null;
|
|
112
137
|
document.getElementById("metadata-browser").classList.add("hidden");
|
|
138
|
+
applyMetadataReadOnlyMode();
|
|
113
139
|
}
|
|
114
140
|
|
|
115
141
|
function closeMetadataModal() {
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// ── Document validation ──────────────────────────────────────────────────────
|
|
2
|
+
// Wires the "Validate" toolbar button: visible only when the loaded document's
|
|
3
|
+
// frontmatter contains `**status:** To be validated`. Clicking flips the status
|
|
4
|
+
// to `Accepted` via PUT /api/documents/:id; if the document's reliability is
|
|
5
|
+
// below 100%, the confirmation modal also warns that source-file hashes will be
|
|
6
|
+
// re-baselined, and POST /api/metadata/:id/refresh is called after the PUT.
|
|
7
|
+
|
|
8
|
+
// Frontmatter on this project is a `---`-fenced block of `**key:** value` lines
|
|
9
|
+
// (not standard YAML). The status line is the only field this module touches.
|
|
10
|
+
const _STATUS_LINE_RE = /^(\*\*status:\*\*\s*).+?\s*$/m;
|
|
11
|
+
|
|
12
|
+
function getDocStatus(content) {
|
|
13
|
+
if (typeof content !== "string") return null;
|
|
14
|
+
const fence = content.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
15
|
+
if (!fence) return null;
|
|
16
|
+
const m = fence[1].match(/^\*\*status:\*\*\s*(.+?)\s*$/m);
|
|
17
|
+
return m ? m[1].trim() : null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function _replaceStatus(content, newStatus) {
|
|
21
|
+
return content.replace(_STATUS_LINE_RE, `$1${newStatus}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function updateValidateButtonForCurrentDoc() {
|
|
25
|
+
const btn = document.getElementById("validate-btn");
|
|
26
|
+
if (!btn) return;
|
|
27
|
+
const status = getDocStatus(
|
|
28
|
+
typeof currentDocContent !== "undefined" ? currentDocContent : "",
|
|
29
|
+
);
|
|
30
|
+
if (status === "To be validated") {
|
|
31
|
+
btn.classList.remove("hidden");
|
|
32
|
+
} else {
|
|
33
|
+
btn.classList.add("hidden");
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function validateCurrentDoc() {
|
|
38
|
+
const id = typeof currentDocId !== "undefined" ? currentDocId : null;
|
|
39
|
+
if (!id) return;
|
|
40
|
+
|
|
41
|
+
// Snapshot accuracy now so the confirm modal warns when re-baselining is implied.
|
|
42
|
+
let accuracy = 1;
|
|
43
|
+
try {
|
|
44
|
+
const r = await fetch("/api/metadata/" + encodeURIComponent(id));
|
|
45
|
+
if (r.ok) {
|
|
46
|
+
const rep = await r.json();
|
|
47
|
+
if (typeof rep.accuracy === "number") accuracy = rep.accuracy;
|
|
48
|
+
}
|
|
49
|
+
} catch {
|
|
50
|
+
// Fall through with accuracy = 1; worst case we skip the warning. The
|
|
51
|
+
// refresh step is still gated on the same value, so semantics stay aligned.
|
|
52
|
+
}
|
|
53
|
+
const pct = Math.round(accuracy * 100);
|
|
54
|
+
const lowAccuracy = pct < 100;
|
|
55
|
+
const detail = lowAccuracy
|
|
56
|
+
? window.t("doc.validate_detail_low_accuracy").replace("{accuracy}", pct + "%")
|
|
57
|
+
: "";
|
|
58
|
+
|
|
59
|
+
const ok = await window.showConfirm({
|
|
60
|
+
title: window.t("doc.validate_title"),
|
|
61
|
+
message: window.t("doc.validate_message"),
|
|
62
|
+
detail,
|
|
63
|
+
detailTone: lowAccuracy ? "warning" : undefined,
|
|
64
|
+
confirmLabel: window.t("doc.validate_confirm"),
|
|
65
|
+
});
|
|
66
|
+
if (!ok) return;
|
|
67
|
+
|
|
68
|
+
const btn = document.getElementById("validate-btn");
|
|
69
|
+
if (btn) btn.disabled = true;
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const newContent = _replaceStatus(currentDocContent, "Accepted");
|
|
73
|
+
if (newContent === currentDocContent) {
|
|
74
|
+
throw new Error("status line not found in frontmatter");
|
|
75
|
+
}
|
|
76
|
+
const putRes = await fetch("/api/documents/" + encodeURIComponent(id), {
|
|
77
|
+
method: "PUT",
|
|
78
|
+
headers: { "Content-Type": "application/json" },
|
|
79
|
+
body: JSON.stringify({ content: newContent }),
|
|
80
|
+
});
|
|
81
|
+
if (!putRes.ok) throw new Error(putRes.statusText || "save failed");
|
|
82
|
+
|
|
83
|
+
if (lowAccuracy) {
|
|
84
|
+
const refRes = await fetch(
|
|
85
|
+
"/api/metadata/" + encodeURIComponent(id) + "/refresh",
|
|
86
|
+
{ method: "POST" },
|
|
87
|
+
);
|
|
88
|
+
if (!refRes.ok) throw new Error(refRes.statusText || "refresh failed");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (typeof openDocument === "function") {
|
|
92
|
+
await openDocument(id, /* skipHistory */ true);
|
|
93
|
+
}
|
|
94
|
+
if (typeof loadMetadataReport === "function") {
|
|
95
|
+
await loadMetadataReport(id);
|
|
96
|
+
}
|
|
97
|
+
} catch (err) {
|
|
98
|
+
const msg = err && err.message ? err.message : String(err);
|
|
99
|
+
alert(window.t("doc.validate_failed") + msg);
|
|
100
|
+
} finally {
|
|
101
|
+
if (btn) btn.disabled = false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
window.validateCurrentDoc = validateCurrentDoc;
|
|
106
|
+
window.updateValidateButtonForCurrentDoc = updateValidateButtonForCurrentDoc;
|
|
107
|
+
window.getDocStatus = getDocStatus;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function parseDocStatus(content: string): string | null;
|
|
2
|
+
export declare function readDocStatus(docsPath: string, decodedDocId: string, extraFiles: string[]): string | null;
|
|
3
|
+
export declare const SUPERSEEDED_STATUS = "SuperSeeded";
|
|
4
|
+
export declare class DocumentSuperSeededError extends Error {
|
|
5
|
+
readonly code = "DOCUMENT_SUPERSEEDED";
|
|
6
|
+
constructor(message?: string);
|
|
7
|
+
}
|
|
8
|
+
export declare function assertNotSuperSeeded(docsPath: string, decodedDocId: string): void;
|
|
9
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/lib/status.ts"],"names":[],"mappings":"AAcA,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM7D;AAmBD,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,EAAE,GACnB,MAAM,GAAG,IAAI,CAQf;AAED,eAAO,MAAM,kBAAkB,gBAAgB,CAAC;AAKhD,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,QAAQ,CAAC,IAAI,0BAA0B;gBAErC,OAAO,SAAoD;CAK9D;AAED,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,GACnB,IAAI,CAKN"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ── Frontmatter status helpers ───────────────────────────────────────────────
|
|
3
|
+
// The project's frontmatter is not standard YAML: each line is `**key:** value`
|
|
4
|
+
// inside a `---`-fenced block. This module reads only the `status` line — used
|
|
5
|
+
// to gate mutations based on the doc lifecycle (e.g. block metadata writes on
|
|
6
|
+
// a SuperSeeded ADR). The `assertNotSuperSeeded` guard is consumed both by the
|
|
7
|
+
// HTTP routes and by the MCP tools — they share the same source of truth.
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.DocumentSuperSeededError = exports.SUPERSEEDED_STATUS = void 0;
|
|
13
|
+
exports.parseDocStatus = parseDocStatus;
|
|
14
|
+
exports.readDocStatus = readDocStatus;
|
|
15
|
+
exports.assertNotSuperSeeded = assertNotSuperSeeded;
|
|
16
|
+
const fs_1 = __importDefault(require("fs"));
|
|
17
|
+
const path_1 = __importDefault(require("path"));
|
|
18
|
+
const config_1 = require("./config");
|
|
19
|
+
const STATUS_LINE_RE = /^\*\*status:\*\*\s*(.+?)\s*$/m;
|
|
20
|
+
const FRONTMATTER_FENCE_RE = /^---\s*\n([\s\S]*?)\n---/;
|
|
21
|
+
function parseDocStatus(content) {
|
|
22
|
+
if (typeof content !== "string")
|
|
23
|
+
return null;
|
|
24
|
+
const fence = content.match(FRONTMATTER_FENCE_RE);
|
|
25
|
+
if (!fence)
|
|
26
|
+
return null;
|
|
27
|
+
const m = fence[1].match(STATUS_LINE_RE);
|
|
28
|
+
return m ? m[1].trim() : null;
|
|
29
|
+
}
|
|
30
|
+
// Resolve a doc id (already decoded) to its .md file path, honouring the same
|
|
31
|
+
// rules the documents route uses: extraFiles for absolute ids, safe-path for
|
|
32
|
+
// regular ids. Returns null if the file is not readable or escapes docsPath.
|
|
33
|
+
function resolveDocFilePath(docsPath, decodedDocId, extraFiles) {
|
|
34
|
+
if (path_1.default.isAbsolute(decodedDocId)) {
|
|
35
|
+
const candidate = decodedDocId + ".md";
|
|
36
|
+
return extraFiles.includes(candidate) ? candidate : null;
|
|
37
|
+
}
|
|
38
|
+
const resolved = path_1.default.resolve(docsPath, decodedDocId + ".md");
|
|
39
|
+
if (!resolved.startsWith(path_1.default.resolve(docsPath) + path_1.default.sep))
|
|
40
|
+
return null;
|
|
41
|
+
return resolved;
|
|
42
|
+
}
|
|
43
|
+
function readDocStatus(docsPath, decodedDocId, extraFiles) {
|
|
44
|
+
const filePath = resolveDocFilePath(docsPath, decodedDocId, extraFiles);
|
|
45
|
+
if (!filePath || !fs_1.default.existsSync(filePath))
|
|
46
|
+
return null;
|
|
47
|
+
try {
|
|
48
|
+
return parseDocStatus(fs_1.default.readFileSync(filePath, "utf-8"));
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.SUPERSEEDED_STATUS = "SuperSeeded";
|
|
55
|
+
// Typed error so callers (HTTP routes, MCP tool wrapper) can distinguish a
|
|
56
|
+
// lifecycle rejection from a generic failure and map it to the right response
|
|
57
|
+
// envelope (403 for HTTP, MCP `isError: true` content wrapper).
|
|
58
|
+
class DocumentSuperSeededError extends Error {
|
|
59
|
+
constructor(message = "Document is SuperSeeded; metadata is read-only.") {
|
|
60
|
+
super(message);
|
|
61
|
+
this.code = "DOCUMENT_SUPERSEEDED";
|
|
62
|
+
this.name = "DocumentSuperSeededError";
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
exports.DocumentSuperSeededError = DocumentSuperSeededError;
|
|
66
|
+
function assertNotSuperSeeded(docsPath, decodedDocId) {
|
|
67
|
+
const { extraFiles = [] } = (0, config_1.readConfig)(docsPath);
|
|
68
|
+
if (readDocStatus(docsPath, decodedDocId, extraFiles) === exports.SUPERSEEDED_STATUS) {
|
|
69
|
+
throw new DocumentSuperSeededError();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/lib/status.ts"],"names":[],"mappings":";AAAA,gFAAgF;AAChF,gFAAgF;AAChF,+EAA+E;AAC/E,8EAA8E;AAC9E,+EAA+E;AAC/E,0EAA0E;;;;;;AAS1E,wCAMC;AAmBD,sCAYC;AAiBD,oDAQC;AArED,4CAAoB;AACpB,gDAAwB;AACxB,qCAAsC;AAEtC,MAAM,cAAc,GAAG,+BAA+B,CAAC;AACvD,MAAM,oBAAoB,GAAG,0BAA0B,CAAC;AAExD,SAAgB,cAAc,CAAC,OAAe;IAC5C,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC7C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAClD,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IACzC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAChC,CAAC;AAED,8EAA8E;AAC9E,6EAA6E;AAC7E,6EAA6E;AAC7E,SAAS,kBAAkB,CACzB,QAAgB,EAChB,YAAoB,EACpB,UAAoB;IAEpB,IAAI,cAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,YAAY,GAAG,KAAK,CAAC;QACvC,OAAO,UAAU,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3D,CAAC;IACD,MAAM,QAAQ,GAAG,cAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,YAAY,GAAG,KAAK,CAAC,CAAC;IAC9D,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,cAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,cAAI,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACzE,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAgB,aAAa,CAC3B,QAAgB,EAChB,YAAoB,EACpB,UAAoB;IAEpB,MAAM,QAAQ,GAAG,kBAAkB,CAAC,QAAQ,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;IACxE,IAAI,CAAC,QAAQ,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IACvD,IAAI,CAAC;QACH,OAAO,cAAc,CAAC,YAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAEY,QAAA,kBAAkB,GAAG,aAAa,CAAC;AAEhD,2EAA2E;AAC3E,8EAA8E;AAC9E,gEAAgE;AAChE,MAAa,wBAAyB,SAAQ,KAAK;IAEjD,YACE,OAAO,GAAG,iDAAiD;QAE3D,KAAK,CAAC,OAAO,CAAC,CAAC;QAJR,SAAI,GAAG,sBAAsB,CAAC;QAKrC,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AARD,4DAQC;AAED,SAAgB,oBAAoB,CAClC,QAAgB,EAChB,YAAoB;IAEpB,MAAM,EAAE,UAAU,GAAG,EAAE,EAAE,GAAG,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC;IACjD,IAAI,aAAa,CAAC,QAAQ,EAAE,YAAY,EAAE,UAAU,CAAC,KAAK,0BAAkB,EAAE,CAAC;QAC7E,MAAM,IAAI,wBAAwB,EAAE,CAAC;IACvC,CAAC;AACH,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tools/metadata.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../../../src/mcp/tools/metadata.ts"],"names":[],"mappings":"AA8CA,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE;;;;;EAKtE;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE;;;;;EAMrE;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE;;;;;EAkD5E;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE;;;;;EAcrB;AAED,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;;;;;EA4BnC;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;;;;;EAwBnC;AAED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM;;;;;EAsDzD"}
|
|
@@ -14,6 +14,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
14
14
|
const fs_1 = __importDefault(require("fs"));
|
|
15
15
|
const metadata_1 = require("../../lib/metadata");
|
|
16
16
|
const hash_1 = require("../../lib/hash");
|
|
17
|
+
const status_1 = require("../../lib/status");
|
|
17
18
|
const documents_1 = require("./documents");
|
|
18
19
|
const ACCURACY_THRESHOLD = 0.8;
|
|
19
20
|
const FULL_ACCURACY = 1;
|
|
@@ -108,6 +109,7 @@ function toolReviewAdrRelevance(docsPath, args) {
|
|
|
108
109
|
}
|
|
109
110
|
function toolRefreshMetadata(docsPath, args) {
|
|
110
111
|
const docId = decodeDocId(args?.id);
|
|
112
|
+
(0, status_1.assertNotSuperSeeded)(docsPath, docId);
|
|
111
113
|
const sourceRoot = (0, metadata_1.resolveSourceRoot)(docsPath);
|
|
112
114
|
const entries = (0, metadata_1.getDocEntries)(docsPath, docId).map((e) => {
|
|
113
115
|
const abs = path_1.default.resolve(sourceRoot, e.path);
|
|
@@ -122,6 +124,7 @@ function toolRefreshMetadata(docsPath, args) {
|
|
|
122
124
|
}
|
|
123
125
|
function toolAddMetadata(docsPath, args) {
|
|
124
126
|
const docId = decodeDocId(args?.id);
|
|
127
|
+
(0, status_1.assertNotSuperSeeded)(docsPath, docId);
|
|
125
128
|
if (!args.path)
|
|
126
129
|
throw new Error("path is required");
|
|
127
130
|
const sourceRoot = (0, metadata_1.resolveSourceRoot)(docsPath);
|
|
@@ -151,6 +154,7 @@ function toolAddMetadata(docsPath, args) {
|
|
|
151
154
|
}
|
|
152
155
|
function toolRemoveMetadata(docsPath, args) {
|
|
153
156
|
const docId = decodeDocId(args?.id);
|
|
157
|
+
(0, status_1.assertNotSuperSeeded)(docsPath, docId);
|
|
154
158
|
if (!args.path)
|
|
155
159
|
throw new Error("path is required");
|
|
156
160
|
const sourceRoot = (0, metadata_1.resolveSourceRoot)(docsPath);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../../src/mcp/tools/metadata.ts"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../../src/mcp/tools/metadata.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../../src/routes/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../../src/routes/metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAmCpD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAiGvD"}
|
|
@@ -9,6 +9,24 @@ const path_1 = __importDefault(require("path"));
|
|
|
9
9
|
const fs_1 = __importDefault(require("fs"));
|
|
10
10
|
const metadata_1 = require("../lib/metadata");
|
|
11
11
|
const hash_1 = require("../lib/hash");
|
|
12
|
+
const status_1 = require("../lib/status");
|
|
13
|
+
// SuperSeeded documents are read-only as far as metadata is concerned: an ADR
|
|
14
|
+
// that has been replaced should keep the source bindings that prove what the
|
|
15
|
+
// original decision described, frozen at the moment of supersession. The guard
|
|
16
|
+
// itself lives in `lib/status.ts` so MCP tools share the same check.
|
|
17
|
+
function rejectIfSuperSeeded(docsPath, docId, res) {
|
|
18
|
+
try {
|
|
19
|
+
(0, status_1.assertNotSuperSeeded)(docsPath, docId);
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
if (err instanceof status_1.DocumentSuperSeededError) {
|
|
24
|
+
res.status(403).json({ error: err.message });
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
throw err;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
12
30
|
function metadataRouter(docsPath) {
|
|
13
31
|
const router = (0, express_1.Router)();
|
|
14
32
|
// GET /api/metadata/:docId → { items, total, unchanged, modified, missing, accuracy }
|
|
@@ -29,6 +47,8 @@ function metadataRouter(docsPath) {
|
|
|
29
47
|
// POST /api/metadata/:docId body: { path }
|
|
30
48
|
router.post("/:docId", (req, res) => {
|
|
31
49
|
const docId = decodeURIComponent(req.params.docId);
|
|
50
|
+
if (rejectIfSuperSeeded(docsPath, docId, res))
|
|
51
|
+
return;
|
|
32
52
|
const { path: rawPath } = req.body;
|
|
33
53
|
if (!rawPath || typeof rawPath !== "string") {
|
|
34
54
|
return res.status(400).json({ error: "path is required" });
|
|
@@ -64,6 +84,8 @@ function metadataRouter(docsPath) {
|
|
|
64
84
|
// DELETE /api/metadata/:docId body: { path }
|
|
65
85
|
router.delete("/:docId", (req, res) => {
|
|
66
86
|
const docId = decodeURIComponent(req.params.docId);
|
|
87
|
+
if (rejectIfSuperSeeded(docsPath, docId, res))
|
|
88
|
+
return;
|
|
67
89
|
const { path: rel } = req.body;
|
|
68
90
|
if (!rel)
|
|
69
91
|
return res.status(400).json({ error: "path is required" });
|
|
@@ -83,6 +105,8 @@ function metadataRouter(docsPath) {
|
|
|
83
105
|
// POST /api/metadata/:docId/refresh → recompute stored hashes from current file state
|
|
84
106
|
router.post("/:docId/refresh", (req, res) => {
|
|
85
107
|
const docId = decodeURIComponent(req.params.docId);
|
|
108
|
+
if (rejectIfSuperSeeded(docsPath, docId, res))
|
|
109
|
+
return;
|
|
86
110
|
try {
|
|
87
111
|
const sourceRoot = (0, metadata_1.resolveSourceRoot)(docsPath);
|
|
88
112
|
const entries = (0, metadata_1.getDocEntries)(docsPath, docId).map((e) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../src/routes/metadata.ts"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../src/routes/metadata.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "living-documentation",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.17.0",
|
|
4
4
|
"description": "Local Markdown documentation hub with a built-in MCP server — coding agents create ADRs, draw diagrams and detect drift while you code.",
|
|
5
5
|
"main": "dist/src/server.js",
|
|
6
6
|
"bin": {
|