@monoes/monomindcli 1.11.14 → 1.13.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 (434) hide show
  1. package/.claude/agents/generated/channel-intelligence-director.md +87 -0
  2. package/.claude/agents/generated/chief-growth-officer.md +88 -0
  3. package/.claude/agents/generated/content-seo-strategist.md +90 -0
  4. package/.claude/agents/generated/developer-community-strategist.md +91 -0
  5. package/.claude/agents/generated/outreach-partnership-strategist.md +90 -0
  6. package/.claude/agents/generated/social-media-strategist.md +91 -0
  7. package/.claude/agents/generated/video-visual-strategist.md +90 -0
  8. package/.claude/commands/mastermind/master.md +1 -1
  9. package/.claude/helpers/auto-memory-hook.mjs +13 -4
  10. package/.claude/helpers/control-start.cjs +5 -0
  11. package/.claude/helpers/event-logger.cjs +114 -0
  12. package/.claude/helpers/handlers/adr-draft-handler.cjs +19 -5
  13. package/.claude/helpers/handlers/agent-start-handler.cjs +13 -4
  14. package/.claude/helpers/handlers/compact-handler.cjs +2 -0
  15. package/.claude/helpers/handlers/edit-handler.cjs +1 -1
  16. package/.claude/helpers/handlers/gates-handler.cjs +3 -0
  17. package/.claude/helpers/handlers/graph-status-handler.cjs +14 -8
  18. package/.claude/helpers/handlers/loops-status-handler.cjs +5 -2
  19. package/.claude/helpers/handlers/route-handler.cjs +24 -10
  20. package/.claude/helpers/handlers/session-handler.cjs +11 -4
  21. package/.claude/helpers/handlers/session-restore-handler.cjs +35 -19
  22. package/.claude/helpers/handlers/task-handler.cjs +13 -5
  23. package/.claude/helpers/hook-handler.cjs +40 -0
  24. package/.claude/helpers/intelligence.cjs +130 -53
  25. package/.claude/helpers/loop-tracker.cjs +15 -3
  26. package/.claude/helpers/memory-palace.cjs +461 -0
  27. package/.claude/helpers/memory.cjs +138 -14
  28. package/.claude/helpers/metrics-db.mjs +87 -0
  29. package/.claude/helpers/router.cjs +300 -42
  30. package/.claude/helpers/session.cjs +89 -30
  31. package/.claude/helpers/statusline.cjs +148 -4
  32. package/.claude/helpers/toggle-statusline.cjs +73 -0
  33. package/.claude/helpers/token-tracker.cjs +934 -0
  34. package/.claude/helpers/utils/micro-agents.cjs +20 -4
  35. package/.claude/helpers/utils/monograph.cjs +39 -4
  36. package/.claude/helpers/utils/telemetry.cjs +3 -3
  37. package/.claude/skills/mastermind/_protocol.md +25 -15
  38. package/.claude/skills/mastermind/architect.md +3 -3
  39. package/.claude/skills/mastermind/autodev.md +4 -2
  40. package/.claude/skills/mastermind/idea.md +10 -0
  41. package/.claude/skills/mastermind/ops.md +3 -3
  42. package/.claude/skills/mastermind/runorg.md +153 -86
  43. package/dist/src/agents/registry-builder.d.ts.map +1 -1
  44. package/dist/src/agents/registry-builder.js +2 -0
  45. package/dist/src/agents/registry-builder.js.map +1 -1
  46. package/dist/src/autopilot-state.d.ts.map +1 -1
  47. package/dist/src/autopilot-state.js +10 -5
  48. package/dist/src/autopilot-state.js.map +1 -1
  49. package/dist/src/benchmarks/benchmark-runner.d.ts.map +1 -1
  50. package/dist/src/benchmarks/benchmark-runner.js +13 -0
  51. package/dist/src/benchmarks/benchmark-runner.js.map +1 -1
  52. package/dist/src/benchmarks/metric-evaluators.d.ts.map +1 -1
  53. package/dist/src/benchmarks/metric-evaluators.js +20 -9
  54. package/dist/src/benchmarks/metric-evaluators.js.map +1 -1
  55. package/dist/src/browser/actions.d.ts.map +1 -1
  56. package/dist/src/browser/actions.js +10 -3
  57. package/dist/src/browser/actions.js.map +1 -1
  58. package/dist/src/browser/browser.d.ts.map +1 -1
  59. package/dist/src/browser/browser.js +12 -2
  60. package/dist/src/browser/browser.js.map +1 -1
  61. package/dist/src/browser/cdp.d.ts.map +1 -1
  62. package/dist/src/browser/cdp.js +21 -3
  63. package/dist/src/browser/cdp.js.map +1 -1
  64. package/dist/src/browser/har.d.ts.map +1 -1
  65. package/dist/src/browser/har.js +27 -5
  66. package/dist/src/browser/har.js.map +1 -1
  67. package/dist/src/commands/agent.d.ts.map +1 -1
  68. package/dist/src/commands/agent.js +11 -8
  69. package/dist/src/commands/agent.js.map +1 -1
  70. package/dist/src/commands/analyze.d.ts.map +1 -1
  71. package/dist/src/commands/analyze.js +36 -21
  72. package/dist/src/commands/analyze.js.map +1 -1
  73. package/dist/src/commands/autopilot.d.ts.map +1 -1
  74. package/dist/src/commands/autopilot.js +12 -4
  75. package/dist/src/commands/autopilot.js.map +1 -1
  76. package/dist/src/commands/benchmark.d.ts.map +1 -1
  77. package/dist/src/commands/benchmark.js +51 -8
  78. package/dist/src/commands/benchmark.js.map +1 -1
  79. package/dist/src/commands/browse.d.ts.map +1 -1
  80. package/dist/src/commands/browse.js +5 -2
  81. package/dist/src/commands/browse.js.map +1 -1
  82. package/dist/src/commands/claims.d.ts.map +1 -1
  83. package/dist/src/commands/claims.js +29 -11
  84. package/dist/src/commands/claims.js.map +1 -1
  85. package/dist/src/commands/cleanup.d.ts.map +1 -1
  86. package/dist/src/commands/cleanup.js +25 -5
  87. package/dist/src/commands/cleanup.js.map +1 -1
  88. package/dist/src/commands/config.d.ts.map +1 -1
  89. package/dist/src/commands/config.js +15 -7
  90. package/dist/src/commands/config.js.map +1 -1
  91. package/dist/src/commands/daemon.d.ts.map +1 -1
  92. package/dist/src/commands/daemon.js +6 -0
  93. package/dist/src/commands/daemon.js.map +1 -1
  94. package/dist/src/commands/deployment.d.ts.map +1 -1
  95. package/dist/src/commands/deployment.js +34 -19
  96. package/dist/src/commands/deployment.js.map +1 -1
  97. package/dist/src/commands/doctor.d.ts.map +1 -1
  98. package/dist/src/commands/doctor.js +133 -15
  99. package/dist/src/commands/doctor.js.map +1 -1
  100. package/dist/src/commands/guidance.d.ts.map +1 -1
  101. package/dist/src/commands/guidance.js +15 -2
  102. package/dist/src/commands/guidance.js.map +1 -1
  103. package/dist/src/commands/hive-mind.d.ts.map +1 -1
  104. package/dist/src/commands/hive-mind.js +37 -14
  105. package/dist/src/commands/hive-mind.js.map +1 -1
  106. package/dist/src/commands/hooks.d.ts.map +1 -1
  107. package/dist/src/commands/hooks.js +42 -25
  108. package/dist/src/commands/hooks.js.map +1 -1
  109. package/dist/src/commands/init.d.ts.map +1 -1
  110. package/dist/src/commands/init.js +9 -4
  111. package/dist/src/commands/init.js.map +1 -1
  112. package/dist/src/commands/issues.d.ts.map +1 -1
  113. package/dist/src/commands/issues.js +29 -26
  114. package/dist/src/commands/issues.js.map +1 -1
  115. package/dist/src/commands/mcp.d.ts.map +1 -1
  116. package/dist/src/commands/mcp.js +11 -5
  117. package/dist/src/commands/mcp.js.map +1 -1
  118. package/dist/src/commands/memory.d.ts.map +1 -1
  119. package/dist/src/commands/memory.js +10 -0
  120. package/dist/src/commands/memory.js.map +1 -1
  121. package/dist/src/commands/migrate.js +5 -5
  122. package/dist/src/commands/migrate.js.map +1 -1
  123. package/dist/src/commands/monograph.d.ts.map +1 -1
  124. package/dist/src/commands/monograph.js +18 -5
  125. package/dist/src/commands/monograph.js.map +1 -1
  126. package/dist/src/commands/monovector/backup.d.ts.map +1 -1
  127. package/dist/src/commands/monovector/backup.js +8 -2
  128. package/dist/src/commands/monovector/backup.js.map +1 -1
  129. package/dist/src/commands/monovector/benchmark.d.ts.map +1 -1
  130. package/dist/src/commands/monovector/benchmark.js +20 -7
  131. package/dist/src/commands/monovector/benchmark.js.map +1 -1
  132. package/dist/src/commands/monovector/import.d.ts.map +1 -1
  133. package/dist/src/commands/monovector/import.js +15 -0
  134. package/dist/src/commands/monovector/import.js.map +1 -1
  135. package/dist/src/commands/monovector/migrate.d.ts.map +1 -1
  136. package/dist/src/commands/monovector/migrate.js +4 -1
  137. package/dist/src/commands/monovector/migrate.js.map +1 -1
  138. package/dist/src/commands/monovector/optimize.d.ts.map +1 -1
  139. package/dist/src/commands/monovector/optimize.js +11 -0
  140. package/dist/src/commands/monovector/optimize.js.map +1 -1
  141. package/dist/src/commands/monovector/setup.d.ts.map +1 -1
  142. package/dist/src/commands/monovector/setup.js +11 -1
  143. package/dist/src/commands/monovector/setup.js.map +1 -1
  144. package/dist/src/commands/neural.js +1 -1
  145. package/dist/src/commands/neural.js.map +1 -1
  146. package/dist/src/commands/performance.d.ts.map +1 -1
  147. package/dist/src/commands/performance.js +20 -7
  148. package/dist/src/commands/performance.js.map +1 -1
  149. package/dist/src/commands/platforms.d.ts.map +1 -1
  150. package/dist/src/commands/platforms.js +90 -8
  151. package/dist/src/commands/platforms.js.map +1 -1
  152. package/dist/src/commands/plugins.d.ts.map +1 -1
  153. package/dist/src/commands/plugins.js +12 -5
  154. package/dist/src/commands/plugins.js.map +1 -1
  155. package/dist/src/commands/process.d.ts.map +1 -1
  156. package/dist/src/commands/process.js +33 -10
  157. package/dist/src/commands/process.js.map +1 -1
  158. package/dist/src/commands/progress.d.ts.map +1 -1
  159. package/dist/src/commands/progress.js +5 -3
  160. package/dist/src/commands/progress.js.map +1 -1
  161. package/dist/src/commands/providers.js +5 -5
  162. package/dist/src/commands/providers.js.map +1 -1
  163. package/dist/src/commands/replay.d.ts.map +1 -1
  164. package/dist/src/commands/replay.js +8 -2
  165. package/dist/src/commands/replay.js.map +1 -1
  166. package/dist/src/commands/route.d.ts.map +1 -1
  167. package/dist/src/commands/route.js +27 -7
  168. package/dist/src/commands/route.js.map +1 -1
  169. package/dist/src/commands/security.d.ts.map +1 -1
  170. package/dist/src/commands/security.js +4 -0
  171. package/dist/src/commands/security.js.map +1 -1
  172. package/dist/src/commands/session.d.ts.map +1 -1
  173. package/dist/src/commands/session.js +12 -1
  174. package/dist/src/commands/session.js.map +1 -1
  175. package/dist/src/commands/start.d.ts.map +1 -1
  176. package/dist/src/commands/start.js +11 -4
  177. package/dist/src/commands/start.js.map +1 -1
  178. package/dist/src/commands/status.d.ts.map +1 -1
  179. package/dist/src/commands/status.js +7 -4
  180. package/dist/src/commands/status.js.map +1 -1
  181. package/dist/src/commands/swarm.d.ts.map +1 -1
  182. package/dist/src/commands/swarm.js +27 -13
  183. package/dist/src/commands/swarm.js.map +1 -1
  184. package/dist/src/commands/task.d.ts.map +1 -1
  185. package/dist/src/commands/task.js +26 -11
  186. package/dist/src/commands/task.js.map +1 -1
  187. package/dist/src/commands/tokens.d.ts.map +1 -1
  188. package/dist/src/commands/tokens.js +7 -2
  189. package/dist/src/commands/tokens.js.map +1 -1
  190. package/dist/src/commands/transfer-store.d.ts.map +1 -1
  191. package/dist/src/commands/transfer-store.js +36 -22
  192. package/dist/src/commands/transfer-store.js.map +1 -1
  193. package/dist/src/commands/update.d.ts.map +1 -1
  194. package/dist/src/commands/update.js +15 -3
  195. package/dist/src/commands/update.js.map +1 -1
  196. package/dist/src/commands/workflow.d.ts.map +1 -1
  197. package/dist/src/commands/workflow.js +39 -6
  198. package/dist/src/commands/workflow.js.map +1 -1
  199. package/dist/src/consensus/audit-writer.d.ts.map +1 -1
  200. package/dist/src/consensus/audit-writer.js +18 -7
  201. package/dist/src/consensus/audit-writer.js.map +1 -1
  202. package/dist/src/consensus/vote-signer.d.ts.map +1 -1
  203. package/dist/src/consensus/vote-signer.js +25 -8
  204. package/dist/src/consensus/vote-signer.js.map +1 -1
  205. package/dist/src/index.d.ts.map +1 -1
  206. package/dist/src/index.js +7 -3
  207. package/dist/src/index.js.map +1 -1
  208. package/dist/src/init/executor.d.ts.map +1 -1
  209. package/dist/src/init/executor.js +14 -11
  210. package/dist/src/init/executor.js.map +1 -1
  211. package/dist/src/init/shared-instructions-generator.d.ts.map +1 -1
  212. package/dist/src/init/shared-instructions-generator.js +20 -4
  213. package/dist/src/init/shared-instructions-generator.js.map +1 -1
  214. package/dist/src/init/statusline-generator.d.ts.map +1 -1
  215. package/dist/src/init/statusline-generator.js +36 -15
  216. package/dist/src/init/statusline-generator.js.map +1 -1
  217. package/dist/src/mcp-tools/a2a-tools.d.ts.map +1 -1
  218. package/dist/src/mcp-tools/a2a-tools.js +98 -13
  219. package/dist/src/mcp-tools/a2a-tools.js.map +1 -1
  220. package/dist/src/mcp-tools/agent-tools.d.ts.map +1 -1
  221. package/dist/src/mcp-tools/agent-tools.js +16 -3
  222. package/dist/src/mcp-tools/agent-tools.js.map +1 -1
  223. package/dist/src/mcp-tools/analyze-tools.d.ts.map +1 -1
  224. package/dist/src/mcp-tools/analyze-tools.js +80 -17
  225. package/dist/src/mcp-tools/analyze-tools.js.map +1 -1
  226. package/dist/src/mcp-tools/browser-tools.d.ts.map +1 -1
  227. package/dist/src/mcp-tools/browser-tools.js +84 -22
  228. package/dist/src/mcp-tools/browser-tools.js.map +1 -1
  229. package/dist/src/mcp-tools/claims-tools.d.ts.map +1 -1
  230. package/dist/src/mcp-tools/claims-tools.js +35 -7
  231. package/dist/src/mcp-tools/claims-tools.js.map +1 -1
  232. package/dist/src/mcp-tools/config-tools.d.ts.map +1 -1
  233. package/dist/src/mcp-tools/config-tools.js +82 -17
  234. package/dist/src/mcp-tools/config-tools.js.map +1 -1
  235. package/dist/src/mcp-tools/coordination-tools.d.ts.map +1 -1
  236. package/dist/src/mcp-tools/coordination-tools.js +37 -4
  237. package/dist/src/mcp-tools/coordination-tools.js.map +1 -1
  238. package/dist/src/mcp-tools/daa-tools.d.ts.map +1 -1
  239. package/dist/src/mcp-tools/daa-tools.js +49 -7
  240. package/dist/src/mcp-tools/daa-tools.js.map +1 -1
  241. package/dist/src/mcp-tools/embeddings-tools.d.ts.map +1 -1
  242. package/dist/src/mcp-tools/embeddings-tools.js +45 -18
  243. package/dist/src/mcp-tools/embeddings-tools.js.map +1 -1
  244. package/dist/src/mcp-tools/github-tools.d.ts.map +1 -1
  245. package/dist/src/mcp-tools/github-tools.js +75 -25
  246. package/dist/src/mcp-tools/github-tools.js.map +1 -1
  247. package/dist/src/mcp-tools/guidance-tools.d.ts.map +1 -1
  248. package/dist/src/mcp-tools/guidance-tools.js +32 -10
  249. package/dist/src/mcp-tools/guidance-tools.js.map +1 -1
  250. package/dist/src/mcp-tools/hive-mind-tools.d.ts.map +1 -1
  251. package/dist/src/mcp-tools/hive-mind-tools.js +91 -20
  252. package/dist/src/mcp-tools/hive-mind-tools.js.map +1 -1
  253. package/dist/src/mcp-tools/hooks-tools.d.ts.map +1 -1
  254. package/dist/src/mcp-tools/hooks-tools.js +188 -29
  255. package/dist/src/mcp-tools/hooks-tools.js.map +1 -1
  256. package/dist/src/mcp-tools/memory-tools.d.ts.map +1 -1
  257. package/dist/src/mcp-tools/memory-tools.js +25 -7
  258. package/dist/src/mcp-tools/memory-tools.js.map +1 -1
  259. package/dist/src/mcp-tools/monograph-compat.d.ts.map +1 -1
  260. package/dist/src/mcp-tools/monograph-compat.js +11 -2
  261. package/dist/src/mcp-tools/monograph-compat.js.map +1 -1
  262. package/dist/src/mcp-tools/monograph-tools.d.ts.map +1 -1
  263. package/dist/src/mcp-tools/monograph-tools.js +476 -62
  264. package/dist/src/mcp-tools/monograph-tools.js.map +1 -1
  265. package/dist/src/mcp-tools/neural-tools.d.ts.map +1 -1
  266. package/dist/src/mcp-tools/neural-tools.js +44 -9
  267. package/dist/src/mcp-tools/neural-tools.js.map +1 -1
  268. package/dist/src/mcp-tools/performance-tools.d.ts.map +1 -1
  269. package/dist/src/mcp-tools/performance-tools.js +45 -10
  270. package/dist/src/mcp-tools/performance-tools.js.map +1 -1
  271. package/dist/src/mcp-tools/progress-tools.d.ts.map +1 -1
  272. package/dist/src/mcp-tools/progress-tools.js +7 -4
  273. package/dist/src/mcp-tools/progress-tools.js.map +1 -1
  274. package/dist/src/mcp-tools/request-tracker.d.ts.map +1 -1
  275. package/dist/src/mcp-tools/request-tracker.js +15 -1
  276. package/dist/src/mcp-tools/request-tracker.js.map +1 -1
  277. package/dist/src/mcp-tools/security-tools.d.ts.map +1 -1
  278. package/dist/src/mcp-tools/security-tools.js +61 -9
  279. package/dist/src/mcp-tools/security-tools.js.map +1 -1
  280. package/dist/src/mcp-tools/session-tools.d.ts.map +1 -1
  281. package/dist/src/mcp-tools/session-tools.js +45 -14
  282. package/dist/src/mcp-tools/session-tools.js.map +1 -1
  283. package/dist/src/mcp-tools/swarm-tools.d.ts.map +1 -1
  284. package/dist/src/mcp-tools/swarm-tools.js +15 -3
  285. package/dist/src/mcp-tools/swarm-tools.js.map +1 -1
  286. package/dist/src/mcp-tools/system-tools.d.ts.map +1 -1
  287. package/dist/src/mcp-tools/system-tools.js +14 -7
  288. package/dist/src/mcp-tools/system-tools.js.map +1 -1
  289. package/dist/src/mcp-tools/task-tools.d.ts.map +1 -1
  290. package/dist/src/mcp-tools/task-tools.js +52 -10
  291. package/dist/src/mcp-tools/task-tools.js.map +1 -1
  292. package/dist/src/mcp-tools/terminal-tools.d.ts.map +1 -1
  293. package/dist/src/mcp-tools/terminal-tools.js +40 -6
  294. package/dist/src/mcp-tools/terminal-tools.js.map +1 -1
  295. package/dist/src/mcp-tools/transfer-tools.d.ts.map +1 -1
  296. package/dist/src/mcp-tools/transfer-tools.js +37 -4
  297. package/dist/src/mcp-tools/transfer-tools.js.map +1 -1
  298. package/dist/src/mcp-tools/workflow-tools.d.ts.map +1 -1
  299. package/dist/src/mcp-tools/workflow-tools.js +29 -6
  300. package/dist/src/mcp-tools/workflow-tools.js.map +1 -1
  301. package/dist/src/memory/ewc-consolidation.d.ts.map +1 -1
  302. package/dist/src/memory/ewc-consolidation.js +26 -10
  303. package/dist/src/memory/ewc-consolidation.js.map +1 -1
  304. package/dist/src/memory/intelligence.d.ts.map +1 -1
  305. package/dist/src/memory/intelligence.js +80 -19
  306. package/dist/src/memory/intelligence.js.map +1 -1
  307. package/dist/src/memory/memory-bridge.d.ts.map +1 -1
  308. package/dist/src/memory/memory-bridge.js +21 -2
  309. package/dist/src/memory/memory-bridge.js.map +1 -1
  310. package/dist/src/memory/memory-initializer.d.ts.map +1 -1
  311. package/dist/src/memory/memory-initializer.js +67 -3
  312. package/dist/src/memory/memory-initializer.js.map +1 -1
  313. package/dist/src/memory/sona-optimizer.d.ts.map +1 -1
  314. package/dist/src/memory/sona-optimizer.js +14 -4
  315. package/dist/src/memory/sona-optimizer.js.map +1 -1
  316. package/dist/src/monovector/command-outcomes.d.ts.map +1 -1
  317. package/dist/src/monovector/command-outcomes.js +43 -7
  318. package/dist/src/monovector/command-outcomes.js.map +1 -1
  319. package/dist/src/monovector/coverage-router.d.ts.map +1 -1
  320. package/dist/src/monovector/coverage-router.js +8 -4
  321. package/dist/src/monovector/coverage-router.js.map +1 -1
  322. package/dist/src/monovector/coverage-tools.d.ts.map +1 -1
  323. package/dist/src/monovector/coverage-tools.js +6 -3
  324. package/dist/src/monovector/coverage-tools.js.map +1 -1
  325. package/dist/src/monovector/diff-classifier.d.ts.map +1 -1
  326. package/dist/src/monovector/diff-classifier.js +13 -0
  327. package/dist/src/monovector/diff-classifier.js.map +1 -1
  328. package/dist/src/monovector/route-outcomes.d.ts +2 -1
  329. package/dist/src/monovector/route-outcomes.d.ts.map +1 -1
  330. package/dist/src/monovector/route-outcomes.js +46 -4
  331. package/dist/src/monovector/route-outcomes.js.map +1 -1
  332. package/dist/src/plugins/manager.d.ts.map +1 -1
  333. package/dist/src/plugins/manager.js +8 -3
  334. package/dist/src/plugins/manager.js.map +1 -1
  335. package/dist/src/plugins/store/discovery.d.ts.map +1 -1
  336. package/dist/src/plugins/store/discovery.js +46 -2
  337. package/dist/src/plugins/store/discovery.js.map +1 -1
  338. package/dist/src/plugins/store/search.d.ts.map +1 -1
  339. package/dist/src/plugins/store/search.js +5 -4
  340. package/dist/src/plugins/store/search.js.map +1 -1
  341. package/dist/src/production/circuit-breaker.d.ts.map +1 -1
  342. package/dist/src/production/circuit-breaker.js +17 -3
  343. package/dist/src/production/circuit-breaker.js.map +1 -1
  344. package/dist/src/production/error-handler.d.ts.map +1 -1
  345. package/dist/src/production/error-handler.js +3 -0
  346. package/dist/src/production/error-handler.js.map +1 -1
  347. package/dist/src/production/monitoring.d.ts.map +1 -1
  348. package/dist/src/production/monitoring.js +20 -3
  349. package/dist/src/production/monitoring.js.map +1 -1
  350. package/dist/src/production/rate-limiter.d.ts.map +1 -1
  351. package/dist/src/production/rate-limiter.js +13 -4
  352. package/dist/src/production/rate-limiter.js.map +1 -1
  353. package/dist/src/production/retry.d.ts.map +1 -1
  354. package/dist/src/production/retry.js +17 -9
  355. package/dist/src/production/retry.js.map +1 -1
  356. package/dist/src/routing/embed-worker.js +6 -2
  357. package/dist/src/routing/embed-worker.js.map +1 -1
  358. package/dist/src/routing/embedder.d.ts.map +1 -1
  359. package/dist/src/routing/embedder.js +0 -0
  360. package/dist/src/routing/embedder.js.map +1 -1
  361. package/dist/src/routing/llm-caller.d.ts.map +1 -1
  362. package/dist/src/routing/llm-caller.js +13 -2
  363. package/dist/src/routing/llm-caller.js.map +1 -1
  364. package/dist/src/routing/route-layer-factory.d.ts.map +1 -1
  365. package/dist/src/routing/route-layer-factory.js +18 -3
  366. package/dist/src/routing/route-layer-factory.js.map +1 -1
  367. package/dist/src/services/claim-service.d.ts +1 -0
  368. package/dist/src/services/claim-service.d.ts.map +1 -1
  369. package/dist/src/services/claim-service.js +8 -0
  370. package/dist/src/services/claim-service.js.map +1 -1
  371. package/dist/src/services/config-file-manager.d.ts.map +1 -1
  372. package/dist/src/services/config-file-manager.js +14 -2
  373. package/dist/src/services/config-file-manager.js.map +1 -1
  374. package/dist/src/services/headless-worker-executor.d.ts.map +1 -1
  375. package/dist/src/services/headless-worker-executor.js +18 -2
  376. package/dist/src/services/headless-worker-executor.js.map +1 -1
  377. package/dist/src/services/worker-daemon.d.ts.map +1 -1
  378. package/dist/src/services/worker-daemon.js +348 -17
  379. package/dist/src/services/worker-daemon.js.map +1 -1
  380. package/dist/src/transfer/anonymization/index.d.ts +0 -3
  381. package/dist/src/transfer/anonymization/index.d.ts.map +1 -1
  382. package/dist/src/transfer/anonymization/index.js +16 -1
  383. package/dist/src/transfer/anonymization/index.js.map +1 -1
  384. package/dist/src/transfer/export.d.ts.map +1 -1
  385. package/dist/src/transfer/export.js +8 -0
  386. package/dist/src/transfer/export.js.map +1 -1
  387. package/dist/src/transfer/ipfs/upload.d.ts.map +1 -1
  388. package/dist/src/transfer/ipfs/upload.js +33 -3
  389. package/dist/src/transfer/ipfs/upload.js.map +1 -1
  390. package/dist/src/transfer/serialization/cfp.d.ts.map +1 -1
  391. package/dist/src/transfer/serialization/cfp.js +8 -2
  392. package/dist/src/transfer/serialization/cfp.js.map +1 -1
  393. package/dist/src/transfer/storage/gcs.d.ts.map +1 -1
  394. package/dist/src/transfer/storage/gcs.js +37 -3
  395. package/dist/src/transfer/storage/gcs.js.map +1 -1
  396. package/dist/src/transfer/store/discovery.d.ts.map +1 -1
  397. package/dist/src/transfer/store/discovery.js +45 -3
  398. package/dist/src/transfer/store/discovery.js.map +1 -1
  399. package/dist/src/transfer/store/download.d.ts.map +1 -1
  400. package/dist/src/transfer/store/download.js +5 -0
  401. package/dist/src/transfer/store/download.js.map +1 -1
  402. package/dist/src/transfer/store/publish.d.ts.map +1 -1
  403. package/dist/src/transfer/store/publish.js +13 -1
  404. package/dist/src/transfer/store/publish.js.map +1 -1
  405. package/dist/src/transfer/store/registry.d.ts +8 -0
  406. package/dist/src/transfer/store/registry.d.ts.map +1 -1
  407. package/dist/src/transfer/store/registry.js +30 -5
  408. package/dist/src/transfer/store/registry.js.map +1 -1
  409. package/dist/src/transfer/store/search.d.ts.map +1 -1
  410. package/dist/src/transfer/store/search.js +20 -5
  411. package/dist/src/transfer/store/search.js.map +1 -1
  412. package/dist/src/ui/collector.mjs +39 -5
  413. package/dist/src/ui/dashboard.html +1603 -1284
  414. package/dist/src/ui/orgs.html +722 -12
  415. package/dist/src/ui/server.mjs +717 -136
  416. package/dist/src/update/checker.d.ts.map +1 -1
  417. package/dist/src/update/checker.js +59 -7
  418. package/dist/src/update/checker.js.map +1 -1
  419. package/dist/src/update/executor.d.ts.map +1 -1
  420. package/dist/src/update/executor.js +50 -3
  421. package/dist/src/update/executor.js.map +1 -1
  422. package/dist/src/update/index.d.ts.map +1 -1
  423. package/dist/src/update/index.js +18 -1
  424. package/dist/src/update/index.js.map +1 -1
  425. package/dist/src/update/rate-limiter.d.ts +6 -0
  426. package/dist/src/update/rate-limiter.d.ts.map +1 -1
  427. package/dist/src/update/rate-limiter.js +79 -7
  428. package/dist/src/update/rate-limiter.js.map +1 -1
  429. package/dist/src/update/validator.d.ts.map +1 -1
  430. package/dist/src/update/validator.js +52 -1
  431. package/dist/src/update/validator.js.map +1 -1
  432. package/dist/tsconfig.tsbuildinfo +1 -1
  433. package/package.json +2 -3
  434. package/dist/src/ui/data/mastermind-events.jsonl +0 -59
