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.
- package/CHANGELOG.md +504 -0
- package/README.md +201 -0
- package/cli/dist/index.cjs +57378 -0
- package/cli/dist/index.cjs.map +1 -0
- package/cli/dist/index.d.cts +2 -0
- package/cli/package.json +47 -0
- package/config/.env.example +40 -0
- package/config/hooks.json +72 -0
- package/config/instructions/agents-top.md +30 -0
- package/config/instructions/claude-top.md +30 -0
- package/config/mcp_servers.json +57 -0
- package/config/mcp_servers_optional.json +53 -0
- package/config/pi/auth.json.template +14 -0
- package/config/pi/extensions/auto-session-name/index.ts +29 -0
- package/config/pi/extensions/auto-session-name/package.json +16 -0
- package/config/pi/extensions/auto-update/index.ts +71 -0
- package/config/pi/extensions/auto-update/package.json +16 -0
- package/config/pi/extensions/beads/index.ts +166 -0
- package/config/pi/extensions/beads/package.json +16 -0
- package/config/pi/extensions/bg-process/index.ts +230 -0
- package/config/pi/extensions/bg-process/package.json +16 -0
- package/config/pi/extensions/compact-header/index.ts +69 -0
- package/config/pi/extensions/compact-header/package.json +16 -0
- package/config/pi/extensions/core/adapter.ts +52 -0
- package/config/pi/extensions/core/guard-rules.ts +102 -0
- package/config/pi/extensions/core/lib.ts +3 -0
- package/config/pi/extensions/core/logger.ts +45 -0
- package/config/pi/extensions/core/runner.ts +71 -0
- package/config/pi/extensions/core/session-state.ts +59 -0
- package/config/pi/extensions/custom-footer/index.ts +160 -0
- package/config/pi/extensions/custom-footer/package.json +16 -0
- package/config/pi/extensions/custom-provider-qwen-cli/index.ts +363 -0
- package/config/pi/extensions/custom-provider-qwen-cli/package.json +1 -0
- package/config/pi/extensions/git-checkpoint/index.ts +53 -0
- package/config/pi/extensions/git-checkpoint/package.json +16 -0
- package/config/pi/extensions/minimal-mode/index.ts +201 -0
- package/config/pi/extensions/minimal-mode/package.json +16 -0
- package/config/pi/extensions/plan-mode/README.md +65 -0
- package/config/pi/extensions/plan-mode/index.ts +417 -0
- package/config/pi/extensions/plan-mode/package.json +12 -0
- package/config/pi/extensions/plan-mode/utils.ts +324 -0
- package/config/pi/extensions/quality-gates/index.ts +67 -0
- package/config/pi/extensions/quality-gates/package.json +16 -0
- package/config/pi/extensions/service-skills/index.ts +108 -0
- package/config/pi/extensions/service-skills/package.json +16 -0
- package/config/pi/extensions/session-flow/index.ts +131 -0
- package/config/pi/extensions/session-flow/package.json +16 -0
- package/config/pi/extensions/todo/index.ts +299 -0
- package/config/pi/extensions/todo/package.json +16 -0
- package/config/pi/extensions/xtrm-loader/index.ts +89 -0
- package/config/pi/extensions/xtrm-loader/package.json +16 -0
- package/config/pi/install-schema.json +44 -0
- package/config/pi/models.json.template +76 -0
- package/config/pi/pi-worktrees-settings.json +6 -0
- package/config/pi/settings.json.template +16 -0
- package/config/settings.json +70 -0
- package/hooks/README.md +75 -0
- package/hooks/agent_context.py +105 -0
- package/hooks/beads-claim-sync.mjs +166 -0
- package/hooks/beads-commit-gate.mjs +55 -0
- package/hooks/beads-compact-restore.mjs +69 -0
- package/hooks/beads-compact-save.mjs +51 -0
- package/hooks/beads-edit-gate.mjs +45 -0
- package/hooks/beads-gate-core.mjs +215 -0
- package/hooks/beads-gate-messages.mjs +87 -0
- package/hooks/beads-gate-utils.mjs +185 -0
- package/hooks/beads-memory-gate.mjs +61 -0
- package/hooks/beads-stop-gate.mjs +32 -0
- package/hooks/branch-state.mjs +39 -0
- package/hooks/gitnexus/gitnexus-hook.cjs +222 -0
- package/hooks/guard-rules.mjs +118 -0
- package/hooks/hooks.json +116 -0
- package/hooks/main-guard-post-push.mjs +71 -0
- package/hooks/main-guard.mjs +119 -0
- package/hooks/quality-check.cjs +1286 -0
- package/hooks/quality-check.py +345 -0
- package/hooks/serena-workflow-reminder.py +74 -0
- package/package.json +77 -0
- package/project-skills/quality-gates/.claude/hooks/hook-config.json +66 -0
- package/project-skills/quality-gates/.claude/hooks/quality-check.cjs +1286 -0
- package/project-skills/quality-gates/.claude/hooks/quality-check.py +334 -0
- package/project-skills/quality-gates/.claude/settings.json +3 -0
- package/project-skills/quality-gates/.claude/skills/using-quality-gates/SKILL.md +254 -0
- package/project-skills/quality-gates/README.md +109 -0
- package/project-skills/quality-gates/evals/evals.json +181 -0
- package/project-skills/quality-gates/workspace/iteration-1/FINAL-EVAL-SUMMARY.md +75 -0
- package/project-skills/quality-gates/workspace/iteration-1/edge-case-auto-fix-verification/with_skill/outputs/response.md +59 -0
- package/project-skills/quality-gates/workspace/iteration-1/edge-case-mixed-language-project/with_skill/outputs/response.md +60 -0
- package/project-skills/quality-gates/workspace/iteration-1/eval-summary.md +105 -0
- package/project-skills/quality-gates/workspace/iteration-1/partial-install-python-only/with_skill/outputs/response.md +93 -0
- package/project-skills/quality-gates/workspace/iteration-1/python-refactor-request/with_skill/outputs/response.md +104 -0
- package/project-skills/quality-gates/workspace/iteration-1/quality-gate-error-fix/with_skill/outputs/response.md +74 -0
- package/project-skills/quality-gates/workspace/iteration-1/should-not-trigger-general-chat/with_skill/outputs/response.md +18 -0
- package/project-skills/quality-gates/workspace/iteration-1/should-not-trigger-math-question/with_skill/outputs/response.md +18 -0
- package/project-skills/quality-gates/workspace/iteration-1/should-not-trigger-unrelated-coding/with_skill/outputs/response.md +56 -0
- package/project-skills/quality-gates/workspace/iteration-1/tdd-guard-blocking-confusion/with_skill/outputs/response.md +67 -0
- package/project-skills/quality-gates/workspace/iteration-1/typescript-feature-with-tests/with_skill/outputs/response.md +97 -0
- package/project-skills/service-skills-set/.claude/git-hooks/doc_reminder.py +67 -0
- package/project-skills/service-skills-set/.claude/git-hooks/skill_staleness.py +194 -0
- package/project-skills/service-skills-set/.claude/service-registry.json +4 -0
- package/project-skills/service-skills-set/.claude/settings.json +37 -0
- package/project-skills/service-skills-set/.claude/skills/creating-service-skills/SKILL.md +433 -0
- package/project-skills/service-skills-set/.claude/skills/creating-service-skills/references/script_quality_standards.md +425 -0
- package/project-skills/service-skills-set/.claude/skills/creating-service-skills/references/service_skill_system_guide.md +278 -0
- package/project-skills/service-skills-set/.claude/skills/creating-service-skills/scripts/bootstrap.py +308 -0
- package/project-skills/service-skills-set/.claude/skills/creating-service-skills/scripts/deep_dive.py +304 -0
- package/project-skills/service-skills-set/.claude/skills/creating-service-skills/scripts/scaffolder.py +482 -0
- package/project-skills/service-skills-set/.claude/skills/scoping-service-skills/SKILL.md +231 -0
- package/project-skills/service-skills-set/.claude/skills/scoping-service-skills/scripts/scope.py +74 -0
- package/project-skills/service-skills-set/.claude/skills/updating-service-skills/SKILL.md +136 -0
- package/project-skills/service-skills-set/.claude/skills/updating-service-skills/scripts/drift_detector.py +222 -0
- package/project-skills/service-skills-set/.claude/skills/using-service-skills/SKILL.md +108 -0
- package/project-skills/service-skills-set/.claude/skills/using-service-skills/scripts/cataloger.py +74 -0
- package/project-skills/service-skills-set/.claude/skills/using-service-skills/scripts/skill_activator.py +152 -0
- package/project-skills/service-skills-set/README.md +93 -0
- package/project-skills/service-skills-set/install-service-skills.py +193 -0
- package/project-skills/service-skills-set/service-skills-readme.md +236 -0
- package/skills/README.txt +31 -0
- package/skills/clean-code/SKILL.md +201 -0
- package/skills/creating-service-skills/SKILL.md +433 -0
- package/skills/creating-service-skills/references/script_quality_standards.md +425 -0
- package/skills/creating-service-skills/references/service_skill_system_guide.md +278 -0
- package/skills/creating-service-skills/scripts/bootstrap.py +326 -0
- package/skills/creating-service-skills/scripts/deep_dive.py +304 -0
- package/skills/creating-service-skills/scripts/scaffolder.py +482 -0
- package/skills/delegating/SKILL.md +196 -0
- package/skills/delegating/config.yaml +210 -0
- package/skills/delegating/references/orchestration-protocols.md +41 -0
- package/skills/docker-expert/SKILL.md +409 -0
- package/skills/documenting/CHANGELOG.md +23 -0
- package/skills/documenting/README.md +148 -0
- package/skills/documenting/SKILL.md +113 -0
- package/skills/documenting/examples/example_pattern.md +70 -0
- package/skills/documenting/examples/example_reference.md +70 -0
- package/skills/documenting/examples/example_ssot_analytics.md +64 -0
- package/skills/documenting/examples/example_workflow.md +141 -0
- package/skills/documenting/references/changelog-format.md +97 -0
- package/skills/documenting/references/metadata-schema.md +136 -0
- package/skills/documenting/references/taxonomy.md +81 -0
- package/skills/documenting/references/versioning-rules.md +78 -0
- package/skills/documenting/scripts/bump_version.sh +60 -0
- package/skills/documenting/scripts/changelog/__init__.py +0 -0
- package/skills/documenting/scripts/changelog/add_entry.py +216 -0
- package/skills/documenting/scripts/changelog/bump_release.py +117 -0
- package/skills/documenting/scripts/changelog/init_changelog.py +54 -0
- package/skills/documenting/scripts/changelog/validate_changelog.py +128 -0
- package/skills/documenting/scripts/drift_detector.py +266 -0
- package/skills/documenting/scripts/generate_template.py +311 -0
- package/skills/documenting/scripts/list_by_category.sh +84 -0
- package/skills/documenting/scripts/orchestrator.py +255 -0
- package/skills/documenting/scripts/validate_metadata.py +242 -0
- package/skills/documenting/templates/CHANGELOG.md.template +13 -0
- package/skills/find-skills/SKILL.md +133 -0
- package/skills/gitnexus-debugging/SKILL.md +85 -0
- package/skills/gitnexus-exploring/SKILL.md +75 -0
- package/skills/gitnexus-impact-analysis/SKILL.md +94 -0
- package/skills/gitnexus-refactoring/SKILL.md +113 -0
- package/skills/hook-development/SKILL.md +797 -0
- package/skills/hook-development/examples/load-context.sh +55 -0
- package/skills/hook-development/examples/quality-check.js +1168 -0
- package/skills/hook-development/examples/validate-bash.sh +43 -0
- package/skills/hook-development/examples/validate-write.sh +38 -0
- package/skills/hook-development/references/advanced.md +527 -0
- package/skills/hook-development/references/migration.md +369 -0
- package/skills/hook-development/references/patterns.md +412 -0
- package/skills/hook-development/scripts/README.md +164 -0
- package/skills/hook-development/scripts/hook-linter.sh +153 -0
- package/skills/hook-development/scripts/test-hook.sh +252 -0
- package/skills/hook-development/scripts/validate-hook-schema.sh +159 -0
- package/skills/obsidian-cli/SKILL.md +106 -0
- package/skills/orchestrating-agents/SKILL.md +135 -0
- package/skills/orchestrating-agents/config.yaml +45 -0
- package/skills/orchestrating-agents/references/agent-context-integration.md +37 -0
- package/skills/orchestrating-agents/references/examples.md +45 -0
- package/skills/orchestrating-agents/references/handover-protocol.md +31 -0
- package/skills/orchestrating-agents/references/workflows.md +42 -0
- package/skills/orchestrating-agents/scripts/detect_neighbors.py +23 -0
- package/skills/prompt-improving/README.md +162 -0
- package/skills/prompt-improving/SKILL.md +74 -0
- package/skills/prompt-improving/references/analysis_commands.md +24 -0
- package/skills/prompt-improving/references/chain_of_thought.md +24 -0
- package/skills/prompt-improving/references/mcp_definitions.md +20 -0
- package/skills/prompt-improving/references/multishot.md +23 -0
- package/skills/prompt-improving/references/xml_core.md +60 -0
- package/skills/python-testing/SKILL.md +815 -0
- package/skills/scoping-service-skills/SKILL.md +231 -0
- package/skills/scoping-service-skills/scripts/scope.py +74 -0
- package/skills/senior-backend/SKILL.md +209 -0
- package/skills/senior-backend/references/api_design_patterns.md +103 -0
- package/skills/senior-backend/references/backend_security_practices.md +103 -0
- package/skills/senior-backend/references/database_optimization_guide.md +103 -0
- package/skills/senior-backend/scripts/api_load_tester.py +114 -0
- package/skills/senior-backend/scripts/api_scaffolder.py +114 -0
- package/skills/senior-backend/scripts/database_migration_tool.py +114 -0
- package/skills/senior-data-scientist/SKILL.md +226 -0
- package/skills/senior-data-scientist/references/experiment_design_frameworks.md +80 -0
- package/skills/senior-data-scientist/references/feature_engineering_patterns.md +80 -0
- package/skills/senior-data-scientist/references/statistical_methods_advanced.md +80 -0
- package/skills/senior-data-scientist/scripts/experiment_designer.py +100 -0
- package/skills/senior-data-scientist/scripts/feature_engineering_pipeline.py +100 -0
- package/skills/senior-data-scientist/scripts/model_evaluation_suite.py +100 -0
- package/skills/senior-devops/SKILL.md +209 -0
- package/skills/senior-devops/references/cicd_pipeline_guide.md +103 -0
- package/skills/senior-devops/references/deployment_strategies.md +103 -0
- package/skills/senior-devops/references/infrastructure_as_code.md +103 -0
- package/skills/senior-devops/scripts/deployment_manager.py +114 -0
- package/skills/senior-devops/scripts/pipeline_generator.py +114 -0
- package/skills/senior-devops/scripts/terraform_scaffolder.py +114 -0
- package/skills/senior-security/SKILL.md +209 -0
- package/skills/senior-security/references/cryptography_implementation.md +103 -0
- package/skills/senior-security/references/penetration_testing_guide.md +103 -0
- package/skills/senior-security/references/security_architecture_patterns.md +103 -0
- package/skills/senior-security/scripts/pentest_automator.py +114 -0
- package/skills/senior-security/scripts/security_auditor.py +114 -0
- package/skills/senior-security/scripts/threat_modeler.py +114 -0
- package/skills/skill-creator/LICENSE.txt +202 -0
- package/skills/skill-creator/SKILL.md +479 -0
- package/skills/skill-creator/agents/analyzer.md +274 -0
- package/skills/skill-creator/agents/comparator.md +202 -0
- package/skills/skill-creator/agents/grader.md +223 -0
- package/skills/skill-creator/assets/eval_review.html +146 -0
- package/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/skills/skill-creator/references/schemas.md +430 -0
- package/skills/skill-creator/scripts/__init__.py +0 -0
- package/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/skills/skill-creator/scripts/generate_report.py +326 -0
- package/skills/skill-creator/scripts/improve_description.py +248 -0
- package/skills/skill-creator/scripts/package_skill.py +136 -0
- package/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/skills/skill-creator/scripts/run_eval.py +310 -0
- package/skills/skill-creator/scripts/run_loop.py +332 -0
- package/skills/skill-creator/scripts/utils.py +47 -0
- package/skills/sync-docs/SKILL.md +132 -0
- package/skills/sync-docs/evals/evals.json +89 -0
- package/skills/sync-docs/references/doc-structure.md +99 -0
- package/skills/sync-docs/references/schema.md +103 -0
- package/skills/sync-docs/scripts/changelog/add_entry.py +216 -0
- package/skills/sync-docs/scripts/context_gatherer.py +240 -0
- package/skills/sync-docs/scripts/doc_structure_analyzer.py +495 -0
- package/skills/sync-docs/scripts/drift_detector.py +327 -0
- package/skills/sync-docs/scripts/validate_doc.py +365 -0
- package/skills/sync-docs/scripts/validate_metadata.py +185 -0
- package/skills/sync-docs-workspace/iteration-1/benchmark.json +293 -0
- package/skills/sync-docs-workspace/iteration-1/benchmark.md +13 -0
- package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/eval_metadata.json +27 -0
- package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/outputs/result.md +210 -0
- package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/run-1/grading.json +28 -0
- package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/run-1/timing.json +1 -0
- package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/outputs/result.md +101 -0
- package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/run-1/grading.json +28 -0
- package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/run-1/timing.json +5 -0
- package/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/timing.json +5 -0
- package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/eval_metadata.json +27 -0
- package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/outputs/result.md +198 -0
- package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/run-1/grading.json +28 -0
- package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/run-1/timing.json +1 -0
- package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/outputs/result.md +94 -0
- package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/run-1/grading.json +28 -0
- package/skills/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/run-1/timing.json +1 -0
- package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/eval_metadata.json +27 -0
- package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/outputs/result.md +237 -0
- package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/run-1/grading.json +28 -0
- package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/run-1/timing.json +1 -0
- package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/outputs/result.md +134 -0
- package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/run-1/grading.json +28 -0
- package/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/run-1/timing.json +1 -0
- package/skills/sync-docs-workspace/iteration-2/benchmark.json +297 -0
- package/skills/sync-docs-workspace/iteration-2/benchmark.md +13 -0
- package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/eval_metadata.json +27 -0
- package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/outputs/result.md +137 -0
- package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/run-1/grading.json +92 -0
- package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/run-1/timing.json +1 -0
- package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/outputs/result.md +134 -0
- package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/run-1/grading.json +86 -0
- package/skills/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/run-1/timing.json +1 -0
- package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/eval_metadata.json +27 -0
- package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/outputs/result.md +193 -0
- package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/run-1/grading.json +72 -0
- package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/run-1/timing.json +1 -0
- package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/outputs/result.md +211 -0
- package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/run-1/grading.json +91 -0
- package/skills/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/run-1/timing.json +5 -0
- package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/eval_metadata.json +27 -0
- package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/outputs/result.md +182 -0
- package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/run-1/grading.json +95 -0
- package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/run-1/timing.json +1 -0
- package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/outputs/result.md +222 -0
- package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/run-1/grading.json +88 -0
- package/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/run-1/timing.json +5 -0
- package/skills/sync-docs-workspace/iteration-3/benchmark.json +298 -0
- package/skills/sync-docs-workspace/iteration-3/benchmark.md +13 -0
- package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/eval_metadata.json +27 -0
- package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/outputs/result.md +125 -0
- package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/run-1/grading.json +97 -0
- package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/run-1/timing.json +5 -0
- package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/outputs/result.md +144 -0
- package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/run-1/grading.json +78 -0
- package/skills/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/run-1/timing.json +5 -0
- package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/eval_metadata.json +27 -0
- package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/outputs/result.md +104 -0
- package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/run-1/grading.json +91 -0
- package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/run-1/timing.json +5 -0
- package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/outputs/result.md +79 -0
- package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/run-1/grading.json +82 -0
- package/skills/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/run-1/timing.json +5 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/eval_metadata.json +27 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase1_context.json +302 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase2_drift.txt +33 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase3_analysis.json +114 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase4_fix.txt +118 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase5_validate.txt +38 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/result.md +158 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/run-1/grading.json +95 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/run-1/timing.json +5 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/outputs/result.md +71 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/run-1/grading.json +90 -0
- package/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/run-1/timing.json +5 -0
- package/skills/test-planning/SKILL.md +208 -0
- package/skills/test-planning/evals/evals.json +23 -0
- package/skills/updating-service-skills/SKILL.md +136 -0
- package/skills/updating-service-skills/scripts/drift_detector.py +222 -0
- package/skills/using-TDD/SKILL.md +410 -0
- package/skills/using-quality-gates/SKILL.md +254 -0
- package/skills/using-serena-lsp/README.md +8 -0
- package/skills/using-serena-lsp/REFERENCE.md +194 -0
- package/skills/using-serena-lsp/SKILL.md +82 -0
- package/skills/using-service-skills/SKILL.md +108 -0
- package/skills/using-service-skills/scripts/cataloger.py +74 -0
- package/skills/using-service-skills/scripts/skill_activator.py +152 -0
- package/skills/using-service-skills/scripts/test_skill_activator.py +58 -0
- package/skills/using-xtrm/SKILL.md +245 -0
- package/skills/xt-end/SKILL.md +128 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# docs/ Structure Guide
|
|
2
|
+
|
|
3
|
+
This reference defines what belongs in each focused docs/ file vs README.md.
|
|
4
|
+
|
|
5
|
+
## The Rule
|
|
6
|
+
|
|
7
|
+
**README.md** is an entry point — a quick-start and orientation map. It should be < 200 lines. Anything that requires more than a few bullet points belongs in a focused docs/ file.
|
|
8
|
+
|
|
9
|
+
**docs/** holds focused, public-facing SSOT files for each subsystem. Each file:
|
|
10
|
+
- Has YAML frontmatter (see `schema.md`)
|
|
11
|
+
- Covers exactly one subsystem or concern
|
|
12
|
+
- Is linked from README.md with a single line
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## What Goes Where
|
|
17
|
+
|
|
18
|
+
| Content Type | Location | When to Create |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| Quick start, one-liner install | `README.md` | Always |
|
|
21
|
+
| Feature overview table | `README.md` | Always, < 20 lines |
|
|
22
|
+
| Hook events, scripts, behavior | `docs/hooks.md` | When hooks/ dir exists |
|
|
23
|
+
| Pi/Copilot extension catalog | `docs/pi-extensions.md` | When config/pi/extensions/ exists |
|
|
24
|
+
| System architecture, components | `docs/architecture.md` | When > 2 major subsystems |
|
|
25
|
+
| Policy rules and enforcement | `docs/policies.md` | When policies/ dir exists |
|
|
26
|
+
| MCP server config and usage | `docs/mcp-servers.md` | When .mcp.json or mcp servers exist |
|
|
27
|
+
| Skills catalog | `docs/skills.md` | When skills/ dir has > 5 skills |
|
|
28
|
+
| CLI commands reference | `docs/cli-reference.md` | When CLI has > 10 commands |
|
|
29
|
+
| Troubleshooting and FAQs | `docs/troubleshooting.md` | When recurring issues exist |
|
|
30
|
+
| In-progress work plans | `docs/plans/` | Always for planning docs |
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Standard File Shapes
|
|
35
|
+
|
|
36
|
+
### docs/hooks.md
|
|
37
|
+
Covers: hook events, what triggers each hook, which scripts run, output format.
|
|
38
|
+
Section outline:
|
|
39
|
+
```
|
|
40
|
+
## Overview
|
|
41
|
+
## Hook Events
|
|
42
|
+
## Scripts Reference
|
|
43
|
+
## Adding a New Hook
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### docs/pi-extensions.md
|
|
47
|
+
Covers: what Pi extensions are installed, their events, behavior, and configuration.
|
|
48
|
+
Section outline:
|
|
49
|
+
```
|
|
50
|
+
## Overview
|
|
51
|
+
## Installed Extensions
|
|
52
|
+
## Extension Events
|
|
53
|
+
## Configuration
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### docs/architecture.md
|
|
57
|
+
Covers: system overview, key components, data flow, dependency diagram.
|
|
58
|
+
Section outline:
|
|
59
|
+
```
|
|
60
|
+
## System Overview
|
|
61
|
+
## Key Components
|
|
62
|
+
## Data Flow
|
|
63
|
+
## Directory Structure
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### docs/policies.md
|
|
67
|
+
Covers: what policies exist, what each enforces, runtime targets.
|
|
68
|
+
Section outline:
|
|
69
|
+
```
|
|
70
|
+
## Overview
|
|
71
|
+
## Policy Files
|
|
72
|
+
## Policy Compiler
|
|
73
|
+
## Adding a Policy
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Detecting When README is Too Big
|
|
79
|
+
|
|
80
|
+
The `doc_structure_analyzer.py` script flags README as `BLOATED` when:
|
|
81
|
+
1. Line count > 200, AND
|
|
82
|
+
2. At least one section has a matching `docs/` file that doesn't exist yet
|
|
83
|
+
|
|
84
|
+
The `EXTRACTABLE` status means sections are present but README isn't over threshold yet — worth noting but not urgent.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Extraction Process
|
|
89
|
+
|
|
90
|
+
When extracting a section from README to docs/:
|
|
91
|
+
|
|
92
|
+
1. Identify the target section heading and its body in `README.md`
|
|
93
|
+
2. Create `docs/X.md` with `validate_doc.py --generate`
|
|
94
|
+
3. Move the section content into the new file
|
|
95
|
+
4. Replace the original README section with:
|
|
96
|
+
```markdown
|
|
97
|
+
See [docs/X.md](docs/X.md) for the full reference.
|
|
98
|
+
```
|
|
99
|
+
5. Run `validate_doc.py docs/X.md` to confirm schema
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# docs/ File Schema
|
|
2
|
+
|
|
3
|
+
Every file in `docs/` must have YAML frontmatter. This is enforced by `validate_doc.py`.
|
|
4
|
+
|
|
5
|
+
## Frontmatter Fields
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
---
|
|
9
|
+
title: Human Readable Title # required — clear, descriptive
|
|
10
|
+
scope: kebab-case-identifier # required — unique slug for this doc
|
|
11
|
+
category: reference # required — see valid values below
|
|
12
|
+
version: 1.0.0 # required — semver (x.y.z)
|
|
13
|
+
updated: 2026-03-18 # required — ISO date of last update
|
|
14
|
+
description: "One-line summary" # optional
|
|
15
|
+
source_of_truth_for: # optional — glob patterns this doc describes
|
|
16
|
+
- "hooks/**/*.mjs"
|
|
17
|
+
- "policies/*.json"
|
|
18
|
+
domain: [hooks, claude, policy] # optional — cross-cutting tags
|
|
19
|
+
---
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Required Fields
|
|
23
|
+
|
|
24
|
+
| Field | Type | Description | Example |
|
|
25
|
+
|-------|------|-------------|---------|
|
|
26
|
+
| `title` | string | Clear, descriptive title | "Hooks Reference" |
|
|
27
|
+
| `scope` | string | Unique kebab-case slug | "hooks" |
|
|
28
|
+
| `category` | enum | Document type | "reference" |
|
|
29
|
+
| `version` | semver | x.y.z — bump on every update | "1.2.0" |
|
|
30
|
+
| `updated` | date | YYYY-MM-DD of last change | "2026-03-18" |
|
|
31
|
+
|
|
32
|
+
## Category Values
|
|
33
|
+
|
|
34
|
+
| Value | Purpose |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `reference` | Look-up table, cheat sheet, technical spec |
|
|
37
|
+
| `guide` | Step-by-step how-to documentation |
|
|
38
|
+
| `architecture` | System design and component overview |
|
|
39
|
+
| `api` | API contracts, interfaces, schemas |
|
|
40
|
+
| `plan` | Implementation plan or roadmap |
|
|
41
|
+
| `overview` | Summary introduction to a subsystem |
|
|
42
|
+
|
|
43
|
+
## Optional Fields
|
|
44
|
+
|
|
45
|
+
### source_of_truth_for
|
|
46
|
+
A list of glob patterns (fnmatch syntax) pointing to the source files this doc describes. Used by `drift_detector.py` and `doc_structure_analyzer.py` to detect when the source changed but the doc wasn't updated.
|
|
47
|
+
|
|
48
|
+
```yaml
|
|
49
|
+
source_of_truth_for:
|
|
50
|
+
- "hooks/**/*.mjs"
|
|
51
|
+
- "policies/*.json"
|
|
52
|
+
- "config/pi/extensions/**/*.ts"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### domain
|
|
56
|
+
Tags for cross-cutting concerns. Useful for searching related docs.
|
|
57
|
+
|
|
58
|
+
```yaml
|
|
59
|
+
domain: [hooks, claude, pi, enforcement]
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Version Bumping Rules
|
|
63
|
+
|
|
64
|
+
| Change | Bump |
|
|
65
|
+
|---|---|
|
|
66
|
+
| Fix a typo or outdated detail | `patch` (1.0.0 → 1.0.1) |
|
|
67
|
+
| Add a new section | `minor` (1.0.0 → 1.1.0) |
|
|
68
|
+
| Full rewrite or restructure | `major` (1.0.0 → 2.0.0) |
|
|
69
|
+
|
|
70
|
+
Always update `updated:` to today's date alongside the version bump.
|
|
71
|
+
|
|
72
|
+
## INDEX Block
|
|
73
|
+
|
|
74
|
+
`validate_doc.py` auto-generates a navigation table from `##` headings:
|
|
75
|
+
|
|
76
|
+
```markdown
|
|
77
|
+
<!-- INDEX: auto-generated by validate_doc.py — do not edit manually -->
|
|
78
|
+
| Section | Summary |
|
|
79
|
+
|---|---|
|
|
80
|
+
| [Overview](#overview) | ... |
|
|
81
|
+
| [Hook Events](#hook-events) | ... |
|
|
82
|
+
<!-- END INDEX -->
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
This block is regenerated every time `validate_doc.py` runs on the file. Do not edit it manually.
|
|
86
|
+
|
|
87
|
+
## Complete Example
|
|
88
|
+
|
|
89
|
+
```yaml
|
|
90
|
+
---
|
|
91
|
+
title: Hooks Reference
|
|
92
|
+
scope: hooks
|
|
93
|
+
category: reference
|
|
94
|
+
version: 1.1.0
|
|
95
|
+
updated: 2026-03-18
|
|
96
|
+
description: "All hook events, scripts, and behavior for the xtrm plugin"
|
|
97
|
+
source_of_truth_for:
|
|
98
|
+
- "hooks/**/*.mjs"
|
|
99
|
+
- "policies/beads.json"
|
|
100
|
+
- "policies/main-guard.json"
|
|
101
|
+
domain: [hooks, claude, enforcement]
|
|
102
|
+
---
|
|
103
|
+
```
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Add entry to CHANGELOG.md [Unreleased] section.
|
|
4
|
+
|
|
5
|
+
Automatically:
|
|
6
|
+
- Places entry in correct category
|
|
7
|
+
- Creates category if missing
|
|
8
|
+
- Maintains category ordering per Keep a Changelog
|
|
9
|
+
- Preserves existing entries
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
import re
|
|
13
|
+
import sys
|
|
14
|
+
from enum import Enum
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import Optional
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ChangeCategory(Enum):
|
|
20
|
+
"""Keep a Changelog categories in proper order."""
|
|
21
|
+
ADDED = "Added"
|
|
22
|
+
CHANGED = "Changed"
|
|
23
|
+
DEPRECATED = "Deprecated"
|
|
24
|
+
REMOVED = "Removed"
|
|
25
|
+
FIXED = "Fixed"
|
|
26
|
+
SECURITY = "Security"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
CATEGORY_ORDER = [cat.value for cat in ChangeCategory]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def add_entry(changelog_content: str, category: ChangeCategory, description: str) -> str:
|
|
33
|
+
"""
|
|
34
|
+
Add entry to [Unreleased] section under specified category.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
changelog_content: Full CHANGELOG.md content
|
|
38
|
+
category: ChangeCategory enum value
|
|
39
|
+
description: Entry text (without leading "- ")
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Updated changelog content
|
|
43
|
+
"""
|
|
44
|
+
lines = changelog_content.splitlines()
|
|
45
|
+
|
|
46
|
+
# Find [Unreleased] section
|
|
47
|
+
unreleased_idx = None
|
|
48
|
+
for i, line in enumerate(lines):
|
|
49
|
+
if re.match(r"^## \[Unreleased\]", line):
|
|
50
|
+
unreleased_idx = i
|
|
51
|
+
break
|
|
52
|
+
|
|
53
|
+
if unreleased_idx is None:
|
|
54
|
+
raise ValueError("CHANGELOG missing [Unreleased] section")
|
|
55
|
+
|
|
56
|
+
# Find next version section (end of Unreleased)
|
|
57
|
+
next_version_idx = len(lines)
|
|
58
|
+
for i in range(unreleased_idx + 1, len(lines)):
|
|
59
|
+
if re.match(r"^## \[.+\]", lines[i]):
|
|
60
|
+
next_version_idx = i
|
|
61
|
+
break
|
|
62
|
+
|
|
63
|
+
# Find or create category section
|
|
64
|
+
category_name = category.value
|
|
65
|
+
category_idx = None
|
|
66
|
+
|
|
67
|
+
for i in range(unreleased_idx + 1, next_version_idx):
|
|
68
|
+
if lines[i].strip() == f"### {category_name}":
|
|
69
|
+
category_idx = i
|
|
70
|
+
break
|
|
71
|
+
|
|
72
|
+
if category_idx is None:
|
|
73
|
+
# Category doesn't exist, create it in proper order
|
|
74
|
+
category_idx = _insert_category_in_order(
|
|
75
|
+
lines,
|
|
76
|
+
unreleased_idx,
|
|
77
|
+
next_version_idx,
|
|
78
|
+
category_name
|
|
79
|
+
)
|
|
80
|
+
# Update next_version_idx as lines shifted
|
|
81
|
+
# Wait, if I insert, I need to know how many lines.
|
|
82
|
+
# _insert_category_in_order returns the index of the new category header.
|
|
83
|
+
# But if it inserted blank lines, the indices after it shifted.
|
|
84
|
+
# But next_version_idx is an index, so if I insert BEFORE it, it shifts.
|
|
85
|
+
# Let's check _insert_category_in_order implementation logic.
|
|
86
|
+
# It mutates 'lines' list.
|
|
87
|
+
# If it inserts 2 lines, next_version_idx should increase by 2.
|
|
88
|
+
# But wait, next_version_idx was calculated based on initial list.
|
|
89
|
+
# I should probably re-calculate or just use the return value.
|
|
90
|
+
# But wait, the function mutates the list.
|
|
91
|
+
# Let's look at the implementation below.
|
|
92
|
+
|
|
93
|
+
# Recalculate next_version_idx to be safe?
|
|
94
|
+
# Or rely on finding the category index.
|
|
95
|
+
pass
|
|
96
|
+
|
|
97
|
+
# Re-find next version idx just to be safe if lines shifted
|
|
98
|
+
for i in range(unreleased_idx + 1, len(lines)):
|
|
99
|
+
if re.match(r"^## \[.+\]", lines[i]):
|
|
100
|
+
next_version_idx = i
|
|
101
|
+
break
|
|
102
|
+
else:
|
|
103
|
+
next_version_idx = len(lines)
|
|
104
|
+
|
|
105
|
+
# Re-find category index
|
|
106
|
+
for i in range(unreleased_idx + 1, next_version_idx):
|
|
107
|
+
if lines[i].strip() == f"### {category_name}":
|
|
108
|
+
category_idx = i
|
|
109
|
+
break
|
|
110
|
+
|
|
111
|
+
# Find where to insert the entry (after category header)
|
|
112
|
+
insert_idx = category_idx + 1
|
|
113
|
+
|
|
114
|
+
# Skip existing entries to add at end of category
|
|
115
|
+
while insert_idx < len(lines) and insert_idx < next_version_idx and lines[insert_idx].strip().startswith("- "):
|
|
116
|
+
insert_idx += 1
|
|
117
|
+
|
|
118
|
+
# Insert the new entry
|
|
119
|
+
entry_line = f"- {description}"
|
|
120
|
+
lines.insert(insert_idx, entry_line)
|
|
121
|
+
|
|
122
|
+
return '\n'.join(lines)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _insert_category_in_order(
|
|
126
|
+
lines: list,
|
|
127
|
+
unreleased_idx: int,
|
|
128
|
+
next_version_idx: int,
|
|
129
|
+
category_name: str
|
|
130
|
+
) -> int:
|
|
131
|
+
"""
|
|
132
|
+
Insert category header in proper Keep a Changelog order.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
Index where category header was inserted
|
|
136
|
+
"""
|
|
137
|
+
category_order_idx = CATEGORY_ORDER.index(category_name)
|
|
138
|
+
|
|
139
|
+
# Find existing categories in Unreleased section
|
|
140
|
+
existing_categories = []
|
|
141
|
+
# Note: next_version_idx is based on current lines state
|
|
142
|
+
for i in range(unreleased_idx + 1, next_version_idx):
|
|
143
|
+
match = re.match(r"^### (.+)$", lines[i])
|
|
144
|
+
if match:
|
|
145
|
+
cat = match.group(1)
|
|
146
|
+
if cat in CATEGORY_ORDER:
|
|
147
|
+
existing_categories.append((i, cat))
|
|
148
|
+
|
|
149
|
+
# Find insertion point
|
|
150
|
+
insert_idx = next_version_idx
|
|
151
|
+
for idx, cat in existing_categories:
|
|
152
|
+
cat_order_idx = CATEGORY_ORDER.index(cat)
|
|
153
|
+
if category_order_idx < cat_order_idx:
|
|
154
|
+
# Insert before this category
|
|
155
|
+
insert_idx = idx
|
|
156
|
+
break
|
|
157
|
+
|
|
158
|
+
# Insert category header with blank line before if not first
|
|
159
|
+
if existing_categories:
|
|
160
|
+
lines.insert(insert_idx, "")
|
|
161
|
+
insert_idx += 1
|
|
162
|
+
else:
|
|
163
|
+
# First category, add blank line after [Unreleased]
|
|
164
|
+
lines.insert(unreleased_idx + 1, "")
|
|
165
|
+
insert_idx = unreleased_idx + 2
|
|
166
|
+
|
|
167
|
+
lines.insert(insert_idx, f"### {category_name}")
|
|
168
|
+
|
|
169
|
+
return insert_idx
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def add_entry_to_file(
|
|
173
|
+
filepath: Path,
|
|
174
|
+
category: ChangeCategory,
|
|
175
|
+
description: str
|
|
176
|
+
) -> None:
|
|
177
|
+
"""Add entry to CHANGELOG file."""
|
|
178
|
+
if not filepath.exists():
|
|
179
|
+
raise FileNotFoundError(f"CHANGELOG not found: {filepath}")
|
|
180
|
+
|
|
181
|
+
content = filepath.read_text(encoding='utf-8')
|
|
182
|
+
updated = add_entry(content, category, description)
|
|
183
|
+
filepath.write_text(updated, encoding='utf-8')
|
|
184
|
+
|
|
185
|
+
print(f"✅ Added to {filepath.name}:")
|
|
186
|
+
print(f" [{category.value}] {description}")
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def main():
|
|
190
|
+
"""CLI entry point."""
|
|
191
|
+
if len(sys.argv) != 4:
|
|
192
|
+
print("Usage: add_entry.py <changelog_file> <category> <description>")
|
|
193
|
+
print("")
|
|
194
|
+
print("Categories: Added, Changed, Deprecated, Removed, Fixed, Security")
|
|
195
|
+
print("")
|
|
196
|
+
print("Example:")
|
|
197
|
+
print(' add_entry.py CHANGELOG.md Added "New semantic search feature"')
|
|
198
|
+
sys.exit(1)
|
|
199
|
+
|
|
200
|
+
filepath = Path(sys.argv[1])
|
|
201
|
+
category_str = sys.argv[2]
|
|
202
|
+
description = sys.argv[3]
|
|
203
|
+
|
|
204
|
+
# Validate category
|
|
205
|
+
try:
|
|
206
|
+
category = ChangeCategory[category_str.upper()]
|
|
207
|
+
except KeyError:
|
|
208
|
+
print(f"ERROR: Invalid category '{category_str}'")
|
|
209
|
+
print(f"Valid: {', '.join(CATEGORY_ORDER)}")
|
|
210
|
+
sys.exit(1)
|
|
211
|
+
|
|
212
|
+
add_entry_to_file(filepath, category, description)
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
if __name__ == "__main__":
|
|
216
|
+
main()
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Gather project context for documentation sync.
|
|
4
|
+
|
|
5
|
+
Collects:
|
|
6
|
+
- Recently closed bd issues (if .beads/ exists)
|
|
7
|
+
- Recently merged PRs (via git log)
|
|
8
|
+
- bd memories persisted this cycle (bd kv list)
|
|
9
|
+
- Stale docs/ files (via sync-docs drift_detector.py)
|
|
10
|
+
|
|
11
|
+
Outputs JSON to stdout. Safe to run in any project — degrades gracefully
|
|
12
|
+
when bd or drift detection tools are unavailable.
|
|
13
|
+
|
|
14
|
+
Usage:
|
|
15
|
+
context_gatherer.py [--since=30]
|
|
16
|
+
|
|
17
|
+
--since=N Look back N commits for git context (default: 30)
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import sys
|
|
21
|
+
import json
|
|
22
|
+
import subprocess
|
|
23
|
+
import time
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from datetime import datetime, timezone
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def run(cmd: list, cwd: str | None = None, timeout: int = 8) -> str | None:
|
|
29
|
+
"""Run a command, return stdout or None on failure."""
|
|
30
|
+
try:
|
|
31
|
+
result = subprocess.run(
|
|
32
|
+
cmd, cwd=cwd, capture_output=True, text=True, timeout=timeout
|
|
33
|
+
)
|
|
34
|
+
if result.returncode == 0:
|
|
35
|
+
return result.stdout.strip()
|
|
36
|
+
return None
|
|
37
|
+
except Exception:
|
|
38
|
+
return None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def find_project_root() -> Path:
|
|
42
|
+
"""Walk up from cwd looking for .git."""
|
|
43
|
+
p = Path.cwd()
|
|
44
|
+
for parent in [p, *p.parents]:
|
|
45
|
+
if (parent / ".git").exists():
|
|
46
|
+
return parent
|
|
47
|
+
return p
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def find_main_repo_root(root: Path) -> Path:
|
|
51
|
+
"""For git worktrees, resolve the main repo root from the .git file.
|
|
52
|
+
|
|
53
|
+
In a worktree, .git is a file: "gitdir: /path/to/main/.git/worktrees/<name>"
|
|
54
|
+
Navigate up two levels to reach the main .git, then one more for the repo root.
|
|
55
|
+
"""
|
|
56
|
+
git_path = root / ".git"
|
|
57
|
+
if git_path.is_file():
|
|
58
|
+
content = git_path.read_text(encoding="utf-8").strip()
|
|
59
|
+
if content.startswith("gitdir:"):
|
|
60
|
+
worktree_git = Path(content[len("gitdir:"):].strip())
|
|
61
|
+
main_git = worktree_git.parent.parent
|
|
62
|
+
return main_git.parent
|
|
63
|
+
return root
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def ensure_dolt_server(cwd: str) -> bool:
|
|
67
|
+
"""Ensure the Dolt server is running. Start it if not. Returns True if ready."""
|
|
68
|
+
test = run(["bd", "dolt", "test"], cwd=cwd, timeout=5)
|
|
69
|
+
if test is not None:
|
|
70
|
+
return True
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
subprocess.run(
|
|
74
|
+
["bd", "dolt", "start"],
|
|
75
|
+
cwd=cwd,
|
|
76
|
+
capture_output=True,
|
|
77
|
+
text=True,
|
|
78
|
+
timeout=15,
|
|
79
|
+
)
|
|
80
|
+
except Exception:
|
|
81
|
+
return False
|
|
82
|
+
|
|
83
|
+
for _ in range(6):
|
|
84
|
+
time.sleep(1)
|
|
85
|
+
if run(["bd", "dolt", "test"], cwd=cwd, timeout=3) is not None:
|
|
86
|
+
return True
|
|
87
|
+
|
|
88
|
+
return False
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def has_beads(root: Path) -> bool:
|
|
92
|
+
return (root / ".beads").exists()
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def gather_bd_closed(cwd: str) -> list[dict]:
|
|
96
|
+
"""Get recently closed bd issues."""
|
|
97
|
+
out = run(["bd", "list", "--status=closed"], cwd=cwd)
|
|
98
|
+
if not out:
|
|
99
|
+
return []
|
|
100
|
+
|
|
101
|
+
issues = []
|
|
102
|
+
for line in out.splitlines():
|
|
103
|
+
line = line.strip()
|
|
104
|
+
if line.startswith("✓") or "closed" in line.lower():
|
|
105
|
+
parts = line.lstrip("✓ ").split()
|
|
106
|
+
if len(parts) >= 2:
|
|
107
|
+
issue_id = parts[0]
|
|
108
|
+
title_start = 2 if len(parts) > 2 and parts[1].startswith("P") else 1
|
|
109
|
+
title = " ".join(parts[title_start:])
|
|
110
|
+
issues.append({"id": issue_id, "title": title})
|
|
111
|
+
|
|
112
|
+
return issues[:20]
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def gather_bd_memories(cwd: str) -> list[dict]:
|
|
116
|
+
"""Read bd memories via bd kv list, filtering memory.* keys."""
|
|
117
|
+
out = run(["bd", "kv", "list"], cwd=cwd)
|
|
118
|
+
if not out:
|
|
119
|
+
return []
|
|
120
|
+
|
|
121
|
+
memories = []
|
|
122
|
+
for line in out.splitlines():
|
|
123
|
+
stripped = line.strip()
|
|
124
|
+
if not stripped.startswith("memory."):
|
|
125
|
+
continue
|
|
126
|
+
if " = " in stripped:
|
|
127
|
+
key, _, value = stripped.partition(" = ")
|
|
128
|
+
memories.append({"key": key.strip(), "value": value.strip()})
|
|
129
|
+
else:
|
|
130
|
+
memories.append({"key": stripped, "value": ""})
|
|
131
|
+
|
|
132
|
+
return memories[:20]
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def gather_merged_prs(root: Path, since_n: int) -> list[dict]:
|
|
136
|
+
"""Get merged PRs from git log."""
|
|
137
|
+
out = run(
|
|
138
|
+
["git", "log", f"-{since_n}", "--merges", "--oneline", "--format=%H|%s|%ci"],
|
|
139
|
+
cwd=str(root),
|
|
140
|
+
)
|
|
141
|
+
if not out:
|
|
142
|
+
return []
|
|
143
|
+
|
|
144
|
+
prs = []
|
|
145
|
+
for line in out.splitlines():
|
|
146
|
+
parts = line.split("|", 2)
|
|
147
|
+
if len(parts) == 3:
|
|
148
|
+
sha, subject, date = parts
|
|
149
|
+
prs.append({"sha": sha[:8], "subject": subject.strip(), "date": date.strip()})
|
|
150
|
+
return prs[:10]
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def gather_recent_commits(root: Path, since_n: int) -> list[dict]:
|
|
154
|
+
"""Get recent non-merge commits for context."""
|
|
155
|
+
out = run(
|
|
156
|
+
["git", "log", f"-{since_n}", "--no-merges", "--oneline", "--format=%H|%s|%ci"],
|
|
157
|
+
cwd=str(root),
|
|
158
|
+
)
|
|
159
|
+
if not out:
|
|
160
|
+
return []
|
|
161
|
+
|
|
162
|
+
commits = []
|
|
163
|
+
for line in out.splitlines():
|
|
164
|
+
parts = line.split("|", 2)
|
|
165
|
+
if len(parts) == 3:
|
|
166
|
+
sha, subject, date = parts
|
|
167
|
+
commits.append({"sha": sha[:8], "subject": subject.strip(), "date": date.strip()})
|
|
168
|
+
return commits[:15]
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def gather_docs_drift(root: Path, since_n: int) -> dict:
|
|
172
|
+
"""Run sync-docs drift_detector.py and capture stale docs report."""
|
|
173
|
+
candidates = [
|
|
174
|
+
Path.home() / ".claude/skills/sync-docs/scripts/drift_detector.py",
|
|
175
|
+
root / "skills/sync-docs/scripts/drift_detector.py",
|
|
176
|
+
Path(__file__).parent / "drift_detector.py",
|
|
177
|
+
]
|
|
178
|
+
detector = next((p for p in candidates if p.exists()), None)
|
|
179
|
+
if not detector:
|
|
180
|
+
return {"available": False, "stale": []}
|
|
181
|
+
|
|
182
|
+
out = run([sys.executable, str(detector), "scan", "--since", str(since_n), "--json"], cwd=str(root))
|
|
183
|
+
if out is None:
|
|
184
|
+
return {"available": False, "stale": []}
|
|
185
|
+
|
|
186
|
+
try:
|
|
187
|
+
data = json.loads(out)
|
|
188
|
+
return {
|
|
189
|
+
"available": True,
|
|
190
|
+
"stale": data.get("stale", []),
|
|
191
|
+
"count": data.get("count", 0),
|
|
192
|
+
"raw": data,
|
|
193
|
+
}
|
|
194
|
+
except json.JSONDecodeError:
|
|
195
|
+
return {"available": True, "stale": [], "raw": out}
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def main() -> None:
|
|
199
|
+
since_n = 30
|
|
200
|
+
for arg in sys.argv[1:]:
|
|
201
|
+
if arg.startswith("--since="):
|
|
202
|
+
try:
|
|
203
|
+
since_n = int(arg.split("=", 1)[1])
|
|
204
|
+
except ValueError:
|
|
205
|
+
pass
|
|
206
|
+
|
|
207
|
+
root = find_project_root()
|
|
208
|
+
main_root = find_main_repo_root(root)
|
|
209
|
+
bd_cwd = str(main_root)
|
|
210
|
+
bd_available = has_beads(main_root)
|
|
211
|
+
|
|
212
|
+
dolt_ready = False
|
|
213
|
+
dolt_warning: str | None = None
|
|
214
|
+
if bd_available:
|
|
215
|
+
dolt_ready = ensure_dolt_server(bd_cwd)
|
|
216
|
+
if not dolt_ready:
|
|
217
|
+
dolt_warning = (
|
|
218
|
+
"Dolt server could not be started — bd data unavailable. "
|
|
219
|
+
"Run 'bd dolt start' manually from the project root and retry."
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
report = {
|
|
223
|
+
"generated_at": datetime.now(timezone.utc).isoformat(),
|
|
224
|
+
"project_root": str(root),
|
|
225
|
+
"bd_available": bd_available,
|
|
226
|
+
"bd_closed_issues": gather_bd_closed(bd_cwd) if dolt_ready else [],
|
|
227
|
+
"bd_memories": gather_bd_memories(bd_cwd) if dolt_ready else [],
|
|
228
|
+
"merged_prs": gather_merged_prs(root, since_n),
|
|
229
|
+
"recent_commits": gather_recent_commits(root, since_n),
|
|
230
|
+
"docs_drift": gather_docs_drift(root, since_n),
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if dolt_warning:
|
|
234
|
+
report["warnings"] = [dolt_warning]
|
|
235
|
+
|
|
236
|
+
print(json.dumps(report, indent=2))
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
if __name__ == "__main__":
|
|
240
|
+
main()
|