monoco-toolkit 0.3.11__py3-none-any.whl → 0.3.12__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.
Files changed (44) hide show
  1. monoco/core/automation/__init__.py +51 -0
  2. monoco/core/automation/config.py +338 -0
  3. monoco/core/automation/field_watcher.py +296 -0
  4. monoco/core/automation/handlers.py +723 -0
  5. monoco/core/config.py +1 -1
  6. monoco/core/executor/__init__.py +38 -0
  7. monoco/core/executor/agent_action.py +254 -0
  8. monoco/core/executor/git_action.py +303 -0
  9. monoco/core/executor/im_action.py +309 -0
  10. monoco/core/executor/pytest_action.py +218 -0
  11. monoco/core/git.py +15 -0
  12. monoco/core/hooks/context.py +74 -13
  13. monoco/core/router/__init__.py +55 -0
  14. monoco/core/router/action.py +341 -0
  15. monoco/core/router/router.py +392 -0
  16. monoco/core/scheduler/__init__.py +63 -0
  17. monoco/core/scheduler/base.py +152 -0
  18. monoco/core/scheduler/engines.py +175 -0
  19. monoco/core/scheduler/events.py +171 -0
  20. monoco/core/scheduler/local.py +377 -0
  21. monoco/core/watcher/__init__.py +57 -0
  22. monoco/core/watcher/base.py +365 -0
  23. monoco/core/watcher/dropzone.py +152 -0
  24. monoco/core/watcher/issue.py +303 -0
  25. monoco/core/watcher/memo.py +200 -0
  26. monoco/core/watcher/task.py +238 -0
  27. monoco/daemon/events.py +34 -0
  28. monoco/daemon/scheduler.py +172 -201
  29. monoco/daemon/services.py +27 -243
  30. monoco/features/agent/__init__.py +25 -7
  31. monoco/features/agent/cli.py +91 -57
  32. monoco/features/agent/engines.py +31 -170
  33. monoco/features/agent/worker.py +1 -1
  34. monoco/features/issue/commands.py +90 -32
  35. monoco/features/issue/core.py +249 -4
  36. monoco/features/spike/commands.py +5 -3
  37. {monoco_toolkit-0.3.11.dist-info → monoco_toolkit-0.3.12.dist-info}/METADATA +1 -1
  38. {monoco_toolkit-0.3.11.dist-info → monoco_toolkit-0.3.12.dist-info}/RECORD +41 -20
  39. monoco/features/agent/apoptosis.py +0 -44
  40. monoco/features/agent/manager.py +0 -127
  41. monoco/features/agent/session.py +0 -169
  42. {monoco_toolkit-0.3.11.dist-info → monoco_toolkit-0.3.12.dist-info}/WHEEL +0 -0
  43. {monoco_toolkit-0.3.11.dist-info → monoco_toolkit-0.3.12.dist-info}/entry_points.txt +0 -0
  44. {monoco_toolkit-0.3.11.dist-info → monoco_toolkit-0.3.12.dist-info}/licenses/LICENSE +0 -0
