claude-team-mcp 0.4.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.
- claude_team_mcp/__init__.py +24 -0
- claude_team_mcp/__main__.py +8 -0
- claude_team_mcp/cli_backends/__init__.py +44 -0
- claude_team_mcp/cli_backends/base.py +132 -0
- claude_team_mcp/cli_backends/claude.py +110 -0
- claude_team_mcp/cli_backends/codex.py +110 -0
- claude_team_mcp/colors.py +108 -0
- claude_team_mcp/formatting.py +120 -0
- claude_team_mcp/idle_detection.py +488 -0
- claude_team_mcp/iterm_utils.py +1119 -0
- claude_team_mcp/names.py +427 -0
- claude_team_mcp/profile.py +364 -0
- claude_team_mcp/registry.py +426 -0
- claude_team_mcp/schemas/__init__.py +5 -0
- claude_team_mcp/schemas/codex.py +267 -0
- claude_team_mcp/server.py +390 -0
- claude_team_mcp/session_state.py +1058 -0
- claude_team_mcp/subprocess_cache.py +119 -0
- claude_team_mcp/tools/__init__.py +52 -0
- claude_team_mcp/tools/adopt_worker.py +122 -0
- claude_team_mcp/tools/annotate_worker.py +57 -0
- claude_team_mcp/tools/bd_help.py +42 -0
- claude_team_mcp/tools/check_idle_workers.py +98 -0
- claude_team_mcp/tools/close_workers.py +194 -0
- claude_team_mcp/tools/discover_workers.py +129 -0
- claude_team_mcp/tools/examine_worker.py +56 -0
- claude_team_mcp/tools/list_workers.py +76 -0
- claude_team_mcp/tools/list_worktrees.py +106 -0
- claude_team_mcp/tools/message_workers.py +311 -0
- claude_team_mcp/tools/read_worker_logs.py +158 -0
- claude_team_mcp/tools/spawn_workers.py +634 -0
- claude_team_mcp/tools/wait_idle_workers.py +148 -0
- claude_team_mcp/utils/__init__.py +17 -0
- claude_team_mcp/utils/constants.py +87 -0
- claude_team_mcp/utils/errors.py +87 -0
- claude_team_mcp/utils/worktree_detection.py +79 -0
- claude_team_mcp/worker_prompt.py +350 -0
- claude_team_mcp/worktree.py +532 -0
- claude_team_mcp-0.4.0.dist-info/METADATA +414 -0
- claude_team_mcp-0.4.0.dist-info/RECORD +42 -0
- claude_team_mcp-0.4.0.dist-info/WHEEL +4 -0
- claude_team_mcp-0.4.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Read worker logs tool.
|
|
3
|
+
|
|
4
|
+
Provides read_worker_logs for getting conversation history from a Claude Code session.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
from mcp.server.fastmcp import Context, FastMCP
|
|
10
|
+
from mcp.server.session import ServerSession
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from ..server import AppContext
|
|
14
|
+
|
|
15
|
+
from ..utils import error_response, HINTS, get_session_or_error, CONVERSATION_PAGE_SIZE
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def register_tools(mcp: FastMCP) -> None:
|
|
19
|
+
"""Register read_worker_logs tool on the MCP server."""
|
|
20
|
+
|
|
21
|
+
@mcp.tool()
|
|
22
|
+
async def read_worker_logs(
|
|
23
|
+
ctx: Context[ServerSession, "AppContext"],
|
|
24
|
+
session_id: str,
|
|
25
|
+
pages: int = 1,
|
|
26
|
+
offset: int = 0,
|
|
27
|
+
) -> dict:
|
|
28
|
+
"""
|
|
29
|
+
Get conversation history from a Claude Code session with reverse pagination.
|
|
30
|
+
|
|
31
|
+
Returns messages from the session's JSONL file, paginated from the end
|
|
32
|
+
(most recent first by default). Each message includes text content,
|
|
33
|
+
tool use names/inputs, and thinking blocks.
|
|
34
|
+
|
|
35
|
+
Pagination works from the end of the conversation:
|
|
36
|
+
- pages=1, offset=0: Returns the most recent page (default)
|
|
37
|
+
- pages=3, offset=0: Returns the last 3 pages in chronological order
|
|
38
|
+
- pages=2, offset=1: Returns 2 pages, skipping the most recent page
|
|
39
|
+
|
|
40
|
+
Page size is 5 messages (each user or assistant message counts as 1).
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
session_id: ID of the target session.
|
|
44
|
+
Accepts internal IDs, terminal IDs, or worker names.
|
|
45
|
+
pages: Number of pages to return (default 1)
|
|
46
|
+
offset: Number of pages to skip from the end (default 0 = most recent)
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
Dict with:
|
|
50
|
+
- messages: List of message dicts in chronological order
|
|
51
|
+
- page_info: Pagination metadata (total_messages, total_pages, etc.)
|
|
52
|
+
- session_id: The session ID
|
|
53
|
+
"""
|
|
54
|
+
app_ctx = ctx.request_context.lifespan_context
|
|
55
|
+
registry = app_ctx.registry
|
|
56
|
+
|
|
57
|
+
# Validate inputs
|
|
58
|
+
if pages < 1:
|
|
59
|
+
return error_response(
|
|
60
|
+
"pages must be at least 1",
|
|
61
|
+
hint="Use pages=1 to get the most recent page",
|
|
62
|
+
)
|
|
63
|
+
if offset < 0:
|
|
64
|
+
return error_response(
|
|
65
|
+
"offset must be non-negative",
|
|
66
|
+
hint="Use offset=0 for most recent, offset=1 to skip most recent page, etc.",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Look up session (accepts internal ID, terminal ID, or name)
|
|
70
|
+
session = get_session_or_error(registry, session_id)
|
|
71
|
+
if isinstance(session, dict):
|
|
72
|
+
return session # Error response
|
|
73
|
+
|
|
74
|
+
jsonl_path = session.get_jsonl_path()
|
|
75
|
+
if not jsonl_path or not jsonl_path.exists():
|
|
76
|
+
return error_response(
|
|
77
|
+
"No JSONL session file found - Claude may not have started yet",
|
|
78
|
+
hint=HINTS["no_jsonl_file"],
|
|
79
|
+
session_id=session_id,
|
|
80
|
+
status=session.status.value,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# Parse the session state
|
|
84
|
+
state = session.get_conversation_state()
|
|
85
|
+
if not state:
|
|
86
|
+
return error_response(
|
|
87
|
+
"Could not parse session state",
|
|
88
|
+
hint="The JSONL file may be corrupted. Try closing and spawning a new session",
|
|
89
|
+
session_id=session_id,
|
|
90
|
+
status=session.status.value,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# Get all messages (user and assistant with content)
|
|
94
|
+
all_messages = state.conversation
|
|
95
|
+
total_messages = len(all_messages)
|
|
96
|
+
total_pages = (total_messages + CONVERSATION_PAGE_SIZE - 1) // CONVERSATION_PAGE_SIZE
|
|
97
|
+
|
|
98
|
+
if total_messages == 0:
|
|
99
|
+
return {
|
|
100
|
+
"session_id": session_id,
|
|
101
|
+
"messages": [],
|
|
102
|
+
"page_info": {
|
|
103
|
+
"total_messages": 0,
|
|
104
|
+
"total_pages": 0,
|
|
105
|
+
"page_size": CONVERSATION_PAGE_SIZE,
|
|
106
|
+
"pages_returned": 0,
|
|
107
|
+
"offset": offset,
|
|
108
|
+
},
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# Calculate which messages to return using reverse pagination
|
|
112
|
+
# offset=0 means start from the end, offset=1 means skip 1 page from end, etc.
|
|
113
|
+
messages_to_skip_from_end = offset * CONVERSATION_PAGE_SIZE
|
|
114
|
+
messages_to_take = pages * CONVERSATION_PAGE_SIZE
|
|
115
|
+
|
|
116
|
+
# Calculate start and end indices
|
|
117
|
+
# We're working backwards from the end
|
|
118
|
+
end_index = total_messages - messages_to_skip_from_end
|
|
119
|
+
start_index = max(0, end_index - messages_to_take)
|
|
120
|
+
|
|
121
|
+
# Handle edge cases
|
|
122
|
+
if end_index <= 0:
|
|
123
|
+
return {
|
|
124
|
+
"session_id": session_id,
|
|
125
|
+
"messages": [],
|
|
126
|
+
"page_info": {
|
|
127
|
+
"total_messages": total_messages,
|
|
128
|
+
"total_pages": total_pages,
|
|
129
|
+
"page_size": CONVERSATION_PAGE_SIZE,
|
|
130
|
+
"pages_returned": 0,
|
|
131
|
+
"offset": offset,
|
|
132
|
+
"note": f"Offset {offset} is beyond available messages",
|
|
133
|
+
},
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
# Slice messages (already in chronological order)
|
|
137
|
+
selected_messages = all_messages[start_index:end_index]
|
|
138
|
+
|
|
139
|
+
# Convert to dicts
|
|
140
|
+
message_dicts = [msg.to_dict() for msg in selected_messages]
|
|
141
|
+
|
|
142
|
+
# Calculate actual pages returned
|
|
143
|
+
pages_returned = (len(selected_messages) + CONVERSATION_PAGE_SIZE - 1) // CONVERSATION_PAGE_SIZE
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
"session_id": session_id,
|
|
147
|
+
"messages": message_dicts,
|
|
148
|
+
"page_info": {
|
|
149
|
+
"total_messages": total_messages,
|
|
150
|
+
"total_pages": total_pages,
|
|
151
|
+
"page_size": CONVERSATION_PAGE_SIZE,
|
|
152
|
+
"pages_returned": pages_returned,
|
|
153
|
+
"messages_returned": len(selected_messages),
|
|
154
|
+
"offset": offset,
|
|
155
|
+
"start_index": start_index,
|
|
156
|
+
"end_index": end_index,
|
|
157
|
+
},
|
|
158
|
+
}
|