xtrm-tools 0.5.25 → 0.5.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +19 -0
- package/.claude-plugin/plugin.json +9 -0
- package/cli/dist/index.cjs +59 -52
- package/cli/dist/index.cjs.map +1 -1
- package/cli/package.json +1 -1
- package/hooks/beads-claim-sync.mjs +1 -3
- package/package.json +5 -1
- package/plugins/xtrm-tools/.claude-plugin/plugin.json +9 -0
- package/plugins/xtrm-tools/.mcp.json +18 -0
- package/plugins/xtrm-tools/hooks/README.md +61 -0
- package/plugins/xtrm-tools/hooks/beads-claim-sync.mjs +223 -0
- package/plugins/xtrm-tools/hooks/beads-commit-gate.mjs +70 -0
- package/plugins/xtrm-tools/hooks/beads-compact-restore.mjs +69 -0
- package/plugins/xtrm-tools/hooks/beads-compact-save.mjs +51 -0
- package/plugins/xtrm-tools/hooks/beads-edit-gate.mjs +85 -0
- package/plugins/xtrm-tools/hooks/beads-gate-core.mjs +236 -0
- package/plugins/xtrm-tools/hooks/beads-gate-messages.mjs +68 -0
- package/plugins/xtrm-tools/hooks/beads-gate-utils.mjs +194 -0
- package/plugins/xtrm-tools/hooks/beads-memory-gate.mjs +81 -0
- package/plugins/xtrm-tools/hooks/beads-stop-gate.mjs +53 -0
- package/plugins/xtrm-tools/hooks/gitnexus/gitnexus-hook.cjs +222 -0
- package/plugins/xtrm-tools/hooks/hooks.json +115 -0
- package/plugins/xtrm-tools/hooks/quality-check-env.mjs +79 -0
- package/plugins/xtrm-tools/hooks/quality-check.cjs +1286 -0
- package/plugins/xtrm-tools/hooks/quality-check.py +345 -0
- package/plugins/xtrm-tools/hooks/statusline.mjs +145 -0
- package/plugins/xtrm-tools/hooks/using-xtrm-reminder.mjs +35 -0
- package/plugins/xtrm-tools/hooks/worktree-boundary.mjs +33 -0
- package/plugins/xtrm-tools/hooks/xtrm-logger.mjs +123 -0
- package/plugins/xtrm-tools/hooks/xtrm-session-logger.mjs +27 -0
- package/plugins/xtrm-tools/hooks/xtrm-tool-logger.mjs +53 -0
- package/plugins/xtrm-tools/skills/README.txt +31 -0
- package/plugins/xtrm-tools/skills/clean-code/SKILL.md +201 -0
- package/plugins/xtrm-tools/skills/creating-service-skills/SKILL.md +433 -0
- package/plugins/xtrm-tools/skills/creating-service-skills/references/script_quality_standards.md +425 -0
- package/plugins/xtrm-tools/skills/creating-service-skills/references/service_skill_system_guide.md +278 -0
- package/plugins/xtrm-tools/skills/creating-service-skills/scripts/bootstrap.py +326 -0
- package/plugins/xtrm-tools/skills/creating-service-skills/scripts/deep_dive.py +304 -0
- package/plugins/xtrm-tools/skills/creating-service-skills/scripts/scaffolder.py +482 -0
- package/plugins/xtrm-tools/skills/delegating/SKILL.md +196 -0
- package/plugins/xtrm-tools/skills/delegating/config.yaml +210 -0
- package/plugins/xtrm-tools/skills/delegating/references/orchestration-protocols.md +41 -0
- package/plugins/xtrm-tools/skills/docker-expert/SKILL.md +409 -0
- package/plugins/xtrm-tools/skills/documenting/CHANGELOG.md +23 -0
- package/plugins/xtrm-tools/skills/documenting/README.md +148 -0
- package/plugins/xtrm-tools/skills/documenting/SKILL.md +113 -0
- package/plugins/xtrm-tools/skills/documenting/examples/example_pattern.md +70 -0
- package/plugins/xtrm-tools/skills/documenting/examples/example_reference.md +70 -0
- package/plugins/xtrm-tools/skills/documenting/examples/example_ssot_analytics.md +64 -0
- package/plugins/xtrm-tools/skills/documenting/examples/example_workflow.md +141 -0
- package/plugins/xtrm-tools/skills/documenting/references/changelog-format.md +97 -0
- package/plugins/xtrm-tools/skills/documenting/references/metadata-schema.md +136 -0
- package/plugins/xtrm-tools/skills/documenting/references/taxonomy.md +81 -0
- package/plugins/xtrm-tools/skills/documenting/references/versioning-rules.md +78 -0
- package/plugins/xtrm-tools/skills/documenting/scripts/bump_version.sh +60 -0
- package/plugins/xtrm-tools/skills/documenting/scripts/changelog/__init__.py +0 -0
- package/plugins/xtrm-tools/skills/documenting/scripts/changelog/add_entry.py +216 -0
- package/plugins/xtrm-tools/skills/documenting/scripts/changelog/bump_release.py +117 -0
- package/plugins/xtrm-tools/skills/documenting/scripts/changelog/init_changelog.py +54 -0
- package/plugins/xtrm-tools/skills/documenting/scripts/changelog/validate_changelog.py +128 -0
- package/plugins/xtrm-tools/skills/documenting/scripts/drift_detector.py +266 -0
- package/plugins/xtrm-tools/skills/documenting/scripts/generate_template.py +311 -0
- package/plugins/xtrm-tools/skills/documenting/scripts/list_by_category.sh +84 -0
- package/plugins/xtrm-tools/skills/documenting/scripts/orchestrator.py +255 -0
- package/plugins/xtrm-tools/skills/documenting/scripts/validate_metadata.py +242 -0
- package/plugins/xtrm-tools/skills/documenting/templates/CHANGELOG.md.template +13 -0
- package/plugins/xtrm-tools/skills/documenting/tests/integration_test.sh +70 -0
- package/plugins/xtrm-tools/skills/documenting/tests/test_changelog.py +201 -0
- package/plugins/xtrm-tools/skills/documenting/tests/test_drift_detector.py +80 -0
- package/plugins/xtrm-tools/skills/documenting/tests/test_orchestrator.py +52 -0
- package/plugins/xtrm-tools/skills/documenting/tests/test_validate_metadata.py +64 -0
- package/plugins/xtrm-tools/skills/find-skills/SKILL.md +133 -0
- package/plugins/xtrm-tools/skills/gitnexus-debugging/SKILL.md +85 -0
- package/plugins/xtrm-tools/skills/gitnexus-exploring/SKILL.md +75 -0
- package/plugins/xtrm-tools/skills/gitnexus-impact-analysis/SKILL.md +94 -0
- package/plugins/xtrm-tools/skills/gitnexus-refactoring/SKILL.md +113 -0
- package/plugins/xtrm-tools/skills/hook-development/SKILL.md +797 -0
- package/plugins/xtrm-tools/skills/hook-development/examples/load-context.sh +55 -0
- package/plugins/xtrm-tools/skills/hook-development/examples/quality-check.js +1168 -0
- package/plugins/xtrm-tools/skills/hook-development/examples/validate-bash.sh +43 -0
- package/plugins/xtrm-tools/skills/hook-development/examples/validate-write.sh +38 -0
- package/plugins/xtrm-tools/skills/hook-development/references/advanced.md +527 -0
- package/plugins/xtrm-tools/skills/hook-development/references/migration.md +369 -0
- package/plugins/xtrm-tools/skills/hook-development/references/patterns.md +412 -0
- package/plugins/xtrm-tools/skills/hook-development/scripts/README.md +164 -0
- package/plugins/xtrm-tools/skills/hook-development/scripts/hook-linter.sh +153 -0
- package/plugins/xtrm-tools/skills/hook-development/scripts/test-hook.sh +252 -0
- package/plugins/xtrm-tools/skills/hook-development/scripts/validate-hook-schema.sh +159 -0
- package/plugins/xtrm-tools/skills/obsidian-cli/SKILL.md +106 -0
- package/plugins/xtrm-tools/skills/orchestrating-agents/SKILL.md +135 -0
- package/plugins/xtrm-tools/skills/orchestrating-agents/config.yaml +45 -0
- package/plugins/xtrm-tools/skills/orchestrating-agents/references/agent-context-integration.md +37 -0
- package/plugins/xtrm-tools/skills/orchestrating-agents/references/examples.md +45 -0
- package/plugins/xtrm-tools/skills/orchestrating-agents/references/handover-protocol.md +31 -0
- package/plugins/xtrm-tools/skills/orchestrating-agents/references/workflows.md +42 -0
- package/plugins/xtrm-tools/skills/orchestrating-agents/scripts/detect_neighbors.py +23 -0
- package/plugins/xtrm-tools/skills/prompt-improving/README.md +162 -0
- package/plugins/xtrm-tools/skills/prompt-improving/SKILL.md +74 -0
- package/plugins/xtrm-tools/skills/prompt-improving/references/analysis_commands.md +24 -0
- package/plugins/xtrm-tools/skills/prompt-improving/references/chain_of_thought.md +24 -0
- package/plugins/xtrm-tools/skills/prompt-improving/references/mcp_definitions.md +20 -0
- package/plugins/xtrm-tools/skills/prompt-improving/references/multishot.md +23 -0
- package/plugins/xtrm-tools/skills/prompt-improving/references/xml_core.md +60 -0
- package/plugins/xtrm-tools/skills/python-testing/SKILL.md +815 -0
- package/plugins/xtrm-tools/skills/scoping-service-skills/SKILL.md +231 -0
- package/plugins/xtrm-tools/skills/scoping-service-skills/scripts/scope.py +74 -0
- package/plugins/xtrm-tools/skills/senior-backend/SKILL.md +209 -0
- package/plugins/xtrm-tools/skills/senior-backend/references/api_design_patterns.md +103 -0
- package/plugins/xtrm-tools/skills/senior-backend/references/backend_security_practices.md +103 -0
- package/plugins/xtrm-tools/skills/senior-backend/references/database_optimization_guide.md +103 -0
- package/plugins/xtrm-tools/skills/senior-backend/scripts/api_load_tester.py +114 -0
- package/plugins/xtrm-tools/skills/senior-backend/scripts/api_scaffolder.py +114 -0
- package/plugins/xtrm-tools/skills/senior-backend/scripts/database_migration_tool.py +114 -0
- package/plugins/xtrm-tools/skills/senior-data-scientist/SKILL.md +226 -0
- package/plugins/xtrm-tools/skills/senior-data-scientist/references/experiment_design_frameworks.md +80 -0
- package/plugins/xtrm-tools/skills/senior-data-scientist/references/feature_engineering_patterns.md +80 -0
- package/plugins/xtrm-tools/skills/senior-data-scientist/references/statistical_methods_advanced.md +80 -0
- package/plugins/xtrm-tools/skills/senior-data-scientist/scripts/experiment_designer.py +100 -0
- package/plugins/xtrm-tools/skills/senior-data-scientist/scripts/feature_engineering_pipeline.py +100 -0
- package/plugins/xtrm-tools/skills/senior-data-scientist/scripts/model_evaluation_suite.py +100 -0
- package/plugins/xtrm-tools/skills/senior-devops/SKILL.md +209 -0
- package/plugins/xtrm-tools/skills/senior-devops/references/cicd_pipeline_guide.md +103 -0
- package/plugins/xtrm-tools/skills/senior-devops/references/deployment_strategies.md +103 -0
- package/plugins/xtrm-tools/skills/senior-devops/references/infrastructure_as_code.md +103 -0
- package/plugins/xtrm-tools/skills/senior-devops/scripts/deployment_manager.py +114 -0
- package/plugins/xtrm-tools/skills/senior-devops/scripts/pipeline_generator.py +114 -0
- package/plugins/xtrm-tools/skills/senior-devops/scripts/terraform_scaffolder.py +114 -0
- package/plugins/xtrm-tools/skills/senior-security/SKILL.md +209 -0
- package/plugins/xtrm-tools/skills/senior-security/references/cryptography_implementation.md +103 -0
- package/plugins/xtrm-tools/skills/senior-security/references/penetration_testing_guide.md +103 -0
- package/plugins/xtrm-tools/skills/senior-security/references/security_architecture_patterns.md +103 -0
- package/plugins/xtrm-tools/skills/senior-security/scripts/pentest_automator.py +114 -0
- package/plugins/xtrm-tools/skills/senior-security/scripts/security_auditor.py +114 -0
- package/plugins/xtrm-tools/skills/senior-security/scripts/threat_modeler.py +114 -0
- package/plugins/xtrm-tools/skills/skill-creator/LICENSE.txt +202 -0
- package/plugins/xtrm-tools/skills/skill-creator/SKILL.md +479 -0
- package/plugins/xtrm-tools/skills/skill-creator/agents/analyzer.md +274 -0
- package/plugins/xtrm-tools/skills/skill-creator/agents/comparator.md +202 -0
- package/plugins/xtrm-tools/skills/skill-creator/agents/grader.md +223 -0
- package/plugins/xtrm-tools/skills/skill-creator/assets/eval_review.html +146 -0
- package/plugins/xtrm-tools/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/plugins/xtrm-tools/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/plugins/xtrm-tools/skills/skill-creator/references/schemas.md +430 -0
- package/plugins/xtrm-tools/skills/skill-creator/scripts/__init__.py +0 -0
- package/plugins/xtrm-tools/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/plugins/xtrm-tools/skills/skill-creator/scripts/generate_report.py +326 -0
- package/plugins/xtrm-tools/skills/skill-creator/scripts/improve_description.py +248 -0
- package/plugins/xtrm-tools/skills/skill-creator/scripts/package_skill.py +136 -0
- package/plugins/xtrm-tools/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/plugins/xtrm-tools/skills/skill-creator/scripts/run_eval.py +310 -0
- package/plugins/xtrm-tools/skills/skill-creator/scripts/run_loop.py +332 -0
- package/plugins/xtrm-tools/skills/skill-creator/scripts/utils.py +47 -0
- package/plugins/xtrm-tools/skills/sync-docs/SKILL.md +155 -0
- package/plugins/xtrm-tools/skills/sync-docs/evals/evals.json +89 -0
- package/plugins/xtrm-tools/skills/sync-docs/references/doc-structure.md +99 -0
- package/plugins/xtrm-tools/skills/sync-docs/references/schema.md +103 -0
- package/plugins/xtrm-tools/skills/sync-docs/scripts/changelog/add_entry.py +216 -0
- package/plugins/xtrm-tools/skills/sync-docs/scripts/context_gatherer.py +240 -0
- package/plugins/xtrm-tools/skills/sync-docs/scripts/doc_structure_analyzer.py +495 -0
- package/plugins/xtrm-tools/skills/sync-docs/scripts/drift_detector.py +563 -0
- package/plugins/xtrm-tools/skills/sync-docs/scripts/validate_doc.py +365 -0
- package/plugins/xtrm-tools/skills/sync-docs/scripts/validate_metadata.py +185 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/benchmark.json +293 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/benchmark.md +13 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-doc-audit/eval_metadata.json +27 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/outputs/result.md +210 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/run-1/grading.json +28 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/run-1/timing.json +1 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/outputs/result.md +101 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/run-1/grading.json +28 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/run-1/timing.json +5 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/timing.json +5 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-fix-mode/eval_metadata.json +27 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/outputs/result.md +198 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/run-1/grading.json +28 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/run-1/timing.json +1 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/outputs/result.md +94 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/run-1/grading.json +28 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/run-1/timing.json +1 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/eval_metadata.json +27 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/outputs/result.md +237 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/run-1/grading.json +28 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/run-1/timing.json +1 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/outputs/result.md +134 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/run-1/grading.json +28 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/run-1/timing.json +1 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/benchmark.json +297 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/benchmark.md +13 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-doc-audit/eval_metadata.json +27 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/outputs/result.md +137 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/run-1/grading.json +92 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/run-1/timing.json +1 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/outputs/result.md +134 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/run-1/grading.json +86 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/run-1/timing.json +1 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-fix-mode/eval_metadata.json +27 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/outputs/result.md +193 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/run-1/grading.json +72 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/run-1/timing.json +1 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/outputs/result.md +211 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/run-1/grading.json +91 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/run-1/timing.json +5 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/eval_metadata.json +27 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/outputs/result.md +182 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/run-1/grading.json +95 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/run-1/timing.json +1 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/outputs/result.md +222 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/run-1/grading.json +88 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/run-1/timing.json +5 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/benchmark.json +298 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/benchmark.md +13 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-doc-audit/eval_metadata.json +27 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/outputs/result.md +125 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/run-1/grading.json +97 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/run-1/timing.json +5 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/outputs/result.md +144 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/run-1/grading.json +78 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/run-1/timing.json +5 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-fix-mode/eval_metadata.json +27 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/outputs/result.md +104 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/run-1/grading.json +91 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/run-1/timing.json +5 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/outputs/result.md +79 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/run-1/grading.json +82 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/run-1/timing.json +5 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/eval_metadata.json +27 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase1_context.json +302 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase2_drift.txt +33 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase3_analysis.json +114 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase4_fix.txt +118 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase5_validate.txt +38 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/result.md +158 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/run-1/grading.json +95 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/run-1/timing.json +5 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/outputs/result.md +71 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/run-1/grading.json +90 -0
- package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/run-1/timing.json +5 -0
- package/plugins/xtrm-tools/skills/test-planning/SKILL.md +208 -0
- package/plugins/xtrm-tools/skills/test-planning/evals/evals.json +23 -0
- package/plugins/xtrm-tools/skills/updating-service-skills/SKILL.md +136 -0
- package/plugins/xtrm-tools/skills/updating-service-skills/scripts/drift_detector.py +222 -0
- package/plugins/xtrm-tools/skills/using-TDD/SKILL.md +410 -0
- package/plugins/xtrm-tools/skills/using-quality-gates/SKILL.md +254 -0
- package/plugins/xtrm-tools/skills/using-serena-lsp/README.md +8 -0
- package/plugins/xtrm-tools/skills/using-serena-lsp/REFERENCE.md +194 -0
- package/plugins/xtrm-tools/skills/using-serena-lsp/SKILL.md +82 -0
- package/plugins/xtrm-tools/skills/using-service-skills/SKILL.md +108 -0
- package/plugins/xtrm-tools/skills/using-service-skills/scripts/cataloger.py +74 -0
- package/plugins/xtrm-tools/skills/using-service-skills/scripts/skill_activator.py +152 -0
- package/plugins/xtrm-tools/skills/using-service-skills/scripts/test_skill_activator.py +58 -0
- package/plugins/xtrm-tools/skills/using-xtrm/SKILL.md +124 -0
- package/plugins/xtrm-tools/skills/xt-end/SKILL.md +128 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// beads-gate-core.mjs — pure decision functions for beads gate hooks
|
|
3
|
+
// Import from sibling hooks using: import { ... } from './beads-gate-core.mjs';
|
|
4
|
+
//
|
|
5
|
+
// All functions are pure: they return decision objects, never call process.exit()
|
|
6
|
+
// or write to stdout/stderr. Side effects belong in entrypoint wrappers.
|
|
7
|
+
//
|
|
8
|
+
// Dependencies: beads-gate-utils.mjs (adapters)
|
|
9
|
+
|
|
10
|
+
import { readFileSync } from 'node:fs';
|
|
11
|
+
import { resolve } from 'node:path';
|
|
12
|
+
import {
|
|
13
|
+
resolveCwd,
|
|
14
|
+
resolveSessionId,
|
|
15
|
+
isBeadsProject,
|
|
16
|
+
getSessionClaim,
|
|
17
|
+
getTotalWork,
|
|
18
|
+
getInProgress,
|
|
19
|
+
isIssueInProgress,
|
|
20
|
+
resolveWorktreeRoot,
|
|
21
|
+
} from './beads-gate-utils.mjs';
|
|
22
|
+
|
|
23
|
+
// ── Input parsing ────────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Read and parse hook input from stdin. Returns null on parse error.
|
|
27
|
+
* Entrypoints should exit 0 if this returns null (fail-open).
|
|
28
|
+
*/
|
|
29
|
+
export function readHookInput() {
|
|
30
|
+
try {
|
|
31
|
+
return JSON.parse(readFileSync(0, 'utf8'));
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// ── Session context resolution ───────────────────────────────────────────────
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Resolve session context from hook input.
|
|
41
|
+
* Returns { cwd, sessionId, isBeadsProject } or null if cwd can't be resolved.
|
|
42
|
+
*/
|
|
43
|
+
export function resolveSessionContext(input) {
|
|
44
|
+
const cwd = resolveCwd(input);
|
|
45
|
+
if (!cwd) return null;
|
|
46
|
+
return {
|
|
47
|
+
cwd,
|
|
48
|
+
sessionId: resolveSessionId(input),
|
|
49
|
+
isBeadsProject: isBeadsProject(cwd),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ── Claim and work state resolution ──────────────────────────────────────────
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Resolve the claim and work state for a session.
|
|
57
|
+
* Returns { claimed, claimId, totalWork, inProgress } or null if bd unavailable.
|
|
58
|
+
*/
|
|
59
|
+
export function resolveClaimAndWorkState(ctx) {
|
|
60
|
+
if (!ctx.isBeadsProject) {
|
|
61
|
+
return { claimed: false, claimId: null, totalWork: 0, inProgress: null };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const totalWork = getTotalWork(ctx.cwd);
|
|
65
|
+
if (totalWork === null) return null; // bd unavailable
|
|
66
|
+
|
|
67
|
+
const inProgress = getInProgress(ctx.cwd);
|
|
68
|
+
|
|
69
|
+
if (ctx.sessionId) {
|
|
70
|
+
const claimId = getSessionClaim(ctx.sessionId, ctx.cwd);
|
|
71
|
+
if (claimId === null) return null; // bd kv unavailable
|
|
72
|
+
return {
|
|
73
|
+
claimed: !!claimId,
|
|
74
|
+
claimId: claimId || null,
|
|
75
|
+
claimInProgress: claimId ? isIssueInProgress(claimId, ctx.cwd) : false,
|
|
76
|
+
totalWork,
|
|
77
|
+
inProgress,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// No session_id: fallback to global in_progress check
|
|
82
|
+
return {
|
|
83
|
+
claimed: false,
|
|
84
|
+
claimId: null,
|
|
85
|
+
claimInProgress: false,
|
|
86
|
+
totalWork,
|
|
87
|
+
inProgress,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ── Decision functions ───────────────────────────────────────────────────────
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Decide whether a file edit is within the active worktree boundary.
|
|
95
|
+
* If the session cwd is inside .xtrm/worktrees/<name>, block any edit whose
|
|
96
|
+
* resolved path falls outside that worktree root.
|
|
97
|
+
* Returns { allow: boolean, filePath?: string, worktreeRoot?: string }
|
|
98
|
+
*/
|
|
99
|
+
export function decideWorktreeBoundary(input, cwd) {
|
|
100
|
+
const filePath = input?.tool_input?.file_path;
|
|
101
|
+
if (!filePath) return { allow: true };
|
|
102
|
+
|
|
103
|
+
const worktreeRoot = resolveWorktreeRoot(cwd);
|
|
104
|
+
if (!worktreeRoot) return { allow: true }; // not in a worktree — no constraint
|
|
105
|
+
|
|
106
|
+
const abs = resolve(cwd, filePath);
|
|
107
|
+
if (abs === worktreeRoot || abs.startsWith(worktreeRoot + '/')) return { allow: true };
|
|
108
|
+
|
|
109
|
+
return { allow: false, filePath: abs, worktreeRoot };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Decide whether to allow or block an edit operation.
|
|
114
|
+
* Returns { allow: boolean, reason?: string, sessionId?: string }
|
|
115
|
+
*/
|
|
116
|
+
export function decideEditGate(ctx, state) {
|
|
117
|
+
// Not a beads project → allow
|
|
118
|
+
if (!ctx.isBeadsProject) {
|
|
119
|
+
return { allow: true };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// bd unavailable → fail open
|
|
123
|
+
if (state === null) {
|
|
124
|
+
return { allow: true };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Session has an active claim → allow
|
|
128
|
+
if (state.claimed) {
|
|
129
|
+
return { allow: true };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// No trackable work → allow (clean-start state)
|
|
133
|
+
if (state.totalWork === 0) {
|
|
134
|
+
return { allow: true };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Has session_id but no claim + has work → block
|
|
138
|
+
if (ctx.sessionId) {
|
|
139
|
+
return {
|
|
140
|
+
allow: false,
|
|
141
|
+
reason: 'no_claim_with_work',
|
|
142
|
+
sessionId: ctx.sessionId,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Fallback: no session_id, check global in_progress
|
|
147
|
+
if (state.inProgress && state.inProgress.count > 0) {
|
|
148
|
+
return { allow: true };
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// No session_id, no in_progress, but has open work → block
|
|
152
|
+
if (state.totalWork > 0) {
|
|
153
|
+
return {
|
|
154
|
+
allow: false,
|
|
155
|
+
reason: 'no_claim_fallback',
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return { allow: true };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Decide whether to allow or block a git commit operation.
|
|
164
|
+
* Returns { allow: boolean, reason?: string, summary?: string, claimed?: string }
|
|
165
|
+
*/
|
|
166
|
+
export function decideCommitGate(ctx, state) {
|
|
167
|
+
// Not a beads project → allow
|
|
168
|
+
if (!ctx.isBeadsProject) {
|
|
169
|
+
return { allow: true };
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// bd unavailable → fail open
|
|
173
|
+
if (state === null) {
|
|
174
|
+
return { allow: true };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// No active claim → allow (nothing to close)
|
|
178
|
+
if (!state.claimed) {
|
|
179
|
+
return { allow: true };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Claimed issue is no longer in_progress → allow (closed or transferred to another agent)
|
|
183
|
+
if (!state.claimInProgress) {
|
|
184
|
+
return { allow: true };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Session's own claimed issue is still in_progress → block (need to close first)
|
|
188
|
+
return {
|
|
189
|
+
allow: false,
|
|
190
|
+
reason: 'unclosed_claim',
|
|
191
|
+
summary: ` Claimed: ${state.claimId} (still in_progress)`,
|
|
192
|
+
claimed: state.claimId,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Decide whether to allow or block a stop operation.
|
|
198
|
+
* Returns { allow: boolean, reason?: string, summary?: string, claimed?: string }
|
|
199
|
+
*/
|
|
200
|
+
export function decideStopGate(ctx, state) {
|
|
201
|
+
// Not a beads project → allow
|
|
202
|
+
if (!ctx.isBeadsProject) {
|
|
203
|
+
return { allow: true };
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// bd unavailable → fail open
|
|
207
|
+
if (state === null) {
|
|
208
|
+
return { allow: true };
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// No active claim → allow
|
|
212
|
+
if (!state.claimed) {
|
|
213
|
+
// But check for global in_progress (no session_id fallback)
|
|
214
|
+
if (!ctx.sessionId && state.inProgress && state.inProgress.count > 0) {
|
|
215
|
+
return {
|
|
216
|
+
allow: false,
|
|
217
|
+
reason: 'global_in_progress',
|
|
218
|
+
summary: state.inProgress.summary,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
return { allow: true };
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Claimed issue is no longer in_progress → allow (stale claim)
|
|
225
|
+
if (!state.claimInProgress) {
|
|
226
|
+
return { allow: true };
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Session's own claimed issue is still in_progress → block
|
|
230
|
+
return {
|
|
231
|
+
allow: false,
|
|
232
|
+
reason: 'unclosed_claim',
|
|
233
|
+
summary: ` Claimed: ${state.claimId} (still in_progress)`,
|
|
234
|
+
claimed: state.claimId,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// beads-gate-messages.mjs — centralized message templates for beads gate hooks
|
|
3
|
+
// Import from sibling hooks using: import { ... } from './beads-gate-messages.mjs';
|
|
4
|
+
//
|
|
5
|
+
// All user-facing strings live here. Edit this file to change messaging.
|
|
6
|
+
// Policy logic lives in beads-gate-core.mjs.
|
|
7
|
+
|
|
8
|
+
// ── Shared workflow steps ────────────────────────────────────────────
|
|
9
|
+
|
|
10
|
+
export const SESSION_CLOSE_PROTOCOL =
|
|
11
|
+
' bd close <id> --reason="..."\n' +
|
|
12
|
+
' xt end\n';
|
|
13
|
+
|
|
14
|
+
export const COMMIT_NEXT_STEPS =
|
|
15
|
+
' bd close <id> --reason="..." ← closes issue + auto-commits\n' +
|
|
16
|
+
' xt end ← push, PR, merge, worktree cleanup\n';
|
|
17
|
+
|
|
18
|
+
// ── Edit gate messages ───────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
export function editBlockMessage(_sessionId) {
|
|
21
|
+
return (
|
|
22
|
+
'🚫 No active claim — claim an issue first.\n' +
|
|
23
|
+
' bd update <id> --claim\n'
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function editBlockFallbackMessage() {
|
|
28
|
+
return (
|
|
29
|
+
'🚫 No active issue — create one before editing.\n' +
|
|
30
|
+
' bd create --title="<task>" --type=task --priority=2\n' +
|
|
31
|
+
' bd update <id> --claim\n'
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ── Commit gate messages ─────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
export function commitBlockMessage(summary, claimed) {
|
|
38
|
+
const issueSummary = summary ?? ` Claimed: ${claimed}`;
|
|
39
|
+
return (
|
|
40
|
+
'🚫 Close open issues before committing.\n\n' +
|
|
41
|
+
`${issueSummary}\n\n` +
|
|
42
|
+
'Next steps:\n' + COMMIT_NEXT_STEPS
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ── Stop gate messages ───────────────────────────────────────────
|
|
47
|
+
|
|
48
|
+
export function stopBlockMessage(summary, claimed) {
|
|
49
|
+
const issueSummary = summary ?? ` Claimed: ${claimed}`;
|
|
50
|
+
return (
|
|
51
|
+
'🚫 Unresolved issues — close before stopping.\n\n' +
|
|
52
|
+
`${issueSummary}\n\n` +
|
|
53
|
+
'Next steps:\n' + SESSION_CLOSE_PROTOCOL
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ── Memory gate messages ─────────────────────────────────────────
|
|
58
|
+
|
|
59
|
+
export function memoryPromptMessage(claimId) {
|
|
60
|
+
const claimLine = claimId ? `claim \`${claimId}\` was closed.\n` : '';
|
|
61
|
+
return (
|
|
62
|
+
`\u25cf Memory gate: ${claimLine}` +
|
|
63
|
+
'Ask: "Would this be useful in 14 days on a fresh session?"\n' +
|
|
64
|
+
' YES → `bd remember "<insight>"`\n' +
|
|
65
|
+
' NO → note "nothing to persist"\n' +
|
|
66
|
+
' Then: `touch .beads/.memory-gate-done`\n'
|
|
67
|
+
);
|
|
68
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// beads-gate-utils.mjs — shared infrastructure for beads gate hooks
|
|
3
|
+
// Import from sibling hooks using: import { ... } from './beads-gate-utils.mjs';
|
|
4
|
+
// Static ES module imports resolve relative to the importing file's location,
|
|
5
|
+
// not CWD, so this works regardless of the project directory.
|
|
6
|
+
|
|
7
|
+
import { execSync } from 'node:child_process';
|
|
8
|
+
import { existsSync } from 'node:fs';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
|
|
11
|
+
/** Resolve project cwd from hook input JSON. */
|
|
12
|
+
export function resolveCwd(input) {
|
|
13
|
+
return input.cwd ?? process.env.CLAUDE_PROJECT_DIR ?? process.cwd();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Resolve a stable session key for beads hooks.
|
|
18
|
+
* Priority: explicit hook session id -> cwd fallback.
|
|
19
|
+
*/
|
|
20
|
+
export function resolveSessionId(input) {
|
|
21
|
+
return input?.session_id ?? input?.sessionId ?? resolveCwd(input);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Return true if the directory contains a .beads project. */
|
|
25
|
+
export function isBeadsProject(cwd) {
|
|
26
|
+
return existsSync(join(cwd, '.beads'));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get the claimed issue ID for a session from bd kv.
|
|
31
|
+
* Returns: issue ID string if claimed, '' if not set, null if bd kv unavailable.
|
|
32
|
+
* Note: bd kv get exits 1 for missing keys — execSync throws, so we check err.status.
|
|
33
|
+
*/
|
|
34
|
+
export function getSessionClaim(sessionId, cwd) {
|
|
35
|
+
try {
|
|
36
|
+
return execSync(`bd kv get "claimed:${sessionId}"`, {
|
|
37
|
+
encoding: 'utf8',
|
|
38
|
+
cwd,
|
|
39
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
40
|
+
timeout: 5000,
|
|
41
|
+
}).trim();
|
|
42
|
+
} catch (err) {
|
|
43
|
+
if (err.status === 1) return ''; // key not found — no claim
|
|
44
|
+
return null; // command failed — bd kv unavailable
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Parse work counts from a bd list output string.
|
|
50
|
+
* Reads the "Total: N issues (X open, Y in progress)" summary line.
|
|
51
|
+
* Returns { open, inProgress } or null if the line is absent.
|
|
52
|
+
*
|
|
53
|
+
* This is more reliable than counting symbols or tokens: the Total line is
|
|
54
|
+
* a structured summary that doesn't depend on status-legend text or box-drawing
|
|
55
|
+
* characters, and it's present in all non-empty bd list outputs.
|
|
56
|
+
*/
|
|
57
|
+
function parseCounts(output) {
|
|
58
|
+
const m = output.match(/Total:\s*\d+\s+issues?\s*\((\d+)\s+open,\s*(\d+)\s+in progress\)/);
|
|
59
|
+
if (!m) return null;
|
|
60
|
+
return { open: parseInt(m[1], 10), inProgress: parseInt(m[2], 10) };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get in_progress issues as { count, summary }.
|
|
65
|
+
* Returns null if bd is unavailable.
|
|
66
|
+
*/
|
|
67
|
+
export function getInProgress(cwd) {
|
|
68
|
+
try {
|
|
69
|
+
const output = execSync('bd list --status=in_progress', {
|
|
70
|
+
encoding: 'utf8', cwd, stdio: ['pipe', 'pipe', 'pipe'], timeout: 8000,
|
|
71
|
+
});
|
|
72
|
+
const counts = parseCounts(output);
|
|
73
|
+
return {
|
|
74
|
+
count: counts?.inProgress ?? 0,
|
|
75
|
+
summary: output.trim(),
|
|
76
|
+
};
|
|
77
|
+
} catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Return true if a specific issue ID is currently in in_progress status.
|
|
84
|
+
* Used by commit/stop gates to scope the check to the session's own claimed issue.
|
|
85
|
+
* Returns false (fail open) if bd is unavailable.
|
|
86
|
+
*/
|
|
87
|
+
export function isIssueInProgress(issueId, cwd) {
|
|
88
|
+
if (!issueId) return false;
|
|
89
|
+
try {
|
|
90
|
+
const output = execSync('bd list --status=in_progress', {
|
|
91
|
+
encoding: 'utf8', cwd, stdio: ['pipe', 'pipe', 'pipe'], timeout: 8000,
|
|
92
|
+
});
|
|
93
|
+
return output.includes(issueId);
|
|
94
|
+
} catch {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Count total trackable work (open + in_progress issues) using a single bd list call.
|
|
101
|
+
* Returns the count, or null if bd is unavailable.
|
|
102
|
+
*/
|
|
103
|
+
export function getTotalWork(cwd) {
|
|
104
|
+
try {
|
|
105
|
+
// Use default status filter (non-closed) and parse Total summary.
|
|
106
|
+
// Repeating --status is not additive in bd CLI and can collapse to one status.
|
|
107
|
+
const output = execSync('bd list', {
|
|
108
|
+
encoding: 'utf8', cwd, stdio: ['pipe', 'pipe', 'pipe'], timeout: 8000,
|
|
109
|
+
});
|
|
110
|
+
const counts = parseCounts(output);
|
|
111
|
+
if (!counts) return 0; // "No issues found." — nothing to track
|
|
112
|
+
return counts.open + counts.inProgress;
|
|
113
|
+
} catch {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Get the closed-this-session issue ID for a session from bd kv.
|
|
120
|
+
* Returns: issue ID string if set, '' if not set, null if bd kv unavailable.
|
|
121
|
+
*/
|
|
122
|
+
export function getClosedThisSession(sessionId, cwd) {
|
|
123
|
+
try {
|
|
124
|
+
return execSync(`bd kv get "closed-this-session:${sessionId}"`, {
|
|
125
|
+
encoding: 'utf8',
|
|
126
|
+
cwd,
|
|
127
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
128
|
+
timeout: 5000,
|
|
129
|
+
}).trim();
|
|
130
|
+
} catch (err) {
|
|
131
|
+
if (err.status === 1) return ''; // key not found
|
|
132
|
+
return null; // bd kv unavailable
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Return true if the memory gate is pending acknowledgment for this session.
|
|
138
|
+
* Pending = closed-this-session kv is set AND .beads/.memory-gate-done marker is absent.
|
|
139
|
+
*/
|
|
140
|
+
export function isMemoryGatePending(sessionId, cwd) {
|
|
141
|
+
if (existsSync(join(cwd, '.beads', '.memory-gate-done'))) return false;
|
|
142
|
+
const closed = getClosedThisSession(sessionId, cwd);
|
|
143
|
+
return !!closed; // null (unavailable) is falsy → fail open
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Return true if a Bash command is a memory-gate acknowledgment command.
|
|
148
|
+
* These commands are allowed even while the memory gate is pending.
|
|
149
|
+
*/
|
|
150
|
+
export function isMemoryAckCommand(command) {
|
|
151
|
+
return /\bbd\s+remember\b/.test(command) || /\btouch\s+\.beads\/\.memory-gate-done\b/.test(command);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* If cwd is inside a .xtrm/worktrees/<name> directory, return the worktree root path.
|
|
156
|
+
* Returns null if not in a worktree.
|
|
157
|
+
*/
|
|
158
|
+
export function resolveWorktreeRoot(cwd) {
|
|
159
|
+
const m = cwd.match(/^(.+\/\.xtrm\/worktrees\/[^/]+)/);
|
|
160
|
+
return m ? m[1] : null;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Clear the session claim key from bd kv. Non-fatal — best-effort cleanup.
|
|
165
|
+
*/
|
|
166
|
+
export function clearSessionClaim(sessionId, cwd) {
|
|
167
|
+
try {
|
|
168
|
+
execSync(`bd kv clear "claimed:${sessionId}"`, {
|
|
169
|
+
encoding: 'utf8', cwd, stdio: ['pipe', 'pipe', 'pipe'], timeout: 5000,
|
|
170
|
+
});
|
|
171
|
+
} catch {
|
|
172
|
+
// non-fatal
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Option C: wrap hook body with uniform fail-open error handling.
|
|
178
|
+
* Any unexpected top-level throw exits 0 (allow) rather than crashing visibly.
|
|
179
|
+
*
|
|
180
|
+
* Usage:
|
|
181
|
+
* withSafeBdContext(() => {
|
|
182
|
+
* // hook logic here — call process.exit() to set exit code
|
|
183
|
+
* });
|
|
184
|
+
*/
|
|
185
|
+
export function withSafeBdContext(fn) {
|
|
186
|
+
try {
|
|
187
|
+
fn();
|
|
188
|
+
} catch (err) {
|
|
189
|
+
if (err instanceof TypeError || err instanceof ReferenceError || err instanceof SyntaxError) {
|
|
190
|
+
throw err;
|
|
191
|
+
}
|
|
192
|
+
process.exit(0);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// beads-memory-gate — Claude Code Stop hook
|
|
3
|
+
// At session end, forces the agent to evaluate whether this session's work
|
|
4
|
+
// produced insights worth persisting via `bd remember`.
|
|
5
|
+
// Runs after beads-stop-gate (all issues already closed by that point).
|
|
6
|
+
// Exit 0: allow stop | Exit 2: block stop (stderr shown to Claude)
|
|
7
|
+
//
|
|
8
|
+
// Installed by: xtrm install
|
|
9
|
+
|
|
10
|
+
import { execSync } from 'node:child_process';
|
|
11
|
+
import { existsSync, unlinkSync } from 'node:fs';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
import { readHookInput } from './beads-gate-core.mjs';
|
|
14
|
+
import { resolveCwd, resolveSessionId, isBeadsProject, getSessionClaim, clearSessionClaim } from './beads-gate-utils.mjs';
|
|
15
|
+
import { memoryPromptMessage } from './beads-gate-messages.mjs';
|
|
16
|
+
import { logEvent } from './xtrm-logger.mjs';
|
|
17
|
+
|
|
18
|
+
const input = readHookInput();
|
|
19
|
+
if (!input) process.exit(0);
|
|
20
|
+
|
|
21
|
+
const cwd = resolveCwd(input);
|
|
22
|
+
if (!cwd || !isBeadsProject(cwd)) process.exit(0);
|
|
23
|
+
|
|
24
|
+
const sessionId = resolveSessionId(input);
|
|
25
|
+
|
|
26
|
+
// Agent signals evaluation complete by touching this marker, then stops again
|
|
27
|
+
const marker = join(cwd, '.beads', '.memory-gate-done');
|
|
28
|
+
if (existsSync(marker)) {
|
|
29
|
+
try { unlinkSync(marker); } catch { /* ignore */ }
|
|
30
|
+
// Clear the claim and closed-this-session marker
|
|
31
|
+
clearSessionClaim(sessionId, cwd);
|
|
32
|
+
try {
|
|
33
|
+
execSync(`bd kv clear "closed-this-session:${sessionId}"`, {
|
|
34
|
+
cwd,
|
|
35
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
36
|
+
timeout: 5000,
|
|
37
|
+
});
|
|
38
|
+
} catch { /* ignore */ }
|
|
39
|
+
logEvent({
|
|
40
|
+
cwd,
|
|
41
|
+
runtime: 'claude',
|
|
42
|
+
sessionId,
|
|
43
|
+
layer: 'gate',
|
|
44
|
+
kind: 'gate.memory.acked',
|
|
45
|
+
outcome: 'allow',
|
|
46
|
+
});
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Check if an issue was closed this session (set by beads-claim-sync on bd close)
|
|
51
|
+
let closedIssueId = null;
|
|
52
|
+
try {
|
|
53
|
+
closedIssueId = execSync(`bd kv get "closed-this-session:${sessionId}"`, {
|
|
54
|
+
encoding: 'utf8',
|
|
55
|
+
cwd,
|
|
56
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
57
|
+
timeout: 5000,
|
|
58
|
+
}).trim();
|
|
59
|
+
} catch (err) {
|
|
60
|
+
if (err.status === 1) {
|
|
61
|
+
// No closed-this-session marker → nothing to prompt about
|
|
62
|
+
process.exit(0);
|
|
63
|
+
}
|
|
64
|
+
process.exit(0); // fail open
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!closedIssueId) process.exit(0);
|
|
68
|
+
|
|
69
|
+
const memoryMessage = memoryPromptMessage();
|
|
70
|
+
logEvent({
|
|
71
|
+
cwd,
|
|
72
|
+
runtime: 'claude',
|
|
73
|
+
sessionId,
|
|
74
|
+
layer: 'gate',
|
|
75
|
+
kind: 'gate.memory.triggered',
|
|
76
|
+
outcome: 'block',
|
|
77
|
+
issueId: closedIssueId,
|
|
78
|
+
message: memoryMessage,
|
|
79
|
+
});
|
|
80
|
+
process.stderr.write(memoryMessage);
|
|
81
|
+
process.exit(2);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// beads-stop-gate — Claude Code Stop hook
|
|
3
|
+
// Blocks the agent from stopping when this session has an unclosed claim in bd kv.
|
|
4
|
+
// Also blocks when xtrm session state indicates unfinished closure phases.
|
|
5
|
+
// Exit 0: allow stop | Exit 2: block stop (stderr shown to Claude)
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
readHookInput,
|
|
9
|
+
resolveSessionContext,
|
|
10
|
+
resolveClaimAndWorkState,
|
|
11
|
+
decideStopGate,
|
|
12
|
+
} from './beads-gate-core.mjs';
|
|
13
|
+
import { withSafeBdContext } from './beads-gate-utils.mjs';
|
|
14
|
+
import { stopBlockMessage } from './beads-gate-messages.mjs';
|
|
15
|
+
import { logEvent } from './xtrm-logger.mjs';
|
|
16
|
+
|
|
17
|
+
const input = readHookInput();
|
|
18
|
+
if (!input) process.exit(0);
|
|
19
|
+
|
|
20
|
+
withSafeBdContext(() => {
|
|
21
|
+
const ctx = resolveSessionContext(input);
|
|
22
|
+
if (!ctx || !ctx.isBeadsProject) process.exit(0);
|
|
23
|
+
|
|
24
|
+
const state = resolveClaimAndWorkState(ctx);
|
|
25
|
+
const decision = decideStopGate(ctx, state);
|
|
26
|
+
|
|
27
|
+
if (!decision.allow) {
|
|
28
|
+
const message = stopBlockMessage(decision.summary, decision.claimed);
|
|
29
|
+
logEvent({
|
|
30
|
+
cwd: ctx.cwd,
|
|
31
|
+
runtime: 'claude',
|
|
32
|
+
sessionId: ctx.sessionId,
|
|
33
|
+
layer: 'gate',
|
|
34
|
+
kind: 'gate.stop.block',
|
|
35
|
+
outcome: 'block',
|
|
36
|
+
issueId: decision.claimed ?? null,
|
|
37
|
+
message,
|
|
38
|
+
extra: { reason_code: decision.reason },
|
|
39
|
+
});
|
|
40
|
+
process.stderr.write(message);
|
|
41
|
+
process.exit(2);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
logEvent({
|
|
45
|
+
cwd: ctx.cwd,
|
|
46
|
+
runtime: 'claude',
|
|
47
|
+
sessionId: ctx.sessionId,
|
|
48
|
+
layer: 'gate',
|
|
49
|
+
kind: 'session.end',
|
|
50
|
+
outcome: 'allow',
|
|
51
|
+
});
|
|
52
|
+
process.exit(0);
|
|
53
|
+
});
|