@hivehub/rulebook 5.5.1 → 5.7.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 (342) hide show
  1. package/.claude/commands/rulebook-learn-capture.md +41 -48
  2. package/.claude/commands/rulebook-learn-list.md +13 -13
  3. package/README.md +332 -394
  4. package/dist/cli/commands/context-intelligence.d.ts +0 -1
  5. package/dist/cli/commands/context-intelligence.d.ts.map +1 -1
  6. package/dist/cli/commands/context-intelligence.js +12 -33
  7. package/dist/cli/commands/context-intelligence.js.map +1 -1
  8. package/dist/cli/commands/index.d.ts +4 -7
  9. package/dist/cli/commands/index.d.ts.map +1 -1
  10. package/dist/cli/commands/index.js +4 -7
  11. package/dist/cli/commands/index.js.map +1 -1
  12. package/dist/cli/commands/init.d.ts.map +1 -1
  13. package/dist/cli/commands/init.js +40 -81
  14. package/dist/cli/commands/init.js.map +1 -1
  15. package/dist/cli/commands/mcp.d.ts +0 -1
  16. package/dist/cli/commands/mcp.d.ts.map +1 -1
  17. package/dist/cli/commands/mcp.js +1 -7
  18. package/dist/cli/commands/mcp.js.map +1 -1
  19. package/dist/cli/commands/memory.d.ts +7 -1
  20. package/dist/cli/commands/memory.d.ts.map +1 -1
  21. package/dist/cli/commands/memory.js +51 -57
  22. package/dist/cli/commands/memory.js.map +1 -1
  23. package/dist/cli/commands/misc.d.ts +1 -15
  24. package/dist/cli/commands/misc.d.ts.map +1 -1
  25. package/dist/cli/commands/misc.js +36 -215
  26. package/dist/cli/commands/misc.js.map +1 -1
  27. package/dist/cli/commands/plans.d.ts +0 -6
  28. package/dist/cli/commands/plans.d.ts.map +1 -1
  29. package/dist/cli/commands/plans.js +9 -77
  30. package/dist/cli/commands/plans.js.map +1 -1
  31. package/dist/cli/commands/skills.js +6 -6
  32. package/dist/cli/commands/skills.js.map +1 -1
  33. package/dist/cli/commands/task.js +4 -4
  34. package/dist/cli/commands/task.js.map +1 -1
  35. package/dist/cli/commands/update.d.ts.map +1 -1
  36. package/dist/cli/commands/update.js +122 -52
  37. package/dist/cli/commands/update.js.map +1 -1
  38. package/dist/cli/prompts.d.ts.map +1 -1
  39. package/dist/cli/prompts.js +1 -78
  40. package/dist/cli/prompts.js.map +1 -1
  41. package/dist/core/claude/claude-mcp.d.ts +59 -0
  42. package/dist/core/claude/claude-mcp.d.ts.map +1 -0
  43. package/dist/core/claude/claude-mcp.js +220 -0
  44. package/dist/core/claude/claude-mcp.js.map +1 -0
  45. package/dist/core/claude/claude-md-generator.d.ts +52 -0
  46. package/dist/core/claude/claude-md-generator.d.ts.map +1 -0
  47. package/dist/core/claude/claude-md-generator.js +104 -0
  48. package/dist/core/claude/claude-md-generator.js.map +1 -0
  49. package/dist/core/claude/claude-settings-manager.d.ts +44 -0
  50. package/dist/core/claude/claude-settings-manager.d.ts.map +1 -0
  51. package/dist/core/claude/claude-settings-manager.js +194 -0
  52. package/dist/core/claude/claude-settings-manager.js.map +1 -0
  53. package/dist/core/claude-settings-manager.d.ts.map +1 -1
  54. package/dist/core/claude-settings-manager.js +9 -3
  55. package/dist/core/claude-settings-manager.js.map +1 -1
  56. package/dist/core/console/cli-bridge.d.ts +113 -0
  57. package/dist/core/console/cli-bridge.d.ts.map +1 -0
  58. package/dist/core/console/cli-bridge.js +1094 -0
  59. package/dist/core/console/cli-bridge.js.map +1 -0
  60. package/dist/core/detect/detector.d.ts +35 -0
  61. package/dist/core/detect/detector.d.ts.map +1 -0
  62. package/dist/core/detect/detector.js +541 -0
  63. package/dist/core/detect/detector.js.map +1 -0
  64. package/dist/core/docs/docs-generator.d.ts +9 -0
  65. package/dist/core/docs/docs-generator.d.ts.map +1 -0
  66. package/dist/core/docs/docs-generator.js +531 -0
  67. package/dist/core/docs/docs-generator.js.map +1 -0
  68. package/dist/core/docs/mcp-reference-generator.d.ts +13 -0
  69. package/dist/core/docs/mcp-reference-generator.d.ts.map +1 -0
  70. package/dist/core/docs/mcp-reference-generator.js +66 -0
  71. package/dist/core/docs/mcp-reference-generator.js.map +1 -0
  72. package/dist/core/generators/generator.d.ts +54 -0
  73. package/dist/core/generators/generator.d.ts.map +1 -0
  74. package/dist/core/generators/generator.js +1041 -0
  75. package/dist/core/generators/generator.js.map +1 -0
  76. package/dist/core/generators/gitignore-generator.d.ts +13 -0
  77. package/dist/core/generators/gitignore-generator.d.ts.map +1 -0
  78. package/dist/core/generators/gitignore-generator.js +307 -0
  79. package/dist/core/generators/gitignore-generator.js.map +1 -0
  80. package/dist/core/generators/minimal-scaffolder.d.ts +8 -0
  81. package/dist/core/generators/minimal-scaffolder.d.ts.map +1 -0
  82. package/dist/core/generators/minimal-scaffolder.js +51 -0
  83. package/dist/core/generators/minimal-scaffolder.js.map +1 -0
  84. package/dist/core/generators/rules-generator.d.ts +73 -0
  85. package/dist/core/generators/rules-generator.d.ts.map +1 -0
  86. package/dist/core/generators/rules-generator.js +202 -0
  87. package/dist/core/generators/rules-generator.js.map +1 -0
  88. package/dist/core/generators/workflow-generator.d.ts +15 -0
  89. package/dist/core/generators/workflow-generator.d.ts.map +1 -0
  90. package/dist/core/generators/workflow-generator.js +390 -0
  91. package/dist/core/generators/workflow-generator.js.map +1 -0
  92. package/dist/core/ide/multi-tool-generator.d.ts +59 -0
  93. package/dist/core/ide/multi-tool-generator.d.ts.map +1 -0
  94. package/dist/core/ide/multi-tool-generator.js +157 -0
  95. package/dist/core/ide/multi-tool-generator.js.map +1 -0
  96. package/dist/core/ide/opencode-generator.d.ts +72 -0
  97. package/dist/core/ide/opencode-generator.d.ts.map +1 -0
  98. package/dist/core/ide/opencode-generator.js +450 -0
  99. package/dist/core/ide/opencode-generator.js.map +1 -0
  100. package/dist/core/merger.d.ts +1 -1
  101. package/dist/core/merger.d.ts.map +1 -1
  102. package/dist/core/merger.js +5 -5
  103. package/dist/core/merger.js.map +1 -1
  104. package/dist/core/migrator.d.ts +0 -1
  105. package/dist/core/migrator.d.ts.map +1 -1
  106. package/dist/core/migrator.js +4 -29
  107. package/dist/core/migrator.js.map +1 -1
  108. package/dist/core/quality/coverage-checker.d.ts +14 -0
  109. package/dist/core/quality/coverage-checker.d.ts.map +1 -0
  110. package/dist/core/quality/coverage-checker.js +176 -0
  111. package/dist/core/quality/coverage-checker.js.map +1 -0
  112. package/dist/core/quality/dependency-checker.d.ts +21 -0
  113. package/dist/core/quality/dependency-checker.d.ts.map +1 -0
  114. package/dist/core/quality/dependency-checker.js +247 -0
  115. package/dist/core/quality/dependency-checker.js.map +1 -0
  116. package/dist/core/quality/doctor.d.ts +19 -0
  117. package/dist/core/quality/doctor.d.ts.map +1 -0
  118. package/dist/core/quality/doctor.js +163 -0
  119. package/dist/core/quality/doctor.js.map +1 -0
  120. package/dist/core/quality/validator.d.ts +21 -0
  121. package/dist/core/quality/validator.d.ts.map +1 -0
  122. package/dist/core/quality/validator.js +177 -0
  123. package/dist/core/quality/validator.js.map +1 -0
  124. package/dist/core/ralph-scripts.d.ts.map +1 -1
  125. package/dist/core/ralph-scripts.js +7 -6
  126. package/dist/core/ralph-scripts.js.map +1 -1
  127. package/dist/core/skills/skills-manager.d.ts +126 -0
  128. package/dist/core/skills/skills-manager.d.ts.map +1 -0
  129. package/dist/core/skills/skills-manager.js +630 -0
  130. package/dist/core/skills/skills-manager.js.map +1 -0
  131. package/dist/core/state/config-manager.d.ts +86 -0
  132. package/dist/core/state/config-manager.d.ts.map +1 -0
  133. package/dist/core/state/config-manager.js +562 -0
  134. package/dist/core/state/config-manager.js.map +1 -0
  135. package/dist/core/state/override-manager.d.ts +23 -0
  136. package/dist/core/state/override-manager.d.ts.map +1 -0
  137. package/dist/core/state/override-manager.js +82 -0
  138. package/dist/core/state/override-manager.js.map +1 -0
  139. package/dist/core/state/state-writer.d.ts +34 -0
  140. package/dist/core/state/state-writer.d.ts.map +1 -0
  141. package/dist/core/state/state-writer.js +78 -0
  142. package/dist/core/state/state-writer.js.map +1 -0
  143. package/dist/core/state/version-bumper.d.ts +19 -0
  144. package/dist/core/state/version-bumper.d.ts.map +1 -0
  145. package/dist/core/state/version-bumper.js +180 -0
  146. package/dist/core/state/version-bumper.js.map +1 -0
  147. package/dist/core/tasks/decision-manager.d.ts +25 -0
  148. package/dist/core/tasks/decision-manager.d.ts.map +1 -0
  149. package/dist/core/tasks/decision-manager.js +183 -0
  150. package/dist/core/tasks/decision-manager.js.map +1 -0
  151. package/dist/core/tasks/knowledge-manager.d.ts +24 -0
  152. package/dist/core/tasks/knowledge-manager.d.ts.map +1 -0
  153. package/dist/core/tasks/knowledge-manager.js +173 -0
  154. package/dist/core/tasks/knowledge-manager.js.map +1 -0
  155. package/dist/core/tasks/learn-manager.d.ts +27 -0
  156. package/dist/core/tasks/learn-manager.d.ts.map +1 -0
  157. package/dist/core/tasks/learn-manager.js +121 -0
  158. package/dist/core/tasks/learn-manager.js.map +1 -0
  159. package/dist/core/tasks/plans-manager.d.ts +46 -0
  160. package/dist/core/tasks/plans-manager.d.ts.map +1 -0
  161. package/dist/core/tasks/plans-manager.js +158 -0
  162. package/dist/core/tasks/plans-manager.js.map +1 -0
  163. package/dist/core/tasks/task-manager.d.ts +127 -0
  164. package/dist/core/tasks/task-manager.d.ts.map +1 -0
  165. package/dist/core/tasks/task-manager.js +607 -0
  166. package/dist/core/tasks/task-manager.js.map +1 -0
  167. package/dist/core/workspace/project-worker.d.ts +6 -6
  168. package/dist/core/workspace/project-worker.d.ts.map +1 -1
  169. package/dist/core/workspace/project-worker.js +6 -6
  170. package/dist/core/workspace/project-worker.js.map +1 -1
  171. package/dist/index.d.ts +1 -1
  172. package/dist/index.d.ts.map +1 -1
  173. package/dist/index.js +19 -176
  174. package/dist/index.js.map +1 -1
  175. package/dist/mcp/rulebook-server.d.ts.map +1 -1
  176. package/dist/mcp/rulebook-server.js +16 -960
  177. package/dist/mcp/rulebook-server.js.map +1 -1
  178. package/dist/memory/file-search.d.ts +43 -0
  179. package/dist/memory/file-search.d.ts.map +1 -0
  180. package/dist/memory/file-search.js +228 -0
  181. package/dist/memory/file-search.js.map +1 -0
  182. package/dist/memory/file-store.d.ts +99 -0
  183. package/dist/memory/file-store.d.ts.map +1 -0
  184. package/dist/memory/file-store.js +615 -0
  185. package/dist/memory/file-store.js.map +1 -0
  186. package/dist/memory/legacy-migrator.d.ts +27 -0
  187. package/dist/memory/legacy-migrator.d.ts.map +1 -0
  188. package/dist/memory/legacy-migrator.js +185 -0
  189. package/dist/memory/legacy-migrator.js.map +1 -0
  190. package/dist/memory/memory-manager.d.ts +25 -24
  191. package/dist/memory/memory-manager.d.ts.map +1 -1
  192. package/dist/memory/memory-manager.js +97 -140
  193. package/dist/memory/memory-manager.js.map +1 -1
  194. package/dist/memory/memory-types.d.ts +1 -1
  195. package/dist/memory/memory-types.d.ts.map +1 -1
  196. package/dist/types.d.ts +8 -119
  197. package/dist/types.d.ts.map +1 -1
  198. package/dist/utils/file-system.d.ts +22 -0
  199. package/dist/utils/file-system.d.ts.map +1 -1
  200. package/dist/utils/file-system.js +31 -0
  201. package/dist/utils/file-system.js.map +1 -1
  202. package/dist/utils/git-hooks.d.ts.map +1 -1
  203. package/dist/utils/git-hooks.js +3 -2
  204. package/dist/utils/git-hooks.js.map +1 -1
  205. package/package.json +2 -6
  206. package/templates/agents/context-intelligence.md +50 -52
  207. package/templates/cli/OPENCODE.md +85 -18
  208. package/templates/commands/rulebook-learn-capture.md +41 -48
  209. package/templates/commands/rulebook-learn-list.md +13 -13
  210. package/templates/core/AGENTS_LEAN.md +0 -14
  211. package/templates/hooks/check-context-and-handoff.sh +74 -76
  212. package/templates/hooks/enforce-pre-tool.sh +70 -0
  213. package/templates/hooks/enforce-team-for-background-agents.sh +55 -55
  214. package/templates/hooks/on-compact-reinject.sh +34 -34
  215. package/templates/hooks/resume-from-handoff.sh +61 -61
  216. package/templates/hooks/terse-activate.sh +197 -197
  217. package/templates/hooks/terse-mode-tracker.sh +190 -187
  218. package/templates/ides/OPENCODE.md +63 -0
  219. package/templates/skills/cli/opencode/SKILL.md +82 -28
  220. package/.claude/commands/ralph-config.md +0 -112
  221. package/.claude/commands/ralph-history.md +0 -110
  222. package/.claude/commands/ralph-init.md +0 -72
  223. package/.claude/commands/ralph-pause-resume.md +0 -105
  224. package/.claude/commands/ralph-run.md +0 -101
  225. package/.claude/commands/ralph-status.md +0 -76
  226. package/templates/core/RALPH.md +0 -471
  227. package/templates/frameworks/ANGULAR.md +0 -36
  228. package/templates/frameworks/DJANGO.md +0 -83
  229. package/templates/frameworks/ELECTRON.md +0 -147
  230. package/templates/frameworks/FLASK.md +0 -38
  231. package/templates/frameworks/FLUTTER.md +0 -55
  232. package/templates/frameworks/JQUERY.md +0 -32
  233. package/templates/frameworks/LARAVEL.md +0 -38
  234. package/templates/frameworks/NESTJS.md +0 -43
  235. package/templates/frameworks/NEXTJS.md +0 -127
  236. package/templates/frameworks/NUXT.md +0 -40
  237. package/templates/frameworks/RAILS.md +0 -66
  238. package/templates/frameworks/REACT.md +0 -38
  239. package/templates/frameworks/REACT_NATIVE.md +0 -47
  240. package/templates/frameworks/SPRING.md +0 -39
  241. package/templates/frameworks/SYMFONY.md +0 -36
  242. package/templates/frameworks/VUE.md +0 -36
  243. package/templates/frameworks/ZEND.md +0 -35
  244. package/templates/hooks/enforce-mcp-for-tasks.sh +0 -31
  245. package/templates/hooks/enforce-no-deferred.sh +0 -21
  246. package/templates/hooks/enforce-no-shortcuts.sh +0 -31
  247. package/templates/ides/COPILOT.md +0 -37
  248. package/templates/ides/CURSOR.md +0 -43
  249. package/templates/ides/JETBRAINS_AI.md +0 -35
  250. package/templates/ides/REPLIT.md +0 -36
  251. package/templates/ides/TABNINE.md +0 -29
  252. package/templates/ides/VSCODE.md +0 -40
  253. package/templates/ides/WINDSURF.md +0 -36
  254. package/templates/ides/ZED.md +0 -32
  255. package/templates/ides/cursor-mdc/go.mdc +0 -24
  256. package/templates/ides/cursor-mdc/python.mdc +0 -24
  257. package/templates/ides/cursor-mdc/quality.mdc +0 -25
  258. package/templates/ides/cursor-mdc/ralph.mdc +0 -39
  259. package/templates/ides/cursor-mdc/rulebook.mdc +0 -38
  260. package/templates/ides/cursor-mdc/rust.mdc +0 -24
  261. package/templates/ides/cursor-mdc/typescript.mdc +0 -25
  262. package/templates/ralph/ralph-history.bat +0 -4
  263. package/templates/ralph/ralph-history.sh +0 -5
  264. package/templates/ralph/ralph-init.bat +0 -5
  265. package/templates/ralph/ralph-init.sh +0 -5
  266. package/templates/ralph/ralph-pause.bat +0 -5
  267. package/templates/ralph/ralph-pause.sh +0 -5
  268. package/templates/ralph/ralph-run.bat +0 -5
  269. package/templates/ralph/ralph-run.sh +0 -5
  270. package/templates/ralph/ralph-status.bat +0 -4
  271. package/templates/ralph/ralph-status.sh +0 -5
  272. package/templates/services/AZURE_BLOB.md +0 -184
  273. package/templates/services/CASSANDRA.md +0 -239
  274. package/templates/services/DATADOG.md +0 -26
  275. package/templates/services/DOCKER.md +0 -124
  276. package/templates/services/DOCKER_COMPOSE.md +0 -168
  277. package/templates/services/DYNAMODB.md +0 -308
  278. package/templates/services/ELASTICSEARCH.md +0 -347
  279. package/templates/services/GCS.md +0 -178
  280. package/templates/services/HELM.md +0 -194
  281. package/templates/services/INFLUXDB.md +0 -265
  282. package/templates/services/KAFKA.md +0 -341
  283. package/templates/services/KUBERNETES.md +0 -208
  284. package/templates/services/MARIADB.md +0 -183
  285. package/templates/services/MEMCACHED.md +0 -242
  286. package/templates/services/MINIO.md +0 -201
  287. package/templates/services/MONGODB.md +0 -268
  288. package/templates/services/MYSQL.md +0 -358
  289. package/templates/services/NEO4J.md +0 -247
  290. package/templates/services/OPENTELEMETRY.md +0 -25
  291. package/templates/services/ORACLE.md +0 -290
  292. package/templates/services/PINO.md +0 -24
  293. package/templates/services/POSTGRESQL.md +0 -326
  294. package/templates/services/PROMETHEUS.md +0 -33
  295. package/templates/services/RABBITMQ.md +0 -286
  296. package/templates/services/REDIS.md +0 -292
  297. package/templates/services/S3.md +0 -298
  298. package/templates/services/SENTRY.md +0 -23
  299. package/templates/services/SQLITE.md +0 -294
  300. package/templates/services/SQLSERVER.md +0 -294
  301. package/templates/services/WINSTON.md +0 -30
  302. package/templates/skills/frameworks/angular/SKILL.md +0 -46
  303. package/templates/skills/frameworks/django/SKILL.md +0 -93
  304. package/templates/skills/frameworks/electron/SKILL.md +0 -157
  305. package/templates/skills/frameworks/flask/SKILL.md +0 -48
  306. package/templates/skills/frameworks/flutter/SKILL.md +0 -65
  307. package/templates/skills/frameworks/jquery/SKILL.md +0 -42
  308. package/templates/skills/frameworks/laravel/SKILL.md +0 -48
  309. package/templates/skills/frameworks/nestjs/SKILL.md +0 -53
  310. package/templates/skills/frameworks/nextjs/SKILL.md +0 -137
  311. package/templates/skills/frameworks/nuxt/SKILL.md +0 -50
  312. package/templates/skills/frameworks/rails/SKILL.md +0 -76
  313. package/templates/skills/frameworks/react/SKILL.md +0 -48
  314. package/templates/skills/frameworks/react-native/SKILL.md +0 -57
  315. package/templates/skills/frameworks/spring/SKILL.md +0 -49
  316. package/templates/skills/frameworks/symfony/SKILL.md +0 -46
  317. package/templates/skills/frameworks/vue/SKILL.md +0 -46
  318. package/templates/skills/frameworks/zend/SKILL.md +0 -45
  319. package/templates/skills/services/azure-blob/SKILL.md +0 -194
  320. package/templates/skills/services/cassandra/SKILL.md +0 -249
  321. package/templates/skills/services/dynamodb/SKILL.md +0 -318
  322. package/templates/skills/services/elasticsearch/SKILL.md +0 -357
  323. package/templates/skills/services/gcs/SKILL.md +0 -188
  324. package/templates/skills/services/influxdb/SKILL.md +0 -275
  325. package/templates/skills/services/kafka/SKILL.md +0 -351
  326. package/templates/skills/services/mariadb/SKILL.md +0 -193
  327. package/templates/skills/services/memcached/SKILL.md +0 -252
  328. package/templates/skills/services/minio/SKILL.md +0 -211
  329. package/templates/skills/services/mongodb/SKILL.md +0 -278
  330. package/templates/skills/services/mysql/SKILL.md +0 -368
  331. package/templates/skills/services/neo4j/SKILL.md +0 -257
  332. package/templates/skills/services/oracle/SKILL.md +0 -300
  333. package/templates/skills/services/postgresql/SKILL.md +0 -336
  334. package/templates/skills/services/rabbitmq/SKILL.md +0 -296
  335. package/templates/skills/services/redis/SKILL.md +0 -302
  336. package/templates/skills/services/s3/SKILL.md +0 -308
  337. package/templates/skills/services/sqlite/SKILL.md +0 -304
  338. package/templates/skills/services/sqlserver/SKILL.md +0 -304
  339. package/templates/skills/workflows/ralph/SETUP.md +0 -228
  340. package/templates/skills/workflows/ralph/SKILL.md +0 -309
  341. package/templates/skills/workflows/ralph/install.sh +0 -87
  342. package/templates/skills/workflows/ralph/manifest.json +0 -158
