gobby 0.2.5__py3-none-any.whl → 0.2.6__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.
Files changed (148) hide show
  1. gobby/adapters/claude_code.py +13 -4
  2. gobby/adapters/codex.py +43 -3
  3. gobby/agents/runner.py +8 -0
  4. gobby/cli/__init__.py +6 -0
  5. gobby/cli/clones.py +419 -0
  6. gobby/cli/conductor.py +266 -0
  7. gobby/cli/installers/antigravity.py +3 -9
  8. gobby/cli/installers/claude.py +9 -9
  9. gobby/cli/installers/codex.py +2 -8
  10. gobby/cli/installers/gemini.py +2 -8
  11. gobby/cli/installers/shared.py +71 -8
  12. gobby/cli/skills.py +858 -0
  13. gobby/cli/tasks/ai.py +0 -440
  14. gobby/cli/tasks/crud.py +44 -6
  15. gobby/cli/tasks/main.py +0 -4
  16. gobby/cli/tui.py +2 -2
  17. gobby/cli/utils.py +3 -3
  18. gobby/clones/__init__.py +13 -0
  19. gobby/clones/git.py +547 -0
  20. gobby/conductor/__init__.py +16 -0
  21. gobby/conductor/alerts.py +135 -0
  22. gobby/conductor/loop.py +164 -0
  23. gobby/conductor/monitors/__init__.py +11 -0
  24. gobby/conductor/monitors/agents.py +116 -0
  25. gobby/conductor/monitors/tasks.py +155 -0
  26. gobby/conductor/pricing.py +234 -0
  27. gobby/conductor/token_tracker.py +160 -0
  28. gobby/config/app.py +63 -1
  29. gobby/config/search.py +110 -0
  30. gobby/config/servers.py +1 -1
  31. gobby/config/skills.py +43 -0
  32. gobby/config/tasks.py +6 -14
  33. gobby/hooks/event_handlers.py +145 -2
  34. gobby/hooks/hook_manager.py +48 -2
  35. gobby/hooks/skill_manager.py +130 -0
  36. gobby/install/claude/hooks/hook_dispatcher.py +4 -4
  37. gobby/install/codex/hooks/hook_dispatcher.py +1 -1
  38. gobby/install/gemini/hooks/hook_dispatcher.py +87 -12
  39. gobby/llm/claude.py +22 -34
  40. gobby/llm/claude_executor.py +46 -256
  41. gobby/llm/codex_executor.py +59 -291
  42. gobby/llm/executor.py +21 -0
  43. gobby/llm/gemini.py +134 -110
  44. gobby/llm/litellm_executor.py +143 -6
  45. gobby/llm/resolver.py +95 -33
  46. gobby/mcp_proxy/instructions.py +54 -0
  47. gobby/mcp_proxy/models.py +15 -0
  48. gobby/mcp_proxy/registries.py +68 -5
  49. gobby/mcp_proxy/server.py +33 -3
  50. gobby/mcp_proxy/services/tool_proxy.py +81 -1
  51. gobby/mcp_proxy/stdio.py +2 -1
  52. gobby/mcp_proxy/tools/__init__.py +0 -2
  53. gobby/mcp_proxy/tools/agent_messaging.py +317 -0
  54. gobby/mcp_proxy/tools/clones.py +903 -0
  55. gobby/mcp_proxy/tools/memory.py +1 -24
  56. gobby/mcp_proxy/tools/metrics.py +65 -1
  57. gobby/mcp_proxy/tools/orchestration/__init__.py +3 -0
  58. gobby/mcp_proxy/tools/orchestration/cleanup.py +151 -0
  59. gobby/mcp_proxy/tools/orchestration/wait.py +467 -0
  60. gobby/mcp_proxy/tools/session_messages.py +1 -2
  61. gobby/mcp_proxy/tools/skills/__init__.py +631 -0
  62. gobby/mcp_proxy/tools/task_orchestration.py +7 -0
  63. gobby/mcp_proxy/tools/task_readiness.py +14 -0
  64. gobby/mcp_proxy/tools/task_sync.py +1 -1
  65. gobby/mcp_proxy/tools/tasks/_context.py +0 -20
  66. gobby/mcp_proxy/tools/tasks/_crud.py +91 -4
  67. gobby/mcp_proxy/tools/tasks/_expansion.py +348 -0
  68. gobby/mcp_proxy/tools/tasks/_factory.py +6 -16
  69. gobby/mcp_proxy/tools/tasks/_lifecycle.py +60 -29
  70. gobby/mcp_proxy/tools/tasks/_lifecycle_validation.py +18 -29
  71. gobby/mcp_proxy/tools/workflows.py +1 -1
  72. gobby/mcp_proxy/tools/worktrees.py +5 -0
  73. gobby/memory/backends/__init__.py +6 -1
  74. gobby/memory/backends/mem0.py +6 -1
  75. gobby/memory/extractor.py +477 -0
  76. gobby/memory/manager.py +11 -2
  77. gobby/prompts/defaults/handoff/compact.md +63 -0
  78. gobby/prompts/defaults/handoff/session_end.md +57 -0
  79. gobby/prompts/defaults/memory/extract.md +61 -0
  80. gobby/runner.py +37 -16
  81. gobby/search/__init__.py +48 -6
  82. gobby/search/backends/__init__.py +159 -0
  83. gobby/search/backends/embedding.py +225 -0
  84. gobby/search/embeddings.py +238 -0
  85. gobby/search/models.py +148 -0
  86. gobby/search/unified.py +496 -0
  87. gobby/servers/http.py +23 -8
  88. gobby/servers/routes/admin.py +280 -0
  89. gobby/servers/routes/mcp/tools.py +241 -52
  90. gobby/servers/websocket.py +2 -2
  91. gobby/sessions/analyzer.py +2 -0
  92. gobby/sessions/transcripts/base.py +1 -0
  93. gobby/sessions/transcripts/claude.py +64 -5
  94. gobby/skills/__init__.py +91 -0
  95. gobby/skills/loader.py +685 -0
  96. gobby/skills/manager.py +384 -0
  97. gobby/skills/parser.py +258 -0
  98. gobby/skills/search.py +463 -0
  99. gobby/skills/sync.py +119 -0
  100. gobby/skills/updater.py +385 -0
  101. gobby/skills/validator.py +368 -0
  102. gobby/storage/clones.py +378 -0
  103. gobby/storage/database.py +1 -1
  104. gobby/storage/memories.py +43 -13
  105. gobby/storage/migrations.py +180 -6
  106. gobby/storage/sessions.py +73 -0
  107. gobby/storage/skills.py +749 -0
  108. gobby/storage/tasks/_crud.py +4 -4
  109. gobby/storage/tasks/_lifecycle.py +41 -6
  110. gobby/storage/tasks/_manager.py +14 -5
  111. gobby/storage/tasks/_models.py +8 -3
  112. gobby/sync/memories.py +39 -4
  113. gobby/sync/tasks.py +83 -6
  114. gobby/tasks/__init__.py +1 -2
  115. gobby/tasks/validation.py +24 -15
  116. gobby/tui/api_client.py +4 -7
  117. gobby/tui/app.py +5 -3
  118. gobby/tui/screens/orchestrator.py +1 -2
  119. gobby/tui/screens/tasks.py +2 -4
  120. gobby/tui/ws_client.py +1 -1
  121. gobby/utils/daemon_client.py +2 -2
  122. gobby/workflows/actions.py +84 -2
  123. gobby/workflows/context_actions.py +43 -0
  124. gobby/workflows/detection_helpers.py +115 -31
  125. gobby/workflows/engine.py +13 -2
  126. gobby/workflows/lifecycle_evaluator.py +29 -1
  127. gobby/workflows/loader.py +19 -6
  128. gobby/workflows/memory_actions.py +74 -0
  129. gobby/workflows/summary_actions.py +17 -0
  130. gobby/workflows/task_enforcement_actions.py +448 -6
  131. {gobby-0.2.5.dist-info → gobby-0.2.6.dist-info}/METADATA +82 -21
  132. {gobby-0.2.5.dist-info → gobby-0.2.6.dist-info}/RECORD +136 -107
  133. gobby/install/codex/prompts/forget.md +0 -7
  134. gobby/install/codex/prompts/memories.md +0 -7
  135. gobby/install/codex/prompts/recall.md +0 -7
  136. gobby/install/codex/prompts/remember.md +0 -13
  137. gobby/llm/gemini_executor.py +0 -339
  138. gobby/mcp_proxy/tools/task_expansion.py +0 -591
  139. gobby/tasks/context.py +0 -747
  140. gobby/tasks/criteria.py +0 -342
  141. gobby/tasks/expansion.py +0 -626
  142. gobby/tasks/prompts/expand.py +0 -327
  143. gobby/tasks/research.py +0 -421
  144. gobby/tasks/tdd.py +0 -352
  145. {gobby-0.2.5.dist-info → gobby-0.2.6.dist-info}/WHEEL +0 -0
  146. {gobby-0.2.5.dist-info → gobby-0.2.6.dist-info}/entry_points.txt +0 -0
  147. {gobby-0.2.5.dist-info → gobby-0.2.6.dist-info}/licenses/LICENSE.md +0 -0
  148. {gobby-0.2.5.dist-info → gobby-0.2.6.dist-info}/top_level.txt +0 -0
