xtrm-tools 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (333) hide show
  1. package/CHANGELOG.md +504 -0
  2. package/README.md +201 -0
  3. package/cli/dist/index.cjs +57378 -0
  4. package/cli/dist/index.cjs.map +1 -0
  5. package/cli/dist/index.d.cts +2 -0
  6. package/cli/package.json +47 -0
  7. package/config/.env.example +40 -0
  8. package/config/hooks.json +72 -0
  9. package/config/instructions/agents-top.md +30 -0
  10. package/config/instructions/claude-top.md +30 -0
  11. package/config/mcp_servers.json +57 -0
  12. package/config/mcp_servers_optional.json +53 -0
  13. package/config/pi/auth.json.template +14 -0
  14. package/config/pi/extensions/auto-session-name/index.ts +29 -0
  15. package/config/pi/extensions/auto-session-name/package.json +16 -0
  16. package/config/pi/extensions/auto-update/index.ts +71 -0
  17. package/config/pi/extensions/auto-update/package.json +16 -0
  18. package/config/pi/extensions/beads/index.ts +166 -0
  19. package/config/pi/extensions/beads/package.json +16 -0
  20. package/config/pi/extensions/bg-process/index.ts +230 -0
  21. package/config/pi/extensions/bg-process/package.json +16 -0
  22. package/config/pi/extensions/compact-header/index.ts +69 -0
  23. package/config/pi/extensions/compact-header/package.json +16 -0
  24. package/config/pi/extensions/core/adapter.ts +52 -0
  25. package/config/pi/extensions/core/guard-rules.ts +102 -0
  26. package/config/pi/extensions/core/lib.ts +3 -0
  27. package/config/pi/extensions/core/logger.ts +45 -0
  28. package/config/pi/extensions/core/runner.ts +71 -0
  29. package/config/pi/extensions/core/session-state.ts +59 -0
  30. package/config/pi/extensions/custom-footer/index.ts +160 -0
  31. package/config/pi/extensions/custom-footer/package.json +16 -0
  32. package/config/pi/extensions/custom-provider-qwen-cli/index.ts +363 -0
  33. package/config/pi/extensions/custom-provider-qwen-cli/package.json +1 -0
  34. package/config/pi/extensions/git-checkpoint/index.ts +53 -0
  35. package/config/pi/extensions/git-checkpoint/package.json +16 -0
  36. package/config/pi/extensions/minimal-mode/index.ts +201 -0
  37. package/config/pi/extensions/minimal-mode/package.json +16 -0
  38. package/config/pi/extensions/plan-mode/README.md +65 -0
  39. package/config/pi/extensions/plan-mode/index.ts +417 -0
  40. package/config/pi/extensions/plan-mode/package.json +12 -0
  41. package/config/pi/extensions/plan-mode/utils.ts +324 -0
  42. package/config/pi/extensions/quality-gates/index.ts +67 -0
  43. package/config/pi/extensions/quality-gates/package.json +16 -0
  44. package/config/pi/extensions/service-skills/index.ts +108 -0
  45. package/config/pi/extensions/service-skills/package.json +16 -0
  46. package/config/pi/extensions/session-flow/index.ts +131 -0
  47. package/config/pi/extensions/session-flow/package.json +16 -0
  48. package/config/pi/extensions/todo/index.ts +299 -0
  49. package/config/pi/extensions/todo/package.json +16 -0
  50. package/config/pi/extensions/xtrm-loader/index.ts +89 -0
  51. package/config/pi/extensions/xtrm-loader/package.json +16 -0
  52. package/config/pi/install-schema.json +44 -0
  53. package/config/pi/models.json.template +76 -0
  54. package/config/pi/pi-worktrees-settings.json +6 -0
  55. package/config/pi/settings.json.template +16 -0
  56. package/config/settings.json +70 -0
  57. package/hooks/README.md +75 -0
  58. package/hooks/agent_context.py +105 -0
  59. package/hooks/beads-claim-sync.mjs +166 -0
  60. package/hooks/beads-commit-gate.mjs +55 -0
  61. package/hooks/beads-compact-restore.mjs +69 -0
  62. package/hooks/beads-compact-save.mjs +51 -0
  63. package/hooks/beads-edit-gate.mjs +45 -0
  64. package/hooks/beads-gate-core.mjs +215 -0
  65. package/hooks/beads-gate-messages.mjs +87 -0
  66. package/hooks/beads-gate-utils.mjs +185 -0
  67. package/hooks/beads-memory-gate.mjs +61 -0
  68. package/hooks/beads-stop-gate.mjs +32 -0
  69. package/hooks/branch-state.mjs +39 -0
  70. package/hooks/gitnexus/gitnexus-hook.cjs +222 -0
  71. package/hooks/guard-rules.mjs +118 -0
  72. package/hooks/hooks.json +116 -0
  73. package/hooks/main-guard-post-push.mjs +71 -0
  74. package/hooks/main-guard.mjs +119 -0
  75. package/hooks/quality-check.cjs +1286 -0
  76. package/hooks/quality-check.py +345 -0
  77. package/hooks/serena-workflow-reminder.py +74 -0
  78. package/package.json +77 -0
  79. package/project-skills/quality-gates/.claude/hooks/hook-config.json +66 -0
  80. package/project-skills/quality-gates/.claude/hooks/quality-check.cjs +1286 -0
  81. package/project-skills/quality-gates/.claude/hooks/quality-check.py +334 -0
  82. package/project-skills/quality-gates/.claude/settings.json +3 -0
  83. package/project-skills/quality-gates/.claude/skills/using-quality-gates/SKILL.md +254 -0
  84. package/project-skills/quality-gates/README.md +109 -0
  85. package/project-skills/quality-gates/evals/evals.json +181 -0
  86. package/project-skills/quality-gates/workspace/iteration-1/FINAL-EVAL-SUMMARY.md +75 -0
  87. package/project-skills/quality-gates/workspace/iteration-1/edge-case-auto-fix-verification/with_skill/outputs/response.md +59 -0
  88. package/project-skills/quality-gates/workspace/iteration-1/edge-case-mixed-language-project/with_skill/outputs/response.md +60 -0
  89. package/project-skills/quality-gates/workspace/iteration-1/eval-summary.md +105 -0
  90. package/project-skills/quality-gates/workspace/iteration-1/partial-install-python-only/with_skill/outputs/response.md +93 -0
  91. package/project-skills/quality-gates/workspace/iteration-1/python-refactor-request/with_skill/outputs/response.md +104 -0
  92. package/project-skills/quality-gates/workspace/iteration-1/quality-gate-error-fix/with_skill/outputs/response.md +74 -0
  93. package/project-skills/quality-gates/workspace/iteration-1/should-not-trigger-general-chat/with_skill/outputs/response.md +18 -0
  94. package/project-skills/quality-gates/workspace/iteration-1/should-not-trigger-math-question/with_skill/outputs/response.md +18 -0
  95. package/project-skills/quality-gates/workspace/iteration-1/should-not-trigger-unrelated-coding/with_skill/outputs/response.md +56 -0
  96. package/project-skills/quality-gates/workspace/iteration-1/tdd-guard-blocking-confusion/with_skill/outputs/response.md +67 -0
  97. package/project-skills/quality-gates/workspace/iteration-1/typescript-feature-with-tests/with_skill/outputs/response.md +97 -0
  98. package/project-skills/service-skills-set/.claude/git-hooks/doc_reminder.py +67 -0
  99. package/project-skills/service-skills-set/.claude/git-hooks/skill_staleness.py +194 -0
  100. package/project-skills/service-skills-set/.claude/service-registry.json +4 -0
  101. package/project-skills/service-skills-set/.claude/settings.json +37 -0
  102. package/project-skills/service-skills-set/.claude/skills/creating-service-skills/SKILL.md +433 -0
  103. package/project-skills/service-skills-set/.claude/skills/creating-service-skills/references/script_quality_standards.md +425 -0
  104. package/project-skills/service-skills-set/.claude/skills/creating-service-skills/references/service_skill_system_guide.md +278 -0
  105. package/project-skills/service-skills-set/.claude/skills/creating-service-skills/scripts/bootstrap.py +308 -0
  106. package/project-skills/service-skills-set/.claude/skills/creating-service-skills/scripts/deep_dive.py +304 -0
  107. package/project-skills/service-skills-set/.claude/skills/creating-service-skills/scripts/scaffolder.py +482 -0
  108. package/project-skills/service-skills-set/.claude/skills/scoping-service-skills/SKILL.md +231 -0
  109. package/project-skills/service-skills-set/.claude/skills/scoping-service-skills/scripts/scope.py +74 -0
  110. package/project-skills/service-skills-set/.claude/skills/updating-service-skills/SKILL.md +136 -0
  111. package/project-skills/service-skills-set/.claude/skills/updating-service-skills/scripts/drift_detector.py +222 -0
  112. package/project-skills/service-skills-set/.claude/skills/using-service-skills/SKILL.md +108 -0
  113. package/project-skills/service-skills-set/.claude/skills/using-service-skills/scripts/cataloger.py +74 -0
  114. package/project-skills/service-skills-set/.claude/skills/using-service-skills/scripts/skill_activator.py +152 -0
  115. package/project-skills/service-skills-set/README.md +93 -0
  116. package/project-skills/service-skills-set/install-service-skills.py +193 -0
  117. package/project-skills/service-skills-set/service-skills-readme.md +236 -0
  118. package/skills/README.txt +31 -0
  119. package/skills/clean-code/SKILL.md +201 -0
  120. package/skills/creating-service-skills/SKILL.md +433 -0
  121. package/skills/creating-service-skills/references/script_quality_standards.md +425 -0
  122. package/skills/creating-service-skills/references/service_skill_system_guide.md +278 -0
  123. package/skills/creating-service-skills/scripts/bootstrap.py +326 -0
  124. package/skills/creating-service-skills/scripts/deep_dive.py +304 -0
  125. package/skills/creating-service-skills/scripts/scaffolder.py +482 -0
  126. package/skills/delegating/SKILL.md +196 -0
  127. package/skills/delegating/config.yaml +210 -0
  128. package/skills/delegating/references/orchestration-protocols.md +41 -0
  129. package/skills/docker-expert/SKILL.md +409 -0
  130. package/skills/documenting/CHANGELOG.md +23 -0
  131. package/skills/documenting/README.md +148 -0
  132. package/skills/documenting/SKILL.md +113 -0
  133. package/skills/documenting/examples/example_pattern.md +70 -0
  134. package/skills/documenting/examples/example_reference.md +70 -0
  135. package/skills/documenting/examples/example_ssot_analytics.md +64 -0
  136. package/skills/documenting/examples/example_workflow.md +141 -0
  137. package/skills/documenting/references/changelog-format.md +97 -0
  138. package/skills/documenting/references/metadata-schema.md +136 -0
  139. package/skills/documenting/references/taxonomy.md +81 -0
  140. package/skills/documenting/references/versioning-rules.md +78 -0
  141. package/skills/documenting/scripts/bump_version.sh +60 -0
  142. package/skills/documenting/scripts/changelog/__init__.py +0 -0
  143. package/skills/documenting/scripts/changelog/add_entry.py +216 -0
  144. package/skills/documenting/scripts/changelog/bump_release.py +117 -0
  145. package/skills/documenting/scripts/changelog/init_changelog.py +54 -0
  146. package/skills/documenting/scripts/changelog/validate_changelog.py +128 -0
  147. package/skills/documenting/scripts/drift_detector.py +266 -0
  148. package/skills/documenting/scripts/generate_template.py +311 -0
  149. package/skills/documenting/scripts/list_by_category.sh +84 -0
  150. package/skills/documenting/scripts/orchestrator.py +255 -0
  151. package/skills/documenting/scripts/validate_metadata.py +242 -0
  152. package/skills/documenting/templates/CHANGELOG.md.template +13 -0
  153. package/skills/find-skills/SKILL.md +133 -0
  154. package/skills/gitnexus-debugging/SKILL.md +85 -0
  155. package/skills/gitnexus-exploring/SKILL.md +75 -0
  156. package/skills/gitnexus-impact-analysis/SKILL.md +94 -0
  157. package/skills/gitnexus-refactoring/SKILL.md +113 -0
  158. package/skills/hook-development/SKILL.md +797 -0
  159. package/skills/hook-development/examples/load-context.sh +55 -0
  160. package/skills/hook-development/examples/quality-check.js +1168 -0
  161. package/skills/hook-development/examples/validate-bash.sh +43 -0
  162. package/skills/hook-development/examples/validate-write.sh +38 -0
  163. package/skills/hook-development/references/advanced.md +527 -0
  164. package/skills/hook-development/references/migration.md +369 -0
  165. package/skills/hook-development/references/patterns.md +412 -0
  166. package/skills/hook-development/scripts/README.md +164 -0
  167. package/skills/hook-development/scripts/hook-linter.sh +153 -0
  168. package/skills/hook-development/scripts/test-hook.sh +252 -0
  169. package/skills/hook-development/scripts/validate-hook-schema.sh +159 -0
  170. package/skills/obsidian-cli/SKILL.md +106 -0
  171. package/skills/orchestrating-agents/SKILL.md +135 -0
  172. package/skills/orchestrating-agents/config.yaml +45 -0
  173. package/skills/orchestrating-agents/references/agent-context-integration.md +37 -0
  174. package/skills/orchestrating-agents/references/examples.md +45 -0
  175. package/skills/orchestrating-agents/references/handover-protocol.md +31 -0
  176. package/skills/orchestrating-agents/references/workflows.md +42 -0
  177. package/skills/orchestrating-agents/scripts/detect_neighbors.py +23 -0
  178. package/skills/prompt-improving/README.md +162 -0
  179. package/skills/prompt-improving/SKILL.md +74 -0
  180. package/skills/prompt-improving/references/analysis_commands.md +24 -0
  181. package/skills/prompt-improving/references/chain_of_thought.md +24 -0
  182. package/skills/prompt-improving/references/mcp_definitions.md +20 -0
  183. package/skills/prompt-improving/references/multishot.md +23 -0
  184. package/skills/prompt-improving/references/xml_core.md +60 -0
  185. package/skills/python-testing/SKILL.md +815 -0
  186. package/skills/scoping-service-skills/SKILL.md +231 -0
  187. package/skills/scoping-service-skills/scripts/scope.py +74 -0
  188. package/skills/senior-backend/SKILL.md +209 -0
  189. package/skills/senior-backend/references/api_design_patterns.md +103 -0
  190. package/skills/senior-backend/references/backend_security_practices.md +103 -0
  191. package/skills/senior-backend/references/database_optimization_guide.md +103 -0
  192. package/skills/senior-backend/scripts/api_load_tester.py +114 -0
  193. package/skills/senior-backend/scripts/api_scaffolder.py +114 -0
  194. package/skills/senior-backend/scripts/database_migration_tool.py +114 -0
  195. package/skills/senior-data-scientist/SKILL.md +226 -0
  196. package/skills/senior-data-scientist/references/experiment_design_frameworks.md +80 -0
  197. package/skills/senior-data-scientist/references/feature_engineering_patterns.md +80 -0
  198. package/skills/senior-data-scientist/references/statistical_methods_advanced.md +80 -0
  199. package/skills/senior-data-scientist/scripts/experiment_designer.py +100 -0
  200. package/skills/senior-data-scientist/scripts/feature_engineering_pipeline.py +100 -0
  201. package/skills/senior-data-scientist/scripts/model_evaluation_suite.py +100 -0
  202. package/skills/senior-devops/SKILL.md +209 -0
  203. package/skills/senior-devops/references/cicd_pipeline_guide.md +103 -0
  204. package/skills/senior-devops/references/deployment_strategies.md +103 -0
  205. package/skills/senior-devops/references/infrastructure_as_code.md +103 -0
  206. package/skills/senior-devops/scripts/deployment_manager.py +114 -0
  207. package/skills/senior-devops/scripts/pipeline_generator.py +114 -0
  208. package/skills/senior-devops/scripts/terraform_scaffolder.py +114 -0
  209. package/skills/senior-security/SKILL.md +209 -0
  210. package/skills/senior-security/references/cryptography_implementation.md +103 -0
  211. package/skills/senior-security/references/penetration_testing_guide.md +103 -0
  212. package/skills/senior-security/references/security_architecture_patterns.md +103 -0
  213. package/skills/senior-security/scripts/pentest_automator.py +114 -0
  214. package/skills/senior-security/scripts/security_auditor.py +114 -0
  215. package/skills/senior-security/scripts/threat_modeler.py +114 -0
  216. package/skills/skill-creator/LICENSE.txt +202 -0
  217. package/skills/skill-creator/SKILL.md +479 -0
  218. package/skills/skill-creator/agents/analyzer.md +274 -0
  219. package/skills/skill-creator/agents/comparator.md +202 -0
  220. package/skills/skill-creator/agents/grader.md +223 -0
  221. package/skills/skill-creator/assets/eval_review.html +146 -0
  222. package/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  223. package/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  224. package/skills/skill-creator/references/schemas.md +430 -0
  225. package/skills/skill-creator/scripts/__init__.py +0 -0
  226. package/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  227. package/skills/skill-creator/scripts/generate_report.py +326 -0
  228. package/skills/skill-creator/scripts/improve_description.py +248 -0
  229. package/skills/skill-creator/scripts/package_skill.py +136 -0
  230. package/skills/skill-creator/scripts/quick_validate.py +103 -0
  231. package/skills/skill-creator/scripts/run_eval.py +310 -0
  232. package/skills/skill-creator/scripts/run_loop.py +332 -0
  233. package/skills/skill-creator/scripts/utils.py +47 -0
  234. package/skills/sync-docs/SKILL.md +132 -0
  235. package/skills/sync-docs/evals/evals.json +89 -0
  236. package/skills/sync-docs/references/doc-structure.md +99 -0
  237. package/skills/sync-docs/references/schema.md +103 -0
  238. package/skills/sync-docs/scripts/changelog/add_entry.py +216 -0
  239. package/skills/sync-docs/scripts/context_gatherer.py +240 -0
  240. package/skills/sync-docs/scripts/doc_structure_analyzer.py +495 -0
  241. package/skills/sync-docs/scripts/drift_detector.py +327 -0
  242. package/skills/sync-docs/scripts/validate_doc.py +365 -0
  243. package/skills/sync-docs/scripts/validate_metadata.py +185 -0
  244. package/skills/sync-docs-workspace/iteration-1/benchmark.json +293 -0
  245. package/skills/sync-docs-workspace/iteration-1/benchmark.md +13 -0
  246. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/eval_metadata.json +27 -0
  247. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/outputs/result.md +210 -0
  248. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/run-1/grading.json +28 -0
  249. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/run-1/timing.json +1 -0
  250. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/outputs/result.md +101 -0
  251. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/run-1/grading.json +28 -0
  252. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/run-1/timing.json +5 -0
  253. package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/timing.json +5 -0
  254. package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/eval_metadata.json +27 -0
  255. package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/outputs/result.md +198 -0
  256. package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/run-1/grading.json +28 -0
  257. package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/run-1/timing.json +1 -0
  258. package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/outputs/result.md +94 -0
  259. package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/run-1/grading.json +28 -0
  260. package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/run-1/timing.json +1 -0
  261. package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/eval_metadata.json +27 -0
  262. package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/outputs/result.md +237 -0
  263. package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/run-1/grading.json +28 -0
  264. package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/run-1/timing.json +1 -0
  265. package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/outputs/result.md +134 -0
  266. package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/run-1/grading.json +28 -0
  267. package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/run-1/timing.json +1 -0
  268. package/skills/sync-docs-workspace/iteration-2/benchmark.json +297 -0
  269. package/skills/sync-docs-workspace/iteration-2/benchmark.md +13 -0
  270. package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/eval_metadata.json +27 -0
  271. package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/outputs/result.md +137 -0
  272. package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/run-1/grading.json +92 -0
  273. package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/run-1/timing.json +1 -0
  274. package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/outputs/result.md +134 -0
  275. package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/run-1/grading.json +86 -0
  276. package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/run-1/timing.json +1 -0
  277. package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/eval_metadata.json +27 -0
  278. package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/outputs/result.md +193 -0
  279. package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/run-1/grading.json +72 -0
  280. package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/run-1/timing.json +1 -0
  281. package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/outputs/result.md +211 -0
  282. package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/run-1/grading.json +91 -0
  283. package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/run-1/timing.json +5 -0
  284. package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/eval_metadata.json +27 -0
  285. package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/outputs/result.md +182 -0
  286. package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/run-1/grading.json +95 -0
  287. package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/run-1/timing.json +1 -0
  288. package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/outputs/result.md +222 -0
  289. package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/run-1/grading.json +88 -0
  290. package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/run-1/timing.json +5 -0
  291. package/skills/sync-docs-workspace/iteration-3/benchmark.json +298 -0
  292. package/skills/sync-docs-workspace/iteration-3/benchmark.md +13 -0
  293. package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/eval_metadata.json +27 -0
  294. package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/outputs/result.md +125 -0
  295. package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/run-1/grading.json +97 -0
  296. package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/run-1/timing.json +5 -0
  297. package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/outputs/result.md +144 -0
  298. package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/run-1/grading.json +78 -0
  299. package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/run-1/timing.json +5 -0
  300. package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/eval_metadata.json +27 -0
  301. package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/outputs/result.md +104 -0
  302. package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/run-1/grading.json +91 -0
  303. package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/run-1/timing.json +5 -0
  304. package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/outputs/result.md +79 -0
  305. package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/run-1/grading.json +82 -0
  306. package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/run-1/timing.json +5 -0
  307. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/eval_metadata.json +27 -0
  308. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase1_context.json +302 -0
  309. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase2_drift.txt +33 -0
  310. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase3_analysis.json +114 -0
  311. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase4_fix.txt +118 -0
  312. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase5_validate.txt +38 -0
  313. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/result.md +158 -0
  314. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/run-1/grading.json +95 -0
  315. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/run-1/timing.json +5 -0
  316. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/outputs/result.md +71 -0
  317. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/run-1/grading.json +90 -0
  318. package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/run-1/timing.json +5 -0
  319. package/skills/test-planning/SKILL.md +208 -0
  320. package/skills/test-planning/evals/evals.json +23 -0
  321. package/skills/updating-service-skills/SKILL.md +136 -0
  322. package/skills/updating-service-skills/scripts/drift_detector.py +222 -0
  323. package/skills/using-TDD/SKILL.md +410 -0
  324. package/skills/using-quality-gates/SKILL.md +254 -0
  325. package/skills/using-serena-lsp/README.md +8 -0
  326. package/skills/using-serena-lsp/REFERENCE.md +194 -0
  327. package/skills/using-serena-lsp/SKILL.md +82 -0
  328. package/skills/using-service-skills/SKILL.md +108 -0
  329. package/skills/using-service-skills/scripts/cataloger.py +74 -0
  330. package/skills/using-service-skills/scripts/skill_activator.py +152 -0
  331. package/skills/using-service-skills/scripts/test_skill_activator.py +58 -0
  332. package/skills/using-xtrm/SKILL.md +245 -0
  333. package/skills/xt-end/SKILL.md +128 -0
