monoco-toolkit 0.2.8__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.
Files changed (63) hide show
  1. monoco/cli/project.py +35 -31
  2. monoco/cli/workspace.py +26 -16
  3. monoco/core/agent/__init__.py +0 -2
  4. monoco/core/agent/action.py +44 -20
  5. monoco/core/agent/adapters.py +20 -16
  6. monoco/core/agent/protocol.py +5 -4
  7. monoco/core/agent/state.py +21 -21
  8. monoco/core/config.py +90 -33
  9. monoco/core/execution.py +21 -16
  10. monoco/core/feature.py +8 -5
  11. monoco/core/git.py +61 -30
  12. monoco/core/hooks.py +57 -0
  13. monoco/core/injection.py +47 -44
  14. monoco/core/integrations.py +50 -35
  15. monoco/core/lsp.py +12 -1
  16. monoco/core/output.py +35 -16
  17. monoco/core/registry.py +3 -2
  18. monoco/core/setup.py +190 -124
  19. monoco/core/skills.py +121 -107
  20. monoco/core/state.py +12 -10
  21. monoco/core/sync.py +85 -56
  22. monoco/core/telemetry.py +10 -6
  23. monoco/core/workspace.py +26 -19
  24. monoco/daemon/app.py +123 -79
  25. monoco/daemon/commands.py +14 -13
  26. monoco/daemon/models.py +11 -3
  27. monoco/daemon/reproduce_stats.py +8 -8
  28. monoco/daemon/services.py +32 -33
  29. monoco/daemon/stats.py +59 -40
  30. monoco/features/config/commands.py +38 -25
  31. monoco/features/i18n/adapter.py +4 -5
  32. monoco/features/i18n/commands.py +83 -49
  33. monoco/features/i18n/core.py +94 -54
  34. monoco/features/issue/adapter.py +6 -7
  35. monoco/features/issue/commands.py +468 -272
  36. monoco/features/issue/core.py +419 -312
  37. monoco/features/issue/domain/lifecycle.py +33 -23
  38. monoco/features/issue/domain/models.py +71 -38
  39. monoco/features/issue/domain/parser.py +92 -69
  40. monoco/features/issue/domain/workspace.py +19 -16
  41. monoco/features/issue/engine/__init__.py +3 -3
  42. monoco/features/issue/engine/config.py +18 -25
  43. monoco/features/issue/engine/machine.py +72 -39
  44. monoco/features/issue/engine/models.py +4 -2
  45. monoco/features/issue/linter.py +287 -157
  46. monoco/features/issue/lsp/definition.py +26 -19
  47. monoco/features/issue/migration.py +45 -34
  48. monoco/features/issue/models.py +29 -13
  49. monoco/features/issue/monitor.py +24 -8
  50. monoco/features/issue/resources/en/SKILL.md +6 -2
  51. monoco/features/issue/validator.py +383 -208
  52. monoco/features/skills/__init__.py +0 -1
  53. monoco/features/skills/core.py +24 -18
  54. monoco/features/spike/adapter.py +4 -5
  55. monoco/features/spike/commands.py +51 -38
  56. monoco/features/spike/core.py +24 -16
  57. monoco/main.py +34 -21
  58. {monoco_toolkit-0.2.8.dist-info → monoco_toolkit-0.3.0.dist-info}/METADATA +1 -1
  59. monoco_toolkit-0.3.0.dist-info/RECORD +84 -0
  60. monoco_toolkit-0.2.8.dist-info/RECORD +0 -83
  61. {monoco_toolkit-0.2.8.dist-info → monoco_toolkit-0.3.0.dist-info}/WHEEL +0 -0
  62. {monoco_toolkit-0.2.8.dist-info → monoco_toolkit-0.3.0.dist-info}/entry_points.txt +0 -0
  63. {monoco_toolkit-0.2.8.dist-info → monoco_toolkit-0.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -1 +0,0 @@
1
- from .core import init
@@ -1,4 +1,3 @@
1
- import os
2
1
  import re
3
2
  from pathlib import Path
4
3
  from typing import Dict, List, Any
@@ -6,22 +5,23 @@ from rich.console import Console
6
5
 
7
6
  console = Console()
8
7
 
8
+
9
9
  def init(root: Path, resources: List[Dict[str, Any]]):
10
10
  """
11
11
  Initialize the Skills module.
12
-
12
+
13
13
  Args:
14
14
  root: Project root directory.
15
- resources: List of resource dicts from modules.
16
- Expected format:
15
+ resources: List of resource dicts from modules.
16
+ Expected format:
17
17
  {
18
18
  "skills": { "name": "content" },
19
- "prompts": { "name": "content" }
19
+ "prompts": { "name": "content" }
20
20
  }
21
21
  """
22
22
  skills_root = root / "Toolkit" / "skills"
23
23
  skills_root.mkdir(parents=True, exist_ok=True)
24
-
24
+
25
25
  # 1. Write Skills
26
26
  for res in resources:
27
27
  if "skills" in res:
@@ -30,7 +30,7 @@ def init(root: Path, resources: List[Dict[str, Any]]):
30
30
  target_dir.mkdir(exist_ok=True)
31
31
  target_file = target_dir / "SKILL.md"
32
32
  # Idempotency: Overwrite if content is different? Or just always overwrite?
33
- # User asked for "scaffold", implies creation.
33
+ # User asked for "scaffold", implies creation.
34
34
  # Let's overwrite to ensure extensive "Repair" capability.
35
35
  target_file.write_text(content, encoding="utf-8")
36
36
  console.print(f"[dim] - Scaffolding skill:[/dim] {name}")
@@ -38,20 +38,23 @@ def init(root: Path, resources: List[Dict[str, Any]]):
38
38
  # 2. Update Agent Docs
39
39
  update_agent_docs(root, resources)
40
40
 
41
+
41
42
  def update_agent_docs(root: Path, resources: List[Dict[str, Any]]):
42
43
  """
43
44
  Inject prompts into AGENTS.md, GEMINI.md, CLAUDE.md.
44
45
  """
45
46
  target_files = ["AGENTS.md", "GEMINI.md", "CLAUDE.md"]
46
-
47
+
47
48
  # Aggregate Prompts
48
- aggregated_prompt = "\n\n".join([
49
- res["prompts"][name]
50
- for res in resources
51
- if "prompts" in res
52
- for name in res["prompts"]
53
- ])
54
-
49
+ aggregated_prompt = "\n\n".join(
50
+ [
51
+ res["prompts"][name]
52
+ for res in resources
53
+ if "prompts" in res
54
+ for name in res["prompts"]
55
+ ]
56
+ )
57
+
55
58
  injection_content = f"""
56
59
  ## Monoco Toolkit
57
60
 
@@ -63,6 +66,7 @@ The following tools and skills are available in this environment.
63
66
  for filename in target_files:
64
67
  _inject_section(root / filename, injection_content)
65
68
 
69
+
66
70
  def _inject_section(file_path: Path, content: str):
67
71
  if not file_path.exists():
68
72
  # Create if not exists? User said "Edit AGENTS.md...", implies existence.
@@ -73,15 +77,17 @@ def _inject_section(file_path: Path, content: str):
73
77
  return
74
78
 
75
79
  original_content = file_path.read_text(encoding="utf-8")
76
-
80
+
77
81
  # Regex to find existing section
78
82
  # Matches ## Monoco Toolkit ... until next ## or End of String
79
83
  pattern = r"(## Monoco Toolkit.*?)(\n## |\Z)"
80
-
84
+
81
85
  # Check if section exists
82
86
  if re.search(pattern, original_content, re.DOTALL):
83
87
  # Replace
84
- new_content = re.sub(pattern, f"{content.strip()}\n\n\\2", original_content, flags=re.DOTALL)
88
+ new_content = re.sub(
89
+ pattern, f"{content.strip()}\n\n\\2", original_content, flags=re.DOTALL
90
+ )
85
91
  if new_content != original_content:
86
92
  file_path.write_text(new_content, encoding="utf-8")
87
93
  console.print(f"[green]✔[/green] Updated {file_path.name}")
@@ -3,6 +3,7 @@ from typing import Dict
3
3
  from monoco.core.feature import MonocoFeature, IntegrationData
4
4
  from monoco.features.spike import core
5
5
 
6
+
6
7
  class SpikeFeature(MonocoFeature):
7
8
  @property
8
9
  def name(self) -> str:
@@ -16,15 +17,13 @@ class SpikeFeature(MonocoFeature):
16
17
  # Determine language from config, default to 'en'
17
18
  lang = config.get("i18n", {}).get("source_lang", "en")
18
19
  base_dir = Path(__file__).parent / "resources"
19
-
20
+
20
21
  prompt_file = base_dir / lang / "AGENTS.md"
21
22
  if not prompt_file.exists():
22
23
  prompt_file = base_dir / "en" / "AGENTS.md"
23
-
24
+
24
25
  content = ""
25
26
  if prompt_file.exists():
26
27
  content = prompt_file.read_text(encoding="utf-8").strip()
27
28
 
28
- return IntegrationData(
29
- system_prompts={"Spike (Research)": content}
30
- )
29
+ return IntegrationData(system_prompts={"Spike (Research)": content})
@@ -1,7 +1,5 @@
1
1
  import typer
2
2
  from pathlib import Path
3
- from rich.console import Console
4
- from typing import Annotated
5
3
 
6
4
  from monoco.core.config import get_config
7
5
  from monoco.core.output import AgentOutput, OutputManager
@@ -9,6 +7,7 @@ from . import core
9
7
 
10
8
  app = typer.Typer(help="Spike & Repo Management.")
11
9
 
10
+
12
11
  @app.command("init")
13
12
  def init(
14
13
  json: AgentOutput = False,
@@ -17,17 +16,20 @@ def init(
17
16
  config = get_config()
18
17
  root_dir = Path(config.paths.root)
19
18
  spikes_dir_name = config.paths.spikes
20
-
19
+
21
20
  core.ensure_gitignore(root_dir, spikes_dir_name)
22
-
21
+
23
22
  # Create the directory
24
23
  (root_dir / spikes_dir_name).mkdir(exist_ok=True)
25
-
26
- OutputManager.print({
27
- "status": "initialized",
28
- "directory": spikes_dir_name,
29
- "gitignore_updated": True
30
- })
24
+
25
+ OutputManager.print(
26
+ {
27
+ "status": "initialized",
28
+ "directory": spikes_dir_name,
29
+ "gitignore_updated": True,
30
+ }
31
+ )
32
+
31
33
 
32
34
  @app.command("add")
33
35
  def add_repo(
@@ -37,54 +39,60 @@ def add_repo(
37
39
  """Add a new research repository."""
38
40
  config = get_config()
39
41
  root_dir = Path(config.paths.root)
40
-
42
+
41
43
  # Infer name from URL
42
44
  # e.g., https://github.com/foo/bar.git -> bar
43
45
  # e.g., git@github.com:foo/bar.git -> bar
44
46
  name = url.split("/")[-1]
45
47
  if name.endswith(".git"):
46
48
  name = name[:-4]
47
-
49
+
48
50
  core.update_config_repos(root_dir, name, url)
49
- OutputManager.print({
50
- "status": "added",
51
- "name": name,
52
- "url": url,
53
- "message": f"Run 'monoco spike sync' to download content."
54
- })
51
+ OutputManager.print(
52
+ {
53
+ "status": "added",
54
+ "name": name,
55
+ "url": url,
56
+ "message": "Run 'monoco spike sync' to download content.",
57
+ }
58
+ )
59
+
55
60
 
56
61
  @app.command("remove")
57
62
  def remove_repo(
58
63
  name: str = typer.Argument(..., help="Repository Name"),
59
- force: bool = typer.Option(False, "--force", "-f", help="Force delete physical directory without asking"),
64
+ force: bool = typer.Option(
65
+ False, "--force", "-f", help="Force delete physical directory without asking"
66
+ ),
60
67
  json: AgentOutput = False,
61
68
  ):
62
69
  """Remove a repository from configuration."""
63
70
  config = get_config()
64
71
  root_dir = Path(config.paths.root)
65
72
  spikes_dir = root_dir / config.paths.spikes
66
-
73
+
67
74
  if name not in config.project.spike_repos:
68
75
  OutputManager.error(f"Repo {name} not found in configuration.")
69
76
  return
70
77
 
71
78
  # Remove from config
72
79
  core.update_config_repos(root_dir, name, "", remove=True)
73
-
80
+
74
81
  target_path = spikes_dir / name
75
82
  deleted = False
76
83
  if target_path.exists():
77
- if force or typer.confirm(f"Do you want to delete the directory {target_path}?", default=False):
84
+ if force or typer.confirm(
85
+ f"Do you want to delete the directory {target_path}?", default=False
86
+ ):
78
87
  core.remove_repo_dir(spikes_dir, name)
79
88
  deleted = True
80
89
  else:
81
90
  deleted = False
82
-
83
- OutputManager.print({
84
- "status": "removed",
85
- "name": name,
86
- "directory_deleted": deleted
87
- })
91
+
92
+ OutputManager.print(
93
+ {"status": "removed", "name": name, "directory_deleted": deleted}
94
+ )
95
+
88
96
 
89
97
  @app.command("sync")
90
98
  def sync_repos(
@@ -93,28 +101,33 @@ def sync_repos(
93
101
  """Sync (Clone/Pull) all configured repositories."""
94
102
  # Force reload config to get latest updates
95
103
  config = get_config()
96
-
104
+
97
105
  root_dir = Path(config.paths.root)
98
106
  spikes_dir = root_dir / config.paths.spikes
99
107
  spikes_dir.mkdir(exist_ok=True)
100
-
108
+
101
109
  repos = config.project.spike_repos
102
-
110
+
103
111
  if not repos:
104
- OutputManager.print({"status": "empty", "message": "No repositories configured."}, title="Sync")
112
+ OutputManager.print(
113
+ {"status": "empty", "message": "No repositories configured."}, title="Sync"
114
+ )
105
115
  return
106
-
116
+
107
117
  results = []
108
-
118
+
109
119
  for name, url in repos.items():
110
120
  try:
111
121
  core.sync_repo(root_dir, spikes_dir, name, url)
112
122
  results.append({"name": name, "status": "synced", "url": url})
113
123
  except Exception as e:
114
- results.append({"name": name, "status": "failed", "error": str(e), "url": url})
115
-
124
+ results.append(
125
+ {"name": name, "status": "failed", "error": str(e), "url": url}
126
+ )
127
+
116
128
  OutputManager.print(results, title="Sync Results")
117
129
 
130
+
118
131
  @app.command("list")
119
132
  def list_repos(
120
133
  json: AgentOutput = False,
@@ -122,10 +135,10 @@ def list_repos(
122
135
  """List configured repositories."""
123
136
  config = get_config()
124
137
  repos = config.project.spike_repos
125
-
138
+
126
139
  if not repos:
127
140
  OutputManager.print([], title="Repositories")
128
141
  return
129
-
142
+
130
143
  data = [{"name": name, "url": url} for name, url in repos.items()]
131
144
  OutputManager.print(data, title="Repositories")
@@ -1,15 +1,15 @@
1
- import os
2
1
  import shutil
3
2
  import subprocess
4
3
 
5
4
  from pathlib import Path
6
- from typing import Dict, Optional, List, Any
5
+ from typing import List
7
6
  from rich.console import Console
8
7
 
9
- from monoco.core.config import get_config, load_raw_config, save_raw_config, ConfigScope
8
+ from monoco.core.config import load_raw_config, save_raw_config, ConfigScope
10
9
 
11
10
  console = Console()
12
11
 
12
+
13
13
  def run_git_command(cmd: List[str], cwd: Path) -> bool:
14
14
  """Run a git command in the specified directory."""
15
15
  try:
@@ -19,7 +19,7 @@ def run_git_command(cmd: List[str], cwd: Path) -> bool:
19
19
  check=True,
20
20
  stdout=subprocess.PIPE,
21
21
  stderr=subprocess.PIPE,
22
- text=True
22
+ text=True,
23
23
  )
24
24
  return True
25
25
  except subprocess.CalledProcessError as e:
@@ -29,25 +29,29 @@ def run_git_command(cmd: List[str], cwd: Path) -> bool:
29
29
  console.print("[red]Error:[/red] git command not found.")
30
30
  return False
31
31
 
32
- def update_config_repos(root: Path, repo_name: str, repo_url: str, remove: bool = False):
32
+
33
+ def update_config_repos(
34
+ root: Path, repo_name: str, repo_url: str, remove: bool = False
35
+ ):
33
36
  """Update the repos list in the config file."""
34
37
  # Use core config utils
35
38
  data = load_raw_config(ConfigScope.PROJECT, project_root=str(root))
36
-
39
+
37
40
  # Ensure structure exists
38
41
  if "project" not in data:
39
42
  data["project"] = {}
40
43
  if "spike_repos" not in data["project"]:
41
44
  data["project"]["spike_repos"] = {}
42
-
45
+
43
46
  if remove:
44
47
  if repo_name in data["project"]["spike_repos"]:
45
48
  del data["project"]["spike_repos"][repo_name]
46
49
  else:
47
50
  data["project"]["spike_repos"][repo_name] = repo_url
48
-
51
+
49
52
  save_raw_config(ConfigScope.PROJECT, data, project_root=str(root))
50
53
 
54
+
51
55
  def ensure_gitignore(root: Path, target_dir_name: str):
52
56
  """Ensure the target directory is in .gitignore."""
53
57
  gitignore = root / ".gitignore"
@@ -62,24 +66,28 @@ def ensure_gitignore(root: Path, target_dir_name: str):
62
66
  with open(gitignore, "a") as f:
63
67
  f.write(f"{prefix}{target_dir_name}/\n")
64
68
 
69
+
65
70
  def sync_repo(root: Path, spikes_dir: Path, name: str, url: str):
66
71
  """Clone or Pull a repo."""
67
72
  target_path = spikes_dir / name
68
-
73
+
69
74
  if target_path.exists() and (target_path / ".git").exists():
70
75
  console.print(f"Updating [bold]{name}[/bold]...")
71
76
  run_git_command(["git", "pull"], cwd=target_path)
72
77
  else:
73
- # If dir exists but not a git repo, warn or error?
78
+ # If dir exists but not a git repo, warn or error?
74
79
  # For safety, if non-empty and not git, skip or error.
75
80
  if target_path.exists() and any(target_path.iterdir()):
76
- console.print(f"[yellow]Skipping {name}:[/yellow] Directory exists and is not empty, but not a git repo.")
77
- return
81
+ console.print(
82
+ f"[yellow]Skipping {name}:[/yellow] Directory exists and is not empty, but not a git repo."
83
+ )
84
+ return
78
85
 
79
86
  console.print(f"Cloning [bold]{name}[/bold]...")
80
87
  target_path.mkdir(parents=True, exist_ok=True)
81
88
  run_git_command(["git", "clone", url, "."], cwd=target_path)
82
89
 
90
+
83
91
  def remove_repo_dir(spikes_dir: Path, name: str):
84
92
  """Physically remove the repo directory."""
85
93
  target_path = spikes_dir / name
@@ -87,6 +95,7 @@ def remove_repo_dir(spikes_dir: Path, name: str):
87
95
  if target_path.exists():
88
96
  shutil.rmtree(target_path)
89
97
 
98
+
90
99
  SKILL_CONTENT = """---
91
100
  name: git-repo-spike
92
101
  description: Manage external Git repositories as References in `.reference/`.
@@ -107,14 +116,13 @@ This skill normalizes how we introduce external code repositories.
107
116
  3. **Remove**: `monoco spike remove <name>`
108
117
  """
109
118
 
119
+
110
120
  def init(root: Path, spikes_dir_name: str):
111
121
  """Initialize Spike environment."""
112
122
  ensure_gitignore(root, spikes_dir_name)
113
123
  (root / spikes_dir_name).mkdir(exist_ok=True)
114
124
 
115
125
  return {
116
- "skills": {
117
- "git-repo-spike": SKILL_CONTENT
118
- },
119
- "prompts": {} # Handled by adapter via resource files
126
+ "skills": {"git-repo-spike": SKILL_CONTENT},
127
+ "prompts": {}, # Handled by adapter via resource files
120
128
  }
monoco/main.py CHANGED
@@ -7,7 +7,7 @@ app = typer.Typer(
7
7
  name="monoco",
8
8
  help="Monoco Agent Native Toolkit",
9
9
  add_completion=False,
10
- no_args_is_help=True
10
+ no_args_is_help=True,
11
11
  )
12
12
 
13
13
 
@@ -15,9 +15,9 @@ def version_callback(value: bool):
15
15
  if value:
16
16
  # Try to read from pyproject.toml first (for dev mode)
17
17
  from pathlib import Path
18
-
18
+
19
19
  version = "unknown"
20
-
20
+
21
21
  try:
22
22
  # Look for pyproject.toml relative to this file
23
23
  # monoco/main.py -> ../pyproject.toml
@@ -28,13 +28,14 @@ def version_callback(value: bool):
28
28
  if line.strip().startswith('version = "'):
29
29
  version = line.split('"')[1]
30
30
  break
31
-
31
+
32
32
  if version == "unknown":
33
33
  import importlib.metadata
34
+
34
35
  version = importlib.metadata.version("monoco-toolkit")
35
36
  except Exception:
36
- # Fallback
37
- pass
37
+ # Fallback
38
+ pass
38
39
 
39
40
  print(f"Monoco Toolkit v{version}")
40
41
  raise typer.Exit()
@@ -44,27 +45,32 @@ def version_callback(value: bool):
44
45
  def main(
45
46
  ctx: typer.Context,
46
47
  version: Optional[bool] = typer.Option(
47
- None, "--version", "-v", help="Show version and exit", callback=version_callback, is_eager=True
48
+ None,
49
+ "--version",
50
+ "-v",
51
+ help="Show version and exit",
52
+ callback=version_callback,
53
+ is_eager=True,
48
54
  ),
49
55
  root: Optional[str] = typer.Option(
50
56
  None, "--root", help="Explicitly specify the Monoco Workspace root directory."
51
- )
57
+ ),
52
58
  ):
53
59
  """
54
60
  Monoco Toolkit - The sensory and motor system for Monoco Agents.
55
61
  """
56
62
  # Capture command execution
57
63
  from monoco.core.telemetry import capture_event
64
+
58
65
  if ctx.invoked_subcommand:
59
66
  capture_event("cli_command_executed", {"command": ctx.invoked_subcommand})
60
67
 
61
68
  # Strict Workspace Resolution
62
69
  # Commands allowed to run without a workspace
63
- NO_WORKSPACE_COMMANDS = ["init", "clone"]
64
-
70
+ NO_WORKSPACE_COMMANDS = ["init", "clone"]
71
+
65
72
  # Initialize Config
66
73
  from monoco.core.config import get_config, find_monoco_root
67
- from pathlib import Path
68
74
 
69
75
  # If subcommand is not in whitelist, we enforce workspace
70
76
  require_workspace = False
@@ -74,7 +80,7 @@ def main(
74
80
  try:
75
81
  # We pass root if provided. If require_workspace is True, get_config will throw if not found.
76
82
  # Note: If root is None, it defaults to CWD in get_config.
77
-
83
+
78
84
  # Auto-discover root if not provided
79
85
  config_root = root
80
86
  if config_root is None:
@@ -82,25 +88,30 @@ def main(
82
88
  # Only use discovered root if it actually has .monoco
83
89
  if (discovered / ".monoco").exists():
84
90
  config_root = str(discovered)
85
-
91
+
86
92
  get_config(project_root=config_root, require_project=require_workspace)
87
93
  except FileNotFoundError as e:
88
94
  # Graceful exit for workspace errors
89
95
  from rich.console import Console
96
+
90
97
  console = Console()
91
98
  console.print(f"[bold red]Error:[/bold red] {e}")
92
- console.print(f"[yellow]Tip:[/yellow] Run this command in a Monoco Workspace root (containing .monoco), or use [bold]--root <path>[/bold].")
99
+ console.print(
100
+ "[yellow]Tip:[/yellow] Run this command in a Monoco Workspace root (containing .monoco), or use [bold]--root <path>[/bold]."
101
+ )
93
102
  raise typer.Exit(code=1)
94
103
 
104
+
95
105
  from monoco.core.setup import init_cli
106
+
96
107
  app.command(name="init")(init_cli)
97
108
 
98
109
  from monoco.core.sync import sync_command, uninstall_command
110
+
99
111
  app.command(name="sync")(sync_command)
100
112
  app.command(name="uninstall")(uninstall_command)
101
113
 
102
114
 
103
-
104
115
  @app.command()
105
116
  def info():
106
117
  """
@@ -108,7 +119,7 @@ def info():
108
119
  """
109
120
  from pydantic import BaseModel
110
121
  from monoco.core.config import get_config
111
-
122
+
112
123
  settings = get_config()
113
124
 
114
125
  class Status(BaseModel):
@@ -118,8 +129,9 @@ def info():
118
129
  project: str
119
130
 
120
131
  mode = "Agent (JSON)" if os.getenv("AGENT_FLAG") == "true" else "Human (Rich)"
121
-
132
+
122
133
  import importlib.metadata
134
+
123
135
  try:
124
136
  version = importlib.metadata.version("monoco-toolkit")
125
137
  except importlib.metadata.PackageNotFoundError:
@@ -129,14 +141,15 @@ def info():
129
141
  version=version,
130
142
  mode=mode,
131
143
  root=os.getcwd(),
132
- project=f"{settings.project.name} ({settings.project.key})"
144
+ project=f"{settings.project.name} ({settings.project.key})",
133
145
  )
134
-
146
+
135
147
  print_output(status, title="Monoco Toolkit Status")
136
-
148
+
137
149
  if mode == "Human (Rich)":
138
150
  print_output(settings, title="Current Configuration")
139
151
 
152
+
140
153
  # Register Feature Modules
141
154
  # Register Feature Modules
142
155
  from monoco.features.issue import commands as issue_cmd
@@ -154,8 +167,8 @@ app.add_typer(project_cmd.app, name="project", help="Manage projects")
154
167
  app.add_typer(workspace_cmd.app, name="workspace", help="Manage workspace")
155
168
 
156
169
 
157
-
158
170
  from monoco.daemon.commands import serve
171
+
159
172
  app.command(name="serve")(serve)
160
173
 
161
174
  if __name__ == "__main__":
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: monoco-toolkit
3
- Version: 0.2.8
3
+ Version: 0.3.0
4
4
  Summary: Agent Native Toolkit for Monoco - Task Management & Kanban for AI Agents
5
5
  Project-URL: Homepage, https://monoco.io
6
6
  Project-URL: Repository, https://github.com/IndenScale/Monoco