@@ -22,6 +22,7 @@ const monographBuildTool = {
22
22
  path: { type: 'string', description: 'Absolute path to the repo (defaults to project cwd)' },
23
23
  codeOnly: { type: 'boolean', description: 'Only index code files (skip docs, config)' },
24
24
  force: { type: 'boolean', description: 'Force full rebuild even if index is fresh' },
25
+ incremental: { type: 'boolean', description: 'Skip rebuild when index already matches HEAD (default false). Use when you want a no-op if the graph is fresh.' },
25
26
  },
26
27
  },
27
28
  handler: async (input) => {
@@ -31,9 +32,12 @@ const monographBuildTool = {
31
32
  await buildAsync(repoPath, {
32
33
  codeOnly: input.codeOnly ?? false,
33
34
  force: input.force ?? false,
35
+ incremental: input.incremental ?? false,
34
36
  onProgress: (p) => { progressLog += `[${p.phase}] ${p.message ?? ''}\n`; },
35
37
  });
36
- return text(`Monograph build complete for ${repoPath}\n${progressLog}`);
38
+ const skipped = progressLog.includes('skipping rebuild');
39
+ const summary = skipped ? `Index was already fresh — no rebuild needed for ${repoPath}` : `Monograph build complete for ${repoPath}`;
40
+ return text(`${summary}\n${progressLog}`);
37
41
  },
38
42
  };
