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,42 @@
1
+ """higpertext Engine — orquestador central que ensambla perfiles, capacidades y workflows."""
2
+
3
+ from __future__ import annotations
4
+ from pathlib import Path
5
+ from higpertext.kernel.application.engine import ApplicationHigpertextEngine
6
+ from higpertext.kernel.pkg_resources import resolve_resource
7
+ from higpertext.kernel.application.profile_services import ProfileManager
8
+ from higpertext.kernel.application.capability_manager import CapabilityManager
9
+ from higpertext.kernel.application.workflow_manager import WorkflowManager
10
+
11
+ from higpertext.kernel.infrastructure.logger import get_logger
12
+ _log = get_logger()
13
+
14
+
15
+ class HigpertextEngine:
16
+ """Orquestador central del higpertext Engine v5.0 (Fachada de compatibilidad)."""
17
+
18
+ def __init__(self, base_dir: Path) -> None:
19
+ self.base_dir = base_dir
20
+ self._app_engine = ApplicationHigpertextEngine(base_dir)
21
+
22
+ # Preserva atributos públicos requeridos por otras dependencias del kernel
23
+ # e indirectamente tests
24
+ self.profiles = ProfileManager(resolve_resource(base_dir, "src", "config", "profiles"))
25
+ self.capabilities = CapabilityManager(
26
+ resolve_resource(base_dir, "src", "higpertext", "capabilities")
27
+ )
28
+ self.workflows = WorkflowManager(resolve_resource(base_dir, "src", "config", "workflows"))
29
+
30
+ def get_agent_context(self, profile_name: str, env_data: dict | None = None) -> dict:
31
+ """Construye el contexto completo resolviendo la jerarquía de perfiles."""
32
+ return self._app_engine.get_agent_context(profile_name, env_data)
33
+
34
+ def validate_profile(self, profile_name: str) -> tuple[bool, list[str], list[str]]:
35
+ """Valida un perfil e integridad de sus dependencias."""
36
+ return self._app_engine.validate_profile(profile_name)
37
+
38
+ def get_all_capabilities(self) -> list:
39
+ return self.capabilities.get_all_capabilities_data()
40
+
41
+ def get_all_workflows(self) -> list:
42
+ return self.workflows.get_all_workflows_data()
@@ -0,0 +1,69 @@
1
+ """Single source of truth para resolver el ejecutable htx."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import os
7
+ import platform
8
+ import shutil
9
+ from functools import lru_cache
10
+ from pathlib import Path
11
+
12
+
13
+ @lru_cache(maxsize=1)
14
+ def _load_config() -> dict:
15
+ possible_paths = [
16
+ Path(__file__).resolve().parents[3] / "src" / "config" / "htx_config.json",
17
+ Path(__file__).resolve().parents[4] / "src" / "config" / "htx_config.json",
18
+ Path("/home/aomerge/Documentos/Proyects/agents/LLM-agent/src/config/htx_config.json"),
19
+ ]
20
+ for config_path in possible_paths:
21
+ if config_path.exists():
22
+ try:
23
+ return json.loads(config_path.read_text(encoding="utf-8")).get("htx", {})
24
+ except (OSError, json.JSONDecodeError):
25
+ continue
26
+ return {}
27
+
28
+
29
+ def _config() -> dict:
30
+ return _load_config()
31
+
32
+
33
+ def _cli_name() -> str:
34
+ """Nombre del comando CLI para usar en textos/prompts (leído desde config)."""
35
+ return _config().get("cli_name", "htx")
36
+
37
+
38
+ HTX_CMD = f"{_cli_name()} task"
39
+ HTX_WORKFLOW_CMD = f"{_cli_name()} workflow run"
40
+
41
+
42
+ def get_htx_cmd(project_root: Path) -> list[str]:
43
+ """Resuelve el ejecutable htx en orden de prioridad.
44
+
45
+ 1. Variable de entorno HIGPERTEXT_HTX_BIN (override explícito)
46
+ 2. .venv/bin/htx del project_root
47
+ 3. htx en PATH del sistema
48
+ 4. python htx.py (fallback legacy)
49
+ """
50
+ cfg = _config()
51
+
52
+ env_var = cfg.get("env_override", "HIGPERTEXT_HTX_BIN")
53
+ if override := os.environ.get(env_var):
54
+ return [override]
55
+
56
+ is_windows = platform.system() == "Windows"
57
+ venv_key = "venv_bin_windows" if is_windows else "venv_bin"
58
+ venv_rel = cfg.get(venv_key, ".venv/bin/htx")
59
+ venv_htx = project_root / venv_rel
60
+ if venv_htx.exists():
61
+ return [str(venv_htx)]
62
+
63
+ if system_htx := shutil.which("htx"):
64
+ return [system_htx]
65
+
66
+ fallback = cfg.get("fallback_script", "htx.py")
67
+ venv_python = project_root / ".venv" / ("Scripts/python.exe" if is_windows else "bin/python")
68
+ python = str(venv_python) if venv_python.exists() else "python"
69
+ return [python, str(project_root / fallback)]
@@ -0,0 +1,13 @@
1
+ # Infrastructure layer init
2
+ from higpertext.kernel.infrastructure.governance import ContractLoader, AuditLog
3
+ from higpertext.kernel.infrastructure.agent_registry import JsonAgentRegistry
4
+ from higpertext.kernel.infrastructure.env_runtime import RunStore, ComposeRenderer, TemplateLoader, ComposeBackend, resolve_backend
5
+ from higpertext.kernel.infrastructure.output_store import OutputStore
6
+ from higpertext.kernel.infrastructure.profile_store import ProfileStore
7
+ from higpertext.kernel.infrastructure.telemetry_reporter import render as render_telemetry
8
+ from higpertext.kernel.infrastructure.context_engine import GraphIndex, PackStore, should_skeletonize, extract_skeleton, TelemetryReader
9
+ from higpertext.kernel.infrastructure.semantic_engine import FileCache, GraphRebuildHook, GraphStore, LanguageParser, PythonParser, TypeScriptParser
10
+ from higpertext.kernel.infrastructure.logger import get_logger, HtxLogger, reset_logger
11
+
12
+
13
+
@@ -0,0 +1,40 @@
1
+ from __future__ import annotations
2
+ import json
3
+ from pathlib import Path
4
+
5
+ from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
6
+ from higpertext.kernel.domain.agent_registry import AgentRecord
7
+
8
+ _REGISTRY_PATH = Path(WORKSPACE_DIR_NAME) / "config" / "agents_registry.json"
9
+
10
+
11
+ class JsonAgentRegistry:
12
+ def __init__(self, engine_root: Path) -> None:
13
+ self._path = engine_root / _REGISTRY_PATH
14
+
15
+ def load(self) -> list[AgentRecord]:
16
+ if not self._path.exists():
17
+ return []
18
+ try:
19
+ data = json.loads(self._path.read_text(encoding="utf-8"))
20
+ return [AgentRecord(**a) for a in data.get("agents", [])]
21
+ except (OSError, json.JSONDecodeError, TypeError):
22
+ return []
23
+
24
+ def save(self, agents: list[AgentRecord]) -> None:
25
+ self._path.parent.mkdir(parents=True, exist_ok=True)
26
+ payload = {
27
+ "agents": [
28
+ {
29
+ "name": a.name,
30
+ "path": a.path,
31
+ "profile": a.profile,
32
+ "registered_at": a.registered_at,
33
+ }
34
+ for a in agents
35
+ ]
36
+ }
37
+ self._path.write_text(json.dumps(payload, indent=2, ensure_ascii=False), encoding="utf-8")
38
+
39
+ def find_by_name(self, name: str) -> AgentRecord | None:
40
+ return next((a for a in self.load() if a.name == name), None)
@@ -0,0 +1,319 @@
1
+ """higpertext Capability Cache - cache de resultados basado en hash de inputs + TTL (Infraestructura).""" # noqa: E501
2
+
3
+ from __future__ import annotations
4
+ from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
5
+
6
+ import hashlib
7
+ import json
8
+ import os
9
+ # Tipos CompletedProcess; no ejecuta shell aquí.
10
+ import subprocess # nosec B404
11
+ import time
12
+ from dataclasses import dataclass
13
+ from pathlib import Path
14
+
15
+ from higpertext.kernel.app_config import (
16
+ CACHE_DIR as _CACHE_DIR_NAME,
17
+ CACHE_FILE_GLOB as _CACHE_FILE_GLOB,
18
+ NO_CACHE_CAPABILITIES as _NO_CACHE_CAPABILITIES,
19
+ )
20
+
21
+ _DEFAULT_TTL = 300 # 5 minutos
22
+ _DEFAULT_CACHE_DIR = f"{WORKSPACE_DIR_NAME}/{_CACHE_DIR_NAME}"
23
+
24
+
25
+ @dataclass
26
+ class CacheEntry:
27
+ stdout: str
28
+ stderr: str
29
+ returncode: int
30
+ created_at: float
31
+ ttl: float
32
+
33
+ def is_expired(self) -> bool:
34
+ return time.monotonic() - self.created_at > self.ttl
35
+
36
+ def to_dict(self) -> dict:
37
+ return {
38
+ "stdout": self.stdout,
39
+ "stderr": self.stderr,
40
+ "returncode": self.returncode,
41
+ "created_at": self.created_at,
42
+ "ttl": self.ttl,
43
+ }
44
+
45
+ @classmethod
46
+ def from_dict(cls, data: dict) -> "CacheEntry":
47
+ return cls(
48
+ stdout=data["stdout"],
49
+ stderr=data["stderr"],
50
+ returncode=data["returncode"],
51
+ created_at=data["created_at"],
52
+ ttl=data["ttl"],
53
+ )
54
+
55
+
56
+ class CapabilityCache:
57
+ """
58
+ Cache de resultados de capabilities con invalidación por TTL y hash de inputs.
59
+
60
+ La clave de cache combina:
61
+ - capability_id
62
+ - parámetros de invocación (ordenados y serializados)
63
+ - hash del archivo entrypoint (detecta cambios en el script)
64
+ """
65
+
66
+ def __init__(
67
+ self,
68
+ cache_dir: Path | None = None,
69
+ default_ttl: float = _DEFAULT_TTL,
70
+ ) -> None:
71
+ self._cache_dir = cache_dir or (Path(os.getcwd()) / _DEFAULT_CACHE_DIR)
72
+ self._default_ttl = default_ttl
73
+ self._memory: dict[str, CacheEntry] = {}
74
+ # Índice inverso: capability_id → set de claves de cache
75
+ self._cap_index: dict[str, set[str]] = {}
76
+
77
+ def _ensure_dir(self) -> None:
78
+ self._cache_dir.mkdir(parents=True, exist_ok=True)
79
+
80
+ def _cache_key(self, capability_id: str, params: dict, entrypoint: str = "") -> str:
81
+ payload = {
82
+ "id": capability_id,
83
+ "params": dict(sorted(params.items())),
84
+ "entrypoint_hash": self._hash_entrypoint(entrypoint),
85
+ "workspace_fingerprint": self._workspace_fingerprint(params),
86
+ }
87
+ raw = json.dumps(payload, sort_keys=True, ensure_ascii=False)
88
+ return hashlib.sha256(raw.encode()).hexdigest()[:16]
89
+
90
+ @staticmethod
91
+ def _hash_entrypoint(entrypoint: str) -> str:
92
+ """Hash del script para invalidar cache cuando el script cambia."""
93
+ if not entrypoint:
94
+ return ""
95
+ try:
96
+ content = Path(entrypoint).read_bytes()
97
+ return hashlib.md5(content).hexdigest()[:8] # nosec B324
98
+ except OSError:
99
+ return ""
100
+
101
+ def _cache_file(self, key: str) -> Path:
102
+ return self._cache_dir / f"{key}.json"
103
+
104
+ def _workspace_fingerprint(self, params: dict) -> str:
105
+ """Fingerprint barato del workspace y rutas de entrada relevantes."""
106
+ parts = [self._git_fingerprint(), self._params_paths_fingerprint(params)]
107
+ raw = "|".join(part for part in parts if part)
108
+ return hashlib.sha256(raw.encode()).hexdigest()[:16] if raw else ""
109
+
110
+ @staticmethod
111
+ def _git_fingerprint() -> str:
112
+ try:
113
+ head = subprocess.run(
114
+ ["git", "rev-parse", "HEAD"],
115
+ capture_output=True,
116
+ text=True,
117
+ timeout=2,
118
+ check=False,
119
+ ).stdout.strip()
120
+ status = subprocess.run(
121
+ ["git", "status", "--porcelain=v1"],
122
+ capture_output=True,
123
+ text=True,
124
+ timeout=3,
125
+ check=False,
126
+ ).stdout.strip()
127
+ return f"{head}\n{status}"
128
+ except (OSError, subprocess.TimeoutExpired):
129
+ return ""
130
+
131
+ def _params_paths_fingerprint(self, params: dict) -> str:
132
+ path_keys = {
133
+ "path",
134
+ "tests_path",
135
+ "source_path",
136
+ "file",
137
+ "files",
138
+ "target",
139
+ "target_dir",
140
+ }
141
+ chunks: list[str] = []
142
+ for key, value in sorted(params.items()):
143
+ if key not in path_keys or not value:
144
+ continue
145
+ for item in str(value).replace(",", " ").split():
146
+ chunks.extend(self._path_fingerprint(Path(item)))
147
+ return "\n".join(chunks)
148
+
149
+ @staticmethod
150
+ def _path_fingerprint(path: Path) -> list[str]:
151
+ if not path.exists():
152
+ return []
153
+ if path.is_file():
154
+ stat = path.stat()
155
+ return [f"{path}:{stat.st_size}:{stat.st_mtime_ns}"]
156
+ ignored = {
157
+ ".git",
158
+ ".venv",
159
+ "venv",
160
+ "node_modules",
161
+ "__pycache__",
162
+ WORKSPACE_DIR_NAME,
163
+ }
164
+ chunks: list[str] = []
165
+ for child in sorted(path.rglob("*")):
166
+ if len(chunks) >= 2000:
167
+ chunks.append("[truncated]")
168
+ break
169
+ if any(part in ignored for part in child.parts):
170
+ continue
171
+ if child.is_file():
172
+ stat = child.stat()
173
+ chunks.append(f"{child}:{stat.st_size}:{stat.st_mtime_ns}")
174
+ return chunks
175
+
176
+ def get(self, capability_id: str, params: dict, entrypoint: str = "") -> CacheEntry | None:
177
+ """Retorna la entrada cacheada si existe y no ha expirado."""
178
+ short_id = capability_id.split(".")[-1]
179
+ if capability_id in _NO_CACHE_CAPABILITIES or short_id in _NO_CACHE_CAPABILITIES:
180
+ return None
181
+
182
+ key = self._cache_key(capability_id, params, entrypoint)
183
+
184
+ # Primero revisa memoria
185
+ if key in self._memory:
186
+ entry = self._memory[key]
187
+ if not entry.is_expired():
188
+ return entry
189
+ del self._memory[key]
190
+
191
+ # Luego revisa disco
192
+ cache_file = self._cache_file(key)
193
+ if not cache_file.exists():
194
+ return None
195
+
196
+ try:
197
+ data = json.loads(cache_file.read_text(encoding="utf-8"))
198
+ entry = CacheEntry.from_dict(data)
199
+ if entry.is_expired():
200
+ cache_file.unlink(missing_ok=True)
201
+ return None
202
+ self._memory[key] = entry
203
+ return entry
204
+ except (OSError, json.JSONDecodeError, KeyError):
205
+ return None
206
+
207
+ def set(
208
+ self,
209
+ capability_id: str,
210
+ params: dict,
211
+ stdout: str,
212
+ stderr: str,
213
+ returncode: int,
214
+ entrypoint: str = "",
215
+ ttl: float | None = None,
216
+ ) -> None:
217
+ """Almacena un resultado en cache (memoria + disco)."""
218
+ short_id = capability_id.split(".")[-1]
219
+ if capability_id in _NO_CACHE_CAPABILITIES or short_id in _NO_CACHE_CAPABILITIES:
220
+ return
221
+ if returncode != 0:
222
+ return
223
+
224
+ effective_ttl = ttl if ttl is not None else self._default_ttl
225
+ key = self._cache_key(capability_id, params, entrypoint)
226
+ entry = CacheEntry(
227
+ stdout=stdout,
228
+ stderr=stderr,
229
+ returncode=returncode,
230
+ created_at=time.monotonic(),
231
+ ttl=effective_ttl,
232
+ )
233
+ self._memory[key] = entry
234
+ self._cap_index.setdefault(capability_id, set()).add(key)
235
+
236
+ try:
237
+ self._ensure_dir()
238
+ disk_data = {**entry.to_dict(), "_cap_id": capability_id}
239
+ self._cache_file(key).write_text(
240
+ json.dumps(disk_data, ensure_ascii=False, indent=2),
241
+ encoding="utf-8",
242
+ )
243
+ except OSError: # nosec B110
244
+ pass
245
+
246
+ def invalidate(self, capability_id: str) -> int:
247
+ """Invalida todas las entradas de una capability. Retorna cantidad eliminada."""
248
+ keys = self._cap_index.pop(capability_id, set())
249
+ removed_memory = self._invalidate_memory_and_keys(keys)
250
+ removed_disk = self._invalidate_disk_by_id(capability_id)
251
+ return removed_memory + removed_disk
252
+
253
+ def _invalidate_memory_and_keys(self, keys: set[str]) -> int:
254
+ removed = 0
255
+ for k in keys:
256
+ if k in self._memory:
257
+ del self._memory[k]
258
+ removed += 1
259
+ cache_file = self._cache_file(k)
260
+ if cache_file.exists():
261
+ try:
262
+ cache_file.unlink()
263
+ except OSError: # nosec B110
264
+ pass
265
+ return removed
266
+
267
+ def _invalidate_disk_by_id(self, capability_id: str) -> int:
268
+ removed = 0
269
+ if not self._cache_dir.exists():
270
+ return removed
271
+ for f in self._cache_dir.glob(_CACHE_FILE_GLOB):
272
+ try:
273
+ data = json.loads(f.read_text(encoding="utf-8"))
274
+ if data.get("_cap_id") == capability_id:
275
+ key = f.stem
276
+ self._memory.pop(key, None)
277
+ f.unlink()
278
+ removed += 1
279
+ except (OSError, json.JSONDecodeError): # nosec B110
280
+ pass
281
+ return removed
282
+
283
+ def clear_expired(self) -> int:
284
+ """Elimina del disco todas las entradas expiradas. Retorna cantidad."""
285
+ removed = 0
286
+ if not self._cache_dir.exists():
287
+ return 0
288
+ for f in self._cache_dir.glob(_CACHE_FILE_GLOB):
289
+ try:
290
+ data = json.loads(f.read_text(encoding="utf-8"))
291
+ entry = CacheEntry.from_dict(data)
292
+ if entry.is_expired():
293
+ f.unlink()
294
+ removed += 1
295
+ except (OSError, json.JSONDecodeError, KeyError):
296
+ f.unlink(missing_ok=True)
297
+ removed += 1
298
+ return removed
299
+
300
+ def stats(self) -> dict:
301
+ """Retorna estadísticas del cache."""
302
+ total_disk = len(list(self._cache_dir.glob(_CACHE_FILE_GLOB))) if self._cache_dir.exists() else 0
303
+ return {
304
+ "in_memory": len(self._memory),
305
+ "on_disk": total_disk,
306
+ "cache_dir": str(self._cache_dir),
307
+ "default_ttl_seconds": self._default_ttl,
308
+ }
309
+
310
+
311
+ # Singleton global del cache
312
+ _capability_cache: CapabilityCache | None = None
313
+
314
+
315
+ def get_capability_cache() -> CapabilityCache:
316
+ global _capability_cache
317
+ if _capability_cache is None:
318
+ _capability_cache = CapabilityCache()
319
+ return _capability_cache
@@ -0,0 +1,40 @@
1
+ """Módulo centralizado de utilidades y helpers comunes para scripts de capacidades
2
+ (Infraestructura)."""
3
+
4
+ from __future__ import annotations
5
+ from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
6
+ import json
7
+ from pathlib import Path
8
+
9
+
10
+ class CapabilityHelper:
11
+ @staticmethod
12
+ def get_project_root(start_path: Path | None = None) -> Path:
13
+ """Busca recursivamente hacia arriba hasta encontrar el directorio raíz del proyecto
14
+ (.higpertext o .git)."""
15
+ current = Path(start_path or Path(__file__)).resolve()
16
+ for parent in [current] + list(current.parents):
17
+ if (parent / WORKSPACE_DIR_NAME).exists() or (parent / ".git").exists():
18
+ return parent
19
+ # Fallback al directorio de trabajo actual
20
+ return Path.cwd().resolve()
21
+
22
+ @staticmethod
23
+ def load_json_file(file_path: Path) -> dict:
24
+ """Carga y parsea de forma segura un archivo JSON."""
25
+ if not file_path.exists():
26
+ return {}
27
+ try:
28
+ return json.loads(file_path.read_text(encoding="utf-8"))
29
+ except (OSError, json.JSONDecodeError):
30
+ return {}
31
+
32
+ @classmethod
33
+ def load_environment(cls, root: Path) -> dict:
34
+ """Carga el archivo de configuración de entorno del proyecto."""
35
+ return cls.load_json_file(root / WORKSPACE_DIR_NAME / "config" / "environment.json")
36
+
37
+ @classmethod
38
+ def load_session(cls, root: Path) -> dict:
39
+ """Carga la sesión de desarrollo temporal activa del proyecto."""
40
+ return cls.load_json_file(root / WORKSPACE_DIR_NAME / "state" / "session.json")
@@ -0,0 +1 @@
1
+ # Infrastructure CLI init
@@ -0,0 +1,62 @@
1
+ """Handlers CLI para gestión de agentes registrados."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ from pathlib import Path
7
+
8
+
9
+ def dispatch_agent(nexus, args: argparse.Namespace, logger, root_dir: Path) -> None:
10
+ action = getattr(args, "agent_action", None)
11
+ target = getattr(args, "target", None)
12
+ handlers = {
13
+ "init": lambda: nexus.agent_init(args.profile, target),
14
+ "status": lambda: nexus.agent_status(target),
15
+ "clean": lambda: nexus.agent_clean(target),
16
+ "register": lambda: dispatch_agent_register(args, logger, root_dir),
17
+ "sync": lambda: dispatch_agent_sync(args, logger, root_dir),
18
+ "list": lambda: dispatch_agent_list(logger, root_dir),
19
+ }
20
+ handler = handlers.get(action)
21
+ if handler is None:
22
+ logger.info("Uso: htx agent [init|status|clean|register|sync|list]")
23
+ return
24
+ handler()
25
+
26
+
27
+ def dispatch_agent_register(args: argparse.Namespace, logger, root_dir: Path) -> None:
28
+ from higpertext.kernel.infrastructure import JsonAgentRegistry
29
+ from higpertext.kernel.application import RegisterAgentUseCase
30
+
31
+ try:
32
+ repo = JsonAgentRegistry(root_dir)
33
+ rec = RegisterAgentUseCase(repo).execute(args.name, args.path, args.profile)
34
+ logger.ok(f"[SUCCESS] Agente '{rec.name}' registrado (perfil: {rec.profile})")
35
+ except ValueError as e:
36
+ logger.error(f"[ERROR] {e}")
37
+
38
+
39
+ def dispatch_agent_sync(args: argparse.Namespace, logger, root_dir: Path) -> None:
40
+ from higpertext.kernel.infrastructure import JsonAgentRegistry
41
+ from higpertext.kernel.application import SyncAgentUseCase
42
+
43
+ repo = JsonAgentRegistry(root_dir)
44
+ results = SyncAgentUseCase(repo, root_dir).execute(
45
+ getattr(args, "name", None), getattr(args, "assistant", "claude")
46
+ )
47
+ for result in results:
48
+ logger.ok(f" {'✓' if result.success else '✗'} {result.name}: {result.message}")
49
+ if not results:
50
+ logger.info("[INFO] No hay agentes registrados para sincronizar.")
51
+
52
+
53
+ def dispatch_agent_list(logger, root_dir: Path) -> None:
54
+ from higpertext.kernel.infrastructure import JsonAgentRegistry
55
+ from higpertext.kernel.application import ListAgentsUseCase
56
+
57
+ agents = ListAgentsUseCase(JsonAgentRegistry(root_dir)).execute()
58
+ if not agents:
59
+ logger.info("[INFO] No hay agentes registrados.")
60
+ return
61
+ for agent in agents:
62
+ logger.info(f" • {agent.name:20s} perfil: {agent.profile:20s} {agent.path}")
@@ -0,0 +1,39 @@
1
+ """Helpers de parsing para la capa CLI."""
2
+
3
+ from __future__ import annotations
4
+
5
+
6
+ def parse_kv_args(raw_args: list[str]) -> dict:
7
+ """Parsea una lista ['--key', 'val', ...] en un dict."""
8
+ params: dict = {}
9
+ it = iter(raw_args)
10
+ for item in it:
11
+ if item.startswith("--"):
12
+ key = item.lstrip("--")
13
+ try:
14
+ params[key] = next(it)
15
+ except StopIteration:
16
+ params[key] = True
17
+ return params
18
+
19
+
20
+ def pop_bool_flag(task_args: list[str], flag: str, default: bool) -> tuple[bool, list[str]]:
21
+ """Extrae un flag booleano opcional de argumentos remanentes."""
22
+ if flag not in task_args:
23
+ return default, task_args
24
+
25
+ idx = task_args.index(flag)
26
+ task_args.pop(idx)
27
+ value = True
28
+ if idx < len(task_args) and task_args[idx].lower() in (
29
+ "true",
30
+ "1",
31
+ "yes",
32
+ "false",
33
+ "0",
34
+ "no",
35
+ ):
36
+ value = task_args[idx].lower() in ("true", "1", "yes")
37
+ task_args.pop(idx)
38
+
39
+ return value, task_args