monoco-toolkit 0.1.0__py3-none-any.whl → 0.2.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.
Files changed (69) hide show
  1. monoco/cli/__init__.py +0 -0
  2. monoco/cli/project.py +87 -0
  3. monoco/cli/workspace.py +46 -0
  4. monoco/core/agent/__init__.py +5 -0
  5. monoco/core/agent/action.py +144 -0
  6. monoco/core/agent/adapters.py +106 -0
  7. monoco/core/agent/protocol.py +31 -0
  8. monoco/core/agent/state.py +106 -0
  9. monoco/core/config.py +152 -17
  10. monoco/core/execution.py +62 -0
  11. monoco/core/feature.py +58 -0
  12. monoco/core/git.py +51 -2
  13. monoco/core/injection.py +196 -0
  14. monoco/core/integrations.py +234 -0
  15. monoco/core/lsp.py +61 -0
  16. monoco/core/output.py +13 -2
  17. monoco/core/registry.py +36 -0
  18. monoco/core/resources/en/AGENTS.md +8 -0
  19. monoco/core/resources/en/SKILL.md +66 -0
  20. monoco/core/resources/zh/AGENTS.md +8 -0
  21. monoco/core/resources/zh/SKILL.md +66 -0
  22. monoco/core/setup.py +88 -110
  23. monoco/core/skills.py +444 -0
  24. monoco/core/state.py +53 -0
  25. monoco/core/sync.py +224 -0
  26. monoco/core/telemetry.py +4 -1
  27. monoco/core/workspace.py +85 -20
  28. monoco/daemon/app.py +127 -58
  29. monoco/daemon/models.py +4 -0
  30. monoco/daemon/services.py +56 -155
  31. monoco/features/agent/commands.py +166 -0
  32. monoco/features/agent/doctor.py +30 -0
  33. monoco/features/config/commands.py +125 -44
  34. monoco/features/i18n/adapter.py +29 -0
  35. monoco/features/i18n/commands.py +89 -10
  36. monoco/features/i18n/core.py +113 -27
  37. monoco/features/i18n/resources/en/AGENTS.md +8 -0
  38. monoco/features/i18n/resources/en/SKILL.md +94 -0
  39. monoco/features/i18n/resources/zh/AGENTS.md +8 -0
  40. monoco/features/i18n/resources/zh/SKILL.md +94 -0
  41. monoco/features/issue/adapter.py +34 -0
  42. monoco/features/issue/commands.py +183 -65
  43. monoco/features/issue/core.py +172 -77
  44. monoco/features/issue/linter.py +215 -116
  45. monoco/features/issue/migration.py +134 -0
  46. monoco/features/issue/models.py +23 -19
  47. monoco/features/issue/monitor.py +94 -0
  48. monoco/features/issue/resources/en/AGENTS.md +15 -0
  49. monoco/features/issue/resources/en/SKILL.md +87 -0
  50. monoco/features/issue/resources/zh/AGENTS.md +15 -0
  51. monoco/features/issue/resources/zh/SKILL.md +114 -0
  52. monoco/features/issue/validator.py +269 -0
  53. monoco/features/pty/core.py +185 -0
  54. monoco/features/pty/router.py +138 -0
  55. monoco/features/pty/server.py +56 -0
  56. monoco/features/spike/adapter.py +30 -0
  57. monoco/features/spike/commands.py +45 -24
  58. monoco/features/spike/core.py +4 -21
  59. monoco/features/spike/resources/en/AGENTS.md +7 -0
  60. monoco/features/spike/resources/en/SKILL.md +74 -0
  61. monoco/features/spike/resources/zh/AGENTS.md +7 -0
  62. monoco/features/spike/resources/zh/SKILL.md +74 -0
  63. monoco/main.py +115 -2
  64. {monoco_toolkit-0.1.0.dist-info → monoco_toolkit-0.2.5.dist-info}/METADATA +10 -3
  65. monoco_toolkit-0.2.5.dist-info/RECORD +77 -0
  66. monoco_toolkit-0.1.0.dist-info/RECORD +0 -33
  67. {monoco_toolkit-0.1.0.dist-info → monoco_toolkit-0.2.5.dist-info}/WHEEL +0 -0
  68. {monoco_toolkit-0.1.0.dist-info → monoco_toolkit-0.2.5.dist-info}/entry_points.txt +0 -0
  69. {monoco_toolkit-0.1.0.dist-info → monoco_toolkit-0.2.5.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,234 @@
1
+ """
2
+ Core Integration Registry for Agent Frameworks.
3
+
4
+ This module provides a centralized registry for managing integrations with various
5
+ agent frameworks (Cursor, Claude, Gemini, Qwen, Antigravity, etc.).
6
+
7
+ It defines the standard structure for framework integrations and provides utilities
8
+ for detection and configuration.
9
+ """
10
+
11
+ from pathlib import Path
12
+ from typing import Dict, List, Optional
13
+ from pydantic import BaseModel, Field
14
+
15
+
16
+ class AgentIntegration(BaseModel):
17
+ """
18
+ Configuration for a single agent framework integration.
19
+
20
+ Attributes:
21
+ key: Unique identifier for the framework (e.g., 'cursor', 'gemini')
22
+ name: Human-readable name of the framework
23
+ system_prompt_file: Path to the system prompt/rules file relative to project root
24
+ skill_root_dir: Path to the skills directory relative to project root
25
+ bin_name: Optional name of the binary to check for (e.g., 'cursor', 'gemini')
26
+ version_cmd: Optional command to check version (e.g., '--version')
27
+ enabled: Whether this integration is active (default: True)
28
+ """
29
+ key: str = Field(..., description="Unique framework identifier")
30
+ name: str = Field(..., description="Human-readable framework name")
31
+ system_prompt_file: str = Field(..., description="Path to system prompt file (relative to project root)")
32
+ skill_root_dir: str = Field(..., description="Path to skills directory (relative to project root)")
33
+ bin_name: Optional[str] = Field(None, description="Binary name to check for availability")
34
+ version_cmd: Optional[str] = Field(None, description="Command to check version")
35
+ enabled: bool = Field(default=True, description="Whether this integration is active")
36
+
37
+ def check_health(self) -> "AgentProviderHealth":
38
+ """
39
+ Check health of this integration.
40
+ """
41
+ import shutil
42
+ import subprocess
43
+ import time
44
+
45
+ if not self.bin_name:
46
+ return AgentProviderHealth(available=True) # If no binary required, assume ok
47
+
48
+ bin_path = shutil.which(self.bin_name)
49
+ if not bin_path:
50
+ return AgentProviderHealth(available=False, error=f"Binary '{self.bin_name}' not found in PATH")
51
+
52
+ if not self.version_cmd:
53
+ return AgentProviderHealth(available=True, path=bin_path)
54
+
55
+ start_time = time.time()
56
+ try:
57
+ # We use a shortcut to check version cmd
58
+ # Some tools might need e.g. 'cursor --version'
59
+ subprocess.run(
60
+ [self.bin_name] + self.version_cmd.split(),
61
+ check=True,
62
+ capture_output=True,
63
+ timeout=5
64
+ )
65
+ latency = int((time.time() - start_time) * 1000)
66
+ return AgentProviderHealth(available=True, path=bin_path, latency_ms=latency)
67
+ except Exception as e:
68
+ return AgentProviderHealth(available=False, path=bin_path, error=str(e))
69
+
70
+
71
+ class AgentProviderHealth(BaseModel):
72
+ """Health check result for an agent provider."""
73
+ available: bool
74
+ path: Optional[str] = None
75
+ error: Optional[str] = None
76
+ latency_ms: Optional[int] = None
77
+
78
+
79
+ # Default Integration Registry
80
+ DEFAULT_INTEGRATIONS: Dict[str, AgentIntegration] = {
81
+ "cursor": AgentIntegration(
82
+ key="cursor",
83
+ name="Cursor",
84
+ system_prompt_file=".cursorrules",
85
+ skill_root_dir=".cursor/skills/",
86
+ bin_name="cursor",
87
+ version_cmd="--version",
88
+ ),
89
+ "claude": AgentIntegration(
90
+ key="claude",
91
+ name="Claude Code",
92
+ system_prompt_file="CLAUDE.md",
93
+ skill_root_dir=".claude/skills/",
94
+ bin_name="claude",
95
+ version_cmd="--version",
96
+ ),
97
+ "gemini": AgentIntegration(
98
+ key="gemini",
99
+ name="Gemini CLI",
100
+ system_prompt_file="GEMINI.md",
101
+ skill_root_dir=".gemini/skills/",
102
+ bin_name="gemini",
103
+ version_cmd="--version",
104
+ ),
105
+ "qwen": AgentIntegration(
106
+ key="qwen",
107
+ name="Qwen Code",
108
+ system_prompt_file="QWEN.md",
109
+ skill_root_dir=".qwen/skills/",
110
+ bin_name="qwen",
111
+ version_cmd="--version",
112
+ ),
113
+ "agent": AgentIntegration(
114
+ key="agent",
115
+ name="Antigravity",
116
+ system_prompt_file="GEMINI.md",
117
+ skill_root_dir=".agent/skills/",
118
+ ),
119
+ }
120
+
121
+
122
+ def get_integration(
123
+ name: str,
124
+ config_overrides: Optional[Dict[str, AgentIntegration]] = None
125
+ ) -> Optional[AgentIntegration]:
126
+ """
127
+ Get an agent integration by name.
128
+
129
+ Args:
130
+ name: The framework key (e.g., 'cursor', 'gemini')
131
+ config_overrides: Optional user-defined integrations from config
132
+
133
+ Returns:
134
+ AgentIntegration if found, None otherwise
135
+
136
+ Priority:
137
+ 1. User config overrides
138
+ 2. Default registry
139
+ """
140
+ # Check user overrides first
141
+ if config_overrides and name in config_overrides:
142
+ return config_overrides[name]
143
+
144
+ # Fall back to defaults
145
+ return DEFAULT_INTEGRATIONS.get(name)
146
+
147
+
148
+ def get_all_integrations(
149
+ config_overrides: Optional[Dict[str, AgentIntegration]] = None,
150
+ enabled_only: bool = True
151
+ ) -> Dict[str, AgentIntegration]:
152
+ """
153
+ Get all available integrations.
154
+
155
+ Args:
156
+ config_overrides: Optional user-defined integrations from config
157
+ enabled_only: If True, only return enabled integrations
158
+
159
+ Returns:
160
+ Dictionary of all integrations (merged defaults + overrides)
161
+ """
162
+ # Start with defaults
163
+ all_integrations = DEFAULT_INTEGRATIONS.copy()
164
+
165
+ # Merge user overrides
166
+ if config_overrides:
167
+ all_integrations.update(config_overrides)
168
+
169
+ # Filter by enabled status if requested
170
+ if enabled_only:
171
+ return {k: v for k, v in all_integrations.items() if v.enabled}
172
+
173
+ return all_integrations
174
+
175
+
176
+ def detect_frameworks(root: Path) -> List[str]:
177
+ """
178
+ Auto-detect which agent frameworks are present in the project.
179
+
180
+ Detection is based on the existence of characteristic files/directories
181
+ for each framework.
182
+
183
+ Args:
184
+ root: Project root directory
185
+
186
+ Returns:
187
+ List of detected framework keys (e.g., ['cursor', 'gemini'])
188
+
189
+ Example:
190
+ >>> root = Path("/path/to/project")
191
+ >>> frameworks = detect_frameworks(root)
192
+ >>> print(frameworks)
193
+ ['cursor', 'gemini']
194
+ """
195
+ detected = []
196
+
197
+ for key, integration in DEFAULT_INTEGRATIONS.items():
198
+ # Check if system prompt file exists
199
+ prompt_file = root / integration.system_prompt_file
200
+
201
+ # Check if skill directory exists
202
+ skill_dir = root / integration.skill_root_dir
203
+
204
+ # Consider framework present if either exists
205
+ if prompt_file.exists() or skill_dir.exists():
206
+ detected.append(key)
207
+
208
+ return detected
209
+
210
+
211
+ def get_active_integrations(
212
+ root: Path,
213
+ config_overrides: Optional[Dict[str, AgentIntegration]] = None,
214
+ auto_detect: bool = True
215
+ ) -> Dict[str, AgentIntegration]:
216
+ """
217
+ Get integrations that are both enabled and detected in the project.
218
+
219
+ Args:
220
+ root: Project root directory
221
+ config_overrides: Optional user-defined integrations from config
222
+ auto_detect: If True, only return integrations detected in the project
223
+
224
+ Returns:
225
+ Dictionary of active integrations
226
+ """
227
+ all_integrations = get_all_integrations(config_overrides, enabled_only=True)
228
+
229
+ if not auto_detect:
230
+ return all_integrations
231
+
232
+ # Filter by detection
233
+ detected_keys = detect_frameworks(root)
234
+ return {k: v for k, v in all_integrations.items() if k in detected_keys}
monoco/core/lsp.py ADDED
@@ -0,0 +1,61 @@
1
+ from enum import IntEnum
2
+ from typing import List, Optional, Union
3
+ from pydantic import BaseModel
4
+
5
+ class Position(BaseModel):
6
+ """
7
+ Position in a text document expressed as zero-based line and character offset.
8
+ """
9
+ line: int
10
+ character: int
11
+
12
+ def __lt__(self, other):
13
+ if self.line != other.line:
14
+ return self.line < other.line
15
+ return self.character < other.character
16
+
17
+ class Range(BaseModel):
18
+ """
19
+ A range in a text document expressed as (zero-based) start and end positions.
20
+ """
21
+ start: Position
22
+ end: Position
23
+
24
+ def __repr__(self):
25
+ return f"{self.start.line}:{self.start.character}-{self.end.line}:{self.end.character}"
26
+
27
+ class DiagnosticSeverity(IntEnum):
28
+ Error = 1
29
+ Warning = 2
30
+ Information = 3
31
+ Hint = 4
32
+
33
+ class DiagnosticRelatedInformation(BaseModel):
34
+ """
35
+ Represents a related message and source code location for a diagnostic.
36
+ """
37
+ # location: Location # Defined elsewhere or simplified here
38
+ message: str
39
+
40
+ class Diagnostic(BaseModel):
41
+ """
42
+ Represents a diagnostic, such as a compiler error or warning.
43
+ """
44
+ range: Range
45
+ severity: Optional[DiagnosticSeverity] = None
46
+ code: Optional[Union[int, str]] = None
47
+ source: Optional[str] = "monoco"
48
+ message: str
49
+ related_information: Optional[List[DiagnosticRelatedInformation]] = None
50
+ data: Optional[dict] = None # To carry extra info (e.g. for code actions)
51
+
52
+ def to_user_string(self) -> str:
53
+ """Helper to format for CLI output"""
54
+ severity_map = {
55
+ 1: "[red]Error[/red]",
56
+ 2: "[yellow]Warning[/yellow]",
57
+ 3: "[blue]Info[/blue]",
58
+ 4: "[dim]Hint[/dim]"
59
+ }
60
+ sev = severity_map.get(self.severity, "Error")
61
+ return f"{sev}: {self.message} (Line {self.range.start.line + 1})"
monoco/core/output.py CHANGED
@@ -24,8 +24,8 @@ class OutputManager:
24
24
  """
25
25
  Check if running in Agent Mode.
26
26
  Triggers:
27
- 1. Environment variable AGENT_FLAG=true (or 1)
28
- 2. Environment variable MONOCO_AGENT=true (or 1)
27
+ 1. Environment variable AGENT_FLAG=true (or 1)
28
+ 2. Environment variable MONOCO_AGENT=true (or 1)
29
29
  """
30
30
  return os.getenv("AGENT_FLAG", "").lower() in ("true", "1") or \
31
31
  os.getenv("MONOCO_AGENT", "").lower() in ("true", "1")
@@ -40,6 +40,16 @@ class OutputManager:
40
40
  else:
41
41
  OutputManager._render_human(data, title)
42
42
 
43
+ @staticmethod
44
+ def error(message: str):
45
+ """
46
+ Print error message.
47
+ """
48
+ if OutputManager.is_agent_mode():
49
+ print(json.dumps({"error": message}))
50
+ else:
51
+ rprint(f"[bold red]Error:[/bold red] {message}")
52
+
43
53
  @staticmethod
44
54
  def _render_agent(data: Any):
45
55
  """
@@ -95,3 +105,4 @@ class OutputManager:
95
105
 
96
106
  # Global helper
97
107
  print_output = OutputManager.print
108
+ print_error = OutputManager.error
@@ -0,0 +1,36 @@
1
+ from typing import Dict, List, Type
2
+ from monoco.core.feature import MonocoFeature
3
+
4
+ class FeatureRegistry:
5
+ _features: Dict[str, MonocoFeature] = {}
6
+
7
+ @classmethod
8
+ def register(cls, feature: MonocoFeature):
9
+ """Register a feature instance."""
10
+ cls._features[feature.name] = feature
11
+
12
+ @classmethod
13
+ def get_features(cls) -> List[MonocoFeature]:
14
+ """Get all registered features."""
15
+ return list(cls._features.values())
16
+
17
+ @classmethod
18
+ def get_feature(cls, name: str) -> MonocoFeature:
19
+ """Get a specific feature by name."""
20
+ return cls._features.get(name)
21
+
22
+ @classmethod
23
+ def load_defaults(cls):
24
+ """
25
+ Load default core features.
26
+ TODO: In the future, this could be dynamic via entry points.
27
+ """
28
+ # Import here to avoid circular dependencies at module level
29
+ from monoco.features.issue.adapter import IssueFeature
30
+ from monoco.features.spike.adapter import SpikeFeature
31
+ from monoco.features.i18n.adapter import I18nFeature
32
+
33
+ cls.register(IssueFeature())
34
+ cls.register(SpikeFeature())
35
+ cls.register(I18nFeature())
36
+ pass
@@ -0,0 +1,8 @@
1
+ ### Monoco Core
2
+
3
+ Core toolkit commands for project management.
4
+
5
+ - **Init**: `monoco init` (Initialize new Monoco project)
6
+ - **Config**: `monoco config get|set <key> [value]` (Manage configuration)
7
+ - **Sync**: `monoco sync` (Synchronize with agent environments)
8
+ - **Uninstall**: `monoco uninstall` (Clean up agent integrations)
@@ -0,0 +1,66 @@
1
+ ---
2
+ name: monoco-core
3
+ description: Core skill for Monoco Toolkit. Provides essential commands for project initialization, configuration, and workspace management.
4
+ ---
5
+
6
+ # Monoco Core
7
+
8
+ Core functionality and commands for the Monoco Toolkit.
9
+
10
+ ## Overview
11
+
12
+ Monoco is a developer productivity toolkit that provides:
13
+
14
+ - **Project initialization** with standardized structure
15
+ - **Configuration management** at global and project levels
16
+ - **Workspace management** for multi-project setups
17
+
18
+ ## Key Commands
19
+
20
+ ### Project Setup
21
+
22
+ - **`monoco init`**: Initialize a new Monoco project
23
+ - Creates `.monoco/` directory with default configuration
24
+ - Sets up project structure (Issues/, .references/, etc.)
25
+ - Generates initial documentation
26
+
27
+ ### Configuration
28
+
29
+ - **`monoco config`**: Manage configuration
30
+ - `monoco config get <key>`: View configuration value
31
+ - `monoco config set <key> <value>`: Update configuration
32
+ - Supports both global (`~/.monoco/config.yaml`) and project (`.monoco/config.yaml`) scopes
33
+
34
+ ### Agent Integration
35
+
36
+ - **`monoco sync`**: Synchronize with agent environments
37
+
38
+ - Injects system prompts into agent configuration files (GEMINI.md, CLAUDE.md, etc.)
39
+ - Distributes skills to agent framework directories
40
+ - Respects language configuration from `i18n.source_lang`
41
+
42
+ - **`monoco uninstall`**: Clean up agent integrations
43
+ - Removes managed blocks from agent configuration files
44
+ - Cleans up distributed skills
45
+
46
+ ## Configuration Structure
47
+
48
+ Configuration is stored in YAML format at:
49
+
50
+ - **Global**: `~/.monoco/config.yaml`
51
+ - **Project**: `.monoco/config.yaml`
52
+
53
+ Key configuration sections:
54
+
55
+ - `core`: Log level, author
56
+ - `paths`: Directory paths (issues, spikes, specs)
57
+ - `project`: Project metadata, spike repos, workspace members
58
+ - `i18n`: Internationalization settings
59
+ - `agent`: Agent framework integration settings
60
+
61
+ ## Best Practices
62
+
63
+ 1. **Use CLI commands** instead of manual file editing when possible
64
+ 2. **Run `monoco sync`** after configuration changes to update agent environments
65
+ 3. **Commit `.monoco/config.yaml`** to version control for team consistency
66
+ 4. **Keep global config minimal** - most settings should be project-specific
@@ -0,0 +1,8 @@
1
+ ### Monoco 核心
2
+
3
+ 项目管理的核心工具包命令。
4
+
5
+ - **初始化**: `monoco init` (初始化新的 Monoco 项目)
6
+ - **配置**: `monoco config get|set <key> [value]` (管理配置)
7
+ - **同步**: `monoco sync` (与 agent 环境同步)
8
+ - **卸载**: `monoco uninstall` (清理 agent 集成)
@@ -0,0 +1,66 @@
1
+ ---
2
+ name: monoco-core
3
+ description: Monoco Toolkit 的核心技能。提供项目初始化、配置管理和工作空间管理的基础命令。
4
+ ---
5
+
6
+ # Monoco 核心
7
+
8
+ Monoco Toolkit 的核心功能和命令。
9
+
10
+ ## 概述
11
+
12
+ Monoco 是一个开发者生产力工具包,提供:
13
+
14
+ - **项目初始化**:标准化的项目结构
15
+ - **配置管理**:全局和项目级别的配置
16
+ - **工作空间管理**:多项目设置
17
+
18
+ ## 核心命令
19
+
20
+ ### 项目设置
21
+
22
+ - **`monoco init`**: 初始化新的 Monoco 项目
23
+ - 创建 `.monoco/` 目录及默认配置
24
+ - 设置项目结构(Issues/, .references/ 等)
25
+ - 生成初始文档
26
+
27
+ ### 配置管理
28
+
29
+ - **`monoco config`**: 管理配置
30
+ - `monoco config get <key>`: 查看配置值
31
+ - `monoco config set <key> <value>`: 更新配置
32
+ - 支持全局(`~/.monoco/config.yaml`)和项目(`.monoco/config.yaml`)作用域
33
+
34
+ ### Agent 集成
35
+
36
+ - **`monoco sync`**: 与 agent 环境同步
37
+
38
+ - 将系统提示注入到 agent 配置文件(GEMINI.md, CLAUDE.md 等)
39
+ - 分发 skills 到 agent 框架目录
40
+ - 遵循 `i18n.source_lang` 的语言配置
41
+
42
+ - **`monoco uninstall`**: 清理 agent 集成
43
+ - 从 agent 配置文件中移除托管块
44
+ - 清理已分发的 skills
45
+
46
+ ## 配置结构
47
+
48
+ 配置以 YAML 格式存储在:
49
+
50
+ - **全局**: `~/.monoco/config.yaml`
51
+ - **项目**: `.monoco/config.yaml`
52
+
53
+ 关键配置段:
54
+
55
+ - `core`: 编辑器、日志级别、作者
56
+ - `paths`: 目录路径(issues, spikes, specs)
57
+ - `project`: 项目元数据、spike repos、工作空间成员
58
+ - `i18n`: 国际化设置
59
+ - `agent`: Agent 框架集成设置
60
+
61
+ ## 最佳实践
62
+
63
+ 1. **优先使用 CLI 命令**,而不是手动编辑文件
64
+ 2. **配置更改后运行 `monoco sync`** 以更新 agent 环境
65
+ 3. **将 `.monoco/config.yaml` 提交到版本控制**,保持团队一致性
66
+ 4. **保持全局配置最小化** - 大多数设置应该是项目特定的