living-ai-documentation 1.0.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.
Files changed (203) hide show
  1. package/LICENSE +661 -0
  2. package/README.fr.md +344 -0
  3. package/README.md +344 -0
  4. package/dist/bin/cli.d.ts +3 -0
  5. package/dist/bin/cli.d.ts.map +1 -0
  6. package/dist/bin/cli.js +262 -0
  7. package/dist/bin/cli.js.map +1 -0
  8. package/dist/src/frontend/accuracy-gauge.js +70 -0
  9. package/dist/src/frontend/admin.html +1532 -0
  10. package/dist/src/frontend/annotations.js +585 -0
  11. package/dist/src/frontend/boot.js +101 -0
  12. package/dist/src/frontend/config.js +29 -0
  13. package/dist/src/frontend/confirm-modal.js +82 -0
  14. package/dist/src/frontend/context.html +1252 -0
  15. package/dist/src/frontend/dark-mode.js +20 -0
  16. package/dist/src/frontend/diagram/alignment.js +161 -0
  17. package/dist/src/frontend/diagram/clipboard.js +187 -0
  18. package/dist/src/frontend/diagram/constants.js +109 -0
  19. package/dist/src/frontend/diagram/custom-shapes.js +104 -0
  20. package/dist/src/frontend/diagram/debug.js +43 -0
  21. package/dist/src/frontend/diagram/drawio-export.js +649 -0
  22. package/dist/src/frontend/diagram/edge-panel.js +293 -0
  23. package/dist/src/frontend/diagram/edge-rendering.js +12 -0
  24. package/dist/src/frontend/diagram/evidence.js +146 -0
  25. package/dist/src/frontend/diagram/grid.js +78 -0
  26. package/dist/src/frontend/diagram/groups.js +102 -0
  27. package/dist/src/frontend/diagram/history.js +157 -0
  28. package/dist/src/frontend/diagram/image-name-modal.js +48 -0
  29. package/dist/src/frontend/diagram/image-upload.js +36 -0
  30. package/dist/src/frontend/diagram/label-editor.js +115 -0
  31. package/dist/src/frontend/diagram/link-panel.js +144 -0
  32. package/dist/src/frontend/diagram/main.js +364 -0
  33. package/dist/src/frontend/diagram/network.js +2214 -0
  34. package/dist/src/frontend/diagram/node-panel.js +389 -0
  35. package/dist/src/frontend/diagram/node-rendering.js +964 -0
  36. package/dist/src/frontend/diagram/persistence.js +168 -0
  37. package/dist/src/frontend/diagram/ports.js +421 -0
  38. package/dist/src/frontend/diagram/selection-overlay.js +387 -0
  39. package/dist/src/frontend/diagram/state.js +43 -0
  40. package/dist/src/frontend/diagram/t.js +3 -0
  41. package/dist/src/frontend/diagram/toast.js +21 -0
  42. package/dist/src/frontend/diagram/unlock-hold.js +206 -0
  43. package/dist/src/frontend/diagram/zoom.js +20 -0
  44. package/dist/src/frontend/diagram-link-modal.js +137 -0
  45. package/dist/src/frontend/diagram.html +1494 -0
  46. package/dist/src/frontend/documents.js +479 -0
  47. package/dist/src/frontend/export.js +338 -0
  48. package/dist/src/frontend/file-attach.js +178 -0
  49. package/dist/src/frontend/files-modal.js +243 -0
  50. package/dist/src/frontend/i18n/en.json +624 -0
  51. package/dist/src/frontend/i18n/fr.json +624 -0
  52. package/dist/src/frontend/i18n.js +32 -0
  53. package/dist/src/frontend/image-paste.js +126 -0
  54. package/dist/src/frontend/index.html +2806 -0
  55. package/dist/src/frontend/local-search.js +476 -0
  56. package/dist/src/frontend/metadata.js +318 -0
  57. package/dist/src/frontend/misc.js +92 -0
  58. package/dist/src/frontend/new-doc-modal.js +285 -0
  59. package/dist/src/frontend/new-folder-modal.js +169 -0
  60. package/dist/src/frontend/search.js +194 -0
  61. package/dist/src/frontend/shape-editor.html +685 -0
  62. package/dist/src/frontend/sidebar-helpers.js +96 -0
  63. package/dist/src/frontend/sidebar-resize.js +98 -0
  64. package/dist/src/frontend/sidebar.js +351 -0
  65. package/dist/src/frontend/snippet-detect.js +25 -0
  66. package/dist/src/frontend/snippet-table.js +85 -0
  67. package/dist/src/frontend/snippet-tree.js +94 -0
  68. package/dist/src/frontend/snippets.js +1146 -0
  69. package/dist/src/frontend/state.js +46 -0
  70. package/dist/src/frontend/utils.js +21 -0
  71. package/dist/src/frontend/validate.js +107 -0
  72. package/dist/src/frontend/vendor/wordcloud2.js +1187 -0
  73. package/dist/src/frontend/wordcloud.js +693 -0
  74. package/dist/src/lib/config.d.ts +26 -0
  75. package/dist/src/lib/config.d.ts.map +1 -0
  76. package/dist/src/lib/config.js +195 -0
  77. package/dist/src/lib/config.js.map +1 -0
  78. package/dist/src/lib/hash.d.ts +2 -0
  79. package/dist/src/lib/hash.d.ts.map +1 -0
  80. package/dist/src/lib/hash.js +18 -0
  81. package/dist/src/lib/hash.js.map +1 -0
  82. package/dist/src/lib/metadata.d.ts +31 -0
  83. package/dist/src/lib/metadata.d.ts.map +1 -0
  84. package/dist/src/lib/metadata.js +128 -0
  85. package/dist/src/lib/metadata.js.map +1 -0
  86. package/dist/src/lib/parser.d.ts +11 -0
  87. package/dist/src/lib/parser.d.ts.map +1 -0
  88. package/dist/src/lib/parser.js +111 -0
  89. package/dist/src/lib/parser.js.map +1 -0
  90. package/dist/src/lib/status.d.ts +9 -0
  91. package/dist/src/lib/status.d.ts.map +1 -0
  92. package/dist/src/lib/status.js +72 -0
  93. package/dist/src/lib/status.js.map +1 -0
  94. package/dist/src/mcp/server.d.ts +3 -0
  95. package/dist/src/mcp/server.d.ts.map +1 -0
  96. package/dist/src/mcp/server.js +2046 -0
  97. package/dist/src/mcp/server.js.map +1 -0
  98. package/dist/src/mcp/tools/diagrams.d.ts +82 -0
  99. package/dist/src/mcp/tools/diagrams.d.ts.map +1 -0
  100. package/dist/src/mcp/tools/diagrams.js +594 -0
  101. package/dist/src/mcp/tools/diagrams.js.map +1 -0
  102. package/dist/src/mcp/tools/documents.d.ts +44 -0
  103. package/dist/src/mcp/tools/documents.d.ts.map +1 -0
  104. package/dist/src/mcp/tools/documents.js +186 -0
  105. package/dist/src/mcp/tools/documents.js.map +1 -0
  106. package/dist/src/mcp/tools/git.d.ts +10 -0
  107. package/dist/src/mcp/tools/git.d.ts.map +1 -0
  108. package/dist/src/mcp/tools/git.js +217 -0
  109. package/dist/src/mcp/tools/git.js.map +1 -0
  110. package/dist/src/mcp/tools/metadata.d.ts +57 -0
  111. package/dist/src/mcp/tools/metadata.d.ts.map +1 -0
  112. package/dist/src/mcp/tools/metadata.js +222 -0
  113. package/dist/src/mcp/tools/metadata.js.map +1 -0
  114. package/dist/src/mcp/tools/source.d.ts +29 -0
  115. package/dist/src/mcp/tools/source.d.ts.map +1 -0
  116. package/dist/src/mcp/tools/source.js +196 -0
  117. package/dist/src/mcp/tools/source.js.map +1 -0
  118. package/dist/src/routes/annotations.d.ts +3 -0
  119. package/dist/src/routes/annotations.d.ts.map +1 -0
  120. package/dist/src/routes/annotations.js +83 -0
  121. package/dist/src/routes/annotations.js.map +1 -0
  122. package/dist/src/routes/browse-source.d.ts +3 -0
  123. package/dist/src/routes/browse-source.d.ts.map +1 -0
  124. package/dist/src/routes/browse-source.js +79 -0
  125. package/dist/src/routes/browse-source.js.map +1 -0
  126. package/dist/src/routes/browse.d.ts +3 -0
  127. package/dist/src/routes/browse.d.ts.map +1 -0
  128. package/dist/src/routes/browse.js +91 -0
  129. package/dist/src/routes/browse.js.map +1 -0
  130. package/dist/src/routes/config.d.ts +3 -0
  131. package/dist/src/routes/config.d.ts.map +1 -0
  132. package/dist/src/routes/config.js +145 -0
  133. package/dist/src/routes/config.js.map +1 -0
  134. package/dist/src/routes/context.d.ts +3 -0
  135. package/dist/src/routes/context.d.ts.map +1 -0
  136. package/dist/src/routes/context.js +287 -0
  137. package/dist/src/routes/context.js.map +1 -0
  138. package/dist/src/routes/diagrams.d.ts +3 -0
  139. package/dist/src/routes/diagrams.d.ts.map +1 -0
  140. package/dist/src/routes/diagrams.js +69 -0
  141. package/dist/src/routes/diagrams.js.map +1 -0
  142. package/dist/src/routes/documents.d.ts +11 -0
  143. package/dist/src/routes/documents.d.ts.map +1 -0
  144. package/dist/src/routes/documents.js +450 -0
  145. package/dist/src/routes/documents.js.map +1 -0
  146. package/dist/src/routes/export.d.ts +3 -0
  147. package/dist/src/routes/export.d.ts.map +1 -0
  148. package/dist/src/routes/export.js +280 -0
  149. package/dist/src/routes/export.js.map +1 -0
  150. package/dist/src/routes/files.d.ts +3 -0
  151. package/dist/src/routes/files.d.ts.map +1 -0
  152. package/dist/src/routes/files.js +180 -0
  153. package/dist/src/routes/files.js.map +1 -0
  154. package/dist/src/routes/images.d.ts +3 -0
  155. package/dist/src/routes/images.d.ts.map +1 -0
  156. package/dist/src/routes/images.js +49 -0
  157. package/dist/src/routes/images.js.map +1 -0
  158. package/dist/src/routes/metadata.d.ts +3 -0
  159. package/dist/src/routes/metadata.d.ts.map +1 -0
  160. package/dist/src/routes/metadata.js +131 -0
  161. package/dist/src/routes/metadata.js.map +1 -0
  162. package/dist/src/routes/shape-libraries.d.ts +3 -0
  163. package/dist/src/routes/shape-libraries.d.ts.map +1 -0
  164. package/dist/src/routes/shape-libraries.js +118 -0
  165. package/dist/src/routes/shape-libraries.js.map +1 -0
  166. package/dist/src/routes/wordcloud.d.ts +3 -0
  167. package/dist/src/routes/wordcloud.d.ts.map +1 -0
  168. package/dist/src/routes/wordcloud.js +95 -0
  169. package/dist/src/routes/wordcloud.js.map +1 -0
  170. package/dist/src/server.d.ts +7 -0
  171. package/dist/src/server.d.ts.map +1 -0
  172. package/dist/src/server.js +93 -0
  173. package/dist/src/server.js.map +1 -0
  174. package/dist/starter-doc/.living-doc.json +52 -0
  175. package/dist/starter-doc/ADRS/2026_01_01_[ADR]_example_architecture_decision.md +59 -0
  176. package/dist/starter-doc/AI/2026_01_01_how_to.md +112 -0
  177. package/dist/starter-doc/AI/PROJECT-INSTRUCTIONS.md +172 -0
  178. package/dist/starter-doc/AI/PROJECT-STACK.md +77 -0
  179. package/dist/starter-doc/AI/PROJECT-USEFUL-COMMANDS.md +80 -0
  180. package/dist/starter-doc/AI/default/AGENTS.md +31 -0
  181. package/dist/starter-doc/AI/default/CLAUDE.md +31 -0
  182. package/dist/starter-doc/AI/default/MEMORY.md +24 -0
  183. package/dist/starter-doc/AI/rules/no-magic-numbers.md +18 -0
  184. package/dist/starter-doc/AI/rules/track-current-work.md +23 -0
  185. package/dist/starter-doc/WORKLOG/current-task.md +57 -0
  186. package/dist/starter-doc-fr/.living-doc.json +52 -0
  187. package/dist/starter-doc-fr/ADRS/2026_01_01_[ADR]_example_architecture_decision.md +59 -0
  188. package/dist/starter-doc-fr/AI/2026_01_01_how_to.md +100 -0
  189. package/dist/starter-doc-fr/AI/PROJECT-INSTRUCTIONS.md +172 -0
  190. package/dist/starter-doc-fr/AI/PROJECT-STACK.md +77 -0
  191. package/dist/starter-doc-fr/AI/PROJECT-USEFUL-COMMANDS.md +80 -0
  192. package/dist/starter-doc-fr/AI/default/AGENTS.md +31 -0
  193. package/dist/starter-doc-fr/AI/default/CLAUDE.md +31 -0
  194. package/dist/starter-doc-fr/AI/default/MEMORY.md +24 -0
  195. package/dist/starter-doc-fr/AI/rules/no-magic-numbers.md +18 -0
  196. package/dist/starter-doc-fr/AI/rules/track-current-work.md +23 -0
  197. package/dist/starter-doc-fr/WORKLOG/current-task.md +57 -0
  198. package/images/living_documentation.jpg +0 -0
  199. package/images/readme-extra-files.png +0 -0
  200. package/images/readme-filename-pattern.png +0 -0
  201. package/images/readme-intelligent-search-demo.jpg +0 -0
  202. package/images/readme-sidebar.png +0 -0
  203. package/package.json +72 -0
