monoco-toolkit 0.2.5__py3-none-any.whl → 0.2.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. monoco/core/agent/adapters.py +24 -1
  2. monoco/core/config.py +63 -1
  3. monoco/core/integrations.py +8 -0
  4. monoco/core/lsp.py +7 -0
  5. monoco/core/output.py +8 -1
  6. monoco/core/setup.py +8 -0
  7. monoco/features/agent/commands.py +73 -2
  8. monoco/features/agent/core.py +48 -0
  9. monoco/features/agent/resources/en/critique.prompty +16 -0
  10. monoco/features/agent/resources/en/develop.prompty +16 -0
  11. monoco/features/agent/resources/en/investigate.prompty +16 -0
  12. monoco/features/agent/resources/en/refine.prompty +14 -0
  13. monoco/features/agent/resources/en/verify.prompty +16 -0
  14. monoco/features/agent/resources/zh/critique.prompty +18 -0
  15. monoco/features/agent/resources/zh/develop.prompty +18 -0
  16. monoco/features/agent/resources/zh/investigate.prompty +18 -0
  17. monoco/features/agent/resources/zh/refine.prompty +16 -0
  18. monoco/features/agent/resources/zh/verify.prompty +18 -0
  19. monoco/features/issue/commands.py +133 -35
  20. monoco/features/issue/core.py +142 -119
  21. monoco/features/issue/domain/__init__.py +0 -0
  22. monoco/features/issue/domain/lifecycle.py +126 -0
  23. monoco/features/issue/domain/models.py +170 -0
  24. monoco/features/issue/domain/parser.py +223 -0
  25. monoco/features/issue/domain/workspace.py +104 -0
  26. monoco/features/issue/engine/__init__.py +22 -0
  27. monoco/features/issue/engine/config.py +189 -0
  28. monoco/features/issue/engine/machine.py +185 -0
  29. monoco/features/issue/engine/models.py +18 -0
  30. monoco/features/issue/linter.py +32 -11
  31. monoco/features/issue/lsp/__init__.py +3 -0
  32. monoco/features/issue/lsp/definition.py +72 -0
  33. monoco/features/issue/models.py +8 -8
  34. monoco/features/issue/validator.py +181 -65
  35. monoco/features/spike/core.py +5 -22
  36. monoco/main.py +0 -15
  37. {monoco_toolkit-0.2.5.dist-info → monoco_toolkit-0.2.6.dist-info}/METADATA +1 -1
  38. {monoco_toolkit-0.2.5.dist-info → monoco_toolkit-0.2.6.dist-info}/RECORD +41 -22
  39. monoco/features/pty/core.py +0 -185
  40. monoco/features/pty/router.py +0 -138
  41. monoco/features/pty/server.py +0 -56
  42. {monoco_toolkit-0.2.5.dist-info → monoco_toolkit-0.2.6.dist-info}/WHEEL +0 -0
  43. {monoco_toolkit-0.2.5.dist-info → monoco_toolkit-0.2.6.dist-info}/entry_points.txt +0 -0
  44. {monoco_toolkit-0.2.5.dist-info → monoco_toolkit-0.2.6.dist-info}/licenses/LICENSE +0 -0
@@ -21,6 +21,16 @@ class BaseCLIClient:
21
21
 
22
22
  def _build_prompt(self, prompt: str, context_files: List[Path]) -> str:
23
23
  """Concatenate prompt and context files."""
24
+ # Inject Language Rule
25
+ try:
26
+ from monoco.core.config import get_config
27
+ settings = get_config()
28
+ lang = settings.i18n.source_lang
29
+ if lang:
30
+ prompt = f"{prompt}\n\n[SYSTEM: LANGUAGE CONSTRAINT]\nThe project source language is '{lang}'. You MUST use '{lang}' for all thinking and reporting unless explicitly instructed otherwise."
31
+ except Exception:
32
+ pass
33
+
24
34
  full_prompt = [prompt]
25
35
  if context_files:
