xtrm-tools 0.5.25 → 0.5.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/.claude-plugin/marketplace.json +19 -0
  2. package/.claude-plugin/plugin.json +9 -0
  3. package/CHANGELOG.md +4 -0
  4. package/README.md +7 -1
  5. package/cli/dist/index.cjs +319 -355
  6. package/cli/dist/index.cjs.map +1 -1
  7. package/cli/package.json +1 -1
  8. package/config/hooks.json +11 -10
  9. package/config/pi/extensions/beads/index.ts +103 -77
  10. package/config/pi/extensions/custom-footer/index.ts +40 -7
  11. package/config/pi/extensions/quality-gates/index.ts +28 -29
  12. package/config/pi/extensions/session-flow/index.ts +50 -21
  13. package/config/pi/extensions/xtrm-loader/index.ts +38 -24
  14. package/hooks/beads-claim-sync.mjs +1 -3
  15. package/hooks/hooks.json +14 -0
  16. package/package.json +5 -1
  17. package/plugins/xtrm-tools/.claude-plugin/plugin.json +9 -0
  18. package/plugins/xtrm-tools/.mcp.json +18 -0
  19. package/plugins/xtrm-tools/hooks/README.md +61 -0
  20. package/plugins/xtrm-tools/hooks/beads-claim-sync.mjs +223 -0
  21. package/plugins/xtrm-tools/hooks/beads-commit-gate.mjs +70 -0
  22. package/plugins/xtrm-tools/hooks/beads-compact-restore.mjs +69 -0
  23. package/plugins/xtrm-tools/hooks/beads-compact-save.mjs +51 -0
  24. package/plugins/xtrm-tools/hooks/beads-edit-gate.mjs +85 -0
  25. package/plugins/xtrm-tools/hooks/beads-gate-core.mjs +236 -0
  26. package/plugins/xtrm-tools/hooks/beads-gate-messages.mjs +68 -0
  27. package/plugins/xtrm-tools/hooks/beads-gate-utils.mjs +194 -0
  28. package/plugins/xtrm-tools/hooks/beads-memory-gate.mjs +81 -0
  29. package/plugins/xtrm-tools/hooks/beads-stop-gate.mjs +53 -0
  30. package/plugins/xtrm-tools/hooks/gitnexus/gitnexus-hook.cjs +222 -0
  31. package/plugins/xtrm-tools/hooks/hooks.json +129 -0
  32. package/plugins/xtrm-tools/hooks/quality-check-env.mjs +79 -0
  33. package/plugins/xtrm-tools/hooks/quality-check.cjs +1286 -0
  34. package/plugins/xtrm-tools/hooks/quality-check.py +345 -0
  35. package/plugins/xtrm-tools/hooks/statusline.mjs +145 -0
  36. package/plugins/xtrm-tools/hooks/using-xtrm-reminder.mjs +35 -0
  37. package/plugins/xtrm-tools/hooks/worktree-boundary.mjs +33 -0
  38. package/plugins/xtrm-tools/hooks/xtrm-logger.mjs +123 -0
  39. package/plugins/xtrm-tools/hooks/xtrm-session-logger.mjs +27 -0
  40. package/plugins/xtrm-tools/hooks/xtrm-tool-logger.mjs +53 -0
  41. package/plugins/xtrm-tools/skills/README.txt +31 -0
  42. package/plugins/xtrm-tools/skills/clean-code/SKILL.md +201 -0
  43. package/plugins/xtrm-tools/skills/creating-service-skills/SKILL.md +433 -0
  44. package/plugins/xtrm-tools/skills/creating-service-skills/references/script_quality_standards.md +425 -0
  45. package/plugins/xtrm-tools/skills/creating-service-skills/references/service_skill_system_guide.md +278 -0
  46. package/plugins/xtrm-tools/skills/creating-service-skills/scripts/bootstrap.py +326 -0
  47. package/plugins/xtrm-tools/skills/creating-service-skills/scripts/deep_dive.py +304 -0
  48. package/plugins/xtrm-tools/skills/creating-service-skills/scripts/scaffolder.py +482 -0
  49. package/plugins/xtrm-tools/skills/delegating/SKILL.md +196 -0
  50. package/plugins/xtrm-tools/skills/delegating/config.yaml +210 -0
  51. package/plugins/xtrm-tools/skills/delegating/references/orchestration-protocols.md +41 -0
  52. package/plugins/xtrm-tools/skills/docker-expert/SKILL.md +409 -0
  53. package/plugins/xtrm-tools/skills/documenting/CHANGELOG.md +23 -0
  54. package/plugins/xtrm-tools/skills/documenting/README.md +148 -0
  55. package/plugins/xtrm-tools/skills/documenting/SKILL.md +113 -0
  56. package/plugins/xtrm-tools/skills/documenting/examples/example_pattern.md +70 -0
  57. package/plugins/xtrm-tools/skills/documenting/examples/example_reference.md +70 -0
  58. package/plugins/xtrm-tools/skills/documenting/examples/example_ssot_analytics.md +64 -0
  59. package/plugins/xtrm-tools/skills/documenting/examples/example_workflow.md +141 -0
  60. package/plugins/xtrm-tools/skills/documenting/references/changelog-format.md +97 -0
  61. package/plugins/xtrm-tools/skills/documenting/references/metadata-schema.md +136 -0
  62. package/plugins/xtrm-tools/skills/documenting/references/taxonomy.md +81 -0
  63. package/plugins/xtrm-tools/skills/documenting/references/versioning-rules.md +78 -0
  64. package/plugins/xtrm-tools/skills/documenting/scripts/bump_version.sh +60 -0
  65. package/plugins/xtrm-tools/skills/documenting/scripts/changelog/__init__.py +0 -0
  66. package/plugins/xtrm-tools/skills/documenting/scripts/changelog/add_entry.py +216 -0
  67. package/plugins/xtrm-tools/skills/documenting/scripts/changelog/bump_release.py +117 -0
  68. package/plugins/xtrm-tools/skills/documenting/scripts/changelog/init_changelog.py +54 -0
  69. package/plugins/xtrm-tools/skills/documenting/scripts/changelog/validate_changelog.py +128 -0
  70. package/plugins/xtrm-tools/skills/documenting/scripts/drift_detector.py +266 -0
  71. package/plugins/xtrm-tools/skills/documenting/scripts/generate_template.py +311 -0
  72. package/plugins/xtrm-tools/skills/documenting/scripts/list_by_category.sh +84 -0
  73. package/plugins/xtrm-tools/skills/documenting/scripts/orchestrator.py +255 -0
  74. package/plugins/xtrm-tools/skills/documenting/scripts/validate_metadata.py +242 -0
  75. package/plugins/xtrm-tools/skills/documenting/templates/CHANGELOG.md.template +13 -0
  76. package/plugins/xtrm-tools/skills/documenting/tests/integration_test.sh +70 -0
  77. package/plugins/xtrm-tools/skills/documenting/tests/test_changelog.py +201 -0
  78. package/plugins/xtrm-tools/skills/documenting/tests/test_drift_detector.py +80 -0
  79. package/plugins/xtrm-tools/skills/documenting/tests/test_orchestrator.py +52 -0
  80. package/plugins/xtrm-tools/skills/documenting/tests/test_validate_metadata.py +64 -0
  81. package/plugins/xtrm-tools/skills/find-skills/SKILL.md +133 -0
  82. package/plugins/xtrm-tools/skills/gitnexus-debugging/SKILL.md +85 -0
  83. package/plugins/xtrm-tools/skills/gitnexus-exploring/SKILL.md +75 -0
  84. package/plugins/xtrm-tools/skills/gitnexus-impact-analysis/SKILL.md +94 -0
  85. package/plugins/xtrm-tools/skills/gitnexus-refactoring/SKILL.md +113 -0
  86. package/plugins/xtrm-tools/skills/hook-development/SKILL.md +797 -0
  87. package/plugins/xtrm-tools/skills/hook-development/examples/load-context.sh +55 -0
  88. package/plugins/xtrm-tools/skills/hook-development/examples/quality-check.js +1168 -0
  89. package/plugins/xtrm-tools/skills/hook-development/examples/validate-bash.sh +43 -0
  90. package/plugins/xtrm-tools/skills/hook-development/examples/validate-write.sh +38 -0
  91. package/plugins/xtrm-tools/skills/hook-development/references/advanced.md +527 -0
  92. package/plugins/xtrm-tools/skills/hook-development/references/migration.md +369 -0
  93. package/plugins/xtrm-tools/skills/hook-development/references/patterns.md +412 -0
  94. package/plugins/xtrm-tools/skills/hook-development/scripts/README.md +164 -0
  95. package/plugins/xtrm-tools/skills/hook-development/scripts/hook-linter.sh +153 -0
  96. package/plugins/xtrm-tools/skills/hook-development/scripts/test-hook.sh +252 -0
  97. package/plugins/xtrm-tools/skills/hook-development/scripts/validate-hook-schema.sh +159 -0
  98. package/plugins/xtrm-tools/skills/obsidian-cli/SKILL.md +106 -0
  99. package/plugins/xtrm-tools/skills/orchestrating-agents/SKILL.md +135 -0
  100. package/plugins/xtrm-tools/skills/orchestrating-agents/config.yaml +45 -0
  101. package/plugins/xtrm-tools/skills/orchestrating-agents/references/agent-context-integration.md +37 -0
  102. package/plugins/xtrm-tools/skills/orchestrating-agents/references/examples.md +45 -0
  103. package/plugins/xtrm-tools/skills/orchestrating-agents/references/handover-protocol.md +31 -0
  104. package/plugins/xtrm-tools/skills/orchestrating-agents/references/workflows.md +42 -0
  105. package/plugins/xtrm-tools/skills/orchestrating-agents/scripts/detect_neighbors.py +23 -0
  106. package/plugins/xtrm-tools/skills/prompt-improving/README.md +162 -0
  107. package/plugins/xtrm-tools/skills/prompt-improving/SKILL.md +74 -0
  108. package/plugins/xtrm-tools/skills/prompt-improving/references/analysis_commands.md +24 -0
  109. package/plugins/xtrm-tools/skills/prompt-improving/references/chain_of_thought.md +24 -0
  110. package/plugins/xtrm-tools/skills/prompt-improving/references/mcp_definitions.md +20 -0
  111. package/plugins/xtrm-tools/skills/prompt-improving/references/multishot.md +23 -0
  112. package/plugins/xtrm-tools/skills/prompt-improving/references/xml_core.md +60 -0
  113. package/plugins/xtrm-tools/skills/python-testing/SKILL.md +815 -0
  114. package/plugins/xtrm-tools/skills/scoping-service-skills/SKILL.md +231 -0
  115. package/plugins/xtrm-tools/skills/scoping-service-skills/scripts/scope.py +74 -0
  116. package/plugins/xtrm-tools/skills/senior-backend/SKILL.md +209 -0
  117. package/plugins/xtrm-tools/skills/senior-backend/references/api_design_patterns.md +103 -0
  118. package/plugins/xtrm-tools/skills/senior-backend/references/backend_security_practices.md +103 -0
  119. package/plugins/xtrm-tools/skills/senior-backend/references/database_optimization_guide.md +103 -0
  120. package/plugins/xtrm-tools/skills/senior-backend/scripts/api_load_tester.py +114 -0
  121. package/plugins/xtrm-tools/skills/senior-backend/scripts/api_scaffolder.py +114 -0
  122. package/plugins/xtrm-tools/skills/senior-backend/scripts/database_migration_tool.py +114 -0
  123. package/plugins/xtrm-tools/skills/senior-data-scientist/SKILL.md +226 -0
  124. package/plugins/xtrm-tools/skills/senior-data-scientist/references/experiment_design_frameworks.md +80 -0
  125. package/plugins/xtrm-tools/skills/senior-data-scientist/references/feature_engineering_patterns.md +80 -0
  126. package/plugins/xtrm-tools/skills/senior-data-scientist/references/statistical_methods_advanced.md +80 -0
  127. package/plugins/xtrm-tools/skills/senior-data-scientist/scripts/experiment_designer.py +100 -0
  128. package/plugins/xtrm-tools/skills/senior-data-scientist/scripts/feature_engineering_pipeline.py +100 -0
  129. package/plugins/xtrm-tools/skills/senior-data-scientist/scripts/model_evaluation_suite.py +100 -0
  130. package/plugins/xtrm-tools/skills/senior-devops/SKILL.md +209 -0
  131. package/plugins/xtrm-tools/skills/senior-devops/references/cicd_pipeline_guide.md +103 -0
  132. package/plugins/xtrm-tools/skills/senior-devops/references/deployment_strategies.md +103 -0
  133. package/plugins/xtrm-tools/skills/senior-devops/references/infrastructure_as_code.md +103 -0
  134. package/plugins/xtrm-tools/skills/senior-devops/scripts/deployment_manager.py +114 -0
  135. package/plugins/xtrm-tools/skills/senior-devops/scripts/pipeline_generator.py +114 -0
  136. package/plugins/xtrm-tools/skills/senior-devops/scripts/terraform_scaffolder.py +114 -0
  137. package/plugins/xtrm-tools/skills/senior-security/SKILL.md +209 -0
  138. package/plugins/xtrm-tools/skills/senior-security/references/cryptography_implementation.md +103 -0
  139. package/plugins/xtrm-tools/skills/senior-security/references/penetration_testing_guide.md +103 -0
  140. package/plugins/xtrm-tools/skills/senior-security/references/security_architecture_patterns.md +103 -0
  141. package/plugins/xtrm-tools/skills/senior-security/scripts/pentest_automator.py +114 -0
  142. package/plugins/xtrm-tools/skills/senior-security/scripts/security_auditor.py +114 -0
  143. package/plugins/xtrm-tools/skills/senior-security/scripts/threat_modeler.py +114 -0
  144. package/plugins/xtrm-tools/skills/skill-creator/LICENSE.txt +202 -0
  145. package/plugins/xtrm-tools/skills/skill-creator/SKILL.md +479 -0
  146. package/plugins/xtrm-tools/skills/skill-creator/agents/analyzer.md +274 -0
  147. package/plugins/xtrm-tools/skills/skill-creator/agents/comparator.md +202 -0
  148. package/plugins/xtrm-tools/skills/skill-creator/agents/grader.md +223 -0
  149. package/plugins/xtrm-tools/skills/skill-creator/assets/eval_review.html +146 -0
  150. package/plugins/xtrm-tools/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  151. package/plugins/xtrm-tools/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  152. package/plugins/xtrm-tools/skills/skill-creator/references/schemas.md +430 -0
  153. package/plugins/xtrm-tools/skills/skill-creator/scripts/__init__.py +0 -0
  154. package/plugins/xtrm-tools/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  155. package/plugins/xtrm-tools/skills/skill-creator/scripts/generate_report.py +326 -0
  156. package/plugins/xtrm-tools/skills/skill-creator/scripts/improve_description.py +248 -0
  157. package/plugins/xtrm-tools/skills/skill-creator/scripts/package_skill.py +136 -0
  158. package/plugins/xtrm-tools/skills/skill-creator/scripts/quick_validate.py +103 -0
  159. package/plugins/xtrm-tools/skills/skill-creator/scripts/run_eval.py +310 -0
  160. package/plugins/xtrm-tools/skills/skill-creator/scripts/run_loop.py +332 -0
  161. package/plugins/xtrm-tools/skills/skill-creator/scripts/utils.py +47 -0
  162. package/plugins/xtrm-tools/skills/sync-docs/SKILL.md +155 -0
  163. package/plugins/xtrm-tools/skills/sync-docs/evals/evals.json +89 -0
  164. package/plugins/xtrm-tools/skills/sync-docs/references/doc-structure.md +99 -0
  165. package/plugins/xtrm-tools/skills/sync-docs/references/schema.md +103 -0
  166. package/plugins/xtrm-tools/skills/sync-docs/scripts/changelog/add_entry.py +216 -0
  167. package/plugins/xtrm-tools/skills/sync-docs/scripts/context_gatherer.py +240 -0
  168. package/plugins/xtrm-tools/skills/sync-docs/scripts/doc_structure_analyzer.py +495 -0
  169. package/plugins/xtrm-tools/skills/sync-docs/scripts/drift_detector.py +563 -0
  170. package/plugins/xtrm-tools/skills/sync-docs/scripts/validate_doc.py +365 -0
  171. package/plugins/xtrm-tools/skills/sync-docs/scripts/validate_metadata.py +185 -0
  172. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/benchmark.json +293 -0
  173. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/benchmark.md +13 -0
  174. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-doc-audit/eval_metadata.json +27 -0
  175. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/outputs/result.md +210 -0
  176. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/run-1/grading.json +28 -0
  177. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-doc-audit/with_skill/run-1/timing.json +1 -0
  178. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/outputs/result.md +101 -0
  179. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/run-1/grading.json +28 -0
  180. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/run-1/timing.json +5 -0
  181. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-doc-audit/without_skill/timing.json +5 -0
  182. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-fix-mode/eval_metadata.json +27 -0
  183. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/outputs/result.md +198 -0
  184. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/run-1/grading.json +28 -0
  185. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-fix-mode/with_skill/run-1/timing.json +1 -0
  186. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/outputs/result.md +94 -0
  187. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/run-1/grading.json +28 -0
  188. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-fix-mode/without_skill/run-1/timing.json +1 -0
  189. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/eval_metadata.json +27 -0
  190. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/outputs/result.md +237 -0
  191. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/run-1/grading.json +28 -0
  192. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/with_skill/run-1/timing.json +1 -0
  193. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/outputs/result.md +134 -0
  194. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/run-1/grading.json +28 -0
  195. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-1/eval-sprint-closeout/without_skill/run-1/timing.json +1 -0
  196. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/benchmark.json +297 -0
  197. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/benchmark.md +13 -0
  198. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-doc-audit/eval_metadata.json +27 -0
  199. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/outputs/result.md +137 -0
  200. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/run-1/grading.json +92 -0
  201. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-doc-audit/with_skill/run-1/timing.json +1 -0
  202. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/outputs/result.md +134 -0
  203. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/run-1/grading.json +86 -0
  204. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-doc-audit/without_skill/run-1/timing.json +1 -0
  205. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-fix-mode/eval_metadata.json +27 -0
  206. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/outputs/result.md +193 -0
  207. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/run-1/grading.json +72 -0
  208. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-fix-mode/with_skill/run-1/timing.json +1 -0
  209. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/outputs/result.md +211 -0
  210. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/run-1/grading.json +91 -0
  211. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-fix-mode/without_skill/run-1/timing.json +5 -0
  212. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/eval_metadata.json +27 -0
  213. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/outputs/result.md +182 -0
  214. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/run-1/grading.json +95 -0
  215. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/with_skill/run-1/timing.json +1 -0
  216. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/outputs/result.md +222 -0
  217. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/run-1/grading.json +88 -0
  218. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-2/eval-sprint-closeout/without_skill/run-1/timing.json +5 -0
  219. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/benchmark.json +298 -0
  220. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/benchmark.md +13 -0
  221. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-doc-audit/eval_metadata.json +27 -0
  222. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/outputs/result.md +125 -0
  223. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/run-1/grading.json +97 -0
  224. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-doc-audit/with_skill/run-1/timing.json +5 -0
  225. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/outputs/result.md +144 -0
  226. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/run-1/grading.json +78 -0
  227. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-doc-audit/without_skill/run-1/timing.json +5 -0
  228. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-fix-mode/eval_metadata.json +27 -0
  229. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/outputs/result.md +104 -0
  230. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/run-1/grading.json +91 -0
  231. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-fix-mode/with_skill/run-1/timing.json +5 -0
  232. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/outputs/result.md +79 -0
  233. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/run-1/grading.json +82 -0
  234. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-fix-mode/without_skill/run-1/timing.json +5 -0
  235. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/eval_metadata.json +27 -0
  236. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase1_context.json +302 -0
  237. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase2_drift.txt +33 -0
  238. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase3_analysis.json +114 -0
  239. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase4_fix.txt +118 -0
  240. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/phase5_validate.txt +38 -0
  241. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/outputs/result.md +158 -0
  242. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/run-1/grading.json +95 -0
  243. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/with_skill/run-1/timing.json +5 -0
  244. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/outputs/result.md +71 -0
  245. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/run-1/grading.json +90 -0
  246. package/plugins/xtrm-tools/skills/sync-docs-workspace/iteration-3/eval-sprint-closeout/without_skill/run-1/timing.json +5 -0
  247. package/plugins/xtrm-tools/skills/test-planning/SKILL.md +208 -0
  248. package/plugins/xtrm-tools/skills/test-planning/evals/evals.json +23 -0
  249. package/plugins/xtrm-tools/skills/updating-service-skills/SKILL.md +136 -0
  250. package/plugins/xtrm-tools/skills/updating-service-skills/scripts/drift_detector.py +222 -0
  251. package/plugins/xtrm-tools/skills/using-TDD/SKILL.md +410 -0
  252. package/plugins/xtrm-tools/skills/using-quality-gates/SKILL.md +254 -0
  253. package/plugins/xtrm-tools/skills/using-serena-lsp/README.md +8 -0
  254. package/plugins/xtrm-tools/skills/using-serena-lsp/REFERENCE.md +194 -0
  255. package/plugins/xtrm-tools/skills/using-serena-lsp/SKILL.md +82 -0
  256. package/plugins/xtrm-tools/skills/using-service-skills/SKILL.md +108 -0
  257. package/plugins/xtrm-tools/skills/using-service-skills/scripts/cataloger.py +74 -0
  258. package/plugins/xtrm-tools/skills/using-service-skills/scripts/skill_activator.py +152 -0
  259. package/plugins/xtrm-tools/skills/using-service-skills/scripts/test_skill_activator.py +58 -0
  260. package/plugins/xtrm-tools/skills/using-xtrm/SKILL.md +124 -0
  261. package/plugins/xtrm-tools/skills/xt-end/SKILL.md +128 -0