@@ -0,0 +1,2046 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mcpRouter = mcpRouter;
4
+ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
5
+ const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
6
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
7
+ const express_1 = require("express");
8
+ const documents_1 = require("./tools/documents");
9
+ const diagrams_1 = require("./tools/diagrams");
10
+ const source_1 = require("./tools/source");
11
+ const metadata_1 = require("./tools/metadata");
12
+ const git_1 = require("./tools/git");
13
+ // ── Server guide ──────────────────────────────────────────────────────────────
14
+ // Shared by the `instructions` field (sent on MCP initialize) and the
15
+ // `get_server_guide` tool (explicit retrieval for clients that don't surface
16
+ // server instructions to the model).
17
+ const SERVER_GUIDE = `# Living Documentation — Server Guide
18
+
19
+ This server maintains a living documentation system composed of:
20
+ - **Documents** (Markdown) — the source of truth.
21
+ - **Diagrams** — visual derivations of documents.
22
+
23
+ ## Document ↔ diagram contract
24
+ Documents are authoritative. Diagrams are derived views and must not introduce
25
+ information that is absent from the documents. If a diagram needs a concept
26
+ that isn't documented yet, create or update the document first.
27
+
28
+ ## Cross-project documentation workspace convention
29
+ The configured documentation workspace and the source folder mentioned by the
30
+ user may intentionally differ. This is valid when the user wants to keep
31
+ analysis documents and diagrams in a new Living Documentation project instead
32
+ of writing into the source repository.
33
+
34
+ When a user points you to a folder or repository and it does not appear to
35
+ match this MCP's configured \`sourceRoot\` / document inventory, do **not**
36
+ silently switch strategy, do **not** write documents by hand into the pointed
37
+ repository, and do **not** assume the MCP is misconfigured. Ask the user to
38
+ confirm whether this mismatch is intentional.
39
+
40
+ If the user confirms the mismatch is intentional, keep using this MCP workspace
41
+ as the documentation target. First create the missing Markdown source-of-truth
42
+ documents in this MCP project (overview, actors, runtime containers, external
43
+ systems, data flows, key decisions, constraints) using \`create_document\`.
44
+ Only after those documents exist and have been read should you create diagrams
45
+ from them. Use source-code access only as research input for the documents; the
46
+ diagram evidence must cite Markdown documents from this MCP workspace.
47
+
48
+ ## Feature workflow — ADRs are how the documentation grows
49
+ When a coding agent implements or modifies a feature on this project, the
50
+ feature is **not done** until an ADR (Architecture Decision Record) has been
51
+ created (or an existing one superseded) and bound to the source files it
52
+ covers. This is what keeps the documentation alive.
53
+
54
+ ### Mandatory steps after finishing a feature
55
+ 1. \`list_documents\` — get the inventory.
56
+ 2. Shortlist ADRs whose title / category looks topically related to the
57
+ feature, then \`read_document\` their frontmatter (\`description\`,
58
+ \`tags\`) to confirm.
59
+ 3. **Supersede check** — if an existing ADR is **made obsolete** by the new
60
+ feature, use \`update_document(id, ...)\` to flip its \`**status:**\` to
61
+ \`SuperSeeded\` and add a one-line pointer to the new ADR (do **not** call
62
+ \`create_document\` — it does not overwrite and will reject a colliding
63
+ filename).
64
+ 4. \`create_document\` for the new ADR with the **mandatory frontmatter**
65
+ below at \`status: To be validated\`.
66
+ 5. \`add_metadata\` for **each source file** that materially carries the
67
+ feature's logic — never god files (see \`add_metadata\`).
68
+
69
+ ### Mandatory ADR frontmatter
70
+ Every ADR document body starts with:
71
+
72
+ \`\`\`
73
+ ---
74
+ **date:** YYYY-MM-DD
75
+ **status:** To be validated
76
+ **description:** One dense, technical sentence — what the decision does, not why.
77
+ **tags:** 5–10 specific tags mixing concepts, technologies, and key symbol names
78
+ ---
79
+ \`\`\`
80
+
81
+ Rules:
82
+ - \`status:\` is **always** \`To be validated\` at creation. Only the human
83
+ owner promotes to \`Accepted\`. The status has **no effect** on how the LLM
84
+ treats the ADR — only \`SuperSeeded\` is filtered downstream.
85
+ - \`description:\` stays factual and short — one sentence. The "why" goes in
86
+ the body.
87
+ - \`tags:\` are the primary search signal. Mix library names (\`stripe\`,
88
+ \`amplify\`), domain concepts (\`workflow\`, \`moderation\`), and symbol
89
+ names (\`useAdScheduler\`, \`presigned-url\`).
90
+ - \`category\` argument: domain bucket in the filename pattern, uppercase,
91
+ e.g. \`SERVICES CLOUD\`, \`INTEGRATION\`, \`ALGORITHMES\`.
92
+ - \`folder\` argument: \`adrs\` (or the project's ADR sub-folder).
93
+
94
+ ## Markdown conventions for documents written via this MCP
95
+
96
+ Standard CommonMark + GitHub-flavored Markdown is supported as-is (lists, code
97
+ blocks, tables, blockquotes, \`<details>/<summary>\`, etc.). Use vanilla syntax
98
+ for those — there is no need to align table columns visually.
99
+
100
+ The viewer recognises four project-specific link patterns. Use them whenever
101
+ they apply, otherwise the cross-reference is invisible to the reader:
102
+
103
+ - **Cross-document link** — \`[label](?doc=<doublyEncodedId>)\`. The \`id\`
104
+ returned by \`list_documents\` and \`create_document\` is **already** URL-encoded
105
+ once (a doc in folder \`adrs/\` has id \`adrs%2Ffoo\`, not \`adrs/foo\`).
106
+ To embed it in a query string you must encode it **again** — every \`%\`
107
+ becomes \`%25\`, so \`adrs%2Ffoo\` becomes \`adrs%252Ffoo\` in the link href.
108
+ **Operational rule (preferred — zero encoding to do)**: copy the
109
+ \`linkHref\` field returned by \`list_documents\` and \`create_document\` and
110
+ paste it verbatim between the parentheses. Worked example:
111
+ \`{ id: "adrs%2Ffoo", linkHref: "?doc=adrs%252Ffoo" }\` →
112
+ \`[Foo ADR](?doc=adrs%252Ffoo)\`. Append \`#heading-slug\` to the linkHref
113
+ to jump to a specific heading inside the target doc.
114
+ - **Diagram link** (C4 drill-down or ADR → diagram pointer) —
115
+ \`[label](/diagram?id=<diagramId>)\`.
116
+ - **File attachment** — \`[name](./files/<filename>)\` where \`<filename>\` is what
117
+ \`POST /api/files/upload\` returned. The viewer auto-styles these as a purple
118
+ pill with a paperclip glyph; do not add the glyph yourself.
119
+ - **In-doc anchor** — \`[label](#heading-slug)\` where \`heading-slug\` is the
120
+ lowercased + dash-joined version of the heading text (auto-generated).
121
+
122
+ ASCII trees inside a fenced code block render with their box-drawing characters
123
+ preserved (\`├──\`, \`└──\`, \`│ \`). Prefer this over nested bullet lists when
124
+ describing a folder layout or a hierarchy in an ADR.
125
+
126
+ ## Default diagram scope
127
+ - When documenting the project big picture, generate a **context diagram**.
128
+ - Do NOT generate container diagrams, component diagrams, or UML diagrams
129
+ unless the user explicitly asks for them by name.
130
+ - If the user asks for "a diagram", "the big picture", or "documentation",
131
+ produce a context diagram.
132
+
133
+ ## Mandatory workflow before creating or updating any diagram
134
+ 1. Call \`list_documents\` to see what exists.
135
+ 2. Call \`read_document\` on the documents relevant to the requested diagram.
136
+ 3. Call \`list_diagrams\` to check whether the diagram already exists
137
+ (update rather than duplicate by passing its \`id\` back to \`create_diagram\`).
138
+ 4. Only then call \`create_diagram\`, using node/edge content grounded in the
139
+ documents you read.
140
+
141
+ Never invent actors, systems, or relationships that are not present in the
142
+ documents.
143
+
144
+ ## Conventions by diagram type
145
+ ### Context diagram (default)
146
+ - Central system as \`box\` (c-blue).
147
+ - Users / roles as \`actor\` (c-gray).
148
+ - External systems as \`box\` (c-slate).
149
+ - Persistence / datastores as \`database\` (c-teal).
150
+ - Keep to ~10 nodes maximum.
151
+
152
+ ### Container diagram (explicit request only)
153
+ - Each deployable unit as \`box\`.
154
+ - Databases as \`database\`.
155
+ - Queues as \`ellipse\`.
156
+
157
+ ### UML diagram (explicit request only)
158
+ - Follow the requested UML variant's conventions (class, sequence, state,
159
+ activity, use-case …).
160
+
161
+ ### Screen-guide diagram (explicit request only)
162
+ An annotated screenshot built in **three layers**. Source code is the reference
163
+ (not the Markdown docs) — use \`read_source_file\` / \`search_source\`.
164
+
165
+ **1. Background image** — one \`image\` node with the screenshot.
166
+ - \`name: "screenshot"\` (used as edge anchor; not displayed).
167
+ - \`imageSrc\`: URL returned by \`POST /api/images/upload\`.
168
+ - \`width\` / \`height\` = natural screenshot pixels. \`locked: true\`.
169
+
170
+ **2. Zone overlays** — one translucent \`box\` per major layout region
171
+ (left/right sidebar, top bar, main content, footer …).
172
+ - \`bgOpacity: 0.15–0.20\`, \`locked: true\`, empty label.
173
+ - \`width\` / \`height\` / \`x\` / \`y\` cover the zone on the screenshot.
174
+ - One distinct \`color\` per zone (e.g. c-red = left drawer, c-amber = top bar,
175
+ c-cyan = main area). Typical count: **2–5 zones**.
176
+ - Each zone gets a **zone-label post-it** of the **same color**, placed inside
177
+ or at the edge of the zone (1–3 words: "Top Bar", "Collapsible Drawer",
178
+ "Main Page").
179
+
180
+ **3. Feature callouts** — one \`post-it\` per first-level feature, placed
181
+ **outside the screenshot** and linked to the UI element by a free-end arrow.
182
+ - First-level feature = visible without interaction + changes behavior
183
+ significantly when used. Typical count: **4–10**.
184
+ - Label: 2–5 words, title-cased; multi-line allowed via \`\\n\`.
185
+ - Color depends on kind:
186
+ - **Interactive** (button, link, input, toggle) → \`c-amber\` or
187
+ \`c-orange\` (yellow family). **Default.**
188
+ - **Differentiating** (product-distinguishing feature) → a distinct
189
+ non-yellow color (\`c-purple\`, \`c-rose\`, \`c-red\`, \`c-sky\`,
190
+ \`c-teal\`, \`c-green\`). Reserve for the 1–3 hero features.
191
+
192
+ #### Free-end arrows — never anchor on the image node
193
+ Anchoring on the image makes every arrow converge to its centre. Use one of:
194
+ - **\`anchor\` node** (8×8, invisible at rest, visible on hover) placed on the
195
+ target pixel inside the screenshot, with edge
196
+ \`{ from: "<post-it>", to: "<anchor name>" }\`. **Preferred.**
197
+ - **Edge with \`from\` only (no \`to\`)** — renders a floating arrow
198
+ endpoint the user can drag onto the target.
199
+
200
+ Edge labels stay empty on this diagram type — the arrow alone speaks. Missing-
201
+ label warnings are disabled for screen-guide.
202
+
203
+ ### Edges
204
+ - Every edge MUST have a \`label\` describing the interaction as a verb phrase
205
+ ("authenticates", "publishes events to", "reads from", "sends notifications via").
206
+ - Exception: screen-guide diagrams may have unlabeled edges.
207
+
208
+ ## Node label format (C4 convention)
209
+ Either provide a full C4 label in \`name\` using \`\\n\` line breaks, or provide
210
+ \`kind\` plus optional \`description\` and let the MCP build the C4 label:
211
+ \`\`\`
212
+ Name\\n[Type]\\nShort description of role or responsibility
213
+ \`\`\`
214
+ Architectural \`kind\` is separate from visual \`renderAs\`: \`kind\` describes
215
+ the concept, \`renderAs\` chooses the shape. If \`kind\` is present and
216
+ \`renderAs\` is absent, the MCP chooses the default shape and color for that
217
+ kind. Legacy \`type\` still works as the visual shape when \`kind\` is absent.
218
+ Kinds: \`person\`, \`software_system\`, \`external_system\`, \`container\`,
219
+ \`component\`, \`database\`, \`object_storage\`, \`queue\`, \`device\`, \`api\`,
220
+ \`cloud_service\`, \`browser_app\`, \`mobile_app\`, \`backend_service\`, \`job\`,
221
+ \`unknown\`.
222
+ Types include \`[Person]\`, \`[Software System]\`, \`[External System]\`,
223
+ \`[Container]\`, \`[Component]\`, \`[Database]\`, \`[Device]\`.
224
+ Keep descriptions to 1–2 short lines.
225
+
226
+ ## Coordinate system (when positions are provided)
227
+ - Origin \`(0, 0)\` is the canvas center.
228
+ - \`+x\` is right, \`+y\` is down.
229
+ - Use multiples of **40** for grid alignment.
230
+ - \`x\` and \`y\` are **optional**: omit them to let the editor auto-lay out
231
+ nodes. Only provide coordinates when you want a fixed layout (e.g., following
232
+ a C4 convention).
233
+ - **Screen-guide exception**: positions align to screenshot pixels (and
234
+ anchors to target pixels), not to the 40-unit grid.
235
+
236
+ ## Source code access (fallback only)
237
+ Three tools expose read-only access to the project source under \`sourceRoot\`
238
+ (configurable in \`.living-doc.json\`; defaults to the parent folder of
239
+ \`docsFolder\`):
240
+
241
+ - \`list_source_files(pattern?, maxResults?)\`
242
+ - \`read_source_file(path)\`
243
+ - \`search_source(query, pattern?, maxResults?, caseSensitive?)\`
244
+
245
+ **Rules**:
246
+ 1. Documentation tools come first. Use source tools only when the docs do not
247
+ carry the required detail (typical case: screen-guide diagrams, or
248
+ low-level code documentation with no ADR).
249
+ 2. If you find yourself reading more than 3 source files for the same
250
+ diagram, stop and update the documentation first.
251
+ 3. Common ignored folders (\`node_modules\`, \`dist\`, \`.git\`, \`build\`,
252
+ \`target\`, …) are skipped automatically.
253
+
254
+ ## Guardrails (enforced server-side in create_diagram)
255
+ - \`diagramType\` is required.
256
+ - Non-context types (\`container\`, \`component\`, \`uml\`, \`screen-guide\`) are
257
+ rejected unless \`userRequestedExplicitly: true\` is also passed.
258
+ - \`image\` nodes without \`imageSrc\` are rejected.
259
+ - A response \`warnings\` array flags missing edge labels (except for
260
+ screen-guide) or oversized context diagrams.
261
+
262
+ ## Source-file metadata & accuracy
263
+ Documents can be bound to the source files they describe. Each binding stores
264
+ the file's SHA-256 hash so the system can detect drift between docs and code.
265
+
266
+ Tools:
267
+ - \`list_metadata(id)\` — returns the source files attached to a doc.
268
+ - \`get_accuracy(id)\` — classifies each entry (\`unchanged\` / \`modified\` /
269
+ \`missing\`) and returns a weighted \`accuracy\` in [0, 1] (missing weighs 3×
270
+ a simple modification).
271
+ - \`review_adr_relevance(id)\` — validates that the document is an ADR, returns
272
+ its content and metadata accuracy plus the drifted source files to re-read.
273
+ Use prompt \`review-adr-relevance\` for the LLM workflow around this factual
274
+ report.
275
+ - \`add_metadata(id, path)\` — attach a source file (path under
276
+ \`sourceRoot\`) and record its current hash.
277
+ - \`remove_metadata(id, path)\` — detach an entry. Idempotent (no-op
278
+ if the path is not attached). Use this to clean up orphans or to
279
+ handle renames (\`add_metadata\` new path, then
280
+ \`remove_metadata\` old path).
281
+ - \`refresh_metadata(id)\` — re-hash every attached file. Call **after**
282
+ the doc has been updated to re-align it with the current source state.
283
+ - \`list_adrs_below_accuracy()\` — audit: returns up to 10 ADRs whose accuracy
284
+ < 80%, sorted most-degraded first, plus a \`totalBelowThreshold\` counter.
285
+ SuperSeeded ADRs, non-ADR documents, and docs without metadata are excluded.
286
+ Use this instead of looping \`list_documents\` + \`get_accuracy\` for ADR drift.
287
+
288
+ Recommended workflow to keep docs accurate (single-doc):
289
+ 1. \`list_documents\` → pick a doc.
290
+ 2. \`get_accuracy\` → if accuracy < 1, the doc is drifting.
291
+ 3. \`read_document\` and \`read_source_file\` on the \`modified\` entries.
292
+ 4. Decide: is the doc still factually correct, or out of sync with the code?
293
+ - **Still correct** → skip to step 5 (cosmetic code change, no doc rewrite).
294
+ - **Out of sync** → update the doc with \`update_document(id, content)\`.
295
+ 5. \`refresh_metadata\` to re-baseline the hashes.
296
+
297
+ Bulk audit workflow (Scenario B — invoke prompt \`audit-adrs-drift\` for the
298
+ full template):
299
+ 1. \`list_adrs_below_accuracy\` → batch of up to 10 most-degraded ADRs.
300
+ 2. For each item: \`review_adr_relevance\` + \`read_source_file\` on
301
+ \`modified\` entries → decide:
302
+ - **Description still holds** → \`refresh_metadata\` (re-baseline as-is).
303
+ - **Description out of sync** → ask the user before superseding.
304
+ 3. Re-call \`list_adrs_below_accuracy\` until \`totalBelowThreshold\`
305
+ reaches 0 or the remaining items are intentionally drifting.
306
+ `;
307
+ // ── Tool definitions ──────────────────────────────────────────────────────────
308
+ const SHAPE_LIST = "box, actor (person), database, ellipse, circle, post-it, text-free, image, anchor (invisible endpoint for free-end arrows — screen-guide only)";
309
+ const COLOR_LIST = 'c-blue, c-green, c-gray, c-teal, c-amber, c-orange, c-rose, c-purple, c-cyan, c-indigo, c-pink, c-lime, c-red, c-sky, c-slate (short aliases like "blue", "teal" also work)';
310
+ const KIND_LIST = "person, software_system, external_system, container, component, database, object_storage, queue, device, api, cloud_service, browser_app, mobile_app, backend_service, job, unknown";
311
+ const GUIDE_HINT = "If unsure of the workflow, call `get_server_guide` first.";
312
+ const CREATE_DIAGRAM_DESCRIPTION = [
313
+ "Create or overwrite a diagram from a high-level description.",
314
+ "",
315
+ "## Required workflow (do ALL of these before calling)",
316
+ "1. `list_documents` — see what exists.",
317
+ "2. `read_document` on documents relevant to the diagram.",
318
+ "3. `list_diagrams` — if the diagram already exists, pass its `id` back to update in place (do not duplicate).",
319
+ "Do not invent actors, systems, or relationships absent from the documents.",
320
+ "",
321
+ "## Scope rule",
322
+ 'The default diagram for a project is a **context diagram**. Container, component, and UML diagrams are produced ONLY when the user explicitly requests them by name. If the user asks for "a diagram", "the big picture", or "documentation", produce a context diagram.',
323
+ "",
324
+ "## Conventions by diagram type",
325
+ "- Context (default): central system as `box` (c-blue); users as `actor` (c-gray); external systems as `box` (c-slate); datastores as `database` (c-teal). Max ~10 nodes.",
326
+ "- Container (explicit-only): deployables as `box`, databases as `database`, queues as `ellipse`.",
327
+ "- UML (explicit-only): follow the requested UML variant (class, sequence, state, …).",
328
+ '- Every edge MUST have a `label` describing the interaction as a verb phrase ("authenticates", "publishes events to", "reads from").',
329
+ "",
330
+ "## Source-of-truth contract",
331
+ "Documents are authoritative. A diagram must not contain information absent from the documents. If a diagram needs a concept that isn't documented, create or update the document first (via `create_document`).",
332
+ "Use `evidence` on nodes and edges to cite the document sections that justify what is drawn. Evidence must come from Markdown documents read or created through the documentation tools, not from source-code tools. If the required document does not exist, create it first.",
333
+ "",
334
+ "## Cross-project documentation workspace",
335
+ "If the user points you to a folder/repository that does not appear to match this MCP workspace's configured `sourceRoot` or current document inventory, ask whether the mismatch is intentional before creating documents or diagrams.",
336
+ "When the user confirms it is intentional, keep this MCP workspace as the documentation target: create the missing Markdown source-of-truth documents here first, then derive diagrams from those documents. Do not write documentation by hand into the pointed source repository as a fallback.",
337
+ "",
338
+ "## Positioning",
339
+ "`x` and `y` are **optional**. When omitted, the MCP assigns deterministic positions before saving: context diagrams use C4-style columns, flow diagrams use a left-to-right sequence, and other diagrams use a stable grid. Provide coordinates when you need a specific layout; explicit coordinates always win. Origin `(0,0)` is the canvas center, `+x` = right, `+y` = down; use multiples of 40.",
340
+ "",
341
+ "## MCP default styling",
342
+ "Diagrams created through this tool default to `edgesStraight: false`, `gridEnabled: false`, and `alignGuides: true`.",
343
+ "`kind` describes the architectural concept; `renderAs` describes the visual shape. When `kind` is present and `renderAs` is absent, the MCP chooses the default shape and color for that kind and builds a C4 label from `name`, `[Kind]`, and optional `description`. Legacy `type` remains supported as the visual shape when `kind` is absent.",
344
+ 'Edges default to curved port-anchored arrows with `arrowDir: "to"`, `dashes: false`, label offsets at `0`, and automatic `fromPort`/`toPort` inferred from node positions. Label width and font size are estimated from label length unless explicitly supplied.',
345
+ 'Use `arrowDir: "from"` to draw the arrowhead at the source end, or `arrowDir: "both"` when a single relation represents a bidirectional exchange.',
346
+ "",
347
+ "## Guardrails (enforced)",
348
+ "- `diagramType` is required.",
349
+ "- For `container`, `component`, or `uml`, `userRequestedExplicitly: true` is required — confirms the user asked for that type by name. Otherwise the call is rejected.",
350
+ "- Missing edge labels and oversized context diagrams produce warnings.",
351
+ "",
352
+ "## Worked example (context diagram, derived from an ADR)",
353
+ "```json",
354
+ "{",
355
+ ' "diagramType": "context",',
356
+ ' "title": "Living Documentation — system context",',
357
+ ' "nodes": [',
358
+ ' { "name": "Living Documentation\\n[Software System]\\nServes Markdown docs\\nand diagrams", "type": "box", "color": "c-blue" },',
359
+ ' { "name": "Developer\\n[Person]\\nBrowses and edits\\nproject docs", "type": "actor", "color": "c-gray" },',
360
+ ' { "name": "Local filesystem\\n[Datastore]\\nHosts .md files and\\ndiagrams.json", "type": "database","color": "c-teal" }',
361
+ " ],",
362
+ ' "edges": [',
363
+ ' { "from": "Developer\\n[Person]\\nBrowses and edits\\nproject docs", "to": "Living Documentation\\n[Software System]\\nServes Markdown docs\\nand diagrams", "label": "reads and edits docs via" },',
364
+ ' { "from": "Living Documentation\\n[Software System]\\nServes Markdown docs\\nand diagrams", "to": "Local filesystem\\n[Datastore]\\nHosts .md files and\\ndiagrams.json", "label": "reads from / writes to" }',
365
+ " ]",
366
+ "}",
367
+ "```",
368
+ "",
369
+ `## Available shapes and colors`,
370
+ `Shapes: ${SHAPE_LIST}.`,
371
+ `Colors: ${COLOR_LIST}.`,
372
+ `Kinds: ${KIND_LIST}.`,
373
+ "",
374
+ GUIDE_HINT,
375
+ ].join("\n");
376
+ const CREATE_DOCUMENT_DESCRIPTION = [
377
+ "Create a **new** Markdown document. The filename is generated automatically from the configured pattern (date + category + title slug). Pass `content` as full Markdown; omit to create an empty stub. To **modify an existing document** (correct drift, flip `**status:**` to `SuperSeeded`, edit body), use `update_document(id, content)` instead — `create_document` will refuse with `A document with this name already exists` if the target filename collides.",
378
+ "",
379
+ "## `date` argument — retrodocumentation only",
380
+ 'By default the filename date prefix is "now". Pass `date` (ISO 8601, e.g. `2024-08-12` or `2024-08-12T14:33:00Z`) **only** when retrodocumenting an ADR from a past event — typically inside the `retrodocument-adrs-from-git` workflow, where the date must come from the originating git commit. The frontmatter `**date:**` field should match. Outside of retrodocumentation, omit `date`.',
381
+ "",
382
+ "## Primary use case — ADRs (Architecture Decision Records)",
383
+ 'On this project, the dominant use of `create_document` is to record an ADR every time a coding agent implements or modifies a feature. The full workflow is described in `get_server_guide` ("Feature workflow"). In short:',
384
+ "",
385
+ "1. **Supersede check first.** `list_documents` → shortlist ADRs whose title/category overlaps the feature → `read_document` to confirm. If one is obsoleted, overwrite it with `status: SuperSeeded` + a one-line pointer to the new ADR.",
386
+ "2. **Create the new ADR** with the mandatory frontmatter (below).",
387
+ "3. **Bind the source files** with `add_metadata` (see that tool for the god-files exclusion list). Without this, the ADR escapes drift detection.",
388
+ "",
389
+ "## Mandatory ADR frontmatter",
390
+ "Every ADR body starts with these four fields. They drive search, audit, and lifecycle:",
391
+ "",
392
+ "```",
393
+ "---",
394
+ "**date:** YYYY-MM-DD",
395
+ "**status:** To be validated",
396
+ "**description:** One dense, technical sentence — what the decision does, not why.",
397
+ "**tags:** 5–10 specific tags mixing concepts, technologies, and key symbol names",
398
+ "---",
399
+ "```",
400
+ "",
401
+ "- `status:` is **always** `To be validated` at creation. Only the human owner promotes to `Accepted`. The status has **no effect** on how the LLM treats the ADR — only `SuperSeeded` is filtered out downstream.",
402
+ '- `description:` stays factual and short — one sentence. The "why" goes in the body.',
403
+ "- `tags:` are the primary search signal. Be specific.",
404
+ "- `category` is the domain bucket in the filename pattern, uppercase (e.g. `SERVICES CLOUD`, `INTEGRATION`, `ALGORITHMES`).",
405
+ "- `folder` should be `adrs` (or the project ADR sub-folder).",
406
+ "",
407
+ "## Worked ADR example",
408
+ "```json",
409
+ "{",
410
+ ' "title": "ajout ressource storage s3",',
411
+ ' "category": "SERVICES CLOUD",',
412
+ ' "folder": "adrs",',
413
+ ' "content": "---\\n**date:** 2026-04-27\\n**status:** To be validated\\n**description:** Ajout du module S3 Storage via Amplify Gen 2 — bucket nommé via CDK override, CORS configuré, pas de mode hors-ligne\\n**tags:** s3, storage, amplify, CDK, bucket, CORS, cloud\\n---\\n\\n# Ajout ressource storage S3\\n\\n## Contexte\\n...\\n\\n## Décision\\n...\\n\\n## Conséquences\\n..."',
414
+ "}",
415
+ "```",
416
+ "",
417
+ "## Source-of-truth contract",
418
+ "Documents are the source of truth. Diagrams are derived views. If a diagram needs a concept that isn't documented, create or update the document first (here) before calling `create_diagram`.",
419
+ "",
420
+ "## Cross-project documentation workspace",
421
+ "If the user points you to a folder/repository that does not appear to match this MCP workspace, ask whether the mismatch is intentional. When confirmed, create the source-of-truth documents in this MCP workspace first; diagrams must then cite those documents, not raw source-code inspection.",
422
+ "",
423
+ GUIDE_HINT,
424
+ ].join("\n");
425
+ const TOOLS = [
426
+ {
427
+ name: "get_server_guide",
428
+ description: "Return the living-ai-documentation server guide: purpose, mandatory workflow, scope rules (context vs container/UML), diagram conventions, node/edge format, and coordinate system. Call this first whenever you are unsure how to use the server.",
429
+ inputSchema: { type: "object", properties: {} },
430
+ },
431
+ {
432
+ name: "list_documents",
433
+ description: `List all documents with their id, title, category, folder, and \`linkHref\` (the ready-to-paste \`?doc=...\` segment for a Markdown cross-doc link — copy it verbatim, do not re-encode). Documents are the source of truth — read them before creating or updating any diagram. ${GUIDE_HINT}`,
434
+ inputSchema: { type: "object", properties: {} },
435
+ },
436
+ {
437
+ name: "read_document",
438
+ description: `Read the raw Markdown content of a document by its id. Use this to gather facts (actors, systems, flows) before creating a diagram. Ignore documents whose frontmatter contains \`status: SuperSeeded\`. ${GUIDE_HINT}`,
439
+ inputSchema: {
440
+ type: "object",
441
+ properties: {
442
+ id: {
443
+ type: "string",
444
+ description: "Document id as returned by list_documents",
445
+ },
446
+ },
447
+ required: ["id"],
448
+ },
449
+ },
450
+ {
451
+ name: "update_document",
452
+ description: [
453
+ "Overwrite the Markdown content of an existing document by its id. Use this whenever you need to modify a doc in place — e.g. correcting drift detected by `get_accuracy` (Scenario B audit), or flipping `**status:**` to `SuperSeeded` after a feature has obsoleted a prior ADR (Scenario A supersede).",
454
+ "",
455
+ "## Workflow",
456
+ "1. `read_document(id)` to load the current Markdown.",
457
+ "2. Compose the new full content in your reasoning (fix description, body, flip status, etc.).",
458
+ "3. `update_document(id, content)` with the **full** new Markdown body — the file is overwritten exactly with this string.",
459
+ "4. `refresh_metadata(id)` once the doc is back in sync with the source files (re-baselines the SHA-256 hashes).",
460
+ "",
461
+ "The filename, id, date, category, and folder are NOT changed by this call — content-only update. To rename or recategorise, create a new doc with `create_document` and (optionally) supersede the old one via this tool.",
462
+ "",
463
+ "Returns `{ success, id, bytes }`.",
464
+ "",
465
+ GUIDE_HINT,
466
+ ].join("\n"),
467
+ inputSchema: {
468
+ type: "object",
469
+ properties: {
470
+ id: {
471
+ type: "string",
472
+ description: "Document id as returned by list_documents",
473
+ },
474
+ content: {
475
+ type: "string",
476
+ description: "Full Markdown content (frontmatter + body) — the file is overwritten with exactly this string. Must be non-empty.",
477
+ },
478
+ },
479
+ required: ["id", "content"],
480
+ },
481
+ },
482
+ {
483
+ name: "create_document",
484
+ description: CREATE_DOCUMENT_DESCRIPTION,
485
+ inputSchema: {
486
+ type: "object",
487
+ properties: {
488
+ title: { type: "string", description: "Human-readable document title" },
489
+ category: {
490
+ type: "string",
491
+ description: 'Category extracted from the filename, e.g. "Architecture", "Guide"',
492
+ },
493
+ folder: {
494
+ type: "string",
495
+ description: 'Optional subfolder relative to the docs root, e.g. "adrs" or "adrs/backend"',
496
+ },
497
+ content: {
498
+ type: "string",
499
+ description: "Full Markdown content. Omit to create an empty document.",
500
+ },
501
+ date: {
502
+ type: "string",
503
+ description: "Optional ISO 8601 date (e.g. `2024-08-12` or `2024-08-12T14:33:00Z`) that overrides the filename date prefix. Use ONLY when retrodocumenting from a past event (typically a git commit). Defaults to now.",
504
+ },
505
+ },
506
+ required: ["title", "category"],
507
+ },
508
+ },
509
+ {
510
+ name: "list_diagrams",
511
+ description: `List all saved diagrams with their id and title. Always call this before \`create_diagram\` — if a relevant diagram already exists, pass its id back to \`create_diagram\` to update rather than duplicate. ${GUIDE_HINT}`,
512
+ inputSchema: { type: "object", properties: {} },
513
+ },
514
+ {
515
+ name: "read_diagram",
516
+ description: `Read the nodes and edges of an existing diagram by its id. Returns the diagram in the same format accepted by \`create_diagram\`, ready to be modified and passed back. ${GUIDE_HINT}`,
517
+ inputSchema: {
518
+ type: "object",
519
+ properties: {
520
+ id: {
521
+ type: "string",
522
+ description: "Diagram id as returned by list_diagrams",
523
+ },
524
+ },
525
+ required: ["id"],
526
+ },
527
+ },
528
+ {
529
+ name: "create_diagram",
530
+ description: CREATE_DIAGRAM_DESCRIPTION,
531
+ inputSchema: {
532
+ type: "object",
533
+ properties: {
534
+ id: {
535
+ type: "string",
536
+ description: "Optional: existing diagram id to overwrite. If omitted, a new diagram is created.",
537
+ },
538
+ title: { type: "string", description: "Diagram title" },
539
+ diagramType: {
540
+ type: "string",
541
+ enum: [
542
+ "context",
543
+ "container",
544
+ "component",
545
+ "uml",
546
+ "flow",
547
+ "erd",
548
+ "screen-guide",
549
+ "other",
550
+ ],
551
+ description: 'Type of diagram. "context" is the default. "container", "component", "uml", and "screen-guide" require explicit user request — set `userRequestedExplicitly: true` alongside them.',
552
+ },
553
+ userRequestedExplicitly: {
554
+ type: "boolean",
555
+ description: 'Set to true only when the user explicitly asked for a container, component, UML, or screen-guide diagram by name. Required for those diagramType values; ignored for "context".',
556
+ },
557
+ edgesStraight: {
558
+ type: "boolean",
559
+ description: "Optional diagram-level style. Defaults to false for MCP-created diagrams.",
560
+ },
561
+ gridEnabled: {
562
+ type: "boolean",
563
+ description: "Optional diagram-level style. Defaults to false for MCP-created diagrams.",
564
+ },
565
+ alignGuides: {
566
+ type: "boolean",
567
+ description: "Optional diagram-level style. Defaults to true for MCP-created diagrams.",
568
+ },
569
+ nodes: {
570
+ type: "array",
571
+ description: 'List of nodes. Node labels should follow the C4 convention: "Name\\n[Type]\\nShort description".',
572
+ items: {
573
+ type: "object",
574
+ properties: {
575
+ name: {
576
+ type: "string",
577
+ description: "Node label shown in the diagram. With `kind`, pass the display name only and optional `description`; without `kind`, use \\n for C4 labels. Empty string allowed for zone overlays, anchors, and the image background.",
578
+ },
579
+ kind: {
580
+ type: "string",
581
+ enum: KIND_LIST.split(", "),
582
+ description: "Optional architectural concept. When present, the MCP builds a C4 label and chooses default renderAs/color unless overridden.",
583
+ },
584
+ renderAs: {
585
+ type: "string",
586
+ description: `Optional visual shape override used with kind. Available: ${SHAPE_LIST}.`,
587
+ },
588
+ description: {
589
+ type: "string",
590
+ description: "Optional architectural description appended as the third C4 label line when kind is present and name is not already a multiline label.",
591
+ },
592
+ type: {
593
+ type: "string",
594
+ description: `Legacy visual shape. Still supported when kind is absent. Available: ${SHAPE_LIST}.`,
595
+ },
596
+ color: {
597
+ type: "string",
598
+ description: `Color key, e.g. c-blue or "blue". Available: ${COLOR_LIST}.`,
599
+ },
600
+ x: {
601
+ type: "number",
602
+ description: "Optional canvas X (0 = center). If omitted, the MCP assigns a deterministic position before saving. When provided, use multiples of 40 (screen-guide exception: pixel-aligned).",
603
+ },
604
+ y: {
605
+ type: "number",
606
+ description: "Optional canvas Y (0 = center, positive = down). If omitted, the MCP assigns a deterministic position before saving. When provided, use multiples of 40 (screen-guide exception: pixel-aligned).",
607
+ },
608
+ width: {
609
+ type: "number",
610
+ description: "Optional explicit node width in pixels. Required for image backgrounds and zone overlays in screen-guide diagrams. Otherwise estimated from the label.",
611
+ },
612
+ height: {
613
+ type: "number",
614
+ description: "Optional explicit node height in pixels. Required for image backgrounds and zone overlays in screen-guide diagrams. Otherwise estimated from the label.",
615
+ },
616
+ fontSize: {
617
+ type: ["number", "null"],
618
+ description: "Optional node label font size. Defaults to null so the editor uses its shape default.",
619
+ },
620
+ textAlign: {
621
+ type: ["string", "null"],
622
+ description: "Optional node text horizontal alignment. Defaults to null.",
623
+ },
624
+ textValign: {
625
+ type: ["string", "null"],
626
+ description: "Optional node text vertical alignment. Defaults to null.",
627
+ },
628
+ bgOpacity: {
629
+ type: "number",
630
+ description: "Optional background opacity (0–1). Use 0.15–0.20 for translucent zone-overlay boxes in screen-guide diagrams.",
631
+ },
632
+ rotation: {
633
+ type: ["number", "null"],
634
+ description: "Optional node shape rotation in radians. Defaults to 0.",
635
+ },
636
+ labelRotation: {
637
+ type: ["number", "null"],
638
+ description: "Optional node label rotation in radians. Defaults to 0.",
639
+ },
640
+ locked: {
641
+ type: "boolean",
642
+ description: "Optional: lock the node so it cannot be moved or resized by accident. Recommended for screen-guide backgrounds and zone overlays.",
643
+ },
644
+ linkedDiagramId: {
645
+ type: "string",
646
+ description: "Optional: id of another diagram to navigate to when clicking this node (C4 drill-down).",
647
+ },
648
+ groupId: {
649
+ type: ["string", "null"],
650
+ description: "Optional editor group id. Defaults to null.",
651
+ },
652
+ imageSrc: {
653
+ type: "string",
654
+ description: 'Required when `type` is "image". URL path returned by POST /api/images/upload (e.g. "/images/foo.png").',
655
+ },
656
+ evidence: {
657
+ type: "array",
658
+ description: "Optional documentary provenance for this node. Cite only Markdown documents from list_documents/read_document/create_document, not source files.",
659
+ items: {
660
+ type: "object",
661
+ properties: {
662
+ documentId: {
663
+ type: "string",
664
+ description: "Document id as returned by list_documents or create_document.",
665
+ },
666
+ section: {
667
+ type: ["string", "null"],
668
+ description: "Optional section heading inside the document.",
669
+ },
670
+ summary: {
671
+ type: ["string", "null"],
672
+ description: "Short paraphrase of the documentary fact that justifies this node.",
673
+ },
674
+ },
675
+ required: ["documentId"],
676
+ },
677
+ },
678
+ },
679
+ required: ["name"],
680
+ },
681
+ },
682
+ edges: {
683
+ type: "array",
684
+ description: "List of directed edges between nodes. Every edge should have a `label` describing the interaction (verb phrase). Exception: screen-guide edges have empty labels.",
685
+ items: {
686
+ type: "object",
687
+ properties: {
688
+ from: {
689
+ type: "string",
690
+ description: "Name of the source node (must match a node `name` exactly).",
691
+ },
692
+ to: {
693
+ type: "string",
694
+ description: "Name of the target node (must match a node `name` exactly). Optional for screen-guide diagrams — omit to render a free-end arrow the user can drag.",
695
+ },
696
+ label: {
697
+ type: "string",
698
+ description: "Edge label — verb phrase describing the interaction. Strongly recommended; missing labels produce warnings (except for screen-guide).",
699
+ },
700
+ arrowDir: {
701
+ type: "string",
702
+ enum: ["to", "from", "both", "none"],
703
+ description: 'Optional arrow direction. Defaults to "to"; use "from" to draw the arrowhead at the source end, or "both" for one bidirectional exchange edge.',
704
+ },
705
+ dashes: {
706
+ type: "boolean",
707
+ description: "Optional dashed-line flag. Defaults to false.",
708
+ },
709
+ fontSize: {
710
+ type: ["number", "null"],
711
+ description: "Optional edge-label font size. Defaults to 12, or 11 for labels longer than 36 characters.",
712
+ },
713
+ labelRotation: {
714
+ type: ["number", "null"],
715
+ description: "Optional edge-label rotation in radians. Defaults to 0.",
716
+ },
717
+ edgeLabelOffsetX: {
718
+ type: ["number", "null"],
719
+ description: "Optional edge-label X offset. Defaults to 0.",
720
+ },
721
+ edgeLabelOffsetY: {
722
+ type: ["number", "null"],
723
+ description: "Optional edge-label Y offset. Defaults to 0.",
724
+ },
725
+ fromPort: {
726
+ type: ["string", "null"],
727
+ enum: ["N", "NE", "E", "SE", "S", "SW", "W", "NW", null],
728
+ description: "Optional source attachment port. Defaults from relative node positions.",
729
+ },
730
+ toPort: {
731
+ type: ["string", "null"],
732
+ enum: ["N", "NE", "E", "SE", "S", "SW", "W", "NW", null],
733
+ description: "Optional target attachment port. Defaults from relative node positions.",
734
+ },
735
+ edgeColor: {
736
+ type: ["string", "null"],
737
+ description: "Optional custom edge color. Defaults to null.",
738
+ },
739
+ edgeWidth: {
740
+ type: ["number", "null"],
741
+ description: "Optional custom edge width. Defaults to null.",
742
+ },
743
+ edgeLocked: {
744
+ type: "boolean",
745
+ description: "Optional lock flag for the edge. Defaults to false.",
746
+ },
747
+ edgeLabelWidth: {
748
+ type: ["number", "null"],
749
+ description: "Optional fixed edge-label wrapping width. Defaults to 80/95/105 depending on label length.",
750
+ },
751
+ evidence: {
752
+ type: "array",
753
+ description: "Optional documentary provenance for this relation. Cite only Markdown documents from list_documents/read_document/create_document, not source files.",
754
+ items: {
755
+ type: "object",
756
+ properties: {
757
+ documentId: {
758
+ type: "string",
759
+ description: "Document id as returned by list_documents or create_document.",
760
+ },
761
+ section: {
762
+ type: ["string", "null"],
763
+ description: "Optional section heading inside the document.",
764
+ },
765
+ summary: {
766
+ type: ["string", "null"],
767
+ description: "Short paraphrase of the documentary fact that justifies this relation.",
768
+ },
769
+ },
770
+ required: ["documentId"],
771
+ },
772
+ },
773
+ },
774
+ required: ["from"],
775
+ },
776
+ },
777
+ },
778
+ required: ["title", "diagramType", "nodes", "edges"],
779
+ },
780
+ },
781
+ {
782
+ name: "list_source_files",
783
+ description: [
784
+ "List files under the project `sourceRoot` (configured in `.living-doc.json`, defaults to the parent folder of the docs directory).",
785
+ "",
786
+ "Use this tool as a **fallback** when the Markdown documentation lacks a specific low-level detail needed for a diagram — for example, when generating a screen-guide diagram or when documenting a piece of code that has no ADR. For architectural facts, read documents first.",
787
+ "",
788
+ "Common ignored folders are skipped automatically (`node_modules`, `dist`, `.git`, `build`, `target`, etc.).",
789
+ ].join("\n"),
790
+ inputSchema: {
791
+ type: "object",
792
+ properties: {
793
+ pattern: {
794
+ type: "string",
795
+ description: "Optional glob-like pattern matched against the relative path. Supports `*` (within a segment) and `**` (across segments). Example: `src/**/*.ts`.",
796
+ },
797
+ maxResults: {
798
+ type: "number",
799
+ description: "Max number of files to return (default 500, hard cap 2000).",
800
+ },
801
+ },
802
+ },
803
+ },
804
+ {
805
+ name: "read_source_file",
806
+ description: [
807
+ "Read a source file under the project `sourceRoot`. Path must be relative to `sourceRoot`.",
808
+ "",
809
+ "Use this **only after** you have tried the documentation tools (`list_documents` / `read_document`). If you find yourself reading more than 3 source files for the same diagram, stop and update the documentation first — the docs are the source of truth.",
810
+ "",
811
+ "Files larger than 512 KB are rejected; use `search_source` to locate the relevant section.",
812
+ ].join("\n"),
813
+ inputSchema: {
814
+ type: "object",
815
+ properties: {
816
+ path: {
817
+ type: "string",
818
+ description: "Path relative to `sourceRoot`, e.g. `src/frontend/index.html`.",
819
+ },
820
+ },
821
+ required: ["path"],
822
+ },
823
+ },
824
+ {
825
+ name: "list_metadata",
826
+ description: [
827
+ "List the source-file metadata entries attached to a document. Each entry is a source file (path relative to `sourceRoot`) bound to the document with the SHA-256 hash that was stored when it was attached.",
828
+ "",
829
+ "Use together with `get_accuracy` to decide whether a doc needs to be reviewed because one of its source-file dependencies has changed.",
830
+ ].join("\n"),
831
+ inputSchema: {
832
+ type: "object",
833
+ properties: {
834
+ id: {
835
+ type: "string",
836
+ description: "Document id as returned by list_documents",
837
+ },
838
+ },
839
+ required: ["id"],
840
+ },
841
+ },
842
+ {
843
+ name: "get_accuracy",
844
+ description: [
845
+ "Compute a document's accuracy: compares the SHA-256 hashes stored with each metadata entry against the hashes of the source files on disk today.",
846
+ "",
847
+ "Returns each item with status `unchanged` / `modified` / `missing`, counts, and a weighted `accuracy` in [0, 1] (missing weighs 3× a simple modification).",
848
+ "",
849
+ "A value close to 1 means the doc is still aligned with its source files. A value close to 0 means significant drift: read the doc and the modified source files, then update the doc.",
850
+ ].join("\n"),
851
+ inputSchema: {
852
+ type: "object",
853
+ properties: {
854
+ id: { type: "string", description: "Document id" },
855
+ },
856
+ required: ["id"],
857
+ },
858
+ },
859
+ {
860
+ name: "review_adr_relevance",
861
+ description: [
862
+ "Prepare a relevance review for one ADR document.",
863
+ "",
864
+ "The tool accepts a document id, verifies that the document is an ADR, returns the ADR content, its frontmatter summary, the metadata accuracy report, and the source files whose hashes no longer match.",
865
+ "",
866
+ "This is a factual reporting tool, not the whole workflow. Use prompt `review-adr-relevance` when the LLM must decide between `refresh_metadata` and user-confirmed supersession.",
867
+ ].join("\n"),
868
+ inputSchema: {
869
+ type: "object",
870
+ properties: {
871
+ id: {
872
+ type: "string",
873
+ description: "Document id. Must identify an ADR document.",
874
+ },
875
+ },
876
+ required: ["id"],
877
+ },
878
+ },
879
+ {
880
+ name: "refresh_metadata",
881
+ description: [
882
+ "Re-hash every source file attached to a document and overwrite the stored hashes with the current values. Call this AFTER the document has been updated to reflect the current state of its source files — it validates the doc as accurate again.",
883
+ "",
884
+ "Missing files keep their stored hash and remain flagged as missing.",
885
+ ].join("\n"),
886
+ inputSchema: {
887
+ type: "object",
888
+ properties: {
889
+ id: { type: "string", description: "Document id" },
890
+ },
891
+ required: ["id"],
892
+ },
893
+ },
894
+ {
895
+ name: "add_metadata",
896
+ description: [
897
+ "Attach a source file to a document as a metadata dependency. The file path must be under the configured `sourceRoot`. The current SHA-256 hash of the file is recorded.",
898
+ "",
899
+ "If the document already has an entry for that path, its hash is updated.",
900
+ "",
901
+ "## Call this after every `create_document` for an ADR",
902
+ 'Each ADR must be bound to the source files it materially describes. Without this binding, the ADR escapes drift detection (`get_accuracy`, `list_adrs_below_accuracy`) and the documentation stops being "living".',
903
+ "",
904
+ "## What to attach — and what NOT to attach",
905
+ "Attach: every source file whose **logic** is the subject of the ADR (component, hook, service, route, schema, infra config that this decision created or changed).",
906
+ "",
907
+ "Do **NOT** attach god files / god objects — files that change for nearly every feature and would produce false-positive drift signals across many ADRs:",
908
+ "- Lock and manifest files: `package.json`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`, `tsconfig.json`, `requirements.txt`, `Cargo.lock`, `go.sum`, `pyproject.toml` (when it tracks dependencies).",
909
+ "- Central re-export / barrel files (`index.ts` that just re-exports), root routers, root stores, top-level app entry files — unless the ADR is specifically about that file.",
910
+ "- Auto-generated files (build outputs, OpenAPI clients, schema codegen).",
911
+ "",
912
+ "**Rule of thumb**: if a routine modification of the file would NOT reflect a semantic change of the feature this ADR describes, do not attach it.",
913
+ "",
914
+ "Returns only the added entry and aggregate totals. Use `list_metadata` to retrieve the full list.",
915
+ ].join("\n"),
916
+ inputSchema: {
917
+ type: "object",
918
+ properties: {
919
+ id: { type: "string", description: "Document id" },
920
+ path: {
921
+ type: "string",
922
+ description: "Path to the source file, relative to sourceRoot or absolute but under sourceRoot.",
923
+ },
924
+ },
925
+ required: ["id", "path"],
926
+ },
927
+ },
928
+ {
929
+ name: "remove_metadata",
930
+ description: "Remove a source-file metadata entry from a document. Use this to clean up orphan entries when a source file has been deleted or renamed (rename = add the new path then remove the old one). Idempotent: returns removed: null if the path is not currently attached. Does not touch the source file on disk — only updates the metadata.",
931
+ inputSchema: {
932
+ type: "object",
933
+ properties: {
934
+ id: { type: "string", description: "Document id" },
935
+ path: {
936
+ type: "string",
937
+ description: "Path to the source file, relative to sourceRoot or absolute but under sourceRoot.",
938
+ },
939
+ },
940
+ required: ["id", "path"],
941
+ },
942
+ },
943
+ {
944
+ name: "list_adrs_below_accuracy",
945
+ description: "List ADRs whose accuracy has dropped below 80%, sorted from most degraded first. Returns up to 10 ADRs per call along with the total count of ADRs below the threshold. Non-ADR documents, ADRs without metadata (total = 0), and SuperSeeded ADRs are excluded. ADR detection uses the same convention as review_adr_relevance: folder segment `ADRS`, category `ADR`, `[ADR]` in the id, or an `Architecture Decision Record` marker in the opening content.",
946
+ inputSchema: { type: "object", properties: {} },
947
+ },
948
+ {
949
+ name: "search_source",
950
+ description: [
951
+ "Grep-like text search across files under the project `sourceRoot`.",
952
+ "",
953
+ "Preferred over `read_source_file` when you only need to locate a symbol, identifier, or string. Returns `{ file, line, text }` matches.",
954
+ ].join("\n"),
955
+ inputSchema: {
956
+ type: "object",
957
+ properties: {
958
+ query: {
959
+ type: "string",
960
+ description: "Substring to match (plain text, not regex).",
961
+ },
962
+ pattern: {
963
+ type: "string",
964
+ description: "Optional glob to restrict the search (e.g. `src/**/*.ts`).",
965
+ },
966
+ caseSensitive: { type: "boolean", description: "Default false." },
967
+ maxResults: {
968
+ type: "number",
969
+ description: "Max number of matches to return (default 200, hard cap 1000).",
970
+ },
971
+ },
972
+ required: ["query"],
973
+ },
974
+ },
975
+ {
976
+ name: "retrodocument_adrs_from_git",
977
+ description: [
978
+ "Prepare a retrodocumentation packet from recent git history.",
979
+ "",
980
+ "Reads up to `limit` commits (default 100, hard cap 200) from the git repository that contains `sourceRoot`, ordered **oldest first** so the LLM can walk decisions in chronological order. Per commit, returns: sha, committer/author dates (ISO 8601), author name, subject, body, parent count, and `filesChanged` annotated with `changeType` (A/M/D/R/C/T), `underSourceRoot`, `existsNow`, and `godFileSuspect` (lock files, manifests — flagged as poor metadata targets per `add_metadata` guidance).",
981
+ "",
982
+ "Each commit carries a `state`:",
983
+ "- `candidate` — has at least one non-deleted, non-god file under `sourceRoot`; worth a semantic look.",
984
+ "- `trivial` — no source-bearing files (docs-only, formatting, config-only); skip unless the LLM has reason.",
985
+ "- `merge` — has more than one parent; skip unless the merge introduces a documented decision.",
986
+ "",
987
+ "This is a factual reporting tool, not the whole workflow. Use prompt `retrodocument-adrs-from-git` when the LLM must decide whether each commit deserves a new ADR (Outcome A), should supersede an existing one (Outcome B), or be skipped (Outcome C).",
988
+ "",
989
+ "Requires `sourceRoot` to be inside a git working tree; errors out otherwise.",
990
+ ].join("\n"),
991
+ inputSchema: {
992
+ type: "object",
993
+ properties: {
994
+ limit: {
995
+ type: "number",
996
+ description: "Number of commits to return (default 100, max 200).",
997
+ },
998
+ since: {
999
+ type: "string",
1000
+ description: "Optional git --since expression (e.g. `2024-01-01`, `6 months ago`). Passed straight to git log.",
1001
+ },
1002
+ },
1003
+ },
1004
+ },
1005
+ ];
1006
+ // ── MCP Prompts ────────────────────────────────────────────────────────────────
1007
+ // Prompt templates guide the LLM to produce well-structured create_diagram
1008
+ // calls. Layout work (positions, types, colors) happens on the caller's side —
1009
+ // zero tokens consumed by the server.
1010
+ const PROMPTS = [
1011
+ {
1012
+ name: "audit-adrs-drift",
1013
+ description: 'Audit drifting ADRs: list every ADR with reliability < 80%, call `review_adr_relevance`, read the drifted source files, then either re-baseline hashes when the ADR still matches the code or ask the user before superseding it. Auto-invoke when the user asks to audit / refresh / review drifting ADRs ("audite les ADR", "vérifie la fiabilité des ADR", "fais le tour des ADR qui ne sont plus à jour", "review ADR drift").',
1014
+ },
1015
+ {
1016
+ name: "review-adr-relevance",
1017
+ description: "Review one specific ADR whose reliability gauge may be below 100%: call `review_adr_relevance`, read the drifted source files, decide whether the ADR still matches the code, then either refresh metadata or ask the user before superseding it. Auto-invoke when the user asks to verify/check/review the relevance of a specific ADR.",
1018
+ arguments: [
1019
+ {
1020
+ name: "id",
1021
+ description: "Document id of the ADR to review, e.g. `ADRS/2026_05_11_22_33_[MCP]_review_adr_relevance_mcp_tool`.",
1022
+ required: true,
1023
+ },
1024
+ ],
1025
+ },
1026
+ {
1027
+ name: "create-adr",
1028
+ description: 'Record an ADR (Architecture Decision Record) for a feature you just implemented or modified. Auto-invoke when the user signals a feature is done ("feature terminée", "j\'ai fini cette fonctionnalité"), or proactively at the end of a coding task. Walks through: search for ADRs to supersede, write the new ADR with the mandatory frontmatter at status `To be validated`, attach source files via `add_metadata` (god files excluded).',
1029
+ arguments: [
1030
+ {
1031
+ name: "featureSummary",
1032
+ description: 'One-line description of the feature/decision being recorded. Example: "Ajout du module S3 Storage via Amplify Gen 2".',
1033
+ required: false,
1034
+ },
1035
+ {
1036
+ name: "modifiedFiles",
1037
+ description: "Comma-separated list of source files materially modified or created by this feature (relative to sourceRoot). Used to seed the metadata bindings; god files should already be filtered out by the caller.",
1038
+ required: false,
1039
+ },
1040
+ ],
1041
+ },
1042
+ {
1043
+ name: "retrodocument-adrs-from-git",
1044
+ description: 'Retrodocument missing ADRs by walking recent git history oldest-first: call `retrodocument_adrs_from_git`, decide for each candidate commit whether it carries a durable architectural decision worth an ADR, then either skip, create a new ADR dated from the commit, or supersede an earlier ADR before creating the new one. Auto-invoke when the user asks to retrodocument / recreate / backfill / reconstruct ADRs from git ("retrodocumente les ADR depuis git", "recrée les ADR manquants depuis l\'historique", "remonte l\'historique git pour générer les ADR", "backfill ADRs from history"). Distinct from `create-adr` (which records ONE current feature) and from `audit-adrs-drift` (which fixes drift on existing ADRs).',
1045
+ arguments: [
1046
+ {
1047
+ name: "limit",
1048
+ description: "Optional: number of commits to inspect (default 100, hard cap 200).",
1049
+ required: false,
1050
+ },
1051
+ {
1052
+ name: "since",
1053
+ description: "Optional: git --since expression (e.g. `2024-01-01`, `6 months ago`). Restricts the inspected window.",
1054
+ required: false,
1055
+ },
1056
+ ],
1057
+ },
1058
+ {
1059
+ name: "generate-context-diagram",
1060
+ description: 'DEFAULT. Generate a C4 System Context diagram — one system in the center, surrounding users and external systems. Safe to auto-invoke when the user asks for "a diagram", "the big picture", or "documentation".',
1061
+ arguments: [
1062
+ {
1063
+ name: "scope",
1064
+ description: "Optional: name of the system to put at the center. Inferred from the docs if omitted.",
1065
+ required: false,
1066
+ },
1067
+ ],
1068
+ },
1069
+ {
1070
+ name: "generate-container-diagram",
1071
+ description: 'EXPLICIT-ONLY. Generate a C4 Container diagram (internal containers of a single system). Invoke this only when the user explicitly asks for a "container diagram".',
1072
+ },
1073
+ {
1074
+ name: "generate-uml-diagram",
1075
+ description: 'EXPLICIT-ONLY. Generate a UML diagram. Invoke this only when the user explicitly asks for a "UML diagram" by name.',
1076
+ arguments: [
1077
+ {
1078
+ name: "umlType",
1079
+ description: "UML variant: class, sequence, state, activity, or use-case.",
1080
+ required: true,
1081
+ },
1082
+ ],
1083
+ },
1084
+ {
1085
+ name: "update-diagram-from-docs",
1086
+ description: "Re-read source documents and update existing diagrams so they reflect the current state of the documentation. Accepts an optional diagramId to target a single diagram.",
1087
+ arguments: [
1088
+ {
1089
+ name: "diagramId",
1090
+ description: "Optional: id of a single diagram to update. If omitted, all diagrams are inspected.",
1091
+ required: false,
1092
+ },
1093
+ ],
1094
+ },
1095
+ {
1096
+ name: "generate-screen-guide",
1097
+ description: 'EXPLICIT-ONLY. Generate an annotated UI guide: a screenshot image as the background with post-it notes describing each UI element. Reads the source code of the screen (HTML/JSX/template). Invoke only when the user explicitly asks for a "screen guide", "UI guide", or "annotated screenshot".',
1098
+ arguments: [
1099
+ {
1100
+ name: "screenFile",
1101
+ description: "Relative path (under sourceRoot) of the screen source file to document, e.g. `src/frontend/index.html`.",
1102
+ required: true,
1103
+ },
1104
+ {
1105
+ name: "screenshotUrl",
1106
+ description: "Optional: URL of the uploaded screenshot (e.g. `/images/index-2026.png`). If omitted, the prompt will instruct the user to upload one via the Admin UI first.",
1107
+ required: false,
1108
+ },
1109
+ ],
1110
+ },
1111
+ {
1112
+ name: "flow",
1113
+ description: "Left-to-right linear flow diagram — steps or stages in a process.",
1114
+ },
1115
+ {
1116
+ name: "erd",
1117
+ description: "Entity-Relationship Diagram — entities as boxes, relationships as labeled edges.",
1118
+ },
1119
+ ];
1120
+ // Prepended to every diagram prompt — enforces ADR-first information gathering.
1121
+ const PREAMBLE = `
1122
+ ## Before anything else — mine the existing documentation
1123
+
1124
+ Living Documentation is a tool where knowledge lives primarily in Markdown documents (ADRs, guides, decisions).
1125
+ **Do not ask the user questions you can answer yourself by reading the docs.**
1126
+
1127
+ 1. Call \`list_documents\` to get the full document list.
1128
+ 2. Read documents that look architecturally significant regardless of their folder name — look for ADR-style frontmatter (lines starting with \`**status:**\`, \`**description:**\`, \`**tags:**\`), README files, and any document whose title or category suggests architecture, integration, or domain knowledge.
1129
+ 3. **Ignore any document whose frontmatter contains \`status: SuperSeeded\`** — it is deprecated and must not be used as a source of truth.
1130
+ 4. Read the frontmatter (\`description\` and \`tags\` fields) of each relevant document with \`read_document\` to find answers to the diagram-specific questions below.
1131
+ 5. Only ask the user for information that cannot be found in any active (non-superseded) document.
1132
+ 6. Every architectural node or relation should include \`evidence\` entries that cite the Markdown documents and sections that justify it. Evidence must come from documents, not from source code. If the required document does not exist, create it first.
1133
+
1134
+ ## Node semantics and label format — mandatory
1135
+
1136
+ Prefer structured node semantics when calling \`create_diagram\`: pass \`kind\`
1137
+ (\`person\`, \`software_system\`, \`external_system\`, \`container\`, \`component\`,
1138
+ \`database\`, \`object_storage\`, \`queue\`, \`device\`, \`api\`, \`cloud_service\`,
1139
+ \`browser_app\`, \`mobile_app\`, \`backend_service\`, \`job\`, \`unknown\`) plus optional
1140
+ \`description\`. The MCP will build the Simon Brown C4 label and choose the
1141
+ default visual shape/color. Use \`renderAs\` only when the default visual shape
1142
+ should be overridden.
1143
+
1144
+ If you do not use \`kind\`, every node label must follow the C4 convention using \\n for line breaks:
1145
+
1146
+ \`\`\`
1147
+ Name\\n[Type]\\nShort description of role or responsibility
1148
+ \`\`\`
1149
+
1150
+ Examples:
1151
+ - \`"DriveBox\\n[Software System]\\nManages ad campaigns\\ndisplayed on taxi tablets"\`
1152
+ - \`"Advertiser\\n[Person]\\nUploads media and\\npays for campaigns"\`
1153
+ - \`"Stripe\\n[External System]\\nCard payment and\\npre-authorization"\`
1154
+
1155
+ Types to use include: \`[Person]\`, \`[Software System]\`, \`[External System]\`, \`[Container]\`, \`[Component]\`, \`[Database]\`, \`[Device]\`
1156
+ Keep descriptions short — 1 to 2 lines maximum.
1157
+
1158
+ ## C4 progression — mandatory ordering
1159
+
1160
+ C4 diagrams must be created in strict order:
1161
+
1162
+ 1. **Context first** — the entry point when scanning a project's docs for the first time.
1163
+ It answers: what is the system, who uses it, what external systems does it integrate with?
1164
+ 2. **Container after** — a drill-down created only when a Context diagram already exists
1165
+ **and** the reader explicitly asks to go deeper into a specific system.
1166
+ 3. **Component after that** — same rule, only after a Container exists.
1167
+
1168
+ **When reading docs for the first time, always create the Context diagram.**
1169
+ Never jump to Container or Component as the first diagram for a system.
1170
+
1171
+ ## Linked diagrams — C4 drill-down
1172
+
1173
+ Any node can link to an **already-existing** diagram for navigation (e.g. Context → Container → Component).
1174
+
1175
+ **Workflow:**
1176
+ 1. Call \`list_diagrams\`.
1177
+ 2. If a relevant child diagram already exists, add \`linkedDiagramId: "<id>"\` on the matching node.
1178
+ 3. If no child diagram exists, leave \`linkedDiagramId\` unset.
1179
+
1180
+ **RULE — never create child diagrams automatically.**
1181
+ Container and Component diagrams are only created on explicit user request for a specific scope.
1182
+ Do not create them as a side effect of creating a Context diagram.
1183
+
1184
+ Clicking a linked node in the editor navigates directly to the child diagram.
1185
+ `.trim();
1186
+ function buildPromptTemplate(name, args) {
1187
+ switch (name) {
1188
+ case "audit-adrs-drift":
1189
+ return `
1190
+ You are about to **audit ADR drift against the source code each ADR describes**, and bring every drifting ADR back to a clear state.
1191
+
1192
+ ## Step 1 — Inventory drifting ADRs
1193
+
1194
+ Call \`list_adrs_below_accuracy\`. It returns up to 10 ADRs whose reliability is below 80%, sorted most-degraded first, plus a \`totalBelowThreshold\` counter. Non-ADR documents, \`SuperSeeded\` ADRs, and ADRs without metadata are excluded automatically.
1195
+
1196
+ If the result is empty, tell the user *"All ADRs are above the 80% reliability threshold — nothing to audit."* and stop.
1197
+
1198
+ ## Step 2 — Audit each ADR in the batch
1199
+
1200
+ For each ADR returned, in order:
1201
+
1202
+ 1. Call \`review_adr_relevance(id)\` — this validates the ADR and returns the ADR content, metadata accuracy, and \`sourceFilesToReread\`.
1203
+ 2. If \`state\` is \`no_metadata\`, \`metadata_current\`, or \`already_superseeded\`, report the state and move to the next ADR.
1204
+ 3. For every \`sourceFilesToReread\` entry whose status is \`modified\`: call \`read_source_file(path)\`.
1205
+ 4. For every entry whose status is \`missing\`: do **not** refresh. Tell the user the file is missing and ask whether it was renamed or deleted.
1206
+ 5. **Compare and decide.** The ADR's \`document.description\` and body describe a technical decision. Are they still accurate against the current source files, or have they fallen out of sync?
1207
+
1208
+ ### Outcome A — The ADR is still accurate
1209
+ The code changes were cosmetic (renames, formatting, refactors that don't affect documented behavior).
1210
+
1211
+ → Call \`refresh_metadata(id)\` to re-baseline the hashes against the current files.
1212
+
1213
+ Tell the user: *"\`<title>\` — accuracy was X%, but the description still holds. Re-baselined."*
1214
+
1215
+ ### Outcome B — The ADR contradicts the code
1216
+ The description and/or body no longer match what the code does.
1217
+
1218
+ 1. Tell the user exactly what no longer matches.
1219
+ 2. Ask whether they want to supersede the ADR.
1220
+ 3. Wait for the user's answer.
1221
+
1222
+ If the user accepts:
1223
+ - Call \`read_document(id)\` if you need the current Markdown again.
1224
+ - Call \`update_document(id, content)\` with the full Markdown, changing the frontmatter status to exactly \`SuperSeeded\` and adding a short supersession note under the frontmatter.
1225
+ - Tell the user the ADR has been superseded.
1226
+
1227
+ If the user refuses:
1228
+ - Tell the user that they must perform the verification themselves and call \`refresh_metadata(id)\` only when they are satisfied the ADR is aligned with the code.
1229
+
1230
+ ### Outcome C — Source files are missing
1231
+ \`review_adr_relevance\` flags entries as \`missing\` (the source file no longer exists).
1232
+
1233
+ Do **not** auto-remove the metadata entry. The file may have been **renamed** (the user should run \`add_metadata\` for the new path then \`remove_metadata\` for the old one) or genuinely **deleted** (\`remove_metadata\`). Surface the situation to the user and wait for instruction.
1234
+
1235
+ ## Step 3 — Loop until done
1236
+
1237
+ After processing the batch, call \`list_adrs_below_accuracy\` again. If \`totalBelowThreshold\` > 0 **and** the new batch makes progress (different docs or fewer docs), continue from Step 2.
1238
+
1239
+ If the same docs come back unchanged, the remaining drift is intentional or blocked by Outcome C — stop and report.
1240
+
1241
+ ## Step 4 — Final report
1242
+
1243
+ Summarise to the user:
1244
+ - N ADRs audited.
1245
+ - N re-baselined as-is (Outcome A — description was correct).
1246
+ - N superseded after user confirmation (Outcome B).
1247
+ - N flagged for user input (Outcome C — missing source files, refused supersession, or structural change requiring \`create-adr\`).
1248
+ - Final \`totalBelowThreshold\` after the audit.
1249
+ `.trim();
1250
+ case "review-adr-relevance": {
1251
+ const id = (args.id || "").trim();
1252
+ const targetLine = id
1253
+ ? `The user wants to review ADR id: \`${id}\`.`
1254
+ : "The user did not provide an ADR id. Ask for the ADR document id before calling tools.";
1255
+ return `
1256
+ You are about to **review the relevance of one specific ADR against the source files bound in its metadata**.
1257
+
1258
+ ${targetLine}
1259
+
1260
+ ## Goal
1261
+
1262
+ Decide whether the ADR still accurately describes the current source code.
1263
+
1264
+ This is a semantic judgement. The MCP tool prepares the factual report, but you must read the ADR and the changed source files before deciding.
1265
+
1266
+ ## Step 1 — Prepare the ADR review packet
1267
+
1268
+ ${id ? `Call \`review_adr_relevance({ "id": "${id}" })\`.` : 'Ask the user for the ADR id, then call `review_adr_relevance({ "id": "<id>" })`.'}
1269
+
1270
+ If the tool rejects the document as non-ADR, tell the user that this workflow only applies to ADRs and stop.
1271
+
1272
+ Interpret the returned \`state\`:
1273
+
1274
+ - \`no_metadata\`: the ADR has no source metadata, so there is no hash-based review to perform. Tell the user to attach source files with \`add_metadata\` first.
1275
+ - \`metadata_current\`: the accuracy is already 100 %. Tell the user no hash refresh is needed. Only continue with a semantic review if the user explicitly asks.
1276
+ - \`already_superseeded\`: the ADR is already superseded. Tell the user and do not refresh it as an active decision unless they explicitly ask.
1277
+ - \`needs_llm_review\`: continue below.
1278
+
1279
+ ## Step 2 — Read source files
1280
+
1281
+ For every item in \`metadata.sourceFilesToReread\`:
1282
+
1283
+ - if \`status === "modified"\`, call \`read_source_file(path)\`;
1284
+ - if \`status === "missing"\`, do not invent a replacement path. Tell the user the file is missing and ask whether it was renamed or deleted. Do not refresh metadata in this case.
1285
+
1286
+ ## Step 3 — Compare
1287
+
1288
+ Compare:
1289
+
1290
+ - the ADR \`document.description\`;
1291
+ - the body of \`document.content\`;
1292
+ - the current contents of the modified source files.
1293
+
1294
+ Decide whether the ADR still describes the code.
1295
+
1296
+ ## Outcome A — ADR still matches the code
1297
+
1298
+ If the ADR description and body still match the source files:
1299
+
1300
+ 1. Call \`refresh_metadata(id)\`.
1301
+ 2. Tell the user that the ADR remains relevant and that the metadata hashes were refreshed back to 100 %.
1302
+ 3. Mention the files that were reviewed.
1303
+
1304
+ ## Outcome B — ADR contradicts the code
1305
+
1306
+ If the ADR description or body contradicts the source files:
1307
+
1308
+ 1. Tell the user exactly what no longer matches.
1309
+ 2. Ask the user whether they want to supersede the ADR.
1310
+ 3. Wait for the user's answer.
1311
+
1312
+ If the user accepts:
1313
+
1314
+ 1. Call \`read_document(id)\` if you need the current Markdown again.
1315
+ 2. Call \`update_document(id, content)\` with the full Markdown, changing the frontmatter status to exactly \`SuperSeeded\` and adding a short supersession note under the frontmatter.
1316
+ 3. Tell the user the ADR has been superseded.
1317
+
1318
+ If the user refuses:
1319
+
1320
+ Tell the user that they must perform the verification themselves and call \`refresh_metadata(id)\` only when they are satisfied the ADR is aligned with the code.
1321
+
1322
+ ## Important constraints
1323
+
1324
+ - Never call \`refresh_metadata\` before you have compared the ADR to the source files.
1325
+ - Never supersede without explicit user confirmation.
1326
+ - Do not rewrite the ADR into a new accepted state in this workflow. Supersession is a status flip plus a note; a replacement decision should be recorded separately with \`create-adr\`.
1327
+ `.trim();
1328
+ }
1329
+ case "create-adr": {
1330
+ const today = new Date().toISOString().slice(0, 10);
1331
+ const featureLine = args.featureSummary
1332
+ ? `The user described this feature as: **${args.featureSummary}**.`
1333
+ : "Identify in one sentence what was implemented or changed — that sentence becomes the ADR `description:`.";
1334
+ const filesLine = args.modifiedFiles
1335
+ ? `Files reported as modified by this feature: \`${args.modifiedFiles}\`. Verify each one is non-god before attaching.`
1336
+ : "Determine which source files materially carry this feature's logic (component, hook, service, route, schema, infra config). Exclude god files.";
1337
+ return `
1338
+ You are about to record an **ADR (Architecture Decision Record)** for a feature that has just been implemented or modified.
1339
+
1340
+ ${featureLine}
1341
+
1342
+ ## Step 1 — Search for an ADR to supersede
1343
+
1344
+ 1. Call \`list_documents\`.
1345
+ 2. Shortlist ADRs whose title or category looks topically related to the feature (cheap — just title + category strings).
1346
+ 3. \`read_document\` on the shortlisted ADRs and inspect their frontmatter (\`description\`, \`tags\`).
1347
+ 4. If an existing ADR is **made obsolete** by this feature:
1348
+ - \`read_document(id)\` to load its current Markdown.
1349
+ - Modify only the frontmatter: flip \`**status:**\` to \`SuperSeeded\` and add a one-line pointer just under the frontmatter (e.g. \`> Superseded by: <new ADR title>\`). Keep the body intact — supersede is a status flip, not a delete.
1350
+ - \`update_document(id, content)\` with the modified Markdown. Do **not** use \`create_document\` for this — it does not overwrite and will reject a colliding filename.
1351
+ 5. If no ADR is superseded, proceed.
1352
+
1353
+ ## Step 2 — Write the new ADR
1354
+
1355
+ Mandatory frontmatter at the very top of \`content\`:
1356
+
1357
+ \`\`\`
1358
+ ---
1359
+ **date:** ${today}
1360
+ **status:** To be validated
1361
+ **description:** One dense, technical sentence — what the decision does, not why.
1362
+ **tags:** 5–10 specific tags mixing concepts, technologies, and key symbol names
1363
+ ---
1364
+ \`\`\`
1365
+
1366
+ Rules (re-stated, do not skip):
1367
+ - \`status:\` is **always** \`To be validated\`. The human owner promotes to \`Accepted\` later — you do not.
1368
+ - \`description:\` is one sentence, factual, technical. The "why" goes in the body.
1369
+ - \`tags:\` are the primary search signal. Be specific: library names (\`stripe\`, \`amplify\`), domain concepts (\`workflow\`, \`moderation\`), symbol names where relevant (\`useAdScheduler\`, \`presigned-url\`).
1370
+ - Body sections (suggested): \`## Contexte\`, \`## Décision\`, \`## Conséquences\`.
1371
+
1372
+ Call \`create_document\` with:
1373
+ - \`title\` — short, lowercase, becomes the filename slug (e.g. \`ajout ressource storage s3\`).
1374
+ - \`category\` — domain bucket in the filename pattern, **uppercase**, e.g. \`SERVICES CLOUD\`, \`INTEGRATION\`, \`ALGORITHMES\`.
1375
+ - \`folder: "adrs"\` (or the project's ADR sub-folder).
1376
+ - \`content\` — frontmatter + body.
1377
+
1378
+ ## Step 3 — Bind the source files
1379
+
1380
+ For **each** source file that materially carries the feature's logic, call \`add_metadata(<new ADR id>, <relative path>)\`.
1381
+
1382
+ ${filesLine}
1383
+
1384
+ **Do NOT attach god files** — they would produce false-positive drift signals across many ADRs. Excluded by default:
1385
+ - Lock and manifest files: \`package.json\`, \`package-lock.json\`, \`yarn.lock\`, \`pnpm-lock.yaml\`, \`tsconfig.json\`, \`requirements.txt\`, \`Cargo.lock\`, \`go.sum\`.
1386
+ - Central re-export / barrel files, root routers, root stores, top-level app entry files (unless the ADR is about that file).
1387
+ - Auto-generated files (build outputs, codegen).
1388
+
1389
+ Rule of thumb: if a routine modification of the file would NOT reflect a semantic change of *this* feature, do not attach it.
1390
+
1391
+ ## Step 4 — Report
1392
+
1393
+ Tell the user:
1394
+ - The id and title of the new ADR (status \`To be validated\`, awaiting their review).
1395
+ - Whether any prior ADR was superseded — and which.
1396
+ - The list of source files attached as metadata.
1397
+ `.trim();
1398
+ }
1399
+ case "retrodocument-adrs-from-git": {
1400
+ const limitArg = (args.limit || "").trim();
1401
+ const sinceArg = (args.since || "").trim();
1402
+ const limitCallFragment = limitArg
1403
+ ? `"limit": ${Number(limitArg) || 100}`
1404
+ : '"limit": 100';
1405
+ const sinceCallFragment = sinceArg ? `, "since": "${sinceArg}"` : "";
1406
+ return `
1407
+ You are about to **retrodocument missing ADRs by walking recent git history**, oldest commit first, so that each durable architectural decision the project actually made gets a corresponding ADR.
1408
+
1409
+ This workflow exists when a project has accumulated significant code without ADRs (or with sparse ones) and the user wants to backfill that record.
1410
+
1411
+ ## Goal
1412
+
1413
+ For each git commit, decide whether it carries a **durable architectural decision** worth a new ADR — and, if so, write that ADR dated from the commit, attach the right source files, and supersede any earlier ADR that the commit obsoleted.
1414
+
1415
+ ## Step 1 — Prepare the retrodocumentation packet
1416
+
1417
+ Call \`retrodocument_adrs_from_git({ ${limitCallFragment}${sinceCallFragment} })\`.
1418
+
1419
+ The tool returns commits ordered **oldest first** with a precomputed \`state\` per commit:
1420
+ - \`candidate\` — has non-deleted, non-god source files under \`sourceRoot\`. Worth inspecting.
1421
+ - \`trivial\` — no source-bearing files (docs-only, formatting, config-only). Skip unless the subject clearly announces a decision.
1422
+ - \`merge\` — multi-parent merge. Skip unless the merge subject announces a documented decision the constituent commits did not.
1423
+
1424
+ If \`totalCommits === 0\`, tell the user there is no history to retrodocument and stop.
1425
+
1426
+ ## Step 2 — Read the existing ADR inventory
1427
+
1428
+ Call \`list_documents\`, shortlist ADRs (folder \`adrs\`, category \`ADR\`, or \`[ADR]\` in the id), and \`read_document\` the frontmatter (\`description\`, \`tags\`) of any whose topic could overlap the upcoming commits. You will need this to detect supersession candidates without re-listing for each commit.
1429
+
1430
+ ## Step 3 — Walk commits oldest → newest
1431
+
1432
+ For **each** commit returned by the tool, in order:
1433
+
1434
+ 1. **Filter cheaply**:
1435
+ - \`state === "trivial"\` and subject does not announce a decision → skip.
1436
+ - \`state === "merge"\` and the merge subject is generic ("Merge branch …") → skip.
1437
+ - Otherwise continue.
1438
+
1439
+ 2. **Read the evidence**: for each \`filesChanged\` entry where \`underSourceRoot === true\`, \`godFileSuspect === false\`, \`existsNow === true\`, and \`changeType !== "D"\`, call \`read_source_file(path)\`. Cap at ~5 files per commit — if there are more, pick the ones whose names suggest the feature core (component, service, route, schema, infra entry point) and skip the rest.
1440
+
1441
+ 3. **Judge — does this commit carry a durable architectural decision?** It does when the change:
1442
+ - moves an architectural boundary, or
1443
+ - introduces / modifies a public contract, or
1444
+ - changes a storage format, a protocol, a workflow, or
1445
+ - adds a convention later changes will respect, or
1446
+ - resolves a non-obvious trade-off the code alone does not explain.
1447
+
1448
+ It does **not** when the change is a trivial fix, a rename, a formatting pass, a doc tweak, a dependency bump without behaviour change, or a test-only addition.
1449
+
1450
+ 4. **Decide the outcome.**
1451
+
1452
+ ### Outcome A — Create a new ADR (no supersession)
1453
+
1454
+ The commit carries a fresh decision that no prior ADR covers.
1455
+
1456
+ 1. Compose the body, sections suggested: \`## Contexte\`, \`## Décision\`, \`## Conséquences\`. Write the description from the **commit subject + body**, never invented context. If the commit message is empty or unintelligible, downgrade to Outcome C and skip.
1457
+ 2. Mandatory frontmatter — **date comes from the commit**, not today:
1458
+
1459
+ \`\`\`
1460
+ ---
1461
+ **date:** <commit committerDate, YYYY-MM-DD slice>
1462
+ **status:** To be validated
1463
+ **description:** One dense, technical sentence — what the decision does, not why.
1464
+ **tags:** 5–10 specific tags mixing concepts, technologies, and key symbol names
1465
+ ---
1466
+ \`\`\`
1467
+
1468
+ 3. Call \`create_document\` with:
1469
+ - \`title\` — short, lowercase slug derived from the commit subject.
1470
+ - \`category\` — uppercase domain bucket (e.g. \`SERVICES CLOUD\`, \`INTEGRATION\`).
1471
+ - \`folder: "adrs"\` (or the project's ADR sub-folder).
1472
+ - \`date\` — the commit \`committerDate\` (the optional \`date\` argument exists precisely for this retrodocumentation case; **do not omit it here**).
1473
+ - \`content\` — frontmatter + body.
1474
+ 4. For every \`filesChanged\` entry that has \`underSourceRoot === true\`, \`godFileSuspect === false\`, and \`existsNow === true\`, call \`add_metadata(<new ADR id>, <path>)\`. Skip files where \`existsNow === false\` — those were since deleted and cannot be hashed; mention them in the body instead.
1475
+ 5. Call \`refresh_metadata(<new ADR id>)\` to baseline.
1476
+
1477
+ ### Outcome B — Supersede an earlier ADR, then create a new one
1478
+
1479
+ The commit modifies a decision recorded by an earlier ADR (either pre-existing or created in a previous iteration of this same loop).
1480
+
1481
+ 1. Identify the obsoleted ADR from the inventory built in Step 2 (or from ADRs you just created earlier in the walk).
1482
+ 2. \`read_document(<old id>)\` to load its current Markdown.
1483
+ 3. \`update_document(<old id>, <content>)\` flipping \`**status:**\` to exactly \`SuperSeeded\` and adding a one-line pointer just under the frontmatter (e.g. \`> Superseded by: <new ADR title> (commit <shortSha>)\`). Keep the body intact.
1484
+ 4. Then proceed with Outcome A to create the replacement ADR. In the new ADR's body, explicitly reference the superseded ADR title and explain why it no longer applies.
1485
+
1486
+ ### Outcome C — Skip
1487
+
1488
+ The commit is not durable enough (refactor, rename, fix, formatting, test, doc tweak) or its message is too thin to reliably describe.
1489
+
1490
+ Move on without writing anything. Log the skipped sha in your final report.
1491
+
1492
+ ## Step 4 — Stay in sync as you walk
1493
+
1494
+ After each Outcome A or B, **update your in-memory inventory** of ADRs to include the one you just created. Later commits in the walk must be able to detect "this commit obsoletes the ADR I created three commits ago".
1495
+
1496
+ ## Step 5 — Pace yourself
1497
+
1498
+ After the first 3 ADRs created (combined Outcomes A + B), pause and report progress to the user with: the ADRs created, the ADRs superseded, the next commit you are about to process. Wait for the user to confirm \`continue\` before resuming. This protects against runaway retrodocumentation when the LLM and the user disagree on what is "durable".
1499
+
1500
+ Subsequent batches of 5 may proceed without pause unless the user asks for a stop.
1501
+
1502
+ ## Step 6 — Final report
1503
+
1504
+ Once the walk is done, summarise:
1505
+ - N commits processed.
1506
+ - N ADRs created (list title + commit shortSha + date).
1507
+ - N ADRs superseded (list title + new ADR that replaced it).
1508
+ - N commits skipped as not durable (count only).
1509
+ - N commits where source files were already deleted — list shortSha so the user can audit manually.
1510
+
1511
+ ## Important constraints
1512
+
1513
+ - **Date comes from the commit, never from \`now()\`.** Pass the \`date\` argument to \`create_document\` and put the same date in the frontmatter.
1514
+ - **Never invent context.** If the commit subject + body + diff are insufficient to write a one-sentence \`description:\`, skip the commit (Outcome C). A bad ADR is worse than a missing one.
1515
+ - **Never attach god files.** \`godFileSuspect === true\` from the tool is a hard skip for metadata. Same for files where \`existsNow === false\` (they cannot be hashed).
1516
+ - **Never supersede silently.** Always include the explicit pointer (\`> Superseded by: …\`) under the frontmatter of the old ADR, and reference the old ADR by title from the new one's body.
1517
+ - **Order matters.** Process strictly oldest → newest so the supersession chain reads forward in time.
1518
+ - **Do not flip status to \`Accepted\`.** Every retrodocumented ADR ships at \`To be validated\` — only the human owner promotes.
1519
+ `.trim();
1520
+ }
1521
+ case "generate-context-diagram":
1522
+ return `
1523
+ ${PREAMBLE}
1524
+
1525
+ ---
1526
+
1527
+ You are about to create a **C4 System Context Diagram** following Simon Brown's C4 model.
1528
+
1529
+ ## Step 1 — Answer these three questions first (ask the user only if not found in docs)
1530
+
1531
+ 1. **Scope** — What is the software system we are describing?${args.scope ? ` (The user specified: **${args.scope}**.)` : " What is its name and primary responsibility?"}
1532
+ 2. **Users** — Who uses it? For each type of user: what are they doing with the system?
1533
+ 3. **Integrations** — What external systems does it need to integrate with? What data or interactions flow between them?
1534
+
1535
+ Do not proceed to the diagram until you have clear answers to all three.
1536
+
1537
+ ## Step 2 — Build the diagram
1538
+
1539
+ ### Layout rules (grid = 40 units, physics is disabled — positions are final)
1540
+ - **Main system** → center: x: 0, y: 0. Type: box. Color: c-blue.
1541
+ - **Human users (actors)** → left: x: -320, y: 0. Spread vertically by ±160 if several. Type: actor. Color: c-gray.
1542
+ - **External systems** → right: x: 320, y: 0. Spread vertically by ±160 if several. Type: box. Color: c-slate.
1543
+ - **External databases / datastores** → below: x: 0, y: 240. Type: database. Color: c-teal.
1544
+ - All positions must be multiples of 40.
1545
+ - Keep the diagram under ~10 nodes total.
1546
+
1547
+ ### Edge rules
1548
+ - Direction: actor → system, system → external system, system → datastore.
1549
+ - Every edge must have a label describing the interaction in plain language (e.g. "submits orders", "reads customer data", "sends notifications via").
1550
+
1551
+ ### Color palette
1552
+ | Element | Color |
1553
+ |---|---|
1554
+ | Main system | c-blue |
1555
+ | Human actor | c-gray |
1556
+ | External system | c-slate |
1557
+ | Datastore | c-teal |
1558
+
1559
+ ## Step 3 — Call \`create_diagram\` with \`diagramType: "context"\`.
1560
+ `.trim();
1561
+ case "generate-container-diagram":
1562
+ return `
1563
+ ${PREAMBLE}
1564
+
1565
+ ---
1566
+
1567
+ You are about to create a **C4 Container Diagram** following Simon Brown's C4 model.
1568
+
1569
+ ## ⚠️ Explicit-request check
1570
+ Only proceed if the user explicitly asked for a *container* diagram. If the request was generic ("a diagram", "the big picture"), stop and use \`generate-context-diagram\` instead.
1571
+
1572
+ ## ⚠️ Pre-flight check — mandatory before anything else
1573
+
1574
+ 1. Call \`list_diagrams\`.
1575
+ 2. If **no C4 Context diagram exists** for the target system → **stop here**.
1576
+ - Inform the user that a Context diagram must be created first.
1577
+ - Create the Context diagram using the \`generate-context-diagram\` prompt rules.
1578
+ - Do not create the Container diagram in this session.
1579
+ 3. Only proceed to the Container diagram if a Context diagram already exists.
1580
+
1581
+ ## Step 1 — Answer these questions first (ask the user only if not found in docs)
1582
+
1583
+ 1. **System** — Which system are we zooming into?
1584
+ 2. **Containers** — What are its internal containers (web app, mobile app, API, background worker, database, cache…)?
1585
+ 3. **Users** — Which users interact directly with which containers?
1586
+ 4. **Integrations** — Which external systems do the containers communicate with?
1587
+
1588
+ ## Step 2 — Build the diagram
1589
+
1590
+ ### Layout rules (grid = 40 units)
1591
+ Place containers in a logical left-to-right or top-to-bottom flow:
1592
+ - **Frontend / Browser / Mobile**: x: -320, y: 0. Type: box. Color: c-sky.
1593
+ - **API / Backend**: x: 0, y: 0. Type: box. Color: c-blue.
1594
+ - **Database**: x: 320, y: 80. Type: database. Color: c-teal.
1595
+ - **Cache / Queue**: x: 320, y: -80. Type: ellipse. Color: c-amber.
1596
+ - **External actor** (user): x: -560, y: 0. Type: actor. Color: c-gray.
1597
+ - **External system**: x: 0, y: 240. Type: box. Color: c-slate.
1598
+ - Spread additional containers vertically by multiples of 160.
1599
+ - All positions must be multiples of 40.
1600
+
1601
+ ### Edge rules
1602
+ - Label every edge with the protocol or action: "HTTPS", "SQL", "REST", "publishes", "subscribes"…
1603
+
1604
+ ## Step 3 — Call \`create_diagram\` with \`diagramType: "container"\` and \`userRequestedExplicitly: true\`.
1605
+ `.trim();
1606
+ case "generate-uml-diagram": {
1607
+ const umlType = (args.umlType || "").trim().toLowerCase() || "class";
1608
+ return `
1609
+ ${PREAMBLE}
1610
+
1611
+ ---
1612
+
1613
+ You are about to create a **UML ${umlType} diagram**.
1614
+
1615
+ ## ⚠️ Explicit-request check
1616
+ Only proceed if the user explicitly asked for a *UML* diagram by name. Otherwise use \`generate-context-diagram\` instead.
1617
+
1618
+ ## Step 1 — Gather the facts from docs
1619
+
1620
+ Read the documents relevant to the UML ${umlType} diagram. For each element you plan to put on the diagram, make sure it exists in the documentation. Do not invent classes, states, or actors absent from the docs.
1621
+
1622
+ ## Step 2 — Apply the UML ${umlType} conventions
1623
+
1624
+ ${umlTypeGuidance(umlType)}
1625
+
1626
+ ### Common rules (all UML variants)
1627
+ - Each edge must have a label describing the relationship or transition.
1628
+ - Keep labels short; use C4-style multi-line labels for class/component descriptions when helpful.
1629
+ - Use multiples of 40 for positions. Origin (0,0) = canvas center.
1630
+
1631
+ ## Step 3 — Call \`create_diagram\` with \`diagramType: "uml"\` and \`userRequestedExplicitly: true\`.
1632
+ `.trim();
1633
+ }
1634
+ case "update-diagram-from-docs":
1635
+ return `
1636
+ ${PREAMBLE}
1637
+
1638
+ ---
1639
+
1640
+ You are about to **update ${args.diagramId ? `diagram \`${args.diagramId}\`` : "all existing diagrams"}** to reflect the current state of the documentation.
1641
+
1642
+ ## Step 1 — Inventory existing diagrams
1643
+
1644
+ ${args.diagramId
1645
+ ? `1. Call \`read_diagram\` with id \`${args.diagramId}\` to load its current nodes and edges.`
1646
+ : `1. Call \`list_diagrams\` to get all diagrams with their id and title.
1647
+ 2. For each diagram, call \`read_diagram\` to load its current nodes and edges.`}
1648
+
1649
+ ## Step 2 — Gather current architecture knowledge
1650
+
1651
+ 1. Call \`list_documents\` to get all documents.
1652
+ 2. Read the documents that are architecturally significant (ADRs, README, guides with integration or architecture tags).
1653
+ 3. Ignore any document whose frontmatter contains \`status: SuperSeeded\`.
1654
+
1655
+ ## Step 3 — Compare and update
1656
+
1657
+ For each diagram in scope:
1658
+
1659
+ 1. **Identify the diagram type** from its title and content (Context, Container, Flow, ERD, UML…).
1660
+ 2. **Compare** its nodes and edges against the current documentation:
1661
+ - New containers, systems, or actors mentioned in the docs but missing?
1662
+ - Nodes that no longer exist or have been renamed?
1663
+ - Edge labels still accurate?
1664
+ 3. **If up to date** → skip it, report "no changes needed".
1665
+ 4. **If changes are needed** → call \`create_diagram\` with:
1666
+ - The **same \`id\`** as the existing diagram (overwrites it in place).
1667
+ - The same \`diagramType\`. For non-context types, include \`userRequestedExplicitly: true\` since the user is explicitly updating that diagram.
1668
+ - The same title unless a rename is warranted.
1669
+ - Updated nodes and edges, preserving \`x\`/\`y\` positions of unchanged nodes.
1670
+
1671
+ ## Step 4 — Report
1672
+
1673
+ Summarize which diagrams were updated (and what changed) and which were skipped (already up to date).
1674
+ `.trim();
1675
+ case "flow":
1676
+ return `
1677
+ ${PREAMBLE}
1678
+
1679
+ ---
1680
+
1681
+ You are about to create a **linear flow diagram**.
1682
+
1683
+ ## Step 1 — Answer these questions first (ask the user only if not found in docs)
1684
+
1685
+ 1. **Process** — What process or workflow are we representing?
1686
+ 2. **Steps** — What are the steps or stages in order?
1687
+ 3. **Actors** — Are there human actors or external systems involved at any step?
1688
+ 4. **Branches** — Are there decision points or alternative paths?
1689
+
1690
+ ## Step 2 — Build the diagram
1691
+
1692
+ ### Layout rules (grid = 40 units)
1693
+ - Steps are laid out **left to right**, each separated by 240 units on X.
1694
+ - All nodes at y: 0 unless a branch is needed (branch at y: ±160).
1695
+ - First step: x: -480. Then x: -240, x: 0, x: 240, x: 480… (adjust origin to center the flow).
1696
+ - Use type: box for process steps (color: c-blue), type: actor for human actors (color: c-gray), type: database for stores (color: c-teal).
1697
+ - Decision diamonds are not a native shape — use ellipse (color: c-amber) to indicate a decision point.
1698
+ - All positions must be multiples of 40.
1699
+
1700
+ ### Edge rules
1701
+ - Edges are directional left-to-right.
1702
+ - Label branches: "yes / no", "success / error", etc.
1703
+
1704
+ ## Step 3 — Call \`create_diagram\` with \`diagramType: "flow"\`.
1705
+ `.trim();
1706
+ case "erd":
1707
+ return `
1708
+ ${PREAMBLE}
1709
+
1710
+ ---
1711
+
1712
+ You are about to create an **Entity-Relationship Diagram**.
1713
+
1714
+ ## Step 1 — Answer these questions first (ask the user only if not found in docs)
1715
+
1716
+ 1. **Domain** — What domain or bounded context does this ERD cover?
1717
+ 2. **Entities** — What are the main entities (tables, aggregates)?
1718
+ 3. **Relationships** — What are the relationships between them and their cardinalities (1:1, 1:N, N:M)?
1719
+ 4. **Key attributes** — Are there important attributes worth labeling on the edges?
1720
+
1721
+ ## Step 2 — Build the diagram
1722
+
1723
+ ### Layout rules (grid = 40 units)
1724
+ - Each entity is a box. Place them so related entities are close together.
1725
+ - Suggested starting positions for up to 6 entities:
1726
+ - top-left: x: -320, y: -200
1727
+ - top-center: x: 0, y: -200
1728
+ - top-right: x: 320, y: -200
1729
+ - bottom-left: x: -320, y: 200
1730
+ - bottom-center: x: 0, y: 200
1731
+ - bottom-right: x: 320, y: 200
1732
+ - All positions must be multiples of 40.
1733
+ - Color: c-blue for main entities, c-green for junction/pivot tables, c-slate for lookup/reference tables.
1734
+
1735
+ ### Edge rules
1736
+ - Label every edge with the cardinality and nature of the relationship:
1737
+ "1:N", "N:M", "has many", "belongs to", "references", etc.
1738
+ - Edges are undirected by convention in ERDs — leave \`label\` descriptive.
1739
+
1740
+ ## Step 3 — Call \`create_diagram\` with \`diagramType: "erd"\`.
1741
+ `.trim();
1742
+ case "generate-screen-guide": {
1743
+ const screenFile = (args.screenFile || "").trim();
1744
+ const screenshotUrl = (args.screenshotUrl || "").trim();
1745
+ return `
1746
+ ## Screen-guide diagram — source code IS the reference
1747
+
1748
+ A screen guide is an annotated screenshot built in **three layers**:
1749
+ 1. the screenshot image as background,
1750
+ 2. translucent \`box\` overlays covering each major layout region (zones),
1751
+ 3. \`post-it\` callouts for each first-level feature, linked to the UI by
1752
+ free-end arrows.
1753
+
1754
+ **The source code is the authoritative reference**, not the Markdown docs.
1755
+ No ADR describes every button.
1756
+
1757
+ ## ⚠️ Explicit-request check
1758
+ Only proceed if the user explicitly asked for a *screen guide*, *UI guide*, or *annotated screenshot*.
1759
+
1760
+ ## Step 1 — Resolve the screen source
1761
+
1762
+ ${screenFile
1763
+ ? `The user specified \`${screenFile}\`. Call \`read_source_file\` with \`path: "${screenFile}"\`.`
1764
+ : `Ask the user which screen to document (e.g. \`src/frontend/index.html\`). Then call \`read_source_file\` on it.`}
1765
+
1766
+ If the screen pulls in components or partials, use \`search_source\` + \`read_source_file\` to follow them. Cap at ~5 files total — enough to identify zones and first-level features, not to trace every dependency.
1767
+
1768
+ ## Step 2 — Identify layout zones (YOU decide, do not ask)
1769
+
1770
+ Scan the screen structure for **major visual regions** that partition the layout. Typical zones:
1771
+ - Left / right sidebar or drawer
1772
+ - Top bar / header
1773
+ - Main content area
1774
+ - Footer
1775
+ - Right panel
1776
+
1777
+ Pick **2–5 zones**. For each zone, capture:
1778
+ - \`name\` — 1–3 words ("Top Bar", "Collapsible Drawer", "Main Page").
1779
+ - \`color\` — one distinct color per zone. Suggested rotation: \`c-red, c-amber, c-cyan, c-sky, c-lime, c-teal\`. Never reuse a color between two zones.
1780
+
1781
+ You will need the zone's bounding box on the screenshot (left/top/width/height in pixels) — you'll compute that once the user provides the screenshot.
1782
+
1783
+ ## Step 3 — Identify first-level features (YOU decide, do not ask)
1784
+
1785
+ A **first-level feature** is:
1786
+ - **Visible on screen** without any interaction (a button, toggle, input, primary navigation element, filter).
1787
+ - **Changes user-facing behavior significantly** when used (navigates, filters, toggles mode, opens a panel, searches).
1788
+
1789
+ NOT a first-level feature:
1790
+ - Decorative elements (logos, dividers, icons without action).
1791
+ - Controls nested inside a panel/modal that only appears after clicking something.
1792
+ - Pure labels / static text.
1793
+ - Duplicate controls (if the same action has two buttons, count it once).
1794
+
1795
+ Typical count: **4–10** features. Do not pad with minor buttons; do not omit obvious ones.
1796
+
1797
+ For each feature, capture:
1798
+ - \`name\` — 2–5 words, title-cased ("Collapsible Drawer", "Dark / Light Mode", "Text Search in all documents"). Multi-line via \`\\n\` allowed when needed.
1799
+ - \`kind\`:
1800
+ - \`interactive\` — standard button, link, input, toggle. **Default.**
1801
+ - \`differentiating\` — a feature that distinguishes the product from alternatives ("Professional Diagram Editor", "Word Cloud Generator"). Reserve for the 1–3 truly distinguishing features.
1802
+ - \`target\` — which UI element / zone it points to (used to place the anchor and the post-it).
1803
+
1804
+ **Color assignment for feature callouts:**
1805
+ - \`interactive\` → \`c-amber\` or \`c-orange\` (yellow family). Default.
1806
+ - \`differentiating\` → a distinct non-yellow color (\`c-purple\`, \`c-rose\`, \`c-red\`, \`c-sky\`, \`c-teal\`, \`c-green\`). Never yellow.
1807
+
1808
+ ## Step 4 — Request the screenshot and WAIT
1809
+
1810
+ Tell the user:
1811
+
1812
+ > I identified N zones and M first-level features in \`<file>\`:
1813
+ > - Zones: [comma-separated names]
1814
+ > - Features: [comma-separated names, annotated with "(diff)" for the differentiating ones]
1815
+ > I now need a screenshot of this screen. Two options:
1816
+ > (a) Save the PNG into \`./documentation/images/<name>.png\` inside your docs folder.
1817
+ > (b) Paste or drop the image into any existing diagram in the editor — it uploads automatically and returns a URL like \`/images/xxx.png\`.
1818
+ > Please reply with (1) the URL, and (2) the natural pixel width × height of the image.
1819
+
1820
+ **Then stop.** Do not call \`create_diagram\` yet.
1821
+
1822
+ ${screenshotUrl
1823
+ ? `(The user already provided \`${screenshotUrl}\` — you still need the pixel dimensions to place zones correctly.)`
1824
+ : ""}
1825
+
1826
+ ## Step 5 — Build the diagram
1827
+
1828
+ Coordinate system: screen-guide positions align to **screenshot pixels** (canvas centre is origin), NOT to the 40-unit grid. Use the pixel dimensions the user provided.
1829
+
1830
+ ### Nodes
1831
+
1832
+ **A. Background image** (one node, \`locked\`):
1833
+ \`\`\`json
1834
+ { "type": "image", "name": "screenshot", "imageSrc": "<URL>",
1835
+ "width": <imgW>, "height": <imgH>, "x": 0, "y": 0, "locked": true }
1836
+ \`\`\`
1837
+
1838
+ **B. Zone overlays** (one per zone, \`locked\`, translucent):
1839
+ \`\`\`json
1840
+ { "type": "box", "name": "", "color": "<zone color>",
1841
+ "bgOpacity": 0.18, "locked": true,
1842
+ "width": <zoneW>, "height": <zoneH>,
1843
+ "x": <zoneCenterX>, "y": <zoneCenterY> }
1844
+ \`\`\`
1845
+
1846
+ **C. Zone labels** (one post-it per zone, **same color as the zone**):
1847
+ \`\`\`json
1848
+ { "type": "post-it", "name": "<zone name>", "color": "<zone color>",
1849
+ "x": <inside zone>, "y": <inside zone>, "locked": true }
1850
+ \`\`\`
1851
+
1852
+ **D. Feature callouts** (one post-it per feature, placed **outside** the screenshot):
1853
+ \`\`\`json
1854
+ { "type": "post-it", "name": "<feature name>",
1855
+ "color": "<c-amber for interactive, distinct non-yellow for differentiating>",
1856
+ "x": <outside screenshot>, "y": <outside screenshot> }
1857
+ \`\`\`
1858
+ Spread them in horizontal bands above/below the image and/or vertical columns left/right of it. Keep callouts close to their target so the arrow reads naturally.
1859
+
1860
+ **E. Anchors** (one per feature callout, placed on the target pixel — 8×8, invisible at rest):
1861
+ \`\`\`json
1862
+ { "type": "anchor", "name": "a1", "color": "c-gray",
1863
+ "x": <target pixel x>, "y": <target pixel y> }
1864
+ \`\`\`
1865
+ Use short unique names (\`a1\`, \`a2\`, …) — anchors are invisible so the label does not matter.
1866
+
1867
+ ### Edges
1868
+
1869
+ For each feature callout, emit one directed edge from the post-it to its anchor, with an **empty** label:
1870
+ \`\`\`json
1871
+ { "from": "<post-it name>", "to": "a1", "label": "" }
1872
+ \`\`\`
1873
+
1874
+ If you do not know exact target coordinates, you may omit the anchor and the \`to\` field — the edge renders a free-end arrow the user can drag:
1875
+ \`\`\`json
1876
+ { "from": "<post-it name>", "label": "" }
1877
+ \`\`\`
1878
+
1879
+ **Prefer anchors.** The free-end fallback is a shortcut when pixel targets are unknown.
1880
+
1881
+ **Never** point edges at the image node itself — every arrow would converge on the image centre.
1882
+
1883
+ ## Step 6 — Call \`create_diagram\`
1884
+
1885
+ \`\`\`json
1886
+ {
1887
+ "diagramType": "screen-guide",
1888
+ "userRequestedExplicitly": true,
1889
+ "title": "Screen guide — <screen name>",
1890
+ "nodes": [ /* image + zone boxes + zone labels + feature callouts + anchors */ ],
1891
+ "edges": [ /* one edge per feature callout → its anchor */ ]
1892
+ }
1893
+ \`\`\`
1894
+ `.trim();
1895
+ }
1896
+ }
1897
+ }
1898
+ function umlTypeGuidance(umlType) {
1899
+ switch (umlType) {
1900
+ case "class":
1901
+ return `### UML class diagram
1902
+ - Each class is a \`box\` (c-blue for domain classes, c-green for value objects, c-slate for interfaces).
1903
+ - Node label: \`ClassName\\n[Class]\\n+ attr: Type\\n+ method(): Type\`.
1904
+ - Edges: label relationships as "extends", "implements", "has 1", "has *", "uses".`;
1905
+ case "sequence":
1906
+ return `### UML sequence diagram
1907
+ - Each participant is a \`box\` (c-blue for systems, c-gray for actors).
1908
+ - Arrange participants left-to-right at the same y (spacing 200).
1909
+ - Edges are messages; the label is the method/event name and uses arrows top-down by ordering the edges in the array chronologically.`;
1910
+ case "state":
1911
+ return `### UML state diagram
1912
+ - Each state is an \`ellipse\` (c-amber).
1913
+ - Start and end states are \`circle\` (c-slate for end, c-green for start).
1914
+ - Edges are transitions; label with the event/trigger.`;
1915
+ case "activity":
1916
+ return `### UML activity diagram
1917
+ - Activities are \`box\` (c-blue).
1918
+ - Decision nodes are \`ellipse\` (c-amber).
1919
+ - Start/end are \`circle\` (c-green/c-slate).
1920
+ - Edges labeled with the guard or action.`;
1921
+ case "use-case":
1922
+ case "usecase":
1923
+ return `### UML use-case diagram
1924
+ - Actors are \`actor\` (c-gray) on the left (x: -320).
1925
+ - Use cases are \`ellipse\` (c-blue) in the center.
1926
+ - The system boundary is implied by grouping — no explicit box needed.
1927
+ - Edges between actor and use case labeled with the action ("initiates", "participates in").`;
1928
+ default:
1929
+ return `### UML ${umlType} diagram\nFollow the standard UML conventions for \`${umlType}\` diagrams. Use \`box\`, \`ellipse\`, \`actor\`, \`circle\`, or \`database\` shapes as appropriate; label every edge.`;
1930
+ }
1931
+ }
1932
+ function createMcpServer(docsPath) {
1933
+ const server = new index_js_1.Server({ name: "living-ai-documentation", version: "1.2.0" }, {
1934
+ capabilities: { tools: {}, prompts: {} },
1935
+ instructions: SERVER_GUIDE,
1936
+ });
1937
+ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
1938
+ tools: TOOLS,
1939
+ }));
1940
+ server.setRequestHandler(types_js_1.ListPromptsRequestSchema, async () => ({
1941
+ prompts: PROMPTS,
1942
+ }));
1943
+ server.setRequestHandler(types_js_1.GetPromptRequestSchema, async (request) => {
1944
+ const name = request.params.name;
1945
+ const prompt = PROMPTS.find((p) => p.name === name);
1946
+ if (!prompt)
1947
+ throw new Error(`Unknown prompt: ${name}`);
1948
+ const args = (request.params.arguments ?? {});
1949
+ const text = buildPromptTemplate(name, args);
1950
+ return {
1951
+ description: prompt.description,
1952
+ messages: [
1953
+ { role: "user", content: { type: "text", text } },
1954
+ ],
1955
+ };
1956
+ });
1957
+ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
1958
+ const { name, arguments: args = {} } = request.params;
1959
+ try {
1960
+ switch (name) {
1961
+ case "get_server_guide":
1962
+ return { content: [{ type: "text", text: SERVER_GUIDE }] };
1963
+ case "list_documents":
1964
+ return (0, documents_1.toolListDocuments)(docsPath);
1965
+ case "read_document":
1966
+ return (0, documents_1.toolReadDocument)(docsPath, args);
1967
+ case "create_document":
1968
+ return (0, documents_1.toolCreateDocument)(docsPath, args);
1969
+ case "update_document":
1970
+ return (0, documents_1.toolUpdateDocument)(docsPath, args);
1971
+ case "list_diagrams":
1972
+ return (0, diagrams_1.toolListDiagrams)(docsPath);
1973
+ case "read_diagram":
1974
+ return (0, diagrams_1.toolReadDiagram)(docsPath, args);
1975
+ case "create_diagram":
1976
+ return (0, diagrams_1.toolCreateDiagram)(docsPath, args);
1977
+ case "list_source_files":
1978
+ return (0, source_1.toolListSourceFiles)(docsPath, args);
1979
+ case "read_source_file":
1980
+ return (0, source_1.toolReadSourceFile)(docsPath, args);
1981
+ case "search_source":
1982
+ return (0, source_1.toolSearchSource)(docsPath, args);
1983
+ case "list_metadata":
1984
+ return (0, metadata_1.toolListMetadata)(docsPath, args);
1985
+ case "get_accuracy":
1986
+ return (0, metadata_1.toolGetAccuracy)(docsPath, args);
1987
+ case "review_adr_relevance":
1988
+ return (0, metadata_1.toolReviewAdrRelevance)(docsPath, args);
1989
+ case "refresh_metadata":
1990
+ return (0, metadata_1.toolRefreshMetadata)(docsPath, args);
1991
+ case "add_metadata":
1992
+ return (0, metadata_1.toolAddMetadata)(docsPath, args);
1993
+ case "remove_metadata":
1994
+ return (0, metadata_1.toolRemoveMetadata)(docsPath, args);
1995
+ case "list_adrs_below_accuracy":
1996
+ return (0, metadata_1.toolListAdrsBelowAccuracy)(docsPath);
1997
+ case "retrodocument_adrs_from_git":
1998
+ return (0, git_1.toolRetrodocumentAdrsFromGit)(docsPath, args);
1999
+ default:
2000
+ throw new Error(`Unknown tool: ${name}`);
2001
+ }
2002
+ }
2003
+ catch (err) {
2004
+ return {
2005
+ content: [
2006
+ {
2007
+ type: "text",
2008
+ text: `Error: ${err instanceof Error ? err.message : String(err)}`,
2009
+ },
2010
+ ],
2011
+ isError: true,
2012
+ };
2013
+ }
2014
+ });
2015
+ return server;
2016
+ }
2017
+ function mcpRouter(docsPath) {
2018
+ const router = (0, express_1.Router)();
2019
+ // Main MCP endpoint — stateless: one Server + Transport per request
2020
+ router.post("/", async (req, res) => {
2021
+ const server = createMcpServer(docsPath);
2022
+ const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
2023
+ sessionIdGenerator: undefined,
2024
+ });
2025
+ try {
2026
+ await server.connect(transport);
2027
+ await transport.handleRequest(req, res, req.body);
2028
+ }
2029
+ finally {
2030
+ await server.close();
2031
+ }
2032
+ });
2033
+ // GET — surface a helpful message (Claude Desktop / browser landing)
2034
+ router.get("/", (_req, res) => {
2035
+ res.json({
2036
+ mcp: "living-ai-documentation",
2037
+ version: "1.2.0",
2038
+ transport: "streamable-http",
2039
+ endpoint: "POST /mcp",
2040
+ tools: TOOLS,
2041
+ prompts: PROMPTS,
2042
+ });
2043
+ });
2044
+ return router;
2045
+ }
2046
+ //# sourceMappingURL=server.js.map