@@ -2,12 +2,12 @@
2
2
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
3
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
4
  import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, unlinkSync, writeFileSync, } from 'fs';
5
- import { basename, dirname, join, resolve } from 'path';
5
+ import { dirname, join, resolve } from 'path';
6
6
  import { z } from 'zod';
7
- import { ConfigManager } from '../core/config-manager.js';
7
+ import { ConfigManager } from '../core/state/config-manager.js';
8
8
  import { BackgroundIndexer } from '../core/indexer/background-indexer.js';
9
- import { SkillsManager, getDefaultTemplatesPath } from '../core/skills-manager.js';
10
- import { TaskManager } from '../core/task-manager.js';
9
+ import { SkillsManager, getDefaultTemplatesPath } from '../core/skills/skills-manager.js';
10
+ import { TaskManager } from '../core/tasks/task-manager.js';
11
11
  import { WorkspaceManager } from '../core/workspace/workspace-manager.js';
12
12
  // --- Timeout guard for MCP tool handlers ---
13
13
  // Prevents the MCP server from hanging when a tool handler blocks (SQLite, WASM, fs).
@@ -272,28 +272,14 @@ export async function startRulebookMcpServer() {
272
272
  name: 'rulebook-task-management',
273
273
  version: '5.2.0',
274
274
  });
