gobby 0.2.5__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/claude_code.py +13 -4
- 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/runner.py +8 -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/__init__.py +6 -0
- gobby/cli/clones.py +419 -0
- gobby/cli/conductor.py +266 -0
- gobby/cli/install.py +4 -4
- gobby/cli/installers/antigravity.py +3 -9
- gobby/cli/installers/claude.py +15 -9
- gobby/cli/installers/codex.py +2 -8
- gobby/cli/installers/gemini.py +8 -8
- gobby/cli/installers/shared.py +175 -13
- gobby/cli/sessions.py +1 -1
- gobby/cli/skills.py +858 -0
- gobby/cli/tasks/ai.py +0 -440
- gobby/cli/tasks/crud.py +44 -6
- gobby/cli/tasks/main.py +0 -4
- gobby/cli/tui.py +2 -2
- gobby/cli/utils.py +12 -5
- gobby/clones/__init__.py +13 -0
- gobby/clones/git.py +547 -0
- gobby/conductor/__init__.py +16 -0
- gobby/conductor/alerts.py +135 -0
- gobby/conductor/loop.py +164 -0
- gobby/conductor/monitors/__init__.py +11 -0
- gobby/conductor/monitors/agents.py +116 -0
- gobby/conductor/monitors/tasks.py +155 -0
- gobby/conductor/pricing.py +234 -0
- gobby/conductor/token_tracker.py +160 -0
- gobby/config/__init__.py +12 -97
- gobby/config/app.py +69 -91
- gobby/config/extensions.py +2 -2
- gobby/config/features.py +7 -130
- gobby/config/search.py +110 -0
- gobby/config/servers.py +1 -1
- gobby/config/skills.py +43 -0
- gobby/config/tasks.py +9 -41
- gobby/hooks/__init__.py +0 -13
- gobby/hooks/event_handlers.py +188 -2
- gobby/hooks/hook_manager.py +50 -4
- gobby/hooks/plugins.py +1 -1
- gobby/hooks/skill_manager.py +130 -0
- gobby/hooks/webhooks.py +1 -1
- gobby/install/claude/hooks/hook_dispatcher.py +4 -4
- gobby/install/codex/hooks/hook_dispatcher.py +1 -1
- gobby/install/gemini/hooks/hook_dispatcher.py +87 -12
- gobby/llm/claude.py +22 -34
- gobby/llm/claude_executor.py +46 -256
- gobby/llm/codex_executor.py +59 -291
- gobby/llm/executor.py +21 -0
- gobby/llm/gemini.py +134 -110
- gobby/llm/litellm_executor.py +143 -6
- gobby/llm/resolver.py +98 -35
- gobby/mcp_proxy/importer.py +62 -4
- gobby/mcp_proxy/instructions.py +56 -0
- gobby/mcp_proxy/models.py +15 -0
- gobby/mcp_proxy/registries.py +68 -8
- gobby/mcp_proxy/server.py +33 -3
- gobby/mcp_proxy/services/recommendation.py +43 -11
- gobby/mcp_proxy/services/tool_proxy.py +81 -1
- gobby/mcp_proxy/stdio.py +2 -1
- gobby/mcp_proxy/tools/__init__.py +0 -2
- gobby/mcp_proxy/tools/agent_messaging.py +317 -0
- gobby/mcp_proxy/tools/agents.py +31 -731
- gobby/mcp_proxy/tools/clones.py +518 -0
- gobby/mcp_proxy/tools/memory.py +3 -26
- gobby/mcp_proxy/tools/metrics.py +65 -1
- gobby/mcp_proxy/tools/orchestration/__init__.py +3 -0
- gobby/mcp_proxy/tools/orchestration/cleanup.py +151 -0
- gobby/mcp_proxy/tools/orchestration/wait.py +467 -0
- 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 +616 -0
- gobby/mcp_proxy/tools/spawn_agent.py +417 -0
- gobby/mcp_proxy/tools/task_orchestration.py +7 -0
- gobby/mcp_proxy/tools/task_readiness.py +14 -0
- gobby/mcp_proxy/tools/task_sync.py +1 -1
- gobby/mcp_proxy/tools/tasks/_context.py +0 -20
- gobby/mcp_proxy/tools/tasks/_crud.py +91 -4
- gobby/mcp_proxy/tools/tasks/_expansion.py +348 -0
- gobby/mcp_proxy/tools/tasks/_factory.py +6 -16
- gobby/mcp_proxy/tools/tasks/_lifecycle.py +110 -45
- gobby/mcp_proxy/tools/tasks/_lifecycle_validation.py +18 -29
- gobby/mcp_proxy/tools/workflows.py +1 -1
- gobby/mcp_proxy/tools/worktrees.py +0 -338
- gobby/memory/backends/__init__.py +6 -1
- gobby/memory/backends/mem0.py +6 -1
- gobby/memory/extractor.py +477 -0
- gobby/memory/ingestion/__init__.py +5 -0
- gobby/memory/ingestion/multimodal.py +221 -0
- gobby/memory/manager.py +73 -285
- 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 +37 -16
- gobby/search/__init__.py +48 -6
- gobby/search/backends/__init__.py +159 -0
- gobby/search/backends/embedding.py +225 -0
- gobby/search/embeddings.py +238 -0
- gobby/search/models.py +148 -0
- gobby/search/unified.py +496 -0
- gobby/servers/http.py +24 -12
- gobby/servers/routes/admin.py +294 -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 -1317
- gobby/servers/websocket.py +2 -2
- gobby/sessions/analyzer.py +2 -0
- gobby/sessions/lifecycle.py +1 -1
- gobby/sessions/processor.py +10 -0
- gobby/sessions/transcripts/base.py +2 -0
- gobby/sessions/transcripts/claude.py +79 -10
- gobby/skills/__init__.py +91 -0
- gobby/skills/loader.py +685 -0
- gobby/skills/manager.py +384 -0
- gobby/skills/parser.py +286 -0
- gobby/skills/search.py +463 -0
- gobby/skills/sync.py +119 -0
- gobby/skills/updater.py +385 -0
- gobby/skills/validator.py +368 -0
- gobby/storage/clones.py +378 -0
- gobby/storage/database.py +1 -1
- gobby/storage/memories.py +43 -13
- gobby/storage/migrations.py +162 -201
- gobby/storage/sessions.py +116 -7
- gobby/storage/skills.py +782 -0
- gobby/storage/tasks/_crud.py +4 -4
- gobby/storage/tasks/_lifecycle.py +57 -7
- gobby/storage/tasks/_manager.py +14 -5
- gobby/storage/tasks/_models.py +8 -3
- gobby/sync/memories.py +40 -5
- gobby/sync/tasks.py +83 -6
- gobby/tasks/__init__.py +1 -2
- gobby/tasks/external_validator.py +1 -1
- gobby/tasks/validation.py +46 -35
- gobby/tools/summarizer.py +91 -10
- gobby/tui/api_client.py +4 -7
- gobby/tui/app.py +5 -3
- gobby/tui/screens/orchestrator.py +1 -2
- gobby/tui/screens/tasks.py +2 -4
- gobby/tui/ws_client.py +1 -1
- gobby/utils/daemon_client.py +2 -2
- gobby/utils/project_context.py +2 -3
- gobby/utils/status.py +13 -0
- gobby/workflows/actions.py +221 -1135
- gobby/workflows/artifact_actions.py +31 -0
- gobby/workflows/autonomous_actions.py +11 -0
- gobby/workflows/context_actions.py +93 -1
- gobby/workflows/detection_helpers.py +115 -31
- 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/{task_enforcement_actions.py → enforcement/task_policy.py} +29 -388
- gobby/workflows/engine.py +13 -2
- gobby/workflows/git_utils.py +106 -0
- gobby/workflows/lifecycle_evaluator.py +29 -1
- gobby/workflows/llm_actions.py +30 -0
- gobby/workflows/loader.py +19 -6
- gobby/workflows/mcp_actions.py +20 -1
- gobby/workflows/memory_actions.py +154 -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 +111 -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.5.dist-info → gobby-0.2.7.dist-info}/METADATA +87 -21
- {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/RECORD +201 -172
- {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/WHEEL +1 -1
- gobby/adapters/codex.py +0 -1292
- 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/install/codex/prompts/forget.md +0 -7
- gobby/install/codex/prompts/memories.md +0 -7
- gobby/install/codex/prompts/recall.md +0 -7
- gobby/install/codex/prompts/remember.md +0 -13
- gobby/llm/gemini_executor.py +0 -339
- gobby/mcp_proxy/tools/session_messages.py +0 -1056
- gobby/mcp_proxy/tools/task_expansion.py +0 -591
- 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/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/tasks/context.py +0 -747
- gobby/tasks/criteria.py +0 -342
- gobby/tasks/expansion.py +0 -626
- gobby/tasks/prompts/expand.py +0 -327
- gobby/tasks/research.py +0 -421
- gobby/tasks/tdd.py +0 -352
- {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/entry_points.txt +0 -0
- {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/licenses/LICENSE.md +0 -0
- {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/top_level.txt +0 -0
gobby/tools/summarizer.py
CHANGED
|
@@ -11,7 +11,8 @@ import logging
|
|
|
11
11
|
from typing import TYPE_CHECKING, Any
|
|
12
12
|
|
|
13
13
|
if TYPE_CHECKING:
|
|
14
|
-
from gobby.config.
|
|
14
|
+
from gobby.config.features import ToolSummarizerConfig
|
|
15
|
+
from gobby.prompts import PromptLoader
|
|
15
16
|
|
|
16
17
|
logger = logging.getLogger(__name__)
|
|
17
18
|
|
|
@@ -20,12 +21,42 @@ MAX_DESCRIPTION_LENGTH = 200
|
|
|
20
21
|
|
|
21
22
|
# Module-level config reference (set by init_summarizer_config)
|
|
22
23
|
_config: ToolSummarizerConfig | None = None
|
|
24
|
+
_loader: PromptLoader | None = None
|
|
23
25
|
|
|
26
|
+
DEFAULT_SUMMARY_PROMPT = """Summarize this MCP tool description in 180 characters or less.
|
|
27
|
+
Keep it to three sentences or less. Be concise and preserve the key functionality.
|
|
28
|
+
Do not add quotes, extra formatting, or code examples.
|
|
24
29
|
|
|
25
|
-
|
|
30
|
+
Description: {description}
|
|
31
|
+
|
|
32
|
+
Summary:"""
|
|
33
|
+
|
|
34
|
+
DEFAULT_SUMMARY_SYSTEM_PROMPT = "You are a technical summarizer. Create concise tool descriptions."
|
|
35
|
+
|
|
36
|
+
DEFAULT_SERVER_DESC_PROMPT = """Write a single concise sentence describing what the '{server_name}' MCP server does based on its tools.
|
|
37
|
+
|
|
38
|
+
Tools:
|
|
39
|
+
{tools_list}
|
|
40
|
+
|
|
41
|
+
Description (1 sentence, try to keep under 100 characters):"""
|
|
42
|
+
|
|
43
|
+
DEFAULT_SERVER_DESC_SYSTEM_PROMPT = "You write concise technical descriptions."
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def init_summarizer_config(config: ToolSummarizerConfig, project_dir: str | None = None) -> None:
|
|
26
47
|
"""Initialize the summarizer with configuration."""
|
|
27
|
-
|
|
48
|
+
from pathlib import Path
|
|
49
|
+
|
|
50
|
+
global _config, _loader
|
|
28
51
|
_config = config
|
|
52
|
+
_loader = PromptLoader(project_dir=Path(project_dir) if project_dir else None)
|
|
53
|
+
# Register fallbacks
|
|
54
|
+
_loader.register_fallback("features/tool_summary", lambda: DEFAULT_SUMMARY_PROMPT)
|
|
55
|
+
_loader.register_fallback("features/tool_summary_system", lambda: DEFAULT_SUMMARY_SYSTEM_PROMPT)
|
|
56
|
+
_loader.register_fallback("features/server_description", lambda: DEFAULT_SERVER_DESC_PROMPT)
|
|
57
|
+
_loader.register_fallback(
|
|
58
|
+
"features/server_description_system", lambda: DEFAULT_SERVER_DESC_SYSTEM_PROMPT
|
|
59
|
+
)
|
|
29
60
|
|
|
30
61
|
|
|
31
62
|
def _get_config() -> ToolSummarizerConfig:
|
|
@@ -33,7 +64,12 @@ def _get_config() -> ToolSummarizerConfig:
|
|
|
33
64
|
if _config is not None:
|
|
34
65
|
return _config
|
|
35
66
|
# Import here to avoid circular imports
|
|
36
|
-
from gobby.config.
|
|
67
|
+
from gobby.config.features import ToolSummarizerConfig
|
|
68
|
+
|
|
69
|
+
# Ensure loader defaults exist even if init wasn't called
|
|
70
|
+
global _loader
|
|
71
|
+
if _loader is None:
|
|
72
|
+
_loader = PromptLoader()
|
|
37
73
|
|
|
38
74
|
return ToolSummarizerConfig()
|
|
39
75
|
|
|
@@ -53,11 +89,30 @@ async def _summarize_description_with_claude(description: str) -> str:
|
|
|
53
89
|
try:
|
|
54
90
|
from claude_agent_sdk import AssistantMessage, ClaudeAgentOptions, TextBlock, query
|
|
55
91
|
|
|
56
|
-
|
|
92
|
+
# Get summary prompt
|
|
93
|
+
prompt_path = config.prompt_path or "features/tool_summary"
|
|
94
|
+
try:
|
|
95
|
+
# We assume _loader is initialized by _get_config() logic or init
|
|
96
|
+
if _loader is None:
|
|
97
|
+
raise RuntimeError("Summarizer not initialized")
|
|
98
|
+
prompt = _loader.render(prompt_path, {"description": description})
|
|
99
|
+
except (FileNotFoundError, OSError, KeyError, ValueError, RuntimeError) as e:
|
|
100
|
+
logger.debug(f"Failed to load prompt from {prompt_path}: {e}, using default")
|
|
101
|
+
prompt = DEFAULT_SUMMARY_PROMPT.format(description=description)
|
|
102
|
+
|
|
103
|
+
# Get system prompt
|
|
104
|
+
sys_prompt_path = config.system_prompt_path or "features/tool_summary_system"
|
|
105
|
+
try:
|
|
106
|
+
if _loader is None:
|
|
107
|
+
raise RuntimeError("Summarizer not initialized")
|
|
108
|
+
system_prompt = _loader.render(sys_prompt_path, {})
|
|
109
|
+
except (FileNotFoundError, OSError, KeyError, ValueError, RuntimeError) as e:
|
|
110
|
+
logger.debug(f"Failed to load system prompt from {sys_prompt_path}: {e}, using default")
|
|
111
|
+
system_prompt = DEFAULT_SUMMARY_SYSTEM_PROMPT
|
|
57
112
|
|
|
58
113
|
# Configure for single-turn completion
|
|
59
114
|
options = ClaudeAgentOptions(
|
|
60
|
-
system_prompt=
|
|
115
|
+
system_prompt=system_prompt,
|
|
61
116
|
max_turns=1,
|
|
62
117
|
model=config.model,
|
|
63
118
|
allowed_tools=[],
|
|
@@ -137,14 +192,40 @@ async def generate_server_description(
|
|
|
137
192
|
# Build tools list for prompt
|
|
138
193
|
tools_list = "\n".join([f"- {t['name']}: {t['description']}" for t in tool_summaries])
|
|
139
194
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
195
|
+
# Build prompt
|
|
196
|
+
prompt_path = config.server_description_prompt_path or "features/server_description"
|
|
197
|
+
context = {
|
|
198
|
+
"server_name": server_name,
|
|
199
|
+
"tools_list": tools_list,
|
|
200
|
+
}
|
|
201
|
+
try:
|
|
202
|
+
if _loader is None:
|
|
203
|
+
_get_config() # force init
|
|
204
|
+
if _loader is None:
|
|
205
|
+
# Still None after _get_config, use default
|
|
206
|
+
prompt = DEFAULT_SERVER_DESC_PROMPT.format(**context)
|
|
207
|
+
else:
|
|
208
|
+
prompt = _loader.render(prompt_path, context)
|
|
209
|
+
except (FileNotFoundError, OSError, KeyError, ValueError, RuntimeError) as e:
|
|
210
|
+
logger.debug(f"Failed to load prompt from {prompt_path}: {e}, using default")
|
|
211
|
+
prompt = DEFAULT_SERVER_DESC_PROMPT.format(**context)
|
|
212
|
+
|
|
213
|
+
# Get system prompt
|
|
214
|
+
sys_prompt_path = (
|
|
215
|
+
config.server_description_system_prompt_path or "features/server_description_system"
|
|
143
216
|
)
|
|
217
|
+
try:
|
|
218
|
+
if _loader is None:
|
|
219
|
+
system_prompt = DEFAULT_SERVER_DESC_SYSTEM_PROMPT
|
|
220
|
+
else:
|
|
221
|
+
system_prompt = _loader.render(sys_prompt_path, {})
|
|
222
|
+
except (FileNotFoundError, OSError, KeyError, ValueError, RuntimeError) as e:
|
|
223
|
+
logger.debug(f"Failed to load system prompt from {sys_prompt_path}: {e}, using default")
|
|
224
|
+
system_prompt = DEFAULT_SERVER_DESC_SYSTEM_PROMPT
|
|
144
225
|
|
|
145
226
|
# Configure for single-turn completion
|
|
146
227
|
options = ClaudeAgentOptions(
|
|
147
|
-
system_prompt=
|
|
228
|
+
system_prompt=system_prompt,
|
|
148
229
|
max_turns=1,
|
|
149
230
|
model=config.model,
|
|
150
231
|
allowed_tools=[],
|
gobby/tui/api_client.py
CHANGED
|
@@ -10,7 +10,7 @@ import httpx
|
|
|
10
10
|
class GobbyAPIClient:
|
|
11
11
|
"""HTTP client for communicating with Gobby daemon."""
|
|
12
12
|
|
|
13
|
-
def __init__(self, base_url: str = "http://localhost:
|
|
13
|
+
def __init__(self, base_url: str = "http://localhost:60887") -> None:
|
|
14
14
|
self.base_url = base_url.rstrip("/")
|
|
15
15
|
self._client: httpx.AsyncClient | None = None
|
|
16
16
|
|
|
@@ -177,17 +177,14 @@ class GobbyAPIClient:
|
|
|
177
177
|
self,
|
|
178
178
|
task_id: str,
|
|
179
179
|
commit_sha: str | None = None,
|
|
180
|
-
|
|
181
|
-
override_justification: str | None = None,
|
|
180
|
+
reason: str | None = None,
|
|
182
181
|
) -> dict[str, Any]:
|
|
183
182
|
"""Close a task."""
|
|
184
183
|
args: dict[str, Any] = {"task_id": task_id}
|
|
185
184
|
if commit_sha:
|
|
186
185
|
args["commit_sha"] = commit_sha
|
|
187
|
-
if
|
|
188
|
-
args["
|
|
189
|
-
if override_justification:
|
|
190
|
-
args["override_justification"] = override_justification
|
|
186
|
+
if reason:
|
|
187
|
+
args["reason"] = reason
|
|
191
188
|
return await self.call_tool("gobby-tasks", "close_task", args)
|
|
192
189
|
|
|
193
190
|
async def suggest_next_task(self) -> dict[str, Any]:
|
gobby/tui/app.py
CHANGED
|
@@ -158,8 +158,8 @@ class GobbyApp(App[None]):
|
|
|
158
158
|
|
|
159
159
|
def __init__(
|
|
160
160
|
self,
|
|
161
|
-
daemon_url: str = "http://localhost:
|
|
162
|
-
ws_url: str = "ws://localhost:
|
|
161
|
+
daemon_url: str = "http://localhost:60887",
|
|
162
|
+
ws_url: str = "ws://localhost:60888",
|
|
163
163
|
) -> None:
|
|
164
164
|
super().__init__()
|
|
165
165
|
self.daemon_url = daemon_url
|
|
@@ -321,7 +321,9 @@ class GobbyApp(App[None]):
|
|
|
321
321
|
await self.ws_client.disconnect()
|
|
322
322
|
|
|
323
323
|
|
|
324
|
-
def run_tui(
|
|
324
|
+
def run_tui(
|
|
325
|
+
daemon_url: str = "http://localhost:60887", ws_url: str = "ws://localhost:60888"
|
|
326
|
+
) -> None:
|
|
325
327
|
"""Entry point for the TUI application."""
|
|
326
328
|
app = GobbyApp(daemon_url=daemon_url, ws_url=ws_url)
|
|
327
329
|
app.run()
|
|
@@ -826,8 +826,7 @@ class OrchestratorScreen(Widget):
|
|
|
826
826
|
return
|
|
827
827
|
await self.api_client.close_task(
|
|
828
828
|
task_id,
|
|
829
|
-
|
|
830
|
-
override_justification="Orchestrator approval - manual user review",
|
|
829
|
+
reason="completed",
|
|
831
830
|
)
|
|
832
831
|
self.notify(f"Approved: {task.get('ref', task_id)}")
|
|
833
832
|
|
gobby/tui/screens/tasks.py
CHANGED
|
@@ -403,16 +403,14 @@ class TasksScreen(Widget):
|
|
|
403
403
|
# Note: In real usage, this would need a commit SHA
|
|
404
404
|
await client.close_task(
|
|
405
405
|
task_id,
|
|
406
|
-
|
|
407
|
-
override_justification="TUI completion - manual user action",
|
|
406
|
+
reason="obsolete",
|
|
408
407
|
)
|
|
409
408
|
self.notify(f"Task completed: {task_id}")
|
|
410
409
|
|
|
411
410
|
elif button_id == "btn-approve":
|
|
412
411
|
await client.close_task(
|
|
413
412
|
task_id,
|
|
414
|
-
|
|
415
|
-
override_justification="TUI approval - manual user review",
|
|
413
|
+
reason="obsolete",
|
|
416
414
|
)
|
|
417
415
|
self.notify(f"Task approved: {task_id}")
|
|
418
416
|
|
gobby/tui/ws_client.py
CHANGED
gobby/utils/daemon_client.py
CHANGED
|
@@ -11,7 +11,7 @@ Example:
|
|
|
11
11
|
```python
|
|
12
12
|
from gobby.utils.daemon_client import DaemonClient
|
|
13
13
|
|
|
14
|
-
client = DaemonClient(host="localhost", port=
|
|
14
|
+
client = DaemonClient(host="localhost", port=60887)
|
|
15
15
|
|
|
16
16
|
# Check daemon health
|
|
17
17
|
is_healthy, error = client.check_health()
|
|
@@ -57,7 +57,7 @@ class DaemonClient:
|
|
|
57
57
|
def __init__(
|
|
58
58
|
self,
|
|
59
59
|
host: str = "localhost",
|
|
60
|
-
port: int =
|
|
60
|
+
port: int = 60887,
|
|
61
61
|
timeout: float = 5.0,
|
|
62
62
|
logger: logging.Logger | None = None,
|
|
63
63
|
):
|
gobby/utils/project_context.py
CHANGED
|
@@ -10,8 +10,7 @@ from pathlib import Path
|
|
|
10
10
|
from typing import TYPE_CHECKING, Any, cast
|
|
11
11
|
|
|
12
12
|
if TYPE_CHECKING:
|
|
13
|
-
from gobby.config.
|
|
14
|
-
from gobby.config.features import HooksConfig
|
|
13
|
+
from gobby.config.features import HooksConfig, ProjectVerificationConfig
|
|
15
14
|
|
|
16
15
|
logger = logging.getLogger(__name__)
|
|
17
16
|
|
|
@@ -138,7 +137,7 @@ def get_verification_config(cwd: Path | None = None) -> ProjectVerificationConfi
|
|
|
138
137
|
Returns:
|
|
139
138
|
ProjectVerificationConfig if verification section exists, None otherwise.
|
|
140
139
|
"""
|
|
141
|
-
from gobby.config.
|
|
140
|
+
from gobby.config.features import ProjectVerificationConfig
|
|
142
141
|
|
|
143
142
|
context = get_project_context(cwd)
|
|
144
143
|
if not context:
|
gobby/utils/status.py
CHANGED
|
@@ -79,6 +79,11 @@ def fetch_rich_status(http_port: int, timeout: float = 2.0) -> dict[str, Any]:
|
|
|
79
79
|
status_kwargs["memories_count"] = memory.get("count", 0)
|
|
80
80
|
status_kwargs["memories_avg_importance"] = memory.get("avg_importance", 0.0)
|
|
81
81
|
|
|
82
|
+
# Skills
|
|
83
|
+
skills_data = data.get("skills", {})
|
|
84
|
+
if skills_data:
|
|
85
|
+
status_kwargs["skills_total"] = skills_data.get("total", 0)
|
|
86
|
+
|
|
82
87
|
except (httpx.ConnectError, httpx.TimeoutException):
|
|
83
88
|
# Daemon not responding - return empty
|
|
84
89
|
pass
|
|
@@ -117,6 +122,8 @@ def format_status_message(
|
|
|
117
122
|
# Memory
|
|
118
123
|
memories_count: int | None = None,
|
|
119
124
|
memories_avg_importance: float | None = None,
|
|
125
|
+
# Skills
|
|
126
|
+
skills_total: int | None = None,
|
|
120
127
|
**kwargs: Any,
|
|
121
128
|
) -> str:
|
|
122
129
|
"""
|
|
@@ -202,6 +209,12 @@ def format_status_message(
|
|
|
202
209
|
lines.append(f" Unhealthy: {unhealthy_str}")
|
|
203
210
|
lines.append("")
|
|
204
211
|
|
|
212
|
+
# Skills section (only show if we have data)
|
|
213
|
+
if skills_total is not None:
|
|
214
|
+
lines.append("Skills:")
|
|
215
|
+
lines.append(f" Loaded: {skills_total}")
|
|
216
|
+
lines.append("")
|
|
217
|
+
|
|
205
218
|
# Sessions section (only show if we have data)
|
|
206
219
|
if sessions_active is not None or sessions_paused is not None:
|
|
207
220
|
lines.append("Sessions:")
|