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
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Task sync and commit linking MCP tools module.
|
|
3
|
+
|
|
4
|
+
Provides tools for task synchronization and commit linking:
|
|
5
|
+
- sync_tasks: Manually trigger task import/export
|
|
6
|
+
- get_sync_status: Get current sync status
|
|
7
|
+
- link_commit: Link a git commit to a task
|
|
8
|
+
- unlink_commit: Unlink a git commit from a task
|
|
9
|
+
- auto_link_commits: Auto-detect and link commits mentioning task IDs
|
|
10
|
+
- get_task_diff: Get combined diff for all commits linked to a task
|
|
11
|
+
|
|
12
|
+
Extracted from tasks.py using Strangler Fig pattern for code decomposition.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from collections.abc import Callable
|
|
16
|
+
from typing import TYPE_CHECKING, Any
|
|
17
|
+
|
|
18
|
+
from gobby.mcp_proxy.tools.internal import InternalToolRegistry
|
|
19
|
+
from gobby.storage.tasks import TaskNotFoundError
|
|
20
|
+
from gobby.utils.project_context import get_project_context
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from gobby.storage.projects import LocalProjectManager
|
|
24
|
+
from gobby.storage.tasks import LocalTaskManager
|
|
25
|
+
from gobby.sync.tasks import TaskSyncManager
|
|
26
|
+
|
|
27
|
+
__all__ = ["create_sync_registry"]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def get_current_project_id() -> str | None:
|
|
31
|
+
"""Get the current project ID from context."""
|
|
32
|
+
context = get_project_context()
|
|
33
|
+
return context.get("id") if context else None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class SyncToolRegistry(InternalToolRegistry):
|
|
37
|
+
"""Registry for sync tools with test-friendly get_tool method."""
|
|
38
|
+
|
|
39
|
+
def get_tool(self, name: str) -> Callable[..., Any] | None:
|
|
40
|
+
"""Get a tool function by name (for testing)."""
|
|
41
|
+
tool = self._tools.get(name)
|
|
42
|
+
return tool.func if tool else None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def create_sync_registry(
|
|
46
|
+
sync_manager: "TaskSyncManager | None" = None,
|
|
47
|
+
task_manager: "LocalTaskManager | None" = None,
|
|
48
|
+
project_manager: "LocalProjectManager | None" = None,
|
|
49
|
+
auto_link_commits_fn: Callable[..., Any] | None = None,
|
|
50
|
+
get_task_diff_fn: Callable[..., Any] | None = None,
|
|
51
|
+
) -> SyncToolRegistry:
|
|
52
|
+
"""
|
|
53
|
+
Create a registry with task sync and commit linking tools.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
sync_manager: TaskSyncManager instance
|
|
57
|
+
task_manager: LocalTaskManager instance (required for task ID resolution)
|
|
58
|
+
project_manager: LocalProjectManager instance (for repo_path lookup)
|
|
59
|
+
auto_link_commits_fn: Function for auto-linking commits (injectable for testing)
|
|
60
|
+
get_task_diff_fn: Function for getting task diff (injectable for testing)
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
SyncToolRegistry with sync tools registered
|
|
64
|
+
"""
|
|
65
|
+
# Lazy import to avoid circular dependency
|
|
66
|
+
from gobby.mcp_proxy.tools.tasks import resolve_task_id_for_mcp
|
|
67
|
+
|
|
68
|
+
registry = SyncToolRegistry(
|
|
69
|
+
name="gobby-tasks-sync",
|
|
70
|
+
description="Task synchronization and commit linking tools",
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
if sync_manager is None:
|
|
74
|
+
raise ValueError("sync_manager is required")
|
|
75
|
+
if task_manager is None:
|
|
76
|
+
raise ValueError("task_manager is required for task ID resolution")
|
|
77
|
+
|
|
78
|
+
# --- sync_tasks ---
|
|
79
|
+
|
|
80
|
+
def sync_tasks(direction: str = "both") -> dict[str, Any]:
|
|
81
|
+
"""Manually trigger task synchronization."""
|
|
82
|
+
valid_directions = ("import", "export", "both")
|
|
83
|
+
if direction not in valid_directions:
|
|
84
|
+
return {
|
|
85
|
+
"error": f"Invalid direction '{direction}'. Must be one of: {', '.join(valid_directions)}"
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
result = {}
|
|
89
|
+
if direction in ["import", "both"]:
|
|
90
|
+
# Get current project ID for context-aware sync
|
|
91
|
+
project_id = get_current_project_id()
|
|
92
|
+
sync_manager.import_from_jsonl(project_id=project_id)
|
|
93
|
+
result["import"] = "completed"
|
|
94
|
+
|
|
95
|
+
if direction in ["export", "both"]:
|
|
96
|
+
# Get current project ID for context-aware sync
|
|
97
|
+
project_id = get_current_project_id()
|
|
98
|
+
sync_manager.export_to_jsonl(project_id=project_id)
|
|
99
|
+
result["export"] = "completed"
|
|
100
|
+
|
|
101
|
+
return result
|
|
102
|
+
|
|
103
|
+
registry.register(
|
|
104
|
+
name="sync_tasks",
|
|
105
|
+
description="Manually trigger task synchronization.",
|
|
106
|
+
input_schema={
|
|
107
|
+
"type": "object",
|
|
108
|
+
"properties": {
|
|
109
|
+
"direction": {
|
|
110
|
+
"type": "string",
|
|
111
|
+
"description": '"import", "export", or "both"',
|
|
112
|
+
"default": "both",
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
func=sync_tasks,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# --- get_sync_status ---
|
|
120
|
+
|
|
121
|
+
def get_sync_status() -> dict[str, Any]:
|
|
122
|
+
"""Get current synchronization status."""
|
|
123
|
+
result: dict[str, Any] = sync_manager.get_sync_status()
|
|
124
|
+
return result
|
|
125
|
+
|
|
126
|
+
registry.register(
|
|
127
|
+
name="get_sync_status",
|
|
128
|
+
description="Get current synchronization status.",
|
|
129
|
+
input_schema={"type": "object", "properties": {}},
|
|
130
|
+
func=get_sync_status,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# --- link_commit ---
|
|
134
|
+
|
|
135
|
+
def link_commit(task_id: str, commit_sha: str) -> dict[str, Any]:
|
|
136
|
+
"""Link a git commit to a task."""
|
|
137
|
+
# Resolve task reference
|
|
138
|
+
try:
|
|
139
|
+
resolved_task_id = resolve_task_id_for_mcp(task_manager, task_id)
|
|
140
|
+
except (TaskNotFoundError, ValueError) as e:
|
|
141
|
+
return {"error": f"Invalid task_id: {e}"}
|
|
142
|
+
|
|
143
|
+
# Get project repo path for git operations
|
|
144
|
+
ctx = get_project_context()
|
|
145
|
+
repo_path = None
|
|
146
|
+
if ctx and ctx.get("id") and project_manager:
|
|
147
|
+
project = project_manager.get(ctx["id"])
|
|
148
|
+
if project:
|
|
149
|
+
repo_path = project.repo_path
|
|
150
|
+
|
|
151
|
+
try:
|
|
152
|
+
task = task_manager.link_commit(resolved_task_id, commit_sha, cwd=repo_path)
|
|
153
|
+
return {
|
|
154
|
+
"task_id": task.id,
|
|
155
|
+
"commits": task.commits or [],
|
|
156
|
+
}
|
|
157
|
+
except ValueError as e:
|
|
158
|
+
return {"error": str(e)}
|
|
159
|
+
|
|
160
|
+
registry.register(
|
|
161
|
+
name="link_commit",
|
|
162
|
+
description="Link a git commit to a task. Useful for tracking which commits implement a task.",
|
|
163
|
+
input_schema={
|
|
164
|
+
"type": "object",
|
|
165
|
+
"properties": {
|
|
166
|
+
"task_id": {
|
|
167
|
+
"type": "string",
|
|
168
|
+
"description": "Task reference: #N, N (seq_num), path (1.2.3), or UUID",
|
|
169
|
+
},
|
|
170
|
+
"commit_sha": {
|
|
171
|
+
"type": "string",
|
|
172
|
+
"description": "Git commit SHA (short or full)",
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
"required": ["task_id", "commit_sha"],
|
|
176
|
+
},
|
|
177
|
+
func=link_commit,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
# --- unlink_commit ---
|
|
181
|
+
|
|
182
|
+
def unlink_commit(task_id: str, commit_sha: str) -> dict[str, Any]:
|
|
183
|
+
"""Unlink a git commit from a task."""
|
|
184
|
+
# Resolve task reference
|
|
185
|
+
try:
|
|
186
|
+
resolved_task_id = resolve_task_id_for_mcp(task_manager, task_id)
|
|
187
|
+
except (TaskNotFoundError, ValueError) as e:
|
|
188
|
+
return {"error": f"Invalid task_id: {e}"}
|
|
189
|
+
|
|
190
|
+
# Get project repo path for git operations
|
|
191
|
+
ctx = get_project_context()
|
|
192
|
+
repo_path = None
|
|
193
|
+
if ctx and ctx.get("id") and project_manager:
|
|
194
|
+
project = project_manager.get(ctx["id"])
|
|
195
|
+
if project:
|
|
196
|
+
repo_path = project.repo_path
|
|
197
|
+
|
|
198
|
+
try:
|
|
199
|
+
task = task_manager.unlink_commit(resolved_task_id, commit_sha, cwd=repo_path)
|
|
200
|
+
return {
|
|
201
|
+
"task_id": task.id,
|
|
202
|
+
"commits": task.commits or [],
|
|
203
|
+
}
|
|
204
|
+
except ValueError as e:
|
|
205
|
+
return {"error": str(e)}
|
|
206
|
+
|
|
207
|
+
registry.register(
|
|
208
|
+
name="unlink_commit",
|
|
209
|
+
description="Unlink a git commit from a task.",
|
|
210
|
+
input_schema={
|
|
211
|
+
"type": "object",
|
|
212
|
+
"properties": {
|
|
213
|
+
"task_id": {
|
|
214
|
+
"type": "string",
|
|
215
|
+
"description": "Task reference: #N, N (seq_num), path (1.2.3), or UUID",
|
|
216
|
+
},
|
|
217
|
+
"commit_sha": {
|
|
218
|
+
"type": "string",
|
|
219
|
+
"description": "Git commit SHA to unlink",
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
"required": ["task_id", "commit_sha"],
|
|
223
|
+
},
|
|
224
|
+
func=unlink_commit,
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
# --- auto_link_commits ---
|
|
228
|
+
|
|
229
|
+
def auto_link_commits(
|
|
230
|
+
task_id: str | None = None,
|
|
231
|
+
since: str | None = None,
|
|
232
|
+
) -> dict[str, Any]:
|
|
233
|
+
"""Auto-detect and link commits that mention task IDs."""
|
|
234
|
+
if auto_link_commits_fn is None:
|
|
235
|
+
return {"error": "auto_link_commits_fn not configured"}
|
|
236
|
+
|
|
237
|
+
# Resolve task reference if provided
|
|
238
|
+
resolved_task_id = None
|
|
239
|
+
if task_id:
|
|
240
|
+
try:
|
|
241
|
+
resolved_task_id = resolve_task_id_for_mcp(task_manager, task_id)
|
|
242
|
+
except (TaskNotFoundError, ValueError) as e:
|
|
243
|
+
return {"error": f"Invalid task_id: {e}"}
|
|
244
|
+
|
|
245
|
+
# Get project repo_path
|
|
246
|
+
ctx = get_project_context()
|
|
247
|
+
repo_path = None
|
|
248
|
+
if ctx and ctx.get("id") and project_manager:
|
|
249
|
+
project = project_manager.get(ctx["id"])
|
|
250
|
+
if project:
|
|
251
|
+
repo_path = project.repo_path
|
|
252
|
+
|
|
253
|
+
result = auto_link_commits_fn(
|
|
254
|
+
task_manager=task_manager,
|
|
255
|
+
task_id=resolved_task_id,
|
|
256
|
+
since=since,
|
|
257
|
+
cwd=repo_path,
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
return {
|
|
261
|
+
"linked_tasks": result.linked_tasks,
|
|
262
|
+
"total_linked": result.total_linked,
|
|
263
|
+
"skipped": result.skipped,
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
registry.register(
|
|
267
|
+
name="auto_link_commits",
|
|
268
|
+
description="Auto-detect and link commits that mention task IDs in their messages. "
|
|
269
|
+
"Supports patterns: [gt-xxxxx], gt-xxxxx:, Implements/Fixes/Closes gt-xxxxx.",
|
|
270
|
+
input_schema={
|
|
271
|
+
"type": "object",
|
|
272
|
+
"properties": {
|
|
273
|
+
"task_id": {
|
|
274
|
+
"type": "string",
|
|
275
|
+
"description": "Filter to specific task (#N, N, path, or UUID). Optional.",
|
|
276
|
+
"default": None,
|
|
277
|
+
},
|
|
278
|
+
"since": {
|
|
279
|
+
"type": "string",
|
|
280
|
+
"description": "Git --since parameter (e.g., '1 week ago', '2024-01-01')",
|
|
281
|
+
"default": None,
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
func=auto_link_commits,
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
# --- get_task_diff ---
|
|
289
|
+
|
|
290
|
+
def get_task_diff_tool(
|
|
291
|
+
task_id: str,
|
|
292
|
+
include_uncommitted: bool = False,
|
|
293
|
+
) -> dict[str, Any]:
|
|
294
|
+
"""Get the combined diff for all commits linked to a task."""
|
|
295
|
+
# Resolve task reference
|
|
296
|
+
try:
|
|
297
|
+
resolved_task_id = resolve_task_id_for_mcp(task_manager, task_id)
|
|
298
|
+
except (TaskNotFoundError, ValueError) as e:
|
|
299
|
+
return {"error": f"Invalid task_id: {e}"}
|
|
300
|
+
|
|
301
|
+
task = task_manager.get_task(resolved_task_id)
|
|
302
|
+
if not task:
|
|
303
|
+
return {"error": f"Task {task_id} not found"}
|
|
304
|
+
|
|
305
|
+
if get_task_diff_fn is None:
|
|
306
|
+
return {"error": "get_task_diff_fn not configured"}
|
|
307
|
+
|
|
308
|
+
# Get project repo_path
|
|
309
|
+
repo_path = None
|
|
310
|
+
if project_manager and task.project_id:
|
|
311
|
+
project = project_manager.get(task.project_id)
|
|
312
|
+
if project:
|
|
313
|
+
repo_path = project.repo_path
|
|
314
|
+
|
|
315
|
+
result = get_task_diff_fn(
|
|
316
|
+
task_id=resolved_task_id,
|
|
317
|
+
task_manager=task_manager,
|
|
318
|
+
include_uncommitted=include_uncommitted,
|
|
319
|
+
cwd=repo_path,
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
"diff": result.diff,
|
|
324
|
+
"commits": result.commits,
|
|
325
|
+
"has_uncommitted_changes": result.has_uncommitted_changes,
|
|
326
|
+
"file_count": result.file_count,
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
registry.register(
|
|
330
|
+
name="get_task_diff",
|
|
331
|
+
description="Get the combined diff for all commits linked to a task. "
|
|
332
|
+
"Optionally include uncommitted changes.",
|
|
333
|
+
input_schema={
|
|
334
|
+
"type": "object",
|
|
335
|
+
"properties": {
|
|
336
|
+
"task_id": {
|
|
337
|
+
"type": "string",
|
|
338
|
+
"description": "Task reference: #N, N (seq_num), path (1.2.3), or UUID",
|
|
339
|
+
},
|
|
340
|
+
"include_uncommitted": {
|
|
341
|
+
"type": "boolean",
|
|
342
|
+
"description": "Include uncommitted changes in the diff",
|
|
343
|
+
"default": False,
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
"required": ["task_id"],
|
|
347
|
+
},
|
|
348
|
+
func=get_task_diff_tool,
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
return registry
|