gobby 0.2.6__py3-none-any.whl → 0.2.7__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 +1 -1
- gobby/adapters/__init__.py +2 -1
- gobby/adapters/codex_impl/__init__.py +28 -0
- gobby/adapters/codex_impl/adapter.py +722 -0
- gobby/adapters/codex_impl/client.py +679 -0
- gobby/adapters/codex_impl/protocol.py +20 -0
- gobby/adapters/codex_impl/types.py +68 -0
- gobby/agents/definitions.py +11 -1
- gobby/agents/isolation.py +395 -0
- gobby/agents/sandbox.py +261 -0
- gobby/agents/spawn.py +42 -287
- gobby/agents/spawn_executor.py +385 -0
- gobby/agents/spawners/__init__.py +24 -0
- gobby/agents/spawners/command_builder.py +189 -0
- gobby/agents/spawners/embedded.py +21 -2
- gobby/agents/spawners/headless.py +21 -2
- gobby/agents/spawners/prompt_manager.py +125 -0
- gobby/cli/install.py +4 -4
- gobby/cli/installers/claude.py +6 -0
- gobby/cli/installers/gemini.py +6 -0
- gobby/cli/installers/shared.py +103 -4
- gobby/cli/sessions.py +1 -1
- gobby/cli/utils.py +9 -2
- gobby/config/__init__.py +12 -97
- gobby/config/app.py +10 -94
- gobby/config/extensions.py +2 -2
- gobby/config/features.py +7 -130
- gobby/config/tasks.py +4 -28
- gobby/hooks/__init__.py +0 -13
- gobby/hooks/event_handlers.py +45 -2
- gobby/hooks/hook_manager.py +2 -2
- gobby/hooks/plugins.py +1 -1
- gobby/hooks/webhooks.py +1 -1
- gobby/llm/resolver.py +3 -2
- gobby/mcp_proxy/importer.py +62 -4
- gobby/mcp_proxy/instructions.py +2 -0
- gobby/mcp_proxy/registries.py +1 -4
- gobby/mcp_proxy/services/recommendation.py +43 -11
- gobby/mcp_proxy/tools/agents.py +31 -731
- gobby/mcp_proxy/tools/clones.py +0 -385
- gobby/mcp_proxy/tools/memory.py +2 -2
- gobby/mcp_proxy/tools/sessions/__init__.py +14 -0
- gobby/mcp_proxy/tools/sessions/_commits.py +232 -0
- gobby/mcp_proxy/tools/sessions/_crud.py +253 -0
- gobby/mcp_proxy/tools/sessions/_factory.py +63 -0
- gobby/mcp_proxy/tools/sessions/_handoff.py +499 -0
- gobby/mcp_proxy/tools/sessions/_messages.py +138 -0
- gobby/mcp_proxy/tools/skills/__init__.py +14 -29
- gobby/mcp_proxy/tools/spawn_agent.py +417 -0
- gobby/mcp_proxy/tools/tasks/_lifecycle.py +52 -18
- gobby/mcp_proxy/tools/tasks/_lifecycle_validation.py +1 -1
- gobby/mcp_proxy/tools/worktrees.py +0 -343
- gobby/memory/ingestion/__init__.py +5 -0
- gobby/memory/ingestion/multimodal.py +221 -0
- gobby/memory/manager.py +62 -283
- gobby/memory/search/__init__.py +10 -0
- gobby/memory/search/coordinator.py +248 -0
- gobby/memory/services/__init__.py +5 -0
- gobby/memory/services/crossref.py +142 -0
- gobby/prompts/loader.py +5 -2
- gobby/servers/http.py +1 -4
- gobby/servers/routes/admin.py +14 -0
- gobby/servers/routes/mcp/endpoints/__init__.py +61 -0
- gobby/servers/routes/mcp/endpoints/discovery.py +405 -0
- gobby/servers/routes/mcp/endpoints/execution.py +568 -0
- gobby/servers/routes/mcp/endpoints/registry.py +378 -0
- gobby/servers/routes/mcp/endpoints/server.py +304 -0
- gobby/servers/routes/mcp/hooks.py +1 -1
- gobby/servers/routes/mcp/tools.py +48 -1506
- gobby/sessions/lifecycle.py +1 -1
- gobby/sessions/processor.py +10 -0
- gobby/sessions/transcripts/base.py +1 -0
- gobby/sessions/transcripts/claude.py +15 -5
- gobby/skills/parser.py +30 -2
- gobby/storage/migrations.py +159 -372
- gobby/storage/sessions.py +43 -7
- gobby/storage/skills.py +37 -4
- gobby/storage/tasks/_lifecycle.py +18 -3
- gobby/sync/memories.py +1 -1
- gobby/tasks/external_validator.py +1 -1
- gobby/tasks/validation.py +22 -20
- gobby/tools/summarizer.py +91 -10
- gobby/utils/project_context.py +2 -3
- gobby/utils/status.py +13 -0
- gobby/workflows/actions.py +221 -1217
- gobby/workflows/artifact_actions.py +31 -0
- gobby/workflows/autonomous_actions.py +11 -0
- gobby/workflows/context_actions.py +50 -1
- gobby/workflows/enforcement/__init__.py +47 -0
- gobby/workflows/enforcement/blocking.py +269 -0
- gobby/workflows/enforcement/commit_policy.py +283 -0
- gobby/workflows/enforcement/handlers.py +269 -0
- gobby/workflows/enforcement/task_policy.py +542 -0
- gobby/workflows/git_utils.py +106 -0
- gobby/workflows/llm_actions.py +30 -0
- gobby/workflows/mcp_actions.py +20 -1
- gobby/workflows/memory_actions.py +80 -0
- gobby/workflows/safe_evaluator.py +183 -0
- gobby/workflows/session_actions.py +44 -0
- gobby/workflows/state_actions.py +60 -1
- gobby/workflows/stop_signal_actions.py +55 -0
- gobby/workflows/summary_actions.py +94 -1
- gobby/workflows/task_sync_actions.py +347 -0
- gobby/workflows/todo_actions.py +34 -1
- gobby/workflows/webhook_actions.py +185 -0
- {gobby-0.2.6.dist-info → gobby-0.2.7.dist-info}/METADATA +6 -1
- {gobby-0.2.6.dist-info → gobby-0.2.7.dist-info}/RECORD +111 -111
- {gobby-0.2.6.dist-info → gobby-0.2.7.dist-info}/WHEEL +1 -1
- gobby/adapters/codex.py +0 -1332
- gobby/install/claude/commands/gobby/bug.md +0 -51
- gobby/install/claude/commands/gobby/chore.md +0 -51
- gobby/install/claude/commands/gobby/epic.md +0 -52
- gobby/install/claude/commands/gobby/eval.md +0 -235
- gobby/install/claude/commands/gobby/feat.md +0 -49
- gobby/install/claude/commands/gobby/nit.md +0 -52
- gobby/install/claude/commands/gobby/ref.md +0 -52
- gobby/mcp_proxy/tools/session_messages.py +0 -1055
- gobby/prompts/defaults/expansion/system.md +0 -119
- gobby/prompts/defaults/expansion/user.md +0 -48
- gobby/prompts/defaults/external_validation/agent.md +0 -72
- gobby/prompts/defaults/external_validation/external.md +0 -63
- gobby/prompts/defaults/external_validation/spawn.md +0 -83
- gobby/prompts/defaults/external_validation/system.md +0 -6
- gobby/prompts/defaults/features/import_mcp.md +0 -22
- gobby/prompts/defaults/features/import_mcp_github.md +0 -17
- gobby/prompts/defaults/features/import_mcp_search.md +0 -16
- gobby/prompts/defaults/features/recommend_tools.md +0 -32
- gobby/prompts/defaults/features/recommend_tools_hybrid.md +0 -35
- gobby/prompts/defaults/features/recommend_tools_llm.md +0 -30
- gobby/prompts/defaults/features/server_description.md +0 -20
- gobby/prompts/defaults/features/server_description_system.md +0 -6
- gobby/prompts/defaults/features/task_description.md +0 -31
- gobby/prompts/defaults/features/task_description_system.md +0 -6
- gobby/prompts/defaults/features/tool_summary.md +0 -17
- gobby/prompts/defaults/features/tool_summary_system.md +0 -6
- gobby/prompts/defaults/handoff/compact.md +0 -63
- gobby/prompts/defaults/handoff/session_end.md +0 -57
- gobby/prompts/defaults/memory/extract.md +0 -61
- gobby/prompts/defaults/research/step.md +0 -58
- gobby/prompts/defaults/validation/criteria.md +0 -47
- gobby/prompts/defaults/validation/validate.md +0 -38
- gobby/storage/migrations_legacy.py +0 -1359
- gobby/workflows/task_enforcement_actions.py +0 -1343
- {gobby-0.2.6.dist-info → gobby-0.2.7.dist-info}/entry_points.txt +0 -0
- {gobby-0.2.6.dist-info → gobby-0.2.7.dist-info}/licenses/LICENSE.md +0 -0
- {gobby-0.2.6.dist-info → gobby-0.2.7.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"""Session CRUD tools for session management.
|
|
2
|
+
|
|
3
|
+
This module contains MCP tools for:
|
|
4
|
+
- Getting session details (get_session)
|
|
5
|
+
- Getting current session (get_current)
|
|
6
|
+
- Listing sessions (list_sessions)
|
|
7
|
+
- Session statistics (session_stats)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from typing import TYPE_CHECKING, Any
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from gobby.mcp_proxy.tools.internal import InternalToolRegistry
|
|
16
|
+
from gobby.storage.sessions import LocalSessionManager
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def register_crud_tools(
|
|
20
|
+
registry: InternalToolRegistry,
|
|
21
|
+
session_manager: LocalSessionManager,
|
|
22
|
+
) -> None:
|
|
23
|
+
"""
|
|
24
|
+
Register session CRUD tools with a registry.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
registry: The InternalToolRegistry to register tools with
|
|
28
|
+
session_manager: LocalSessionManager instance for session operations
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
@registry.tool(
|
|
32
|
+
name="get_session",
|
|
33
|
+
description="Get session details by ID. Accepts #N (project-scoped ref), UUID, or prefix. Use the session_id from your injected context.",
|
|
34
|
+
)
|
|
35
|
+
def get_session(session_id: str) -> dict[str, Any]:
|
|
36
|
+
"""
|
|
37
|
+
Get session details by session reference.
|
|
38
|
+
|
|
39
|
+
Your session_id is injected into your context at session start.
|
|
40
|
+
Look for 'Session Ref: #N' or 'session_id: xxx' in your system reminders.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
session_id: Session reference - supports #N (project-scoped), UUID, or prefix
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
Session dict with all fields, or error if not found
|
|
47
|
+
"""
|
|
48
|
+
from gobby.utils.project_context import get_project_context
|
|
49
|
+
|
|
50
|
+
# Support #N format, UUID, and prefix matching
|
|
51
|
+
if session_manager is None:
|
|
52
|
+
return {"error": "Session manager not available"}
|
|
53
|
+
|
|
54
|
+
# Get project_id for project-scoped resolution
|
|
55
|
+
project_ctx = get_project_context()
|
|
56
|
+
project_id = project_ctx.get("id") if project_ctx else None
|
|
57
|
+
|
|
58
|
+
# Try to resolve session reference (#N, UUID, or prefix)
|
|
59
|
+
try:
|
|
60
|
+
resolved_id = session_manager.resolve_session_reference(session_id, project_id)
|
|
61
|
+
session = session_manager.get(resolved_id)
|
|
62
|
+
except ValueError:
|
|
63
|
+
session = None
|
|
64
|
+
|
|
65
|
+
if not session:
|
|
66
|
+
return {"error": f"Session {session_id} not found", "found": False}
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
"found": True,
|
|
70
|
+
**session.to_dict(),
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@registry.tool(
|
|
74
|
+
name="get_current",
|
|
75
|
+
description="""Get YOUR current session ID - the CORRECT way to look up your session.
|
|
76
|
+
|
|
77
|
+
Use this when session_id wasn't in your injected context. Pass your external_id
|
|
78
|
+
(from transcript path or GOBBY_SESSION_ID env) and source (claude, gemini, codex).
|
|
79
|
+
|
|
80
|
+
DO NOT use list_sessions to find your session - it won't work with multiple active sessions.""",
|
|
81
|
+
)
|
|
82
|
+
def get_current(
|
|
83
|
+
external_id: str,
|
|
84
|
+
source: str,
|
|
85
|
+
) -> dict[str, Any]:
|
|
86
|
+
"""
|
|
87
|
+
Look up your internal session_id from external_id and source.
|
|
88
|
+
|
|
89
|
+
The agent passes external_id (from injected context or GOBBY_SESSION_ID env var)
|
|
90
|
+
and source (claude, gemini, codex). project_id and machine_id are
|
|
91
|
+
auto-resolved from config files.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
external_id: Your CLI's session ID (from context or GOBBY_SESSION_ID env)
|
|
95
|
+
source: CLI source - "claude", "gemini", or "codex"
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
session_id: Internal Gobby session ID (use for parent_session_id, etc.)
|
|
99
|
+
Plus basic session metadata
|
|
100
|
+
"""
|
|
101
|
+
from gobby.utils.machine_id import get_machine_id
|
|
102
|
+
from gobby.utils.project_context import get_project_context
|
|
103
|
+
|
|
104
|
+
if session_manager is None:
|
|
105
|
+
return {"error": "Session manager not available"}
|
|
106
|
+
|
|
107
|
+
# Auto-resolve context
|
|
108
|
+
machine_id = get_machine_id()
|
|
109
|
+
project_ctx = get_project_context()
|
|
110
|
+
project_id = project_ctx.get("id") if project_ctx else None
|
|
111
|
+
|
|
112
|
+
if not machine_id:
|
|
113
|
+
return {"error": "Could not determine machine_id"}
|
|
114
|
+
if not project_id:
|
|
115
|
+
return {"error": "Could not determine project_id (not in a gobby project?)"}
|
|
116
|
+
|
|
117
|
+
# Use find_by_external_id with full composite key (safe lookup)
|
|
118
|
+
session = session_manager.find_by_external_id(
|
|
119
|
+
external_id=external_id,
|
|
120
|
+
machine_id=machine_id,
|
|
121
|
+
project_id=project_id,
|
|
122
|
+
source=source,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
if not session:
|
|
126
|
+
return {
|
|
127
|
+
"found": False,
|
|
128
|
+
"error": "Session not found",
|
|
129
|
+
"lookup": {
|
|
130
|
+
"external_id": external_id,
|
|
131
|
+
"source": source,
|
|
132
|
+
"project_id": project_id,
|
|
133
|
+
},
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
"found": True,
|
|
138
|
+
"session_id": session.id,
|
|
139
|
+
"project_id": session.project_id,
|
|
140
|
+
"status": session.status,
|
|
141
|
+
"agent_run_id": session.agent_run_id,
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
@registry.tool(
|
|
145
|
+
name="list_sessions",
|
|
146
|
+
description="""List sessions with optional filtering.
|
|
147
|
+
|
|
148
|
+
WARNING: Do NOT use this to find your own session_id!
|
|
149
|
+
- `list_sessions(status="active", limit=1)` will NOT reliably return YOUR session
|
|
150
|
+
- Multiple sessions can be active simultaneously (parallel agents, multiple terminals)
|
|
151
|
+
- Use `get_current(external_id, source)` instead - it uses your unique session key
|
|
152
|
+
|
|
153
|
+
This tool is for browsing/listing sessions, not for self-identification.""",
|
|
154
|
+
)
|
|
155
|
+
def list_sessions(
|
|
156
|
+
project_id: str | None = None,
|
|
157
|
+
status: str | None = None,
|
|
158
|
+
source: str | None = None,
|
|
159
|
+
limit: int = 20,
|
|
160
|
+
) -> dict[str, Any]:
|
|
161
|
+
"""
|
|
162
|
+
List sessions with filters.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
project_id: Filter by project ID
|
|
166
|
+
status: Filter by status (active, paused, expired, archived, handoff_ready)
|
|
167
|
+
source: Filter by CLI source (claude, gemini, codex)
|
|
168
|
+
limit: Max results (default 20)
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
List of sessions and count
|
|
172
|
+
"""
|
|
173
|
+
if session_manager is None:
|
|
174
|
+
return {"error": "Session manager not available"}
|
|
175
|
+
|
|
176
|
+
sessions = session_manager.list(
|
|
177
|
+
project_id=project_id,
|
|
178
|
+
status=status,
|
|
179
|
+
source=source,
|
|
180
|
+
limit=limit,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
total = session_manager.count(
|
|
184
|
+
project_id=project_id,
|
|
185
|
+
status=status,
|
|
186
|
+
source=source,
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
# Detect likely misuse pattern: trying to find own session
|
|
190
|
+
if status == "active" and limit == 1:
|
|
191
|
+
return {
|
|
192
|
+
"warning": (
|
|
193
|
+
"list_sessions(status='active', limit=1) will NOT reliably get YOUR session_id! "
|
|
194
|
+
"Multiple sessions can be active simultaneously. "
|
|
195
|
+
"Use get_current(external_id='<your-external-id>', source='claude') instead."
|
|
196
|
+
),
|
|
197
|
+
"hint": "Your external_id is in your transcript path: /path/to/<external_id>.jsonl",
|
|
198
|
+
"sessions": [s.to_dict() for s in sessions],
|
|
199
|
+
"count": len(sessions),
|
|
200
|
+
"total": total,
|
|
201
|
+
"limit": limit,
|
|
202
|
+
"filters": {
|
|
203
|
+
"project_id": project_id,
|
|
204
|
+
"status": status,
|
|
205
|
+
"source": source,
|
|
206
|
+
},
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
"sessions": [s.to_dict() for s in sessions],
|
|
211
|
+
"count": len(sessions),
|
|
212
|
+
"total": total,
|
|
213
|
+
"limit": limit,
|
|
214
|
+
"filters": {
|
|
215
|
+
"project_id": project_id,
|
|
216
|
+
"status": status,
|
|
217
|
+
"source": source,
|
|
218
|
+
},
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
@registry.tool(
|
|
222
|
+
name="session_stats",
|
|
223
|
+
description="Get session statistics for a project.",
|
|
224
|
+
)
|
|
225
|
+
def session_stats(project_id: str | None = None) -> dict[str, Any]:
|
|
226
|
+
"""
|
|
227
|
+
Get session statistics.
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
project_id: Filter by project ID (optional)
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
Statistics including total, by_status, by_source
|
|
234
|
+
"""
|
|
235
|
+
if session_manager is None:
|
|
236
|
+
return {"error": "Session manager not available"}
|
|
237
|
+
|
|
238
|
+
total = session_manager.count(project_id=project_id)
|
|
239
|
+
by_status = session_manager.count_by_status()
|
|
240
|
+
|
|
241
|
+
# Count by source
|
|
242
|
+
by_source: dict[str, int] = {}
|
|
243
|
+
for src in ["claude_code", "gemini", "codex"]:
|
|
244
|
+
count = session_manager.count(project_id=project_id, source=src)
|
|
245
|
+
if count > 0:
|
|
246
|
+
by_source[src] = count
|
|
247
|
+
|
|
248
|
+
return {
|
|
249
|
+
"total": total,
|
|
250
|
+
"by_status": by_status,
|
|
251
|
+
"by_source": by_source,
|
|
252
|
+
"project_id": project_id,
|
|
253
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Factory function for creating the session messages tool registry.
|
|
2
|
+
|
|
3
|
+
Orchestrates the creation of all session tool sub-registries and merges them
|
|
4
|
+
into a unified registry.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
10
|
+
|
|
11
|
+
from gobby.mcp_proxy.tools.internal import InternalToolRegistry
|
|
12
|
+
from gobby.mcp_proxy.tools.sessions._commits import register_commits_tools
|
|
13
|
+
from gobby.mcp_proxy.tools.sessions._crud import register_crud_tools
|
|
14
|
+
from gobby.mcp_proxy.tools.sessions._handoff import register_handoff_tools
|
|
15
|
+
from gobby.mcp_proxy.tools.sessions._messages import register_message_tools
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from gobby.storage.session_messages import LocalSessionMessageManager
|
|
19
|
+
from gobby.storage.sessions import LocalSessionManager
|
|
20
|
+
|
|
21
|
+
__all__ = ["create_session_messages_registry"]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def create_session_messages_registry(
|
|
25
|
+
message_manager: LocalSessionMessageManager | None = None,
|
|
26
|
+
session_manager: LocalSessionManager | None = None,
|
|
27
|
+
) -> InternalToolRegistry:
|
|
28
|
+
"""
|
|
29
|
+
Create a sessions tool registry with session and message tools.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
message_manager: LocalSessionMessageManager instance for message operations
|
|
33
|
+
session_manager: LocalSessionManager instance for session CRUD
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
InternalToolRegistry with all session tools registered
|
|
37
|
+
"""
|
|
38
|
+
registry = InternalToolRegistry(
|
|
39
|
+
name="gobby-sessions",
|
|
40
|
+
description="Session management and message querying - CRUD, retrieval, search",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# --- Message Tools ---
|
|
44
|
+
# Only register if message_manager is available
|
|
45
|
+
if message_manager is not None:
|
|
46
|
+
register_message_tools(registry, message_manager)
|
|
47
|
+
|
|
48
|
+
# --- Handoff Tools ---
|
|
49
|
+
# Only register if session_manager is available
|
|
50
|
+
if session_manager is not None:
|
|
51
|
+
register_handoff_tools(registry, session_manager)
|
|
52
|
+
|
|
53
|
+
# --- Session CRUD Tools ---
|
|
54
|
+
# Only register if session_manager is available
|
|
55
|
+
if session_manager is not None:
|
|
56
|
+
register_crud_tools(registry, session_manager)
|
|
57
|
+
|
|
58
|
+
# --- Commits Tools ---
|
|
59
|
+
# Only register if session_manager is available
|
|
60
|
+
if session_manager is not None:
|
|
61
|
+
register_commits_tools(registry, session_manager)
|
|
62
|
+
|
|
63
|
+
return registry
|