@kinqs/brainrouter-mcp-server 0.3.4

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 (337) hide show
  1. package/.env.example +144 -0
  2. package/README.md +56 -0
  3. package/agents/README.md +120 -0
  4. package/agents/code-reviewer.md +97 -0
  5. package/agents/security-auditor.md +101 -0
  6. package/agents/test-engineer.md +95 -0
  7. package/dist/__tests__/agent_mode.test.d.ts +1 -0
  8. package/dist/__tests__/api-routes.test.d.ts +1 -0
  9. package/dist/__tests__/api-routes.test.js +170 -0
  10. package/dist/__tests__/crypto.test.d.ts +1 -0
  11. package/dist/__tests__/crypto.test.js +28 -0
  12. package/dist/__tests__/host-integrations.test.d.ts +1 -0
  13. package/dist/__tests__/host-integrations.test.js +82 -0
  14. package/dist/__tests__/integration.test.d.ts +1 -0
  15. package/dist/__tests__/integration.test.js +50 -0
  16. package/dist/__tests__/loader.test.d.ts +1 -0
  17. package/dist/__tests__/loader.test.js +89 -0
  18. package/dist/__tests__/neural-spark.test.d.ts +1 -0
  19. package/dist/__tests__/neural-spark.test.js +112 -0
  20. package/dist/__tests__/pagination.test.d.ts +1 -0
  21. package/dist/__tests__/pagination.test.js +23 -0
  22. package/dist/__tests__/redaction.test.d.ts +1 -0
  23. package/dist/__tests__/redaction.test.js +17 -0
  24. package/dist/__tests__/registry.test.d.ts +1 -0
  25. package/dist/__tests__/registry.test.js +56 -0
  26. package/dist/__tests__/retry.test.d.ts +1 -0
  27. package/dist/__tests__/retry.test.js +30 -0
  28. package/dist/__tests__/skill-activation.test.d.ts +1 -0
  29. package/dist/__tests__/skill-activation.test.js +112 -0
  30. package/dist/__tests__/working-memory.test.d.ts +1 -0
  31. package/dist/__tests__/working-memory.test.js +200 -0
  32. package/dist/__tests__/workspace-paths.test.d.ts +1 -0
  33. package/dist/__tests__/workspace-paths.test.js +56 -0
  34. package/dist/__tests__/writer.test.d.ts +1 -0
  35. package/dist/__tests__/writer.test.js +94 -0
  36. package/dist/api/auth/crypto.d.ts +4 -0
  37. package/dist/api/auth/crypto.js +54 -0
  38. package/dist/api/middleware/auth.d.ts +12 -0
  39. package/dist/api/middleware/auth.js +90 -0
  40. package/dist/api/pagination.d.ts +18 -0
  41. package/dist/api/pagination.js +32 -0
  42. package/dist/api/routes/auth.d.ts +1 -0
  43. package/dist/api/routes/auth.js +130 -0
  44. package/dist/api/routes/chat-completions.d.ts +7 -0
  45. package/dist/api/routes/chat-completions.js +474 -0
  46. package/dist/api/routes/contradictions.d.ts +1 -0
  47. package/dist/api/routes/contradictions.js +28 -0
  48. package/dist/api/routes/evidence.d.ts +1 -0
  49. package/dist/api/routes/evidence.js +59 -0
  50. package/dist/api/routes/governance.d.ts +1 -0
  51. package/dist/api/routes/governance.js +95 -0
  52. package/dist/api/routes/graph.d.ts +1 -0
  53. package/dist/api/routes/graph.js +25 -0
  54. package/dist/api/routes/hooks.d.ts +1 -0
  55. package/dist/api/routes/hooks.js +88 -0
  56. package/dist/api/routes/memories.d.ts +1 -0
  57. package/dist/api/routes/memories.js +92 -0
  58. package/dist/api/routes/persona.d.ts +1 -0
  59. package/dist/api/routes/persona.js +9 -0
  60. package/dist/api/routes/scenes.d.ts +1 -0
  61. package/dist/api/routes/scenes.js +35 -0
  62. package/dist/api/routes/skills.d.ts +1 -0
  63. package/dist/api/routes/skills.js +14 -0
  64. package/dist/api/routes/stats.d.ts +1 -0
  65. package/dist/api/routes/stats.js +8 -0
  66. package/dist/api/routes/users.d.ts +1 -0
  67. package/dist/api/routes/users.js +82 -0
  68. package/dist/api/routes/working.d.ts +1 -0
  69. package/dist/api/routes/working.js +88 -0
  70. package/dist/index.d.ts +2 -0
  71. package/dist/index.js +492 -0
  72. package/dist/integrations/claude-code.d.ts +12 -0
  73. package/dist/integrations/claude-code.js +35 -0
  74. package/dist/integrations/codex.d.ts +12 -0
  75. package/dist/integrations/codex.js +34 -0
  76. package/dist/integrations/generic-mcp.d.ts +52 -0
  77. package/dist/integrations/generic-mcp.js +118 -0
  78. package/dist/loader.d.ts +29 -0
  79. package/dist/loader.js +200 -0
  80. package/dist/memory/capture.d.ts +35 -0
  81. package/dist/memory/capture.js +230 -0
  82. package/dist/memory/config.d.ts +2 -0
  83. package/dist/memory/config.js +3 -0
  84. package/dist/memory/engine.d.ts +203 -0
  85. package/dist/memory/engine.js +626 -0
  86. package/dist/memory/llm-semaphore.d.ts +41 -0
  87. package/dist/memory/llm-semaphore.js +81 -0
  88. package/dist/memory/memory-type-config.d.ts +11 -0
  89. package/dist/memory/memory-type-config.js +65 -0
  90. package/dist/memory/pipeline/cognitive-contradiction.d.ts +7 -0
  91. package/dist/memory/pipeline/cognitive-contradiction.js +59 -0
  92. package/dist/memory/pipeline/cognitive-dedup.d.ts +23 -0
  93. package/dist/memory/pipeline/cognitive-dedup.js +38 -0
  94. package/dist/memory/pipeline/cognitive-extractor.d.ts +21 -0
  95. package/dist/memory/pipeline/cognitive-extractor.js +183 -0
  96. package/dist/memory/pipeline/contextual-focus-builder.d.ts +13 -0
  97. package/dist/memory/pipeline/contextual-focus-builder.js +135 -0
  98. package/dist/memory/pipeline/focus-direction-shift.d.ts +10 -0
  99. package/dist/memory/pipeline/focus-direction-shift.js +27 -0
  100. package/dist/memory/pipeline/graph-builder.d.ts +11 -0
  101. package/dist/memory/pipeline/graph-builder.js +88 -0
  102. package/dist/memory/pipeline/graph-recall.d.ts +13 -0
  103. package/dist/memory/pipeline/graph-recall.js +55 -0
  104. package/dist/memory/pipeline/identity-distiller.d.ts +15 -0
  105. package/dist/memory/pipeline/identity-distiller.js +40 -0
  106. package/dist/memory/pipeline/l1-contradiction.d.ts +7 -0
  107. package/dist/memory/pipeline/l1-contradiction.js +66 -0
  108. package/dist/memory/pipeline/l1-dedup.d.ts +23 -0
  109. package/dist/memory/pipeline/l1-dedup.js +39 -0
  110. package/dist/memory/pipeline/l1-extractor.d.ts +21 -0
  111. package/dist/memory/pipeline/l1-extractor.js +180 -0
  112. package/dist/memory/pipeline/l2-direction-shift.d.ts +10 -0
  113. package/dist/memory/pipeline/l2-direction-shift.js +27 -0
  114. package/dist/memory/pipeline/l2-scene.d.ts +15 -0
  115. package/dist/memory/pipeline/l2-scene.js +140 -0
  116. package/dist/memory/pipeline/l3-distiller.d.ts +15 -0
  117. package/dist/memory/pipeline/l3-distiller.js +40 -0
  118. package/dist/memory/pipeline/neural-spark.d.ts +27 -0
  119. package/dist/memory/pipeline/neural-spark.js +78 -0
  120. package/dist/memory/pipeline/skill-prewarm.d.ts +63 -0
  121. package/dist/memory/pipeline/skill-prewarm.js +127 -0
  122. package/dist/memory/pipeline/task-queue.d.ts +54 -0
  123. package/dist/memory/pipeline/task-queue.js +117 -0
  124. package/dist/memory/prompts/cognitive-contradiction.d.ts +1 -0
  125. package/dist/memory/prompts/cognitive-contradiction.js +25 -0
  126. package/dist/memory/prompts/cognitive-extraction.d.ts +10 -0
  127. package/dist/memory/prompts/cognitive-extraction.js +114 -0
  128. package/dist/memory/prompts/core-identity.d.ts +6 -0
  129. package/dist/memory/prompts/core-identity.js +60 -0
  130. package/dist/memory/prompts/focus-direction-shift.d.ts +5 -0
  131. package/dist/memory/prompts/focus-direction-shift.js +32 -0
  132. package/dist/memory/prompts/focus-scene-cluster.d.ts +2 -0
  133. package/dist/memory/prompts/focus-scene-cluster.js +33 -0
  134. package/dist/memory/prompts/focus-scene.d.ts +7 -0
  135. package/dist/memory/prompts/focus-scene.js +40 -0
  136. package/dist/memory/prompts/graph-extraction-batch.d.ts +14 -0
  137. package/dist/memory/prompts/graph-extraction-batch.js +54 -0
  138. package/dist/memory/prompts/graph-extraction.d.ts +2 -0
  139. package/dist/memory/prompts/graph-extraction.js +53 -0
  140. package/dist/memory/prompts/l1-contradiction-batch.d.ts +16 -0
  141. package/dist/memory/prompts/l1-contradiction-batch.js +47 -0
  142. package/dist/memory/prompts/l1-contradiction.d.ts +1 -0
  143. package/dist/memory/prompts/l1-contradiction.js +25 -0
  144. package/dist/memory/prompts/l1-extraction.d.ts +10 -0
  145. package/dist/memory/prompts/l1-extraction.js +114 -0
  146. package/dist/memory/prompts/l2-direction-shift.d.ts +5 -0
  147. package/dist/memory/prompts/l2-direction-shift.js +32 -0
  148. package/dist/memory/prompts/l2-scene-cluster.d.ts +2 -0
  149. package/dist/memory/prompts/l2-scene-cluster.js +33 -0
  150. package/dist/memory/prompts/l2-scene.d.ts +7 -0
  151. package/dist/memory/prompts/l2-scene.js +40 -0
  152. package/dist/memory/prompts/l3-persona.d.ts +6 -0
  153. package/dist/memory/prompts/l3-persona.js +60 -0
  154. package/dist/memory/recall.d.ts +47 -0
  155. package/dist/memory/recall.js +427 -0
  156. package/dist/memory/redaction.d.ts +1 -0
  157. package/dist/memory/redaction.js +24 -0
  158. package/dist/memory/retry.d.ts +13 -0
  159. package/dist/memory/retry.js +53 -0
  160. package/dist/memory/scheduler.d.ts +9 -0
  161. package/dist/memory/scheduler.js +16 -0
  162. package/dist/memory/skill-hints-loader.d.ts +30 -0
  163. package/dist/memory/skill-hints-loader.js +100 -0
  164. package/dist/memory/store/embedding.d.ts +16 -0
  165. package/dist/memory/store/embedding.js +68 -0
  166. package/dist/memory/store/reranker.d.ts +24 -0
  167. package/dist/memory/store/reranker.js +83 -0
  168. package/dist/memory/store/sqlite.d.ts +167 -0
  169. package/dist/memory/store/sqlite.js +1816 -0
  170. package/dist/memory/store/types.d.ts +101 -0
  171. package/dist/memory/store/types.js +1 -0
  172. package/dist/memory/types.d.ts +207 -0
  173. package/dist/memory/types.js +7 -0
  174. package/dist/memory/validation.d.ts +441 -0
  175. package/dist/memory/validation.js +129 -0
  176. package/dist/memory/working/canvas.d.ts +5 -0
  177. package/dist/memory/working/canvas.js +43 -0
  178. package/dist/memory/working/offload.d.ts +71 -0
  179. package/dist/memory/working/offload.js +211 -0
  180. package/dist/memory/working/step-log.d.ts +16 -0
  181. package/dist/memory/working/step-log.js +35 -0
  182. package/dist/registry.d.ts +34 -0
  183. package/dist/registry.js +305 -0
  184. package/dist/resolver.d.ts +17 -0
  185. package/dist/resolver.js +126 -0
  186. package/dist/scripts/validate-foreign-workspace-path.d.ts +1 -0
  187. package/dist/scripts/validate-foreign-workspace-path.js +39 -0
  188. package/dist/tools/agent_memory_tools.d.ts +485 -0
  189. package/dist/tools/agent_memory_tools.js +793 -0
  190. package/dist/tools/create_skill.d.ts +46 -0
  191. package/dist/tools/create_skill.js +46 -0
  192. package/dist/tools/get_doc.d.ts +21 -0
  193. package/dist/tools/get_doc.js +24 -0
  194. package/dist/tools/get_persona.d.ts +15 -0
  195. package/dist/tools/get_persona.js +20 -0
  196. package/dist/tools/get_reference.d.ts +15 -0
  197. package/dist/tools/get_reference.js +20 -0
  198. package/dist/tools/get_skill.d.ts +34 -0
  199. package/dist/tools/get_skill.js +65 -0
  200. package/dist/tools/get_template_doc.d.ts +21 -0
  201. package/dist/tools/get_template_doc.js +24 -0
  202. package/dist/tools/list_docs.d.ts +15 -0
  203. package/dist/tools/list_docs.js +16 -0
  204. package/dist/tools/list_skills.d.ts +18 -0
  205. package/dist/tools/list_skills.js +17 -0
  206. package/dist/tools/list_template_docs.d.ts +15 -0
  207. package/dist/tools/list_template_docs.js +16 -0
  208. package/dist/tools/memory-engineering.d.ts +225 -0
  209. package/dist/tools/memory-engineering.js +284 -0
  210. package/dist/tools/memory-explain.d.ts +34 -0
  211. package/dist/tools/memory-explain.js +109 -0
  212. package/dist/tools/memory-governance.d.ts +171 -0
  213. package/dist/tools/memory-governance.js +224 -0
  214. package/dist/tools/memory-hooks.d.ts +67 -0
  215. package/dist/tools/memory-hooks.js +102 -0
  216. package/dist/tools/memory-working.d.ts +98 -0
  217. package/dist/tools/memory-working.js +101 -0
  218. package/dist/tools/memory_capture_turn.d.ts +66 -0
  219. package/dist/tools/memory_capture_turn.js +85 -0
  220. package/dist/tools/memory_consolidate.d.ts +55 -0
  221. package/dist/tools/memory_consolidate.js +176 -0
  222. package/dist/tools/memory_contradictions.d.ts +53 -0
  223. package/dist/tools/memory_contradictions.js +52 -0
  224. package/dist/tools/memory_graph_query.d.ts +51 -0
  225. package/dist/tools/memory_graph_query.js +35 -0
  226. package/dist/tools/memory_mark_cited.d.ts +43 -0
  227. package/dist/tools/memory_mark_cited.js +63 -0
  228. package/dist/tools/memory_recall.d.ts +77 -0
  229. package/dist/tools/memory_recall.js +81 -0
  230. package/dist/tools/memory_register_skill_hints.d.ts +49 -0
  231. package/dist/tools/memory_register_skill_hints.js +55 -0
  232. package/dist/tools/memory_resolve_session.d.ts +24 -0
  233. package/dist/tools/memory_resolve_session.js +133 -0
  234. package/dist/tools/memory_search.d.ts +146 -0
  235. package/dist/tools/memory_search.js +84 -0
  236. package/dist/tools/search_skills.d.ts +18 -0
  237. package/dist/tools/search_skills.js +17 -0
  238. package/dist/tools/update_doc.d.ts +24 -0
  239. package/dist/tools/update_doc.js +35 -0
  240. package/dist/tools/update_skill.d.ts +30 -0
  241. package/dist/tools/update_skill.js +80 -0
  242. package/dist/types.d.ts +81 -0
  243. package/dist/types.js +4 -0
  244. package/dist/writer.d.ts +30 -0
  245. package/dist/writer.js +220 -0
  246. package/docs/TEMPLATE ONLY +1 -0
  247. package/docs/api/API.md +64 -0
  248. package/docs/api/security/SECURITY.md +58 -0
  249. package/docs/deployment/DockerDeployment.md +30 -0
  250. package/docs/design/Design.md +59 -0
  251. package/docs/design/themes/apple.md +101 -0
  252. package/docs/design/themes/dieter-grid.md +100 -0
  253. package/docs/design/themes/gallery-white.md +100 -0
  254. package/docs/design/themes/pinterest.md +101 -0
  255. package/docs/design/themes/realty-open-house.md +101 -0
  256. package/docs/design/themes/vodafone.md +101 -0
  257. package/docs/hooks/Hooks.md +30 -0
  258. package/docs/schema/Schema.md +35 -0
  259. package/docs/strategy/ScalingStrategy.md +19 -0
  260. package/package.json +88 -0
  261. package/references/accessibility-checklist.md +160 -0
  262. package/references/orchestration-patterns.md +370 -0
  263. package/references/performance-checklist.md +153 -0
  264. package/references/security-checklist.md +134 -0
  265. package/references/testing-patterns.md +236 -0
  266. package/skills/agent/adr-skill/SKILL.md +299 -0
  267. package/skills/agent/agentic-engineering-workflow/SKILL.md +95 -0
  268. package/skills/agent/bootstrap-skill/SKILL.md +103 -0
  269. package/skills/agent/context-engineering/SKILL.md +307 -0
  270. package/skills/agent/debugging-and-error-recovery/SKILL.md +308 -0
  271. package/skills/agent/developer-growth-analysis/SKILL.md +328 -0
  272. package/skills/agent/doubt-driven-skill/SKILL.md +249 -0
  273. package/skills/agent/handover-skill/SKILL.md +112 -0
  274. package/skills/agent/idea-refine-skill/SKILL.md +185 -0
  275. package/skills/agent/idea-refine-skill/examples.md +238 -0
  276. package/skills/agent/idea-refine-skill/frameworks.md +99 -0
  277. package/skills/agent/idea-refine-skill/refinement-criteria.md +113 -0
  278. package/skills/agent/interview-skill/SKILL.md +226 -0
  279. package/skills/agent/planning-skill/SKILL.md +270 -0
  280. package/skills/agent/skill-authoring/SKILL.md +189 -0
  281. package/skills/agent/source-driven-skill/SKILL.md +197 -0
  282. package/skills/agent/spec-driven-skill/SKILL.md +221 -0
  283. package/skills/agent/sync-skill/SKILL.md +92 -0
  284. package/skills/agent/using-agent-skills/SKILL.md +189 -0
  285. package/skills/api/a11y-skill/SKILL.md +88 -0
  286. package/skills/api/api-skill/SKILL.md +123 -0
  287. package/skills/api/auth-skill/SKILL.md +80 -0
  288. package/skills/api/debug-skill/SKILL.md +535 -0
  289. package/skills/api/performance-skill/SKILL.md +100 -0
  290. package/skills/api/testing-skill/SKILL.md +100 -0
  291. package/skills/codebase/code-review-and-quality/SKILL.md +228 -0
  292. package/skills/codebase/code-simplification/SKILL.md +352 -0
  293. package/skills/codebase/code-structure-cleanup/SKILL.md +142 -0
  294. package/skills/codebase/concerns-skill/SKILL.md +89 -0
  295. package/skills/codebase/conventions-skill/SKILL.md +95 -0
  296. package/skills/codebase/doc-management-skill/SKILL.md +47 -0
  297. package/skills/codebase/git-workflow-skill/SKILL.md +312 -0
  298. package/skills/communication/1-3-1-rule/SKILL.md +120 -0
  299. package/skills/design/brutalist-skill/SKILL.md +131 -0
  300. package/skills/design/concept-diagrams/SKILL.md +387 -0
  301. package/skills/design/concept-diagrams/examples/apartment-floor-plan-conversion.md +244 -0
  302. package/skills/design/concept-diagrams/examples/automated-password-reset-flow.md +276 -0
  303. package/skills/design/concept-diagrams/examples/autonomous-llm-research-agent-flow.md +240 -0
  304. package/skills/design/concept-diagrams/examples/banana-journey-tree-to-smoothie.md +161 -0
  305. package/skills/design/concept-diagrams/examples/commercial-aircraft-structure.md +209 -0
  306. package/skills/design/concept-diagrams/examples/cpu-ooo-microarchitecture.md +236 -0
  307. package/skills/design/concept-diagrams/examples/electricity-grid-flow.md +182 -0
  308. package/skills/design/concept-diagrams/examples/feature-film-production-pipeline.md +172 -0
  309. package/skills/design/concept-diagrams/examples/hospital-emergency-department-flow.md +165 -0
  310. package/skills/design/concept-diagrams/examples/ml-benchmark-grouped-bar-chart.md +114 -0
  311. package/skills/design/concept-diagrams/examples/place-order-uml-sequence.md +325 -0
  312. package/skills/design/concept-diagrams/examples/smart-city-infrastructure.md +173 -0
  313. package/skills/design/concept-diagrams/examples/smartphone-layer-anatomy.md +154 -0
  314. package/skills/design/concept-diagrams/examples/sn2-reaction-mechanism.md +247 -0
  315. package/skills/design/concept-diagrams/examples/wind-turbine-structure.md +338 -0
  316. package/skills/design/concept-diagrams/references/dashboard-patterns.md +43 -0
  317. package/skills/design/concept-diagrams/references/infrastructure-patterns.md +144 -0
  318. package/skills/design/concept-diagrams/references/physical-shape-cookbook.md +42 -0
  319. package/skills/design/concept-diagrams/templates/template.html +174 -0
  320. package/skills/design/gpt-tasteskill/SKILL.md +114 -0
  321. package/skills/design/minimalist-skill/SKILL.md +116 -0
  322. package/skills/design/output-skill/SKILL.md +87 -0
  323. package/skills/design/redesign-skill/SKILL.md +213 -0
  324. package/skills/design/soft-skill/SKILL.md +132 -0
  325. package/skills/design/stitch-skill/EXAMPLE.md +121 -0
  326. package/skills/design/stitch-skill/SKILL.md +222 -0
  327. package/skills/design/taste-skill/SKILL.md +269 -0
  328. package/skills/devops/ci-cd-skill/SKILL.md +402 -0
  329. package/skills/devops/docker-skill/SKILL.md +297 -0
  330. package/skills/devops/domain-skill/SKILL.md +234 -0
  331. package/skills/lifecycle/changelog-generator/SKILL.md +135 -0
  332. package/skills/lifecycle/incremental-skill/SKILL.md +257 -0
  333. package/skills/lifecycle/migration-skill/SKILL.md +218 -0
  334. package/skills/lifecycle/shipping-skill/SKILL.md +321 -0
  335. package/skills/memory/agent-memory/SKILL.md +122 -0
  336. package/skills/qa/browser-testing-skill/SKILL.md +314 -0
  337. package/skills/ux/adversarial-ux-skill/SKILL.md +168 -0