275
- // --- v5.3.0 F10: opt-in telemetry middleware ---
276
- const { createTelemetryMiddleware } = await import('../core/telemetry.js');
277
- const telemetryEnabled = configManager
278
- ? (await configManager.loadConfig())?.features?.telemetry === true
279
- : false;
280
- const telemetry = createTelemetryMiddleware({
281
- enabled: telemetryEnabled,
282
- dir: join(projectRoot, '.rulebook', 'telemetry'),
283
- });
284
- // --- Wrap all tool handlers with timeout guard + telemetry ---
285
- // Intercept registerTool to automatically add timeout protection and
286
- // optional telemetry recording to every handler.
275
+ // --- Wrap all tool handlers with a timeout guard ---
287
276
  const originalRegisterTool = server.registerTool.bind(server);
288
277
  server.registerTool = ((name, config, handler) => {
289
278
  const wrappedHandler = async (...handlerArgs) => {
290
- const start = Date.now();
291
- let success = true;
292
279
  try {
293
280
  return await withTimeout(handler(...handlerArgs), MCP_TOOL_TIMEOUT_MS, name);
294
281
  }
295
282
  catch (error) {
296
- success = false;
297
283
  const msg = error instanceof Error ? error.message : String(error);
298
284
  console.error(`[rulebook-mcp] ${name} error: ${msg}`);
299
285
  return {
@@ -302,14 +288,6 @@ export async function startRulebookMcpServer() {
302
288
  ],
303
289
  };
304
290
  }
305
- finally {
306
- telemetry.record({
307
- tool: name,
308
- latency_ms: Date.now() - start,
309
- success,
310
- timestamp: new Date().toISOString(),
311
- });
312
- }
313
291
  };
314
292
  return originalRegisterTool(name, config, wrappedHandler);
315
293
  });
