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,132 @@
|
|
|
1
|
+
"""TelemetryReporter — dashboard de telemetría en terminal (Infraestructura)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from higpertext.kernel.app_config import (
|
|
7
|
+
TELEMETRY_BOX_WIDTH as _W,
|
|
8
|
+
TELEMETRY_BAR_WIDTH as _BAR_W,
|
|
9
|
+
TELEMETRY_EMPTY_TITLE,
|
|
10
|
+
TELEMETRY_EMPTY_LINES,
|
|
11
|
+
TELEMETRY_SECTION_LABELS as _LABELS,
|
|
12
|
+
TELEMETRY_ACTIVITY_ICONS as _ICONS,
|
|
13
|
+
)
|
|
14
|
+
from higpertext.kernel.application.telemetry import TelemetryAggregator
|
|
15
|
+
from higpertext.kernel.infrastructure.logger import HtxLogger, get_logger, render_box
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _box_row(text: str = "") -> str:
|
|
19
|
+
pad = _W - len(text) - 2
|
|
20
|
+
return f"║ {text}{' ' * pad}║"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _sep() -> str:
|
|
24
|
+
return "─" * (_W + 2)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def render(
|
|
28
|
+
project_root: Path,
|
|
29
|
+
days: int = 7,
|
|
30
|
+
project_id: str | None = None,
|
|
31
|
+
*,
|
|
32
|
+
logger: HtxLogger | None = None,
|
|
33
|
+
) -> str:
|
|
34
|
+
"""Genera el dashboard de telemetría y lo emite vía logger.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
project_root: Raíz del proyecto.
|
|
38
|
+
days: Ventana de días a analizar.
|
|
39
|
+
project_id: Filtro opcional de proyecto.
|
|
40
|
+
logger: Instancia HtxLogger a usar. Si es None se obtiene el singleton.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
El string renderizado (compatibilidad con callers que capturan output).
|
|
44
|
+
"""
|
|
45
|
+
log: HtxLogger = logger or get_logger(project_root)
|
|
46
|
+
agg = TelemetryAggregator(project_root, project_id=project_id)
|
|
47
|
+
m = agg.compute(days)
|
|
48
|
+
|
|
49
|
+
if not m:
|
|
50
|
+
block = render_box(
|
|
51
|
+
TELEMETRY_EMPTY_TITLE,
|
|
52
|
+
[_box_row(line) for line in TELEMETRY_EMPTY_LINES],
|
|
53
|
+
)
|
|
54
|
+
log.warning(block)
|
|
55
|
+
return block + "\n"
|
|
56
|
+
|
|
57
|
+
project_label = f" · {project_id}" if project_id else ""
|
|
58
|
+
h = int(m["total_duration_min"] // 60)
|
|
59
|
+
mn = int(m["total_duration_min"] % 60)
|
|
60
|
+
duration_str = f"{h}h {mn}m" if h else f"{mn}m"
|
|
61
|
+
|
|
62
|
+
active_hint = f" (activa: {m['sessions_active']})" if m["sessions_active"] else ""
|
|
63
|
+
|
|
64
|
+
corr = m["correlations"]
|
|
65
|
+
adoption = corr["higpertext_adoption_pct"]
|
|
66
|
+
adoption_bar = _bar(adoption, 100)
|
|
67
|
+
higpertext_calls = corr["higpertext_calls"]
|
|
68
|
+
higpertext_direct = corr.get("higpertext_direct_calls", 0)
|
|
69
|
+
bash_direct = corr["bash_direct_calls"]
|
|
70
|
+
|
|
71
|
+
rows = [
|
|
72
|
+
_box_row(),
|
|
73
|
+
_box_row(f"Sesiones : {m['sessions_total']}{active_hint}"),
|
|
74
|
+
_box_row(f"Tiempo total : {duration_str}"),
|
|
75
|
+
_box_row(f"Commits : {m['commits_total']} (solicitudes resueltas)"),
|
|
76
|
+
_box_row(f"Tool calls : {m['tool_calls_total']}"),
|
|
77
|
+
_box_row(f"Tokens est. : {m['estimated_tokens']:,}"),
|
|
78
|
+
_box_row(f"Costo est. : ${m['estimated_cost_usd']:.4f} USD"),
|
|
79
|
+
_box_row(),
|
|
80
|
+
_box_row(_LABELS["correlations"]),
|
|
81
|
+
_box_row(_sep()[: _W - 2]),
|
|
82
|
+
_box_row(f"Tokens/sesión : {corr['tokens_per_session']:,}"),
|
|
83
|
+
_box_row(f"Costo/commit : ${corr['cost_per_commit_usd']:.4f} USD"),
|
|
84
|
+
_box_row(f"Commits/sesión : {corr['commits_per_session']}"),
|
|
85
|
+
_box_row(f"Adopción higpertext : {adoption_bar} {adoption}%"),
|
|
86
|
+
_box_row(
|
|
87
|
+
f" intercepts+caps: {higpertext_calls - higpertext_direct}"
|
|
88
|
+
f" · htx.py directo: {higpertext_direct}"
|
|
89
|
+
f" · bash: {bash_direct}"
|
|
90
|
+
),
|
|
91
|
+
_box_row(),
|
|
92
|
+
]
|
|
93
|
+
|
|
94
|
+
if m["top_capabilities"]:
|
|
95
|
+
rows.append(_box_row(_LABELS["top_caps"]))
|
|
96
|
+
rows.append(_box_row(_sep()[: _W - 2]))
|
|
97
|
+
for i, (cap, count) in enumerate(m["top_capabilities"], 1):
|
|
98
|
+
rows.append(_box_row(f" {i}. {cap:<30} ×{count}"))
|
|
99
|
+
|
|
100
|
+
if m.get("top_direct_tools"):
|
|
101
|
+
rows.append(_box_row(_LABELS["top_tools"]))
|
|
102
|
+
rows.append(_box_row(_sep()[: _W - 2]))
|
|
103
|
+
for i, (tool, count) in enumerate(m["top_direct_tools"], 1):
|
|
104
|
+
rows.append(_box_row(f" {i}. {tool:<30} ×{count}"))
|
|
105
|
+
|
|
106
|
+
recent = m.get("recent_activity", [])
|
|
107
|
+
if recent:
|
|
108
|
+
rows += [_box_row(), _box_row(_LABELS["recent_activity"])]
|
|
109
|
+
rows.append(_box_row(_sep()[: _W - 2]))
|
|
110
|
+
for act in recent:
|
|
111
|
+
icon = _activity_icon(act["op_type"])
|
|
112
|
+
target = act["target"]
|
|
113
|
+
max_target = _W - 12
|
|
114
|
+
if len(target) > max_target:
|
|
115
|
+
target = "…" + target[-(max_target - 1):]
|
|
116
|
+
rows.append(_box_row(f" {icon} {target}"))
|
|
117
|
+
|
|
118
|
+
rows.append(_box_row())
|
|
119
|
+
|
|
120
|
+
title = f"HIGPERTEXT TELEMETRY · últimos {days} días{project_label}"
|
|
121
|
+
block = render_box(title, rows)
|
|
122
|
+
log.info(block)
|
|
123
|
+
return block + "\n"
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _activity_icon(op_type: str) -> str:
|
|
127
|
+
return _ICONS.get(op_type, _ICONS["default"])
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _bar(value: float, total: float) -> str:
|
|
131
|
+
filled = int(round(value / total * _BAR_W)) if total else 0
|
|
132
|
+
return "█" * filled + "░" * (_BAR_W - filled)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Infrastructure validation init
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"""Validador de contratos técnicos definidos en el JSON de cada capacidad (Infraestructura)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
import re
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ContractValidator:
|
|
10
|
+
"""Validador de contratos técnicos definidos en el JSON de cada capacidad."""
|
|
11
|
+
|
|
12
|
+
@staticmethod
|
|
13
|
+
def validate(
|
|
14
|
+
params: dict,
|
|
15
|
+
stdout: str,
|
|
16
|
+
stderr: str,
|
|
17
|
+
returncode: int,
|
|
18
|
+
capability_data: dict,
|
|
19
|
+
) -> tuple[bool, list[str]]:
|
|
20
|
+
errors = []
|
|
21
|
+
errors.extend(ContractValidator._validate_params(params, capability_data))
|
|
22
|
+
|
|
23
|
+
contract = capability_data.get("contract", {})
|
|
24
|
+
if not contract:
|
|
25
|
+
return len(errors) == 0, errors
|
|
26
|
+
|
|
27
|
+
errors.extend(
|
|
28
|
+
ContractValidator._validate_contract(stdout, stderr, params, capability_data, contract)
|
|
29
|
+
)
|
|
30
|
+
return len(errors) == 0, errors
|
|
31
|
+
|
|
32
|
+
@staticmethod
|
|
33
|
+
def _validate_params(params: dict, capability_data: dict) -> list[str]:
|
|
34
|
+
errors = []
|
|
35
|
+
for param_def in capability_data.get("parameters", []):
|
|
36
|
+
name = param_def.get("name")
|
|
37
|
+
if name is None:
|
|
38
|
+
continue
|
|
39
|
+
|
|
40
|
+
if param_def.get("required", False) and name not in params:
|
|
41
|
+
errors.append(f"El parámetro obligatorio '{name}' no fue provisto.")
|
|
42
|
+
continue
|
|
43
|
+
|
|
44
|
+
if name in params:
|
|
45
|
+
validator = ContractValidator._param_type_validators().get(
|
|
46
|
+
param_def.get("type", "string").lower()
|
|
47
|
+
)
|
|
48
|
+
if validator:
|
|
49
|
+
errors.extend(validator(name, params[name]))
|
|
50
|
+
return errors
|
|
51
|
+
|
|
52
|
+
@staticmethod
|
|
53
|
+
def _param_type_validators() -> dict[str, callable]:
|
|
54
|
+
return {
|
|
55
|
+
"integer": ContractValidator._validate_integer_param,
|
|
56
|
+
"boolean": ContractValidator._validate_boolean_param,
|
|
57
|
+
"array": ContractValidator._validate_array_param,
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@staticmethod
|
|
61
|
+
def _validate_integer_param(name: str, value) -> list[str]:
|
|
62
|
+
try:
|
|
63
|
+
int(value)
|
|
64
|
+
return []
|
|
65
|
+
except (ValueError, TypeError):
|
|
66
|
+
return [
|
|
67
|
+
f"El parámetro '{name}' debe ser de tipo entero (recibido: '{value}')."
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
@staticmethod
|
|
71
|
+
def _validate_boolean_param(name: str, value) -> list[str]:
|
|
72
|
+
if isinstance(value, bool) or str(value).lower() in (
|
|
73
|
+
"true",
|
|
74
|
+
"false",
|
|
75
|
+
"1",
|
|
76
|
+
"0",
|
|
77
|
+
):
|
|
78
|
+
return []
|
|
79
|
+
return [
|
|
80
|
+
f"El parámetro '{name}' debe ser booleano (recibido: '{value}')."
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
@staticmethod
|
|
84
|
+
def _validate_array_param(name: str, value) -> list[str]:
|
|
85
|
+
if isinstance(value, (list, tuple)) or isinstance(value, str):
|
|
86
|
+
return []
|
|
87
|
+
return [
|
|
88
|
+
f"El parámetro '{name}' debe ser de tipo array (recibido: '{value}')."
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
@staticmethod
|
|
92
|
+
def _validate_contract(
|
|
93
|
+
stdout: str,
|
|
94
|
+
stderr: str,
|
|
95
|
+
params: dict,
|
|
96
|
+
capability_data: dict,
|
|
97
|
+
contract: dict,
|
|
98
|
+
) -> list[str]:
|
|
99
|
+
errors = []
|
|
100
|
+
expected_format = contract.get("format", "").lower()
|
|
101
|
+
|
|
102
|
+
if expected_format == "json":
|
|
103
|
+
errors.extend(
|
|
104
|
+
ContractValidator._validate_json_output(stdout, contract.get("required_fields", []))
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
errors.extend(ContractValidator._validate_patterns(stdout, stderr, contract))
|
|
108
|
+
errors.extend(
|
|
109
|
+
ContractValidator._validate_expected_files(params, capability_data, contract.get("expected_files", []))
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
return errors
|
|
113
|
+
|
|
114
|
+
@staticmethod
|
|
115
|
+
def _validate_json_output(stdout: str, required_fields: list[str]) -> list[str]:
|
|
116
|
+
errors = []
|
|
117
|
+
try:
|
|
118
|
+
json_data = json.loads(stdout)
|
|
119
|
+
for field in required_fields:
|
|
120
|
+
if field not in json_data:
|
|
121
|
+
errors.append(f"El output JSON no contiene el campo obligatorio: '{field}'")
|
|
122
|
+
except json.JSONDecodeError:
|
|
123
|
+
errors.append("El contrato exige formato JSON, pero el output no es JSON válido.")
|
|
124
|
+
return errors
|
|
125
|
+
|
|
126
|
+
@staticmethod
|
|
127
|
+
def _validate_patterns(stdout: str, stderr: str, contract: dict) -> list[str]:
|
|
128
|
+
errors = []
|
|
129
|
+
for pattern in contract.get("required_patterns", []):
|
|
130
|
+
if not re.search(pattern, stdout):
|
|
131
|
+
errors.append(f"El output no contiene el patrón requerido: '{pattern}'")
|
|
132
|
+
|
|
133
|
+
for pattern in contract.get("forbidden_patterns", []):
|
|
134
|
+
if re.search(pattern, stdout) or re.search(pattern, stderr):
|
|
135
|
+
errors.append(f"Se detectó un patrón prohibido en el output/stderr: '{pattern}'")
|
|
136
|
+
return errors
|
|
137
|
+
|
|
138
|
+
@staticmethod
|
|
139
|
+
def _validate_expected_files(
|
|
140
|
+
params: dict,
|
|
141
|
+
capability_data: dict,
|
|
142
|
+
file_templates: list[str],
|
|
143
|
+
) -> list[str]:
|
|
144
|
+
errors = []
|
|
145
|
+
for file_template in file_templates:
|
|
146
|
+
try:
|
|
147
|
+
interpolated_path = file_template
|
|
148
|
+
for key, val in params.items():
|
|
149
|
+
interpolated_path = interpolated_path.replace(f"{{{key}}}", str(val))
|
|
150
|
+
for param_def in capability_data.get("parameters", []):
|
|
151
|
+
p_name = param_def.get("name")
|
|
152
|
+
if p_name and f"{{{p_name}}}" in interpolated_path and "default" in param_def:
|
|
153
|
+
interpolated_path = interpolated_path.replace(
|
|
154
|
+
f"{{{p_name}}}", str(param_def["default"])
|
|
155
|
+
)
|
|
156
|
+
target_file = Path(interpolated_path).resolve()
|
|
157
|
+
if not target_file.exists():
|
|
158
|
+
errors.append(f"Archivo esperado no fue creado: '{interpolated_path}'")
|
|
159
|
+
elif target_file.stat().st_size == 0:
|
|
160
|
+
errors.append(f"Archivo '{interpolated_path}' creado pero vacío (0 bytes).")
|
|
161
|
+
except OSError as e:
|
|
162
|
+
errors.append(f"Error validando archivo '{file_template}': {e}")
|
|
163
|
+
return errors
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Resolución de recursos empaquetados — fallback dev tree -> wheel instalado."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def pkg_data_root() -> Path | None:
|
|
8
|
+
"""Raíz de higpertext_data (perfiles, capabilities json, templates, hooks_catalog)."""
|
|
9
|
+
try:
|
|
10
|
+
import higpertext_data
|
|
11
|
+
|
|
12
|
+
return Path(higpertext_data.__path__[0]).resolve()
|
|
13
|
+
except (ImportError, AttributeError, IndexError):
|
|
14
|
+
return None
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def installed_src_root() -> Path | None:
|
|
18
|
+
"""Raíz equivalente a src/ vía el paquete higpertext instalado (módulos .py reales)."""
|
|
19
|
+
try:
|
|
20
|
+
import higpertext
|
|
21
|
+
|
|
22
|
+
return Path(higpertext.__path__[0]).resolve().parent
|
|
23
|
+
except (ImportError, AttributeError, IndexError):
|
|
24
|
+
return None
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def resolve_resource(base_dir: Path, *rel_parts: str) -> Path:
|
|
28
|
+
"""base_dir/rel_parts si existe; si no, cae a pkg_data_root()/rel_parts[1:]
|
|
29
|
+
cuando rel_parts[0] == 'src'."""
|
|
30
|
+
dev_path = base_dir.joinpath(*rel_parts)
|
|
31
|
+
if dev_path.exists():
|
|
32
|
+
return dev_path
|
|
33
|
+
pkg_root = pkg_data_root()
|
|
34
|
+
if pkg_root is not None and rel_parts and rel_parts[0] == "src":
|
|
35
|
+
pkg_path = pkg_root.joinpath(*rel_parts[1:])
|
|
36
|
+
if pkg_path.exists():
|
|
37
|
+
return pkg_path
|
|
38
|
+
return dev_path
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
"""higpertext Session Manager — fachada del ciclo de vida de sesiones temporales.
|
|
2
|
+
|
|
3
|
+
Delega en:
|
|
4
|
+
- SessionContextBuilder (resolución de skills/subagentes)
|
|
5
|
+
- ResourceDeployer (despliegue y restauración de recursos)
|
|
6
|
+
- MarkdownRenderer (generación de Markdown — via ResourceDeployer)
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
|
|
11
|
+
|
|
12
|
+
import datetime
|
|
13
|
+
import json
|
|
14
|
+
import os
|
|
15
|
+
import secrets
|
|
16
|
+
import shutil
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
from higpertext.kernel.infrastructure.presentation.markdown_renderer import (
|
|
20
|
+
MarkdownRenderer,
|
|
21
|
+
)
|
|
22
|
+
from higpertext.kernel.infrastructure.deployment.resource_deployer import (
|
|
23
|
+
ResourceDeployer,
|
|
24
|
+
)
|
|
25
|
+
from higpertext.kernel.application.context_builder import SessionContextBuilder
|
|
26
|
+
from higpertext.kernel.infrastructure.logger import get_logger
|
|
27
|
+
from higpertext.kernel.app_config import (
|
|
28
|
+
DEFAULT_ASSISTANT as _DEFAULT_ASSISTANT,
|
|
29
|
+
DEFAULT_PROFILE as _DEFAULT_PROFILE,
|
|
30
|
+
ASSISTANT_PATHS as _ASSISTANT_PATHS,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
_log = get_logger()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class SessionManager:
|
|
37
|
+
"""Fachada: orquesta el ciclo de vida completo de una sesión temporal."""
|
|
38
|
+
|
|
39
|
+
def __init__(self, project_root: Path, root_dir: Path) -> None:
|
|
40
|
+
self.project_root = project_root
|
|
41
|
+
self.root_dir = root_dir
|
|
42
|
+
self.session_file = project_root / WORKSPACE_DIR_NAME / "state" / "session.json"
|
|
43
|
+
self.env_file = project_root / WORKSPACE_DIR_NAME / "config" / "environment.json"
|
|
44
|
+
self.session_file.parent.mkdir(parents=True, exist_ok=True)
|
|
45
|
+
self.env_file.parent.mkdir(parents=True, exist_ok=True)
|
|
46
|
+
self._context_builder = SessionContextBuilder(project_root, root_dir)
|
|
47
|
+
self._deployer = ResourceDeployer(project_root, root_dir)
|
|
48
|
+
|
|
49
|
+
# --- Environment helpers ---
|
|
50
|
+
|
|
51
|
+
def get_assistant_and_profile(self) -> tuple[str, str]:
|
|
52
|
+
if not self.env_file.exists():
|
|
53
|
+
return _DEFAULT_ASSISTANT, _DEFAULT_PROFILE
|
|
54
|
+
try:
|
|
55
|
+
data = json.loads(self.env_file.read_text(encoding="utf-8"))
|
|
56
|
+
return (
|
|
57
|
+
data.get("assistant", _DEFAULT_ASSISTANT),
|
|
58
|
+
data.get("active_profile", _DEFAULT_PROFILE),
|
|
59
|
+
)
|
|
60
|
+
except (OSError, json.JSONDecodeError):
|
|
61
|
+
return _DEFAULT_ASSISTANT, _DEFAULT_PROFILE
|
|
62
|
+
|
|
63
|
+
def get_model(self, assistant: str) -> str | None:
|
|
64
|
+
try:
|
|
65
|
+
if self.env_file.exists():
|
|
66
|
+
data = json.loads(self.env_file.read_text(encoding="utf-8"))
|
|
67
|
+
model = data.get("llm", {}).get("assistants", {}).get(assistant, {}).get("model")
|
|
68
|
+
if model:
|
|
69
|
+
return model
|
|
70
|
+
return None
|
|
71
|
+
except (OSError, json.JSONDecodeError):
|
|
72
|
+
return None
|
|
73
|
+
|
|
74
|
+
def get_paths(self, assistant: str) -> tuple[Path, Path, Path]:
|
|
75
|
+
wf, sk, sa = _ASSISTANT_PATHS.get(assistant, _ASSISTANT_PATHS[_DEFAULT_ASSISTANT])
|
|
76
|
+
root = self.project_root
|
|
77
|
+
return root / wf, root / sk, root / sa
|
|
78
|
+
|
|
79
|
+
def get_agent_system_dir(self) -> Path:
|
|
80
|
+
env_path = os.getenv("AGENT_SYSTEM_PATH")
|
|
81
|
+
if env_path and Path(env_path).exists():
|
|
82
|
+
return Path(env_path).resolve()
|
|
83
|
+
candidate = self.root_dir.parent.parent / "app" / "APP_Scripts_PowerShell" / "AgentSystem"
|
|
84
|
+
return candidate if candidate.exists() else self.root_dir
|
|
85
|
+
|
|
86
|
+
# --- Session lifecycle ---
|
|
87
|
+
|
|
88
|
+
def start_session(
|
|
89
|
+
self,
|
|
90
|
+
profile_name: str,
|
|
91
|
+
assistant: str,
|
|
92
|
+
skills: list | None = None,
|
|
93
|
+
subagents: list | None = None,
|
|
94
|
+
) -> dict:
|
|
95
|
+
self.clean_session()
|
|
96
|
+
skills, subagents = self._context_builder.resolve_resources(profile_name, skills, subagents)
|
|
97
|
+
|
|
98
|
+
session_id = f"sess_{int(datetime.datetime.now().timestamp())}_{secrets.token_hex(2)}"
|
|
99
|
+
session_data = {
|
|
100
|
+
"session_id": session_id,
|
|
101
|
+
"profile": profile_name,
|
|
102
|
+
"assistant": assistant,
|
|
103
|
+
"status": "active",
|
|
104
|
+
"created_at": datetime.datetime.now().isoformat(),
|
|
105
|
+
"active_skills": skills,
|
|
106
|
+
"active_subagents": subagents,
|
|
107
|
+
"tasks": [],
|
|
108
|
+
}
|
|
109
|
+
self.session_file.parent.mkdir(parents=True, exist_ok=True)
|
|
110
|
+
self.session_file.write_text(
|
|
111
|
+
json.dumps(session_data, indent=4, ensure_ascii=False), encoding="utf-8"
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
wf_dest, sk_dest, sa_dest = self.get_paths(assistant)
|
|
115
|
+
self._run_adapter_hook(assistant, "on_session_start", profile_name)
|
|
116
|
+
self._deployer.deploy_skills(skills, sk_dest)
|
|
117
|
+
skills_str, beans_str = self._deployer.build_resource_links(
|
|
118
|
+
skills, subagents, sk_dest, sa_dest
|
|
119
|
+
)
|
|
120
|
+
self._deployer.deploy_subagents(subagents, sa_dest, skills_str)
|
|
121
|
+
self._deployer.deploy_playbooks(
|
|
122
|
+
wf_dest,
|
|
123
|
+
skills_str,
|
|
124
|
+
beans_str,
|
|
125
|
+
session_id,
|
|
126
|
+
assistant,
|
|
127
|
+
get_model_fn=self.get_model,
|
|
128
|
+
get_profile_fn=self._load_active_profile_data,
|
|
129
|
+
)
|
|
130
|
+
# Mirror gemini resources to .agents/ (antigravity deprecated, same flow)
|
|
131
|
+
if assistant == "gemini":
|
|
132
|
+
self._mirror_gemini_to_agents(self.project_root)
|
|
133
|
+
self._refresh_semantic_graph()
|
|
134
|
+
_log.ok(f"[SUCCESS] Sesión temporal '{session_id}' iniciada.")
|
|
135
|
+
return session_data
|
|
136
|
+
|
|
137
|
+
def _mirror_gemini_to_agents(self, project_root: Path) -> None:
|
|
138
|
+
import shutil as _shutil
|
|
139
|
+
|
|
140
|
+
mapping = {"skills": "skills", "agents": "agents", "workflows": "workflows"}
|
|
141
|
+
for src_sub, dst_sub in mapping.items():
|
|
142
|
+
src = project_root / ".gemini" / src_sub
|
|
143
|
+
dst = project_root / ".agents" / dst_sub
|
|
144
|
+
if not src.exists():
|
|
145
|
+
continue
|
|
146
|
+
dst.mkdir(parents=True, exist_ok=True)
|
|
147
|
+
for item in src.iterdir():
|
|
148
|
+
if item.is_file():
|
|
149
|
+
_shutil.copy2(item, dst / item.name)
|
|
150
|
+
elif item.is_dir():
|
|
151
|
+
_shutil.copytree(item, dst / item.name, dirs_exist_ok=True)
|
|
152
|
+
|
|
153
|
+
def clean_session(self) -> bool:
|
|
154
|
+
assistant = self._read_session_assistant()
|
|
155
|
+
wf_dest, sk_dest, sa_dest = self.get_paths(assistant)
|
|
156
|
+
|
|
157
|
+
for d in (sk_dest, sa_dest):
|
|
158
|
+
if d.exists():
|
|
159
|
+
try:
|
|
160
|
+
shutil.rmtree(d)
|
|
161
|
+
except OSError: # nosec B110
|
|
162
|
+
pass
|
|
163
|
+
|
|
164
|
+
if assistant == "gemini":
|
|
165
|
+
for sub in ("skills", "agents", "workflows"):
|
|
166
|
+
d = self.project_root / ".agents" / sub
|
|
167
|
+
if d.exists():
|
|
168
|
+
try:
|
|
169
|
+
shutil.rmtree(d)
|
|
170
|
+
except OSError: # nosec B110
|
|
171
|
+
pass
|
|
172
|
+
|
|
173
|
+
# Limpiar cache de capabilities
|
|
174
|
+
cache_dir = self.project_root / WORKSPACE_DIR_NAME / "__cache__"
|
|
175
|
+
if cache_dir.exists():
|
|
176
|
+
for f in cache_dir.glob("*.json"):
|
|
177
|
+
try:
|
|
178
|
+
f.unlink()
|
|
179
|
+
except OSError: # nosec B110
|
|
180
|
+
pass
|
|
181
|
+
|
|
182
|
+
self._run_adapter_hook(assistant, "on_session_clean")
|
|
183
|
+
self._deployer.restore_playbooks(
|
|
184
|
+
wf_dest,
|
|
185
|
+
assistant,
|
|
186
|
+
get_model_fn=self.get_model,
|
|
187
|
+
get_profile_fn=self._load_active_profile_data,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
from higpertext.kernel.infrastructure.file_repositories import (
|
|
191
|
+
FileSessionRepository,
|
|
192
|
+
)
|
|
193
|
+
from higpertext.kernel.application.session_services import (
|
|
194
|
+
SessionApplicationService,
|
|
195
|
+
)
|
|
196
|
+
from higpertext.kernel.infrastructure.file_repositories import (
|
|
197
|
+
FileProfileRepository,
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
# Generar reporte de telemetría de forma automática antes de borrar recursos
|
|
201
|
+
try:
|
|
202
|
+
from higpertext.kernel.infrastructure.telemetry_reporter import render as render_telemetry
|
|
203
|
+
from higpertext.kernel.infrastructure import OutputStore
|
|
204
|
+
|
|
205
|
+
report_content = render_telemetry(self.project_root, days=7)
|
|
206
|
+
OutputStore(self.project_root).write(
|
|
207
|
+
"common.telemetry-report", report_content, fmt="txt"
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
# Generar el Diario de Decisiones
|
|
211
|
+
from higpertext.capabilities.common.scripts.commit_rationale_log import (
|
|
212
|
+
main as run_rationale_log,
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
try:
|
|
216
|
+
import sys as _sys
|
|
217
|
+
|
|
218
|
+
_orig = _sys.argv
|
|
219
|
+
_sys.argv = [_sys.argv[0]]
|
|
220
|
+
run_rationale_log()
|
|
221
|
+
_sys.argv = _orig
|
|
222
|
+
except Exception: # nosec B110
|
|
223
|
+
pass
|
|
224
|
+
|
|
225
|
+
# Generar el Análisis de Desviación Arquitectónica
|
|
226
|
+
from higpertext.capabilities.common.scripts.architecture_drift_report import (
|
|
227
|
+
main as run_drift_report,
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
try:
|
|
231
|
+
_sys.argv = [_sys.argv[0]]
|
|
232
|
+
run_drift_report()
|
|
233
|
+
except Exception: # nosec B110
|
|
234
|
+
pass
|
|
235
|
+
finally:
|
|
236
|
+
_sys.argv = _orig
|
|
237
|
+
|
|
238
|
+
from higpertext.capabilities.common.scripts.report_viewer import (
|
|
239
|
+
main as run_report_viewer,
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
try:
|
|
243
|
+
_sys.argv = [_sys.argv[0]]
|
|
244
|
+
run_report_viewer()
|
|
245
|
+
except Exception: # nosec B110
|
|
246
|
+
pass
|
|
247
|
+
finally:
|
|
248
|
+
_sys.argv = _orig
|
|
249
|
+
except Exception as e: # nosec B110
|
|
250
|
+
pass
|
|
251
|
+
|
|
252
|
+
session_repo = FileSessionRepository(self.session_file)
|
|
253
|
+
profile_repo = FileProfileRepository(self.project_root / "src" / "config" / "profiles")
|
|
254
|
+
session_service = SessionApplicationService(session_repo, profile_repo)
|
|
255
|
+
session_service.clean_session()
|
|
256
|
+
|
|
257
|
+
_log.ok("[SUCCESS] Sesión temporal y recursos limpiados exitosamente.")
|
|
258
|
+
return True
|
|
259
|
+
|
|
260
|
+
# --- Private helpers ---
|
|
261
|
+
|
|
262
|
+
def _read_session_assistant(self) -> str:
|
|
263
|
+
if self.session_file.exists():
|
|
264
|
+
try:
|
|
265
|
+
data = json.loads(self.session_file.read_text(encoding="utf-8"))
|
|
266
|
+
return data.get("assistant", _DEFAULT_ASSISTANT)
|
|
267
|
+
except (OSError, json.JSONDecodeError): # nosec B110
|
|
268
|
+
pass
|
|
269
|
+
assistant, _ = self.get_assistant_and_profile()
|
|
270
|
+
return assistant
|
|
271
|
+
|
|
272
|
+
def _refresh_semantic_graph(self) -> None:
|
|
273
|
+
try:
|
|
274
|
+
from higpertext.kernel.infrastructure.parser.semantic_graph import (
|
|
275
|
+
SemanticGraphGenerator,
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
_log.info("[*] Actualizando grafo semántico del proyecto...")
|
|
279
|
+
SemanticGraphGenerator.generate(self.project_root)
|
|
280
|
+
_log.ok("[SUCCESS] Grafo semántico actualizado.")
|
|
281
|
+
except (ImportError, OSError) as e:
|
|
282
|
+
_log.warning(f"[WARNING] No se pudo actualizar el grafo semántico: {e}")
|
|
283
|
+
|
|
284
|
+
def _load_active_profile_data(self):
|
|
285
|
+
try:
|
|
286
|
+
_, active_profile = self.get_assistant_and_profile()
|
|
287
|
+
from higpertext.kernel.engine import HigpertextEngine
|
|
288
|
+
|
|
289
|
+
engine = HigpertextEngine(self.root_dir)
|
|
290
|
+
return engine.profiles.load_profile(active_profile)
|
|
291
|
+
except Exception:
|
|
292
|
+
return None
|
|
293
|
+
|
|
294
|
+
def _run_adapter_hook(self, assistant: str, hook_name: str, profile_name: str = "") -> None:
|
|
295
|
+
try:
|
|
296
|
+
import sys
|
|
297
|
+
|
|
298
|
+
if str(self.root_dir) not in sys.path:
|
|
299
|
+
sys.path.append(str(self.root_dir))
|
|
300
|
+
from higpertext.adapters.adapter_utils import get_adapter_class
|
|
301
|
+
|
|
302
|
+
adapter_cls = get_adapter_class(assistant)
|
|
303
|
+
if not (adapter_cls and hasattr(adapter_cls, hook_name)):
|
|
304
|
+
return
|
|
305
|
+
if hook_name == "on_session_start" and profile_name:
|
|
306
|
+
from higpertext.kernel.engine import HigpertextEngine
|
|
307
|
+
|
|
308
|
+
engine = HigpertextEngine(self.root_dir)
|
|
309
|
+
context = engine.get_agent_context(profile_name)
|
|
310
|
+
if context:
|
|
311
|
+
getattr(adapter_cls, hook_name)(context, self.project_root)
|
|
312
|
+
else:
|
|
313
|
+
getattr(adapter_cls, hook_name)(self.project_root)
|
|
314
|
+
except Exception as e:
|
|
315
|
+
_log.warning(f"[!] Error ejecutando {hook_name} para '{assistant}': {e}")
|
|
316
|
+
|
|
317
|
+
@classmethod
|
|
318
|
+
def _generate_workflow_base_md(cls, data, assistant="gemini", profile_model=None):
|
|
319
|
+
return MarkdownRenderer.generate_workflow_base_md(data, assistant, profile_model)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
id: generic-shell
|
|
2
|
+
description: Alpine shell runner for simple local commands
|
|
3
|
+
services:
|
|
4
|
+
app:
|
|
5
|
+
image: alpine:3.20
|
|
6
|
+
working_dir: /workspace
|
|
7
|
+
volumes:
|
|
8
|
+
- .:/workspace
|
|
9
|
+
command: sleep infinity
|
|
10
|
+
tasks:
|
|
11
|
+
echo:
|
|
12
|
+
service: app
|
|
13
|
+
command: echo higpertext-env-ready
|
|
14
|
+
defaults:
|
|
15
|
+
service: app
|
|
16
|
+
task: echo
|
|
17
|
+
timeout_seconds: 120
|
|
18
|
+
cleanup: true
|
|
19
|
+
security:
|
|
20
|
+
network: isolated
|
|
21
|
+
privileged: false
|