gobby/tasks/tdd.py DELETED
@@ -1,352 +0,0 @@
1
- """
2
- TDD sandwich pattern utilities for task expansion.
3
-
4
- This module provides shared logic for applying the TDD (Test-Driven Development)
5
- sandwich pattern to task expansions. The sandwich wraps implementation tasks:
6
- - ONE [TDD] task at the start (RED phase - write failing tests)
7
- - Original tasks renamed with [IMPL] prefix (GREEN phase - make tests pass)
8
- - ONE [REF] task at the end (BLUE phase - refactor while keeping tests green)
9
-
10
- Used by both MCP expand_task tool and CLI expand command.
11
- """
12
-
13
- import logging
14
- import re
15
- from typing import TYPE_CHECKING, Any
16
-
17
- if TYPE_CHECKING:
18
- from gobby.storage.task_dependencies import TaskDependencyManager
19
- from gobby.storage.tasks import LocalTaskManager
20
-
21
- logger = logging.getLogger(__name__)
22
-
23
- __all__ = [
24
- "TDD_PREFIXES",
25
- "TDD_SKIP_PATTERNS",
26
- "TDD_CRITERIA_RED",
27
- "TDD_CRITERIA_BLUE",
28
- "TDD_PARENT_CRITERIA",
29
- "TDD_CATEGORIES",
30
- "should_skip_tdd",
31
- "should_skip_expansion",
32
- "apply_tdd_sandwich",
33
- "build_expansion_context",
34
- ]
35
-
36
- # TDD triplet prefixes - used for both skip detection and triplet creation
37
- TDD_PREFIXES = ("[TDD]", "[IMPL]", "[REF]")
38
-
39
- # Task categories that should get TDD treatment
40
- TDD_CATEGORIES = ("code", "config")
41
-
42
- # Patterns for tasks that should skip TDD transformation (case-insensitive)
43
- TDD_SKIP_PATTERNS = (
44
- # New TDD prefixes (already in triplet form)
45
- r"^\[TDD\]",
46
- r"^\[IMPL\]",
47
- r"^\[REF\]",
48
- # Legacy TDD prefixes (backwards compatibility)
49
- r"^Write tests for:",
50
- r"^Implement:",
51
- r"^Refactor:",
52
- # Deletion tasks (simple operations, no tests needed)
53
- r"^Delete\b",
54
- r"^Remove\b",
55
- # Documentation updates
56
- r"^Update.*README",
57
- r"^Update.*documentation",
58
- r"^Update.*docs\b",
59
- # Config file updates
60
- r"^Update.*\.toml\b",
61
- r"^Update.*\.yaml\b",
62
- r"^Update.*\.yml\b",
63
- r"^Update.*\.json\b",
64
- r"^Update.*\.env\b",
65
- r"^Update.*config",
66
- )
67
-
68
- # TDD validation criteria templates per phase
69
- TDD_CRITERIA_RED = """## Deliverable
70
- - [ ] Tests written that define expected behavior
71
- - [ ] Tests fail when run (no implementation yet)
72
- - [ ] Test coverage addresses acceptance criteria from parent task
73
- """
74
-
75
- TDD_CRITERIA_BLUE = """## Deliverable
76
- - [ ] All tests continue to pass
77
- - [ ] Code refactored for clarity and maintainability
78
- - [ ] No new functionality added (refactor only)
79
- - [ ] Unrelated bugs discovered during refactor logged as new bug tasks
80
-
81
- **Note:** If you discover bugs outside your scope during refactoring, create bug tasks
82
- for them rather than fixing them now.
83
- """
84
-
85
- TDD_PARENT_CRITERIA = """## Deliverable
86
- - [ ] All child tasks completed
87
- """
88
-
89
-
90
- def should_skip_tdd(title: str) -> bool:
91
- """
92
- Check if a task should skip TDD transformation based on its title.
93
-
94
- Tasks are skipped if they match any TDD_SKIP_PATTERNS:
95
- - Already TDD triplet tasks ([TDD], [IMPL], [REF] prefixes)
96
- - Legacy TDD prefixes (Write tests for:, Implement:, Refactor:)
97
- - Deletion tasks (Delete X, Remove Y)
98
- - Documentation updates (Update README, Update docs)
99
- - Config file updates (Update pyproject.toml, Update .env)
100
-
101
- Args:
102
- title: The task title to check
103
-
104
- Returns:
105
- True if the task should skip TDD transformation, False otherwise
106
- """
107
- for pattern in TDD_SKIP_PATTERNS:
108
- if re.search(pattern, title, re.IGNORECASE):
109
- return True
110
- return False
111
-
112
-
113
- def should_skip_expansion(title: str, is_expanded: bool, force: bool = False) -> tuple[bool, str]:
114
- """
115
- Check if a task should be skipped from expansion.
116
-
117
- Tasks are skipped if:
118
- - Already expanded (is_expanded=True) unless force=True
119
- - Title starts with TDD prefixes ([TDD], [IMPL], [REF]) - these are atomic tasks
120
-
121
- Args:
122
- title: The task title to check
123
- is_expanded: Whether the task's is_expanded flag is set
124
- force: Whether to force expansion even if already expanded
125
-
126
- Returns:
127
- Tuple of (should_skip: bool, reason: str)
128
- reason is empty string if should_skip is False
129
- """
130
- # Check for TDD prefixes - these tasks should never be expanded
131
- for prefix in TDD_PREFIXES:
132
- if title.startswith(prefix):
133
- return True, f"TDD task ({prefix})"
134
-
135
- # Check if already expanded
136
- if is_expanded and not force:
137
- return True, "already expanded"
138
-
139
- return False, ""
140
-
141
-
142
- async def apply_tdd_sandwich(
143
- task_manager: "LocalTaskManager",
144
- dep_manager: "TaskDependencyManager",
145
- parent_task_id: str,
146
- impl_task_ids: list[str],
147
- refactor_task_ids: list[str] | None = None,
148
- ) -> dict[str, Any]:
149
- """Apply TDD sandwich pattern to a parent task's children.
150
-
151
- Creates a "sandwich" structure where implementation tasks are wrapped:
152
- - ONE [TDD] task at the start (RED phase - write failing tests for all impls)
153
- - Original child tasks renamed with [IMPL] prefix (GREEN phase)
154
- - Intermediate [REF] tasks (refactor-category subtasks) depend on all [IMPL]s
155
- - ONE final [REF] task at the end (BLUE phase - refactor everything)
156
-
157
- Dependencies are wired:
158
- - All [IMPL] tasks are blocked by the [TDD] task
159
- - Intermediate [REF] tasks are blocked by all [IMPL] tasks
160
- - Final [REF] task is blocked by [TDD], all [IMPL]s, and intermediate [REF]s
161
-
162
- Args:
163
- task_manager: LocalTaskManager instance for task CRUD
164
- dep_manager: TaskDependencyManager instance for dependency wiring
165
- parent_task_id: The parent task ID being expanded
166
- impl_task_ids: List of implementation task IDs (the original children)
167
- refactor_task_ids: List of refactor-category task IDs (optional)
168
-
169
- Returns:
170
- Dict with:
171
- - success: True if sandwich was applied
172
- - tasks_created: Number of tasks created (2: TDD + REF)
173
- - test_task_id: ID of the created TDD task
174
- - refactor_task_id: ID of the created REF task
175
- - impl_task_count: Number of impl tasks wrapped
176
- - intermediate_refactor_count: Number of intermediate refactor tasks processed
177
- Or error info if failed
178
- """
179
- parent = task_manager.get_task(parent_task_id)
180
- if not parent:
181
- return {"success": False, "error": f"Parent task not found: {parent_task_id}"}
182
-
183
- if not impl_task_ids:
184
- return {"success": False, "error": "No implementation tasks to wrap"}
185
-
186
- # Skip if already TDD-applied
187
- if parent.is_tdd_applied:
188
- return {"success": False, "skipped": True, "reason": "already_applied"}
189
-
190
- try:
191
- # Build list of impl task titles for TDD task context
192
- impl_titles = []
193
- for impl_id in impl_task_ids:
194
- impl_task = task_manager.get_task(impl_id)
195
- if impl_task:
196
- impl_titles.append(f"- {impl_task.title}")
197
- impl_list = "\n".join(impl_titles) if impl_titles else "- (implementation tasks)"
198
-
199
- # 1. Create ONE Test Task (Red phase) - tests for all implementations
200
- test_task = task_manager.create_task(
201
- title=f"[TDD] Write failing tests for {parent.title}",
202
- description=(
203
- f"Write failing tests for: {parent.title}\n\n"
204
- "## Implementation tasks to cover:\n"
205
- f"{impl_list}\n\n"
206
- "RED phase of TDD - define expected behavior before implementation."
207
- ),
208
- project_id=parent.project_id,
209
- parent_task_id=parent.id,
210
- task_type="task",
211
- priority=parent.priority,
212
- validation_criteria=TDD_CRITERIA_RED,
213
- category="test",
214
- )
215
-
216
- # 2. Add [IMPL] prefix to all implementation tasks and wire dependencies
217
- for impl_id in impl_task_ids:
218
- impl_task = task_manager.get_task(impl_id)
219
- if impl_task and not impl_task.title.startswith("[IMPL]"):
220
- task_manager.update_task(impl_id, title=f"[IMPL] {impl_task.title}")
221
- try:
222
- dep_manager.add_dependency(impl_id, test_task.id, "blocks")
223
- except ValueError:
224
- pass # Dependency already exists
225
-
226
- # 3. Add [REF] prefix to intermediate refactor tasks and wire dependencies
227
- # These are refactor-category subtasks from the expansion (not the final [REF])
228
- intermediate_refactor_ids: list[str] = []
229
- for ref_id in refactor_task_ids or []:
230
- ref_task = task_manager.get_task(ref_id)
231
- if ref_task and not ref_task.title.startswith("[REF]"):
232
- task_manager.update_task(ref_id, title=f"[REF] {ref_task.title}")
233
- intermediate_refactor_ids.append(ref_id)
234
- # Each intermediate [REF] depends on all [IMPL] tasks
235
- for impl_id in impl_task_ids:
236
- try:
237
- dep_manager.add_dependency(ref_id, impl_id, "blocks")
238
- except ValueError:
239
- pass # Dependency already exists
240
-
241
- # 5. Create ONE final Refactor Task (Blue phase) - refactor after all impls done
242
- refactor_task = task_manager.create_task(
243
- title=f"[REF] Refactor and verify {parent.title}",
244
- description=(
245
- f"Refactor implementations in: {parent.title}\n\n"
246
- "BLUE phase of TDD - clean up while keeping tests green."
247
- ),
248
- project_id=parent.project_id,
249
- parent_task_id=parent.id,
250
- task_type="task",
251
- priority=parent.priority,
252
- validation_criteria=TDD_CRITERIA_BLUE,
253
- category="code",
254
- )
255
-
256
- # 6. Wire final refactor to be blocked by TDD, all impls, and intermediate refs
257
- # REFACTOR depends on TDD (must complete testing before refactoring)
258
- try:
259
- dep_manager.add_dependency(refactor_task.id, test_task.id, "blocks")
260
- except ValueError:
261
- pass # Dependency already exists
262
-
263
- # REFACTOR depends on all impl tasks
264
- for impl_id in impl_task_ids:
265
- try:
266
- dep_manager.add_dependency(refactor_task.id, impl_id, "blocks")
267
- except ValueError:
268
- pass # Dependency already exists
269
-
270
- # REFACTOR depends on all intermediate refactor tasks (if any)
271
- for ref_id in intermediate_refactor_ids:
272
- try:
273
- dep_manager.add_dependency(refactor_task.id, ref_id, "blocks")
274
- except ValueError:
275
- pass # Dependency already exists
276
-
277
- # Mark parent as TDD-applied
278
- task_manager.update_task(
279
- parent.id,
280
- is_tdd_applied=True,
281
- validation_criteria=TDD_PARENT_CRITERIA,
282
- )
283
-
284
- return {
285
- "success": True,
286
- "tasks_created": 2, # TDD + final REF (impl tasks already existed)
287
- "test_task_id": test_task.id,
288
- "refactor_task_id": refactor_task.id,
289
- "impl_task_count": len(impl_task_ids),
290
- "intermediate_refactor_count": len(intermediate_refactor_ids),
291
- }
292
- except Exception as e:
293
- return {"success": False, "error": str(e)}
294
-
295
-
296
- def build_expansion_context(
297
- expansion_context_json: str | None,
298
- user_context: str | None,
299
- ) -> str | None:
300
- """
301
- Build context for expansion by merging stored data with user context.
302
-
303
- If the task has expansion_context (legacy enrichment data), parse it and
304
- include research findings, validation criteria, and complexity info.
305
-
306
- Args:
307
- expansion_context_json: JSON string from task.expansion_context (may be None)
308
- user_context: User-provided context string (may be None)
309
-
310
- Returns:
311
- Merged context string, or None if no context available
312
- """
313
- import json
314
-
315
- enrichment_parts: list[str] = []
316
-
317
- # Parse stored expansion_context (legacy enrichment data)
318
- if expansion_context_json:
319
- try:
320
- enrichment_data = json.loads(expansion_context_json)
321
-
322
- # Include research findings
323
- if research := enrichment_data.get("research_findings"):
324
- enrichment_parts.append(f"## Research Findings\n{research}")
325
-
326
- # Include validation criteria
327
- if validation := enrichment_data.get("validation_criteria"):
328
- enrichment_parts.append(f"## Validation Criteria\n{validation}")
329
-
330
- # Include complexity info
331
- complexity_level = enrichment_data.get("complexity_level")
332
- subtask_count = enrichment_data.get("suggested_subtask_count")
333
- if complexity_level or subtask_count:
334
- complexity_info = []
335
- if complexity_level:
336
- complexity_info.append(f"Complexity level: {complexity_level}")
337
- if subtask_count:
338
- complexity_info.append(f"Suggested subtask count: {subtask_count}")
339
- enrichment_parts.append("## Complexity Analysis\n" + "\n".join(complexity_info))
340
-
341
- except (json.JSONDecodeError, TypeError):
342
- # Legacy or plain text context - preserve it as raw text
343
- enrichment_parts.append(f"## Legacy Expansion Context\n{expansion_context_json}")
344
-
345
- # Add user-provided context
346
- if user_context:
347
- enrichment_parts.append(f"## Additional Context\n{user_context}")
348
-
349
- # Return merged context or None
350
- if enrichment_parts:
351
- return "\n\n".join(enrichment_parts)
352
- return None
File without changes