@@ -1144,491 +1122,6 @@ export async function startRulebookMcpServer() {
1144
1122
  };
1145
1123
  }
1146
1124
  });
1147
- // Ralph Autonomous Loop Tools (v3.0)
1148
- const ralphConfig = await configManager.loadConfig();
1149
- const ralphEnabled = ralphConfig.ralph?.enabled ?? true;
1150
- if (ralphEnabled) {
1151
- // Register tool: rulebook_ralph_init
1152
- server.registerTool('rulebook_ralph_init', {
1153
- title: 'Initialize Ralph',
1154
- description: 'Initialize Ralph autonomous loop and create PRD from rulebook tasks',
1155
- inputSchema: {},
1156
- }, async () => {
1157
- try {
1158
- const { Logger } = await import('../core/logger.js');
1159
- const { RalphManager } = await import('../core/ralph-manager.js');
1160
- const { PRDGenerator } = await import('../core/prd-generator.js');
1161
- const logger = new Logger(projectRoot);
1162
- const ralphManager = new RalphManager(projectRoot, logger);
1163
- const prdGenerator = new PRDGenerator(projectRoot, logger);
1164
- const configData = await configManager.loadConfig();
1165
- const maxIterations = configData.ralph?.maxIterations || 10;
1166
- const tool = (configData.ralph?.tool || 'claude');
1167
- // Generate PRD first, then initialize with correct task count
1168
- const prd = await prdGenerator.generatePRD(basename(projectRoot) || 'project');
1169
- const { writeFile } = await import('../utils/file-system.js');
1170
- const prdPath = join(projectRoot, '.rulebook', 'ralph', 'prd.json');
1171
- await writeFile(prdPath, JSON.stringify(prd, null, 2));
1172
- // Initialize after PRD is written so task count is correct
1173
- await ralphManager.initialize(maxIterations, tool);
1174
- return {
1175
- content: [
1176
- {
1177
- type: 'text',
1178
- text: JSON.stringify({
1179
- success: true,
1180
- message: `Ralph initialized with ${prd.userStories.length} user stories`,
1181
- tasks: prd.userStories.length,
1182
- maxIterations,
1183
- tool,
1184
- }),
1185
- },
1186
- ],
1187
- };
1188
- }
1189
- catch (error) {
1190
- return {
1191
- content: [
1192
- {
1193
- type: 'text',
1194
- text: JSON.stringify({ success: false, error: String(error) }),
1195
- },
1196
- ],
1197
- };
1198
- }
1199
- });
1200
- // Register tool: rulebook_ralph_run
1201
- server.registerTool('rulebook_ralph_run', {
1202
- title: 'Run Ralph Loop',
1203
- description: 'Execute Ralph autonomous iteration loop',
1204
- inputSchema: {
1205
- maxIterations: z.number().optional().describe('Maximum iterations'),
1206
- tool: z.enum(['claude', 'amp', 'gemini']).optional().describe('AI tool to use'),
1207
- },
1208
- }, async (args) => {
1209
- try {
1210
- const { Logger } = await import('../core/logger.js');
1211
- const { RalphManager } = await import('../core/ralph-manager.js');
1212
- const { RalphParser } = await import('../agents/ralph-parser.js');
1213
- const { spawn } = await import('child_process');
1214
- const { execSync } = await import('child_process');
1215
- const logger = new Logger(projectRoot);
1216
- const ralphManager = new RalphManager(projectRoot, logger);
1217
- const configData = await configManager.loadConfig();
1218
- const maxIterations = args.maxIterations || configData.ralph?.maxIterations || 10;
1219
- const tool = (args.tool || configData.ralph?.tool || 'claude');
1220
- // ── Concurrency guard: prevent multiple simultaneous Ralph runs ──
1221
- const lockAcquired = await ralphManager.acquireLock(tool);
1222
- if (!lockAcquired) {
1223
- const lockInfo = await ralphManager.getLockInfo();
1224
- return {
1225
- content: [
1226
- {
1227
- type: 'text',
1228
- text: JSON.stringify({
1229
- success: false,
1230
- error: `Ralph is already running (PID ${lockInfo?.pid}, started ${lockInfo?.startedAt}, task: ${lockInfo?.currentTask || 'starting'}, iteration: ${lockInfo?.iteration || 0}). Wait for it to finish or check ralph_status. Do NOT start another run.`,
1231
- }),
1232
- },
1233
- ],
1234
- };
1235
- }
1236
- // Lock cleanup is handled by the top-level SIGINT handler (line ~858)
1237
- // which shuts down all managers. Adding per-call SIGINT/SIGTERM listeners
1238
- // causes accumulation and race conditions with the server shutdown handler.
1239
- try {
1240
- // Validate tool is available before starting
1241
- const toolCmdNames = {
1242
- claude: 'claude',
1243
- amp: 'amp',
1244
- gemini: 'gemini',
1245
- };
1246
- const toolCmd = toolCmdNames[tool] || 'claude';
1247
- try {
1248
- execSync(`${toolCmd} --version`, { stdio: 'pipe', timeout: 10000 });
1249
- }
1250
- catch {
1251
- return {
1252
- content: [
1253
- {
1254
- type: 'text',
1255
- text: JSON.stringify({
1256
- success: false,
1257
- error: `CLI tool "${toolCmd}" not found or not responding. Install it first: https://docs.anthropic.com/claude-code`,
1258
- }),
1259
- },
1260
- ],
1261
- };
1262
- }
1263
- // Resume existing state if available, otherwise initialize fresh
1264
- const existingState = await ralphManager.getStatus();
1265
- if (!existingState) {
1266
- await ralphManager.initialize(maxIterations, tool);
1267
- }
1268
- // Helper: run a shell command and return stdout
1269
- const runCmd = (cmd, cmdArgs) => new Promise((resolve) => {
1270
- let stdout = '';
1271
- let stderr = '';
1272
- const proc = spawn(cmd, cmdArgs, {
1273
- cwd: projectRoot,
1274
- shell: true,
1275
- stdio: ['pipe', 'pipe', 'pipe'],
1276
- });
1277
- proc.stdout?.on('data', (d) => {
1278
- stdout += d.toString();
1279
- });
1280
- proc.stderr?.on('data', (d) => {
1281
- stderr += d.toString();
1282
- });
1283
- proc.on('close', (code) => resolve({ code: code ?? 1, stdout, stderr }));
1284
- proc.on('error', (err) => resolve({ code: 1, stdout, stderr: err.message }));
1285
- });
1286
- // Helper: build prompt for AI agent
1287
- const buildPrompt = (task, projectName) => {
1288
- const criteria = (task.acceptanceCriteria || [])
1289
- .map((c) => `- ${c}`)
1290
- .join('\n');
1291
- return [
1292
- `You are working on project: ${projectName}`,
1293
- ``,
1294
- `## Current Task: ${task.title}`,
1295
- `ID: ${task.id}`,
1296
- ``,
1297
- `## Description`,
1298
- task.description,
1299
- ``,
1300
- `## Acceptance Criteria`,
1301
- criteria,
1302
- ``,
1303
- task.notes ? `## Notes\n${task.notes}\n` : '',
1304
- `## Instructions`,
1305
- `1. Implement the changes described above`,
1306
- `2. Ensure all acceptance criteria are met`,
1307
- `3. Run quality checks: type-check, lint, tests`,
1308
- `4. Fix any issues found by quality checks`,
1309
- `5. When done, summarize what was changed`,
1310
- ]
1311
- .filter(Boolean)
1312
- .join('\n');
1313
- };
1314
- // Helper: execute AI agent with proper error handling
1315
- const executeAgent = (agentTool, prompt) => new Promise((resolve, reject) => {
1316
- let output = '';
1317
- let stderrOutput = '';
1318
- const toolCmds = {
1319
- claude: {
1320
- cmd: 'claude',
1321
- args: ['-p', '--dangerously-skip-permissions', '--verbose'],
1322
- stdinPrompt: true,
1323
- },
1324
- amp: { cmd: 'amp', args: ['-p', prompt], stdinPrompt: false },
1325
- gemini: { cmd: 'gemini', args: ['-p', prompt], stdinPrompt: false },
1326
- };
1327
- const cfg = toolCmds[agentTool] || toolCmds.claude;
1328
- let settled = false;
1329
- const settle = (fn) => {
1330
- if (!settled) {
1331
- settled = true;
1332
- fn();
1333
- }
1334
- };
1335
- const proc = spawn(cfg.cmd, cfg.args, {
1336
- cwd: projectRoot,
1337
- shell: true,
1338
- stdio: ['pipe', 'pipe', 'pipe'],
1339
- });
1340
- if (cfg.stdinPrompt && proc.stdin) {
1341
- proc.stdin.write(prompt);
1342
- proc.stdin.end();
1343
- }
1344
- proc.stdout?.on('data', (d) => {
1345
- output += d.toString();
1346
- });
1347
- proc.stderr?.on('data', (d) => {
1348
- stderrOutput += d.toString();
1349
- });
1350
- proc.on('close', (code) => {
1351
- settle(() => {
1352
- if (code === 0 || output.length > 0) {
1353
- resolve(output);
1354
- }
1355
- else {
1356
- reject(new Error(`Agent ${agentTool} exited with code ${code}${stderrOutput ? ': ' + stderrOutput.slice(0, 500) : ''}`));
1357
- }
1358
- });
1359
- });
1360
- proc.on('error', (err) => {
1361
- settle(() => reject(new Error(`Failed to spawn ${agentTool}: ${err.message}`)));
1362
- });
1363
- const timeout = setTimeout(() => {
1364
- proc.kill('SIGTERM');
1365
- settle(() => resolve(output || `Agent ${agentTool} timed out after 10 minutes`));
1366
- }, 600000);
1367
- proc.on('close', () => clearTimeout(timeout));
1368
- });
1369
- // Sync task count from PRD
1370
- await ralphManager.refreshTaskCount();
1371
- // Load PRD for project name (used in prompts)
1372
- const prd = await ralphManager.loadPRD();
1373
- if (!prd || !prd.userStories || prd.userStories.length === 0) {
1374
- return {
1375
- content: [
1376
- {
1377
- type: 'text',
1378
- text: JSON.stringify({
1379
- success: false,
1380
- error: 'No PRD found or no user stories. Run rulebook_ralph_init first.',
1381
- }),
1382
- },
1383
- ],
1384
- };
1385
- }
1386
- const projectName = prd.project || 'unknown';
1387
- const totalTasks = prd.userStories.filter((s) => !s.passes).length;
1388
- let iterationCount = 0;
1389
- const iterationResults = [];
1390
- // Log to stderr so MCP callers can see progress
1391
- const logProgress = (msg) => {
1392
- process.stderr.write(`[Ralph] ${msg}\n`);
1393
- };
1394
- logProgress(`Starting Ralph loop: ${totalTasks} pending tasks, max ${maxIterations} iterations, tool=${tool}`);
1395
- while (ralphManager.canContinue() && iterationCount < maxIterations) {
1396
- iterationCount++;
1397
- const task = await ralphManager.getNextTask();
1398
- if (!task)
1399
- break;
1400
- // Update lock with current progress
1401
- await ralphManager.updateLockProgress(iterationCount, `${task.id}: ${task.title}`);
1402
- logProgress(`Iteration ${iterationCount}/${maxIterations} — Task: ${task.id} "${task.title}"`);
1403
- const startTime = Date.now();
1404
- // 1. Execute AI agent
1405
- let agentOutput = '';
1406
- try {
1407
- logProgress(` Executing ${tool} agent...`);
1408
- const prompt = buildPrompt(task, projectName);
1409
- agentOutput = await executeAgent(tool, prompt);
1410
- logProgress(` Agent finished (${((Date.now() - startTime) / 1000).toFixed(0)}s)`);
1411
- }
1412
- catch (agentErr) {
1413
- agentOutput = `Error: ${agentErr.message || agentErr}`;
1414
- logProgress(` Agent error: ${agentErr.message || agentErr}`);
1415
- }
1416
- // 2. Run quality gates
1417
- logProgress(` Running quality gates...`);
1418
- const [typeCheck, lint, tests] = await Promise.all([
1419
- runCmd('npm', ['run', 'type-check']).then((r) => r.code === 0),
1420
- runCmd('npm', ['run', 'lint']).then((r) => r.code === 0),
1421
- runCmd('npm', ['test']).then((r) => r.code === 0),
1422
- ]);
1423
- const qualityChecks = { type_check: typeCheck, lint, tests, coverage_met: tests };
1424
- const allPass = typeCheck && lint && tests;
1425
- const passCount = Object.values(qualityChecks).filter(Boolean).length;
1426
- const status = allPass
1427
- ? 'success'
1428
- : passCount >= 2
1429
- ? 'partial'
1430
- : 'failed';
1431
- logProgress(` Quality: type-check=${typeCheck ? 'PASS' : 'FAIL'} lint=${lint ? 'PASS' : 'FAIL'} tests=${tests ? 'PASS' : 'FAIL'} → ${status.toUpperCase()}`);
1432
- // 3. Git commit if all gates pass
1433
- let gitCommit;
1434
- if (allPass) {
1435
- await runCmd('git', ['add', '-A']);
1436
- const commitResult = await runCmd('git', [
1437
- 'commit',
1438
- '-m',
1439
- `ralph(${task.id}): ${task.title}\n\nIteration ${iterationCount} - Ralph autonomous loop`,
1440
- ]);
1441
- const hashMatch = commitResult.stdout.match(/\[[\w/.-]+ ([a-f0-9]+)\]/);
1442
- gitCommit = hashMatch ? hashMatch[1] : undefined;
1443
- await ralphManager.markStoryComplete(task.id);
1444
- logProgress(` Committed: ${gitCommit || 'no hash'} — Story ${task.id} COMPLETE`);
1445
- }
1446
- const iterDuration = Date.now() - startTime;
1447
- // 4. Parse output for learnings/errors
1448
- const parsed = RalphParser.parseAgentOutput(agentOutput, iterationCount, task.id, task.title, tool);
1449
- // 5. Record iteration and refresh task count for canContinue()
1450
- await ralphManager.recordIteration({
1451
- iteration: iterationCount,
1452
- timestamp: new Date().toISOString(),
1453
- task_id: task.id,
1454
- task_title: task.title,
1455
- status,
1456
- ai_tool: tool,
1457
- execution_time_ms: iterDuration,
1458
- quality_checks: qualityChecks,
1459
- output_summary: parsed.output_summary || `Iteration ${iterationCount}: ${task.title}`,
1460
- git_commit: gitCommit,
1461
- learnings: parsed.learnings,
1462
- errors: parsed.errors,
1463
- metadata: {
1464
- context_loss_count: parsed.metadata.context_loss_count,
1465
- parsed_completion: parsed.metadata.parsed_completion,
1466
- },
1467
- });
1468
- iterationResults.push({
1469
- iteration: iterationCount,
1470
- taskId: task.id,
1471
- taskTitle: task.title,
1472
- status,
1473
- durationMs: iterDuration,
1474
- });
1475
- // Refresh task count so canContinue() reflects updated PRD
1476
- await ralphManager.refreshTaskCount();
1477
- logProgress(` Iteration ${iterationCount} complete (${(iterDuration / 1000).toFixed(0)}s)\n`);
1478
- }
1479
- const stats = await ralphManager.getTaskStats();
1480
- logProgress(`Ralph loop finished: ${iterationCount} iterations, ${stats.completed}/${stats.total} tasks completed`);
1481
- return {
1482
- content: [
1483
- {
1484
- type: 'text',
1485
- text: JSON.stringify({
1486
- success: true,
1487
- iterations: iterationCount,
1488
- completed: stats.completed,
1489
- total: stats.total,
1490
- results: iterationResults,
1491
- }),
1492
- },
1493
- ],
1494
- };
1495
- }
1496
- finally {
1497
- // Always release lock, even on error
1498
- await ralphManager.releaseLock();
1499
- }
1500
- }
1501
- catch (error) {
1502
- return {
1503
- content: [
1504
- {
1505
- type: 'text',
1506
- text: JSON.stringify({ success: false, error: String(error) }),
1507
- },
1508
- ],
1509
- };
1510
- }
1511
- });
1512
- // Register tool: rulebook_ralph_status
1513
- server.registerTool('rulebook_ralph_status', {
1514
- title: 'Ralph Status',
1515
- description: 'Get current Ralph loop status',
1516
- inputSchema: {},
1517
- }, async () => {
1518
- try {
1519
- const { Logger } = await import('../core/logger.js');
1520
- const { RalphManager } = await import('../core/ralph-manager.js');
1521
- const logger = new Logger(projectRoot);
1522
- const ralphManager = new RalphManager(projectRoot, logger);
1523
- const status = await ralphManager.getStatus();
1524
- if (!status) {
1525
- return {
1526
- content: [
1527
- {
1528
- type: 'text',
1529
- text: JSON.stringify({ success: false, error: 'Ralph not initialized' }),
1530
- },
1531
- ],
1532
- };
1533
- }
1534
- const stats = await ralphManager.getTaskStats();
1535
- // Check if Ralph is currently running (lock held by alive process)
1536
- const running = await ralphManager.isRunning();
1537
- const lockInfo = running ? await ralphManager.getLockInfo() : null;
1538
- return {
1539
- content: [
1540
- {
1541
- type: 'text',
1542
- text: JSON.stringify({
1543
- success: true,
1544
- running,
1545
- ...(running && lockInfo
1546
- ? {
1547
- runningPid: lockInfo.pid,
1548
- runningTask: lockInfo.currentTask || null,
1549
- runningIteration: lockInfo.iteration || 0,
1550
- runningSince: lockInfo.startedAt,
1551
- }
1552
- : {}),
1553
- iteration: status.current_iteration,
1554
- maxIterations: status.max_iterations,
1555
- completedTasks: stats.completed,
1556
- totalTasks: stats.total,
1557
- paused: status.paused,
1558
- tool: status.tool,
1559
- startedAt: status.started_at,
1560
- }),
1561
- },
1562
- ],
1563
- };
1564
- }
1565
- catch (error) {
1566
- return {
1567
- content: [
1568
- {
1569
- type: 'text',
1570
- text: JSON.stringify({ success: false, error: String(error) }),
1571
- },
1572
- ],
1573
- };
1574
- }
1575
- });
1576
- // Register tool: rulebook_ralph_get_iteration_history
1577
- server.registerTool('rulebook_ralph_get_iteration_history', {
1578
- title: 'Ralph Iteration History',
1579
- description: 'Get Ralph iteration history and statistics',
1580
- inputSchema: {
1581
- limit: z.number().optional().describe('Maximum iterations to return'),
1582
- taskId: z.string().optional().describe('Filter by task ID'),
1583
- },
1584
- }, async (args) => {
1585
- try {
1586
- const { Logger } = await import('../core/logger.js');
1587
- const { IterationTracker } = await import('../core/iteration-tracker.js');
1588
- const logger = new Logger(projectRoot);
1589
- const tracker = new IterationTracker(projectRoot, logger);
1590
- const history = await tracker.getHistory(args.limit || 10, args.taskId);
1591
- const stats = await tracker.getStatistics();
1592
- return {
1593
- content: [
1594
- {
1595
- type: 'text',
1596
- text: JSON.stringify({
1597
- success: true,
1598
- iterations: history.length,
1599
- history: history.map((iter) => ({
1600
- iteration: iter.iteration,
1601
- taskId: iter.task_id,
1602
- taskTitle: iter.task_title,
1603
- status: iter.status,
1604
- duration: iter.duration_ms,
1605
- qualityChecks: iter.quality_checks,
1606
- commit: iter.git_commit,
1607
- })),
1608
- statistics: {
1609
- total: stats.total_iterations,
1610
- successful: stats.successful_iterations,
1611
- failed: stats.failed_iterations,
1612
- successRate: (stats.success_rate * 100).toFixed(1) + '%',
1613
- avgDuration: stats.average_duration_ms,
1614
- },
1615
- }),
1616
- },
1617
- ],
1618
- };
1619
- }
1620
- catch (error) {
1621
- return {
1622
- content: [
1623
- {
1624
- type: 'text',
1625
- text: JSON.stringify({ success: false, error: String(error) }),
1626
- },
1627
- ],
1628
- };
1629
- }
1630
- });
1631
- }
1632
1125
  // --- Background Indexer Tools ---