@@ -0,0 +1,84 @@
1
+ import { z } from 'zod';
2
+ import { memoryEngine } from '../memory/engine.js';
3
+ export const memorySearchToolSchema = {
4
+ name: 'memory_search',
5
+ description: 'Perform a semantic or keyword search across memory records. ' +
6
+ 'Use this when automatic recall was insufficient. ' +
7
+ 'Optionally pass `asOf` (ISO 8601) to query what memories were valid at a specific point in time, ' +
8
+ 'or `filters` to narrow by type / scene / time window / priority / skillTag.',
9
+ inputSchema: {
10
+ type: 'object',
11
+ properties: {
12
+ userId: { type: 'string', description: 'User identifier for isolation' },
13
+ query: { type: 'string', description: 'Search query' },
14
+ sessionKey: { type: 'string', description: 'Session identifier' },
15
+ activeSkill: { type: 'string', description: 'Current active skill boost' },
16
+ limit: { type: 'number', description: 'Max results to return (default 10)' },
17
+ asOf: {
18
+ type: 'string',
19
+ description: 'Optional ISO 8601 timestamp for point-in-time recall. ' +
20
+ 'Returns memories that existed AND were valid at this moment. ' +
21
+ 'Example: "2025-03-15T12:00:00.000Z"',
22
+ },
23
+ filters: {
24
+ type: 'object',
25
+ description: 'Optional filters narrowing the candidate pool before ranking.',
26
+ properties: {
27
+ types: { type: 'array', items: { type: 'string' }, description: "Whitelist of memory types (e.g. ['instruction', 'feedback'])." },
28
+ scenes: { type: 'array', items: { type: 'string' }, description: 'Whitelist of contextual focus scene names.' },
29
+ capturedAfter: { type: 'string', description: 'ISO 8601 lower bound on created_time.' },
30
+ capturedBefore: { type: 'string', description: 'ISO 8601 upper bound on created_time.' },
31
+ minPriority: { type: 'number', description: 'Drop records whose stored priority is below this threshold (0-100).' },
32
+ skillTag: { type: 'string', description: 'Restrict to records produced under this skill tag.' },
33
+ },
34
+ },
35
+ },
36
+ required: ['query', 'sessionKey'],
37
+ },
38
+ };
39
+ export const memorySearchSchema = z.object({
40
+ userId: z.string().optional(),
41
+ query: z.string(),
42
+ sessionKey: z.string(),
43
+ activeSkill: z.string().optional(),
44
+ limit: z.number().int().positive().optional(),
45
+ asOf: z.string().optional(),
46
+ filters: z.object({
47
+ types: z.array(z.string()).optional(),
48
+ scenes: z.array(z.string()).optional(),
49
+ capturedAfter: z.string().optional(),
50
+ capturedBefore: z.string().optional(),
51
+ minPriority: z.number().optional(),
52
+ skillTag: z.string().optional(),
53
+ }).optional(),
54
+ });
55
+ export async function handleMemorySearch(args, options) {
56
+ const params = memorySearchSchema.parse(args);
57
+ const effectiveUserId = params.userId ?? options?.defaultUserId ?? "default";
58
+ try {
59
+ // Point-in-time search path
60
+ if (params.asOf) {
61
+ const result = memoryEngine.searchAsOf(effectiveUserId, params.query, params.asOf, params.limit ?? 10);
62
+ return {
63
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
64
+ };
65
+ }
66
+ // Standard recall path
67
+ const result = await memoryEngine.recall({
68
+ userId: effectiveUserId,
69
+ sessionKey: params.sessionKey,
70
+ query: params.query,
71
+ activeSkill: params.activeSkill,
72
+ filters: params.filters,
73
+ });
74
+ return {
75
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
76
+ };
77
+ }
78
+ catch (err) {
79
+ return {
80
+ isError: true,
81
+ content: [{ type: 'text', text: `memory_search failed: ${err.message}` }],
82
+ };
83
+ }
84
+ }
@@ -0,0 +1,18 @@
1
+ import { z } from 'zod';
2
+ import type { Registry } from '../registry.js';
3
+ export declare const searchSkillsSchema: z.ZodObject<{
4
+ query: z.ZodString;
5
+ scope: z.ZodDefault<z.ZodOptional<z.ZodEnum<["global", "local", "all"]>>>;
6
+ }, "strip", z.ZodTypeAny, {
7
+ scope: "global" | "local" | "all";
8
+ query: string;
9
+ }, {
10
+ query: string;
11
+ scope?: "global" | "local" | "all" | undefined;
12
+ }>;
13
+ export declare function searchSkills(registry: Registry, args: z.infer<typeof searchSkillsSchema>): Promise<{
14
+ content: {
15
+ type: string;
16
+ text: string;
17
+ }[];
18
+ }>;
@@ -0,0 +1,17 @@
1
+ import { z } from 'zod';
2
+ export const searchSkillsSchema = z.object({
3
+ query: z.string(),
4
+ scope: z.enum(['global', 'local', 'all']).optional().default('all'),
5
+ });
6
+ export async function searchSkills(registry, args) {
7
+ const results = registry.searchSkills(args.query, args.scope);
8
+ const sanitized = results.map(({ filePath, ...rest }) => rest);
9
+ return {
10
+ content: [
11
+ {
12
+ type: 'text',
13
+ text: JSON.stringify(sanitized, null, 2),
14
+ },
15
+ ],
16
+ };
17
+ }
@@ -0,0 +1,24 @@
1
+ import { z } from 'zod';
2
+ import type { Registry } from '../registry.js';
3
+ export declare const updateDocSchema: z.ZodObject<{
4
+ name: z.ZodString;
5
+ section: z.ZodString;
6
+ content: z.ZodString;
7
+ createIfMissing: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
8
+ }, "strip", z.ZodTypeAny, {
9
+ name: string;
10
+ content: string;
11
+ section: string;
12
+ createIfMissing: boolean;
13
+ }, {
14
+ name: string;
15
+ content: string;
16
+ section: string;
17
+ createIfMissing?: boolean | undefined;
18
+ }>;
19
+ export declare function updateDoc(registry: Registry, args: z.infer<typeof updateDocSchema>): Promise<{
20
+ content: {
21
+ type: string;
22
+ text: string;
23
+ }[];
24
+ }>;
@@ -0,0 +1,35 @@
1
+ import { z } from 'zod';
2
+ import { join } from 'path';
3
+ import { updateDocSection } from '../writer.js';
4
+ export const updateDocSchema = z.object({
5
+ name: z.string(),
6
+ section: z.string(),
7
+ content: z.string(),
8
+ createIfMissing: z.boolean().optional().default(true),
9
+ });
10
+ export async function updateDoc(registry, args) {
11
+ const localRoot = registry.getLocalRoot();
12
+ if (!localRoot) {
13
+ throw new Error('No local root detected. Documentation updates are only allowed in project repositories.');
14
+ }
15
+ const manifest = registry.getDoc(args.name);
16
+ let filePath;
17
+ if (manifest) {
18
+ filePath = manifest.filePath;
19
+ }
20
+ else {
21
+ if (!args.createIfMissing) {
22
+ throw new Error(`Document "${args.name}" not found.`);
23
+ }
24
+ filePath = join(localRoot, 'docs', `${args.name}.md`);
25
+ }
26
+ updateDocSection(filePath, args.section, args.content, localRoot, args.createIfMissing);
27
+ return {
28
+ content: [
29
+ {
30
+ type: 'text',
31
+ text: `Successfully updated section "${args.section}" in ${manifest ? manifest.name : args.name}.`,
32
+ },
33
+ ],
34
+ };
35
+ }
@@ -0,0 +1,30 @@
1
+ import { z } from 'zod';
2
+ import type { Registry } from '../registry.js';
3
+ export declare const updateSkillSchema: z.ZodObject<{
4
+ name: z.ZodString;
5
+ section: z.ZodEnum<["overview", "workflow", "usage", "detailed_instructions", "checklist", "full"]>;
6
+ content: z.ZodString;
7
+ targetScope: z.ZodOptional<z.ZodEnum<["global", "local"]>>;
8
+ project: z.ZodOptional<z.ZodString>;
9
+ }, "strip", z.ZodTypeAny, {
10
+ name: string;
11
+ content: string;
12
+ section: "overview" | "workflow" | "usage" | "detailed_instructions" | "checklist" | "full";
13
+ project?: string | undefined;
14
+ targetScope?: "global" | "local" | undefined;
15
+ }, {
16
+ name: string;
17
+ content: string;
18
+ section: "overview" | "workflow" | "usage" | "detailed_instructions" | "checklist" | "full";
19
+ project?: string | undefined;
20
+ targetScope?: "global" | "local" | undefined;
21
+ }>;
22
+ export declare function updateSkill(registry: Registry, args: z.infer<typeof updateSkillSchema>): Promise<{
23
+ content: {
24
+ type: string;
25
+ text: string;
26
+ }[];
27
+ metadata: {
28
+ scope: import("../types.js").SkillScope;
29
+ };
30
+ }>;
@@ -0,0 +1,80 @@
1
+ import { z } from 'zod';
2
+ import { readFileSync, writeFileSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { mkdirSync } from 'fs';
5
+ import { updateSkillSection } from '../writer.js';
6
+ export const updateSkillSchema = z.object({
7
+ name: z.string(),
8
+ section: z.enum(['overview', 'workflow', 'usage', 'detailed_instructions', 'checklist', 'full']),
9
+ content: z.string(),
10
+ targetScope: z.enum(['global', 'local']).optional(),
11
+ project: z.string().optional(),
12
+ });
13
+ export async function updateSkill(registry, args) {
14
+ const manifest = registry.getSkill(args.name);
15
+ if (!manifest) {
16
+ throw new Error(`Skill "${args.name}" not found.`);
17
+ }
18
+ const localRoot = registry.getLocalRoot();
19
+ const globalRoot = registry.getGlobalRoot();
20
+ const localProjectName = registry.getLocalProjectName();
21
+ // Decide where to write
22
+ const scope = args.targetScope ?? (manifest.scope === 'global' ? 'local' : 'local');
23
+ const targetRoot = scope === 'global' ? globalRoot : localRoot;
24
+ if (!targetRoot) {
25
+ throw new Error(`No ${scope} root detected.`);
26
+ }
27
+ let filePath = manifest.filePath;
28
+ if (scope === 'global') {
29
+ // We want to write to global. If it's currently local, we determine the global destination.
30
+ if (manifest.scope === 'local') {
31
+ const project = args.project ?? manifest.project ?? localProjectName;
32
+ if (!project) {
33
+ throw new Error('Project name is required to promote a skill to global scope.');
34
+ }
35
+ const baseFolder = 'projects';
36
+ const projectFolder = project;
37
+ const globalSkillDir = join(globalRoot, baseFolder, projectFolder, 'skills', manifest.category, manifest.name);
38
+ filePath = join(globalSkillDir, 'SKILL.md');
39
+ if (!readFileSync(filePath, { flag: 'a+' })) {
40
+ mkdirSync(globalSkillDir, { recursive: true });
41
+ const localContent = readFileSync(manifest.filePath, 'utf-8');
42
+ writeFileSync(filePath, localContent, 'utf-8');
43
+ }
44
+ }
45
+ }
46
+ else {
47
+ // Default/Local scope: shadow global if necessary
48
+ if (!localRoot) {
49
+ throw new Error('Local root not detected. Cannot update local skills.');
50
+ }
51
+ if (manifest.scope === 'global') {
52
+ // In local repos, we MUST use projects/ folder
53
+ const project = localProjectName;
54
+ if (!project) {
55
+ throw new Error('Project name is required to shadow a global skill locally.');
56
+ }
57
+ const localSkillDir = join(localRoot, 'projects', project, 'skills', manifest.category, manifest.name);
58
+ const localSkillPath = join(localSkillDir, 'SKILL.md');
59
+ if (!readFileSync(localSkillPath, { flag: 'a+' })) {
60
+ mkdirSync(localSkillDir, { recursive: true });
61
+ const globalContent = readFileSync(manifest.filePath, 'utf-8');
62
+ writeFileSync(localSkillPath, globalContent, 'utf-8');
63
+ }
64
+ filePath = localSkillPath;
65
+ }
66
+ }
67
+ updateSkillSection(filePath, args.section, args.content, targetRoot);
68
+ registry.refresh();
69
+ return {
70
+ content: [
71
+ {
72
+ type: 'text',
73
+ text: `Successfully updated section "${args.section}" of skill "${args.name}" in ${scope} registry.`,
74
+ },
75
+ ],
76
+ metadata: {
77
+ scope: registry.getSkill(args.name)?.scope ?? scope,
78
+ },
79
+ };
80
+ }
@@ -0,0 +1,81 @@
1
+ export type SkillScope = 'global' | 'local';
2
+ export type DocCategory = 'api' | 'design' | 'schema' | 'deployment' | 'hooks' | 'strategy' | 'other';
3
+ /**
4
+ * Every named section extractable from a SKILL.md.
5
+ * Ordered cheapest → most expensive by token count.
6
+ */
7
+ export type SkillSection = 'description' | 'overview' | 'when_to_use' | 'workflow' | 'usage' | 'detailed_instructions' | 'phases' | 'checklist' | 'red_flags' | 'rationalizations' | 'full';
8
+ export interface SkillManifest {
9
+ /** kebab-case slug matching directory name and frontmatter `name` */
10
+ name: string;
11
+ /** subcategory folder: agent | api | devops | lifecycle | design | … */
12
+ category: string;
13
+ /** from YAML frontmatter `description` field */
14
+ description: string;
15
+ /** absolute path to SKILL.md */
16
+ filePath: string;
17
+ /** global = BrainRouter repo; local = downstream project repo */
18
+ scope: SkillScope;
19
+ /** Optional project name for project-specific skills */
20
+ project?: string;
21
+ }
22
+ export interface DocManifest {
23
+ /** lowercase slug e.g. "api", "design", "schema" */
24
+ name: string;
25
+ category: DocCategory;
26
+ /** absolute path to the doc file */
27
+ filePath: string;
28
+ lastModified: Date;
29
+ }
30
+ export interface PersonaManifest {
31
+ /** kebab-case e.g. "code-reviewer", "security-auditor" */
32
+ name: string;
33
+ filePath: string;
34
+ }
35
+ export interface ReferenceManifest {
36
+ /** kebab-case e.g. "security-checklist", "testing-patterns" */
37
+ name: string;
38
+ filePath: string;
39
+ }
40
+ /** The unit returned to an agent — extracted content + provenance. */
41
+ export interface Fragment {
42
+ /** The extracted text content */
43
+ content: string;
44
+ /** Relative path for traceability (e.g. "skills/agent/bootstrap/SKILL.md") */
45
+ source: string;
46
+ /** Only present for skill fragments */
47
+ scope?: SkillScope;
48
+ /** Rough token estimate: Math.ceil(content.length / 4) */
49
+ tokenEstimate: number;
50
+ }
51
+ export interface RegistryConfig {
52
+ /** Absolute path to BrainRouter repo root (always resolved from __dirname) */
53
+ globalRoot: string;
54
+ /** Absolute path to downstream project repo root (optional) */
55
+ localRoot?: string;
56
+ /** Name of the local project (from brainrouter.config.json) */
57
+ localProjectName?: string;
58
+ }
59
+ /** Shape of brainrouter.config.json in a downstream repo */
60
+ export interface BrainRouterConfig {
61
+ project?: string;
62
+ techStack?: string[];
63
+ localSkillsPath?: string;
64
+ localDocsPath?: string;
65
+ activeCategories?: string[];
66
+ }
67
+ export interface CreateSkillResult {
68
+ created: true;
69
+ path: string;
70
+ tokenEstimate: number;
71
+ }
72
+ export interface UpdateSkillResult {
73
+ updated: true;
74
+ path: string;
75
+ scope: SkillScope;
76
+ }
77
+ export interface UpdateDocResult {
78
+ updated: true;
79
+ path: string;
80
+ section: string;
81
+ }
package/dist/types.js ADDED
@@ -0,0 +1,4 @@
1
+ // ─────────────────────────────────────────────
2
+ // BrainRouter MCP Server — Shared Types
3
+ // ─────────────────────────────────────────────
4
+ export {};
@@ -0,0 +1,30 @@
1
+ import type { SkillSection } from './types.js';
2
+ export interface ScaffoldSkillParams {
3
+ name: string;
4
+ category: string;
5
+ description: string;
6
+ targetRoot: string;
7
+ project?: string;
8
+ overview?: string;
9
+ when_to_use?: string;
10
+ workflow?: string[];
11
+ usage?: string;
12
+ checklist?: string[];
13
+ }
14
+ /**
15
+ * Create a new SKILL.md in the specified registry.
16
+ * Returns the absolute path of the created file.
17
+ */
18
+ export declare function scaffoldSkill(params: ScaffoldSkillParams): string;
19
+ /**
20
+ * Update a named ## section in an existing SKILL.md.
21
+ * If section is "full", replaces the entire body content.
22
+ * Returns the absolute path of the updated file.
23
+ */
24
+ export declare function updateSkillSection(filePath: string, section: Extract<SkillSection, 'overview' | 'workflow' | 'usage' | 'detailed_instructions' | 'checklist' | 'full'>, newContent: string, targetRoot: string): string;
25
+ /**
26
+ * Update a named ## section in a project doc (API.md, Design.md, etc.).
27
+ * If createIfMissing is true and the section doesn't exist, it is appended.
28
+ * Returns the absolute path of the updated file.
29
+ */
30
+ export declare function updateDocSection(filePath: string, sectionHeading: string, newContent: string, targetRoot: string, createIfMissing?: boolean): string;
package/dist/writer.js ADDED
@@ -0,0 +1,220 @@
1
+ // ─────────────────────────────────────────────
2
+ // BrainRouter MCP Server — Safe Writer
3
+ // Creates and updates markdown files in localRoot or globalRoot.
4
+ // ─────────────────────────────────────────────
5
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
6
+ import { resolve, join, relative, dirname, basename } from 'path';
7
+ import matter from 'gray-matter';
8
+ // ─── Safety Guard ────────────────────────────
9
+ /**
10
+ * Throws if targetPath is not inside allowedRoot.
11
+ * Prevents unauthorized writes outside project roots.
12
+ */
13
+ function assertInsideRoot(targetPath, allowedRoot) {
14
+ const resolvedTarget = resolve(targetPath);
15
+ const resolvedRoot = resolve(allowedRoot);
16
+ const rel = relative(resolvedRoot, resolvedTarget);
17
+ if (rel.startsWith('..') || resolvedTarget === resolvedRoot) {
18
+ throw new Error(`WRITE BLOCKED: "${targetPath}" is outside the allowed root "${allowedRoot}".`);
19
+ }
20
+ // Block writes to the universal skills folder to prevent agents from modifying core skills
21
+ const firstPart = rel.split('/')[0];
22
+ if (firstPart === 'skills') {
23
+ throw new Error(`WRITE BLOCKED: Modifying the universal "skills/" folder is not allowed. All skills must be stored in "projects/".`);
24
+ }
25
+ }
26
+ // ─── Skill Authoring Template ────────────────
27
+ /**
28
+ * Generates a canonical SKILL.md from the skill-authoring template structure.
29
+ */
30
+ function buildSkillTemplate(params) {
31
+ const { name, category, description, overview, when_to_use, workflow, usage, checklist } = params;
32
+ const workflowSection = workflow?.length
33
+ ? workflow.map((step, i) => `${i + 1}. ${step}`).join('\n')
34
+ : '1. [Step 1]\n2. [Step 2]\n3. [Step 3]';
35
+ const checklistSection = checklist?.length
36
+ ? checklist.map((item) => `- [ ] ${item}`).join('\n')
37
+ : '- [ ] [Verification item 1]\n- [ ] [Verification item 2]';
38
+ return `---
39
+ name: ${name}
40
+ category: ${category}
41
+ description: ${description}
42
+ ---
43
+
44
+ # ${name
45
+ .split('-')
46
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
47
+ .join(' ')}
48
+
49
+ ## Overview
50
+ ${overview ?? '[One-two sentences explaining what this skill does and why it matters.]'}
51
+
52
+ ## When to Use
53
+ ${when_to_use ?? '- [Triggering condition 1]\n- [Triggering condition 2]\n- NOT for: [exclusions]'}
54
+
55
+ ## Workflow
56
+
57
+ ${workflowSection}
58
+
59
+ ## Usage
60
+
61
+ \`\`\`bash
62
+ # [Example command or trigger phrase]
63
+ \`\`\`
64
+
65
+ ${usage ? `${usage}\n\n` : ''}## Common Rationalizations
66
+
67
+ | Rationalization | Reality |
68
+ |---|---|
69
+ | [Excuse an agent might use to skip a step] | [Why that excuse is wrong] |
70
+
71
+ ## Red Flags
72
+ - [Observable sign that this skill is being violated]
73
+
74
+ ## Verification
75
+ ${checklistSection}
76
+ `;
77
+ }
78
+ /**
79
+ * Create a new SKILL.md in the specified registry.
80
+ * Returns the absolute path of the created file.
81
+ */
82
+ export function scaffoldSkill(params) {
83
+ const { name, category, targetRoot, project, ...rest } = params;
84
+ // Skills MUST follow projects/<project_name>/skills/<category>/<name>/ structure
85
+ if (!project) {
86
+ throw new Error('Project name is required to create a skill.');
87
+ }
88
+ const baseFolder = 'projects';
89
+ const projectFolder = project;
90
+ const skillDir = join(targetRoot, baseFolder, projectFolder, 'skills', category, name);
91
+ const skillPath = join(skillDir, 'SKILL.md');
92
+ assertInsideRoot(skillPath, targetRoot);
93
+ if (existsSync(skillPath)) {
94
+ throw new Error(`Skill "${name}" already exists at "${skillPath}". Use update_skill to modify it.`);
95
+ }
96
+ mkdirSync(skillDir, { recursive: true });
97
+ const content = buildSkillTemplate({ name, category, ...rest });
98
+ writeFileSync(skillPath, content, 'utf-8');
99
+ return skillPath;
100
+ }
101
+ // ─── Section Update ──────────────────────────
102
+ const UPDATABLE_SECTIONS = {
103
+ overview: ['overview'],
104
+ workflow: ['workflow', 'core process', 'the workflow', 'steps', 'process'],
105
+ usage: ['usage', 'example usage', 'examples'],
106
+ detailed_instructions: ['detailed instructions', 'instructions'],
107
+ checklist: ['verification', 'required checks'],
108
+ };
109
+ /**
110
+ * Update a named ## section in an existing SKILL.md.
111
+ * If section is "full", replaces the entire body content.
112
+ * Returns the absolute path of the updated file.
113
+ */
114
+ export function updateSkillSection(filePath, section, newContent, targetRoot) {
115
+ assertInsideRoot(filePath, targetRoot);
116
+ const raw = readFileSync(filePath, 'utf-8');
117
+ const parsed = matter(raw);
118
+ if (section === 'full') {
119
+ // Replace entire body, preserve frontmatter
120
+ const updated = matter.stringify(newContent, parsed.data);
121
+ writeFileSync(filePath, updated, 'utf-8');
122
+ return filePath;
123
+ }
124
+ const aliases = UPDATABLE_SECTIONS[section] ?? [section.replace(/_/g, ' ')];
125
+ const lines = parsed.content.split('\n');
126
+ const result = [];
127
+ let inTarget = false;
128
+ let replaced = false;
129
+ for (const line of lines) {
130
+ const h2Match = line.match(/^##\s+(.+)/);
131
+ if (h2Match) {
132
+ const heading = h2Match[1].trim().toLowerCase();
133
+ if (aliases.some((a) => heading.includes(a))) {
134
+ inTarget = true;
135
+ result.push(line); // keep the heading
136
+ result.push('');
137
+ result.push(newContent.trim());
138
+ result.push(''); // Ensure blank line before next section
139
+ replaced = true;
140
+ continue;
141
+ }
142
+ else if (inTarget) {
143
+ inTarget = false;
144
+ }
145
+ }
146
+ if (!inTarget)
147
+ result.push(line);
148
+ }
149
+ if (!replaced) {
150
+ // Section not found — append it
151
+ result.push('');
152
+ result.push(`## ${section.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase())}`);
153
+ result.push('');
154
+ result.push(newContent.trim());
155
+ result.push('');
156
+ }
157
+ const updatedBody = result.join('\n');
158
+ const updatedFile = matter.stringify(updatedBody, parsed.data);
159
+ writeFileSync(filePath, updatedFile, 'utf-8');
160
+ return filePath;
161
+ }
162
+ // ─── Doc Update ─────────────────────────────
163
+ /**
164
+ * Update a named ## section in a project doc (API.md, Design.md, etc.).
165
+ * If createIfMissing is true and the section doesn't exist, it is appended.
166
+ * Returns the absolute path of the updated file.
167
+ */
168
+ export function updateDocSection(filePath, sectionHeading, newContent, targetRoot, createIfMissing = true) {
169
+ assertInsideRoot(filePath, targetRoot);
170
+ mkdirSync(dirname(filePath), { recursive: true });
171
+ let raw = '';
172
+ if (existsSync(filePath)) {
173
+ raw = readFileSync(filePath, 'utf-8');
174
+ }
175
+ else {
176
+ if (!createIfMissing) {
177
+ throw new Error(`File "${filePath}" not found.`);
178
+ }
179
+ const name = basename(filePath, '.md').toUpperCase();
180
+ raw = `# ${name}\n`;
181
+ }
182
+ const lines = raw.split('\n');
183
+ const result = [];
184
+ let inTarget = false;
185
+ let replaced = false;
186
+ for (const line of lines) {
187
+ const h2Match = line.match(/^##\s+(.+)/);
188
+ if (h2Match) {
189
+ const heading = h2Match[1].trim().toLowerCase();
190
+ if (heading.includes(sectionHeading.toLowerCase())) {
191
+ inTarget = true;
192
+ result.push(line);
193
+ result.push('');
194
+ result.push(newContent.trim());
195
+ result.push(''); // Ensure blank line before next section
196
+ replaced = true;
197
+ continue;
198
+ }
199
+ else if (inTarget) {
200
+ inTarget = false;
201
+ }
202
+ }
203
+ if (!inTarget)
204
+ result.push(line);
205
+ }
206
+ if (!replaced) {
207
+ if (!createIfMissing) {
208
+ throw new Error(`Section "${sectionHeading}" not found in "${filePath}".`);
209
+ }
210
+ result.push('');
211
+ result.push(`## ${sectionHeading}`);
212
+ result.push('');
213
+ result.push(newContent.trim());
214
+ result.push('');
215
+ }
216
+ writeFileSync(filePath, result.join('\n'), 'utf-8');
217
+ // Ensure the directory for the file exists (already should, but safe)
218
+ mkdirSync(dirname(filePath), { recursive: true });
219
+ return filePath;
220
+ }
@@ -0,0 +1 @@
1
+ E