@@ -0,0 +1,563 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Detect documentation drift between docs/ files and git-modified files.
4
+
5
+ A docs file is considered stale when:
6
+ 1. It declares source globs in frontmatter (`source_of_truth_for` or `tracks`)
7
+ 2. AND there are commits affecting those source files AFTER the doc's `synced_at` hash
8
+
9
+ If `synced_at` is not set, the doc is considered stale (never synced).
10
+
11
+ Subcommands:
12
+ scan [--since N] [--json] — scan all docs files (default N=30 commits)
13
+ check <docs-file> [--since N] [--json] — check one docs file
14
+ hook [--json] — check current uncommitted changes
15
+ update-sync <docs-file> -- update synced_at to current HEAD hash
16
+ """
17
+
18
+ import sys
19
+ import re
20
+ import json
21
+ import fnmatch
22
+ import subprocess
23
+ from pathlib import Path
24
+ from typing import Any
25
+
26
+ try:
27
+ import yaml
28
+ except ImportError: # pragma: no cover
29
+ yaml = None
30
+
31
+
32
+ def find_project_root() -> Path:
33
+ """Walk up from cwd looking for docs/ and .git."""
34
+ p = Path.cwd()
35
+ for parent in [p, *p.parents]:
36
+ if (parent / ".git").exists():
37
+ return parent
38
+ return p
39
+
40
+
41
+ def get_docs_files(project_root: Path) -> list[Path]:
42
+ docs_dir = project_root / "docs"
43
+ if not docs_dir.exists():
44
+ return []
45
+ return sorted(docs_dir.rglob("*.md"))
46
+
47
+
48
+ def extract_frontmatter(content: str) -> dict[str, Any]:
49
+ match = re.match(r"^---\n(.*?)\n---\n", content, re.DOTALL)
50
+ if not match:
51
+ return {}
52
+
53
+ raw = match.group(1)
54
+ if yaml is not None:
55
+ try:
56
+ return yaml.safe_load(raw) or {}
57
+ except Exception:
58
+ return {}
59
+
60
+ # Minimal fallback parser for environments without pyyaml
61
+ fm: dict[str, Any] = {}
62
+ current_key: str | None = None
63
+ for line in raw.splitlines():
64
+ if not line.strip() or line.strip().startswith("#"):
65
+ continue
66
+ if re.match(r"^[A-Za-z0-9_\-]+:\s*", line):
67
+ key, value = line.split(":", 1)
68
+ key = key.strip()
69
+ value = value.strip()
70
+ if not value:
71
+ fm[key] = []
72
+ current_key = key
73
+ else:
74
+ fm[key] = value.strip('"')
75
+ current_key = None
76
+ elif current_key and line.strip().startswith("-"):
77
+ item = line.strip()[1:].strip().strip('"')
78
+ if isinstance(fm.get(current_key), list):
79
+ fm[current_key].append(item)
80
+ return fm
81
+
82
+
83
+ def extract_globs(content: str) -> list[str]:
84
+ fm = extract_frontmatter(content)
85
+ source = fm.get("source_of_truth_for", [])
86
+ tracks = fm.get("tracks", [])
87
+
88
+ globs: list[str] = []
89
+ if isinstance(source, list):
90
+ globs.extend(str(x) for x in source)
91
+ if isinstance(tracks, list):
92
+ for item in tracks:
93
+ s = str(item)
94
+ if s not in globs:
95
+ globs.append(s)
96
+
97
+ return [g for g in globs if g.strip()]
98
+
99
+
100
+ def extract_updated(content: str) -> str:
101
+ fm = extract_frontmatter(content)
102
+ return str(fm.get("updated", ""))
103
+
104
+
105
+ def extract_synced_at(content: str) -> str | None:
106
+ """Extract the synced_at git hash from frontmatter."""
107
+ fm = extract_frontmatter(content)
108
+ synced = fm.get("synced_at")
109
+ if synced and isinstance(synced, str) and synced.strip():
110
+ return synced.strip()
111
+ return None
112
+
113
+
114
+ def get_current_head_hash(project_root: Path) -> str | None:
115
+ """Get the current HEAD commit hash (short form)."""
116
+ try:
117
+ result = subprocess.run(
118
+ ["git", "rev-parse", "--short", "HEAD"],
119
+ cwd=project_root,
120
+ capture_output=True,
121
+ text=True,
122
+ timeout=5,
123
+ )
124
+ if result.returncode == 0:
125
+ return result.stdout.strip()
126
+ except Exception:
127
+ pass
128
+ return None
129
+
130
+
131
+ def get_commits_after_hash(project_root: Path, synced_hash: str, source_files: list[str]) -> list[str]:
132
+ """
133
+ Check if there are commits affecting source_files after synced_hash.
134
+ Returns list of affected files (empty if no changes after sync point).
135
+ """
136
+ affected: list[str] = []
137
+ try:
138
+ # Check each source file for commits after the sync point
139
+ for source in source_files:
140
+ result = subprocess.run(
141
+ ["git", "log", f"{synced_hash}..HEAD", "--oneline", "--", source],
142
+ cwd=project_root,
143
+ capture_output=True,
144
+ text=True,
145
+ timeout=10,
146
+ )
147
+ if result.returncode == 0 and result.stdout.strip():
148
+ affected.append(source)
149
+ except Exception:
150
+ pass
151
+ return affected
152
+
153
+
154
+ def is_valid_git_hash(project_root: Path, hash_ref: str) -> bool:
155
+ """Check if a hash/ref is valid in the git repository."""
156
+ try:
157
+ result = subprocess.run(
158
+ ["git", "rev-parse", "--verify", hash_ref],
159
+ cwd=project_root,
160
+ capture_output=True,
161
+ text=True,
162
+ timeout=5,
163
+ )
164
+ return result.returncode == 0
165
+ except Exception:
166
+ return False
167
+
168
+
169
+ def _match_glob(path: str, pattern: str) -> bool:
170
+ path_parts = Path(path).as_posix().split("/")
171
+ pattern_parts = Path(pattern).as_posix().split("/")
172
+
173
+ def _match(pp: list[str], pat: list[str]) -> bool:
174
+ if not pat:
175
+ return not pp
176
+ if pat[0] == "**":
177
+ for i in range(len(pp) + 1):
178
+ if _match(pp[i:], pat[1:]):
179
+ return True
180
+ return False
181
+ if not pp:
182
+ return False
183
+ return fnmatch.fnmatch(pp[0], pat[0]) and _match(pp[1:], pat[1:])
184
+
185
+ return _match(path_parts, pattern_parts)
186
+
187
+
188
+ def match_files_to_globs(files: list[str], globs: list[str]) -> list[str]:
189
+ matched: list[str] = []
190
+ for file_path in files:
191
+ for pattern in globs:
192
+ if _match_glob(file_path, pattern):
193
+ matched.append(file_path)
194
+ break
195
+ return matched
196
+
197
+
198
+ def get_recent_modified_files(project_root: Path, since_n_commits: int = 30) -> list[str]:
199
+ try:
200
+ result = subprocess.run(
201
+ ["git", "log", f"-{since_n_commits}", "--name-only", "--format="],
202
+ cwd=project_root,
203
+ capture_output=True,
204
+ text=True,
205
+ timeout=10,
206
+ )
207
+ if result.returncode != 0:
208
+ return []
209
+ return [l.strip() for l in result.stdout.splitlines() if l.strip()]
210
+ except Exception:
211
+ return []
212
+
213
+
214
+ def get_files_matching_globs(project_root: Path, globs: list[str]) -> list[str]:
215
+ """Get all tracked files matching the given glob patterns."""
216
+ matched: list[str] = []
217
+ try:
218
+ # Get all tracked files
219
+ result = subprocess.run(
220
+ ["git", "ls-files"],
221
+ cwd=project_root,
222
+ capture_output=True,
223
+ text=True,
224
+ timeout=30,
225
+ )
226
+ if result.returncode != 0:
227
+ return []
228
+
229
+ all_files = [l.strip() for l in result.stdout.splitlines() if l.strip()]
230
+ matched = match_files_to_globs(all_files, globs)
231
+ except Exception:
232
+ pass
233
+ return matched
234
+
235
+
236
+ def get_session_written_files(project_root: Path) -> list[str]:
237
+ try:
238
+ unstaged = subprocess.run(
239
+ ["git", "diff", "HEAD", "--name-only"],
240
+ cwd=project_root,
241
+ capture_output=True,
242
+ text=True,
243
+ timeout=10,
244
+ )
245
+ staged = subprocess.run(
246
+ ["git", "diff", "--cached", "--name-only"],
247
+ cwd=project_root,
248
+ capture_output=True,
249
+ text=True,
250
+ timeout=10,
251
+ )
252
+ files = unstaged.stdout.splitlines() + staged.stdout.splitlines()
253
+ return sorted({f.strip() for f in files if f.strip()})
254
+ except Exception:
255
+ return []
256
+
257
+
258
+ def scan_docs(project_root: Path, changed_files: list[str], use_hash_check: bool = True) -> list[dict[str, Any]]:
259
+ """
260
+ Scan docs for drift.
261
+
262
+ If use_hash_check=True (default): use synced_at hash comparison
263
+ If use_hash_check=False: use legacy recent-commits matching (for --since flag)
264
+ """
265
+ stale: list[dict[str, Any]] = []
266
+ for doc_path in get_docs_files(project_root):
267
+ content = doc_path.read_text(encoding="utf-8", errors="replace")
268
+ globs = extract_globs(content)
269
+ if not globs:
270
+ continue
271
+
272
+ synced_at = extract_synced_at(content)
273
+ updated = extract_updated(content)
274
+
275
+ if use_hash_check and synced_at:
276
+ # Hash-based check: are there commits affecting source files after synced_at?
277
+ if not is_valid_git_hash(project_root, synced_at):
278
+ # Invalid hash (maybe rebased/force-pushed) - treat as stale
279
+ stale.append({
280
+ "doc": str(doc_path.relative_to(project_root)),
281
+ "updated": updated,
282
+ "synced_at": synced_at,
283
+ "synced_at_valid": False,
284
+ "matched_files": [],
285
+ "globs": globs,
286
+ "reason": "synced_at hash not found in git history",
287
+ })
288
+ continue
289
+
290
+ # Get all tracked files matching the globs
291
+ source_files = get_files_matching_globs(project_root, globs)
292
+
293
+ # Check which files have commits after synced_at
294
+ affected = get_commits_after_hash(project_root, synced_at, source_files)
295
+
296
+ if affected:
297
+ stale.append({
298
+ "doc": str(doc_path.relative_to(project_root)),
299
+ "updated": updated,
300
+ "synced_at": synced_at,
301
+ "synced_at_valid": True,
302
+ "matched_files": affected[:10],
303
+ "globs": globs,
304
+ "reason": "source files changed after sync point",
305
+ })
306
+ elif use_hash_check:
307
+ # No synced_at hash - doc needs initial sync
308
+ source_files = get_files_matching_globs(project_root, globs)
309
+ if source_files:
310
+ stale.append({
311
+ "doc": str(doc_path.relative_to(project_root)),
312
+ "updated": updated,
313
+ "synced_at": None,
314
+ "synced_at_valid": False,
315
+ "matched_files": source_files[:10],
316
+ "globs": globs,
317
+ "reason": "no synced_at hash - needs initial sync",
318
+ })
319
+ else:
320
+ # Legacy check: match against recent commits
321
+ matched = match_files_to_globs(changed_files, globs)
322
+ if matched:
323
+ stale.append({
324
+ "doc": str(doc_path.relative_to(project_root)),
325
+ "updated": updated,
326
+ "synced_at": synced_at,
327
+ "synced_at_valid": synced_at is not None,
328
+ "matched_files": matched[:10],
329
+ "globs": globs,
330
+ "reason": "recent commits match",
331
+ })
332
+ return stale
333
+
334
+
335
+ def print_human_report(stale: list[dict[str, Any]], source: str) -> None:
336
+ if not stale:
337
+ print(f"[Docs Drift] All docs up to date ({source}).")
338
+ return
339
+
340
+ print(f"[Drift Report] {len(stale)} stale doc(s) detected:\n")
341
+ for item in stale:
342
+ print(f" {item['doc']}")
343
+ synced = item.get("synced_at")
344
+ if synced:
345
+ valid = item.get("synced_at_valid", True)
346
+ status = "valid" if valid else "INVALID (not in git history)"
347
+ print(f" Synced at: {synced} ({status})")
348
+ else:
349
+ print(f" Synced at: (not set)")
350
+ print(f" Last updated: {item['updated'] or 'unknown'}")
351
+ reason = item.get("reason", "source files changed")
352
+ print(f" Reason: {reason}")
353
+ if item.get("matched_files"):
354
+ for file_path in item["matched_files"][:3]:
355
+ print(f" Modified: {file_path}")
356
+ print("")
357
+ print("Run /sync-docs to review and update stale docs.")
358
+ print("After updating, run: drift_detector.py update-sync <docs-file>")
359
+
360
+
361
+ def cmd_scan(args: list[str]) -> None:
362
+ since = 30
363
+ as_json = "--json" in args
364
+ use_legacy = "--legacy" in args or "--since" in args
365
+
366
+ if "--since" in args:
367
+ idx = args.index("--since")
368
+ if idx + 1 < len(args):
369
+ since = int(args[idx + 1])
370
+
371
+ project_root = find_project_root()
372
+
373
+ if use_legacy:
374
+ # Legacy mode: match against recent commits
375
+ changed = get_recent_modified_files(project_root, since)
376
+ stale = scan_docs(project_root, changed, use_hash_check=False)
377
+ source = f"last {since} commits (legacy mode)"
378
+ else:
379
+ # Default: hash-based check
380
+ stale = scan_docs(project_root, [], use_hash_check=True)
381
+ source = "hash-based sync check"
382
+
383
+ if as_json:
384
+ print(
385
+ json.dumps(
386
+ {
387
+ "mode": "scan",
388
+ "legacy": use_legacy,
389
+ "since": since if use_legacy else None,
390
+ "count": len(stale),
391
+ "stale": stale,
392
+ },
393
+ indent=2,
394
+ )
395
+ )
396
+ else:
397
+ print_human_report(stale, source)
398
+
399
+ sys.exit(1 if stale else 0)
400
+
401
+
402
+ def cmd_check(args: list[str]) -> None:
403
+ if not args:
404
+ print("Usage: drift_detector.py check <docs-file> [--since N] [--json]")
405
+ sys.exit(1)
406
+
407
+ target = args[0]
408
+ as_json = "--json" in args
409
+ since = 30
410
+ if "--since" in args:
411
+ idx = args.index("--since")
412
+ if idx + 1 < len(args):
413
+ since = int(args[idx + 1])
414
+
415
+ project_root = find_project_root()
416
+ doc_path = (project_root / target).resolve()
417
+ if not doc_path.exists():
418
+ print(f"Doc not found: {target}")
419
+ sys.exit(1)
420
+
421
+ changed = get_recent_modified_files(project_root, since)
422
+ content = doc_path.read_text(encoding="utf-8")
423
+ globs = extract_globs(content)
424
+ matched = match_files_to_globs(changed, globs) if globs else []
425
+
426
+ payload = {
427
+ "mode": "check",
428
+ "doc": str(doc_path.relative_to(project_root)),
429
+ "since": since,
430
+ "stale": bool(matched),
431
+ "matched_files": matched[:10],
432
+ "globs": globs,
433
+ }
434
+
435
+ if as_json:
436
+ print(json.dumps(payload, indent=2))
437
+ else:
438
+ if matched:
439
+ print(f"{payload['doc']}: STALE")
440
+ for f in matched[:5]:
441
+ print(f" Modified: {f}")
442
+ else:
443
+ print(f"{payload['doc']}: up to date")
444
+
445
+ sys.exit(1 if matched else 0)
446
+
447
+
448
+ def cmd_hook(args: list[str]) -> None:
449
+ as_json = "--json" in args
450
+ project_root = find_project_root()
451
+ changed = get_session_written_files(project_root)
452
+ if not changed:
453
+ sys.exit(0)
454
+
455
+ # Hook mode always uses legacy check (uncommitted changes, not committed history)
456
+ stale = scan_docs(project_root, changed, use_hash_check=False)
457
+ if not stale:
458
+ sys.exit(0)
459
+
460
+ if as_json:
461
+ print(
462
+ json.dumps(
463
+ {
464
+ "hookSpecificOutput": {
465
+ "hookEventName": "Stop",
466
+ "additionalContext": (
467
+ f"[Docs Drift] {len(stale)} docs may need updates. "
468
+ "Run /sync-docs to review."
469
+ ),
470
+ }
471
+ }
472
+ )
473
+ )
474
+ else:
475
+ print_human_report(stale, "current session changes")
476
+
477
+ sys.exit(1)
478
+
479
+
480
+ def cmd_update_sync(args: list[str]) -> None:
481
+ """Update synced_at field in a doc's frontmatter to current HEAD hash."""
482
+ if not args or args[0].startswith("--"):
483
+ print("Usage: drift_detector.py update-sync <docs-file>")
484
+ print(" Updates the synced_at field to current HEAD hash")
485
+ sys.exit(1)
486
+
487
+ target = args[0]
488
+ project_root = find_project_root()
489
+ doc_path = (project_root / target).resolve()
490
+
491
+ if not doc_path.exists():
492
+ print(f"Doc not found: {target}")
493
+ sys.exit(1)
494
+
495
+ # Get current HEAD hash
496
+ head_hash = get_current_head_hash(project_root)
497
+ if not head_hash:
498
+ print("Failed to get current HEAD hash")
499
+ sys.exit(1)
500
+
501
+ # Read doc content
502
+ content = doc_path.read_text(encoding="utf-8")
503
+
504
+ # Check for frontmatter
505
+ fm_match = re.match(r"^(---\n)(.*?)(\n---\n)", content, re.DOTALL)
506
+ if not fm_match:
507
+ print(f"No frontmatter found in {target}")
508
+ sys.exit(1)
509
+
510
+ frontmatter_block = fm_match.group(2)
511
+ rest_of_content = content[fm_match.end():]
512
+
513
+ # Parse frontmatter
514
+ fm = extract_frontmatter(content)
515
+
516
+ # Update or add synced_at
517
+ if "synced_at" in fm:
518
+ # Replace existing synced_at
519
+ new_frontmatter = re.sub(
520
+ r"^synced_at:\s*.*$",
521
+ f"synced_at: {head_hash}",
522
+ frontmatter_block,
523
+ flags=re.MULTILINE,
524
+ )
525
+ else:
526
+ # Add synced_at after updated field, or at end
527
+ if "updated" in fm:
528
+ new_frontmatter = re.sub(
529
+ r"^(updated:\s*.*)$",
530
+ rf"\1\nsynced_at: {head_hash}",
531
+ frontmatter_block,
532
+ flags=re.MULTILINE,
533
+ )
534
+ else:
535
+ new_frontmatter = frontmatter_block.rstrip() + f"\nsynced_at: {head_hash}"
536
+
537
+ # Reconstruct file
538
+ new_content = f"---\n{new_frontmatter}\n---\n{rest_of_content}"
539
+
540
+ # Write back
541
+ doc_path.write_text(new_content, encoding="utf-8")
542
+ print(f"Updated {target}: synced_at = {head_hash}")
543
+
544
+
545
+ SUBCOMMANDS = {"scan": cmd_scan, "check": cmd_check, "hook": cmd_hook, "update-sync": cmd_update_sync}
546
+
547
+
548
+ def main() -> None:
549
+ args = sys.argv[1:]
550
+ if not args or args[0] not in SUBCOMMANDS:
551
+ print("Usage: drift_detector.py <scan|check|hook|update-sync> [options]")
552
+ print(" scan [--legacy] [--since N] [--json] scan all docs (hash-based by default)")
553
+ print(" scan --legacy --since N legacy mode: match recent commits")
554
+ print(" check <docs-file> [--since N] check one docs file")
555
+ print(" hook [--json] stop-hook mode (uncommitted changes)")
556
+ print(" update-sync <docs-file> set synced_at to current HEAD")
557
+ sys.exit(1)
558
+
559
+ SUBCOMMANDS[args[0]](args[1:])
560
+
561
+
562
+ if __name__ == "__main__":
563
+ main()