monoco-toolkit 0.3.12__py3-none-any.whl → 0.4.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/core/automation/__init__.py +0 -11
- monoco/core/automation/handlers.py +108 -26
- monoco/core/config.py +28 -10
- monoco/core/daemon/__init__.py +5 -0
- monoco/core/daemon/pid.py +290 -0
- monoco/core/injection.py +86 -8
- monoco/core/integrations.py +0 -24
- monoco/core/router/__init__.py +1 -39
- monoco/core/router/action.py +3 -142
- monoco/core/scheduler/events.py +28 -2
- monoco/core/setup.py +9 -0
- monoco/core/sync.py +199 -4
- monoco/core/watcher/__init__.py +6 -0
- monoco/core/watcher/base.py +18 -1
- monoco/core/watcher/im.py +460 -0
- monoco/core/watcher/memo.py +40 -48
- monoco/daemon/app.py +3 -60
- monoco/daemon/commands.py +459 -25
- monoco/daemon/scheduler.py +1 -16
- monoco/daemon/services.py +15 -0
- monoco/features/agent/resources/en/AGENTS.md +14 -14
- monoco/features/agent/resources/en/skills/monoco_role_engineer/SKILL.md +101 -0
- monoco/features/agent/resources/en/skills/monoco_role_manager/SKILL.md +95 -0
- monoco/features/agent/resources/en/skills/monoco_role_planner/SKILL.md +177 -0
- monoco/features/agent/resources/en/skills/monoco_role_reviewer/SKILL.md +139 -0
- monoco/features/agent/resources/zh/skills/monoco_role_engineer/SKILL.md +101 -0
- monoco/features/agent/resources/zh/skills/monoco_role_manager/SKILL.md +95 -0
- monoco/features/agent/resources/zh/skills/monoco_role_planner/SKILL.md +177 -0
- monoco/features/agent/resources/zh/skills/monoco_role_reviewer/SKILL.md +139 -0
- monoco/features/hooks/__init__.py +61 -6
- monoco/features/hooks/commands.py +281 -271
- monoco/features/hooks/dispatchers/__init__.py +23 -0
- monoco/features/hooks/dispatchers/agent_dispatcher.py +486 -0
- monoco/features/hooks/dispatchers/git_dispatcher.py +478 -0
- monoco/features/hooks/manager.py +357 -0
- monoco/features/hooks/models.py +262 -0
- monoco/features/hooks/parser.py +322 -0
- monoco/features/hooks/universal_interceptor.py +503 -0
- monoco/features/im/__init__.py +67 -0
- monoco/features/im/core.py +782 -0
- monoco/features/im/models.py +311 -0
- monoco/features/issue/commands.py +65 -50
- monoco/features/issue/core.py +199 -99
- monoco/features/issue/domain_commands.py +0 -19
- monoco/features/issue/resources/en/AGENTS.md +17 -122
- monoco/features/issue/resources/hooks/agent/before-tool.sh +102 -0
- monoco/features/issue/resources/hooks/agent/session-start.sh +88 -0
- monoco/features/issue/resources/hooks/{post-checkout.sh → git/git-post-checkout.sh} +10 -9
- monoco/features/issue/resources/hooks/git/git-pre-commit.sh +31 -0
- monoco/features/issue/resources/hooks/{pre-push.sh → git/git-pre-push.sh} +7 -13
- monoco/features/issue/resources/zh/AGENTS.md +18 -123
- monoco/features/memo/cli.py +15 -64
- monoco/features/memo/core.py +6 -34
- monoco/features/memo/models.py +24 -15
- monoco/features/memo/resources/en/AGENTS.md +31 -0
- monoco/features/memo/resources/zh/AGENTS.md +28 -5
- monoco/main.py +5 -3
- {monoco_toolkit-0.3.12.dist-info → monoco_toolkit-0.4.0.dist-info}/METADATA +1 -1
- monoco_toolkit-0.4.0.dist-info/RECORD +170 -0
- monoco/core/automation/config.py +0 -338
- monoco/core/execution.py +0 -67
- monoco/core/executor/__init__.py +0 -38
- monoco/core/executor/agent_action.py +0 -254
- monoco/core/executor/git_action.py +0 -303
- monoco/core/executor/im_action.py +0 -309
- monoco/core/executor/pytest_action.py +0 -218
- monoco/core/router/router.py +0 -392
- monoco/features/agent/resources/atoms/atom-code-dev.yaml +0 -61
- monoco/features/agent/resources/atoms/atom-issue-lifecycle.yaml +0 -73
- monoco/features/agent/resources/atoms/atom-knowledge.yaml +0 -55
- monoco/features/agent/resources/atoms/atom-review.yaml +0 -60
- monoco/features/agent/resources/en/skills/monoco_atom_core/SKILL.md +0 -99
- monoco/features/agent/resources/en/skills/monoco_workflow_agent_engineer/SKILL.md +0 -94
- monoco/features/agent/resources/en/skills/monoco_workflow_agent_manager/SKILL.md +0 -93
- monoco/features/agent/resources/en/skills/monoco_workflow_agent_planner/SKILL.md +0 -85
- monoco/features/agent/resources/en/skills/monoco_workflow_agent_reviewer/SKILL.md +0 -114
- monoco/features/agent/resources/workflows/workflow-dev.yaml +0 -83
- monoco/features/agent/resources/workflows/workflow-issue-create.yaml +0 -72
- monoco/features/agent/resources/workflows/workflow-review.yaml +0 -94
- monoco/features/agent/resources/zh/roles/monoco_role_engineer.yaml +0 -49
- monoco/features/agent/resources/zh/roles/monoco_role_manager.yaml +0 -46
- monoco/features/agent/resources/zh/roles/monoco_role_planner.yaml +0 -46
- monoco/features/agent/resources/zh/roles/monoco_role_reviewer.yaml +0 -47
- monoco/features/agent/resources/zh/skills/monoco_atom_core/SKILL.md +0 -99
- monoco/features/agent/resources/zh/skills/monoco_workflow_agent_engineer/SKILL.md +0 -94
- monoco/features/agent/resources/zh/skills/monoco_workflow_agent_manager/SKILL.md +0 -88
- monoco/features/agent/resources/zh/skills/monoco_workflow_agent_planner/SKILL.md +0 -259
- monoco/features/agent/resources/zh/skills/monoco_workflow_agent_reviewer/SKILL.md +0 -137
- monoco/features/artifact/resources/zh/skills/monoco_atom_artifact/SKILL.md +0 -278
- monoco/features/glossary/resources/en/skills/monoco_atom_glossary/SKILL.md +0 -35
- monoco/features/glossary/resources/zh/skills/monoco_atom_glossary/SKILL.md +0 -35
- monoco/features/hooks/adapter.py +0 -67
- monoco/features/hooks/core.py +0 -441
- monoco/features/i18n/resources/en/skills/monoco_atom_i18n/SKILL.md +0 -96
- monoco/features/i18n/resources/en/skills/monoco_workflow_i18n_scan/SKILL.md +0 -105
- monoco/features/i18n/resources/zh/skills/monoco_atom_i18n/SKILL.md +0 -96
- monoco/features/i18n/resources/zh/skills/monoco_workflow_i18n_scan/SKILL.md +0 -105
- monoco/features/issue/resources/en/skills/monoco_atom_issue/SKILL.md +0 -165
- monoco/features/issue/resources/en/skills/monoco_workflow_issue_creation/SKILL.md +0 -167
- monoco/features/issue/resources/en/skills/monoco_workflow_issue_development/SKILL.md +0 -224
- monoco/features/issue/resources/en/skills/monoco_workflow_issue_management/SKILL.md +0 -159
- monoco/features/issue/resources/en/skills/monoco_workflow_issue_refinement/SKILL.md +0 -203
- monoco/features/issue/resources/hooks/pre-commit.sh +0 -41
- monoco/features/issue/resources/zh/skills/monoco_atom_issue_lifecycle/SKILL.md +0 -190
- monoco/features/issue/resources/zh/skills/monoco_workflow_issue_creation/SKILL.md +0 -167
- monoco/features/issue/resources/zh/skills/monoco_workflow_issue_development/SKILL.md +0 -224
- monoco/features/issue/resources/zh/skills/monoco_workflow_issue_management/SKILL.md +0 -159
- monoco/features/issue/resources/zh/skills/monoco_workflow_issue_refinement/SKILL.md +0 -203
- monoco/features/memo/resources/en/skills/monoco_atom_memo/SKILL.md +0 -77
- monoco/features/memo/resources/en/skills/monoco_workflow_note_processing/SKILL.md +0 -140
- monoco/features/memo/resources/zh/skills/monoco_atom_memo/SKILL.md +0 -77
- monoco/features/memo/resources/zh/skills/monoco_workflow_note_processing/SKILL.md +0 -140
- monoco/features/spike/resources/en/skills/monoco_atom_spike/SKILL.md +0 -76
- monoco/features/spike/resources/en/skills/monoco_workflow_research/SKILL.md +0 -121
- monoco/features/spike/resources/zh/skills/monoco_atom_spike/SKILL.md +0 -76
- monoco/features/spike/resources/zh/skills/monoco_workflow_research/SKILL.md +0 -121
- monoco_toolkit-0.3.12.dist-info/RECORD +0 -202
- {monoco_toolkit-0.3.12.dist-info → monoco_toolkit-0.4.0.dist-info}/WHEEL +0 -0
- {monoco_toolkit-0.3.12.dist-info → monoco_toolkit-0.4.0.dist-info}/entry_points.txt +0 -0
- {monoco_toolkit-0.3.12.dist-info → monoco_toolkit-0.4.0.dist-info}/licenses/LICENSE +0 -0
monoco/features/hooks/core.py
DELETED
|
@@ -1,441 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Core logic for Git Hooks management.
|
|
3
|
-
|
|
4
|
-
Implements the distributed hooks + aggregator pattern:
|
|
5
|
-
- Each Feature stores its hooks in resources/hooks/{hook-type}.sh
|
|
6
|
-
- This module discovers, sorts by priority, and generates final hooks
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
import os
|
|
10
|
-
import stat
|
|
11
|
-
from dataclasses import dataclass, field
|
|
12
|
-
from enum import Enum
|
|
13
|
-
from pathlib import Path
|
|
14
|
-
from typing import Dict, List, Optional, Tuple
|
|
15
|
-
|
|
16
|
-
from rich.console import Console
|
|
17
|
-
|
|
18
|
-
console = Console()
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class HookType(str, Enum):
|
|
22
|
-
"""Supported git hook types."""
|
|
23
|
-
|
|
24
|
-
PRE_COMMIT = "pre-commit"
|
|
25
|
-
PRE_PUSH = "pre-push"
|
|
26
|
-
POST_CHECKOUT = "post-checkout"
|
|
27
|
-
PRE_REBASE = "pre-rebase"
|
|
28
|
-
COMMIT_MSG = "commit-msg"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
@dataclass
|
|
32
|
-
class HookDeclaration:
|
|
33
|
-
"""
|
|
34
|
-
Metadata for a hook script contributed by a Feature.
|
|
35
|
-
|
|
36
|
-
Attributes:
|
|
37
|
-
hook_type: Type of git hook (pre-commit, pre-push, etc.)
|
|
38
|
-
script_path: Path to the hook script file
|
|
39
|
-
feature_name: Name of the contributing Feature
|
|
40
|
-
priority: Execution priority (lower = earlier, default 100)
|
|
41
|
-
"""
|
|
42
|
-
|
|
43
|
-
hook_type: HookType
|
|
44
|
-
script_path: Path
|
|
45
|
-
feature_name: str
|
|
46
|
-
priority: int = 100
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
@dataclass
|
|
50
|
-
class HookConfig:
|
|
51
|
-
"""Configuration for hooks feature."""
|
|
52
|
-
|
|
53
|
-
enabled: bool = True
|
|
54
|
-
enabled_features: Dict[str, bool] = field(default_factory=dict)
|
|
55
|
-
# Global hook enable/disable by type
|
|
56
|
-
enabled_hooks: Dict[str, bool] = field(default_factory=lambda: {
|
|
57
|
-
"pre-commit": True,
|
|
58
|
-
"pre-push": False, # Disabled by default
|
|
59
|
-
"post-checkout": False,
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
class GitHooksManager:
|
|
64
|
-
"""
|
|
65
|
-
Manages discovery, aggregation, and installation of git hooks.
|
|
66
|
-
|
|
67
|
-
This class implements the aggregator pattern in the distributed hooks architecture:
|
|
68
|
-
1. Discovers hooks from all Features in resources/hooks/
|
|
69
|
-
2. Sorts them by priority
|
|
70
|
-
3. Generates combined hook scripts
|
|
71
|
-
4. Installs them to .git/hooks/
|
|
72
|
-
"""
|
|
73
|
-
|
|
74
|
-
# Header marker to identify Monoco-managed hooks
|
|
75
|
-
MONOCO_MARKER = "# Monoco Managed Hook - Auto-generated. Do not edit manually."
|
|
76
|
-
|
|
77
|
-
def __init__(self, project_root: Path, config: Optional[HookConfig] = None):
|
|
78
|
-
"""
|
|
79
|
-
Initialize the hooks manager.
|
|
80
|
-
|
|
81
|
-
Args:
|
|
82
|
-
project_root: Root directory of the project (contains .git/)
|
|
83
|
-
config: Optional hooks configuration
|
|
84
|
-
"""
|
|
85
|
-
self.project_root = project_root
|
|
86
|
-
self.config = config or HookConfig()
|
|
87
|
-
self.git_dir = project_root / ".git"
|
|
88
|
-
self.hooks_dir = self.git_dir / "hooks"
|
|
89
|
-
|
|
90
|
-
def is_git_repo(self) -> bool:
|
|
91
|
-
"""Check if project root is a git repository."""
|
|
92
|
-
return self.git_dir.exists() and self.git_dir.is_dir()
|
|
93
|
-
|
|
94
|
-
def collect_hooks(
|
|
95
|
-
self, features_dir: Optional[Path] = None
|
|
96
|
-
) -> Dict[HookType, List[HookDeclaration]]:
|
|
97
|
-
"""
|
|
98
|
-
Discover all hook scripts from Features.
|
|
99
|
-
|
|
100
|
-
Scans features/{feature}/resources/hooks/ for hook scripts.
|
|
101
|
-
|
|
102
|
-
Args:
|
|
103
|
-
features_dir: Root directory containing features (defaults to monoco/features/)
|
|
104
|
-
|
|
105
|
-
Returns:
|
|
106
|
-
Dictionary mapping hook types to sorted list of hook declarations
|
|
107
|
-
"""
|
|
108
|
-
if features_dir is None:
|
|
109
|
-
# Default to monoco/features/ relative to this file
|
|
110
|
-
features_dir = Path(__file__).parent.parent
|
|
111
|
-
|
|
112
|
-
hooks_by_type: Dict[HookType, List[HookDeclaration]] = {
|
|
113
|
-
hook_type: [] for hook_type in HookType
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if not features_dir.exists():
|
|
117
|
-
return hooks_by_type
|
|
118
|
-
|
|
119
|
-
for feature_dir in features_dir.iterdir():
|
|
120
|
-
if not feature_dir.is_dir() or feature_dir.name.startswith("_"):
|
|
121
|
-
continue
|
|
122
|
-
|
|
123
|
-
feature_name = feature_dir.name
|
|
124
|
-
|
|
125
|
-
# Check if this feature is enabled in config
|
|
126
|
-
if self.config.enabled_features.get(feature_name, True) is False:
|
|
127
|
-
continue
|
|
128
|
-
|
|
129
|
-
hooks_dir = feature_dir / "resources" / "hooks"
|
|
130
|
-
if not hooks_dir.exists():
|
|
131
|
-
continue
|
|
132
|
-
|
|
133
|
-
# Discover hook scripts
|
|
134
|
-
for hook_script in hooks_dir.iterdir():
|
|
135
|
-
if not hook_script.is_file():
|
|
136
|
-
continue
|
|
137
|
-
|
|
138
|
-
# Parse hook type from filename (e.g., pre-commit.sh -> pre-commit)
|
|
139
|
-
hook_type = self._parse_hook_type(hook_script.name)
|
|
140
|
-
if hook_type is None:
|
|
141
|
-
continue
|
|
142
|
-
|
|
143
|
-
# Check if this hook type is globally enabled
|
|
144
|
-
if not self.config.enabled_hooks.get(hook_type.value, True):
|
|
145
|
-
continue
|
|
146
|
-
|
|
147
|
-
# Get feature priority from adapter if available
|
|
148
|
-
priority = self._get_feature_priority(features_dir, feature_name)
|
|
149
|
-
|
|
150
|
-
declaration = HookDeclaration(
|
|
151
|
-
hook_type=hook_type,
|
|
152
|
-
script_path=hook_script,
|
|
153
|
-
feature_name=feature_name,
|
|
154
|
-
priority=priority,
|
|
155
|
-
)
|
|
156
|
-
hooks_by_type[hook_type].append(declaration)
|
|
157
|
-
|
|
158
|
-
# Sort each list by priority
|
|
159
|
-
for hook_type in hooks_by_type:
|
|
160
|
-
hooks_by_type[hook_type].sort(key=lambda h: h.priority)
|
|
161
|
-
|
|
162
|
-
return hooks_by_type
|
|
163
|
-
|
|
164
|
-
def _parse_hook_type(self, filename: str) -> Optional[HookType]:
|
|
165
|
-
"""Parse hook type from filename (e.g., 'pre-commit.sh' -> HookType.PRE_COMMIT)."""
|
|
166
|
-
# Remove extension
|
|
167
|
-
name = filename
|
|
168
|
-
for ext in [".sh", ".py", ".bash"]:
|
|
169
|
-
if name.endswith(ext):
|
|
170
|
-
name = name[: -len(ext)]
|
|
171
|
-
break
|
|
172
|
-
|
|
173
|
-
try:
|
|
174
|
-
return HookType(name)
|
|
175
|
-
except ValueError:
|
|
176
|
-
return None
|
|
177
|
-
|
|
178
|
-
def _get_feature_priority(self, features_dir: Path, feature_name: str) -> int:
|
|
179
|
-
"""Get feature priority from its adapter metadata."""
|
|
180
|
-
adapter_path = features_dir / feature_name / "adapter.py"
|
|
181
|
-
if not adapter_path.exists():
|
|
182
|
-
return 100
|
|
183
|
-
|
|
184
|
-
try:
|
|
185
|
-
# Import the adapter module
|
|
186
|
-
import importlib.util
|
|
187
|
-
|
|
188
|
-
spec = importlib.util.spec_from_file_location(
|
|
189
|
-
f"monoco.features.{feature_name}.adapter", adapter_path
|
|
190
|
-
)
|
|
191
|
-
if spec is None or spec.loader is None:
|
|
192
|
-
return 100
|
|
193
|
-
|
|
194
|
-
module = importlib.util.module_from_spec(spec)
|
|
195
|
-
spec.loader.exec_module(module)
|
|
196
|
-
|
|
197
|
-
# Look for Feature class with metadata
|
|
198
|
-
for attr_name in dir(module):
|
|
199
|
-
attr = getattr(module, attr_name)
|
|
200
|
-
if hasattr(attr, "metadata"):
|
|
201
|
-
metadata = attr.metadata
|
|
202
|
-
if hasattr(metadata, "priority"):
|
|
203
|
-
return metadata.priority
|
|
204
|
-
except Exception:
|
|
205
|
-
pass
|
|
206
|
-
|
|
207
|
-
return 100
|
|
208
|
-
|
|
209
|
-
def generate_hook_script(self, declarations: List[HookDeclaration]) -> str:
|
|
210
|
-
"""
|
|
211
|
-
Generate a combined hook script from multiple declarations.
|
|
212
|
-
|
|
213
|
-
Args:
|
|
214
|
-
declarations: List of hook declarations to combine
|
|
215
|
-
|
|
216
|
-
Returns:
|
|
217
|
-
Generated shell script content
|
|
218
|
-
"""
|
|
219
|
-
lines = [
|
|
220
|
-
"#!/bin/sh",
|
|
221
|
-
self.MONOCO_MARKER,
|
|
222
|
-
"# Generated by Monoco Toolkit",
|
|
223
|
-
"",
|
|
224
|
-
"# Store the original exit code",
|
|
225
|
-
"OVERALL_EXIT=0",
|
|
226
|
-
"",
|
|
227
|
-
]
|
|
228
|
-
|
|
229
|
-
# Add virtual environment detection
|
|
230
|
-
lines.extend([
|
|
231
|
-
"# Detect virtual environment",
|
|
232
|
-
'if [ -n "$VIRTUAL_ENV" ]; then',
|
|
233
|
-
' PYTHON_CMD="$VIRTUAL_ENV/bin/python"',
|
|
234
|
-
'elif [ -f "./.venv/bin/python" ]; then',
|
|
235
|
-
' PYTHON_CMD="./.venv/bin/python"',
|
|
236
|
-
'elif [ -f "./venv/bin/python" ]; then',
|
|
237
|
-
' PYTHON_CMD="./venv/bin/python"',
|
|
238
|
-
'else',
|
|
239
|
-
' PYTHON_CMD="python3"',
|
|
240
|
-
'fi',
|
|
241
|
-
'',
|
|
242
|
-
"# Detect monoco command",
|
|
243
|
-
'MONOCO_CMD="$PYTHON_CMD -m monoco"',
|
|
244
|
-
"",
|
|
245
|
-
])
|
|
246
|
-
|
|
247
|
-
for decl in declarations:
|
|
248
|
-
lines.extend([
|
|
249
|
-
f"# --- Hook from {decl.feature_name} (priority: {decl.priority}) ---",
|
|
250
|
-
f'echo "[Monoco] Running {decl.hook_type.value} hook: {decl.feature_name}"',
|
|
251
|
-
])
|
|
252
|
-
|
|
253
|
-
# Read and include the hook script content
|
|
254
|
-
try:
|
|
255
|
-
content = decl.script_path.read_text(encoding="utf-8")
|
|
256
|
-
# Remove shebang if present since we're in a combined script
|
|
257
|
-
lines_content = content.splitlines()
|
|
258
|
-
if lines_content and lines_content[0].startswith("#!/"):
|
|
259
|
-
lines_content = lines_content[1:]
|
|
260
|
-
|
|
261
|
-
for line in lines_content:
|
|
262
|
-
lines.append(line)
|
|
263
|
-
except Exception as e:
|
|
264
|
-
lines.append(f'echo "[Monoco] Error reading hook: {e}" >&2')
|
|
265
|
-
|
|
266
|
-
lines.extend([
|
|
267
|
-
"# Capture exit code",
|
|
268
|
-
"HOOK_EXIT=$?",
|
|
269
|
-
'if [ $HOOK_EXIT -ne 0 ]; then',
|
|
270
|
-
' echo "[Monoco] Hook failed with exit code $HOOK_EXIT"',
|
|
271
|
-
" OVERALL_EXIT=$HOOK_EXIT",
|
|
272
|
-
"fi",
|
|
273
|
-
"",
|
|
274
|
-
])
|
|
275
|
-
|
|
276
|
-
lines.extend([
|
|
277
|
-
"# Exit with the first non-zero exit code",
|
|
278
|
-
"exit $OVERALL_EXIT",
|
|
279
|
-
"",
|
|
280
|
-
])
|
|
281
|
-
|
|
282
|
-
return "\n".join(lines)
|
|
283
|
-
|
|
284
|
-
def install(self, features_dir: Optional[Path] = None) -> Dict[HookType, bool]:
|
|
285
|
-
"""
|
|
286
|
-
Install all discovered hooks to .git/hooks/.
|
|
287
|
-
|
|
288
|
-
Args:
|
|
289
|
-
features_dir: Root directory containing features
|
|
290
|
-
|
|
291
|
-
Returns:
|
|
292
|
-
Dictionary mapping hook types to success status
|
|
293
|
-
"""
|
|
294
|
-
results = {}
|
|
295
|
-
|
|
296
|
-
if not self.is_git_repo():
|
|
297
|
-
console.print("[yellow]Warning: Not a git repository. Skipping hook installation.[/yellow]")
|
|
298
|
-
return results
|
|
299
|
-
|
|
300
|
-
self.hooks_dir.mkdir(exist_ok=True)
|
|
301
|
-
|
|
302
|
-
# Collect all hooks
|
|
303
|
-
hooks_by_type = self.collect_hooks(features_dir)
|
|
304
|
-
|
|
305
|
-
for hook_type, declarations in hooks_by_type.items():
|
|
306
|
-
if not declarations:
|
|
307
|
-
continue
|
|
308
|
-
|
|
309
|
-
# Check if hook type is enabled
|
|
310
|
-
if not self.config.enabled_hooks.get(hook_type.value, True):
|
|
311
|
-
continue
|
|
312
|
-
|
|
313
|
-
hook_path = self.hooks_dir / hook_type.value
|
|
314
|
-
|
|
315
|
-
# Check for existing non-monoco hook
|
|
316
|
-
if hook_path.exists():
|
|
317
|
-
try:
|
|
318
|
-
content = hook_path.read_text(encoding="utf-8")
|
|
319
|
-
if self.MONOCO_MARKER not in content:
|
|
320
|
-
console.print(
|
|
321
|
-
f"[yellow]Warning: {hook_type.value} already exists and is not managed by Monoco. Skipping.[/yellow]"
|
|
322
|
-
)
|
|
323
|
-
results[hook_type] = False
|
|
324
|
-
continue
|
|
325
|
-
except Exception as e:
|
|
326
|
-
console.print(
|
|
327
|
-
f"[yellow]Warning: Cannot read existing {hook_type.value}: {e}. Skipping.[/yellow]"
|
|
328
|
-
)
|
|
329
|
-
results[hook_type] = False
|
|
330
|
-
continue
|
|
331
|
-
|
|
332
|
-
# Generate and write hook script
|
|
333
|
-
script_content = self.generate_hook_script(declarations)
|
|
334
|
-
|
|
335
|
-
try:
|
|
336
|
-
hook_path.write_text(script_content, encoding="utf-8")
|
|
337
|
-
# Make executable
|
|
338
|
-
hook_path.chmod(hook_path.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
|
|
339
|
-
console.print(f"[green]✓ Installed {hook_type.value} hook ({len(declarations)} scripts)[/green]")
|
|
340
|
-
results[hook_type] = True
|
|
341
|
-
except Exception as e:
|
|
342
|
-
console.print(f"[red]✗ Failed to install {hook_type.value}: {e}[/red]")
|
|
343
|
-
results[hook_type] = False
|
|
344
|
-
|
|
345
|
-
return results
|
|
346
|
-
|
|
347
|
-
def uninstall(self) -> Dict[HookType, bool]:
|
|
348
|
-
"""
|
|
349
|
-
Uninstall all Monoco-managed hooks from .git/hooks/.
|
|
350
|
-
|
|
351
|
-
Returns:
|
|
352
|
-
Dictionary mapping hook types to success status
|
|
353
|
-
"""
|
|
354
|
-
results = {}
|
|
355
|
-
|
|
356
|
-
if not self.is_git_repo():
|
|
357
|
-
console.print("[yellow]Warning: Not a git repository.[/yellow]")
|
|
358
|
-
return results
|
|
359
|
-
|
|
360
|
-
for hook_type in HookType:
|
|
361
|
-
hook_path = self.hooks_dir / hook_type.value
|
|
362
|
-
|
|
363
|
-
if not hook_path.exists():
|
|
364
|
-
continue
|
|
365
|
-
|
|
366
|
-
try:
|
|
367
|
-
content = hook_path.read_text(encoding="utf-8")
|
|
368
|
-
if self.MONOCO_MARKER in content:
|
|
369
|
-
hook_path.unlink()
|
|
370
|
-
console.print(f"[green]✓ Removed {hook_type.value} hook[/green]")
|
|
371
|
-
results[hook_type] = True
|
|
372
|
-
else:
|
|
373
|
-
console.print(
|
|
374
|
-
f"[dim]Skipping {hook_type.value}: not managed by Monoco[/dim]"
|
|
375
|
-
)
|
|
376
|
-
results[hook_type] = False
|
|
377
|
-
except Exception as e:
|
|
378
|
-
console.print(f"[red]✗ Failed to remove {hook_type.value}: {e}[/red]")
|
|
379
|
-
results[hook_type] = False
|
|
380
|
-
|
|
381
|
-
return results
|
|
382
|
-
|
|
383
|
-
def get_status(self, features_dir: Optional[Path] = None) -> Dict[str, any]:
|
|
384
|
-
"""
|
|
385
|
-
Get current hooks installation status.
|
|
386
|
-
|
|
387
|
-
Args:
|
|
388
|
-
features_dir: Root directory containing features
|
|
389
|
-
|
|
390
|
-
Returns:
|
|
391
|
-
Status dictionary with installed hooks and discovered scripts
|
|
392
|
-
"""
|
|
393
|
-
status = {
|
|
394
|
-
"is_git_repo": self.is_git_repo(),
|
|
395
|
-
"hooks_dir": str(self.hooks_dir) if self.is_git_repo() else None,
|
|
396
|
-
"installed": {},
|
|
397
|
-
"discovered": {},
|
|
398
|
-
"config": {
|
|
399
|
-
"enabled": self.config.enabled,
|
|
400
|
-
"enabled_features": self.config.enabled_features,
|
|
401
|
-
"enabled_hooks": self.config.enabled_hooks,
|
|
402
|
-
},
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
if not self.is_git_repo():
|
|
406
|
-
return status
|
|
407
|
-
|
|
408
|
-
# Check installed hooks
|
|
409
|
-
for hook_type in HookType:
|
|
410
|
-
hook_path = self.hooks_dir / hook_type.value
|
|
411
|
-
if hook_path.exists():
|
|
412
|
-
try:
|
|
413
|
-
content = hook_path.read_text(encoding="utf-8")
|
|
414
|
-
is_monoco = self.MONOCO_MARKER in content
|
|
415
|
-
status["installed"][hook_type.value] = {
|
|
416
|
-
"exists": True,
|
|
417
|
-
"managed_by_monoco": is_monoco,
|
|
418
|
-
}
|
|
419
|
-
except Exception:
|
|
420
|
-
status["installed"][hook_type.value] = {
|
|
421
|
-
"exists": True,
|
|
422
|
-
"managed_by_monoco": False,
|
|
423
|
-
"error": "Cannot read file",
|
|
424
|
-
}
|
|
425
|
-
else:
|
|
426
|
-
status["installed"][hook_type.value] = {"exists": False}
|
|
427
|
-
|
|
428
|
-
# Discover available hooks
|
|
429
|
-
hooks_by_type = self.collect_hooks(features_dir)
|
|
430
|
-
for hook_type, declarations in hooks_by_type.items():
|
|
431
|
-
if declarations:
|
|
432
|
-
status["discovered"][hook_type.value] = [
|
|
433
|
-
{
|
|
434
|
-
"feature": d.feature_name,
|
|
435
|
-
"path": str(d.script_path),
|
|
436
|
-
"priority": d.priority,
|
|
437
|
-
}
|
|
438
|
-
for d in declarations
|
|
439
|
-
]
|
|
440
|
-
|
|
441
|
-
return status
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: monoco_atom_i18n
|
|
3
|
-
description: Internationalization quality control for documentation. Ensures multi-language documentation stays synchronized.
|
|
4
|
-
type: atom
|
|
5
|
-
version: 1.0.0
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Documentation I18n
|
|
9
|
-
|
|
10
|
-
Manage internationalization for Monoco project documentation.
|
|
11
|
-
|
|
12
|
-
## Overview
|
|
13
|
-
|
|
14
|
-
The I18n feature provides:
|
|
15
|
-
|
|
16
|
-
- **Automatic scanning** for missing translations
|
|
17
|
-
- **Standardized structure** for multi-language documentation
|
|
18
|
-
- **Quality control** to maintain documentation parity
|
|
19
|
-
|
|
20
|
-
## Key Commands
|
|
21
|
-
|
|
22
|
-
### Scan for Missing Translations
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
monoco i18n scan
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
Scans the project for markdown files and reports missing translations.
|
|
29
|
-
|
|
30
|
-
**Output**:
|
|
31
|
-
|
|
32
|
-
- Lists source files without corresponding translations
|
|
33
|
-
- Shows which target languages are missing
|
|
34
|
-
- Respects `.gitignore` and default exclusions
|
|
35
|
-
|
|
36
|
-
## Configuration
|
|
37
|
-
|
|
38
|
-
I18n settings are configured in `.monoco/config.yaml`:
|
|
39
|
-
|
|
40
|
-
```yaml
|
|
41
|
-
i18n:
|
|
42
|
-
source_lang: en # Source language code
|
|
43
|
-
target_langs: # Target language codes
|
|
44
|
-
- zh
|
|
45
|
-
- ja
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
## Documentation Structure
|
|
49
|
-
|
|
50
|
-
### Root Files (Suffix Pattern)
|
|
51
|
-
|
|
52
|
-
For files in the project root:
|
|
53
|
-
|
|
54
|
-
- Source: `README.md`
|
|
55
|
-
- Chinese: `README_ZH.md`
|
|
56
|
-
- Japanese: `README_JA.md`
|
|
57
|
-
|
|
58
|
-
### Subdirectory Files (Directory Pattern)
|
|
59
|
-
|
|
60
|
-
For files in `docs/` or other directories:
|
|
61
|
-
|
|
62
|
-
```
|
|
63
|
-
docs/
|
|
64
|
-
├── en/
|
|
65
|
-
│ ├── guide.md
|
|
66
|
-
│ └── api.md
|
|
67
|
-
├── zh/
|
|
68
|
-
│ ├── guide.md
|
|
69
|
-
│ └── api.md
|
|
70
|
-
└── ja/
|
|
71
|
-
├── guide.md
|
|
72
|
-
└── api.md
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
## Exclusion Rules
|
|
76
|
-
|
|
77
|
-
The following are automatically excluded from i18n scanning:
|
|
78
|
-
|
|
79
|
-
- `.gitignore` patterns (respected automatically)
|
|
80
|
-
- `.references/` directory
|
|
81
|
-
- Build artifacts (`dist/`, `build/`, `node_modules/`)
|
|
82
|
-
- `Issues/` directory
|
|
83
|
-
|
|
84
|
-
## Best Practices
|
|
85
|
-
|
|
86
|
-
1. **Create English First**: Write documentation in the source language first
|
|
87
|
-
2. **Follow Naming Convention**: Use the appropriate pattern (suffix or directory)
|
|
88
|
-
3. **Run Scan Regularly**: Use `monoco i18n scan` to verify coverage
|
|
89
|
-
4. **Commit All Languages**: Keep translations in version control
|
|
90
|
-
|
|
91
|
-
## Workflow
|
|
92
|
-
|
|
93
|
-
1. Write documentation in source language (e.g., English)
|
|
94
|
-
2. Create translation files following the naming convention
|
|
95
|
-
3. Run `monoco i18n scan` to verify all translations exist
|
|
96
|
-
4. Fix any missing translations reported by the scan
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: monoco_workflow_i18n_scan
|
|
3
|
-
description: I18n Scan Workflow (Flow Skill). Defines the standard operational process from scanning missing translations to generating translation tasks, ensuring multilingual documentation quality.
|
|
4
|
-
type: workflow
|
|
5
|
-
domain: i18n
|
|
6
|
-
version: 1.0.0
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# I18n Scan Workflow
|
|
10
|
-
|
|
11
|
-
Standardized workflow for I18n scanning, ensuring the "Scan → Identify → Generate Tasks" process.
|
|
12
|
-
|
|
13
|
-
## Workflow State Machine
|
|
14
|
-
|
|
15
|
-
```mermaid
|
|
16
|
-
stateDiagram-v2
|
|
17
|
-
[*] --> Scan: Trigger scan
|
|
18
|
-
|
|
19
|
-
Scan --> Identify: Scan completed
|
|
20
|
-
Scan --> Scan: Configuration error<br/>(fix configuration)
|
|
21
|
-
|
|
22
|
-
Identify --> GenerateTasks: Missing found
|
|
23
|
-
Identify --> [*]: No missing<br/>(completed)
|
|
24
|
-
|
|
25
|
-
GenerateTasks --> [*]: Task generation completed
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Execution Steps
|
|
29
|
-
|
|
30
|
-
### 1. Scan (Scanning)
|
|
31
|
-
|
|
32
|
-
- **Goal**: Scan all documents in the project, identify translation coverage
|
|
33
|
-
- **Input**: Project files, i18n configuration
|
|
34
|
-
- **Output**: Scan report
|
|
35
|
-
- **Checkpoints**:
|
|
36
|
-
- [ ] Check i18n configuration in `.monoco/config.yaml`
|
|
37
|
-
- [ ] Run `monoco i18n scan`
|
|
38
|
-
- [ ] Confirm source and target language settings are correct
|
|
39
|
-
- [ ] Verify exclusion rules (.gitignore, build directories, etc.)
|
|
40
|
-
|
|
41
|
-
### 2. Identify (Identify Missing)
|
|
42
|
-
|
|
43
|
-
- **Goal**: Analyze scan results, identify specific missing translations
|
|
44
|
-
- **Strategy**: Compare source and target files
|
|
45
|
-
- **Checkpoints**:
|
|
46
|
-
- [ ] List all source files with missing translations
|
|
47
|
-
- [ ] Identify missing target languages
|
|
48
|
-
- [ ] Assess impact scope of missing translations
|
|
49
|
-
- [ ] Sort by priority (core documents first)
|
|
50
|
-
|
|
51
|
-
### 3. Generate Tasks (Generate Tasks)
|
|
52
|
-
|
|
53
|
-
- **Goal**: Create tracking tasks for missing translations
|
|
54
|
-
- **Strategy**: Create Issue or memo based on missing status
|
|
55
|
-
- **Checkpoints**:
|
|
56
|
-
- [ ] Create Feature Issue for core document missing translations
|
|
57
|
-
- [ ] Create Memo reminder for secondary document missing translations
|
|
58
|
-
- [ ] Annotate file paths requiring translation in the Issue
|
|
59
|
-
- [ ] Set reasonable priority and deadline
|
|
60
|
-
|
|
61
|
-
## Decision Branches
|
|
62
|
-
|
|
63
|
-
| Condition | Action |
|
|
64
|
-
|-----------|--------|
|
|
65
|
-
| Configuration error | Fix `.monoco/config.yaml`, rescan |
|
|
66
|
-
| No missing translations | Process completed, no further action needed |
|
|
67
|
-
| Large amount missing | Create Epic, split into multiple Features |
|
|
68
|
-
| Critical document missing | High priority, create Issue immediately |
|
|
69
|
-
|
|
70
|
-
## Compliance Requirements
|
|
71
|
-
|
|
72
|
-
- **Required**: Verify i18n configuration is correct before scanning
|
|
73
|
-
- **Required**: All core documents must have corresponding translations
|
|
74
|
-
- **Recommended**: Run scans regularly (e.g., weekly)
|
|
75
|
-
- **Recommended**: Bind translation tasks with feature development
|
|
76
|
-
|
|
77
|
-
## Related Commands
|
|
78
|
-
|
|
79
|
-
```bash
|
|
80
|
-
# Scan for missing translations
|
|
81
|
-
monoco i18n scan
|
|
82
|
-
|
|
83
|
-
# Create translation task
|
|
84
|
-
monoco issue create feature -t "Translate {filename} to {lang}"
|
|
85
|
-
|
|
86
|
-
# Add memo
|
|
87
|
-
monoco memo add "Needs translation: {filepath}"
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
## Output Example
|
|
91
|
-
|
|
92
|
-
After scanning completes, a report like the following should be generated:
|
|
93
|
-
|
|
94
|
-
```
|
|
95
|
-
I18n Scan Report
|
|
96
|
-
================
|
|
97
|
-
Source Language: en
|
|
98
|
-
Target Languages: zh, ja
|
|
99
|
-
|
|
100
|
-
Missing Translations:
|
|
101
|
-
- docs/guide.md → zh/guide.md [MISSING]
|
|
102
|
-
- docs/api.md → ja/api.md [MISSING]
|
|
103
|
-
|
|
104
|
-
Coverage: 85%
|
|
105
|
-
```
|