devpilot-agentic-cli 1.0.2__py3-none-any.whl → 1.0.3__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.
- agent/cli.py +94 -6
- agent/config.py +21 -6
- agent/context.py +6 -8
- agent/mcp_client.py +67 -4
- agent/setup_wizard.py +93 -35
- {devpilot_agentic_cli-1.0.2.dist-info → devpilot_agentic_cli-1.0.3.dist-info}/METADATA +16 -18
- {devpilot_agentic_cli-1.0.2.dist-info → devpilot_agentic_cli-1.0.3.dist-info}/RECORD +10 -10
- {devpilot_agentic_cli-1.0.2.dist-info → devpilot_agentic_cli-1.0.3.dist-info}/WHEEL +0 -0
- {devpilot_agentic_cli-1.0.2.dist-info → devpilot_agentic_cli-1.0.3.dist-info}/entry_points.txt +0 -0
- {devpilot_agentic_cli-1.0.2.dist-info → devpilot_agentic_cli-1.0.3.dist-info}/top_level.txt +0 -0
agent/cli.py
CHANGED
|
@@ -12,18 +12,93 @@ import argparse
|
|
|
12
12
|
import asyncio
|
|
13
13
|
import os
|
|
14
14
|
import sys
|
|
15
|
+
import time
|
|
15
16
|
from datetime import datetime
|
|
16
17
|
from pathlib import Path
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
|
|
20
|
+
def _fix_windows_console() -> None:
|
|
21
|
+
"""
|
|
22
|
+
Enable ANSI/VT100 support and UTF-8 encoding in Windows terminals.
|
|
23
|
+
|
|
24
|
+
Root cause of the blank black CMD screen:
|
|
25
|
+
- CMD.exe does NOT enable Virtual Terminal Processing by default.
|
|
26
|
+
- Textual sends ANSI escape sequences to probe terminal capabilities.
|
|
27
|
+
- Without VT support, CMD either hangs or renders nothing.
|
|
28
|
+
- PowerShell has VT enabled by default → works immediately.
|
|
29
|
+
|
|
30
|
+
Fixes applied:
|
|
31
|
+
1. Enable ENABLE_VIRTUAL_TERMINAL_PROCESSING via Windows API (ctypes).
|
|
32
|
+
2. Switch stdout/stderr to UTF-8 so → ✓ etc don't crash in cp1252.
|
|
33
|
+
3. Set TERM / COLORTERM so Textual skips slow capability negotiation.
|
|
34
|
+
"""
|
|
35
|
+
if sys.platform != "win32":
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
# ── 1. Enable Virtual Terminal Processing ─────────────────────────────────
|
|
39
|
+
try:
|
|
40
|
+
import ctypes
|
|
41
|
+
import ctypes.wintypes
|
|
42
|
+
kernel32 = ctypes.windll.kernel32 # type: ignore[attr-defined]
|
|
43
|
+
|
|
44
|
+
ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004
|
|
45
|
+
ENABLE_PROCESSED_OUTPUT = 0x0001
|
|
46
|
+
|
|
47
|
+
for handle_id in (-10, -11): # STD_INPUT=-10, STD_OUTPUT=-11
|
|
48
|
+
handle = kernel32.GetStdHandle(handle_id)
|
|
49
|
+
if handle and handle != -1:
|
|
50
|
+
mode = ctypes.wintypes.DWORD(0)
|
|
51
|
+
if kernel32.GetConsoleMode(handle, ctypes.byref(mode)):
|
|
52
|
+
new_mode = (mode.value
|
|
53
|
+
| ENABLE_VIRTUAL_TERMINAL_PROCESSING
|
|
54
|
+
| ENABLE_PROCESSED_OUTPUT)
|
|
55
|
+
kernel32.SetConsoleMode(handle, new_mode)
|
|
56
|
+
except Exception:
|
|
57
|
+
pass # non-fatal — worst case CMD is slow, not broken
|
|
58
|
+
|
|
59
|
+
# ── 2. Switch stdout/stderr to UTF-8 ──────────────────────────────────────
|
|
60
|
+
# Prevents UnicodeEncodeError on → ✓ ✗ characters in cp1252 CMD sessions
|
|
61
|
+
try:
|
|
62
|
+
if hasattr(sys.stdout, "reconfigure"):
|
|
63
|
+
sys.stdout.reconfigure(encoding="utf-8", errors="replace") # type: ignore[union-attr]
|
|
64
|
+
if hasattr(sys.stderr, "reconfigure"):
|
|
65
|
+
sys.stderr.reconfigure(encoding="utf-8", errors="replace") # type: ignore[union-attr]
|
|
66
|
+
# Also tell Windows console host to use UTF-8 codepage
|
|
67
|
+
import ctypes
|
|
68
|
+
ctypes.windll.kernel32.SetConsoleOutputCP(65001) # type: ignore[attr-defined]
|
|
69
|
+
except Exception:
|
|
70
|
+
pass
|
|
71
|
+
|
|
72
|
+
# ── 3. Hint terminal type so Textual doesn't hang on capability detection ─
|
|
73
|
+
# Textual checks these env vars first; without them it sends probe sequences
|
|
74
|
+
# that CMD ignores, causing a multi-second hang.
|
|
75
|
+
os.environ.setdefault("TERM", "xterm-256color")
|
|
76
|
+
os.environ.setdefault("COLORTERM", "truecolor")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# Run immediately — must happen before any rich/textual import
|
|
80
|
+
_fix_windows_console()
|
|
81
|
+
|
|
82
|
+
# Fast imports only at module level — heavy libs (fastapi, mcp) are lazy-loaded
|
|
19
83
|
from agent.config import Config, ConfigError
|
|
20
84
|
from agent.history import HistoryManager
|
|
21
85
|
from agent.loop import run_agent_loop
|
|
22
|
-
from agent.mcp_client import MCPManager
|
|
23
86
|
from agent.providers.factory import create_provider
|
|
24
87
|
from agent.tools import ToolRegistry
|
|
25
88
|
from agent.ui import UI
|
|
26
89
|
|
|
90
|
+
_T0 = time.perf_counter()
|
|
91
|
+
|
|
92
|
+
def _log_startup(msg: str) -> None:
|
|
93
|
+
"""Print a startup progress line. Helps users see DevPilot is loading."""
|
|
94
|
+
elapsed = time.perf_counter() - _T0
|
|
95
|
+
# Use plain ASCII fallback so CMD doesn't choke on escape codes if VT failed
|
|
96
|
+
print(f"\r[{elapsed:.1f}s] {msg}...", end="", flush=True)
|
|
97
|
+
|
|
98
|
+
def _clear_startup() -> None:
|
|
99
|
+
"""Clear the startup progress line once TUI takes over."""
|
|
100
|
+
print("\r" + " " * 60 + "\r", end="", flush=True)
|
|
101
|
+
|
|
27
102
|
|
|
28
103
|
def parse_args() -> argparse.Namespace:
|
|
29
104
|
parser = argparse.ArgumentParser(
|
|
@@ -88,7 +163,8 @@ def _ensure_api_key(config: Config, args: argparse.Namespace) -> Config:
|
|
|
88
163
|
# Force re-run wizard if --setup flag passed
|
|
89
164
|
if args.setup or not config.active_api_key:
|
|
90
165
|
from agent.setup_wizard import run_setup_wizard
|
|
91
|
-
|
|
166
|
+
_user_env = Path.home() / ".devpilot" / ".env"
|
|
167
|
+
success = run_setup_wizard(env_path=_user_env)
|
|
92
168
|
if not success:
|
|
93
169
|
# Wizard skipped (CI/no TTY) or failed — print helpful error
|
|
94
170
|
UI.print_error(
|
|
@@ -115,6 +191,7 @@ async def main_async() -> None:
|
|
|
115
191
|
_apply_cli_overrides(args)
|
|
116
192
|
|
|
117
193
|
# Load config
|
|
194
|
+
_log_startup("Loading configuration")
|
|
118
195
|
try:
|
|
119
196
|
config = Config.load()
|
|
120
197
|
except ConfigError as e:
|
|
@@ -123,8 +200,11 @@ async def main_async() -> None:
|
|
|
123
200
|
|
|
124
201
|
# Handle --setup flag (force wizard even if key exists)
|
|
125
202
|
if args.setup:
|
|
203
|
+
_clear_startup()
|
|
126
204
|
from agent.setup_wizard import run_setup_wizard
|
|
127
|
-
|
|
205
|
+
_user_env = Path.home() / ".devpilot" / ".env"
|
|
206
|
+
run_setup_wizard(env_path=_user_env)
|
|
207
|
+
|
|
128
208
|
try:
|
|
129
209
|
config = Config.load()
|
|
130
210
|
except ConfigError as e:
|
|
@@ -142,20 +222,26 @@ async def main_async() -> None:
|
|
|
142
222
|
sys.exit(1)
|
|
143
223
|
|
|
144
224
|
# Wire up provider, context, registry
|
|
225
|
+
_log_startup("Initializing AI provider")
|
|
145
226
|
provider = create_provider(config)
|
|
146
227
|
|
|
228
|
+
_log_startup("Scanning project context")
|
|
147
229
|
from agent.context import RepoContext
|
|
148
230
|
repo_context = RepoContext(config.workdir)
|
|
149
231
|
registry = ToolRegistry(config, _context=repo_context)
|
|
150
232
|
|
|
151
|
-
# MCP
|
|
233
|
+
# MCP — lazy import to avoid loading the mcp library at startup
|
|
234
|
+
_log_startup("Connecting MCP servers")
|
|
235
|
+
from agent.mcp_client import MCPManager
|
|
152
236
|
mcp_config_path = Path("mcp_servers.json")
|
|
153
237
|
if not mcp_config_path.exists():
|
|
154
238
|
mcp_config_path = Path(__file__).parent.parent / "mcp_servers.json"
|
|
155
239
|
mcp_manager = MCPManager(mcp_config_path)
|
|
156
240
|
await mcp_manager.connect_all(registry)
|
|
157
241
|
|
|
158
|
-
# A2A server
|
|
242
|
+
# A2A server — lazy import to avoid loading fastapi/pydantic at startup
|
|
243
|
+
_log_startup("Starting A2A server")
|
|
244
|
+
from agent.a2a_server import app as a2a_app
|
|
159
245
|
a2a_app.state.config = config
|
|
160
246
|
a2a_app.state.registry = registry
|
|
161
247
|
|
|
@@ -224,7 +310,9 @@ async def main_async() -> None:
|
|
|
224
310
|
sys.exit(0)
|
|
225
311
|
|
|
226
312
|
# ── Interactive TUI mode ──────────────────────────────────────────────────
|
|
313
|
+
_log_startup("Starting DevPilot TUI")
|
|
227
314
|
from agent.tui.app import DevPilotApp
|
|
315
|
+
_clear_startup() # erase progress line before TUI takes over the screen
|
|
228
316
|
app = DevPilotApp(
|
|
229
317
|
provider=provider,
|
|
230
318
|
registry=registry,
|
agent/config.py
CHANGED
|
@@ -17,8 +17,19 @@ from typing import Literal
|
|
|
17
17
|
|
|
18
18
|
from dotenv import load_dotenv
|
|
19
19
|
|
|
20
|
-
# ──
|
|
21
|
-
|
|
20
|
+
# ── Persistent user config: ~/.devpilot/.env ─────────────────────────────────
|
|
21
|
+
# This is where the setup wizard saves configuration so it persists
|
|
22
|
+
# regardless of which directory `devpilot` is run from.
|
|
23
|
+
_USER_CONFIG_DIR = Path.home() / ".devpilot"
|
|
24
|
+
_USER_ENV_FILE = _USER_CONFIG_DIR / ".env"
|
|
25
|
+
|
|
26
|
+
# Load global user config first — this is where the setup wizard saves settings
|
|
27
|
+
load_dotenv(dotenv_path=_USER_ENV_FILE, override=False)
|
|
28
|
+
|
|
29
|
+
# Load project-local .env second — can ADD vars but won't override global config
|
|
30
|
+
# (override=False means global ~/.devpilot/.env always wins)
|
|
31
|
+
load_dotenv(dotenv_path=Path(".") / ".env", override=False)
|
|
32
|
+
|
|
22
33
|
|
|
23
34
|
|
|
24
35
|
# ── Custom exception ─────────────────────────────────────────────────────────
|
|
@@ -32,8 +43,8 @@ class ConfigError(Exception):
|
|
|
32
43
|
Provider = Literal["anthropic", "openai"]
|
|
33
44
|
|
|
34
45
|
PROVIDER_DEFAULTS: dict[str, str] = {
|
|
35
|
-
"anthropic": "claude-opus-4-5",
|
|
36
|
-
"openai":
|
|
46
|
+
"anthropic": "claude-opus-4-5-20251101",
|
|
47
|
+
"openai": "gpt-5.4",
|
|
37
48
|
}
|
|
38
49
|
|
|
39
50
|
# Keys required per provider (checked lazily so we can build/test without keys)
|
|
@@ -43,11 +54,15 @@ REQUIRED_ENV_KEYS: dict[str, str] = {
|
|
|
43
54
|
}
|
|
44
55
|
|
|
45
56
|
# Models that support extended thinking (Anthropic only)
|
|
57
|
+
# Verified via Anthropic API — May 2026
|
|
46
58
|
THINKING_CAPABLE_MODELS: set[str] = {
|
|
59
|
+
"claude-opus-4-7",
|
|
60
|
+
"claude-opus-4-6",
|
|
61
|
+
"claude-opus-4-5-20251101",
|
|
62
|
+
"claude-opus-4-1-20250805",
|
|
63
|
+
"claude-sonnet-4-5-20250929",
|
|
47
64
|
"claude-3-7-sonnet-20250219",
|
|
48
65
|
"claude-3-5-sonnet-20241022",
|
|
49
|
-
"claude-opus-4-5",
|
|
50
|
-
"claude-opus-4-20250514",
|
|
51
66
|
}
|
|
52
67
|
|
|
53
68
|
|
agent/context.py
CHANGED
|
@@ -145,33 +145,31 @@ class RepoContext:
|
|
|
145
145
|
return sigs
|
|
146
146
|
|
|
147
147
|
def _build_project_tree(self, max_entries: int = 200) -> list[str]:
|
|
148
|
+
"""
|
|
149
|
+
Build a fast file-listing project tree.
|
|
150
|
+
AST signature extraction is intentionally skipped here to avoid
|
|
151
|
+
blocking startup — signatures are extracted lazily on file read.
|
|
152
|
+
"""
|
|
148
153
|
entries: list[str] = []
|
|
149
154
|
ignores = {
|
|
150
|
-
".git", "node_modules", ".venv", "__pycache__", "dist",
|
|
155
|
+
".git", "node_modules", ".venv", "__pycache__", "dist",
|
|
151
156
|
"build", ".next", ".tox", "coverage_html_report", ".devpilot_sessions"
|
|
152
157
|
}
|
|
153
158
|
|
|
154
159
|
def _traverse(directory: Path, prefix: str = "") -> None:
|
|
155
160
|
if len(entries) >= max_entries:
|
|
156
161
|
return
|
|
157
|
-
|
|
158
162
|
try:
|
|
159
163
|
for item in sorted(directory.iterdir()):
|
|
160
164
|
if item.name.startswith(".") and item.name not in (".env", ".gitignore", ".github"):
|
|
161
165
|
continue
|
|
162
166
|
if item.name in ignores or item.name.endswith(".egg-info"):
|
|
163
167
|
continue
|
|
164
|
-
|
|
165
168
|
if item.is_dir():
|
|
166
169
|
entries.append(f"{prefix}📁 {item.name}/")
|
|
167
170
|
_traverse(item, prefix + " ")
|
|
168
171
|
else:
|
|
169
172
|
entries.append(f"{prefix}📄 {item.name}")
|
|
170
|
-
if item.suffix in (".py", ".js", ".ts"):
|
|
171
|
-
sigs = self._extract_signatures(item)
|
|
172
|
-
for sig in sigs:
|
|
173
|
-
entries.append(f"{prefix}{sig}")
|
|
174
|
-
|
|
175
173
|
if len(entries) >= max_entries:
|
|
176
174
|
entries.append("… (truncated to ~200 items for context size)")
|
|
177
175
|
break
|
agent/mcp_client.py
CHANGED
|
@@ -8,6 +8,7 @@ and registers them into the ToolRegistry.
|
|
|
8
8
|
|
|
9
9
|
import json
|
|
10
10
|
import asyncio
|
|
11
|
+
import shutil
|
|
11
12
|
from pathlib import Path
|
|
12
13
|
|
|
13
14
|
from mcp.client.session import ClientSession
|
|
@@ -18,6 +19,43 @@ from agent.tools import ToolRegistry, ToolResult
|
|
|
18
19
|
from agent.ui import UI
|
|
19
20
|
|
|
20
21
|
|
|
22
|
+
# ── Install hints for common MCP server commands ─────────────────────────────
|
|
23
|
+
|
|
24
|
+
_INSTALL_HINTS: dict[str, str] = {
|
|
25
|
+
"npx": "Node.js is not installed or not on PATH.\n"
|
|
26
|
+
" → Install it from https://nodejs.org/ (LTS version recommended)\n"
|
|
27
|
+
" → After installing, restart your terminal and try again.",
|
|
28
|
+
"node": "Node.js is not installed or not on PATH.\n"
|
|
29
|
+
" → Install it from https://nodejs.org/",
|
|
30
|
+
"uvx": "'uvx' (uv tool runner) is not installed.\n"
|
|
31
|
+
" → Install uv: https://docs.astral.sh/uv/getting-started/installation/",
|
|
32
|
+
"docker": "Docker is not installed or not running.\n"
|
|
33
|
+
" → Install Docker Desktop from https://www.docker.com/products/docker-desktop/",
|
|
34
|
+
"python": "Python is not on PATH (unexpected — DevPilot itself runs on Python).",
|
|
35
|
+
"python3":"Python 3 is not on PATH.",
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _check_command(command: str, server_name: str) -> bool:
|
|
40
|
+
"""
|
|
41
|
+
Return True if `command` is available on PATH.
|
|
42
|
+
If not, print a clear, actionable error and return False.
|
|
43
|
+
"""
|
|
44
|
+
if shutil.which(command) is not None:
|
|
45
|
+
return True
|
|
46
|
+
|
|
47
|
+
hint = _INSTALL_HINTS.get(command.lower(),
|
|
48
|
+
f"'{command}' was not found on your PATH.\n"
|
|
49
|
+
f" → Make sure it is installed and your terminal can see it."
|
|
50
|
+
)
|
|
51
|
+
UI.print_error(
|
|
52
|
+
f"MCP server '{server_name}' requires '{command}' but it was not found.\n"
|
|
53
|
+
f" {hint}\n"
|
|
54
|
+
f" This MCP server will be skipped. Disable it in mcp_servers.json to suppress this message."
|
|
55
|
+
)
|
|
56
|
+
return False
|
|
57
|
+
|
|
58
|
+
|
|
21
59
|
class MCPManager:
|
|
22
60
|
"""Manages connections to multiple MCP servers."""
|
|
23
61
|
|
|
@@ -79,7 +117,14 @@ class MCPManager:
|
|
|
79
117
|
ready_event.set()
|
|
80
118
|
|
|
81
119
|
async def connect_all(self, registry: ToolRegistry) -> None:
|
|
82
|
-
"""Connect to all servers in mcp_servers.json and register tools.
|
|
120
|
+
"""Connect to all servers in mcp_servers.json and register tools.
|
|
121
|
+
|
|
122
|
+
Uses a non-blocking approach: MCP servers connect in background tasks.
|
|
123
|
+
Startup waits at most MCP_CONNECT_TIMEOUT seconds total so a slow
|
|
124
|
+
npx download never freezes DevPilot at launch.
|
|
125
|
+
"""
|
|
126
|
+
MCP_CONNECT_TIMEOUT = 5.0 # seconds to wait before giving up and continuing
|
|
127
|
+
|
|
83
128
|
if not self.config_path.exists():
|
|
84
129
|
return
|
|
85
130
|
|
|
@@ -92,7 +137,7 @@ class MCPManager:
|
|
|
92
137
|
return
|
|
93
138
|
|
|
94
139
|
if isinstance(servers, dict):
|
|
95
|
-
server_items = servers.items()
|
|
140
|
+
server_items = list(servers.items())
|
|
96
141
|
else:
|
|
97
142
|
server_items = [(s.get("name", f"server_{i}"), s) for i, s in enumerate(servers)]
|
|
98
143
|
|
|
@@ -100,7 +145,7 @@ class MCPManager:
|
|
|
100
145
|
for name, server_config in server_items:
|
|
101
146
|
if server_config.get("enabled", True) is False:
|
|
102
147
|
continue
|
|
103
|
-
|
|
148
|
+
|
|
104
149
|
command = server_config.get("command")
|
|
105
150
|
args = server_config.get("args", [])
|
|
106
151
|
|
|
@@ -108,6 +153,10 @@ class MCPManager:
|
|
|
108
153
|
UI.print_error(f"MCP server '{name}' missing 'command'. Skipping.")
|
|
109
154
|
continue
|
|
110
155
|
|
|
156
|
+
# Pre-flight: make sure the binary is actually installed
|
|
157
|
+
if not _check_command(command, name):
|
|
158
|
+
continue
|
|
159
|
+
|
|
111
160
|
ready_event = asyncio.Event()
|
|
112
161
|
events.append(ready_event)
|
|
113
162
|
task = asyncio.create_task(
|
|
@@ -116,7 +165,21 @@ class MCPManager:
|
|
|
116
165
|
self._tasks.append(task)
|
|
117
166
|
|
|
118
167
|
if events:
|
|
119
|
-
|
|
168
|
+
# Wait for all servers to be ready, but cap total wait time.
|
|
169
|
+
# If any server is slow (e.g. npx downloading a package), DevPilot
|
|
170
|
+
# still starts promptly and the server connects in the background.
|
|
171
|
+
try:
|
|
172
|
+
await asyncio.wait_for(
|
|
173
|
+
asyncio.gather(*(e.wait() for e in events)),
|
|
174
|
+
timeout=MCP_CONNECT_TIMEOUT,
|
|
175
|
+
)
|
|
176
|
+
except asyncio.TimeoutError:
|
|
177
|
+
pending = sum(1 for e in events if not e.is_set())
|
|
178
|
+
UI.print_info(
|
|
179
|
+
f"{pending} MCP server(s) still connecting in background "
|
|
180
|
+
f"(took >{MCP_CONNECT_TIMEOUT:.0f}s). DevPilot is ready now."
|
|
181
|
+
)
|
|
182
|
+
|
|
120
183
|
|
|
121
184
|
async def close(self) -> None:
|
|
122
185
|
"""Close all connections."""
|
agent/setup_wizard.py
CHANGED
|
@@ -25,24 +25,69 @@ from rich.table import Table
|
|
|
25
25
|
|
|
26
26
|
console = Console()
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
|
|
29
|
+
def _prompt_secret(prompt_text: str) -> str:
|
|
30
|
+
"""
|
|
31
|
+
Prompt for a secret (API key) showing '*' for each character typed.
|
|
32
|
+
Works on Windows (CMD / PowerShell) where rich's password=True renders
|
|
33
|
+
completely blank and provides no visual feedback to the user.
|
|
34
|
+
Falls back to rich Prompt (password=True) on non-TTY / CI environments.
|
|
35
|
+
"""
|
|
36
|
+
import sys
|
|
37
|
+
if not sys.stdin.isatty():
|
|
38
|
+
return Prompt.ask(prompt_text, password=True).strip()
|
|
39
|
+
|
|
40
|
+
import platform
|
|
41
|
+
if platform.system() == "Windows":
|
|
42
|
+
import msvcrt
|
|
43
|
+
console.print(f"{prompt_text}: ", end="")
|
|
44
|
+
chars: list[str] = []
|
|
45
|
+
while True:
|
|
46
|
+
ch = msvcrt.getwch() # read one char without echo
|
|
47
|
+
if ch in ("\r", "\n"): # Enter key
|
|
48
|
+
console.print() # move to next line
|
|
49
|
+
break
|
|
50
|
+
elif ch == "\x03": # Ctrl+C
|
|
51
|
+
raise KeyboardInterrupt
|
|
52
|
+
elif ch in ("\x08", "\x7f"): # Backspace
|
|
53
|
+
if chars:
|
|
54
|
+
chars.pop()
|
|
55
|
+
# erase last asterisk: backspace + space + backspace
|
|
56
|
+
console.print("\b \b", end="")
|
|
57
|
+
elif ch == "\x00" or ch == "\xe0": # special key prefix — skip next byte
|
|
58
|
+
msvcrt.getwch()
|
|
59
|
+
else:
|
|
60
|
+
chars.append(ch)
|
|
61
|
+
console.print("*", end="")
|
|
62
|
+
return "".join(chars).strip()
|
|
63
|
+
else:
|
|
64
|
+
# Unix: getpass already hides input cleanly
|
|
65
|
+
import getpass
|
|
66
|
+
return getpass.getpass(f"{prompt_text}: ").strip()
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# ── Model lists (verified against live APIs) ──────────────────────────────────
|
|
70
|
+
# Last verified: May 2026
|
|
29
71
|
|
|
30
72
|
_ANTHROPIC_MODELS = [
|
|
31
|
-
|
|
32
|
-
("claude-
|
|
33
|
-
("claude-
|
|
34
|
-
("claude-
|
|
73
|
+
# Verified via GET https://api.anthropic.com/v1/models
|
|
74
|
+
("claude-opus-4-7", "Newest — most capable Claude (latest)"),
|
|
75
|
+
("claude-opus-4-5-20251101", "Claude Opus 4.5 — powerful & reliable"),
|
|
76
|
+
("claude-sonnet-4-5-20250929", "Claude Sonnet 4.5 — balanced speed & quality"),
|
|
77
|
+
("claude-haiku-4-5-20251001", "Claude Haiku 4.5 — fastest, most affordable"),
|
|
35
78
|
]
|
|
36
79
|
|
|
37
80
|
_OPENAI_MODELS = [
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
("
|
|
41
|
-
("
|
|
81
|
+
# Verified via platform.openai.com/docs/models (May 2026)
|
|
82
|
+
# Note: gpt-4o, o3, o4-mini are retired as of early 2026
|
|
83
|
+
("gpt-5.5", "Flagship — best reasoning & coding"),
|
|
84
|
+
("gpt-5.4", "Primary model — coding & professional work"),
|
|
85
|
+
("gpt-5.4-mini", "Fast & cost-efficient"),
|
|
86
|
+
("gpt-5.4-nano", "Fastest — high-volume low-latency tasks"),
|
|
42
87
|
]
|
|
43
88
|
|
|
44
89
|
# OpenAI-compatible third-party providers
|
|
45
|
-
# (
|
|
90
|
+
# (display_name, key_url, key_env_var, base_url, models)
|
|
46
91
|
_COMPATIBLE_PROVIDERS = {
|
|
47
92
|
"1": (
|
|
48
93
|
"Groq",
|
|
@@ -50,10 +95,12 @@ _COMPATIBLE_PROVIDERS = {
|
|
|
50
95
|
"GROQ_API_KEY",
|
|
51
96
|
"https://api.groq.com/openai/v1",
|
|
52
97
|
[
|
|
53
|
-
|
|
54
|
-
("llama-3.
|
|
55
|
-
("
|
|
56
|
-
("
|
|
98
|
+
# Verified via GET https://api.groq.com/openai/v1/models
|
|
99
|
+
("llama-3.3-70b-versatile", "Llama 3.3 70B — best quality (131k ctx)"),
|
|
100
|
+
("meta-llama/llama-4-scout-17b-16e-instruct","Llama 4 Scout 17B — latest & fast"),
|
|
101
|
+
("qwen/qwen3-32b", "Qwen3 32B — strong reasoning"),
|
|
102
|
+
("llama-3.1-8b-instant", "Llama 3.1 8B — ultra-fast"),
|
|
103
|
+
("groq/compound", "Groq Compound — agentic tasks"),
|
|
57
104
|
],
|
|
58
105
|
),
|
|
59
106
|
"2": (
|
|
@@ -62,9 +109,12 @@ _COMPATIBLE_PROVIDERS = {
|
|
|
62
109
|
"TOGETHER_API_KEY",
|
|
63
110
|
"https://api.together.xyz/v1",
|
|
64
111
|
[
|
|
65
|
-
|
|
66
|
-
("meta-llama/Llama-
|
|
67
|
-
("
|
|
112
|
+
# Verified via Together AI docs (May 2026)
|
|
113
|
+
("meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8", "Llama 4 Maverick — best quality"),
|
|
114
|
+
("meta-llama/Llama-4-Scout-17B-16E-Instruct-FP8", "Llama 4 Scout — fast MoE"),
|
|
115
|
+
("meta-llama/Llama-3.3-70B-Instruct-Turbo", "Llama 3.3 70B Turbo — reliable"),
|
|
116
|
+
("meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo", "Llama 3.1 405B — most capable"),
|
|
117
|
+
("meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo", "Llama 3.1 8B — very fast"),
|
|
68
118
|
],
|
|
69
119
|
),
|
|
70
120
|
"3": (
|
|
@@ -73,9 +123,10 @@ _COMPATIBLE_PROVIDERS = {
|
|
|
73
123
|
"MISTRAL_API_KEY",
|
|
74
124
|
"https://api.mistral.ai/v1",
|
|
75
125
|
[
|
|
76
|
-
|
|
77
|
-
("mistral-
|
|
78
|
-
("
|
|
126
|
+
# Verified via Mistral docs — latest aliases always point to newest stable
|
|
127
|
+
("mistral-large-latest", "Most capable Mistral model"),
|
|
128
|
+
("mistral-small-latest", "Fast and affordable"),
|
|
129
|
+
("codestral-latest", "Optimised for code generation"),
|
|
79
130
|
],
|
|
80
131
|
),
|
|
81
132
|
"4": (
|
|
@@ -84,10 +135,11 @@ _COMPATIBLE_PROVIDERS = {
|
|
|
84
135
|
"OLLAMA_API_KEY", # Ollama doesn't need a real key
|
|
85
136
|
"http://localhost:11434/v1",
|
|
86
137
|
[
|
|
87
|
-
|
|
88
|
-
("
|
|
89
|
-
("
|
|
90
|
-
("
|
|
138
|
+
# Run: ollama pull <model> before using
|
|
139
|
+
("qwen2.5-coder:7b", "Qwen2.5-Coder 7B — best local coding (8GB VRAM)"),
|
|
140
|
+
("qwen2.5-coder:32b", "Qwen2.5-Coder 32B — benchmark king (24GB VRAM)"),
|
|
141
|
+
("deepseek-coder-v2:16b","DeepSeek-Coder-V2 16B — strong coding (16GB VRAM)"),
|
|
142
|
+
("llama3.3:70b", "Llama 3.3 70B — general purpose"),
|
|
91
143
|
],
|
|
92
144
|
),
|
|
93
145
|
"5": (
|
|
@@ -100,6 +152,7 @@ _COMPATIBLE_PROVIDERS = {
|
|
|
100
152
|
}
|
|
101
153
|
|
|
102
154
|
|
|
155
|
+
|
|
103
156
|
# ── Helpers ───────────────────────────────────────────────────────────────────
|
|
104
157
|
|
|
105
158
|
def _is_interactive() -> bool:
|
|
@@ -162,12 +215,17 @@ def _pick_model(models: list[tuple[str, str]], allow_custom: bool = False) -> st
|
|
|
162
215
|
def run_setup_wizard(env_path: Path | None = None) -> bool:
|
|
163
216
|
"""
|
|
164
217
|
Run the interactive first-run setup wizard.
|
|
218
|
+
Saves configuration to ~/.devpilot/.env so settings persist
|
|
219
|
+
regardless of which directory `devpilot` is run from.
|
|
165
220
|
Returns True if setup completed, False if skipped/failed.
|
|
166
221
|
"""
|
|
167
222
|
if not _is_interactive():
|
|
168
223
|
return False
|
|
169
224
|
|
|
170
|
-
|
|
225
|
+
# Always save to the persistent user config directory
|
|
226
|
+
user_config_dir = Path.home() / ".devpilot"
|
|
227
|
+
user_config_dir.mkdir(parents=True, exist_ok=True)
|
|
228
|
+
env_path = env_path or (user_config_dir / ".env")
|
|
171
229
|
|
|
172
230
|
console.print(Panel(
|
|
173
231
|
"[bold cyan]Welcome to DevPilot! 🚀[/bold cyan]\n\n"
|
|
@@ -179,12 +237,12 @@ def run_setup_wizard(env_path: Path | None = None) -> bool:
|
|
|
179
237
|
|
|
180
238
|
# ── Step 1: Choose provider ───────────────────────────────────────────────
|
|
181
239
|
console.print("\n[bold]Step 1 of 3 — Choose your AI provider[/bold]\n")
|
|
182
|
-
console.print(" [cyan]1[/cyan] Anthropic (Claude
|
|
183
|
-
console.print(" [cyan]2[/cyan] OpenAI (GPT-
|
|
184
|
-
console.print(" [cyan]3[/cyan] Groq (Llama
|
|
185
|
-
console.print(" [cyan]4[/cyan] Together AI (Llama
|
|
186
|
-
console.print(" [cyan]5[/cyan] Mistral AI (Mistral, Codestral)")
|
|
187
|
-
console.print(" [cyan]6[/cyan] Ollama (local models
|
|
240
|
+
console.print(" [cyan]1[/cyan] Anthropic (Claude Opus 4.7, Sonnet 4.5, Haiku 4.5)")
|
|
241
|
+
console.print(" [cyan]2[/cyan] OpenAI (GPT-5.5, GPT-5.4, GPT-5.4-mini)")
|
|
242
|
+
console.print(" [cyan]3[/cyan] Groq (Llama 4 Scout, Llama 3.3 70B — very fast, free tier)")
|
|
243
|
+
console.print(" [cyan]4[/cyan] Together AI (Llama 4 Maverick/Scout, Llama 3.3 70B)")
|
|
244
|
+
console.print(" [cyan]5[/cyan] Mistral AI (Mistral Large, Codestral)")
|
|
245
|
+
console.print(" [cyan]6[/cyan] Ollama (local models — Qwen2.5-Coder, DeepSeek, Llama)")
|
|
188
246
|
console.print(" [cyan]7[/cyan] Other (any OpenAI-compatible endpoint)")
|
|
189
247
|
|
|
190
248
|
choice = Prompt.ask("\nProvider", choices=["1","2","3","4","5","6","7"], default="1")
|
|
@@ -195,7 +253,7 @@ def run_setup_wizard(env_path: Path | None = None) -> bool:
|
|
|
195
253
|
if choice == "1":
|
|
196
254
|
console.print("\n[bold]Step 2 of 3 — Enter your Anthropic API key[/bold]")
|
|
197
255
|
console.print(" Get one at: [link=https://console.anthropic.com/]https://console.anthropic.com/[/link]")
|
|
198
|
-
api_key =
|
|
256
|
+
api_key = _prompt_secret("ANTHROPIC_API_KEY")
|
|
199
257
|
if not api_key:
|
|
200
258
|
console.print("[red]API key cannot be empty.[/red]")
|
|
201
259
|
return False
|
|
@@ -215,7 +273,7 @@ def run_setup_wizard(env_path: Path | None = None) -> bool:
|
|
|
215
273
|
elif choice == "2":
|
|
216
274
|
console.print("\n[bold]Step 2 of 3 — Enter your OpenAI API key[/bold]")
|
|
217
275
|
console.print(" Get one at: [link=https://platform.openai.com/api-keys]https://platform.openai.com/api-keys[/link]")
|
|
218
|
-
api_key =
|
|
276
|
+
api_key = _prompt_secret("OPENAI_API_KEY")
|
|
219
277
|
if not api_key:
|
|
220
278
|
console.print("[red]API key cannot be empty.[/red]")
|
|
221
279
|
return False
|
|
@@ -244,7 +302,7 @@ def run_setup_wizard(env_path: Path | None = None) -> bool:
|
|
|
244
302
|
api_key = "ollama"
|
|
245
303
|
else:
|
|
246
304
|
console.print(f" Get one at: [link={key_url}]{key_url}[/link]")
|
|
247
|
-
api_key =
|
|
305
|
+
api_key = _prompt_secret(key_env)
|
|
248
306
|
if not api_key:
|
|
249
307
|
console.print("[red]API key cannot be empty.[/red]")
|
|
250
308
|
return False
|
|
@@ -264,7 +322,7 @@ def run_setup_wizard(env_path: Path | None = None) -> bool:
|
|
|
264
322
|
elif choice == "7":
|
|
265
323
|
console.print("\n[bold]Step 2 of 3 — Custom OpenAI-compatible endpoint[/bold]")
|
|
266
324
|
base_url = Prompt.ask("Base URL (e.g. https://api.example.com/v1)").strip()
|
|
267
|
-
api_key =
|
|
325
|
+
api_key = _prompt_secret("API key")
|
|
268
326
|
model = Prompt.ask("Model name (e.g. llama-3-70b)").strip()
|
|
269
327
|
|
|
270
328
|
if not base_url or not model:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devpilot-agentic-cli
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.3
|
|
4
4
|
Summary: Autonomous AI coding agent for your terminal — Claude, GPT-4o, Groq, Ollama, and more
|
|
5
5
|
Author: Thijesh Praveen V
|
|
6
6
|
License: MIT
|
|
@@ -46,7 +46,7 @@ Requires-Dist: pytest-asyncio>=0.23.7; extra == "dev"
|
|
|
46
46
|
[](https://pypi.org/project/devpilot-agentic-cli/)
|
|
47
47
|
[](https://opensource.org/licenses/MIT)
|
|
48
48
|
|
|
49
|
-
**An autonomous AI coding agent for your terminal.** DevPilot gives Claude, GPT
|
|
49
|
+
**An autonomous AI coding agent for your terminal.** DevPilot gives Claude, GPT, Groq, Mistral, or any local model a full suite of tools — file read/write, bash execution, code search, git, MCP, and more — orchestrated into a self-healing agentic loop inside a rich Textual TUI. Works in PowerShell, CMD, and any modern terminal.
|
|
50
50
|
|
|
51
51
|
```
|
|
52
52
|
┌─ DevPilot ──────────────────────────────────────────────────────┐
|
|
@@ -76,7 +76,6 @@ Requires-Dist: pytest-asyncio>=0.23.7; extra == "dev"
|
|
|
76
76
|
| **Git** | `git_status`, `git_commit` with surgical file staging |
|
|
77
77
|
| **Documentation** | `doc_gen` (markdown), `diagram` (Mermaid) |
|
|
78
78
|
| **Web search** | `web_search` via Tavily (optional) |
|
|
79
|
-
|
|
80
79
|
| **MCP** | Connect any MCP server via `mcp_servers.json` |
|
|
81
80
|
| **A2A** | Agent-to-agent task delegation over HTTP |
|
|
82
81
|
| **Providers** | Anthropic, OpenAI, Groq, Together AI, Mistral, Ollama, any OpenAI-compatible endpoint |
|
|
@@ -92,7 +91,7 @@ pip install devpilot-agentic-cli
|
|
|
92
91
|
devpilot
|
|
93
92
|
```
|
|
94
93
|
|
|
95
|
-
That's it. On first run DevPilot launches a setup wizard — pick your provider, enter your API key, choose a model. It saves everything to
|
|
94
|
+
That's it. On first run DevPilot launches a setup wizard — pick your provider, enter your API key, choose a model. It saves everything to `~/.devpilot/.env` and opens the TUI. Every subsequent run starts immediately.
|
|
96
95
|
|
|
97
96
|
### Optional Features
|
|
98
97
|
|
|
@@ -111,19 +110,19 @@ DevPilot works with any of these out of the box — the setup wizard walks you t
|
|
|
111
110
|
|
|
112
111
|
| Provider | Models | Get API key |
|
|
113
112
|
|---|---|---|
|
|
114
|
-
| **Anthropic** | claude-opus-4-5, claude-sonnet-4-5, claude-haiku-4-5 | [console.anthropic.com](https://console.anthropic.com/) |
|
|
115
|
-
| **OpenAI** | gpt-
|
|
116
|
-
| **Groq** | llama-3.3-70b,
|
|
117
|
-
| **Together AI** | Llama
|
|
118
|
-
| **Mistral AI** | mistral-large, codestral | [console.mistral.ai](https://console.mistral.ai/api-keys/) |
|
|
119
|
-
| **Ollama** |
|
|
113
|
+
| **Anthropic** | claude-opus-4-7, claude-opus-4-5-20251101, claude-sonnet-4-5-20250929, claude-haiku-4-5-20251001 | [console.anthropic.com](https://console.anthropic.com/) |
|
|
114
|
+
| **OpenAI** | gpt-5.5, gpt-5.4, gpt-5.4-mini, gpt-5.4-nano | [platform.openai.com](https://platform.openai.com/api-keys) |
|
|
115
|
+
| **Groq** | llama-3.3-70b-versatile, llama-4-scout-17b, qwen3-32b | [console.groq.com](https://console.groq.com/keys) |
|
|
116
|
+
| **Together AI** | Llama 4 Maverick/Scout, Llama 3.3 70B Turbo | [api.together.xyz](https://api.together.xyz/settings/api-keys) |
|
|
117
|
+
| **Mistral AI** | mistral-large-latest, mistral-small-latest, codestral-latest | [console.mistral.ai](https://console.mistral.ai/api-keys/) |
|
|
118
|
+
| **Ollama** | qwen2.5-coder:7b, deepseek-coder-v2:16b, llama3.3:70b — no API key needed | [ollama.com](https://ollama.com/library) |
|
|
120
119
|
| **Other** | Any OpenAI-compatible endpoint | — |
|
|
121
120
|
|
|
122
121
|
---
|
|
123
122
|
|
|
124
123
|
## Configuration
|
|
125
124
|
|
|
126
|
-
All settings live in
|
|
125
|
+
All settings live in `~/.devpilot/.env` — a persistent file in your home directory that works regardless of which folder you run `devpilot` from. The setup wizard creates this on first run. You can edit it manually anytime — or re-run the wizard with `devpilot --setup`.
|
|
127
126
|
|
|
128
127
|
### Full settings reference
|
|
129
128
|
|
|
@@ -131,9 +130,10 @@ All settings live in a `.env` file in your project directory. The setup wizard c
|
|
|
131
130
|
|---|---|---|
|
|
132
131
|
| `ANTHROPIC_API_KEY` | — | API key for Anthropic provider |
|
|
133
132
|
| `OPENAI_API_KEY` | — | API key for OpenAI / Groq / Together / Mistral / Ollama |
|
|
133
|
+
| `GROQ_API_KEY` | — | API key for Groq (optional — can reuse as OPENAI_API_KEY) |
|
|
134
134
|
| `DEVPILOT_PROVIDER` | `anthropic` | `anthropic` or `openai` |
|
|
135
|
-
| `DEVPILOT_MODEL` | `claude-opus-4-5` | Model name |
|
|
136
|
-
| `DEVPILOT_BASE_URL` | — | Custom endpoint, e.g. `
|
|
135
|
+
| `DEVPILOT_MODEL` | `claude-opus-4-5-20251101` | Model name |
|
|
136
|
+
| `DEVPILOT_BASE_URL` | — | Custom endpoint, e.g. `https://api.groq.com/openai/v1` |
|
|
137
137
|
| `DEVPILOT_NO_CONFIRM` | `false` | Skip confirmation prompts (useful for CI) |
|
|
138
138
|
| `DEVPILOT_MAX_ITERATIONS` | `50` | Max tool-use iterations before loop aborts |
|
|
139
139
|
| `DEVPILOT_WORKDIR` | `cwd` | Root directory for file operations |
|
|
@@ -144,12 +144,12 @@ All settings live in a `.env` file in your project directory. The setup wizard c
|
|
|
144
144
|
### Override priority
|
|
145
145
|
|
|
146
146
|
```
|
|
147
|
-
CLI flags → env vars →
|
|
147
|
+
CLI flags → env vars → ~/.devpilot/.env → defaults
|
|
148
148
|
```
|
|
149
149
|
|
|
150
150
|
Per-run override example:
|
|
151
151
|
```bash
|
|
152
|
-
DEVPILOT_MODEL=
|
|
152
|
+
DEVPILOT_MODEL=llama-3.3-70b-versatile devpilot --task "fix typos"
|
|
153
153
|
```
|
|
154
154
|
|
|
155
155
|
---
|
|
@@ -172,7 +172,6 @@ Options:
|
|
|
172
172
|
--a2a-port PORT A2A server port (default: 8000)
|
|
173
173
|
--no-a2a Disable A2A server
|
|
174
174
|
--no-web-search Disable Tavily web search
|
|
175
|
-
|
|
176
175
|
--setup Re-run the setup wizard
|
|
177
176
|
```
|
|
178
177
|
|
|
@@ -232,7 +231,7 @@ agent/
|
|
|
232
231
|
├── setup_wizard.py First-run interactive configuration wizard
|
|
233
232
|
├── loop.py Core agentic loop (plan → act → verify → heal)
|
|
234
233
|
├── config.py Config dataclass — all settings from env vars
|
|
235
|
-
├── context.py RepoContext — file awareness, AST map
|
|
234
|
+
├── context.py RepoContext — file awareness, AST project map
|
|
236
235
|
├── history.py Conversation history + smart context pruning
|
|
237
236
|
├── providers/
|
|
238
237
|
│ ├── anthropic_provider.py
|
|
@@ -247,7 +246,6 @@ agent/
|
|
|
247
246
|
│ ├── doc_gen.py doc_gen
|
|
248
247
|
│ ├── diagram.py diagram (Mermaid)
|
|
249
248
|
│ ├── web_search.py web_search (Tavily)
|
|
250
|
-
|
|
251
249
|
│ ├── a2a.py A2A delegation
|
|
252
250
|
│ └── registry.py ToolRegistry + PermissionGuard
|
|
253
251
|
└── tui/
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
agent/__init__.py,sha256=lfJPQT9NbRRWfa9YABD9u8apcLjs3tzDVZvrOb69GBQ,25
|
|
2
2
|
agent/a2a_client.py,sha256=vY4qZahkWP-DVU2smIeTz1xLj61kkDjE9Tmt_-9PKUU,3416
|
|
3
3
|
agent/a2a_server.py,sha256=3rkDy8dm49_5qCa6fKYkLdmHTnHs5ocHBuZ8j32-p48,5230
|
|
4
|
-
agent/cli.py,sha256=
|
|
5
|
-
agent/config.py,sha256=
|
|
6
|
-
agent/context.py,sha256=
|
|
4
|
+
agent/cli.py,sha256=X8GSasVVjtE9b-rEPnoy6lBf0L2Q9MJ2DX7Otb91xoA,12897
|
|
5
|
+
agent/config.py,sha256=b53O7kkdAUYTNCm7YLxBYiySj6ZXn2qzoWqgPN1NIUw,11244
|
|
6
|
+
agent/context.py,sha256=atGJgIiMAmYfcNu6k9gwUzsz5cykBAx9A8PCdgK64R0,7297
|
|
7
7
|
agent/history.py,sha256=IMY3IO5TN9Sh7tJPAWE9VZYC0pkAwgPj2a_F1yA4OmE,6730
|
|
8
8
|
agent/loop.py,sha256=8lTvCSAljPdmyyJ1uf0Q9qulUFNE3d4v3ZNzRae4c1w,3514
|
|
9
|
-
agent/mcp_client.py,sha256=
|
|
10
|
-
agent/setup_wizard.py,sha256=
|
|
9
|
+
agent/mcp_client.py,sha256=KquR1Hp_GRA37aIFQaBrD3hYlI5ZLkF9Q5yH_x5XGbE,7764
|
|
10
|
+
agent/setup_wizard.py,sha256=KNDxy-0jC6erB9IGpZoPCcrgpzU523D8p1zEx8aMbC0,15655
|
|
11
11
|
agent/ui.py,sha256=LK8L2fTq_JIcYiVVjpVWaoYMFWXwqUcqYL4gspdAqvs,8283
|
|
12
12
|
agent/providers/__init__.py,sha256=6xBg26vCBV2e3hybMT2JCHEZoRNpImkVOK-FytBW4xY,166
|
|
13
13
|
agent/providers/anthropic_provider.py,sha256=i257T8T7fYuUEVvsy-3_eudbjSlxZqbn3zi7DFvukRE,6067
|
|
@@ -28,8 +28,8 @@ agent/tools/shell.py,sha256=i9nar3gyS28p6wjfAljNREUll-7RiD_LhQQ_CDkz-CM,3923
|
|
|
28
28
|
agent/tools/web_search.py,sha256=7a533lYcRG0rwYle00xsIncfPRL1zCiS-wsL_qVxlyI,3736
|
|
29
29
|
agent/tui/__init__.py,sha256=FB4u1BY9RSmYVfCM2yMeCyMmzjnb9T0bhmPp9hHH8Ys,37
|
|
30
30
|
agent/tui/app.py,sha256=ZClXMLgXvohtLlYogKMpQISjEiFTHzNP6XPSeM6y4xU,18598
|
|
31
|
-
devpilot_agentic_cli-1.0.
|
|
32
|
-
devpilot_agentic_cli-1.0.
|
|
33
|
-
devpilot_agentic_cli-1.0.
|
|
34
|
-
devpilot_agentic_cli-1.0.
|
|
35
|
-
devpilot_agentic_cli-1.0.
|
|
31
|
+
devpilot_agentic_cli-1.0.3.dist-info/METADATA,sha256=xgWjgjjANVyROUmPQvTfdCzMElpEyG4tFEmGtNmAPpo,11504
|
|
32
|
+
devpilot_agentic_cli-1.0.3.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
33
|
+
devpilot_agentic_cli-1.0.3.dist-info/entry_points.txt,sha256=Zi0zH4sqSQptehekvn5CBhU452GQ23Vyja4l8C58IuY,44
|
|
34
|
+
devpilot_agentic_cli-1.0.3.dist-info/top_level.txt,sha256=0gvCG7PHc22NA63j3bTGi2Zc37ym9t8Pf90ZLzf1kGA,6
|
|
35
|
+
devpilot_agentic_cli-1.0.3.dist-info/RECORD,,
|
|
File without changes
|
{devpilot_agentic_cli-1.0.2.dist-info → devpilot_agentic_cli-1.0.3.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|