maverick-installer 0.1.2__tar.gz

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,57 @@
1
+ Metadata-Version: 2.4
2
+ Name: maverick-installer
3
+ Version: 0.1.2
4
+ Summary: Interactive setup wizard for Maverick
5
+ Author: cdayAI
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/cdayAI/maverick
8
+ Requires-Python: >=3.10
9
+ Description-Content-Type: text/markdown
10
+ Requires-Dist: maverick-agent>=0.1
11
+ Requires-Dist: questionary>=2.0
12
+ Requires-Dist: rich>=13.7
13
+
14
+ # maverick-installer
15
+
16
+ The interactive setup wizard. Installed as part of the kernel's
17
+ `[installer]` extra:
18
+
19
+ ```bash
20
+ pipx install 'maverick-agent[installer]'
21
+ maverick init
22
+ ```
23
+
24
+ If the kernel is already installed without the extra:
25
+
26
+ ```bash
27
+ pipx inject maverick-agent maverick-installer
28
+ ```
29
+
30
+ A standalone `maverick-init` entry point is also exposed (same flags).
31
+
32
+ ## Modes
33
+
34
+ `maverick init` first asks how you want to set up:
35
+
36
+ - **consumer** (default) — four questions (name, API key, working
37
+ directory, budget) with safe defaults. About a minute. This is what
38
+ the desktop GUI installer runs too, via the same code path.
39
+ - **advanced** — pick every provider and per-role model, channels,
40
+ safety profile, sandbox backend, budget, capabilities, web search,
41
+ MCP servers, plugins, tool ACLs, rate limits, retention, persona,
42
+ and notifications.
43
+
44
+ ## Flags
45
+
46
+ ```bash
47
+ maverick init --fast # skip every prompt; write recommended defaults
48
+ maverick init --resume # resume an advanced run from the last unanswered question
49
+ ```
50
+
51
+ Both flags work via `maverick init` and the standalone `maverick-init`.
52
+
53
+ ## Output
54
+
55
+ Writes `~/.maverick/config.toml` (0o600) and, when you enter any keys,
56
+ `~/.maverick/.env` (0o600). The agent reads from there. Re-running the
57
+ wizard overwrites both.
@@ -0,0 +1,44 @@
1
+ # maverick-installer
2
+
3
+ The interactive setup wizard. Installed as part of the kernel's
4
+ `[installer]` extra:
5
+
6
+ ```bash
7
+ pipx install 'maverick-agent[installer]'
8
+ maverick init
9
+ ```
10
+
11
+ If the kernel is already installed without the extra:
12
+
13
+ ```bash
14
+ pipx inject maverick-agent maverick-installer
15
+ ```
16
+
17
+ A standalone `maverick-init` entry point is also exposed (same flags).
18
+
19
+ ## Modes
20
+
21
+ `maverick init` first asks how you want to set up:
22
+
23
+ - **consumer** (default) — four questions (name, API key, working
24
+ directory, budget) with safe defaults. About a minute. This is what
25
+ the desktop GUI installer runs too, via the same code path.
26
+ - **advanced** — pick every provider and per-role model, channels,
27
+ safety profile, sandbox backend, budget, capabilities, web search,
28
+ MCP servers, plugins, tool ACLs, rate limits, retention, persona,
29
+ and notifications.
30
+
31
+ ## Flags
32
+
33
+ ```bash
34
+ maverick init --fast # skip every prompt; write recommended defaults
35
+ maverick init --resume # resume an advanced run from the last unanswered question
36
+ ```
37
+
38
+ Both flags work via `maverick init` and the standalone `maverick-init`.
39
+
40
+ ## Output
41
+
42
+ Writes `~/.maverick/config.toml` (0o600) and, when you enter any keys,
43
+ `~/.maverick/.env` (0o600). The agent reads from there. Re-running the
44
+ wizard overwrites both.
@@ -0,0 +1,3 @@
1
+ """Maverick interactive installer."""
2
+
3
+ __version__ = "0.1.2"
@@ -0,0 +1,124 @@
1
+ """Python sidecar for the Tauri desktop installer.
2
+
3
+ Reads wizard steps from stdin, writes JSON-formatted next-step
4
+ descriptors to stdout. The Tauri Rust shell drives this process and
5
+ the Svelte UI sends user answers via Tauri invoke calls.
6
+
7
+ Protocol (line-delimited JSON):
8
+
9
+ stdin: <user_answer_string> (empty string for first call)
10
+ stdout: {"id": "<step_id>", "question": "...", "choices": ["...", ...]}
11
+
12
+ When the wizard is complete, sidecar emits ``{"id": "__done__", ...}``
13
+ and exits.
14
+
15
+ The four questions mirror the CLI's consumer mode exactly (name,
16
+ sign-in key, working directory, budget) and the resulting config is
17
+ written by the SAME ``write_consumer_config`` helper the CLI uses, so
18
+ the GUI and CLI can't drift.
19
+ """
20
+ from __future__ import annotations
21
+
22
+ import json
23
+ import os
24
+ import sys
25
+ from pathlib import Path
26
+ from typing import Any
27
+
28
+ from .wizard import write_consumer_config
29
+
30
+
31
+ def _step(id: str, question: str, choices: list[str], *, kind: str = "choice") -> dict[str, Any]:
32
+ # `kind` lets the Svelte UI render the right control: a choice list,
33
+ # a free-text box, or a masked secret field.
34
+ return {"id": id, "question": question, "choices": choices, "kind": kind}
35
+
36
+
37
+ def _send(step: dict[str, Any]) -> None:
38
+ sys.stdout.write(json.dumps(step) + "\n")
39
+ sys.stdout.flush()
40
+
41
+
42
+ def _recv() -> str:
43
+ return sys.stdin.readline().strip()
44
+
45
+
46
+ def run() -> None:
47
+ """Sidecar entry point: the four-question consumer flow.
48
+
49
+ Matches ``maverick_installer.wizard.run_consumer`` question for
50
+ question. No jargon, no provider picker, no DevTools paste.
51
+ """
52
+ default_name = os.environ.get("USER") or os.environ.get("USERNAME") or ""
53
+ default_workdir = str(Path.home() / "Documents" / "Maverick")
54
+
55
+ # The first invoke carries no answer; consume it and ask Q1.
56
+ _recv()
57
+
58
+ # Q1: name
59
+ _send(_step(
60
+ "name",
61
+ "What should we call you?",
62
+ [],
63
+ kind="text",
64
+ ))
65
+ user_name = _recv().strip() or default_name or "you"
66
+
67
+ # Q2: API key (sign-in). The UI shows the console.anthropic.com link
68
+ # and a masked field. Blank == skip (config saved without a key).
69
+ _send(_step(
70
+ "api_key",
71
+ "Paste your Anthropic API key. Get one at "
72
+ "https://console.anthropic.com/settings/keys (or leave blank to skip).",
73
+ [],
74
+ kind="secret",
75
+ ))
76
+ raw_key = _recv().strip()
77
+ keys: dict[str, str] = {"ANTHROPIC_API_KEY": raw_key} if raw_key else {}
78
+
79
+ # Q3: working directory
80
+ _send(_step(
81
+ "workdir",
82
+ "Where can Maverick work? (a folder it can create files in)",
83
+ [],
84
+ kind="text",
85
+ ))
86
+ workdir = _recv().strip() or default_workdir
87
+
88
+ # Q4: budget
89
+ _send(_step(
90
+ "budget",
91
+ "Stop after spending how much per task?",
92
+ ["$1", "$5", "$20"],
93
+ ))
94
+ budget_ans = _recv().strip() or "$5"
95
+ try:
96
+ dollars = float(budget_ans.lstrip("$"))
97
+ except ValueError:
98
+ dollars = 5.0
99
+ budget = {
100
+ "max_dollars": dollars,
101
+ "max_wall_seconds": 600.0,
102
+ "max_tool_calls": 100,
103
+ }
104
+
105
+ write_consumer_config(
106
+ user_name=user_name, keys=keys, workdir=workdir, budget=budget,
107
+ )
108
+
109
+ if keys:
110
+ msg = f"Setup complete, {user_name}. Maverick is ready."
111
+ else:
112
+ msg = (
113
+ f"Setup saved, {user_name}. Add an API key later from Settings "
114
+ "or by running 'maverick init' again."
115
+ )
116
+ _send(_step("__done__", msg, []))
117
+
118
+
119
+ if __name__ == "__main__":
120
+ try:
121
+ run()
122
+ except Exception as e:
123
+ _send({"id": "__error__", "question": str(e), "choices": [], "kind": "error"})
124
+ sys.exit(1)
@@ -0,0 +1,36 @@
1
+ """Standalone entry point for the installer.
2
+
3
+ Installed as the ``maverick-init`` console script. Also reachable via
4
+ ``maverick init`` when the core CLI is installed.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import argparse
9
+ import sys
10
+
11
+ from .wizard import run
12
+
13
+
14
+ def main(argv: list[str] | None = None) -> int:
15
+ parser = argparse.ArgumentParser(
16
+ prog="maverick-init",
17
+ description="Interactive setup wizard for Maverick.",
18
+ )
19
+ parser.add_argument(
20
+ "--fast", action="store_true",
21
+ help="Skip every prompt; use recommended defaults.",
22
+ )
23
+ parser.add_argument(
24
+ "--resume", action="store_true",
25
+ help="Resume from the last unanswered wizard question.",
26
+ )
27
+ args = parser.parse_args(argv)
28
+ try:
29
+ return run(fast=args.fast, resume=args.resume)
30
+ except (KeyboardInterrupt, EOFError):
31
+ print("\nAborted. Re-run `maverick init` any time.")
32
+ return 130
33
+
34
+
35
+ if __name__ == "__main__":
36
+ sys.exit(main())
@@ -0,0 +1,183 @@
1
+ """Curated catalog of supported models per provider.
2
+
3
+ Updated whenever providers ship new models. Each entry has an id, a
4
+ notes string the wizard shows, and a status marker.
5
+
6
+ All five providers are now wired up. Picking any of them in the wizard
7
+ generates a config that the agent kernel actually dispatches to via
8
+ the multi-provider LLM facade.
9
+ """
10
+
11
+ ROLES: list[tuple[str, str]] = [
12
+ ("orchestrator", "Plans, decomposes, verifies. Use a large model here."),
13
+ ("researcher", "Searches and gathers information."),
14
+ ("coder", "Writes and tests code."),
15
+ ("writer", "Drafts longer-form prose."),
16
+ ("analyst", "Synthesises findings; reasoning-heavy."),
17
+ ("revisor", "Second-pass review when verification fails."),
18
+ ("verifier", "Independent final-answer check."),
19
+ ("summarizer", "Distillation. A small model is enough."),
20
+ ("skill_distiller", "Turns trajectories into reusable skills."),
21
+ ]
22
+
23
+
24
+ PROVIDERS: dict[str, dict] = {
25
+ "anthropic": {
26
+ "status": "ready",
27
+ "label": "Anthropic Claude",
28
+ "env": "ANTHROPIC_API_KEY",
29
+ "models": [
30
+ {"id": "claude-opus-4-7", "notes": "Smartest, slowest, most expensive. Best for orchestrator/revisor."},
31
+ {"id": "claude-sonnet-4-6", "notes": "Balanced. Recommended workhorse."},
32
+ {"id": "claude-haiku-4-5", "notes": "Fast and cheap. Good for summarizer."},
33
+ ],
34
+ },
35
+ "openai": {
36
+ "status": "ready",
37
+ "label": "OpenAI (ChatGPT / GPT)",
38
+ "env": "OPENAI_API_KEY",
39
+ "models": [
40
+ {"id": "gpt-5.5", "notes": "Most capable. Tool-use and long reasoning."},
41
+ {"id": "gpt-5.4", "notes": "Balanced workhorse."},
42
+ {"id": "gpt-5.4-mini", "notes": "Cheaper, fast."},
43
+ {"id": "gpt-5.4-nano", "notes": "Tiny, very cheap. Good for summarizer."},
44
+ ],
45
+ },
46
+ "moonshot": {
47
+ "status": "ready",
48
+ "label": "Moonshot / Kimi",
49
+ "env": "MOONSHOT_API_KEY",
50
+ "models": [
51
+ {"id": "kimi-k2", "notes": "Latest Kimi. Strong agentic/code performance."},
52
+ {"id": "kimi-k1.5", "notes": "Cheaper, still solid."},
53
+ {"id": "moonshot-v1-128k", "notes": "128k context window."},
54
+ ],
55
+ },
56
+ "deepseek": {
57
+ "status": "ready",
58
+ "label": "DeepSeek",
59
+ "env": "DEEPSEEK_API_KEY",
60
+ "models": [
61
+ {"id": "deepseek-chat", "notes": "V3.2 chat. Cheap, capable workhorse."},
62
+ {"id": "deepseek-reasoner", "notes": "R1-line reasoning. Slower, deeper."},
63
+ {"id": "deepseek-v4-flash", "notes": "Very cheap. Good for summarizer."},
64
+ ],
65
+ },
66
+ "xai": {
67
+ "status": "ready",
68
+ "label": "xAI Grok",
69
+ "env": "XAI_API_KEY",
70
+ "models": [
71
+ {"id": "grok-4-latest", "notes": "Flagship. Reasoning + tools."},
72
+ {"id": "grok-4-mini", "notes": "Cheaper sibling."},
73
+ {"id": "grok-code-fast", "notes": "Code-tuned, low latency."},
74
+ ],
75
+ },
76
+ "gemini": {
77
+ "status": "ready",
78
+ "label": "Google Gemini",
79
+ "env": "GEMINI_API_KEY",
80
+ "models": [
81
+ {"id": "gemini-3-pro", "notes": "Long context, smart."},
82
+ {"id": "gemini-3-flash", "notes": "Fast and cheap."},
83
+ ],
84
+ },
85
+ "openrouter": {
86
+ "status": "ready",
87
+ "label": "OpenRouter (200+ models via one API)",
88
+ "env": "OPENROUTER_API_KEY",
89
+ "models": [
90
+ {"id": "auto", "notes": "OpenRouter picks for you."},
91
+ {"id": "meta-llama/llama-3.3-70b", "notes": "Open weight, strong general."},
92
+ {"id": "google/gemini-pro-1.5", "notes": "Long context."},
93
+ {"id": "deepseek/deepseek-r1", "notes": "Strong reasoning, cheap."},
94
+ ],
95
+ },
96
+ "ollama": {
97
+ "status": "ready",
98
+ "label": "Ollama (local, free, private)",
99
+ "env": None,
100
+ "models": [
101
+ {"id": "llama3.3:70b", "notes": "Local, free, requires beefy machine."},
102
+ {"id": "qwen2.5-coder:32b", "notes": "Local, code-focused."},
103
+ {"id": "phi3:14b", "notes": "Local, small, fast."},
104
+ ],
105
+ },
106
+ "tgi": {
107
+ "status": "ready",
108
+ "label": "HuggingFace TGI (self-hosted inference)",
109
+ "env": None,
110
+ "models": [
111
+ {"id": "tgi", "notes": "Whatever model your TGI server serves; URL via TGI_BASE_URL env."},
112
+ ],
113
+ },
114
+ "chatgpt-session": {
115
+ "status": "ready",
116
+ "label": "ChatGPT browser session (use your Plus subscription, no API key)",
117
+ "env": None,
118
+ "session": True,
119
+ "tool_support": False,
120
+ "models": [
121
+ {"id": "gpt-4o", "notes": "Free for Plus subscribers. Best for summarizer/writer/analyst."},
122
+ {"id": "gpt-4o-mini", "notes": "Free tier model. Use for cheap roles."},
123
+ ],
124
+ },
125
+ "claude-session": {
126
+ "status": "ready",
127
+ "label": "Claude.ai browser session (use your Pro subscription, no API key)",
128
+ "env": None,
129
+ "session": True,
130
+ "tool_support": False,
131
+ "models": [
132
+ {"id": "claude-sonnet-4-6", "notes": "Pro default. Best for summarizer/writer/analyst."},
133
+ {"id": "claude-haiku-4-5", "notes": "Faster, lower quota cost."},
134
+ ],
135
+ },
136
+ "kimi-session": {
137
+ "status": "ready",
138
+ "label": "Kimi browser session (use your kimi.com subscription)",
139
+ "env": None,
140
+ "session": True,
141
+ "tool_support": False,
142
+ "models": [
143
+ {"id": "kimi-k2", "notes": "Latest Kimi. Strong agentic / code."},
144
+ {"id": "kimi-k1.5", "notes": "Cheaper, lighter quota cost."},
145
+ ],
146
+ },
147
+ "grok-session": {
148
+ "status": "ready",
149
+ "label": "Grok via x.com browser session (requires X Premium)",
150
+ "env": None,
151
+ "session": True,
152
+ "tool_support": False,
153
+ "models": [
154
+ {"id": "grok-4-latest", "notes": "Flagship. Reasoning + tools."},
155
+ {"id": "grok-4-mini", "notes": "Cheaper sibling."},
156
+ ],
157
+ },
158
+ "gemini-session": {
159
+ "status": "ready",
160
+ "label": "Gemini browser session (gemini.google.com Advanced)",
161
+ "env": None,
162
+ "session": True,
163
+ "tool_support": False,
164
+ "models": [
165
+ {"id": "gemini-3-pro", "notes": "Long context, smart."},
166
+ {"id": "gemini-3-flash", "notes": "Fast and cheap."},
167
+ ],
168
+ },
169
+ }
170
+
171
+
172
+ def default_for_role(role: str) -> str:
173
+ return {
174
+ "orchestrator": "anthropic:claude-opus-4-7",
175
+ "researcher": "anthropic:claude-sonnet-4-6",
176
+ "coder": "anthropic:claude-sonnet-4-6",
177
+ "writer": "anthropic:claude-sonnet-4-6",
178
+ "analyst": "anthropic:claude-sonnet-4-6",
179
+ "revisor": "anthropic:claude-opus-4-7",
180
+ "verifier": "anthropic:claude-sonnet-4-6",
181
+ "summarizer": "anthropic:claude-haiku-4-5",
182
+ "skill_distiller": "anthropic:claude-sonnet-4-6",
183
+ }[role]