26
36
  full_prompt.append("\n\n--- CONTEXT FILES ---")
@@ -93,10 +103,23 @@ class QwenClient(BaseCLIClient, AgentClient):
93
103
  return await self._run_command([self._executable, full_prompt])
94
104
 
95
105
 
106
+ class KimiClient(BaseCLIClient, AgentClient):
107
+ """Adapter for Moonshot Kimi CLI."""
108
+
109
+ def __init__(self):
110
+ super().__init__("kimi")
111
+
112
+ async def execute(self, prompt: str, context_files: List[Path] = []) -> str:
113
+ full_prompt = self._build_prompt(prompt, context_files)
114
+ # Usage: kimi "prompt"
115
+ return await self._run_command([self._executable, full_prompt])
116
+
117
+
96
118
  _ADAPTERS = {
97
119
  "gemini": GeminiClient,
98
120
  "claude": ClaudeClient,
99
- "qwen": QwenClient
121
+ "qwen": QwenClient,
122
+ "kimi": KimiClient
100
123
  }
101
124
 
102
125
  def get_agent_client(name: str) -> AgentClient:
monoco/core/config.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  import yaml
3
3
  from pathlib import Path
4
- from typing import Optional, Dict, Any, Callable, Awaitable
4
+ from typing import Optional, Dict, Any, Callable, Awaitable, List
5
5
  from enum import Enum
6
6
  from pydantic import BaseModel, Field
7
7
 
@@ -56,6 +56,67 @@ class AgentConfig(BaseModel):
56
56
  description="Custom agent framework integrations (overrides defaults from monoco.core.integrations)"
57
57
  )
58
58
 
59
+ class IssueTypeConfig(BaseModel):
60
+ name: str
61
+ label: str
62
+ prefix: str
63
+ folder: str
64
+ description: Optional[str] = None
65
+
66
+ class TransitionConfig(BaseModel):
67
+ name: str
68
+ label: str
69
+ icon: Optional[str] = None
70
+ from_status: Optional[str] = None
71
+ from_stage: Optional[str] = None
72
+ to_status: str
73
+ to_stage: Optional[str] = None
74
+ required_solution: Optional[str] = None
75
+ description: str = ""
76
+ command_template: Optional[str] = None
77
+
78
+ class IssueSchemaConfig(BaseModel):
79
+ types: List[IssueTypeConfig] = Field(default_factory=list)
80
+ statuses: List[str] = Field(default_factory=list)
81
+ stages: List[str] = Field(default_factory=list)
82
+ solutions: List[str] = Field(default_factory=list)
83
+ workflows: List[TransitionConfig] = Field(default_factory=list)
84
+
85
+ def merge(self, other: "IssueSchemaConfig") -> "IssueSchemaConfig":
86
+ if not other:
87
+ return self
88
+
89
+ # Types: merge by name
90
+ if other.types:
91
+ type_map = {t.name: t for t in self.types}
92
+ for ot in other.types:
93
+ type_map[ot.name] = ot
94
+ self.types = list(type_map.values())
95
+
96
+ # Statuses: replace if provided
97
+ if other.statuses:
98
+ self.statuses = other.statuses
99
+
100
+ # Stages: replace if provided
101
+ if other.stages:
102
+ self.stages = other.stages
103
+
104
+ # Solutions: replace if provided
105
+ if other.solutions:
106
+ self.solutions = other.solutions
107
+
108
+ # Workflows (Transitions): merge by name
109
+ if other.workflows:
110
+ wf_map = {w.name: w for w in self.workflows}
111
+ for ow in other.workflows:
112
+ wf_map[ow.name] = ow
113
+ self.workflows = list(wf_map.values())
114
+
115
+ return self
116
+
117
+ class StateMachineConfig(BaseModel):
118
+ transitions: List[TransitionConfig]
119
+
59
120
  class MonocoConfig(BaseModel):
