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,154 @@
|
|
|
1
|
+
"""higpertext Environment Manager — initializes and manages environment context (Application)."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
import json
|
|
6
|
+
import shutil
|
|
7
|
+
import datetime
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
|
|
10
|
+
|
|
11
|
+
from higpertext.kernel.infrastructure.logger import get_logger
|
|
12
|
+
_log = get_logger()
|
|
13
|
+
|
|
14
|
+
# Adjusting parents[2] to parents[3] since the file is now in application/
|
|
15
|
+
_MODEL_DEFAULTS_FILE = Path(__file__).parents[3] / "config" / "environments" / "model_defaults.json"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def load_model_defaults() -> dict:
|
|
19
|
+
"""Carga model_config desde src/config/environments/model_defaults.json."""
|
|
20
|
+
try:
|
|
21
|
+
return json.loads(_MODEL_DEFAULTS_FILE.read_text(encoding="utf-8")).get("model_config", {})
|
|
22
|
+
except (OSError, json.JSONDecodeError):
|
|
23
|
+
return {}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class EnvironmentManager:
|
|
27
|
+
"""Gestiona la inicialización y persistencia del contexto del entorno
|
|
28
|
+
en .higpertext/environment.json."""
|
|
29
|
+
|
|
30
|
+
def __init__(self, target_dir: Path):
|
|
31
|
+
self.target_dir = target_dir
|
|
32
|
+
self.higpertext_dir = target_dir / WORKSPACE_DIR_NAME
|
|
33
|
+
self.env_file = self.higpertext_dir / "config" / "environment.json"
|
|
34
|
+
|
|
35
|
+
def is_initialized(self) -> bool:
|
|
36
|
+
"""Verifica si el proyecto ya ha sido inicializado por higpertext."""
|
|
37
|
+
return self.env_file.exists()
|
|
38
|
+
|
|
39
|
+
def load_environment(self) -> dict:
|
|
40
|
+
"""Carga los metadatos y variables del entorno desde el archivo JSON."""
|
|
41
|
+
if not self.is_initialized():
|
|
42
|
+
return {}
|
|
43
|
+
try:
|
|
44
|
+
return json.loads(self.env_file.read_text(encoding="utf-8"))
|
|
45
|
+
except (OSError, json.JSONDecodeError) as e:
|
|
46
|
+
_log.warning(f"[!] Error leyendo {self.env_file}: {e}")
|
|
47
|
+
return {}
|
|
48
|
+
|
|
49
|
+
def save_environment(self, data: dict) -> None:
|
|
50
|
+
"""Guarda los metadatos y variables de entorno en el archivo JSON."""
|
|
51
|
+
self.higpertext_dir.mkdir(parents=True, exist_ok=True)
|
|
52
|
+
self.env_file.parent.mkdir(parents=True, exist_ok=True)
|
|
53
|
+
self.env_file.write_text(json.dumps(data, indent=4, ensure_ascii=False), encoding="utf-8")
|
|
54
|
+
_log.ok(f"[*] Entorno guardado exitosamente en: {self.env_file}")
|
|
55
|
+
|
|
56
|
+
def _merge_list(self, existing: dict, key: str, new_val: str, fallback: str) -> list:
|
|
57
|
+
"""Fusiona listas únicas preservando valores previos."""
|
|
58
|
+
result = list(existing.get(key, []))
|
|
59
|
+
legacy = existing.get(key[:-1]) # e.g. "assistant" from "assistants"
|
|
60
|
+
if legacy and legacy not in result:
|
|
61
|
+
result.append(legacy)
|
|
62
|
+
if new_val and new_val not in result:
|
|
63
|
+
result.append(new_val)
|
|
64
|
+
return result or [fallback]
|
|
65
|
+
|
|
66
|
+
# Campos que el kernel gestiona — no se propagan desde existing al merge final
|
|
67
|
+
_MANAGED_KEYS = {
|
|
68
|
+
"schema_version",
|
|
69
|
+
"project_name",
|
|
70
|
+
"initialized_at",
|
|
71
|
+
"last_updated",
|
|
72
|
+
"assistants",
|
|
73
|
+
"assistant",
|
|
74
|
+
"active_profiles",
|
|
75
|
+
"active_profile",
|
|
76
|
+
"system_environment",
|
|
77
|
+
"variables",
|
|
78
|
+
"wikis",
|
|
79
|
+
"model_config",
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
def initialize_environment(self, profile_name: str, assistant: str) -> dict:
|
|
83
|
+
"""Inicializa o actualiza el archivo de entorno capturando variables clave del sistema."""
|
|
84
|
+
existing = self.load_environment()
|
|
85
|
+
existing_vars = existing.get("variables", {})
|
|
86
|
+
|
|
87
|
+
assistants = self._merge_list(existing, "assistants", assistant, "gemini")
|
|
88
|
+
active_profiles = self._merge_list(existing, "active_profiles", profile_name, "ado_admin")
|
|
89
|
+
|
|
90
|
+
org_url = os.getenv(
|
|
91
|
+
"ADO_ORG_URL",
|
|
92
|
+
existing_vars.get("organization_url"),
|
|
93
|
+
)
|
|
94
|
+
guidelines_source = os.getenv(
|
|
95
|
+
"HIGPERTEXT_GUIDELINES_SOURCE", existing_vars.get("guidelines_source")
|
|
96
|
+
)
|
|
97
|
+
_reserved_vars = {
|
|
98
|
+
"default_branch",
|
|
99
|
+
"repository_id",
|
|
100
|
+
"repo_id",
|
|
101
|
+
"organization_url",
|
|
102
|
+
"guidelines_source",
|
|
103
|
+
}
|
|
104
|
+
variables = {
|
|
105
|
+
"default_branch": existing_vars.get("default_branch", "main"),
|
|
106
|
+
"repository_id": existing_vars.get("repository_id", self.target_dir.name),
|
|
107
|
+
"repo_id": existing_vars.get("repo_id", self.target_dir.name),
|
|
108
|
+
"organization_url": org_url,
|
|
109
|
+
"guidelines_source": guidelines_source,
|
|
110
|
+
**{k: v for k, v in existing_vars.items() if k not in _reserved_vars},
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
# Preservar campos custom del usuario que no son gestionados por el kernel
|
|
114
|
+
user_custom = {k: v for k, v in existing.items() if k not in self._MANAGED_KEYS}
|
|
115
|
+
|
|
116
|
+
data = {
|
|
117
|
+
**user_custom,
|
|
118
|
+
"schema_version": "5.0.0",
|
|
119
|
+
"project_name": self.target_dir.name,
|
|
120
|
+
"initialized_at": existing.get("initialized_at", datetime.datetime.now().isoformat()),
|
|
121
|
+
"last_updated": datetime.datetime.now().isoformat(),
|
|
122
|
+
"assistants": assistants,
|
|
123
|
+
"assistant": assistant or existing.get("assistant", "gemini"),
|
|
124
|
+
"active_profiles": active_profiles,
|
|
125
|
+
"active_profile": profile_name or existing.get("active_profile", "ado_admin"),
|
|
126
|
+
"system_environment": {
|
|
127
|
+
"os": sys.platform,
|
|
128
|
+
"python_executable": sys.executable,
|
|
129
|
+
"has_powershell": bool(shutil.which("powershell") or shutil.which("pwsh")),
|
|
130
|
+
"project_root": str(self.target_dir.absolute()),
|
|
131
|
+
},
|
|
132
|
+
"variables": variables,
|
|
133
|
+
"wikis": existing.get("wikis", {}),
|
|
134
|
+
"model_config": existing.get("model_config", {}),
|
|
135
|
+
}
|
|
136
|
+
self.save_environment(data)
|
|
137
|
+
return data
|
|
138
|
+
|
|
139
|
+
def add_active_profile(self, profile_name: str) -> dict:
|
|
140
|
+
"""Añade y registra de forma permanente un nuevo perfil en el proyecto activo."""
|
|
141
|
+
data = self.load_environment()
|
|
142
|
+
if not data:
|
|
143
|
+
return {}
|
|
144
|
+
active_profiles = data.get("active_profiles", [])
|
|
145
|
+
if "active_profile" in data and data["active_profile"] not in active_profiles:
|
|
146
|
+
active_profiles.append(data["active_profile"])
|
|
147
|
+
if profile_name and profile_name not in active_profiles:
|
|
148
|
+
active_profiles.append(profile_name)
|
|
149
|
+
data["active_profiles"] = active_profiles
|
|
150
|
+
data["active_profile"] = profile_name
|
|
151
|
+
data["last_updated"] = datetime.datetime.now().isoformat()
|
|
152
|
+
data["model_config"] = data.get("model_config", {})
|
|
153
|
+
self.save_environment(data)
|
|
154
|
+
return data
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"""Casos de uso y coordinadores de Gobernanza (Aplicación)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import json
|
|
6
|
+
from datetime import datetime, timezone
|
|
7
|
+
import re
|
|
8
|
+
|
|
9
|
+
from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
|
|
10
|
+
from higpertext.kernel.domain.governance import Scope, Severity, Finding, Verdict, GovernanceException
|
|
11
|
+
from higpertext.kernel.infrastructure.governance import ContractLoader, AuditLog
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ExceptionRegistry:
|
|
15
|
+
def __init__(self, project_root: Path) -> None:
|
|
16
|
+
self._store = project_root / WORKSPACE_DIR_NAME / "state" / "governance_exceptions.json"
|
|
17
|
+
|
|
18
|
+
def register(self, exc: GovernanceException) -> None:
|
|
19
|
+
exceptions = self._load_all()
|
|
20
|
+
key = f"{exc.profile}:{exc.rule_id}"
|
|
21
|
+
data = exc.to_dict()
|
|
22
|
+
data["created_at"] = datetime.now(timezone.utc).isoformat(timespec="seconds")
|
|
23
|
+
exceptions[key] = data
|
|
24
|
+
self._save(exceptions)
|
|
25
|
+
|
|
26
|
+
def is_excepted(self, rule_id: str, profile: str) -> bool:
|
|
27
|
+
exceptions = self._load_all()
|
|
28
|
+
key = f"{profile}:{rule_id}"
|
|
29
|
+
entry = exceptions.get(key) or exceptions.get(f"global:{rule_id}")
|
|
30
|
+
if not entry:
|
|
31
|
+
return False
|
|
32
|
+
exc = GovernanceException.from_dict(entry)
|
|
33
|
+
return exc.is_active()
|
|
34
|
+
|
|
35
|
+
def list_active(self, profile: str = "") -> list[GovernanceException]:
|
|
36
|
+
all_exc = self._load_all()
|
|
37
|
+
result = []
|
|
38
|
+
for key, data in all_exc.items():
|
|
39
|
+
exc = GovernanceException.from_dict(data)
|
|
40
|
+
if not exc.is_active():
|
|
41
|
+
continue
|
|
42
|
+
if profile and exc.profile not in (profile, "global"):
|
|
43
|
+
continue
|
|
44
|
+
result.append(exc)
|
|
45
|
+
return result
|
|
46
|
+
|
|
47
|
+
def _load_all(self) -> dict:
|
|
48
|
+
if not self._store.exists():
|
|
49
|
+
return {}
|
|
50
|
+
try:
|
|
51
|
+
return json.loads(self._store.read_text(encoding="utf-8"))
|
|
52
|
+
except (OSError, json.JSONDecodeError):
|
|
53
|
+
return {}
|
|
54
|
+
|
|
55
|
+
def _save(self, data: dict) -> None:
|
|
56
|
+
self._store.parent.mkdir(parents=True, exist_ok=True)
|
|
57
|
+
self._store.write_text(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class GovernanceEnforcer:
|
|
61
|
+
"""Evalúa gobernanza efectiva para un perfil y scope, con excepciones y audit trail."""
|
|
62
|
+
|
|
63
|
+
def __init__(self, project_root: Path) -> None:
|
|
64
|
+
self._root = project_root
|
|
65
|
+
self._loader = ContractLoader(project_root)
|
|
66
|
+
self._audit = AuditLog(project_root)
|
|
67
|
+
self._exceptions = ExceptionRegistry(project_root)
|
|
68
|
+
|
|
69
|
+
def evaluate(
|
|
70
|
+
self,
|
|
71
|
+
scope: str,
|
|
72
|
+
profile: str = "",
|
|
73
|
+
triggered_by: str = "",
|
|
74
|
+
context: dict | None = None,
|
|
75
|
+
) -> Verdict:
|
|
76
|
+
"""Evalúa todas las reglas aplicables al scope y perfil dados."""
|
|
77
|
+
scope_enum = self._normalize_scope(scope)
|
|
78
|
+
rules = self._loader.load(profile)
|
|
79
|
+
verdict = Verdict(scope=scope)
|
|
80
|
+
|
|
81
|
+
for rule in rules:
|
|
82
|
+
if self._should_skip_rule(rule, profile, scope_enum):
|
|
83
|
+
continue
|
|
84
|
+
self._apply_rule(rule, verdict, profile, context)
|
|
85
|
+
|
|
86
|
+
self._audit.record(verdict, profile=profile, triggered_by=triggered_by)
|
|
87
|
+
return verdict
|
|
88
|
+
|
|
89
|
+
def _normalize_scope(self, scope: str) -> Scope:
|
|
90
|
+
try:
|
|
91
|
+
return Scope(scope)
|
|
92
|
+
except ValueError:
|
|
93
|
+
return Scope.ANY
|
|
94
|
+
|
|
95
|
+
def _should_skip_rule(self, rule, profile: str, scope_enum: Scope) -> bool:
|
|
96
|
+
return (
|
|
97
|
+
not rule.applies_to(scope_enum)
|
|
98
|
+
or self._exceptions.is_excepted(rule.id, profile)
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
def _apply_rule(self, rule, verdict: Verdict, profile: str, context: dict | None) -> None:
|
|
102
|
+
if rule.automated and context:
|
|
103
|
+
finding = self._run_automated_check(rule, context, profile)
|
|
104
|
+
if finding:
|
|
105
|
+
verdict.add(finding)
|
|
106
|
+
return
|
|
107
|
+
|
|
108
|
+
if not rule.automated and rule.severity == Severity.HIGH:
|
|
109
|
+
verdict.add(
|
|
110
|
+
Finding(
|
|
111
|
+
rule_id=rule.id,
|
|
112
|
+
severity=Severity.MEDIUM, # degradar a WARN, nunca BLOCK
|
|
113
|
+
message=rule.description,
|
|
114
|
+
source=rule.source,
|
|
115
|
+
detail="Verificación manual requerida.",
|
|
116
|
+
)
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
def _run_automated_check(self, rule, context: dict, profile: str) -> Finding | None:
|
|
120
|
+
"""Ejecuta verificaciones automáticas según el ID de la regla."""
|
|
121
|
+
checks = {
|
|
122
|
+
"security.no-hardcoded-secrets": self._check_no_secrets,
|
|
123
|
+
"code_quality.max-function-lines": self._check_function_lines,
|
|
124
|
+
"code_quality.min-coverage": self._check_coverage,
|
|
125
|
+
"gitflow_commits.conventional-format": self._check_commit_format,
|
|
126
|
+
}
|
|
127
|
+
checker = checks.get(rule.id)
|
|
128
|
+
if checker:
|
|
129
|
+
return checker(rule, context, profile)
|
|
130
|
+
return None
|
|
131
|
+
|
|
132
|
+
@staticmethod
|
|
133
|
+
def _check_no_secrets(rule, context: dict, profile: str) -> Finding | None:
|
|
134
|
+
patterns = [
|
|
135
|
+
r"(?i)(password|passwd|secret|token|api_key|apikey)\s*=\s*['\"][^'\"]{4,}['\"]",
|
|
136
|
+
r"(?i)bearer\s+[a-zA-Z0-9\-._~+/]{20,}",
|
|
137
|
+
]
|
|
138
|
+
diff = context.get("diff", "")
|
|
139
|
+
for pat in patterns:
|
|
140
|
+
if re.search(pat, diff):
|
|
141
|
+
return Finding(
|
|
142
|
+
rule_id=rule.id,
|
|
143
|
+
severity=rule.severity,
|
|
144
|
+
message="Posible secret hardcodeado detectado en el diff.",
|
|
145
|
+
source=rule.source,
|
|
146
|
+
detail="Usa variables de entorno o un secrets manager.",
|
|
147
|
+
)
|
|
148
|
+
return None
|
|
149
|
+
|
|
150
|
+
@staticmethod
|
|
151
|
+
def _check_function_lines(rule, context: dict, profile: str) -> Finding | None:
|
|
152
|
+
threshold = rule.numeric_threshold or 30
|
|
153
|
+
violations = context.get("function_line_violations", [])
|
|
154
|
+
if violations:
|
|
155
|
+
return Finding(
|
|
156
|
+
rule_id=rule.id,
|
|
157
|
+
severity=rule.severity,
|
|
158
|
+
message=f"{len(violations)} función(es) exceden {int(threshold)} líneas.",
|
|
159
|
+
source=rule.source,
|
|
160
|
+
detail=", ".join(violations[:5]),
|
|
161
|
+
)
|
|
162
|
+
return None
|
|
163
|
+
|
|
164
|
+
@staticmethod
|
|
165
|
+
def _check_coverage(rule, context: dict, profile: str) -> Finding | None:
|
|
166
|
+
threshold = rule.numeric_threshold or 80.0
|
|
167
|
+
coverage = context.get("coverage_pct")
|
|
168
|
+
if coverage is not None and coverage < threshold:
|
|
169
|
+
return Finding(
|
|
170
|
+
rule_id=rule.id,
|
|
171
|
+
severity=rule.severity,
|
|
172
|
+
message=f"Cobertura {coverage:.1f}% < umbral {threshold:.0f}%.",
|
|
173
|
+
source=rule.source,
|
|
174
|
+
)
|
|
175
|
+
return None
|
|
176
|
+
|
|
177
|
+
@staticmethod
|
|
178
|
+
def _check_commit_format(rule, context: dict, profile: str) -> Finding | None:
|
|
179
|
+
msg = context.get("commit_message", "")
|
|
180
|
+
pattern = (
|
|
181
|
+
r"^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)"
|
|
182
|
+
r"(\([^)]+\))?(!)?: .+"
|
|
183
|
+
)
|
|
184
|
+
if msg and not re.match(pattern, msg):
|
|
185
|
+
return Finding(
|
|
186
|
+
rule_id=rule.id,
|
|
187
|
+
severity=rule.severity,
|
|
188
|
+
message="Mensaje de commit no sigue Conventional Commits.",
|
|
189
|
+
source=rule.source,
|
|
190
|
+
detail=f"Recibido: '{msg[:60]}'",
|
|
191
|
+
)
|
|
192
|
+
return None
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""HookRegistry — carga hooks_config.json y filtra por asistente + perfil."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from higpertext.kernel.infrastructure.hook_config_loader import (
|
|
7
|
+
load_hooks_config,
|
|
8
|
+
save_hooks_config,
|
|
9
|
+
)
|
|
10
|
+
from higpertext.kernel.domain.hook_models import HookDefinition, WebhookEvent
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class HookRegistry:
|
|
14
|
+
def __init__(self, project_root: Path) -> None:
|
|
15
|
+
self._project_root = project_root
|
|
16
|
+
self._data: dict = load_hooks_config(project_root)
|
|
17
|
+
|
|
18
|
+
def _get_valid_hooks(self) -> list[dict]:
|
|
19
|
+
all_hooks: list[dict] = self._data.get("hooks", []) + self._data.get("agent_hooks", [])
|
|
20
|
+
return [
|
|
21
|
+
h
|
|
22
|
+
for h in all_hooks
|
|
23
|
+
if isinstance(h, dict) and "id" in h and "event" in h and "script" in h
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
def _get_profile_ids(self, profile: str) -> set[str]:
|
|
27
|
+
profile_ids: set[str] = set(self._data.get("profile_hooks", {}).get(profile, []))
|
|
28
|
+
|
|
29
|
+
# Siempre permite que los hooks locales del agente se ejecuten,
|
|
30
|
+
# asociándolos al perfil activo
|
|
31
|
+
for h in self._data.get("agent_hooks", []):
|
|
32
|
+
if isinstance(h, dict) and "id" in h:
|
|
33
|
+
profile_ids.add(h["id"])
|
|
34
|
+
|
|
35
|
+
return profile_ids
|
|
36
|
+
|
|
37
|
+
def _is_hook_allowed(self, raw: dict, assistant: str, profile: str, profile_ids: set[str]) -> bool:
|
|
38
|
+
if not raw.get("enabled", True):
|
|
39
|
+
return False
|
|
40
|
+
|
|
41
|
+
allowed_assistants = raw.get("assistants", [])
|
|
42
|
+
if allowed_assistants and assistant not in allowed_assistants:
|
|
43
|
+
return False
|
|
44
|
+
|
|
45
|
+
allowed_profiles = raw.get("profiles", [])
|
|
46
|
+
if allowed_profiles and profile not in allowed_profiles:
|
|
47
|
+
return False
|
|
48
|
+
|
|
49
|
+
return not profile_ids or raw["id"] in profile_ids
|
|
50
|
+
|
|
51
|
+
def get_hooks_for(self, assistant: str, profile: str) -> list[HookDefinition]:
|
|
52
|
+
"""Devuelve hooks activos filtrados por asistente y perfil."""
|
|
53
|
+
all_hooks = self._get_valid_hooks()
|
|
54
|
+
profile_ids = self._get_profile_ids(profile)
|
|
55
|
+
|
|
56
|
+
result: list[HookDefinition] = []
|
|
57
|
+
for raw in all_hooks:
|
|
58
|
+
if not self._is_hook_allowed(raw, assistant, profile, profile_ids):
|
|
59
|
+
continue
|
|
60
|
+
result.append(
|
|
61
|
+
HookDefinition(
|
|
62
|
+
id=raw["id"],
|
|
63
|
+
event=raw["event"],
|
|
64
|
+
script=raw["script"],
|
|
65
|
+
description=raw.get("description", ""),
|
|
66
|
+
matcher=raw.get("matcher", ""),
|
|
67
|
+
timeout=raw.get("timeout", 10),
|
|
68
|
+
enabled=raw.get("enabled", True),
|
|
69
|
+
assistants=raw.get("assistants", []),
|
|
70
|
+
profiles=raw.get("profiles", []),
|
|
71
|
+
capability_id=raw.get("capability_id", ""),
|
|
72
|
+
)
|
|
73
|
+
)
|
|
74
|
+
return result
|
|
75
|
+
|
|
76
|
+
def get_webhooks_for(self, assistant: str) -> list[WebhookEvent]:
|
|
77
|
+
result: list[WebhookEvent] = []
|
|
78
|
+
for raw in self._data.get("webhooks", []):
|
|
79
|
+
if not raw.get("enabled", False):
|
|
80
|
+
continue
|
|
81
|
+
allowed = raw.get("assistants", [])
|
|
82
|
+
if allowed and assistant not in allowed:
|
|
83
|
+
continue
|
|
84
|
+
result.append(
|
|
85
|
+
WebhookEvent(
|
|
86
|
+
id=raw["id"],
|
|
87
|
+
event=raw["event"],
|
|
88
|
+
url=raw["url"],
|
|
89
|
+
payload_template=raw.get("payload_template", {}),
|
|
90
|
+
assistants=raw.get("assistants", []),
|
|
91
|
+
enabled=raw.get("enabled", False),
|
|
92
|
+
timeout=raw.get("timeout", 5),
|
|
93
|
+
)
|
|
94
|
+
)
|
|
95
|
+
return result
|
|
96
|
+
|
|
97
|
+
def get_all_hook_ids(self) -> list[str]:
|
|
98
|
+
return [h["id"] for h in self._data.get("hooks", [])]
|
|
99
|
+
|
|
100
|
+
def save(self, data: dict) -> None:
|
|
101
|
+
self._data = data
|
|
102
|
+
save_hooks_config(self._project_root, data)
|