hanzo-mcp 0.7.7__py3-none-any.whl → 0.8.0__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.
Potentially problematic release.
This version of hanzo-mcp might be problematic. Click here for more details.
- hanzo_mcp/__init__.py +6 -0
- hanzo_mcp/__main__.py +1 -1
- hanzo_mcp/analytics/__init__.py +2 -2
- hanzo_mcp/analytics/posthog_analytics.py +76 -82
- hanzo_mcp/cli.py +31 -36
- hanzo_mcp/cli_enhanced.py +94 -72
- hanzo_mcp/cli_plugin.py +27 -17
- hanzo_mcp/config/__init__.py +2 -2
- hanzo_mcp/config/settings.py +112 -88
- hanzo_mcp/config/tool_config.py +32 -34
- hanzo_mcp/dev_server.py +66 -67
- hanzo_mcp/prompts/__init__.py +94 -12
- hanzo_mcp/prompts/enhanced_prompts.py +809 -0
- hanzo_mcp/prompts/example_custom_prompt.py +6 -5
- hanzo_mcp/prompts/project_todo_reminder.py +0 -1
- hanzo_mcp/prompts/tool_explorer.py +10 -7
- hanzo_mcp/server.py +17 -21
- hanzo_mcp/server_enhanced.py +15 -22
- hanzo_mcp/tools/__init__.py +56 -28
- hanzo_mcp/tools/agent/__init__.py +16 -19
- hanzo_mcp/tools/agent/agent.py +82 -65
- hanzo_mcp/tools/agent/agent_tool.py +152 -122
- hanzo_mcp/tools/agent/agent_tool_v1_deprecated.py +66 -62
- hanzo_mcp/tools/agent/clarification_protocol.py +55 -50
- hanzo_mcp/tools/agent/clarification_tool.py +11 -10
- hanzo_mcp/tools/agent/claude_cli_tool.py +21 -20
- hanzo_mcp/tools/agent/claude_desktop_auth.py +130 -144
- hanzo_mcp/tools/agent/cli_agent_base.py +59 -53
- hanzo_mcp/tools/agent/code_auth.py +102 -107
- hanzo_mcp/tools/agent/code_auth_tool.py +28 -27
- hanzo_mcp/tools/agent/codex_cli_tool.py +20 -19
- hanzo_mcp/tools/agent/critic_tool.py +86 -73
- hanzo_mcp/tools/agent/gemini_cli_tool.py +21 -20
- hanzo_mcp/tools/agent/grok_cli_tool.py +21 -20
- hanzo_mcp/tools/agent/iching_tool.py +404 -139
- hanzo_mcp/tools/agent/network_tool.py +89 -73
- hanzo_mcp/tools/agent/prompt.py +2 -1
- hanzo_mcp/tools/agent/review_tool.py +101 -98
- hanzo_mcp/tools/agent/swarm_alias.py +87 -0
- hanzo_mcp/tools/agent/swarm_tool.py +246 -161
- hanzo_mcp/tools/agent/swarm_tool_v1_deprecated.py +134 -92
- hanzo_mcp/tools/agent/tool_adapter.py +21 -11
- hanzo_mcp/tools/common/__init__.py +1 -1
- hanzo_mcp/tools/common/base.py +3 -5
- hanzo_mcp/tools/common/batch_tool.py +46 -39
- hanzo_mcp/tools/common/config_tool.py +120 -84
- hanzo_mcp/tools/common/context.py +1 -5
- hanzo_mcp/tools/common/context_fix.py +5 -3
- hanzo_mcp/tools/common/critic_tool.py +4 -8
- hanzo_mcp/tools/common/decorators.py +58 -56
- hanzo_mcp/tools/common/enhanced_base.py +29 -32
- hanzo_mcp/tools/common/fastmcp_pagination.py +91 -94
- hanzo_mcp/tools/common/forgiving_edit.py +91 -87
- hanzo_mcp/tools/common/mode.py +15 -17
- hanzo_mcp/tools/common/mode_loader.py +27 -24
- hanzo_mcp/tools/common/paginated_base.py +61 -53
- hanzo_mcp/tools/common/paginated_response.py +72 -79
- hanzo_mcp/tools/common/pagination.py +50 -53
- hanzo_mcp/tools/common/permissions.py +4 -4
- hanzo_mcp/tools/common/personality.py +186 -138
- hanzo_mcp/tools/common/plugin_loader.py +54 -54
- hanzo_mcp/tools/common/stats.py +65 -47
- hanzo_mcp/tools/common/test_helpers.py +31 -0
- hanzo_mcp/tools/common/thinking_tool.py +4 -8
- hanzo_mcp/tools/common/tool_disable.py +17 -12
- hanzo_mcp/tools/common/tool_enable.py +13 -14
- hanzo_mcp/tools/common/tool_list.py +36 -28
- hanzo_mcp/tools/common/truncate.py +23 -23
- hanzo_mcp/tools/config/__init__.py +4 -4
- hanzo_mcp/tools/config/config_tool.py +42 -29
- hanzo_mcp/tools/config/index_config.py +37 -34
- hanzo_mcp/tools/config/mode_tool.py +175 -55
- hanzo_mcp/tools/database/__init__.py +15 -12
- hanzo_mcp/tools/database/database_manager.py +77 -75
- hanzo_mcp/tools/database/graph.py +137 -91
- hanzo_mcp/tools/database/graph_add.py +30 -18
- hanzo_mcp/tools/database/graph_query.py +178 -102
- hanzo_mcp/tools/database/graph_remove.py +33 -28
- hanzo_mcp/tools/database/graph_search.py +97 -75
- hanzo_mcp/tools/database/graph_stats.py +91 -59
- hanzo_mcp/tools/database/sql.py +107 -79
- hanzo_mcp/tools/database/sql_query.py +30 -24
- hanzo_mcp/tools/database/sql_search.py +29 -25
- hanzo_mcp/tools/database/sql_stats.py +47 -35
- hanzo_mcp/tools/editor/neovim_command.py +25 -28
- hanzo_mcp/tools/editor/neovim_edit.py +21 -23
- hanzo_mcp/tools/editor/neovim_session.py +60 -54
- hanzo_mcp/tools/filesystem/__init__.py +31 -30
- hanzo_mcp/tools/filesystem/ast_multi_edit.py +329 -249
- hanzo_mcp/tools/filesystem/ast_tool.py +4 -4
- hanzo_mcp/tools/filesystem/base.py +1 -1
- hanzo_mcp/tools/filesystem/batch_search.py +316 -224
- hanzo_mcp/tools/filesystem/content_replace.py +4 -4
- hanzo_mcp/tools/filesystem/diff.py +71 -59
- hanzo_mcp/tools/filesystem/directory_tree.py +7 -7
- hanzo_mcp/tools/filesystem/directory_tree_paginated.py +49 -37
- hanzo_mcp/tools/filesystem/edit.py +4 -4
- hanzo_mcp/tools/filesystem/find.py +173 -80
- hanzo_mcp/tools/filesystem/find_files.py +73 -52
- hanzo_mcp/tools/filesystem/git_search.py +157 -104
- hanzo_mcp/tools/filesystem/grep.py +8 -8
- hanzo_mcp/tools/filesystem/multi_edit.py +4 -8
- hanzo_mcp/tools/filesystem/read.py +12 -10
- hanzo_mcp/tools/filesystem/rules_tool.py +59 -43
- hanzo_mcp/tools/filesystem/search_tool.py +263 -207
- hanzo_mcp/tools/filesystem/symbols_tool.py +94 -54
- hanzo_mcp/tools/filesystem/tree.py +35 -33
- hanzo_mcp/tools/filesystem/unix_aliases.py +13 -18
- hanzo_mcp/tools/filesystem/watch.py +37 -36
- hanzo_mcp/tools/filesystem/write.py +4 -8
- hanzo_mcp/tools/jupyter/__init__.py +4 -4
- hanzo_mcp/tools/jupyter/base.py +4 -5
- hanzo_mcp/tools/jupyter/jupyter.py +67 -47
- hanzo_mcp/tools/jupyter/notebook_edit.py +4 -4
- hanzo_mcp/tools/jupyter/notebook_read.py +4 -7
- hanzo_mcp/tools/llm/__init__.py +5 -7
- hanzo_mcp/tools/llm/consensus_tool.py +72 -52
- hanzo_mcp/tools/llm/llm_manage.py +101 -60
- hanzo_mcp/tools/llm/llm_tool.py +226 -166
- hanzo_mcp/tools/llm/provider_tools.py +25 -26
- hanzo_mcp/tools/lsp/__init__.py +1 -1
- hanzo_mcp/tools/lsp/lsp_tool.py +228 -143
- hanzo_mcp/tools/mcp/__init__.py +2 -3
- hanzo_mcp/tools/mcp/mcp_add.py +27 -25
- hanzo_mcp/tools/mcp/mcp_remove.py +7 -8
- hanzo_mcp/tools/mcp/mcp_stats.py +23 -22
- hanzo_mcp/tools/mcp/mcp_tool.py +129 -98
- hanzo_mcp/tools/memory/__init__.py +39 -21
- hanzo_mcp/tools/memory/knowledge_tools.py +124 -99
- hanzo_mcp/tools/memory/memory_tools.py +90 -108
- hanzo_mcp/tools/search/__init__.py +7 -2
- hanzo_mcp/tools/search/find_tool.py +297 -212
- hanzo_mcp/tools/search/unified_search.py +366 -314
- hanzo_mcp/tools/shell/__init__.py +8 -7
- hanzo_mcp/tools/shell/auto_background.py +56 -49
- hanzo_mcp/tools/shell/base.py +1 -1
- hanzo_mcp/tools/shell/base_process.py +75 -75
- hanzo_mcp/tools/shell/bash_session.py +2 -2
- hanzo_mcp/tools/shell/bash_session_executor.py +4 -4
- hanzo_mcp/tools/shell/bash_tool.py +24 -31
- hanzo_mcp/tools/shell/command_executor.py +12 -12
- hanzo_mcp/tools/shell/logs.py +43 -33
- hanzo_mcp/tools/shell/npx.py +13 -13
- hanzo_mcp/tools/shell/npx_background.py +24 -21
- hanzo_mcp/tools/shell/npx_tool.py +18 -22
- hanzo_mcp/tools/shell/open.py +19 -21
- hanzo_mcp/tools/shell/pkill.py +31 -26
- hanzo_mcp/tools/shell/process_tool.py +32 -32
- hanzo_mcp/tools/shell/processes.py +57 -58
- hanzo_mcp/tools/shell/run_background.py +24 -25
- hanzo_mcp/tools/shell/run_command.py +5 -5
- hanzo_mcp/tools/shell/run_command_windows.py +5 -5
- hanzo_mcp/tools/shell/session_storage.py +3 -3
- hanzo_mcp/tools/shell/streaming_command.py +141 -126
- hanzo_mcp/tools/shell/uvx.py +24 -25
- hanzo_mcp/tools/shell/uvx_background.py +35 -33
- hanzo_mcp/tools/shell/uvx_tool.py +18 -22
- hanzo_mcp/tools/todo/__init__.py +6 -2
- hanzo_mcp/tools/todo/todo.py +50 -37
- hanzo_mcp/tools/todo/todo_read.py +5 -8
- hanzo_mcp/tools/todo/todo_write.py +5 -7
- hanzo_mcp/tools/vector/__init__.py +40 -28
- hanzo_mcp/tools/vector/ast_analyzer.py +176 -143
- hanzo_mcp/tools/vector/git_ingester.py +170 -179
- hanzo_mcp/tools/vector/index_tool.py +96 -44
- hanzo_mcp/tools/vector/infinity_store.py +283 -228
- hanzo_mcp/tools/vector/mock_infinity.py +39 -40
- hanzo_mcp/tools/vector/project_manager.py +88 -78
- hanzo_mcp/tools/vector/vector.py +59 -42
- hanzo_mcp/tools/vector/vector_index.py +30 -27
- hanzo_mcp/tools/vector/vector_search.py +64 -45
- hanzo_mcp/types.py +6 -4
- {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/METADATA +1 -1
- hanzo_mcp-0.8.0.dist-info/RECORD +185 -0
- hanzo_mcp-0.7.7.dist-info/RECORD +0 -182
- {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/WHEEL +0 -0
- {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/entry_points.txt +0 -0
- {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/top_level.txt +0 -0
|
@@ -5,15 +5,16 @@ This package provides tools for executing shell commands and scripts.
|
|
|
5
5
|
|
|
6
6
|
from mcp.server import FastMCP
|
|
7
7
|
|
|
8
|
+
from hanzo_mcp.tools.shell.open import open_tool
|
|
8
9
|
from hanzo_mcp.tools.common.base import BaseTool, ToolRegistry
|
|
9
|
-
from hanzo_mcp.tools.
|
|
10
|
+
from hanzo_mcp.tools.shell.npx_tool import npx_tool
|
|
11
|
+
from hanzo_mcp.tools.shell.uvx_tool import uvx_tool
|
|
10
12
|
|
|
11
13
|
# Import tools
|
|
12
14
|
from hanzo_mcp.tools.shell.bash_tool import bash_tool
|
|
13
|
-
from hanzo_mcp.tools.
|
|
14
|
-
from hanzo_mcp.tools.shell.uvx_tool import uvx_tool
|
|
15
|
+
from hanzo_mcp.tools.common.permissions import PermissionManager
|
|
15
16
|
from hanzo_mcp.tools.shell.process_tool import process_tool
|
|
16
|
-
|
|
17
|
+
|
|
17
18
|
# from hanzo_mcp.tools.shell.streaming_command import StreamingCommandTool
|
|
18
19
|
|
|
19
20
|
# Export all tool classes
|
|
@@ -38,10 +39,10 @@ def get_shell_tools(
|
|
|
38
39
|
bash_tool.permission_manager = permission_manager
|
|
39
40
|
npx_tool.permission_manager = permission_manager
|
|
40
41
|
uvx_tool.permission_manager = permission_manager
|
|
41
|
-
|
|
42
|
+
|
|
42
43
|
# Note: StreamingCommandTool is abstract and shouldn't be instantiated directly
|
|
43
44
|
# It's used as a base class for other streaming tools
|
|
44
|
-
|
|
45
|
+
|
|
45
46
|
return [
|
|
46
47
|
bash_tool,
|
|
47
48
|
npx_tool,
|
|
@@ -67,4 +68,4 @@ def register_shell_tools(
|
|
|
67
68
|
"""
|
|
68
69
|
tools = get_shell_tools(permission_manager)
|
|
69
70
|
ToolRegistry.register_tools(mcp_server, tools)
|
|
70
|
-
return tools
|
|
71
|
+
return tools
|
|
@@ -4,32 +4,33 @@ This module provides automatic backgrounding of long-running processes.
|
|
|
4
4
|
Commands that take more than 2 minutes automatically continue in background.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
import asyncio
|
|
8
|
-
import os
|
|
9
7
|
import time
|
|
10
8
|
import uuid
|
|
9
|
+
import asyncio
|
|
10
|
+
from typing import Tuple, Optional
|
|
11
11
|
from pathlib import Path
|
|
12
|
-
from typing import Any, Optional, Tuple
|
|
13
12
|
|
|
14
13
|
from hanzo_mcp.tools.shell.base_process import ProcessManager
|
|
15
14
|
|
|
16
15
|
|
|
17
16
|
class AutoBackgroundExecutor:
|
|
18
17
|
"""Executor that automatically backgrounds long-running processes."""
|
|
19
|
-
|
|
18
|
+
|
|
20
19
|
# Default timeout before auto-backgrounding (2 minutes)
|
|
21
20
|
DEFAULT_TIMEOUT = 120.0
|
|
22
|
-
|
|
23
|
-
def __init__(
|
|
21
|
+
|
|
22
|
+
def __init__(
|
|
23
|
+
self, process_manager: ProcessManager, timeout: float = DEFAULT_TIMEOUT
|
|
24
|
+
):
|
|
24
25
|
"""Initialize the auto-background executor.
|
|
25
|
-
|
|
26
|
+
|
|
26
27
|
Args:
|
|
27
28
|
process_manager: Process manager for tracking background processes
|
|
28
29
|
timeout: Timeout in seconds before auto-backgrounding (default: 120s)
|
|
29
30
|
"""
|
|
30
31
|
self.process_manager = process_manager
|
|
31
32
|
self.timeout = timeout
|
|
32
|
-
|
|
33
|
+
|
|
33
34
|
async def execute_with_auto_background(
|
|
34
35
|
self,
|
|
35
36
|
cmd_args: list[str],
|
|
@@ -38,22 +39,22 @@ class AutoBackgroundExecutor:
|
|
|
38
39
|
env: Optional[dict[str, str]] = None,
|
|
39
40
|
) -> Tuple[str, bool, Optional[str]]:
|
|
40
41
|
"""Execute a command with automatic backgrounding if it takes too long.
|
|
41
|
-
|
|
42
|
+
|
|
42
43
|
Args:
|
|
43
44
|
cmd_args: Command arguments list
|
|
44
45
|
tool_name: Name of the tool (for process ID generation)
|
|
45
46
|
cwd: Working directory
|
|
46
47
|
env: Environment variables
|
|
47
|
-
|
|
48
|
+
|
|
48
49
|
Returns:
|
|
49
50
|
Tuple of (output/status, was_backgrounded, process_id)
|
|
50
51
|
"""
|
|
51
52
|
# Generate process ID
|
|
52
53
|
process_id = f"{tool_name}_{uuid.uuid4().hex[:8]}"
|
|
53
|
-
|
|
54
|
+
|
|
54
55
|
# Create log file
|
|
55
56
|
log_file = self.process_manager.create_log_file(process_id)
|
|
56
|
-
|
|
57
|
+
|
|
57
58
|
# Start the process
|
|
58
59
|
process = await asyncio.create_subprocess_exec(
|
|
59
60
|
*cmd_args,
|
|
@@ -62,69 +63,75 @@ class AutoBackgroundExecutor:
|
|
|
62
63
|
cwd=cwd,
|
|
63
64
|
env=env,
|
|
64
65
|
)
|
|
65
|
-
|
|
66
|
+
|
|
66
67
|
# Track in process manager
|
|
67
68
|
self.process_manager.add_process(process_id, process, str(log_file))
|
|
68
|
-
|
|
69
|
+
|
|
69
70
|
# Try to wait for completion with timeout
|
|
70
71
|
start_time = time.time()
|
|
71
72
|
output_lines = []
|
|
72
|
-
|
|
73
|
+
|
|
73
74
|
try:
|
|
74
75
|
# Create tasks for reading output and waiting for process
|
|
75
76
|
async def read_output():
|
|
76
77
|
"""Read output from process."""
|
|
77
78
|
if process.stdout:
|
|
78
79
|
async for line in process.stdout:
|
|
79
|
-
line_str = line.decode(
|
|
80
|
+
line_str = line.decode("utf-8", errors="replace")
|
|
80
81
|
output_lines.append(line_str)
|
|
81
82
|
# Also write to log file
|
|
82
|
-
with open(log_file,
|
|
83
|
+
with open(log_file, "a") as f:
|
|
83
84
|
f.write(line_str)
|
|
84
|
-
|
|
85
|
+
|
|
85
86
|
async def wait_for_process():
|
|
86
87
|
"""Wait for process to complete."""
|
|
87
88
|
return await process.wait()
|
|
88
|
-
|
|
89
|
+
|
|
89
90
|
# Run both tasks with timeout
|
|
90
91
|
read_task = asyncio.create_task(read_output())
|
|
91
92
|
wait_task = asyncio.create_task(wait_for_process())
|
|
92
|
-
|
|
93
|
+
|
|
93
94
|
# Wait for either timeout or completion
|
|
94
95
|
done, pending = await asyncio.wait(
|
|
95
96
|
[read_task, wait_task],
|
|
96
97
|
timeout=self.timeout,
|
|
97
|
-
return_when=asyncio.FIRST_COMPLETED
|
|
98
|
+
return_when=asyncio.FIRST_COMPLETED,
|
|
98
99
|
)
|
|
99
|
-
|
|
100
|
+
|
|
100
101
|
# Check if process completed
|
|
101
102
|
if wait_task in done:
|
|
102
103
|
# Process completed within timeout
|
|
103
104
|
return_code = await wait_task
|
|
104
105
|
await read_task # Ensure all output is read
|
|
105
|
-
|
|
106
|
+
|
|
106
107
|
# Mark process as completed
|
|
107
108
|
self.process_manager.mark_completed(process_id, return_code)
|
|
108
|
-
|
|
109
|
-
output =
|
|
109
|
+
|
|
110
|
+
output = "".join(output_lines)
|
|
110
111
|
if return_code != 0:
|
|
111
|
-
return
|
|
112
|
+
return (
|
|
113
|
+
f"Command failed with exit code {return_code}:\n{output}",
|
|
114
|
+
False,
|
|
115
|
+
None,
|
|
116
|
+
)
|
|
112
117
|
else:
|
|
113
118
|
return output, False, None
|
|
114
|
-
|
|
119
|
+
|
|
115
120
|
else:
|
|
116
121
|
# Timeout reached - background the process
|
|
117
122
|
# Cancel the tasks we were waiting on
|
|
118
123
|
for task in pending:
|
|
119
124
|
task.cancel()
|
|
120
|
-
|
|
125
|
+
|
|
121
126
|
# Continue reading output in background
|
|
122
|
-
asyncio.create_task(
|
|
123
|
-
|
|
127
|
+
asyncio.create_task(
|
|
128
|
+
self._background_reader(process, process_id, log_file)
|
|
129
|
+
)
|
|
130
|
+
|
|
124
131
|
# Return status message
|
|
125
132
|
elapsed = time.time() - start_time
|
|
126
|
-
partial_output =
|
|
127
|
-
|
|
133
|
+
partial_output = "".join(output_lines[-50:]) # Last 50 lines
|
|
134
|
+
|
|
128
135
|
return (
|
|
129
136
|
f"Process automatically backgrounded after {elapsed:.1f}s\n"
|
|
130
137
|
f"Process ID: {process_id}\n"
|
|
@@ -133,17 +140,17 @@ class AutoBackgroundExecutor:
|
|
|
133
140
|
f"Use 'process --action kill --id {process_id}' to stop the process\n\n"
|
|
134
141
|
f"=== Last output ===\n{partial_output}",
|
|
135
142
|
True,
|
|
136
|
-
process_id
|
|
143
|
+
process_id,
|
|
137
144
|
)
|
|
138
|
-
|
|
145
|
+
|
|
139
146
|
except Exception as e:
|
|
140
147
|
# Handle errors
|
|
141
148
|
self.process_manager.mark_completed(process_id, -1)
|
|
142
149
|
return f"Error executing command: {str(e)}", False, None
|
|
143
|
-
|
|
150
|
+
|
|
144
151
|
async def _background_reader(self, process, process_id: str, log_file: Path):
|
|
145
152
|
"""Continue reading output from a backgrounded process.
|
|
146
|
-
|
|
153
|
+
|
|
147
154
|
Args:
|
|
148
155
|
process: The subprocess
|
|
149
156
|
process_id: Process identifier
|
|
@@ -153,24 +160,24 @@ class AutoBackgroundExecutor:
|
|
|
153
160
|
# Continue reading output
|
|
154
161
|
if process.stdout:
|
|
155
162
|
async for line in process.stdout:
|
|
156
|
-
with open(log_file,
|
|
157
|
-
f.write(line.decode(
|
|
158
|
-
|
|
163
|
+
with open(log_file, "a") as f:
|
|
164
|
+
f.write(line.decode("utf-8", errors="replace"))
|
|
165
|
+
|
|
159
166
|
# Wait for process to complete
|
|
160
167
|
return_code = await process.wait()
|
|
161
|
-
|
|
168
|
+
|
|
162
169
|
# Mark as completed
|
|
163
170
|
self.process_manager.mark_completed(process_id, return_code)
|
|
164
|
-
|
|
171
|
+
|
|
165
172
|
# Add completion marker to log
|
|
166
|
-
with open(log_file,
|
|
173
|
+
with open(log_file, "a") as f:
|
|
167
174
|
f.write(f"\n\n=== Process completed with exit code {return_code} ===\n")
|
|
168
|
-
|
|
175
|
+
|
|
169
176
|
except Exception as e:
|
|
170
177
|
# Log error
|
|
171
|
-
with open(log_file,
|
|
178
|
+
with open(log_file, "a") as f:
|
|
172
179
|
f.write(f"\n\n=== Background reader error: {str(e)} ===\n")
|
|
173
|
-
|
|
180
|
+
|
|
174
181
|
self.process_manager.mark_completed(process_id, -1)
|
|
175
182
|
|
|
176
183
|
|
|
@@ -181,13 +188,13 @@ def format_auto_background_message(
|
|
|
181
188
|
partial_output: str = "",
|
|
182
189
|
) -> str:
|
|
183
190
|
"""Format a user-friendly message for auto-backgrounded processes.
|
|
184
|
-
|
|
191
|
+
|
|
185
192
|
Args:
|
|
186
193
|
process_id: Process identifier
|
|
187
194
|
elapsed_time: Time elapsed before backgrounding
|
|
188
195
|
log_file: Path to log file
|
|
189
196
|
partial_output: Partial output to show
|
|
190
|
-
|
|
197
|
+
|
|
191
198
|
Returns:
|
|
192
199
|
Formatted message
|
|
193
200
|
"""
|
|
@@ -199,5 +206,5 @@ def format_auto_background_message(
|
|
|
199
206
|
f" • View logs: process --action logs --id {process_id}\n"
|
|
200
207
|
f" • Check status: process\n"
|
|
201
208
|
f" • Stop process: process --action kill --id {process_id}\n"
|
|
202
|
-
f"{
|
|
203
|
-
)
|
|
209
|
+
f"{chr(10) + '=== Recent output ===' + chr(10) + partial_output if partial_output else ''}"
|
|
210
|
+
)
|
hanzo_mcp/tools/shell/base.py
CHANGED