monoco-toolkit 0.3.10__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 (130) hide show
  1. monoco/__main__.py +8 -0
  2. monoco/core/artifacts/__init__.py +16 -0
  3. monoco/core/artifacts/manager.py +575 -0
  4. monoco/core/artifacts/models.py +161 -0
  5. monoco/core/automation/__init__.py +51 -0
  6. monoco/core/automation/config.py +338 -0
  7. monoco/core/automation/field_watcher.py +296 -0
  8. monoco/core/automation/handlers.py +723 -0
  9. monoco/core/config.py +31 -4
  10. monoco/core/executor/__init__.py +38 -0
  11. monoco/core/executor/agent_action.py +254 -0
  12. monoco/core/executor/git_action.py +303 -0
  13. monoco/core/executor/im_action.py +309 -0
  14. monoco/core/executor/pytest_action.py +218 -0
  15. monoco/core/git.py +38 -0
  16. monoco/core/hooks/context.py +74 -13
  17. monoco/core/ingestion/__init__.py +20 -0
  18. monoco/core/ingestion/discovery.py +248 -0
  19. monoco/core/ingestion/watcher.py +343 -0
  20. monoco/core/ingestion/worker.py +436 -0
  21. monoco/core/loader.py +633 -0
  22. monoco/core/registry.py +34 -25
  23. monoco/core/router/__init__.py +55 -0
  24. monoco/core/router/action.py +341 -0
  25. monoco/core/router/router.py +392 -0
  26. monoco/core/scheduler/__init__.py +63 -0
  27. monoco/core/scheduler/base.py +152 -0
  28. monoco/core/scheduler/engines.py +175 -0
  29. monoco/core/scheduler/events.py +171 -0
  30. monoco/core/scheduler/local.py +377 -0
  31. monoco/core/skills.py +119 -80
  32. monoco/core/watcher/__init__.py +57 -0
  33. monoco/core/watcher/base.py +365 -0
  34. monoco/core/watcher/dropzone.py +152 -0
  35. monoco/core/watcher/issue.py +303 -0
  36. monoco/core/watcher/memo.py +200 -0
  37. monoco/core/watcher/task.py +238 -0
  38. monoco/daemon/app.py +77 -1
  39. monoco/daemon/commands.py +10 -0
  40. monoco/daemon/events.py +34 -0
  41. monoco/daemon/mailroom_service.py +196 -0
  42. monoco/daemon/models.py +1 -0
  43. monoco/daemon/scheduler.py +207 -0
  44. monoco/daemon/services.py +27 -58
  45. monoco/daemon/triggers.py +55 -0
  46. monoco/features/agent/__init__.py +25 -7
  47. monoco/features/agent/adapter.py +17 -7
  48. monoco/features/agent/cli.py +91 -57
  49. monoco/features/agent/engines.py +31 -170
  50. monoco/{core/resources/en/skills/monoco_core → features/agent/resources/en/skills/monoco_atom_core}/SKILL.md +2 -2
  51. monoco/features/agent/resources/en/skills/{flow_engineer → monoco_workflow_agent_engineer}/SKILL.md +2 -2
  52. monoco/features/agent/resources/en/skills/{flow_manager → monoco_workflow_agent_manager}/SKILL.md +2 -2
  53. monoco/features/agent/resources/en/skills/{flow_planner → monoco_workflow_agent_planner}/SKILL.md +2 -2
  54. monoco/features/agent/resources/en/skills/{flow_reviewer → monoco_workflow_agent_reviewer}/SKILL.md +2 -2
  55. monoco/features/agent/resources/{roles/role-engineer.yaml → zh/roles/monoco_role_engineer.yaml} +3 -3
  56. monoco/features/agent/resources/{roles/role-manager.yaml → zh/roles/monoco_role_manager.yaml} +8 -8
  57. monoco/features/agent/resources/{roles/role-planner.yaml → zh/roles/monoco_role_planner.yaml} +8 -8
  58. monoco/features/agent/resources/{roles/role-reviewer.yaml → zh/roles/monoco_role_reviewer.yaml} +8 -8
  59. monoco/{core/resources/zh/skills/monoco_core → features/agent/resources/zh/skills/monoco_atom_core}/SKILL.md +2 -2
  60. monoco/features/agent/resources/zh/skills/{flow_engineer → monoco_workflow_agent_engineer}/SKILL.md +2 -2
  61. monoco/features/agent/resources/zh/skills/{flow_manager → monoco_workflow_agent_manager}/SKILL.md +2 -2
  62. monoco/features/agent/resources/zh/skills/{flow_planner → monoco_workflow_agent_planner}/SKILL.md +2 -2
  63. monoco/features/agent/resources/zh/skills/{flow_reviewer → monoco_workflow_agent_reviewer}/SKILL.md +2 -2
  64. monoco/features/agent/worker.py +1 -1
  65. monoco/features/artifact/__init__.py +0 -0
  66. monoco/features/artifact/adapter.py +33 -0
  67. monoco/features/artifact/resources/zh/AGENTS.md +14 -0
  68. monoco/features/artifact/resources/zh/skills/monoco_atom_artifact/SKILL.md +278 -0
  69. monoco/features/glossary/adapter.py +18 -7
  70. monoco/features/glossary/resources/en/skills/{monoco_glossary → monoco_atom_glossary}/SKILL.md +2 -2
  71. monoco/features/glossary/resources/zh/skills/{monoco_glossary → monoco_atom_glossary}/SKILL.md +2 -2
  72. monoco/features/hooks/__init__.py +11 -0
  73. monoco/features/hooks/adapter.py +67 -0
  74. monoco/features/hooks/commands.py +309 -0
  75. monoco/features/hooks/core.py +441 -0
  76. monoco/features/hooks/resources/ADDING_HOOKS.md +234 -0
  77. monoco/features/i18n/adapter.py +18 -5
  78. monoco/features/i18n/core.py +482 -17
  79. monoco/features/i18n/resources/en/skills/{monoco_i18n → monoco_atom_i18n}/SKILL.md +2 -2
  80. monoco/features/i18n/resources/en/skills/{i18n_scan_workflow → monoco_workflow_i18n_scan}/SKILL.md +2 -2
  81. monoco/features/i18n/resources/zh/skills/{monoco_i18n → monoco_atom_i18n}/SKILL.md +2 -2
  82. monoco/features/i18n/resources/zh/skills/{i18n_scan_workflow → monoco_workflow_i18n_scan}/SKILL.md +2 -2
  83. monoco/features/issue/adapter.py +19 -6
  84. monoco/features/issue/commands.py +352 -20
  85. monoco/features/issue/core.py +475 -16
  86. monoco/features/issue/engine/machine.py +114 -4
  87. monoco/features/issue/linter.py +60 -5
  88. monoco/features/issue/models.py +2 -2
  89. monoco/features/issue/resources/en/AGENTS.md +109 -0
  90. monoco/features/issue/resources/en/skills/{monoco_issue → monoco_atom_issue}/SKILL.md +2 -2
  91. monoco/features/issue/resources/en/skills/{issue_create_workflow → monoco_workflow_issue_creation}/SKILL.md +2 -2
  92. monoco/features/issue/resources/en/skills/{issue_develop_workflow → monoco_workflow_issue_development}/SKILL.md +2 -2
  93. monoco/features/issue/resources/en/skills/{issue_lifecycle_workflow → monoco_workflow_issue_management}/SKILL.md +2 -2
  94. monoco/features/issue/resources/en/skills/{issue_refine_workflow → monoco_workflow_issue_refinement}/SKILL.md +2 -2
  95. monoco/features/issue/resources/hooks/post-checkout.sh +39 -0
  96. monoco/features/issue/resources/hooks/pre-commit.sh +41 -0
  97. monoco/features/issue/resources/hooks/pre-push.sh +35 -0
  98. monoco/features/issue/resources/zh/AGENTS.md +109 -0
  99. monoco/features/issue/resources/zh/skills/{monoco_issue → monoco_atom_issue_lifecycle}/SKILL.md +2 -2
  100. monoco/features/issue/resources/zh/skills/{issue_create_workflow → monoco_workflow_issue_creation}/SKILL.md +2 -2
  101. monoco/features/issue/resources/zh/skills/{issue_develop_workflow → monoco_workflow_issue_development}/SKILL.md +2 -2
  102. monoco/features/issue/resources/zh/skills/{issue_lifecycle_workflow → monoco_workflow_issue_management}/SKILL.md +2 -2
  103. monoco/features/issue/resources/zh/skills/{issue_refine_workflow → monoco_workflow_issue_refinement}/SKILL.md +2 -2
  104. monoco/features/issue/validator.py +101 -1
  105. monoco/features/memo/adapter.py +21 -8
  106. monoco/features/memo/cli.py +103 -10
  107. monoco/features/memo/core.py +178 -92
  108. monoco/features/memo/models.py +53 -0
  109. monoco/features/memo/resources/en/skills/{monoco_memo → monoco_atom_memo}/SKILL.md +2 -2
  110. monoco/features/memo/resources/en/skills/{note_processing_workflow → monoco_workflow_note_processing}/SKILL.md +2 -2
  111. monoco/features/memo/resources/zh/skills/{monoco_memo → monoco_atom_memo}/SKILL.md +2 -2
  112. monoco/features/memo/resources/zh/skills/{note_processing_workflow → monoco_workflow_note_processing}/SKILL.md +2 -2
  113. monoco/features/spike/adapter.py +18 -5
  114. monoco/features/spike/commands.py +5 -3
  115. monoco/features/spike/resources/en/skills/{monoco_spike → monoco_atom_spike}/SKILL.md +2 -2
  116. monoco/features/spike/resources/en/skills/{research_workflow → monoco_workflow_research}/SKILL.md +2 -2
  117. monoco/features/spike/resources/zh/skills/{monoco_spike → monoco_atom_spike}/SKILL.md +2 -2
  118. monoco/features/spike/resources/zh/skills/{research_workflow → monoco_workflow_research}/SKILL.md +2 -2
  119. monoco/main.py +38 -1
  120. {monoco_toolkit-0.3.10.dist-info → monoco_toolkit-0.3.12.dist-info}/METADATA +7 -1
  121. monoco_toolkit-0.3.12.dist-info/RECORD +202 -0
  122. monoco/features/agent/apoptosis.py +0 -44
  123. monoco/features/agent/manager.py +0 -91
  124. monoco/features/agent/session.py +0 -121
  125. monoco_toolkit-0.3.10.dist-info/RECORD +0 -156
  126. /monoco/{core → features/agent}/resources/en/AGENTS.md +0 -0
  127. /monoco/{core → features/agent}/resources/zh/AGENTS.md +0 -0
  128. {monoco_toolkit-0.3.10.dist-info → monoco_toolkit-0.3.12.dist-info}/WHEEL +0 -0
  129. {monoco_toolkit-0.3.10.dist-info → monoco_toolkit-0.3.12.dist-info}/entry_points.txt +0 -0
  130. {monoco_toolkit-0.3.10.dist-info → monoco_toolkit-0.3.12.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,207 @@
1
+ """
2
+ Scheduler Service - Unified event-driven architecture (FEAT-0164).
3
+
4
+ This module implements a unified event-driven scheduler service that:
5
+ 1. Uses AgentScheduler for agent lifecycle management (FEAT-0160)
6
+ 2. Integrates Watcher framework for file system events (FEAT-0161)
7
+ 3. Uses ActionRouter for event routing (FEAT-0161)
8
+ 4. Uses new Handler framework from core.automation (FEAT-0162)
9
+
10
+ Replaces the old architecture based on SessionManager + SemaphoreManager + polling loops.
11
+ """
12
+
13
+ import asyncio
14
+ import logging
15
+ import os
16
+ from typing import Dict, Optional, List, Any
17
+ from pathlib import Path
18
+
19
+ from monoco.daemon.services import ProjectManager
20
+ from monoco.core.scheduler import (
21
+ AgentEventType,
22
+ event_bus,
23
+ AgentScheduler,
24
+ LocalProcessScheduler,
25
+ )
26
+ from monoco.core.router import ActionRouter
27
+ from monoco.core.watcher import WatchConfig, IssueWatcher, MemoWatcher, TaskWatcher
28
+ from monoco.core.automation.handlers import start_all_handlers, stop_all_handlers
29
+ from monoco.core.config import get_config
30
+
31
+ logger = logging.getLogger("monoco.daemon.scheduler")
32
+
33
+
34
+ class SchedulerService:
35
+ """
36
+ Unified event-driven scheduler service.
37
+
38
+ Responsibilities:
39
+ - Initialize and manage AgentScheduler
40
+ - Setup and manage Watchers for file system events
41
+ - Configure ActionRouter for event routing
42
+ - Start/stop all handlers
43
+
44
+ Architecture:
45
+ ```
46
+ SchedulerService
47
+ ├── AgentScheduler (LocalProcessScheduler)
48
+ │ └── Manages agent process lifecycle
49
+ ├── Watchers
50
+ │ ├── IssueWatcher -> EventBus
51
+ │ ├── MemoWatcher -> EventBus
52
+ │ └── TaskWatcher -> EventBus
53
+ ├── ActionRouter
54
+ │ └── Routes events to Actions
55
+ └── Handlers (from core.automation)
56
+ ├── TaskFileHandler
57
+ ├── IssueStageHandler
58
+ ├── MemoThresholdHandler
59
+ └── PRCreatedHandler
60
+ ```
61
+ """
62
+
63
+ def __init__(self, project_manager: ProjectManager):
64
+ self.project_manager = project_manager
65
+
66
+ # AgentScheduler (FEAT-0160)
67
+ scheduler_config = self._load_scheduler_config()
68
+ self.agent_scheduler: AgentScheduler = LocalProcessScheduler(
69
+ max_concurrent=scheduler_config.get("max_concurrent", 5),
70
+ project_root=Path.cwd(),
71
+ )
72
+
73
+ # ActionRouter (FEAT-0161)
74
+ self.action_router = ActionRouter(event_bus)
75
+
76
+ # Watchers (FEAT-0161)
77
+ self.watchers: List[Any] = []
78
+
79
+ # Handlers (FEAT-0162)
80
+ self.handlers: List[Any] = []
81
+
82
+ # Background tasks
83
+ self._tasks: List[asyncio.Task] = []
84
+ self._running = False
85
+
86
+ def _load_scheduler_config(self) -> Dict[str, Any]:
87
+ """Load scheduler configuration from config files and env vars."""
88
+ config = {"max_concurrent": 5}
89
+
90
+ try:
91
+ settings = get_config()
92
+
93
+ # Check for concurrency config
94
+ if hasattr(settings, "agent") and hasattr(settings.agent, "concurrency"):
95
+ concurrency_config = settings.agent.concurrency
96
+ if hasattr(concurrency_config, "global_max"):
97
+ config["max_concurrent"] = concurrency_config.global_max
98
+
99
+ # Check for environment variable override
100
+ env_max_agents = os.environ.get("MONOCO_MAX_AGENTS")
101
+ if env_max_agents:
102
+ try:
103
+ config["max_concurrent"] = int(env_max_agents)
104
+ logger.info(f"Overriding max_concurrent from environment: {env_max_agents}")
105
+ except ValueError:
106
+ logger.warning(f"Invalid MONOCO_MAX_AGENTS value: {env_max_agents}")
107
+
108
+ return config
109
+ except Exception as e:
110
+ logger.warning(f"Failed to load scheduler config: {e}. Using defaults.")
111
+ return config
112
+
113
+ async def start(self):
114
+ """Start the scheduler service."""
115
+ logger.info("Starting Scheduler Service (unified event-driven architecture)...")
116
+ self._running = True
117
+
118
+ # 1. Start EventBus
119
+ await event_bus.start()
120
+
121
+ # 2. Start AgentScheduler
122
+ await self.agent_scheduler.start()
123
+
124
+ # 3. Setup and start Watchers
125
+ self._setup_watchers()
126
+ for watcher in self.watchers:
127
+ await watcher.start()
128
+
129
+ # 4. Start Handlers (FEAT-0162)
130
+ self.handlers = start_all_handlers(self.agent_scheduler)
131
+
132
+ # 5. Start ActionRouter
133
+ await self.action_router.start()
134
+
135
+ logger.info("Scheduler Service started with unified event-driven architecture")
136
+
137
+ def stop(self):
138
+ """Stop the scheduler service."""
139
+ logger.info("Stopping Scheduler Service...")
140
+ self._running = False
141
+
142
+ # Cancel background tasks
143
+ for task in self._tasks:
144
+ task.cancel()
145
+
146
+ # Stop ActionRouter
147
+ asyncio.create_task(self.action_router.stop())
148
+
149
+ # Stop Handlers
150
+ stop_all_handlers(self.handlers)
151
+ self.handlers = []
152
+
153
+ # Stop Watchers
154
+ for watcher in self.watchers:
155
+ asyncio.create_task(watcher.stop())
156
+ self.watchers = []
157
+
158
+ # Stop AgentScheduler
159
+ asyncio.create_task(self.agent_scheduler.stop())
160
+
161
+ # Stop EventBus
162
+ asyncio.create_task(event_bus.stop())
163
+
164
+ logger.info("Scheduler Service stopped")
165
+
166
+ def _setup_watchers(self):
167
+ """Initialize all filesystem watchers."""
168
+ for project_ctx in self.project_manager.projects.values():
169
+ # IssueWatcher
170
+ config = WatchConfig(
171
+ path=project_ctx.issues_root,
172
+ patterns=["*.md"],
173
+ recursive=True,
174
+ )
175
+ self.watchers.append(IssueWatcher(config, event_bus))
176
+
177
+ # MemoWatcher
178
+ memo_path = project_ctx.path / "Memos" / "inbox.md"
179
+ if memo_path.exists():
180
+ memo_config = WatchConfig(
181
+ path=memo_path,
182
+ patterns=["*.md"],
183
+ )
184
+ self.watchers.append(MemoWatcher(memo_config, event_bus))
185
+
186
+ # TaskWatcher (if tasks.md exists)
187
+ task_path = project_ctx.path / "tasks.md"
188
+ if task_path.exists():
189
+ task_config = WatchConfig(
190
+ path=task_path,
191
+ patterns=["*.md"],
192
+ )
193
+ self.watchers.append(TaskWatcher(task_config, event_bus))
194
+
195
+ logger.info(f"Setup {len(self.watchers)} watchers")
196
+
197
+ def get_stats(self) -> Dict[str, Any]:
198
+ """Get scheduler service statistics."""
199
+ return {
200
+ "running": self._running,
201
+ "event_bus": event_bus.get_stats(),
202
+ "agent_scheduler": self.agent_scheduler.get_stats(),
203
+ "watchers": len(self.watchers),
204
+ "handlers": len(self.handlers),
205
+ "action_router": self.action_router.get_stats(),
206
+ "projects": len(self.project_manager.projects),
207
+ }
monoco/daemon/services.py CHANGED
@@ -3,7 +3,7 @@ from typing import List, Optional, Dict, Any
3
3
  from asyncio import Queue
4
4
  from pathlib import Path
5
5
 
6
- import json
6
+ from monoco.core.workspace import MonocoProject, Workspace
7
7
 
8
8
  logger = logging.getLogger("monoco.daemon.services")
9
9
 
@@ -31,6 +31,7 @@ class Broadcaster:
31
31
  if not self.subscribers:
32
32
  return
33
33
 
34
+ import json
34
35
  message = {"event": event_type, "data": json.dumps(payload)}
35
36
 
36
37
  # Dispatch to all queues
@@ -40,12 +41,6 @@ class Broadcaster:
40
41
  logger.debug(f"Broadcasted {event_type} to {len(self.subscribers)} clients.")
41
42
 
42
43
 
43
- # Monitors moved to monoco.core.git and monoco.features.issue.monitor
44
-
45
-
46
- from monoco.core.workspace import MonocoProject, Workspace
47
-
48
-
49
44
  class ProjectContext:
50
45
  """
51
46
  Holds the runtime state for a single project.
@@ -58,7 +53,31 @@ class ProjectContext:
58
53
  self.name = project.name
59
54
  self.path = project.path
60
55
  self.issues_root = project.issues_root
61
- self.monitor = IssueMonitor(self.issues_root, broadcaster, project_id=self.id)
56
+
57
+ async def on_upsert(issue_data: dict):
58
+ await broadcaster.broadcast(
59
+ "issue_upserted", {"issue": issue_data, "project_id": self.id}
60
+ )
61
+
62
+ async def on_delete(issue_data: dict):
63
+ await broadcaster.broadcast(
64
+ "issue_deleted", {"id": issue_data["id"], "project_id": self.id}
65
+ )
66
+
67
+ from monoco.features.issue.monitor import IssueMonitor
68
+ self.monitor = IssueMonitor(self.issues_root, on_upsert, on_delete)
69
+
70
+ async def notify_move(self, old_path: str, new_path: str, issue_data: dict):
71
+ """Explicitly notify frontend about a logical move (Physical path changed)."""
72
+ await self.broadcaster.broadcast(
73
+ "issue_moved",
74
+ {
75
+ "old_path": old_path,
76
+ "new_path": new_path,
77
+ "issue": issue_data,
78
+ "project_id": self.id,
79
+ },
80
+ )
62
81
 
63
82
  async def start(self):
64
83
  await self.monitor.start()
@@ -113,53 +132,3 @@ class ProjectManager:
113
132
  }
114
133
  for p in self.projects.values()
115
134
  ]
116
-
117
-
118
- from monoco.features.issue.monitor import IssueMonitor
119
-
120
-
121
- class ProjectContext:
122
- """
123
- Holds the runtime state for a single project.
124
- Now wraps the core MonocoProject primitive.
125
- """
126
-
127
- def __init__(self, project: MonocoProject, broadcaster: Broadcaster):
128
- self.project = project
129
- self.id = project.id
130
- self.name = project.name
131
- self.path = project.path
132
- self.issues_root = project.issues_root
133
-
134
- async def on_upsert(issue_data: dict):
135
- await broadcaster.broadcast(
136
- "issue_upserted", {"issue": issue_data, "project_id": self.id}
137
- )
138
-
139
- async def on_delete(issue_data: dict):
140
- # We skip broadcast here if it's part of a move?
141
- # Actually, standard upsert/delete is fine, but we need a specialized event for MOVE
142
- # to help VS Code redirect without closing/reopening.
143
- await broadcaster.broadcast(
144
- "issue_deleted", {"id": issue_data["id"], "project_id": self.id}
145
- )
146
-
147
- self.monitor = IssueMonitor(self.issues_root, on_upsert, on_delete)
148
-
149
- async def notify_move(self, old_path: str, new_path: str, issue_data: dict):
150
- """Explicitly notify frontend about a logical move (Physical path changed)."""
151
- await self.broadcaster.broadcast(
152
- "issue_moved",
153
- {
154
- "old_path": old_path,
155
- "new_path": new_path,
156
- "issue": issue_data,
157
- "project_id": self.id,
158
- },
159
- )
160
-
161
- async def start(self):
162
- await self.monitor.start()
163
-
164
- def stop(self):
165
- self.monitor.stop()
@@ -0,0 +1,55 @@
1
+ from typing import TYPE_CHECKING, Optional, List, Any
2
+ from pathlib import Path
3
+ from monoco.features.memo.core import load_memos
4
+ from monoco.features.issue.models import IssueMetadata, IssueStatus, IssueStage
5
+
6
+ if TYPE_CHECKING:
7
+ from monoco.features.issue.models import IssueMetadata
8
+
9
+ class TriggerPolicy:
10
+ """
11
+ Base class for trigger policies.
12
+ """
13
+ def evaluate(self, context: dict) -> bool:
14
+ raise NotImplementedError
15
+
16
+ class MemoAccumulationPolicy(TriggerPolicy):
17
+ """
18
+ Trigger when pending memos exceed a threshold.
19
+ """
20
+ def __init__(self, count_threshold: int = 5):
21
+ self.count_threshold = count_threshold
22
+
23
+ def evaluate(self, context: dict) -> bool:
24
+ issues_root = context.get("issues_root")
25
+ if not issues_root:
26
+ return False
27
+
28
+ if isinstance(issues_root, str):
29
+ issues_root = Path(issues_root)
30
+
31
+ try:
32
+ memos = load_memos(issues_root)
33
+ pending_memos = [m for m in memos if m.status == "pending"]
34
+ return len(pending_memos) >= self.count_threshold
35
+ except Exception as e:
36
+ print(f"Error evaluating MemoAccumulationPolicy: {e}")
37
+ return False
38
+
39
+ class HandoverPolicy(TriggerPolicy):
40
+ """
41
+ Trigger when an issue enters a specific state (e.g. Open/Doing for Engineer).
42
+ """
43
+ def __init__(self, target_status: IssueStatus, target_stage: IssueStage):
44
+ self.target_status = target_status
45
+ self.target_stage = target_stage
46
+
47
+ def evaluate(self, context: dict) -> bool:
48
+ issue: Optional[IssueMetadata] = context.get("issue")
49
+ if not issue:
50
+ return False
51
+
52
+ return (
53
+ issue.status == self.target_status
54
+ and issue.stage == self.target_stage
55
+ )
@@ -1,10 +1,25 @@
1
+ """
2
+ Agent feature module - CLI interface for agent operations.
3
+
4
+ Note: The old SessionManager/RuntimeSession/ApoptosisManager architecture
5
+ has been removed in FEAT-0164. This module now provides CLI commands that
6
+ use the new AgentScheduler abstraction from core.scheduler.
7
+ """
8
+
1
9
  from .models import RoleTemplate, AgentRoleConfig as AgentConfig, SchedulerConfig
2
10
  from .worker import Worker
3
11
  from .config import load_scheduler_config, load_agent_config
4
12
  from .defaults import DEFAULT_ROLES
5
- from .session import Session, RuntimeSession
6
- from .manager import SessionManager
7
- from .apoptosis import ApoptosisManager
13
+
14
+ # Re-export engines from core.scheduler for backward compatibility
15
+ from monoco.core.scheduler import (
16
+ EngineAdapter,
17
+ EngineFactory,
18
+ GeminiAdapter,
19
+ ClaudeAdapter,
20
+ QwenAdapter,
21
+ KimiAdapter,
22
+ )
8
23
 
9
24
  __all__ = [
10
25
  "RoleTemplate",
@@ -14,8 +29,11 @@ __all__ = [
14
29
  "Worker",
15
30
  "load_scheduler_config",
16
31
  "DEFAULT_ROLES",
17
- "Session",
18
- "RuntimeSession",
19
- "SessionManager",
20
- "ApoptosisManager",
32
+ # Re-exported from core.scheduler
33
+ "EngineAdapter",
34
+ "EngineFactory",
35
+ "GeminiAdapter",
36
+ "ClaudeAdapter",
37
+ "QwenAdapter",
38
+ "KimiAdapter",
21
39
  ]
@@ -1,18 +1,28 @@
1
1
  from pathlib import Path
2
2
  from typing import Dict
3
- from monoco.core.feature import MonocoFeature, IntegrationData
3
+ from monoco.core.loader import FeatureModule, FeatureMetadata
4
+ from monoco.core.feature import IntegrationData
4
5
 
5
6
 
6
- class AgentFeature(MonocoFeature):
7
- @property
8
- def name(self) -> str:
9
- return "agent"
7
+ class AgentFeature(FeatureModule):
8
+ """Agent management feature module with unified lifecycle support."""
10
9
 
11
- def initialize(self, root: Path, config: Dict) -> None:
12
- # Agent feature doesn't require special initialization
10
+ @property
11
+ def metadata(self) -> FeatureMetadata:
12
+ return FeatureMetadata(
13
+ name="agent",
14
+ version="1.0.0",
15
+ description="Agent session and role management",
16
+ dependencies=["core"],
17
+ priority=20,
18
+ )
19
+
20
+ def _on_mount(self, context: "FeatureContext") -> None: # type: ignore
21
+ """Agent feature doesn't require special initialization."""
13
22
  pass
14
23
 
15
24
  def integrate(self, root: Path, config: Dict) -> IntegrationData:
25
+ """Provide integration data for agent environment."""
16
26
  # Determine language from config, default to 'en'
17
27
  lang = config.get("i18n", {}).get("source_lang", "en")
18
28