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,222 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * GitNexus Claude Code Hook — PostToolUse enrichment
4
+ *
5
+ * Fires AFTER Read/Grep/Glob/Bash/Serena tools complete.
6
+ * Extracts patterns from both tool input AND output, runs
7
+ * `gitnexus augment <pattern>`, and injects a [GitNexus: ...]
8
+ * block into Claude's context — mirroring pi-gitnexus behavior.
9
+ *
10
+ * Features:
11
+ * - PostToolUse (vs old PreToolUse) — enriches actual result
12
+ * - Session-keyed dedup cache (/tmp) — no redundant lookups
13
+ * - Pattern extraction from output content (grep-style scanning)
14
+ * - Serena tool support — extracts symbol names from name_path
15
+ * - Graceful failure — always exits 0
16
+ */
17
+
18
+ 'use strict';
19
+
20
+ const fs = require('fs');
21
+ const path = require('path');
22
+ const os = require('os');
23
+ const { spawnSync } = require('child_process');
24
+
25
+ const CODE_EXTS = new Set([
26
+ '.ts', '.tsx', '.js', '.mjs', '.cjs', '.py', '.go', '.rs',
27
+ '.java', '.kt', '.cpp', '.c', '.h', '.rb', '.php', '.cs',
28
+ ]);
29
+
30
+ const SERENA_SYMBOL_TOOLS = new Set([
31
+ 'mcp__serena__find_symbol',
32
+ 'mcp__serena__find_referencing_symbols',
33
+ 'mcp__serena__replace_symbol_body',
34
+ 'mcp__serena__insert_after_symbol',
35
+ 'mcp__serena__insert_before_symbol',
36
+ ]);
37
+
38
+ const SERENA_FILE_TOOLS = new Set([
39
+ 'mcp__serena__get_symbols_overview',
40
+ 'mcp__serena__search_for_pattern',
41
+ ]);
42
+
43
+ const SERENA_RENAME = 'mcp__serena__rename_symbol';
44
+
45
+ function readInput() {
46
+ try {
47
+ return JSON.parse(fs.readFileSync(0, 'utf-8'));
48
+ } catch {
49
+ return {};
50
+ }
51
+ }
52
+
53
+ function findGitNexusIndex(startDir) {
54
+ let dir = startDir || process.cwd();
55
+ for (let i = 0; i < 6; i++) {
56
+ if (fs.existsSync(path.join(dir, '.gitnexus'))) return true;
57
+ const parent = path.dirname(dir);
58
+ if (parent === dir) break;
59
+ dir = parent;
60
+ }
61
+ return false;
62
+ }
63
+
64
+ function getCacheFile(sessionId) {
65
+ const id = sessionId ? sessionId.replace(/[^a-zA-Z0-9_-]/g, '_') : 'default';
66
+ return path.join(os.tmpdir(), `gitnexus-aug-${id}`);
67
+ }
68
+
69
+ function loadCache(cacheFile) {
70
+ try {
71
+ return new Set(fs.readFileSync(cacheFile, 'utf-8').split('\n').filter(Boolean));
72
+ } catch {
73
+ return new Set();
74
+ }
75
+ }
76
+
77
+ function saveToCache(cacheFile, pattern) {
78
+ try {
79
+ fs.appendFileSync(cacheFile, pattern + '\n');
80
+ } catch { /* graceful */ }
81
+ }
82
+
83
+ function symbolFromNamePath(namePath) {
84
+ if (!namePath) return null;
85
+ const parts = namePath.split('/').filter(Boolean);
86
+ const last = parts[parts.length - 1];
87
+ return last ? last.replace(/\[\d+\]$/, '') : null;
88
+ }
89
+
90
+ function symbolFromFilePath(filePath) {
91
+ if (!filePath) return null;
92
+ const ext = path.extname(filePath);
93
+ if (!CODE_EXTS.has(ext)) return null;
94
+ return path.basename(filePath, ext);
95
+ }
96
+
97
+ function extractFilePatternsFromOutput(content) {
98
+ if (!content || typeof content !== 'string') return [];
99
+ const patterns = new Set();
100
+ const lines = content.split('\n').slice(0, 50);
101
+ for (const line of lines) {
102
+ const m = line.match(/^([^\s:]+\.[a-z]{1,5}):\d+:/);
103
+ if (m) {
104
+ const ext = path.extname(m[1]);
105
+ if (CODE_EXTS.has(ext)) patterns.add(path.basename(m[1], ext));
106
+ }
107
+ }
108
+ return [...patterns];
109
+ }
110
+
111
+ function extractPatterns(toolName, toolInput, toolResponse) {
112
+ const patterns = [];
113
+ const content = typeof toolResponse === 'string'
114
+ ? toolResponse
115
+ : (toolResponse?.content ?? toolResponse?.output ?? '');
116
+
117
+ if (toolName === 'Read') {
118
+ const sym = symbolFromFilePath(toolInput.file_path);
119
+ if (sym) patterns.push(sym);
120
+ }
121
+
122
+ if (toolName === 'Grep') {
123
+ const raw = toolInput.pattern || '';
124
+ const cleaned = raw.replace(/[.*+?^${}()|[\]\\]/g, '').trim();
125
+ if (cleaned.length >= 3) patterns.push(cleaned);
126
+ patterns.push(...extractFilePatternsFromOutput(content));
127
+ }
128
+
129
+ if (toolName === 'Glob') {
130
+ const raw = toolInput.pattern || '';
131
+ const m = raw.match(/([a-zA-Z][a-zA-Z0-9_-]{2,})/);
132
+ if (m) patterns.push(m[1]);
133
+ patterns.push(...extractFilePatternsFromOutput(
134
+ Array.isArray(toolResponse) ? toolResponse.join('\n') : String(toolResponse || '')
135
+ ));
136
+ }
137
+
138
+ if (toolName === 'Bash') {
139
+ const cmd = toolInput.command || '';
140
+ if (!/\brg\b|\bgrep\b/.test(cmd)) return [];
141
+ const tokens = cmd.split(/\s+/);
142
+ let foundCmd = false, skipNext = false;
143
+ const flagsWithValues = new Set(['-e','-f','-m','-A','-B','-C','-g','--glob','-t','--type','--include','--exclude']);
144
+ for (const token of tokens) {
145
+ if (skipNext) { skipNext = false; continue; }
146
+ if (!foundCmd) { if (/\brg$|\bgrep$/.test(token)) foundCmd = true; continue; }
147
+ if (token.startsWith('-')) { if (flagsWithValues.has(token)) skipNext = true; continue; }
148
+ const cleaned = token.replace(/['"]/g, '').replace(/[.*+?^${}()|[\]\\]/g, '').trim();
149
+ if (cleaned.length >= 3) { patterns.push(cleaned); break; }
150
+ }
151
+ patterns.push(...extractFilePatternsFromOutput(content));
152
+ }
153
+
154
+ if (SERENA_SYMBOL_TOOLS.has(toolName)) {
155
+ const sym = symbolFromNamePath(toolInput.name_path_pattern || toolInput.name_path);
156
+ if (sym) patterns.push(sym);
157
+ }
158
+
159
+ if (toolName === SERENA_RENAME) {
160
+ if (toolInput.symbol_name) patterns.push(toolInput.symbol_name);
161
+ }
162
+
163
+ if (SERENA_FILE_TOOLS.has(toolName)) {
164
+ const sym = symbolFromFilePath(toolInput.relative_path || toolInput.file_path);
165
+ if (sym) patterns.push(sym);
166
+ const sub = toolInput.substring || toolInput.pattern || '';
167
+ const cleaned = sub.replace(/[.*+?^${}()|[\]\\]/g, '').trim();
168
+ if (cleaned.length >= 3) patterns.push(cleaned);
169
+ }
170
+
171
+ return [...new Set(patterns.filter(p => p && p.length >= 3))];
172
+ }
173
+
174
+ function runAugment(pattern, cwd) {
175
+ try {
176
+ const child = spawnSync('gitnexus', ['augment', pattern], {
177
+ encoding: 'utf-8',
178
+ timeout: 8000,
179
+ cwd,
180
+ stdio: ['pipe', 'pipe', 'pipe'],
181
+ });
182
+ return (child.stderr || '').trim();
183
+ } catch {
184
+ return '';
185
+ }
186
+ }
187
+
188
+ function main() {
189
+ try {
190
+ const input = readInput();
191
+ if (input.hook_event_name !== 'PostToolUse') return;
192
+
193
+ const cwd = input.cwd || process.cwd();
194
+ if (!findGitNexusIndex(cwd)) return;
195
+
196
+ const toolName = input.tool_name || '';
197
+ const toolInput = input.tool_input || {};
198
+ const toolResponse = input.tool_response ?? input.tool_result ?? '';
199
+
200
+ const patterns = extractPatterns(toolName, toolInput, toolResponse);
201
+ if (patterns.length === 0) return;
202
+
203
+ const cacheFile = getCacheFile(input.session_id);
204
+ const cache = loadCache(cacheFile);
205
+
206
+ const results = [];
207
+ for (const pattern of patterns) {
208
+ if (cache.has(pattern)) continue;
209
+ const out = runAugment(pattern, cwd);
210
+ saveToCache(cacheFile, pattern);
211
+ if (out) results.push(out);
212
+ }
213
+
214
+ if (results.length > 0) {
215
+ process.stdout.write('[GitNexus]\n' + results.join('\n\n') + '\n');
216
+ }
217
+ } catch (err) {
218
+ process.stderr.write('GitNexus hook error: ' + err.message + '\n');
219
+ }
220
+ }
221
+
222
+ main();
@@ -0,0 +1,118 @@
1
+ // Canonical guard rule definitions shared across hooks, policies, and extensions.
2
+ // Pure data module: named exports only.
3
+
4
+ export const WRITE_TOOLS = [
5
+ 'Edit',
6
+ 'Write',
7
+ 'MultiEdit',
8
+ 'NotebookEdit',
9
+ 'mcp__serena__rename_symbol',
10
+ 'mcp__serena__replace_symbol_body',
11
+ 'mcp__serena__insert_after_symbol',
12
+ 'mcp__serena__insert_before_symbol',
13
+ ];
14
+
15
+ export const DANGEROUS_BASH_PATTERNS = [
16
+ 'sed\\s+-i',
17
+ 'echo\\s+[^\\n]*>',
18
+ 'printf\\s+[^\\n]*>',
19
+ 'cat\\s+[^\\n]*>',
20
+ 'tee\\b',
21
+ '(?:^|\\s)(?:vim|nano|vi)\\b',
22
+ '(?:^|\\s)mv\\b',
23
+ '(?:^|\\s)cp\\b',
24
+ '(?:^|\\s)rm\\b',
25
+ '(?:^|\\s)mkdir\\b',
26
+ '(?:^|\\s)touch\\b',
27
+ '(?:^|\\s)chmod\\b',
28
+ '(?:^|\\s)chown\\b',
29
+ '>>',
30
+ '(?:^|\\s)git\\s+add\\b',
31
+ '(?:^|\\s)git\\s+commit\\b',
32
+ '(?:^|\\s)git\\s+merge\\b',
33
+ '(?:^|\\s)git\\s+push\\b',
34
+ '(?:^|\\s)git\\s+reset\\b',
35
+ '(?:^|\\s)git\\s+checkout\\b',
36
+ '(?:^|\\s)git\\s+rebase\\b',
37
+ '(?:^|\\s)git\\s+stash\\b',
38
+ '(?:^|\\s)npm\\s+install\\b',
39
+ '(?:^|\\s)bun\\s+install\\b',
40
+ '(?:^|\\s)bun\\s+add\\b',
41
+ '(?:^|\\s)node\\s+(?:-e|--eval)\\b',
42
+ '(?:^|\\s)bun\\s+(?:-e|--eval)\\b',
43
+ '(?:^|\\s)python\\s+-c\\b',
44
+ '(?:^|\\s)perl\\s+-e\\b',
45
+ '(?:^|\\s)ruby\\s+-e\\b',
46
+ ];
47
+
48
+ export const SAFE_BASH_PREFIXES = [
49
+ // Git read-only
50
+ 'git status',
51
+ 'git log',
52
+ 'git diff',
53
+ 'git show',
54
+ 'git blame',
55
+ 'git branch',
56
+ 'git fetch',
57
+ 'git remote',
58
+ 'git config',
59
+ 'git pull',
60
+ 'git stash',
61
+ 'git worktree',
62
+ 'git checkout -b',
63
+ 'git switch -c',
64
+ // Tools
65
+ 'gh',
66
+ 'bd',
67
+ 'npx gitnexus',
68
+ 'xtrm finish',
69
+ // Read-only filesystem
70
+ 'cat',
71
+ 'ls',
72
+ 'head',
73
+ 'tail',
74
+ 'pwd',
75
+ 'which',
76
+ 'type',
77
+ 'env',
78
+ 'printenv',
79
+ 'find',
80
+ 'grep',
81
+ 'rg',
82
+ 'fd',
83
+ 'wc',
84
+ 'sort',
85
+ 'uniq',
86
+ 'cut',
87
+ 'awk',
88
+ 'jq',
89
+ 'yq',
90
+ 'bat',
91
+ 'less',
92
+ 'more',
93
+ 'file',
94
+ 'stat',
95
+ 'du',
96
+ 'tree',
97
+ // Allowed writes (specific paths)
98
+ 'touch .beads/',
99
+ ];
100
+
101
+ export const NATIVE_TEAM_TOOLS = [
102
+ 'Task',
103
+ 'TeamCreate',
104
+ 'TeamDelete',
105
+ 'SendMessage',
106
+ 'TaskCreate',
107
+ 'TaskUpdate',
108
+ 'TaskList',
109
+ 'TaskGet',
110
+ 'TaskOutput',
111
+ 'TaskStop',
112
+ ];
113
+
114
+ export const INTERACTIVE_TOOLS = [
115
+ 'AskUserQuestion',
116
+ 'EnterPlanMode',
117
+ 'EnterWorktree',
118
+ ];
@@ -0,0 +1,116 @@
1
+ {
2
+ "hooks": {
3
+ "PostToolUse": [
4
+ {
5
+ "matcher": "Bash|execute_shell_command|bash",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/beads-claim-sync.mjs",
10
+ "timeout": 5000
11
+ }
12
+ ]
13
+ },
14
+ {
15
+ "matcher": "Edit|Write|MultiEdit|NotebookEdit|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol",
16
+ "hooks": [
17
+ {
18
+ "type": "command",
19
+ "command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/quality-check.cjs",
20
+ "timeout": 30000
21
+ },
22
+ {
23
+ "type": "command",
24
+ "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/quality-check.py",
25
+ "timeout": 30000
26
+ }
27
+ ]
28
+ },
29
+ {
30
+ "matcher": "Bash|mcp__serena__find_symbol|mcp__serena__get_symbols_overview|mcp__serena__search_for_pattern|mcp__serena__find_referencing_symbols|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol|mcp__serena__rename_symbol",
31
+ "hooks": [
32
+ {
33
+ "type": "command",
34
+ "command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/gitnexus/gitnexus-hook.cjs",
35
+ "timeout": 10000
36
+ }
37
+ ]
38
+ }
39
+ ],
40
+ "Stop": [
41
+ {
42
+ "hooks": [
43
+ {
44
+ "type": "command",
45
+ "command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/beads-stop-gate.mjs",
46
+ "timeout": 5000
47
+ },
48
+ {
49
+ "type": "command",
50
+ "command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/beads-memory-gate.mjs",
51
+ "timeout": 8000
52
+ }
53
+ ]
54
+ }
55
+ ],
56
+ "SessionStart": [
57
+ {
58
+ "hooks": [
59
+ {
60
+ "type": "command",
61
+ "command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/beads-compact-restore.mjs",
62
+ "timeout": 5000
63
+ },
64
+ {
65
+ "type": "command",
66
+ "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/serena-workflow-reminder.py"
67
+ }
68
+ ]
69
+ }
70
+ ],
71
+ "PreToolUse": [
72
+ {
73
+ "matcher": "Edit|Write|MultiEdit|NotebookEdit|mcp__serena__rename_symbol|mcp__serena__replace_symbol_body|mcp__serena__insert_after_symbol|mcp__serena__insert_before_symbol",
74
+ "hooks": [
75
+ {
76
+ "type": "command",
77
+ "command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/beads-edit-gate.mjs",
78
+ "timeout": 5000
79
+ }
80
+ ]
81
+ },
82
+ {
83
+ "matcher": "Bash",
84
+ "hooks": [
85
+ {
86
+ "type": "command",
87
+ "command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/beads-commit-gate.mjs",
88
+ "timeout": 5000
89
+ }
90
+ ]
91
+ }
92
+ ],
93
+ "PreCompact": [
94
+ {
95
+ "hooks": [
96
+ {
97
+ "type": "command",
98
+ "command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/beads-compact-save.mjs",
99
+ "timeout": 5000
100
+ }
101
+ ]
102
+ }
103
+ ],
104
+ "UserPromptSubmit": [
105
+ {
106
+ "hooks": [
107
+ {
108
+ "type": "command",
109
+ "command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/branch-state.mjs",
110
+ "timeout": 3000
111
+ }
112
+ ]
113
+ }
114
+ ]
115
+ }
116
+ }
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env node
2
+ // Claude Code PostToolUse hook — after successful feature-branch push,
3
+ // inject next-step PR workflow guidance.
4
+ // Exit 0 in all paths (informational only).
5
+ //
6
+ // Installed by: xtrm install
7
+
8
+ import { execSync } from 'node:child_process';
9
+ import { readFileSync } from 'node:fs';
10
+
11
+ let input;
12
+ try {
13
+ input = JSON.parse(readFileSync(0, 'utf8'));
14
+ } catch {
15
+ process.exit(0);
16
+ }
17
+
18
+ if ((input.tool_name ?? '') !== 'Bash') process.exit(0);
19
+ const cmd = (input.tool_input?.command ?? '').trim().replace(/\s+/g, ' ');
20
+ if (!/^git\s+push\b/.test(cmd)) process.exit(0);
21
+
22
+ function commandSucceeded(payload) {
23
+ const tr = payload?.tool_response ?? payload?.tool_result ?? payload?.result;
24
+ if (!tr || typeof tr !== 'object') return true;
25
+
26
+ if (tr.success === false) return false;
27
+ if (tr.error) return false;
28
+
29
+ const numeric = [tr.exit_code, tr.exitCode, tr.status, tr.returncode]
30
+ .find((v) => Number.isInteger(v));
31
+ if (typeof numeric === 'number' && numeric !== 0) return false;
32
+
33
+ return true;
34
+ }
35
+
36
+ if (!commandSucceeded(input)) process.exit(0);
37
+
38
+ const cwd = input.cwd || process.cwd();
39
+ let branch = '';
40
+ try {
41
+ branch = execSync('git branch --show-current', {
42
+ cwd,
43
+ encoding: 'utf8',
44
+ stdio: ['pipe', 'pipe', 'pipe'],
45
+ }).trim();
46
+ } catch {
47
+ process.exit(0);
48
+ }
49
+
50
+ const protectedBranches = process.env.MAIN_GUARD_PROTECTED_BRANCHES
51
+ ? process.env.MAIN_GUARD_PROTECTED_BRANCHES.split(',').map((b) => b.trim()).filter(Boolean)
52
+ : ['main', 'master'];
53
+
54
+ if (!branch || protectedBranches.includes(branch)) process.exit(0);
55
+
56
+ const tokens = cmd.split(' ');
57
+ const lastToken = tokens[tokens.length - 1] ?? '';
58
+ const explicitlyProtectedTarget = protectedBranches
59
+ .some((b) => lastToken === b || lastToken.endsWith(`:${b}`));
60
+ if (explicitlyProtectedTarget) process.exit(0);
61
+
62
+ process.stdout.write(JSON.stringify({
63
+ additionalContext:
64
+ `✅ Pushed '${branch}'. Next steps:\n` +
65
+ ' 1. gh pr create --fill\n' +
66
+ ' 2. gh pr merge --squash\n' +
67
+ ' 3. git checkout main && git reset --hard origin/main\n' +
68
+ 'Ensure beads state is updated (e.g. bd close <id>).',
69
+ }));
70
+ process.stdout.write('\n');
71
+ process.exit(0);
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env node
2
+ // Claude Code PreToolUse hook — block writes and direct master pushes
3
+ // Exit 0: allow | Exit 2: block (message shown to user)
4
+ //
5
+ // Installed by: xtrm install
6
+
7
+ import { execSync } from 'node:child_process';
8
+ import { existsSync, readFileSync } from 'node:fs';
9
+ import { join } from 'node:path';
10
+ import { WRITE_TOOLS, SAFE_BASH_PREFIXES } from './guard-rules.mjs';
11
+
12
+ let branch = '';
13
+ try {
14
+ branch = execSync('git branch --show-current', {
15
+ encoding: 'utf8',
16
+ stdio: ['pipe', 'pipe', 'pipe'],
17
+ }).trim();
18
+ } catch {}
19
+
20
+ const protectedBranches = process.env.MAIN_GUARD_PROTECTED_BRANCHES
21
+ ? process.env.MAIN_GUARD_PROTECTED_BRANCHES.split(',').map(b => b.trim()).filter(Boolean)
22
+ : ['main', 'master'];
23
+
24
+ if (!branch || !protectedBranches.includes(branch)) {
25
+ process.exit(0);
26
+ }
27
+
28
+ let input;
29
+ try {
30
+ input = JSON.parse(readFileSync(0, 'utf8'));
31
+ } catch {
32
+ process.exit(0);
33
+ }
34
+
35
+ const tool = input.tool_name ?? '';
36
+ const cwd = input.cwd || process.cwd();
37
+
38
+ function deny(reason) {
39
+ process.stdout.write(JSON.stringify({ decision: 'block', reason }));
40
+ process.stdout.write('\n');
41
+ process.exit(0);
42
+ }
43
+
44
+ function getSessionState(cwd) {
45
+ const statePath = join(cwd, '.xtrm-session-state.json');
46
+ if (!existsSync(statePath)) return null;
47
+ try {
48
+ return JSON.parse(readFileSync(statePath, 'utf8'));
49
+ } catch {
50
+ return null;
51
+ }
52
+ }
53
+
54
+ function normalizeGitCCommand(cmd) {
55
+ const match = cmd.match(/^git\s+-C\s+(?:"[^"]+"|'[^']+'|\S+)\s+(.+)$/);
56
+ if (match?.[1]) return `git ${match[1]}`;
57
+ return cmd;
58
+ }
59
+
60
+ if (WRITE_TOOLS.includes(tool)) {
61
+ deny(`⛔ On '${branch}' — start on a feature branch and claim an issue.\n`
62
+ + ' git checkout -b feature/<name> (or: git switch -c feature/<name>)\n'
63
+ + ' bd update <id> --claim\n');
64
+ }
65
+
66
+ if (tool === 'Bash') {
67
+ const cmd = (input.tool_input?.command ?? '').trim().replace(/\s+/g, ' ');
68
+ const normalizedCmd = normalizeGitCCommand(cmd);
69
+ const state = getSessionState(cwd);
70
+
71
+ if (process.env.MAIN_GUARD_ALLOW_BASH === '1') {
72
+ process.exit(0);
73
+ }
74
+
75
+ if (/^gh\s+pr\s+merge\b/.test(cmd)) {
76
+ if (!/--squash\b/.test(cmd)) {
77
+ deny('⛔ Squash only: gh pr merge --squash\n'
78
+ + ' (override: MAIN_GUARD_ALLOW_BASH=1 gh pr merge --merge)\n');
79
+ }
80
+ process.exit(0);
81
+ }
82
+
83
+ const SAFE_BASH_PATTERNS = [
84
+ ...SAFE_BASH_PREFIXES.map(prefix => new RegExp(`^${prefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`)),
85
+ ...protectedBranches.map(b => new RegExp(`^git\\s+reset\\s+--hard\\s+origin/${b}\\b`)),
86
+ ];
87
+
88
+ if (SAFE_BASH_PATTERNS.some(p => p.test(cmd) || p.test(normalizedCmd))) {
89
+ process.exit(0);
90
+ }
91
+
92
+ if (/\bgit\s+commit\b/.test(normalizedCmd)) {
93
+ deny(`⛔ No commits on '${branch}' — use a feature branch/worktree.\n`
94
+ + ' git checkout -b feature/<name>\n'
95
+ + ' bd update <id> --claim\n');
96
+ }
97
+
98
+ if (/\bgit\s+push\b/.test(normalizedCmd)) {
99
+ const tokens = normalizedCmd.split(' ');
100
+ const lastToken = tokens[tokens.length - 1];
101
+ const explicitProtected = protectedBranches.some(b => lastToken === b || lastToken.endsWith(`:${b}`));
102
+ const impliedProtected = tokens.length <= 3 && protectedBranches.includes(branch);
103
+ if (explicitProtected || impliedProtected) {
104
+ deny(`⛔ No direct push to '${branch}' — push a feature branch and open a PR.\n`
105
+ + ' git push -u origin <feature-branch> && gh pr create --fill\n');
106
+ }
107
+ process.exit(0);
108
+ }
109
+
110
+ const handoff = state?.worktreePath
111
+ ? ` Active worktree session recorded: ${state.worktreePath}\n (Current workaround) use feature branch flow until worktree bug is fixed.\n`
112
+ : ' Exit: git checkout -b feature/<name> (or: git switch -c feature/<name>)\n Then: bd update <id> --claim\n';
113
+
114
+ deny(`⛔ Bash restricted on '${branch}'. Allowed: read-only commands, gh, bd, git checkout -b, git switch -c.\n`
115
+ + handoff
116
+ + ' Override: MAIN_GUARD_ALLOW_BASH=1 <cmd>\n');
117
+ }
118
+
119
+ process.exit(0);