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,36 @@
|
|
|
1
|
+
"""Handlers CLI para ciclo de vida de sesiones."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def parse_session_resources(args: argparse.Namespace) -> tuple[list | None, list | None]:
|
|
10
|
+
skills = [s.strip() for s in args.skills.split(",")] if args.skills else None
|
|
11
|
+
subagents = [sa.strip() for sa in args.subagents.split(",")] if args.subagents else None
|
|
12
|
+
return skills, subagents
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def start_session(
|
|
16
|
+
nexus,
|
|
17
|
+
session_mgr,
|
|
18
|
+
args: argparse.Namespace,
|
|
19
|
+
default_profile: str,
|
|
20
|
+
default_assistant: str,
|
|
21
|
+
) -> None:
|
|
22
|
+
profile = args.profile or default_profile
|
|
23
|
+
assistant = args.assistant or default_assistant
|
|
24
|
+
skills, subagents = parse_session_resources(args)
|
|
25
|
+
session_mgr.start_session(profile, assistant, skills, subagents)
|
|
26
|
+
nexus.load_agent_profile(profile, assistant)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def dispatch_session(nexus, args: argparse.Namespace, root_dir: Path, session_manager_cls) -> None:
|
|
30
|
+
session_mgr = session_manager_cls(Path.cwd(), root_dir)
|
|
31
|
+
assistant, profile = session_mgr.get_assistant_and_profile()
|
|
32
|
+
if args.action == "start":
|
|
33
|
+
start_session(nexus, session_mgr, args, profile, assistant)
|
|
34
|
+
elif args.action == "clean":
|
|
35
|
+
session_mgr.clean_session()
|
|
36
|
+
nexus.load_agent_profile(profile, assistant)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Handlers CLI para ejecución de tareas/capacidades."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
|
|
7
|
+
from higpertext.kernel.infrastructure.cli.arguments import parse_kv_args, pop_bool_flag
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def dispatch_task(nexus, args: argparse.Namespace) -> None:
|
|
11
|
+
task_args = list(args.task_args) if args.task_args else []
|
|
12
|
+
no_cache = getattr(args, "no_cache", False)
|
|
13
|
+
stream = getattr(args, "stream", False)
|
|
14
|
+
|
|
15
|
+
no_cache, task_args = pop_bool_flag(task_args, "--no-cache", no_cache)
|
|
16
|
+
stream, task_args = pop_bool_flag(task_args, "--stream", stream)
|
|
17
|
+
|
|
18
|
+
nexus.run_task(
|
|
19
|
+
args.name,
|
|
20
|
+
parse_kv_args(task_args),
|
|
21
|
+
stream=stream,
|
|
22
|
+
no_cache=no_cache,
|
|
23
|
+
)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""Presentación de resultados de tareas/capacidades."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
# Solo tipado de CompletedProcess.
|
|
6
|
+
import subprocess # nosec B404
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def build_memory_notes(
|
|
10
|
+
task_name: str,
|
|
11
|
+
params: dict,
|
|
12
|
+
result: subprocess.CompletedProcess,
|
|
13
|
+
contract_success: bool,
|
|
14
|
+
contract_errors: list,
|
|
15
|
+
) -> str:
|
|
16
|
+
notes = f"Ejecución de {task_name} con params: {params}"
|
|
17
|
+
if not contract_success:
|
|
18
|
+
notes += f" | Falló Contrato: {', '.join(contract_errors)}"
|
|
19
|
+
elif result.stdout:
|
|
20
|
+
notes += f" | OUT: {result.stdout[:150].strip()}"
|
|
21
|
+
if result.stderr:
|
|
22
|
+
notes += f" | ERR: {result.stderr[:150].strip()}"
|
|
23
|
+
return notes.replace("\n", " ").replace("\r", "")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def print_task_failure(
|
|
27
|
+
task_name: str,
|
|
28
|
+
result: subprocess.CompletedProcess,
|
|
29
|
+
contract_success: bool,
|
|
30
|
+
contract_errors: list,
|
|
31
|
+
logger,
|
|
32
|
+
) -> None:
|
|
33
|
+
if not contract_success:
|
|
34
|
+
logger.error(f"[ERROR] Falló la validación del contrato técnico para '{task_name}':")
|
|
35
|
+
for error in contract_errors:
|
|
36
|
+
logger.info(f" - [CONTRATO] {error}")
|
|
37
|
+
else:
|
|
38
|
+
logger.error(f"[ERROR] Falló la ejecución:\n{result.stderr}")
|
|
39
|
+
if result.stdout:
|
|
40
|
+
logger.info(f"Detalles (stdout):\n{result.stdout[:500]}")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def report_task_result(
|
|
44
|
+
task_name: str,
|
|
45
|
+
result: subprocess.CompletedProcess,
|
|
46
|
+
contract_success: bool,
|
|
47
|
+
contract_errors: list,
|
|
48
|
+
logger,
|
|
49
|
+
) -> bool:
|
|
50
|
+
if result.returncode == 0 and contract_success:
|
|
51
|
+
logger.ok("[SUCCESS] Tarea completada y contrato técnico validado.")
|
|
52
|
+
if result.stdout:
|
|
53
|
+
logger.info(result.stdout)
|
|
54
|
+
return True
|
|
55
|
+
print_task_failure(task_name, result, contract_success, contract_errors, logger)
|
|
56
|
+
return False
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Handlers CLI para workflows."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
|
|
7
|
+
from higpertext.kernel.infrastructure.cli.arguments import parse_kv_args
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def dispatch_workflow(nexus, args: argparse.Namespace) -> None:
|
|
11
|
+
if args.workflow_action == "run":
|
|
12
|
+
nexus.run_workflow(args.name, parse_kv_args(args.wf_args))
|
|
13
|
+
else:
|
|
14
|
+
nexus.list_workflows_cli()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def resolve_workflow_params(workflow: dict, cli_params: dict) -> dict:
|
|
18
|
+
params: dict = {}
|
|
19
|
+
for parameter in workflow.get("parameters", []):
|
|
20
|
+
name = parameter.get("name")
|
|
21
|
+
params[name] = cli_params.get(name, parameter.get("default", ""))
|
|
22
|
+
for key, value in cli_params.items():
|
|
23
|
+
if key not in params:
|
|
24
|
+
params[key] = value
|
|
25
|
+
return params
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from higpertext.kernel.domain.compilers import ICompiler
|
|
3
|
+
from higpertext.kernel.infrastructure.compilers.hook_compiler import HookCompiler
|
|
4
|
+
from higpertext.kernel.infrastructure.compilers.playbook_compiler import PlaybookCompiler
|
|
5
|
+
from higpertext.kernel.infrastructure.compilers.guide_compiler import GuideCompiler
|
|
6
|
+
from higpertext.kernel.infrastructure.compilers.graph_compiler import GraphCompiler
|
|
7
|
+
|
|
8
|
+
class CompilerFactory:
|
|
9
|
+
@staticmethod
|
|
10
|
+
def create(activity_type: str, project_root: Path, engine_root: Path = None, pkg_data_dir: Path = None, engine = None) -> ICompiler:
|
|
11
|
+
"""Fabrica el compilador correspondiente según el tipo de actividad."""
|
|
12
|
+
if activity_type == "hook":
|
|
13
|
+
if not pkg_data_dir:
|
|
14
|
+
raise ValueError("pkg_data_dir is required for hook compiler")
|
|
15
|
+
return HookCompiler(project_root, pkg_data_dir)
|
|
16
|
+
elif activity_type == "playbook":
|
|
17
|
+
if not engine_root or not pkg_data_dir or not engine:
|
|
18
|
+
raise ValueError("engine_root, pkg_data_dir, and engine are required for playbook compiler")
|
|
19
|
+
return PlaybookCompiler(project_root, engine_root, pkg_data_dir, engine)
|
|
20
|
+
elif activity_type == "guide":
|
|
21
|
+
if not engine:
|
|
22
|
+
raise ValueError("engine is required for guide compiler")
|
|
23
|
+
return GuideCompiler(project_root, engine)
|
|
24
|
+
elif activity_type == "graph":
|
|
25
|
+
return GraphCompiler(project_root)
|
|
26
|
+
else:
|
|
27
|
+
raise ValueError(f"Unknown compiler activity type: {activity_type}")
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from higpertext.kernel.domain.compilers import ICompiler
|
|
3
|
+
from higpertext.kernel.infrastructure.logger import get_logger
|
|
4
|
+
_log = get_logger()
|
|
5
|
+
|
|
6
|
+
class GraphCompiler(ICompiler):
|
|
7
|
+
def __init__(self, project_root: Path):
|
|
8
|
+
self.project_root = project_root
|
|
9
|
+
|
|
10
|
+
def compile(self) -> bool:
|
|
11
|
+
"""Genera el grafo semántico inicial."""
|
|
12
|
+
try:
|
|
13
|
+
from higpertext.kernel.infrastructure.parser.semantic_graph import SemanticGraphGenerator
|
|
14
|
+
_log.info("[*] Generando grafo semántico inicial...")
|
|
15
|
+
SemanticGraphGenerator.generate(self.project_root)
|
|
16
|
+
_log.ok("[SUCCESS] Grafo semántico generado en .higpertext/state/semantic_graph.md")
|
|
17
|
+
return True
|
|
18
|
+
except Exception as e:
|
|
19
|
+
_log.warning(f"[WARNING] No se pudo generar el grafo semántico: {e}")
|
|
20
|
+
return False
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from higpertext.kernel.domain.compilers import ICompiler
|
|
3
|
+
from higpertext.kernel.infrastructure.logger import get_logger
|
|
4
|
+
_log = get_logger()
|
|
5
|
+
|
|
6
|
+
class GuideCompiler(ICompiler):
|
|
7
|
+
def __init__(self, target_path: Path, engine):
|
|
8
|
+
self.target_path = target_path
|
|
9
|
+
self.engine = engine
|
|
10
|
+
|
|
11
|
+
def compile(self, assistant: str) -> bool:
|
|
12
|
+
"""Genera la guía del asistente con capacidades globales."""
|
|
13
|
+
try:
|
|
14
|
+
try:
|
|
15
|
+
global_ctx = self.engine.get_agent_context("global")
|
|
16
|
+
guide_caps = global_ctx.get("active_capabilities", [])
|
|
17
|
+
except (OSError, KeyError):
|
|
18
|
+
guide_caps = []
|
|
19
|
+
|
|
20
|
+
from higpertext.kernel.infrastructure.cli.router import _GUIDE_SPECS
|
|
21
|
+
spec = _GUIDE_SPECS.get(assistant)
|
|
22
|
+
if not spec:
|
|
23
|
+
return False
|
|
24
|
+
|
|
25
|
+
rel_path, title, intro = spec
|
|
26
|
+
guide_file = self.target_path / rel_path
|
|
27
|
+
guide_file.parent.mkdir(parents=True, exist_ok=True)
|
|
28
|
+
self._write_md_guide(guide_file, title, intro, guide_caps)
|
|
29
|
+
return True
|
|
30
|
+
except Exception as e:
|
|
31
|
+
_log.warning(f"[!] Error generando guía de usuario: {e}")
|
|
32
|
+
return False
|
|
33
|
+
|
|
34
|
+
def _write_md_guide(
|
|
35
|
+
self, file_path: Path, title: str, intro_lines: list[str], capabilities: list
|
|
36
|
+
) -> None:
|
|
37
|
+
from higpertext.kernel.infrastructure.cli.router import _PROFILES_SECTION, _RULES_SECTION
|
|
38
|
+
content = [title] + intro_lines + _PROFILES_SECTION + _RULES_SECTION
|
|
39
|
+
content.append("\n## 🛠️ Comandos y Herramientas a Integrar")
|
|
40
|
+
for cap in capabilities:
|
|
41
|
+
short_id = cap["id"].split(".")[-1]
|
|
42
|
+
content += [
|
|
43
|
+
f"### {cap['id']}",
|
|
44
|
+
f"- **Propósito**: {cap.get('description', '')}",
|
|
45
|
+
f"- **Comando Base**: `htx task {short_id} [argumentos_aqui]`",
|
|
46
|
+
"- **Notas de Integración**: *(Espacio para documentar parámetros específicos del proyecto)*\n",
|
|
47
|
+
]
|
|
48
|
+
content.append("\n---\n*higpertext Engine Framework - Automated Agent Configuration.*")
|
|
49
|
+
file_path.write_text("\n".join(content), encoding="utf-8")
|
|
50
|
+
_log.ok("[SUCCESS] Guía generada: " f"{file_path.relative_to(file_path.parent.parent)}")
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import json
|
|
3
|
+
from higpertext.kernel.domain.compilers import ICompiler
|
|
4
|
+
from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
|
|
5
|
+
from higpertext.kernel.infrastructure.logger import get_logger
|
|
6
|
+
_log = get_logger()
|
|
7
|
+
|
|
8
|
+
class HookCompiler(ICompiler):
|
|
9
|
+
def __init__(self, project_root: Path, pkg_data_dir: Path):
|
|
10
|
+
self.project_root = project_root
|
|
11
|
+
self.pkg_data_dir = pkg_data_dir
|
|
12
|
+
|
|
13
|
+
def compile(self, profile_name: str, assistant: str | None = None, context: dict | None = None) -> bool:
|
|
14
|
+
"""Compila las capas de hooks y renderiza la configuración nativa del asistente."""
|
|
15
|
+
try:
|
|
16
|
+
if assistant and context:
|
|
17
|
+
from higpertext.kernel.application.skill_hook_compiler import SkillHookCompiler
|
|
18
|
+
cap_ids = [c["id"] for c in context.get("active_capabilities", [])]
|
|
19
|
+
SkillHookCompiler(self.project_root).compile(profile_name, cap_ids)
|
|
20
|
+
|
|
21
|
+
# Compilar capas de hooks
|
|
22
|
+
self._compile_hook_layers(profile_name)
|
|
23
|
+
|
|
24
|
+
if assistant and context:
|
|
25
|
+
from higpertext.kernel.application.hook_renderer import HookRenderer
|
|
26
|
+
HookRenderer(self.project_root).render(assistant, profile_name)
|
|
27
|
+
return True
|
|
28
|
+
except Exception as e:
|
|
29
|
+
_log.warning(f"[WARNING] Falló compilación de hooks: {e}")
|
|
30
|
+
return False
|
|
31
|
+
|
|
32
|
+
def _compile_hook_layers(self, profile_name: str) -> None:
|
|
33
|
+
engine_src = self.pkg_data_dir / "config" / "hooks"
|
|
34
|
+
agent_src = self.project_root / "src" / "config" / "hooks"
|
|
35
|
+
layers = [
|
|
36
|
+
("global", engine_src / "global"),
|
|
37
|
+
("profile", engine_src / "profiles" / profile_name),
|
|
38
|
+
("profile_local", agent_src / "profiles" / profile_name),
|
|
39
|
+
("custom", agent_src / "custom"),
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
compiled: list[dict] = []
|
|
43
|
+
for layer_name, layer_path in layers:
|
|
44
|
+
if not layer_path.exists():
|
|
45
|
+
continue
|
|
46
|
+
for hook_file in sorted(layer_path.glob("*.json")):
|
|
47
|
+
try:
|
|
48
|
+
hook_data = json.loads(hook_file.read_text(encoding="utf-8"))
|
|
49
|
+
hook_data["_layer"] = layer_name
|
|
50
|
+
hook_data["_source"] = hook_file.as_posix()
|
|
51
|
+
if "script" in hook_data:
|
|
52
|
+
hook_data["script"] = str(Path(hook_data["script"]))
|
|
53
|
+
compiled.append(hook_data)
|
|
54
|
+
except (OSError, json.JSONDecodeError) as e:
|
|
55
|
+
_log.warning(f"[WARNING] Hook ignorado {hook_file.name}: {e}")
|
|
56
|
+
|
|
57
|
+
out_dir = self.project_root / WORKSPACE_DIR_NAME / "config"
|
|
58
|
+
out_dir.mkdir(parents=True, exist_ok=True)
|
|
59
|
+
out_file = out_dir / "hooks_config.json"
|
|
60
|
+
existing: dict = {}
|
|
61
|
+
if out_file.exists():
|
|
62
|
+
try:
|
|
63
|
+
existing = json.loads(out_file.read_text(encoding="utf-8"))
|
|
64
|
+
except (OSError, json.JSONDecodeError):
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
existing["agent_hooks"] = compiled
|
|
68
|
+
out_file.write_text(json.dumps(existing, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
69
|
+
_log.info(f"[*] Hooks compilados ({len(compiled)} entradas) en: {out_file}")
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import json
|
|
3
|
+
import shutil
|
|
4
|
+
from higpertext.kernel.domain.compilers import ICompiler
|
|
5
|
+
from higpertext.kernel.config_paths import WORKSPACE_DIR_NAME
|
|
6
|
+
from higpertext.kernel.infrastructure.logger import get_logger
|
|
7
|
+
_log = get_logger()
|
|
8
|
+
|
|
9
|
+
class PlaybookCompiler(ICompiler):
|
|
10
|
+
def __init__(self, project_root: Path, engine_root: Path, pkg_data_dir: Path, engine):
|
|
11
|
+
self.project_root = project_root
|
|
12
|
+
self.engine_root = engine_root
|
|
13
|
+
self.pkg_data_dir = pkg_data_dir
|
|
14
|
+
self.engine = engine
|
|
15
|
+
|
|
16
|
+
def compile(self, assistant: str, copy_resources: bool = True) -> bool:
|
|
17
|
+
"""Genera los playbooks primarios adaptados al asistente."""
|
|
18
|
+
try:
|
|
19
|
+
has_session, session_id = self._read_session_state()
|
|
20
|
+
from higpertext.kernel.session_manager import SessionManager
|
|
21
|
+
session_mgr = SessionManager(self.project_root, self.engine_root)
|
|
22
|
+
wf_dest, sk_dest, sa_dest = session_mgr.get_paths(assistant)
|
|
23
|
+
|
|
24
|
+
if not has_session:
|
|
25
|
+
for d in (sk_dest, sa_dest):
|
|
26
|
+
if d.exists():
|
|
27
|
+
try:
|
|
28
|
+
shutil.rmtree(d)
|
|
29
|
+
except OSError:
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
from higpertext.kernel.infrastructure.cli.router import _ASSISTANT_IGNORE, _IGNORE_CONTENT
|
|
33
|
+
for ignore_name in _ASSISTANT_IGNORE.get(assistant, ()):
|
|
34
|
+
(self.project_root / ignore_name).write_text(_IGNORE_CONTENT, encoding="utf-8")
|
|
35
|
+
|
|
36
|
+
skills_str, subs_str = self._build_playbook_strings(
|
|
37
|
+
has_session, session_id, sk_dest, sa_dest
|
|
38
|
+
)
|
|
39
|
+
self._write_playbooks(
|
|
40
|
+
session_mgr,
|
|
41
|
+
wf_dest,
|
|
42
|
+
skills_str,
|
|
43
|
+
subs_str,
|
|
44
|
+
has_session,
|
|
45
|
+
session_id,
|
|
46
|
+
assistant,
|
|
47
|
+
)
|
|
48
|
+
_log.info(f"[*] Workflows generados dinámicamente en: {wf_dest}")
|
|
49
|
+
return True
|
|
50
|
+
except Exception as e:
|
|
51
|
+
_log.warning(f"[!] Error compilando playbooks: {e}")
|
|
52
|
+
return False
|
|
53
|
+
|
|
54
|
+
def _read_session_state(self) -> tuple[bool, str | None]:
|
|
55
|
+
session_file = self.project_root / WORKSPACE_DIR_NAME / "state" / "session.json"
|
|
56
|
+
if not session_file.exists():
|
|
57
|
+
return False, None
|
|
58
|
+
try:
|
|
59
|
+
data = json.loads(session_file.read_text(encoding="utf-8"))
|
|
60
|
+
if data.get("status") == "active":
|
|
61
|
+
return True, data.get("session_id")
|
|
62
|
+
except (OSError, json.JSONDecodeError):
|
|
63
|
+
pass
|
|
64
|
+
return False, None
|
|
65
|
+
|
|
66
|
+
def _collect_skill_links(self, skills_dest: Path) -> list[str]:
|
|
67
|
+
if not skills_dest.exists():
|
|
68
|
+
return []
|
|
69
|
+
links = []
|
|
70
|
+
for item in sorted(skills_dest.iterdir()):
|
|
71
|
+
if not item.is_dir():
|
|
72
|
+
continue
|
|
73
|
+
try:
|
|
74
|
+
rel = item.relative_to(self.project_root).as_posix()
|
|
75
|
+
links.append(f"- [{item.name}](file:///{rel}/SKILL.md)")
|
|
76
|
+
except ValueError:
|
|
77
|
+
links.append(f"- `{item.name}`")
|
|
78
|
+
return links
|
|
79
|
+
|
|
80
|
+
def _collect_subagent_links(self, subagents_dest: Path) -> list[str]:
|
|
81
|
+
if not subagents_dest.exists():
|
|
82
|
+
return []
|
|
83
|
+
links = []
|
|
84
|
+
for item in sorted(subagents_dest.glob("*.md")):
|
|
85
|
+
try:
|
|
86
|
+
rel = item.relative_to(self.project_root).as_posix()
|
|
87
|
+
links.append(f"- [{item.stem}](file:///{rel})")
|
|
88
|
+
except ValueError:
|
|
89
|
+
links.append(f"- `{item.stem}`")
|
|
90
|
+
return links
|
|
91
|
+
|
|
92
|
+
def _build_playbook_strings(
|
|
93
|
+
self,
|
|
94
|
+
has_session: bool,
|
|
95
|
+
session_id: str | None,
|
|
96
|
+
skills_dest: Path,
|
|
97
|
+
subagents_dest: Path,
|
|
98
|
+
) -> tuple[str, str]:
|
|
99
|
+
if has_session:
|
|
100
|
+
sk = self._collect_skill_links(skills_dest)
|
|
101
|
+
sa = self._collect_subagent_links(subagents_dest)
|
|
102
|
+
skills_str = "\n".join(sk) if sk else "- `00-quick-reference`"
|
|
103
|
+
subs_str = "\n".join(sa) if sa else "- `research`"
|
|
104
|
+
else:
|
|
105
|
+
skills_str = "_No active session — run `session-start` to mount skills._"
|
|
106
|
+
subs_str = "_No active session — run `session-start` to mount subagents._"
|
|
107
|
+
return skills_str, subs_str
|
|
108
|
+
|
|
109
|
+
def _write_playbooks(
|
|
110
|
+
self,
|
|
111
|
+
session_mgr,
|
|
112
|
+
workflows_dest: Path,
|
|
113
|
+
skills_str: str,
|
|
114
|
+
subs_str: str,
|
|
115
|
+
has_session: bool,
|
|
116
|
+
session_id: str | None,
|
|
117
|
+
assistant: str,
|
|
118
|
+
) -> None:
|
|
119
|
+
tmpl_dir = self.pkg_data_dir / "higpertext" / "templates" / "workflows"
|
|
120
|
+
workflows_dest.mkdir(parents=True, exist_ok=True)
|
|
121
|
+
for stale in workflows_dest.glob("*.md"):
|
|
122
|
+
try:
|
|
123
|
+
stale.unlink()
|
|
124
|
+
except OSError:
|
|
125
|
+
pass
|
|
126
|
+
session_block = (
|
|
127
|
+
(f"\n# Session Info\n- **Session ID**: `{session_id}`\n- **Status**: `active`")
|
|
128
|
+
if (has_session and session_id)
|
|
129
|
+
else ""
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
for name in ("spec", "plan", "build", "review"):
|
|
133
|
+
src = tmpl_dir / f"{name}.json"
|
|
134
|
+
if not src.exists():
|
|
135
|
+
continue
|
|
136
|
+
try:
|
|
137
|
+
data = json.loads(src.read_text(encoding="utf-8"))
|
|
138
|
+
profile_model = session_mgr.get_model(assistant)
|
|
139
|
+
try:
|
|
140
|
+
_, active_profile = session_mgr.get_assistant_and_profile()
|
|
141
|
+
profile_data = self.engine.profiles.load_profile(active_profile)
|
|
142
|
+
if profile_data and "model" in profile_data:
|
|
143
|
+
profile_model = profile_data["model"]
|
|
144
|
+
except Exception as exc:
|
|
145
|
+
_log.warning(f"[!] Modelo de perfil activo no disponible: {exc}")
|
|
146
|
+
|
|
147
|
+
content = session_mgr._generate_workflow_base_md(data, assistant, profile_model)
|
|
148
|
+
content = content.replace("{required_skills_str}", skills_str)
|
|
149
|
+
content = content.replace("{related_subagents_str}", subs_str)
|
|
150
|
+
content += session_block
|
|
151
|
+
|
|
152
|
+
(workflows_dest / f"{name}.md").write_text(content, encoding="utf-8")
|
|
153
|
+
except (OSError, json.JSONDecodeError) as e:
|
|
154
|
+
_log.warning(f"[!] Error compilando playbook '{name}': {e}")
|