60
121
  """
61
122
  Main Configuration Schema.
@@ -68,6 +129,7 @@ class MonocoConfig(BaseModel):
68
129
  ui: UIConfig = Field(default_factory=UIConfig)
69
130
  telemetry: TelemetryConfig = Field(default_factory=TelemetryConfig)
70
131
  agent: AgentConfig = Field(default_factory=AgentConfig)
132
+ issue: IssueSchemaConfig = Field(default_factory=IssueSchemaConfig)
71
133
 
72
134
  @staticmethod
73
135
  def _deep_merge(base: Dict[str, Any], update: Dict[str, Any]) -> Dict[str, Any]:
@@ -110,6 +110,14 @@ DEFAULT_INTEGRATIONS: Dict[str, AgentIntegration] = {
110
110
  bin_name="qwen",
111
111
  version_cmd="--version",
112
112
  ),
113
+ "kimi": AgentIntegration(
114
+ key="kimi",
115
+ name="Kimi CLI",
116
+ system_prompt_file="KIMI.md",
117
+ skill_root_dir=".kimi/skills/",
118
+ bin_name="kimi",
119
+ version_cmd="--version",
120
+ ),
113
121
  "agent": AgentIntegration(
114
122
  key="agent",
115
123
  name="Antigravity",
monoco/core/lsp.py CHANGED
@@ -24,6 +24,13 @@ class Range(BaseModel):
24
24
  def __repr__(self):
25
25
  return f"{self.start.line}:{self.start.character}-{self.end.line}:{self.end.character}"
26
26
 
27
+ class Location(BaseModel):
28
+ """
29
+ Represents a location inside a resource, such as a line of code inside a text file.
30
+ """
31
+ uri: str
32
+ range: Range
33
+
27
34
  class DiagnosticSeverity(IntEnum):
28
35
  Error = 1
29
36
  Warning = 2
monoco/core/output.py CHANGED
@@ -63,8 +63,15 @@ class OutputManager:
63
63
  print(json.dumps([item.model_dump(mode='json', exclude_none=True) for item in data], separators=(',', ':')))
64
64
  else:
65
65
  # Fallback for dicts/lists/primitives
66
+ def _encoder(obj):
67
+ if isinstance(obj, BaseModel):
68
+ return obj.model_dump(mode='json', exclude_none=True)
69
+ if hasattr(obj, 'value'): # Enum support
70
+ return obj.value
71
+ return str(obj)
72
+
66
73
  try:
67
- print(json.dumps(data, separators=(',', ':'), default=str))
74
+ print(json.dumps(data, separators=(',', ':'), default=_encoder))
68
75
  except TypeError:
69
76
  print(str(data))
70
77
 
monoco/core/setup.py CHANGED
@@ -258,6 +258,14 @@ def init_cli(
258
258
  (cwd / "Issues").mkdir(exist_ok=True)
259
259
  (cwd / ".references").mkdir(exist_ok=True)
260
260
 
261
+ # Initialize Agent Resources
262
+ try:
263
+ from monoco.features.agent.core import init_agent_resources
264
+ init_agent_resources(cwd)
265
+ console.print(f"[dim] - Agent Resources: .monoco/actions/*.prompty[/dim]")
266
+ except Exception as e:
267
+ console.print(f"[yellow]Warning: Failed to init agent resources: {e}[/yellow]")
268
+
261
269
  console.print("\n[bold green]✓ Monoco Project Initialized![/bold green]")
262
270
  console.print(f"Access configured! issues will be created as [bold]{project_key}-XXX[/bold]")
263
271
 
@@ -12,6 +12,8 @@ import re
12
12
  import json as j
13
13
 
14
14
  app = typer.Typer()
15
+ action_app = typer.Typer(name="action", help="Manage generic agent actions/prompts.")
16
+ app.add_typer(action_app)
15
17
 
16
18
  @app.command(name="run")
17
19
  def run_command(
@@ -100,8 +102,8 @@ def run_command(
100
102
  print_error(f"Execution failed: {e}")
101
103
  raise typer.Exit(1)
102
104
 
103
- @app.command()
104
- def list(
105
+ @action_app.command(name="list")
106
+ def action_list(
105
107
  json: AgentOutput = False,
106
108
  context: Optional[str] = typer.Option(None, "--context", help="Context for filtering (JSON string)")
107
109
  ):
@@ -118,9 +120,59 @@ def list(
118
120
  print_error(f"Invalid context JSON: {e}")
119
121
 
120
122
  actions = registry.list_available(action_context)
123
+
124
+ # Filter by State Machine if context implies an Issue
125
+ if action_context and (action_context.status or action_context.stage):
126
+ try:
127
+ from monoco.features.issue.engine.machine import StateMachine
128
+ from monoco.features.issue.models import IssueMetadata
129
+
130
+ cfg = settings.issue
131
+ sm = StateMachine(cfg)
132
+
133
+ # Create a mock metadata for state check
134
+ mock_meta = IssueMetadata(
135
+ id="mock-id",
136
+ title="Mock Issue",
137
+ type=action_context.type or "feature",
138
+ status=action_context.status or "open",
139
+ stage=action_context.stage
140
+ )
141
+
142
+ allowed_transitions = sm.get_available_transitions(mock_meta)
143
+ allowed_names = {t.name for t in allowed_transitions}
144
+
145
+ # Identify which actions are actually transitions
146
+ all_transition_names = {t.name for t in cfg.workflows}
147
+
148
+ filtered_actions = []
149
+ for action in actions:
150
+ # If an action is a formal transition, it must be allowed
151
+ if action.name in all_transition_names:
152
+ if action.name in allowed_names:
153
+ filtered_actions.append(action)
154
+ else:
155
+ # Generic actions are passed through (already filtered by 'when')
156
+ filtered_actions.append(action)
157
+
158
+ actions = filtered_actions
159
+
160
+ except Exception:
161
+ # Fallback if Issue feature is missing or context is invalid
162
+ pass
163
+
121
164
  # OutputManager handles list of Pydantic models automatically for both JSON and Table
122
165
  print_output(actions, title="Available Actions")
123
166
 
167
+ @app.command(name="list")
168
+ def list_providers(
169
+ json: AgentOutput = False,
170
+ force: bool = typer.Option(False, "--force", "-f", help="Force refresh of agent state")
171
+ ):
172
+ """List available agent providers and their status."""
173
+ # Reuse status logic
174
+ status(json=json, force=force)
175
+
124
176
  @app.command()
125
177
  def status(
126
178
  json: AgentOutput = False,
@@ -164,3 +216,22 @@ def doctor(
164
216
  """
