claude-team-mcp 0.4.0__py3-none-any.whl → 0.6.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/cli_backends/codex.py +2 -3
- claude_team_mcp/issue_tracker/__init__.py +132 -0
- claude_team_mcp/tools/__init__.py +2 -2
- claude_team_mcp/tools/issue_tracker_help.py +50 -0
- claude_team_mcp/tools/message_workers.py +10 -3
- claude_team_mcp/tools/spawn_workers.py +137 -62
- claude_team_mcp/utils/__init__.py +13 -5
- claude_team_mcp/utils/constants.py +151 -29
- claude_team_mcp/utils/worktree_detection.py +37 -15
- claude_team_mcp/worker_prompt.py +119 -33
- claude_team_mcp/worktree.py +29 -20
- {claude_team_mcp-0.4.0.dist-info → claude_team_mcp-0.6.0.dist-info}/METADATA +18 -5
- {claude_team_mcp-0.4.0.dist-info → claude_team_mcp-0.6.0.dist-info}/RECORD +15 -14
- claude_team_mcp/tools/bd_help.py +0 -42
- {claude_team_mcp-0.4.0.dist-info → claude_team_mcp-0.6.0.dist-info}/WHEEL +0 -0
- {claude_team_mcp-0.4.0.dist-info → claude_team_mcp-0.6.0.dist-info}/entry_points.txt +0 -0
|
@@ -58,10 +58,9 @@ class CodexCLI(AgentCLI):
|
|
|
58
58
|
"""
|
|
59
59
|
args: list[str] = []
|
|
60
60
|
|
|
61
|
-
# Codex uses --
|
|
62
|
-
# (--full-auto doesn't work through happy wrapper)
|
|
61
|
+
# Codex uses --full-auto for autonomous operation.
|
|
63
62
|
if dangerously_skip_permissions:
|
|
64
|
-
args.append("--
|
|
63
|
+
args.append("--full-auto")
|
|
65
64
|
|
|
66
65
|
# Note: settings_file is ignored - Codex doesn't support this
|
|
67
66
|
# Idle detection uses session file polling instead
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Issue tracker abstraction module.
|
|
3
|
+
|
|
4
|
+
Defines a protocol and backend implementations for issue tracker commands.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
import os
|
|
11
|
+
from dataclasses import dataclass, field
|
|
12
|
+
from typing import Protocol, runtime_checkable
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger("claude-team-mcp")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@runtime_checkable
|
|
18
|
+
class IssueTrackerBackend(Protocol):
|
|
19
|
+
"""
|
|
20
|
+
Protocol defining the issue tracker backend interface.
|
|
21
|
+
|
|
22
|
+
Backends provide a name, CLI command, marker directory, and command templates.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
name: str
|
|
26
|
+
cli: str
|
|
27
|
+
marker_dir: str
|
|
28
|
+
commands: dict[str, str]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass(frozen=True)
|
|
32
|
+
class BeadsBackend:
|
|
33
|
+
"""Beads issue tracker backend."""
|
|
34
|
+
|
|
35
|
+
name: str = "beads"
|
|
36
|
+
cli: str = "bd"
|
|
37
|
+
marker_dir: str = ".beads"
|
|
38
|
+
commands: dict[str, str] = field(
|
|
39
|
+
default_factory=lambda: {
|
|
40
|
+
"list": "bd --no-db list",
|
|
41
|
+
"ready": "bd --no-db ready",
|
|
42
|
+
"show": "bd --no-db show {issue_id}",
|
|
43
|
+
"update": "bd --no-db update {issue_id} --status {status}",
|
|
44
|
+
"close": "bd --no-db close {issue_id}",
|
|
45
|
+
"create": (
|
|
46
|
+
"bd --no-db create --title \"{title}\" --type {type} "
|
|
47
|
+
"--priority {priority} --description \"{description}\""
|
|
48
|
+
),
|
|
49
|
+
"comment": "bd --no-db comment {issue_id} \"{comment}\"",
|
|
50
|
+
"dep_add": "bd --no-db dep add {issue_id} {dependency_id}",
|
|
51
|
+
"dep_tree": "bd --no-db dep tree {issue_id}",
|
|
52
|
+
}
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dataclass(frozen=True)
|
|
57
|
+
class PebblesBackend:
|
|
58
|
+
"""Pebbles issue tracker backend."""
|
|
59
|
+
|
|
60
|
+
name: str = "pebbles"
|
|
61
|
+
cli: str = "pb"
|
|
62
|
+
marker_dir: str = ".pebbles"
|
|
63
|
+
commands: dict[str, str] = field(
|
|
64
|
+
default_factory=lambda: {
|
|
65
|
+
"list": "pb list",
|
|
66
|
+
"ready": "pb ready",
|
|
67
|
+
"show": "pb show {issue_id}",
|
|
68
|
+
"update": "pb update {issue_id} -status {status}",
|
|
69
|
+
"close": "pb close {issue_id}",
|
|
70
|
+
"create": (
|
|
71
|
+
"pb create -title \"{title}\" -type {type} -priority {priority} "
|
|
72
|
+
"-description \"{description}\""
|
|
73
|
+
),
|
|
74
|
+
"comment": "pb comment {issue_id} -body \"{comment}\"",
|
|
75
|
+
"dep_add": "pb dep add {issue_id} {dependency_id}",
|
|
76
|
+
"dep_tree": "pb dep tree {issue_id}",
|
|
77
|
+
}
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
BEADS_BACKEND = BeadsBackend()
|
|
82
|
+
PEBBLES_BACKEND = PebblesBackend()
|
|
83
|
+
BACKEND_REGISTRY: dict[str, IssueTrackerBackend] = {
|
|
84
|
+
BEADS_BACKEND.name: BEADS_BACKEND,
|
|
85
|
+
PEBBLES_BACKEND.name: PEBBLES_BACKEND,
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def detect_issue_tracker(project_path: str) -> IssueTrackerBackend | None:
|
|
90
|
+
"""
|
|
91
|
+
Detect the issue tracker backend for the given project path.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
project_path: Absolute or relative path to the project root.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
The detected IssueTrackerBackend, or None if no markers are present.
|
|
98
|
+
"""
|
|
99
|
+
beads_marker = os.path.join(project_path, BEADS_BACKEND.marker_dir)
|
|
100
|
+
pebbles_marker = os.path.join(project_path, PEBBLES_BACKEND.marker_dir)
|
|
101
|
+
|
|
102
|
+
# Check marker directories in the project root.
|
|
103
|
+
beads_present = os.path.isdir(beads_marker)
|
|
104
|
+
pebbles_present = os.path.isdir(pebbles_marker)
|
|
105
|
+
|
|
106
|
+
# Resolve the deterministic backend when both markers exist.
|
|
107
|
+
if beads_present and pebbles_present:
|
|
108
|
+
logger.warning(
|
|
109
|
+
"Both .beads and .pebbles found in %s; defaulting to pebbles",
|
|
110
|
+
project_path,
|
|
111
|
+
)
|
|
112
|
+
return PEBBLES_BACKEND
|
|
113
|
+
|
|
114
|
+
# Return the matching backend if only one marker exists.
|
|
115
|
+
if pebbles_present:
|
|
116
|
+
return PEBBLES_BACKEND
|
|
117
|
+
|
|
118
|
+
if beads_present:
|
|
119
|
+
return BEADS_BACKEND
|
|
120
|
+
|
|
121
|
+
return None
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
__all__ = [
|
|
125
|
+
"IssueTrackerBackend",
|
|
126
|
+
"BeadsBackend",
|
|
127
|
+
"PebblesBackend",
|
|
128
|
+
"BEADS_BACKEND",
|
|
129
|
+
"PEBBLES_BACKEND",
|
|
130
|
+
"BACKEND_REGISTRY",
|
|
131
|
+
"detect_issue_tracker",
|
|
132
|
+
]
|
|
@@ -8,7 +8,7 @@ from mcp.server.fastmcp import FastMCP
|
|
|
8
8
|
|
|
9
9
|
from . import adopt_worker
|
|
10
10
|
from . import annotate_worker
|
|
11
|
-
from . import
|
|
11
|
+
from . import issue_tracker_help
|
|
12
12
|
from . import check_idle_workers
|
|
13
13
|
from . import close_workers
|
|
14
14
|
from . import discover_workers
|
|
@@ -31,7 +31,7 @@ def register_all_tools(mcp: FastMCP, ensure_connection) -> None:
|
|
|
31
31
|
"""
|
|
32
32
|
# Tools that don't need ensure_connection
|
|
33
33
|
annotate_worker.register_tools(mcp)
|
|
34
|
-
|
|
34
|
+
issue_tracker_help.register_tools(mcp)
|
|
35
35
|
check_idle_workers.register_tools(mcp)
|
|
36
36
|
close_workers.register_tools(mcp)
|
|
37
37
|
examine_worker.register_tools(mcp)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Issue tracker help tool.
|
|
3
|
+
|
|
4
|
+
Provides issue_tracker_help for quick reference on issue tracking commands.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
from mcp.server.fastmcp import FastMCP
|
|
10
|
+
|
|
11
|
+
from ..issue_tracker import BACKEND_REGISTRY, detect_issue_tracker
|
|
12
|
+
from ..utils import build_issue_tracker_help_text, build_issue_tracker_quick_commands
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def register_tools(mcp: FastMCP) -> None:
|
|
16
|
+
"""Register issue_tracker_help tool on the MCP server."""
|
|
17
|
+
|
|
18
|
+
@mcp.tool()
|
|
19
|
+
async def issue_tracker_help() -> dict:
|
|
20
|
+
"""
|
|
21
|
+
Get a quick reference guide for using issue tracking.
|
|
22
|
+
|
|
23
|
+
Returns condensed documentation on tracker commands, workflow patterns,
|
|
24
|
+
and best practices for worker sessions. Call this tool when you need
|
|
25
|
+
guidance on tracking progress, adding comments, or managing issues.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
Dict with help text and key command examples
|
|
29
|
+
"""
|
|
30
|
+
project_path = str(Path.cwd())
|
|
31
|
+
backend = detect_issue_tracker(project_path)
|
|
32
|
+
help_text = build_issue_tracker_help_text(backend)
|
|
33
|
+
quick_commands = build_issue_tracker_quick_commands(backend)
|
|
34
|
+
|
|
35
|
+
response = {
|
|
36
|
+
"help": help_text,
|
|
37
|
+
"quick_commands": quick_commands,
|
|
38
|
+
"worker_tip": (
|
|
39
|
+
"As a worker, add comments to track progress rather than closing issues. "
|
|
40
|
+
"The coordinator will close issues after reviewing your work."
|
|
41
|
+
),
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if backend is None:
|
|
45
|
+
response["supported_trackers"] = sorted(BACKEND_REGISTRY.keys())
|
|
46
|
+
else:
|
|
47
|
+
response["tracker"] = backend.name
|
|
48
|
+
response["cli"] = backend.cli
|
|
49
|
+
|
|
50
|
+
return response
|
|
@@ -19,9 +19,10 @@ from ..idle_detection import (
|
|
|
19
19
|
wait_for_any_idle as wait_for_any_idle_impl,
|
|
20
20
|
SessionInfo,
|
|
21
21
|
)
|
|
22
|
+
from ..issue_tracker import detect_issue_tracker
|
|
22
23
|
from ..iterm_utils import send_prompt_for_agent
|
|
23
24
|
from ..registry import SessionStatus
|
|
24
|
-
from ..utils import error_response, HINTS
|
|
25
|
+
from ..utils import build_worker_message_hint, error_response, HINTS
|
|
25
26
|
|
|
26
27
|
logger = logging.getLogger("claude-team-mcp")
|
|
27
28
|
|
|
@@ -187,8 +188,14 @@ def register_tools(mcp: FastMCP) -> None:
|
|
|
187
188
|
# Update status to busy
|
|
188
189
|
registry.update_status(sid, SessionStatus.BUSY)
|
|
189
190
|
|
|
190
|
-
# Append hint
|
|
191
|
-
|
|
191
|
+
# Append tracker-specific hint so workers know how to log progress.
|
|
192
|
+
tracker_path = (
|
|
193
|
+
str(session.main_repo_path)
|
|
194
|
+
if session.main_repo_path is not None
|
|
195
|
+
else session.project_path
|
|
196
|
+
)
|
|
197
|
+
tracker_backend = detect_issue_tracker(tracker_path)
|
|
198
|
+
message_with_hint = message + build_worker_message_hint(tracker_backend)
|
|
192
199
|
|
|
193
200
|
# Send the message using agent-specific input handling.
|
|
194
201
|
# Codex needs a longer pre-Enter delay than Claude.
|
|
@@ -23,6 +23,7 @@ from ..iterm_utils import (
|
|
|
23
23
|
MAX_PANES_PER_TAB,
|
|
24
24
|
create_multi_pane_layout,
|
|
25
25
|
find_available_window,
|
|
26
|
+
get_window_for_session,
|
|
26
27
|
send_prompt,
|
|
27
28
|
send_prompt_for_agent,
|
|
28
29
|
split_pane,
|
|
@@ -32,7 +33,7 @@ from ..iterm_utils import (
|
|
|
32
33
|
from ..names import pick_names_for_count
|
|
33
34
|
from ..profile import apply_appearance_colors
|
|
34
35
|
from ..registry import SessionStatus
|
|
35
|
-
from ..utils import HINTS, error_response,
|
|
36
|
+
from ..utils import HINTS, error_response, get_worktree_tracker_dir
|
|
36
37
|
from ..worker_prompt import generate_worker_prompt, get_coordinator_guidance
|
|
37
38
|
from ..worktree import WorktreeError, create_local_worktree
|
|
38
39
|
|
|
@@ -324,76 +325,140 @@ def register_tools(mcp: FastMCP, ensure_connection) -> None:
|
|
|
324
325
|
if layout == "auto":
|
|
325
326
|
# Try to find an existing window where the ENTIRE batch fits.
|
|
326
327
|
# This keeps spawn batches together rather than spreading across windows.
|
|
327
|
-
managed_iterm_ids: set[str] = {
|
|
328
|
-
s.iterm_session.session_id
|
|
329
|
-
for s in registry.list_all()
|
|
330
|
-
if s.iterm_session is not None
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
# Find a window with enough space for ALL workers
|
|
334
|
-
result = await find_available_window(
|
|
335
|
-
app,
|
|
336
|
-
max_panes=MAX_PANES_PER_TAB,
|
|
337
|
-
managed_session_ids=managed_iterm_ids,
|
|
338
|
-
)
|
|
339
|
-
|
|
340
328
|
target_tab = None
|
|
341
329
|
initial_pane_count = 0
|
|
342
330
|
first_session = None # Session to split from
|
|
343
331
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
332
|
+
# Prefer the coordinator's window when running inside iTerm2.
|
|
333
|
+
# ITERM_SESSION_ID format is "wXtYpZ:UUID" - extract just the UUID.
|
|
334
|
+
iterm_session_env = os.environ.get("ITERM_SESSION_ID")
|
|
335
|
+
coordinator_session_id = None
|
|
336
|
+
if iterm_session_env and ":" in iterm_session_env:
|
|
337
|
+
coordinator_session_id = iterm_session_env.split(":", 1)[1]
|
|
338
|
+
if coordinator_session_id:
|
|
339
|
+
coordinator_session = None
|
|
340
|
+
coordinator_tab = None
|
|
341
|
+
|
|
342
|
+
for window in app.terminal_windows:
|
|
343
|
+
for tab in window.tabs:
|
|
344
|
+
for session in tab.sessions:
|
|
345
|
+
if session.session_id == coordinator_session_id:
|
|
346
|
+
coordinator_session = session
|
|
347
|
+
coordinator_tab = tab
|
|
348
|
+
break
|
|
349
|
+
if coordinator_session:
|
|
350
|
+
break
|
|
351
|
+
if coordinator_session:
|
|
352
|
+
break
|
|
353
|
+
|
|
354
|
+
if coordinator_session and coordinator_tab:
|
|
355
|
+
coordinator_window = await get_window_for_session(
|
|
356
|
+
app, coordinator_session
|
|
356
357
|
)
|
|
358
|
+
if coordinator_window is not None:
|
|
359
|
+
initial_pane_count = len(coordinator_tab.sessions)
|
|
360
|
+
available_slots = MAX_PANES_PER_TAB - initial_pane_count
|
|
361
|
+
if worker_count <= available_slots:
|
|
362
|
+
target_tab = coordinator_tab
|
|
363
|
+
first_session = coordinator_session
|
|
364
|
+
logger.debug(
|
|
365
|
+
"Using coordinator window "
|
|
366
|
+
f"({initial_pane_count} panes, {available_slots} slots)"
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
if target_tab is None:
|
|
370
|
+
managed_iterm_ids: set[str] = {
|
|
371
|
+
s.iterm_session.session_id
|
|
372
|
+
for s in registry.list_all()
|
|
373
|
+
if s.iterm_session is not None
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
# Find a window with enough space for ALL workers
|
|
377
|
+
result = await find_available_window(
|
|
378
|
+
app,
|
|
379
|
+
max_panes=MAX_PANES_PER_TAB,
|
|
380
|
+
managed_session_ids=managed_iterm_ids,
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
if result:
|
|
384
|
+
window, tab, existing_session = result
|
|
385
|
+
initial_pane_count = len(tab.sessions)
|
|
386
|
+
available_slots = MAX_PANES_PER_TAB - initial_pane_count
|
|
387
|
+
|
|
388
|
+
if worker_count <= available_slots:
|
|
389
|
+
# Entire batch fits in this window
|
|
390
|
+
target_tab = tab
|
|
391
|
+
first_session = existing_session
|
|
392
|
+
logger.debug(
|
|
393
|
+
f"Batch of {worker_count} fits in existing window "
|
|
394
|
+
f"({initial_pane_count} panes, {available_slots} slots)"
|
|
395
|
+
)
|
|
357
396
|
|
|
358
397
|
if target_tab:
|
|
359
398
|
# Reuse existing window - track pane count locally (iTerm objects stale)
|
|
360
399
|
local_pane_count = initial_pane_count
|
|
361
|
-
|
|
400
|
+
final_pane_count = initial_pane_count + worker_count
|
|
401
|
+
# Track created sessions for splitting
|
|
362
402
|
created_sessions: list = []
|
|
363
403
|
|
|
364
404
|
for i in range(worker_count):
|
|
365
|
-
#
|
|
366
|
-
#
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
405
|
+
# Choose layout strategy based on final pane count:
|
|
406
|
+
# - 3 panes: coordinator full left, workers stacked right
|
|
407
|
+
# - 4 panes: quad (TL→TR→BL→BR)
|
|
408
|
+
if final_pane_count == 3:
|
|
409
|
+
# Layout: coordinator | worker1
|
|
410
|
+
# |--------
|
|
411
|
+
# | worker2
|
|
412
|
+
if local_pane_count == 1:
|
|
413
|
+
# First split: vertical from coordinator
|
|
414
|
+
new_session = await split_pane(
|
|
415
|
+
first_session,
|
|
416
|
+
vertical=True,
|
|
417
|
+
before=False,
|
|
418
|
+
profile=None,
|
|
419
|
+
profile_customizations=profile_customizations[i],
|
|
420
|
+
)
|
|
421
|
+
else:
|
|
422
|
+
# Second split: horizontal from first worker (stack on right)
|
|
423
|
+
new_session = await split_pane(
|
|
424
|
+
created_sessions[0],
|
|
425
|
+
vertical=False,
|
|
426
|
+
before=False,
|
|
427
|
+
profile=None,
|
|
428
|
+
profile_customizations=profile_customizations[i],
|
|
429
|
+
)
|
|
430
|
+
else:
|
|
431
|
+
# Quad pattern: TL→TR(vsplit)→BL(hsplit)→BR(hsplit)
|
|
432
|
+
if local_pane_count == 1:
|
|
433
|
+
# First split: vertical (left/right)
|
|
434
|
+
new_session = await split_pane(
|
|
435
|
+
first_session,
|
|
436
|
+
vertical=True,
|
|
437
|
+
before=False,
|
|
438
|
+
profile=None,
|
|
439
|
+
profile_customizations=profile_customizations[i],
|
|
440
|
+
)
|
|
441
|
+
elif local_pane_count == 2:
|
|
442
|
+
# Second split: horizontal from left pane (bottom-left)
|
|
443
|
+
new_session = await split_pane(
|
|
444
|
+
first_session,
|
|
445
|
+
vertical=False,
|
|
446
|
+
before=False,
|
|
447
|
+
profile=None,
|
|
448
|
+
profile_customizations=profile_customizations[i],
|
|
449
|
+
)
|
|
450
|
+
else: # local_pane_count == 3
|
|
451
|
+
# Third split: horizontal from right pane (bottom-right)
|
|
452
|
+
tr_session = (
|
|
453
|
+
created_sessions[0] if created_sessions else first_session
|
|
454
|
+
)
|
|
455
|
+
new_session = await split_pane(
|
|
456
|
+
tr_session,
|
|
457
|
+
vertical=False,
|
|
458
|
+
before=False,
|
|
459
|
+
profile=None,
|
|
460
|
+
profile_customizations=profile_customizations[i],
|
|
461
|
+
)
|
|
397
462
|
|
|
398
463
|
pane_sessions.append(new_session)
|
|
399
464
|
created_sessions.append(new_session)
|
|
@@ -476,9 +541,13 @@ def register_tools(mcp: FastMCP, ensure_connection) -> None:
|
|
|
476
541
|
marker_id = session_ids[index]
|
|
477
542
|
agent_type = agent_types[index]
|
|
478
543
|
|
|
479
|
-
# Check for worktree and set
|
|
480
|
-
|
|
481
|
-
|
|
544
|
+
# Check for worktree and set tracker env var if needed.
|
|
545
|
+
tracker_info = get_worktree_tracker_dir(project_path)
|
|
546
|
+
if tracker_info:
|
|
547
|
+
env_var, tracker_dir = tracker_info
|
|
548
|
+
env = {env_var: tracker_dir}
|
|
549
|
+
else:
|
|
550
|
+
env = None
|
|
482
551
|
|
|
483
552
|
if agent_type == "codex":
|
|
484
553
|
# Start Codex in interactive mode using start_agent_in_session
|
|
@@ -560,12 +629,18 @@ def register_tools(mcp: FastMCP, ensure_connection) -> None:
|
|
|
560
629
|
if not bead and not custom_prompt:
|
|
561
630
|
workers_awaiting_task.append(managed.name)
|
|
562
631
|
|
|
632
|
+
tracker_path = (
|
|
633
|
+
str(managed.main_repo_path)
|
|
634
|
+
if managed.main_repo_path is not None
|
|
635
|
+
else managed.project_path
|
|
636
|
+
)
|
|
563
637
|
worker_prompt = generate_worker_prompt(
|
|
564
638
|
managed.session_id,
|
|
565
639
|
resolved_names[i],
|
|
566
640
|
agent_type=managed.agent_type,
|
|
567
641
|
use_worktree=use_worktree,
|
|
568
642
|
bead=bead,
|
|
643
|
+
project_path=tracker_path,
|
|
569
644
|
custom_prompt=custom_prompt,
|
|
570
645
|
)
|
|
571
646
|
|
|
@@ -2,16 +2,24 @@
|
|
|
2
2
|
Shared utilities for Claude Team MCP tools.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
from .constants import
|
|
5
|
+
from .constants import (
|
|
6
|
+
CONVERSATION_PAGE_SIZE,
|
|
7
|
+
ISSUE_TRACKER_HELP_TOOL,
|
|
8
|
+
build_issue_tracker_help_text,
|
|
9
|
+
build_issue_tracker_quick_commands,
|
|
10
|
+
build_worker_message_hint,
|
|
11
|
+
)
|
|
6
12
|
from .errors import error_response, HINTS, get_session_or_error
|
|
7
|
-
from .worktree_detection import
|
|
13
|
+
from .worktree_detection import get_worktree_tracker_dir
|
|
8
14
|
|
|
9
15
|
__all__ = [
|
|
10
|
-
"BEADS_HELP_TEXT",
|
|
11
16
|
"CONVERSATION_PAGE_SIZE",
|
|
12
|
-
"
|
|
17
|
+
"ISSUE_TRACKER_HELP_TOOL",
|
|
18
|
+
"build_issue_tracker_help_text",
|
|
19
|
+
"build_issue_tracker_quick_commands",
|
|
20
|
+
"build_worker_message_hint",
|
|
13
21
|
"error_response",
|
|
14
22
|
"HINTS",
|
|
15
23
|
"get_session_or_error",
|
|
16
|
-
"
|
|
24
|
+
"get_worktree_tracker_dir",
|
|
17
25
|
]
|