@@ -1,169 +0,0 @@
1
- from datetime import datetime
2
- from typing import Optional
3
- from pathlib import Path
4
- from pydantic import BaseModel, Field, ConfigDict
5
-
6
- from .worker import Worker
7
- from monoco.core.hooks import HookContext, HookRegistry, get_registry
8
- from monoco.core.config import find_monoco_root
9
-
10
-
11
- class Session(BaseModel):
12
- """
13
- Represents a runtime session of a worker.
14
- Persisted state of the session.
15
- """
16
-
17
- model_config = ConfigDict(arbitrary_types_allowed=True)
18
-
19
- id: str = Field(..., description="Unique session ID (likely UUID)")
20
- issue_id: str = Field(..., description="The Issue ID this session is working on")
21
- role_name: str = Field(..., description="Name of the role employed")
22
- status: str = Field(
23
- default="pending", description="pending, running, suspended, terminated"
24
- )
25
- branch_name: str = Field(
26
- ..., description="Git branch name associated with this session"
27
- )
28
- pid: Optional[int] = Field(default=None, description="Process ID of the worker")
29
- created_at: datetime = Field(default_factory=datetime.now)
30
- updated_at: datetime = Field(default_factory=datetime.now)
31
- # History could be a list of logs or pointers to git commits
32
- # For now, let's keep it simple. The git log IS the history.
33
-
34
-
35
- class RuntimeSession:
36
- """
37
- The in-memory wrapper around the Session model and the active Worker.
38
- """
39
-
40
- def __init__(
41
- self,
42
- session_model: Session,
43
- worker: Optional[Worker],
44
- hook_registry: Optional[HookRegistry] = None,
45
- project_root: Optional[Path] = None,
46
- save_callback: Optional[callable] = None,
47
- ):
48
- self.model = session_model
49
- self.worker = worker
50
- self.hook_registry = hook_registry or get_registry()
51
- self.project_root = project_root or find_monoco_root()
52
- self.save_callback = save_callback
53
-
54
- def _save(self):
55
- if self.save_callback:
56
- self.save_callback(self.model)
57
-
58
- def _create_hook_context(self) -> HookContext:
59
- """Create a HookContext from the current session state."""
60
- return HookContext.from_runtime_session(self, self.project_root)
61
-
62
- def start(self, context: Optional[dict] = None):
63
- if not self.worker:
64
- raise RuntimeError(
65
- "Cannot start session in observer mode (no worker attached)"
66
- )
67
-
68
- print(
69
- f"Session {self.model.id}: Starting worker on branch {self.model.branch_name}"
70
- )
71
- # In real impl, checking out branch happening here
72
- self.model.status = "running"
73
- self.model.updated_at = datetime.now()
74
-
75
- try:
76
- # Execute on_session_start hooks
77
- hook_context = self._create_hook_context()
78
- self.hook_registry.execute_on_session_start(hook_context)
79
-
80
- self.worker.start(context)
81
- # Async mode: we assume it started running.
82
- # Use poll or refresh_status to check later.
83
- self.model.status = "running"
84
- self.model.pid = self.worker.process_id
85
- except Exception:
86
- self.model.status = "failed"
87
- raise
88
- finally:
89
- self.model.updated_at = datetime.now()
90
- self._save()
91
-
92
- def refresh_status(self) -> str:
93
- """
94
- Polls the worker and updates the session model status.
95
- """
96
- if self.worker:
97
- worker_status = self.worker.poll()
98
- self.model.status = worker_status
99
- else:
100
- # Observer mode
101
- if self.model.pid:
102
- try:
103
- import os
104
-
105
- # Check if process exists.
106
- # kill(pid, 0) does not send a signal but raises OSError if pid missing
107
- os.kill(self.model.pid, 0)
108
- # If we are here, process exists. We assume running if it was running.
109
- # We can't detect "suspended" easily without psutil.
110
- if self.model.status == "terminated":
111
- # If we thought it was terminated but it's alive, maybe update?
112
- # Or keep as terminated? Let's assume running if found.
113
- pass
114
- except OSError:
115
- self.model.status = "terminated"
116
- else:
117
- self.model.status = "terminated"
118
-
119
- self.model.updated_at = datetime.now()
120
- self._save()
121
- return self.model.status
122
-
123
- def suspend(self):
124
- if not self.worker:
125
- raise RuntimeError("Cannot suspend session in observer mode")
126
-
127
- print(f"Session {self.model.id}: Suspending worker")
128
- self.worker.stop()
129
- self.model.status = "suspended"
130
- self.model.updated_at = datetime.now()
131
- self._save()
132
- # In real impl, ensure git commit of current state?
133
-
134
- def resume(self):
135
- if not self.worker:
136
- raise RuntimeError("Cannot resume session in observer mode")
137
-
138
- print(f"Session {self.model.id}: Resuming worker")
139
- self.worker.start() # In real impl, might need to re-init process
140
-
141
- # Async mode: assume running
142
- self.model.status = "running"
143
- self.model.pid = self.worker.process_id
144
- self.model.updated_at = datetime.now()
145
- self._save()
146
-
147
- def terminate(self):
148
- print(f"Session {self.model.id}: Terminating")
149
-
150
- # Execute on_session_end hooks before stopping worker
151
- # This allows hooks to perform cleanup while session context is still valid
152
- try:
153
- hook_context = self._create_hook_context()
154
- results = self.hook_registry.execute_on_session_end(hook_context)
155
-
156
- # Log hook results
157
- for result in results:
158
- if result.status == "failure":
159
- print(f" Hook warning: {result.message}")
160
- except Exception as e:
161
- # Don't let hook errors prevent session termination
162
- print(f" Hook execution error: {e}")
163
-
164
- if self.worker:
165
- self.worker.stop()
166
-
167
- self.model.status = "terminated"
168
- self.model.updated_at = datetime.now()
169
- self._save()