165
217
  from monoco.features.agent.doctor import doctor as doc_impl
166
218
  doc_impl(force)
219
+
220
+ @app.command()
221
+ def init(
222
+ force: bool = typer.Option(False, "--force", "-f", help="Force overwrite existing resources")
223
+ ):
224
+ """
225
+ Initialize Agent Resources (prompts) in the current project.
226
+ """
227
+ settings = get_config()
228
+ root = Path(settings.paths.root)
229
+
230
+ from monoco.features.agent.core import init_agent_resources
231
+ # TODO: Pass force arg when supported by core
232
+ init_agent_resources(root)
233
+
234
+ if OutputManager.is_agent_mode():
235
+ OutputManager.print({"status": "initialized"})
236
+ else:
237
+ print(f"Agent resources initialized in {root}")
@@ -0,0 +1,48 @@
1
+ import shutil
2
+ import os
3
+ from pathlib import Path
4
+ from typing import List
5
+ try:
6
+ from importlib.resources import files
7
+ except ImportError:
8
+ # Fallback for python < 3.9
9
+ from importlib_resources import files
10
+
11
+ def init_agent_resources(project_root: Path):
12
+ """
13
+ Initialize Agent resources (prompts) in the project workspace.
14
+ """
15
+ actions_dir = project_root / ".monoco" / "actions"
16
+ actions_dir.mkdir(parents=True, exist_ok=True)
17
+
18
+ # Determine language from config, default to 'en'
19
+ # We need to load config to know the language.
20
+ # But this function might be called before full config load?
21
+ # Helper to peek at config or default to 'en'
22
+ from monoco.core.config import get_config
23
+ try:
24
+ settings = get_config(str(project_root), require_project=False) # Best effort
25
+ lang = settings.core.language or "en"
26
+ except Exception:
27
+ lang = "en"
28
+
29
+ # Define source path relative to this module
30
+ try:
31
+ current_dir = Path(__file__).parent
32
+
33
+ # Try specific language, fallback to 'en'
34
+ source_dir = current_dir / "resources" / lang
35
+ if not source_dir.exists():
36
+ source_dir = current_dir / "resources" / "en"
37
+
38
+ if source_dir.exists():
39
+ for item in source_dir.glob("*.prompty"):
40
+ target = actions_dir / item.name
41
+ # Copy if not exists, or overwrite?
42
+ # Ideally init should be safe to run multiple times (idempotent)
43
+ # But user might have customized them.
44
+ if not target.exists():
45
+ shutil.copy2(item, target)
46
+ except Exception as e:
47
+ # Fallback or Log?
48
+ pass
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: critique
3
+ description: Critique the code or design against requirements.
4
+ provider: chat
5
+ ---
6
+ You are a Principal Code Reviewer.
7
+ Your task is to critique the following implementation/design:
8
+
9
+ {{file}}
10
+
11
+ # Instructions
12
+ 1. **Gap Analysis**: Check if all Acceptance Criteria are met.
13
+ 2. **Code Quality**: Identify potential bugs, security issues, or performance bottlenecks.
14
+ 3. **Design Patterns**: Suggest better patterns if applicable.
15
+
16
+ Output a structured review.
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: develop
3
+ description: 执行核心开发任务:编码与单元测试。
4
+ provider: chat
5
+ ---
6
+ You are a Principal Software Engineer.
7
+ Your task is to implement the feature described in this Issue:
8
+
9
+ {{file}}
10
+
11
+ # Instructions
12
+ 1. **Implementation**: Write the code required to satisfy the Acceptance Criteria.
13
+ 2. **Unit Tests**: Add or update unit tests to verify your changes.
14
+ 3. **Linting**: Ensure code follows project style guidelines.
15
+
16
+ Please provide the code changes.
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: investigate
3
+ description: 扫描 Codebase,识别架构设计、业务约束,丰富 Issue 引用网络。
4
+ provider: chat
5
+ ---
6
+ You are a Senior Software Architect.
7
+ Your task is to investigate the feasibility and impact of the following Issue:
8
+
9
+ {{file}}
10
+
11
+ # Instructions
12
+ 1. **Architecture Scan**: Identify which modules/files need to be modified.
13
+ 2. **Dependency Analysis**: Suggest `parent`, `dependencies`, and `related` issues.
14
+ 3. **Constraint Check**: Identify any business rules or technical constraints (e.g., Billing module impact).
15
+
16
+ Output your findings as a comment or update the Issue description directly.
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: refine
3
+ description: 细化需求,将 Draft 转化为可执行的 Plan。
4
+ provider: chat
5
+ ---
6
+ You are a Product Owner / Systems Analyst.
7
+ Refine the following Draft Issue into a concrete Technical Plan:
8
+
9
+ {{file}}
10
+
11
+ # Instructions
12
+ 1. **Clarify Objective**: Ensure the goal is specific and standard.
13
+ 2. **Expand Criteria**: Add detailed Acceptance Criteria.
14
+ 3. **Breakdown Tasks**: List concrete Technical Tasks.
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: verify
3
+ description: 代为检查工单完整性、代码质量与逻辑一致性。
4
+ provider: chat
5
+ ---
6
+ You are a QA Lead / Release Manager.
7
+ Your task is to verify if the following Issue is ready for delivery:
8
+
9
+ {{file}}
10
+
11
+ # Instructions
12
+ 1. **Definition of Done**: Check if all Technical Tasks are checked and Acceptance Criteria met.
13
+ 2. **Quality Check**: Review the code changes (if provided in context) for bugs or antipatterns.
14
+ 3. **Completeness**: Ensure documentation and tests are present.
15
+
16
+ Output "PASS" if ready, or a list of "BLOCKERS" if not.
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: critique
3
+ description: 对当前实现或设计进行批判性审查。
4
+ provider: chat
5
+ when:
6
+ stageMatch: "review"
7
+ ---
8
+ 你是一位首席代码审查员。
9
+ 你的任务是对以下实现/设计进行批判性审查:
10
+
11
+ {{file}}
12
+
13
+ # 指令
14
+ 1. **差距分析**: 检查是否满足所有验收标准。
15
+ 2. **代码质量**: 识别潜在的 Bug、安全问题或性能瓶颈。
16
+ 3. **设计模式**: 如果适用,建议更好的设计模式。
17
+
18
+ 输出结构化的审查意见。
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: develop
3
+ description: 执行核心开发任务:编码与单元测试。
4
+ provider: chat
5
+ when:
6
+ stageMatch: "doing"
7
+ ---
8
+ 你是一位首席软件工程师。
9
+ 你的任务是实现此 Issue 中描述的功能:
10
+
11
+ {{file}}
12
+
13
+ # 指令
14
+ 1. **代码实现**: 编写满足验收标准所需的代码。
15
+ 2. **单元测试**: 添加或更新单元测试以验证你的更改。
16
+ 3. **代码规范**: 确保代码遵循项目风格指南 (Linting)。
17
+
18
+ 请提供代码变更。
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: investigate
3
+ description: 扫描代码库,识别架构设计、业务约束,丰富 Issue 引用网络。
4
+ provider: chat
5
+ when:
6
+ statusMatch: "open"
7
+ ---
8
+ 你是一位资深软件架构师。
9
+ 你的任务是调查以下 Issue 的可行性和影响:
10
+
11
+ {{file}}
12
+
13
+ # 指令
14
+ 1. **架构扫描**: 识别哪些模块/文件需要修改。
15
+ 2. **依赖分析**: 建议 `parent` (父级), `dependencies` (依赖), 和 `related` (相关) 议题。
16
+ 3. **约束检查**: 识别任何业务规则或技术约束(例如,即使很小的改动也可能影响计费模块)。
17
+
18
+ 请以评论形式输出你的发现,或直接更新 Issue 描述。
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: refine
3
+ description: 细化需求,将 Draft 转化为可执行的 Plan。
4
+ provider: chat
5
+ when:
6
+ stageMatch: "draft"
7
+ ---
8
+ 你是一位产品负责人 (PO) / 系统分析师。
9
+ 将以下草案 (Draft) Issue 细化为具体的技术计划:
10
+
11
+ {{file}}
12
+
13
+ # 指令
14
+ 1. **阐明目标**: 确保目标具体且标准。
15
+ 2. **扩展标准**: 添加详细的验收标准 (Acceptance Criteria)。
16
+ 3. **任务分解**: 列出具体的技术任务 (Technical Tasks)。
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: verify
3
+ description: 代为检查工单完整性、代码质量与逻辑一致性。
4
+ provider: chat
5
+ when:
6
+ stageMatch: "review|done"
7
+ ---
8
+ 你是一位 QA 负责人 / 发布经理。
9
+ 你的任务是验证以下 Issue 是否已准备好交付:
10
+
11
+ {{file}}
12
+
13
+ # 指令
14
+ 1. **完成定义 (DoD)**: 检查是否所有技术任务 (Technical Tasks) 都已勾选,且满足验收标准。
15
+ 2. **质量检查**: 审查代码变更(如果在上下文中提供了),查找 Bug 或反模式。
16
+ 3. **完整性**: 确保文档和测试都已存在。
17
+
18
+ 如果准备好了,输出 "PASS";否则列出 "BLOCKERS" (阻碍项)。