gobby 0.2.5__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.
- gobby/__init__.py +3 -0
- gobby/adapters/__init__.py +30 -0
- gobby/adapters/base.py +93 -0
- gobby/adapters/claude_code.py +276 -0
- gobby/adapters/codex.py +1292 -0
- gobby/adapters/gemini.py +343 -0
- gobby/agents/__init__.py +37 -0
- gobby/agents/codex_session.py +120 -0
- gobby/agents/constants.py +112 -0
- gobby/agents/context.py +362 -0
- gobby/agents/definitions.py +133 -0
- gobby/agents/gemini_session.py +111 -0
- gobby/agents/registry.py +618 -0
- gobby/agents/runner.py +968 -0
- gobby/agents/session.py +259 -0
- gobby/agents/spawn.py +916 -0
- gobby/agents/spawners/__init__.py +77 -0
- gobby/agents/spawners/base.py +142 -0
- gobby/agents/spawners/cross_platform.py +266 -0
- gobby/agents/spawners/embedded.py +225 -0
- gobby/agents/spawners/headless.py +226 -0
- gobby/agents/spawners/linux.py +125 -0
- gobby/agents/spawners/macos.py +277 -0
- gobby/agents/spawners/windows.py +308 -0
- gobby/agents/tty_config.py +319 -0
- gobby/autonomous/__init__.py +32 -0
- gobby/autonomous/progress_tracker.py +447 -0
- gobby/autonomous/stop_registry.py +269 -0
- gobby/autonomous/stuck_detector.py +383 -0
- gobby/cli/__init__.py +67 -0
- gobby/cli/__main__.py +8 -0
- gobby/cli/agents.py +529 -0
- gobby/cli/artifacts.py +266 -0
- gobby/cli/daemon.py +329 -0
- gobby/cli/extensions.py +526 -0
- gobby/cli/github.py +263 -0
- gobby/cli/init.py +53 -0
- gobby/cli/install.py +614 -0
- gobby/cli/installers/__init__.py +37 -0
- gobby/cli/installers/antigravity.py +65 -0
- gobby/cli/installers/claude.py +363 -0
- gobby/cli/installers/codex.py +192 -0
- gobby/cli/installers/gemini.py +294 -0
- gobby/cli/installers/git_hooks.py +377 -0
- gobby/cli/installers/shared.py +737 -0
- gobby/cli/linear.py +250 -0
- gobby/cli/mcp.py +30 -0
- gobby/cli/mcp_proxy.py +698 -0
- gobby/cli/memory.py +304 -0
- gobby/cli/merge.py +384 -0
- gobby/cli/projects.py +79 -0
- gobby/cli/sessions.py +622 -0
- gobby/cli/tasks/__init__.py +30 -0
- gobby/cli/tasks/_utils.py +658 -0
- gobby/cli/tasks/ai.py +1025 -0
- gobby/cli/tasks/commits.py +169 -0
- gobby/cli/tasks/crud.py +685 -0
- gobby/cli/tasks/deps.py +135 -0
- gobby/cli/tasks/labels.py +63 -0
- gobby/cli/tasks/main.py +273 -0
- gobby/cli/tasks/search.py +178 -0
- gobby/cli/tui.py +34 -0
- gobby/cli/utils.py +513 -0
- gobby/cli/workflows.py +927 -0
- gobby/cli/worktrees.py +481 -0
- gobby/config/__init__.py +129 -0
- gobby/config/app.py +551 -0
- gobby/config/extensions.py +167 -0
- gobby/config/features.py +472 -0
- gobby/config/llm_providers.py +98 -0
- gobby/config/logging.py +66 -0
- gobby/config/mcp.py +346 -0
- gobby/config/persistence.py +247 -0
- gobby/config/servers.py +141 -0
- gobby/config/sessions.py +250 -0
- gobby/config/tasks.py +784 -0
- gobby/hooks/__init__.py +104 -0
- gobby/hooks/artifact_capture.py +213 -0
- gobby/hooks/broadcaster.py +243 -0
- gobby/hooks/event_handlers.py +723 -0
- gobby/hooks/events.py +218 -0
- gobby/hooks/git.py +169 -0
- gobby/hooks/health_monitor.py +171 -0
- gobby/hooks/hook_manager.py +856 -0
- gobby/hooks/hook_types.py +575 -0
- gobby/hooks/plugins.py +813 -0
- gobby/hooks/session_coordinator.py +396 -0
- gobby/hooks/verification_runner.py +268 -0
- gobby/hooks/webhooks.py +339 -0
- gobby/install/claude/commands/gobby/bug.md +51 -0
- gobby/install/claude/commands/gobby/chore.md +51 -0
- gobby/install/claude/commands/gobby/epic.md +52 -0
- gobby/install/claude/commands/gobby/eval.md +235 -0
- gobby/install/claude/commands/gobby/feat.md +49 -0
- gobby/install/claude/commands/gobby/nit.md +52 -0
- gobby/install/claude/commands/gobby/ref.md +52 -0
- gobby/install/claude/hooks/HOOK_SCHEMAS.md +632 -0
- gobby/install/claude/hooks/hook_dispatcher.py +364 -0
- gobby/install/claude/hooks/validate_settings.py +102 -0
- gobby/install/claude/hooks-template.json +118 -0
- gobby/install/codex/hooks/hook_dispatcher.py +153 -0
- gobby/install/codex/prompts/forget.md +7 -0
- gobby/install/codex/prompts/memories.md +7 -0
- gobby/install/codex/prompts/recall.md +7 -0
- gobby/install/codex/prompts/remember.md +13 -0
- gobby/install/gemini/hooks/hook_dispatcher.py +268 -0
- gobby/install/gemini/hooks-template.json +138 -0
- gobby/install/shared/plugins/code_guardian.py +456 -0
- gobby/install/shared/plugins/example_notify.py +331 -0
- gobby/integrations/__init__.py +10 -0
- gobby/integrations/github.py +145 -0
- gobby/integrations/linear.py +145 -0
- gobby/llm/__init__.py +40 -0
- gobby/llm/base.py +120 -0
- gobby/llm/claude.py +578 -0
- gobby/llm/claude_executor.py +503 -0
- gobby/llm/codex.py +322 -0
- gobby/llm/codex_executor.py +513 -0
- gobby/llm/executor.py +316 -0
- gobby/llm/factory.py +34 -0
- gobby/llm/gemini.py +258 -0
- gobby/llm/gemini_executor.py +339 -0
- gobby/llm/litellm.py +287 -0
- gobby/llm/litellm_executor.py +303 -0
- gobby/llm/resolver.py +499 -0
- gobby/llm/service.py +236 -0
- gobby/mcp_proxy/__init__.py +29 -0
- gobby/mcp_proxy/actions.py +175 -0
- gobby/mcp_proxy/daemon_control.py +198 -0
- gobby/mcp_proxy/importer.py +436 -0
- gobby/mcp_proxy/lazy.py +325 -0
- gobby/mcp_proxy/manager.py +798 -0
- gobby/mcp_proxy/metrics.py +609 -0
- gobby/mcp_proxy/models.py +139 -0
- gobby/mcp_proxy/registries.py +215 -0
- gobby/mcp_proxy/schema_hash.py +381 -0
- gobby/mcp_proxy/semantic_search.py +706 -0
- gobby/mcp_proxy/server.py +549 -0
- gobby/mcp_proxy/services/__init__.py +0 -0
- gobby/mcp_proxy/services/fallback.py +306 -0
- gobby/mcp_proxy/services/recommendation.py +224 -0
- gobby/mcp_proxy/services/server_mgmt.py +214 -0
- gobby/mcp_proxy/services/system.py +72 -0
- gobby/mcp_proxy/services/tool_filter.py +231 -0
- gobby/mcp_proxy/services/tool_proxy.py +309 -0
- gobby/mcp_proxy/stdio.py +565 -0
- gobby/mcp_proxy/tools/__init__.py +27 -0
- gobby/mcp_proxy/tools/agents.py +1103 -0
- gobby/mcp_proxy/tools/artifacts.py +207 -0
- gobby/mcp_proxy/tools/hub.py +335 -0
- gobby/mcp_proxy/tools/internal.py +337 -0
- gobby/mcp_proxy/tools/memory.py +543 -0
- gobby/mcp_proxy/tools/merge.py +422 -0
- gobby/mcp_proxy/tools/metrics.py +283 -0
- gobby/mcp_proxy/tools/orchestration/__init__.py +23 -0
- gobby/mcp_proxy/tools/orchestration/cleanup.py +619 -0
- gobby/mcp_proxy/tools/orchestration/monitor.py +380 -0
- gobby/mcp_proxy/tools/orchestration/orchestrate.py +746 -0
- gobby/mcp_proxy/tools/orchestration/review.py +736 -0
- gobby/mcp_proxy/tools/orchestration/utils.py +16 -0
- gobby/mcp_proxy/tools/session_messages.py +1056 -0
- gobby/mcp_proxy/tools/task_dependencies.py +219 -0
- gobby/mcp_proxy/tools/task_expansion.py +591 -0
- gobby/mcp_proxy/tools/task_github.py +393 -0
- gobby/mcp_proxy/tools/task_linear.py +379 -0
- gobby/mcp_proxy/tools/task_orchestration.py +77 -0
- gobby/mcp_proxy/tools/task_readiness.py +522 -0
- gobby/mcp_proxy/tools/task_sync.py +351 -0
- gobby/mcp_proxy/tools/task_validation.py +843 -0
- gobby/mcp_proxy/tools/tasks/__init__.py +25 -0
- gobby/mcp_proxy/tools/tasks/_context.py +112 -0
- gobby/mcp_proxy/tools/tasks/_crud.py +516 -0
- gobby/mcp_proxy/tools/tasks/_factory.py +176 -0
- gobby/mcp_proxy/tools/tasks/_helpers.py +129 -0
- gobby/mcp_proxy/tools/tasks/_lifecycle.py +517 -0
- gobby/mcp_proxy/tools/tasks/_lifecycle_validation.py +301 -0
- gobby/mcp_proxy/tools/tasks/_resolution.py +55 -0
- gobby/mcp_proxy/tools/tasks/_search.py +215 -0
- gobby/mcp_proxy/tools/tasks/_session.py +125 -0
- gobby/mcp_proxy/tools/workflows.py +973 -0
- gobby/mcp_proxy/tools/worktrees.py +1264 -0
- gobby/mcp_proxy/transports/__init__.py +0 -0
- gobby/mcp_proxy/transports/base.py +95 -0
- gobby/mcp_proxy/transports/factory.py +44 -0
- gobby/mcp_proxy/transports/http.py +139 -0
- gobby/mcp_proxy/transports/stdio.py +213 -0
- gobby/mcp_proxy/transports/websocket.py +136 -0
- gobby/memory/backends/__init__.py +116 -0
- gobby/memory/backends/mem0.py +408 -0
- gobby/memory/backends/memu.py +485 -0
- gobby/memory/backends/null.py +111 -0
- gobby/memory/backends/openmemory.py +537 -0
- gobby/memory/backends/sqlite.py +304 -0
- gobby/memory/context.py +87 -0
- gobby/memory/manager.py +1001 -0
- gobby/memory/protocol.py +451 -0
- gobby/memory/search/__init__.py +66 -0
- gobby/memory/search/text.py +127 -0
- gobby/memory/viz.py +258 -0
- gobby/prompts/__init__.py +13 -0
- gobby/prompts/defaults/expansion/system.md +119 -0
- gobby/prompts/defaults/expansion/user.md +48 -0
- gobby/prompts/defaults/external_validation/agent.md +72 -0
- gobby/prompts/defaults/external_validation/external.md +63 -0
- gobby/prompts/defaults/external_validation/spawn.md +83 -0
- gobby/prompts/defaults/external_validation/system.md +6 -0
- gobby/prompts/defaults/features/import_mcp.md +22 -0
- gobby/prompts/defaults/features/import_mcp_github.md +17 -0
- gobby/prompts/defaults/features/import_mcp_search.md +16 -0
- gobby/prompts/defaults/features/recommend_tools.md +32 -0
- gobby/prompts/defaults/features/recommend_tools_hybrid.md +35 -0
- gobby/prompts/defaults/features/recommend_tools_llm.md +30 -0
- gobby/prompts/defaults/features/server_description.md +20 -0
- gobby/prompts/defaults/features/server_description_system.md +6 -0
- gobby/prompts/defaults/features/task_description.md +31 -0
- gobby/prompts/defaults/features/task_description_system.md +6 -0
- gobby/prompts/defaults/features/tool_summary.md +17 -0
- gobby/prompts/defaults/features/tool_summary_system.md +6 -0
- gobby/prompts/defaults/research/step.md +58 -0
- gobby/prompts/defaults/validation/criteria.md +47 -0
- gobby/prompts/defaults/validation/validate.md +38 -0
- gobby/prompts/loader.py +346 -0
- gobby/prompts/models.py +113 -0
- gobby/py.typed +0 -0
- gobby/runner.py +488 -0
- gobby/search/__init__.py +23 -0
- gobby/search/protocol.py +104 -0
- gobby/search/tfidf.py +232 -0
- gobby/servers/__init__.py +7 -0
- gobby/servers/http.py +636 -0
- gobby/servers/models.py +31 -0
- gobby/servers/routes/__init__.py +23 -0
- gobby/servers/routes/admin.py +416 -0
- gobby/servers/routes/dependencies.py +118 -0
- gobby/servers/routes/mcp/__init__.py +24 -0
- gobby/servers/routes/mcp/hooks.py +135 -0
- gobby/servers/routes/mcp/plugins.py +121 -0
- gobby/servers/routes/mcp/tools.py +1337 -0
- gobby/servers/routes/mcp/webhooks.py +159 -0
- gobby/servers/routes/sessions.py +582 -0
- gobby/servers/websocket.py +766 -0
- gobby/sessions/__init__.py +13 -0
- gobby/sessions/analyzer.py +322 -0
- gobby/sessions/lifecycle.py +240 -0
- gobby/sessions/manager.py +563 -0
- gobby/sessions/processor.py +225 -0
- gobby/sessions/summary.py +532 -0
- gobby/sessions/transcripts/__init__.py +41 -0
- gobby/sessions/transcripts/base.py +125 -0
- gobby/sessions/transcripts/claude.py +386 -0
- gobby/sessions/transcripts/codex.py +143 -0
- gobby/sessions/transcripts/gemini.py +195 -0
- gobby/storage/__init__.py +21 -0
- gobby/storage/agents.py +409 -0
- gobby/storage/artifact_classifier.py +341 -0
- gobby/storage/artifacts.py +285 -0
- gobby/storage/compaction.py +67 -0
- gobby/storage/database.py +357 -0
- gobby/storage/inter_session_messages.py +194 -0
- gobby/storage/mcp.py +680 -0
- gobby/storage/memories.py +562 -0
- gobby/storage/merge_resolutions.py +550 -0
- gobby/storage/migrations.py +860 -0
- gobby/storage/migrations_legacy.py +1359 -0
- gobby/storage/projects.py +166 -0
- gobby/storage/session_messages.py +251 -0
- gobby/storage/session_tasks.py +97 -0
- gobby/storage/sessions.py +817 -0
- gobby/storage/task_dependencies.py +223 -0
- gobby/storage/tasks/__init__.py +42 -0
- gobby/storage/tasks/_aggregates.py +180 -0
- gobby/storage/tasks/_crud.py +449 -0
- gobby/storage/tasks/_id.py +104 -0
- gobby/storage/tasks/_lifecycle.py +311 -0
- gobby/storage/tasks/_manager.py +889 -0
- gobby/storage/tasks/_models.py +300 -0
- gobby/storage/tasks/_ordering.py +119 -0
- gobby/storage/tasks/_path_cache.py +110 -0
- gobby/storage/tasks/_queries.py +343 -0
- gobby/storage/tasks/_search.py +143 -0
- gobby/storage/workflow_audit.py +393 -0
- gobby/storage/worktrees.py +547 -0
- gobby/sync/__init__.py +29 -0
- gobby/sync/github.py +333 -0
- gobby/sync/linear.py +304 -0
- gobby/sync/memories.py +284 -0
- gobby/sync/tasks.py +641 -0
- gobby/tasks/__init__.py +8 -0
- gobby/tasks/build_verification.py +193 -0
- gobby/tasks/commits.py +633 -0
- gobby/tasks/context.py +747 -0
- gobby/tasks/criteria.py +342 -0
- gobby/tasks/enhanced_validator.py +226 -0
- gobby/tasks/escalation.py +263 -0
- gobby/tasks/expansion.py +626 -0
- gobby/tasks/external_validator.py +764 -0
- gobby/tasks/issue_extraction.py +171 -0
- gobby/tasks/prompts/expand.py +327 -0
- gobby/tasks/research.py +421 -0
- gobby/tasks/tdd.py +352 -0
- gobby/tasks/tree_builder.py +263 -0
- gobby/tasks/validation.py +712 -0
- gobby/tasks/validation_history.py +357 -0
- gobby/tasks/validation_models.py +89 -0
- gobby/tools/__init__.py +0 -0
- gobby/tools/summarizer.py +170 -0
- gobby/tui/__init__.py +5 -0
- gobby/tui/api_client.py +281 -0
- gobby/tui/app.py +327 -0
- gobby/tui/screens/__init__.py +25 -0
- gobby/tui/screens/agents.py +333 -0
- gobby/tui/screens/chat.py +450 -0
- gobby/tui/screens/dashboard.py +377 -0
- gobby/tui/screens/memory.py +305 -0
- gobby/tui/screens/metrics.py +231 -0
- gobby/tui/screens/orchestrator.py +904 -0
- gobby/tui/screens/sessions.py +412 -0
- gobby/tui/screens/tasks.py +442 -0
- gobby/tui/screens/workflows.py +289 -0
- gobby/tui/screens/worktrees.py +174 -0
- gobby/tui/widgets/__init__.py +21 -0
- gobby/tui/widgets/chat.py +210 -0
- gobby/tui/widgets/conductor.py +104 -0
- gobby/tui/widgets/menu.py +132 -0
- gobby/tui/widgets/message_panel.py +160 -0
- gobby/tui/widgets/review_gate.py +224 -0
- gobby/tui/widgets/task_tree.py +99 -0
- gobby/tui/widgets/token_budget.py +166 -0
- gobby/tui/ws_client.py +258 -0
- gobby/utils/__init__.py +3 -0
- gobby/utils/daemon_client.py +235 -0
- gobby/utils/git.py +222 -0
- gobby/utils/id.py +38 -0
- gobby/utils/json_helpers.py +161 -0
- gobby/utils/logging.py +376 -0
- gobby/utils/machine_id.py +135 -0
- gobby/utils/metrics.py +589 -0
- gobby/utils/project_context.py +182 -0
- gobby/utils/project_init.py +263 -0
- gobby/utils/status.py +256 -0
- gobby/utils/validation.py +80 -0
- gobby/utils/version.py +23 -0
- gobby/workflows/__init__.py +4 -0
- gobby/workflows/actions.py +1310 -0
- gobby/workflows/approval_flow.py +138 -0
- gobby/workflows/artifact_actions.py +103 -0
- gobby/workflows/audit_helpers.py +110 -0
- gobby/workflows/autonomous_actions.py +286 -0
- gobby/workflows/context_actions.py +394 -0
- gobby/workflows/definitions.py +130 -0
- gobby/workflows/detection_helpers.py +208 -0
- gobby/workflows/engine.py +485 -0
- gobby/workflows/evaluator.py +669 -0
- gobby/workflows/git_utils.py +96 -0
- gobby/workflows/hooks.py +169 -0
- gobby/workflows/lifecycle_evaluator.py +613 -0
- gobby/workflows/llm_actions.py +70 -0
- gobby/workflows/loader.py +333 -0
- gobby/workflows/mcp_actions.py +60 -0
- gobby/workflows/memory_actions.py +272 -0
- gobby/workflows/premature_stop.py +164 -0
- gobby/workflows/session_actions.py +139 -0
- gobby/workflows/state_actions.py +123 -0
- gobby/workflows/state_manager.py +104 -0
- gobby/workflows/stop_signal_actions.py +163 -0
- gobby/workflows/summary_actions.py +344 -0
- gobby/workflows/task_actions.py +249 -0
- gobby/workflows/task_enforcement_actions.py +901 -0
- gobby/workflows/templates.py +52 -0
- gobby/workflows/todo_actions.py +84 -0
- gobby/workflows/webhook.py +223 -0
- gobby/workflows/webhook_executor.py +399 -0
- gobby/worktrees/__init__.py +5 -0
- gobby/worktrees/git.py +690 -0
- gobby/worktrees/merge/__init__.py +20 -0
- gobby/worktrees/merge/conflict_parser.py +177 -0
- gobby/worktrees/merge/resolver.py +485 -0
- gobby-0.2.5.dist-info/METADATA +351 -0
- gobby-0.2.5.dist-info/RECORD +383 -0
- gobby-0.2.5.dist-info/WHEEL +5 -0
- gobby-0.2.5.dist-info/entry_points.txt +2 -0
- gobby-0.2.5.dist-info/licenses/LICENSE.md +193 -0
- gobby-0.2.5.dist-info/top_level.txt +1 -0
gobby/mcp_proxy/stdio.py
ADDED
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Stdio MCP server implementation.
|
|
3
|
+
|
|
4
|
+
This server runs as a stdio process for Claude Code and proxies
|
|
5
|
+
tool calls to the HTTP daemon.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import logging
|
|
10
|
+
import sys
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
import httpx
|
|
14
|
+
from mcp.server.fastmcp import FastMCP
|
|
15
|
+
|
|
16
|
+
from gobby.config.app import load_config
|
|
17
|
+
from gobby.mcp_proxy.daemon_control import (
|
|
18
|
+
check_daemon_http_health,
|
|
19
|
+
get_daemon_pid,
|
|
20
|
+
is_daemon_running,
|
|
21
|
+
restart_daemon_process,
|
|
22
|
+
start_daemon_process,
|
|
23
|
+
stop_daemon_process,
|
|
24
|
+
)
|
|
25
|
+
from gobby.mcp_proxy.registries import setup_internal_registries
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"create_stdio_mcp_server",
|
|
29
|
+
"check_daemon_http_health",
|
|
30
|
+
"get_daemon_pid",
|
|
31
|
+
"is_daemon_running",
|
|
32
|
+
"restart_daemon_process",
|
|
33
|
+
"start_daemon_process",
|
|
34
|
+
"stop_daemon_process",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
logger = logging.getLogger("gobby.mcp.stdio")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class DaemonProxy:
|
|
41
|
+
"""Proxy for HTTP daemon API calls."""
|
|
42
|
+
|
|
43
|
+
def __init__(self, port: int):
|
|
44
|
+
self.port = port
|
|
45
|
+
self.base_url = f"http://localhost:{port}"
|
|
46
|
+
|
|
47
|
+
async def _request(
|
|
48
|
+
self,
|
|
49
|
+
method: str,
|
|
50
|
+
path: str,
|
|
51
|
+
json: dict[str, Any] | None = None,
|
|
52
|
+
timeout: float = 30.0,
|
|
53
|
+
) -> dict[str, Any]:
|
|
54
|
+
"""Make HTTP request to daemon."""
|
|
55
|
+
try:
|
|
56
|
+
async with httpx.AsyncClient() as client:
|
|
57
|
+
resp = await client.request(
|
|
58
|
+
method,
|
|
59
|
+
f"{self.base_url}{path}",
|
|
60
|
+
json=json,
|
|
61
|
+
timeout=timeout,
|
|
62
|
+
)
|
|
63
|
+
if resp.status_code == 200:
|
|
64
|
+
data: dict[str, Any] = resp.json()
|
|
65
|
+
return data
|
|
66
|
+
else:
|
|
67
|
+
return {"success": False, "error": f"HTTP {resp.status_code}: {resp.text}"}
|
|
68
|
+
except httpx.ConnectError:
|
|
69
|
+
return {"success": False, "error": "Daemon not running or not reachable"}
|
|
70
|
+
except Exception as e:
|
|
71
|
+
error_msg = str(e) or f"{type(e).__name__}: (no message)"
|
|
72
|
+
return {"success": False, "error": error_msg}
|
|
73
|
+
|
|
74
|
+
async def get_status(self) -> dict[str, Any]:
|
|
75
|
+
"""Get daemon status."""
|
|
76
|
+
return await self._request("GET", "/admin/status")
|
|
77
|
+
|
|
78
|
+
async def list_tools(self, server: str | None = None) -> dict[str, Any]:
|
|
79
|
+
"""List tools from MCP servers."""
|
|
80
|
+
if server:
|
|
81
|
+
return await self._request("GET", f"/mcp/{server}/tools")
|
|
82
|
+
# List all - need to get server list first
|
|
83
|
+
status = await self.get_status()
|
|
84
|
+
if status.get("success") is False:
|
|
85
|
+
return status
|
|
86
|
+
servers = status.get("mcp_servers", {})
|
|
87
|
+
all_tools: dict[str, list[dict[str, Any]]] = {}
|
|
88
|
+
for srv_name in servers:
|
|
89
|
+
result = await self._request("GET", f"/mcp/{srv_name}/tools")
|
|
90
|
+
if result.get("success"):
|
|
91
|
+
all_tools[srv_name] = result.get("tools", [])
|
|
92
|
+
return {
|
|
93
|
+
"success": True,
|
|
94
|
+
"servers": [{"name": n, "tools": t} for n, t in all_tools.items()],
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async def call_tool(
|
|
98
|
+
self, server_name: str, tool_name: str, arguments: dict[str, Any] | None = None
|
|
99
|
+
) -> dict[str, Any]:
|
|
100
|
+
# Tool-specific timeouts
|
|
101
|
+
config = load_config()
|
|
102
|
+
# Default to standard timeout
|
|
103
|
+
timeout = 30.0
|
|
104
|
+
# Check for tool-specific override in config
|
|
105
|
+
if (
|
|
106
|
+
config.mcp_client_proxy.tool_timeouts
|
|
107
|
+
and tool_name in config.mcp_client_proxy.tool_timeouts
|
|
108
|
+
):
|
|
109
|
+
timeout = config.mcp_client_proxy.tool_timeouts[tool_name]
|
|
110
|
+
# Fallback for LLM-based task tools if not explicit in config
|
|
111
|
+
elif tool_name in (
|
|
112
|
+
"expand_task",
|
|
113
|
+
"apply_tdd",
|
|
114
|
+
"suggest_next_task",
|
|
115
|
+
"validate_task",
|
|
116
|
+
):
|
|
117
|
+
timeout = 300.0
|
|
118
|
+
|
|
119
|
+
return await self._request(
|
|
120
|
+
"POST",
|
|
121
|
+
f"/mcp/{server_name}/tools/{tool_name}",
|
|
122
|
+
json=arguments or {},
|
|
123
|
+
timeout=timeout,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
async def get_tool_schema(self, server_name: str, tool_name: str) -> dict[str, Any]:
|
|
127
|
+
"""Get schema for a specific tool."""
|
|
128
|
+
result = await self._request(
|
|
129
|
+
"POST",
|
|
130
|
+
"/mcp/tools/schema",
|
|
131
|
+
json={"server_name": server_name, "tool_name": tool_name},
|
|
132
|
+
)
|
|
133
|
+
if "error" in result:
|
|
134
|
+
return {"success": False, "error": result["error"]}
|
|
135
|
+
return {
|
|
136
|
+
"success": True,
|
|
137
|
+
"tool": {
|
|
138
|
+
"name": result.get("name"),
|
|
139
|
+
"description": result.get("description"),
|
|
140
|
+
"inputSchema": result.get("inputSchema"),
|
|
141
|
+
},
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async def list_mcp_servers(self) -> dict[str, Any]:
|
|
145
|
+
"""List configured MCP servers (includes internal gobby-* servers)."""
|
|
146
|
+
return await self._request("GET", "/mcp/servers")
|
|
147
|
+
|
|
148
|
+
async def recommend_tools(
|
|
149
|
+
self,
|
|
150
|
+
task_description: str,
|
|
151
|
+
agent_id: str | None = None,
|
|
152
|
+
search_mode: str = "llm",
|
|
153
|
+
top_k: int = 10,
|
|
154
|
+
min_similarity: float = 0.3,
|
|
155
|
+
cwd: str | None = None,
|
|
156
|
+
) -> dict[str, Any]:
|
|
157
|
+
"""Get tool recommendations for a task."""
|
|
158
|
+
return await self._request(
|
|
159
|
+
"POST",
|
|
160
|
+
"/mcp/tools/recommend",
|
|
161
|
+
json={
|
|
162
|
+
"task_description": task_description,
|
|
163
|
+
"agent_id": agent_id,
|
|
164
|
+
"search_mode": search_mode,
|
|
165
|
+
"top_k": top_k,
|
|
166
|
+
"min_similarity": min_similarity,
|
|
167
|
+
"cwd": cwd,
|
|
168
|
+
},
|
|
169
|
+
timeout=60.0,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
async def search_tools(
|
|
173
|
+
self,
|
|
174
|
+
query: str,
|
|
175
|
+
top_k: int = 10,
|
|
176
|
+
min_similarity: float = 0.0,
|
|
177
|
+
server: str | None = None,
|
|
178
|
+
cwd: str | None = None,
|
|
179
|
+
) -> dict[str, Any]:
|
|
180
|
+
"""Search for tools using semantic similarity."""
|
|
181
|
+
return await self._request(
|
|
182
|
+
"POST",
|
|
183
|
+
"/mcp/tools/search",
|
|
184
|
+
json={
|
|
185
|
+
"query": query,
|
|
186
|
+
"top_k": top_k,
|
|
187
|
+
"min_similarity": min_similarity,
|
|
188
|
+
"server": server,
|
|
189
|
+
"cwd": cwd,
|
|
190
|
+
},
|
|
191
|
+
timeout=60.0,
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
async def add_mcp_server(
|
|
195
|
+
self,
|
|
196
|
+
name: str,
|
|
197
|
+
transport: str,
|
|
198
|
+
url: str | None = None,
|
|
199
|
+
headers: dict[str, str] | None = None,
|
|
200
|
+
command: str | None = None,
|
|
201
|
+
args: list[str] | None = None,
|
|
202
|
+
env: dict[str, str] | None = None,
|
|
203
|
+
enabled: bool = True,
|
|
204
|
+
) -> dict[str, Any]:
|
|
205
|
+
"""Add a new MCP server to the daemon's configuration."""
|
|
206
|
+
return await self._request(
|
|
207
|
+
"POST",
|
|
208
|
+
"/mcp/servers",
|
|
209
|
+
json={
|
|
210
|
+
"name": name,
|
|
211
|
+
"transport": transport,
|
|
212
|
+
"url": url,
|
|
213
|
+
"headers": headers,
|
|
214
|
+
"command": command,
|
|
215
|
+
"args": args,
|
|
216
|
+
"env": env,
|
|
217
|
+
"enabled": enabled,
|
|
218
|
+
},
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
async def remove_mcp_server(self, name: str) -> dict[str, Any]:
|
|
222
|
+
"""Remove an MCP server from the daemon's configuration."""
|
|
223
|
+
return await self._request("DELETE", f"/mcp/servers/{name}")
|
|
224
|
+
|
|
225
|
+
async def import_mcp_server(
|
|
226
|
+
self,
|
|
227
|
+
from_project: str | None = None,
|
|
228
|
+
servers: list[str] | None = None,
|
|
229
|
+
github_url: str | None = None,
|
|
230
|
+
query: str | None = None,
|
|
231
|
+
) -> dict[str, Any]:
|
|
232
|
+
"""Import MCP servers from various sources."""
|
|
233
|
+
return await self._request(
|
|
234
|
+
"POST",
|
|
235
|
+
"/mcp/servers/import",
|
|
236
|
+
json={
|
|
237
|
+
"from_project": from_project,
|
|
238
|
+
"servers": servers,
|
|
239
|
+
"github_url": github_url,
|
|
240
|
+
"query": query,
|
|
241
|
+
},
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
async def init_project(
|
|
245
|
+
self, name: str | None = None, github_url: str | None = None
|
|
246
|
+
) -> dict[str, Any]:
|
|
247
|
+
"""Initialize a project - use 'gobby init' CLI command instead."""
|
|
248
|
+
return {
|
|
249
|
+
"success": False,
|
|
250
|
+
"error": "init_project requires CLI access. Run 'gobby init' from your terminal.",
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def create_stdio_mcp_server() -> FastMCP:
|
|
255
|
+
"""Create stdio MCP server."""
|
|
256
|
+
# Load configuration
|
|
257
|
+
config = load_config()
|
|
258
|
+
|
|
259
|
+
# Initialize basic managers (mocked/simplified for this refactor example)
|
|
260
|
+
session_manager = None
|
|
261
|
+
memory_manager = None
|
|
262
|
+
|
|
263
|
+
# Setup internal registries using extracted function
|
|
264
|
+
_ = setup_internal_registries(config, session_manager, memory_manager)
|
|
265
|
+
|
|
266
|
+
# Initialize MCP server and daemon proxy
|
|
267
|
+
mcp = FastMCP("gobby")
|
|
268
|
+
proxy = DaemonProxy(config.daemon_port)
|
|
269
|
+
|
|
270
|
+
register_proxy_tools(mcp, proxy)
|
|
271
|
+
|
|
272
|
+
return mcp
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def register_proxy_tools(mcp: FastMCP, proxy: DaemonProxy) -> None:
|
|
276
|
+
"""Register proxy tools on the MCP server."""
|
|
277
|
+
|
|
278
|
+
@mcp.tool()
|
|
279
|
+
async def list_mcp_servers() -> dict[str, Any]:
|
|
280
|
+
"""
|
|
281
|
+
List all MCP servers configured in the daemon.
|
|
282
|
+
|
|
283
|
+
Returns details about each MCP server including connection status,
|
|
284
|
+
available tools, and resources.
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
Dict with servers list, total count, and connected count
|
|
288
|
+
"""
|
|
289
|
+
return await proxy.list_mcp_servers()
|
|
290
|
+
|
|
291
|
+
@mcp.tool()
|
|
292
|
+
async def list_tools(server: str) -> dict[str, Any]:
|
|
293
|
+
"""
|
|
294
|
+
List tools from MCP servers.
|
|
295
|
+
|
|
296
|
+
Use this to discover tools available on servers.
|
|
297
|
+
|
|
298
|
+
Args:
|
|
299
|
+
server: Server name (e.g., "context7", "supabase").
|
|
300
|
+
Use list_mcp_servers() first to discover available servers.
|
|
301
|
+
|
|
302
|
+
Returns:
|
|
303
|
+
Dict with tool listings
|
|
304
|
+
"""
|
|
305
|
+
return await proxy.list_tools(server)
|
|
306
|
+
|
|
307
|
+
@mcp.tool()
|
|
308
|
+
async def get_tool_schema(server_name: str, tool_name: str) -> dict[str, Any]:
|
|
309
|
+
"""
|
|
310
|
+
Get full schema (inputSchema) for a specific MCP tool.
|
|
311
|
+
|
|
312
|
+
Use list_tools() first to discover available tools, then use this to get
|
|
313
|
+
full details before calling the tool.
|
|
314
|
+
|
|
315
|
+
Args:
|
|
316
|
+
server_name: Name of the MCP server (e.g., "context7", "supabase")
|
|
317
|
+
tool_name: Name of the tool (e.g., "get-library-docs", "list_tables")
|
|
318
|
+
|
|
319
|
+
Returns:
|
|
320
|
+
Dict with tool name, description, and full inputSchema
|
|
321
|
+
"""
|
|
322
|
+
return await proxy.get_tool_schema(server_name, tool_name)
|
|
323
|
+
|
|
324
|
+
@mcp.tool()
|
|
325
|
+
async def call_tool(
|
|
326
|
+
server_name: str,
|
|
327
|
+
tool_name: str,
|
|
328
|
+
arguments: dict[str, Any] | None = None,
|
|
329
|
+
) -> dict[str, Any]:
|
|
330
|
+
"""
|
|
331
|
+
Execute a tool on a connected MCP server.
|
|
332
|
+
|
|
333
|
+
This is the primary way to interact with MCP servers (Supabase, memory, etc.)
|
|
334
|
+
through the Gobby daemon.
|
|
335
|
+
|
|
336
|
+
Args:
|
|
337
|
+
server_name: Name of the MCP server
|
|
338
|
+
tool_name: Name of the specific tool to execute
|
|
339
|
+
arguments: Dictionary of arguments required by the tool (optional)
|
|
340
|
+
|
|
341
|
+
Returns:
|
|
342
|
+
Dictionary with success status and tool execution result
|
|
343
|
+
"""
|
|
344
|
+
return await proxy.call_tool(server_name, tool_name, arguments)
|
|
345
|
+
|
|
346
|
+
@mcp.tool()
|
|
347
|
+
async def recommend_tools(
|
|
348
|
+
task_description: str,
|
|
349
|
+
agent_id: str | None = None,
|
|
350
|
+
search_mode: str = "llm",
|
|
351
|
+
top_k: int = 10,
|
|
352
|
+
min_similarity: float = 0.3,
|
|
353
|
+
) -> dict[str, Any]:
|
|
354
|
+
"""
|
|
355
|
+
Get intelligent tool recommendations for a given task.
|
|
356
|
+
|
|
357
|
+
Args:
|
|
358
|
+
task_description: Description of what you're trying to accomplish
|
|
359
|
+
agent_id: Optional agent profile ID to filter tools by assigned permissions
|
|
360
|
+
search_mode: How to search - "llm" (default), "semantic", or "hybrid"
|
|
361
|
+
top_k: Maximum recommendations to return (semantic/hybrid modes)
|
|
362
|
+
min_similarity: Minimum similarity threshold (semantic/hybrid modes)
|
|
363
|
+
|
|
364
|
+
Returns:
|
|
365
|
+
Dict with tool recommendations and usage suggestions
|
|
366
|
+
"""
|
|
367
|
+
import os
|
|
368
|
+
|
|
369
|
+
cwd = os.getcwd()
|
|
370
|
+
return await proxy.recommend_tools(
|
|
371
|
+
task_description,
|
|
372
|
+
agent_id,
|
|
373
|
+
search_mode=search_mode,
|
|
374
|
+
top_k=top_k,
|
|
375
|
+
min_similarity=min_similarity,
|
|
376
|
+
cwd=cwd,
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
@mcp.tool()
|
|
380
|
+
async def search_tools(
|
|
381
|
+
query: str,
|
|
382
|
+
top_k: int = 10,
|
|
383
|
+
min_similarity: float = 0.0,
|
|
384
|
+
server: str | None = None,
|
|
385
|
+
) -> dict[str, Any]:
|
|
386
|
+
"""
|
|
387
|
+
Search for tools using semantic similarity.
|
|
388
|
+
|
|
389
|
+
Uses embedding-based search to find tools matching a natural language query.
|
|
390
|
+
Requires embeddings to be generated first (happens automatically on first search).
|
|
391
|
+
|
|
392
|
+
Args:
|
|
393
|
+
query: Natural language description of the tool you need
|
|
394
|
+
top_k: Maximum number of results to return (default: 10)
|
|
395
|
+
min_similarity: Minimum similarity threshold 0-1 (default: 0.0)
|
|
396
|
+
server: Optional server name to filter results
|
|
397
|
+
|
|
398
|
+
Returns:
|
|
399
|
+
Dict with matching tools sorted by similarity
|
|
400
|
+
"""
|
|
401
|
+
import os
|
|
402
|
+
|
|
403
|
+
cwd = os.getcwd()
|
|
404
|
+
return await proxy.search_tools(
|
|
405
|
+
query,
|
|
406
|
+
top_k=top_k,
|
|
407
|
+
min_similarity=min_similarity,
|
|
408
|
+
server=server,
|
|
409
|
+
cwd=cwd,
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
@mcp.tool()
|
|
413
|
+
async def init_project(
|
|
414
|
+
name: str | None = None, github_url: str | None = None
|
|
415
|
+
) -> dict[str, Any]:
|
|
416
|
+
"""
|
|
417
|
+
Initialize a new Gobby project in the current directory.
|
|
418
|
+
|
|
419
|
+
Args:
|
|
420
|
+
name: Optional project name (auto-detected from directory name if not provided)
|
|
421
|
+
github_url: Optional GitHub URL (auto-detected from git remote if not provided)
|
|
422
|
+
|
|
423
|
+
Returns:
|
|
424
|
+
Dict with success status and project details
|
|
425
|
+
"""
|
|
426
|
+
return await proxy.init_project(name, github_url)
|
|
427
|
+
|
|
428
|
+
@mcp.tool()
|
|
429
|
+
async def add_mcp_server(
|
|
430
|
+
name: str,
|
|
431
|
+
transport: str,
|
|
432
|
+
url: str | None = None,
|
|
433
|
+
headers: dict[str, str] | None = None,
|
|
434
|
+
command: str | None = None,
|
|
435
|
+
args: list[str] | None = None,
|
|
436
|
+
env: dict[str, str] | None = None,
|
|
437
|
+
enabled: bool = True,
|
|
438
|
+
) -> dict[str, Any]:
|
|
439
|
+
"""
|
|
440
|
+
Add a new MCP server to the daemon's configuration.
|
|
441
|
+
|
|
442
|
+
Args:
|
|
443
|
+
name: Unique server name
|
|
444
|
+
transport: Transport type - "http", "stdio", or "websocket"
|
|
445
|
+
url: Server URL (required for http/websocket)
|
|
446
|
+
headers: Custom HTTP headers (optional)
|
|
447
|
+
command: Command to run (required for stdio)
|
|
448
|
+
args: Command arguments (optional for stdio)
|
|
449
|
+
env: Environment variables (optional for stdio)
|
|
450
|
+
enabled: Whether server is enabled (default: True)
|
|
451
|
+
|
|
452
|
+
Returns:
|
|
453
|
+
Result dict with success status
|
|
454
|
+
"""
|
|
455
|
+
return await proxy.add_mcp_server(
|
|
456
|
+
name=name,
|
|
457
|
+
transport=transport,
|
|
458
|
+
url=url,
|
|
459
|
+
headers=headers,
|
|
460
|
+
command=command,
|
|
461
|
+
args=args,
|
|
462
|
+
env=env,
|
|
463
|
+
enabled=enabled,
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
@mcp.tool()
|
|
467
|
+
async def remove_mcp_server(name: str) -> dict[str, Any]:
|
|
468
|
+
"""
|
|
469
|
+
Remove an MCP server from the daemon's configuration.
|
|
470
|
+
|
|
471
|
+
Args:
|
|
472
|
+
name: Server name to remove
|
|
473
|
+
|
|
474
|
+
Returns:
|
|
475
|
+
Result dict with success status
|
|
476
|
+
"""
|
|
477
|
+
return await proxy.remove_mcp_server(name)
|
|
478
|
+
|
|
479
|
+
@mcp.tool()
|
|
480
|
+
async def import_mcp_server(
|
|
481
|
+
from_project: str | None = None,
|
|
482
|
+
servers: list[str] | None = None,
|
|
483
|
+
github_url: str | None = None,
|
|
484
|
+
query: str | None = None,
|
|
485
|
+
) -> dict[str, Any]:
|
|
486
|
+
"""
|
|
487
|
+
Import MCP servers from various sources.
|
|
488
|
+
|
|
489
|
+
Args:
|
|
490
|
+
from_project: Source project name to import servers from
|
|
491
|
+
servers: Optional list of specific server names to import
|
|
492
|
+
github_url: GitHub repository URL to parse for MCP server config
|
|
493
|
+
query: Natural language search query
|
|
494
|
+
|
|
495
|
+
Returns:
|
|
496
|
+
Result dict with imported servers or config to fill in
|
|
497
|
+
"""
|
|
498
|
+
return await proxy.import_mcp_server(
|
|
499
|
+
from_project=from_project,
|
|
500
|
+
servers=servers,
|
|
501
|
+
github_url=github_url,
|
|
502
|
+
query=query,
|
|
503
|
+
)
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
async def ensure_daemon_running() -> None:
|
|
507
|
+
"""Ensure the Gobby daemon is running and healthy."""
|
|
508
|
+
config = load_config()
|
|
509
|
+
port = config.daemon_port
|
|
510
|
+
ws_port = config.websocket.port
|
|
511
|
+
|
|
512
|
+
# Check if running
|
|
513
|
+
if is_daemon_running():
|
|
514
|
+
# Check health
|
|
515
|
+
if await check_daemon_http_health(port):
|
|
516
|
+
return
|
|
517
|
+
|
|
518
|
+
# Unhealthy, restart
|
|
519
|
+
logger.warning("Daemon running but unhealthy, restarting...")
|
|
520
|
+
pid = get_daemon_pid()
|
|
521
|
+
await restart_daemon_process(pid, port, ws_port)
|
|
522
|
+
else:
|
|
523
|
+
# Start
|
|
524
|
+
result = await start_daemon_process(port, ws_port)
|
|
525
|
+
if not result.get("success"):
|
|
526
|
+
logger.error(
|
|
527
|
+
"Failed to start daemon: %s (port=%d, ws_port=%d)",
|
|
528
|
+
result.get("error", "unknown error"),
|
|
529
|
+
port,
|
|
530
|
+
ws_port,
|
|
531
|
+
)
|
|
532
|
+
sys.exit(1)
|
|
533
|
+
|
|
534
|
+
# Wait for health
|
|
535
|
+
last_health_response = None
|
|
536
|
+
for _i in range(10):
|
|
537
|
+
last_health_response = await check_daemon_http_health(port)
|
|
538
|
+
if last_health_response:
|
|
539
|
+
return
|
|
540
|
+
await asyncio.sleep(1)
|
|
541
|
+
|
|
542
|
+
# Health check timed out
|
|
543
|
+
pid = get_daemon_pid()
|
|
544
|
+
logger.error(
|
|
545
|
+
"Daemon failed to become healthy after 10 attempts (pid=%s, port=%d, ws_port=%d, last_health=%s)",
|
|
546
|
+
pid,
|
|
547
|
+
port,
|
|
548
|
+
ws_port,
|
|
549
|
+
last_health_response,
|
|
550
|
+
)
|
|
551
|
+
sys.exit(1)
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
async def main() -> None:
|
|
555
|
+
"""Main entry point for stdio MCP server."""
|
|
556
|
+
# Ensure daemon is running first
|
|
557
|
+
await ensure_daemon_running()
|
|
558
|
+
|
|
559
|
+
# Create and run the MCP server
|
|
560
|
+
mcp = create_stdio_mcp_server()
|
|
561
|
+
await mcp.run_stdio_async()
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
if __name__ == "__main__":
|
|
565
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCP proxy tools module.
|
|
3
|
+
|
|
4
|
+
Provides factory functions for creating tool registries.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# Main task registry (facade that merges all task-related registries)
|
|
8
|
+
# Extracted task module registries (for direct use or testing)
|
|
9
|
+
from gobby.mcp_proxy.tools.task_dependencies import create_dependency_registry
|
|
10
|
+
from gobby.mcp_proxy.tools.task_expansion import create_expansion_registry
|
|
11
|
+
from gobby.mcp_proxy.tools.task_github import create_github_sync_registry
|
|
12
|
+
from gobby.mcp_proxy.tools.task_readiness import create_readiness_registry
|
|
13
|
+
from gobby.mcp_proxy.tools.task_sync import create_sync_registry
|
|
14
|
+
from gobby.mcp_proxy.tools.task_validation import create_validation_registry
|
|
15
|
+
from gobby.mcp_proxy.tools.tasks import create_task_registry
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
# Main facade
|
|
19
|
+
"create_task_registry",
|
|
20
|
+
# Extracted registries
|
|
21
|
+
"create_dependency_registry",
|
|
22
|
+
"create_expansion_registry",
|
|
23
|
+
"create_github_sync_registry",
|
|
24
|
+
"create_readiness_registry",
|
|
25
|
+
"create_sync_registry",
|
|
26
|
+
"create_validation_registry",
|
|
27
|
+
]
|