gobby 0.2.6__py3-none-any.whl → 0.2.8__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/claude_code.py +96 -35
- 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/adapters/gemini.py +140 -38
- gobby/agents/definitions.py +11 -1
- gobby/agents/isolation.py +525 -0
- gobby/agents/registry.py +11 -0
- gobby/agents/sandbox.py +261 -0
- gobby/agents/session.py +1 -0
- gobby/agents/spawn.py +42 -287
- gobby/agents/spawn_executor.py +415 -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/macos.py +26 -1
- gobby/agents/spawners/prompt_manager.py +125 -0
- gobby/cli/__init__.py +0 -2
- 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/memory.py +185 -0
- gobby/cli/sessions.py +1 -1
- gobby/cli/utils.py +9 -2
- gobby/clones/git.py +177 -0
- 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/skills.py +31 -0
- gobby/config/tasks.py +4 -28
- gobby/hooks/__init__.py +0 -13
- gobby/hooks/event_handlers.py +150 -8
- gobby/hooks/hook_manager.py +21 -3
- gobby/hooks/plugins.py +1 -1
- gobby/hooks/webhooks.py +1 -1
- gobby/install/gemini/hooks/hook_dispatcher.py +74 -15
- gobby/llm/resolver.py +3 -2
- gobby/mcp_proxy/importer.py +62 -4
- gobby/mcp_proxy/instructions.py +4 -2
- gobby/mcp_proxy/registries.py +22 -8
- gobby/mcp_proxy/services/recommendation.py +43 -11
- gobby/mcp_proxy/tools/agent_messaging.py +93 -44
- gobby/mcp_proxy/tools/agents.py +76 -740
- gobby/mcp_proxy/tools/artifacts.py +43 -9
- 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 +239 -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 +503 -0
- gobby/mcp_proxy/tools/sessions/_messages.py +166 -0
- gobby/mcp_proxy/tools/skills/__init__.py +14 -29
- gobby/mcp_proxy/tools/spawn_agent.py +455 -0
- gobby/mcp_proxy/tools/tasks/_context.py +18 -0
- gobby/mcp_proxy/tools/tasks/_crud.py +13 -6
- gobby/mcp_proxy/tools/tasks/_lifecycle.py +79 -30
- gobby/mcp_proxy/tools/tasks/_lifecycle_validation.py +1 -1
- gobby/mcp_proxy/tools/tasks/_session.py +22 -7
- gobby/mcp_proxy/tools/workflows.py +84 -34
- gobby/mcp_proxy/tools/worktrees.py +32 -350
- gobby/memory/extractor.py +15 -1
- 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/runner.py +13 -0
- 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 +51 -4
- gobby/servers/routes/mcp/tools.py +48 -1506
- gobby/servers/websocket.py +57 -1
- gobby/sessions/analyzer.py +2 -2
- gobby/sessions/lifecycle.py +1 -1
- gobby/sessions/manager.py +9 -0
- gobby/sessions/processor.py +10 -0
- gobby/sessions/transcripts/base.py +1 -0
- gobby/sessions/transcripts/claude.py +15 -5
- gobby/sessions/transcripts/gemini.py +100 -34
- gobby/skills/parser.py +30 -2
- gobby/storage/database.py +9 -2
- gobby/storage/memories.py +32 -21
- gobby/storage/migrations.py +174 -368
- gobby/storage/sessions.py +45 -7
- gobby/storage/skills.py +80 -7
- 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/detection_helpers.py +38 -24
- gobby/workflows/enforcement/__init__.py +47 -0
- gobby/workflows/enforcement/blocking.py +281 -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/engine.py +93 -0
- gobby/workflows/evaluator.py +110 -0
- gobby/workflows/git_utils.py +106 -0
- gobby/workflows/hooks.py +41 -0
- gobby/workflows/llm_actions.py +30 -0
- gobby/workflows/mcp_actions.py +20 -1
- gobby/workflows/memory_actions.py +91 -0
- gobby/workflows/safe_evaluator.py +191 -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 +217 -51
- 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.8.dist-info}/METADATA +6 -1
- {gobby-0.2.6.dist-info → gobby-0.2.8.dist-info}/RECORD +139 -163
- {gobby-0.2.6.dist-info → gobby-0.2.8.dist-info}/WHEEL +1 -1
- gobby/adapters/codex.py +0 -1332
- gobby/cli/tui.py +0 -34
- 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/tui/__init__.py +0 -5
- gobby/tui/api_client.py +0 -278
- gobby/tui/app.py +0 -329
- gobby/tui/screens/__init__.py +0 -25
- gobby/tui/screens/agents.py +0 -333
- gobby/tui/screens/chat.py +0 -450
- gobby/tui/screens/dashboard.py +0 -377
- gobby/tui/screens/memory.py +0 -305
- gobby/tui/screens/metrics.py +0 -231
- gobby/tui/screens/orchestrator.py +0 -903
- gobby/tui/screens/sessions.py +0 -412
- gobby/tui/screens/tasks.py +0 -440
- gobby/tui/screens/workflows.py +0 -289
- gobby/tui/screens/worktrees.py +0 -174
- gobby/tui/widgets/__init__.py +0 -21
- gobby/tui/widgets/chat.py +0 -210
- gobby/tui/widgets/conductor.py +0 -104
- gobby/tui/widgets/menu.py +0 -132
- gobby/tui/widgets/message_panel.py +0 -160
- gobby/tui/widgets/review_gate.py +0 -224
- gobby/tui/widgets/task_tree.py +0 -99
- gobby/tui/widgets/token_budget.py +0 -166
- gobby/tui/ws_client.py +0 -258
- gobby/workflows/task_enforcement_actions.py +0 -1343
- {gobby-0.2.6.dist-info → gobby-0.2.8.dist-info}/entry_points.txt +0 -0
- {gobby-0.2.6.dist-info → gobby-0.2.8.dist-info}/licenses/LICENSE.md +0 -0
- {gobby-0.2.6.dist-info → gobby-0.2.8.dist-info}/top_level.txt +0 -0
gobby/tui/screens/metrics.py
DELETED
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
"""Metrics screen with tool usage statistics."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import asyncio
|
|
6
|
-
from typing import Any
|
|
7
|
-
|
|
8
|
-
from textual.app import ComposeResult
|
|
9
|
-
from textual.containers import Container, Horizontal, Vertical
|
|
10
|
-
from textual.css.query import NoMatches
|
|
11
|
-
from textual.reactive import reactive
|
|
12
|
-
from textual.widget import Widget
|
|
13
|
-
from textual.widgets import (
|
|
14
|
-
Button,
|
|
15
|
-
DataTable,
|
|
16
|
-
LoadingIndicator,
|
|
17
|
-
Static,
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
from gobby.tui.api_client import GobbyAPIClient
|
|
21
|
-
from gobby.tui.ws_client import GobbyWebSocketClient
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class MetricsSummaryPanel(Widget):
|
|
25
|
-
"""Panel showing metrics summary."""
|
|
26
|
-
|
|
27
|
-
DEFAULT_CSS = """
|
|
28
|
-
MetricsSummaryPanel {
|
|
29
|
-
height: auto;
|
|
30
|
-
padding: 1;
|
|
31
|
-
border: round #45475a;
|
|
32
|
-
margin: 1;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
MetricsSummaryPanel .summary-title {
|
|
36
|
-
text-style: bold;
|
|
37
|
-
color: #a78bfa;
|
|
38
|
-
padding-bottom: 1;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
MetricsSummaryPanel .summary-grid {
|
|
42
|
-
layout: grid;
|
|
43
|
-
grid-size: 4 1;
|
|
44
|
-
grid-gutter: 2;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
MetricsSummaryPanel .stat-box {
|
|
48
|
-
height: 4;
|
|
49
|
-
border: round #45475a;
|
|
50
|
-
padding: 0 1;
|
|
51
|
-
content-align: center middle;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
MetricsSummaryPanel .stat-value {
|
|
55
|
-
text-style: bold;
|
|
56
|
-
color: #06b6d4;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
MetricsSummaryPanel .stat-label {
|
|
60
|
-
color: #a6adc8;
|
|
61
|
-
}
|
|
62
|
-
"""
|
|
63
|
-
|
|
64
|
-
metrics: reactive[dict[str, Any] | None] = reactive(None)
|
|
65
|
-
|
|
66
|
-
def compose(self) -> ComposeResult:
|
|
67
|
-
yield Static("📊 Summary", classes="summary-title")
|
|
68
|
-
|
|
69
|
-
with Horizontal(classes="summary-grid"):
|
|
70
|
-
# Total calls
|
|
71
|
-
with Vertical(classes="stat-box"):
|
|
72
|
-
total = self.metrics.get("total_calls", 0) if self.metrics else 0
|
|
73
|
-
yield Static(str(total), classes="stat-value")
|
|
74
|
-
yield Static("Total Calls", classes="stat-label")
|
|
75
|
-
|
|
76
|
-
# Success rate
|
|
77
|
-
with Vertical(classes="stat-box"):
|
|
78
|
-
rate = self.metrics.get("success_rate", 0) if self.metrics else 0
|
|
79
|
-
yield Static(f"{rate:.1%}", classes="stat-value")
|
|
80
|
-
yield Static("Success Rate", classes="stat-label")
|
|
81
|
-
|
|
82
|
-
# Avg response time
|
|
83
|
-
with Vertical(classes="stat-box"):
|
|
84
|
-
avg_time = self.metrics.get("avg_response_ms", 0) if self.metrics else 0
|
|
85
|
-
yield Static(f"{avg_time:.0f}ms", classes="stat-value")
|
|
86
|
-
yield Static("Avg Response", classes="stat-label")
|
|
87
|
-
|
|
88
|
-
# Active servers
|
|
89
|
-
with Vertical(classes="stat-box"):
|
|
90
|
-
servers = self.metrics.get("active_servers", 0) if self.metrics else 0
|
|
91
|
-
yield Static(str(servers), classes="stat-value")
|
|
92
|
-
yield Static("Active Servers", classes="stat-label")
|
|
93
|
-
|
|
94
|
-
def watch_metrics(self, metrics: dict[str, Any] | None) -> None:
|
|
95
|
-
"""Recompose when metrics change."""
|
|
96
|
-
asyncio.create_task(self.recompose())
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
class MetricsScreen(Widget):
|
|
100
|
-
"""Metrics screen showing tool usage statistics."""
|
|
101
|
-
|
|
102
|
-
DEFAULT_CSS = """
|
|
103
|
-
MetricsScreen {
|
|
104
|
-
width: 1fr;
|
|
105
|
-
height: 1fr;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
MetricsScreen .screen-header {
|
|
109
|
-
height: auto;
|
|
110
|
-
padding: 1;
|
|
111
|
-
background: #313244;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
MetricsScreen .header-row {
|
|
115
|
-
layout: horizontal;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
MetricsScreen .panel-title {
|
|
119
|
-
text-style: bold;
|
|
120
|
-
color: #a78bfa;
|
|
121
|
-
width: 1fr;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
MetricsScreen .content-area {
|
|
125
|
-
height: 1fr;
|
|
126
|
-
padding: 1;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
MetricsScreen #tools-table {
|
|
130
|
-
height: 1fr;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
MetricsScreen .loading-container {
|
|
134
|
-
width: 1fr;
|
|
135
|
-
height: 1fr;
|
|
136
|
-
content-align: center middle;
|
|
137
|
-
}
|
|
138
|
-
"""
|
|
139
|
-
|
|
140
|
-
loading = reactive(True)
|
|
141
|
-
metrics: reactive[dict[str, Any] | None] = reactive(None)
|
|
142
|
-
tool_metrics: reactive[list[dict[str, Any]]] = reactive(list)
|
|
143
|
-
|
|
144
|
-
def __init__(
|
|
145
|
-
self,
|
|
146
|
-
api_client: GobbyAPIClient,
|
|
147
|
-
ws_client: GobbyWebSocketClient,
|
|
148
|
-
**kwargs: Any,
|
|
149
|
-
) -> None:
|
|
150
|
-
super().__init__(**kwargs)
|
|
151
|
-
self.api_client = api_client
|
|
152
|
-
self.ws_client = ws_client
|
|
153
|
-
|
|
154
|
-
def compose(self) -> ComposeResult:
|
|
155
|
-
with Vertical(classes="screen-header"):
|
|
156
|
-
with Horizontal(classes="header-row"):
|
|
157
|
-
yield Static("📈 Metrics", classes="panel-title")
|
|
158
|
-
yield Button("Refresh", id="btn-refresh")
|
|
159
|
-
yield Button("Export", id="btn-export")
|
|
160
|
-
|
|
161
|
-
if self.loading:
|
|
162
|
-
with Container(classes="loading-container"):
|
|
163
|
-
yield LoadingIndicator()
|
|
164
|
-
else:
|
|
165
|
-
with Vertical(classes="content-area"):
|
|
166
|
-
yield MetricsSummaryPanel(id="summary-panel")
|
|
167
|
-
yield Static("Tool Usage", classes="panel-title")
|
|
168
|
-
yield DataTable(id="tools-table")
|
|
169
|
-
|
|
170
|
-
async def on_mount(self) -> None:
|
|
171
|
-
"""Load data when mounted."""
|
|
172
|
-
await self.refresh_data()
|
|
173
|
-
|
|
174
|
-
async def refresh_data(self) -> None:
|
|
175
|
-
"""Refresh metrics data."""
|
|
176
|
-
try:
|
|
177
|
-
async with GobbyAPIClient(self.api_client.base_url) as client:
|
|
178
|
-
result = await client.call_tool(
|
|
179
|
-
"gobby-metrics",
|
|
180
|
-
"get_metrics",
|
|
181
|
-
{},
|
|
182
|
-
)
|
|
183
|
-
self.metrics = result.get("summary", {})
|
|
184
|
-
self.tool_metrics = result.get("tools", [])
|
|
185
|
-
|
|
186
|
-
except Exception as e:
|
|
187
|
-
self.notify(f"Failed to load metrics: {e}", severity="error")
|
|
188
|
-
finally:
|
|
189
|
-
self.loading = False
|
|
190
|
-
await self.recompose()
|
|
191
|
-
await self._update_summary()
|
|
192
|
-
await self._setup_table()
|
|
193
|
-
|
|
194
|
-
async def _update_summary(self) -> None:
|
|
195
|
-
"""Update the summary panel."""
|
|
196
|
-
try:
|
|
197
|
-
panel = self.query_one("#summary-panel", MetricsSummaryPanel)
|
|
198
|
-
panel.metrics = self.metrics
|
|
199
|
-
except NoMatches:
|
|
200
|
-
pass # Widget may not be mounted yet
|
|
201
|
-
|
|
202
|
-
async def _setup_table(self) -> None:
|
|
203
|
-
"""Set up and populate the tools table."""
|
|
204
|
-
try:
|
|
205
|
-
table = self.query_one("#tools-table", DataTable)
|
|
206
|
-
table.clear(columns=True)
|
|
207
|
-
table.add_columns("Server", "Tool", "Calls", "Success", "Avg Time")
|
|
208
|
-
table.cursor_type = "row"
|
|
209
|
-
|
|
210
|
-
for tool in self.tool_metrics:
|
|
211
|
-
server = tool.get("server", "unknown")
|
|
212
|
-
name = tool.get("name", "unknown")
|
|
213
|
-
calls = str(tool.get("calls", 0))
|
|
214
|
-
success = f"{tool.get('success_rate', 0):.1%}"
|
|
215
|
-
avg_time = f"{tool.get('avg_ms', 0):.0f}ms"
|
|
216
|
-
|
|
217
|
-
table.add_row(server, name, calls, success, avg_time)
|
|
218
|
-
|
|
219
|
-
except NoMatches:
|
|
220
|
-
pass # Table widget may not be mounted yet
|
|
221
|
-
|
|
222
|
-
async def on_button_pressed(self, event: Button.Pressed) -> None:
|
|
223
|
-
"""Handle button presses."""
|
|
224
|
-
button_id = event.button.id
|
|
225
|
-
|
|
226
|
-
if button_id == "btn-refresh":
|
|
227
|
-
self.loading = True
|
|
228
|
-
await self.refresh_data()
|
|
229
|
-
|
|
230
|
-
elif button_id == "btn-export":
|
|
231
|
-
self.notify("Export coming soon", severity="information")
|