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,191 @@
1
+ """higpertext Health Check — verifica integridad del motor en < 2 s (Infraestructura)."""
2
+
3
+ from __future__ import annotations
4
+ from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
5
+ import json
6
+ import time
7
+ import importlib.util
8
+ from pathlib import Path
9
+ from higpertext.kernel.pkg_resources import resolve_resource, pkg_data_root
10
+ from higpertext.kernel.infrastructure.logger import get_logger
11
+ _log = get_logger()
12
+
13
+ ROOT_DIR = Path(__file__).resolve().parent.parent.parent.parent.parent.parent
14
+ CAPS_DIR = resolve_resource(ROOT_DIR, "src", "higpertext", "capabilities")
15
+ CUSTOM_CAPS_DIR = ROOT_DIR / WORKSPACE_DIR_NAME / "capabilities"
16
+
17
+
18
+ def _check_json_valid(path: Path) -> str | None:
19
+ try:
20
+ json.loads(path.read_text(encoding="utf-8"))
21
+ return None
22
+ except (json.JSONDecodeError, OSError) as e:
23
+ return str(e)
24
+
25
+
26
+ def _collect_all_caps() -> list[Path]:
27
+ dirs = [CAPS_DIR]
28
+ if CUSTOM_CAPS_DIR.exists():
29
+ dirs.append(CUSTOM_CAPS_DIR)
30
+ result = []
31
+ for d in dirs:
32
+ result.extend(d.rglob("*.json"))
33
+ return result
34
+
35
+
36
+ def _display_path(p: Path) -> str:
37
+ for base in (ROOT_DIR, pkg_data_root()):
38
+ if base is not None:
39
+ try:
40
+ return str(p.relative_to(base))
41
+ except ValueError:
42
+ continue
43
+ return str(p)
44
+
45
+
46
+ def _check_entrypoint(cap_json: Path, entrypoint: str) -> dict | None:
47
+ ep_path = entrypoint
48
+ for prefix in ("python3 ", "python "):
49
+ if ep_path.startswith(prefix):
50
+ ep_path = ep_path[len(prefix) :]
51
+ break
52
+ candidates = [ROOT_DIR / "src" / ep_path, ROOT_DIR / ep_path]
53
+ pkg_root = pkg_data_root()
54
+ if pkg_root is not None:
55
+ candidates.append(pkg_root / ep_path)
56
+ if any(c.exists() for c in candidates):
57
+ return None
58
+ return {
59
+ "file": _display_path(cap_json),
60
+ "severity": "critical",
61
+ "issue": f"Entrypoint no encontrado: {entrypoint}",
62
+ }
63
+
64
+
65
+ def _check_capabilities() -> list[dict]:
66
+ issues = []
67
+ for cap_json in _collect_all_caps():
68
+ err = _check_json_valid(cap_json)
69
+ if err:
70
+ issues.append(
71
+ {
72
+ "file": _display_path(cap_json),
73
+ "severity": "critical",
74
+ "issue": f"JSON inválido: {err}",
75
+ }
76
+ )
77
+ continue
78
+
79
+ data = json.loads(cap_json.read_text(encoding="utf-8"))
80
+
81
+ if "version" not in data:
82
+ issues.append(
83
+ {
84
+ "file": _display_path(cap_json),
85
+ "severity": "warning",
86
+ "issue": "Falta campo 'version'",
87
+ }
88
+ )
89
+
90
+ entrypoint = data.get("entrypoint")
91
+ if entrypoint:
92
+ issue = _check_entrypoint(cap_json, entrypoint)
93
+ if issue:
94
+ issues.append(issue)
95
+ return issues
96
+
97
+
98
+ def _check_python_deps() -> list[dict]:
99
+ required = ["argparse", "json", "pathlib", "subprocess", "ast"]
100
+ issues = []
101
+ for mod in required:
102
+ if importlib.util.find_spec(mod) is None:
103
+ issues.append(
104
+ {
105
+ "module": mod,
106
+ "severity": "critical",
107
+ "issue": "Módulo requerido no disponible",
108
+ }
109
+ )
110
+ return issues
111
+
112
+
113
+ def _check_venv() -> dict:
114
+ import platform
115
+ venv_name = ".venv"
116
+ try:
117
+ from higpertext.kernel.htx_resolver import _load_config
118
+ cfg = _load_config()
119
+ is_windows = platform.system() == "Windows"
120
+ venv_rel = cfg.get("venv_bin_windows" if is_windows else "venv_bin", ".venv/bin/htx")
121
+ venv_name = str(Path(venv_rel).parent.parent)
122
+ except Exception as exc:
123
+ _log.warning(f"[health] No se pudo leer config de venv: {exc}")
124
+ venv = ROOT_DIR / venv_name
125
+ if venv.exists():
126
+ return {"status": "ok", "path": str(venv.relative_to(ROOT_DIR))}
127
+ return {
128
+ "status": "warning",
129
+ "message": f"{venv_name} no encontrado — usando Python del sistema",
130
+ }
131
+
132
+
133
+ def run_health_check(verbose: bool = False) -> int:
134
+ t0 = time.time()
135
+ _log.info("=" * 60)
136
+ _log.info("HIGPERTEXT ENGINE — HEALTH CHECK")
137
+ _log.info("=" * 60)
138
+
139
+ cap_issues = _check_capabilities()
140
+ critical_caps = [i for i in cap_issues if i["severity"] == "critical"]
141
+ warning_caps = [i for i in cap_issues if i["severity"] == "warning"]
142
+
143
+ _log.info(f"\n[Capabilities] {len(_collect_all_caps())} archivos JSON escaneados")
144
+ _print_issues(critical_caps, "errores críticos", "✖", verbose=True)
145
+ _print_issues(warning_caps, "advertencias", "⚠", verbose=verbose)
146
+
147
+ dep_issues = _check_python_deps()
148
+ _log.info(f"\n[Python Deps] Módulos core del motor")
149
+ _print_issues(dep_issues, "Módulos faltantes", "✖", key="module")
150
+
151
+ venv_status = _check_venv()
152
+ _log.info(f"\n[Entorno]")
153
+ if venv_status["status"] == "ok":
154
+ _log.info(f" ✔ .venv encontrado: {venv_status['path']}")
155
+ else:
156
+ _log.warning(f" ⚠ {venv_status['message']}")
157
+
158
+ elapsed = time.time() - t0
159
+ ok = len(critical_caps) == 0 and len(dep_issues) == 0
160
+ _log.info(f"\n{'=' * 60}")
161
+ status_label = "OK" if ok else "FAIL"
162
+ _log.info(f"Estado: {status_label} | Tiempo: {elapsed:.2f}s")
163
+ _log.info("=" * 60)
164
+
165
+ return 0 if ok else 1
166
+
167
+
168
+ def _print_issues(
169
+ issues: list[dict],
170
+ label: str,
171
+ symbol: str,
172
+ verbose: bool = False,
173
+ key: str = "issue",
174
+ ) -> None:
175
+ if not issues:
176
+ if label in ("errores críticos", "Módulos faltantes"):
177
+ _log.info(f" ✔ Sin {label.lower()}")
178
+ return
179
+
180
+ show_all = verbose or label in ("errores críticos", "Módulos faltantes")
181
+ total = len(issues)
182
+ if not show_all:
183
+ _log.info(f" {symbol} {total} {label} (usa --verbose para ver)")
184
+ return
185
+
186
+ _log.info(f" {symbol} {total} {label}:")
187
+ for issue in issues[:10]:
188
+ file_info = f"{issue['file']}: " if 'file' in issue else ""
189
+ _log.info(f" - {file_info}{issue[key]}")
190
+ if total > 10 and verbose:
191
+ _log.info(f" ... y {total - 10} más (usa --verbose para ver todos)")
@@ -0,0 +1,227 @@
1
+ """Implementación de infraestructura para ejecución de entornos Docker/Podman."""
2
+
3
+ from __future__ import annotations
4
+ import json
5
+ import shutil
6
+ # Ejecución de Docker/Podman con listas y sin shell.
7
+ import subprocess # nosec B404
8
+ from dataclasses import dataclass
9
+ from pathlib import Path
10
+ from typing import Any
11
+ import yaml
12
+
13
+ from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
14
+ from higpertext.kernel.domain.env_runtime import EnvironmentTemplate, RunState, RunSpec
15
+
16
+
17
+ def run_process(args: list[str], cwd: str, timeout: int = 300) -> tuple[int, str, str]:
18
+ """Ejecuta proceso sin shell y devuelve rc/stdout/stderr."""
19
+ result = subprocess.run(
20
+ args, cwd=cwd, timeout=timeout, capture_output=True, text=True
21
+ )
22
+ return result.returncode, result.stdout or "", result.stderr or ""
23
+
24
+
25
+ @dataclass(frozen=True)
26
+ class CommandResult:
27
+ rc: int
28
+ stdout: str
29
+ stderr: str
30
+
31
+
32
+ class ComposeBackend:
33
+ """Backend común para docker compose y podman compose."""
34
+
35
+ def __init__(self, engine: str) -> None:
36
+ self.engine = engine
37
+
38
+ def available(self) -> bool:
39
+ return shutil.which(self.engine) is not None
40
+
41
+ def compose_base(self, project_name: str, compose_file: Path) -> list[str]:
42
+ return [self.engine, "compose", "-p", project_name, "-f", str(compose_file)]
43
+
44
+ def up(self, project_name: str, compose_file: Path, cwd: Path, timeout: int) -> CommandResult:
45
+ return self._run(self.compose_base(project_name, compose_file) + ["up", "-d"], cwd, timeout)
46
+
47
+ def exec(
48
+ self,
49
+ project_name: str,
50
+ compose_file: Path,
51
+ cwd: Path,
52
+ service: str,
53
+ command: str,
54
+ timeout: int,
55
+ ) -> CommandResult:
56
+ args = self.compose_base(project_name, compose_file) + [
57
+ "exec",
58
+ "-T",
59
+ service,
60
+ "sh",
61
+ "-lc",
62
+ command,
63
+ ]
64
+ return self._run(args, cwd, timeout)
65
+
66
+ def logs(
67
+ self,
68
+ project_name: str,
69
+ compose_file: Path,
70
+ cwd: Path,
71
+ service: str = "",
72
+ tail: int = 200,
73
+ ) -> CommandResult:
74
+ args = self.compose_base(project_name, compose_file) + [
75
+ "logs",
76
+ "--no-color",
77
+ "--tail",
78
+ str(tail),
79
+ ]
80
+ if service:
81
+ args.append(service)
82
+ return self._run(args, cwd, 60)
83
+
84
+ def down(
85
+ self, project_name: str, compose_file: Path, cwd: Path, volumes: bool = False
86
+ ) -> CommandResult:
87
+ args = self.compose_base(project_name, compose_file) + ["down"]
88
+ if volumes:
89
+ args.append("--volumes")
90
+ return self._run(args, cwd, 120)
91
+
92
+ @staticmethod
93
+ def _run(args: list[str], cwd: Path, timeout: int) -> CommandResult:
94
+ rc, stdout, stderr = run_process(args, str(cwd), timeout)
95
+ return CommandResult(rc, stdout, stderr)
96
+
97
+
98
+ def resolve_backend(engine: str) -> ComposeBackend:
99
+ """Selecciona Docker/Podman; auto prefiere Docker y luego Podman."""
100
+ candidates = ["docker", "podman"] if engine == "auto" else [engine]
101
+ for candidate in candidates:
102
+ backend = ComposeBackend(candidate)
103
+ if backend.available():
104
+ return backend
105
+ raise RuntimeError(f"No hay motor de contenedores disponible para: {engine}")
106
+
107
+
108
+ class RunStore:
109
+ """Guarda estados bajo .higpertext/env/runs/<run_id>."""
110
+
111
+ def __init__(self, project_root: Path) -> None:
112
+ self.root = project_root / WORKSPACE_DIR_NAME / "env" / "runs"
113
+ self.root.mkdir(parents=True, exist_ok=True)
114
+
115
+ def run_dir(self, run_id: str) -> Path:
116
+ path = self.root / run_id
117
+ path.mkdir(parents=True, exist_ok=True)
118
+ (path / "logs").mkdir(exist_ok=True)
119
+ return path
120
+
121
+ def save(self, state: RunState) -> None:
122
+ path = Path(state.run_dir) / "state.json"
123
+ path.write_text(json.dumps(state.to_dict(), ensure_ascii=False, indent=2), encoding="utf-8")
124
+
125
+ def load(self, run_id: str) -> RunState:
126
+ path = self.root / run_id / "state.json"
127
+ if not path.exists():
128
+ raise FileNotFoundError(f"Run no encontrado: {run_id}")
129
+ return RunState.from_dict(json.loads(path.read_text(encoding="utf-8")))
130
+
131
+ def list(self) -> list[RunState]:
132
+ states = []
133
+ for path in sorted(self.root.glob("*/state.json")):
134
+ try:
135
+ states.append(RunState.from_dict(json.loads(path.read_text(encoding="utf-8"))))
136
+ except (OSError, json.JSONDecodeError, TypeError):
137
+ continue
138
+ return states
139
+
140
+ def delete(self, run_id: str) -> None:
141
+ shutil.rmtree(self.root / run_id, ignore_errors=True)
142
+
143
+
144
+ class ComposeRenderer:
145
+ """Convierte una plantilla a Docker/Podman Compose."""
146
+
147
+ def render(self, template: EnvironmentTemplate, spec: RunSpec, run_dir: Path) -> Path:
148
+ services = {
149
+ name: self._service_payload(payload, template, spec)
150
+ for name, payload in template.services.items()
151
+ }
152
+ compose = {"services": services}
153
+ if template.security.get("network", "isolated") == "isolated":
154
+ compose["networks"] = {"default": {"name": f"{run_dir.name}_net"}}
155
+ path = run_dir / "compose.yaml"
156
+ path.write_text(yaml.safe_dump(compose, sort_keys=False), encoding="utf-8")
157
+ return path
158
+
159
+ def _service_payload(
160
+ self, payload: dict[str, Any], template: EnvironmentTemplate, spec: RunSpec
161
+ ) -> dict[str, Any]:
162
+ result = {k: v for k, v in payload.items() if k not in {"tasks", "install", "env"}}
163
+ limits = template.limits
164
+ if limits.get("memory"):
165
+ result["mem_limit"] = str(limits["memory"])
166
+ if limits.get("cpus"):
167
+ result["cpus"] = str(limits["cpus"])
168
+ env = dict(result.get("environment", {}) or {})
169
+ env.update(payload.get("env", {}) or {})
170
+ env.update(spec.env)
171
+ if env:
172
+ result["environment"] = env
173
+ result["privileged"] = bool(template.security.get("privileged", False))
174
+ return result
175
+
176
+
177
+ class TemplateLoader:
178
+ """Resuelve templates locales primero y luego templates del motor."""
179
+
180
+ def __init__(self, project_root: Path) -> None:
181
+ self.project_root = project_root
182
+ self.local_dir = project_root / WORKSPACE_DIR_NAME / "env" / "templates"
183
+ self.engine_dir = Path(__file__).resolve().parents[2] / "templates" / "env"
184
+
185
+ def list_templates(self) -> list[EnvironmentTemplate]:
186
+ templates: dict[str, EnvironmentTemplate] = {}
187
+ for directory in (self.engine_dir, self.local_dir):
188
+ if not directory.exists():
189
+ continue
190
+ for path in sorted(
191
+ [
192
+ *directory.glob("*.yaml"),
193
+ *directory.glob("*.yml"),
194
+ *directory.glob("*.json"),
195
+ ]
196
+ ):
197
+ template = self.load_file(path)
198
+ templates[template.id] = template
199
+ return sorted(templates.values(), key=lambda item: item.id)
200
+
201
+ def load(self, template_id: str) -> EnvironmentTemplate:
202
+ for directory in (self.local_dir, self.engine_dir):
203
+ for suffix in (".yaml", ".yml", ".json"):
204
+ path = directory / f"{template_id}{suffix}"
205
+ if path.exists():
206
+ return self.load_file(path)
207
+ raise FileNotFoundError(f"Template no encontrado: {template_id}")
208
+
209
+ @staticmethod
210
+ def load_file(path: Path) -> EnvironmentTemplate:
211
+ data: dict[str, Any]
212
+ if path.suffix == ".json":
213
+ data = json.loads(path.read_text(encoding="utf-8"))
214
+ else:
215
+ data = yaml.safe_load(path.read_text(encoding="utf-8")) or {}
216
+ if not data.get("id") or not isinstance(data.get("services"), dict):
217
+ raise ValueError(f"Template inválido: {path}")
218
+ return EnvironmentTemplate(
219
+ id=data["id"],
220
+ description=data.get("description", ""),
221
+ services=data["services"],
222
+ defaults=data.get("defaults", {}),
223
+ tasks=data.get("tasks", data.get("checks", {})),
224
+ limits=data.get("limits", {}),
225
+ security=data.get("security", {}),
226
+ source=path,
227
+ )
@@ -0,0 +1 @@
1
+ # Infrastructure execution init
@@ -0,0 +1,188 @@
1
+ """higpertext Parallel Executor — ejecución concurrente de pasos independientes en workflows
2
+ (Infraestructura)."""
3
+
4
+ from __future__ import annotations
5
+ import threading
6
+ from dataclasses import dataclass, field
7
+ from typing import Callable
8
+
9
+ from higpertext.kernel.infrastructure.logger import get_logger
10
+ _log = get_logger()
11
+
12
+
13
+ @dataclass
14
+ class StepResult:
15
+ step: int
16
+ task: str
17
+ success: bool
18
+ error: str = ""
19
+
20
+
21
+ @dataclass
22
+ class StepGroup:
23
+ """Grupo de pasos que pueden ejecutarse en paralelo."""
24
+
25
+ steps: list[dict] = field(default_factory=list)
26
+
27
+ def is_parallel(self) -> bool:
28
+ return len(self.steps) > 1
29
+
30
+
31
+ def build_step_groups(chain: list[dict]) -> list[StepGroup]:
32
+ """Agrupa pasos del workflow por nivel de paralelismo."""
33
+ sorted_chain = sorted(chain, key=lambda x: x.get("step", 0))
34
+ groups: list[StepGroup] = []
35
+ current_group: StepGroup | None = None
36
+ current_pg: str | None = None
37
+
38
+ for step in sorted_chain:
39
+ is_parallel = step.get("parallel", False)
40
+ pg = step.get("parallel_group", None)
41
+
42
+ if is_parallel:
43
+ effective_pg = pg or "__auto__"
44
+ if current_group is None or current_pg != effective_pg:
45
+ current_group = StepGroup()
46
+ groups.append(current_group)
47
+ current_pg = effective_pg
48
+ current_group.steps.append(step)
49
+ else:
50
+ current_group = StepGroup(steps=[step])
51
+ groups.append(current_group)
52
+ current_pg = None
53
+
54
+ return groups
55
+
56
+
57
+ class ParallelExecutor:
58
+ """Ejecuta grupos de pasos de workflow en paralelo usando threads."""
59
+
60
+ def __init__(self, run_task_fn: Callable[[str, dict], bool]) -> None:
61
+ self._run_task = run_task_fn
62
+
63
+ def execute_group(self, group: StepGroup, params: dict) -> list[StepResult]:
64
+ if not group.is_parallel():
65
+ return [self._execute_step(group.steps[0], params)]
66
+
67
+ results: list[StepResult] = []
68
+ lock = threading.Lock()
69
+ threads: list[threading.Thread] = []
70
+
71
+ def worker(step: dict) -> None:
72
+ res = self._execute_step(step, params)
73
+ with lock:
74
+ results.append(res)
75
+
76
+ step_nums = [s.get("step", "?") for s in group.steps]
77
+ _log.info(f"[Parallel] Ejecutando pasos {step_nums} concurrentemente...")
78
+
79
+ for step in group.steps:
80
+ t = threading.Thread(target=worker, args=(step,), daemon=True)
81
+ threads.append(t)
82
+ t.start()
83
+
84
+ for t in threads:
85
+ t.join()
86
+
87
+ results.sort(key=lambda r: r.step)
88
+ return results
89
+
90
+ def _execute_step(self, step: dict, params: dict) -> StepResult:
91
+ step_type = step.get("type", "task")
92
+ step_num = step.get("step", 0)
93
+ merged = {**params, **step.get("params", {})}
94
+
95
+ if step_type == "llm":
96
+ return self._execute_llm_step(step, step_num, merged)
97
+
98
+ task_name = step.get("task", "")
99
+ _log.info(f"[Step {step_num}] Iniciando tarea: {task_name}")
100
+ try:
101
+ success = self._run_task(task_name, merged)
102
+ return StepResult(step=step_num, task=task_name, success=success)
103
+ except Exception as e: # noqa: BLE001
104
+ return StepResult(step=step_num, task=task_name, success=False, error=str(e))
105
+
106
+ def _execute_llm_step(self, step: dict, step_num: int, params: dict) -> StepResult:
107
+ """Ejecuta un step de tipo 'llm' via common.llm-invoke."""
108
+ llm_params = {
109
+ "prompt": step.get("prompt", params.get("prompt", "")),
110
+ "provider": step.get("provider", params.get("provider", "")),
111
+ "model": step.get("model", params.get("model", "")),
112
+ "system": step.get("system", params.get("system", "")),
113
+ "max_tokens": step.get("max_tokens", params.get("max_tokens", 1024)),
114
+ "temperature": step.get("temperature", params.get("temperature", 0.7)),
115
+ "stream": step.get("stream", params.get("stream", "false")),
116
+ "output_file": step.get("output_file", params.get("output_file", "")),
117
+ }
118
+ label = f"llm:{step.get('provider', 'default')}"
119
+ _log.info(f"[Step {step_num}] Iniciando step LLM: {label}")
120
+ try:
121
+ success = self._run_task("common.llm-invoke", llm_params)
122
+ return StepResult(step=step_num, task=label, success=success)
123
+ except Exception as e: # noqa: BLE001
124
+ return StepResult(step=step_num, task=label, success=False, error=str(e))
125
+
126
+ def _resolve_step_params(
127
+ self,
128
+ group: StepGroup,
129
+ params: dict,
130
+ interpolate_fn: Callable[[dict, dict], dict] | None,
131
+ ) -> list[dict]:
132
+ step_params_list: list[dict] = []
133
+ for step in group.steps:
134
+ raw = step.get("params", {})
135
+ resolved = interpolate_fn(raw, params) if interpolate_fn else raw
136
+ step_params_list.append(resolved)
137
+ return step_params_list
138
+
139
+ def _execute_group_with_params(
140
+ self,
141
+ group: StepGroup,
142
+ step_params_list: list[dict],
143
+ params: dict,
144
+ ) -> list[StepResult]:
145
+ if group.is_parallel():
146
+ enriched_steps = [
147
+ {**step, "params": sp}
148
+ for step, sp in zip(group.steps, step_params_list)
149
+ ]
150
+ group_with_params = StepGroup(steps=enriched_steps)
151
+ return self.execute_group(group_with_params, params)
152
+
153
+ step = {**group.steps[0], "params": step_params_list[0]}
154
+ return [self._execute_step(step, params)]
155
+
156
+ def _handle_results(self, group: StepGroup, results: list[StepResult]) -> bool:
157
+ for res in results:
158
+ if res.success:
159
+ continue
160
+
161
+ step_def = next((s for s in group.steps if s.get("step") == res.step), {})
162
+ on_failure = step_def.get("on_failure", "abort")
163
+ if res.error:
164
+ _log.warning(f"[!] Paso {res.step} ({res.task}) — excepción: {res.error}")
165
+ else:
166
+ _log.warning(f"[!] Paso {res.step} ({res.task}) falló. Acción: {on_failure}")
167
+
168
+ if on_failure == "abort":
169
+ _log.error("[ERROR] Flujo de trabajo abortado.")
170
+ return False
171
+ return True
172
+
173
+ def execute_chain(
174
+ self,
175
+ chain: list[dict],
176
+ params: dict,
177
+ interpolate_fn: Callable[[dict, dict], dict] | None = None,
178
+ ) -> bool:
179
+ groups = build_step_groups(chain)
180
+
181
+ for group in groups:
182
+ step_params_list = self._resolve_step_params(group, params, interpolate_fn)
183
+ results = self._execute_group_with_params(group, step_params_list, params)
184
+ if not self._handle_results(group, results):
185
+ return False
186
+
187
+ _log.ok("\n[SUCCESS] Flujo de trabajo completado con éxito.")
188
+ return True