1633
1126
  // Register tool: rulebook_codebase_search
1634
1127
  server.registerTool('rulebook_codebase_search', {
@@ -1883,7 +1376,7 @@ export async function startRulebookMcpServer() {
1883
1376
  const root = args.projectId && workspaceManager
1884
1377
  ? (await workspaceManager.getWorker(args.projectId)).projectRoot
1885
1378
  : projectRoot;
1886
- const { DecisionManager } = await import('../core/decision-manager.js');
1379
+ const { DecisionManager } = await import('../core/tasks/decision-manager.js');
1887
1380
  const dm = new DecisionManager(root);
1888
1381
  const decision = await dm.create(args.title, {
1889
1382
  context: args.context,
@@ -1931,7 +1424,7 @@ export async function startRulebookMcpServer() {
1931
1424
  const root = args.projectId && workspaceManager
1932
1425
  ? (await workspaceManager.getWorker(args.projectId)).projectRoot
1933
1426
  : projectRoot;
1934
- const { DecisionManager } = await import('../core/decision-manager.js');
1427
+ const { DecisionManager } = await import('../core/tasks/decision-manager.js');
1935
1428
  const dm = new DecisionManager(root);
1936
1429
  const decisions = await dm.list(args.status);
1937
1430
  return {
@@ -1970,7 +1463,7 @@ export async function startRulebookMcpServer() {
1970
1463
  const root = args.projectId && workspaceManager
1971
1464
  ? (await workspaceManager.getWorker(args.projectId)).projectRoot
1972
1465
  : projectRoot;
1973
- const { DecisionManager } = await import('../core/decision-manager.js');
1466
+ const { DecisionManager } = await import('../core/tasks/decision-manager.js');
1974
1467
  const dm = new DecisionManager(root);
1975
1468
  const result = await dm.show(args.id);
1976
1469
  if (!result) {
@@ -2029,7 +1522,7 @@ export async function startRulebookMcpServer() {
2029
1522
  const root = args.projectId && workspaceManager
2030
1523
  ? (await workspaceManager.getWorker(args.projectId)).projectRoot
2031
1524
  : projectRoot;
2032
- const { DecisionManager } = await import('../core/decision-manager.js');
1525
+ const { DecisionManager } = await import('../core/tasks/decision-manager.js');
2033
1526
  const dm = new DecisionManager(root);
2034
1527
  const updated = await dm.update(args.id, {
2035
1528
  status: args.status,
@@ -2089,7 +1582,7 @@ export async function startRulebookMcpServer() {
2089
1582
  const root = args.projectId && workspaceManager
2090
1583
  ? (await workspaceManager.getWorker(args.projectId)).projectRoot
2091
1584
  : projectRoot;
2092
- const { KnowledgeManager } = await import('../core/knowledge-manager.js');
1585
+ const { KnowledgeManager } = await import('../core/tasks/knowledge-manager.js');
2093
1586
  const km = new KnowledgeManager(root);
2094
1587
  const entry = await km.add(args.type, args.title, {
2095
1588
  category: args.category,
@@ -2136,7 +1629,7 @@ export async function startRulebookMcpServer() {
2136
1629
  const root = args.projectId && workspaceManager
2137
1630
  ? (await workspaceManager.getWorker(args.projectId)).projectRoot
2138
1631
  : projectRoot;
2139
- const { KnowledgeManager } = await import('../core/knowledge-manager.js');
1632
+ const { KnowledgeManager } = await import('../core/tasks/knowledge-manager.js');
2140
1633
  const km = new KnowledgeManager(root);
2141
1634
  const entries = await km.list(args.type, args.category);
2142
1635
  return {
@@ -2175,7 +1668,7 @@ export async function startRulebookMcpServer() {
2175
1668
  const root = args.projectId && workspaceManager
2176
1669
  ? (await workspaceManager.getWorker(args.projectId)).projectRoot
2177
1670
  : projectRoot;
2178
- const { KnowledgeManager } = await import('../core/knowledge-manager.js');
1671
+ const { KnowledgeManager } = await import('../core/tasks/knowledge-manager.js');
2179
1672
  const km = new KnowledgeManager(root);
2180
1673
  const result = await km.show(args.id);
2181
1674
  if (!result) {
@@ -2230,7 +1723,7 @@ export async function startRulebookMcpServer() {
2230
1723
  const root = args.projectId && workspaceManager
2231
1724
  ? (await workspaceManager.getWorker(args.projectId)).projectRoot
2232
1725
  : projectRoot;
2233
- const { LearnManager } = await import('../core/learn-manager.js');
1726
+ const { LearnManager } = await import('../core/tasks/learn-manager.js');
2234
1727
  const lm = new LearnManager(root);
2235
1728
  const learning = await lm.capture(args.title, args.content, {
2236
1729
  tags: args.tags,
@@ -2272,7 +1765,7 @@ export async function startRulebookMcpServer() {
2272
1765
  const root = args.projectId && workspaceManager
2273
1766
  ? (await workspaceManager.getWorker(args.projectId)).projectRoot
2274
1767
  : projectRoot;
2275
- const { LearnManager } = await import('../core/learn-manager.js');
1768
+ const { LearnManager } = await import('../core/tasks/learn-manager.js');
2276
1769
  const lm = new LearnManager(root);
2277
1770
  const learnings = await lm.list(args.limit);
2278
1771
  return {
@@ -2315,7 +1808,7 @@ export async function startRulebookMcpServer() {
2315
1808
  const root = args.projectId && workspaceManager
2316
1809
  ? (await workspaceManager.getWorker(args.projectId)).projectRoot
2317
1810
  : projectRoot;
2318
- const { LearnManager } = await import('../core/learn-manager.js');
1811
+ const { LearnManager } = await import('../core/tasks/learn-manager.js');
2319
1812
  const lm = new LearnManager(root);
2320
1813
  const result = await lm.promote(args.id, args.target, { title: args.title });
2321
1814
  if (!result) {
@@ -2490,7 +1983,7 @@ export async function startRulebookMcpServer() {
2490
1983
  ? (await workspaceManager.getWorker(args.projectId)).projectRoot
2491
1984
  : projectRoot;
2492
1985
  const { listRules } = await import('../core/rule-engine.js');
2493
- const { listRulesWithSource } = await import('../core/rules-generator.js');
1986
+ const { listRulesWithSource } = await import('../core/generators/rules-generator.js');
2494
1987
  const canonical = await listRules(root);
2495
1988
  const languageRules = await listRulesWithSource(root);
2496
1989
  return {
@@ -2521,443 +2014,6 @@ export async function startRulebookMcpServer() {
2521
2014
  };
2522
2015
  }
2523
2016
  });
2524
- // Register tool: rulebook_doctor_run
2525
- server.registerTool('rulebook_doctor_run', {
2526
- title: 'Run Doctor',
2527
- description: 'Run rulebook health checks: file sizes, broken @imports, stale STATE.md, missing files',
2528
- inputSchema: { projectId: projectIdSchema },
2529
- }, async (args) => {
2530
- try {
2531
- const root = args.projectId && workspaceManager
2532
- ? (await workspaceManager.getWorker(args.projectId)).projectRoot
2533
- : projectRoot;
2534
- const { runDoctor } = await import('../core/doctor.js');
2535
- const report = await runDoctor(root);
2536
- return {
2537
- content: [{ type: 'text', text: JSON.stringify({ success: true, ...report }) }],
2538
- };
2539
- }
2540
- catch (error) {
2541
- return {
2542
- content: [
2543
- {
2544
- type: 'text',
2545
- text: JSON.stringify({
2546
- success: false,
2547
- error: error instanceof Error ? error.message : String(error),
2548
- }),
2549
- },
2550
- ],
2551
- };
2552
- }
2553
- });
2554
- // Register tool: rulebook_analysis_create
2555
- server.registerTool('rulebook_analysis_create', {
2556
- title: 'Create Analysis',
2557
- description: 'Scaffold a new structured analysis in docs/analysis/<slug>/',
2558
- inputSchema: {
2559
- topic: z.string().describe('Analysis topic'),
2560
- noTasks: z.boolean().optional().describe('Skip task materialization'),
2561
- projectId: projectIdSchema,
2562
- },
2563
- }, async (args) => {
2564
- try {
2565
- const root = args.projectId && workspaceManager
2566
- ? (await workspaceManager.getWorker(args.projectId)).projectRoot
2567
- : projectRoot;
2568
- const { createAnalysis } = await import('../core/analysis-manager.js');
2569
- const result = await createAnalysis(root, {
2570
- topic: args.topic,
2571
- noTasks: args.noTasks ?? false,
2572
- });
2573
- return {
2574
- content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }) }],
2575
- };
2576
- }
2577
- catch (error) {
2578
- return {
2579
- content: [
2580
- {
2581
- type: 'text',
2582
- text: JSON.stringify({
2583
- success: false,
2584
- error: error instanceof Error ? error.message : String(error),
2585
- }),
2586
- },
2587
- ],
2588
- };
2589
- }
2590
- });
2591
- // Register tool: rulebook_analysis_list
2592
- server.registerTool('rulebook_analysis_list', {
2593
- title: 'List Analyses',
2594
- description: 'List all structured analyses in docs/analysis/',
2595
- inputSchema: { projectId: projectIdSchema },
2596
- }, async (args) => {
2597
- try {
2598
- const root = args.projectId && workspaceManager
2599
- ? (await workspaceManager.getWorker(args.projectId)).projectRoot
2600
- : projectRoot;
2601
- const { listAnalyses } = await import('../core/analysis-manager.js');
2602
- const analyses = await listAnalyses(root);
2603
- return {
2604
- content: [
2605
- {
2606
- type: 'text',
2607
- text: JSON.stringify({ success: true, analyses, count: analyses.length }),
2608
- },
2609
- ],
2610
- };
2611
- }
2612
- catch (error) {
2613
- return {
2614
- content: [
2615
- {
2616
- type: 'text',
2617
- text: JSON.stringify({
2618
- success: false,
2619
- error: error instanceof Error ? error.message : String(error),
2620
- }),
2621
- },
2622
- ],
2623
- };
2624
- }
2625
- });
2626
- // Register tool: rulebook_analysis_show
2627
- server.registerTool('rulebook_analysis_show', {
2628
- title: 'Show Analysis',
2629
- description: 'Show the contents of a structured analysis by slug',
2630
- inputSchema: {
2631
- slug: z.string().describe('Analysis slug (directory name)'),
2632
- projectId: projectIdSchema,
2633
- },
2634
- }, async (args) => {
2635
- try {
2636
- const root = args.projectId && workspaceManager
2637
- ? (await workspaceManager.getWorker(args.projectId)).projectRoot
2638
- : projectRoot;
2639
- const { showAnalysis } = await import('../core/analysis-manager.js');
2640
- const analysis = await showAnalysis(root, args.slug);
2641
- if (!analysis) {
2642
- return {
2643
- content: [
2644
- {
2645
- type: 'text',
2646
- text: JSON.stringify({
2647
- success: false,
2648
- error: `Analysis "${args.slug}" not found`,
2649
- }),
2650
- },
2651
- ],
2652
- };
2653
- }
2654
- return {
2655
- content: [{ type: 'text', text: JSON.stringify({ success: true, ...analysis }) }],
2656
- };
2657
- }
2658
- catch (error) {
2659
- return {
2660
- content: [
2661
- {
2662
- type: 'text',
2663
- text: JSON.stringify({
2664
- success: false,
2665
- error: error instanceof Error ? error.message : String(error),
2666
- }),
2667
- },
2668
- ],
2669
- };
2670
- }
2671
- });
2672
- // Register tool: rulebook_blockers
2673
- server.registerTool('rulebook_blockers', {
2674
- title: 'Show Blockers',
2675
- description: 'Show task blocker chain with cascade impact analysis',
2676
- inputSchema: {
2677
- projectId: projectIdSchema,
2678
- },
2679
- }, async (args) => {
2680
- try {
2681
- const tm = await getTaskMgr(args.projectId);
2682
- const tasks = await tm.listTasks();
2683
- // Build blocker chain from task metadata
2684
- const blockers = [];
2685
- for (const task of tasks) {
2686
- const metadata = await tm.getTaskMetadata(task.id);
2687
- const blocks = Array.isArray(metadata?.blocks) ? metadata.blocks : [];
2688
- const blockedBy = Array.isArray(metadata?.blockedBy)
2689
- ? metadata.blockedBy
2690
- : [];
2691
- if (blocks.length > 0 || blockedBy.length > 0) {
2692
- blockers.push({
2693
- taskId: task.id,
2694
- blocks,
2695
- blockedBy,
2696
- cascadeImpact: metadata?.cascadeImpact || blocks.length,
2697
- });
2698
- }
2699
- }
2700
- // Sort by cascade impact (highest first)
2701
- blockers.sort((a, b) => b.cascadeImpact - a.cascadeImpact);
2702
- return {
2703
- content: [
2704
- {
2705
- type: 'text',
2706
- text: JSON.stringify({ success: true, blockers, count: blockers.length }),
2707
- },
2708
- ],
2709
- };
2710
- }
2711
- catch (error) {
2712
- return {
2713
- content: [
2714
- {
2715
- type: 'text',
2716
- text: JSON.stringify({
2717
- success: false,
2718
- error: error instanceof Error ? error.message : String(error),
2719
- }),
2720
- },
2721
- ],
2722
- };
2723
- }
2724
- });
2725
- // ── v5.4.0 compress tools ──────────────────────────────────────────
2726
- server.registerTool('rulebook_compress', {
2727
- title: 'Compress Memory File',
2728
- description: 'Compress a markdown memory file (prose-only rewriter; preserves code, URLs, paths, dates, versions byte-for-byte). Writes a backup to <file>.original.md and replaces the file in place. Returns before/after byte counts and validator result.',
2729
- inputSchema: {
2730
- filePath: z
2731
- .string()
2732
- .describe('Absolute or project-relative path to the .md file to compress'),
2733
- dryRun: z
2734
- .boolean()
2735
- .optional()
2736
- .describe('Return the would-be result without writing anything'),
2737
- projectId: projectIdSchema,
2738
- },
2739
- }, async (args) => {
2740
- try {
2741
- const { readFile, writeFile, fileExists } = await import('../utils/file-system.js');
2742
- const { compress } = await import('../core/compress/compressor.js');
2743
- const path = await import('path');
2744
- const projectRoot = process.cwd();
2745
- const abs = path.default.isAbsolute(args.filePath)
2746
- ? args.filePath
2747
- : path.default.join(projectRoot, args.filePath);
2748
- if (!(await fileExists(abs))) {
2749
- return {
2750
- content: [
2751
- {
2752
- type: 'text',
2753
- text: JSON.stringify({ success: false, error: `File not found: ${abs}` }),
2754
- },
2755
- ],
2756
- };
2757
- }
2758
- const original = await readFile(abs);
2759
- const result = compress(original);
2760
- if (!result.validation.ok) {
2761
- return {
2762
- content: [
2763
- {
2764
- type: 'text',
2765
- text: JSON.stringify({
2766
- success: false,
2767
- error: 'Validator rejected the compressed output',
2768
- violations: result.validation.violations.slice(0, 10),
2769
- }),
2770
- },
2771
- ],
2772
- };
2773
- }
2774
- const backupPath = abs.replace(/\.md$/i, '.original.md');
2775
- if (!args.dryRun) {
2776
- if (!(await fileExists(backupPath))) {
2777
- await writeFile(backupPath, original);
2778
- }
2779
- await writeFile(abs, result.output);
2780
- }
2781
- return {
2782
- content: [
2783
- {
2784
- type: 'text',
2785
- text: JSON.stringify({
2786
- success: true,
2787
- filePath: abs,
2788
- dryRun: !!args.dryRun,
2789
- originalBytes: result.validation.stats.originalBytes,
2790
- compressedBytes: result.validation.stats.compressedBytes,
2791
- savedPct: Math.round((1 - result.validation.stats.ratio) * 100),
2792
- retries: result.retries,
2793
- backup: args.dryRun ? null : backupPath,
2794
- }),
2795
- },
2796
- ],
2797
- };
2798
- }
2799
- catch (error) {
2800
- return {
2801
- content: [
2802
- {
2803
- type: 'text',
2804
- text: JSON.stringify({
2805
- success: false,
2806
- error: error instanceof Error ? error.message : String(error),
2807
- }),
2808
- },
2809
- ],
2810
- };
2811
- }
2812
- });
2813
- server.registerTool('rulebook_evals_measure', {
2814
- title: 'Measure Terse Evals',
2815
- description: 'Run the offline three-arm evaluation measurement (baseline/terse/rulebook-terse). Reads snapshots committed under evals/snapshots/, uses tiktoken when installed (falls back to UTF-8 byte counts otherwise). Returns per-prompt lift, total lift, and pass/fail against arms.json liftThreshold. Does NOT call the Anthropic API — safe for CI without credentials.',
2816
- inputSchema: {
2817
- projectId: projectIdSchema,
2818
- },
2819
- }, async () => {
2820
- try {
2821
- const path = await import('path');
2822
- const root = process.cwd();
2823
- const measurePath = path.default.resolve(root, 'evals/measure.js');
2824
- const { existsSync } = await import('fs');
2825
- // Resolve the project-local evals path so rulebook run from a
2826
- // user project (no evals/ directory) fails cleanly.
2827
- const measureModulePath = existsSync(measurePath)
2828
- ? measurePath
2829
- : path.default.resolve(root, 'evals/measure.ts');
2830
- if (!existsSync(measureModulePath)) {
2831
- return {
2832
- content: [
2833
- {
2834
- type: 'text',
2835
- text: JSON.stringify({
2836
- success: false,
2837
- error: 'evals/ directory not found in project — this tool targets the Rulebook repo itself, not downstream projects.',
2838
- }),
2839
- },
2840
- ],
2841
- };
2842
- }
2843
- // Use a bare URL import so Node resolves the project-local file
2844
- // regardless of where the MCP server was installed from.
2845
- const mod = (await import(/* @vite-ignore */ measureModulePath));
2846
- const report = await mod.measure(path.default.resolve(root, 'evals/snapshots/results.json'), path.default.resolve(root, 'evals/arms.json'));
2847
- return {
2848
- content: [{ type: 'text', text: JSON.stringify({ success: true, report }) }],
2849
- };
2850
- }
2851
- catch (error) {
2852
- return {
2853
- content: [
2854
- {
2855
- type: 'text',
2856
- text: JSON.stringify({
2857
- success: false,
2858
- error: error instanceof Error ? error.message : String(error),
2859
- }),
2860
- },
2861
- ],
2862
- };
2863
- }
2864
- });
2865
- server.registerTool('rulebook_evals_run', {
2866
- title: 'Run Terse Evals Against Live API',
2867
- description: 'Regenerate evals/snapshots/results.json by calling the Anthropic API for every (prompt, arm) pair. Requires ANTHROPIC_API_KEY in the environment and @anthropic-ai/sdk in the project. Expensive — run only when SKILL.md or prompts change. Use rulebook_evals_measure for the cheap offline comparison.',
2868
- inputSchema: {
2869
- projectId: projectIdSchema,
2870
- },
2871
- }, async () => {
2872
- try {
2873
- if (!process.env.ANTHROPIC_API_KEY) {
2874
- return {
2875
- content: [
2876
- {
2877
- type: 'text',
2878
- text: JSON.stringify({
2879
- success: false,
2880
- error: 'ANTHROPIC_API_KEY is not set.',
2881
- }),
2882
- },
2883
- ],
2884
- };
2885
- }
2886
- // Delegate to the CLI script — spawning keeps this non-blocking
2887
- // and isolates the API dependency from the MCP server process.
2888
- const { spawn } = await import('child_process');
2889
- const result = await new Promise((resolvePromise) => {
2890
- const child = spawn('npx', ['tsx', 'evals/llm_run.ts'], {
2891
- cwd: process.cwd(),
2892
- shell: true,
2893
- });
2894
- let stdout = '';
2895
- let stderr = '';
2896
- child.stdout.on('data', (d) => (stdout += String(d)));
2897
- child.stderr.on('data', (d) => (stderr += String(d)));
2898
- child.on('close', (code) => resolvePromise({ stdout, stderr, code: code ?? 1 }));
2899
- });
2900
- return {
2901
- content: [
2902
- {
2903
- type: 'text',
2904
- text: JSON.stringify({
2905
- success: result.code === 0,
2906
- exitCode: result.code,
2907
- stdout: result.stdout.slice(-4000),
2908
- stderr: result.stderr.slice(-2000),
2909
- }),
2910
- },
2911
- ],
2912
- };
2913
- }
2914
- catch (error) {
2915
- return {
2916
- content: [
2917
- {
2918
- type: 'text',
2919
- text: JSON.stringify({
2920
- success: false,
2921
- error: error instanceof Error ? error.message : String(error),
2922
- }),
2923
- },
2924
- ],
2925
- };
2926
- }
2927
- });
2928
- server.registerTool('rulebook_compress_list', {
2929
- title: 'List Compression Candidates',
2930
- description: 'List markdown memory files in the project that are compression candidates (CLAUDE.md, AGENTS.md, AGENTS.override.md, .rulebook/PLANS.md, .rulebook/STATE.md, and all .md under .rulebook/knowledge/ + .rulebook/learnings/). Reports current size + backup state.',
2931
- inputSchema: {
2932
- projectId: projectIdSchema,
2933
- },
2934
- }, async () => {
2935
- try {
2936
- const { listCompressCandidates } = await import('../core/compress/discover.js');
2937
- const candidates = await listCompressCandidates(process.cwd());
2938
- return {
2939
- content: [
2940
- {
2941
- type: 'text',
2942
- text: JSON.stringify({ success: true, candidates, count: candidates.length }),
2943
- },
2944
- ],
2945
- };
2946
- }
2947
- catch (error) {
2948
- return {
2949
- content: [
2950
- {
2951
- type: 'text',
2952
- text: JSON.stringify({
2953
- success: false,
2954
- error: error instanceof Error ? error.message : String(error),
2955
- }),
2956
- },
2957
- ],
2958
- };
2959
- }
2960
- });
2961
2017
  const transport = new StdioServerTransport();
2962
2018
  await server.connect(transport);
2963
2019
  }