claude-task-master 0.1.4__py3-none-any.whl → 0.1.5__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_task_master/__init__.py +1 -1
- claude_task_master/api/models.py +309 -0
- claude_task_master/api/routes.py +229 -0
- claude_task_master/api/routes_repo.py +317 -0
- claude_task_master/bin/claudetm +1 -1
- claude_task_master/cli.py +3 -1
- claude_task_master/cli_commands/mailbox.py +295 -0
- claude_task_master/cli_commands/workflow.py +37 -0
- claude_task_master/core/__init__.py +5 -0
- claude_task_master/core/agent_phases.py +1 -1
- claude_task_master/core/orchestrator.py +432 -9
- claude_task_master/core/parallel.py +4 -4
- claude_task_master/core/plan_updater.py +199 -0
- claude_task_master/core/pr_context.py +176 -62
- claude_task_master/core/prompts.py +4 -0
- claude_task_master/core/prompts_plan_update.py +148 -0
- claude_task_master/core/state.py +5 -1
- claude_task_master/core/workflow_stages.py +229 -22
- claude_task_master/github/client_pr.py +86 -20
- claude_task_master/mailbox/__init__.py +23 -0
- claude_task_master/mailbox/merger.py +163 -0
- claude_task_master/mailbox/models.py +95 -0
- claude_task_master/mailbox/storage.py +209 -0
- claude_task_master/mcp/server.py +183 -0
- claude_task_master/mcp/tools.py +921 -0
- claude_task_master/webhooks/events.py +356 -2
- {claude_task_master-0.1.4.dist-info → claude_task_master-0.1.5.dist-info}/METADATA +223 -4
- {claude_task_master-0.1.4.dist-info → claude_task_master-0.1.5.dist-info}/RECORD +31 -23
- {claude_task_master-0.1.4.dist-info → claude_task_master-0.1.5.dist-info}/WHEEL +1 -1
- {claude_task_master-0.1.4.dist-info → claude_task_master-0.1.5.dist-info}/entry_points.txt +0 -0
- {claude_task_master-0.1.4.dist-info → claude_task_master-0.1.5.dist-info}/top_level.txt +0 -0
claude_task_master/__init__.py
CHANGED
claude_task_master/api/models.py
CHANGED
|
@@ -9,6 +9,9 @@ Request Models:
|
|
|
9
9
|
- ResumeRequest: Resume a paused/blocked task
|
|
10
10
|
- ConfigUpdateRequest: Update task configuration
|
|
11
11
|
- TaskInitRequest: Initialize a new task
|
|
12
|
+
- CloneRepoRequest: Clone a git repository to the workspace
|
|
13
|
+
- SetupRepoRequest: Set up a cloned repository for development
|
|
14
|
+
- PlanRepoRequest: Create a plan for a repository (read-only)
|
|
12
15
|
|
|
13
16
|
Response Models:
|
|
14
17
|
- TaskStatusResponse: Full task status information
|
|
@@ -19,17 +22,26 @@ Response Models:
|
|
|
19
22
|
- ContextResponse: Accumulated context/learnings
|
|
20
23
|
- HealthResponse: Server health status
|
|
21
24
|
- ErrorResponse: Standard error response
|
|
25
|
+
- CloneRepoResponse: Result of cloning a repository
|
|
26
|
+
- SetupRepoResponse: Result of setting up a repository
|
|
27
|
+
- PlanRepoResponse: Result of planning for a repository
|
|
22
28
|
|
|
23
29
|
Usage:
|
|
24
30
|
from claude_task_master.api.models import (
|
|
25
31
|
PauseRequest,
|
|
26
32
|
TaskStatusResponse,
|
|
27
33
|
ErrorResponse,
|
|
34
|
+
CloneRepoRequest,
|
|
35
|
+
CloneRepoResponse,
|
|
28
36
|
)
|
|
29
37
|
|
|
30
38
|
@app.post("/control/pause", response_model=ControlResponse)
|
|
31
39
|
async def pause_task(request: PauseRequest):
|
|
32
40
|
...
|
|
41
|
+
|
|
42
|
+
@app.post("/repo/clone", response_model=CloneRepoResponse)
|
|
43
|
+
async def clone_repo(request: CloneRepoRequest):
|
|
44
|
+
...
|
|
33
45
|
"""
|
|
34
46
|
|
|
35
47
|
from __future__ import annotations
|
|
@@ -246,6 +258,120 @@ class TaskInitRequest(BaseModel):
|
|
|
246
258
|
)
|
|
247
259
|
|
|
248
260
|
|
|
261
|
+
# =============================================================================
|
|
262
|
+
# Repo Setup Request Models
|
|
263
|
+
# =============================================================================
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
class CloneRepoRequest(BaseModel):
|
|
267
|
+
"""Request model for cloning a git repository.
|
|
268
|
+
|
|
269
|
+
Clones a repository to the workspace for AI developer environments.
|
|
270
|
+
Default target is ~/workspace/claude-task-master/{repo-name}.
|
|
271
|
+
|
|
272
|
+
Attributes:
|
|
273
|
+
url: Git repository URL (HTTPS or SSH format).
|
|
274
|
+
target_dir: Optional custom target directory path.
|
|
275
|
+
If not provided, defaults to ~/workspace/claude-task-master/{repo-name}.
|
|
276
|
+
branch: Optional branch to checkout after cloning.
|
|
277
|
+
"""
|
|
278
|
+
|
|
279
|
+
url: str = Field(
|
|
280
|
+
...,
|
|
281
|
+
min_length=1,
|
|
282
|
+
max_length=2048,
|
|
283
|
+
description="Git repository URL (HTTPS or SSH format)",
|
|
284
|
+
examples=[
|
|
285
|
+
"https://github.com/user/repo.git",
|
|
286
|
+
"git@github.com:user/repo.git",
|
|
287
|
+
],
|
|
288
|
+
)
|
|
289
|
+
target_dir: str | None = Field(
|
|
290
|
+
default=None,
|
|
291
|
+
max_length=4096,
|
|
292
|
+
description="Optional custom target directory path. "
|
|
293
|
+
"Defaults to ~/workspace/claude-task-master/{repo-name}",
|
|
294
|
+
examples=[
|
|
295
|
+
"~/workspace/claude-task-master/my-project",
|
|
296
|
+
"/home/user/projects/my-app",
|
|
297
|
+
],
|
|
298
|
+
)
|
|
299
|
+
branch: str | None = Field(
|
|
300
|
+
default=None,
|
|
301
|
+
max_length=256,
|
|
302
|
+
description="Optional branch to checkout after cloning",
|
|
303
|
+
examples=["main", "develop", "feature/new-feature"],
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
class SetupRepoRequest(BaseModel):
|
|
308
|
+
"""Request model for setting up a cloned repository for development.
|
|
309
|
+
|
|
310
|
+
Detects the project type and performs appropriate setup:
|
|
311
|
+
- Creates virtual environment (for Python projects)
|
|
312
|
+
- Installs dependencies (pip, npm, pnpm, yarn, bun)
|
|
313
|
+
- Runs setup scripts (setup-hooks.sh, setup.sh, etc.)
|
|
314
|
+
|
|
315
|
+
Attributes:
|
|
316
|
+
work_dir: Path to the cloned repository directory.
|
|
317
|
+
"""
|
|
318
|
+
|
|
319
|
+
work_dir: str = Field(
|
|
320
|
+
...,
|
|
321
|
+
min_length=1,
|
|
322
|
+
max_length=4096,
|
|
323
|
+
description="Path to the cloned repository directory to set up",
|
|
324
|
+
examples=[
|
|
325
|
+
"~/workspace/claude-task-master/my-project",
|
|
326
|
+
"/home/user/projects/my-app",
|
|
327
|
+
],
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
class PlanRepoRequest(BaseModel):
|
|
332
|
+
"""Request model for creating a plan for a repository.
|
|
333
|
+
|
|
334
|
+
Creates a plan without executing any work. Uses read-only tools
|
|
335
|
+
(Read, Glob, Grep) to analyze the codebase and outputs a structured
|
|
336
|
+
plan with tasks and success criteria.
|
|
337
|
+
|
|
338
|
+
Use this after cloning and setting up a repo to plan work before
|
|
339
|
+
execution, or to get a plan for a new goal in an existing repository.
|
|
340
|
+
|
|
341
|
+
Attributes:
|
|
342
|
+
work_dir: Path to the repository directory to plan for.
|
|
343
|
+
goal: The goal/task description to plan for.
|
|
344
|
+
model: Model to use for planning (default: opus for best quality).
|
|
345
|
+
"""
|
|
346
|
+
|
|
347
|
+
work_dir: str = Field(
|
|
348
|
+
...,
|
|
349
|
+
min_length=1,
|
|
350
|
+
max_length=4096,
|
|
351
|
+
description="Path to the repository directory to plan for",
|
|
352
|
+
examples=[
|
|
353
|
+
"~/workspace/claude-task-master/my-project",
|
|
354
|
+
"/home/user/projects/my-app",
|
|
355
|
+
],
|
|
356
|
+
)
|
|
357
|
+
goal: str = Field(
|
|
358
|
+
...,
|
|
359
|
+
min_length=1,
|
|
360
|
+
max_length=10000,
|
|
361
|
+
description="The goal/task description to plan for",
|
|
362
|
+
examples=[
|
|
363
|
+
"Implement user authentication with JWT",
|
|
364
|
+
"Add dark mode support to the UI",
|
|
365
|
+
"Fix the database connection pooling issue",
|
|
366
|
+
],
|
|
367
|
+
)
|
|
368
|
+
model: str = Field(
|
|
369
|
+
default="opus",
|
|
370
|
+
pattern="^(opus|sonnet|haiku)$",
|
|
371
|
+
description="Model to use for planning (opus, sonnet, haiku)",
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
|
|
249
375
|
# =============================================================================
|
|
250
376
|
# Response Models - Nested Components
|
|
251
377
|
# =============================================================================
|
|
@@ -551,3 +677,186 @@ class APIInfo(BaseModel):
|
|
|
551
677
|
version: str
|
|
552
678
|
description: str = "REST API for Claude Task Master task orchestration"
|
|
553
679
|
docs_url: str | None = "/docs"
|
|
680
|
+
|
|
681
|
+
|
|
682
|
+
# =============================================================================
|
|
683
|
+
# Mailbox Request/Response Models
|
|
684
|
+
# =============================================================================
|
|
685
|
+
|
|
686
|
+
|
|
687
|
+
class SendMailboxMessageRequest(BaseModel):
|
|
688
|
+
"""Request model for sending a message to the mailbox.
|
|
689
|
+
|
|
690
|
+
Attributes:
|
|
691
|
+
content: The message content describing the change request.
|
|
692
|
+
sender: Identifier of the sender (default: "anonymous").
|
|
693
|
+
priority: Message priority (0=low, 1=normal, 2=high, 3=urgent).
|
|
694
|
+
metadata: Optional additional metadata.
|
|
695
|
+
"""
|
|
696
|
+
|
|
697
|
+
content: str = Field(
|
|
698
|
+
...,
|
|
699
|
+
min_length=1,
|
|
700
|
+
max_length=100000,
|
|
701
|
+
description="The message content describing the change request",
|
|
702
|
+
examples=["Please also add tests for the new feature", "Prioritize the bug fix"],
|
|
703
|
+
)
|
|
704
|
+
sender: str = Field(
|
|
705
|
+
default="anonymous",
|
|
706
|
+
max_length=256,
|
|
707
|
+
description="Identifier of the sender",
|
|
708
|
+
examples=["supervisor-agent", "user@example.com", "monitoring-system"],
|
|
709
|
+
)
|
|
710
|
+
priority: int = Field(
|
|
711
|
+
default=1,
|
|
712
|
+
ge=0,
|
|
713
|
+
le=3,
|
|
714
|
+
description="Message priority (0=low, 1=normal, 2=high, 3=urgent)",
|
|
715
|
+
)
|
|
716
|
+
metadata: dict[str, Any] | None = Field(
|
|
717
|
+
default=None,
|
|
718
|
+
description="Optional additional metadata",
|
|
719
|
+
)
|
|
720
|
+
|
|
721
|
+
|
|
722
|
+
class SendMailboxMessageResponse(BaseModel):
|
|
723
|
+
"""Response model for sending a message to the mailbox.
|
|
724
|
+
|
|
725
|
+
Attributes:
|
|
726
|
+
success: Whether the message was sent successfully.
|
|
727
|
+
message_id: The ID of the created message.
|
|
728
|
+
message: Human-readable result message.
|
|
729
|
+
error: Error message if request failed.
|
|
730
|
+
"""
|
|
731
|
+
|
|
732
|
+
success: bool
|
|
733
|
+
message_id: str | None = None
|
|
734
|
+
message: str | None = None
|
|
735
|
+
error: str | None = None
|
|
736
|
+
|
|
737
|
+
|
|
738
|
+
class MailboxMessagePreview(BaseModel):
|
|
739
|
+
"""Preview of a mailbox message for status responses.
|
|
740
|
+
|
|
741
|
+
Attributes:
|
|
742
|
+
id: Message ID.
|
|
743
|
+
sender: Message sender.
|
|
744
|
+
content_preview: Truncated message content.
|
|
745
|
+
priority: Message priority level.
|
|
746
|
+
timestamp: When the message was created.
|
|
747
|
+
"""
|
|
748
|
+
|
|
749
|
+
id: str
|
|
750
|
+
sender: str
|
|
751
|
+
content_preview: str
|
|
752
|
+
priority: int
|
|
753
|
+
timestamp: datetime
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
class MailboxStatusResponse(BaseModel):
|
|
757
|
+
"""Response model for mailbox status check.
|
|
758
|
+
|
|
759
|
+
Attributes:
|
|
760
|
+
success: Whether the request succeeded.
|
|
761
|
+
count: Number of pending messages.
|
|
762
|
+
messages: List of message previews.
|
|
763
|
+
last_checked: When the mailbox was last checked.
|
|
764
|
+
total_messages_received: Total count of messages ever received.
|
|
765
|
+
error: Error message if request failed.
|
|
766
|
+
"""
|
|
767
|
+
|
|
768
|
+
success: bool
|
|
769
|
+
count: int = 0
|
|
770
|
+
messages: list[MailboxMessagePreview] = []
|
|
771
|
+
last_checked: datetime | None = None
|
|
772
|
+
total_messages_received: int = 0
|
|
773
|
+
error: str | None = None
|
|
774
|
+
|
|
775
|
+
|
|
776
|
+
class ClearMailboxResponse(BaseModel):
|
|
777
|
+
"""Response model for clearing the mailbox.
|
|
778
|
+
|
|
779
|
+
Attributes:
|
|
780
|
+
success: Whether the operation succeeded.
|
|
781
|
+
messages_cleared: Number of messages that were cleared.
|
|
782
|
+
message: Human-readable result message.
|
|
783
|
+
error: Error message if operation failed.
|
|
784
|
+
"""
|
|
785
|
+
|
|
786
|
+
success: bool
|
|
787
|
+
messages_cleared: int = 0
|
|
788
|
+
message: str | None = None
|
|
789
|
+
error: str | None = None
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
# =============================================================================
|
|
793
|
+
# Repo Setup Response Models
|
|
794
|
+
# =============================================================================
|
|
795
|
+
|
|
796
|
+
|
|
797
|
+
class CloneRepoResponse(BaseModel):
|
|
798
|
+
"""Response model for cloning a git repository.
|
|
799
|
+
|
|
800
|
+
Attributes:
|
|
801
|
+
success: Whether the clone operation succeeded.
|
|
802
|
+
message: Human-readable result message.
|
|
803
|
+
repo_url: The repository URL that was cloned.
|
|
804
|
+
target_dir: The directory where the repo was cloned to.
|
|
805
|
+
branch: The branch that was checked out (if specified).
|
|
806
|
+
error: Error message if clone failed.
|
|
807
|
+
"""
|
|
808
|
+
|
|
809
|
+
success: bool
|
|
810
|
+
message: str
|
|
811
|
+
repo_url: str | None = None
|
|
812
|
+
target_dir: str | None = None
|
|
813
|
+
branch: str | None = None
|
|
814
|
+
error: str | None = None
|
|
815
|
+
|
|
816
|
+
|
|
817
|
+
class SetupRepoResponse(BaseModel):
|
|
818
|
+
"""Response model for setting up a repository for development.
|
|
819
|
+
|
|
820
|
+
Attributes:
|
|
821
|
+
success: Whether the setup operation succeeded.
|
|
822
|
+
message: Human-readable result message.
|
|
823
|
+
work_dir: The directory that was set up.
|
|
824
|
+
steps_completed: List of setup steps that were completed.
|
|
825
|
+
venv_path: Path to the virtual environment (if created).
|
|
826
|
+
dependencies_installed: Whether dependencies were successfully installed.
|
|
827
|
+
setup_scripts_run: List of setup scripts that were executed.
|
|
828
|
+
error: Error message if setup failed.
|
|
829
|
+
"""
|
|
830
|
+
|
|
831
|
+
success: bool
|
|
832
|
+
message: str
|
|
833
|
+
work_dir: str | None = None
|
|
834
|
+
steps_completed: list[str] = []
|
|
835
|
+
venv_path: str | None = None
|
|
836
|
+
dependencies_installed: bool = False
|
|
837
|
+
setup_scripts_run: list[str] = []
|
|
838
|
+
error: str | None = None
|
|
839
|
+
|
|
840
|
+
|
|
841
|
+
class PlanRepoResponse(BaseModel):
|
|
842
|
+
"""Response model for creating a plan for a repository.
|
|
843
|
+
|
|
844
|
+
Attributes:
|
|
845
|
+
success: Whether the planning operation succeeded.
|
|
846
|
+
message: Human-readable result message.
|
|
847
|
+
work_dir: The repository directory that was analyzed.
|
|
848
|
+
goal: The goal that was planned for.
|
|
849
|
+
plan: The generated plan (markdown with task checkboxes).
|
|
850
|
+
criteria: The success criteria for the plan.
|
|
851
|
+
run_id: The run ID for the created task state.
|
|
852
|
+
error: Error message if planning failed.
|
|
853
|
+
"""
|
|
854
|
+
|
|
855
|
+
success: bool
|
|
856
|
+
message: str
|
|
857
|
+
work_dir: str | None = None
|
|
858
|
+
goal: str | None = None
|
|
859
|
+
plan: str | None = None
|
|
860
|
+
criteria: str | None = None
|
|
861
|
+
run_id: str | None = None
|
|
862
|
+
error: str | None = None
|
claude_task_master/api/routes.py
CHANGED
|
@@ -15,6 +15,9 @@ Endpoints:
|
|
|
15
15
|
- POST /control/stop: Stop a running task with optional cleanup
|
|
16
16
|
- POST /control/resume: Resume a paused or blocked task
|
|
17
17
|
- PATCH /config: Update runtime configuration options
|
|
18
|
+
- POST /repo/clone: Clone a git repository to workspace
|
|
19
|
+
- POST /repo/setup: Set up a cloned repository for development
|
|
20
|
+
- POST /repo/plan: Create a plan for a repository (read-only)
|
|
18
21
|
|
|
19
22
|
Usage:
|
|
20
23
|
from claude_task_master.api.routes import (
|
|
@@ -44,15 +47,20 @@ from typing import TYPE_CHECKING, Any
|
|
|
44
47
|
|
|
45
48
|
from claude_task_master import __version__
|
|
46
49
|
from claude_task_master.api.models import (
|
|
50
|
+
ClearMailboxResponse,
|
|
47
51
|
ConfigUpdateRequest,
|
|
48
52
|
ContextResponse,
|
|
49
53
|
ControlResponse,
|
|
50
54
|
ErrorResponse,
|
|
51
55
|
HealthResponse,
|
|
52
56
|
LogsResponse,
|
|
57
|
+
MailboxMessagePreview,
|
|
58
|
+
MailboxStatusResponse,
|
|
53
59
|
PlanResponse,
|
|
54
60
|
ProgressResponse,
|
|
55
61
|
ResumeRequest,
|
|
62
|
+
SendMailboxMessageRequest,
|
|
63
|
+
SendMailboxMessageResponse,
|
|
56
64
|
StopRequest,
|
|
57
65
|
TaskDeleteResponse,
|
|
58
66
|
TaskInitRequest,
|
|
@@ -64,6 +72,7 @@ from claude_task_master.api.models import (
|
|
|
64
72
|
WebhookStatusInfo,
|
|
65
73
|
WorkflowStage,
|
|
66
74
|
)
|
|
75
|
+
from claude_task_master.api.routes_repo import create_repo_router
|
|
67
76
|
from claude_task_master.api.routes_webhooks import create_webhooks_router
|
|
68
77
|
from claude_task_master.core.agent import ModelType
|
|
69
78
|
from claude_task_master.core.control import ControlManager
|
|
@@ -1099,6 +1108,216 @@ def create_task_router() -> APIRouter:
|
|
|
1099
1108
|
return router
|
|
1100
1109
|
|
|
1101
1110
|
|
|
1111
|
+
# =============================================================================
|
|
1112
|
+
# Mailbox Router (Send, Status, Clear)
|
|
1113
|
+
# =============================================================================
|
|
1114
|
+
|
|
1115
|
+
|
|
1116
|
+
def create_mailbox_router() -> APIRouter:
|
|
1117
|
+
"""Create router for mailbox endpoints.
|
|
1118
|
+
|
|
1119
|
+
These endpoints allow external systems to send messages to the mailbox
|
|
1120
|
+
which will be processed after the current task completes.
|
|
1121
|
+
|
|
1122
|
+
Returns:
|
|
1123
|
+
APIRouter configured with mailbox endpoints.
|
|
1124
|
+
|
|
1125
|
+
Raises:
|
|
1126
|
+
ImportError: If FastAPI is not installed.
|
|
1127
|
+
"""
|
|
1128
|
+
if not FASTAPI_AVAILABLE:
|
|
1129
|
+
raise ImportError(
|
|
1130
|
+
"FastAPI not installed. Install with: pip install claude-task-master[api]"
|
|
1131
|
+
)
|
|
1132
|
+
|
|
1133
|
+
router = APIRouter(tags=["Mailbox"])
|
|
1134
|
+
|
|
1135
|
+
@router.post(
|
|
1136
|
+
"/send",
|
|
1137
|
+
response_model=SendMailboxMessageResponse,
|
|
1138
|
+
responses={
|
|
1139
|
+
400: {"model": ErrorResponse, "description": "Invalid request"},
|
|
1140
|
+
500: {"model": ErrorResponse, "description": "Internal server error"},
|
|
1141
|
+
},
|
|
1142
|
+
summary="Send Message to Mailbox",
|
|
1143
|
+
description="Send a message to the claudetm mailbox for processing after the current task.",
|
|
1144
|
+
)
|
|
1145
|
+
async def send_message(
|
|
1146
|
+
request: Request, message_request: SendMailboxMessageRequest
|
|
1147
|
+
) -> SendMailboxMessageResponse | JSONResponse:
|
|
1148
|
+
"""Send a message to the mailbox.
|
|
1149
|
+
|
|
1150
|
+
Messages in the mailbox will be processed after the current task completes.
|
|
1151
|
+
Multiple messages are merged into a single change request that updates
|
|
1152
|
+
the plan before continuing work.
|
|
1153
|
+
|
|
1154
|
+
Args:
|
|
1155
|
+
message_request: The message to send with content, sender, and priority.
|
|
1156
|
+
|
|
1157
|
+
Returns:
|
|
1158
|
+
SendMailboxMessageResponse with message_id on success.
|
|
1159
|
+
|
|
1160
|
+
Raises:
|
|
1161
|
+
400: If the request is invalid.
|
|
1162
|
+
500: If an error occurs sending the message.
|
|
1163
|
+
"""
|
|
1164
|
+
from claude_task_master.mailbox import MailboxStorage
|
|
1165
|
+
|
|
1166
|
+
working_dir: Path = getattr(request.app.state, "working_dir", Path.cwd())
|
|
1167
|
+
state_dir = working_dir / ".claude-task-master"
|
|
1168
|
+
|
|
1169
|
+
# Validate content is not empty/whitespace only
|
|
1170
|
+
if not message_request.content.strip():
|
|
1171
|
+
return JSONResponse(
|
|
1172
|
+
status_code=400,
|
|
1173
|
+
content=ErrorResponse(
|
|
1174
|
+
error="invalid_request",
|
|
1175
|
+
message="Message content cannot be empty or whitespace only",
|
|
1176
|
+
suggestion="Provide a non-empty message content",
|
|
1177
|
+
).model_dump(),
|
|
1178
|
+
)
|
|
1179
|
+
|
|
1180
|
+
try:
|
|
1181
|
+
mailbox = MailboxStorage(state_dir=state_dir)
|
|
1182
|
+
message_id = mailbox.add_message(
|
|
1183
|
+
content=message_request.content.strip(),
|
|
1184
|
+
sender=message_request.sender,
|
|
1185
|
+
priority=message_request.priority,
|
|
1186
|
+
metadata=message_request.metadata or {},
|
|
1187
|
+
)
|
|
1188
|
+
|
|
1189
|
+
return SendMailboxMessageResponse(
|
|
1190
|
+
success=True,
|
|
1191
|
+
message_id=message_id,
|
|
1192
|
+
message=f"Message sent successfully (id: {message_id})",
|
|
1193
|
+
)
|
|
1194
|
+
|
|
1195
|
+
except Exception as e:
|
|
1196
|
+
logger.exception("Error sending message to mailbox")
|
|
1197
|
+
return JSONResponse(
|
|
1198
|
+
status_code=500,
|
|
1199
|
+
content=ErrorResponse(
|
|
1200
|
+
error="internal_error",
|
|
1201
|
+
message="Failed to send message to mailbox",
|
|
1202
|
+
detail=str(e),
|
|
1203
|
+
).model_dump(),
|
|
1204
|
+
)
|
|
1205
|
+
|
|
1206
|
+
@router.get(
|
|
1207
|
+
"",
|
|
1208
|
+
response_model=MailboxStatusResponse,
|
|
1209
|
+
responses={
|
|
1210
|
+
500: {"model": ErrorResponse, "description": "Internal server error"},
|
|
1211
|
+
},
|
|
1212
|
+
summary="Get Mailbox Status",
|
|
1213
|
+
description="Check the status of the mailbox including message count and previews.",
|
|
1214
|
+
)
|
|
1215
|
+
async def get_mailbox_status(request: Request) -> MailboxStatusResponse | JSONResponse:
|
|
1216
|
+
"""Get mailbox status.
|
|
1217
|
+
|
|
1218
|
+
Returns the number of pending messages and previews of each.
|
|
1219
|
+
|
|
1220
|
+
Returns:
|
|
1221
|
+
MailboxStatusResponse with message count and previews.
|
|
1222
|
+
|
|
1223
|
+
Raises:
|
|
1224
|
+
500: If an error occurs checking the mailbox.
|
|
1225
|
+
"""
|
|
1226
|
+
from datetime import datetime as dt
|
|
1227
|
+
|
|
1228
|
+
from claude_task_master.mailbox import MailboxStorage
|
|
1229
|
+
|
|
1230
|
+
working_dir: Path = getattr(request.app.state, "working_dir", Path.cwd())
|
|
1231
|
+
state_dir = working_dir / ".claude-task-master"
|
|
1232
|
+
|
|
1233
|
+
try:
|
|
1234
|
+
mailbox = MailboxStorage(state_dir=state_dir)
|
|
1235
|
+
status = mailbox.get_status()
|
|
1236
|
+
|
|
1237
|
+
# Convert preview dicts to MailboxMessagePreview models
|
|
1238
|
+
previews = []
|
|
1239
|
+
for preview_data in status["previews"]:
|
|
1240
|
+
previews.append(
|
|
1241
|
+
MailboxMessagePreview(
|
|
1242
|
+
id=preview_data["id"],
|
|
1243
|
+
sender=preview_data["sender"],
|
|
1244
|
+
content_preview=preview_data["content_preview"],
|
|
1245
|
+
priority=preview_data["priority"],
|
|
1246
|
+
timestamp=dt.fromisoformat(preview_data["timestamp"]),
|
|
1247
|
+
)
|
|
1248
|
+
)
|
|
1249
|
+
|
|
1250
|
+
# Parse last_checked if present
|
|
1251
|
+
last_checked = None
|
|
1252
|
+
if status["last_checked"]:
|
|
1253
|
+
last_checked = dt.fromisoformat(status["last_checked"])
|
|
1254
|
+
|
|
1255
|
+
return MailboxStatusResponse(
|
|
1256
|
+
success=True,
|
|
1257
|
+
count=status["count"],
|
|
1258
|
+
messages=previews,
|
|
1259
|
+
last_checked=last_checked,
|
|
1260
|
+
total_messages_received=status["total_messages_received"],
|
|
1261
|
+
)
|
|
1262
|
+
|
|
1263
|
+
except Exception as e:
|
|
1264
|
+
logger.exception("Error checking mailbox status")
|
|
1265
|
+
return JSONResponse(
|
|
1266
|
+
status_code=500,
|
|
1267
|
+
content=ErrorResponse(
|
|
1268
|
+
error="internal_error",
|
|
1269
|
+
message="Failed to check mailbox status",
|
|
1270
|
+
detail=str(e),
|
|
1271
|
+
).model_dump(),
|
|
1272
|
+
)
|
|
1273
|
+
|
|
1274
|
+
@router.delete(
|
|
1275
|
+
"",
|
|
1276
|
+
response_model=ClearMailboxResponse,
|
|
1277
|
+
responses={
|
|
1278
|
+
500: {"model": ErrorResponse, "description": "Internal server error"},
|
|
1279
|
+
},
|
|
1280
|
+
summary="Clear Mailbox",
|
|
1281
|
+
description="Clear all messages from the mailbox.",
|
|
1282
|
+
)
|
|
1283
|
+
async def clear_mailbox(request: Request) -> ClearMailboxResponse | JSONResponse:
|
|
1284
|
+
"""Clear all messages from the mailbox.
|
|
1285
|
+
|
|
1286
|
+
Returns:
|
|
1287
|
+
ClearMailboxResponse with number of messages cleared.
|
|
1288
|
+
|
|
1289
|
+
Raises:
|
|
1290
|
+
500: If an error occurs clearing the mailbox.
|
|
1291
|
+
"""
|
|
1292
|
+
from claude_task_master.mailbox import MailboxStorage
|
|
1293
|
+
|
|
1294
|
+
working_dir: Path = getattr(request.app.state, "working_dir", Path.cwd())
|
|
1295
|
+
state_dir = working_dir / ".claude-task-master"
|
|
1296
|
+
|
|
1297
|
+
try:
|
|
1298
|
+
mailbox = MailboxStorage(state_dir=state_dir)
|
|
1299
|
+
count = mailbox.clear()
|
|
1300
|
+
|
|
1301
|
+
return ClearMailboxResponse(
|
|
1302
|
+
success=True,
|
|
1303
|
+
messages_cleared=count,
|
|
1304
|
+
message=f"Cleared {count} message(s) from mailbox",
|
|
1305
|
+
)
|
|
1306
|
+
|
|
1307
|
+
except Exception as e:
|
|
1308
|
+
logger.exception("Error clearing mailbox")
|
|
1309
|
+
return JSONResponse(
|
|
1310
|
+
status_code=500,
|
|
1311
|
+
content=ErrorResponse(
|
|
1312
|
+
error="internal_error",
|
|
1313
|
+
message="Failed to clear mailbox",
|
|
1314
|
+
detail=str(e),
|
|
1315
|
+
).model_dump(),
|
|
1316
|
+
)
|
|
1317
|
+
|
|
1318
|
+
return router
|
|
1319
|
+
|
|
1320
|
+
|
|
1102
1321
|
# =============================================================================
|
|
1103
1322
|
# Router Registration
|
|
1104
1323
|
# =============================================================================
|
|
@@ -1129,7 +1348,17 @@ def register_routes(app: FastAPI) -> None:
|
|
|
1129
1348
|
webhooks_router = create_webhooks_router()
|
|
1130
1349
|
app.include_router(webhooks_router, prefix="/webhooks")
|
|
1131
1350
|
|
|
1351
|
+
# Create and register mailbox router
|
|
1352
|
+
mailbox_router = create_mailbox_router()
|
|
1353
|
+
app.include_router(mailbox_router, prefix="/mailbox")
|
|
1354
|
+
|
|
1355
|
+
# Create and register repo setup router
|
|
1356
|
+
repo_router = create_repo_router()
|
|
1357
|
+
app.include_router(repo_router, prefix="/repo")
|
|
1358
|
+
|
|
1132
1359
|
logger.debug("Registered info routes: /status, /plan, /logs, /progress, /context, /health")
|
|
1133
1360
|
logger.debug("Registered control routes: /control/stop, /control/resume, /config")
|
|
1134
1361
|
logger.debug("Registered task routes: /task/init, /task")
|
|
1135
1362
|
logger.debug("Registered webhook routes: /webhooks, /webhooks/{id}, /webhooks/test")
|
|
1363
|
+
logger.debug("Registered mailbox routes: /mailbox/send, /mailbox")
|
|
1364
|
+
logger.debug("Registered repo routes: /repo/clone, /repo/setup, /repo/plan")
|