spark-agent 0.9.6__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.
- spark_agent-0.9.6/LICENSE +21 -0
- spark_agent-0.9.6/PKG-INFO +199 -0
- spark_agent-0.9.6/README.md +145 -0
- spark_agent-0.9.6/pyproject.toml +129 -0
- spark_agent-0.9.6/setup.cfg +4 -0
- spark_agent-0.9.6/src/spark/__init__.py +14 -0
- spark_agent-0.9.6/src/spark/__main__.py +4 -0
- spark_agent-0.9.6/src/spark/agents.py +184 -0
- spark_agent-0.9.6/src/spark/asyncutil.py +55 -0
- spark_agent-0.9.6/src/spark/cli.py +820 -0
- spark_agent-0.9.6/src/spark/config.py +813 -0
- spark_agent-0.9.6/src/spark/core/__init__.py +3 -0
- spark_agent-0.9.6/src/spark/core/checkpoints.py +429 -0
- spark_agent-0.9.6/src/spark/core/compact.py +497 -0
- spark_agent-0.9.6/src/spark/core/context.py +335 -0
- spark_agent-0.9.6/src/spark/core/context_profile.py +139 -0
- spark_agent-0.9.6/src/spark/core/graph.py +381 -0
- spark_agent-0.9.6/src/spark/core/loop.py +1135 -0
- spark_agent-0.9.6/src/spark/core/tokens.py +40 -0
- spark_agent-0.9.6/src/spark/desktop.py +127 -0
- spark_agent-0.9.6/src/spark/edit/__init__.py +48 -0
- spark_agent-0.9.6/src/spark/edit/ast_check.py +109 -0
- spark_agent-0.9.6/src/spark/edit/core.py +248 -0
- spark_agent-0.9.6/src/spark/edit/tool.py +148 -0
- spark_agent-0.9.6/src/spark/errors.py +10 -0
- spark_agent-0.9.6/src/spark/evals/__init__.py +21 -0
- spark_agent-0.9.6/src/spark/evals/__main__.py +64 -0
- spark_agent-0.9.6/src/spark/evals/data/swe_lite_real_subset.json +74 -0
- spark_agent-0.9.6/src/spark/evals/download_real.py +59 -0
- spark_agent-0.9.6/src/spark/evals/harness.py +413 -0
- spark_agent-0.9.6/src/spark/evals/scenarios.py +246 -0
- spark_agent-0.9.6/src/spark/git_memory.py +293 -0
- spark_agent-0.9.6/src/spark/hooks.py +147 -0
- spark_agent-0.9.6/src/spark/mcp_expose.py +108 -0
- spark_agent-0.9.6/src/spark/mcp_registry.py +429 -0
- spark_agent-0.9.6/src/spark/memory/__init__.py +0 -0
- spark_agent-0.9.6/src/spark/memory/extractor.py +265 -0
- spark_agent-0.9.6/src/spark/memory/llm.py +108 -0
- spark_agent-0.9.6/src/spark/memory/service.py +443 -0
- spark_agent-0.9.6/src/spark/memory/store.py +851 -0
- spark_agent-0.9.6/src/spark/model_catalog.py +161 -0
- spark_agent-0.9.6/src/spark/models.py +74 -0
- spark_agent-0.9.6/src/spark/onboard.py +320 -0
- spark_agent-0.9.6/src/spark/otel.py +93 -0
- spark_agent-0.9.6/src/spark/platform_compat.py +23 -0
- spark_agent-0.9.6/src/spark/policy.py +261 -0
- spark_agent-0.9.6/src/spark/prompts/system.md +33 -0
- spark_agent-0.9.6/src/spark/providers/__init__.py +19 -0
- spark_agent-0.9.6/src/spark/providers/base.py +14 -0
- spark_agent-0.9.6/src/spark/providers/factory.py +43 -0
- spark_agent-0.9.6/src/spark/providers/mock.py +55 -0
- spark_agent-0.9.6/src/spark/providers/openai_compat.py +453 -0
- spark_agent-0.9.6/src/spark/providers/probe.py +188 -0
- spark_agent-0.9.6/src/spark/providers/routing.py +347 -0
- spark_agent-0.9.6/src/spark/pty/__init__.py +307 -0
- spark_agent-0.9.6/src/spark/repo_map.py +288 -0
- spark_agent-0.9.6/src/spark/sandbox.py +273 -0
- spark_agent-0.9.6/src/spark/sanitize.py +104 -0
- spark_agent-0.9.6/src/spark/skills.py +103 -0
- spark_agent-0.9.6/src/spark/slash.py +159 -0
- spark_agent-0.9.6/src/spark/store.py +771 -0
- spark_agent-0.9.6/src/spark/structured.py +168 -0
- spark_agent-0.9.6/src/spark/tools/__init__.py +3 -0
- spark_agent-0.9.6/src/spark/tools/_common.py +16 -0
- spark_agent-0.9.6/src/spark/tools/bg.py +310 -0
- spark_agent-0.9.6/src/spark/tools/diagnostics.py +149 -0
- spark_agent-0.9.6/src/spark/tools/fs.py +249 -0
- spark_agent-0.9.6/src/spark/tools/gitops.py +379 -0
- spark_agent-0.9.6/src/spark/tools/mcp_bridge.py +427 -0
- spark_agent-0.9.6/src/spark/tools/notebook.py +123 -0
- spark_agent-0.9.6/src/spark/tools/registry.py +537 -0
- spark_agent-0.9.6/src/spark/tools/search.py +269 -0
- spark_agent-0.9.6/src/spark/tools/shell.py +297 -0
- spark_agent-0.9.6/src/spark/tools/untrusted.py +44 -0
- spark_agent-0.9.6/src/spark/tools/web.py +246 -0
- spark_agent-0.9.6/src/spark/tui/__init__.py +3 -0
- spark_agent-0.9.6/src/spark/tui/app.py +584 -0
- spark_agent-0.9.6/src/spark/tui/welcome.py +126 -0
- spark_agent-0.9.6/src/spark/web/__init__.py +3 -0
- spark_agent-0.9.6/src/spark/web/_handlers.py +862 -0
- spark_agent-0.9.6/src/spark/web/_httpbase.py +26 -0
- spark_agent-0.9.6/src/spark/web/_routing.py +12 -0
- spark_agent-0.9.6/src/spark/web/api_spec.py +162 -0
- spark_agent-0.9.6/src/spark/web/dist/assets/SettingsModal-C3YLub9B.js +4 -0
- spark_agent-0.9.6/src/spark/web/dist/assets/highlight-CBGBLn5w.js +5 -0
- spark_agent-0.9.6/src/spark/web/dist/assets/index-DG4oXX01.js +42 -0
- spark_agent-0.9.6/src/spark/web/dist/assets/index-SPHoMi93.css +1 -0
- spark_agent-0.9.6/src/spark/web/dist/assets/markdown-CnxUTuzz.js +29 -0
- spark_agent-0.9.6/src/spark/web/dist/assets/react-DyzINgAZ.js +9 -0
- spark_agent-0.9.6/src/spark/web/dist/favicon.svg +17 -0
- spark_agent-0.9.6/src/spark/web/dist/index.html +29 -0
- spark_agent-0.9.6/src/spark/web/index.html +253 -0
- spark_agent-0.9.6/src/spark/web/pty_api.py +162 -0
- spark_agent-0.9.6/src/spark/web/routes.py +543 -0
- spark_agent-0.9.6/src/spark/web/server.py +134 -0
- spark_agent-0.9.6/src/spark/web/sse.py +263 -0
- spark_agent-0.9.6/src/spark/web/state.py +363 -0
- spark_agent-0.9.6/src/spark/web/utils.py +175 -0
- spark_agent-0.9.6/src/spark_agent.egg-info/PKG-INFO +199 -0
- spark_agent-0.9.6/src/spark_agent.egg-info/SOURCES.txt +172 -0
- spark_agent-0.9.6/src/spark_agent.egg-info/dependency_links.txt +1 -0
- spark_agent-0.9.6/src/spark_agent.egg-info/entry_points.txt +2 -0
- spark_agent-0.9.6/src/spark_agent.egg-info/requires.txt +43 -0
- spark_agent-0.9.6/src/spark_agent.egg-info/top_level.txt +1 -0
- spark_agent-0.9.6/tests/test_acl_predicate.py +53 -0
- spark_agent-0.9.6/tests/test_adversarial_security.py +464 -0
- spark_agent-0.9.6/tests/test_approval_and_ssrf.py +160 -0
- spark_agent-0.9.6/tests/test_checkpoints.py +130 -0
- spark_agent-0.9.6/tests/test_cli_onboarding.py +234 -0
- spark_agent-0.9.6/tests/test_compaction.py +148 -0
- spark_agent-0.9.6/tests/test_config_acl.py +72 -0
- spark_agent-0.9.6/tests/test_config_provenance.py +106 -0
- spark_agent-0.9.6/tests/test_context.py +148 -0
- spark_agent-0.9.6/tests/test_desktop.py +40 -0
- spark_agent-0.9.6/tests/test_e2e_pipeline.py +334 -0
- spark_agent-0.9.6/tests/test_e2e_server.py +338 -0
- spark_agent-0.9.6/tests/test_exec.py +25 -0
- spark_agent-0.9.6/tests/test_git_bg_persist.py +194 -0
- spark_agent-0.9.6/tests/test_graph_routing.py +142 -0
- spark_agent-0.9.6/tests/test_hooks.py +158 -0
- spark_agent-0.9.6/tests/test_hooks_extended.py +146 -0
- spark_agent-0.9.6/tests/test_langgraph_path.py +172 -0
- spark_agent-0.9.6/tests/test_loop.py +88 -0
- spark_agent-0.9.6/tests/test_mcp.py +82 -0
- spark_agent-0.9.6/tests/test_mcp_bridge_boundary.py +231 -0
- spark_agent-0.9.6/tests/test_mcp_expose.py +54 -0
- spark_agent-0.9.6/tests/test_memory.py +249 -0
- spark_agent-0.9.6/tests/test_memory_store_boundary.py +338 -0
- spark_agent-0.9.6/tests/test_msg_ops.py +85 -0
- spark_agent-0.9.6/tests/test_p0_fixes.py +154 -0
- spark_agent-0.9.6/tests/test_p0_repo_map.py +63 -0
- spark_agent-0.9.6/tests/test_p0_telemetry.py +109 -0
- spark_agent-0.9.6/tests/test_p0_untrusted_sandbox.py +92 -0
- spark_agent-0.9.6/tests/test_p1_01_instructor.py +202 -0
- spark_agent-0.9.6/tests/test_p1_02_searchreplace.py +259 -0
- spark_agent-0.9.6/tests/test_p1_03_testcmd.py +254 -0
- spark_agent-0.9.6/tests/test_p1_04_declsubagent.py +315 -0
- spark_agent-0.9.6/tests/test_p1_05_pty.py +154 -0
- spark_agent-0.9.6/tests/test_p1_06_evals.py +141 -0
- spark_agent-0.9.6/tests/test_p1_07_mcp_registry.py +320 -0
- spark_agent-0.9.6/tests/test_p1_08_gitmemory.py +220 -0
- spark_agent-0.9.6/tests/test_p1_09_security.py +179 -0
- spark_agent-0.9.6/tests/test_p1_10_routing.py +242 -0
- spark_agent-0.9.6/tests/test_p1_capabilities.py +229 -0
- spark_agent-0.9.6/tests/test_p1_fixes.py +490 -0
- spark_agent-0.9.6/tests/test_p1_model_catalog.py +68 -0
- spark_agent-0.9.6/tests/test_p1_provider_resilience.py +153 -0
- spark_agent-0.9.6/tests/test_p2_context_profile.py +65 -0
- spark_agent-0.9.6/tests/test_p2_mcp_resources_prompts.py +77 -0
- spark_agent-0.9.6/tests/test_perf_bounds.py +304 -0
- spark_agent-0.9.6/tests/test_policy.py +83 -0
- spark_agent-0.9.6/tests/test_probe.py +78 -0
- spark_agent-0.9.6/tests/test_prompt_cache.py +99 -0
- spark_agent-0.9.6/tests/test_provider_config.py +63 -0
- spark_agent-0.9.6/tests/test_pty.py +105 -0
- spark_agent-0.9.6/tests/test_pty_http.py +131 -0
- spark_agent-0.9.6/tests/test_registry_scope.py +72 -0
- spark_agent-0.9.6/tests/test_reliability.py +198 -0
- spark_agent-0.9.6/tests/test_sandbox.py +18 -0
- spark_agent-0.9.6/tests/test_sandbox_policy.py +205 -0
- spark_agent-0.9.6/tests/test_sanitize.py +115 -0
- spark_agent-0.9.6/tests/test_search_web.py +90 -0
- spark_agent-0.9.6/tests/test_settings_api.py +180 -0
- spark_agent-0.9.6/tests/test_skills.py +90 -0
- spark_agent-0.9.6/tests/test_store.py +32 -0
- spark_agent-0.9.6/tests/test_store_fork.py +35 -0
- spark_agent-0.9.6/tests/test_task_notebook.py +146 -0
- spark_agent-0.9.6/tests/test_tools.py +63 -0
- spark_agent-0.9.6/tests/test_tui_welcome.py +199 -0
- spark_agent-0.9.6/tests/test_user_journeys.py +284 -0
- spark_agent-0.9.6/tests/test_web_port.py +32 -0
- spark_agent-0.9.6/tests/test_web_sse.py +262 -0
- spark_agent-0.9.6/tests/test_wildcard_permission.py +212 -0
- spark_agent-0.9.6/tests/test_worktree.py +141 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 badhope
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: spark-agent
|
|
3
|
+
Version: 0.9.6
|
|
4
|
+
Summary: Spark [Ember] — local-first coding agent with a Codex-style loop
|
|
5
|
+
License: MIT
|
|
6
|
+
Keywords: ai,agent,coding,local-first,llm,chatbot
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
14
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: chromadb>=1.0
|
|
19
|
+
Requires-Dist: instructor<2.0,>=1.4
|
|
20
|
+
Requires-Dist: litellm<2.0,>=1.0
|
|
21
|
+
Requires-Dist: llama-index-core<1.0,>=0.12
|
|
22
|
+
Requires-Dist: llama-index-llms-openai-like<1.0,>=0.3
|
|
23
|
+
Requires-Dist: httpx<1.0,>=0.27
|
|
24
|
+
Requires-Dist: langgraph<1.0,>=0.3
|
|
25
|
+
Requires-Dist: langgraph-checkpoint-sqlite<3.0,>=2.0
|
|
26
|
+
Requires-Dist: mcp<2.0,>=1.0; python_version >= "3.10"
|
|
27
|
+
Requires-Dist: pydantic<3.0,>=2.7
|
|
28
|
+
Requires-Dist: pydantic-settings<3.0,>=2.0
|
|
29
|
+
Requires-Dist: textual<1.0,>=0.80
|
|
30
|
+
Requires-Dist: tomlkit<1.0,>=0.13
|
|
31
|
+
Requires-Dist: tree-sitter<0.27,>=0.25
|
|
32
|
+
Requires-Dist: tree-sitter-javascript<0.26,>=0.23
|
|
33
|
+
Requires-Dist: tree-sitter-python<0.26,>=0.23
|
|
34
|
+
Requires-Dist: tree-sitter-typescript<0.24,>=0.23
|
|
35
|
+
Requires-Dist: typer<1.0,>=0.12
|
|
36
|
+
Provides-Extra: dev
|
|
37
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
38
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
39
|
+
Requires-Dist: pytest-cov>=4.1; extra == "dev"
|
|
40
|
+
Requires-Dist: ruff>=0.7; extra == "dev"
|
|
41
|
+
Requires-Dist: import-linter>=2.0; extra == "dev"
|
|
42
|
+
Requires-Dist: mypy>=1.11; extra == "dev"
|
|
43
|
+
Requires-Dist: bandit>=1.7; extra == "dev"
|
|
44
|
+
Requires-Dist: pre-commit>=3.6; extra == "dev"
|
|
45
|
+
Provides-Extra: telemetry
|
|
46
|
+
Requires-Dist: opentelemetry-api>=1.28; extra == "telemetry"
|
|
47
|
+
Requires-Dist: opentelemetry-sdk>=1.28; extra == "telemetry"
|
|
48
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-grpc>=1.28; extra == "telemetry"
|
|
49
|
+
Provides-Extra: pty
|
|
50
|
+
Requires-Dist: ptyprocess>=0.7; sys_platform != "win32" and extra == "pty"
|
|
51
|
+
Provides-Extra: desktop
|
|
52
|
+
Requires-Dist: pywebview>=5.0; extra == "desktop"
|
|
53
|
+
Dynamic: license-file
|
|
54
|
+
|
|
55
|
+
> 🌐 [English](README.md) | [中文](README_zh.md)
|
|
56
|
+
|
|
57
|
+
# Spark — Local-first AI Coding Agent
|
|
58
|
+
|
|
59
|
+
[](https://opensource.org/licenses/MIT)
|
|
60
|
+
[](https://www.python.org/)
|
|
61
|
+
[](https://nodejs.org/)
|
|
62
|
+
|
|
63
|
+
**Code stays with you. Keys stay with you.** A self-hosted AI coding assistant that runs entirely on your machine — zero privacy leaks, full control.
|
|
64
|
+
|
|
65
|
+
## Core Values
|
|
66
|
+
|
|
67
|
+
🔒 **Privacy First** — All code, conversation, and memory data stay entirely local. No third-party servers involved.
|
|
68
|
+
⚡ **Four Form Factors** — Web UI, native desktop window, terminal TUI, and scriptable CLI.
|
|
69
|
+
🧠 **Persistent Memory** — A vector memory store that remembers your project preferences, naming conventions, and workflow habits.
|
|
70
|
+
🔬 **Four-Level Sandbox** — From read-only analysis to full access, tunable by risk profile.
|
|
71
|
+
⏮️ **Checkpoint & Rollback** — Workspace snapshots plus conversation restore — jump to any previous state like Git.
|
|
72
|
+
|
|
73
|
+
## Preview
|
|
74
|
+
|
|
75
|
+
### Chat · driven by a real model
|
|
76
|
+
|
|
77
|
+
> SSE streaming, Markdown code blocks, expandable tool-call cards, live context-usage meter.
|
|
78
|
+
> This is a real session: the model read `pyproject.toml` and summarized the project — the `read_file` card shows ✓ Completed.
|
|
79
|
+
|
|
80
|
+

|
|
81
|
+
|
|
82
|
+
### English UI · one-click switch
|
|
83
|
+
|
|
84
|
+
> Built-in Chinese/English localization (Settings → Display → Language). Here the model chained
|
|
85
|
+
> `read_file` + `glob` to survey the repo — both tool calls show Completed.
|
|
86
|
+
|
|
87
|
+

|
|
88
|
+
|
|
89
|
+
### Settings · models and profiles
|
|
90
|
+
|
|
91
|
+
> 8 built-in presets (DeepSeek / Qwen / GLM / Kimi / Doubao / Agnes / Ollama / custom),
|
|
92
|
+
> multiple saved model profiles with one-click switching, a `Test connection` probe, and three reasoning-effort levels.
|
|
93
|
+
|
|
94
|
+

|
|
95
|
+
|
|
96
|
+
### Settings · permissions and sandbox
|
|
97
|
+
|
|
98
|
+
> Four access levels: sandbox-only / workspace (recommended) / full-access / unrestricted,
|
|
99
|
+
> each with an explicit behavior description. The protected-path list is user-editable and defaults to
|
|
100
|
+
> `/etc`, `/root/.spark` and Spark's own source tree.
|
|
101
|
+
|
|
102
|
+

|
|
103
|
+
|
|
104
|
+
### Settings · display and customization
|
|
105
|
+
|
|
106
|
+
> Light/dark/system theme, six display toggles (thinking / tools / plan card / context usage /
|
|
107
|
+
> session keywords / notices), and a **fully customizable system prompt** (empty = built-in default).
|
|
108
|
+
|
|
109
|
+

|
|
110
|
+
|
|
111
|
+
### File viewer · syntax highlighting
|
|
112
|
+
|
|
113
|
+
> Browse the workdir tree and preview files with line numbers and highlight.js syntax highlighting
|
|
114
|
+
> (including correct coloring of multi-line tokens), file sizes, and graceful handling of binary/oversized files.
|
|
115
|
+
|
|
116
|
+

|
|
117
|
+
|
|
118
|
+
### Windows EXE · no install required
|
|
119
|
+
|
|
120
|
+
> Packaged with PyInstaller as a single executable (`dist/spark.exe`) — double-click to run, no Python needed.
|
|
121
|
+
> Shown here: the model really invoked `run_shell`, read back the output `42`, and reported the exit code correctly.
|
|
122
|
+
|
|
123
|
+

|
|
124
|
+
|
|
125
|
+
## Quick Start
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
git clone https://gitcode.com/badhope/spark # 或 GitHub: https://github.com/badhope/spark
|
|
129
|
+
cd spark && python3 -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
130
|
+
pip install -e ".[dev]"
|
|
131
|
+
spark web --workdir /your/project
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Open the printed address in your browser. **Without an API key Spark starts in demo mode (mock);
|
|
135
|
+
paste a key into the web settings and it switches to the real model immediately — no restart.**
|
|
136
|
+
|
|
137
|
+
Windows users can also build a portable EXE (Python 3.11+):
|
|
138
|
+
|
|
139
|
+
```powershell
|
|
140
|
+
powershell -ExecutionPolicy Bypass -File scripts/build-windows.ps1
|
|
141
|
+
dist\spark\spark.exe web # or just double-click dist\spark.exe
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Four Form Factors
|
|
145
|
+
|
|
146
|
+
| Form | Command | Use case |
|
|
147
|
+
|------|---------|----------|
|
|
148
|
+
| Web UI | `spark web` | Everyday chat, file viewer, terminal, execution graph (auto-picks a free port) |
|
|
149
|
+
| Desktop | `spark desktop` | Native window via pywebview, bound to loopback |
|
|
150
|
+
| Terminal TUI | `spark` | Pure terminal environments, remote SSH |
|
|
151
|
+
| CLI / scripts | `spark exec "task"` | Automation, CI, piping |
|
|
152
|
+
| MCP server | `spark mcp-serve` | Expose every built-in tool to other MCP clients |
|
|
153
|
+
|
|
154
|
+
## Feature Overview
|
|
155
|
+
|
|
156
|
+
| Category | Features |
|
|
157
|
+
|----------|----------|
|
|
158
|
+
| Chat | SSE streaming, Markdown code blocks, image attachments, reasoning stream display |
|
|
159
|
+
| Tools | File read/write, apply_edit with AST syntax gate, grep/glob, shell, background jobs, Jupyter, web search/fetch, full Git suite, worktrees |
|
|
160
|
+
| Planning | Multi-step plans (PlanCard visualization), parallel sub-agent delegation (up to 4), declarative sub-agents (`.claude/agents/*.md`) |
|
|
161
|
+
| Approval | Six approval modes (incl. plan-only / approve-plan), `[[permissions]]` wildcard rule engine, three-way approval dialog |
|
|
162
|
+
| Permissions | Four-level sandbox, protected paths, credential-path protection, token-level shell checks, MCP least-privilege allowlists |
|
|
163
|
+
| Memory | AGENTS.md injection, vector long-term memory (embeddings + optional reranker), auto-extraction, web-based management |
|
|
164
|
+
| Persistence | Sessions, checkpoint rollback (works without git), hot config reload, token usage stats |
|
|
165
|
+
| Models | Any OpenAI-compatible endpoint, local Ollama, multi-profile switching, `spark test` probe |
|
|
166
|
+
| Extension | MCP client (stdio/SSE/HTTP + OAuth), MCP registry search (with China-availability ratings), project skills `.spark/skills/`, lifecycle hooks |
|
|
167
|
+
| UI | Chinese/English, light/dark themes, command palette (Ctrl+K), file viewer, built-in terminal, web reader, execution graph, checkpoint panel |
|
|
168
|
+
|
|
169
|
+
## Architecture
|
|
170
|
+
|
|
171
|
+

|
|
172
|
+
|
|
173
|
+
Detailed architecture → [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
|
|
174
|
+
|
|
175
|
+
## Platform Requirements
|
|
176
|
+
|
|
177
|
+
- Python 3.11+
|
|
178
|
+
- Node.js 18+ (frontend development only; the bundled frontend ships prebuilt)
|
|
179
|
+
- Any OpenAI-compatible API (DeepSeek, OpenAI, Ollama, Azure, Agnes, Unisound, SenseNova, …)
|
|
180
|
+
- Windows / macOS / Linux (one-click EXE build on Windows)
|
|
181
|
+
|
|
182
|
+
## Documentation
|
|
183
|
+
|
|
184
|
+
| Document | Contents |
|
|
185
|
+
|----------|----------|
|
|
186
|
+
| [docs/INSTALL.md](docs/INSTALL.md) | Install & packaging (incl. Windows EXE) |
|
|
187
|
+
| [docs/CONFIGURATION.md](docs/CONFIGURATION.md) | Configuration reference (config.toml / env vars / API overview) |
|
|
188
|
+
| [docs/API.md](docs/API.md) | HTTP API and SSE event protocol |
|
|
189
|
+
| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | Architecture notes |
|
|
190
|
+
| [docs/competitive-comparison.md](docs/competitive-comparison.md) | Feature comparison vs Qoder / ZCode / opencode / Codex CLI |
|
|
191
|
+
|
|
192
|
+
## Community
|
|
193
|
+
|
|
194
|
+
- Contributing: [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
195
|
+
- Issue Tracker: use the **Issues** tab of this repository
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
**License:** MIT · **Author:** badhope · **Built with ❤️ in Shenzhen**
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
> 🌐 [English](README.md) | [中文](README_zh.md)
|
|
2
|
+
|
|
3
|
+
# Spark — Local-first AI Coding Agent
|
|
4
|
+
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://www.python.org/)
|
|
7
|
+
[](https://nodejs.org/)
|
|
8
|
+
|
|
9
|
+
**Code stays with you. Keys stay with you.** A self-hosted AI coding assistant that runs entirely on your machine — zero privacy leaks, full control.
|
|
10
|
+
|
|
11
|
+
## Core Values
|
|
12
|
+
|
|
13
|
+
🔒 **Privacy First** — All code, conversation, and memory data stay entirely local. No third-party servers involved.
|
|
14
|
+
⚡ **Four Form Factors** — Web UI, native desktop window, terminal TUI, and scriptable CLI.
|
|
15
|
+
🧠 **Persistent Memory** — A vector memory store that remembers your project preferences, naming conventions, and workflow habits.
|
|
16
|
+
🔬 **Four-Level Sandbox** — From read-only analysis to full access, tunable by risk profile.
|
|
17
|
+
⏮️ **Checkpoint & Rollback** — Workspace snapshots plus conversation restore — jump to any previous state like Git.
|
|
18
|
+
|
|
19
|
+
## Preview
|
|
20
|
+
|
|
21
|
+
### Chat · driven by a real model
|
|
22
|
+
|
|
23
|
+
> SSE streaming, Markdown code blocks, expandable tool-call cards, live context-usage meter.
|
|
24
|
+
> This is a real session: the model read `pyproject.toml` and summarized the project — the `read_file` card shows ✓ Completed.
|
|
25
|
+
|
|
26
|
+

|
|
27
|
+
|
|
28
|
+
### English UI · one-click switch
|
|
29
|
+
|
|
30
|
+
> Built-in Chinese/English localization (Settings → Display → Language). Here the model chained
|
|
31
|
+
> `read_file` + `glob` to survey the repo — both tool calls show Completed.
|
|
32
|
+
|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
### Settings · models and profiles
|
|
36
|
+
|
|
37
|
+
> 8 built-in presets (DeepSeek / Qwen / GLM / Kimi / Doubao / Agnes / Ollama / custom),
|
|
38
|
+
> multiple saved model profiles with one-click switching, a `Test connection` probe, and three reasoning-effort levels.
|
|
39
|
+
|
|
40
|
+

|
|
41
|
+
|
|
42
|
+
### Settings · permissions and sandbox
|
|
43
|
+
|
|
44
|
+
> Four access levels: sandbox-only / workspace (recommended) / full-access / unrestricted,
|
|
45
|
+
> each with an explicit behavior description. The protected-path list is user-editable and defaults to
|
|
46
|
+
> `/etc`, `/root/.spark` and Spark's own source tree.
|
|
47
|
+
|
|
48
|
+

|
|
49
|
+
|
|
50
|
+
### Settings · display and customization
|
|
51
|
+
|
|
52
|
+
> Light/dark/system theme, six display toggles (thinking / tools / plan card / context usage /
|
|
53
|
+
> session keywords / notices), and a **fully customizable system prompt** (empty = built-in default).
|
|
54
|
+
|
|
55
|
+

|
|
56
|
+
|
|
57
|
+
### File viewer · syntax highlighting
|
|
58
|
+
|
|
59
|
+
> Browse the workdir tree and preview files with line numbers and highlight.js syntax highlighting
|
|
60
|
+
> (including correct coloring of multi-line tokens), file sizes, and graceful handling of binary/oversized files.
|
|
61
|
+
|
|
62
|
+

|
|
63
|
+
|
|
64
|
+
### Windows EXE · no install required
|
|
65
|
+
|
|
66
|
+
> Packaged with PyInstaller as a single executable (`dist/spark.exe`) — double-click to run, no Python needed.
|
|
67
|
+
> Shown here: the model really invoked `run_shell`, read back the output `42`, and reported the exit code correctly.
|
|
68
|
+
|
|
69
|
+

|
|
70
|
+
|
|
71
|
+
## Quick Start
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
git clone https://gitcode.com/badhope/spark # 或 GitHub: https://github.com/badhope/spark
|
|
75
|
+
cd spark && python3 -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
76
|
+
pip install -e ".[dev]"
|
|
77
|
+
spark web --workdir /your/project
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Open the printed address in your browser. **Without an API key Spark starts in demo mode (mock);
|
|
81
|
+
paste a key into the web settings and it switches to the real model immediately — no restart.**
|
|
82
|
+
|
|
83
|
+
Windows users can also build a portable EXE (Python 3.11+):
|
|
84
|
+
|
|
85
|
+
```powershell
|
|
86
|
+
powershell -ExecutionPolicy Bypass -File scripts/build-windows.ps1
|
|
87
|
+
dist\spark\spark.exe web # or just double-click dist\spark.exe
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Four Form Factors
|
|
91
|
+
|
|
92
|
+
| Form | Command | Use case |
|
|
93
|
+
|------|---------|----------|
|
|
94
|
+
| Web UI | `spark web` | Everyday chat, file viewer, terminal, execution graph (auto-picks a free port) |
|
|
95
|
+
| Desktop | `spark desktop` | Native window via pywebview, bound to loopback |
|
|
96
|
+
| Terminal TUI | `spark` | Pure terminal environments, remote SSH |
|
|
97
|
+
| CLI / scripts | `spark exec "task"` | Automation, CI, piping |
|
|
98
|
+
| MCP server | `spark mcp-serve` | Expose every built-in tool to other MCP clients |
|
|
99
|
+
|
|
100
|
+
## Feature Overview
|
|
101
|
+
|
|
102
|
+
| Category | Features |
|
|
103
|
+
|----------|----------|
|
|
104
|
+
| Chat | SSE streaming, Markdown code blocks, image attachments, reasoning stream display |
|
|
105
|
+
| Tools | File read/write, apply_edit with AST syntax gate, grep/glob, shell, background jobs, Jupyter, web search/fetch, full Git suite, worktrees |
|
|
106
|
+
| Planning | Multi-step plans (PlanCard visualization), parallel sub-agent delegation (up to 4), declarative sub-agents (`.claude/agents/*.md`) |
|
|
107
|
+
| Approval | Six approval modes (incl. plan-only / approve-plan), `[[permissions]]` wildcard rule engine, three-way approval dialog |
|
|
108
|
+
| Permissions | Four-level sandbox, protected paths, credential-path protection, token-level shell checks, MCP least-privilege allowlists |
|
|
109
|
+
| Memory | AGENTS.md injection, vector long-term memory (embeddings + optional reranker), auto-extraction, web-based management |
|
|
110
|
+
| Persistence | Sessions, checkpoint rollback (works without git), hot config reload, token usage stats |
|
|
111
|
+
| Models | Any OpenAI-compatible endpoint, local Ollama, multi-profile switching, `spark test` probe |
|
|
112
|
+
| Extension | MCP client (stdio/SSE/HTTP + OAuth), MCP registry search (with China-availability ratings), project skills `.spark/skills/`, lifecycle hooks |
|
|
113
|
+
| UI | Chinese/English, light/dark themes, command palette (Ctrl+K), file viewer, built-in terminal, web reader, execution graph, checkpoint panel |
|
|
114
|
+
|
|
115
|
+
## Architecture
|
|
116
|
+
|
|
117
|
+

|
|
118
|
+
|
|
119
|
+
Detailed architecture → [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
|
|
120
|
+
|
|
121
|
+
## Platform Requirements
|
|
122
|
+
|
|
123
|
+
- Python 3.11+
|
|
124
|
+
- Node.js 18+ (frontend development only; the bundled frontend ships prebuilt)
|
|
125
|
+
- Any OpenAI-compatible API (DeepSeek, OpenAI, Ollama, Azure, Agnes, Unisound, SenseNova, …)
|
|
126
|
+
- Windows / macOS / Linux (one-click EXE build on Windows)
|
|
127
|
+
|
|
128
|
+
## Documentation
|
|
129
|
+
|
|
130
|
+
| Document | Contents |
|
|
131
|
+
|----------|----------|
|
|
132
|
+
| [docs/INSTALL.md](docs/INSTALL.md) | Install & packaging (incl. Windows EXE) |
|
|
133
|
+
| [docs/CONFIGURATION.md](docs/CONFIGURATION.md) | Configuration reference (config.toml / env vars / API overview) |
|
|
134
|
+
| [docs/API.md](docs/API.md) | HTTP API and SSE event protocol |
|
|
135
|
+
| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | Architecture notes |
|
|
136
|
+
| [docs/competitive-comparison.md](docs/competitive-comparison.md) | Feature comparison vs Qoder / ZCode / opencode / Codex CLI |
|
|
137
|
+
|
|
138
|
+
## Community
|
|
139
|
+
|
|
140
|
+
- Contributing: [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
141
|
+
- Issue Tracker: use the **Issues** tab of this repository
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
**License:** MIT · **Author:** badhope · **Built with ❤️ in Shenzhen**
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=69", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "spark-agent"
|
|
7
|
+
version = "0.9.6"
|
|
8
|
+
description = "Spark [Ember] — local-first coding agent with a Codex-style loop"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
keywords = ["ai", "agent", "coding", "local-first", "llm", "chatbot"]
|
|
12
|
+
requires-python = ">=3.11"
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 3 - Alpha",
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.11",
|
|
18
|
+
"Programming Language :: Python :: 3.12",
|
|
19
|
+
"Programming Language :: Python :: 3.13",
|
|
20
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
21
|
+
"Topic :: Software Development :: Code Generators",
|
|
22
|
+
]
|
|
23
|
+
dependencies = [
|
|
24
|
+
"chromadb>=1.0",
|
|
25
|
+
"instructor>=1.4,<2.0",
|
|
26
|
+
"litellm>=1.0,<2.0",
|
|
27
|
+
"llama-index-core>=0.12,<1.0",
|
|
28
|
+
"llama-index-llms-openai-like>=0.3,<1.0",
|
|
29
|
+
"httpx>=0.27,<1.0",
|
|
30
|
+
"langgraph>=0.3,<1.0",
|
|
31
|
+
"langgraph-checkpoint-sqlite>=2.0,<3.0",
|
|
32
|
+
"mcp>=1.0,<2.0; python_version>=\"3.10\"",
|
|
33
|
+
"pydantic>=2.7,<3.0",
|
|
34
|
+
"pydantic-settings>=2.0,<3.0",
|
|
35
|
+
"textual>=0.80,<1.0",
|
|
36
|
+
"tomlkit>=0.13,<1.0",
|
|
37
|
+
"tree-sitter>=0.25,<0.27",
|
|
38
|
+
"tree-sitter-javascript>=0.23,<0.26",
|
|
39
|
+
"tree-sitter-python>=0.23,<0.26",
|
|
40
|
+
"tree-sitter-typescript>=0.23,<0.24",
|
|
41
|
+
"typer>=0.12,<1.0",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[project.optional-dependencies]
|
|
45
|
+
dev = [
|
|
46
|
+
"pytest>=8.0",
|
|
47
|
+
"pytest-asyncio>=0.23",
|
|
48
|
+
"pytest-cov>=4.1",
|
|
49
|
+
"ruff>=0.7",
|
|
50
|
+
"import-linter>=2.0",
|
|
51
|
+
"mypy>=1.11",
|
|
52
|
+
"bandit>=1.7",
|
|
53
|
+
"pre-commit>=3.6",
|
|
54
|
+
]
|
|
55
|
+
# P0-9: 观测(Langfuse 自托管 = OTLP 端点,spark 直接接入 OTLP 即可)
|
|
56
|
+
telemetry = [
|
|
57
|
+
"opentelemetry-api>=1.28",
|
|
58
|
+
"opentelemetry-sdk>=1.28",
|
|
59
|
+
"opentelemetry-exporter-otlp-proto-grpc>=1.28",
|
|
60
|
+
]
|
|
61
|
+
# P1-5: 内置终端(真实 PTY)。Windows 不支持(需 winpty/ConPTY),
|
|
62
|
+
# 故用环境标记排除;未安装时 spark.pty 可导入但 PtyManager() 给出清晰报错。
|
|
63
|
+
pty = [
|
|
64
|
+
"ptyprocess>=0.7; sys_platform != 'win32'",
|
|
65
|
+
]
|
|
66
|
+
desktop = [
|
|
67
|
+
"pywebview>=5.0",
|
|
68
|
+
]
|
|
69
|
+
|
|
70
|
+
[project.scripts]
|
|
71
|
+
spark = "spark.cli:app"
|
|
72
|
+
|
|
73
|
+
[tool.setuptools.packages.find]
|
|
74
|
+
where = ["src"]
|
|
75
|
+
|
|
76
|
+
[tool.setuptools.package-data]
|
|
77
|
+
spark = ["prompts/*.md", "web/*.html", "web/dist/*", "web/dist/assets/*", "evals/data/*.json"]
|
|
78
|
+
|
|
79
|
+
[tool.pytest.ini_options]
|
|
80
|
+
asyncio_mode = "auto"
|
|
81
|
+
testpaths = ["tests"]
|
|
82
|
+
pythonpath = ["src"]
|
|
83
|
+
|
|
84
|
+
[tool.ruff]
|
|
85
|
+
line-length = 100
|
|
86
|
+
target-version = "py311"
|
|
87
|
+
|
|
88
|
+
[tool.ruff.lint]
|
|
89
|
+
select = [
|
|
90
|
+
"E4", # pycodestyle import errors
|
|
91
|
+
"E7", # pycodestyle statement errors
|
|
92
|
+
"E9", # pycodestyle runtime errors
|
|
93
|
+
"F", # pyflakes
|
|
94
|
+
"I001", # import sorting
|
|
95
|
+
]
|
|
96
|
+
ignore = []
|
|
97
|
+
|
|
98
|
+
[tool.ruff.lint.per-file-ignores]
|
|
99
|
+
# search.py deliberately defers pydantic/spark imports to avoid a circular
|
|
100
|
+
# import at module load time.
|
|
101
|
+
"src/spark/tools/search.py" = ["E402"]
|
|
102
|
+
# 以下文件中 logger = logging.getLogger(__name__) 紧跟在 __future__ 与 stdlib
|
|
103
|
+
# 导入之后、第三方/本地导入之前,避免 E402 噪音。
|
|
104
|
+
"src/spark/core/graph.py" = ["E402"]
|
|
105
|
+
"src/spark/memory/service.py" = ["E402"]
|
|
106
|
+
"src/spark/tools/shell.py" = ["E402"]
|
|
107
|
+
"src/spark/tui/app.py" = ["E402"]
|
|
108
|
+
# routes.py 保持 import-light:pty 写路径在 _POST_HANDLERS 定义后就近懒加载,
|
|
109
|
+
# 不为 import 排序把 pty 依赖提到模块顶部。
|
|
110
|
+
"src/spark/web/routes.py" = ["E402", "I001"]
|
|
111
|
+
|
|
112
|
+
[tool.mypy]
|
|
113
|
+
python_version = "3.11"
|
|
114
|
+
ignore_missing_imports = true
|
|
115
|
+
warn_unused_ignores = false
|
|
116
|
+
warn_return_any = false
|
|
117
|
+
check_untyped_defs = false
|
|
118
|
+
|
|
119
|
+
[[tool.mypy.overrides]]
|
|
120
|
+
module = [
|
|
121
|
+
"chromadb.*",
|
|
122
|
+
"llama_index.*",
|
|
123
|
+
"langgraph.*",
|
|
124
|
+
"litellm.*",
|
|
125
|
+
"textual.*",
|
|
126
|
+
"typer.*",
|
|
127
|
+
]
|
|
128
|
+
ignore_missing_imports = true
|
|
129
|
+
follow_imports = "skip"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Spark — local-first AI coding agent."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
# Skip LiteLLM's model-cost-map fetch from raw.githubusercontent.com, which is
|
|
6
|
+
# unreachable from mainland China and burns ~9s of connection retries on every
|
|
7
|
+
# process start. The bundled local map ships in the wheel; users can opt back
|
|
8
|
+
# into remote refreshes by setting the variable to False explicitly.
|
|
9
|
+
# Must run before the first litellm import anywhere in the package (litellm
|
|
10
|
+
# reads this variable at import time), so it lives at the package root —
|
|
11
|
+
# every entry point (cli/web/desktop) imports spark first.
|
|
12
|
+
os.environ.setdefault("LITELLM_LOCAL_MODEL_COST_MAP", "True")
|
|
13
|
+
|
|
14
|
+
__version__ = "0.9.6"
|