39
43
  // ── monograph_query ───────────────────────────────────────────────────────────
@@ -54,19 +58,38 @@ const monographQueryTool = {
54
58
  const { hybridQuery } = await import('@monoes/monograph');
55
59
  const db = openDb(getDbPath());
56
60
  try {
57
- const limit = input.limit ?? 20;
61
+ // Cap limit: passed directly to SQLite queries and hybridQuery; an
62
+ // unlimited value saturates memory with rows.
63
+ const MAX_QUERY_LIMIT = 1_000;
64
+ const rawLimit = input.limit ?? 20;
65
+ const limit = Number.isFinite(rawLimit) && rawLimit > 0
66
+ ? Math.min(Math.floor(rawLimit), MAX_QUERY_LIMIT)
67
+ : 20;
68
+ // Cap query: passed to FTS5 and hybridQuery; very long queries waste
69
+ // parse time and can stress the FTS tokenizer.
70
+ const MAX_MONOGRAPH_QUERY_LEN = 16 * 1024;
71
+ const rawQuery = input.query;
72
+ const query = typeof rawQuery === 'string' && rawQuery.length > MAX_MONOGRAPH_QUERY_LEN
73
+ ? rawQuery.slice(0, MAX_MONOGRAPH_QUERY_LEN)
74
+ : rawQuery;
58
75
  const label = input.label;
59
76
  if (process.env['MONOGRAPH_EMBEDDINGS'] === 'true') {
60
- const results = await hybridQuery(db, input.query, { limit, label });
77
+ const results = await hybridQuery(db, query, { limit, label });
61
78
  if (results.length === 0)
62
79
  return text('No results found.');
63
- const lines = results.map(r => `[${r.label ?? '?'}] ${r.name ?? r.id} ${r.filePath ?? ''} (score: ${r.score.toFixed(4)})`);
80
+ const lines = results.map(r => {
81
+ const loc = r.filePath ? (r.startLine != null ? `${r.filePath}:${r.startLine}` : r.filePath) : '';
82
+ return `[${r.label ?? '?'}] ${r.name ?? r.id} ${loc} (score: ${r.score.toFixed(4)})`;
83
+ });
64
84
  return text(lines.join('\n'));
65
85
  }
66
- const results = ftsSearch(db, input.query, limit, label);
86
+ const results = ftsSearch(db, query, limit, label);
67
87
  if (results.length === 0)
68
88
  return text('No results found.');
69
- const lines = results.map(r => `[${r.label}] ${r.name} ${r.filePath ?? ''} (score: ${r.rank.toFixed(3)})`);
89
+ const lines = results.map(r => {
90
+ const loc = r.filePath ? (r.startLine != null ? `${r.filePath}:${r.startLine}` : r.filePath) : '';
91
+ return `[${r.label}] ${r.name} ${loc} (score: ${r.rank.toFixed(3)})`;
92
+ });
70
93
  return text(lines.join('\n'));
71
94
  }
72
95
  finally {
@@ -104,7 +127,9 @@ const monographHealthTool = {
104
127
  const { execSync } = await import('child_process');
105
128
  const db = openDb(getDbPath());
106
129
  try {
107
- const meta = db.prepare("SELECT value FROM index_meta WHERE key = 'lastCommit'").get();
130
+ // The orchestrator writes the key as 'last_commit_hash' (orchestrator.ts:68).
131
+ // Fall back to legacy 'lastCommit' for indexes built with older versions.
132
+ const meta = db.prepare("SELECT value FROM index_meta WHERE key = 'last_commit_hash'").get() ?? db.prepare("SELECT value FROM index_meta WHERE key = 'lastCommit'").get();
108
133
  const lastCommit = meta?.value ?? null;
109
134
  if (!lastCommit)
110
135
  return text('Index has never been built. Run monograph_build first.');
@@ -141,10 +166,15 @@ const monographGodNodesTool = {
141
166
  const { openDb, closeDb } = await import('@monoes/monograph');
142
167
  const db = openDb(getDbPath());
143
168
  try {
144
- const limit = input.limit ?? 20;
169
+ // Cap limit: passed directly to the SQL LIMIT clause.
170
+ const MAX_GOD_NODES_LIMIT = 1_000;
171
+ const rawGodLimit = input.limit ?? 20;
172
+ const limit = Number.isFinite(rawGodLimit) && rawGodLimit > 0
173
+ ? Math.min(Math.floor(rawGodLimit), MAX_GOD_NODES_LIMIT)
174
+ : 20;
145
175
  const excluded = ['File', 'Folder', 'Community', 'Concept'];
146
176
  const rows = db.prepare(`
147
- SELECT n.id, n.label, n.name, n.file_path,
177
+ SELECT n.id, n.label, n.name, n.file_path, n.start_line,
148
178
  COUNT(DISTINCT e1.id) + COUNT(DISTINCT e2.id) AS degree,
149
179
  COUNT(DISTINCT e2.id) AS in_degree,
150
180
  COUNT(DISTINCT e1.id) AS out_degree
@@ -157,7 +187,10 @@ const monographGodNodesTool = {
157
187
  `).all(...excluded, limit);
158
188
  if (rows.length === 0)
159
189
  return text('No god nodes found. Run monograph_build first.');
160
- const lines = rows.map(r => `[${r.label}] ${r.name} degree=${r.degree} (↑${r.out_degree} ↓${r.in_degree}) ${r.file_path ?? ''}`);
190
+ const lines = rows.map(r => {
191
+ const loc = r.file_path ? (r.start_line != null ? `${r.file_path}:${r.start_line}` : r.file_path) : '';
192
+ return `[${r.label}] ${r.name} degree=${r.degree} (↑${r.out_degree} ↓${r.in_degree}) ${loc}`;
193
+ });
161
194
  return text(lines.join('\n'));
162
195
  }
163
196
  finally {
@@ -215,7 +248,15 @@ const monographShortestPathTool = {
215
248
  const path = getShortestPath(db, input.source, input.target, input.maxDepth ?? 6);
216
249
  if (!path)
217
250
  return text(`No path found between ${input.source} and ${input.target}`);
218
- return text(`Path (${path.length - 1} hops):\n${path.join(' ')}`);
251
+ // Enrich each node ID with file:line for direct LLM navigation
252
+ const enriched = path.map(nodeId => {
253
+ const row = db.prepare('SELECT label, name, file_path, start_line FROM nodes WHERE id = ? OR name = ? LIMIT 1').get(nodeId, nodeId);
254
+ if (!row)
255
+ return nodeId;
256
+ const loc = row.file_path ? (row.start_line != null ? `${row.file_path}:${row.start_line}` : row.file_path) : '';
257
+ return loc ? `${row.name ?? nodeId} [${loc}]` : (row.name ?? nodeId);
258
+ });
259
+ return text(`Path (${path.length - 1} hops):\n${enriched.join(' → ')}`);
219
260
  }
220
261
  finally {
221
262
  closeDb(db);
@@ -234,13 +275,24 @@ const monographCommunityTool = {
234
275
  required: ['id'],
235
276
  },
236
277
  handler: async (input) => {
278
+ // Validate community ID — must be a finite integer. parseInt(NaN) or a float
279
+ // would silently become 0 in SQLite (NaN → NULL → 0 coercion), which would
280
+ // return all nodes in community 0 instead of an error.
281
+ const rawId = typeof input.id === 'number' ? input.id : parseInt(String(input.id), 10);
282
+ if (!Number.isFinite(rawId) || rawId !== Math.floor(rawId)) {
283
+ return text(`Invalid community ID: ${input.id} (must be an integer)`);
284
+ }
285
+ const communityId = rawId;
237
286
  const { openDb, closeDb } = await import('@monoes/monograph');
238
287
  const db = openDb(getDbPath());
239
288
  try {
240
- const rows = db.prepare('SELECT * FROM nodes WHERE community_id = ?').all(parseInt(input.id, 10));
289
+ const rows = db.prepare('SELECT id, label, name, file_path, start_line FROM nodes WHERE community_id = ?').all(communityId);
241
290
  if (rows.length === 0)
242
- return text(`No nodes in community ${input.id}`);
243
- return text(rows.map(r => `[${r.label}] ${r.name} ${r.file_path ?? ''}`).join('\n'));
291
+ return text(`No nodes in community ${communityId}`);
292
+ return text(rows.map(r => {
293
+ const loc = r.file_path ? (r.start_line != null ? `${r.file_path}:${r.start_line}` : r.file_path) : '';
294
+ return `[${r.label}] ${r.name} ${loc}`;
295
+ }).join('\n'));
244
296
  }
245
297
  finally {
246
298
  closeDb(db);
@@ -259,9 +311,16 @@ const monographSurprisesTool = {
259
311
  const { openDb, closeDb } = await import('@monoes/monograph');
260
312
  const db = openDb(getDbPath());
261
313
  try {
262
- const limit = input.limit ?? 20;
314
+ // Cap limit: passed directly to the SQL LIMIT clause.
315
+ const MAX_SURPRISES_LIMIT = 1_000;
316
+ const rawSurprisesLimit = input.limit ?? 20;
317
+ const limit = Number.isFinite(rawSurprisesLimit) && rawSurprisesLimit > 0
318
+ ? Math.min(Math.floor(rawSurprisesLimit), MAX_SURPRISES_LIMIT)
319
+ : 20;
263
320
  const rows = db.prepare(`
264
- SELECT e.*, n1.name as src_name, n2.name as tgt_name
321
+ SELECT e.confidence, e.confidence_score, e.relation,
322
+ n1.name as src_name, n1.file_path as src_file, n1.start_line as src_line,
323
+ n2.name as tgt_name, n2.file_path as tgt_file, n2.start_line as tgt_line
265
324
  FROM edges e
266
325
  JOIN nodes n1 ON n1.id = e.source_id
267
326
  JOIN nodes n2 ON n2.id = e.target_id
@@ -270,7 +329,12 @@ const monographSurprisesTool = {
270
329
  `).all(limit);
271
330
  if (rows.length === 0)
272
331
  return text('No surprising connections found.');
273
- return text(rows.map(r => `[${r.confidence}] ${r.src_name} --${r.relation}--> ${r.tgt_name} (score: ${r.confidence_score})`).join('\n'));
332
+ return text(rows.map(r => {
333
+ const srcLoc = r.src_file ? (r.src_line != null ? `${r.src_file}:${r.src_line}` : r.src_file) : '';
334
+ const tgtLoc = r.tgt_file ? (r.tgt_line != null ? `${r.tgt_file}:${r.tgt_line}` : r.tgt_file) : '';
335
+ const locHint = srcLoc || tgtLoc ? ` [${srcLoc}${tgtLoc ? ` → ${tgtLoc}` : ''}]` : '';
336
+ return `[${r.confidence}] ${r.src_name} --${r.relation}--> ${r.tgt_name} (score: ${r.confidence_score})${locHint}`;
337
+ }).join('\n'));
274
338
  }
275
339
  finally {
276
340
  closeDb(db);
@@ -293,8 +357,26 @@ const monographSuggestTool = {
293
357
  const { hybridQuery } = await import('@monoes/monograph');
294
358
  const db = openDb(getDbPath());
295
359
  try {
296
- const limit = input.limit ?? 10;
297
- const task = input.task ?? '';
360
+ // Cap limit and task: limit is passed directly to SQL LIMIT clause;
361
+ // task is forwarded to hybridQuery (embedding path) or FTS.
362
+ const MAX_SUGGEST_LIMIT = 1_000;
363
+ const MAX_SUGGEST_TASK_LEN = 16 * 1024;
364
+ const rawSuggestLimit = input.limit ?? 10;
365
+ const limit = Number.isFinite(rawSuggestLimit) && rawSuggestLimit > 0
366
+ ? Math.min(Math.floor(rawSuggestLimit), MAX_SUGGEST_LIMIT)
367
+ : 10;
368
+ const rawTask = input.task ?? '';
369
+ const task = typeof rawTask === 'string' && rawTask.length > MAX_SUGGEST_TASK_LEN
370
+ ? rawTask.slice(0, MAX_SUGGEST_TASK_LEN)
371
+ : rawTask;
372
+ // Format a suggestion row as a navigable string for LLM consumption.
373
+ // Includes file:line references so the LLM can jump directly to the code.
374
+ const formatSuggestion = (r) => {
375
+ const srcLoc = r.src_file ? (r.src_line != null ? `${r.src_file}:${r.src_line}` : r.src_file) : '';
376
+ const tgtLoc = r.tgt_file ? (r.tgt_line != null ? `${r.tgt_file}:${r.tgt_line}` : r.tgt_file) : '';
377
+ const locHint = srcLoc ? ` [${srcLoc}${tgtLoc ? ` → ${tgtLoc}` : ''}]` : '';
378
+ return `Why does ${r.src} ${r.relation.toLowerCase()} ${r.tgt}? (${r.confidence})${locHint}`;
379
+ };
298
380
  // When a task is provided and embeddings are enabled, use semantic search
299
381
  // to find relevant nodes and surface edge-level questions about them.
300
382
  if (task && process.env['MONOGRAPH_EMBEDDINGS'] === 'true') {
@@ -304,7 +386,9 @@ const monographSuggestTool = {
304
386
  return text('No suggestions for this task. Run monograph_build first or try a different query.');
305
387
  }
306
388
  const rows = db.prepare(`
307
- SELECT e.relation, e.confidence, n1.name as src, n2.name as tgt, n1.file_path as src_file
389
+ SELECT e.relation, e.confidence, n1.name as src, n2.name as tgt,
390
+ n1.file_path as src_file, n1.start_line as src_line,
391
+ n2.file_path as tgt_file, n2.start_line as tgt_line
308
392
  FROM edges e
309
393
  JOIN nodes n1 ON n1.id = e.source_id
310
394
  JOIN nodes n2 ON n2.id = e.target_id
@@ -313,11 +397,13 @@ const monographSuggestTool = {
313
397
  AND e.confidence IN ('AMBIGUOUS', 'INFERRED')
314
398
  LIMIT 100
315
399
  `).all(...[...hitIds], ...[...hitIds]);
316
- const questions = rows.map(r => `Why does ${r.src} ${r.relation.toLowerCase()} ${r.tgt}? (${r.confidence})`);
400
+ const questions = rows.map(formatSuggestion);
317
401
  return text(questions.slice(0, limit).join('\n') || 'No suggestions for this task. Run monograph_build first.');
318
402
  }
319
403
  const rows = db.prepare(`
320
- SELECT e.relation, e.confidence, n1.name as src, n2.name as tgt, n1.file_path as src_file
404
+ SELECT e.relation, e.confidence, n1.name as src, n2.name as tgt,
405
+ n1.file_path as src_file, n1.start_line as src_line,
406
+ n2.file_path as tgt_file, n2.start_line as tgt_line
321
407
  FROM edges e
322
408
  JOIN nodes n1 ON n1.id = e.source_id
323
409
  JOIN nodes n2 ON n2.id = e.target_id
@@ -325,7 +411,7 @@ const monographSuggestTool = {
325
411
  LIMIT 100
326
412
  `).all();
327
413
  let scored = rows.map(r => ({
328
- q: `Why does ${r.src} ${r.relation.toLowerCase()} ${r.tgt}? (${r.confidence})`,
414
+ q: formatSuggestion(r),
329
415
  relevance: task ? taskRelevance(task, r.src + ' ' + r.tgt + ' ' + (r.src_file ?? '')) : 0,
330
416
  }));
331
417
  if (task)
@@ -357,7 +443,13 @@ const monographVisualizeTool = {
357
443
  const { openDb, closeDb, toJson, toHtml, toSvg } = await import('@monoes/monograph');
358
444
  const db = openDb(getDbPath());
359
445
  try {
360
- const limit = input.maxNodes ?? 500;
446
+ // Cap maxNodes: passed to SQL LIMIT clause for both nodes (n) and edges
447
+ // (n*3). Without a cap an attacker requests all rows from both tables.
448
+ const MAX_EXPORT_NODES = 10_000;
449
+ const rawMaxNodes = input.maxNodes ?? 500;
450
+ const limit = Number.isFinite(rawMaxNodes) && rawMaxNodes > 0
451
+ ? Math.min(Math.floor(rawMaxNodes), MAX_EXPORT_NODES)
452
+ : 500;
361
453
  const nodes = db.prepare('SELECT * FROM nodes LIMIT ?').all(limit);
362
454
  const edges = db.prepare('SELECT * FROM edges LIMIT ?').all(limit * 3);
363
455
  const fmt = input.format ?? 'html';
@@ -420,7 +512,7 @@ const monographReportTool = {
420
512
  const nodeCount = countNodes(db);
421
513
  const edgeCount = countEdges(db);
422
514
  const topNodes = db.prepare(`
423
- SELECT n.name, n.label, n.file_path,
515
+ SELECT n.name, n.label, n.file_path, n.start_line,
424
516
  COUNT(DISTINCT e1.id) + COUNT(DISTINCT e2.id) AS degree
425
517
  FROM nodes n
426
518
  LEFT JOIN edges e1 ON e1.source_id = n.id
@@ -433,7 +525,10 @@ const monographReportTool = {
433
525
  `**Generated:** ${new Date().toISOString()}`,
434
526
  `**Nodes:** ${nodeCount} **Edges:** ${edgeCount}\n`,
435
527
  '## Top 10 Most Connected Entities\n',
436
- ...topNodes.map((n, i) => `${i + 1}. **${n.name}** (${n.label}) — degree ${n.degree} \`${n.file_path ?? ''}\``),
528
+ ...topNodes.map((n, i) => {
529
+ const loc = n.file_path ? (n.start_line != null ? `${n.file_path}:${n.start_line}` : n.file_path) : '';
530
+ return `${i + 1}. **${n.name}** (${n.label}) — degree ${n.degree}${loc ? ` \`${loc}\`` : ''}`;
531
+ }),
437
532
  ].join('\n');
438
533
  const outPath = resolve(input.path ?? join(getProjectCwd(), '.monomind', 'GRAPH_REPORT.md'));
439
534
  const allowedRoot = resolve(getProjectCwd());
@@ -442,7 +537,7 @@ const monographReportTool = {
442
537
  }
443
538
  mkdirSync(join(outPath, '..'), { recursive: true });
444
539
  writeFileSync(outPath, report);
445
- return text(`Report written to ${outPath}`);
540
+ return text(`${report}\n\nReport written to ${outPath}`);
446
541
  }
447
542
  finally {
448
543
  closeDb(db);
@@ -462,8 +557,24 @@ const monographStalenessTool = {
462
557
  handler: async (input) => {
463
558
  const { getMonographStaleness } = await import('@monoes/monograph');
464
559
  const repoPath = input.path ?? getProjectCwd();
465
- const report = await getMonographStaleness(repoPath);
466
- return text(JSON.stringify(report, null, 2));
560
+ const r = await getMonographStaleness(repoPath);
561
+ if (!r.indexedCommit && !r.currentCommit) {
562
+ return text('Index has never been built or repo has no git history. Run monograph_build first.');
563
+ }
564
+ const statusLine = r.isStale
565
+ ? `STALE — index at ${r.indexedCommit}, HEAD at ${r.currentCommit}`
566
+ : `FRESH — index matches HEAD (${r.currentCommit})`;
567
+ const lines = [`Staleness: ${statusLine}`];
568
+ if (r.staleSince)
569
+ lines.push(`Stale since: ${r.staleSince}`);
570
+ if (r.changedSince.length > 0) {
571
+ const shown = r.changedSince.slice(0, 10);
572
+ const more = r.changedSince.length - shown.length;
573
+ lines.push(`Changed files (${r.changedSince.length}):${shown.map(f => `\n ${f}`).join('')}${more > 0 ? `\n … ${more} more` : ''}`);
574
+ }
575
+ if (r.isStale)
576
+ lines.push('Action: run monograph_build to re-index');
577
+ return text(lines.join('\n'));
467
578
  },
468
579
  };
469
580
  // ── monograph_snapshot ────────────────────────────────────────────────────────
@@ -479,13 +590,19 @@ const monographSnapshotTool = {
479
590
  handler: async (input) => {
480
591
  const { openDb, closeDb, snapshotFromDb } = await import('@monoes/monograph');
481
592
  const { writeFileSync, mkdirSync } = await import('fs');
593
+ const { resolve: resolvePath } = await import('path');
482
594
  const db = openDb(getDbPath());
483
595
  try {
484
596
  const snapshot = snapshotFromDb(db);
485
- const name = input.name ?? new Date().toISOString().replace(/[:.]/g, '-');
486
- const snapshotDir = join(getProjectCwd(), '.monomind', 'snapshots');
597
+ const rawName = input.name ?? new Date().toISOString().replace(/[:.]/g, '-');
598
+ const SAFE_NAME_RE = /^[a-zA-Z0-9_.\-]+$/;
599
+ if (!SAFE_NAME_RE.test(rawName))
600
+ return text(`Invalid snapshot name: ${rawName}`);
601
+ const snapshotDir = resolvePath(join(getProjectCwd(), '.monomind', 'snapshots'));
487
602
  mkdirSync(snapshotDir, { recursive: true });
488
- const outPath = join(snapshotDir, `${name}.json`);
603
+ const outPath = join(snapshotDir, `${rawName}.json`);
604
+ if (!resolvePath(outPath).startsWith(snapshotDir))
605
+ return text(`Path traversal detected in snapshot name`);
489
606
  writeFileSync(outPath, JSON.stringify(snapshot, null, 2));
490
607
  return text(`Snapshot saved: ${outPath}\n nodes: ${snapshot.nodes.length} edges: ${snapshot.edges.length}`);
491
608
  }
@@ -508,18 +625,37 @@ const monographDiffTool = {
508
625
  },
509
626
  handler: async (input) => {
510
627
  const { openDb, closeDb, snapshotFromDb, diffSnapshots } = await import('@monoes/monograph');
511
- const { readFileSync, existsSync } = await import('fs');
512
- const snapshotDir = join(getProjectCwd(), '.monomind', 'snapshots');
513
- const beforePath = join(snapshotDir, `${input.before}.json`);
628
+ const { readFileSync, existsSync, statSync: statSyncSnap } = await import('fs');
629
+ const { resolve: resolvePath } = await import('path');
630
+ const MAX_SNAPSHOT_BYTES = 100 * 1024 * 1024; // 100 MB
631
+ const snapshotDir = resolvePath(join(getProjectCwd(), '.monomind', 'snapshots'));
632
+ // Reject snapshot names containing path separators or traversal sequences
633
+ const SAFE_SNAPSHOT_NAME = /^[a-zA-Z0-9_.\-]+$/;
634
+ const beforeName = input.before;
635
+ if (!SAFE_SNAPSHOT_NAME.test(beforeName))
636
+ return text(`Invalid snapshot name: ${beforeName}`);
637
+ const beforePath = join(snapshotDir, `${beforeName}.json`);
638
+ if (!resolvePath(beforePath).startsWith(snapshotDir))
639
+ return text(`Path traversal detected in snapshot name`);
514
640
  if (!existsSync(beforePath)) {
515
641
  return text(`Snapshot not found: ${beforePath}\nCreate one first with monograph_snapshot.`);
516
642
  }
643
+ if (statSyncSnap(beforePath).size > MAX_SNAPSHOT_BYTES) {
644
+ return text(`Snapshot too large to diff: ${beforePath}`);
645
+ }
517
646
  const before = JSON.parse(readFileSync(beforePath, 'utf-8'));
518
647
  let after;
519
648
  if (input.after) {
520
- const afterPath = join(snapshotDir, `${input.after}.json`);
649
+ const afterName = input.after;
650
+ if (!SAFE_SNAPSHOT_NAME.test(afterName))
651
+ return text(`Invalid snapshot name: ${afterName}`);
652
+ const afterPath = join(snapshotDir, `${afterName}.json`);
653
+ if (!resolvePath(afterPath).startsWith(snapshotDir))
654
+ return text(`Path traversal detected in snapshot name`);
521
655
  if (!existsSync(afterPath))
522
656
  return text(`Snapshot not found: ${afterPath}`);
657
+ if (statSyncSnap(afterPath).size > MAX_SNAPSHOT_BYTES)
658
+ return text(`Snapshot too large to diff: ${afterPath}`);
523
659
  after = JSON.parse(readFileSync(afterPath, 'utf-8'));
524
660
  }
525
661
  else {
@@ -532,13 +668,33 @@ const monographDiffTool = {
532
668
  }
533
669
  }
534
670
  const diff = diffSnapshots(before, after);
671
+ const nodeById = new Map();
672
+ const indexNodes = (nodes) => {
673
+ for (const n of nodes) {
674
+ if (n.id)
675
+ nodeById.set(n.id, n);
676
+ }
677
+ };
678
+ indexNodes(before.nodes);
679
+ indexNodes(after.nodes);
680
+ const resolveEdgeEnd = (id) => {
681
+ const ref = nodeById.get(id);
682
+ if (!ref)
683
+ return id; // fallback to raw id if not found
684
+ const loc = ref.filePath ? (ref.startLine != null ? `${ref.filePath}:${ref.startLine}` : ref.filePath) : '';
685
+ return loc ? `${ref.name} [${loc}]` : ref.name;
686
+ };
535
687
  const section = (label, items) => items.length > 0 ? `\n${label} (${items.length}):\n${items.slice(0, 10).join('\n')}${items.length > 10 ? `\n … ${items.length - 10} more` : ''}` : '';
688
+ const formatNode = (n) => {
689
+ const loc = n.filePath ? (n.startLine != null ? `${n.filePath}:${n.startLine}` : n.filePath) : '';
690
+ return ` [${n.label ?? '?'}] ${n.name ?? '?'}${loc ? ` ${loc}` : ''}`;
691
+ };
536
692
  const lines = [
537
693
  `Diff: ${diff.summary}`,
538
- section('New nodes', diff.newNodes.map(n => ` + [${n.label}] ${n.name} ${n.filePath ?? ''}`)),
539
- section('Removed nodes', diff.removedNodes.map(n => ` - [${n.label}] ${n.name} ${n.filePath ?? ''}`)),
540
- section('New edges', diff.newEdges.map(e => ` + ${e.sourceId} --[${e.relation}]--> ${e.targetId}`)),
541
- section('Removed edges', diff.removedEdges.map(e => ` - ${e.sourceId} --[${e.relation}]--> ${e.targetId}`)),
694
+ section('New nodes', diff.newNodes.map(n => ` + ${formatNode(n)}`)),
695
+ section('Removed nodes', diff.removedNodes.map(n => ` - ${formatNode(n)}`)),
696
+ section('New edges', diff.newEdges.map(e => ` + ${resolveEdgeEnd(e.sourceId)} --[${e.relation}]--> ${resolveEdgeEnd(e.targetId)}`)),
697
+ section('Removed edges', diff.removedEdges.map(e => ` - ${resolveEdgeEnd(e.sourceId)} --[${e.relation}]--> ${resolveEdgeEnd(e.targetId)}`)),
542
698
  ].join('');
543
699
  return text(lines);
544
700
  },
@@ -614,11 +770,52 @@ const monographContextTool = {
614
770
  const { getMonographContext } = await import('@monoes/monograph');
615
771
  const db = openDb(getDbPath());
616
772
  try {
773
+ // Cap name and filePath: forwarded to parameterized SQL via getMonographContext.
774
+ // Very long strings waste memory before the query even executes.
775
+ const MAX_CTX_NAME_LEN = 512;
776
+ const MAX_CTX_PATH_LEN = 4 * 1024;
777
+ const rawCtxName = input.name;
778
+ const ctxName = typeof rawCtxName === 'string' && rawCtxName.length > MAX_CTX_NAME_LEN
779
+ ? rawCtxName.slice(0, MAX_CTX_NAME_LEN) : rawCtxName;
780
+ const rawCtxPath = input.filePath;
781
+ const ctxPath = typeof rawCtxPath === 'string' && rawCtxPath.length > MAX_CTX_PATH_LEN
782
+ ? rawCtxPath.slice(0, MAX_CTX_PATH_LEN) : rawCtxPath;
617
783
  const result = getMonographContext(db, {
618
- name: input.name,
619
- filePath: input.filePath,
784
+ name: ctxName,
785
+ filePath: ctxPath,
620
786
  });
621
- return text(JSON.stringify(result, null, 2));
787
+ if (!result || !result.node)
788
+ return text(`No symbol found: ${ctxName}`);
789
+ // Format context as structured text for direct LLM consumption
790
+ const n = result.node;
791
+ const loc = n.filePath ? (n.startLine != null ? `${n.filePath}:${n.startLine}` : n.filePath) : '';
792
+ const lines = [
793
+ `[${n.label ?? '?'}] ${n.name} ${loc}`,
794
+ '',
795
+ ];
796
+ const formatNodes = (nodes, label) => {
797
+ if (!Array.isArray(nodes) || nodes.length === 0)
798
+ return;
799
+ lines.push(`${label} (${nodes.length}):`);
800
+ for (const node of nodes.slice(0, 20)) {
801
+ const fp = node.filePath ?? node.file_path ?? '';
802
+ const ln = node.startLine ?? node.start_line;
803
+ const nodeLoc = fp ? (ln != null ? `${fp}:${ln}` : fp) : '';
804
+ lines.push(` [${node.label ?? '?'}] ${node.name ?? node.id} ${nodeLoc}`);
805
+ }
806
+ if (nodes.length > 20)
807
+ lines.push(` … ${nodes.length - 20} more`);
808
+ lines.push('');
809
+ };
810
+ formatNodes(result.callers, 'Callers');
811
+ formatNodes(result.callees, 'Callees');
812
+ formatNodes(result.imports, 'Imports');
813
+ formatNodes(result.importedBy, 'ImportedBy');
814
+ if (result.community != null)
815
+ lines.push(`Community: ${result.community}`);
816
+ if (result.communityName)
817
+ lines.push(`Community name: ${result.communityName}`);
818
+ return text(lines.join('\n').trim());
622
819
  }
623
820
  finally {
624
821
  closeDb(db);
@@ -643,12 +840,52 @@ const monographImpactTool = {
643
840
  const { getMonographImpact } = await import('@monoes/monograph');
644
841
  const db = openDb(getDbPath());
645
842
  try {
843
+ // Cap name/filePath; enforce depth ≤ 6 as documented in the schema description.
844
+ const MAX_IMPACT_NAME_LEN = 512;
845
+ const MAX_IMPACT_PATH_LEN = 4 * 1024;
846
+ const rawImpactName = input.name;
847
+ const impactName = typeof rawImpactName === 'string' && rawImpactName.length > MAX_IMPACT_NAME_LEN
848
+ ? rawImpactName.slice(0, MAX_IMPACT_NAME_LEN) : rawImpactName;
849
+ const rawImpactPath = input.filePath;
850
+ const impactPath = typeof rawImpactPath === 'string' && rawImpactPath.length > MAX_IMPACT_PATH_LEN
851
+ ? rawImpactPath.slice(0, MAX_IMPACT_PATH_LEN) : rawImpactPath;
852
+ const rawDepth = input.depth;
853
+ const depth = typeof rawDepth === 'number' && Number.isFinite(rawDepth) && rawDepth > 0
854
+ ? Math.min(Math.floor(rawDepth), 6) : rawDepth;
646
855
  const result = getMonographImpact(db, {
647
- name: input.name,
648
- filePath: input.filePath,
649
- depth: input.depth,
856
+ name: impactName,
857
+ filePath: impactPath,
858
+ depth,
650
859
  });
651
- return text(JSON.stringify(result, null, 2));
860
+ if (!result || !result.root)
861
+ return text(`No symbol found: ${impactName}`);
862
+ // Format impact as structured text for direct LLM consumption
863
+ const root = result.root;
864
+ const rootLoc = root.filePath ? (root.startLine != null ? `${root.filePath}:${root.startLine}` : root.filePath) : '';
865
+ const lines = [
866
+ `[${root.label ?? '?'}] ${root.name} ${rootLoc}`,
867
+ '',
868
+ `Blast radius: ${result.totalAffected ?? 0} symbols affected`,
869
+ ];
870
+ if (result.riskScore != null) {
871
+ const riskLabel = result.riskScore >= 0.8 ? 'HIGH' : result.riskScore >= 0.5 ? 'MEDIUM' : 'LOW';
872
+ lines.push(`Risk score: ${result.riskScore.toFixed(2)} (${riskLabel})`);
873
+ }
874
+ lines.push('');
875
+ const affected = (result.affected ?? result.callers ?? []);
876
+ if (affected.length > 0) {
877
+ lines.push(`Affected callers (${affected.length}):`);
878
+ for (const sym of affected.slice(0, 20)) {
879
+ const fp = sym.filePath ?? sym.file_path ?? '';
880
+ const ln = sym.startLine ?? sym.start_line;
881
+ const symLoc = fp ? (ln != null ? `${fp}:${ln}` : fp) : '';
882
+ const depth_marker = sym.depth != null ? ` [depth ${sym.depth}]` : '';
883
+ lines.push(` [${sym.label ?? '?'}] ${sym.name ?? sym.id} ${symLoc}${depth_marker}`);
884
+ }
885
+ if (affected.length > 20)
886
+ lines.push(` … ${affected.length - 20} more`);
887
+ }
888
+ return text(lines.join('\n').trim());
652
889
  }
653
890
  finally {
654
891
  closeDb(db);
@@ -675,7 +912,35 @@ const monographDetectChangesTool = {
675
912
  baseBranch: input.baseBranch,
676
913
  includeTests: input.includeTests,
677
914
  }, getProjectCwd());
678
- return text(JSON.stringify(result, null, 2));
915
+ // Format as structured text for direct LLM navigation instead of raw JSON
916
+ const r = result;
917
+ if (!r || (!r.changedFiles?.length && !r.affectedSymbols?.length)) {
918
+ return text('No changed files found relative to the base branch.');
919
+ }
920
+ const lines = [];
921
+ const base = r.baseBranch ?? 'main';
922
+ const changedFiles = r.changedFiles ?? [];
923
+ lines.push(`Changed files vs ${base}: ${changedFiles.length}`);
924
+ if (changedFiles.length > 0) {
925
+ for (const f of changedFiles.slice(0, 20))
926
+ lines.push(` ${f}`);
927
+ if (changedFiles.length > 20)
928
+ lines.push(` … ${changedFiles.length - 20} more`);
929
+ }
930
+ lines.push('');
931
+ const affected = r.affectedSymbols ?? r.affected ?? [];
932
+ if (affected.length > 0) {
933
+ lines.push(`Affected symbols (${affected.length}):`);
934
+ for (const sym of affected.slice(0, 30)) {
935
+ const fp = sym.filePath ?? sym.file_path ?? '';
936
+ const ln = sym.startLine ?? sym.start_line;
937
+ const loc = fp ? (ln != null ? `${fp}:${ln}` : fp) : '';
938
+ lines.push(` [${sym.label ?? '?'}] ${sym.name ?? sym.id} ${loc}`);
939
+ }
940
+ if (affected.length > 30)
941
+ lines.push(` … ${affected.length - 30} more`);
942
+ }
943
+ return text(lines.join('\n').trim());
679
944
  }
680
945
  finally {
681
946
  closeDb(db);
@@ -707,7 +972,25 @@ const monographRenameTool = {
707
972
  filePath: input.filePath,
708
973
  dryRun: input.dryRun ?? true,
709
974
  });
710
- return text(JSON.stringify(result, null, 2));
975
+ // Format as structured text for direct LLM navigation instead of raw JSON
976
+ const rn = result;
977
+ if (!rn)
978
+ return text(`Symbol not found: ${input.oldName}`);
979
+ const occurrences = rn.occurrences ?? rn.references ?? [];
980
+ const lines = [
981
+ `Rename: ${input.oldName} → ${input.newName} (dry-run)`,
982
+ `Occurrences: ${occurrences.length}`,
983
+ '',
984
+ ];
985
+ for (const occ of occurrences.slice(0, 30)) {
986
+ const fp = occ.filePath ?? occ.file_path ?? '';
987
+ const ln = occ.line ?? occ.startLine ?? occ.start_line;
988
+ const loc = fp ? (ln != null ? `${fp}:${ln}` : fp) : '';
989
+ lines.push(` ${loc || occ}`);
990
+ }
991
+ if (occurrences.length > 30)
992
+ lines.push(` … ${occurrences.length - 30} more`);
993
+ return text(lines.join('\n').trim());
711
994
  }
712
995
  finally {
713
996
  closeDb(db);
@@ -736,7 +1019,17 @@ const monographRouteMapTool = {
736
1019
  method: input.method,
737
1020
  includeMiddleware: input.includeMiddleware,
738
1021
  });
739
- return text(JSON.stringify(result, null, 2));
1022
+ if (result.routes.length === 0)
1023
+ return text('No routes found. Run monograph_build first or adjust your filters.');
1024
+ const lines = [`Routes (${result.total} total):`];
1025
+ for (const r of result.routes) {
1026
+ const loc = r.handlerFile
1027
+ ? (r.handlerLine != null ? `${r.handlerFile}:${r.handlerLine}` : r.handlerFile)
1028
+ : '';
1029
+ const mw = r.middlewareChain.length > 0 ? ` middleware: ${r.middlewareChain.join(' → ')}` : '';
1030
+ lines.push(` ${r.method} ${r.path}${r.handlerName ? ` → ${r.handlerName}` : ''}${loc ? ` (${loc})` : ''}${mw}`);
1031
+ }
1032
+ return text(lines.join('\n'));
740
1033
  }
741
1034
  finally {
742
1035
  closeDb(db);
@@ -764,7 +1057,33 @@ const monographApiImpactTool = {
764
1057
  routePath: input.routePath,
765
1058
  method: input.method,
766
1059
  });
767
- return text(JSON.stringify(result, null, 2));
1060
+ if (!result.route)
1061
+ return text(`Route not found: ${input.routePath}. Run monograph_build or check the path.`);
1062
+ const riskLabel = result.riskScore >= 0.7 ? 'HIGH' : result.riskScore >= 0.4 ? 'MEDIUM' : 'LOW';
1063
+ const lines = [
1064
+ `Route: ${result.route.method} ${result.route.path} risk=${riskLabel} (${result.riskScore.toFixed(2)})`,
1065
+ ];
1066
+ if (result.handler) {
1067
+ const hLoc = result.handler.filePath
1068
+ ? (result.handler.startLine != null ? `${result.handler.filePath}:${result.handler.startLine}` : result.handler.filePath)
1069
+ : '';
1070
+ lines.push(`Handler: ${result.handler.name}${hLoc ? ` ${hLoc}` : ''}`);
1071
+ }
1072
+ if (result.callees.length > 0) {
1073
+ lines.push(`Callees (${result.callees.length}):`);
1074
+ for (const c of result.callees.slice(0, 15)) {
1075
+ const loc = c.node.filePath
1076
+ ? (c.node.startLine != null ? `${c.node.filePath}:${c.node.startLine}` : c.node.filePath)
1077
+ : '';
1078
+ lines.push(` ${' '.repeat(c.depth)}→ ${c.node.name} [${c.node.label}]${loc ? ` ${loc}` : ''}`);
1079
+ }
1080
+ if (result.callees.length > 15)
1081
+ lines.push(` … ${result.callees.length - 15} more`);
1082
+ }
1083
+ if (result.affectedProcesses.length > 0) {
1084
+ lines.push(`Affected processes: ${result.affectedProcesses.map(p => p.name).join(', ')}`);
1085
+ }
1086
+ return text(lines.join('\n'));
768
1087
  }
769
1088
  finally {
770
1089
  closeDb(db);
@@ -818,7 +1137,14 @@ const monographCypherTool = {
818
1137
  const { getMonographCypher } = await import('@monoes/monograph');
819
1138
  const db = openDb(getDbPath());
820
1139
  try {
821
- const result = getMonographCypher(db, input.query);
1140
+ // Cap query: forwarded to the Cypher query engine; very long strings
1141
+ // waste parse time and can stress the query compiler.
1142
+ const MAX_CYPHER_QUERY_LEN = 16 * 1024;
1143
+ const rawCypherQuery = input.query;
1144
+ const cypherQuery = typeof rawCypherQuery === 'string' && rawCypherQuery.length > MAX_CYPHER_QUERY_LEN
1145
+ ? rawCypherQuery.slice(0, MAX_CYPHER_QUERY_LEN)
1146
+ : rawCypherQuery;
1147
+ const result = getMonographCypher(db, cypherQuery);
822
1148
  if (result.error)
823
1149
  return text(`Error: ${result.error}`);
824
1150
  if (result.rows.length === 0)
@@ -846,7 +1172,15 @@ const monographGroupListTool = {
846
1172
  const { getGroupList } = await import('@monoes/monograph');
847
1173
  const configPath = input.configPath ?? join(getProjectCwd(), 'group.yaml');
848
1174
  const result = await getGroupList(configPath);
849
- return text(JSON.stringify(result, null, 2));
1175
+ if (!result.repos || result.repos.length === 0) {
1176
+ return text(`Group: ${result.group?.name ?? 'unknown'}\nNo repos configured. Check ${configPath}`);
1177
+ }
1178
+ const lines = [`Group: ${result.group?.name ?? 'unknown'} (${result.repos.length} repos)`];
1179
+ for (const r of result.repos) {
1180
+ const indexed = r.indexedAt ? r.indexedAt.slice(0, 10) : 'never';
1181
+ lines.push(` ${r.name} nodes=${r.nodeCount} indexed=${indexed} ${r.path}`);
1182
+ }
1183
+ return text(lines.join('\n'));
850
1184
  },
851
1185
  };
852
1186
  // ── monograph_group_query ─────────────────────────────────────────────────────
@@ -865,7 +1199,18 @@ const monographGroupQueryTool = {
865
1199
  handler: async (input) => {
866
1200
  const { runGroupQuery } = await import('@monoes/monograph');
867
1201
  const configPath = input.configPath ?? join(getProjectCwd(), 'group.yaml');
868
- const results = await runGroupQuery(configPath, input.query, input.limit);
1202
+ // Cap query and limit forwarded to runGroupQuery.
1203
+ const MAX_GROUP_QUERY_LEN = 16 * 1024;
1204
+ const MAX_GROUP_LIMIT = 1_000;
1205
+ const rawGroupQuery = input.query;
1206
+ const groupQuery = typeof rawGroupQuery === 'string' && rawGroupQuery.length > MAX_GROUP_QUERY_LEN
1207
+ ? rawGroupQuery.slice(0, MAX_GROUP_QUERY_LEN)
1208
+ : rawGroupQuery;
1209
+ const rawGroupLimit = input.limit;
1210
+ const groupLimit = Number.isFinite(rawGroupLimit) && (rawGroupLimit ?? 0) > 0
1211
+ ? Math.min(Math.floor(rawGroupLimit), MAX_GROUP_LIMIT)
1212
+ : rawGroupLimit;
1213
+ const results = await runGroupQuery(configPath, groupQuery, groupLimit);
869
1214
  if (results.length === 0)
870
1215
  return text('No results found.');
871
1216
  const lines = results.map(r => `[${r.label}] ${r.name} ${r.filePath ?? ''} repo:${r.repo} (score: ${r.score.toFixed(4)})`);
@@ -888,7 +1233,12 @@ const monographWikiTool = {
888
1233
  const db = openDb(getDbPath());
889
1234
  try {
890
1235
  const result = getWikiToolResult(db, { communityId: input.communityId });
891
- return text(JSON.stringify(result, null, 2));
1236
+ if (result.pages.length === 0) {
1237
+ return text('No wiki pages found. Run monograph_wiki_build to generate community wiki pages.');
1238
+ }
1239
+ // Return pages as readable prose — content is already LLM-generated markdown.
1240
+ const sections = result.pages.map(p => `--- Community ${p.communityId} ---\n${p.content}`);
1241
+ return text(sections.join('\n\n'));
892
1242
  }
893
1243
  finally {
894
1244
  closeDb(db);
@@ -917,7 +1267,16 @@ const monographWikiBuildTool = {
917
1267
  force: input.force,
918
1268
  model: input.model,
919
1269
  });
920
- return text(JSON.stringify(result, null, 2));
1270
+ if (result.error)
1271
+ return text(`Wiki build failed: ${result.error}`);
1272
+ const parts = [];
1273
+ if (result.generated != null)
1274
+ parts.push(`${result.generated} page(s) generated`);
1275
+ if (result.skipped != null && result.skipped > 0)
1276
+ parts.push(`${result.skipped} skipped (already exist)`);
1277
+ if (result.errors != null && result.errors > 0)
1278
+ parts.push(`${result.errors} error(s)`);
1279
+ return text(`Wiki build complete: ${parts.join(', ') || 'nothing to do'}. Use monograph_wiki to read the pages.`);
921
1280
  }
922
1281
  finally {
923
1282
  closeDb(db);
@@ -965,7 +1324,13 @@ const monographToolMapTool = {
965
1324
  const results = getToolMap(db, { tool: input.tool });
966
1325
  if (results.length === 0)
967
1326
  return text('No tools found. Run monograph_build first.');
968
- return text(JSON.stringify(results, null, 2));
1327
+ const lines = results.map(r => {
1328
+ const loc = r.handlerFile
1329
+ ? (r.handlerLine != null ? `${r.handlerFile}:${r.handlerLine}` : r.handlerFile)
1330
+ : (r.filePath ?? '');
1331
+ return `${r.name}${r.handlerName ? ` → ${r.handlerName}` : ''}${loc ? ` (${loc})` : ''}`;
1332
+ });
1333
+ return text(`Tools (${results.length}):\n${lines.join('\n')}`);
969
1334
  }
970
1335
  finally {
971
1336
  closeDb(db);
@@ -993,7 +1358,38 @@ const monographShapeCheckTool = {
993
1358
  route: input.route,
994
1359
  file: input.file,
995
1360
  });
996
- return text(JSON.stringify(result, null, 2));
1361
+ // Render as structured text so LLMs can act on it directly without parsing JSON.
1362
+ const lines = [];
1363
+ lines.push(`Shape check: ${result.message}`);
1364
+ if (result.route) {
1365
+ const handlerLoc = result.route.handlerFile
1366
+ ? ` Handler: ${result.route.handlerName} [${result.route.handlerFile}]`
1367
+ : ` Handler: ${result.route.handlerName}`;
1368
+ lines.push(`Route: ${result.route.method} ${result.route.path}`);
1369
+ lines.push(handlerLoc);
1370
+ }
1371
+ if (result.shape.returnedKeys.length > 0) {
1372
+ lines.push(` Returned keys: ${result.shape.returnedKeys.join(', ')}`);
1373
+ }
1374
+ if (result.shape.accessedKeys.length > 0) {
1375
+ lines.push(` Accessed keys: ${result.shape.accessedKeys.join(', ')}`);
1376
+ }
1377
+ if (result.shape.mismatches.length > 0) {
1378
+ lines.push(` Mismatches (accessed but not returned): ${result.shape.mismatches.join(', ')}`);
1379
+ }
1380
+ if (result.shape.extra.length > 0) {
1381
+ lines.push(` Unused returned keys: ${result.shape.extra.join(', ')}`);
1382
+ }
1383
+ if (result.consumers.length > 0) {
1384
+ lines.push(` Consumers (${result.consumers.length}):`);
1385
+ for (const c of result.consumers.slice(0, 10)) {
1386
+ lines.push(` - ${c.name} [${c.filePath}]`);
1387
+ }
1388
+ if (result.consumers.length > 10) {
1389
+ lines.push(` … ${result.consumers.length - 10} more`);
1390
+ }
1391
+ }
1392
+ return text(lines.join('\n'));
997
1393
  }
998
1394
  finally {
999
1395
  closeDb(db);
@@ -1039,10 +1435,20 @@ const monographAugmentTool = {
1039
1435
  handler: async (input) => {
1040
1436
  const { augmentContext } = await import('@monoes/monograph');
1041
1437
  const repoPath = getProjectCwd();
1438
+ // Cap query (forwarded to FTS/embedding in augmentContext) and topK
1439
+ // (controls how many context nodes are retrieved).
1440
+ const MAX_AUGMENT_QUERY_LEN = 16 * 1024;
1441
+ const MAX_AUGMENT_TOP_K = 100;
1442
+ const rawAugmentQuery = input.query;
1443
+ const augmentQuery = typeof rawAugmentQuery === 'string' && rawAugmentQuery.length > MAX_AUGMENT_QUERY_LEN
1444
+ ? rawAugmentQuery.slice(0, MAX_AUGMENT_QUERY_LEN) : rawAugmentQuery;
1445
+ const rawTopK = input.topK ?? 10;
1446
+ const topK = Number.isFinite(rawTopK) && rawTopK > 0
1447
+ ? Math.min(Math.floor(rawTopK), MAX_AUGMENT_TOP_K) : 10;
1042
1448
  const result = await augmentContext({
1043
- query: input.query,
1449
+ query: augmentQuery,
1044
1450
  repoPath,
1045
- topK: input.topK ?? 10,
1451
+ topK,
1046
1452
  format: input.format ?? 'markdown',
1047
1453
  });
1048
1454
  return text(result);
@@ -1308,11 +1714,19 @@ const monographNeighborsTool = {
1308
1714
  });
1309
1715
  if (!result.node)
1310
1716
  return text(`No node found with name: ${input.name}`);
1717
+ const nodeFilePath = result.node.filePath ?? '';
1718
+ const nodeStartLine = result.node.startLine ?? result.node.start_line;
1719
+ const nodeLoc = nodeFilePath ? (nodeStartLine != null ? `${nodeFilePath}:${nodeStartLine}` : nodeFilePath) : '';
1311
1720
  const lines = [
1312
- `[${result.node.label}] ${result.node.name} ${result.node.filePath ?? ''}`,
1721
+ `[${result.node.label}] ${result.node.name} ${nodeLoc}`,
1313
1722
  `Neighbors: ${result.neighbors.length}`,
1314
1723
  '',
1315
- ...result.neighbors.map(n => ` ${n.direction === 'inbound' ? '←' : '→'} [${n.node.label}] ${n.node.name} (${n.relation}) ${n.node.filePath ?? ''}`),
1724
+ ...result.neighbors.map(n => {
1725
+ const fp = n.node.filePath ?? n.node.file_path ?? '';
1726
+ const ln = n.node.startLine ?? n.node.start_line;
1727
+ const loc = fp ? (ln != null ? `${fp}:${ln}` : fp) : '';
1728
+ return ` ${n.direction === 'inbound' ? '←' : '→'} [${n.node.label}] ${n.node.name} (${n.relation}) ${loc}`;
1729
+ }),
1316
1730
  ];
1317
1731
  return text(lines.join('\n'));
1318
1732
  }