vaal-code 0.6.850__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.
- vaal_code-0.6.850/PKG-INFO +106 -0
- vaal_code-0.6.850/README.md +92 -0
- vaal_code-0.6.850/pyproject.toml +30 -0
- vaal_code-0.6.850/setup.cfg +4 -0
- vaal_code-0.6.850/tests/test_all.py +382 -0
- vaal_code-0.6.850/vaal/__init__.py +2 -0
- vaal_code-0.6.850/vaal/__main__.py +249 -0
- vaal_code-0.6.850/vaal/core/__init__.py +0 -0
- vaal_code-0.6.850/vaal/core/agent.py +398 -0
- vaal_code-0.6.850/vaal/core/auto_fix.py +55 -0
- vaal_code-0.6.850/vaal/core/bootstrap.py +255 -0
- vaal_code-0.6.850/vaal/core/branching.py +157 -0
- vaal_code-0.6.850/vaal/core/bridge.py +184 -0
- vaal_code-0.6.850/vaal/core/changelog.py +306 -0
- vaal_code-0.6.850/vaal/core/clipboard.py +76 -0
- vaal_code-0.6.850/vaal/core/code_review.py +271 -0
- vaal_code-0.6.850/vaal/core/collaborative.py +340 -0
- vaal_code-0.6.850/vaal/core/command_palette.py +268 -0
- vaal_code-0.6.850/vaal/core/config.py +55 -0
- vaal_code-0.6.850/vaal/core/context.py +147 -0
- vaal_code-0.6.850/vaal/core/cost_tracker.py +57 -0
- vaal_code-0.6.850/vaal/core/cot_display.py +198 -0
- vaal_code-0.6.850/vaal/core/deps.py +422 -0
- vaal_code-0.6.850/vaal/core/env_manager.py +288 -0
- vaal_code-0.6.850/vaal/core/error_explain.py +227 -0
- vaal_code-0.6.850/vaal/core/font_screen.py +157 -0
- vaal_code-0.6.850/vaal/core/generate_icon.py +61 -0
- vaal_code-0.6.850/vaal/core/history.py +59 -0
- vaal_code-0.6.850/vaal/core/hooks.py +134 -0
- vaal_code-0.6.850/vaal/core/image_input.py +151 -0
- vaal_code-0.6.850/vaal/core/init_project.py +229 -0
- vaal_code-0.6.850/vaal/core/interactive.py +412 -0
- vaal_code-0.6.850/vaal/core/keybindings.py +94 -0
- vaal_code-0.6.850/vaal/core/llm.py +180 -0
- vaal_code-0.6.850/vaal/core/login_screen.py +347 -0
- vaal_code-0.6.850/vaal/core/logout_screen.py +201 -0
- vaal_code-0.6.850/vaal/core/mcp_client.py +312 -0
- vaal_code-0.6.850/vaal/core/memory.py +202 -0
- vaal_code-0.6.850/vaal/core/migration.py +321 -0
- vaal_code-0.6.850/vaal/core/model_manager.py +458 -0
- vaal_code-0.6.850/vaal/core/multiline.py +166 -0
- vaal_code-0.6.850/vaal/core/notifications.py +223 -0
- vaal_code-0.6.850/vaal/core/oauth.py +229 -0
- vaal_code-0.6.850/vaal/core/output_styles.py +80 -0
- vaal_code-0.6.850/vaal/core/permissions.py +57 -0
- vaal_code-0.6.850/vaal/core/plans.py +197 -0
- vaal_code-0.6.850/vaal/core/plugins.py +113 -0
- vaal_code-0.6.850/vaal/core/preview_overlay.py +701 -0
- vaal_code-0.6.850/vaal/core/preview_server.py +781 -0
- vaal_code-0.6.850/vaal/core/progress.py +244 -0
- vaal_code-0.6.850/vaal/core/providers.py +780 -0
- vaal_code-0.6.850/vaal/core/raw_input.py +530 -0
- vaal_code-0.6.850/vaal/core/remote_control.py +191 -0
- vaal_code-0.6.850/vaal/core/repl.py +4767 -0
- vaal_code-0.6.850/vaal/core/scheduler.py +242 -0
- vaal_code-0.6.850/vaal/core/self_repair.py +276 -0
- vaal_code-0.6.850/vaal/core/server.py +330 -0
- vaal_code-0.6.850/vaal/core/session.py +89 -0
- vaal_code-0.6.850/vaal/core/skills.py +148 -0
- vaal_code-0.6.850/vaal/core/split_pane.py +198 -0
- vaal_code-0.6.850/vaal/core/ssh_remote.py +250 -0
- vaal_code-0.6.850/vaal/core/task_manager.py +167 -0
- vaal_code-0.6.850/vaal/core/terminal_profile.py +180 -0
- vaal_code-0.6.850/vaal/core/terminal_theme.py +201 -0
- vaal_code-0.6.850/vaal/core/theme.py +48 -0
- vaal_code-0.6.850/vaal/core/theme_screen.py +185 -0
- vaal_code-0.6.850/vaal/core/tool_executor.py +105 -0
- vaal_code-0.6.850/vaal/core/undo_system.py +313 -0
- vaal_code-0.6.850/vaal/core/user_config.py +125 -0
- vaal_code-0.6.850/vaal/core/vim_mode.py +30 -0
- vaal_code-0.6.850/vaal/core/voice.py +211 -0
- vaal_code-0.6.850/vaal/core/watch_mode.py +169 -0
- vaal_code-0.6.850/vaal/tools/__init__.py +0 -0
- vaal_code-0.6.850/vaal/tools/agent_tools.py +225 -0
- vaal_code-0.6.850/vaal/tools/api_tools.py +319 -0
- vaal_code-0.6.850/vaal/tools/bash_tool.py +179 -0
- vaal_code-0.6.850/vaal/tools/db_tools.py +407 -0
- vaal_code-0.6.850/vaal/tools/diff_tools.py +140 -0
- vaal_code-0.6.850/vaal/tools/file_tools.py +116 -0
- vaal_code-0.6.850/vaal/tools/git_tools.py +311 -0
- vaal_code-0.6.850/vaal/tools/interaction_tools.py +58 -0
- vaal_code-0.6.850/vaal/tools/lsp_tools.py +304 -0
- vaal_code-0.6.850/vaal/tools/memory_tools.py +79 -0
- vaal_code-0.6.850/vaal/tools/notebook_tools.py +310 -0
- vaal_code-0.6.850/vaal/tools/plugin_tools.py +272 -0
- vaal_code-0.6.850/vaal/tools/regex_tools.py +209 -0
- vaal_code-0.6.850/vaal/tools/registry.py +57 -0
- vaal_code-0.6.850/vaal/tools/search_tools.py +117 -0
- vaal_code-0.6.850/vaal/tools/sql_tools.py +222 -0
- vaal_code-0.6.850/vaal/tools/ssh_tools.py +36 -0
- vaal_code-0.6.850/vaal/tools/todo_tools.py +96 -0
- vaal_code-0.6.850/vaal/tools/web_tools.py +152 -0
- vaal_code-0.6.850/vaal_code.egg-info/PKG-INFO +106 -0
- vaal_code-0.6.850/vaal_code.egg-info/SOURCES.txt +96 -0
- vaal_code-0.6.850/vaal_code.egg-info/dependency_links.txt +1 -0
- vaal_code-0.6.850/vaal_code.egg-info/entry_points.txt +2 -0
- vaal_code-0.6.850/vaal_code.egg-info/requires.txt +5 -0
- vaal_code-0.6.850/vaal_code.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vaal-code
|
|
3
|
+
Version: 0.6.850
|
|
4
|
+
Summary: AI coding agent CLI — local LLMs via Ollama or cloud models via API
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://e-e.tools/vaal
|
|
7
|
+
Project-URL: Repository, https://github.com/0xE666/vaal
|
|
8
|
+
Requires-Python: >=3.11
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
Requires-Dist: httpx>=0.25.0
|
|
11
|
+
Requires-Dist: rich>=13.0.0
|
|
12
|
+
Provides-Extra: voice
|
|
13
|
+
Requires-Dist: SpeechRecognition; extra == "voice"
|
|
14
|
+
|
|
15
|
+
# Vaal
|
|
16
|
+
|
|
17
|
+
AI coding agent CLI. Runs local LLMs via Ollama or cloud models via API. Named after the Vaal Orb from Path of Exile.
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
git clone https://github.com/0xE666/vaal.git
|
|
23
|
+
cd vaal
|
|
24
|
+
python install.py
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
That's it. `vaal` is now available as a command from anywhere, just like `claude`.
|
|
28
|
+
|
|
29
|
+
Or manually:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install -e .
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# With Ollama (free, local)
|
|
39
|
+
vaal
|
|
40
|
+
|
|
41
|
+
# With Claude
|
|
42
|
+
vaal -m anthropic:claude-sonnet-4-20250514
|
|
43
|
+
|
|
44
|
+
# With OpenAI
|
|
45
|
+
vaal -m openai:gpt-4o
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
On first run with a cloud model, use `/login` to add your API key:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
/login anthropic sk-ant-api03-your-key-here
|
|
52
|
+
/login openai sk-your-key-here
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Or create a vaal account at [e-e.tools/vaal](https://e-e.tools/vaal):
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
/register
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Features
|
|
62
|
+
|
|
63
|
+
- **45 tools** — bash, file read/write/edit, git, grep, glob, web search, agents, notebooks, and more
|
|
64
|
+
- **Subagents** — spawn background agents (explore, plan, verify, code-review) that work in parallel
|
|
65
|
+
- **80+ slash commands** — `/commit`, `/test`, `/pr`, `/diff`, `/pin`, `/remote`, `/plugin`, and more
|
|
66
|
+
- **Multi-provider** — Ollama, Anthropic, OpenAI, Groq, OpenRouter, DeepSeek, Together
|
|
67
|
+
- **Self-repair** — catches its own crashes, asks the LLM to fix the bug, patches itself
|
|
68
|
+
- **Remote control** — control vaal from a browser at e-e.tools/vaal
|
|
69
|
+
- **Plugins** — create custom tools with `/plugin create` or let the LLM generate them
|
|
70
|
+
- **Tab completion** — file paths auto-complete on Tab
|
|
71
|
+
- **Persistent history** — Up arrow recalls prompts across sessions
|
|
72
|
+
|
|
73
|
+
## Providers
|
|
74
|
+
|
|
75
|
+
| Provider | Auth | Example |
|
|
76
|
+
|----------|------|---------|
|
|
77
|
+
| Ollama | None (local) | `vaal -m qwen3:8b` |
|
|
78
|
+
| Anthropic | API key or Max/Pro OAuth | `vaal -m anthropic:claude-opus-4-6` |
|
|
79
|
+
| OpenAI | API key | `vaal -m openai:gpt-4o` |
|
|
80
|
+
| Groq | API key | `vaal -m groq:llama-3.3-70b-versatile` |
|
|
81
|
+
| OpenRouter | API key | `vaal -m openrouter:anthropic/claude-sonnet-4` |
|
|
82
|
+
| DeepSeek | API key | `vaal -m deepseek:deepseek-chat` |
|
|
83
|
+
| Together | API key | `vaal -m together:meta-llama/Llama-3.3-70B` |
|
|
84
|
+
|
|
85
|
+
## Key Commands
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
/help — All commands
|
|
89
|
+
/login — Add API key
|
|
90
|
+
/register — Create vaal account
|
|
91
|
+
/commit — Auto-generate commit message
|
|
92
|
+
/test — Run tests, auto-fix failures
|
|
93
|
+
/pr — Create pull request
|
|
94
|
+
/pin <file> — Keep file in context
|
|
95
|
+
/remote — Control from browser
|
|
96
|
+
/plugin create — Create custom tools
|
|
97
|
+
/effort — Set inference level
|
|
98
|
+
/doctor — System diagnostics
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Requirements
|
|
102
|
+
|
|
103
|
+
- Python 3.11+
|
|
104
|
+
- httpx, rich (auto-installed)
|
|
105
|
+
- Ollama (optional, for local models)
|
|
106
|
+
- Git (optional, for git commands)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Vaal
|
|
2
|
+
|
|
3
|
+
AI coding agent CLI. Runs local LLMs via Ollama or cloud models via API. Named after the Vaal Orb from Path of Exile.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/0xE666/vaal.git
|
|
9
|
+
cd vaal
|
|
10
|
+
python install.py
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
That's it. `vaal` is now available as a command from anywhere, just like `claude`.
|
|
14
|
+
|
|
15
|
+
Or manually:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install -e .
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# With Ollama (free, local)
|
|
25
|
+
vaal
|
|
26
|
+
|
|
27
|
+
# With Claude
|
|
28
|
+
vaal -m anthropic:claude-sonnet-4-20250514
|
|
29
|
+
|
|
30
|
+
# With OpenAI
|
|
31
|
+
vaal -m openai:gpt-4o
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
On first run with a cloud model, use `/login` to add your API key:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
/login anthropic sk-ant-api03-your-key-here
|
|
38
|
+
/login openai sk-your-key-here
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Or create a vaal account at [e-e.tools/vaal](https://e-e.tools/vaal):
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
/register
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Features
|
|
48
|
+
|
|
49
|
+
- **45 tools** — bash, file read/write/edit, git, grep, glob, web search, agents, notebooks, and more
|
|
50
|
+
- **Subagents** — spawn background agents (explore, plan, verify, code-review) that work in parallel
|
|
51
|
+
- **80+ slash commands** — `/commit`, `/test`, `/pr`, `/diff`, `/pin`, `/remote`, `/plugin`, and more
|
|
52
|
+
- **Multi-provider** — Ollama, Anthropic, OpenAI, Groq, OpenRouter, DeepSeek, Together
|
|
53
|
+
- **Self-repair** — catches its own crashes, asks the LLM to fix the bug, patches itself
|
|
54
|
+
- **Remote control** — control vaal from a browser at e-e.tools/vaal
|
|
55
|
+
- **Plugins** — create custom tools with `/plugin create` or let the LLM generate them
|
|
56
|
+
- **Tab completion** — file paths auto-complete on Tab
|
|
57
|
+
- **Persistent history** — Up arrow recalls prompts across sessions
|
|
58
|
+
|
|
59
|
+
## Providers
|
|
60
|
+
|
|
61
|
+
| Provider | Auth | Example |
|
|
62
|
+
|----------|------|---------|
|
|
63
|
+
| Ollama | None (local) | `vaal -m qwen3:8b` |
|
|
64
|
+
| Anthropic | API key or Max/Pro OAuth | `vaal -m anthropic:claude-opus-4-6` |
|
|
65
|
+
| OpenAI | API key | `vaal -m openai:gpt-4o` |
|
|
66
|
+
| Groq | API key | `vaal -m groq:llama-3.3-70b-versatile` |
|
|
67
|
+
| OpenRouter | API key | `vaal -m openrouter:anthropic/claude-sonnet-4` |
|
|
68
|
+
| DeepSeek | API key | `vaal -m deepseek:deepseek-chat` |
|
|
69
|
+
| Together | API key | `vaal -m together:meta-llama/Llama-3.3-70B` |
|
|
70
|
+
|
|
71
|
+
## Key Commands
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
/help — All commands
|
|
75
|
+
/login — Add API key
|
|
76
|
+
/register — Create vaal account
|
|
77
|
+
/commit — Auto-generate commit message
|
|
78
|
+
/test — Run tests, auto-fix failures
|
|
79
|
+
/pr — Create pull request
|
|
80
|
+
/pin <file> — Keep file in context
|
|
81
|
+
/remote — Control from browser
|
|
82
|
+
/plugin create — Create custom tools
|
|
83
|
+
/effort — Set inference level
|
|
84
|
+
/doctor — System diagnostics
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Requirements
|
|
88
|
+
|
|
89
|
+
- Python 3.11+
|
|
90
|
+
- httpx, rich (auto-installed)
|
|
91
|
+
- Ollama (optional, for local models)
|
|
92
|
+
- Git (optional, for git commands)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "vaal-code"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "AI coding agent CLI — local LLMs via Ollama or cloud models via API"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {text = "MIT"}
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
dependencies = [
|
|
13
|
+
"httpx>=0.25.0",
|
|
14
|
+
"rich>=13.0.0",
|
|
15
|
+
]
|
|
16
|
+
[project.optional-dependencies]
|
|
17
|
+
voice = ["SpeechRecognition"]
|
|
18
|
+
|
|
19
|
+
[project.scripts]
|
|
20
|
+
vaal = "vaal.__main__:main"
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
Homepage = "https://e-e.tools/vaal"
|
|
24
|
+
Repository = "https://github.com/0xE666/vaal"
|
|
25
|
+
|
|
26
|
+
[tool.setuptools.dynamic]
|
|
27
|
+
version = {attr = "vaal.__version__"}
|
|
28
|
+
|
|
29
|
+
[tool.setuptools.packages.find]
|
|
30
|
+
include = ["vaal*"]
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
"""Comprehensive test of all vaal features."""
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
import json
|
|
5
|
+
import tempfile
|
|
6
|
+
import shutil
|
|
7
|
+
|
|
8
|
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
|
|
9
|
+
os.chdir(os.path.join(os.path.dirname(__file__), ".."))
|
|
10
|
+
|
|
11
|
+
R = {}
|
|
12
|
+
|
|
13
|
+
def t(name, cond):
|
|
14
|
+
R[name] = bool(cond)
|
|
15
|
+
print(f' {"OK" if cond else "FAIL"}: {name}')
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# ── TOOLS ──────────────────────────────────────────────
|
|
19
|
+
|
|
20
|
+
td = tempfile.mkdtemp(prefix="vt_")
|
|
21
|
+
os.makedirs(os.path.join(td, "src"))
|
|
22
|
+
hp = os.path.join(td, "src/hello.py")
|
|
23
|
+
open(hp, "w").write('def greet(name):\n return f"Hello, {name}!"\nclass Foo:\n pass\n')
|
|
24
|
+
open(os.path.join(td, "src/util.py"), "w").write("import os\ndef get_cwd():\n return os.getcwd()\n")
|
|
25
|
+
open(os.path.join(td, "notes.md"), "w").write("# Notes\n")
|
|
26
|
+
|
|
27
|
+
print("=== BASH ===")
|
|
28
|
+
from vaal.tools.bash_tool import bash_tool
|
|
29
|
+
t("bash:echo", "hello" in bash_tool(command="echo hello"))
|
|
30
|
+
t("bash:ver", "Python" in bash_tool(command="python --version"))
|
|
31
|
+
|
|
32
|
+
print("=== FILE TOOLS ===")
|
|
33
|
+
from vaal.tools.file_tools import read_tool, write_tool, edit_tool
|
|
34
|
+
t("read", "def greet" in read_tool(file_path=hp))
|
|
35
|
+
t("read:miss", "error" in read_tool(file_path="/no/file").lower())
|
|
36
|
+
nf = os.path.join(td, "o.txt")
|
|
37
|
+
write_tool(file_path=nf, content="ok")
|
|
38
|
+
t("write", open(nf).read() == "ok")
|
|
39
|
+
edit_tool(file_path=hp, old_string="Hello", new_string="Hi")
|
|
40
|
+
t("edit", "Hi" in open(hp).read())
|
|
41
|
+
t("edit:miss", "not found" in edit_tool(file_path=hp, old_string="ZZ", new_string="x").lower())
|
|
42
|
+
|
|
43
|
+
print("=== SEARCH ===")
|
|
44
|
+
from vaal.tools.search_tools import glob_tool, grep_tool
|
|
45
|
+
t("glob", "hello.py" in glob_tool(pattern="**/*.py", path=td))
|
|
46
|
+
t("grep", "hello.py" in grep_tool(pattern="def greet", path=td))
|
|
47
|
+
|
|
48
|
+
print("=== LSP ===")
|
|
49
|
+
from vaal.tools.lsp_tools import find_definition, find_references, list_symbols, file_tree
|
|
50
|
+
t("lsp:def", "greet" in find_definition(symbol="greet", path=td))
|
|
51
|
+
t("lsp:refs", "greet" in find_references(symbol="greet", path=td))
|
|
52
|
+
t("lsp:sym", "greet" in list_symbols(file_path=hp))
|
|
53
|
+
t("lsp:tree", "src" in file_tree(path=td))
|
|
54
|
+
|
|
55
|
+
print("=== DIFF ===")
|
|
56
|
+
from vaal.tools.diff_tools import show_diff
|
|
57
|
+
f1, f2 = os.path.join(td, "a.txt"), os.path.join(td, "b.txt")
|
|
58
|
+
open(f1, "w").write("a\nb\n")
|
|
59
|
+
open(f2, "w").write("a\nc\n")
|
|
60
|
+
r = show_diff(file_a=f1, file_b=f2)
|
|
61
|
+
t("diff", "b" in r or "c" in r)
|
|
62
|
+
|
|
63
|
+
print("=== WEB ===")
|
|
64
|
+
from vaal.tools.web_tools import web_fetch, web_search
|
|
65
|
+
t("web:fetch", len(web_fetch(url="https://httpbin.org/get")) > 10)
|
|
66
|
+
t("web:search", len(web_search(query="python")) > 10)
|
|
67
|
+
|
|
68
|
+
print("=== MEMORY TOOLS ===")
|
|
69
|
+
from vaal.tools.memory_tools import save_memory_tool, search_memory_tool, list_memories_tool
|
|
70
|
+
save_memory_tool(name="_vt", content="t", memory_type="project", description="t")
|
|
71
|
+
t("mem:save", True)
|
|
72
|
+
t("mem:list", len(list_memories_tool()) >= 0)
|
|
73
|
+
t("mem:search", True)
|
|
74
|
+
|
|
75
|
+
print("=== NOTEBOOK ===")
|
|
76
|
+
from vaal.tools.notebook_tools import run_python, notebook_read, notebook_edit
|
|
77
|
+
t("py:print", "4" in run_python(code="print(2+2)"))
|
|
78
|
+
t("py:err", "Error" in run_python(code="1/0"))
|
|
79
|
+
t("py:expr", "[1, 2, 3]" in run_python(code="[1,2,3]"))
|
|
80
|
+
nbp = os.path.join(td, "t.ipynb")
|
|
81
|
+
json.dump({"nbformat": 4, "nbformat_minor": 5, "metadata": {}, "cells": [
|
|
82
|
+
{"cell_type": "code", "metadata": {}, "source": ["x=1"], "execution_count": None, "outputs": []}
|
|
83
|
+
]}, open(nbp, "w"))
|
|
84
|
+
t("nb:read", "x=1" in notebook_read(path=nbp))
|
|
85
|
+
notebook_edit(path=nbp, action="insert_after", cell_index="0", content="y=2")
|
|
86
|
+
t("nb:edit", "2 cells" in notebook_read(path=nbp))
|
|
87
|
+
notebook_edit(path=nbp, action="replace", cell_index="0", content="z=3")
|
|
88
|
+
t("nb:replace", "z=3" in notebook_read(path=nbp, cell_index="0"))
|
|
89
|
+
notebook_edit(path=nbp, action="delete", cell_index="1")
|
|
90
|
+
t("nb:delete", "1 cells" in notebook_read(path=nbp))
|
|
91
|
+
|
|
92
|
+
print("=== SSH ===")
|
|
93
|
+
from vaal.tools.ssh_tools import ssh_exec
|
|
94
|
+
t("ssh:nc", "not connected" in ssh_exec(command="hi").lower())
|
|
95
|
+
|
|
96
|
+
print("=== TODO ===")
|
|
97
|
+
from vaal.core.task_manager import reset_task_manager
|
|
98
|
+
from vaal.tools.todo_tools import todo_create, todo_update, todo_list
|
|
99
|
+
reset_task_manager()
|
|
100
|
+
r = json.loads(todo_create(title="T"))
|
|
101
|
+
t("todo:create", r["status"] == "pending")
|
|
102
|
+
r2 = json.loads(todo_update(id=r["id"], status="completed"))
|
|
103
|
+
t("todo:update", r2["status"] == "completed")
|
|
104
|
+
t("todo:list", len(json.loads(todo_list())["todos"]) == 1)
|
|
105
|
+
|
|
106
|
+
print("=== AGENT TOOLS ===")
|
|
107
|
+
from vaal.tools.agent_tools import check_agent, list_agents, AGENT_TYPES
|
|
108
|
+
t("agent:types", len(AGENT_TYPES) == 5)
|
|
109
|
+
t("agent:list", "agents" in json.loads(list_agents()))
|
|
110
|
+
t("agent:miss", "error" in json.loads(check_agent(agent_id="xx")))
|
|
111
|
+
|
|
112
|
+
print("=== API ===")
|
|
113
|
+
from vaal.tools.api_tools import api_request, handle_api_command
|
|
114
|
+
t("api:get", len(api_request(method="GET", url="https://httpbin.org/get")) > 10)
|
|
115
|
+
t("api:hist", isinstance(handle_api_command("history"), str))
|
|
116
|
+
|
|
117
|
+
print("=== DB ===")
|
|
118
|
+
from vaal.tools.db_tools import handle_db_command
|
|
119
|
+
t("db:cmd", len(handle_db_command("")) > 0)
|
|
120
|
+
|
|
121
|
+
# ── CORE ──────────────────────────────────────────────
|
|
122
|
+
|
|
123
|
+
print("\n=== SESSION ===")
|
|
124
|
+
from vaal.core.session import Session
|
|
125
|
+
s = Session(model="test")
|
|
126
|
+
s.add_message("user", "hello")
|
|
127
|
+
s.add_message("assistant", "hi")
|
|
128
|
+
t("session:add", len(s.messages) == 2)
|
|
129
|
+
t("session:chat", len(s.get_chat_messages()) == 2)
|
|
130
|
+
s.save()
|
|
131
|
+
s2 = Session.load(s.session_id)
|
|
132
|
+
t("session:load", len(s2.messages) == 2)
|
|
133
|
+
t("session:list", isinstance(Session.list_sessions(), list))
|
|
134
|
+
|
|
135
|
+
print("=== CONTEXT ===")
|
|
136
|
+
from vaal.core.context import ContextManager, estimate_tokens, estimate_messages_tokens
|
|
137
|
+
cm = ContextManager(max_tokens=1000)
|
|
138
|
+
t("ctx:est", estimate_tokens("hello world") > 0)
|
|
139
|
+
t("ctx:pct", cm.usage_pct([{"role": "user", "content": "hi"}]) >= 0)
|
|
140
|
+
|
|
141
|
+
print("=== COST ===")
|
|
142
|
+
from vaal.core.cost_tracker import CostTracker
|
|
143
|
+
ct = CostTracker()
|
|
144
|
+
ct.record(label="t", input_tokens=100, output_tokens=50)
|
|
145
|
+
t("cost:total", ct.total_tokens == 150)
|
|
146
|
+
t("cost:summary", len(ct.summary()) > 0)
|
|
147
|
+
|
|
148
|
+
print("=== HISTORY ===")
|
|
149
|
+
from vaal.core.history import record_prompt, load_history, format_history
|
|
150
|
+
record_prompt("test", "m", "s")
|
|
151
|
+
t("hist:load", isinstance(load_history(limit=5), list))
|
|
152
|
+
t("hist:format", isinstance(format_history(load_history()), str))
|
|
153
|
+
|
|
154
|
+
print("=== AUTO_FIX ===")
|
|
155
|
+
from vaal.core.auto_fix import is_enabled, toggle, detect_bash_failure, build_fix_prompt
|
|
156
|
+
t("fix:enabled", isinstance(is_enabled(), bool))
|
|
157
|
+
old = is_enabled()
|
|
158
|
+
toggle()
|
|
159
|
+
t("fix:toggle", is_enabled() != old)
|
|
160
|
+
toggle()
|
|
161
|
+
t("fix:detect_ok", detect_bash_failure("read", "ok") is None)
|
|
162
|
+
t("fix:detect_err", detect_bash_failure("bash", "[exit code: 1] not found") is not None)
|
|
163
|
+
t("fix:detect_err2", detect_bash_failure("bash", "[error: timeout]") is not None)
|
|
164
|
+
t("fix:prompt", len(build_fix_prompt("ls", "not found", 1)) > 0)
|
|
165
|
+
|
|
166
|
+
print("=== BOOTSTRAP ===")
|
|
167
|
+
from vaal.core.bootstrap import scan_project
|
|
168
|
+
pi = scan_project(os.getcwd())
|
|
169
|
+
t("boot:scan", pi is not None)
|
|
170
|
+
|
|
171
|
+
print("=== USER_CONFIG ===")
|
|
172
|
+
from vaal.core.user_config import UserConfig
|
|
173
|
+
uc = UserConfig()
|
|
174
|
+
t("config:model", isinstance(uc.default_model, str))
|
|
175
|
+
t("config:dict", isinstance(uc.as_dict(), dict))
|
|
176
|
+
|
|
177
|
+
print("=== KEYBINDINGS ===")
|
|
178
|
+
from vaal.core.keybindings import KeybindingManager
|
|
179
|
+
kb = KeybindingManager()
|
|
180
|
+
t("keys:all", isinstance(kb.all_bindings(), dict))
|
|
181
|
+
t("keys:table", len(kb.format_table()) > 0)
|
|
182
|
+
|
|
183
|
+
print("=== VIM ===")
|
|
184
|
+
from vaal.core.vim_mode import VimMode
|
|
185
|
+
vm = VimMode()
|
|
186
|
+
t("vim:init", not vm.enabled)
|
|
187
|
+
vm.toggle()
|
|
188
|
+
t("vim:toggle", vm.enabled)
|
|
189
|
+
vm.toggle()
|
|
190
|
+
|
|
191
|
+
print("=== OUTPUT STYLES ===")
|
|
192
|
+
from vaal.core.output_styles import OutputStyleManager
|
|
193
|
+
osm = OutputStyleManager()
|
|
194
|
+
t("style:current", osm.current == "default")
|
|
195
|
+
t("style:avail", len(osm.available_styles()) > 0)
|
|
196
|
+
|
|
197
|
+
print("=== THEMES ===")
|
|
198
|
+
from vaal.core.terminal_theme import get_theme_names, get_theme, load_preference
|
|
199
|
+
t("theme:names", len(get_theme_names()) >= 5)
|
|
200
|
+
t("theme:get", get_theme("vaal") is not None)
|
|
201
|
+
|
|
202
|
+
print("=== PLANS ===")
|
|
203
|
+
from vaal.core.plans import create_plan, list_plans
|
|
204
|
+
plan = create_plan(title="Test", step_descriptions=["S1", "S2", "S3"])
|
|
205
|
+
t("plan:create", plan is not None)
|
|
206
|
+
t("plan:progress", "0/3" in plan.progress)
|
|
207
|
+
plan.advance()
|
|
208
|
+
t("plan:advance", "1/3" in plan.progress)
|
|
209
|
+
|
|
210
|
+
print("=== MEMORY STORE ===")
|
|
211
|
+
from vaal.core.memory import MemoryStore
|
|
212
|
+
ms = MemoryStore()
|
|
213
|
+
t("memstore:list", isinstance(ms.list_memories(), list))
|
|
214
|
+
|
|
215
|
+
print("=== BRANCHING ===")
|
|
216
|
+
from vaal.core.branching import BranchManager
|
|
217
|
+
bm = BranchManager()
|
|
218
|
+
bm.create_branch("test-b", [{"role": "user", "content": "hi"}])
|
|
219
|
+
t("branch:create", bm.has_branch("test-b"))
|
|
220
|
+
t("branch:list", len(bm.list_branches()) > 0)
|
|
221
|
+
|
|
222
|
+
print("=== MULTILINE ===")
|
|
223
|
+
from vaal.core.multiline import is_multiline_trigger
|
|
224
|
+
t("multi:triple", is_multiline_trigger('"""'))
|
|
225
|
+
t("multi:normal", not is_multiline_trigger("hello"))
|
|
226
|
+
|
|
227
|
+
print("=== SKILLS ===")
|
|
228
|
+
from vaal.core.skills import load_skills
|
|
229
|
+
t("skills:load", isinstance(load_skills(), list))
|
|
230
|
+
|
|
231
|
+
print("=== HOOKS ===")
|
|
232
|
+
from vaal.core.hooks import load_hooks, run_hooks
|
|
233
|
+
hooks = load_hooks()
|
|
234
|
+
t("hooks:load", isinstance(hooks, (dict, list)))
|
|
235
|
+
run_hooks("pre_tool", {"tool_name": "test"}, hooks)
|
|
236
|
+
t("hooks:run", True)
|
|
237
|
+
|
|
238
|
+
print("=== TASK_MANAGER ===")
|
|
239
|
+
reset_task_manager()
|
|
240
|
+
from vaal.core.task_manager import get_task_manager, TaskStatus
|
|
241
|
+
tm = get_task_manager()
|
|
242
|
+
task = tm.create(title="T")
|
|
243
|
+
t("tm:create", task.title == "T")
|
|
244
|
+
tm.update(task.id, status=TaskStatus.IN_PROGRESS)
|
|
245
|
+
t("tm:update", tm.get(task.id).status == TaskStatus.IN_PROGRESS)
|
|
246
|
+
tm.complete(task.id)
|
|
247
|
+
t("tm:complete", tm.get(task.id).status == TaskStatus.COMPLETED)
|
|
248
|
+
t("tm:summary", "1/1" in tm.summary)
|
|
249
|
+
|
|
250
|
+
print("=== AGENT POOL ===")
|
|
251
|
+
from vaal.core.agent import AgentPool, reset_agent_pool
|
|
252
|
+
reset_agent_pool()
|
|
253
|
+
pool = AgentPool()
|
|
254
|
+
t("pool:empty", pool.total_count == 0)
|
|
255
|
+
|
|
256
|
+
print("=== SCHEDULER ===")
|
|
257
|
+
from vaal.core.scheduler import get_scheduler
|
|
258
|
+
sched = get_scheduler()
|
|
259
|
+
t("sched:list", len(sched.list_tasks()) == 0)
|
|
260
|
+
|
|
261
|
+
print("=== COLLAB ===")
|
|
262
|
+
from vaal.core.collaborative import collab_start, collab_leave, collab_info
|
|
263
|
+
ok, code = collab_start()
|
|
264
|
+
t("collab:start", ok)
|
|
265
|
+
t("collab:info", collab_info() is not None)
|
|
266
|
+
collab_leave()
|
|
267
|
+
t("collab:leave", collab_info() is None)
|
|
268
|
+
|
|
269
|
+
print("=== PERMISSIONS ===")
|
|
270
|
+
from vaal.core.permissions import PermissionManager
|
|
271
|
+
pm = PermissionManager(mode="auto")
|
|
272
|
+
t("perm:safe", not pm.needs_approval("read"))
|
|
273
|
+
t("perm:danger", pm.needs_approval("bash"))
|
|
274
|
+
pm.approve("bash", remember=True)
|
|
275
|
+
t("perm:approve", not pm.needs_approval("bash"))
|
|
276
|
+
pm2 = PermissionManager(mode="yolo")
|
|
277
|
+
t("perm:yolo", not pm2.needs_approval("bash"))
|
|
278
|
+
pm3 = PermissionManager(mode="auto")
|
|
279
|
+
pm3.deny_tool("grep")
|
|
280
|
+
t("perm:deny", pm3.is_denied("grep"))
|
|
281
|
+
pm3.deny_prefix("git_")
|
|
282
|
+
t("perm:pfx", pm3.is_denied("git_commit"))
|
|
283
|
+
|
|
284
|
+
print("=== PLUGINS ===")
|
|
285
|
+
from vaal.core.plugins import load_plugins
|
|
286
|
+
t("plugins:load", isinstance(load_plugins(), list))
|
|
287
|
+
|
|
288
|
+
print("=== MCP ===")
|
|
289
|
+
from vaal.core.mcp_client import get_mcp_manager
|
|
290
|
+
mgr = get_mcp_manager()
|
|
291
|
+
t("mcp:list", isinstance(mgr.list_servers(), list))
|
|
292
|
+
|
|
293
|
+
print("=== UNDO ===")
|
|
294
|
+
from vaal.core.undo_system import get_undo_system
|
|
295
|
+
undo = get_undo_system()
|
|
296
|
+
undo.clear() # Clear any state from earlier tests
|
|
297
|
+
t("undo:empty", not undo.undo()[0])
|
|
298
|
+
t("redo:empty", not undo.redo()[0])
|
|
299
|
+
|
|
300
|
+
print("=== ENV_MANAGER ===")
|
|
301
|
+
from vaal.core.env_manager import EnvManager
|
|
302
|
+
em = EnvManager()
|
|
303
|
+
t("env:list", len(em.list_env()) > 0)
|
|
304
|
+
t("env:cmd", len(em.handle_command("")) > 0)
|
|
305
|
+
|
|
306
|
+
print("=== SPLIT_PANE ===")
|
|
307
|
+
from vaal.core.split_pane import SplitPane
|
|
308
|
+
sp = SplitPane()
|
|
309
|
+
t("split:cmd", len(sp.handle_command("")) > 0)
|
|
310
|
+
|
|
311
|
+
print("=== NOTIFICATIONS ===")
|
|
312
|
+
from vaal.core.notifications import get_notification_manager
|
|
313
|
+
nm = get_notification_manager()
|
|
314
|
+
t("notify:cmd", len(nm.handle_command("")) > 0)
|
|
315
|
+
|
|
316
|
+
print("=== ERROR_EXPLAIN ===")
|
|
317
|
+
from vaal.core.error_explain import detect_error, build_explain_prompt
|
|
318
|
+
t("err:yes", detect_error("Traceback (most recent call last):"))
|
|
319
|
+
t("err:no", not detect_error("all good"))
|
|
320
|
+
t("err:prompt", len(build_explain_prompt("TypeError: bad")) > 0)
|
|
321
|
+
|
|
322
|
+
print("=== MIGRATION ===")
|
|
323
|
+
from vaal.core.migration import get_migration_profile
|
|
324
|
+
t("migrate:flask", get_migration_profile("flask", "fastapi") is not None)
|
|
325
|
+
t("migrate:none", get_migration_profile("x", "y") is None)
|
|
326
|
+
|
|
327
|
+
print("=== CODE_REVIEW ===")
|
|
328
|
+
from vaal.core.code_review import build_review_prompt, parse_review_response
|
|
329
|
+
t("review:prompt", len(build_review_prompt("diff")) > 0)
|
|
330
|
+
parsed = parse_review_response("[CRITICAL] f.py:10\nSQL injection\n-> parameterize")
|
|
331
|
+
t("review:parse", len(parsed) > 0 and parsed[0].severity.value == "critical")
|
|
332
|
+
|
|
333
|
+
print("=== DEPS ===")
|
|
334
|
+
from vaal.core.deps import scan_dep_files, format_dep_report
|
|
335
|
+
deps = scan_dep_files()
|
|
336
|
+
t("deps:scan", isinstance(deps, list))
|
|
337
|
+
|
|
338
|
+
print("=== COT_DISPLAY ===")
|
|
339
|
+
from vaal.core.cot_display import CotDisplay
|
|
340
|
+
t("cot:init", CotDisplay() is not None)
|
|
341
|
+
|
|
342
|
+
print("=== PROGRESS ===")
|
|
343
|
+
from vaal.core.progress import get_progress_tracker
|
|
344
|
+
t("progress:init", get_progress_tracker().active_count == 0)
|
|
345
|
+
|
|
346
|
+
print("=== CLIPBOARD ===")
|
|
347
|
+
from vaal.core.clipboard import copy_to_clipboard, paste_from_clipboard
|
|
348
|
+
copy_to_clipboard("vaal_test_123")
|
|
349
|
+
t("clip:copy", True)
|
|
350
|
+
t("clip:paste", "vaal_test_123" in (paste_from_clipboard() or ""))
|
|
351
|
+
|
|
352
|
+
print("=== IMAGE_INPUT ===")
|
|
353
|
+
from vaal.core.image_input import is_image_path, encode_image, build_image_message, build_ollama_image_message, get_clipboard_image
|
|
354
|
+
t("img:path_yes", is_image_path("photo.png"))
|
|
355
|
+
t("img:path_no", not is_image_path("readme.md"))
|
|
356
|
+
t("img:clipboard", True) # just verify no crash
|
|
357
|
+
get_clipboard_image()
|
|
358
|
+
|
|
359
|
+
print("=== SSH_REMOTE ===")
|
|
360
|
+
from vaal.core.ssh_remote import get_ssh_manager
|
|
361
|
+
sm = get_ssh_manager()
|
|
362
|
+
t("sshm:info", sm.info() is None) # not connected
|
|
363
|
+
t("sshm:connected", not sm.is_connected)
|
|
364
|
+
|
|
365
|
+
# ── CLEANUP & SUMMARY ──────────────────────────────────
|
|
366
|
+
|
|
367
|
+
try:
|
|
368
|
+
shutil.rmtree(td, ignore_errors=True)
|
|
369
|
+
except Exception:
|
|
370
|
+
pass
|
|
371
|
+
|
|
372
|
+
passed = sum(1 for v in R.values() if v)
|
|
373
|
+
failed = sum(1 for v in R.values() if not v)
|
|
374
|
+
print(f"\n{'=' * 50}")
|
|
375
|
+
print(f" {passed}/{len(R)} PASSED, {failed} FAILED")
|
|
376
|
+
print(f"{'=' * 50}")
|
|
377
|
+
if failed:
|
|
378
|
+
print("FAILURES:")
|
|
379
|
+
for k, v in R.items():
|
|
380
|
+
if not v:
|
|
381
|
+
print(f" FAIL: {k}")
|
|
382
|
+
sys.exit(1)
|