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.
- config/adapters_config.json +450 -0
- config/antigravity_agent_template.json +31 -0
- config/app_config.json +174 -0
- config/context_engine.json +33 -0
- config/environments/model_defaults.json +5 -0
- config/governance/branching_strategy.json +36 -0
- config/governance/deployment_gates.json +30 -0
- config/governance/guidelines_contract.json +54 -0
- config/governance/quality_gates.json +39 -0
- config/governance/section_rules.json +22 -0
- config/governance/security_guardrails.json +52 -0
- config/hooks/README.md +35 -0
- config/hooks/custom/test_output_limiter.json +9 -0
- config/hooks/global/session_prompt.json +9 -0
- config/htx_config.json +24 -0
- config/profile_learner.json +18 -0
- config/profiles/base_agent.json +40 -0
- config/profiles/base_auditor.json +19 -0
- config/profiles/base_developer.json +19 -0
- config/profiles/base_operator.json +16 -0
- config/profiles/global.json +33 -0
- config/profiles/software_developer.json +23 -0
- config/router_content.json +137 -0
- config/semantic_graph.json +66 -0
- config/workflows/ado_release_flow.json +38 -0
- config/workflows/docs-update.json +33 -0
- config/workflows/governance-check.yaml +26 -0
- config/workflows/guidelines-sync.json +40 -0
- config/workflows/higpertext-build.json +73 -0
- config/workflows/higpertext-plan.json +38 -0
- config/workflows/higpertext-review.json +41 -0
- config/workflows/pr-quality-check.json +56 -0
- config/workflows/quality-remediation.json +57 -0
- higpertext/__init__.py +18 -0
- higpertext/adapters/__init__.py +27 -0
- higpertext/adapters/adapter_utils.py +604 -0
- higpertext/adapters/claude_adapter/__init__.py +0 -0
- higpertext/adapters/claude_adapter/claude_adapter.py +154 -0
- higpertext/adapters/copilot_adapter/__init__.py +0 -0
- higpertext/adapters/copilot_adapter/copilot_adapter.py +231 -0
- higpertext/adapters/gemini_adapter/__init__.py +0 -0
- higpertext/adapters/gemini_adapter/gemini_adapter.py +211 -0
- higpertext/adapters/llm_formatter.py +46 -0
- higpertext/adapters/open_code_adapter/__init__.py +0 -0
- higpertext/adapters/open_code_adapter/open_code_adapter.py +480 -0
- higpertext/capabilities/capabilities_runner.py +216 -0
- higpertext/capabilities/common/agent-builder.json +54 -0
- higpertext/capabilities/common/agent-sync.json +34 -0
- higpertext/capabilities/common/code-skeletonizer.json +35 -0
- higpertext/capabilities/common/commit-report.json +42 -0
- higpertext/capabilities/common/context-assembler.json +37 -0
- higpertext/capabilities/common/context-budget-report.json +15 -0
- higpertext/capabilities/common/dep-manager.json +43 -0
- higpertext/capabilities/common/docs-sync.json +14 -0
- higpertext/capabilities/common/doctor.json +18 -0
- higpertext/capabilities/common/efficiency-meter.json +31 -0
- higpertext/capabilities/common/env-catalog.json +13 -0
- higpertext/capabilities/common/env-clean.json +14 -0
- higpertext/capabilities/common/env-logs.json +16 -0
- higpertext/capabilities/common/env-runner.json +23 -0
- higpertext/capabilities/common/env-status.json +13 -0
- higpertext/capabilities/common/env-stop.json +14 -0
- higpertext/capabilities/common/env-template.json +14 -0
- higpertext/capabilities/common/error-context-locator.json +23 -0
- higpertext/capabilities/common/eval-agent.json +33 -0
- higpertext/capabilities/common/file-map.json +17 -0
- higpertext/capabilities/common/governance-exception.json +54 -0
- higpertext/capabilities/common/graph-query.json +59 -0
- higpertext/capabilities/common/graph-rebuild.json +31 -0
- higpertext/capabilities/common/graph-visualize.json +37 -0
- higpertext/capabilities/common/grep-search.json +176 -0
- higpertext/capabilities/common/higpertext-tester.json +25 -0
- higpertext/capabilities/common/hook-health.json +19 -0
- higpertext/capabilities/common/hook-sync-check.json +19 -0
- higpertext/capabilities/common/hooks-manager.json +55 -0
- higpertext/capabilities/common/knowledge-asker.json +27 -0
- higpertext/capabilities/common/list-rules.json +27 -0
- higpertext/capabilities/common/llm-invoke.json +59 -0
- higpertext/capabilities/common/load-rules.json +37 -0
- higpertext/capabilities/common/memory-manager.json +65 -0
- higpertext/capabilities/common/quality-scan.json +21 -0
- higpertext/capabilities/common/quality-updater.json +35 -0
- higpertext/capabilities/common/rag-index.json +17 -0
- higpertext/capabilities/common/report-viewer.json +24 -0
- higpertext/capabilities/common/roadmap-report.json +37 -0
- higpertext/capabilities/common/scripts/_env_cli.py +65 -0
- higpertext/capabilities/common/scripts/agent_builder.py +60 -0
- higpertext/capabilities/common/scripts/agent_sync.py +56 -0
- higpertext/capabilities/common/scripts/ask_higpertext.py +38 -0
- higpertext/capabilities/common/scripts/code_skeletonizer.py +225 -0
- higpertext/capabilities/common/scripts/commit_report.py +134 -0
- higpertext/capabilities/common/scripts/context_assembler.py +70 -0
- higpertext/capabilities/common/scripts/context_budget_report.py +53 -0
- higpertext/capabilities/common/scripts/dep_manager.py +81 -0
- higpertext/capabilities/common/scripts/docs_sync.py +981 -0
- higpertext/capabilities/common/scripts/doctor.py +144 -0
- higpertext/capabilities/common/scripts/efficiency_meter.py +83 -0
- higpertext/capabilities/common/scripts/env_catalog.py +47 -0
- higpertext/capabilities/common/scripts/env_clean.py +30 -0
- higpertext/capabilities/common/scripts/env_logs.py +32 -0
- higpertext/capabilities/common/scripts/env_runner.py +53 -0
- higpertext/capabilities/common/scripts/env_status.py +38 -0
- higpertext/capabilities/common/scripts/env_stop.py +30 -0
- higpertext/capabilities/common/scripts/env_template.py +73 -0
- higpertext/capabilities/common/scripts/error_context_locator.py +138 -0
- higpertext/capabilities/common/scripts/eval_agent.py +80 -0
- higpertext/capabilities/common/scripts/file_map.py +95 -0
- higpertext/capabilities/common/scripts/governance_exception.py +116 -0
- higpertext/capabilities/common/scripts/graph_query.py +104 -0
- higpertext/capabilities/common/scripts/graph_rebuild.py +107 -0
- higpertext/capabilities/common/scripts/graph_visualize.py +76 -0
- higpertext/capabilities/common/scripts/grep_search.py +648 -0
- higpertext/capabilities/common/scripts/higpertext_tester.py +102 -0
- higpertext/capabilities/common/scripts/hook_health.py +149 -0
- higpertext/capabilities/common/scripts/hook_sync_check.py +134 -0
- higpertext/capabilities/common/scripts/hooks_manager.py +171 -0
- higpertext/capabilities/common/scripts/list_rules.py +175 -0
- higpertext/capabilities/common/scripts/llm_invoke.py +135 -0
- higpertext/capabilities/common/scripts/load_rules.py +379 -0
- higpertext/capabilities/common/scripts/memory_manager.py +210 -0
- higpertext/capabilities/common/scripts/presentation_engine.py +63 -0
- higpertext/capabilities/common/scripts/quality_scan.py +132 -0
- higpertext/capabilities/common/scripts/rag_index.py +39 -0
- higpertext/capabilities/common/scripts/report_viewer.py +106 -0
- higpertext/capabilities/common/scripts/roadmap_report.py +73 -0
- higpertext/capabilities/common/scripts/search_router.py +111 -0
- higpertext/capabilities/common/scripts/semantic_diff.py +166 -0
- higpertext/capabilities/common/scripts/semantic_search.py +43 -0
- higpertext/capabilities/common/scripts/session_control.py +136 -0
- higpertext/capabilities/common/scripts/smart_read.py +232 -0
- higpertext/capabilities/common/scripts/subagent_executor.py +143 -0
- higpertext/capabilities/common/scripts/sync_agents.py +353 -0
- higpertext/capabilities/common/scripts/task_decomposer.py +78 -0
- higpertext/capabilities/common/scripts/telemetry_report.py +36 -0
- higpertext/capabilities/common/search-router.json +24 -0
- higpertext/capabilities/common/semantic-diff.json +40 -0
- higpertext/capabilities/common/semantic-search.json +19 -0
- higpertext/capabilities/common/session-clean.json +20 -0
- higpertext/capabilities/common/session-start.json +44 -0
- higpertext/capabilities/common/smart-read.json +28 -0
- higpertext/capabilities/common/subagent-executor.json +25 -0
- higpertext/capabilities/common/sync-agents.json +32 -0
- higpertext/capabilities/common/task-decomposer.json +37 -0
- higpertext/capabilities/common/telemetry-report.json +23 -0
- higpertext/capabilities/git/__init__.py +0 -0
- higpertext/capabilities/git/committer.json +61 -0
- higpertext/capabilities/git/diff.json +33 -0
- higpertext/capabilities/git/ls-files.json +44 -0
- higpertext/capabilities/git/rm.json +27 -0
- higpertext/capabilities/git/scripts/__init__.py +0 -0
- higpertext/capabilities/git/scripts/commit_changes.py +1077 -0
- higpertext/capabilities/git/scripts/git_diff.py +171 -0
- higpertext/capabilities/git/scripts/git_ls_files.py +376 -0
- higpertext/capabilities/git/scripts/git_rm.py +62 -0
- higpertext/capabilities/security/k8s-auditor.json +33 -0
- higpertext/capabilities/security/scripts/k8s_auditor.py +307 -0
- higpertext/capabilities/security/scripts/secret_scanner.py +235 -0
- higpertext/capabilities/security/secret-scanner.json +32 -0
- higpertext/hooks/__init__.py +28 -0
- higpertext/hooks/_compat.py +27 -0
- higpertext/hooks/hook_tasks/__init__.py +1 -0
- higpertext/hooks/hook_tasks/_rules/__init__.py +0 -0
- higpertext/hooks/hook_tasks/_rules/bash_rules.py +635 -0
- higpertext/hooks/hook_tasks/_rules/context_engine_rule.py +79 -0
- higpertext/hooks/hook_tasks/_rules/context_rules.py +199 -0
- higpertext/hooks/hook_tasks/_rules/governance_adapter.py +72 -0
- higpertext/hooks/hook_tasks/_rules/profile_rules.json +25 -0
- higpertext/hooks/hook_tasks/_rules/quality_rules.py +86 -0
- higpertext/hooks/hook_tasks/_rules/security_rules.py +214 -0
- higpertext/hooks/hook_tasks/_rules/session_rules.py +316 -0
- higpertext/hooks/hook_tasks/_rules/telemetry_rules.py +121 -0
- higpertext/hooks/hook_tasks/audit_logger_hook.py +28 -0
- higpertext/hooks/hook_tasks/hook_bash_guard.py +101 -0
- higpertext/hooks/hook_tasks/hook_code_quality.py +48 -0
- higpertext/hooks/hook_tasks/hook_context_hint.py +46 -0
- higpertext/hooks/hook_tasks/hook_context_manager.py +44 -0
- higpertext/hooks/hook_tasks/hook_io.py +122 -0
- higpertext/hooks/hook_tasks/hook_loop_guard.py +182 -0
- higpertext/hooks/hook_tasks/hook_post_observer.py +54 -0
- higpertext/hooks/hook_tasks/hook_read_guard.py +85 -0
- higpertext/hooks/hook_tasks/hook_security_guard.py +81 -0
- higpertext/hooks/hook_tasks/hook_session_prompt.py +83 -0
- higpertext/hooks/hook_tasks/hook_session_stop.py +115 -0
- higpertext/hooks/hook_tasks/hook_utils.py +144 -0
- higpertext/hooks/hook_tasks/session_guard_hook.py +23 -0
- higpertext/hooks/hook_tasks/telemetry_utils.py +176 -0
- higpertext/hooks/hook_tasks/test_echo_hook.py +33 -0
- higpertext/hooks/hook_tasks/webhook_hook.py +54 -0
- higpertext/hooks/hook_tasks/workflow_runner_hook.py +49 -0
- higpertext/hooks/hooks_catalog.json +116 -0
- higpertext/kernel/__init__.py +63 -0
- higpertext/kernel/_compat.py +138 -0
- higpertext/kernel/app_config.py +117 -0
- higpertext/kernel/application/__init__.py +13 -0
- higpertext/kernel/application/agent_registry.py +102 -0
- higpertext/kernel/application/capability_manager.py +61 -0
- higpertext/kernel/application/commit_reporter.py +247 -0
- higpertext/kernel/application/context_builder.py +166 -0
- higpertext/kernel/application/context_engine.py +409 -0
- higpertext/kernel/application/engine.py +41 -0
- higpertext/kernel/application/env_runtime.py +174 -0
- higpertext/kernel/application/environment_manager.py +154 -0
- higpertext/kernel/application/governance.py +192 -0
- higpertext/kernel/application/hook_registry.py +102 -0
- higpertext/kernel/application/hook_renderer.py +720 -0
- higpertext/kernel/application/ports.py +49 -0
- higpertext/kernel/application/profile_learner.py +358 -0
- higpertext/kernel/application/profile_service.py +205 -0
- higpertext/kernel/application/profile_services.py +6 -0
- higpertext/kernel/application/profile_use_cases.py +93 -0
- higpertext/kernel/application/rag_service.py +75 -0
- higpertext/kernel/application/roadmap_reporter.py +178 -0
- higpertext/kernel/application/semantic_engine.py +258 -0
- higpertext/kernel/application/session_services.py +33 -0
- higpertext/kernel/application/skill_hook_compiler.py +85 -0
- higpertext/kernel/application/telemetry.py +326 -0
- higpertext/kernel/application/workflow_manager.py +176 -0
- higpertext/kernel/config_paths.py +66 -0
- higpertext/kernel/domain/__init__.py +12 -0
- higpertext/kernel/domain/agent_registry.py +23 -0
- higpertext/kernel/domain/commit_reporter.py +155 -0
- higpertext/kernel/domain/compilers.py +7 -0
- higpertext/kernel/domain/context_engine.py +319 -0
- higpertext/kernel/domain/entities.py +51 -0
- higpertext/kernel/domain/env_runtime.py +62 -0
- higpertext/kernel/domain/governance.py +198 -0
- higpertext/kernel/domain/hook_models.py +29 -0
- higpertext/kernel/domain/profile_learner.py +186 -0
- higpertext/kernel/domain/rag.py +70 -0
- higpertext/kernel/domain/repositories.py +8 -0
- higpertext/kernel/domain/roadmap_reporter.py +80 -0
- higpertext/kernel/domain/semantic_engine.py +107 -0
- higpertext/kernel/engine.py +42 -0
- higpertext/kernel/htx_resolver.py +69 -0
- higpertext/kernel/infrastructure/__init__.py +13 -0
- higpertext/kernel/infrastructure/agent_registry.py +40 -0
- higpertext/kernel/infrastructure/cache/capability_cache.py +319 -0
- higpertext/kernel/infrastructure/capability_helper.py +40 -0
- higpertext/kernel/infrastructure/cli/__init__.py +1 -0
- higpertext/kernel/infrastructure/cli/agent_commands.py +62 -0
- higpertext/kernel/infrastructure/cli/arguments.py +39 -0
- higpertext/kernel/infrastructure/cli/capability_command_builder.py +86 -0
- higpertext/kernel/infrastructure/cli/capability_task_service.py +234 -0
- higpertext/kernel/infrastructure/cli/cli_search.py +234 -0
- higpertext/kernel/infrastructure/cli/parameter_contracts.py +83 -0
- higpertext/kernel/infrastructure/cli/parser_builder.py +122 -0
- higpertext/kernel/infrastructure/cli/profile_commands.py +89 -0
- higpertext/kernel/infrastructure/cli/roadmap_commands.py +117 -0
- higpertext/kernel/infrastructure/cli/router.py +1110 -0
- higpertext/kernel/infrastructure/cli/session_commands.py +36 -0
- higpertext/kernel/infrastructure/cli/task_commands.py +23 -0
- higpertext/kernel/infrastructure/cli/task_result_reporter.py +56 -0
- higpertext/kernel/infrastructure/cli/workflow_commands.py +25 -0
- higpertext/kernel/infrastructure/compilers/__init__.py +3 -0
- higpertext/kernel/infrastructure/compilers/factory.py +27 -0
- higpertext/kernel/infrastructure/compilers/graph_compiler.py +20 -0
- higpertext/kernel/infrastructure/compilers/guide_compiler.py +50 -0
- higpertext/kernel/infrastructure/compilers/hook_compiler.py +69 -0
- higpertext/kernel/infrastructure/compilers/playbook_compiler.py +154 -0
- higpertext/kernel/infrastructure/context_engine.py +303 -0
- higpertext/kernel/infrastructure/database/local_vector_store.py +99 -0
- higpertext/kernel/infrastructure/deployment/__init__.py +1 -0
- higpertext/kernel/infrastructure/deployment/resource_deployer.py +283 -0
- higpertext/kernel/infrastructure/diagnostics/__init__.py +1 -0
- higpertext/kernel/infrastructure/diagnostics/health.py +191 -0
- higpertext/kernel/infrastructure/env_runtime.py +227 -0
- higpertext/kernel/infrastructure/execution/__init__.py +1 -0
- higpertext/kernel/infrastructure/execution/parallel.py +188 -0
- higpertext/kernel/infrastructure/execution/resilience.py +155 -0
- higpertext/kernel/infrastructure/file_repositories.py +213 -0
- higpertext/kernel/infrastructure/governance.py +198 -0
- higpertext/kernel/infrastructure/hook_config_loader.py +53 -0
- higpertext/kernel/infrastructure/hook_webhook_dispatcher.py +61 -0
- higpertext/kernel/infrastructure/hook_workflow_bridge.py +60 -0
- higpertext/kernel/infrastructure/llm/__init__.py +6 -0
- higpertext/kernel/infrastructure/llm/provider.py +46 -0
- higpertext/kernel/infrastructure/llm/providers/__init__.py +0 -0
- higpertext/kernel/infrastructure/llm/providers/anthropic_provider.py +94 -0
- higpertext/kernel/infrastructure/llm/providers/gemini_embeddings.py +74 -0
- higpertext/kernel/infrastructure/llm/providers/gemini_provider.py +101 -0
- higpertext/kernel/infrastructure/llm/providers/ollama_provider.py +110 -0
- higpertext/kernel/infrastructure/llm/providers/openai_provider.py +98 -0
- higpertext/kernel/infrastructure/llm/registry.py +81 -0
- higpertext/kernel/infrastructure/logger.py +303 -0
- higpertext/kernel/infrastructure/output_store.py +70 -0
- higpertext/kernel/infrastructure/parser/__init__.py +1 -0
- higpertext/kernel/infrastructure/parser/code_chunker.py +144 -0
- higpertext/kernel/infrastructure/parser/language/__init__.py +14 -0
- higpertext/kernel/infrastructure/parser/language/base.py +41 -0
- higpertext/kernel/infrastructure/parser/language/powershell_parser.py +35 -0
- higpertext/kernel/infrastructure/parser/language/python_parser.py +98 -0
- higpertext/kernel/infrastructure/parser/language/typescript_parser.py +91 -0
- higpertext/kernel/infrastructure/parser/semantic_graph.py +409 -0
- higpertext/kernel/infrastructure/presentation/__init__.py +1 -0
- higpertext/kernel/infrastructure/presentation/html_renderer.py +137 -0
- higpertext/kernel/infrastructure/presentation/markdown_renderer.py +84 -0
- higpertext/kernel/infrastructure/presentation/markdown_report_renderer.py +97 -0
- higpertext/kernel/infrastructure/profile_store.py +28 -0
- higpertext/kernel/infrastructure/semantic_engine.py +289 -0
- higpertext/kernel/infrastructure/telemetry_reporter.py +132 -0
- higpertext/kernel/infrastructure/validation/__init__.py +1 -0
- higpertext/kernel/infrastructure/validation/contract_validator.py +163 -0
- higpertext/kernel/pkg_resources.py +38 -0
- higpertext/kernel/session_manager.py +319 -0
- higpertext/templates/env/generic-shell.yaml +21 -0
- higpertext/templates/env/node-vitest.yaml +27 -0
- higpertext/templates/env/python-pytest.yaml +29 -0
- higpertext/templates/html/commit_body.html +20 -0
- higpertext/templates/html/commit_diff.html +4 -0
- higpertext/templates/html/commit_index.html +29 -0
- higpertext/templates/html/commit_layer.html +11 -0
- higpertext/templates/html/commit_shell.html +28 -0
- higpertext/templates/html/graph_visualize.html +86 -0
- higpertext/templates/html/roadmap_body.html +12 -0
- higpertext/templates/html/roadmap_phase.html +5 -0
- higpertext/templates/html/roadmap_shell.html +29 -0
- higpertext/templates/markdown/commit_report.md +18 -0
- higpertext/templates/markdown/efficiency_report.md +12 -0
- higpertext/templates/markdown/roadmap_report.md +25 -0
- higpertext/templates/skills/best-practices.md +7 -0
- higpertext/templates/skills/clean-code.md +8 -0
- higpertext/templates/skills/ddd-standards.md +7 -0
- higpertext/templates/skills/tdd-practices.md +7 -0
- higpertext/templates/subagents/architect.md +7 -0
- higpertext/templates/subagents/test-engineer.md +7 -0
- higpertext/templates/workflows/build.json +23 -0
- higpertext/templates/workflows/compact.json +21 -0
- higpertext/templates/workflows/plan.json +59 -0
- higpertext/templates/workflows/review.json +26 -0
- higpertext/templates/workflows/spec.json +27 -0
- higpertext_cli-0.8.0.dist-info/METADATA +35 -0
- higpertext_cli-0.8.0.dist-info/RECORD +335 -0
- higpertext_cli-0.8.0.dist-info/WHEEL +5 -0
- higpertext_cli-0.8.0.dist-info/entry_points.txt +2 -0
- higpertext_cli-0.8.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""higpertext Code Skeletonizer — Genera un esqueleto de un archivo de código para ahorrar tokens.""" # noqa: E501
|
|
3
|
+
|
|
4
|
+
import sys
|
|
5
|
+
import argparse
|
|
6
|
+
import ast
|
|
7
|
+
import re
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from higpertext.kernel.infrastructure.logger import get_logger
|
|
11
|
+
_log = get_logger()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SkeletonTransformer(ast.NodeTransformer):
|
|
15
|
+
"""Transformador AST que conserva solo firmas, docstrings e imports."""
|
|
16
|
+
|
|
17
|
+
def visit_Module(self, node):
|
|
18
|
+
new_body = []
|
|
19
|
+
for stmt in node.body:
|
|
20
|
+
if isinstance(
|
|
21
|
+
stmt,
|
|
22
|
+
(
|
|
23
|
+
ast.ClassDef,
|
|
24
|
+
ast.FunctionDef,
|
|
25
|
+
ast.AsyncFunctionDef,
|
|
26
|
+
ast.Import,
|
|
27
|
+
ast.ImportFrom,
|
|
28
|
+
),
|
|
29
|
+
):
|
|
30
|
+
new_body.append(self.visit(stmt))
|
|
31
|
+
elif isinstance(stmt, (ast.Assign, ast.AnnAssign)):
|
|
32
|
+
new_body.append(stmt)
|
|
33
|
+
elif (
|
|
34
|
+
isinstance(stmt, ast.Expr)
|
|
35
|
+
and isinstance(stmt.value, ast.Constant)
|
|
36
|
+
and isinstance(stmt.value.value, str)
|
|
37
|
+
):
|
|
38
|
+
new_body.append(stmt)
|
|
39
|
+
node.body = new_body
|
|
40
|
+
return node
|
|
41
|
+
|
|
42
|
+
def visit_ClassDef(self, node):
|
|
43
|
+
new_body = []
|
|
44
|
+
for stmt in node.body:
|
|
45
|
+
if isinstance(stmt, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
|
|
46
|
+
new_body.append(self.visit(stmt))
|
|
47
|
+
elif isinstance(stmt, (ast.Assign, ast.AnnAssign)):
|
|
48
|
+
new_body.append(stmt)
|
|
49
|
+
elif (
|
|
50
|
+
isinstance(stmt, ast.Expr)
|
|
51
|
+
and isinstance(stmt.value, ast.Constant)
|
|
52
|
+
and isinstance(stmt.value.value, str)
|
|
53
|
+
):
|
|
54
|
+
new_body.append(stmt)
|
|
55
|
+
node.body = new_body
|
|
56
|
+
return node
|
|
57
|
+
|
|
58
|
+
def visit_FunctionDef(self, node):
|
|
59
|
+
# Conservar decoradores y firma, vaciar cuerpo conservando docstring si existe
|
|
60
|
+
docstring = ast.get_docstring(node)
|
|
61
|
+
new_body = []
|
|
62
|
+
if docstring is not None:
|
|
63
|
+
if (
|
|
64
|
+
node.body
|
|
65
|
+
and isinstance(node.body[0], ast.Expr)
|
|
66
|
+
and isinstance(node.body[0].value, ast.Constant)
|
|
67
|
+
and isinstance(node.body[0].value.value, str)
|
|
68
|
+
):
|
|
69
|
+
new_body.append(node.body[0])
|
|
70
|
+
new_body.append(ast.Pass())
|
|
71
|
+
node.body = new_body
|
|
72
|
+
return node
|
|
73
|
+
|
|
74
|
+
def visit_AsyncFunctionDef(self, node):
|
|
75
|
+
return self.visit_FunctionDef(node)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def skeletonize_python(source: str) -> str:
|
|
79
|
+
"""Esqueletiza código Python usando AST."""
|
|
80
|
+
try:
|
|
81
|
+
tree = ast.parse(source)
|
|
82
|
+
transformer = SkeletonTransformer()
|
|
83
|
+
transformed_tree = transformer.visit(tree)
|
|
84
|
+
# Aseguramos que los nodos sean válidos y tengan line numbers si es necesario
|
|
85
|
+
ast.fix_missing_locations(transformed_tree)
|
|
86
|
+
return ast.unparse(transformed_tree)
|
|
87
|
+
except Exception as e:
|
|
88
|
+
return f"# [Error parseando AST Python: {e}]\n" + skeletonize_line_by_line(
|
|
89
|
+
source, comment_char="#"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def skeletonize_line_by_line(source: str, comment_char: str = "#") -> str:
|
|
94
|
+
"""Fallback heurístico basado en líneas para otros lenguajes."""
|
|
95
|
+
lines = source.splitlines()
|
|
96
|
+
output_lines = []
|
|
97
|
+
in_block = False
|
|
98
|
+
brace_depth = 0
|
|
99
|
+
|
|
100
|
+
# Heurística simple para lenguajes con llaves {} (JS, TS, C, Go, etc.)
|
|
101
|
+
is_brace_lang = comment_char == "//"
|
|
102
|
+
|
|
103
|
+
for line in lines:
|
|
104
|
+
stripped = line.strip()
|
|
105
|
+
|
|
106
|
+
# Mantener imports y paquetes
|
|
107
|
+
if any(
|
|
108
|
+
stripped.startswith(prefix) for prefix in ["import ", "from ", "package ", "require("]
|
|
109
|
+
):
|
|
110
|
+
output_lines.append(line)
|
|
111
|
+
continue
|
|
112
|
+
|
|
113
|
+
if is_brace_lang:
|
|
114
|
+
# Detección de llaves
|
|
115
|
+
open_braces = stripped.count("{")
|
|
116
|
+
close_braces = stripped.count("}")
|
|
117
|
+
|
|
118
|
+
# Si estamos dentro de una función, omitimos su contenido
|
|
119
|
+
if in_block:
|
|
120
|
+
brace_depth += open_braces - close_braces
|
|
121
|
+
if brace_depth <= 0:
|
|
122
|
+
in_block = False
|
|
123
|
+
output_lines.append(re.sub(r"^[ \t]*", "", line)) # mantener el cierre }
|
|
124
|
+
continue
|
|
125
|
+
|
|
126
|
+
# Detectar firmas de funciones, clases o métodos
|
|
127
|
+
if (
|
|
128
|
+
any(
|
|
129
|
+
p in stripped
|
|
130
|
+
for p in [
|
|
131
|
+
"function ",
|
|
132
|
+
"class ",
|
|
133
|
+
"interface ",
|
|
134
|
+
"constructor",
|
|
135
|
+
"const ",
|
|
136
|
+
"let ",
|
|
137
|
+
"export ",
|
|
138
|
+
]
|
|
139
|
+
)
|
|
140
|
+
and "{" in stripped
|
|
141
|
+
):
|
|
142
|
+
output_lines.append(line)
|
|
143
|
+
brace_depth = open_braces - close_braces
|
|
144
|
+
if brace_depth > 0:
|
|
145
|
+
in_block = True
|
|
146
|
+
# Añadir indicador de elisión
|
|
147
|
+
indent = len(line) - len(stripped)
|
|
148
|
+
output_lines.append(" " * (indent + 4) + f"{comment_char} ...")
|
|
149
|
+
continue
|
|
150
|
+
else:
|
|
151
|
+
# Mantener comentarios de documentación externos
|
|
152
|
+
if (
|
|
153
|
+
stripped.startswith("/*")
|
|
154
|
+
or stripped.startswith("*")
|
|
155
|
+
or stripped.startswith("//")
|
|
156
|
+
):
|
|
157
|
+
output_lines.append(line)
|
|
158
|
+
elif stripped == "":
|
|
159
|
+
output_lines.append("")
|
|
160
|
+
else:
|
|
161
|
+
# Fallback genérico para scripts de Bash o similares
|
|
162
|
+
if (
|
|
163
|
+
stripped.startswith("function ")
|
|
164
|
+
or (stripped.endswith("()") or "()" in stripped)
|
|
165
|
+
or stripped.startswith("def ")
|
|
166
|
+
):
|
|
167
|
+
output_lines.append(line)
|
|
168
|
+
output_lines.append(f" {comment_char} ...")
|
|
169
|
+
elif stripped.startswith("#") or stripped == "":
|
|
170
|
+
output_lines.append(line)
|
|
171
|
+
|
|
172
|
+
return "\n".join(output_lines)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def skeletonize_file(file_path: Path) -> str:
|
|
176
|
+
"""Lee un archivo y lo esqueletiza según su tipo."""
|
|
177
|
+
content = file_path.read_text(encoding="utf-8")
|
|
178
|
+
|
|
179
|
+
if file_path.suffix == ".py":
|
|
180
|
+
return skeletonize_python(content)
|
|
181
|
+
elif file_path.suffix in [
|
|
182
|
+
".js",
|
|
183
|
+
".ts",
|
|
184
|
+
".tsx",
|
|
185
|
+
".jsx",
|
|
186
|
+
".go",
|
|
187
|
+
".c",
|
|
188
|
+
".cpp",
|
|
189
|
+
".java",
|
|
190
|
+
]:
|
|
191
|
+
return skeletonize_line_by_line(content, comment_char="//")
|
|
192
|
+
else:
|
|
193
|
+
return skeletonize_line_by_line(content, comment_char="#")
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def main():
|
|
197
|
+
parser = argparse.ArgumentParser(
|
|
198
|
+
description="Esqueletiza archivos de código para optimizar contexto."
|
|
199
|
+
)
|
|
200
|
+
parser.add_argument("--path", required=True, help="Ruta del archivo a esqueletizar")
|
|
201
|
+
parser.add_argument("--output", required=False, help="Archivo de destino opcional")
|
|
202
|
+
args = parser.parse_args()
|
|
203
|
+
|
|
204
|
+
input_path = Path(args.path)
|
|
205
|
+
if not input_path.exists() or not input_path.is_file():
|
|
206
|
+
_log.error(f"[ERROR] El archivo especificado no existe o no es válido: {args.path}")
|
|
207
|
+
sys.exit(1)
|
|
208
|
+
|
|
209
|
+
try:
|
|
210
|
+
skeleton = skeletonize_file(input_path)
|
|
211
|
+
|
|
212
|
+
if args.output:
|
|
213
|
+
output_path = Path(args.output)
|
|
214
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
215
|
+
output_path.write_text(skeleton, encoding="utf-8")
|
|
216
|
+
_log.ok(f"[SUCCESS] Esqueleto guardado con éxito en: {output_path}")
|
|
217
|
+
else:
|
|
218
|
+
_log.info(skeleton)
|
|
219
|
+
except Exception as e:
|
|
220
|
+
_log.error(f"[ERROR] Error procesando el archivo: {e}")
|
|
221
|
+
sys.exit(1)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
if __name__ == "__main__":
|
|
225
|
+
main()
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"""Capability common.commit-report — reporte explicativo de commits."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from higpertext.kernel.application.commit_reporter import ReportBuilder, ImpactAnalyzer, CommitParser
|
|
5
|
+
import argparse
|
|
6
|
+
# Invoca git/htx con lista de argumentos y shell=False.
|
|
7
|
+
import subprocess # nosec B404
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
|
|
11
|
+
|
|
12
|
+
from higpertext.kernel.infrastructure.logger import get_logger
|
|
13
|
+
_log = get_logger()
|
|
14
|
+
|
|
15
|
+
_HERE = Path(__file__).resolve()
|
|
16
|
+
_ROOT = next((p for p in _HERE.parents if (p / "src/config/htx_config.json").exists()), _HERE.parents[4])
|
|
17
|
+
sys.path.insert(0, str(_ROOT / "src"))
|
|
18
|
+
sys.path.insert(0, str(_ROOT))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _git(args: list[str]) -> str:
|
|
22
|
+
result = subprocess.run(["git"] + args, capture_output=True, text=True, cwd=_ROOT)
|
|
23
|
+
return result.stdout.strip()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _parse_args() -> argparse.Namespace:
|
|
27
|
+
parser = argparse.ArgumentParser(description="Genera reporte explicativo de commits.")
|
|
28
|
+
parser.add_argument("--commit", default="HEAD")
|
|
29
|
+
parser.add_argument("--range", dest="range_", default=None)
|
|
30
|
+
parser.add_argument("--format", dest="fmt", default="markdown", choices=["markdown", "html"])
|
|
31
|
+
parser.add_argument("--output", default=None)
|
|
32
|
+
parser.add_argument(
|
|
33
|
+
"--diff", action="store_true", help="Incluye el diff completo línea por línea."
|
|
34
|
+
)
|
|
35
|
+
return parser.parse_args()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _resolve_output(args: argparse.Namespace, short_hash: str) -> Path:
|
|
39
|
+
if args.output:
|
|
40
|
+
return Path(args.output)
|
|
41
|
+
ext = "html" if args.fmt == "html" else "md"
|
|
42
|
+
out_dir = _ROOT / WORKSPACE_DIR_NAME / "reports" / "commits"
|
|
43
|
+
out_dir.mkdir(parents=True, exist_ok=True)
|
|
44
|
+
return out_dir / f"{short_hash}_report.{ext}"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _build_show_output(ref: str) -> str:
|
|
48
|
+
header = _git(
|
|
49
|
+
[
|
|
50
|
+
"log",
|
|
51
|
+
"-1",
|
|
52
|
+
"--format=%h %s%nAuthor: %an <%ae>%nDate: %ad",
|
|
53
|
+
"--date=short",
|
|
54
|
+
ref,
|
|
55
|
+
]
|
|
56
|
+
)
|
|
57
|
+
stat = _git(["show", "--stat", "--format=", ref])
|
|
58
|
+
return header + "\n" + stat
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _get_full_diff(ref: str) -> str:
|
|
62
|
+
return _git(["show", "--format=", "-p", "--unified=3", ref])
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _handle_single(args: argparse.Namespace) -> None:
|
|
66
|
+
ref = args.commit
|
|
67
|
+
show_out = _build_show_output(ref)
|
|
68
|
+
parser = CommitParser()
|
|
69
|
+
report = parser.parse_show(show_out)
|
|
70
|
+
if report is None:
|
|
71
|
+
_log.error(f"[ERROR] No se pudo parsear el commit: {ref}")
|
|
72
|
+
sys.exit(1)
|
|
73
|
+
analysis = ImpactAnalyzer().analyze(report)
|
|
74
|
+
builder = ReportBuilder()
|
|
75
|
+
full_diff = _get_full_diff(ref) if args.diff else None
|
|
76
|
+
if args.fmt == "html":
|
|
77
|
+
content = builder.to_html(report, analysis, diff=full_diff)
|
|
78
|
+
else:
|
|
79
|
+
content = builder.to_markdown(report, analysis, diff=full_diff)
|
|
80
|
+
out = _resolve_output(args, report.commit.short_hash)
|
|
81
|
+
out.write_text(content, encoding="utf-8")
|
|
82
|
+
_print_summary(report, analysis, out)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _handle_range(args: argparse.Namespace) -> None:
|
|
86
|
+
log_out = _git(["log", "--format=%h|||%s|||%an <%ae>|||%ad", "--date=short", args.range_])
|
|
87
|
+
commits = CommitParser().parse_log(log_out)
|
|
88
|
+
if not commits:
|
|
89
|
+
_log.error(f"[ERROR] No se encontraron commits en el rango: {args.range_}")
|
|
90
|
+
sys.exit(1)
|
|
91
|
+
lines = [
|
|
92
|
+
f"# Commit Range Report — `{args.range_}`\n",
|
|
93
|
+
f"**{len(commits)} commits**\n\n---\n",
|
|
94
|
+
]
|
|
95
|
+
for commit in commits:
|
|
96
|
+
show_out = _build_show_output(commit.hash)
|
|
97
|
+
report = CommitParser().parse_show(show_out)
|
|
98
|
+
if report is None:
|
|
99
|
+
continue
|
|
100
|
+
analysis = ImpactAnalyzer().analyze(report)
|
|
101
|
+
lines.append(ReportBuilder().to_markdown(report, analysis))
|
|
102
|
+
lines.append("\n---\n")
|
|
103
|
+
content = "\n".join(lines)
|
|
104
|
+
out = _resolve_output(args, "range")
|
|
105
|
+
out.write_text(content, encoding="utf-8")
|
|
106
|
+
_log.ok(f"[SUCCESS] Reporte de {len(commits)} commits escrito en: {out}")
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _print_summary(report, analysis, out: Path) -> None:
|
|
110
|
+
c = report.commit
|
|
111
|
+
_log.info("╔─ HIGPERTEXT · Commit Report ────────────────────────────────")
|
|
112
|
+
_log.info(f"│ Commit : {c.short_hash} ({c.commit_type.value})")
|
|
113
|
+
_log.info(f"│ Scope : {c.scope or '—'}")
|
|
114
|
+
_log.info(f"│ Autor : {c.author}")
|
|
115
|
+
_log.info(f"│ Fecha : {c.date}")
|
|
116
|
+
_log.info(f"│ Archivos : {report.changed_files_count}")
|
|
117
|
+
_log.info(f"│ +Lines : {report.total_additions} -Lines: {report.total_deletions}")
|
|
118
|
+
_log.info(f"│ Tags : {', '.join(analysis.impact_tags)}")
|
|
119
|
+
_log.info(f"│ Reporte : {out.relative_to(_ROOT)}")
|
|
120
|
+
_log.info("╚───────────────────────────────────────────────────────")
|
|
121
|
+
_log.info(f"\n{analysis.summary}")
|
|
122
|
+
_log.ok(f"\n[SUCCESS] Reporte generado: {out}")
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def main() -> None:
|
|
126
|
+
args = _parse_args()
|
|
127
|
+
if args.range_:
|
|
128
|
+
_handle_range(args)
|
|
129
|
+
else:
|
|
130
|
+
_handle_single(args)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
if __name__ == "__main__":
|
|
134
|
+
main()
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Capability common.context-assembler — ensambla un context pack curado para una tarea.
|
|
2
|
+
|
|
3
|
+
Dado un objetivo (--goal) y tipo (--type), selecciona del semantic graph los
|
|
4
|
+
símbolos relevantes bajo un presupuesto de tokens y emite un artefacto Markdown
|
|
5
|
+
en .higpertext/state/context_packs/ que el agente puede leer.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
import argparse
|
|
10
|
+
import sys
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from higpertext.kernel.infrastructure.logger import get_logger
|
|
13
|
+
_log = get_logger()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _resolve_core() -> Path:
|
|
17
|
+
"""Localiza src/core para importar el context_engine."""
|
|
18
|
+
here = Path(__file__).resolve()
|
|
19
|
+
for parent in here.parents:
|
|
20
|
+
core = parent / "src" / "core"
|
|
21
|
+
if core.exists():
|
|
22
|
+
return core
|
|
23
|
+
return here.parent
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def main() -> None:
|
|
27
|
+
parser = argparse.ArgumentParser(description="Ensambla un context pack curado.")
|
|
28
|
+
parser.add_argument("--goal", required=True, help="Objetivo de la tarea.")
|
|
29
|
+
parser.add_argument(
|
|
30
|
+
"--type",
|
|
31
|
+
default="feature",
|
|
32
|
+
help="Tipo: refactor|feature|bugfix|review. Default: feature.",
|
|
33
|
+
)
|
|
34
|
+
parser.add_argument(
|
|
35
|
+
"--budget",
|
|
36
|
+
type=int,
|
|
37
|
+
default=8000,
|
|
38
|
+
help="Presupuesto de tokens del pack. Default: 8000.",
|
|
39
|
+
)
|
|
40
|
+
args = parser.parse_args()
|
|
41
|
+
|
|
42
|
+
core = _resolve_core()
|
|
43
|
+
if str(core) not in sys.path:
|
|
44
|
+
sys.path.insert(0, str(core))
|
|
45
|
+
|
|
46
|
+
from higpertext.context_engine.domain.task_intent import TaskIntent
|
|
47
|
+
from higpertext.context_engine.application.context_assembler import ContextAssembler
|
|
48
|
+
from higpertext.context_engine.infrastructure.pack_store import PackStore
|
|
49
|
+
|
|
50
|
+
project_root = core.parent.parent
|
|
51
|
+
intent = TaskIntent.from_goal(args.goal, args.type, token_budget=args.budget)
|
|
52
|
+
assembler = ContextAssembler(project_root)
|
|
53
|
+
pack = assembler.assemble(intent)
|
|
54
|
+
|
|
55
|
+
store = PackStore(project_root)
|
|
56
|
+
path = store.save(pack)
|
|
57
|
+
|
|
58
|
+
rel = path.relative_to(project_root).as_posix()
|
|
59
|
+
_log.box("HIGPERTEXT · Context Pack generado", [
|
|
60
|
+
f"│ Objetivo : {intent.goal}",
|
|
61
|
+
f"│ Keywords : {', '.join(intent.keywords) or '—'}",
|
|
62
|
+
f"│ Símbolos : {len(pack.relevant_symbols)}",
|
|
63
|
+
f"│ Tokens~ : {pack.estimated_tokens} / {intent.token_budget}",
|
|
64
|
+
f"│ Artefacto : {rel}",
|
|
65
|
+
])
|
|
66
|
+
_log.ok(f"\n[SUCCESS] Pack disponible. Lee el archivo: {rel}")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
if __name__ == "__main__":
|
|
70
|
+
main()
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""common.context-budget-report — estima coste de contexto antes de leer/buscar."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import json
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from higpertext.kernel.infrastructure.logger import get_logger
|
|
10
|
+
_log = get_logger()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def estimate(path: Path, operation: str, budget: int) -> dict:
|
|
14
|
+
size = path.stat().st_size if path.exists() and path.is_file() else 0
|
|
15
|
+
tokens = max(1, size // (5 if operation == "skeleton" else 4))
|
|
16
|
+
recommendation = "read range"
|
|
17
|
+
if operation == "search":
|
|
18
|
+
recommendation = "grep"
|
|
19
|
+
elif operation == "skeleton" or tokens > budget:
|
|
20
|
+
recommendation = "skeleton"
|
|
21
|
+
if tokens > budget * 2:
|
|
22
|
+
recommendation = "summary"
|
|
23
|
+
return {
|
|
24
|
+
"path": str(path),
|
|
25
|
+
"operation": operation,
|
|
26
|
+
"bytes": size,
|
|
27
|
+
"estimated_tokens": tokens,
|
|
28
|
+
"budget": budget,
|
|
29
|
+
"recommendation": recommendation,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def main() -> None:
|
|
34
|
+
parser = argparse.ArgumentParser(description="Estima presupuesto de contexto")
|
|
35
|
+
parser.add_argument("--path", required=True)
|
|
36
|
+
parser.add_argument("--operation", default="read", choices=["read", "search", "skeleton"])
|
|
37
|
+
parser.add_argument("--budget", type=int, default=4000)
|
|
38
|
+
parser.add_argument("--json", default="false")
|
|
39
|
+
args = parser.parse_args()
|
|
40
|
+
report = estimate(Path(args.path), args.operation, args.budget)
|
|
41
|
+
if args.json.lower() in {"true", "1", "yes"}:
|
|
42
|
+
print(json.dumps(report, ensure_ascii=False, indent=2))
|
|
43
|
+
return
|
|
44
|
+
_log.info("╔─ HIGPERTEXT · Context Budget Report ───────────────────────")
|
|
45
|
+
_log.info(f"│ Archivo : {report['path']}")
|
|
46
|
+
_log.info(f"│ Operación : {report['operation']}")
|
|
47
|
+
_log.info(f"│ Tokens est. : {report['estimated_tokens']} / {report['budget']}")
|
|
48
|
+
_log.info(f"│ Recomendado : {report['recommendation']}")
|
|
49
|
+
_log.info("╚────────────────────────────────────────────────────────────")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
if __name__ == "__main__":
|
|
53
|
+
main()
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""common.dep-manager — gestiona dependencias usando .venv del proyecto."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import subprocess # nosec B404
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from higpertext.kernel.infrastructure.logger import get_logger
|
|
12
|
+
_log = get_logger()
|
|
13
|
+
|
|
14
|
+
_HERE = Path(__file__).resolve()
|
|
15
|
+
_PROJECT_ROOT = next(
|
|
16
|
+
(p for p in _HERE.parents if (p / "src/config/htx_config.json").exists()),
|
|
17
|
+
_HERE.parents[4],
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
_VENV_PIP = _PROJECT_ROOT / ".venv" / "bin" / "pip"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _pip(args: list[str]) -> tuple[int, str, str]:
|
|
24
|
+
pip = str(_VENV_PIP) if _VENV_PIP.exists() else "pip"
|
|
25
|
+
res = subprocess.run([pip] + args, capture_output=True, text=True) # nosec B603
|
|
26
|
+
return res.returncode, res.stdout, res.stderr
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _update_requirements(packages: list[str]) -> None:
|
|
30
|
+
req = _PROJECT_ROOT / "requirements.txt"
|
|
31
|
+
if not req.exists():
|
|
32
|
+
return
|
|
33
|
+
rc, out, _ = _pip(["freeze"])
|
|
34
|
+
if rc == 0:
|
|
35
|
+
req.write_text(out, encoding="utf-8")
|
|
36
|
+
_log.ok(f"[*] requirements.txt actualizado ({len(out.splitlines())} paquetes)")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def main() -> None:
|
|
40
|
+
parser = argparse.ArgumentParser(description="higpertext Dependency Manager")
|
|
41
|
+
parser.add_argument("--action", required=True, choices=["install", "uninstall", "list"])
|
|
42
|
+
parser.add_argument("--packages", default="")
|
|
43
|
+
parser.add_argument("--dev", default="false")
|
|
44
|
+
args = parser.parse_args()
|
|
45
|
+
|
|
46
|
+
packages = [p.strip() for p in args.packages.replace(",", " ").split() if p.strip()]
|
|
47
|
+
|
|
48
|
+
if args.action == "install":
|
|
49
|
+
if not packages:
|
|
50
|
+
_log.error("[ERROR] --packages es requerido para install.")
|
|
51
|
+
sys.exit(1)
|
|
52
|
+
_log.info(f"[*] Instalando: {', '.join(packages)} en .venv...")
|
|
53
|
+
rc, out, err = _pip(["install"] + packages)
|
|
54
|
+
if rc != 0:
|
|
55
|
+
_log.error(f"[ERROR] {err}")
|
|
56
|
+
sys.exit(rc)
|
|
57
|
+
_log.info(out.strip())
|
|
58
|
+
_update_requirements(packages)
|
|
59
|
+
_log.ok(f"[SUCCESS] {len(packages)} paquete(s) instalado(s).")
|
|
60
|
+
|
|
61
|
+
elif args.action == "uninstall":
|
|
62
|
+
if not packages:
|
|
63
|
+
_log.error("[ERROR] --packages es requerido para uninstall.")
|
|
64
|
+
sys.exit(1)
|
|
65
|
+
_log.info(f"[*] Desinstalando: {', '.join(packages)}...")
|
|
66
|
+
rc, out, err = _pip(["uninstall", "-y"] + packages)
|
|
67
|
+
if rc != 0:
|
|
68
|
+
_log.error(f"[ERROR] {err}")
|
|
69
|
+
sys.exit(rc)
|
|
70
|
+
_log.info(out.strip())
|
|
71
|
+
_update_requirements([])
|
|
72
|
+
_log.ok(f"[SUCCESS] {len(packages)} paquete(s) desinstalado(s).")
|
|
73
|
+
|
|
74
|
+
elif args.action == "list":
|
|
75
|
+
rc, out, _ = _pip(["list", "--format=columns"])
|
|
76
|
+
_log.info(out)
|
|
77
|
+
_log.ok("[SUCCESS] Listado de dependencias completado.")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if __name__ == "__main__":
|
|
81
|
+
main()
|