@hivehub/rulebook 5.8.2 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +86 -216
- package/dist/cli/commands/claude.d.ts.map +1 -1
- package/dist/cli/commands/claude.js +10 -4
- package/dist/cli/commands/claude.js.map +1 -1
- package/dist/cli/commands/context-intelligence.d.ts.map +1 -1
- package/dist/cli/commands/context-intelligence.js.map +1 -1
- package/dist/cli/commands/index.d.ts +1 -2
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +1 -2
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +16 -91
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/mcp.d.ts.map +1 -1
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/misc.d.ts +0 -1
- package/dist/cli/commands/misc.d.ts.map +1 -1
- package/dist/cli/commands/misc.js +0 -76
- package/dist/cli/commands/misc.js.map +1 -1
- package/dist/cli/commands/plans.d.ts.map +1 -1
- package/dist/cli/commands/plans.js.map +1 -1
- package/dist/cli/commands/skills.d.ts.map +1 -1
- package/dist/cli/commands/skills.js +6 -2
- package/dist/cli/commands/skills.js.map +1 -1
- package/dist/cli/commands/task.d.ts.map +1 -1
- package/dist/cli/commands/task.js +3 -1
- package/dist/cli/commands/task.js.map +1 -1
- package/dist/cli/commands/update.d.ts +7 -0
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/update.js +61 -165
- package/dist/cli/commands/update.js.map +1 -1
- package/dist/cli/commands/workspace.d.ts.map +1 -1
- package/dist/cli/commands/workspace.js +4 -3
- package/dist/cli/commands/workspace.js.map +1 -1
- package/dist/cli/prompts.d.ts.map +1 -1
- package/dist/cli/prompts.js +0 -40
- package/dist/cli/prompts.js.map +1 -1
- package/dist/core/claude/claude-mcp.d.ts.map +1 -1
- package/dist/core/claude/claude-mcp.js +1 -1
- package/dist/core/claude/claude-mcp.js.map +1 -1
- package/dist/core/claude/claude-md-generator.d.ts.map +1 -1
- package/dist/core/claude/claude-md-generator.js.map +1 -1
- package/dist/core/claude/claude-settings-manager.d.ts.map +1 -1
- package/dist/core/claude/claude-settings-manager.js +9 -6
- package/dist/core/claude/claude-settings-manager.js.map +1 -1
- package/dist/core/custom-templates.d.ts.map +1 -1
- package/dist/core/custom-templates.js.map +1 -1
- package/dist/core/detect/detector.d.ts +0 -28
- package/dist/core/detect/detector.d.ts.map +1 -1
- package/dist/core/detect/detector.js +5 -84
- package/dist/core/detect/detector.js.map +1 -1
- package/dist/core/detect/library-registry.d.ts.map +1 -1
- package/dist/core/detect/library-registry.js.map +1 -1
- package/dist/core/docs/docs-generator.d.ts.map +1 -1
- package/dist/core/docs/docs-generator.js.map +1 -1
- package/dist/core/docs/mcp-reference-generator.d.ts.map +1 -1
- package/dist/core/docs/mcp-reference-generator.js.map +1 -1
- package/dist/core/generators/generator.d.ts.map +1 -1
- package/dist/core/generators/generator.js +0 -72
- package/dist/core/generators/generator.js.map +1 -1
- package/dist/core/generators/gitignore-generator.d.ts.map +1 -1
- package/dist/core/generators/gitignore-generator.js +12 -1
- package/dist/core/generators/gitignore-generator.js.map +1 -1
- package/dist/core/generators/minimal-scaffolder.d.ts.map +1 -1
- package/dist/core/generators/minimal-scaffolder.js.map +1 -1
- package/dist/core/generators/rules-generator.d.ts.map +1 -1
- package/dist/core/generators/rules-generator.js.map +1 -1
- package/dist/core/generators/workflow-generator.d.ts +0 -10
- package/dist/core/generators/workflow-generator.d.ts.map +1 -1
- package/dist/core/generators/workflow-generator.js +0 -307
- package/dist/core/generators/workflow-generator.js.map +1 -1
- package/dist/core/logger.d.ts.map +1 -1
- package/dist/core/logger.js.map +1 -1
- package/dist/core/merger.d.ts.map +1 -1
- package/dist/core/merger.js.map +1 -1
- package/dist/core/migrator.d.ts.map +1 -1
- package/dist/core/migrator.js +2 -1
- package/dist/core/migrator.js.map +1 -1
- package/dist/core/quality/coverage-checker.d.ts.map +1 -1
- package/dist/core/quality/coverage-checker.js.map +1 -1
- package/dist/core/quality/dependency-checker.d.ts.map +1 -1
- package/dist/core/quality/dependency-checker.js +3 -1
- package/dist/core/quality/dependency-checker.js.map +1 -1
- package/dist/core/quality/doctor.d.ts.map +1 -1
- package/dist/core/quality/doctor.js.map +1 -1
- package/dist/core/quality/validator.d.ts.map +1 -1
- package/dist/core/quality/validator.js.map +1 -1
- package/dist/core/rule-engine.d.ts +5 -21
- package/dist/core/rule-engine.d.ts.map +1 -1
- package/dist/core/rule-engine.js +9 -191
- package/dist/core/rule-engine.js.map +1 -1
- package/dist/core/skills/skills-manager.d.ts.map +1 -1
- package/dist/core/skills/skills-manager.js.map +1 -1
- package/dist/core/state/config-manager.d.ts.map +1 -1
- package/dist/core/state/config-manager.js +6 -50
- package/dist/core/state/config-manager.js.map +1 -1
- package/dist/core/state/override-manager.js.map +1 -1
- package/dist/core/state/state-writer.d.ts.map +1 -1
- package/dist/core/state/state-writer.js.map +1 -1
- package/dist/core/state/version-bumper.d.ts.map +1 -1
- package/dist/core/state/version-bumper.js.map +1 -1
- package/dist/core/tasks/decision-manager.d.ts.map +1 -1
- package/dist/core/tasks/decision-manager.js +6 -1
- package/dist/core/tasks/decision-manager.js.map +1 -1
- package/dist/core/tasks/knowledge-manager.d.ts.map +1 -1
- package/dist/core/tasks/knowledge-manager.js.map +1 -1
- package/dist/core/tasks/learn-manager.d.ts.map +1 -1
- package/dist/core/tasks/learn-manager.js.map +1 -1
- package/dist/core/tasks/plans-manager.d.ts.map +1 -1
- package/dist/core/tasks/plans-manager.js.map +1 -1
- package/dist/core/tasks/task-manager.d.ts.map +1 -1
- package/dist/core/tasks/task-manager.js.map +1 -1
- package/dist/core/workspace/legacy-migrator.d.ts.map +1 -1
- package/dist/core/workspace/legacy-migrator.js.map +1 -1
- package/dist/core/workspace/project-worker.d.ts +0 -4
- package/dist/core/workspace/project-worker.d.ts.map +1 -1
- package/dist/core/workspace/project-worker.js +0 -28
- package/dist/core/workspace/project-worker.js.map +1 -1
- package/dist/core/workspace/workspace-manager.d.ts +0 -11
- package/dist/core/workspace/workspace-manager.d.ts.map +1 -1
- package/dist/core/workspace/workspace-manager.js +6 -30
- package/dist/core/workspace/workspace-manager.js.map +1 -1
- package/dist/core/workspace/workspace-types.d.ts +0 -1
- package/dist/core/workspace/workspace-types.d.ts.map +1 -1
- package/dist/hooks/safe-flag-io.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -82
- package/dist/index.js.map +1 -1
- package/dist/mcp/rulebook-server.d.ts.map +1 -1
- package/dist/mcp/rulebook-server.js +55 -1634
- package/dist/mcp/rulebook-server.js.map +1 -1
- package/dist/mcp/tools/context.d.ts +23 -0
- package/dist/mcp/tools/context.d.ts.map +1 -0
- package/dist/mcp/tools/context.js +2 -0
- package/dist/mcp/tools/context.js.map +1 -0
- package/dist/mcp/tools/decision-tools.d.ts +5 -0
- package/dist/mcp/tools/decision-tools.d.ts.map +1 -0
- package/dist/mcp/tools/decision-tools.js +220 -0
- package/dist/mcp/tools/decision-tools.js.map +1 -0
- package/dist/mcp/tools/knowledge-tools.d.ts +5 -0
- package/dist/mcp/tools/knowledge-tools.d.ts.map +1 -0
- package/dist/mcp/tools/knowledge-tools.js +157 -0
- package/dist/mcp/tools/knowledge-tools.js.map +1 -0
- package/dist/mcp/tools/learn-tools.d.ts +5 -0
- package/dist/mcp/tools/learn-tools.d.ts.map +1 -0
- package/dist/mcp/tools/learn-tools.js +150 -0
- package/dist/mcp/tools/learn-tools.js.map +1 -0
- package/dist/mcp/tools/rules-tools.d.ts +4 -0
- package/dist/mcp/tools/rules-tools.d.ts.map +1 -0
- package/dist/mcp/tools/rules-tools.js +47 -0
- package/dist/mcp/tools/rules-tools.js.map +1 -0
- package/dist/mcp/tools/skill-tools.d.ts +5 -0
- package/dist/mcp/tools/skill-tools.d.ts.map +1 -0
- package/dist/mcp/tools/skill-tools.js +330 -0
- package/dist/mcp/tools/skill-tools.js.map +1 -0
- package/dist/mcp/tools/task-tools.d.ts +5 -0
- package/dist/mcp/tools/task-tools.d.ts.map +1 -0
- package/dist/mcp/tools/task-tools.js +185 -0
- package/dist/mcp/tools/task-tools.js.map +1 -0
- package/dist/mcp/tools/workspace-tools.d.ts +6 -0
- package/dist/mcp/tools/workspace-tools.d.ts.map +1 -0
- package/dist/mcp/tools/workspace-tools.js +118 -0
- package/dist/mcp/tools/workspace-tools.js.map +1 -0
- package/dist/types.d.ts +1 -46
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/file-system.d.ts.map +1 -1
- package/dist/utils/file-system.js.map +1 -1
- package/dist/utils/git-hooks.d.ts.map +1 -1
- package/dist/utils/git-hooks.js.map +1 -1
- package/dist/utils/gitignore.d.ts.map +1 -1
- package/dist/utils/gitignore.js.map +1 -1
- package/dist/utils/rulesignore.d.ts.map +1 -1
- package/dist/utils/rulesignore.js.map +1 -1
- package/package.json +25 -27
- package/templates/agents/architect.md +51 -51
- package/templates/agents/build-engineer.md +36 -36
- package/templates/agents/code-reviewer.md +47 -47
- package/templates/agents/docs-writer.md +38 -38
- package/templates/agents/implementer.md +42 -42
- package/templates/agents/performance-engineer.md +49 -49
- package/templates/agents/researcher.md +38 -38
- package/templates/agents/security-reviewer.md +40 -40
- package/templates/agents/team-lead.md +37 -37
- package/templates/agents/tester.md +48 -48
- package/templates/ci/rulebook-review.yml +26 -26
- package/templates/cli/CLAUDE.md +102 -117
- package/templates/cli/_GENERIC_TEMPLATE.md +29 -29
- package/templates/commands/rulebook-decision-create.md +55 -55
- package/templates/commands/rulebook-decision-list.md +15 -15
- package/templates/commands/rulebook-knowledge-add.md +41 -41
- package/templates/commands/rulebook-knowledge-list.md +15 -15
- package/templates/commands/rulebook-learn-capture.md +1 -2
- package/templates/commands/rulebook-task-apply.md +67 -67
- package/templates/commands/rulebook-task-archive.md +94 -94
- package/templates/commands/rulebook-task-create.md +93 -93
- package/templates/commands/rulebook-task-list.md +42 -42
- package/templates/commands/rulebook-task-show.md +52 -52
- package/templates/commands/rulebook-task-validate.md +53 -53
- package/templates/compact-context/_default.md +23 -23
- package/templates/compact-context/cpp.md +26 -26
- package/templates/compact-context/go.md +26 -26
- package/templates/compact-context/python.md +26 -26
- package/templates/compact-context/rust.md +28 -28
- package/templates/compact-context/typescript.md +29 -29
- package/templates/core/AGENTS_LEAN.md +4 -9
- package/templates/core/AGENTS_OVERRIDE.md +16 -16
- package/templates/core/AGENT_AUTOMATION.md +273 -296
- package/templates/core/CLAUDE_MD_v2.md +85 -90
- package/templates/core/DAG.md +304 -304
- package/templates/core/DECISIONS.md +38 -38
- package/templates/core/DOCUMENTATION_RULES.md +36 -36
- package/templates/core/KNOWLEDGE.md +49 -49
- package/templates/core/MULTI_AGENT.md +74 -74
- package/templates/core/PLANS.md +28 -28
- package/templates/core/QUALITY_ENFORCEMENT.md +68 -68
- package/templates/core/RULEBOOK.md +1936 -1947
- package/templates/core/TIER1_PROHIBITIONS.md +154 -154
- package/templates/core/TOKEN_OPTIMIZATION.md +49 -49
- package/templates/core/WORKSPACE.md +4 -8
- package/templates/git/CI_CD_PATTERNS.md +661 -661
- package/templates/git/GITHUB_ACTIONS.md +728 -728
- package/templates/git/GITLAB_CI.md +730 -730
- package/templates/git/GIT_WORKFLOW.md +1192 -1192
- package/templates/git/SECRETS_MANAGEMENT.md +585 -585
- package/templates/hooks/COMMIT_MSG.md +530 -530
- package/templates/hooks/POST_CHECKOUT.md +546 -546
- package/templates/hooks/PREPARE_COMMIT_MSG.md +619 -619
- package/templates/hooks/PRE_COMMIT.md +414 -414
- package/templates/hooks/PRE_PUSH.md +601 -601
- package/templates/hooks/enforce-pre-tool.sh +26 -9
- package/templates/hooks/update-check.ps1 +84 -84
- package/templates/hooks/update-check.sh +45 -21
- package/templates/languages/C.md +333 -333
- package/templates/languages/CPP.md +743 -743
- package/templates/languages/CSHARP.md +417 -417
- package/templates/languages/ELIXIR.md +454 -454
- package/templates/languages/ERLANG.md +361 -361
- package/templates/languages/GO.md +645 -645
- package/templates/languages/HASKELL.md +177 -177
- package/templates/languages/JAVA.md +607 -607
- package/templates/languages/JAVASCRIPT.md +631 -631
- package/templates/languages/JULIA.md +97 -97
- package/templates/languages/KOTLIN.md +511 -511
- package/templates/languages/LISP.md +100 -100
- package/templates/languages/LUA.md +74 -74
- package/templates/languages/OBJECTIVEC.md +90 -90
- package/templates/languages/PHP.md +416 -416
- package/templates/languages/PYTHON.md +682 -682
- package/templates/languages/RUBY.md +421 -421
- package/templates/languages/RUST.md +477 -477
- package/templates/languages/SAS.md +73 -73
- package/templates/languages/SCALA.md +348 -348
- package/templates/languages/SOLIDITY.md +580 -580
- package/templates/languages/SQL.md +137 -137
- package/templates/languages/SWIFT.md +466 -466
- package/templates/languages/TYPESCRIPT.md +591 -591
- package/templates/languages/ZIG.md +265 -265
- package/templates/modules/CONTEXT7.md +54 -54
- package/templates/modules/GITHUB_MCP.md +64 -64
- package/templates/modules/PLAYWRIGHT.md +90 -90
- package/templates/modules/RULEBOOK_MCP.md +208 -208
- package/templates/modules/SERENA.md +337 -337
- package/templates/modules/SUPABASE.md +223 -223
- package/templates/modules/SYNAP.md +69 -69
- package/templates/modules/VECTORIZER.md +63 -63
- package/templates/modules/sequential-thinking.md +42 -42
- package/templates/rules/consult-analysis-before-implementing.md +21 -23
- package/templates/rules/cpp.md +46 -46
- package/templates/rules/csharp.md +44 -44
- package/templates/rules/diagnostic-first.md +39 -39
- package/templates/rules/fail-twice-escalate.md +46 -46
- package/templates/rules/follow-task-sequence.md +36 -36
- package/templates/rules/git-safety.md +29 -29
- package/templates/rules/go.md +40 -40
- package/templates/rules/incremental-implementation.md +56 -56
- package/templates/rules/incremental-tests.md +29 -29
- package/templates/rules/java.md +43 -43
- package/templates/rules/javascript.md +39 -39
- package/templates/rules/knowledge-base-usage.md +41 -41
- package/templates/rules/multi-agent-teams.md +75 -75
- package/templates/rules/no-deferred.md +31 -31
- package/templates/rules/no-shortcuts.md +30 -30
- package/templates/rules/python.md +43 -43
- package/templates/rules/research-first.md +30 -30
- package/templates/rules/respect-handoff-trigger.md +41 -41
- package/templates/rules/rust.md +40 -40
- package/templates/rules/sequential-editing.md +21 -21
- package/templates/rules/session-workflow.md +24 -24
- package/templates/rules/task-decomposition.md +32 -32
- package/templates/rules/typescript.md +40 -40
- package/templates/skills/cli/claude/SKILL.md +42 -42
- package/templates/skills/core/agent-automation/SKILL.md +194 -194
- package/templates/skills/core/dag/SKILL.md +314 -314
- package/templates/skills/core/documentation-rules/SKILL.md +46 -46
- package/templates/skills/core/quality-enforcement/SKILL.md +78 -78
- package/templates/skills/core/rulebook/SKILL.md +176 -176
- package/templates/skills/core/rulebook-terse/SKILL.md +116 -116
- package/templates/skills/core/rulebook-terse-commit/SKILL.md +96 -96
- package/templates/skills/core/rulebook-terse-review/SKILL.md +112 -112
- package/templates/skills/dev/accessibility/SKILL.md +17 -17
- package/templates/skills/dev/analysis/SKILL.md +19 -19
- package/templates/skills/dev/api-design/SKILL.md +15 -15
- package/templates/skills/dev/architect/SKILL.md +17 -17
- package/templates/skills/dev/build-fix/SKILL.md +17 -17
- package/templates/skills/dev/db-design/SKILL.md +15 -15
- package/templates/skills/dev/debug/SKILL.md +16 -16
- package/templates/skills/dev/deploy/SKILL.md +17 -17
- package/templates/skills/dev/docs/SKILL.md +17 -17
- package/templates/skills/dev/handoff/SKILL.md +27 -27
- package/templates/skills/dev/migrate/SKILL.md +15 -15
- package/templates/skills/dev/perf/SKILL.md +17 -17
- package/templates/skills/dev/refactor/SKILL.md +17 -17
- package/templates/skills/dev/research/SKILL.md +14 -14
- package/templates/skills/dev/review/SKILL.md +18 -18
- package/templates/skills/dev/security-audit/SKILL.md +17 -17
- package/templates/skills/languages/c/SKILL.md +343 -343
- package/templates/skills/languages/cpp/SKILL.md +753 -753
- package/templates/skills/languages/csharp/SKILL.md +427 -427
- package/templates/skills/languages/elixir/SKILL.md +464 -464
- package/templates/skills/languages/erlang/SKILL.md +371 -371
- package/templates/skills/languages/go/SKILL.md +655 -655
- package/templates/skills/languages/haskell/SKILL.md +187 -187
- package/templates/skills/languages/java/SKILL.md +617 -617
- package/templates/skills/languages/javascript/SKILL.md +641 -641
- package/templates/skills/languages/julia/SKILL.md +107 -107
- package/templates/skills/languages/kotlin/SKILL.md +521 -521
- package/templates/skills/languages/lisp/SKILL.md +110 -110
- package/templates/skills/languages/lua/SKILL.md +84 -84
- package/templates/skills/languages/objectivec/SKILL.md +100 -100
- package/templates/skills/languages/php/SKILL.md +426 -426
- package/templates/skills/languages/python/SKILL.md +692 -692
- package/templates/skills/languages/ruby/SKILL.md +431 -431
- package/templates/skills/languages/rust/SKILL.md +487 -487
- package/templates/skills/languages/sas/SKILL.md +83 -83
- package/templates/skills/languages/scala/SKILL.md +358 -358
- package/templates/skills/languages/solidity/SKILL.md +590 -590
- package/templates/skills/languages/sql/SKILL.md +147 -147
- package/templates/skills/languages/swift/SKILL.md +476 -476
- package/templates/skills/languages/typescript/SKILL.md +302 -302
- package/templates/skills/languages/zig/SKILL.md +275 -275
- package/templates/skills/modules/context7/SKILL.md +64 -64
- package/templates/skills/modules/github-mcp/SKILL.md +74 -74
- package/templates/skills/modules/playwright/SKILL.md +100 -100
- package/templates/skills/modules/rulebook-mcp/SKILL.md +166 -166
- package/templates/skills/modules/serena/SKILL.md +347 -347
- package/templates/skills/modules/supabase/SKILL.md +233 -233
- package/templates/skills/modules/synap/SKILL.md +79 -79
- package/templates/skills/modules/vectorizer/SKILL.md +73 -73
- package/.claude/commands/analysis.md +0 -35
- package/.claude/commands/continue.md +0 -33
- package/.claude/commands/rulebook-decision-create.md +0 -55
- package/.claude/commands/rulebook-decision-list.md +0 -15
- package/.claude/commands/rulebook-knowledge-add.md +0 -41
- package/.claude/commands/rulebook-knowledge-list.md +0 -15
- package/.claude/commands/rulebook-learn-capture.md +0 -41
- package/.claude/commands/rulebook-learn-list.md +0 -13
- package/.claude/commands/rulebook-memory-save.md +0 -48
- package/.claude/commands/rulebook-memory-search.md +0 -47
- package/.claude/commands/rulebook-task-apply.md +0 -67
- package/.claude/commands/rulebook-task-archive.md +0 -94
- package/.claude/commands/rulebook-task-create.md +0 -93
- package/.claude/commands/rulebook-task-list.md +0 -42
- package/.claude/commands/rulebook-task-show.md +0 -52
- package/.claude/commands/rulebook-task-validate.md +0 -53
- package/.claude-plugin/marketplace.json +0 -28
- package/.claude-plugin/plugin.json +0 -8
- package/dist/agents/claude-code.d.ts +0 -69
- package/dist/agents/claude-code.d.ts.map +0 -1
- package/dist/agents/claude-code.js +0 -180
- package/dist/agents/claude-code.js.map +0 -1
- package/dist/agents/cursor-agent.d.ts +0 -184
- package/dist/agents/cursor-agent.d.ts.map +0 -1
- package/dist/agents/cursor-agent.js +0 -299
- package/dist/agents/cursor-agent.js.map +0 -1
- package/dist/agents/gemini-cli.d.ts +0 -69
- package/dist/agents/gemini-cli.d.ts.map +0 -1
- package/dist/agents/gemini-cli.js +0 -180
- package/dist/agents/gemini-cli.js.map +0 -1
- package/dist/cli/commands/memory.d.ts +0 -30
- package/dist/cli/commands/memory.d.ts.map +0 -1
- package/dist/cli/commands/memory.js +0 -259
- package/dist/cli/commands/memory.js.map +0 -1
- package/dist/core/console/cli-bridge.d.ts +0 -113
- package/dist/core/console/cli-bridge.d.ts.map +0 -1
- package/dist/core/console/cli-bridge.js +0 -1094
- package/dist/core/console/cli-bridge.js.map +0 -1
- package/dist/core/ide/multi-tool-generator.d.ts +0 -59
- package/dist/core/ide/multi-tool-generator.d.ts.map +0 -1
- package/dist/core/ide/multi-tool-generator.js +0 -157
- package/dist/core/ide/multi-tool-generator.js.map +0 -1
- package/dist/core/ide/opencode-generator.d.ts +0 -72
- package/dist/core/ide/opencode-generator.d.ts.map +0 -1
- package/dist/core/ide/opencode-generator.js +0 -450
- package/dist/core/ide/opencode-generator.js.map +0 -1
- package/dist/core/indexer/background-indexer.d.ts +0 -35
- package/dist/core/indexer/background-indexer.d.ts.map +0 -1
- package/dist/core/indexer/background-indexer.js +0 -267
- package/dist/core/indexer/background-indexer.js.map +0 -1
- package/dist/core/indexer/file-parser.d.ts +0 -28
- package/dist/core/indexer/file-parser.d.ts.map +0 -1
- package/dist/core/indexer/file-parser.js +0 -171
- package/dist/core/indexer/file-parser.js.map +0 -1
- package/dist/core/indexer/indexer-types.d.ts +0 -37
- package/dist/core/indexer/indexer-types.d.ts.map +0 -1
- package/dist/core/indexer/indexer-types.js +0 -8
- package/dist/core/indexer/indexer-types.js.map +0 -1
- package/dist/memory/file-search.d.ts +0 -43
- package/dist/memory/file-search.d.ts.map +0 -1
- package/dist/memory/file-search.js +0 -228
- package/dist/memory/file-search.js.map +0 -1
- package/dist/memory/file-store.d.ts +0 -99
- package/dist/memory/file-store.d.ts.map +0 -1
- package/dist/memory/file-store.js +0 -615
- package/dist/memory/file-store.js.map +0 -1
- package/dist/memory/legacy-migrator.d.ts +0 -27
- package/dist/memory/legacy-migrator.d.ts.map +0 -1
- package/dist/memory/legacy-migrator.js +0 -185
- package/dist/memory/legacy-migrator.js.map +0 -1
- package/dist/memory/memory-hooks.d.ts +0 -48
- package/dist/memory/memory-hooks.d.ts.map +0 -1
- package/dist/memory/memory-hooks.js +0 -248
- package/dist/memory/memory-hooks.js.map +0 -1
- package/dist/memory/memory-manager.d.ts +0 -65
- package/dist/memory/memory-manager.d.ts.map +0 -1
- package/dist/memory/memory-manager.js +0 -223
- package/dist/memory/memory-manager.js.map +0 -1
- package/dist/memory/memory-types.d.ts +0 -85
- package/dist/memory/memory-types.d.ts.map +0 -1
- package/dist/memory/memory-types.js +0 -7
- package/dist/memory/memory-types.js.map +0 -1
- package/templates/agents/accessibility-reviewer.md +0 -43
- package/templates/agents/api-designer.md +0 -42
- package/templates/agents/compiler/codegen-debugger.md +0 -34
- package/templates/agents/compiler/stdlib-engineer.md +0 -28
- package/templates/agents/compiler/test-coverage-guardian.md +0 -31
- package/templates/agents/context-intelligence.md +0 -50
- package/templates/agents/database-architect.md +0 -41
- package/templates/agents/devops-engineer.md +0 -42
- package/templates/agents/game-engine/cpp-core-expert.md +0 -35
- package/templates/agents/game-engine/render-engineer.md +0 -22
- package/templates/agents/game-engine/shader-engineer.md +0 -38
- package/templates/agents/game-engine/systems-integration.md +0 -43
- package/templates/agents/generic/code-reviewer.md +0 -41
- package/templates/agents/generic/docs-writer.md +0 -25
- package/templates/agents/generic/project-manager.md +0 -36
- package/templates/agents/generic/researcher.md +0 -34
- package/templates/agents/generic/test-engineer.md +0 -41
- package/templates/agents/i18n-engineer.md +0 -42
- package/templates/agents/migration-engineer.md +0 -42
- package/templates/agents/mobile/platform-specialist.md +0 -22
- package/templates/agents/mobile/ui-engineer.md +0 -22
- package/templates/agents/project-manager.md +0 -217
- package/templates/agents/refactoring-agent.md +0 -41
- package/templates/agents/ux-reviewer.md +0 -43
- package/templates/agents/web-app/api-designer.md +0 -22
- package/templates/agents/web-app/backend-engineer.md +0 -30
- package/templates/agents/web-app/database-engineer.md +0 -22
- package/templates/agents/web-app/frontend-engineer.md +0 -29
- package/templates/agents/web-app/security-reviewer.md +0 -32
- package/templates/cli/AIDER.md +0 -49
- package/templates/cli/AMAZON_Q.md +0 -25
- package/templates/cli/AUGGIE.md +0 -32
- package/templates/cli/CLINE.md +0 -99
- package/templates/cli/CODEBUDDY.md +0 -20
- package/templates/cli/CODEIUM.md +0 -20
- package/templates/cli/CODEX.md +0 -21
- package/templates/cli/CONTINUE.md +0 -34
- package/templates/cli/CURSOR_CLI.md +0 -62
- package/templates/cli/FACTORY.md +0 -18
- package/templates/cli/GEMINI.md +0 -35
- package/templates/cli/KILOCODE.md +0 -18
- package/templates/cli/OPENCODE.md +0 -85
- package/templates/cli/gemini-extension.json +0 -77
- package/templates/commands/rulebook-memory-save.md +0 -48
- package/templates/commands/rulebook-memory-search.md +0 -47
- package/templates/ides/CONTINUE_RULES.md +0 -16
- package/templates/ides/COPILOT_INSTRUCTIONS.md +0 -23
- package/templates/ides/GEMINI_RULES.md +0 -17
- package/templates/ides/OPENCODE.md +0 -63
- package/templates/ides/WINDSURF_RULES.md +0 -14
- package/templates/modules/ATLASSIAN.md +0 -255
- package/templates/modules/FIGMA.md +0 -267
- package/templates/modules/GRAFANA.md +0 -328
- package/templates/modules/MEMORY.md +0 -126
- package/templates/modules/NOTION.md +0 -247
- package/templates/skills/cli/aider/SKILL.md +0 -59
- package/templates/skills/cli/amazon-q/SKILL.md +0 -35
- package/templates/skills/cli/auggie/SKILL.md +0 -42
- package/templates/skills/cli/cline/SKILL.md +0 -42
- package/templates/skills/cli/codebuddy/SKILL.md +0 -30
- package/templates/skills/cli/codeium/SKILL.md +0 -30
- package/templates/skills/cli/codex/SKILL.md +0 -31
- package/templates/skills/cli/continue/SKILL.md +0 -44
- package/templates/skills/cli/cursor-cli/SKILL.md +0 -38
- package/templates/skills/cli/factory/SKILL.md +0 -28
- package/templates/skills/cli/gemini/SKILL.md +0 -45
- package/templates/skills/cli/kilocode/SKILL.md +0 -28
- package/templates/skills/cli/opencode/SKILL.md +0 -82
- package/templates/skills/ides/copilot/SKILL.md +0 -47
- package/templates/skills/ides/cursor/SKILL.md +0 -53
- package/templates/skills/ides/jetbrains-ai/SKILL.md +0 -45
- package/templates/skills/ides/replit/SKILL.md +0 -46
- package/templates/skills/ides/tabnine/SKILL.md +0 -39
- package/templates/skills/ides/vscode/SKILL.md +0 -50
- package/templates/skills/ides/windsurf/SKILL.md +0 -46
- package/templates/skills/ides/zed/SKILL.md +0 -42
- package/templates/skills/modules/atlassian/SKILL.md +0 -265
- package/templates/skills/modules/figma/SKILL.md +0 -277
- package/templates/skills/modules/grafana/SKILL.md +0 -338
- package/templates/skills/modules/memory/SKILL.md +0 -73
- package/templates/skills/modules/notion/SKILL.md +0 -257
|
@@ -5,10 +5,16 @@ import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, unlinkSync,
|
|
|
5
5
|
import { dirname, join, resolve } from 'path';
|
|
6
6
|
import { z } from 'zod';
|
|
7
7
|
import { ConfigManager } from '../core/state/config-manager.js';
|
|
8
|
-
import { BackgroundIndexer } from '../core/indexer/background-indexer.js';
|
|
9
8
|
import { SkillsManager, getDefaultTemplatesPath } from '../core/skills/skills-manager.js';
|
|
10
9
|
import { TaskManager } from '../core/tasks/task-manager.js';
|
|
11
10
|
import { WorkspaceManager } from '../core/workspace/workspace-manager.js';
|
|
11
|
+
import { registerTaskTools } from './tools/task-tools.js';
|
|
12
|
+
import { registerSkillTools } from './tools/skill-tools.js';
|
|
13
|
+
import { registerWorkspaceTools } from './tools/workspace-tools.js';
|
|
14
|
+
import { registerDecisionTools } from './tools/decision-tools.js';
|
|
15
|
+
import { registerKnowledgeTools } from './tools/knowledge-tools.js';
|
|
16
|
+
import { registerLearnTools } from './tools/learn-tools.js';
|
|
17
|
+
import { registerRulesTools } from './tools/rules-tools.js';
|
|
12
18
|
// --- Timeout guard for MCP tool handlers ---
|
|
13
19
|
// Prevents the MCP server from hanging when a tool handler blocks (SQLite, WASM, fs).
|
|
14
20
|
const MCP_TOOL_TIMEOUT_MS = parseInt(process.env.RULEBOOK_MCP_TIMEOUT_MS ?? '10000', 10);
|
|
@@ -260,1590 +266,52 @@ export async function startRulebookMcpServer() {
|
|
|
260
266
|
const w = await workspaceManager.getWorker(projectId);
|
|
261
267
|
return w.getSkillsManager();
|
|
262
268
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
const w = await workspaceManager.getWorker(pid);
|
|
267
|
-
return w.getMemoryManager();
|
|
268
|
-
}
|
|
269
|
-
return memoryManager;
|
|
270
|
-
}
|
|
271
|
-
const server = new McpServer({
|
|
272
|
-
name: 'rulebook-task-management',
|
|
273
|
-
version: '5.2.0',
|
|
274
|
-
});
|
|
275
|
-
// --- Wrap all tool handlers with a timeout guard ---
|
|
276
|
-
const originalRegisterTool = server.registerTool.bind(server);
|
|
277
|
-
server.registerTool = ((name, config, handler) => {
|
|
278
|
-
const wrappedHandler = async (...handlerArgs) => {
|
|
279
|
-
try {
|
|
280
|
-
return await withTimeout(handler(...handlerArgs), MCP_TOOL_TIMEOUT_MS, name);
|
|
281
|
-
}
|
|
282
|
-
catch (error) {
|
|
283
|
-
const msg = error instanceof Error ? error.message : String(error);
|
|
284
|
-
console.error(`[rulebook-mcp] ${name} error: ${msg}`);
|
|
285
|
-
return {
|
|
286
|
-
content: [
|
|
287
|
-
{ type: 'text', text: JSON.stringify({ success: false, error: msg }) },
|
|
288
|
-
],
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
};
|
|
292
|
-
return originalRegisterTool(name, config, wrappedHandler);
|
|
293
|
-
});
|
|
294
|
-
// Zod schema reused across tools for workspace project targeting
|
|
295
|
-
const projectIdSchema = z
|
|
296
|
-
.string()
|
|
297
|
-
.optional()
|
|
298
|
-
.describe('Project ID (workspace mode only, defaults to default project)');
|
|
299
|
-
// Register tool: rulebook_task_create
|
|
300
|
-
server.registerTool('rulebook_task_create', {
|
|
301
|
-
title: 'Create Rulebook Task',
|
|
302
|
-
description: 'Create a new Rulebook task',
|
|
303
|
-
inputSchema: {
|
|
304
|
-
taskId: z
|
|
305
|
-
.string()
|
|
306
|
-
.describe('Task ID with phase prefix: phase<N>_<description> (e.g., phase1_add-user-auth, phase2a_fix-login-bug)'),
|
|
307
|
-
projectId: projectIdSchema,
|
|
308
|
-
},
|
|
309
|
-
}, async (args) => {
|
|
310
|
-
const tm = await getTaskMgr(args.projectId);
|
|
311
|
-
await tm.createTask(args.taskId);
|
|
312
|
-
const resultText = JSON.stringify({
|
|
313
|
-
success: true,
|
|
314
|
-
taskId: args.taskId,
|
|
315
|
-
message: `Task ${args.taskId} created successfully`,
|
|
316
|
-
});
|
|
317
|
-
autoCapture('rulebook_task_create', args, resultText);
|
|
318
|
-
return { content: [{ type: 'text', text: resultText }] };
|
|
319
|
-
});
|
|
320
|
-
// Register tool: rulebook_task_list
|
|
321
|
-
server.registerTool('rulebook_task_list', {
|
|
322
|
-
title: 'List Rulebook Tasks',
|
|
323
|
-
description: 'List all Rulebook tasks',
|
|
324
|
-
inputSchema: {
|
|
325
|
-
includeArchived: z.boolean().optional().describe('Include archived tasks'),
|
|
326
|
-
status: z
|
|
327
|
-
.enum(['pending', 'in-progress', 'completed', 'blocked'])
|
|
328
|
-
.optional()
|
|
329
|
-
.describe('Filter by status'),
|
|
330
|
-
projectId: projectIdSchema,
|
|
331
|
-
},
|
|
332
|
-
}, async (args) => {
|
|
333
|
-
const tm = await getTaskMgr(args.projectId);
|
|
334
|
-
const tasks = await tm.listTasks(args.includeArchived || false);
|
|
335
|
-
let filtered = tasks;
|
|
336
|
-
if (args.status) {
|
|
337
|
-
filtered = tasks.filter((t) => t.status === args.status);
|
|
338
|
-
}
|
|
339
|
-
return {
|
|
340
|
-
content: [
|
|
341
|
-
{
|
|
342
|
-
type: 'text',
|
|
343
|
-
text: JSON.stringify({
|
|
344
|
-
tasks: filtered.map((t) => ({
|
|
345
|
-
id: t.id,
|
|
346
|
-
title: t.title,
|
|
347
|
-
status: t.status,
|
|
348
|
-
createdAt: t.createdAt,
|
|
349
|
-
updatedAt: t.updatedAt,
|
|
350
|
-
})),
|
|
351
|
-
count: filtered.length,
|
|
352
|
-
}),
|
|
353
|
-
},
|
|
354
|
-
],
|
|
355
|
-
};
|
|
356
|
-
});
|
|
357
|
-
// Register tool: rulebook_task_show
|
|
358
|
-
server.registerTool('rulebook_task_show', {
|
|
359
|
-
title: 'Show Rulebook Task',
|
|
360
|
-
description: 'Show task details',
|
|
361
|
-
inputSchema: {
|
|
362
|
-
taskId: z.string().describe('Task ID to show'),
|
|
363
|
-
projectId: projectIdSchema,
|
|
364
|
-
},
|
|
365
|
-
}, async (args) => {
|
|
366
|
-
const tm = await getTaskMgr(args.projectId);
|
|
367
|
-
const task = await tm.showTask(args.taskId);
|
|
368
|
-
return {
|
|
369
|
-
content: [
|
|
370
|
-
{
|
|
371
|
-
type: 'text',
|
|
372
|
-
text: JSON.stringify({
|
|
373
|
-
task: task
|
|
374
|
-
? {
|
|
375
|
-
id: task.id,
|
|
376
|
-
title: task.title,
|
|
377
|
-
status: task.status,
|
|
378
|
-
proposal: task.proposal,
|
|
379
|
-
tasks: task.tasks,
|
|
380
|
-
design: task.design,
|
|
381
|
-
specs: task.specs,
|
|
382
|
-
createdAt: task.createdAt,
|
|
383
|
-
updatedAt: task.updatedAt,
|
|
384
|
-
}
|
|
385
|
-
: null,
|
|
386
|
-
found: task !== null,
|
|
387
|
-
}),
|
|
388
|
-
},
|
|
389
|
-
],
|
|
390
|
-
};
|
|
391
|
-
});
|
|
392
|
-
// Register tool: rulebook_task_update
|
|
393
|
-
server.registerTool('rulebook_task_update', {
|
|
394
|
-
title: 'Update Rulebook Task',
|
|
395
|
-
description: 'Update task status',
|
|
396
|
-
inputSchema: {
|
|
397
|
-
taskId: z.string().describe('Task ID to update'),
|
|
398
|
-
status: z
|
|
399
|
-
.enum(['pending', 'in-progress', 'completed', 'blocked'])
|
|
400
|
-
.optional()
|
|
401
|
-
.describe('New status'),
|
|
402
|
-
projectId: projectIdSchema,
|
|
403
|
-
},
|
|
404
|
-
}, async (args) => {
|
|
405
|
-
const tm = await getTaskMgr(args.projectId);
|
|
406
|
-
if (args.status) {
|
|
407
|
-
await tm.updateTaskStatus(args.taskId, args.status);
|
|
408
|
-
}
|
|
409
|
-
const resultText = JSON.stringify({
|
|
410
|
-
success: true,
|
|
411
|
-
taskId: args.taskId,
|
|
412
|
-
message: `Task ${args.taskId} updated successfully`,
|
|
413
|
-
});
|
|
414
|
-
autoCapture('rulebook_task_update', args, resultText);
|
|
415
|
-
return { content: [{ type: 'text', text: resultText }] };
|
|
416
|
-
});
|
|
417
|
-
// Register tool: rulebook_task_validate
|
|
418
|
-
server.registerTool('rulebook_task_validate', {
|
|
419
|
-
title: 'Validate Rulebook Task',
|
|
420
|
-
description: 'Validate task format',
|
|
421
|
-
inputSchema: {
|
|
422
|
-
taskId: z.string().describe('Task ID to validate'),
|
|
423
|
-
projectId: projectIdSchema,
|
|
424
|
-
},
|
|
425
|
-
}, async (args) => {
|
|
426
|
-
const tm = await getTaskMgr(args.projectId);
|
|
427
|
-
const validation = await tm.validateTask(args.taskId);
|
|
428
|
-
return {
|
|
429
|
-
content: [
|
|
430
|
-
{
|
|
431
|
-
type: 'text',
|
|
432
|
-
text: JSON.stringify({
|
|
433
|
-
valid: validation.valid,
|
|
434
|
-
errors: validation.errors,
|
|
435
|
-
warnings: validation.warnings,
|
|
436
|
-
}),
|
|
437
|
-
},
|
|
438
|
-
],
|
|
439
|
-
};
|
|
440
|
-
});
|
|
441
|
-
// Register tool: rulebook_task_archive
|
|
442
|
-
server.registerTool('rulebook_task_archive', {
|
|
443
|
-
title: 'Archive Rulebook Task',
|
|
444
|
-
description: 'Archive a completed task',
|
|
445
|
-
inputSchema: {
|
|
446
|
-
taskId: z
|
|
447
|
-
.string()
|
|
448
|
-
.describe('Task ID to archive (must use phase prefix, e.g., phase1_my-task)'),
|
|
449
|
-
skipValidation: z.boolean().optional().describe('Skip validation before archiving'),
|
|
450
|
-
projectId: projectIdSchema,
|
|
451
|
-
},
|
|
452
|
-
}, async (args) => {
|
|
453
|
-
const tm = await getTaskMgr(args.projectId);
|
|
454
|
-
await tm.archiveTask(args.taskId, args.skipValidation || false);
|
|
455
|
-
const resultText = JSON.stringify({
|
|
456
|
-
success: true,
|
|
457
|
-
taskId: args.taskId,
|
|
458
|
-
message: `Task ${args.taskId} archived successfully`,
|
|
459
|
-
});
|
|
460
|
-
autoCapture('rulebook_task_archive', args, resultText);
|
|
461
|
-
return { content: [{ type: 'text', text: resultText }] };
|
|
462
|
-
});
|
|
463
|
-
// Register tool: rulebook_task_delete
|
|
464
|
-
server.registerTool('rulebook_task_delete', {
|
|
465
|
-
title: 'Delete Rulebook Task',
|
|
466
|
-
description: 'Delete a task permanently',
|
|
467
|
-
inputSchema: {
|
|
468
|
-
taskId: z.string().describe('Task ID to delete'),
|
|
469
|
-
projectId: projectIdSchema,
|
|
470
|
-
},
|
|
471
|
-
}, async (args) => {
|
|
472
|
-
const tm = await getTaskMgr(args.projectId);
|
|
473
|
-
await tm.deleteTask(args.taskId);
|
|
474
|
-
const resultText = JSON.stringify({
|
|
475
|
-
success: true,
|
|
476
|
-
taskId: args.taskId,
|
|
477
|
-
message: `Task ${args.taskId} deleted successfully`,
|
|
478
|
-
});
|
|
479
|
-
autoCapture('rulebook_task_delete', args, resultText);
|
|
480
|
-
return { content: [{ type: 'text', text: resultText }] };
|
|
481
|
-
});
|
|
482
|
-
// ============================================
|
|
483
|
-
// Skills Management Functions (v2.0)
|
|
484
|
-
// ============================================
|
|
485
|
-
// Register tool: rulebook_skill_list
|
|
486
|
-
server.registerTool('rulebook_skill_list', {
|
|
487
|
-
title: 'List Available Skills',
|
|
488
|
-
description: 'List all available skills, optionally filtered by category',
|
|
489
|
-
inputSchema: {
|
|
490
|
-
category: z
|
|
491
|
-
.enum([
|
|
492
|
-
'languages',
|
|
493
|
-
'frameworks',
|
|
494
|
-
'modules',
|
|
495
|
-
'services',
|
|
496
|
-
'workflows',
|
|
497
|
-
'ides',
|
|
498
|
-
'core',
|
|
499
|
-
'cli',
|
|
500
|
-
'git',
|
|
501
|
-
'hooks',
|
|
502
|
-
])
|
|
503
|
-
.optional()
|
|
504
|
-
.describe('Filter by category'),
|
|
505
|
-
enabledOnly: z.boolean().optional().describe('Show only enabled skills'),
|
|
506
|
-
projectId: projectIdSchema,
|
|
507
|
-
},
|
|
508
|
-
}, async (args) => {
|
|
509
|
-
try {
|
|
510
|
-
const sm = await getSkillsMgr(args.projectId);
|
|
511
|
-
const cm = await getConfigMgr(args.projectId);
|
|
512
|
-
let skills;
|
|
513
|
-
if (args.category) {
|
|
514
|
-
skills = await sm.getSkillsByCategory(args.category);
|
|
515
|
-
}
|
|
516
|
-
else {
|
|
517
|
-
skills = await sm.getSkills();
|
|
518
|
-
}
|
|
519
|
-
const rbConfig = await cm.loadConfig();
|
|
520
|
-
const enabledIds = new Set(rbConfig.skills?.enabled || []);
|
|
521
|
-
let filteredSkills = skills.map((s) => ({
|
|
522
|
-
id: s.id,
|
|
523
|
-
name: s.metadata.name,
|
|
524
|
-
description: s.metadata.description,
|
|
525
|
-
category: s.category,
|
|
526
|
-
enabled: enabledIds.has(s.id),
|
|
527
|
-
version: s.metadata.version,
|
|
528
|
-
tags: s.metadata.tags,
|
|
529
|
-
}));
|
|
530
|
-
if (args.enabledOnly) {
|
|
531
|
-
filteredSkills = filteredSkills.filter((s) => s.enabled);
|
|
532
|
-
}
|
|
533
|
-
return {
|
|
534
|
-
content: [
|
|
535
|
-
{
|
|
536
|
-
type: 'text',
|
|
537
|
-
text: JSON.stringify({
|
|
538
|
-
success: true,
|
|
539
|
-
skills: filteredSkills,
|
|
540
|
-
count: filteredSkills.length,
|
|
541
|
-
category: args.category || 'all',
|
|
542
|
-
}),
|
|
543
|
-
},
|
|
544
|
-
],
|
|
545
|
-
};
|
|
546
|
-
}
|
|
547
|
-
catch (error) {
|
|
548
|
-
return {
|
|
549
|
-
content: [
|
|
550
|
-
{
|
|
551
|
-
type: 'text',
|
|
552
|
-
text: JSON.stringify({
|
|
553
|
-
success: false,
|
|
554
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
555
|
-
}),
|
|
556
|
-
},
|
|
557
|
-
],
|
|
558
|
-
};
|
|
559
|
-
}
|
|
560
|
-
});
|
|
561
|
-
// Register tool: rulebook_skill_show
|
|
562
|
-
server.registerTool('rulebook_skill_show', {
|
|
563
|
-
title: 'Show Skill Details',
|
|
564
|
-
description: 'Show detailed information about a specific skill',
|
|
565
|
-
inputSchema: {
|
|
566
|
-
skillId: z.string().describe('Skill ID (e.g., languages/typescript)'),
|
|
567
|
-
projectId: projectIdSchema,
|
|
568
|
-
},
|
|
569
|
-
}, async (args) => {
|
|
570
|
-
try {
|
|
571
|
-
const sm = await getSkillsMgr(args.projectId);
|
|
572
|
-
const cm = await getConfigMgr(args.projectId);
|
|
573
|
-
const skill = await sm.getSkillById(args.skillId);
|
|
574
|
-
if (!skill) {
|
|
575
|
-
return {
|
|
576
|
-
content: [
|
|
577
|
-
{
|
|
578
|
-
type: 'text',
|
|
579
|
-
text: JSON.stringify({
|
|
580
|
-
success: false,
|
|
581
|
-
error: `Skill not found: ${args.skillId}`,
|
|
582
|
-
suggestion: 'Use rulebook_skill_list to see available skills',
|
|
583
|
-
}),
|
|
584
|
-
},
|
|
585
|
-
],
|
|
586
|
-
};
|
|
587
|
-
}
|
|
588
|
-
const rbConfig = await cm.loadConfig();
|
|
589
|
-
const enabled = rbConfig.skills?.enabled?.includes(args.skillId) || false;
|
|
590
|
-
return {
|
|
591
|
-
content: [
|
|
592
|
-
{
|
|
593
|
-
type: 'text',
|
|
594
|
-
text: JSON.stringify({
|
|
595
|
-
success: true,
|
|
596
|
-
skill: {
|
|
597
|
-
id: skill.id,
|
|
598
|
-
name: skill.metadata.name,
|
|
599
|
-
description: skill.metadata.description,
|
|
600
|
-
category: skill.category,
|
|
601
|
-
enabled,
|
|
602
|
-
version: skill.metadata.version,
|
|
603
|
-
author: skill.metadata.author,
|
|
604
|
-
tags: skill.metadata.tags,
|
|
605
|
-
dependencies: skill.metadata.dependencies,
|
|
606
|
-
conflicts: skill.metadata.conflicts,
|
|
607
|
-
content: skill.content.slice(0, 2000) + (skill.content.length > 2000 ? '...' : ''),
|
|
608
|
-
},
|
|
609
|
-
}),
|
|
610
|
-
},
|
|
611
|
-
],
|
|
612
|
-
};
|
|
613
|
-
}
|
|
614
|
-
catch (error) {
|
|
615
|
-
return {
|
|
616
|
-
content: [
|
|
617
|
-
{
|
|
618
|
-
type: 'text',
|
|
619
|
-
text: JSON.stringify({
|
|
620
|
-
success: false,
|
|
621
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
622
|
-
}),
|
|
623
|
-
},
|
|
624
|
-
],
|
|
625
|
-
};
|
|
626
|
-
}
|
|
627
|
-
});
|
|
628
|
-
// Register tool: rulebook_skill_enable
|
|
629
|
-
server.registerTool('rulebook_skill_enable', {
|
|
630
|
-
title: 'Enable Skill',
|
|
631
|
-
description: 'Enable a skill in the project configuration',
|
|
632
|
-
inputSchema: {
|
|
633
|
-
skillId: z.string().describe('Skill ID to enable (e.g., languages/typescript)'),
|
|
634
|
-
projectId: projectIdSchema,
|
|
635
|
-
},
|
|
636
|
-
}, async (args) => {
|
|
637
|
-
try {
|
|
638
|
-
const sm = await getSkillsMgr(args.projectId);
|
|
639
|
-
const cm = await getConfigMgr(args.projectId);
|
|
640
|
-
let rbConfig = await cm.loadConfig();
|
|
641
|
-
rbConfig = await sm.enableSkill(args.skillId, rbConfig);
|
|
642
|
-
await cm.saveConfig(rbConfig);
|
|
643
|
-
const validation = await sm.validateSkills(rbConfig);
|
|
644
|
-
const resultText = JSON.stringify({
|
|
645
|
-
success: true,
|
|
646
|
-
skillId: args.skillId,
|
|
647
|
-
message: `Skill ${args.skillId} enabled successfully`,
|
|
648
|
-
warnings: validation.warnings,
|
|
649
|
-
conflicts: validation.conflicts,
|
|
650
|
-
});
|
|
651
|
-
autoCapture('rulebook_skill_enable', args, resultText);
|
|
652
|
-
return { content: [{ type: 'text', text: resultText }] };
|
|
653
|
-
}
|
|
654
|
-
catch (error) {
|
|
655
|
-
return {
|
|
656
|
-
content: [
|
|
657
|
-
{
|
|
658
|
-
type: 'text',
|
|
659
|
-
text: JSON.stringify({
|
|
660
|
-
success: false,
|
|
661
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
662
|
-
}),
|
|
663
|
-
},
|
|
664
|
-
],
|
|
665
|
-
};
|
|
666
|
-
}
|
|
667
|
-
});
|
|
668
|
-
// Register tool: rulebook_skill_disable
|
|
669
|
-
server.registerTool('rulebook_skill_disable', {
|
|
670
|
-
title: 'Disable Skill',
|
|
671
|
-
description: 'Disable a skill in the project configuration',
|
|
672
|
-
inputSchema: {
|
|
673
|
-
skillId: z.string().describe('Skill ID to disable (e.g., languages/typescript)'),
|
|
674
|
-
projectId: projectIdSchema,
|
|
675
|
-
},
|
|
676
|
-
}, async (args) => {
|
|
677
|
-
try {
|
|
678
|
-
const sm = await getSkillsMgr(args.projectId);
|
|
679
|
-
const cm = await getConfigMgr(args.projectId);
|
|
680
|
-
let rbConfig = await cm.loadConfig();
|
|
681
|
-
if (!rbConfig.skills?.enabled?.includes(args.skillId)) {
|
|
682
|
-
return {
|
|
683
|
-
content: [
|
|
684
|
-
{
|
|
685
|
-
type: 'text',
|
|
686
|
-
text: JSON.stringify({
|
|
687
|
-
success: false,
|
|
688
|
-
error: `Skill ${args.skillId} is not currently enabled`,
|
|
689
|
-
}),
|
|
690
|
-
},
|
|
691
|
-
],
|
|
692
|
-
};
|
|
693
|
-
}
|
|
694
|
-
rbConfig = await sm.disableSkill(args.skillId, rbConfig);
|
|
695
|
-
await cm.saveConfig(rbConfig);
|
|
696
|
-
const resultText = JSON.stringify({
|
|
697
|
-
success: true,
|
|
698
|
-
skillId: args.skillId,
|
|
699
|
-
message: `Skill ${args.skillId} disabled successfully`,
|
|
700
|
-
});
|
|
701
|
-
autoCapture('rulebook_skill_disable', args, resultText);
|
|
702
|
-
return { content: [{ type: 'text', text: resultText }] };
|
|
703
|
-
}
|
|
704
|
-
catch (error) {
|
|
705
|
-
return {
|
|
706
|
-
content: [
|
|
707
|
-
{
|
|
708
|
-
type: 'text',
|
|
709
|
-
text: JSON.stringify({
|
|
710
|
-
success: false,
|
|
711
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
712
|
-
}),
|
|
713
|
-
},
|
|
714
|
-
],
|
|
715
|
-
};
|
|
716
|
-
}
|
|
717
|
-
});
|
|
718
|
-
// Register tool: rulebook_skill_search
|
|
719
|
-
server.registerTool('rulebook_skill_search', {
|
|
720
|
-
title: 'Search Skills',
|
|
721
|
-
description: 'Search for skills by name, description, or tags',
|
|
722
|
-
inputSchema: {
|
|
723
|
-
query: z.string().describe('Search query'),
|
|
724
|
-
projectId: projectIdSchema,
|
|
725
|
-
},
|
|
726
|
-
}, async (args) => {
|
|
727
|
-
try {
|
|
728
|
-
const sm = await getSkillsMgr(args.projectId);
|
|
729
|
-
const cm = await getConfigMgr(args.projectId);
|
|
730
|
-
const skills = await sm.searchSkills(args.query);
|
|
731
|
-
const rbConfig = await cm.loadConfig();
|
|
732
|
-
const enabledIds = new Set(rbConfig.skills?.enabled || []);
|
|
733
|
-
return {
|
|
734
|
-
content: [
|
|
735
|
-
{
|
|
736
|
-
type: 'text',
|
|
737
|
-
text: JSON.stringify({
|
|
738
|
-
success: true,
|
|
739
|
-
query: args.query,
|
|
740
|
-
skills: skills.map((s) => ({
|
|
741
|
-
id: s.id,
|
|
742
|
-
name: s.metadata.name,
|
|
743
|
-
description: s.metadata.description,
|
|
744
|
-
category: s.category,
|
|
745
|
-
enabled: enabledIds.has(s.id),
|
|
746
|
-
})),
|
|
747
|
-
count: skills.length,
|
|
748
|
-
}),
|
|
749
|
-
},
|
|
750
|
-
],
|
|
751
|
-
};
|
|
752
|
-
}
|
|
753
|
-
catch (error) {
|
|
754
|
-
return {
|
|
755
|
-
content: [
|
|
756
|
-
{
|
|
757
|
-
type: 'text',
|
|
758
|
-
text: JSON.stringify({
|
|
759
|
-
success: false,
|
|
760
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
761
|
-
}),
|
|
762
|
-
},
|
|
763
|
-
],
|
|
764
|
-
};
|
|
765
|
-
}
|
|
766
|
-
});
|
|
767
|
-
// Register tool: rulebook_skill_validate
|
|
768
|
-
server.registerTool('rulebook_skill_validate', {
|
|
769
|
-
title: 'Validate Skills Configuration',
|
|
770
|
-
description: 'Validate the current skills configuration for conflicts and dependencies',
|
|
771
|
-
inputSchema: {
|
|
772
|
-
projectId: projectIdSchema,
|
|
773
|
-
},
|
|
774
|
-
}, async (args) => {
|
|
775
|
-
try {
|
|
776
|
-
const sm = await getSkillsMgr(args.projectId);
|
|
777
|
-
const cm = await getConfigMgr(args.projectId);
|
|
778
|
-
const rbConfig = await cm.loadConfig();
|
|
779
|
-
const validation = await sm.validateSkills(rbConfig);
|
|
780
|
-
return {
|
|
781
|
-
content: [
|
|
782
|
-
{
|
|
783
|
-
type: 'text',
|
|
784
|
-
text: JSON.stringify({
|
|
785
|
-
success: true,
|
|
786
|
-
valid: validation.valid,
|
|
787
|
-
errors: validation.errors,
|
|
788
|
-
warnings: validation.warnings,
|
|
789
|
-
conflicts: validation.conflicts,
|
|
790
|
-
enabledCount: rbConfig.skills?.enabled?.length || 0,
|
|
791
|
-
}),
|
|
792
|
-
},
|
|
793
|
-
],
|
|
794
|
-
};
|
|
795
|
-
}
|
|
796
|
-
catch (error) {
|
|
797
|
-
return {
|
|
798
|
-
content: [
|
|
799
|
-
{
|
|
800
|
-
type: 'text',
|
|
801
|
-
text: JSON.stringify({
|
|
802
|
-
success: false,
|
|
803
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
804
|
-
}),
|
|
805
|
-
},
|
|
806
|
-
],
|
|
807
|
-
};
|
|
808
|
-
}
|
|
809
|
-
});
|
|
810
|
-
// ============================================
|
|
811
|
-
// Memory System Functions (v3.0)
|
|
812
|
-
// ============================================
|
|
813
|
-
// Conditionally initialize MemoryManager (single-project mode only;
|
|
814
|
-
// in workspace mode each worker manages its own memory)
|
|
815
|
-
let memoryManager = null;
|
|
816
|
-
let bgIndexer = null;
|
|
817
|
-
let autoCaptureEnabled = false;
|
|
818
|
-
if (!isWorkspaceMode) {
|
|
819
|
-
const rulebookConfig = await configManager.loadConfig();
|
|
820
|
-
if (rulebookConfig.memory?.enabled) {
|
|
821
|
-
try {
|
|
822
|
-
const { createMemoryManager } = await import('../memory/memory-manager.js');
|
|
823
|
-
const memoryDbPath = join(projectRoot, rulebookConfig.memory.dbPath ?? '.rulebook/memory/memory.db');
|
|
824
|
-
console.error(`[rulebook-mcp] Memory DB: ${memoryDbPath}`);
|
|
825
|
-
memoryManager = createMemoryManager(projectRoot, rulebookConfig.memory);
|
|
826
|
-
autoCaptureEnabled = rulebookConfig.memory.autoCapture !== false;
|
|
827
|
-
// Boot Background Indexer only if memory is enabled (opt-in to save resources)
|
|
828
|
-
const indexerEnabled = rulebookConfig.memory?.enabled === true;
|
|
829
|
-
if (indexerEnabled) {
|
|
830
|
-
bgIndexer = new BackgroundIndexer(memoryManager, projectRoot, {
|
|
831
|
-
enabled: true,
|
|
832
|
-
...rulebookConfig.indexer,
|
|
833
|
-
});
|
|
834
|
-
setTimeout(() => {
|
|
835
|
-
try {
|
|
836
|
-
bgIndexer?.start();
|
|
837
|
-
}
|
|
838
|
-
catch (e) {
|
|
839
|
-
console.error('[rulebook-mcp] BackgroundIndexer start failed:', e);
|
|
840
|
-
}
|
|
841
|
-
}, 5000);
|
|
842
|
-
}
|
|
843
|
-
global.__indexerStatus = () => bgIndexer?.getStatus();
|
|
844
|
-
}
|
|
845
|
-
catch (e) {
|
|
846
|
-
console.warn('[rulebook-mcp] Failed to boot Memory/Indexer:', e);
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
// --- Graceful shutdown for both modes ---
|
|
851
|
-
// Handles SIGINT (Ctrl+C), SIGTERM (parent exit), SIGHUP (terminal close),
|
|
852
|
-
// and stdin close (parent process died without signaling).
|
|
853
|
-
let isShuttingDown = false;
|
|
854
|
-
async function gracefulShutdown(reason) {
|
|
855
|
-
if (isShuttingDown)
|
|
856
|
-
return; // Prevent double-shutdown races
|
|
857
|
-
isShuttingDown = true;
|
|
858
|
-
console.error(`[rulebook-mcp] Shutting down (${reason})...`);
|
|
859
|
-
try {
|
|
860
|
-
if (bgIndexer)
|
|
861
|
-
bgIndexer.stop();
|
|
862
|
-
if (workspaceManager) {
|
|
863
|
-
await workspaceManager.shutdownAll();
|
|
864
|
-
}
|
|
865
|
-
if (memoryManager)
|
|
866
|
-
await memoryManager.close();
|
|
867
|
-
releasePidLock(pidFilePath);
|
|
868
|
-
}
|
|
869
|
-
catch (e) {
|
|
870
|
-
console.error('[rulebook-mcp] Error during shutdown:', e);
|
|
871
|
-
}
|
|
872
|
-
process.exit(0);
|
|
873
|
-
}
|
|
874
|
-
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
|
|
875
|
-
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
|
|
876
|
-
process.on('SIGHUP', () => gracefulShutdown('SIGHUP'));
|
|
877
|
-
// Detect parent process exit: when the MCP client (e.g. Claude Code) dies,
|
|
878
|
-
// stdin closes. Without this, the server becomes an orphan that leaks memory.
|
|
879
|
-
process.stdin.on('end', () => gracefulShutdown('stdin closed'));
|
|
880
|
-
process.stdin.on('close', () => gracefulShutdown('stdin closed'));
|
|
881
|
-
// Safety net: if stdin becomes unreadable but doesn't emit 'end'/'close'
|
|
882
|
-
// (can happen on Windows), poll stdin.readable every 30s.
|
|
883
|
-
const STDIN_POLL_INTERVAL_MS = 30_000;
|
|
884
|
-
const stdinPollTimer = setInterval(() => {
|
|
885
|
-
if (process.stdin.destroyed || !process.stdin.readable) {
|
|
886
|
-
clearInterval(stdinPollTimer);
|
|
887
|
-
gracefulShutdown('stdin unreadable');
|
|
888
|
-
}
|
|
889
|
-
}, STDIN_POLL_INTERVAL_MS);
|
|
890
|
-
stdinPollTimer.unref(); // Don't keep the process alive just for this timer
|
|
891
|
-
/**
|
|
892
|
-
* Auto-capture: save tool interactions to memory in the background.
|
|
893
|
-
* Fire-and-forget — never blocks or fails the original tool call.
|
|
894
|
-
* Has its own 2s timeout to prevent hanging the event loop.
|
|
895
|
-
*
|
|
896
|
-
* The dynamic import is cached after the first call to avoid repeated
|
|
897
|
-
* module loading overhead on every tool invocation.
|
|
898
|
-
*/
|
|
899
|
-
const AUTO_CAPTURE_TIMEOUT_MS = 2000;
|
|
900
|
-
let _captureFromToolCall = null;
|
|
901
|
-
async function autoCapture(toolName, args, resultText) {
|
|
902
|
-
if (!memoryManager || !autoCaptureEnabled)
|
|
903
|
-
return;
|
|
904
|
-
try {
|
|
905
|
-
await withTimeout((async () => {
|
|
906
|
-
if (!_captureFromToolCall) {
|
|
907
|
-
const mod = await import('../memory/memory-hooks.js');
|
|
908
|
-
_captureFromToolCall = mod.captureFromToolCall;
|
|
909
|
-
}
|
|
910
|
-
const captured = _captureFromToolCall(toolName, args, resultText);
|
|
911
|
-
if (!captured)
|
|
912
|
-
return;
|
|
913
|
-
await memoryManager.saveMemory({
|
|
914
|
-
type: captured.type,
|
|
915
|
-
title: captured.title,
|
|
916
|
-
content: captured.content,
|
|
917
|
-
tags: captured.tags,
|
|
918
|
-
});
|
|
919
|
-
})(), AUTO_CAPTURE_TIMEOUT_MS, `autoCapture(${toolName})`);
|
|
920
|
-
}
|
|
921
|
-
catch {
|
|
922
|
-
// Never fail the original tool call — timeout or error is silently dropped
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
function memoryNotEnabled() {
|
|
926
|
-
return {
|
|
927
|
-
content: [
|
|
928
|
-
{
|
|
929
|
-
type: 'text',
|
|
930
|
-
text: JSON.stringify({
|
|
931
|
-
success: false,
|
|
932
|
-
error: 'Memory system is not enabled. Set memory.enabled=true in .rulebook',
|
|
933
|
-
}),
|
|
934
|
-
},
|
|
935
|
-
],
|
|
936
|
-
};
|
|
937
|
-
}
|
|
938
|
-
// Register tool: rulebook_memory_search
|
|
939
|
-
server.registerTool('rulebook_memory_search', {
|
|
940
|
-
title: 'Search Memories',
|
|
941
|
-
description: 'Search persistent memories using hybrid BM25+vector search',
|
|
942
|
-
inputSchema: {
|
|
943
|
-
query: z.string().describe('Search query'),
|
|
944
|
-
limit: z.number().optional().describe('Max results (default 20)'),
|
|
945
|
-
mode: z.enum(['bm25', 'vector', 'hybrid']).optional().describe('Search mode'),
|
|
946
|
-
type: z.string().optional().describe('Filter by memory type'),
|
|
947
|
-
projectId: projectIdSchema,
|
|
948
|
-
},
|
|
949
|
-
}, async (args) => {
|
|
950
|
-
const mm = await getMemMgr(args.projectId);
|
|
951
|
-
if (!mm)
|
|
952
|
-
return memoryNotEnabled();
|
|
953
|
-
try {
|
|
954
|
-
const results = await mm.searchMemories({
|
|
955
|
-
query: args.query,
|
|
956
|
-
limit: args.limit,
|
|
957
|
-
mode: args.mode,
|
|
958
|
-
type: args.type,
|
|
959
|
-
});
|
|
960
|
-
return {
|
|
961
|
-
content: [
|
|
962
|
-
{
|
|
963
|
-
type: 'text',
|
|
964
|
-
text: JSON.stringify({ success: true, results, total: results.length }),
|
|
965
|
-
},
|
|
966
|
-
],
|
|
967
|
-
};
|
|
968
|
-
}
|
|
969
|
-
catch (error) {
|
|
970
|
-
return {
|
|
971
|
-
content: [
|
|
972
|
-
{ type: 'text', text: JSON.stringify({ success: false, error: String(error) }) },
|
|
973
|
-
],
|
|
974
|
-
};
|
|
975
|
-
}
|
|
976
|
-
});
|
|
977
|
-
// Register tool: rulebook_memory_timeline
|
|
978
|
-
server.registerTool('rulebook_memory_timeline', {
|
|
979
|
-
title: 'Memory Timeline',
|
|
980
|
-
description: 'Get chronological context around a specific memory',
|
|
981
|
-
inputSchema: {
|
|
982
|
-
memoryId: z.string().describe('Memory ID to anchor timeline'),
|
|
983
|
-
window: z.number().optional().describe('Number of memories before/after (default 5)'),
|
|
984
|
-
projectId: projectIdSchema,
|
|
985
|
-
},
|
|
986
|
-
}, async (args) => {
|
|
987
|
-
const mm = await getMemMgr(args.projectId);
|
|
988
|
-
if (!mm)
|
|
989
|
-
return memoryNotEnabled();
|
|
990
|
-
try {
|
|
991
|
-
const timeline = await mm.getTimeline(args.memoryId, args.window);
|
|
992
|
-
return {
|
|
993
|
-
content: [{ type: 'text', text: JSON.stringify({ success: true, timeline }) }],
|
|
994
|
-
};
|
|
995
|
-
}
|
|
996
|
-
catch (error) {
|
|
997
|
-
return {
|
|
998
|
-
content: [
|
|
999
|
-
{ type: 'text', text: JSON.stringify({ success: false, error: String(error) }) },
|
|
1000
|
-
],
|
|
1001
|
-
};
|
|
1002
|
-
}
|
|
1003
|
-
});
|
|
1004
|
-
// Register tool: rulebook_memory_get
|
|
1005
|
-
server.registerTool('rulebook_memory_get', {
|
|
1006
|
-
title: 'Get Memory Details',
|
|
1007
|
-
description: 'Get full details for specific memory IDs',
|
|
1008
|
-
inputSchema: {
|
|
1009
|
-
ids: z.array(z.string()).describe('Memory IDs to fetch'),
|
|
1010
|
-
projectId: projectIdSchema,
|
|
1011
|
-
},
|
|
1012
|
-
}, async (args) => {
|
|
1013
|
-
const mm = await getMemMgr(args.projectId);
|
|
1014
|
-
if (!mm)
|
|
1015
|
-
return memoryNotEnabled();
|
|
1016
|
-
try {
|
|
1017
|
-
const memories = await mm.getFullDetails(args.ids);
|
|
1018
|
-
return {
|
|
1019
|
-
content: [{ type: 'text', text: JSON.stringify({ success: true, memories }) }],
|
|
1020
|
-
};
|
|
1021
|
-
}
|
|
1022
|
-
catch (error) {
|
|
1023
|
-
return {
|
|
1024
|
-
content: [
|
|
1025
|
-
{ type: 'text', text: JSON.stringify({ success: false, error: String(error) }) },
|
|
1026
|
-
],
|
|
1027
|
-
};
|
|
1028
|
-
}
|
|
1029
|
-
});
|
|
1030
|
-
// Register tool: rulebook_memory_save
|
|
1031
|
-
server.registerTool('rulebook_memory_save', {
|
|
1032
|
-
title: 'Save Memory',
|
|
1033
|
-
description: 'Save a new memory manually',
|
|
1034
|
-
inputSchema: {
|
|
1035
|
-
type: z
|
|
1036
|
-
.string()
|
|
1037
|
-
.describe('Memory type (bugfix, feature, refactor, decision, discovery, change, observation)'),
|
|
1038
|
-
title: z.string().describe('Memory title'),
|
|
1039
|
-
content: z.string().describe('Memory content'),
|
|
1040
|
-
tags: z.array(z.string()).optional().describe('Tags'),
|
|
1041
|
-
projectId: projectIdSchema,
|
|
1042
|
-
},
|
|
1043
|
-
}, async (args) => {
|
|
1044
|
-
const mm = await getMemMgr(args.projectId);
|
|
1045
|
-
if (!mm)
|
|
1046
|
-
return memoryNotEnabled();
|
|
1047
|
-
try {
|
|
1048
|
-
const memory = await mm.saveMemory({
|
|
1049
|
-
type: args.type,
|
|
1050
|
-
title: args.title,
|
|
1051
|
-
content: args.content,
|
|
1052
|
-
tags: args.tags,
|
|
1053
|
-
});
|
|
1054
|
-
return {
|
|
1055
|
-
content: [
|
|
1056
|
-
{
|
|
1057
|
-
type: 'text',
|
|
1058
|
-
text: JSON.stringify({
|
|
1059
|
-
success: true,
|
|
1060
|
-
memory: { id: memory.id, type: memory.type, title: memory.title },
|
|
1061
|
-
}),
|
|
1062
|
-
},
|
|
1063
|
-
],
|
|
1064
|
-
};
|
|
1065
|
-
}
|
|
1066
|
-
catch (error) {
|
|
1067
|
-
return {
|
|
1068
|
-
content: [
|
|
1069
|
-
{ type: 'text', text: JSON.stringify({ success: false, error: String(error) }) },
|
|
1070
|
-
],
|
|
1071
|
-
};
|
|
1072
|
-
}
|
|
1073
|
-
});
|
|
1074
|
-
// Register tool: rulebook_memory_stats
|
|
1075
|
-
server.registerTool('rulebook_memory_stats', {
|
|
1076
|
-
title: 'Memory Statistics',
|
|
1077
|
-
description: 'Get memory database statistics',
|
|
1078
|
-
inputSchema: {
|
|
1079
|
-
projectId: projectIdSchema,
|
|
1080
|
-
},
|
|
1081
|
-
}, async (args) => {
|
|
1082
|
-
const mm = await getMemMgr(args.projectId);
|
|
1083
|
-
if (!mm)
|
|
1084
|
-
return memoryNotEnabled();
|
|
1085
|
-
try {
|
|
1086
|
-
const stats = await mm.getStats();
|
|
1087
|
-
return {
|
|
1088
|
-
content: [{ type: 'text', text: JSON.stringify({ success: true, stats }) }],
|
|
1089
|
-
};
|
|
1090
|
-
}
|
|
1091
|
-
catch (error) {
|
|
1092
|
-
return {
|
|
1093
|
-
content: [
|
|
1094
|
-
{ type: 'text', text: JSON.stringify({ success: false, error: String(error) }) },
|
|
1095
|
-
],
|
|
1096
|
-
};
|
|
1097
|
-
}
|
|
1098
|
-
});
|
|
1099
|
-
// Register tool: rulebook_memory_cleanup
|
|
1100
|
-
server.registerTool('rulebook_memory_cleanup', {
|
|
1101
|
-
title: 'Memory Cleanup',
|
|
1102
|
-
description: 'Force memory eviction and cleanup',
|
|
1103
|
-
inputSchema: {
|
|
1104
|
-
force: z.boolean().optional().describe('Force cleanup regardless of size'),
|
|
1105
|
-
projectId: projectIdSchema,
|
|
1106
|
-
},
|
|
1107
|
-
}, async (args) => {
|
|
1108
|
-
const mm = await getMemMgr(args.projectId);
|
|
1109
|
-
if (!mm)
|
|
1110
|
-
return memoryNotEnabled();
|
|
1111
|
-
try {
|
|
1112
|
-
const result = await mm.cleanup(args.force ?? false);
|
|
1113
|
-
return {
|
|
1114
|
-
content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }) }],
|
|
1115
|
-
};
|
|
1116
|
-
}
|
|
1117
|
-
catch (error) {
|
|
1118
|
-
return {
|
|
1119
|
-
content: [
|
|
1120
|
-
{ type: 'text', text: JSON.stringify({ success: false, error: String(error) }) },
|
|
1121
|
-
],
|
|
1122
|
-
};
|
|
1123
|
-
}
|
|
1124
|
-
});
|
|
1125
|
-
// --- Background Indexer Tools ---
|
|
1126
|
-
// Register tool: rulebook_codebase_search
|
|
1127
|
-
server.registerTool('rulebook_codebase_search', {
|
|
1128
|
-
title: 'Codebase Semantic Search',
|
|
1129
|
-
description: 'Search the entire project semantically (via AST chunks and paragraphs)',
|
|
1130
|
-
inputSchema: {
|
|
1131
|
-
query: z.string().describe('The code or concept you are looking for'),
|
|
1132
|
-
limit: z.number().optional().describe('Result limit (default 10)'),
|
|
1133
|
-
},
|
|
1134
|
-
}, async (args) => {
|
|
1135
|
-
if (!memoryManager)
|
|
1136
|
-
return memoryNotEnabled();
|
|
1137
|
-
try {
|
|
1138
|
-
const results = await memoryManager.searchMemories({
|
|
1139
|
-
query: args.query,
|
|
1140
|
-
limit: args.limit ?? 10,
|
|
1141
|
-
mode: 'hybrid', // Force hybrid search for best code-chunk matching
|
|
1142
|
-
});
|
|
1143
|
-
// Filter out normal memories, keep only code nodes
|
|
1144
|
-
const codeResults = results.filter((r) => r.id.startsWith('__code__'));
|
|
1145
|
-
return {
|
|
1146
|
-
content: [
|
|
1147
|
-
{ type: 'text', text: JSON.stringify({ success: true, results: codeResults }) },
|
|
1148
|
-
],
|
|
1149
|
-
};
|
|
1150
|
-
}
|
|
1151
|
-
catch (error) {
|
|
1152
|
-
return {
|
|
1153
|
-
content: [
|
|
1154
|
-
{ type: 'text', text: JSON.stringify({ success: false, error: String(error) }) },
|
|
1155
|
-
],
|
|
1156
|
-
};
|
|
1157
|
-
}
|
|
1158
|
-
});
|
|
1159
|
-
// Register tool: rulebook_codebase_graph
|
|
1160
|
-
server.registerTool('rulebook_codebase_graph', {
|
|
1161
|
-
title: 'Codebase Graph Explorer',
|
|
1162
|
-
description: 'Find relationships (imports, exports) of a specific code node or file',
|
|
1163
|
-
inputSchema: {
|
|
1164
|
-
filePath: z.string().describe('The strict file path to query (e.g. src/core/app.ts)'),
|
|
1165
|
-
},
|
|
1166
|
-
}, async (args) => {
|
|
1167
|
-
if (!memoryManager)
|
|
1168
|
-
return memoryNotEnabled();
|
|
1169
|
-
try {
|
|
1170
|
-
// Since V1 has limited Graph search implementation in memory-search,
|
|
1171
|
-
// we'll return a placeholder indicating the edge relations.
|
|
1172
|
-
// In a real implementation we would call a memoryManager.getGraphAdjacent(args.filePath)
|
|
1173
|
-
return {
|
|
1174
|
-
content: [
|
|
1175
|
-
{
|
|
1176
|
-
type: 'text',
|
|
1177
|
-
text: JSON.stringify({
|
|
1178
|
-
success: true,
|
|
1179
|
-
message: `Graph query for ${args.filePath} accepted. (Note: Graph deep-search pending V2 implementation, use codebase_search for now.)`,
|
|
1180
|
-
filePath: args.filePath,
|
|
1181
|
-
}),
|
|
1182
|
-
},
|
|
1183
|
-
],
|
|
1184
|
-
};
|
|
1185
|
-
}
|
|
1186
|
-
catch (error) {
|
|
1187
|
-
return {
|
|
1188
|
-
content: [
|
|
1189
|
-
{ type: 'text', text: JSON.stringify({ success: false, error: String(error) }) },
|
|
1190
|
-
],
|
|
1191
|
-
};
|
|
1192
|
-
}
|
|
1193
|
-
});
|
|
1194
|
-
// Register tool: rulebook_indexer_status
|
|
1195
|
-
server.registerTool('rulebook_indexer_status', {
|
|
1196
|
-
title: 'Background Indexer Status',
|
|
1197
|
-
description: 'Get the status of the local autonomous filesystem indexer',
|
|
1198
|
-
inputSchema: {},
|
|
1199
|
-
}, async () => {
|
|
1200
|
-
try {
|
|
1201
|
-
// Because the BackgroundIndexer runs asynchronously, we fetch its global state
|
|
1202
|
-
// assuming it was attached to the server context during boot.
|
|
1203
|
-
const status = global.__indexerStatus
|
|
1204
|
-
? global.__indexerStatus()
|
|
1205
|
-
: { running: false, error: 'Indexer not attached to global context' };
|
|
1206
|
-
return {
|
|
1207
|
-
content: [{ type: 'text', text: JSON.stringify({ success: true, status }) }],
|
|
1208
|
-
};
|
|
1209
|
-
}
|
|
1210
|
-
catch (error) {
|
|
1211
|
-
return {
|
|
1212
|
-
content: [
|
|
1213
|
-
{ type: 'text', text: JSON.stringify({ success: false, error: String(error) }) },
|
|
1214
|
-
],
|
|
1215
|
-
};
|
|
1216
|
-
}
|
|
1217
|
-
});
|
|
1218
|
-
// ============================================
|
|
1219
|
-
// Workspace Tools (v4.2 — workspace mode only)
|
|
1220
|
-
// ============================================
|
|
1221
|
-
if (workspaceManager) {
|
|
1222
|
-
// Register tool: rulebook_workspace_list
|
|
1223
|
-
server.registerTool('rulebook_workspace_list', {
|
|
1224
|
-
title: 'List Workspace Projects',
|
|
1225
|
-
description: 'List all projects in the current workspace',
|
|
1226
|
-
inputSchema: {},
|
|
1227
|
-
}, async () => {
|
|
1228
|
-
const projects = workspaceManager.getProjects();
|
|
1229
|
-
const activeIds = workspaceManager.getActiveWorkerIds();
|
|
1230
|
-
return {
|
|
1231
|
-
content: [
|
|
1232
|
-
{
|
|
1233
|
-
type: 'text',
|
|
1234
|
-
text: JSON.stringify({
|
|
1235
|
-
success: true,
|
|
1236
|
-
workspace: workspaceManager.getConfig().name,
|
|
1237
|
-
defaultProject: workspaceManager.getDefaultProjectId(),
|
|
1238
|
-
projects: projects.map((p) => ({
|
|
1239
|
-
name: p.name,
|
|
1240
|
-
path: p.path,
|
|
1241
|
-
workerActive: activeIds.includes(p.name),
|
|
1242
|
-
})),
|
|
1243
|
-
count: projects.length,
|
|
1244
|
-
}),
|
|
1245
|
-
},
|
|
1246
|
-
],
|
|
1247
|
-
};
|
|
1248
|
-
});
|
|
1249
|
-
// Register tool: rulebook_workspace_status
|
|
1250
|
-
server.registerTool('rulebook_workspace_status', {
|
|
1251
|
-
title: 'Workspace Status',
|
|
1252
|
-
description: 'Get detailed status of all workspace projects (workers, tasks, memory)',
|
|
1253
|
-
inputSchema: {},
|
|
1254
|
-
}, async () => {
|
|
1255
|
-
try {
|
|
1256
|
-
const status = await workspaceManager.getStatus();
|
|
1257
|
-
return {
|
|
1258
|
-
content: [{ type: 'text', text: JSON.stringify({ success: true, ...status }) }],
|
|
1259
|
-
};
|
|
1260
|
-
}
|
|
1261
|
-
catch (error) {
|
|
1262
|
-
return {
|
|
1263
|
-
content: [
|
|
1264
|
-
{ type: 'text', text: JSON.stringify({ success: false, error: String(error) }) },
|
|
1265
|
-
],
|
|
1266
|
-
};
|
|
1267
|
-
}
|
|
1268
|
-
});
|
|
1269
|
-
// Register tool: rulebook_workspace_search
|
|
1270
|
-
server.registerTool('rulebook_workspace_search', {
|
|
1271
|
-
title: 'Cross-Project Memory Search',
|
|
1272
|
-
description: 'Search memories across all projects in the workspace',
|
|
1273
|
-
inputSchema: {
|
|
1274
|
-
query: z.string().describe('Search query'),
|
|
1275
|
-
limit: z.number().optional().describe('Max results per project (default 10)'),
|
|
1276
|
-
},
|
|
1277
|
-
}, async (args) => {
|
|
1278
|
-
try {
|
|
1279
|
-
const results = await workspaceManager.searchMemoryAcrossProjects(args.query, {
|
|
1280
|
-
limit: args.limit,
|
|
1281
|
-
});
|
|
1282
|
-
return {
|
|
1283
|
-
content: [
|
|
1284
|
-
{
|
|
1285
|
-
type: 'text',
|
|
1286
|
-
text: JSON.stringify({
|
|
1287
|
-
success: true,
|
|
1288
|
-
results,
|
|
1289
|
-
projectsSearched: results.length,
|
|
1290
|
-
}),
|
|
1291
|
-
},
|
|
1292
|
-
],
|
|
1293
|
-
};
|
|
1294
|
-
}
|
|
1295
|
-
catch (error) {
|
|
1296
|
-
return {
|
|
1297
|
-
content: [
|
|
1298
|
-
{ type: 'text', text: JSON.stringify({ success: false, error: String(error) }) },
|
|
1299
|
-
],
|
|
1300
|
-
};
|
|
1301
|
-
}
|
|
1302
|
-
});
|
|
1303
|
-
// Register tool: rulebook_workspace_tasks
|
|
1304
|
-
server.registerTool('rulebook_workspace_tasks', {
|
|
1305
|
-
title: 'List Tasks Across Projects',
|
|
1306
|
-
description: 'List tasks from all workspace projects',
|
|
1307
|
-
inputSchema: {
|
|
1308
|
-
status: z
|
|
1309
|
-
.enum(['pending', 'in-progress', 'completed', 'blocked'])
|
|
1310
|
-
.optional()
|
|
1311
|
-
.describe('Filter by status'),
|
|
1312
|
-
},
|
|
1313
|
-
}, async (args) => {
|
|
1314
|
-
try {
|
|
1315
|
-
const allTasks = [];
|
|
1316
|
-
for (const project of workspaceManager.getProjects()) {
|
|
1317
|
-
try {
|
|
1318
|
-
const tm = await getTaskMgr(project.name);
|
|
1319
|
-
const tasks = await tm.listTasks(false);
|
|
1320
|
-
const filtered = args.status ? tasks.filter((t) => t.status === args.status) : tasks;
|
|
1321
|
-
if (filtered.length > 0) {
|
|
1322
|
-
allTasks.push({
|
|
1323
|
-
project: project.name,
|
|
1324
|
-
tasks: filtered.map((t) => ({
|
|
1325
|
-
id: t.id,
|
|
1326
|
-
title: t.title,
|
|
1327
|
-
status: t.status,
|
|
1328
|
-
})),
|
|
1329
|
-
});
|
|
1330
|
-
}
|
|
1331
|
-
}
|
|
1332
|
-
catch {
|
|
1333
|
-
// Skip projects that fail
|
|
1334
|
-
}
|
|
1335
|
-
}
|
|
1336
|
-
return {
|
|
1337
|
-
content: [
|
|
1338
|
-
{
|
|
1339
|
-
type: 'text',
|
|
1340
|
-
text: JSON.stringify({
|
|
1341
|
-
success: true,
|
|
1342
|
-
projects: allTasks,
|
|
1343
|
-
totalTasks: allTasks.reduce((sum, p) => sum + p.tasks.length, 0),
|
|
1344
|
-
}),
|
|
1345
|
-
},
|
|
1346
|
-
],
|
|
1347
|
-
};
|
|
1348
|
-
}
|
|
1349
|
-
catch (error) {
|
|
1350
|
-
return {
|
|
1351
|
-
content: [
|
|
1352
|
-
{ type: 'text', text: JSON.stringify({ success: false, error: String(error) }) },
|
|
1353
|
-
],
|
|
1354
|
-
};
|
|
1355
|
-
}
|
|
1356
|
-
});
|
|
1357
|
-
}
|
|
1358
|
-
// ============================================
|
|
1359
|
-
// Context Intelligence Layer Tools (v4.4)
|
|
1360
|
-
// ============================================
|
|
1361
|
-
// Register tool: rulebook_decision_create
|
|
1362
|
-
server.registerTool('rulebook_decision_create', {
|
|
1363
|
-
title: 'Create Decision Record',
|
|
1364
|
-
description: 'Create a new architectural decision record (ADR)',
|
|
1365
|
-
inputSchema: {
|
|
1366
|
-
title: z.string().describe('Decision title'),
|
|
1367
|
-
context: z.string().optional().describe('Context and problem statement'),
|
|
1368
|
-
decision: z.string().optional().describe('The decision made'),
|
|
1369
|
-
alternatives: z.array(z.string()).optional().describe('Alternatives considered'),
|
|
1370
|
-
consequences: z.string().optional().describe('Consequences and tradeoffs'),
|
|
1371
|
-
relatedTasks: z.array(z.string()).optional().describe('Related task IDs'),
|
|
1372
|
-
projectId: projectIdSchema,
|
|
1373
|
-
},
|
|
1374
|
-
}, async (args) => {
|
|
1375
|
-
try {
|
|
1376
|
-
const root = args.projectId && workspaceManager
|
|
1377
|
-
? (await workspaceManager.getWorker(args.projectId)).projectRoot
|
|
1378
|
-
: projectRoot;
|
|
1379
|
-
const { DecisionManager } = await import('../core/tasks/decision-manager.js');
|
|
1380
|
-
const dm = new DecisionManager(root);
|
|
1381
|
-
const decision = await dm.create(args.title, {
|
|
1382
|
-
context: args.context,
|
|
1383
|
-
decision: args.decision,
|
|
1384
|
-
alternatives: args.alternatives,
|
|
1385
|
-
consequences: args.consequences,
|
|
1386
|
-
relatedTasks: args.relatedTasks,
|
|
1387
|
-
});
|
|
1388
|
-
return {
|
|
1389
|
-
content: [
|
|
1390
|
-
{
|
|
1391
|
-
type: 'text',
|
|
1392
|
-
text: JSON.stringify({ success: true, decision }),
|
|
1393
|
-
},
|
|
1394
|
-
],
|
|
1395
|
-
};
|
|
1396
|
-
}
|
|
1397
|
-
catch (error) {
|
|
1398
|
-
return {
|
|
1399
|
-
content: [
|
|
1400
|
-
{
|
|
1401
|
-
type: 'text',
|
|
1402
|
-
text: JSON.stringify({
|
|
1403
|
-
success: false,
|
|
1404
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1405
|
-
}),
|
|
1406
|
-
},
|
|
1407
|
-
],
|
|
1408
|
-
};
|
|
1409
|
-
}
|
|
1410
|
-
});
|
|
1411
|
-
// Register tool: rulebook_decision_list
|
|
1412
|
-
server.registerTool('rulebook_decision_list', {
|
|
1413
|
-
title: 'List Decision Records',
|
|
1414
|
-
description: 'List all architectural decision records',
|
|
1415
|
-
inputSchema: {
|
|
1416
|
-
status: z
|
|
1417
|
-
.string()
|
|
1418
|
-
.optional()
|
|
1419
|
-
.describe('Filter by status (proposed, accepted, rejected, superseded, deprecated)'),
|
|
1420
|
-
projectId: projectIdSchema,
|
|
1421
|
-
},
|
|
1422
|
-
}, async (args) => {
|
|
1423
|
-
try {
|
|
1424
|
-
const root = args.projectId && workspaceManager
|
|
1425
|
-
? (await workspaceManager.getWorker(args.projectId)).projectRoot
|
|
1426
|
-
: projectRoot;
|
|
1427
|
-
const { DecisionManager } = await import('../core/tasks/decision-manager.js');
|
|
1428
|
-
const dm = new DecisionManager(root);
|
|
1429
|
-
const decisions = await dm.list(args.status);
|
|
1430
|
-
return {
|
|
1431
|
-
content: [
|
|
1432
|
-
{
|
|
1433
|
-
type: 'text',
|
|
1434
|
-
text: JSON.stringify({ success: true, decisions, count: decisions.length }),
|
|
1435
|
-
},
|
|
1436
|
-
],
|
|
1437
|
-
};
|
|
1438
|
-
}
|
|
1439
|
-
catch (error) {
|
|
1440
|
-
return {
|
|
1441
|
-
content: [
|
|
1442
|
-
{
|
|
1443
|
-
type: 'text',
|
|
1444
|
-
text: JSON.stringify({
|
|
1445
|
-
success: false,
|
|
1446
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1447
|
-
}),
|
|
1448
|
-
},
|
|
1449
|
-
],
|
|
1450
|
-
};
|
|
1451
|
-
}
|
|
1452
|
-
});
|
|
1453
|
-
// Register tool: rulebook_decision_show
|
|
1454
|
-
server.registerTool('rulebook_decision_show', {
|
|
1455
|
-
title: 'Show Decision Record',
|
|
1456
|
-
description: 'Show full details of a decision record',
|
|
1457
|
-
inputSchema: {
|
|
1458
|
-
id: z.number().describe('Decision ID'),
|
|
1459
|
-
projectId: projectIdSchema,
|
|
1460
|
-
},
|
|
1461
|
-
}, async (args) => {
|
|
1462
|
-
try {
|
|
1463
|
-
const root = args.projectId && workspaceManager
|
|
1464
|
-
? (await workspaceManager.getWorker(args.projectId)).projectRoot
|
|
1465
|
-
: projectRoot;
|
|
1466
|
-
const { DecisionManager } = await import('../core/tasks/decision-manager.js');
|
|
1467
|
-
const dm = new DecisionManager(root);
|
|
1468
|
-
const result = await dm.show(args.id);
|
|
1469
|
-
if (!result) {
|
|
1470
|
-
return {
|
|
1471
|
-
content: [
|
|
1472
|
-
{
|
|
1473
|
-
type: 'text',
|
|
1474
|
-
text: JSON.stringify({ success: false, error: `Decision ${args.id} not found` }),
|
|
1475
|
-
},
|
|
1476
|
-
],
|
|
1477
|
-
};
|
|
1478
|
-
}
|
|
1479
|
-
return {
|
|
1480
|
-
content: [
|
|
1481
|
-
{
|
|
1482
|
-
type: 'text',
|
|
1483
|
-
text: JSON.stringify({
|
|
1484
|
-
success: true,
|
|
1485
|
-
decision: result.decision,
|
|
1486
|
-
content: result.content,
|
|
1487
|
-
}),
|
|
1488
|
-
},
|
|
1489
|
-
],
|
|
1490
|
-
};
|
|
1491
|
-
}
|
|
1492
|
-
catch (error) {
|
|
1493
|
-
return {
|
|
1494
|
-
content: [
|
|
1495
|
-
{
|
|
1496
|
-
type: 'text',
|
|
1497
|
-
text: JSON.stringify({
|
|
1498
|
-
success: false,
|
|
1499
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1500
|
-
}),
|
|
1501
|
-
},
|
|
1502
|
-
],
|
|
1503
|
-
};
|
|
1504
|
-
}
|
|
1505
|
-
});
|
|
1506
|
-
// Register tool: rulebook_decision_update
|
|
1507
|
-
server.registerTool('rulebook_decision_update', {
|
|
1508
|
-
title: 'Update Decision Record',
|
|
1509
|
-
description: 'Update an existing architectural decision record',
|
|
1510
|
-
inputSchema: {
|
|
1511
|
-
id: z.number().describe('Decision ID to update'),
|
|
1512
|
-
status: z
|
|
1513
|
-
.string()
|
|
1514
|
-
.optional()
|
|
1515
|
-
.describe('New status (proposed, accepted, rejected, superseded, deprecated)'),
|
|
1516
|
-
context: z.string().optional().describe('Updated context'),
|
|
1517
|
-
decision: z.string().optional().describe('Updated decision text'),
|
|
1518
|
-
projectId: projectIdSchema,
|
|
1519
|
-
},
|
|
1520
|
-
}, async (args) => {
|
|
1521
|
-
try {
|
|
1522
|
-
const root = args.projectId && workspaceManager
|
|
1523
|
-
? (await workspaceManager.getWorker(args.projectId)).projectRoot
|
|
1524
|
-
: projectRoot;
|
|
1525
|
-
const { DecisionManager } = await import('../core/tasks/decision-manager.js');
|
|
1526
|
-
const dm = new DecisionManager(root);
|
|
1527
|
-
const updated = await dm.update(args.id, {
|
|
1528
|
-
status: args.status,
|
|
1529
|
-
context: args.context,
|
|
1530
|
-
decision: args.decision,
|
|
1531
|
-
});
|
|
1532
|
-
if (!updated) {
|
|
1533
|
-
return {
|
|
1534
|
-
content: [
|
|
1535
|
-
{
|
|
1536
|
-
type: 'text',
|
|
1537
|
-
text: JSON.stringify({ success: false, error: `Decision ${args.id} not found` }),
|
|
1538
|
-
},
|
|
1539
|
-
],
|
|
1540
|
-
};
|
|
1541
|
-
}
|
|
1542
|
-
return {
|
|
1543
|
-
content: [
|
|
1544
|
-
{
|
|
1545
|
-
type: 'text',
|
|
1546
|
-
text: JSON.stringify({ success: true, decision: updated }),
|
|
1547
|
-
},
|
|
1548
|
-
],
|
|
1549
|
-
};
|
|
1550
|
-
}
|
|
1551
|
-
catch (error) {
|
|
1552
|
-
return {
|
|
1553
|
-
content: [
|
|
1554
|
-
{
|
|
1555
|
-
type: 'text',
|
|
1556
|
-
text: JSON.stringify({
|
|
1557
|
-
success: false,
|
|
1558
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1559
|
-
}),
|
|
1560
|
-
},
|
|
1561
|
-
],
|
|
1562
|
-
};
|
|
1563
|
-
}
|
|
1564
|
-
});
|
|
1565
|
-
// Register tool: rulebook_knowledge_add
|
|
1566
|
-
server.registerTool('rulebook_knowledge_add', {
|
|
1567
|
-
title: 'Add Knowledge Entry',
|
|
1568
|
-
description: 'Add a new pattern or anti-pattern to the project knowledge base',
|
|
1569
|
-
inputSchema: {
|
|
1570
|
-
type: z.string().describe('Knowledge type: "pattern" or "anti-pattern"'),
|
|
1571
|
-
title: z.string().describe('Entry title'),
|
|
1572
|
-
category: z.string().describe('Category (e.g. code, architecture, testing, security)'),
|
|
1573
|
-
description: z.string().describe('Description of the pattern'),
|
|
1574
|
-
example: z.string().optional().describe('Code or usage example'),
|
|
1575
|
-
whenToUse: z.string().optional().describe('When to use this pattern'),
|
|
1576
|
-
whenNotToUse: z.string().optional().describe('When NOT to use this pattern'),
|
|
1577
|
-
tags: z.array(z.string()).optional().describe('Tags for search'),
|
|
1578
|
-
projectId: projectIdSchema,
|
|
1579
|
-
},
|
|
1580
|
-
}, async (args) => {
|
|
1581
|
-
try {
|
|
1582
|
-
const root = args.projectId && workspaceManager
|
|
1583
|
-
? (await workspaceManager.getWorker(args.projectId)).projectRoot
|
|
1584
|
-
: projectRoot;
|
|
1585
|
-
const { KnowledgeManager } = await import('../core/tasks/knowledge-manager.js');
|
|
1586
|
-
const km = new KnowledgeManager(root);
|
|
1587
|
-
const entry = await km.add(args.type, args.title, {
|
|
1588
|
-
category: args.category,
|
|
1589
|
-
description: args.description,
|
|
1590
|
-
example: args.example,
|
|
1591
|
-
whenToUse: args.whenToUse,
|
|
1592
|
-
whenNotToUse: args.whenNotToUse,
|
|
1593
|
-
tags: args.tags,
|
|
1594
|
-
});
|
|
1595
|
-
return {
|
|
1596
|
-
content: [
|
|
1597
|
-
{
|
|
1598
|
-
type: 'text',
|
|
1599
|
-
text: JSON.stringify({ success: true, entry }),
|
|
1600
|
-
},
|
|
1601
|
-
],
|
|
1602
|
-
};
|
|
1603
|
-
}
|
|
1604
|
-
catch (error) {
|
|
1605
|
-
return {
|
|
1606
|
-
content: [
|
|
1607
|
-
{
|
|
1608
|
-
type: 'text',
|
|
1609
|
-
text: JSON.stringify({
|
|
1610
|
-
success: false,
|
|
1611
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1612
|
-
}),
|
|
1613
|
-
},
|
|
1614
|
-
],
|
|
1615
|
-
};
|
|
1616
|
-
}
|
|
1617
|
-
});
|
|
1618
|
-
// Register tool: rulebook_knowledge_list
|
|
1619
|
-
server.registerTool('rulebook_knowledge_list', {
|
|
1620
|
-
title: 'List Knowledge Entries',
|
|
1621
|
-
description: 'List patterns and anti-patterns in the project knowledge base',
|
|
1622
|
-
inputSchema: {
|
|
1623
|
-
type: z.string().optional().describe('Filter by type: "pattern" or "anti-pattern"'),
|
|
1624
|
-
category: z.string().optional().describe('Filter by category'),
|
|
1625
|
-
projectId: projectIdSchema,
|
|
1626
|
-
},
|
|
1627
|
-
}, async (args) => {
|
|
1628
|
-
try {
|
|
1629
|
-
const root = args.projectId && workspaceManager
|
|
1630
|
-
? (await workspaceManager.getWorker(args.projectId)).projectRoot
|
|
1631
|
-
: projectRoot;
|
|
1632
|
-
const { KnowledgeManager } = await import('../core/tasks/knowledge-manager.js');
|
|
1633
|
-
const km = new KnowledgeManager(root);
|
|
1634
|
-
const entries = await km.list(args.type, args.category);
|
|
1635
|
-
return {
|
|
1636
|
-
content: [
|
|
1637
|
-
{
|
|
1638
|
-
type: 'text',
|
|
1639
|
-
text: JSON.stringify({ success: true, entries, count: entries.length }),
|
|
1640
|
-
},
|
|
1641
|
-
],
|
|
1642
|
-
};
|
|
1643
|
-
}
|
|
1644
|
-
catch (error) {
|
|
1645
|
-
return {
|
|
1646
|
-
content: [
|
|
1647
|
-
{
|
|
1648
|
-
type: 'text',
|
|
1649
|
-
text: JSON.stringify({
|
|
1650
|
-
success: false,
|
|
1651
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1652
|
-
}),
|
|
1653
|
-
},
|
|
1654
|
-
],
|
|
1655
|
-
};
|
|
1656
|
-
}
|
|
269
|
+
const server = new McpServer({
|
|
270
|
+
name: 'rulebook-task-management',
|
|
271
|
+
version: '5.2.0',
|
|
1657
272
|
});
|
|
1658
|
-
//
|
|
1659
|
-
server.registerTool(
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
projectId: projectIdSchema,
|
|
1665
|
-
},
|
|
1666
|
-
}, async (args) => {
|
|
1667
|
-
try {
|
|
1668
|
-
const root = args.projectId && workspaceManager
|
|
1669
|
-
? (await workspaceManager.getWorker(args.projectId)).projectRoot
|
|
1670
|
-
: projectRoot;
|
|
1671
|
-
const { KnowledgeManager } = await import('../core/tasks/knowledge-manager.js');
|
|
1672
|
-
const km = new KnowledgeManager(root);
|
|
1673
|
-
const result = await km.show(args.id);
|
|
1674
|
-
if (!result) {
|
|
1675
|
-
return {
|
|
1676
|
-
content: [
|
|
1677
|
-
{
|
|
1678
|
-
type: 'text',
|
|
1679
|
-
text: JSON.stringify({
|
|
1680
|
-
success: false,
|
|
1681
|
-
error: `Knowledge entry "${args.id}" not found`,
|
|
1682
|
-
}),
|
|
1683
|
-
},
|
|
1684
|
-
],
|
|
1685
|
-
};
|
|
273
|
+
// --- Wrap all tool handlers with a timeout guard ---
|
|
274
|
+
const originalRegisterTool = server.registerTool.bind(server);
|
|
275
|
+
server.registerTool = ((name, config, handler) => {
|
|
276
|
+
const wrappedHandler = async (...handlerArgs) => {
|
|
277
|
+
try {
|
|
278
|
+
return await withTimeout(handler(...handlerArgs), MCP_TOOL_TIMEOUT_MS, name);
|
|
1686
279
|
}
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
type: 'text',
|
|
1691
|
-
text: JSON.stringify({ success: true, entry: result.entry, content: result.content }),
|
|
1692
|
-
},
|
|
1693
|
-
],
|
|
1694
|
-
};
|
|
1695
|
-
}
|
|
1696
|
-
catch (error) {
|
|
1697
|
-
return {
|
|
1698
|
-
content: [
|
|
1699
|
-
{
|
|
1700
|
-
type: 'text',
|
|
1701
|
-
text: JSON.stringify({
|
|
1702
|
-
success: false,
|
|
1703
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1704
|
-
}),
|
|
1705
|
-
},
|
|
1706
|
-
],
|
|
1707
|
-
};
|
|
1708
|
-
}
|
|
1709
|
-
});
|
|
1710
|
-
// Register tool: rulebook_learn_capture
|
|
1711
|
-
server.registerTool('rulebook_learn_capture', {
|
|
1712
|
-
title: 'Capture Learning',
|
|
1713
|
-
description: 'Capture a learning or insight for future reference',
|
|
1714
|
-
inputSchema: {
|
|
1715
|
-
title: z.string().describe('Brief title for the learning'),
|
|
1716
|
-
content: z.string().describe('Full content of the learning'),
|
|
1717
|
-
tags: z.array(z.string()).optional().describe('Tags for search'),
|
|
1718
|
-
relatedTask: z.string().optional().describe('Related task ID'),
|
|
1719
|
-
projectId: projectIdSchema,
|
|
1720
|
-
},
|
|
1721
|
-
}, async (args) => {
|
|
1722
|
-
try {
|
|
1723
|
-
const root = args.projectId && workspaceManager
|
|
1724
|
-
? (await workspaceManager.getWorker(args.projectId)).projectRoot
|
|
1725
|
-
: projectRoot;
|
|
1726
|
-
const { LearnManager } = await import('../core/tasks/learn-manager.js');
|
|
1727
|
-
const lm = new LearnManager(root);
|
|
1728
|
-
const learning = await lm.capture(args.title, args.content, {
|
|
1729
|
-
tags: args.tags,
|
|
1730
|
-
relatedTask: args.relatedTask,
|
|
1731
|
-
});
|
|
1732
|
-
return {
|
|
1733
|
-
content: [
|
|
1734
|
-
{
|
|
1735
|
-
type: 'text',
|
|
1736
|
-
text: JSON.stringify({ success: true, learning }),
|
|
1737
|
-
},
|
|
1738
|
-
],
|
|
1739
|
-
};
|
|
1740
|
-
}
|
|
1741
|
-
catch (error) {
|
|
1742
|
-
return {
|
|
1743
|
-
content: [
|
|
1744
|
-
{
|
|
1745
|
-
type: 'text',
|
|
1746
|
-
text: JSON.stringify({
|
|
1747
|
-
success: false,
|
|
1748
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1749
|
-
}),
|
|
1750
|
-
},
|
|
1751
|
-
],
|
|
1752
|
-
};
|
|
1753
|
-
}
|
|
1754
|
-
});
|
|
1755
|
-
// Register tool: rulebook_learn_list
|
|
1756
|
-
server.registerTool('rulebook_learn_list', {
|
|
1757
|
-
title: 'List Learnings',
|
|
1758
|
-
description: 'List captured learnings, newest first',
|
|
1759
|
-
inputSchema: {
|
|
1760
|
-
limit: z.number().optional().describe('Maximum number of learnings to return'),
|
|
1761
|
-
projectId: projectIdSchema,
|
|
1762
|
-
},
|
|
1763
|
-
}, async (args) => {
|
|
1764
|
-
try {
|
|
1765
|
-
const root = args.projectId && workspaceManager
|
|
1766
|
-
? (await workspaceManager.getWorker(args.projectId)).projectRoot
|
|
1767
|
-
: projectRoot;
|
|
1768
|
-
const { LearnManager } = await import('../core/tasks/learn-manager.js');
|
|
1769
|
-
const lm = new LearnManager(root);
|
|
1770
|
-
const learnings = await lm.list(args.limit);
|
|
1771
|
-
return {
|
|
1772
|
-
content: [
|
|
1773
|
-
{
|
|
1774
|
-
type: 'text',
|
|
1775
|
-
text: JSON.stringify({ success: true, learnings, count: learnings.length }),
|
|
1776
|
-
},
|
|
1777
|
-
],
|
|
1778
|
-
};
|
|
1779
|
-
}
|
|
1780
|
-
catch (error) {
|
|
1781
|
-
return {
|
|
1782
|
-
content: [
|
|
1783
|
-
{
|
|
1784
|
-
type: 'text',
|
|
1785
|
-
text: JSON.stringify({
|
|
1786
|
-
success: false,
|
|
1787
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1788
|
-
}),
|
|
1789
|
-
},
|
|
1790
|
-
],
|
|
1791
|
-
};
|
|
1792
|
-
}
|
|
1793
|
-
});
|
|
1794
|
-
// Register tool: rulebook_learn_promote
|
|
1795
|
-
server.registerTool('rulebook_learn_promote', {
|
|
1796
|
-
title: 'Promote Learning',
|
|
1797
|
-
description: 'Promote a learning to a knowledge entry or decision record',
|
|
1798
|
-
inputSchema: {
|
|
1799
|
-
id: z.string().describe('Learning ID to promote'),
|
|
1800
|
-
target: z
|
|
1801
|
-
.enum(['knowledge', 'decision'])
|
|
1802
|
-
.describe('Promote to knowledge base or decision record'),
|
|
1803
|
-
title: z.string().optional().describe('Override title for the promoted entry'),
|
|
1804
|
-
projectId: projectIdSchema,
|
|
1805
|
-
},
|
|
1806
|
-
}, async (args) => {
|
|
1807
|
-
try {
|
|
1808
|
-
const root = args.projectId && workspaceManager
|
|
1809
|
-
? (await workspaceManager.getWorker(args.projectId)).projectRoot
|
|
1810
|
-
: projectRoot;
|
|
1811
|
-
const { LearnManager } = await import('../core/tasks/learn-manager.js');
|
|
1812
|
-
const lm = new LearnManager(root);
|
|
1813
|
-
const result = await lm.promote(args.id, args.target, { title: args.title });
|
|
1814
|
-
if (!result) {
|
|
280
|
+
catch (error) {
|
|
281
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
282
|
+
console.error(`[rulebook-mcp] ${name} error: ${msg}`);
|
|
1815
283
|
return {
|
|
1816
284
|
content: [
|
|
1817
285
|
{
|
|
1818
286
|
type: 'text',
|
|
1819
|
-
text: JSON.stringify({ success: false, error:
|
|
287
|
+
text: JSON.stringify({ success: false, error: msg }),
|
|
1820
288
|
},
|
|
1821
289
|
],
|
|
1822
290
|
};
|
|
1823
291
|
}
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
{
|
|
1827
|
-
type: 'text',
|
|
1828
|
-
text: JSON.stringify({ success: true, promoted: result }),
|
|
1829
|
-
},
|
|
1830
|
-
],
|
|
1831
|
-
};
|
|
1832
|
-
}
|
|
1833
|
-
catch (error) {
|
|
1834
|
-
return {
|
|
1835
|
-
content: [
|
|
1836
|
-
{
|
|
1837
|
-
type: 'text',
|
|
1838
|
-
text: JSON.stringify({
|
|
1839
|
-
success: false,
|
|
1840
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1841
|
-
}),
|
|
1842
|
-
},
|
|
1843
|
-
],
|
|
1844
|
-
};
|
|
1845
|
-
}
|
|
292
|
+
};
|
|
293
|
+
return originalRegisterTool(name, config, wrappedHandler);
|
|
1846
294
|
});
|
|
295
|
+
// Zod schema reused across tools for workspace project targeting
|
|
296
|
+
const projectIdSchema = z
|
|
297
|
+
.string()
|
|
298
|
+
.optional()
|
|
299
|
+
.describe('Project ID (workspace mode only, defaults to default project)');
|
|
300
|
+
// Shared context handed to each extracted domain tool module.
|
|
301
|
+
const ctx = {
|
|
302
|
+
projectRoot,
|
|
303
|
+
workspaceManager,
|
|
304
|
+
projectIdSchema,
|
|
305
|
+
getTaskMgr,
|
|
306
|
+
getConfigMgr,
|
|
307
|
+
getSkillsMgr,
|
|
308
|
+
};
|
|
309
|
+
registerTaskTools(server, ctx);
|
|
310
|
+
registerSkillTools(server, ctx);
|
|
311
|
+
registerWorkspaceTools(server, ctx);
|
|
312
|
+
registerDecisionTools(server, ctx);
|
|
313
|
+
registerKnowledgeTools(server, ctx);
|
|
314
|
+
registerLearnTools(server, ctx);
|
|
1847
315
|
// ── v5.0 Tools: Session Management, Rules, Blockers ──────────────────
|
|
1848
316
|
// Register tool: rulebook_session_start
|
|
1849
317
|
server.registerTool('rulebook_session_start', {
|
|
@@ -1870,15 +338,6 @@ export async function startRulebookMcpServer() {
|
|
|
1870
338
|
if (existsSync(plansPath)) {
|
|
1871
339
|
result.plans = await readFile(plansPath, 'utf-8');
|
|
1872
340
|
}
|
|
1873
|
-
// Search relevant memories
|
|
1874
|
-
if (args.query && memoryManager) {
|
|
1875
|
-
const searchResults = await memoryManager.searchMemories({
|
|
1876
|
-
query: args.query,
|
|
1877
|
-
mode: 'hybrid',
|
|
1878
|
-
limit: 5,
|
|
1879
|
-
});
|
|
1880
|
-
result.memories = searchResults;
|
|
1881
|
-
}
|
|
1882
341
|
return {
|
|
1883
342
|
content: [{ type: 'text', text: JSON.stringify({ success: true, ...result }) }],
|
|
1884
343
|
};
|
|
@@ -1938,63 +397,13 @@ export async function startRulebookMcpServer() {
|
|
|
1938
397
|
mkdirSync(dir, { recursive: true });
|
|
1939
398
|
await writeFile(plansPath, newContent, 'utf-8');
|
|
1940
399
|
}
|
|
1941
|
-
// Also save to memory if available
|
|
1942
|
-
if (memoryManager) {
|
|
1943
|
-
await memoryManager.saveMemory({
|
|
1944
|
-
type: 'observation',
|
|
1945
|
-
title: `Session summary ${date}`,
|
|
1946
|
-
content: args.summary,
|
|
1947
|
-
tags: ['session', 'summary'],
|
|
1948
|
-
});
|
|
1949
|
-
}
|
|
1950
|
-
return {
|
|
1951
|
-
content: [
|
|
1952
|
-
{
|
|
1953
|
-
type: 'text',
|
|
1954
|
-
text: JSON.stringify({ success: true, message: 'Session summary saved to PLANS.md' }),
|
|
1955
|
-
},
|
|
1956
|
-
],
|
|
1957
|
-
};
|
|
1958
|
-
}
|
|
1959
|
-
catch (error) {
|
|
1960
|
-
return {
|
|
1961
|
-
content: [
|
|
1962
|
-
{
|
|
1963
|
-
type: 'text',
|
|
1964
|
-
text: JSON.stringify({
|
|
1965
|
-
success: false,
|
|
1966
|
-
error: error instanceof Error ? error.message : String(error),
|
|
1967
|
-
}),
|
|
1968
|
-
},
|
|
1969
|
-
],
|
|
1970
|
-
};
|
|
1971
|
-
}
|
|
1972
|
-
});
|
|
1973
|
-
// Register tool: rulebook_rules_list
|
|
1974
|
-
server.registerTool('rulebook_rules_list', {
|
|
1975
|
-
title: 'List Rules',
|
|
1976
|
-
description: 'List canonical rules from .rulebook/rules/ AND path-scoped language rules from .claude/rules/. Each entry is classified by source (generated by rulebook vs user-authored).',
|
|
1977
|
-
inputSchema: {
|
|
1978
|
-
projectId: projectIdSchema,
|
|
1979
|
-
},
|
|
1980
|
-
}, async (args) => {
|
|
1981
|
-
try {
|
|
1982
|
-
const root = args.projectId && workspaceManager
|
|
1983
|
-
? (await workspaceManager.getWorker(args.projectId)).projectRoot
|
|
1984
|
-
: projectRoot;
|
|
1985
|
-
const { listRules } = await import('../core/rule-engine.js');
|
|
1986
|
-
const { listRulesWithSource } = await import('../core/generators/rules-generator.js');
|
|
1987
|
-
const canonical = await listRules(root);
|
|
1988
|
-
const languageRules = await listRulesWithSource(root);
|
|
1989
400
|
return {
|
|
1990
401
|
content: [
|
|
1991
402
|
{
|
|
1992
403
|
type: 'text',
|
|
1993
404
|
text: JSON.stringify({
|
|
1994
405
|
success: true,
|
|
1995
|
-
|
|
1996
|
-
languageRules,
|
|
1997
|
-
count: canonical.length + languageRules.length,
|
|
406
|
+
message: 'Session summary saved to PLANS.md',
|
|
1998
407
|
}),
|
|
1999
408
|
},
|
|
2000
409
|
],
|
|
@@ -2014,6 +423,18 @@ export async function startRulebookMcpServer() {
|
|
|
2014
423
|
};
|
|
2015
424
|
}
|
|
2016
425
|
});
|
|
426
|
+
registerRulesTools(server, ctx);
|
|
427
|
+
// Release the PID lock on shutdown so a restart can re-acquire it.
|
|
428
|
+
const releaseLock = () => releasePidLock(pidFilePath);
|
|
429
|
+
process.on('SIGINT', () => {
|
|
430
|
+
releaseLock();
|
|
431
|
+
process.exit(0);
|
|
432
|
+
});
|
|
433
|
+
process.on('SIGTERM', () => {
|
|
434
|
+
releaseLock();
|
|
435
|
+
process.exit(0);
|
|
436
|
+
});
|
|
437
|
+
process.on('exit', releaseLock);
|
|
2017
438
|
const transport = new StdioServerTransport();
|
|
2018
439
|
await server.connect(transport);
|
|
2019
440
|
}
|