monoco-toolkit 0.2.7__py3-none-any.whl → 0.3.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.
- monoco/cli/project.py +35 -31
- monoco/cli/workspace.py +26 -16
- monoco/core/agent/__init__.py +0 -2
- monoco/core/agent/action.py +44 -20
- monoco/core/agent/adapters.py +20 -16
- monoco/core/agent/protocol.py +5 -4
- monoco/core/agent/state.py +21 -21
- monoco/core/config.py +90 -33
- monoco/core/execution.py +21 -16
- monoco/core/feature.py +8 -5
- monoco/core/git.py +61 -30
- monoco/core/hooks.py +57 -0
- monoco/core/injection.py +47 -44
- monoco/core/integrations.py +50 -35
- monoco/core/lsp.py +12 -1
- monoco/core/output.py +35 -16
- monoco/core/registry.py +3 -2
- monoco/core/setup.py +190 -124
- monoco/core/skills.py +121 -107
- monoco/core/state.py +12 -10
- monoco/core/sync.py +85 -56
- monoco/core/telemetry.py +10 -6
- monoco/core/workspace.py +26 -19
- monoco/daemon/app.py +123 -79
- monoco/daemon/commands.py +14 -13
- monoco/daemon/models.py +11 -3
- monoco/daemon/reproduce_stats.py +8 -8
- monoco/daemon/services.py +32 -33
- monoco/daemon/stats.py +59 -40
- monoco/features/config/commands.py +38 -25
- monoco/features/i18n/adapter.py +4 -5
- monoco/features/i18n/commands.py +83 -49
- monoco/features/i18n/core.py +94 -54
- monoco/features/issue/adapter.py +6 -7
- monoco/features/issue/commands.py +500 -260
- monoco/features/issue/core.py +504 -293
- monoco/features/issue/domain/lifecycle.py +33 -23
- monoco/features/issue/domain/models.py +71 -38
- monoco/features/issue/domain/parser.py +92 -69
- monoco/features/issue/domain/workspace.py +19 -16
- monoco/features/issue/engine/__init__.py +3 -3
- monoco/features/issue/engine/config.py +18 -25
- monoco/features/issue/engine/machine.py +72 -39
- monoco/features/issue/engine/models.py +4 -2
- monoco/features/issue/linter.py +326 -111
- monoco/features/issue/lsp/definition.py +26 -19
- monoco/features/issue/migration.py +45 -34
- monoco/features/issue/models.py +30 -13
- monoco/features/issue/monitor.py +24 -8
- monoco/features/issue/resources/en/AGENTS.md +5 -0
- monoco/features/issue/resources/en/SKILL.md +30 -2
- monoco/features/issue/resources/zh/AGENTS.md +5 -0
- monoco/features/issue/resources/zh/SKILL.md +26 -1
- monoco/features/issue/validator.py +417 -172
- monoco/features/skills/__init__.py +0 -1
- monoco/features/skills/core.py +24 -18
- monoco/features/spike/adapter.py +4 -5
- monoco/features/spike/commands.py +51 -38
- monoco/features/spike/core.py +24 -16
- monoco/main.py +34 -21
- {monoco_toolkit-0.2.7.dist-info → monoco_toolkit-0.3.0.dist-info}/METADATA +10 -3
- monoco_toolkit-0.3.0.dist-info/RECORD +84 -0
- monoco_toolkit-0.2.7.dist-info/RECORD +0 -83
- {monoco_toolkit-0.2.7.dist-info → monoco_toolkit-0.3.0.dist-info}/WHEEL +0 -0
- {monoco_toolkit-0.2.7.dist-info → monoco_toolkit-0.3.0.dist-info}/entry_points.txt +0 -0
- {monoco_toolkit-0.2.7.dist-info → monoco_toolkit-0.3.0.dist-info}/licenses/LICENSE +0 -0
monoco/core/config.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import os
|
|
2
1
|
import yaml
|
|
3
2
|
from pathlib import Path
|
|
4
3
|
from typing import Optional, Dict, Any, Callable, Awaitable, List
|
|
@@ -11,41 +10,66 @@ from watchdog.observers import Observer
|
|
|
11
10
|
from watchdog.events import FileSystemEventHandler
|
|
12
11
|
|
|
13
12
|
|
|
14
|
-
|
|
15
13
|
logger = logging.getLogger("monoco.core.config")
|
|
16
14
|
|
|
15
|
+
|
|
17
16
|
class PathsConfig(BaseModel):
|
|
18
17
|
"""Configuration for directory paths."""
|
|
18
|
+
|
|
19
19
|
root: str = Field(default=".", description="Project root directory")
|
|
20
20
|
issues: str = Field(default="Issues", description="Directory for issues")
|
|
21
|
-
spikes: str = Field(
|
|
22
|
-
|
|
21
|
+
spikes: str = Field(
|
|
22
|
+
default=".references", description="Directory for spikes/research"
|
|
23
|
+
)
|
|
24
|
+
|
|
23
25
|
|
|
24
26
|
class CoreConfig(BaseModel):
|
|
25
27
|
"""Core system configuration."""
|
|
28
|
+
|
|
26
29
|
log_level: str = Field(default="INFO", description="Logging verbosity")
|
|
27
|
-
author: Optional[str] = Field(
|
|
30
|
+
author: Optional[str] = Field(
|
|
31
|
+
default=None, description="Default author for new artifacts"
|
|
32
|
+
)
|
|
33
|
+
|
|
28
34
|
|
|
29
35
|
class ProjectConfig(BaseModel):
|
|
30
36
|
"""Project identity configuration."""
|
|
37
|
+
|
|
31
38
|
name: str = Field(default="Monoco Project", description="Project name")
|
|
32
39
|
key: str = Field(default="MON", description="Project key/prefix for IDs")
|
|
33
|
-
spike_repos: Dict[str, str] = Field(
|
|
34
|
-
|
|
40
|
+
spike_repos: Dict[str, str] = Field(
|
|
41
|
+
default_factory=dict,
|
|
42
|
+
description="Managed external research repositories (name -> url)",
|
|
43
|
+
)
|
|
44
|
+
members: Dict[str, str] = Field(
|
|
45
|
+
default_factory=dict,
|
|
46
|
+
description="Workspace member projects (name -> relative_path)",
|
|
47
|
+
)
|
|
48
|
+
|
|
35
49
|
|
|
36
50
|
class I18nConfig(BaseModel):
|
|
37
51
|
"""Configuration for internationalization."""
|
|
52
|
+
|
|
38
53
|
source_lang: str = Field(default="en", description="Source language code")
|
|
39
|
-
target_langs: list[str] = Field(
|
|
54
|
+
target_langs: list[str] = Field(
|
|
55
|
+
default_factory=lambda: ["zh"], description="Target language codes"
|
|
56
|
+
)
|
|
57
|
+
|
|
40
58
|
|
|
41
59
|
class UIConfig(BaseModel):
|
|
42
60
|
"""Configuration for UI customizations."""
|
|
43
|
-
|
|
61
|
+
|
|
62
|
+
dictionary: Dict[str, str] = Field(
|
|
63
|
+
default_factory=dict, description="Custom domain terminology mapping"
|
|
64
|
+
)
|
|
65
|
+
|
|
44
66
|
|
|
45
67
|
class TelemetryConfig(BaseModel):
|
|
46
68
|
"""Configuration for Telemetry."""
|
|
47
|
-
enabled: Optional[bool] = Field(default=None, description="Whether telemetry is enabled")
|
|
48
69
|
|
|
70
|
+
enabled: Optional[bool] = Field(
|
|
71
|
+
default=None, description="Whether telemetry is enabled"
|
|
72
|
+
)
|
|
49
73
|
|
|
50
74
|
|
|
51
75
|
class IssueTypeConfig(BaseModel):
|
|
@@ -55,6 +79,7 @@ class IssueTypeConfig(BaseModel):
|
|
|
55
79
|
folder: str
|
|
56
80
|
description: Optional[str] = None
|
|
57
81
|
|
|
82
|
+
|
|
58
83
|
class TransitionConfig(BaseModel):
|
|
59
84
|
name: str
|
|
60
85
|
label: str
|
|
@@ -67,6 +92,7 @@ class TransitionConfig(BaseModel):
|
|
|
67
92
|
description: str = ""
|
|
68
93
|
command_template: Optional[str] = None
|
|
69
94
|
|
|
95
|
+
|
|
70
96
|
class IssueSchemaConfig(BaseModel):
|
|
71
97
|
types: List[IssueTypeConfig] = Field(default_factory=list)
|
|
72
98
|
statuses: List[str] = Field(default_factory=list)
|
|
@@ -77,49 +103,56 @@ class IssueSchemaConfig(BaseModel):
|
|
|
77
103
|
def merge(self, other: "IssueSchemaConfig") -> "IssueSchemaConfig":
|
|
78
104
|
if not other:
|
|
79
105
|
return self
|
|
80
|
-
|
|
106
|
+
|
|
81
107
|
# Types: merge by name
|
|
82
108
|
if other.types:
|
|
83
109
|
type_map = {t.name: t for t in self.types}
|
|
84
110
|
for ot in other.types:
|
|
85
111
|
type_map[ot.name] = ot
|
|
86
112
|
self.types = list(type_map.values())
|
|
87
|
-
|
|
113
|
+
|
|
88
114
|
# Statuses: replace if provided
|
|
89
115
|
if other.statuses:
|
|
90
116
|
self.statuses = other.statuses
|
|
91
|
-
|
|
117
|
+
|
|
92
118
|
# Stages: replace if provided
|
|
93
119
|
if other.stages:
|
|
94
120
|
self.stages = other.stages
|
|
95
|
-
|
|
121
|
+
|
|
96
122
|
# Solutions: replace if provided
|
|
97
123
|
if other.solutions:
|
|
98
124
|
self.solutions = other.solutions
|
|
99
|
-
|
|
125
|
+
|
|
100
126
|
# Workflows (Transitions): merge by name
|
|
101
127
|
if other.workflows:
|
|
102
128
|
wf_map = {w.name: w for w in self.workflows}
|
|
103
129
|
for ow in other.workflows:
|
|
104
130
|
wf_map[ow.name] = ow
|
|
105
131
|
self.workflows = list(wf_map.values())
|
|
106
|
-
|
|
132
|
+
|
|
107
133
|
return self
|
|
108
134
|
|
|
135
|
+
|
|
109
136
|
class StateMachineConfig(BaseModel):
|
|
110
137
|
transitions: List[TransitionConfig]
|
|
111
138
|
|
|
139
|
+
|
|
112
140
|
class MonocoConfig(BaseModel):
|
|
113
141
|
"""
|
|
114
142
|
Main Configuration Schema.
|
|
115
143
|
Hierarchy: Defaults < User Config (~/.monoco/config.yaml) < Project Config (./.monoco/config.yaml)
|
|
116
144
|
"""
|
|
145
|
+
|
|
117
146
|
core: CoreConfig = Field(default_factory=CoreConfig)
|
|
118
147
|
paths: PathsConfig = Field(default_factory=PathsConfig)
|
|
119
148
|
project: ProjectConfig = Field(default_factory=ProjectConfig)
|
|
120
149
|
i18n: I18nConfig = Field(default_factory=I18nConfig)
|
|
121
150
|
ui: UIConfig = Field(default_factory=UIConfig)
|
|
122
151
|
telemetry: TelemetryConfig = Field(default_factory=TelemetryConfig)
|
|
152
|
+
hooks: Dict[str, str] = Field(
|
|
153
|
+
default_factory=dict,
|
|
154
|
+
description="Git hooks configuration (hook_name -> command)",
|
|
155
|
+
)
|
|
123
156
|
|
|
124
157
|
issue: IssueSchemaConfig = Field(default_factory=IssueSchemaConfig)
|
|
125
158
|
|
|
@@ -134,10 +167,12 @@ class MonocoConfig(BaseModel):
|
|
|
134
167
|
return base
|
|
135
168
|
|
|
136
169
|
@classmethod
|
|
137
|
-
def load(
|
|
170
|
+
def load(
|
|
171
|
+
cls, project_root: Optional[str] = None, require_project: bool = False
|
|
172
|
+
) -> "MonocoConfig":
|
|
138
173
|
"""
|
|
139
174
|
Load configuration from multiple sources.
|
|
140
|
-
|
|
175
|
+
|
|
141
176
|
Args:
|
|
142
177
|
project_root: Explicit root path. If None, uses CWD.
|
|
143
178
|
require_project: If True, raises error if .monoco directory is missing.
|
|
@@ -147,16 +182,18 @@ class MonocoConfig(BaseModel):
|
|
|
147
182
|
|
|
148
183
|
# 2. Define config paths
|
|
149
184
|
home_path = Path.home() / ".monoco" / "config.yaml"
|
|
150
|
-
|
|
185
|
+
|
|
151
186
|
# Determine project path
|
|
152
187
|
cwd = Path(project_root) if project_root else Path.cwd()
|
|
153
188
|
# FIX-0009: strict separation of workspace and project config
|
|
154
189
|
workspace_config_path = cwd / ".monoco" / "workspace.yaml"
|
|
155
190
|
project_config_path = cwd / ".monoco" / "project.yaml"
|
|
156
|
-
|
|
191
|
+
|
|
157
192
|
# Strict Workspace Check
|
|
158
193
|
if require_project and not (cwd / ".monoco").exists():
|
|
159
|
-
raise FileNotFoundError(
|
|
194
|
+
raise FileNotFoundError(
|
|
195
|
+
f"Monoco workspace not found in {cwd}. (No .monoco directory)"
|
|
196
|
+
)
|
|
160
197
|
|
|
161
198
|
# 3. Load User Config
|
|
162
199
|
if home_path.exists():
|
|
@@ -165,12 +202,12 @@ class MonocoConfig(BaseModel):
|
|
|
165
202
|
user_config = yaml.safe_load(f)
|
|
166
203
|
if user_config:
|
|
167
204
|
cls._deep_merge(config_data, user_config)
|
|
168
|
-
except Exception
|
|
205
|
+
except Exception:
|
|
169
206
|
# We don't want to crash on config load fail, implementing simple warning equivalent
|
|
170
207
|
pass
|
|
171
208
|
|
|
172
209
|
# 4. Load Project/Workspace Config
|
|
173
|
-
|
|
210
|
+
|
|
174
211
|
# 4a. Load workspace.yaml (Global Environment)
|
|
175
212
|
if workspace_config_path.exists():
|
|
176
213
|
try:
|
|
@@ -204,10 +241,14 @@ class MonocoConfig(BaseModel):
|
|
|
204
241
|
# 5. Instantiate Model
|
|
205
242
|
return cls(**config_data)
|
|
206
243
|
|
|
244
|
+
|
|
207
245
|
# Global singleton
|
|
208
246
|
_settings = None
|
|
209
247
|
|
|
210
|
-
|
|
248
|
+
|
|
249
|
+
def get_config(
|
|
250
|
+
project_root: Optional[str] = None, require_project: bool = False
|
|
251
|
+
) -> MonocoConfig:
|
|
211
252
|
global _settings
|
|
212
253
|
# If explicit root provided, always reload.
|
|
213
254
|
# If require_project is True, we must reload to ensure validation happens (in case a previous loose load occurred).
|
|
@@ -215,11 +256,13 @@ def get_config(project_root: Optional[str] = None, require_project: bool = False
|
|
|
215
256
|
_settings = MonocoConfig.load(project_root, require_project=require_project)
|
|
216
257
|
return _settings
|
|
217
258
|
|
|
259
|
+
|
|
218
260
|
class ConfigScope(str, Enum):
|
|
219
261
|
GLOBAL = "global"
|
|
220
262
|
PROJECT = "project"
|
|
221
263
|
WORKSPACE = "workspace"
|
|
222
264
|
|
|
265
|
+
|
|
223
266
|
def get_config_path(scope: ConfigScope, project_root: Optional[str] = None) -> Path:
|
|
224
267
|
"""Get the path to the configuration file for a given scope."""
|
|
225
268
|
if scope == ConfigScope.GLOBAL:
|
|
@@ -232,6 +275,7 @@ def get_config_path(scope: ConfigScope, project_root: Optional[str] = None) -> P
|
|
|
232
275
|
cwd = Path(project_root) if project_root else Path.cwd()
|
|
233
276
|
return cwd / ".monoco" / "project.yaml"
|
|
234
277
|
|
|
278
|
+
|
|
235
279
|
def find_monoco_root(start_path: Optional[Path] = None) -> Path:
|
|
236
280
|
"""
|
|
237
281
|
Find the Monoco Workspace root.
|
|
@@ -239,18 +283,21 @@ def find_monoco_root(start_path: Optional[Path] = None) -> Path:
|
|
|
239
283
|
Recursive upward lookup is disabled per FIX-0009.
|
|
240
284
|
"""
|
|
241
285
|
current = (start_path or Path.cwd()).resolve()
|
|
242
|
-
|
|
286
|
+
|
|
243
287
|
# Check if we are inside a .monoco folder
|
|
244
288
|
if current.name == ".monoco":
|
|
245
289
|
return current.parent
|
|
246
|
-
|
|
290
|
+
|
|
247
291
|
# Check if current directory has .monoco
|
|
248
292
|
if (current / ".monoco").exists():
|
|
249
293
|
return current
|
|
250
|
-
|
|
294
|
+
|
|
251
295
|
return current
|
|
252
296
|
|
|
253
|
-
|
|
297
|
+
|
|
298
|
+
def load_raw_config(
|
|
299
|
+
scope: ConfigScope, project_root: Optional[str] = None
|
|
300
|
+
) -> Dict[str, Any]:
|
|
254
301
|
"""Load raw configuration dictionary from a specific scope."""
|
|
255
302
|
path = get_config_path(scope, project_root)
|
|
256
303
|
if not path.exists():
|
|
@@ -262,15 +309,21 @@ def load_raw_config(scope: ConfigScope, project_root: Optional[str] = None) -> D
|
|
|
262
309
|
logger.warning(f"Failed to load config from {path}: {e}")
|
|
263
310
|
return {}
|
|
264
311
|
|
|
265
|
-
|
|
312
|
+
|
|
313
|
+
def save_raw_config(
|
|
314
|
+
scope: ConfigScope, data: Dict[str, Any], project_root: Optional[str] = None
|
|
315
|
+
) -> None:
|
|
266
316
|
"""Save raw configuration dictionary to a specific scope."""
|
|
267
317
|
path = get_config_path(scope, project_root)
|
|
268
318
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
269
319
|
with open(path, "w") as f:
|
|
270
320
|
yaml.dump(data, f, default_flow_style=False)
|
|
271
321
|
|
|
322
|
+
|
|
272
323
|
class ConfigEventHandler(FileSystemEventHandler):
|
|
273
|
-
def __init__(
|
|
324
|
+
def __init__(
|
|
325
|
+
self, loop, on_change: Callable[[], Awaitable[None]], config_path: Path
|
|
326
|
+
):
|
|
274
327
|
self.loop = loop
|
|
275
328
|
self.on_change = on_change
|
|
276
329
|
self.config_path = config_path
|
|
@@ -279,10 +332,12 @@ class ConfigEventHandler(FileSystemEventHandler):
|
|
|
279
332
|
if event.src_path == str(self.config_path):
|
|
280
333
|
asyncio.run_coroutine_threadsafe(self.on_change(), self.loop)
|
|
281
334
|
|
|
335
|
+
|
|
282
336
|
class ConfigMonitor:
|
|
283
337
|
"""
|
|
284
338
|
Monitors a configuration file for changes.
|
|
285
339
|
"""
|
|
340
|
+
|
|
286
341
|
def __init__(self, config_path: Path, on_change: Callable[[], Awaitable[None]]):
|
|
287
342
|
self.config_path = config_path
|
|
288
343
|
self.on_change = on_change
|
|
@@ -291,13 +346,15 @@ class ConfigMonitor:
|
|
|
291
346
|
async def start(self):
|
|
292
347
|
loop = asyncio.get_running_loop()
|
|
293
348
|
event_handler = ConfigEventHandler(loop, self.on_change, self.config_path)
|
|
294
|
-
|
|
349
|
+
|
|
295
350
|
if not self.config_path.exists():
|
|
296
351
|
# Ensure parent exists at least
|
|
297
352
|
self.config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
298
|
-
|
|
353
|
+
|
|
299
354
|
# We watch the parent directory for the specific file
|
|
300
|
-
self.observer.schedule(
|
|
355
|
+
self.observer.schedule(
|
|
356
|
+
event_handler, str(self.config_path.parent), recursive=False
|
|
357
|
+
)
|
|
301
358
|
self.observer.start()
|
|
302
359
|
logger.info(f"Config Monitor started for {self.config_path}")
|
|
303
360
|
|
monoco/core/execution.py
CHANGED
|
@@ -1,62 +1,67 @@
|
|
|
1
|
-
import os
|
|
2
1
|
from pathlib import Path
|
|
3
|
-
from typing import List,
|
|
2
|
+
from typing import List, Optional
|
|
4
3
|
from pydantic import BaseModel
|
|
5
4
|
|
|
5
|
+
|
|
6
6
|
class ExecutionProfile(BaseModel):
|
|
7
7
|
name: str
|
|
8
|
-
source: str
|
|
8
|
+
source: str # "Global" or "Project"
|
|
9
9
|
path: str
|
|
10
10
|
content: Optional[str] = None
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
|
|
13
|
+
def scan_execution_profiles(
|
|
14
|
+
project_root: Optional[Path] = None,
|
|
15
|
+
) -> List[ExecutionProfile]:
|
|
13
16
|
"""
|
|
14
17
|
Scan for execution profiles (SOPs) in global and project scopes.
|
|
15
18
|
"""
|
|
16
19
|
profiles = []
|
|
17
|
-
|
|
20
|
+
|
|
18
21
|
# 1. Global Scope
|
|
19
22
|
global_path = Path.home() / ".monoco" / "execution"
|
|
20
23
|
if global_path.exists():
|
|
21
24
|
profiles.extend(_scan_dir(global_path, "Global"))
|
|
22
|
-
|
|
25
|
+
|
|
23
26
|
# 2. Project Scope
|
|
24
27
|
if project_root:
|
|
25
28
|
project_path = project_root / ".monoco" / "execution"
|
|
26
29
|
if project_path.exists():
|
|
27
30
|
profiles.extend(_scan_dir(project_path, "Project"))
|
|
28
|
-
|
|
31
|
+
|
|
29
32
|
return profiles
|
|
30
33
|
|
|
34
|
+
|
|
31
35
|
def _scan_dir(base_path: Path, source: str) -> List[ExecutionProfile]:
|
|
32
36
|
profiles = []
|
|
33
37
|
if not base_path.is_dir():
|
|
34
38
|
return profiles
|
|
35
|
-
|
|
39
|
+
|
|
36
40
|
for item in base_path.iterdir():
|
|
37
41
|
if item.is_dir():
|
|
38
42
|
sop_path = item / "SOP.md"
|
|
39
43
|
if sop_path.exists():
|
|
40
|
-
profiles.append(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
)
|
|
44
|
+
profiles.append(
|
|
45
|
+
ExecutionProfile(
|
|
46
|
+
name=item.name, source=source, path=str(sop_path.absolute())
|
|
47
|
+
)
|
|
48
|
+
)
|
|
45
49
|
return profiles
|
|
46
50
|
|
|
51
|
+
|
|
47
52
|
def get_profile_detail(profile_path: str) -> Optional[ExecutionProfile]:
|
|
48
53
|
path = Path(profile_path)
|
|
49
54
|
if not path.exists():
|
|
50
55
|
return None
|
|
51
|
-
|
|
56
|
+
|
|
52
57
|
# Determine source (rough heuristic)
|
|
53
58
|
source = "Project"
|
|
54
59
|
if str(path).startswith(str(Path.home() / ".monoco")):
|
|
55
60
|
source = "Global"
|
|
56
|
-
|
|
61
|
+
|
|
57
62
|
return ExecutionProfile(
|
|
58
63
|
name=path.parent.name,
|
|
59
64
|
source=source,
|
|
60
65
|
path=str(path.absolute()),
|
|
61
|
-
content=path.read_text(encoding=
|
|
66
|
+
content=path.read_text(encoding="utf-8"),
|
|
62
67
|
)
|
monoco/core/feature.py
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
2
|
from dataclasses import dataclass, field
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from typing import Dict, List
|
|
4
|
+
from typing import Dict, List
|
|
5
|
+
|
|
5
6
|
|
|
6
7
|
@dataclass
|
|
7
8
|
class IntegrationData:
|
|
8
9
|
"""
|
|
9
10
|
Data collection returned by a feature for integration into the Agent environment.
|
|
10
11
|
"""
|
|
12
|
+
|
|
11
13
|
# System Prompts to be injected into agent configuration (e.g., .cursorrules)
|
|
12
14
|
# Key: Section Title (e.g., "Issue Management"), Value: Markdown Content
|
|
13
15
|
system_prompts: Dict[str, str] = field(default_factory=dict)
|
|
14
|
-
|
|
16
|
+
|
|
15
17
|
# Paths to skill directories or files to be copied/symlinked
|
|
16
18
|
# DEPRECATED: Skill distribution is cancelled. Only prompts are synced.
|
|
17
19
|
skills: List[Path] = field(default_factory=list)
|
|
18
20
|
|
|
21
|
+
|
|
19
22
|
class MonocoFeature(ABC):
|
|
20
23
|
"""
|
|
21
24
|
Abstract base class for all Monoco features.
|
|
@@ -34,7 +37,7 @@ class MonocoFeature(ABC):
|
|
|
34
37
|
Lifecycle hook: Physical Structure Initialization.
|
|
35
38
|
Called during `monoco init`.
|
|
36
39
|
Responsible for creating necessary directories, files, and config templates.
|
|
37
|
-
|
|
40
|
+
|
|
38
41
|
Args:
|
|
39
42
|
root: The root directory of the project.
|
|
40
43
|
config: The full project configuration dictionary.
|
|
@@ -47,11 +50,11 @@ class MonocoFeature(ABC):
|
|
|
47
50
|
Lifecycle hook: Agent Environment Integration.
|
|
48
51
|
Called during `monoco sync`.
|
|
49
52
|
Responsible for returning data (prompts, skills) needed for the Agent Setup.
|
|
50
|
-
|
|
53
|
+
|
|
51
54
|
Args:
|
|
52
55
|
root: The root directory of the project.
|
|
53
56
|
config: The full project configuration dictionary.
|
|
54
|
-
|
|
57
|
+
|
|
55
58
|
Returns:
|
|
56
59
|
IntegrationData object containing prompts and skills.
|
|
57
60
|
"""
|