@@ -0,0 +1,75 @@
1
+ # Hooks
2
+
3
+ Claude Code hooks that extend agent behavior with automated checks, workflow enhancements, and safety guardrails.
4
+
5
+ ## Overview
6
+
7
+ Hooks intercept specific events in the Claude Code lifecycle. Following architecture decisions in v2.0.0+, the hook ecosystem is designed exclusively for Claude Code.
8
+
9
+ *Note: In v2.1.15+, several older hooks (`skill-suggestion.py`, `skill-discovery.py`, `gitnexus-impact-reminder.py`, and `type-safety-enforcement.py`) were removed or superseded by native capabilities, CLI commands, and consolidated quality gates.*
10
+
11
+ ## Project Hooks
12
+
13
+ ### main-guard.mjs
14
+
15
+ **Purpose**: Enforces PR-only merge workflow with full git protection. Blocks direct commits and dangerous `git checkout`, `git reset`, and file writes via Bash on protected branches (`main`/`master`).
16
+
17
+ **Trigger**: PreToolUse (Write|Edit|MultiEdit|Serena edit tools|Bash)
18
+
19
+ **Configuration**: Installed automatically to protect the main branch from unreviewed changes.
20
+
21
+ ### main-guard-post-push.mjs
22
+
23
+ **Purpose**: Workflow enforcement. After pushing a feature branch, reminds to open a PR, merge using `gh pr merge --squash`, and sync local via `git reset --hard origin/main`.
24
+
25
+ **Trigger**: PostToolUse (Bash: git push)
26
+
27
+ ### gitnexus-hook.cjs
28
+
29
+ **Purpose**: Enriches tool calls with knowledge graph context via `gitnexus augment`. Now supports Serena tools and uses a deduplication cache for efficiency.
30
+
31
+ **Trigger**: PostToolUse (Grep|Glob|Bash|Serena edit tools)
32
+
33
+ ## Beads Issue Tracking Gates
34
+
35
+ The beads gate hooks integrate the `bd` (beads) issue tracker directly into Claude's workflow, ensuring no code changes happen without an active ticket.
36
+
37
+ **Installation**: Installed with `xtrm install all` or included when `beads`+`dolt` is available.
38
+
39
+ ### Core Gates
40
+ - **`beads-edit-gate.mjs`** (PreToolUse) — Blocks writes/edits without an active issue claim.
41
+ - **`beads-commit-gate.mjs`** (PreToolUse) — Blocks commits with an unresolved session claim.
42
+ - **`beads-stop-gate.mjs`** (Stop) — Blocks session stop while a claim remains open.
43
+ - **`beads-close-memory-prompt.mjs`** (PostToolUse) — Prompts memory handoff after `bd close`.
44
+
45
+ ### Compaction & State Preservation (v2.1.18+)
46
+ - **`beads-pre-compact.mjs`** (PreCompact) — Saves the currently `in_progress` beads state before Claude clears context.
47
+ - **`beads-session-start.mjs`** (SessionStart) — Restores the `in_progress` state when the session restarts after compaction.
48
+
49
+ *Note: As of v2.1.18+, hook blocking messages are quieted and compacted to save tokens.*
50
+
51
+ ## Hook Timeouts
52
+
53
+ Adjust hook execution timeouts in `settings.json` if commands take longer than expected:
54
+
55
+ ```json
56
+ {
57
+ "hooks": {
58
+ "PostToolUse": [{
59
+ "hooks": [{
60
+ "timeout": 5000 // Timeout in milliseconds (5000ms = 5 seconds)
61
+ }]
62
+ }]
63
+ }
64
+ }
65
+ ```
66
+
67
+ ## Creating Custom Hooks
68
+
69
+ To create new project-specific hooks, use the `hook-development` global skill. Follow the canonical structure defined in the `xtrm-tools` core libraries.
70
+
71
+ For debugging orphaned hooks, use `xtrm clean`.
72
+
73
+ ## Pi Extensions Migration
74
+
75
+ Core workflow hooks have been migrated to native Pi Extensions for better performance and integration. See the [Pi Extensions Migration Guide](../docs/pi-extensions-migration.md) for details.
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env python3
2
+ import json
3
+ import sys
4
+ import os
5
+
6
+ class AgentContext:
7
+ def __init__(self):
8
+ try:
9
+ # Read JSON from stdin once
10
+ self.data = json.load(sys.stdin)
11
+ except Exception:
12
+ self.data = {}
13
+
14
+ self.tool_name = self.data.get('tool_name')
15
+ self.tool_input = self.data.get('tool_input', {})
16
+ self.event = self.data.get('hook_event_name')
17
+ self.prompt = self.data.get('prompt', '')
18
+
19
+ # Determine Agent Type
20
+ if self.tool_name in ['run_shell_command', 'read_file', 'write_file', 'replace']:
21
+ self.agent_type = 'gemini'
22
+ elif self.tool_name in ['Bash', 'Read', 'Write', 'Edit', 'Glob', 'Grep']:
23
+ self.agent_type = 'claude'
24
+ else:
25
+ # Fallback based on env vars
26
+ if os.environ.get('GEMINI_PROJECT_DIR'):
27
+ self.agent_type = 'gemini'
28
+ else:
29
+ self.agent_type = 'claude'
30
+
31
+ def is_shell_tool(self):
32
+ return self.tool_name in ['Bash', 'run_shell_command']
33
+
34
+ def is_write_tool(self):
35
+ return self.tool_name in ['Write', 'write_file']
36
+
37
+ def is_edit_tool(self):
38
+ return self.tool_name in ['Edit', 'replace']
39
+
40
+ def get_command(self):
41
+ return self.tool_input.get('command', '')
42
+
43
+ def get_file_path(self):
44
+ return self.tool_input.get('file_path', '')
45
+
46
+ def block(self, reason, system_message=None):
47
+ """Unified block response.
48
+
49
+ Only PreToolUse hooks support permissionDecision: deny.
50
+ For other hooks, use continue: false to block execution.
51
+ """
52
+ output = {}
53
+
54
+ if system_message:
55
+ output["systemMessage"] = system_message
56
+
57
+ # Only PreToolUse hooks support permissionDecision
58
+ if self.event == "PreToolUse":
59
+ output["hookSpecificOutput"] = {
60
+ "hookEventName": self.event,
61
+ "permissionDecision": "deny",
62
+ "permissionDecisionReason": reason
63
+ }
64
+ else:
65
+ # For non-PreToolUse hooks, use continue: false to block
66
+ output["continue"] = False
67
+ output["stopReason"] = reason
68
+
69
+ print(json.dumps(output))
70
+ sys.exit(0)
71
+
72
+ def allow(self, system_message=None, additional_context=None):
73
+ """Unified allow response.
74
+
75
+ For PreToolUse hooks: outputs permissionDecision in hookSpecificOutput
76
+ For other hooks (UserPromptSubmit, SessionStart, PostToolUse):
77
+ only systemMessage and/or additionalContext are valid
78
+ """
79
+ output = {}
80
+
81
+ if system_message:
82
+ output["systemMessage"] = system_message
83
+
84
+ # Build hookSpecificOutput if we have PreToolUse or additionalContext
85
+ if self.event == "PreToolUse" or additional_context:
86
+ hook_output = {"hookEventName": self.event}
87
+
88
+ # Only PreToolUse supports permissionDecision
89
+ if self.event == "PreToolUse":
90
+ hook_output["permissionDecision"] = "allow"
91
+
92
+ if additional_context:
93
+ hook_output["additionalContext"] = additional_context
94
+
95
+ output["hookSpecificOutput"] = hook_output
96
+
97
+ # Only print output if we have something to say
98
+ if output:
99
+ print(json.dumps(output))
100
+
101
+ sys.exit(0)
102
+
103
+ def fail_open(self):
104
+ """Standard fail-open behavior"""
105
+ sys.exit(0)
@@ -0,0 +1,166 @@
1
+ #!/usr/bin/env node
2
+ // beads-claim-sync — PostToolUse hook
3
+ // bd update --claim → set kv claim
4
+ // bd close → auto-commit staged changes, set closed-this-session kv for memory gate
5
+
6
+ import { spawnSync } from 'node:child_process';
7
+ import { readFileSync, existsSync } from 'node:fs';
8
+ import { join } from 'node:path';
9
+ import { resolveSessionId } from './beads-gate-utils.mjs';
10
+
11
+ function readInput() {
12
+ try {
13
+ return JSON.parse(readFileSync(0, 'utf-8'));
14
+ } catch {
15
+ return null;
16
+ }
17
+ }
18
+
19
+ function isBeadsProject(cwd) {
20
+ return existsSync(join(cwd, '.beads'));
21
+ }
22
+
23
+ function isShellTool(toolName) {
24
+ return toolName === 'Bash' || toolName === 'bash' || toolName === 'execute_shell_command';
25
+ }
26
+
27
+ function commandSucceeded(payload) {
28
+ const tr = payload?.tool_response ?? payload?.tool_result ?? payload?.result;
29
+ if (!tr || typeof tr !== 'object') return true;
30
+
31
+ if (tr.success === false) return false;
32
+ if (tr.error) return false;
33
+
34
+ const numeric = [tr.exit_code, tr.exitCode, tr.status, tr.returncode].find((v) => Number.isInteger(v));
35
+ if (typeof numeric === 'number' && numeric !== 0) return false;
36
+
37
+ return true;
38
+ }
39
+
40
+ function runGit(args, cwd, timeout = 8000) {
41
+ return spawnSync('git', args, {
42
+ cwd,
43
+ stdio: ['pipe', 'pipe', 'pipe'],
44
+ encoding: 'utf8',
45
+ timeout,
46
+ });
47
+ }
48
+
49
+ function runBd(args, cwd, timeout = 5000) {
50
+ return spawnSync('bd', args, {
51
+ cwd,
52
+ stdio: ['pipe', 'pipe', 'pipe'],
53
+ encoding: 'utf8',
54
+ timeout,
55
+ });
56
+ }
57
+
58
+ function hasGitChanges(cwd) {
59
+ const result = runGit(['status', '--porcelain'], cwd);
60
+ if (result.status !== 0) return false;
61
+ return result.stdout.trim().length > 0;
62
+ }
63
+
64
+ function getCloseReason(cwd, issueId, command) {
65
+ // 1. Parse --reason "..." from the command itself (fastest, no extra call)
66
+ const reasonMatch = command.match(/--reason[=\s]+["']([^"']+)["']/);
67
+ if (reasonMatch) return reasonMatch[1].trim();
68
+
69
+ // 2. Fall back to bd show <id> --json
70
+ const show = runBd(['show', issueId, '--json'], cwd);
71
+ if (show.status === 0 && show.stdout) {
72
+ try {
73
+ const parsed = JSON.parse(show.stdout);
74
+ const reason = parsed?.[0]?.close_reason;
75
+ if (typeof reason === 'string' && reason.trim().length > 0) return reason.trim();
76
+ } catch { /* fall through */ }
77
+ }
78
+
79
+ return `Close ${issueId}`;
80
+ }
81
+
82
+ function autoCommit(cwd, issueId, command) {
83
+ if (!hasGitChanges(cwd)) {
84
+ return { ok: true, message: 'No changes detected — auto-commit skipped.' };
85
+ }
86
+
87
+ const reason = getCloseReason(cwd, issueId, command);
88
+ const commitMessage = `${reason} (${issueId})`;
89
+ const result = runGit(['commit', '-am', commitMessage], cwd, 15000);
90
+ if (result.status !== 0) {
91
+ const err = (result.stderr || result.stdout || '').trim();
92
+ return { ok: false, message: `Auto-commit failed: ${err || 'unknown error'}` };
93
+ }
94
+
95
+ return { ok: true, message: `Auto-committed: \`${commitMessage}\`` };
96
+ }
97
+
98
+
99
+ function main() {
100
+ const input = readInput();
101
+ if (!input || input.hook_event_name !== 'PostToolUse') process.exit(0);
102
+ if (!isShellTool(input.tool_name)) process.exit(0);
103
+
104
+ const cwd = input.cwd || process.cwd();
105
+ if (!isBeadsProject(cwd)) process.exit(0);
106
+
107
+ const command = input.tool_input?.command || '';
108
+ const sessionId = resolveSessionId(input);
109
+
110
+ // Auto-claim: bd update <id> --claim (fire regardless of exit code — bd returns 1 for "already in_progress")
111
+ if (/\bbd\s+update\b/.test(command) && /--claim\b/.test(command)) {
112
+ const match = command.match(/\bbd\s+update\s+(\S+)/);
113
+ if (match) {
114
+ const issueId = match[1];
115
+ const result = spawnSync('bd', ['kv', 'set', `claimed:${sessionId}`, issueId], {
116
+ cwd,
117
+ stdio: ['pipe', 'pipe', 'pipe'],
118
+ timeout: 5000,
119
+ });
120
+
121
+ if (result.status !== 0) {
122
+ const err = (result.stderr || result.stdout || '').toString().trim();
123
+ if (err) process.stderr.write(`Beads claim sync warning: ${err}\n`);
124
+ process.exit(0);
125
+ }
126
+
127
+ process.stdout.write(JSON.stringify({
128
+ additionalContext: `\n✅ **Beads**: Session \`${sessionId}\` claimed issue \`${issueId}\`.`,
129
+ }));
130
+ process.stdout.write('\n');
131
+ process.exit(0);
132
+ }
133
+ }
134
+
135
+ // On bd close: auto-commit staged changes, then mark closed-this-session for memory gate
136
+ if (/\bbd\s+close\b/.test(command) && commandSucceeded(input)) {
137
+ const match = command.match(/\bbd\s+close\s+(\S+)/);
138
+ const closedIssueId = match?.[1];
139
+
140
+ // Auto-commit before marking the gate (no-op if clean)
141
+ const commit = closedIssueId ? autoCommit(cwd, closedIssueId, command) : null;
142
+
143
+ // Mark this issue as closed this session (memory gate reads this)
144
+ if (closedIssueId) {
145
+ spawnSync('bd', ['kv', 'set', `closed-this-session:${sessionId}`, closedIssueId], {
146
+ cwd,
147
+ stdio: ['pipe', 'pipe', 'pipe'],
148
+ timeout: 5000,
149
+ });
150
+ }
151
+
152
+ const commitLine = commit
153
+ ? `\n${commit.ok ? '✅' : '⚠️'} **Session Flow**: ${commit.message}`
154
+ : '';
155
+
156
+ process.stdout.write(JSON.stringify({
157
+ additionalContext: `\n🔓 **Beads**: Issue closed.${commitLine}\nEvaluate insights, then acknowledge:\n \`bd remember "<insight>"\` (or note "nothing")\n \`touch .beads/.memory-gate-done\``,
158
+ }));
159
+ process.stdout.write('\n');
160
+ process.exit(0);
161
+ }
162
+
163
+ process.exit(0);
164
+ }
165
+
166
+ main();
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+ // beads-commit-gate — Claude Code PreToolUse hook
3
+ // Blocks `git commit` when this session still has an unclosed claim in bd kv.
4
+ // Falls back to global in_progress check when session_id is unavailable.
5
+ // Forces: close issues first, THEN commit.
6
+ // Exit 0: allow | Exit 2: block (stderr shown to Claude)
7
+ //
8
+ // Installed by: xtrm install
9
+
10
+ import {
11
+ readHookInput,
12
+ resolveSessionContext,
13
+ resolveClaimAndWorkState,
14
+ decideCommitGate,
15
+ } from './beads-gate-core.mjs';
16
+ import { withSafeBdContext, isMemoryGatePending, isMemoryAckCommand } from './beads-gate-utils.mjs';
17
+ import { commitBlockMessage, memoryGatePendingMessage } from './beads-gate-messages.mjs';
18
+
19
+ const input = readHookInput();
20
+ if (!input) process.exit(0);
21
+
22
+ if ((input.tool_name ?? '') !== 'Bash') process.exit(0);
23
+
24
+ const command = input.tool_input?.command ?? '';
25
+ // Strip quoted strings to avoid matching patterns inside --reason "..." or similar args
26
+ const commandUnquoted = command.replace(/'[^']*'|"[^"]*"/g, '');
27
+
28
+ withSafeBdContext(() => {
29
+ const ctx = resolveSessionContext(input);
30
+ if (!ctx || !ctx.isBeadsProject) process.exit(0);
31
+
32
+ // Memory gate: block all Bash except acknowledgment commands while gate pending
33
+ if (ctx.sessionId && isMemoryGatePending(ctx.sessionId, ctx.cwd)) {
34
+ if (!isMemoryAckCommand(commandUnquoted)) {
35
+ process.stdout.write(JSON.stringify({ decision: 'block', reason: memoryGatePendingMessage() }));
36
+ process.stdout.write('\n');
37
+ process.exit(0);
38
+ }
39
+ process.exit(0); // memory-ack command — allow
40
+ }
41
+
42
+ // Only intercept git commit for the claim-gate check
43
+ if (!/\bgit\s+commit\b/.test(commandUnquoted)) process.exit(0);
44
+
45
+ const state = resolveClaimAndWorkState(ctx);
46
+ const decision = decideCommitGate(ctx, state);
47
+
48
+ if (decision.allow) process.exit(0);
49
+
50
+ // Block with structured decision
51
+ const reason = commitBlockMessage(decision.summary, decision.claimed);
52
+ process.stdout.write(JSON.stringify({ decision: 'block', reason }));
53
+ process.stdout.write('\n');
54
+ process.exit(0);
55
+ });
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+ // Claude Code SessionStart hook — restore in_progress beads issues after context compaction.
3
+ // Reads .beads/.last_active (written by beads-compact-save.mjs), reinstates statuses,
4
+ // restores session state file, deletes the marker, and injects a brief agent context message.
5
+ // Exit 0 in all paths (informational only).
6
+
7
+ import { execSync } from 'node:child_process';
8
+ import { readFileSync, existsSync, unlinkSync } from 'node:fs';
9
+ import path from 'node:path';
10
+
11
+ let input;
12
+ try {
13
+ input = JSON.parse(readFileSync(0, 'utf8'));
14
+ } catch {
15
+ process.exit(0);
16
+ }
17
+
18
+ const cwd = input.cwd ?? process.env.CLAUDE_PROJECT_DIR ?? process.cwd();
19
+ const lastActivePath = path.join(cwd, '.beads', '.last_active');
20
+
21
+ if (!existsSync(lastActivePath)) process.exit(0);
22
+
23
+ let ids = [];
24
+
25
+ try {
26
+ const raw = readFileSync(lastActivePath, 'utf8').trim();
27
+ if (raw.startsWith('{')) {
28
+ const parsed = JSON.parse(raw);
29
+ ids = Array.isArray(parsed.ids) ? parsed.ids.filter(Boolean) : [];
30
+ } else {
31
+ // Backward compatibility: legacy newline format
32
+ ids = raw.split('\n').filter(Boolean);
33
+ }
34
+ } catch {
35
+ // If file is malformed, just delete and continue fail-open.
36
+ }
37
+
38
+ // Clean up regardless of whether restore succeeds
39
+ unlinkSync(lastActivePath);
40
+
41
+ let restored = 0;
42
+ for (const id of ids) {
43
+ try {
44
+ execSync(`bd update ${id} --status in_progress`, {
45
+ encoding: 'utf8',
46
+ cwd,
47
+ stdio: ['pipe', 'pipe', 'pipe'],
48
+ timeout: 5000,
49
+ });
50
+ restored++;
51
+ } catch {
52
+ // ignore — issue may no longer exist
53
+ }
54
+ }
55
+
56
+ if (restored > 0) {
57
+ const lines = [`Restored ${restored} in_progress issue${restored === 1 ? '' : 's'} from last session before compaction.`];
58
+
59
+ process.stdout.write(
60
+ JSON.stringify({
61
+ hookSpecificOutput: {
62
+ hookEventName: 'SessionStart',
63
+ additionalSystemPrompt: `${lines.join(' ')} Check \`bd list\` for details.`,
64
+ },
65
+ }) + '\n',
66
+ );
67
+ }
68
+
69
+ process.exit(0);
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env node
2
+ // Claude Code PreCompact hook — save in_progress beads issues before context is compacted.
3
+ // Writes a compact bundle to .beads/.last_active for restore hook.
4
+ // Bundle includes issue IDs and xtrm session state when available.
5
+ // Exit 0 in all paths (informational only).
6
+
7
+ import { execSync } from 'node:child_process';
8
+ import { readFileSync, writeFileSync, existsSync } from 'node:fs';
9
+ import path from 'node:path';
10
+
11
+ let input;
12
+ try {
13
+ input = JSON.parse(readFileSync(0, 'utf8'));
14
+ } catch {
15
+ process.exit(0);
16
+ }
17
+
18
+ const cwd = input.cwd ?? process.env.CLAUDE_PROJECT_DIR ?? process.cwd();
19
+ const beadsDir = path.join(cwd, '.beads');
20
+
21
+ if (!existsSync(beadsDir)) process.exit(0);
22
+
23
+ let output = '';
24
+ try {
25
+ output = execSync('bd list --status=in_progress', {
26
+ encoding: 'utf8',
27
+ cwd,
28
+ stdio: ['pipe', 'pipe', 'pipe'],
29
+ timeout: 8000,
30
+ }).trim();
31
+ } catch {
32
+ process.exit(0);
33
+ }
34
+
35
+ // Parse issue IDs — lines like "◐ proj-abc123 ● P1 Title"
36
+ const ids = [];
37
+ for (const line of output.split('\n')) {
38
+ const match = line.trim().match(/^[○◐●✓❄]\s+([\w-]+)\s/u);
39
+ if (match) ids.push(match[1]);
40
+ }
41
+
42
+ const bundle = {
43
+ ids,
44
+ savedAt: new Date().toISOString(),
45
+ };
46
+
47
+ if (bundle.ids.length === 0) process.exit(0);
48
+
49
+ writeFileSync(path.join(beadsDir, '.last_active'), JSON.stringify(bundle, null, 2) + '\n', 'utf8');
50
+
51
+ process.exit(0);
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+ // beads-edit-gate — Claude Code PreToolUse hook
3
+ // Blocks file edits when this session has not claimed a beads issue via bd kv.
4
+ // Falls back to global in_progress check when session_id is unavailable.
5
+ // Only active in projects with a .beads/ directory.
6
+ // Exit 0: allow | Exit 2: block (stderr shown to Claude)
7
+ //
8
+ // Installed by: xtrm install
9
+
10
+ import {
11
+ readHookInput,
12
+ resolveSessionContext,
13
+ resolveClaimAndWorkState,
14
+ decideEditGate,
15
+ } from './beads-gate-core.mjs';
16
+ import { withSafeBdContext, isMemoryGatePending } from './beads-gate-utils.mjs';
17
+ import { editBlockMessage, editBlockFallbackMessage, memoryGatePendingMessage } from './beads-gate-messages.mjs';
18
+
19
+ const input = readHookInput();
20
+ if (!input) process.exit(0);
21
+
22
+ withSafeBdContext(() => {
23
+ const ctx = resolveSessionContext(input);
24
+ if (!ctx || !ctx.isBeadsProject) process.exit(0);
25
+
26
+ // Memory gate takes priority: block edits while pending acknowledgment
27
+ if (ctx.sessionId && isMemoryGatePending(ctx.sessionId, ctx.cwd)) {
28
+ process.stdout.write(JSON.stringify({ decision: 'block', reason: memoryGatePendingMessage() }));
29
+ process.stdout.write('\n');
30
+ process.exit(0);
31
+ }
32
+
33
+ const state = resolveClaimAndWorkState(ctx);
34
+ const decision = decideEditGate(ctx, state);
35
+
36
+ if (decision.allow) process.exit(0);
37
+
38
+ // Block with appropriate message
39
+ const reason = decision.reason === 'no_claim_with_work'
40
+ ? editBlockMessage(decision.sessionId)
41
+ : editBlockFallbackMessage();
42
+ process.stdout.write(JSON.stringify({ decision: 'block', reason }));
43
+ process.stdout.write('\n');
44
+ process.exit(0);
45
+ });