higpertext-cli 0.8.0__py3-none-any.whl

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 (335) hide show
  1. config/adapters_config.json +450 -0
  2. config/antigravity_agent_template.json +31 -0
  3. config/app_config.json +174 -0
  4. config/context_engine.json +33 -0
  5. config/environments/model_defaults.json +5 -0
  6. config/governance/branching_strategy.json +36 -0
  7. config/governance/deployment_gates.json +30 -0
  8. config/governance/guidelines_contract.json +54 -0
  9. config/governance/quality_gates.json +39 -0
  10. config/governance/section_rules.json +22 -0
  11. config/governance/security_guardrails.json +52 -0
  12. config/hooks/README.md +35 -0
  13. config/hooks/custom/test_output_limiter.json +9 -0
  14. config/hooks/global/session_prompt.json +9 -0
  15. config/htx_config.json +24 -0
  16. config/profile_learner.json +18 -0
  17. config/profiles/base_agent.json +40 -0
  18. config/profiles/base_auditor.json +19 -0
  19. config/profiles/base_developer.json +19 -0
  20. config/profiles/base_operator.json +16 -0
  21. config/profiles/global.json +33 -0
  22. config/profiles/software_developer.json +23 -0
  23. config/router_content.json +137 -0
  24. config/semantic_graph.json +66 -0
  25. config/workflows/ado_release_flow.json +38 -0
  26. config/workflows/docs-update.json +33 -0
  27. config/workflows/governance-check.yaml +26 -0
  28. config/workflows/guidelines-sync.json +40 -0
  29. config/workflows/higpertext-build.json +73 -0
  30. config/workflows/higpertext-plan.json +38 -0
  31. config/workflows/higpertext-review.json +41 -0
  32. config/workflows/pr-quality-check.json +56 -0
  33. config/workflows/quality-remediation.json +57 -0
  34. higpertext/__init__.py +18 -0
  35. higpertext/adapters/__init__.py +27 -0
  36. higpertext/adapters/adapter_utils.py +604 -0
  37. higpertext/adapters/claude_adapter/__init__.py +0 -0
  38. higpertext/adapters/claude_adapter/claude_adapter.py +154 -0
  39. higpertext/adapters/copilot_adapter/__init__.py +0 -0
  40. higpertext/adapters/copilot_adapter/copilot_adapter.py +231 -0
  41. higpertext/adapters/gemini_adapter/__init__.py +0 -0
  42. higpertext/adapters/gemini_adapter/gemini_adapter.py +211 -0
  43. higpertext/adapters/llm_formatter.py +46 -0
  44. higpertext/adapters/open_code_adapter/__init__.py +0 -0
  45. higpertext/adapters/open_code_adapter/open_code_adapter.py +480 -0
  46. higpertext/capabilities/capabilities_runner.py +216 -0
  47. higpertext/capabilities/common/agent-builder.json +54 -0
  48. higpertext/capabilities/common/agent-sync.json +34 -0
  49. higpertext/capabilities/common/code-skeletonizer.json +35 -0
  50. higpertext/capabilities/common/commit-report.json +42 -0
  51. higpertext/capabilities/common/context-assembler.json +37 -0
  52. higpertext/capabilities/common/context-budget-report.json +15 -0
  53. higpertext/capabilities/common/dep-manager.json +43 -0
  54. higpertext/capabilities/common/docs-sync.json +14 -0
  55. higpertext/capabilities/common/doctor.json +18 -0
  56. higpertext/capabilities/common/efficiency-meter.json +31 -0
  57. higpertext/capabilities/common/env-catalog.json +13 -0
  58. higpertext/capabilities/common/env-clean.json +14 -0
  59. higpertext/capabilities/common/env-logs.json +16 -0
  60. higpertext/capabilities/common/env-runner.json +23 -0
  61. higpertext/capabilities/common/env-status.json +13 -0
  62. higpertext/capabilities/common/env-stop.json +14 -0
  63. higpertext/capabilities/common/env-template.json +14 -0
  64. higpertext/capabilities/common/error-context-locator.json +23 -0
  65. higpertext/capabilities/common/eval-agent.json +33 -0
  66. higpertext/capabilities/common/file-map.json +17 -0
  67. higpertext/capabilities/common/governance-exception.json +54 -0
  68. higpertext/capabilities/common/graph-query.json +59 -0
  69. higpertext/capabilities/common/graph-rebuild.json +31 -0
  70. higpertext/capabilities/common/graph-visualize.json +37 -0
  71. higpertext/capabilities/common/grep-search.json +176 -0
  72. higpertext/capabilities/common/higpertext-tester.json +25 -0
  73. higpertext/capabilities/common/hook-health.json +19 -0
  74. higpertext/capabilities/common/hook-sync-check.json +19 -0
  75. higpertext/capabilities/common/hooks-manager.json +55 -0
  76. higpertext/capabilities/common/knowledge-asker.json +27 -0
  77. higpertext/capabilities/common/list-rules.json +27 -0
  78. higpertext/capabilities/common/llm-invoke.json +59 -0
  79. higpertext/capabilities/common/load-rules.json +37 -0
  80. higpertext/capabilities/common/memory-manager.json +65 -0
  81. higpertext/capabilities/common/quality-scan.json +21 -0
  82. higpertext/capabilities/common/quality-updater.json +35 -0
  83. higpertext/capabilities/common/rag-index.json +17 -0
  84. higpertext/capabilities/common/report-viewer.json +24 -0
  85. higpertext/capabilities/common/roadmap-report.json +37 -0
  86. higpertext/capabilities/common/scripts/_env_cli.py +65 -0
  87. higpertext/capabilities/common/scripts/agent_builder.py +60 -0
  88. higpertext/capabilities/common/scripts/agent_sync.py +56 -0
  89. higpertext/capabilities/common/scripts/ask_higpertext.py +38 -0
  90. higpertext/capabilities/common/scripts/code_skeletonizer.py +225 -0
  91. higpertext/capabilities/common/scripts/commit_report.py +134 -0
  92. higpertext/capabilities/common/scripts/context_assembler.py +70 -0
  93. higpertext/capabilities/common/scripts/context_budget_report.py +53 -0
  94. higpertext/capabilities/common/scripts/dep_manager.py +81 -0
  95. higpertext/capabilities/common/scripts/docs_sync.py +981 -0
  96. higpertext/capabilities/common/scripts/doctor.py +144 -0
  97. higpertext/capabilities/common/scripts/efficiency_meter.py +83 -0
  98. higpertext/capabilities/common/scripts/env_catalog.py +47 -0
  99. higpertext/capabilities/common/scripts/env_clean.py +30 -0
  100. higpertext/capabilities/common/scripts/env_logs.py +32 -0
  101. higpertext/capabilities/common/scripts/env_runner.py +53 -0
  102. higpertext/capabilities/common/scripts/env_status.py +38 -0
  103. higpertext/capabilities/common/scripts/env_stop.py +30 -0
  104. higpertext/capabilities/common/scripts/env_template.py +73 -0
  105. higpertext/capabilities/common/scripts/error_context_locator.py +138 -0
  106. higpertext/capabilities/common/scripts/eval_agent.py +80 -0
  107. higpertext/capabilities/common/scripts/file_map.py +95 -0
  108. higpertext/capabilities/common/scripts/governance_exception.py +116 -0
  109. higpertext/capabilities/common/scripts/graph_query.py +104 -0
  110. higpertext/capabilities/common/scripts/graph_rebuild.py +107 -0
  111. higpertext/capabilities/common/scripts/graph_visualize.py +76 -0
  112. higpertext/capabilities/common/scripts/grep_search.py +648 -0
  113. higpertext/capabilities/common/scripts/higpertext_tester.py +102 -0
  114. higpertext/capabilities/common/scripts/hook_health.py +149 -0
  115. higpertext/capabilities/common/scripts/hook_sync_check.py +134 -0
  116. higpertext/capabilities/common/scripts/hooks_manager.py +171 -0
  117. higpertext/capabilities/common/scripts/list_rules.py +175 -0
  118. higpertext/capabilities/common/scripts/llm_invoke.py +135 -0
  119. higpertext/capabilities/common/scripts/load_rules.py +379 -0
  120. higpertext/capabilities/common/scripts/memory_manager.py +210 -0
  121. higpertext/capabilities/common/scripts/presentation_engine.py +63 -0
  122. higpertext/capabilities/common/scripts/quality_scan.py +132 -0
  123. higpertext/capabilities/common/scripts/rag_index.py +39 -0
  124. higpertext/capabilities/common/scripts/report_viewer.py +106 -0
  125. higpertext/capabilities/common/scripts/roadmap_report.py +73 -0
  126. higpertext/capabilities/common/scripts/search_router.py +111 -0
  127. higpertext/capabilities/common/scripts/semantic_diff.py +166 -0
  128. higpertext/capabilities/common/scripts/semantic_search.py +43 -0
  129. higpertext/capabilities/common/scripts/session_control.py +136 -0
  130. higpertext/capabilities/common/scripts/smart_read.py +232 -0
  131. higpertext/capabilities/common/scripts/subagent_executor.py +143 -0
  132. higpertext/capabilities/common/scripts/sync_agents.py +353 -0
  133. higpertext/capabilities/common/scripts/task_decomposer.py +78 -0
  134. higpertext/capabilities/common/scripts/telemetry_report.py +36 -0
  135. higpertext/capabilities/common/search-router.json +24 -0
  136. higpertext/capabilities/common/semantic-diff.json +40 -0
  137. higpertext/capabilities/common/semantic-search.json +19 -0
  138. higpertext/capabilities/common/session-clean.json +20 -0
  139. higpertext/capabilities/common/session-start.json +44 -0
  140. higpertext/capabilities/common/smart-read.json +28 -0
  141. higpertext/capabilities/common/subagent-executor.json +25 -0
  142. higpertext/capabilities/common/sync-agents.json +32 -0
  143. higpertext/capabilities/common/task-decomposer.json +37 -0
  144. higpertext/capabilities/common/telemetry-report.json +23 -0
  145. higpertext/capabilities/git/__init__.py +0 -0
  146. higpertext/capabilities/git/committer.json +61 -0
  147. higpertext/capabilities/git/diff.json +33 -0
  148. higpertext/capabilities/git/ls-files.json +44 -0
  149. higpertext/capabilities/git/rm.json +27 -0
  150. higpertext/capabilities/git/scripts/__init__.py +0 -0
  151. higpertext/capabilities/git/scripts/commit_changes.py +1077 -0
  152. higpertext/capabilities/git/scripts/git_diff.py +171 -0
  153. higpertext/capabilities/git/scripts/git_ls_files.py +376 -0
  154. higpertext/capabilities/git/scripts/git_rm.py +62 -0
  155. higpertext/capabilities/security/k8s-auditor.json +33 -0
  156. higpertext/capabilities/security/scripts/k8s_auditor.py +307 -0
  157. higpertext/capabilities/security/scripts/secret_scanner.py +235 -0
  158. higpertext/capabilities/security/secret-scanner.json +32 -0
  159. higpertext/hooks/__init__.py +28 -0
  160. higpertext/hooks/_compat.py +27 -0
  161. higpertext/hooks/hook_tasks/__init__.py +1 -0
  162. higpertext/hooks/hook_tasks/_rules/__init__.py +0 -0
  163. higpertext/hooks/hook_tasks/_rules/bash_rules.py +635 -0
  164. higpertext/hooks/hook_tasks/_rules/context_engine_rule.py +79 -0
  165. higpertext/hooks/hook_tasks/_rules/context_rules.py +199 -0
  166. higpertext/hooks/hook_tasks/_rules/governance_adapter.py +72 -0
  167. higpertext/hooks/hook_tasks/_rules/profile_rules.json +25 -0
  168. higpertext/hooks/hook_tasks/_rules/quality_rules.py +86 -0
  169. higpertext/hooks/hook_tasks/_rules/security_rules.py +214 -0
  170. higpertext/hooks/hook_tasks/_rules/session_rules.py +316 -0
  171. higpertext/hooks/hook_tasks/_rules/telemetry_rules.py +121 -0
  172. higpertext/hooks/hook_tasks/audit_logger_hook.py +28 -0
  173. higpertext/hooks/hook_tasks/hook_bash_guard.py +101 -0
  174. higpertext/hooks/hook_tasks/hook_code_quality.py +48 -0
  175. higpertext/hooks/hook_tasks/hook_context_hint.py +46 -0
  176. higpertext/hooks/hook_tasks/hook_context_manager.py +44 -0
  177. higpertext/hooks/hook_tasks/hook_io.py +122 -0
  178. higpertext/hooks/hook_tasks/hook_loop_guard.py +182 -0
  179. higpertext/hooks/hook_tasks/hook_post_observer.py +54 -0
  180. higpertext/hooks/hook_tasks/hook_read_guard.py +85 -0
  181. higpertext/hooks/hook_tasks/hook_security_guard.py +81 -0
  182. higpertext/hooks/hook_tasks/hook_session_prompt.py +83 -0
  183. higpertext/hooks/hook_tasks/hook_session_stop.py +115 -0
  184. higpertext/hooks/hook_tasks/hook_utils.py +144 -0
  185. higpertext/hooks/hook_tasks/session_guard_hook.py +23 -0
  186. higpertext/hooks/hook_tasks/telemetry_utils.py +176 -0
  187. higpertext/hooks/hook_tasks/test_echo_hook.py +33 -0
  188. higpertext/hooks/hook_tasks/webhook_hook.py +54 -0
  189. higpertext/hooks/hook_tasks/workflow_runner_hook.py +49 -0
  190. higpertext/hooks/hooks_catalog.json +116 -0
  191. higpertext/kernel/__init__.py +63 -0
  192. higpertext/kernel/_compat.py +138 -0
  193. higpertext/kernel/app_config.py +117 -0
  194. higpertext/kernel/application/__init__.py +13 -0
  195. higpertext/kernel/application/agent_registry.py +102 -0
  196. higpertext/kernel/application/capability_manager.py +61 -0
  197. higpertext/kernel/application/commit_reporter.py +247 -0
  198. higpertext/kernel/application/context_builder.py +166 -0
  199. higpertext/kernel/application/context_engine.py +409 -0
  200. higpertext/kernel/application/engine.py +41 -0
  201. higpertext/kernel/application/env_runtime.py +174 -0
  202. higpertext/kernel/application/environment_manager.py +154 -0
  203. higpertext/kernel/application/governance.py +192 -0
  204. higpertext/kernel/application/hook_registry.py +102 -0
  205. higpertext/kernel/application/hook_renderer.py +720 -0
  206. higpertext/kernel/application/ports.py +49 -0
  207. higpertext/kernel/application/profile_learner.py +358 -0
  208. higpertext/kernel/application/profile_service.py +205 -0
  209. higpertext/kernel/application/profile_services.py +6 -0
  210. higpertext/kernel/application/profile_use_cases.py +93 -0
  211. higpertext/kernel/application/rag_service.py +75 -0
  212. higpertext/kernel/application/roadmap_reporter.py +178 -0
  213. higpertext/kernel/application/semantic_engine.py +258 -0
  214. higpertext/kernel/application/session_services.py +33 -0
  215. higpertext/kernel/application/skill_hook_compiler.py +85 -0
  216. higpertext/kernel/application/telemetry.py +326 -0
  217. higpertext/kernel/application/workflow_manager.py +176 -0
  218. higpertext/kernel/config_paths.py +66 -0
  219. higpertext/kernel/domain/__init__.py +12 -0
  220. higpertext/kernel/domain/agent_registry.py +23 -0
  221. higpertext/kernel/domain/commit_reporter.py +155 -0
  222. higpertext/kernel/domain/compilers.py +7 -0
  223. higpertext/kernel/domain/context_engine.py +319 -0
  224. higpertext/kernel/domain/entities.py +51 -0
  225. higpertext/kernel/domain/env_runtime.py +62 -0
  226. higpertext/kernel/domain/governance.py +198 -0
  227. higpertext/kernel/domain/hook_models.py +29 -0
  228. higpertext/kernel/domain/profile_learner.py +186 -0
  229. higpertext/kernel/domain/rag.py +70 -0
  230. higpertext/kernel/domain/repositories.py +8 -0
  231. higpertext/kernel/domain/roadmap_reporter.py +80 -0
  232. higpertext/kernel/domain/semantic_engine.py +107 -0
  233. higpertext/kernel/engine.py +42 -0
  234. higpertext/kernel/htx_resolver.py +69 -0
  235. higpertext/kernel/infrastructure/__init__.py +13 -0
  236. higpertext/kernel/infrastructure/agent_registry.py +40 -0
  237. higpertext/kernel/infrastructure/cache/capability_cache.py +319 -0
  238. higpertext/kernel/infrastructure/capability_helper.py +40 -0
  239. higpertext/kernel/infrastructure/cli/__init__.py +1 -0
  240. higpertext/kernel/infrastructure/cli/agent_commands.py +62 -0
  241. higpertext/kernel/infrastructure/cli/arguments.py +39 -0
  242. higpertext/kernel/infrastructure/cli/capability_command_builder.py +86 -0
  243. higpertext/kernel/infrastructure/cli/capability_task_service.py +234 -0
  244. higpertext/kernel/infrastructure/cli/cli_search.py +234 -0
  245. higpertext/kernel/infrastructure/cli/parameter_contracts.py +83 -0
  246. higpertext/kernel/infrastructure/cli/parser_builder.py +122 -0
  247. higpertext/kernel/infrastructure/cli/profile_commands.py +89 -0
  248. higpertext/kernel/infrastructure/cli/roadmap_commands.py +117 -0
  249. higpertext/kernel/infrastructure/cli/router.py +1110 -0
  250. higpertext/kernel/infrastructure/cli/session_commands.py +36 -0
  251. higpertext/kernel/infrastructure/cli/task_commands.py +23 -0
  252. higpertext/kernel/infrastructure/cli/task_result_reporter.py +56 -0
  253. higpertext/kernel/infrastructure/cli/workflow_commands.py +25 -0
  254. higpertext/kernel/infrastructure/compilers/__init__.py +3 -0
  255. higpertext/kernel/infrastructure/compilers/factory.py +27 -0
  256. higpertext/kernel/infrastructure/compilers/graph_compiler.py +20 -0
  257. higpertext/kernel/infrastructure/compilers/guide_compiler.py +50 -0
  258. higpertext/kernel/infrastructure/compilers/hook_compiler.py +69 -0
  259. higpertext/kernel/infrastructure/compilers/playbook_compiler.py +154 -0
  260. higpertext/kernel/infrastructure/context_engine.py +303 -0
  261. higpertext/kernel/infrastructure/database/local_vector_store.py +99 -0
  262. higpertext/kernel/infrastructure/deployment/__init__.py +1 -0
  263. higpertext/kernel/infrastructure/deployment/resource_deployer.py +283 -0
  264. higpertext/kernel/infrastructure/diagnostics/__init__.py +1 -0
  265. higpertext/kernel/infrastructure/diagnostics/health.py +191 -0
  266. higpertext/kernel/infrastructure/env_runtime.py +227 -0
  267. higpertext/kernel/infrastructure/execution/__init__.py +1 -0
  268. higpertext/kernel/infrastructure/execution/parallel.py +188 -0
  269. higpertext/kernel/infrastructure/execution/resilience.py +155 -0
  270. higpertext/kernel/infrastructure/file_repositories.py +213 -0
  271. higpertext/kernel/infrastructure/governance.py +198 -0
  272. higpertext/kernel/infrastructure/hook_config_loader.py +53 -0
  273. higpertext/kernel/infrastructure/hook_webhook_dispatcher.py +61 -0
  274. higpertext/kernel/infrastructure/hook_workflow_bridge.py +60 -0
  275. higpertext/kernel/infrastructure/llm/__init__.py +6 -0
  276. higpertext/kernel/infrastructure/llm/provider.py +46 -0
  277. higpertext/kernel/infrastructure/llm/providers/__init__.py +0 -0
  278. higpertext/kernel/infrastructure/llm/providers/anthropic_provider.py +94 -0
  279. higpertext/kernel/infrastructure/llm/providers/gemini_embeddings.py +74 -0
  280. higpertext/kernel/infrastructure/llm/providers/gemini_provider.py +101 -0
  281. higpertext/kernel/infrastructure/llm/providers/ollama_provider.py +110 -0
  282. higpertext/kernel/infrastructure/llm/providers/openai_provider.py +98 -0
  283. higpertext/kernel/infrastructure/llm/registry.py +81 -0
  284. higpertext/kernel/infrastructure/logger.py +303 -0
  285. higpertext/kernel/infrastructure/output_store.py +70 -0
  286. higpertext/kernel/infrastructure/parser/__init__.py +1 -0
  287. higpertext/kernel/infrastructure/parser/code_chunker.py +144 -0
  288. higpertext/kernel/infrastructure/parser/language/__init__.py +14 -0
  289. higpertext/kernel/infrastructure/parser/language/base.py +41 -0
  290. higpertext/kernel/infrastructure/parser/language/powershell_parser.py +35 -0
  291. higpertext/kernel/infrastructure/parser/language/python_parser.py +98 -0
  292. higpertext/kernel/infrastructure/parser/language/typescript_parser.py +91 -0
  293. higpertext/kernel/infrastructure/parser/semantic_graph.py +409 -0
  294. higpertext/kernel/infrastructure/presentation/__init__.py +1 -0
  295. higpertext/kernel/infrastructure/presentation/html_renderer.py +137 -0
  296. higpertext/kernel/infrastructure/presentation/markdown_renderer.py +84 -0
  297. higpertext/kernel/infrastructure/presentation/markdown_report_renderer.py +97 -0
  298. higpertext/kernel/infrastructure/profile_store.py +28 -0
  299. higpertext/kernel/infrastructure/semantic_engine.py +289 -0
  300. higpertext/kernel/infrastructure/telemetry_reporter.py +132 -0
  301. higpertext/kernel/infrastructure/validation/__init__.py +1 -0
  302. higpertext/kernel/infrastructure/validation/contract_validator.py +163 -0
  303. higpertext/kernel/pkg_resources.py +38 -0
  304. higpertext/kernel/session_manager.py +319 -0
  305. higpertext/templates/env/generic-shell.yaml +21 -0
  306. higpertext/templates/env/node-vitest.yaml +27 -0
  307. higpertext/templates/env/python-pytest.yaml +29 -0
  308. higpertext/templates/html/commit_body.html +20 -0
  309. higpertext/templates/html/commit_diff.html +4 -0
  310. higpertext/templates/html/commit_index.html +29 -0
  311. higpertext/templates/html/commit_layer.html +11 -0
  312. higpertext/templates/html/commit_shell.html +28 -0
  313. higpertext/templates/html/graph_visualize.html +86 -0
  314. higpertext/templates/html/roadmap_body.html +12 -0
  315. higpertext/templates/html/roadmap_phase.html +5 -0
  316. higpertext/templates/html/roadmap_shell.html +29 -0
  317. higpertext/templates/markdown/commit_report.md +18 -0
  318. higpertext/templates/markdown/efficiency_report.md +12 -0
  319. higpertext/templates/markdown/roadmap_report.md +25 -0
  320. higpertext/templates/skills/best-practices.md +7 -0
  321. higpertext/templates/skills/clean-code.md +8 -0
  322. higpertext/templates/skills/ddd-standards.md +7 -0
  323. higpertext/templates/skills/tdd-practices.md +7 -0
  324. higpertext/templates/subagents/architect.md +7 -0
  325. higpertext/templates/subagents/test-engineer.md +7 -0
  326. higpertext/templates/workflows/build.json +23 -0
  327. higpertext/templates/workflows/compact.json +21 -0
  328. higpertext/templates/workflows/plan.json +59 -0
  329. higpertext/templates/workflows/review.json +26 -0
  330. higpertext/templates/workflows/spec.json +27 -0
  331. higpertext_cli-0.8.0.dist-info/METADATA +35 -0
  332. higpertext_cli-0.8.0.dist-info/RECORD +335 -0
  333. higpertext_cli-0.8.0.dist-info/WHEEL +5 -0
  334. higpertext_cli-0.8.0.dist-info/entry_points.txt +2 -0
  335. higpertext_cli-0.8.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,303 @@
