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,115 @@
|
|
|
1
|
+
"""Hook Stop — cierra sesión automáticamente y muestra resumen de turno."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from higpertext.hooks.hook_tasks._rules.governance_adapter import get_session_limits
|
|
5
|
+
import higpertext.hooks.hook_tasks.telemetry_utils as telem
|
|
6
|
+
from higpertext.hooks.hook_tasks.hook_utils import get_project_root
|
|
7
|
+
from higpertext.hooks.hook_tasks.hook_io import (
|
|
8
|
+
hook_main,
|
|
9
|
+
read_json_file,
|
|
10
|
+
emit_stop_reason,
|
|
11
|
+
)
|
|
12
|
+
import sys
|
|
13
|
+
import subprocess # nosec B404
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
_SRC = Path(__file__).resolve().parents[3] # src/
|
|
17
|
+
if str(_SRC) not in sys.path:
|
|
18
|
+
sys.path.insert(0, str(_SRC))
|
|
19
|
+
from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _pending(root: Path) -> tuple[list[str], int, bool]:
|
|
23
|
+
try:
|
|
24
|
+
r = subprocess.run( # nosec B603 B607
|
|
25
|
+
["git", "status", "--porcelain"],
|
|
26
|
+
capture_output=True,
|
|
27
|
+
text=True,
|
|
28
|
+
cwd=str(root),
|
|
29
|
+
timeout=10,
|
|
30
|
+
)
|
|
31
|
+
lines = [line[3:] for line in r.stdout.strip().splitlines() if line.strip()]
|
|
32
|
+
limit = get_session_limits(root)
|
|
33
|
+
return lines, limit, len(lines) > limit
|
|
34
|
+
except (OSError, subprocess.TimeoutExpired):
|
|
35
|
+
return [], 5, False
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _last_commit(root: Path) -> str:
|
|
39
|
+
try:
|
|
40
|
+
r = subprocess.run( # nosec B603 B607
|
|
41
|
+
["git", "log", "--oneline", "-1"],
|
|
42
|
+
capture_output=True,
|
|
43
|
+
text=True,
|
|
44
|
+
cwd=str(root),
|
|
45
|
+
timeout=5,
|
|
46
|
+
)
|
|
47
|
+
return r.stdout.strip()
|
|
48
|
+
except (OSError, subprocess.TimeoutExpired):
|
|
49
|
+
return "—"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _clean_session(root: Path) -> bool:
|
|
53
|
+
"""Ejecuta session-clean y devuelve True si tuvo éxito."""
|
|
54
|
+
from higpertext.hooks.hook_tasks.hook_utils import get_htx
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
r = subprocess.run( # nosec B603
|
|
58
|
+
[get_htx(root), "task", "common.session-clean", "--action", "clean"],
|
|
59
|
+
capture_output=True,
|
|
60
|
+
text=True,
|
|
61
|
+
cwd=str(root),
|
|
62
|
+
timeout=20,
|
|
63
|
+
)
|
|
64
|
+
return r.returncode == 0
|
|
65
|
+
except Exception:
|
|
66
|
+
return False
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _build_banner(
|
|
70
|
+
files: list[str],
|
|
71
|
+
limit: int,
|
|
72
|
+
exceeded: bool,
|
|
73
|
+
commit: str,
|
|
74
|
+
active: bool,
|
|
75
|
+
sid: str,
|
|
76
|
+
profile: str,
|
|
77
|
+
) -> str:
|
|
78
|
+
lines = ["╔─ HIGPERTEXT · Fin de turno ──────────────────────────────"]
|
|
79
|
+
if files:
|
|
80
|
+
indicator = "❌ [GOBERNANZA]" if exceeded else "⚠"
|
|
81
|
+
lines.append(f"│ {indicator} {len(files)} archivo(s) sin commitear (Límite: {limit}):")
|
|
82
|
+
for f in files[:8]:
|
|
83
|
+
lines.append(f"│ • {f}")
|
|
84
|
+
if len(files) > 8:
|
|
85
|
+
lines.append(f"│ ... y {len(files) - 8} más")
|
|
86
|
+
lines.append('│ → committer --message "tipo(scope): descripción"')
|
|
87
|
+
else:
|
|
88
|
+
lines.append(f"│ ✓ Working tree limpio · {commit}")
|
|
89
|
+
if active:
|
|
90
|
+
lines.append(f"│ Sesión : {sid} · perfil: {profile}")
|
|
91
|
+
lines.append("│ ✓ Workspace restablecido al estado inicial")
|
|
92
|
+
lines.append("╚───────────────────────────────────────────────────────")
|
|
93
|
+
return "\n".join(lines)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@hook_main
|
|
97
|
+
def main() -> None:
|
|
98
|
+
root = get_project_root()
|
|
99
|
+
session = read_json_file(root / WORKSPACE_DIR_NAME / "state" / "session.json")
|
|
100
|
+
env = read_json_file(root / WORKSPACE_DIR_NAME / "config" / "environment.json")
|
|
101
|
+
active = session.get("status") == "active"
|
|
102
|
+
sid = session.get("session_id", "—")
|
|
103
|
+
profile = env.get("active_profile", "global")
|
|
104
|
+
files, limit, exceeded = _pending(root)
|
|
105
|
+
commit = _last_commit(root)
|
|
106
|
+
|
|
107
|
+
if active:
|
|
108
|
+
telem.session_stop(root, sid, profile)
|
|
109
|
+
_clean_session(root)
|
|
110
|
+
|
|
111
|
+
emit_stop_reason(_build_banner(files, limit, exceeded, commit, active, sid, profile))
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
if __name__ == "__main__":
|
|
115
|
+
main()
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""Utilidades compartidas para hook tasks de higpertext."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
# Add src to sys.path so we can import from higpertext
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import platform
|
|
11
|
+
import shutil
|
|
12
|
+
# Helpers ejecutan htx con shell=False.
|
|
13
|
+
import subprocess # nosec B404
|
|
14
|
+
from datetime import datetime, timezone
|
|
15
|
+
|
|
16
|
+
sys_path_src = Path(__file__).resolve().parents[3]
|
|
17
|
+
if str(sys_path_src) not in sys.path:
|
|
18
|
+
sys.path.insert(0, str(sys_path_src))
|
|
19
|
+
from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
|
|
20
|
+
HIGPERTEXT_DIR = WORKSPACE_DIR_NAME
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def get_project_root() -> Path:
|
|
25
|
+
"""Resuelve la raíz del proyecto desde environment.json.
|
|
26
|
+
|
|
27
|
+
Cuando un hook task se despliega en .<assistant>/hooks/, el archivo
|
|
28
|
+
environment.json se encuentra en ../../.higpertext/environment.json relativo
|
|
29
|
+
al script. Siempre hay un htx.py launcher en esa raíz.
|
|
30
|
+
"""
|
|
31
|
+
# Busca environment.json en dos ubicaciones candidatas:
|
|
32
|
+
# 1. Relativo al script (cuando el hook está desplegado en .<assistant>/hooks/)
|
|
33
|
+
# 2. Relativo al CWD del proceso (cuando se ejecuta desde la raíz del proyecto)
|
|
34
|
+
candidates = [
|
|
35
|
+
Path(__file__).resolve().parent
|
|
36
|
+
/ ".."
|
|
37
|
+
/ ".."
|
|
38
|
+
/ HIGPERTEXT_DIR
|
|
39
|
+
/ "config"
|
|
40
|
+
/ "environment.json",
|
|
41
|
+
Path.cwd() / HIGPERTEXT_DIR / "config" / "environment.json",
|
|
42
|
+
]
|
|
43
|
+
for env_path in candidates:
|
|
44
|
+
env_path = env_path.resolve()
|
|
45
|
+
if env_path.exists():
|
|
46
|
+
try:
|
|
47
|
+
data = json.loads(env_path.read_text(encoding="utf-8"))
|
|
48
|
+
root = data.get("system_environment", {}).get("project_root")
|
|
49
|
+
if root:
|
|
50
|
+
return Path(root)
|
|
51
|
+
except (OSError, json.JSONDecodeError): # nosec B110
|
|
52
|
+
pass
|
|
53
|
+
# Fallback: CWD si contiene htx.py (indica que somos la raíz del proyecto)
|
|
54
|
+
cwd = Path.cwd()
|
|
55
|
+
if (cwd / "htx.py").exists():
|
|
56
|
+
return cwd
|
|
57
|
+
return Path(__file__).resolve().parents[1]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def get_htx() -> str:
|
|
61
|
+
"""Retorna el primer elemento del comando htx resuelto via htx_resolver."""
|
|
62
|
+
root = get_project_root()
|
|
63
|
+
try:
|
|
64
|
+
from higpertext.kernel.htx_resolver import get_htx_cmd
|
|
65
|
+
|
|
66
|
+
cmd = get_htx_cmd(root)
|
|
67
|
+
return cmd[0]
|
|
68
|
+
except ImportError:
|
|
69
|
+
venv_htx = root / ".venv" / ("Scripts" if platform.system() == "Windows" else "bin") / "htx"
|
|
70
|
+
if venv_htx.exists():
|
|
71
|
+
return str(venv_htx)
|
|
72
|
+
if htx := shutil.which("htx"):
|
|
73
|
+
return htx
|
|
74
|
+
return str(root / ".venv" / "bin" / "python")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _htx_args(capability: str, params: dict) -> list[str]:
|
|
78
|
+
htx = get_htx()
|
|
79
|
+
base = (
|
|
80
|
+
[htx, "task", capability]
|
|
81
|
+
if not htx.endswith("python")
|
|
82
|
+
else [htx, "htx.py", "task", capability]
|
|
83
|
+
)
|
|
84
|
+
return base + [arg for k, v in params.items() for arg in (f"--{k}", str(v))]
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def hook_log_path(root: Path | None = None) -> Path:
|
|
88
|
+
"""Retorna la ruta del log estructurado de hooks."""
|
|
89
|
+
base = root or get_project_root()
|
|
90
|
+
return base / HIGPERTEXT_DIR / "logs" / "hooks.jsonl"
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def log_hook_event(event: dict, root: Path | None = None) -> None:
|
|
94
|
+
"""Registra un evento JSONL de hook sin interrumpir la ejecución."""
|
|
95
|
+
try:
|
|
96
|
+
path = hook_log_path(root)
|
|
97
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
98
|
+
payload = {
|
|
99
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
100
|
+
**event,
|
|
101
|
+
}
|
|
102
|
+
with path.open("a", encoding="utf-8") as fh:
|
|
103
|
+
fh.write(json.dumps(payload, ensure_ascii=False, sort_keys=True) + "\n")
|
|
104
|
+
except OSError: # nosec B110
|
|
105
|
+
pass
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def log_hook_error(hook_id: str, message: str, root: Path | None = None, **extra: object) -> None:
|
|
109
|
+
"""Registra errores no bloqueantes de hooks."""
|
|
110
|
+
log_hook_event(
|
|
111
|
+
{
|
|
112
|
+
"severity": "error",
|
|
113
|
+
"hook_id": hook_id,
|
|
114
|
+
"message": message[:1000],
|
|
115
|
+
**extra,
|
|
116
|
+
},
|
|
117
|
+
root=root,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def run_higpertext_task(capability: str, params: dict) -> str:
|
|
122
|
+
"""Ejecuta una capability higpertext y retorna su output combinado."""
|
|
123
|
+
root = get_project_root()
|
|
124
|
+
args = _htx_args(capability, params)
|
|
125
|
+
try:
|
|
126
|
+
result = subprocess.run(args, capture_output=True, text=True, cwd=str(root), timeout=30)
|
|
127
|
+
except subprocess.TimeoutExpired as exc:
|
|
128
|
+
log_hook_error(
|
|
129
|
+
"run_higpertext_task",
|
|
130
|
+
f"Timeout ejecutando capability {capability}",
|
|
131
|
+
root=root,
|
|
132
|
+
capability=capability,
|
|
133
|
+
timeout=exc.timeout,
|
|
134
|
+
)
|
|
135
|
+
return str(exc)
|
|
136
|
+
if result.returncode != 0:
|
|
137
|
+
log_hook_error(
|
|
138
|
+
"run_higpertext_task",
|
|
139
|
+
f"Capability {capability} terminó con código {result.returncode}",
|
|
140
|
+
root=root,
|
|
141
|
+
capability=capability,
|
|
142
|
+
returncode=result.returncode,
|
|
143
|
+
)
|
|
144
|
+
return (result.stdout or "") + (result.stderr or "")
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Hook SessionStart — verifica estado de la sesión y emite continue."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
import json
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
_SRC = Path(__file__).resolve().parents[3]
|
|
9
|
+
if str(_SRC) not in sys.path:
|
|
10
|
+
sys.path.insert(0, str(_SRC))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def main() -> None:
|
|
14
|
+
raw = sys.stdin.read().strip()
|
|
15
|
+
try:
|
|
16
|
+
json.loads(raw) if raw else {}
|
|
17
|
+
except json.JSONDecodeError: # nosec B110
|
|
18
|
+
pass
|
|
19
|
+
print(json.dumps({"continue": True}))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
if __name__ == "__main__":
|
|
23
|
+
main()
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"""Wrapper liviano de telemetría para uso desde hook tasks desplegados."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
from datetime import datetime, timezone
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _now() -> str:
|
|
12
|
+
return datetime.now(timezone.utc).isoformat(timespec="seconds")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _store(root: Path) -> Path:
|
|
16
|
+
return root / WORKSPACE_DIR_NAME / "state" / "telemetry.jsonl"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _project_id(root: Path) -> str:
|
|
20
|
+
"""Lee project_id desde environment.json → variables.repository_id."""
|
|
21
|
+
env_file = root / WORKSPACE_DIR_NAME / "config" / "environment.json"
|
|
22
|
+
try:
|
|
23
|
+
data = json.loads(env_file.read_text(encoding="utf-8"))
|
|
24
|
+
return (
|
|
25
|
+
data.get("variables", {}).get("repository_id") or data.get("project_name") or root.name
|
|
26
|
+
)
|
|
27
|
+
except (OSError, json.JSONDecodeError):
|
|
28
|
+
return root.name
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def record(root: Path, event: str, **fields) -> None:
|
|
32
|
+
entry = {"ts": _now(), "event": event, "project_id": _project_id(root), **fields}
|
|
33
|
+
try:
|
|
34
|
+
with _store(root).open("a", encoding="utf-8") as fh:
|
|
35
|
+
fh.write(json.dumps(entry, ensure_ascii=False) + "\n")
|
|
36
|
+
except OSError: # nosec B110
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def session_start(root: Path, session_id: str, profile: str) -> None:
|
|
41
|
+
record(root, "session_start", session_id=session_id, profile=profile)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def session_stop(root: Path, session_id: str, profile: str) -> None:
|
|
45
|
+
"""Calcula duración buscando el session_start correspondiente en el store."""
|
|
46
|
+
duration_min = _calc_duration(root, session_id)
|
|
47
|
+
record(
|
|
48
|
+
root,
|
|
49
|
+
"session_stop",
|
|
50
|
+
session_id=session_id,
|
|
51
|
+
profile=profile,
|
|
52
|
+
duration_min=round(duration_min, 2),
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def tool_call(
|
|
57
|
+
root: Path,
|
|
58
|
+
session_id: str,
|
|
59
|
+
tool_name: str,
|
|
60
|
+
input_chars: int,
|
|
61
|
+
output_chars: int,
|
|
62
|
+
is_higpertext_call: bool = False,
|
|
63
|
+
) -> None:
|
|
64
|
+
# Precios claude-sonnet-4-6 (junio 2026, por millón de tokens)
|
|
65
|
+
# Distribución real del usuario: 98% cache_read, 2% output/write
|
|
66
|
+
# input=$3/M output=$15/M cache_write=$3.75/M cache_read=$0.30/M
|
|
67
|
+
input_tokens = input_chars // 4
|
|
68
|
+
output_tokens = output_chars // 4
|
|
69
|
+
# Aproximación: input_chars del LLM son mayoritariamente cache_read
|
|
70
|
+
# Se estima 80% cache_read + 20% cache_write del input
|
|
71
|
+
cache_read_tokens = int(input_tokens * 0.80)
|
|
72
|
+
cache_write_tokens = int(input_tokens * 0.20)
|
|
73
|
+
estimated_tokens = input_tokens + output_tokens
|
|
74
|
+
|
|
75
|
+
cost = (
|
|
76
|
+
cache_read_tokens * 0.30 / 1_000_000
|
|
77
|
+
+ cache_write_tokens * 3.75 / 1_000_000
|
|
78
|
+
+ output_tokens * 15.0 / 1_000_000
|
|
79
|
+
)
|
|
80
|
+
record(
|
|
81
|
+
root,
|
|
82
|
+
"tool_call",
|
|
83
|
+
session_id=session_id,
|
|
84
|
+
tool=tool_name,
|
|
85
|
+
input_chars=input_chars,
|
|
86
|
+
output_chars=output_chars,
|
|
87
|
+
estimated_tokens=estimated_tokens,
|
|
88
|
+
estimated_cost_usd=round(cost, 6),
|
|
89
|
+
is_higpertext_call=is_higpertext_call,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def activity(
|
|
94
|
+
root: Path,
|
|
95
|
+
session_id: str,
|
|
96
|
+
tool: str,
|
|
97
|
+
op_type: str,
|
|
98
|
+
target: str,
|
|
99
|
+
scope: str = "",
|
|
100
|
+
higpertext_related: bool = False,
|
|
101
|
+
) -> None:
|
|
102
|
+
"""Registra una operación atómica del agente (Edit, Write, Read, Bash, etc.)."""
|
|
103
|
+
record(
|
|
104
|
+
root,
|
|
105
|
+
"activity",
|
|
106
|
+
session_id=session_id,
|
|
107
|
+
tool=tool,
|
|
108
|
+
op_type=op_type,
|
|
109
|
+
target=target[:120],
|
|
110
|
+
scope=scope,
|
|
111
|
+
higpertext_related=higpertext_related,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def hook_intercept(root: Path, session_id: str, capability_id: str, fragment: str) -> None:
|
|
116
|
+
record(
|
|
117
|
+
root,
|
|
118
|
+
"hook_intercept",
|
|
119
|
+
session_id=session_id,
|
|
120
|
+
capability=capability_id,
|
|
121
|
+
fragment=fragment[:80],
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def capability_used(root: Path, session_id: str, capability_id: str) -> None:
|
|
126
|
+
record(root, "capability_used", session_id=session_id, capability=capability_id)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def commit_event(
|
|
130
|
+
root: Path,
|
|
131
|
+
session_id: str,
|
|
132
|
+
commit_hash: str,
|
|
133
|
+
commit_type: str,
|
|
134
|
+
scope: str,
|
|
135
|
+
profile: str,
|
|
136
|
+
) -> None:
|
|
137
|
+
record(
|
|
138
|
+
root,
|
|
139
|
+
"commit",
|
|
140
|
+
session_id=session_id,
|
|
141
|
+
hash=commit_hash,
|
|
142
|
+
type=commit_type,
|
|
143
|
+
scope=scope,
|
|
144
|
+
profile=profile,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
# ------------------------------------------------------------------
|
|
149
|
+
# Helpers
|
|
150
|
+
# ------------------------------------------------------------------
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _calc_duration(root: Path, session_id: str) -> float:
|
|
154
|
+
"""Busca el session_start del session_id y retorna minutos transcurridos."""
|
|
155
|
+
store = _store(root)
|
|
156
|
+
if not store.exists():
|
|
157
|
+
return 0.0
|
|
158
|
+
start_ts = None
|
|
159
|
+
try:
|
|
160
|
+
for line in store.read_text(encoding="utf-8").splitlines():
|
|
161
|
+
try:
|
|
162
|
+
e = json.loads(line)
|
|
163
|
+
if e.get("event") == "session_start" and e.get("session_id") == session_id:
|
|
164
|
+
start_ts = e.get("ts")
|
|
165
|
+
except (json.JSONDecodeError, KeyError):
|
|
166
|
+
continue
|
|
167
|
+
except OSError:
|
|
168
|
+
return 0.0
|
|
169
|
+
if not start_ts:
|
|
170
|
+
return 0.0
|
|
171
|
+
try:
|
|
172
|
+
t0 = datetime.fromisoformat(start_ts)
|
|
173
|
+
t1 = datetime.now(timezone.utc)
|
|
174
|
+
return (t1 - t0).total_seconds() / 60
|
|
175
|
+
except ValueError:
|
|
176
|
+
return 0.0
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Hook de diagnóstico — devuelve continue:true con echo del payload."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
import json
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
_SRC = Path(__file__).resolve().parents[3]
|
|
9
|
+
if str(_SRC) not in sys.path:
|
|
10
|
+
sys.path.insert(0, str(_SRC))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def main() -> None:
|
|
14
|
+
raw = sys.stdin.read().strip()
|
|
15
|
+
try:
|
|
16
|
+
payload = json.loads(raw) if raw else {}
|
|
17
|
+
except json.JSONDecodeError:
|
|
18
|
+
payload = {}
|
|
19
|
+
print(
|
|
20
|
+
json.dumps(
|
|
21
|
+
{
|
|
22
|
+
"continue": True,
|
|
23
|
+
"hookSpecificOutput": {
|
|
24
|
+
"hookEventName": "PreToolUse",
|
|
25
|
+
"additionalContext": f"[hooks] echo: {json.dumps(payload)}",
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
if __name__ == "__main__":
|
|
33
|
+
main()
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Hook PostToolUse/Stop — dispara webhooks configurados en hooks_config.json."""
|
|
2
|
+
from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
|
|
3
|
+
|
|
4
|
+
import sys
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def main() -> None:
|
|
10
|
+
data = json.load(sys.stdin)
|
|
11
|
+
event = data.get("hook_event", "PostToolUse")
|
|
12
|
+
tool_name = data.get("tool_name", "")
|
|
13
|
+
session_id = data.get("session_id", "")
|
|
14
|
+
|
|
15
|
+
root = Path(__file__).resolve().parents[5]
|
|
16
|
+
|
|
17
|
+
# Importación dinámica para evitar dependencia de sys.path en tiempo de hook
|
|
18
|
+
import importlib.util
|
|
19
|
+
|
|
20
|
+
spec = importlib.util.spec_from_file_location(
|
|
21
|
+
"webhook_dispatcher",
|
|
22
|
+
root / "src" / "higpertext" / "hooks" / "webhook_dispatcher.py",
|
|
23
|
+
)
|
|
24
|
+
mod = importlib.util.module_from_spec(spec) # type: ignore[arg-type]
|
|
25
|
+
spec.loader.exec_module(mod) # type: ignore[union-attr]
|
|
26
|
+
|
|
27
|
+
env_path = root / WORKSPACE_DIR_NAME / "config" / "environment.json"
|
|
28
|
+
assistant = "claude"
|
|
29
|
+
profile = "software_developer"
|
|
30
|
+
if env_path.exists():
|
|
31
|
+
try:
|
|
32
|
+
env = json.loads(env_path.read_text(encoding="utf-8"))
|
|
33
|
+
assistant = env.get("assistant", assistant)
|
|
34
|
+
profile = env.get("active_profile", profile)
|
|
35
|
+
except (OSError, json.JSONDecodeError): # nosec B110
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
dispatcher = mod.WebhookDispatcher(root)
|
|
39
|
+
dispatcher.dispatch(
|
|
40
|
+
event,
|
|
41
|
+
assistant,
|
|
42
|
+
{
|
|
43
|
+
"tool": tool_name,
|
|
44
|
+
"session_id": session_id,
|
|
45
|
+
"profile": profile,
|
|
46
|
+
"assistant": assistant,
|
|
47
|
+
},
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
print(json.dumps({"continue": True}))
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
if __name__ == "__main__":
|
|
54
|
+
main()
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Hook task — ejecuta un workflow higpertext como hook PostToolUse o Stop."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
import json
|
|
5
|
+
import argparse
|
|
6
|
+
from higpertext.hooks.hook_tasks.hook_utils import get_project_root, get_htx
|
|
7
|
+
# Workflow runner usa comando htx controlado.
|
|
8
|
+
import subprocess # nosec B404
|
|
9
|
+
|
|
10
|
+
from higpertext.kernel.infrastructure.logger import get_logger
|
|
11
|
+
_log = get_logger()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def main() -> None:
|
|
15
|
+
parser = argparse.ArgumentParser()
|
|
16
|
+
parser.add_argument("--workflow", required=True)
|
|
17
|
+
args, _ = parser.parse_known_args()
|
|
18
|
+
|
|
19
|
+
hook_data: dict = {}
|
|
20
|
+
if not sys.stdin.isatty():
|
|
21
|
+
try:
|
|
22
|
+
hook_data = json.load(sys.stdin)
|
|
23
|
+
except (json.JSONDecodeError, ValueError): # nosec B110
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
root = get_project_root()
|
|
27
|
+
result = subprocess.run(
|
|
28
|
+
[get_htx(root), "workflow", "run", args.workflow],
|
|
29
|
+
capture_output=True,
|
|
30
|
+
text=True,
|
|
31
|
+
cwd=str(root),
|
|
32
|
+
)
|
|
33
|
+
output = result.stdout or result.stderr
|
|
34
|
+
|
|
35
|
+
print(
|
|
36
|
+
json.dumps(
|
|
37
|
+
{
|
|
38
|
+
"continue": True,
|
|
39
|
+
"hookSpecificOutput": {
|
|
40
|
+
"hookEventName": hook_data.get("hook_event", "PostToolUse"),
|
|
41
|
+
"additionalContext": output[:2000],
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
)
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
if __name__ == "__main__":
|
|
49
|
+
main()
|