monoco-toolkit 0.1.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.
@@ -0,0 +1,56 @@
1
+ import logging
2
+ import signal
3
+ import sys
4
+ from typing import Optional
5
+ from pathlib import Path
6
+ from contextlib import asynccontextmanager
7
+ import uvicorn
8
+ from fastapi import FastAPI
9
+ from monoco.features.pty.router import router as pty_router, pty_manager
10
+
11
+ @asynccontextmanager
12
+ async def lifespan(app: FastAPI):
13
+ # Startup
14
+ yield
15
+ # Shutdown
16
+ logging.info("Shutting down PTY manager and cleaning up sessions...")
17
+ pty_manager.close_all_sessions()
18
+
19
+ def run_pty_server(host: str = "127.0.0.1", port: int = 3124, cwd: Optional[Path] = None):
20
+ """
21
+ Entry point for the 'monoco pty' command.
22
+ """
23
+ # Configure Logging
24
+ logging.basicConfig(level=logging.INFO)
25
+
26
+ # Register a manual signal handler to ensure we catch termination even if uvicorn misses it
27
+ # or if we are stuck before uvicorn starts.
28
+ def handle_signal(signum, frame):
29
+ logging.info(f"Received signal {signum}, initiating shutdown...")
30
+ # We rely on uvicorn to handle the actual exit loop for SIGINT/SIGTERM usually,
31
+ # but having this log confirms propagation.
32
+ # If uvicorn is running, it should catch this first.
33
+ # If not, we exit manually.
34
+ sys.exit(0)
35
+
36
+ # Note: Uvicorn overwrites SIGINT/SIGTERM handlers by default.
37
+ # relying on lifespan is the standard "Uvicorn way".
38
+
39
+ app = FastAPI(title="Monoco PTY Service", lifespan=lifespan)
40
+ app.include_router(pty_router)
41
+
42
+ # If cwd is provided, we might want to set it as current process CWD
43
+ # so that new sessions default to it.
44
+ if cwd and cwd.exists():
45
+ import os
46
+ os.chdir(cwd)
47
+ logging.info(f"PTY Service Root: {cwd}")
48
+
49
+ logging.info(f"Starting Monoco PTY Service on ws://{host}:{port}")
50
+ try:
51
+ uvicorn.run(app, host=host, port=port)
52
+ except KeyboardInterrupt:
53
+ pass
54
+ finally:
55
+ # Final safety net
56
+ pty_manager.close_all_sessions()
@@ -0,0 +1 @@
1
+ from .core import init
@@ -0,0 +1,96 @@
1
+ import os
2
+ import re
3
+ from pathlib import Path
4
+ from typing import Dict, List, Any
5
+ from rich.console import Console
6
+
7
+ console = Console()
8
+
9
+ def init(root: Path, resources: List[Dict[str, Any]]):
10
+ """
11
+ Initialize the Skills module.
12
+
13
+ Args:
14
+ root: Project root directory.
15
+ resources: List of resource dicts from modules.
16
+ Expected format:
17
+ {
18
+ "skills": { "name": "content" },
19
+ "prompts": { "name": "content" }
20
+ }
21
+ """
22
+ skills_root = root / "Toolkit" / "skills"
23
+ skills_root.mkdir(parents=True, exist_ok=True)
24
+
25
+ # 1. Write Skills
26
+ for res in resources:
27
+ if "skills" in res:
28
+ for name, content in res["skills"].items():
29
+ target_dir = skills_root / name
30
+ target_dir.mkdir(exist_ok=True)
31
+ target_file = target_dir / "SKILL.md"
32
+ # Idempotency: Overwrite if content is different? Or just always overwrite?
33
+ # User asked for "scaffold", implies creation.
34
+ # Let's overwrite to ensure extensive "Repair" capability.
35
+ target_file.write_text(content, encoding="utf-8")
36
+ console.print(f"[dim] - Scaffolding skill:[/dim] {name}")
37
+
38
+ # 2. Update Agent Docs
39
+ update_agent_docs(root, resources)
40
+
41
+ def update_agent_docs(root: Path, resources: List[Dict[str, Any]]):
42
+ """
43
+ Inject prompts into AGENTS.md, GEMINI.md, CLAUDE.md.
44
+ """
45
+ target_files = ["AGENTS.md", "GEMINI.md", "CLAUDE.md"]
46
+
47
+ # 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
+
55
+ injection_content = f"""
56
+ ## Monoco Toolkit
57
+
58
+ The following tools and skills are available in this environment.
59
+
60
+ {aggregated_prompt}
61
+ """
62
+
63
+ for filename in target_files:
64
+ _inject_section(root / filename, injection_content)
65
+
66
+ def _inject_section(file_path: Path, content: str):
67
+ if not file_path.exists():
68
+ # Create if not exists? User said "Edit AGENTS.md...", implies existence.
69
+ # But if we init in a fresh repo, maybe we should create them?
70
+ # Let's create if missing.
71
+ file_path.write_text(f"# Project Guidelines\n{content}", encoding="utf-8")
72
+ console.print(f"[green]✔[/green] Created {file_path.name}")
73
+ return
74
+
75
+ original_content = file_path.read_text(encoding="utf-8")
76
+
77
+ # Regex to find existing section
78
+ # Matches ## Monoco Toolkit ... until next ## or End of String
79
+ pattern = r"(## Monoco Toolkit.*?)(\n## |\Z)"
80
+
81
+ # Check if section exists
82
+ if re.search(pattern, original_content, re.DOTALL):
83
+ # Replace
84
+ new_content = re.sub(pattern, f"{content.strip()}\n\n\\2", original_content, flags=re.DOTALL)
85
+ if new_content != original_content:
86
+ file_path.write_text(new_content, encoding="utf-8")
87
+ console.print(f"[green]✔[/green] Updated {file_path.name}")
88
+ else:
89
+ console.print(f"[dim] - {file_path.name} is up to date.[/dim]")
90
+ else:
91
+ # Append
92
+ with open(file_path, "a", encoding="utf-8") as f:
93
+ if not original_content.endswith("\n"):
94
+ f.write("\n")
95
+ f.write(content)
96
+ console.print(f"[green]✔[/green] Appended to {file_path.name}")
@@ -0,0 +1,110 @@
1
+ import typer
2
+ from pathlib import Path
3
+ from rich.console import Console
4
+
5
+ from monoco.core.config import get_config
6
+ from . import core
7
+
8
+ app = typer.Typer(help="Spike & Repo Management.")
9
+ console = Console()
10
+
11
+ @app.command("init")
12
+ def init():
13
+ """Initialize the Spike environment (gitignore setup)."""
14
+ config = get_config()
15
+ root_dir = Path(config.paths.root)
16
+ spikes_dir_name = config.paths.spikes
17
+
18
+ core.ensure_gitignore(root_dir, spikes_dir_name)
19
+
20
+ # Create the directory
21
+ (root_dir / spikes_dir_name).mkdir(exist_ok=True)
22
+
23
+ console.print(f"[green]✔[/green] Initialized Spike environment. Added '{spikes_dir_name}/' to .gitignore.")
24
+
25
+ @app.command("add")
26
+ def add_repo(
27
+ url: str = typer.Argument(..., help="Git Repository URL"),
28
+ ):
29
+ """Add a new research repository."""
30
+ config = get_config()
31
+ root_dir = Path(config.paths.root)
32
+
33
+ # Infer name from URL
34
+ # e.g., https://github.com/foo/bar.git -> bar
35
+ # e.g., git@github.com:foo/bar.git -> bar
36
+ name = url.split("/")[-1]
37
+ if name.endswith(".git"):
38
+ name = name[:-4]
39
+
40
+ core.update_config_repos(root_dir, name, url)
41
+ console.print(f"[green]✔[/green] Added repo [bold]{name}[/bold] ({url}) to configuration.")
42
+ console.print("Run [bold]monoco spike sync[/bold] to download content.")
43
+
44
+ @app.command("remove")
45
+ def remove_repo(
46
+ name: str = typer.Argument(..., help="Repository Name"),
47
+ force: bool = typer.Option(False, "--force", "-f", help="Force delete physical directory without asking"),
48
+ ):
49
+ """Remove a repository from configuration."""
50
+ config = get_config()
51
+ root_dir = Path(config.paths.root)
52
+ spikes_dir = root_dir / config.paths.spikes
53
+
54
+ if name not in config.project.spike_repos:
55
+ console.print(f"[yellow]![/yellow] Repo [bold]{name}[/bold] not found in configuration.")
56
+ return
57
+
58
+ # Remove from config
59
+ core.update_config_repos(root_dir, name, "", remove=True)
60
+ console.print(f"[green]✔[/green] Removed [bold]{name}[/bold] from configuration.")
61
+
62
+ target_path = spikes_dir / name
63
+ if target_path.exists():
64
+ if force or typer.confirm(f"Do you want to delete the directory {target_path}?", default=False):
65
+ core.remove_repo_dir(spikes_dir, name)
66
+ console.print(f"[gray]✔[/gray] Deleted directory {target_path}.")
67
+ else:
68
+ console.print(f"[gray]ℹ[/gray] Directory {target_path} kept.")
69
+
70
+ @app.command("sync")
71
+ def sync_repos():
72
+ """Sync (Clone/Pull) all configured repositories."""
73
+ # Force reload config to get latest updates
74
+ config = get_config()
75
+ # Note: get_config is a singleton, so for 'add' then 'sync' in same process,
76
+ # we rely on 'add' writing to disk and us reading from memory?
77
+ # Actually, if we run standard CLI "monoco spike add" then "monoco spike sync",
78
+ # they are separate processes, so config loads fresh.
79
+
80
+ root_dir = Path(config.paths.root)
81
+ spikes_dir = root_dir / config.paths.spikes
82
+ spikes_dir.mkdir(exist_ok=True)
83
+
84
+ repos = config.project.spike_repos
85
+
86
+ if not repos:
87
+ console.print("[yellow]No repositories configured.[/yellow] Use 'monoco spike add <url>' first.")
88
+ return
89
+
90
+ console.print(f"Syncing {len(repos)} repositories...")
91
+
92
+ for name, url in repos.items():
93
+ core.sync_repo(root_dir, spikes_dir, name, url)
94
+
95
+ console.print("[green]✔[/green] Sync complete.")
96
+
97
+ # Alias for list (showing configured repos) could be useful but not strictly asked for.
98
+ # Let's add a simple list command to see what we have.
99
+ @app.command("list")
100
+ def list_repos():
101
+ """List configured repositories."""
102
+ config = get_config()
103
+ repos = config.project.spike_repos
104
+
105
+ if not repos:
106
+ console.print("[yellow]No repositories configured.[/yellow]")
107
+ return
108
+
109
+ for name, url in repos.items():
110
+ console.print(f"- [bold]{name}[/bold]: {url}")
@@ -0,0 +1,154 @@
1
+ import os
2
+ import shutil
3
+ import subprocess
4
+ import yaml
5
+ from pathlib import Path
6
+ from typing import Dict, Optional, List, Any
7
+ from rich.console import Console
8
+
9
+ from monoco.core.config import get_config
10
+
11
+ console = Console()
12
+
13
+ def run_git_command(cmd: List[str], cwd: Path) -> bool:
14
+ """Run a git command in the specified directory."""
15
+ try:
16
+ subprocess.run(
17
+ cmd,
18
+ cwd=cwd,
19
+ check=True,
20
+ stdout=subprocess.PIPE,
21
+ stderr=subprocess.PIPE,
22
+ text=True
23
+ )
24
+ return True
25
+ except subprocess.CalledProcessError as e:
26
+ console.print(f"[red]Git Error:[/red] {' '.join(cmd)}\n{e.stderr}")
27
+ return False
28
+ except FileNotFoundError:
29
+ console.print("[red]Error:[/red] git command not found.")
30
+ return False
31
+
32
+ def get_config_file_path(root: Path) -> Path:
33
+ """Determine the config file to update."""
34
+ # Priority 1: .monoco/config.yaml
35
+ hidden = root / ".monoco" / "config.yaml"
36
+ if hidden.exists():
37
+ return hidden
38
+
39
+ # Priority 2: monoco.yaml
40
+ visible = root / "monoco.yaml"
41
+ if visible.exists():
42
+ return visible
43
+
44
+ # Default to .monoco/config.yaml for new files
45
+ hidden.parent.mkdir(exist_ok=True)
46
+ return hidden
47
+
48
+ def update_config_repos(root: Path, repo_name: str, repo_url: str, remove: bool = False):
49
+ """Update the repos list in the config file."""
50
+ config_path = get_config_file_path(root)
51
+
52
+ data = {}
53
+ if config_path.exists():
54
+ try:
55
+ with open(config_path, "r") as f:
56
+ data = yaml.safe_load(f) or {}
57
+ except Exception:
58
+ data = {}
59
+
60
+ # Ensure structure exists
61
+ if "project" not in data:
62
+ data["project"] = {}
63
+ if "spike_repos" not in data["project"]:
64
+ data["project"]["spike_repos"] = {}
65
+
66
+ if remove:
67
+ if repo_name in data["project"]["spike_repos"]:
68
+ del data["project"]["spike_repos"][repo_name]
69
+ else:
70
+ data["project"]["spike_repos"][repo_name] = repo_url
71
+
72
+ with open(config_path, "w") as f:
73
+ yaml.dump(data, f, sort_keys=False, default_flow_style=False)
74
+
75
+ def ensure_gitignore(root: Path, target_dir_name: str):
76
+ """Ensure the target directory is in .gitignore."""
77
+ gitignore = root / ".gitignore"
78
+ if not gitignore.exists():
79
+ gitignore.write_text(f"{target_dir_name}/\n")
80
+ return
81
+
82
+ content = gitignore.read_text()
83
+ if f"{target_dir_name}/" not in content and f"{target_dir_name}" not in content:
84
+ # Avoid redundant newlines if file ends with one
85
+ prefix = "\n" if content and not content.endswith("\n") else ""
86
+ with open(gitignore, "a") as f:
87
+ f.write(f"{prefix}{target_dir_name}/\n")
88
+
89
+ def sync_repo(root: Path, spikes_dir: Path, name: str, url: str):
90
+ """Clone or Pull a repo."""
91
+ target_path = spikes_dir / name
92
+
93
+ if target_path.exists() and (target_path / ".git").exists():
94
+ console.print(f"Updating [bold]{name}[/bold]...")
95
+ run_git_command(["git", "pull"], cwd=target_path)
96
+ else:
97
+ # If dir exists but not a git repo, warn or error?
98
+ # For safety, if non-empty and not git, skip or error.
99
+ if target_path.exists() and any(target_path.iterdir()):
100
+ console.print(f"[yellow]Skipping {name}:[/yellow] Directory exists and is not empty, but not a git repo.")
101
+ return
102
+
103
+ console.print(f"Cloning [bold]{name}[/bold]...")
104
+ target_path.mkdir(parents=True, exist_ok=True)
105
+ run_git_command(["git", "clone", url, "."], cwd=target_path)
106
+
107
+ def remove_repo_dir(spikes_dir: Path, name: str):
108
+ """Physically remove the repo directory."""
109
+ target_path = spikes_dir / name
110
+
111
+ if target_path.exists():
112
+ shutil.rmtree(target_path)
113
+
114
+ SKILL_CONTENT = """---
115
+ name: git-repo-spike
116
+ description: Manage external Git repositories as References in `.reference/`.
117
+ ---
118
+
119
+ # Git Repo Spike (Reference Management)
120
+
121
+ This skill normalizes how we introduce external code repositories.
122
+
123
+ ## Core Principles
124
+ 1. **Read-Only**: Code in `.reference/` is for reference only.
125
+ 2. **Isolation**: All external repos sit within `.reference/`.
126
+ 3. **VCS Hygiene**: `.reference/` is gitignored. We track the intent to clone, not the files.
127
+
128
+ ## Workflow
129
+ 1. **Add**: `monoco spike add <url>`
130
+ 2. **Sync**: `monoco spike sync` (Clones/Pulls all repos)
131
+ 3. **Remove**: `monoco spike remove <name>`
132
+ """
133
+
134
+ PROMPT_CONTENT = """### Spike (Research)
135
+ Manage external reference repositories.
136
+ - **Add Repo**: `monoco spike add <url>` (Available in `.reference/<name>` for reading)
137
+ - **Sync**: `monoco spike sync` (Run to download content)
138
+ - **Constraint**: Never edit files in `.reference/`. Treat them as read-only external knowledge."""
139
+
140
+ def init(root: Path, spikes_dir_name: str):
141
+ """Initialize Spike environment."""
142
+ ensure_gitignore(root, spikes_dir_name)
143
+ (root / spikes_dir_name).mkdir(exist_ok=True)
144
+
145
+ def get_resources() -> Dict[str, Any]:
146
+ return {
147
+ "skills": {
148
+ "git-repo-spike": SKILL_CONTENT
149
+ },
150
+ "prompts": {
151
+ "spike": PROMPT_CONTENT
152
+ }
153
+ }
154
+
monoco/main.py ADDED
@@ -0,0 +1,110 @@
1
+ import os
2
+ import typer
3
+ from typing import Optional
4
+ from monoco.core.output import print_output
5
+
6
+ app = typer.Typer(
7
+ name="monoco",
8
+ help="Monoco Agent Native Toolkit",
9
+ add_completion=False,
10
+ no_args_is_help=True
11
+ )
12
+
13
+
14
+ def version_callback(value: bool):
15
+ if value:
16
+ import importlib.metadata
17
+ try:
18
+ version = importlib.metadata.version("monoco-toolkit")
19
+ except importlib.metadata.PackageNotFoundError:
20
+ version = "unknown"
21
+ print(f"Monoco Toolkit v{version}")
22
+ raise typer.Exit()
23
+
24
+
25
+ @app.callback()
26
+ def main(
27
+ ctx: typer.Context,
28
+ version: Optional[bool] = typer.Option(
29
+ None, "--version", "-v", help="Show version and exit", callback=version_callback, is_eager=True
30
+ ),
31
+ ):
32
+ """
33
+ Monoco Toolkit - The sensory and motor system for Monoco Agents.
34
+ """
35
+ # Capture command execution
36
+ from monoco.core.telemetry import capture_event
37
+ if ctx.invoked_subcommand:
38
+ capture_event("cli_command_executed", {"command": ctx.invoked_subcommand})
39
+
40
+ from monoco.core.setup import init_cli
41
+ app.command(name="init")(init_cli)
42
+
43
+ @app.command()
44
+ def info():
45
+ """
46
+ Show toolkit information and current mode.
47
+ """
48
+ from pydantic import BaseModel
49
+ from monoco.core.config import get_config
50
+
51
+ settings = get_config()
52
+
53
+ class Status(BaseModel):
54
+ version: str
55
+ mode: str
56
+ root: str
57
+ project: str
58
+
59
+ mode = "Agent (JSON)" if os.getenv("AGENT_FLAG") == "true" else "Human (Rich)"
60
+
61
+ import importlib.metadata
62
+ try:
63
+ version = importlib.metadata.version("monoco-toolkit")
64
+ except importlib.metadata.PackageNotFoundError:
65
+ version = "unknown"
66
+
67
+ status = Status(
68
+ version=version,
69
+ mode=mode,
70
+ root=os.getcwd(),
71
+ project=f"{settings.project.name} ({settings.project.key})"
72
+ )
73
+
74
+ print_output(status, title="Monoco Toolkit Status")
75
+
76
+ if mode == "Human (Rich)":
77
+ print_output(settings, title="Current Configuration")
78
+
79
+ # Register Feature Modules
80
+ # Register Feature Modules
81
+ from monoco.features.issue import commands as issue_cmd
82
+ from monoco.features.spike import commands as spike_cmd
83
+ from monoco.features.i18n import commands as i18n_cmd
84
+ from monoco.features.config import commands as config_cmd
85
+
86
+ app.add_typer(issue_cmd.app, name="issue", help="Manage development issues")
87
+ app.add_typer(spike_cmd.app, name="spike", help="Manage research spikes")
88
+ app.add_typer(i18n_cmd.app, name="i18n", help="Manage documentation i18n")
89
+ app.add_typer(config_cmd.app, name="config", help="Manage configuration")
90
+
91
+ from monoco.daemon.commands import serve
92
+ app.command(name="serve")(serve)
93
+
94
+ @app.command()
95
+ def pty(
96
+ host: str = "127.0.0.1",
97
+ port: int = 3124,
98
+ cwd: Optional[str] = None
99
+ ):
100
+ """
101
+ Start the Monoco PTY Daemon (WebSocket).
102
+ """
103
+ from monoco.features.pty.server import run_pty_server
104
+ from pathlib import Path
105
+
106
+ path = Path(cwd) if cwd else None
107
+ run_pty_server(host, port, path)
108
+
109
+ if __name__ == "__main__":
110
+ app()
@@ -0,0 +1,93 @@
1
+ Metadata-Version: 2.4
2
+ Name: monoco-toolkit
3
+ Version: 0.1.5
4
+ Summary: Agent Native Toolkit for Monoco - Task Management & Kanban for AI Agents
5
+ Project-URL: Homepage, https://monoco.io
6
+ Project-URL: Repository, https://github.com/IndenScale/Monoco
7
+ Project-URL: Documentation, https://monoco.io/docs
8
+ Project-URL: Issues, https://github.com/IndenScale/Monoco/issues
9
+ Author-email: Monoco Team <dev@monoco.io>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: agent-native,ai-agents,cli,kanban,monoco,task-management,workflow
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Office/Business :: Groupware
21
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
22
+ Classifier: Topic :: Software Development :: Quality Assurance
23
+ Requires-Python: >=3.10
24
+ Requires-Dist: fastapi>=0.100.0
25
+ Requires-Dist: httpx>=0.28.1
26
+ Requires-Dist: prompt-toolkit>=3.0.0
27
+ Requires-Dist: pydantic>=2.0.0
28
+ Requires-Dist: pyyaml>=6.0
29
+ Requires-Dist: rich>=13.0.0
30
+ Requires-Dist: sse-starlette>=1.6.0
31
+ Requires-Dist: typer[all]>=0.9.0
32
+ Requires-Dist: uvicorn[standard]>=0.20.0
33
+ Requires-Dist: watchdog>=6.0.0
34
+ Description-Content-Type: text/markdown
35
+
36
+ # Monoco: Harnessing AI Agents
37
+
38
+ > **The control interface between raw AI velocity and human information bandwidth.**
39
+
40
+ Production in the LLM era is exploding along a vertical curve. A single AI agent can work 24/7, generating massive amounts of intermediate data that far exceeds the biological information bandwidth of a human supervisor. When one agent becomes a hundred, the bottleneck is no longer "intelligence"—it is "command and control."
41
+
42
+ **Monoco is the Cockpit.**
43
+
44
+ It doesn't just "run" agents; it "encapsulates" them. It provides a deterministic barrier between the chaotic, raw execution power of LLMs and the rigorous, finite decision bandwidth of human engineers. It ensures that every agentic action eventually collapses into the outcome you intended.
45
+
46
+ ## Workflow: Plan - Execute - Review - Archive
47
+
48
+ Monoco channels agent execution into a clear cycle:
49
+
50
+ 1. **Plan**: Decompose complex missions through **Project → Epic → Feature** hierarchies into executable atomic units.
51
+ 2. **Execute**: Agents work autonomously based on acceptance criteria defined in Issues, with all intermediate states persisted as structured files.
52
+ 3. **Review**: Humans monitor progress through the Kanban dashboard, intervening only at critical decision points.
53
+ 4. **Archive**: Completed tasks automatically transition to archived states, forming a traceable project history.
54
+
55
+ ## The Control Matrix
56
+
57
+ - **Task Anchors (Issues)**: Define missions via structured files, setting clear boundaries and acceptance criteria for agents.
58
+ - **Deterministic Interface (CLI)**: Acts as a sensory extension for LLMs, providing them with structured perception of project state and eliminating hallucinated guesses.
59
+ - **Mission Dashboard (Kanban)**: A high-fidelity visual console that allows humans to audit tasks and transition states with minimal cognitive load.
60
+
61
+ ## Quick Start
62
+
63
+ ### 1. Install the Control Suite
64
+
65
+ ```bash
66
+ pip install monoco-toolkit
67
+ ```
68
+
69
+ ### 2. Initialize the Workflow
70
+
71
+ ```bash
72
+ monoco init
73
+ ```
74
+
75
+ ### 3. Take Control
76
+
77
+ Start the backend control hub:
78
+
79
+ ```bash
80
+ monoco serve
81
+ ```
82
+
83
+ Then, launch the visual mission dashboard from anywhere:
84
+
85
+ ```bash
86
+ npx @monoco-io/kanban
87
+ ```
88
+
89
+ Visit `http://localhost:3123` (or the URL displayed in your terminal) to enter your cockpit.
90
+
91
+ ---
92
+
93
+ _"Cars are made to drive, not to fix."_
@@ -0,0 +1,36 @@
1
+ monoco/main.py,sha256=_16blpwjqnSsmahwj9lJ6Cgm_6OVYw9BsdORepY3zX8,3058
2
+ monoco/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ monoco/core/config.py,sha256=oiWB4bYkLGNhV9J3nGHdYjnVIux0gi8u9oYEpcvanpA,4768
4
+ monoco/core/git.py,sha256=Qy5VjCKe0Y1y0rjqYULxT_viS7S4phTljf8hkd9DA8Q,6424
5
+ monoco/core/output.py,sha256=CK8efvj0Q-pWrcJMdXwbuCyfsykWZ_pen9YWuDsivXQ,3192
6
+ monoco/core/setup.py,sha256=qbMh6LV5wvXNYwquzxpmf3JZAoNDcwLClnNZ2QXPajs,8406
7
+ monoco/core/telemetry.py,sha256=DZQGOhvpe0XL34RCDaTZEUhmkD4abBTZumZJQlALzpY,2923
8
+ monoco/core/workspace.py,sha256=pFMC2culomxOF6Q1XqpEHCB8WjEEPBxKObUsOVpIG-E,1306
9
+ monoco/daemon/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ monoco/daemon/app.py,sha256=RdNVjaB1JJUJ3_qCfKzBWyTRoNZV10KsBxoMHG--To8,12819
11
+ monoco/daemon/commands.py,sha256=dN4D8ca0vPjj0WyjCSs8senneta1afm_bnNYv_kmGlU,1125
12
+ monoco/daemon/models.py,sha256=DqhR8_t0Oz1Tptqkw9KGZMgvPyL8mvb01aFdbmKqi4M,812
13
+ monoco/daemon/reproduce_stats.py,sha256=Q_zAj0Yj8l-77QDdtsLz1kWr68HeO7f1T6xC6VP43Vo,1261
14
+ monoco/daemon/services.py,sha256=ExSPd2J4QtzrHPG_sYjNMDtA3p_3xmQXo_gfL-2oIUY,9151
15
+ monoco/daemon/stats.py,sha256=r-L0k6CdxkAkwLZV3V-jW7PldB9S3uNklQGLCEKA3Sc,4563
16
+ monoco/features/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ monoco/features/config/commands.py,sha256=BySoGkIYia6RTsouDREAyjLV14n-_sZnInzPDlPdYCo,2139
18
+ monoco/features/i18n/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ monoco/features/i18n/commands.py,sha256=M_T8Ddw54p42wsZIowFjBq72mXKLsppzBRcHUByfhls,4816
20
+ monoco/features/i18n/core.py,sha256=recjfNhJA2xdqFUMIivZ2omQZEzbgXJ1QvhjmvEDj24,5957
21
+ monoco/features/issue/commands.py,sha256=w89KS19pJfMRzbIMIECQatalvPe4Q5rT8vSPfUnRQik,29448
22
+ monoco/features/issue/core.py,sha256=iX-p7fTQUThKcAYOzlbBHldqG5naJV012cBvIxYIeFA,43778
23
+ monoco/features/issue/linter.py,sha256=ZMNpp_0ehbzBMYROfPtCr4O4JL8mhdO9L0F3EAi96lE,7657
24
+ monoco/features/issue/models.py,sha256=sepGxdgvRFRSc4tyvcUB9oXFBkDyS9_g0bGZEaE8Eq8,4970
25
+ monoco/features/pty/core.py,sha256=eM1EvHQrgExSnatO15pyfhh1VZoz0BBTfNYdXqG8HZ8,5711
26
+ monoco/features/pty/router.py,sha256=7h80EPpOuE7hX5ifkxkzffcLZGecd5X8OmNvOji5ToI,5078
27
+ monoco/features/pty/server.py,sha256=kw2csMZ_R4_Xx6ta2dbznWtgNZLfrWOAkMp8NjlZYBc,1920
28
+ monoco/features/skills/__init__.py,sha256=L8YNGPWyyFWq5WqNossfeB0AKHJF_omrn1VzJBrRFcM,23
29
+ monoco/features/skills/core.py,sha256=mpd0Cq-k2MvHRTPq9saFvZgYXUBGJ9pnK5lUmzUfZbY,3418
30
+ monoco/features/spike/commands.py,sha256=BpwYYIpihmezJACOxgQojsCM7RwXqL0_EB6wCl--Mm8,3947
31
+ monoco/features/spike/core.py,sha256=FSlO3Lhz49_nyFp68TpxBdkFKksShz5S33Qxh74ZFpY,5150
32
+ monoco_toolkit-0.1.5.dist-info/METADATA,sha256=1j6huqrvTPN4rMnw_rdB8RweTuvf85jrlCrgP2HpKTY,3743
33
+ monoco_toolkit-0.1.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
34
+ monoco_toolkit-0.1.5.dist-info/entry_points.txt,sha256=iYj7FWYBdtClU15-Du1skqD0s6SFSIhJvxJ29VWp8ng,43
35
+ monoco_toolkit-0.1.5.dist-info/licenses/LICENSE,sha256=ACAGGjV6aod4eIlVUTx1q9PZbnZGN5bBwkSs9RHj83s,1071
36
+ monoco_toolkit-0.1.5.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ monoco = monoco.main:app