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,80 @@
|
|
|
1
|
+
"""Capability common.eval-agent — puente entre el CLI de higpertext y el suite pytest de evaluación.
|
|
2
|
+
|
|
3
|
+
Uso:
|
|
4
|
+
htx task eval-agent --mode static
|
|
5
|
+
htx task eval-agent --mode hooks
|
|
6
|
+
htx task eval-agent --mode behavioral --provider gemini --profile sre
|
|
7
|
+
htx task eval-agent --mode all --provider anthropic
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import argparse
|
|
13
|
+
import os
|
|
14
|
+
# Ejecuta pytest con comando construido internamente.
|
|
15
|
+
import subprocess # nosec B404
|
|
16
|
+
import sys
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
from higpertext.kernel.infrastructure.logger import get_logger
|
|
20
|
+
_log = get_logger()
|
|
21
|
+
|
|
22
|
+
ROOT_DIR = Path(__file__).resolve().parents[5]
|
|
23
|
+
EVAL_DIR = ROOT_DIR / "tests" / "eval"
|
|
24
|
+
|
|
25
|
+
_MARKER_MAP = {
|
|
26
|
+
"static": "static",
|
|
27
|
+
"behavioral": "behavioral",
|
|
28
|
+
"hooks": "hooks",
|
|
29
|
+
"safety": "safety",
|
|
30
|
+
"all": None,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _parse_args() -> argparse.Namespace:
|
|
35
|
+
p = argparse.ArgumentParser(
|
|
36
|
+
description="higpertext Eval Agent — framework de evaluación de modelos"
|
|
37
|
+
)
|
|
38
|
+
p.add_argument("--profile", default="all", help="Perfil a evaluar (default: all)")
|
|
39
|
+
p.add_argument("--mode", default="static", choices=list(_MARKER_MAP), help="Modo de evaluación")
|
|
40
|
+
p.add_argument(
|
|
41
|
+
"--provider",
|
|
42
|
+
default="",
|
|
43
|
+
help="Provider LLM para behavioral/safety: gemini | anthropic",
|
|
44
|
+
)
|
|
45
|
+
return p.parse_args()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _build_cmd(mode: str, profile: str) -> list[str]:
|
|
49
|
+
cmd = [sys.executable, "-m", "pytest", str(EVAL_DIR), "-v", "--tb=short"]
|
|
50
|
+
marker = _MARKER_MAP[mode]
|
|
51
|
+
if marker:
|
|
52
|
+
cmd += ["-m", marker]
|
|
53
|
+
if profile != "all":
|
|
54
|
+
cmd += ["--profile", profile]
|
|
55
|
+
return cmd
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def main() -> None:
|
|
59
|
+
args = _parse_args()
|
|
60
|
+
env = os.environ.copy()
|
|
61
|
+
|
|
62
|
+
if args.provider:
|
|
63
|
+
env["HIGPERTEXT_LLM_PROVIDER"] = args.provider
|
|
64
|
+
|
|
65
|
+
if args.mode in ("behavioral", "safety", "all") and not env.get("RUN_BEHAVIORAL_TESTS"):
|
|
66
|
+
_log.info(
|
|
67
|
+
"[eval-agent] AVISO: RUN_BEHAVIORAL_TESTS no configurada.\n"
|
|
68
|
+
"Los tests behavioral y safety serán skipped.\n"
|
|
69
|
+
"Para activarlos: $env:RUN_BEHAVIORAL_TESTS=1"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
cmd = _build_cmd(args.mode, args.profile)
|
|
73
|
+
_log.info(f"[eval-agent] Ejecutando: {' '.join(cmd)}\n")
|
|
74
|
+
|
|
75
|
+
result = subprocess.run(cmd, env=env, cwd=str(ROOT_DIR))
|
|
76
|
+
sys.exit(result.returncode)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
if __name__ == "__main__":
|
|
80
|
+
main()
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""common.file-map — mapa compacto de archivos para exploración sin blobs."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import json
|
|
7
|
+
import subprocess # nosec B404
|
|
8
|
+
from collections import Counter, defaultdict
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from higpertext.kernel.infrastructure.logger import get_logger
|
|
12
|
+
_log = get_logger()
|
|
13
|
+
|
|
14
|
+
_HEAVY_ASSET_PATTERNS = ("*.min.js", "*.bundle.min.js", "*.min.css", "*.map")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _git_files() -> list[str]:
|
|
18
|
+
result = subprocess.run(["git", "ls-files"], capture_output=True, text=True) # nosec B603 B607
|
|
19
|
+
return result.stdout.splitlines() if result.returncode == 0 else []
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _is_heavy_asset(path: str) -> bool:
|
|
23
|
+
p = Path(path)
|
|
24
|
+
if "assets" not in p.parts:
|
|
25
|
+
return False
|
|
26
|
+
return any(p.match(pattern) for pattern in _HEAVY_ASSET_PATTERNS)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def build_map(
|
|
30
|
+
path: str, max_depth: int, large_threshold_kb: int, include_assets: bool = False
|
|
31
|
+
) -> dict:
|
|
32
|
+
prefix = path.strip().strip("/")
|
|
33
|
+
files = [f for f in _git_files() if not prefix or f == prefix or f.startswith(f"{prefix}/")]
|
|
34
|
+
skipped_assets = [f for f in files if _is_heavy_asset(f)]
|
|
35
|
+
if not include_assets:
|
|
36
|
+
files = [f for f in files if not _is_heavy_asset(f)]
|
|
37
|
+
dirs: dict[str, int] = defaultdict(int)
|
|
38
|
+
extensions: Counter[str] = Counter()
|
|
39
|
+
large = []
|
|
40
|
+
for file in files:
|
|
41
|
+
rel = file[len(prefix) + 1 :] if prefix and file.startswith(f"{prefix}/") else file
|
|
42
|
+
top = "/".join(Path(rel).parts[:max_depth]) or "."
|
|
43
|
+
dirs[top] += 1
|
|
44
|
+
extensions[Path(file).suffix or "[sin extensión]"] += 1
|
|
45
|
+
p = Path(file)
|
|
46
|
+
if p.exists() and p.stat().st_size / 1024 >= large_threshold_kb:
|
|
47
|
+
large.append({"path": file, "kb": round(p.stat().st_size / 1024, 1)})
|
|
48
|
+
return {
|
|
49
|
+
"path": path or ".",
|
|
50
|
+
"total": len(files),
|
|
51
|
+
"directories": dict(sorted(dirs.items())),
|
|
52
|
+
"extensions": dict(extensions.most_common()),
|
|
53
|
+
"large_files": large[:20],
|
|
54
|
+
"skipped_heavy_assets": len(skipped_assets) if not include_assets else 0,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def main() -> None:
|
|
59
|
+
parser = argparse.ArgumentParser(description="Mapa compacto de archivos")
|
|
60
|
+
parser.add_argument("--path", default="")
|
|
61
|
+
parser.add_argument("--preset", default="all") # reservado para compatibilidad con plan
|
|
62
|
+
parser.add_argument("--max_depth", type=int, default=2)
|
|
63
|
+
parser.add_argument("--show_sizes", default="false")
|
|
64
|
+
parser.add_argument("--large_threshold_kb", type=int, default=100)
|
|
65
|
+
parser.add_argument("--include_assets", default="false")
|
|
66
|
+
parser.add_argument("--json", default="false")
|
|
67
|
+
args = parser.parse_args()
|
|
68
|
+
include_assets = args.include_assets.lower() in {"true", "1", "yes"}
|
|
69
|
+
data = build_map(args.path, args.max_depth, args.large_threshold_kb, include_assets)
|
|
70
|
+
if args.json.lower() in {"true", "1", "yes"}:
|
|
71
|
+
print(json.dumps(data, ensure_ascii=False, indent=2))
|
|
72
|
+
return
|
|
73
|
+
_log.info("╔─ HIGPERTEXT · File Map ────────────────────────────────────")
|
|
74
|
+
_log.info(f"│ Path : {data['path']}")
|
|
75
|
+
_log.info(f"│ Total : {data['total']} archivo(s)")
|
|
76
|
+
_log.info("╠─ Directorios ──────────────────────────────────────────────")
|
|
77
|
+
for directory, count in list(data["directories"].items())[:50]:
|
|
78
|
+
_log.info(f"│ {directory}: {count}")
|
|
79
|
+
_log.info("╠─ Extensiones ──────────────────────────────────────────────")
|
|
80
|
+
for ext, count in data["extensions"].items():
|
|
81
|
+
_log.info(f"│ {ext}: {count}")
|
|
82
|
+
if data["large_files"]:
|
|
83
|
+
_log.info("╠─ Grandes ─────────────────────────────────────────────────")
|
|
84
|
+
for item in data["large_files"]:
|
|
85
|
+
_log.info(
|
|
86
|
+
f"│ {item['path']} ({item['kb']} KB) → htx task common.smart-read --path {item['path']} --mode auto" # noqa: E501
|
|
87
|
+
)
|
|
88
|
+
if data["skipped_heavy_assets"]:
|
|
89
|
+
_log.info(f"│ Assets pesados omitidos: {
|
|
90
|
+
data['skipped_heavy_assets']} (usa --include_assets true)")
|
|
91
|
+
_log.info("╚────────────────────────────────────────────────────────────")
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
if __name__ == "__main__":
|
|
95
|
+
main()
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""common.governance-exception — registra y lista excepciones de gobernanza."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import json
|
|
7
|
+
import sys
|
|
8
|
+
from datetime import date
|
|
9
|
+
from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
_HERE = Path(__file__).resolve()
|
|
13
|
+
_PROJECT_ROOT = next(
|
|
14
|
+
(p for p in _HERE.parents if (p / "src/config/htx_config.json").exists()),
|
|
15
|
+
_HERE.parents[4],
|
|
16
|
+
)
|
|
17
|
+
sys.path.insert(0, str(_PROJECT_ROOT / "src"))
|
|
18
|
+
|
|
19
|
+
from higpertext.kernel.application.governance import ExceptionRegistry # noqa: E402
|
|
20
|
+
from higpertext.kernel.domain.governance import GovernanceException, Severity # noqa: E402
|
|
21
|
+
from higpertext.kernel.infrastructure.governance import ContractLoader # noqa: E402
|
|
22
|
+
|
|
23
|
+
from higpertext.kernel.infrastructure.logger import get_logger
|
|
24
|
+
_log = get_logger()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _get_active_profile() -> str:
|
|
28
|
+
env_file = _PROJECT_ROOT / WORKSPACE_DIR_NAME / "config" / "environment.json"
|
|
29
|
+
if env_file.exists():
|
|
30
|
+
try:
|
|
31
|
+
return json.loads(env_file.read_text(encoding="utf-8")).get("active_profile", "global")
|
|
32
|
+
except (OSError, json.JSONDecodeError): # nosec B110
|
|
33
|
+
pass
|
|
34
|
+
return "global"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _rule_is_critical(rule_id: str) -> bool:
|
|
38
|
+
loader = ContractLoader(_PROJECT_ROOT)
|
|
39
|
+
for rule in loader.load():
|
|
40
|
+
if rule.id == rule_id and rule.severity == Severity.CRITICAL:
|
|
41
|
+
return True
|
|
42
|
+
return False
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def cmd_register(args: argparse.Namespace, registry: ExceptionRegistry) -> None:
|
|
46
|
+
if not args.rule_id:
|
|
47
|
+
_log.error("[ERROR] --rule_id es requerido para register.")
|
|
48
|
+
sys.exit(1)
|
|
49
|
+
if not args.reason:
|
|
50
|
+
_log.error("[ERROR] --reason es requerido para register.")
|
|
51
|
+
sys.exit(1)
|
|
52
|
+
if not args.approver:
|
|
53
|
+
_log.error("[ERROR] --approver es requerido para register.")
|
|
54
|
+
sys.exit(1)
|
|
55
|
+
|
|
56
|
+
if _rule_is_critical(args.rule_id):
|
|
57
|
+
_log.info(f"[BLOCK] La regla '{args.rule_id}' es CRITICAL — no se puede exceptuar.")
|
|
58
|
+
sys.exit(1)
|
|
59
|
+
|
|
60
|
+
profile = args.profile or _get_active_profile()
|
|
61
|
+
expires = date.fromisoformat(args.expires) if args.expires else None
|
|
62
|
+
|
|
63
|
+
exc = GovernanceException(
|
|
64
|
+
rule_id=args.rule_id,
|
|
65
|
+
reason=args.reason,
|
|
66
|
+
approver=args.approver,
|
|
67
|
+
profile=profile,
|
|
68
|
+
expires=expires,
|
|
69
|
+
)
|
|
70
|
+
registry.register(exc)
|
|
71
|
+
|
|
72
|
+
_log.ok(f"[SUCCESS] Excepción registrada para regla '{args.rule_id}' en perfil '{profile}'.")
|
|
73
|
+
if expires:
|
|
74
|
+
_log.info(f" Expira: {expires.isoformat()}")
|
|
75
|
+
_log.info(f" Aprobador: {args.approver}")
|
|
76
|
+
_log.info(f" Motivo: {args.reason}")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def cmd_list(args: argparse.Namespace, registry: ExceptionRegistry) -> None:
|
|
80
|
+
profile = args.profile or _get_active_profile()
|
|
81
|
+
exceptions = registry.list_active(profile)
|
|
82
|
+
|
|
83
|
+
if not exceptions:
|
|
84
|
+
_log.info(f"[*] No hay excepciones activas para el perfil '{profile}'.")
|
|
85
|
+
return
|
|
86
|
+
|
|
87
|
+
_log.info(f"\n Excepciones activas — perfil: {profile}\n")
|
|
88
|
+
_log.info(f" {'Regla':<35} {'Aprobador':<15} {'Expira':<12} Motivo")
|
|
89
|
+
_log.info(f" {'-' * 35} {'-' * 15} {'-' * 12} {'-' * 30}")
|
|
90
|
+
for exc in exceptions:
|
|
91
|
+
exp = exc.expires.isoformat() if exc.expires else "indefinido"
|
|
92
|
+
_log.info(f" {exc.rule_id:<35} {exc.approver:<15} {exp:<12} {exc.reason[:40]}")
|
|
93
|
+
_log.info("")
|
|
94
|
+
_log.ok("[SUCCESS] Listado completado.")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def main() -> None:
|
|
98
|
+
parser = argparse.ArgumentParser(description="higpertext Governance Exception Manager")
|
|
99
|
+
parser.add_argument("--action", required=True, choices=["register", "list"])
|
|
100
|
+
parser.add_argument("--rule_id", default="")
|
|
101
|
+
parser.add_argument("--reason", default="")
|
|
102
|
+
parser.add_argument("--approver", default="")
|
|
103
|
+
parser.add_argument("--expires", default="")
|
|
104
|
+
parser.add_argument("--profile", default="")
|
|
105
|
+
args = parser.parse_args()
|
|
106
|
+
|
|
107
|
+
registry = ExceptionRegistry(_PROJECT_ROOT)
|
|
108
|
+
|
|
109
|
+
if args.action == "register":
|
|
110
|
+
cmd_register(args, registry)
|
|
111
|
+
else:
|
|
112
|
+
cmd_list(args, registry)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
if __name__ == "__main__":
|
|
116
|
+
main()
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""Capability common.graph-query — consulta el grafo semántico por keyword."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
import argparse
|
|
5
|
+
import json
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
|
|
9
|
+
from higpertext.kernel.infrastructure.logger import get_logger
|
|
10
|
+
_log = get_logger()
|
|
11
|
+
|
|
12
|
+
def _resolve_core() -> Path:
|
|
13
|
+
here = Path(__file__).resolve()
|
|
14
|
+
for parent in here.parents:
|
|
15
|
+
core = parent / "src" / "core"
|
|
16
|
+
if core.exists():
|
|
17
|
+
return core
|
|
18
|
+
raise RuntimeError("No se encontró src/core")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def main() -> None:
|
|
22
|
+
parser = argparse.ArgumentParser(description="Consulta el grafo semántico.")
|
|
23
|
+
parser.add_argument("--symbol", required=True, help="Keyword o nombre de símbolo.")
|
|
24
|
+
parser.add_argument("--depth", type=int, default=2)
|
|
25
|
+
parser.add_argument("--budget", type=int, default=8000)
|
|
26
|
+
parser.add_argument(
|
|
27
|
+
"--type", default="", help="Filtra tipo: class,function,method,variable,module"
|
|
28
|
+
)
|
|
29
|
+
parser.add_argument("--limit", type=int, default=50, help="Máximo de símbolos a mostrar")
|
|
30
|
+
parser.add_argument(
|
|
31
|
+
"--files_only",
|
|
32
|
+
default="false",
|
|
33
|
+
help="Muestra solo archivos únicos (true/false)",
|
|
34
|
+
)
|
|
35
|
+
parser.add_argument("--json", default="false", help="Emite JSON estructurado (true/false)")
|
|
36
|
+
args = parser.parse_args()
|
|
37
|
+
|
|
38
|
+
core = _resolve_core()
|
|
39
|
+
if str(core) not in sys.path:
|
|
40
|
+
sys.path.insert(0, str(core))
|
|
41
|
+
sys.path.insert(0, str(core.parent.parent))
|
|
42
|
+
|
|
43
|
+
root = Path(".").resolve()
|
|
44
|
+
graph_path = root / WORKSPACE_DIR_NAME / "state" / "semantic_graph.json"
|
|
45
|
+
if not graph_path.exists():
|
|
46
|
+
_log.error("[ERROR] semantic_graph.json no encontrado. Ejecuta: htx task common.graph-rebuild")
|
|
47
|
+
sys.exit(1)
|
|
48
|
+
|
|
49
|
+
from higpertext.semantic_engine.infrastructure.graph_store import GraphStore
|
|
50
|
+
from higpertext.semantic_engine.application.context_ranker import ContextRanker
|
|
51
|
+
|
|
52
|
+
graph = GraphStore(root=root).load()
|
|
53
|
+
ranker = ContextRanker(graph)
|
|
54
|
+
results = ranker.rank(keywords=[args.symbol], budget=args.budget, depth=args.depth)
|
|
55
|
+
if args.type:
|
|
56
|
+
results = [s for s in results if s.type.value == args.type]
|
|
57
|
+
results = results[: max(1, args.limit)]
|
|
58
|
+
|
|
59
|
+
if not results:
|
|
60
|
+
_log.info(f"[NOT FOUND] No se encontraron símbolos relacionados con '{args.symbol}'.")
|
|
61
|
+
sys.exit(0)
|
|
62
|
+
|
|
63
|
+
if args.json.lower() in {"true", "1", "yes"}:
|
|
64
|
+
print(
|
|
65
|
+
json.dumps(
|
|
66
|
+
{
|
|
67
|
+
"keyword": args.symbol,
|
|
68
|
+
"depth": args.depth,
|
|
69
|
+
"count": len(results),
|
|
70
|
+
"symbols": [
|
|
71
|
+
{
|
|
72
|
+
"type": s.type.value,
|
|
73
|
+
"name": s.name,
|
|
74
|
+
"file": s.file,
|
|
75
|
+
"line": s.line,
|
|
76
|
+
}
|
|
77
|
+
for s in results
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
ensure_ascii=False,
|
|
81
|
+
indent=2,
|
|
82
|
+
)
|
|
83
|
+
)
|
|
84
|
+
return
|
|
85
|
+
|
|
86
|
+
_log.info("╔─ HIGPERTEXT · Graph Query ──────────────────────────────────")
|
|
87
|
+
_log.info(f"│ Keyword : {args.symbol}")
|
|
88
|
+
_log.info(f"│ Depth : {args.depth}")
|
|
89
|
+
_log.info(f"│ Símbolos : {len(results)}")
|
|
90
|
+
_log.info("╠───────────────────────────────────────────────────────")
|
|
91
|
+
if args.files_only.lower() in {"true", "1", "yes"}:
|
|
92
|
+
for file in sorted({s.file for s in results}):
|
|
93
|
+
_log.info(f"│ {file}")
|
|
94
|
+
_log.info("╚───────────────────────────────────────────────────────")
|
|
95
|
+
_log.ok(f"\n[SUCCESS] {len(set(s.file for s in results))} archivo(s) encontrados.")
|
|
96
|
+
return
|
|
97
|
+
for s in results:
|
|
98
|
+
_log.info(f"│ [{s.type.value:8}] {s.name:30} {s.file}:{s.line}")
|
|
99
|
+
_log.info("╚───────────────────────────────────────────────────────")
|
|
100
|
+
_log.ok(f"\n[SUCCESS] {len(results)} símbolos encontrados.")
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
if __name__ == "__main__":
|
|
104
|
+
main()
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""Capability common.graph-rebuild — regenera el grafo semántico del proyecto."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
import argparse
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
|
|
8
|
+
from higpertext.kernel.infrastructure.logger import get_logger
|
|
9
|
+
_log = get_logger()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _resolve_core() -> Path:
|
|
13
|
+
here = Path(__file__).resolve()
|
|
14
|
+
for parent in here.parents:
|
|
15
|
+
core = parent / "src" / "core"
|
|
16
|
+
if core.exists():
|
|
17
|
+
return core
|
|
18
|
+
raise RuntimeError("No se encontró src/core")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _parse_args() -> argparse.Namespace:
|
|
22
|
+
parser = argparse.ArgumentParser(description="Regenera el grafo semántico.")
|
|
23
|
+
parser.add_argument("--root", default=".", help="Directorio raíz del proyecto.")
|
|
24
|
+
parser.add_argument("--god_threshold", type=int, default=5)
|
|
25
|
+
parser.add_argument(
|
|
26
|
+
"--incremental",
|
|
27
|
+
type=lambda x: x.lower() != "false",
|
|
28
|
+
default=True,
|
|
29
|
+
help="Usa caché incremental (default: true). Pasa false para rebuild completo.",
|
|
30
|
+
)
|
|
31
|
+
return parser.parse_args()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _setup_path() -> None:
|
|
35
|
+
core = _resolve_core()
|
|
36
|
+
if str(core) not in sys.path:
|
|
37
|
+
sys.path.insert(0, str(core))
|
|
38
|
+
sys.path.insert(0, str(core.parent.parent))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _print_summary(root, graph, god_nodes, clusters, path, stats, threshold) -> None:
|
|
42
|
+
mode = "incremental" if stats.get("skipped", 0) > 0 else "full"
|
|
43
|
+
_log.info("╔─ HIGPERTEXT · Graph Rebuild ────────────────────────────────")
|
|
44
|
+
_log.info(f"│ Modo : {mode} (parsed={stats['parsed']}, skipped={stats['skipped']})")
|
|
45
|
+
_log.info(f"│ Símbolos indexados : {graph.symbol_count}")
|
|
46
|
+
_log.info(f"│ Relaciones : {graph.relation_count}")
|
|
47
|
+
_log.info(f"│ God nodes : {len(god_nodes)} (threshold={threshold})")
|
|
48
|
+
_log.info(f"│ Comunidades : {len(clusters)}")
|
|
49
|
+
_log.info(f"│ Artefacto : {path.relative_to(root)}")
|
|
50
|
+
_log.info("╚───────────────────────────────────────────────────────")
|
|
51
|
+
if god_nodes:
|
|
52
|
+
_log.warning("\n⚠ God nodes detectados:")
|
|
53
|
+
for n in god_nodes:
|
|
54
|
+
_log.info(f" • {n.name} ({n.file}:{n.line})")
|
|
55
|
+
_log.ok("\n[SUCCESS] Grafo semántico regenerado.")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def main() -> None:
|
|
59
|
+
args = _parse_args()
|
|
60
|
+
_setup_path()
|
|
61
|
+
|
|
62
|
+
from higpertext.semantic_engine.application.graph_builder import GraphBuilder
|
|
63
|
+
from higpertext.semantic_engine.application.cluster_service import ClusterService
|
|
64
|
+
from higpertext.semantic_engine.infrastructure.graph_store import GraphStore
|
|
65
|
+
|
|
66
|
+
root = Path(args.root).resolve()
|
|
67
|
+
_log.info(f"[*] Analizando proyecto: {root} (incremental={args.incremental})")
|
|
68
|
+
|
|
69
|
+
builder = GraphBuilder()
|
|
70
|
+
result = builder.build_with_stats(root=root, incremental=args.incremental)
|
|
71
|
+
graph, stats = result["graph"], result
|
|
72
|
+
|
|
73
|
+
store = GraphStore(root=root)
|
|
74
|
+
path = store.save(graph)
|
|
75
|
+
|
|
76
|
+
god_nodes = graph.god_nodes(threshold=args.god_threshold)
|
|
77
|
+
clusters = ClusterService().detect(graph)
|
|
78
|
+
_update_summary_md(root, graph, god_nodes, clusters)
|
|
79
|
+
_print_summary(root, graph, god_nodes, clusters, path, stats, args.god_threshold)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _update_summary_md(root, graph, god_nodes, clusters) -> None:
|
|
83
|
+
md_path = root / WORKSPACE_DIR_NAME / "state" / "semantic_graph.md"
|
|
84
|
+
lines = [
|
|
85
|
+
"# Project Semantic Graph\n",
|
|
86
|
+
"\nThis file is auto-generated by `common.graph-rebuild`. Do not edit manually.\n",
|
|
87
|
+
f"\n## Overview\n- **Total symbols**: {graph.symbol_count}\n",
|
|
88
|
+
f"- **Total relations**: {graph.relation_count}\n",
|
|
89
|
+
f"- **God nodes**: {len(god_nodes)}\n",
|
|
90
|
+
f"- **Communities**: {len(clusters)}\n",
|
|
91
|
+
"\n## God Nodes\n",
|
|
92
|
+
]
|
|
93
|
+
if god_nodes:
|
|
94
|
+
for n in god_nodes:
|
|
95
|
+
lines.append(f"- `{n.name}` — `{n.file}:{n.line}`\n")
|
|
96
|
+
else:
|
|
97
|
+
lines.append("_None detected._\n")
|
|
98
|
+
|
|
99
|
+
lines.append("\n## Communities\n")
|
|
100
|
+
for c in clusters:
|
|
101
|
+
lines.append(f"- **{c.id}** ({c.size} symbols)\n")
|
|
102
|
+
|
|
103
|
+
md_path.write_text("".join(lines), encoding="utf-8")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
if __name__ == "__main__":
|
|
107
|
+
main()
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Capability common.graph-visualize — genera HTML interactivo D3.js del grafo."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
|
|
5
|
+
import argparse
|
|
6
|
+
import json
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from higpertext.kernel.pkg_resources import resolve_resource
|
|
11
|
+
from higpertext.kernel.config_paths import PROJECT_ROOT
|
|
12
|
+
|
|
13
|
+
from higpertext.kernel.infrastructure.logger import get_logger
|
|
14
|
+
_log = get_logger()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _load_graph(graph_path: Path, max_nodes: int) -> tuple[list, list]:
|
|
18
|
+
raw = json.loads(graph_path.read_text(encoding="utf-8"))
|
|
19
|
+
symbols = raw["symbols"][:max_nodes]
|
|
20
|
+
allowed_ids = {f"{s['file']}::{s['name']}" for s in symbols}
|
|
21
|
+
nodes = [
|
|
22
|
+
{"id": f"{s['file']}::{s['name']}", "label": s["name"], "type": s["type"]} for s in symbols
|
|
23
|
+
]
|
|
24
|
+
links = [
|
|
25
|
+
{"source": r["source"], "target": r["target"]}
|
|
26
|
+
for r in raw["relations"]
|
|
27
|
+
if r["source"] in allowed_ids and r["target"] in allowed_ids
|
|
28
|
+
]
|
|
29
|
+
return nodes, links
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _render(nodes: list, links: list, god_threshold: int, out: Path) -> None:
|
|
33
|
+
template_path = resolve_resource(
|
|
34
|
+
PROJECT_ROOT, "src", "higpertext", "templates", "html", "graph_visualize.html"
|
|
35
|
+
)
|
|
36
|
+
if not template_path.exists():
|
|
37
|
+
raise FileNotFoundError(f"Plantilla HTML no encontrada: {template_path}")
|
|
38
|
+
template = template_path.read_text(encoding="utf-8")
|
|
39
|
+
|
|
40
|
+
html = (
|
|
41
|
+
template.replace("{node_count}", str(len(nodes)))
|
|
42
|
+
.replace("{edge_count}", str(len(links)))
|
|
43
|
+
.replace("{god_threshold}", str(god_threshold))
|
|
44
|
+
.replace("{graph_json}", json.dumps({"nodes": nodes, "links": links}))
|
|
45
|
+
)
|
|
46
|
+
out.parent.mkdir(parents=True, exist_ok=True)
|
|
47
|
+
out.write_text(html, encoding="utf-8")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def main() -> None:
|
|
51
|
+
parser = argparse.ArgumentParser(description="Genera grafo HTML interactivo.")
|
|
52
|
+
parser.add_argument("--output", default=".higpertext/reports/semantic_graph.html")
|
|
53
|
+
parser.add_argument("--max_nodes", type=int, default=200)
|
|
54
|
+
parser.add_argument("--god_threshold", type=int, default=5)
|
|
55
|
+
args = parser.parse_args()
|
|
56
|
+
|
|
57
|
+
graph_path = Path(".").resolve() / WORKSPACE_DIR_NAME / "state" / "semantic_graph.json"
|
|
58
|
+
if not graph_path.exists():
|
|
59
|
+
_log.error("[ERROR] semantic_graph.json no encontrado. Ejecuta: htx task common.graph-rebuild")
|
|
60
|
+
sys.exit(1)
|
|
61
|
+
|
|
62
|
+
nodes, links = _load_graph(graph_path, args.max_nodes)
|
|
63
|
+
out = Path(args.output)
|
|
64
|
+
_render(nodes, links, args.god_threshold, out)
|
|
65
|
+
|
|
66
|
+
_log.info("╔─ HIGPERTEXT · Graph Visualize ──────────────────────────────")
|
|
67
|
+
_log.info(f"│ Nodos renderizados : {len(nodes)}")
|
|
68
|
+
_log.info(f"│ Aristas : {len(links)}")
|
|
69
|
+
_log.info(f"│ God threshold : {args.god_threshold}")
|
|
70
|
+
_log.info(f"│ Artefacto : {out}")
|
|
71
|
+
_log.info("╚───────────────────────────────────────────────────────")
|
|
72
|
+
_log.ok(f"\n[SUCCESS] Abre en tu navegador: {out}")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
if __name__ == "__main__":
|
|
76
|
+
main()
|