velune-cli 1.0.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.
- velune/__init__.py +5 -0
- velune/__main__.py +6 -0
- velune/cli/__init__.py +5 -0
- velune/cli/app.py +212 -0
- velune/cli/autocomplete.py +76 -0
- velune/cli/banner.py +98 -0
- velune/cli/commands/__init__.py +32 -0
- velune/cli/commands/ask.py +149 -0
- velune/cli/commands/base.py +16 -0
- velune/cli/commands/chat.py +188 -0
- velune/cli/commands/config.py +182 -0
- velune/cli/commands/daemon.py +85 -0
- velune/cli/commands/doctor.py +373 -0
- velune/cli/commands/init.py +160 -0
- velune/cli/commands/mcp.py +80 -0
- velune/cli/commands/memory.py +269 -0
- velune/cli/commands/models.py +462 -0
- velune/cli/commands/preflight.py +95 -0
- velune/cli/commands/run.py +171 -0
- velune/cli/commands/setup.py +182 -0
- velune/cli/commands/workspace.py +217 -0
- velune/cli/context.py +37 -0
- velune/cli/councilmodel_ui.py +171 -0
- velune/cli/display/council_view.py +240 -0
- velune/cli/display/memory_view.py +93 -0
- velune/cli/display/panels.py +35 -0
- velune/cli/display/progress.py +25 -0
- velune/cli/display/themes.py +21 -0
- velune/cli/main.py +15 -0
- velune/cli/model_selector.py +44 -0
- velune/cli/modes.py +86 -0
- velune/cli/pull_ui.py +118 -0
- velune/cli/registry.py +81 -0
- velune/cli/repl.py +1178 -0
- velune/cli/session_manager.py +69 -0
- velune/cli/slash_commands.py +37 -0
- velune/cognition/__init__.py +19 -0
- velune/cognition/arbitrator.py +216 -0
- velune/cognition/architecture.py +398 -0
- velune/cognition/council/__init__.py +47 -0
- velune/cognition/council/base.py +216 -0
- velune/cognition/council/challenger.py +70 -0
- velune/cognition/council/coder.py +79 -0
- velune/cognition/council/critic_agent.py +39 -0
- velune/cognition/council/critic_configs.py +111 -0
- velune/cognition/council/critics.py +41 -0
- velune/cognition/council/debate.py +44 -0
- velune/cognition/council/factory.py +140 -0
- velune/cognition/council/messages.py +53 -0
- velune/cognition/council/planner.py +119 -0
- velune/cognition/council/reviewer.py +72 -0
- velune/cognition/council/synthesizer.py +67 -0
- velune/cognition/council/tiers.py +181 -0
- velune/cognition/firewall.py +256 -0
- velune/cognition/module.py +38 -0
- velune/cognition/orchestrator.py +886 -0
- velune/cognition/personality.py +236 -0
- velune/cognition/style_resolver.py +62 -0
- velune/cognition/verification.py +201 -0
- velune/context/__init__.py +11 -0
- velune/context/extractive.py +94 -0
- velune/context/window.py +62 -0
- velune/core/__init__.py +89 -0
- velune/core/background.py +5 -0
- velune/core/config/__init__.py +37 -0
- velune/core/errors/__init__.py +53 -0
- velune/core/errors/execution.py +26 -0
- velune/core/errors/memory.py +21 -0
- velune/core/errors/orchestration.py +26 -0
- velune/core/errors/provider.py +31 -0
- velune/core/event_loop.py +30 -0
- velune/core/logging.py +83 -0
- velune/core/runtime.py +106 -0
- velune/core/task_registry.py +120 -0
- velune/core/trace.py +80 -0
- velune/core/types/__init__.py +48 -0
- velune/core/types/agent.py +49 -0
- velune/core/types/context.py +39 -0
- velune/core/types/inference.py +35 -0
- velune/core/types/memory.py +39 -0
- velune/core/types/model.py +64 -0
- velune/core/types/provider.py +35 -0
- velune/core/types/repository.py +35 -0
- velune/core/types/task.py +56 -0
- velune/core/types/workspace.py +28 -0
- velune/daemon/client.py +13 -0
- velune/daemon/server.py +115 -0
- velune/daemon/transport.py +169 -0
- velune/events.py +194 -0
- velune/execution/__init__.py +22 -0
- velune/execution/benchmarker.py +311 -0
- velune/execution/cancellation.py +53 -0
- velune/execution/checkpointer.py +128 -0
- velune/execution/command_spec.py +140 -0
- velune/execution/diff_preview.py +172 -0
- velune/execution/executor.py +173 -0
- velune/execution/module.py +16 -0
- velune/execution/multi_diff.py +70 -0
- velune/execution/path_guard.py +19 -0
- velune/execution/planner.py +91 -0
- velune/execution/rollback.py +80 -0
- velune/execution/sandbox.py +257 -0
- velune/execution/validator.py +113 -0
- velune/hardware/__init__.py +1 -0
- velune/hardware/detector.py +162 -0
- velune/kernel/__init__.py +58 -0
- velune/kernel/bootstrap.py +107 -0
- velune/kernel/config.py +252 -0
- velune/kernel/health.py +54 -0
- velune/kernel/lifecycle.py +102 -0
- velune/kernel/module.py +15 -0
- velune/kernel/modules.py +23 -0
- velune/kernel/registry.py +93 -0
- velune/kernel/schemas.py +28 -0
- velune/main.py +9 -0
- velune/mcp/__init__.py +9 -0
- velune/mcp/client.py +113 -0
- velune/mcp/config.py +19 -0
- velune/mcp/server.py +90 -0
- velune/memory/__init__.py +28 -0
- velune/memory/lifecycle.py +154 -0
- velune/memory/module.py +94 -0
- velune/memory/prioritizer.py +65 -0
- velune/memory/storage/sqlite_manager.py +368 -0
- velune/memory/tiers/episodic.py +156 -0
- velune/memory/tiers/graph.py +282 -0
- velune/memory/tiers/lineage.py +367 -0
- velune/memory/tiers/semantic.py +198 -0
- velune/memory/tiers/working.py +165 -0
- velune/models/__init__.py +16 -0
- velune/models/module.py +18 -0
- velune/models/probes.py +182 -0
- velune/models/profile_cache.py +82 -0
- velune/models/profiler.py +105 -0
- velune/models/registry.py +201 -0
- velune/models/scorer.py +225 -0
- velune/models/specializations.py +196 -0
- velune/orchestration/__init__.py +15 -0
- velune/orchestration/module.py +14 -0
- velune/orchestration/role_assignments.py +78 -0
- velune/orchestration/schemas.py +99 -0
- velune/plugins/__init__.py +13 -0
- velune/plugins/hooks.py +49 -0
- velune/plugins/loader.py +95 -0
- velune/plugins/registry.py +54 -0
- velune/plugins/schemas.py +19 -0
- velune/providers/__init__.py +18 -0
- velune/providers/adapters/anthropic.py +231 -0
- velune/providers/adapters/fireworks.py +115 -0
- velune/providers/adapters/google.py +234 -0
- velune/providers/adapters/groq.py +151 -0
- velune/providers/adapters/huggingface.py +203 -0
- velune/providers/adapters/llamacpp.py +202 -0
- velune/providers/adapters/lmstudio.py +173 -0
- velune/providers/adapters/ollama.py +186 -0
- velune/providers/adapters/openai.py +207 -0
- velune/providers/adapters/openrouter.py +81 -0
- velune/providers/adapters/together.py +134 -0
- velune/providers/adapters/xai.py +60 -0
- velune/providers/base.py +86 -0
- velune/providers/benchmarker.py +135 -0
- velune/providers/discovery/__init__.py +33 -0
- velune/providers/discovery/anthropic.py +77 -0
- velune/providers/discovery/benchmarks.py +44 -0
- velune/providers/discovery/classifier.py +69 -0
- velune/providers/discovery/fireworks.py +95 -0
- velune/providers/discovery/gguf.py +87 -0
- velune/providers/discovery/google.py +95 -0
- velune/providers/discovery/gpu.py +109 -0
- velune/providers/discovery/groq.py +20 -0
- velune/providers/discovery/huggingface.py +67 -0
- velune/providers/discovery/lmstudio.py +80 -0
- velune/providers/discovery/ollama.py +165 -0
- velune/providers/discovery/openai.py +96 -0
- velune/providers/discovery/openrouter.py +113 -0
- velune/providers/discovery/scanner.py +114 -0
- velune/providers/discovery/together.py +114 -0
- velune/providers/discovery/xai.py +57 -0
- velune/providers/keystore.py +83 -0
- velune/providers/local_paths.py +49 -0
- velune/providers/local_resolver.py +208 -0
- velune/providers/module.py +15 -0
- velune/providers/ollama_manager.py +193 -0
- velune/providers/registry.py +173 -0
- velune/providers/router.py +82 -0
- velune/py.typed +0 -0
- velune/repository/__init__.py +21 -0
- velune/repository/analyzer.py +123 -0
- velune/repository/cognition.py +172 -0
- velune/repository/grapher.py +182 -0
- velune/repository/indexer.py +229 -0
- velune/repository/module.py +15 -0
- velune/repository/parser.py +378 -0
- velune/repository/project_type.py +293 -0
- velune/repository/scanner.py +177 -0
- velune/repository/schemas.py +102 -0
- velune/repository/tracker.py +233 -0
- velune/retrieval/__init__.py +27 -0
- velune/retrieval/graph.py +117 -0
- velune/retrieval/hybrid.py +250 -0
- velune/retrieval/keyword.py +113 -0
- velune/retrieval/module.py +19 -0
- velune/retrieval/reranker.py +68 -0
- velune/retrieval/schemas.py +59 -0
- velune/retrieval/vector.py +163 -0
- velune/telemetry/__init__.py +7 -0
- velune/telemetry/cognition.py +260 -0
- velune/telemetry/token_tracker.py +133 -0
- velune/tools/__init__.py +41 -0
- velune/tools/base/registry.py +84 -0
- velune/tools/base/tool.py +63 -0
- velune/tools/code/navigate.py +107 -0
- velune/tools/code/search.py +112 -0
- velune/tools/filesystem/read.py +75 -0
- velune/tools/filesystem/search.py +123 -0
- velune/tools/filesystem/write.py +160 -0
- velune/tools/git/history.py +185 -0
- velune/tools/git/operations.py +132 -0
- velune/tools/git/state.py +134 -0
- velune/tools/module.py +65 -0
- velune/tools/terminal/execute.py +72 -0
- velune/tools/terminal/history.py +47 -0
- velune/tools/web/fetch.py +55 -0
- velune/tools/web/validator.py +96 -0
- velune_cli-1.0.0.dist-info/METADATA +497 -0
- velune_cli-1.0.0.dist-info/RECORD +229 -0
- velune_cli-1.0.0.dist-info/WHEEL +4 -0
- velune_cli-1.0.0.dist-info/entry_points.txt +2 -0
- velune_cli-1.0.0.dist-info/licenses/LICENSE +201 -0
velune/cli/modes.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class SessionMode(Enum):
|
|
6
|
+
NORMAL = "normal"
|
|
7
|
+
OPTIMUS = "optimus"
|
|
8
|
+
GODLY = "godly"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class ModeConfig:
|
|
13
|
+
mode: SessionMode
|
|
14
|
+
council_tier: str # "instant" | "minimal" | "standard" | "full" | "auto"
|
|
15
|
+
context_compression: bool # compress context before each call
|
|
16
|
+
max_context_tokens: int # hard cap on context sent per call
|
|
17
|
+
temperature: float
|
|
18
|
+
retrieval_depth: int # how many memory + repo chunks to pull
|
|
19
|
+
use_fastest_model: bool # optimus: pick smallest capable model
|
|
20
|
+
use_largest_model: bool # godly: pick largest available model
|
|
21
|
+
disable_critics: bool # optimus: skip critic agents
|
|
22
|
+
description: str
|
|
23
|
+
prompt_color: str # Rich color for prompt badge
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
MODE_CONFIGS: dict[SessionMode, ModeConfig] = {
|
|
27
|
+
SessionMode.NORMAL: ModeConfig(
|
|
28
|
+
mode=SessionMode.NORMAL,
|
|
29
|
+
council_tier="auto",
|
|
30
|
+
context_compression=False,
|
|
31
|
+
max_context_tokens=16384,
|
|
32
|
+
temperature=0.3,
|
|
33
|
+
retrieval_depth=8,
|
|
34
|
+
use_fastest_model=False,
|
|
35
|
+
use_largest_model=False,
|
|
36
|
+
disable_critics=False,
|
|
37
|
+
description="Balanced — auto-selects council tier per task",
|
|
38
|
+
prompt_color="cyan",
|
|
39
|
+
),
|
|
40
|
+
SessionMode.OPTIMUS: ModeConfig(
|
|
41
|
+
mode=SessionMode.OPTIMUS,
|
|
42
|
+
council_tier="instant",
|
|
43
|
+
context_compression=True,
|
|
44
|
+
max_context_tokens=4096,
|
|
45
|
+
temperature=0.1,
|
|
46
|
+
retrieval_depth=3,
|
|
47
|
+
use_fastest_model=True,
|
|
48
|
+
use_largest_model=False,
|
|
49
|
+
disable_critics=True,
|
|
50
|
+
description="Speed mode — smallest model, compressed context, instant tier",
|
|
51
|
+
prompt_color="yellow",
|
|
52
|
+
),
|
|
53
|
+
SessionMode.GODLY: ModeConfig(
|
|
54
|
+
mode=SessionMode.GODLY,
|
|
55
|
+
council_tier="full",
|
|
56
|
+
context_compression=False,
|
|
57
|
+
max_context_tokens=128000,
|
|
58
|
+
temperature=0.5,
|
|
59
|
+
retrieval_depth=20,
|
|
60
|
+
use_fastest_model=False,
|
|
61
|
+
use_largest_model=True,
|
|
62
|
+
disable_critics=False,
|
|
63
|
+
description="Maximum — largest model, full context, complete council",
|
|
64
|
+
prompt_color="magenta",
|
|
65
|
+
),
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class ModeManager:
|
|
70
|
+
def __init__(self) -> None:
|
|
71
|
+
self._active = SessionMode.NORMAL
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def current(self) -> SessionMode:
|
|
75
|
+
return self._active
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def config(self) -> ModeConfig:
|
|
79
|
+
return MODE_CONFIGS[self._active]
|
|
80
|
+
|
|
81
|
+
def set_mode(self, mode: SessionMode) -> ModeConfig:
|
|
82
|
+
self._active = mode
|
|
83
|
+
return self.config
|
|
84
|
+
|
|
85
|
+
def is_normal(self) -> bool:
|
|
86
|
+
return self._active == SessionMode.NORMAL
|
velune/cli/pull_ui.py
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""Interactive model browser TUI for /pull — select a model to download."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from prompt_toolkit.application import Application
|
|
8
|
+
from prompt_toolkit.formatted_text import FormattedText
|
|
9
|
+
from prompt_toolkit.key_binding import KeyBindings
|
|
10
|
+
from prompt_toolkit.layout import Layout
|
|
11
|
+
from prompt_toolkit.layout.containers import Window
|
|
12
|
+
from prompt_toolkit.layout.controls import FormattedTextControl
|
|
13
|
+
|
|
14
|
+
from velune.providers.ollama_manager import RECOMMENDED_MODELS
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from rich.console import Console
|
|
18
|
+
|
|
19
|
+
_SKILL_STYLES: dict[str, str] = {
|
|
20
|
+
"coding": "fg:ansigreen",
|
|
21
|
+
"reasoning": "fg:ansimagenta",
|
|
22
|
+
"embedding": "fg:ansicyan",
|
|
23
|
+
"general": "fg:ansibrightblack",
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
async def run_pull_ui(
|
|
28
|
+
local_models: list[str],
|
|
29
|
+
hardware_ram_gb: float,
|
|
30
|
+
console: Console,
|
|
31
|
+
) -> str | None:
|
|
32
|
+
"""Show the interactive model browser and return the chosen model_id, or None."""
|
|
33
|
+
|
|
34
|
+
selected_idx = [0]
|
|
35
|
+
result: list[str | None] = [None]
|
|
36
|
+
|
|
37
|
+
def _fits(model: dict) -> bool:
|
|
38
|
+
try:
|
|
39
|
+
needed = float(model["ram_needed"].replace(" GB", "").strip())
|
|
40
|
+
return hardware_ram_gb >= needed
|
|
41
|
+
except Exception:
|
|
42
|
+
return True
|
|
43
|
+
|
|
44
|
+
def render_list() -> FormattedText:
|
|
45
|
+
lines: list[tuple[str, str]] = []
|
|
46
|
+
lines.append(("bold", " Available models to pull\n"))
|
|
47
|
+
lines.append(("fg:ansibrightblack", " ↑↓ navigate · Enter pull · Esc cancel\n\n"))
|
|
48
|
+
lines.append(("fg:ansibrightblack", f" Your RAM: {hardware_ram_gb:.0f} GB\n\n"))
|
|
49
|
+
|
|
50
|
+
for i, model in enumerate(RECOMMENDED_MODELS):
|
|
51
|
+
is_active = i == selected_idx[0]
|
|
52
|
+
prefix = "❯ " if is_active else " "
|
|
53
|
+
row_style = "bold fg:cyan" if is_active else ""
|
|
54
|
+
model_id = model["model_id"]
|
|
55
|
+
is_local = any(
|
|
56
|
+
m == model_id or m.split(":")[0] == model_id.split(":")[0]
|
|
57
|
+
and m == model_id
|
|
58
|
+
for m in local_models
|
|
59
|
+
)
|
|
60
|
+
fits = _fits(model)
|
|
61
|
+
skill = model.get("skill", "general")
|
|
62
|
+
skill_style = _SKILL_STYLES.get(skill, "fg:ansibrightblack")
|
|
63
|
+
|
|
64
|
+
if is_local:
|
|
65
|
+
status = " ✓ installed"
|
|
66
|
+
status_style = "fg:ansigreen"
|
|
67
|
+
elif not fits:
|
|
68
|
+
status = " needs more RAM"
|
|
69
|
+
status_style = "fg:ansibrightblack"
|
|
70
|
+
else:
|
|
71
|
+
status = ""
|
|
72
|
+
status_style = ""
|
|
73
|
+
|
|
74
|
+
lines.append((
|
|
75
|
+
row_style,
|
|
76
|
+
f" {prefix}{model_id:<34} {model['size_gb']:4.1f} GB ",
|
|
77
|
+
))
|
|
78
|
+
lines.append((skill_style, f"[{skill}]"))
|
|
79
|
+
if status:
|
|
80
|
+
lines.append((status_style, status))
|
|
81
|
+
lines.append(("", "\n"))
|
|
82
|
+
|
|
83
|
+
if is_active:
|
|
84
|
+
lines.append(("fg:ansibrightblack", f" {model['description']}\n"))
|
|
85
|
+
lines.append(("fg:ansibrightblack", f" RAM needed: {model['ram_needed']}\n"))
|
|
86
|
+
|
|
87
|
+
return FormattedText(lines)
|
|
88
|
+
|
|
89
|
+
kb = KeyBindings()
|
|
90
|
+
|
|
91
|
+
@kb.add("up")
|
|
92
|
+
def _up(event) -> None:
|
|
93
|
+
selected_idx[0] = (selected_idx[0] - 1) % len(RECOMMENDED_MODELS)
|
|
94
|
+
|
|
95
|
+
@kb.add("down")
|
|
96
|
+
def _down(event) -> None:
|
|
97
|
+
selected_idx[0] = (selected_idx[0] + 1) % len(RECOMMENDED_MODELS)
|
|
98
|
+
|
|
99
|
+
@kb.add("enter")
|
|
100
|
+
def _select(event) -> None:
|
|
101
|
+
result[0] = RECOMMENDED_MODELS[selected_idx[0]]["model_id"]
|
|
102
|
+
event.app.exit()
|
|
103
|
+
|
|
104
|
+
@kb.add("escape")
|
|
105
|
+
@kb.add("c-c")
|
|
106
|
+
def _cancel(event) -> None:
|
|
107
|
+
event.app.exit()
|
|
108
|
+
|
|
109
|
+
app = Application(
|
|
110
|
+
layout=Layout(Window(
|
|
111
|
+
content=FormattedTextControl(render_list, focusable=True),
|
|
112
|
+
)),
|
|
113
|
+
key_bindings=kb,
|
|
114
|
+
full_screen=False,
|
|
115
|
+
mouse_support=False,
|
|
116
|
+
)
|
|
117
|
+
await app.run_async()
|
|
118
|
+
return result[0]
|
velune/cli/registry.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""CLI command discovery and registration."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import importlib
|
|
6
|
+
from collections.abc import Sequence
|
|
7
|
+
from importlib.metadata import EntryPoint, entry_points
|
|
8
|
+
from types import ModuleType
|
|
9
|
+
|
|
10
|
+
import typer
|
|
11
|
+
|
|
12
|
+
from velune.cli.commands import (
|
|
13
|
+
ask_command,
|
|
14
|
+
chat_command,
|
|
15
|
+
config_cmd,
|
|
16
|
+
daemon_cmd,
|
|
17
|
+
doctor_cmd,
|
|
18
|
+
init_command,
|
|
19
|
+
mcp_cmd,
|
|
20
|
+
mcp_serve,
|
|
21
|
+
memory_cmd,
|
|
22
|
+
models_cmd,
|
|
23
|
+
run_command,
|
|
24
|
+
setup_command,
|
|
25
|
+
workspace_cmd,
|
|
26
|
+
)
|
|
27
|
+
from velune.kernel.registry import ServiceContainer
|
|
28
|
+
|
|
29
|
+
BUILTIN_COMMAND_MODULES: Sequence[str] = (
|
|
30
|
+
"velune.cli.commands.ask",
|
|
31
|
+
"velune.cli.commands.chat",
|
|
32
|
+
"velune.cli.commands.run",
|
|
33
|
+
"velune.cli.commands.models",
|
|
34
|
+
"velune.cli.commands.workspace",
|
|
35
|
+
"velune.cli.commands.memory",
|
|
36
|
+
"velune.cli.commands.config",
|
|
37
|
+
"velune.cli.commands.daemon",
|
|
38
|
+
"velune.cli.commands.doctor",
|
|
39
|
+
"velune.cli.commands.mcp",
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def discover_builtin_modules() -> list[ModuleType]:
|
|
44
|
+
"""Import and return built-in command modules."""
|
|
45
|
+
|
|
46
|
+
modules: list[ModuleType] = []
|
|
47
|
+
for module_name in BUILTIN_COMMAND_MODULES:
|
|
48
|
+
modules.append(importlib.import_module(module_name))
|
|
49
|
+
return modules
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def discover_plugin_entry_points(group: str = "velune.commands") -> list[EntryPoint]:
|
|
53
|
+
"""Return third-party command extension entry points."""
|
|
54
|
+
|
|
55
|
+
return list(entry_points(group=group))
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def register_commands(app: typer.Typer, container: ServiceContainer) -> None:
|
|
59
|
+
"""Attach all built-in and plugin command groups to the app."""
|
|
60
|
+
|
|
61
|
+
app.command(name="ask")(ask_command)
|
|
62
|
+
app.command(name="chat")(chat_command)
|
|
63
|
+
app.command(name="init")(init_command)
|
|
64
|
+
app.command(name="run")(run_command)
|
|
65
|
+
app.command(name="setup")(setup_command)
|
|
66
|
+
app.command(name="mcp-serve")(mcp_serve)
|
|
67
|
+
app.add_typer(models_cmd, name="models")
|
|
68
|
+
app.add_typer(workspace_cmd, name="workspace")
|
|
69
|
+
app.add_typer(memory_cmd, name="memory")
|
|
70
|
+
app.add_typer(config_cmd, name="config")
|
|
71
|
+
app.add_typer(daemon_cmd, name="daemon")
|
|
72
|
+
app.add_typer(doctor_cmd, name="doctor")
|
|
73
|
+
app.add_typer(mcp_cmd, name="mcp")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
for entry_point in discover_plugin_entry_points():
|
|
77
|
+
loaded = entry_point.load()
|
|
78
|
+
if hasattr(loaded, "register"):
|
|
79
|
+
loaded.register(app=app, container=container)
|
|
80
|
+
elif callable(loaded):
|
|
81
|
+
loaded(app=app, container=container)
|