1
+ """Higpertext CLI Logger — infraestructura de logging para la CLI.
2
+
3
+ Provee un logger estructurado con:
4
+ - Salida a consola con colores ANSI (nivel configurable).
5
+ - Rotación de archivo en .higpertext/logs/htx.log (sin dependencias externas).
6
+ - Niveles semánticos: info, ok, warn, error, debug alineados con el estilo de la CLI.
7
+ - `event_block()` — emite un bloque estructurado AI-legible en un solo call.
8
+ - Factory `get_logger` para obtener la instancia singleton configurada.
9
+
10
+ Formato de bloque (AI-legible):
11
+ ╔─ htx · <event> ─────────────────────────────────────────
12
+ │ status : ok
13
+ │ sessions_analyzed : 12
14
+ │ ...
15
+ ╚─────────────────────────────────────────────────────────
16
+
17
+ Uso:
18
+ from higpertext.kernel.infrastructure.logger import get_logger
19
+ log = get_logger(project_root=root)
20
+ log.event_block("profile-learn", status="ok", fields={
21
+ "sessions_analyzed": 12,
22
+ "calibration_mode": "z-score",
23
+ })
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import logging
29
+ import logging.handlers
30
+ import os
31
+ import sys
32
+ from pathlib import Path
33
+ from typing import Any
34
+
35
+ from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
36
+
37
+ # ── Constantes ────────────────────────────────────────────────────────────────
38
+
39
+ from higpertext.kernel.app_config import LOGGER_NAME, LOG_FILE as _LOG_FILE
40
+ _MAX_BYTES = 1_048_576 # 1 MB
41
+ _BACKUP_COUNT = 3
42
+ _DEFAULT_LEVEL = logging.INFO
43
+
44
+ # Nivel personalizado OK (entre INFO y WARNING)
45
+ _OK_LEVEL = 25
46
+ logging.addLevelName(_OK_LEVEL, "OK")
47
+
48
+ _BOX_WIDTH = 57 # ancho interior del bloque ╔─…╚─
49
+
50
+ # ── Colores ANSI ──────────────────────────────────────────────────────────────
51
+
52
+ _RESET = "\033[0m"
53
+ _BOLD = "\033[1m"
54
+
55
+ _COLORS: dict[int, str] = {
56
+ logging.DEBUG: "\033[36m", # cyan
57
+ logging.INFO: "\033[34m", # blue
58
+ _OK_LEVEL: "\033[32m", # green
59
+ logging.WARNING: "\033[33m", # yellow
60
+ logging.ERROR: "\033[31m", # red
61
+ logging.CRITICAL: "\033[35m", # magenta
62
+ }
63
+
64
+ _PREFIX: dict[int, str] = {
65
+ logging.DEBUG: "[DBG]",
66
+ logging.INFO: "[*] ",
67
+ _OK_LEVEL: "[OK] ",
68
+ logging.WARNING: "[!] ",
69
+ logging.ERROR: "[ERR]",
70
+ logging.CRITICAL: "[!!!]",
71
+ }
72
+
73
+ _STATUS_ICON: dict[str, str] = {
74
+ "ok": "✓",
75
+ "error": "✗",
76
+ "warn": "⚠",
77
+ "skip": "—",
78
+ }
79
+
80
+
81
+ # ── Formatters ────────────────────────────────────────────────────────────────
82
+
83
+ class _ColorFormatter(logging.Formatter):
84
+ """Formatter con colores ANSI para salida en consola."""
85
+
86
+ _use_color: bool = sys.stdout.isatty() and os.getenv("NO_COLOR") is None
87
+
88
+ def format(self, record: logging.LogRecord) -> str:
89
+ level = record.levelno
90
+ prefix = _PREFIX.get(level, "[?] ")
91
+ msg = super().format(record)
92
+
93
+ if self._use_color:
94
+ color = _COLORS.get(level, "")
95
+ return f"{color}{_BOLD}{prefix}{_RESET} {msg}"
96
+ return f"{prefix} {msg}"
97
+
98
+
99
+ class _PlainFormatter(logging.Formatter):
100
+ """Formatter sin colores para archivos de log."""
101
+
102
+ def format(self, record: logging.LogRecord) -> str:
103
+ prefix = _PREFIX.get(record.levelno, "[?] ")
104
+ return f"{prefix} {super().format(record)}"
105
+
106
+
107
+ # ── Bloque estructurado ───────────────────────────────────────────────────────
108
+
109
+ def _build_event_block(
110
+ event: str,
111
+ status: str,
112
+ fields: dict[str, Any],
113
+ ) -> str:
114
+ """Construye un bloque de texto estructurado AI-legible.
115
+
116
+ El formato es intencionalmente consistente con el banner de session_stop
117
+ para que el asistente pueda parsearlo mediante texto plano.
118
+
119
+ ╔─ htx · profile-learn ───────────────────────────────────
120
+ │ status : ✓ ok
121
+ │ sessions_analyzed : 12
122
+ │ calibration_mode : z-score
123
+ │ adoption_pct : 78%
124
+ ╚─────────────────────────────────────────────────────────
125
+ """
126
+ title = f"htx · {event}"
127
+ header_fill = "─" * max(0, _BOX_WIDTH - len(title) - 1)
128
+ header = f"╔─ {title} {header_fill}"
129
+
130
+ icon = _STATUS_ICON.get(status, status)
131
+ rows: list[str] = [f"│ {'status':<20}: {icon} {status}"]
132
+
133
+ # Calcula el ancho de la columna de claves
134
+ max_key = max((len(k) for k in fields), default=6)
135
+ col = max(max_key, 20)
136
+
137
+ for key, value in fields.items():
138
+ val_str = str(value) if value not in (None, "", []) else "—"
139
+ rows.append(f"│ {key:<{col}}: {val_str}")
140
+
141
+ footer = "╚" + "─" * (_BOX_WIDTH + 2)
142
+
143
+ return "\n".join([header, *rows, footer])
144
+
145
+
146
+ # ── Caja genérica ─────────────────────────────────────────────────────────────
147
+
148
+ def render_box(title: str, lines: list[str]) -> str:
149
+ """Construye un bloque de caja ╔─ … ╚─ como string.
150
+
151
+ Uso desde hooks/RuleResult (canal LLM) o cualquier código que necesite
152
+ el string antes de decidir cómo emitirlo.
153
+
154
+ render_box("HIGPERTEXT · Loop Guard · BLOQUEADO", [
155
+ f"│ Herramienta : {tool}",
156
+ "│ Acción : cambia el enfoque",
157
+ ])
158
+ """
159
+ header_fill = "─" * max(0, _BOX_WIDTH - len(title) - 1)
160
+ header = f"╔─ {title} {header_fill}"
161
+ footer = "╚" + "─" * (_BOX_WIDTH + 2)
162
+ return "\n".join([header, *lines, footer])
163
+
164
+
165
+ # ── Logger extendido ──────────────────────────────────────────────────────────
166
+
167
+ class HtxLogger(logging.Logger):
168
+ """Logger con métodos semánticos y emisión de bloques estructurados."""
169
+
170
+ def ok(self, msg: str, *args: object, **kwargs: object) -> None:
171
+ """Emite un mensaje de nivel OK (verde)."""
172
+ if self.isEnabledFor(_OK_LEVEL):
173
+ self._log(_OK_LEVEL, msg, args, **kwargs)
174
+
175
+ def section(self, title: str) -> None:
176
+ """Imprime un separador de sección visible en consola."""
177
+ self.info("─" * 3 + f" {title} " + "─" * max(0, 48 - len(title)))
178
+
179
+ def box(self, title: str, lines: list[str], level: int = logging.INFO) -> None:
180
+ """Emite un bloque de caja ╔─ … ╚─ via el logger.
181
+
182
+ Equivalente a llamar render_box() y luego _log(level, ...).
183
+ Usar cuando el destinatario es el log interno (consola/archivo),
184
+ no el LLM (para eso usar render_box() + emit_block/RuleResult).
185
+ """
186
+ if self.isEnabledFor(level):
187
+ self._log(level, render_box(title, lines), ())
188
+
189
+ def event_block(
190
+ self,
191
+ event: str,
192
+ *,
193
+ status: str = "ok",
194
+ fields: dict[str, Any] | None = None,
195
+ ) -> None:
196
+ """Emite un bloque estructurado AI-legible en una sola llamada.
197
+
198
+ Elimina la repetición de múltiples `log.info()` para campos
199
+ relacionados. El bloque se emite completo en un solo mensaje,
200
+ lo que facilita el parseo por parte del asistente.
201
+
202
+ Args:
203
+ event: Identificador del evento (ej: "profile-learn").
204
+ status: Estado del resultado: "ok" | "error" | "warn" | "skip".
205
+ fields: Diccionario ordenado de campo → valor a mostrar.
206
+
207
+ Example:
208
+ log.event_block("profile-learn", status="ok", fields={
209
+ "sessions_analyzed": 12,
210
+ "calibration_mode": "z-score",
211
+ "adoption_pct": "78%",
212
+ "strong_patterns": "hooks frecuentes, commits convencionales",
213
+ "weak_patterns": None,
214
+ "commit_topics": "refactor, api, test",
215
+ })
216
+ """
217
+ block = _build_event_block(event, status, fields or {})
218
+ level = _OK_LEVEL if status == "ok" else (
219
+ logging.WARNING if status == "warn" else
220
+ logging.ERROR if status == "error" else
221
+ logging.INFO
222
+ )
223
+ if self.isEnabledFor(level):
224
+ self._log(level, block, ())
225
+
226
+
227
+ # ── Factory ───────────────────────────────────────────────────────────────────
228
+
229
+ logging.setLoggerClass(HtxLogger)
230
+
231
+ _instance: HtxLogger | None = None
232
+
233
+
234
+ def get_logger(
235
+ project_root: Path | None = None,
236
+ *,
237
+ level: int = _DEFAULT_LEVEL,
238
+ file_logging: bool = True,
239
+ ) -> HtxLogger:
240
+ """Retorna la instancia singleton del logger higpertext.
241
+
242
+ Args:
243
+ project_root: Raíz del proyecto para calcular la ruta del archivo de log.
244
+ Si es None, solo se emite a consola.
245
+ level: Nivel mínimo de logging (default: INFO).
246
+ file_logging: Si True, agrega un handler de archivo rotativo.
247
+ """
248
+ global _instance
249
+ if _instance is not None:
250
+ return _instance
251
+
252
+ logger: HtxLogger = logging.getLogger(LOGGER_NAME) # type: ignore[assignment]
253
+ logger.setLevel(level)
254
+ logger.propagate = False
255
+
256
+ # ── Handler consola ───────────────────────────────────────────────────────
257
+ # Use a subclass that resolves sys.stdout dynamically so pytest capsys works.
258
+ class _DynamicStdoutHandler(logging.StreamHandler):
259
+ @property
260
+ def stream(self): # type: ignore[override]
261
+ return sys.stdout
262
+
263
+ @stream.setter
264
+ def stream(self, value): # type: ignore[override]
265
+ pass # ignore the value set by StreamHandler.__init__
266
+
267
+ console = _DynamicStdoutHandler()
268
+ console.setLevel(level)
269
+ console.setFormatter(_ColorFormatter("%(message)s"))
270
+ logger.addHandler(console)
271
+
272
+ # ── Handler archivo (opcional) ────────────────────────────────────────────
273
+ if file_logging and project_root is not None:
274
+ log_dir = project_root / WORKSPACE_DIR_NAME / "logs"
275
+ try:
276
+ log_dir.mkdir(parents=True, exist_ok=True)
277
+ file_handler = logging.handlers.RotatingFileHandler(
278
+ log_dir / _LOG_FILE,
279
+ maxBytes=_MAX_BYTES,
280
+ backupCount=_BACKUP_COUNT,
281
+ encoding="utf-8",
282
+ )
283
+ file_handler.setLevel(logging.DEBUG)
284
+ file_handler.setFormatter(
285
+ _PlainFormatter(
286
+ "%(asctime)s %(levelname)-8s %(message)s",
287
+ datefmt="%Y-%m-%dT%H:%M:%S",
288
+ )
289
+ )
290
+ logger.addHandler(file_handler)
291
+ except OSError:
292
+ pass # nosec — no bloquear si no se puede escribir el log
293
+
294
+ _instance = logger
295
+ return _instance
296
+
297
+
298
+ def reset_logger() -> None:
299
+ """Limpia la instancia singleton (útil en tests)."""
300
+ global _instance
301
+ if _instance is not None:
302
+ _instance.handlers.clear()
303
+ _instance = None
@@ -0,0 +1,70 @@
1
+ """OutputStore — persiste outputs de capabilities en .higpertext/reports/ con índice."""
2
+
3
+ from __future__ import annotations
4
+ import json
5
+ import re
6
+ from datetime import datetime, timezone
7
+ from pathlib import Path
8
+
9
+ from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
10
+ from higpertext.kernel.app_config import REPORTS_DIR as _REPORTS_DIR, INDEX_FILE as _INDEX_FILE
11
+
12
+
13
+ def _canonical_name(capability_id: str) -> str:
14
+ """Convierte 'common.telemetry-report' → 'common_telemetry_report'."""
15
+ return re.sub(r"[.\-\s]+", "_", capability_id)
16
+
17
+
18
+ class OutputStore:
19
+ """Persiste y recupera outputs de capabilities sin modificar su stdout.
20
+
21
+ El stdout al agente no se toca. Esta clase es una capa secundaria
22
+ de persistencia para que otras tools puedan leer outputs anteriores.
23
+ """
24
+
25
+ def __init__(self, project_root: Path) -> None:
26
+ self._reports_dir = project_root / WORKSPACE_DIR_NAME / _REPORTS_DIR
27
+ self._index_path = self._reports_dir / _INDEX_FILE
28
+
29
+ def write(self, capability_id: str, content: str, fmt: str = "md") -> Path:
30
+ """Persiste el output de una capability y actualiza el índice."""
31
+ self._reports_dir.mkdir(parents=True, exist_ok=True)
32
+ filename = f"{_canonical_name(capability_id)}.{fmt}"
33
+ out_path = self._reports_dir / filename
34
+ out_path.write_text(content, encoding="utf-8")
35
+ self._update_index(capability_id, out_path, len(content))
36
+ return out_path
37
+
38
+ def read(self, capability_id: str) -> str | None:
39
+ """Retorna el último output persistido de una capability, o None."""
40
+ index = self._load_index()
41
+ entry = index.get(capability_id)
42
+ if not entry:
43
+ return None
44
+ path = Path(entry["path"])
45
+ if not path.exists():
46
+ return None
47
+ return path.read_text(encoding="utf-8")
48
+
49
+ def list(self) -> dict[str, dict]:
50
+ """Retorna el índice completo: {capability_id: {path, ts, size_bytes}}."""
51
+ return self._load_index()
52
+
53
+ def _update_index(self, capability_id: str, path: Path, size: int) -> None:
54
+ index = self._load_index()
55
+ index[capability_id] = {
56
+ "path": str(path),
57
+ "ts": datetime.now(timezone.utc).isoformat(timespec="seconds"),
58
+ "size_bytes": size,
59
+ }
60
+ self._index_path.write_text(
61
+ json.dumps(index, indent=2, ensure_ascii=False), encoding="utf-8"
62
+ )
63
+
64
+ def _load_index(self) -> dict:
65
+ if not self._index_path.exists():
66
+ return {}
67
+ try:
68
+ return json.loads(self._index_path.read_text(encoding="utf-8"))
69
+ except (OSError, json.JSONDecodeError):
70
+ return {}
@@ -0,0 +1 @@
1
+ # Infrastructure parser init
@@ -0,0 +1,144 @@
1
+ """CodeChunker - Divide archivos Python y Markdown en fragmentos semánticos."""
2
+
3
+ from __future__ import annotations
4
+ import ast
5
+ from pathlib import Path
6
+ from higpertext.kernel.domain.rag import DocumentChunk
7
+
8
+
9
+ class CodeChunker:
10
+ """Divide archivos de código y documentación en bloques individuales."""
11
+
12
+ @staticmethod
13
+ def chunk_file(file_path: Path, max_chars: int = 1500) -> list[DocumentChunk]:
14
+ """Detecta la extensión e invoca al chunker especializado."""
15
+ if not file_path.exists() or file_path.is_dir():
16
+ return []
17
+
18
+ try:
19
+ content = file_path.read_text(encoding="utf-8", errors="replace")
20
+ except OSError:
21
+ return []
22
+
23
+ if file_path.suffix == ".py":
24
+ return CodeChunker._chunk_python(file_path, content)
25
+ elif file_path.suffix == ".md":
26
+ return CodeChunker._chunk_markdown(file_path, content)
27
+ else:
28
+ return CodeChunker._chunk_generic(file_path, content, max_chars)
29
+
30
+ @staticmethod
31
+ def _chunk_python(file_path: Path, content: str) -> list[DocumentChunk]:
32
+ chunks: list[DocumentChunk] = []
33
+ lines = content.splitlines()
34
+
35
+ try:
36
+ tree = ast.parse(content)
37
+ except SyntaxError:
38
+ # Fallback a segmentación genérica si hay error sintáctico
39
+ return CodeChunker._chunk_generic(file_path, content)
40
+
41
+ # Extraer módulos/clases/funciones
42
+ for node in ast.iter_child_nodes(tree):
43
+ if isinstance(node, (ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef)):
44
+ start = node.lineno
45
+ # Intentar calcular línea final
46
+ end = getattr(node, "end_lineno", len(lines))
47
+ block_content = "\n".join(lines[start - 1 : end])
48
+ chunk_type = "class" if isinstance(node, ast.ClassDef) else "function"
49
+
50
+ chunks.append(
51
+ DocumentChunk(
52
+ file=str(file_path.resolve()),
53
+ content=block_content,
54
+ chunk_type=chunk_type,
55
+ start_line=start,
56
+ end_line=end,
57
+ metadata={"name": node.name},
58
+ )
59
+ )
60
+
61
+ # Si no se extrajeron bloques estructurales, o el archivo es pequeño, agregar todo el archivo
62
+ if not chunks:
63
+ chunks.append(
64
+ DocumentChunk(
65
+ file=str(file_path.resolve()),
66
+ content=content,
67
+ chunk_type="general",
68
+ start_line=1,
69
+ end_line=len(lines),
70
+ )
71
+ )
72
+ return chunks
73
+
74
+ @staticmethod
75
+ def _chunk_markdown(file_path: Path, content: str) -> list[DocumentChunk]:
76
+ chunks: list[DocumentChunk] = []
77
+ lines = content.splitlines()
78
+ current_chunk_lines: list[str] = []
79
+ start_line = 1
80
+
81
+ for idx, line in enumerate(lines, 1):
82
+ if line.startswith("## ") or line.startswith("# "):
83
+ if current_chunk_lines:
84
+ chunks.append(
85
+ DocumentChunk(
86
+ file=str(file_path.resolve()),
87
+ content="\n".join(current_chunk_lines),
88
+ chunk_type="markdown",
89
+ start_line=start_line,
90
+ end_line=idx - 1,
91
+ )
92
+ )
93
+ current_chunk_lines = []
94
+ start_line = idx
95
+ current_chunk_lines.append(line)
96
+
97
+ if current_chunk_lines:
98
+ chunks.append(
99
+ DocumentChunk(
100
+ file=str(file_path.resolve()),
101
+ content="\n".join(current_chunk_lines),
102
+ chunk_type="markdown",
103
+ start_line=start_line,
104
+ end_line=len(lines),
105
+ )
106
+ )
107
+ return chunks
108
+
109
+ @staticmethod
110
+ def _chunk_generic(file_path: Path, content: str, max_chars: int = 1500) -> list[DocumentChunk]:
111
+ chunks: list[DocumentChunk] = []
112
+ lines = content.splitlines()
113
+ current_lines: list[str] = []
114
+ current_len = 0
115
+ start_line = 1
116
+
117
+ for idx, line in enumerate(lines, 1):
118
+ current_lines.append(line)
119
+ current_len += len(line) + 1
120
+ if current_len >= max_chars:
121
+ chunks.append(
122
+ DocumentChunk(
123
+ file=str(file_path.resolve()),
124
+ content="\n".join(current_lines),
125
+ chunk_type="general",
126
+ start_line=start_line,
127
+ end_line=idx,
128
+ )
129
+ )
130
+ current_lines = []
131
+ current_len = 0
132
+ start_line = idx + 1
133
+
134
+ if current_lines:
135
+ chunks.append(
136
+ DocumentChunk(
137
+ file=str(file_path.resolve()),
138
+ content="\n".join(current_lines),
139
+ chunk_type="general",
140
+ start_line=start_line,
141
+ end_line=len(lines),
142
+ )
143
+ )
144
+ return chunks
@@ -0,0 +1,14 @@
1
+ """Shared language parsers — single source of truth for all file-type parsing."""
2
+
3
+ from .base import LanguageParser, ParseResult
4
+ from .python_parser import PythonParser
5
+ from .typescript_parser import TypeScriptParser
6
+ from .powershell_parser import PowerShellParser
7
+
8
+ __all__ = [
9
+ "LanguageParser",
10
+ "ParseResult",
11
+ "PythonParser",
12
+ "TypeScriptParser",
13
+ "PowerShellParser",
14
+ ]
@@ -0,0 +1,41 @@
1
+ """Base contract for all language parsers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from abc import ABC, abstractmethod
6
+ from dataclasses import dataclass, field
7
+ from pathlib import Path
8
+
9
+
10
+ @dataclass
11
+ class ParseResult:
12
+ """Canonical output of every LanguageParser."""
13
+
14
+ imports: list[str] = field(default_factory=list)
15
+ classes: list[dict] = field(default_factory=list)
16
+ functions: list[dict] = field(default_factory=list)
17
+ summary: str = ""
18
+ type: str = "unknown"
19
+ is_entry_point: bool = False
20
+ size: int = 0
21
+
22
+ def to_dict(self) -> dict:
23
+ return {
24
+ "imports": self.imports,
25
+ "classes": self.classes,
26
+ "functions": self.functions,
27
+ "summary": self.summary,
28
+ "type": self.type,
29
+ "is_entry_point": self.is_entry_point,
30
+ "size": self.size,
31
+ }
32
+
33
+
34
+ class LanguageParser(ABC):
35
+ """Contract: every language parser reads a file and returns a ParseResult."""
36
+
37
+ @abstractmethod
38
+ def parse_file(self, file_path: Path) -> ParseResult: ...
39
+
40
+ def empty(self, note: str = "", lang_type: str = "unknown") -> ParseResult:
41
+ return ParseResult(summary=note, type=lang_type)
@@ -0,0 +1,35 @@
1
+ """PowerShell language parser."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ from pathlib import Path
7
+
8
+ from .base import LanguageParser, ParseResult
9
+
10
+ _PS_FUNC = re.compile(r"(?i)^\s*function\s+([a-zA-Z0-9_-]+)")
11
+ _PS_USING = re.compile(r"(?i)^\s*using\s+module\s+([a-zA-Z0-9_\-\.]+)")
12
+
13
+
14
+ class PowerShellParser(LanguageParser):
15
+ """Parses PowerShell files via regex line scanning."""
16
+
17
+ def parse_file(self, file_path: Path) -> ParseResult:
18
+ try:
19
+ lines = file_path.read_text(encoding="utf-8", errors="replace").splitlines()
20
+ except OSError:
21
+ return self.empty(lang_type="powershell")
22
+
23
+ functions = [
24
+ {"name": m.group(1), "parameters": [], "docstring": ""}
25
+ for line in lines
26
+ for m in [_PS_FUNC.match(line)]
27
+ if m
28
+ ]
29
+ imports = [
30
+ m.group(1)
31
+ for line in lines
32
+ for m in [_PS_USING.match(line)]
33
+ if m
34
+ ]
35
+ return ParseResult(imports=imports, functions=functions, type="powershell")