nonoka-cli 0.1.0__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nonoka_cli-0.1.0 → nonoka_cli-0.2.2}/.gitignore +11 -1
- nonoka_cli-0.2.2/LICENSE +21 -0
- nonoka_cli-0.2.2/NOTICE +41 -0
- nonoka_cli-0.2.2/PKG-INFO +274 -0
- nonoka_cli-0.2.2/README.md +247 -0
- nonoka_cli-0.2.2/TODO.md +77 -0
- nonoka_cli-0.2.2/install.sh +306 -0
- nonoka_cli-0.2.2/nonoka.yaml +15 -0
- nonoka_cli-0.2.2/nonoka.yaml.example +49 -0
- nonoka_cli-0.2.2/packages/nonoka-opencode-provider/.gitignore +34 -0
- nonoka_cli-0.2.2/packages/nonoka-opencode-provider/LICENSE +21 -0
- nonoka_cli-0.2.2/packages/nonoka-opencode-provider/README.md +77 -0
- nonoka_cli-0.2.2/packages/nonoka-opencode-provider/bun.lock +43 -0
- nonoka_cli-0.2.2/packages/nonoka-opencode-provider/nonoka-opencode-provider-0.2.0.tgz +0 -0
- nonoka_cli-0.2.2/packages/nonoka-opencode-provider/package.json +53 -0
- nonoka_cli-0.2.2/packages/nonoka-opencode-provider/src/index.ts +116 -0
- nonoka_cli-0.2.2/packages/nonoka-opencode-provider/src/nonoka-language-model.ts +378 -0
- nonoka_cli-0.2.2/packages/nonoka-opencode-provider/src/protocol.ts +133 -0
- nonoka_cli-0.2.2/packages/nonoka-opencode-provider/src/stream.ts +164 -0
- nonoka_cli-0.2.2/packages/nonoka-opencode-provider/tests/language-model.test.ts +38 -0
- nonoka_cli-0.2.2/packages/nonoka-opencode-provider/tests/protocol.test.ts +73 -0
- nonoka_cli-0.2.2/packages/nonoka-opencode-provider/tests/stream.test.ts +70 -0
- nonoka_cli-0.2.2/packages/nonoka-opencode-provider/tsconfig.json +24 -0
- {nonoka_cli-0.1.0 → nonoka_cli-0.2.2}/pyproject.toml +15 -5
- nonoka_cli-0.2.2/src/nonoka_cli/bridge/__init__.py +19 -0
- nonoka_cli-0.2.2/src/nonoka_cli/bridge/events.py +94 -0
- nonoka_cli-0.2.2/src/nonoka_cli/bridge/handler.py +252 -0
- nonoka_cli-0.2.2/src/nonoka_cli/bridge/protocol.py +159 -0
- nonoka_cli-0.2.2/src/nonoka_cli/bridge/server.py +189 -0
- nonoka_cli-0.2.2/src/nonoka_cli/cli.py +122 -0
- nonoka_cli-0.2.2/src/nonoka_cli/commands/__init__.py +1 -0
- nonoka_cli-0.2.2/src/nonoka_cli/commands/config_cmd.py +356 -0
- nonoka_cli-0.2.2/src/nonoka_cli/commands/doctor_cmd.py +351 -0
- nonoka_cli-0.2.2/src/nonoka_cli/commands/opencode_cmd.py +149 -0
- {nonoka_cli-0.1.0 → nonoka_cli-0.2.2}/src/nonoka_cli/config/__init__.py +3 -2
- nonoka_cli-0.2.2/src/nonoka_cli/config/loader.py +279 -0
- nonoka_cli-0.2.2/src/nonoka_cli/config/manager.py +163 -0
- {nonoka_cli-0.1.0 → nonoka_cli-0.2.2}/src/nonoka_cli/config/models.py +5 -3
- nonoka_cli-0.2.2/src/nonoka_cli/core/agent_factory.py +220 -0
- nonoka_cli-0.2.2/src/nonoka_cli/core/mcp_service.py +52 -0
- nonoka_cli-0.2.2/src/nonoka_cli/core/orchestrator.py +399 -0
- nonoka_cli-0.2.2/src/nonoka_cli/core/runner_service.py +91 -0
- nonoka_cli-0.2.2/src/nonoka_cli/core/session_service.py +87 -0
- nonoka_cli-0.2.2/src/nonoka_cli/core/tool_service.py +32 -0
- nonoka_cli-0.2.2/src/nonoka_cli/mcp/__init__.py +6 -0
- nonoka_cli-0.2.2/src/nonoka_cli/mcp/manager.py +373 -0
- nonoka_cli-0.2.2/src/nonoka_cli/mcp/models.py +19 -0
- nonoka_cli-0.2.2/src/nonoka_cli/sessions/__init__.py +8 -0
- nonoka_cli-0.2.2/src/nonoka_cli/sessions/manager.py +315 -0
- nonoka_cli-0.2.2/src/nonoka_cli/sessions/models.py +24 -0
- nonoka_cli-0.2.2/src/nonoka_cli/skills/__init__.py +7 -0
- nonoka_cli-0.2.2/src/nonoka_cli/skills/manager.py +204 -0
- nonoka_cli-0.2.2/src/nonoka_cli/tools/__init__.py +7 -0
- nonoka_cli-0.2.2/src/nonoka_cli/tools/builtins/__init__.py +12 -0
- nonoka_cli-0.2.2/src/nonoka_cli/tools/builtins/file_tools.py +488 -0
- nonoka_cli-0.2.2/src/nonoka_cli/tools/loader.py +206 -0
- nonoka_cli-0.2.2/src/nonoka_cli/utils/errors.py +48 -0
- {nonoka_cli-0.1.0 → nonoka_cli-0.2.2}/src/nonoka_cli/utils/logging.py +3 -2
- nonoka_cli-0.2.2/tests/conftest.py +10 -0
- nonoka_cli-0.2.2/tests/unit/bridge/test_events.py +118 -0
- nonoka_cli-0.2.2/tests/unit/bridge/test_handler.py +79 -0
- nonoka_cli-0.2.2/tests/unit/bridge/test_protocol.py +63 -0
- nonoka_cli-0.2.2/tests/unit/commands/test_config_cmd.py +99 -0
- nonoka_cli-0.2.2/tests/unit/commands/test_doctor_cmd.py +210 -0
- nonoka_cli-0.2.2/tests/unit/commands/test_opencode_cmd.py +51 -0
- nonoka_cli-0.2.2/tests/unit/config/test_loader.py +76 -0
- nonoka_cli-0.2.2/tests/unit/config/test_models.py +55 -0
- nonoka_cli-0.2.2/tests/unit/sessions/test_manager.py +58 -0
- {nonoka_cli-0.1.0 → nonoka_cli-0.2.2}/uv.lock +536 -480
- nonoka_cli-0.1.0/PKG-INFO +0 -69
- nonoka_cli-0.1.0/README.md +0 -46
- nonoka_cli-0.1.0/config.yaml.example +0 -40
- nonoka_cli-0.1.0/src/nonoka_cli/cli.py +0 -134
- nonoka_cli-0.1.0/src/nonoka_cli/config/loader.py +0 -130
- nonoka_cli-0.1.0/src/nonoka_cli/core/agent_factory.py +0 -78
- nonoka_cli-0.1.0/src/nonoka_cli/core/orchestrator.py +0 -138
- nonoka_cli-0.1.0/src/nonoka_cli/shell/__init__.py +0 -5
- nonoka_cli-0.1.0/src/nonoka_cli/shell/repl.py +0 -164
- nonoka_cli-0.1.0/src/nonoka_cli/ui/__init__.py +0 -5
- nonoka_cli-0.1.0/src/nonoka_cli/ui/renderer.py +0 -78
- nonoka_cli-0.1.0/src/nonoka_cli/utils/errors.py +0 -28
- nonoka_cli-0.1.0/tests/__init__.py +0 -1
- nonoka_cli-0.1.0/tests/conftest.py +0 -72
- nonoka_cli-0.1.0/tests/integration/__init__.py +0 -1
- nonoka_cli-0.1.0/tests/integration/test_real_llm.py +0 -215
- nonoka_cli-0.1.0/tests/unit/__init__.py +0 -1
- nonoka_cli-0.1.0/tests/unit/test_config.py +0 -151
- nonoka_cli-0.1.0/tests/unit/test_core.py +0 -193
- nonoka_cli-0.1.0/tests/unit/test_shell.py +0 -158
- nonoka_cli-0.1.0/tests/unit/test_ui.py +0 -164
- {nonoka_cli-0.1.0 → nonoka_cli-0.2.2}/src/nonoka_cli/__init__.py +0 -0
- {nonoka_cli-0.1.0 → nonoka_cli-0.2.2}/src/nonoka_cli/__main__.py +0 -0
- {nonoka_cli-0.1.0 → nonoka_cli-0.2.2}/src/nonoka_cli/core/__init__.py +1 -1
- {nonoka_cli-0.1.0 → nonoka_cli-0.2.2}/src/nonoka_cli/core/context.py +0 -0
- {nonoka_cli-0.1.0 → nonoka_cli-0.2.2}/src/nonoka_cli/utils/__init__.py +0 -0
|
@@ -40,10 +40,20 @@ MANIFEST
|
|
|
40
40
|
.coverage
|
|
41
41
|
htmlcov/
|
|
42
42
|
.tox/
|
|
43
|
+
.codegraph/
|
|
44
|
+
.ruff_cache/
|
|
43
45
|
|
|
44
46
|
# OS
|
|
45
47
|
.DS_Store
|
|
46
48
|
Thumbs.db
|
|
47
49
|
|
|
48
50
|
# Logs
|
|
49
|
-
*.log
|
|
51
|
+
*.log
|
|
52
|
+
|
|
53
|
+
node_modules/
|
|
54
|
+
dist/
|
|
55
|
+
nonoka-cli-prev/
|
|
56
|
+
|
|
57
|
+
# Private planning documents
|
|
58
|
+
DESIGN.md
|
|
59
|
+
REFACTOR.md
|
nonoka_cli-0.2.2/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 fyerfyer
|
|
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.
|
nonoka_cli-0.2.2/NOTICE
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
nonoka-cli — OpenCode backend for the Nonoka Agent framework
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 fyerfyer
|
|
4
|
+
|
|
5
|
+
This project is licensed under the MIT License (see LICENSE).
|
|
6
|
+
|
|
7
|
+
Third-party software and attribution
|
|
8
|
+
-------------------------------------
|
|
9
|
+
|
|
10
|
+
1. OpenCode
|
|
11
|
+
- Repository: https://github.com/anomalyco/opencode
|
|
12
|
+
- License: MIT
|
|
13
|
+
- Copyright: OpenCode team and contributors
|
|
14
|
+
- The terminal TUI, desktop application, and OpenCode server/client
|
|
15
|
+
architecture are provided by OpenCode. nonoka-cli does not modify
|
|
16
|
+
OpenCode source code; it integrates via OpenCode's custom provider
|
|
17
|
+
mechanism and the Vercel AI SDK provider interface.
|
|
18
|
+
|
|
19
|
+
2. Vercel AI SDK
|
|
20
|
+
- Repository: https://github.com/vercel/ai
|
|
21
|
+
- License: Apache License 2.0
|
|
22
|
+
- nonoka-opencode-provider implements the Vercel AI SDK provider API.
|
|
23
|
+
|
|
24
|
+
3. LiteLLM
|
|
25
|
+
- Repository: https://github.com/BerriAI/litellm
|
|
26
|
+
- License: MIT
|
|
27
|
+
- Used by the underlying nonoka Agent framework for multi-provider LLM calls.
|
|
28
|
+
|
|
29
|
+
4. MCP (Model Context Protocol)
|
|
30
|
+
- Repository: https://github.com/modelcontextprotocol
|
|
31
|
+
- License: MIT
|
|
32
|
+
- Used for tool server integration.
|
|
33
|
+
|
|
34
|
+
Agent core
|
|
35
|
+
----------
|
|
36
|
+
The conversational agent core, execution engine, checkpoint/memory system,
|
|
37
|
+
and tool framework are provided by the Nonoka Python Agent framework
|
|
38
|
+
(https://pypi.org/project/nonoka/), independently developed by fyerfyer.
|
|
39
|
+
|
|
40
|
+
This NOTICE file is provided for attribution purposes. If you distribute
|
|
41
|
+
binaries or derivative works, please keep the above notices intact.
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nonoka-cli
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: OpenCode backend for the Nonoka Agent framework
|
|
5
|
+
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
License-File: NOTICE
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Requires-Dist: nonoka>=1.3.1
|
|
18
|
+
Requires-Dist: pydantic>=2.0
|
|
19
|
+
Requires-Dist: python-dotenv>=1.0
|
|
20
|
+
Requires-Dist: pyyaml>=6.0
|
|
21
|
+
Requires-Dist: structlog>=24.0.0
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
|
|
24
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# nonoka-cli
|
|
29
|
+
|
|
30
|
+
OpenCode backend for the [Nonoka](https://pypi.org/project/nonoka/) Agent framework.
|
|
31
|
+
|
|
32
|
+
`nonoka-cli` runs as a stdio NDJSON bridge server (`nonoka-cli --server`) that
|
|
33
|
+
talks to the `nonoka-opencode-provider` TypeScript package. OpenCode uses the
|
|
34
|
+
provider to drive Nonoka agents, with full support for tool cards and
|
|
35
|
+
human-in-the-loop (HITL) approval.
|
|
36
|
+
|
|
37
|
+
## Quick install
|
|
38
|
+
|
|
39
|
+
The easiest way to get nonoka + OpenCode is the one-line installer:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
curl -fsSL https://nonoka.dev/install.sh | bash
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The installer will:
|
|
46
|
+
|
|
47
|
+
1. Check Python 3.10+ and Node/npm.
|
|
48
|
+
2. Install or update OpenCode.
|
|
49
|
+
3. Install `nonoka-cli` and the OpenCode provider.
|
|
50
|
+
4. Generate `~/.config/nonoka/config.yaml` and `~/.config/opencode/opencode.json`.
|
|
51
|
+
|
|
52
|
+
After installing, configure your API key and run `opencode`:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Interactive: it will ask for your key and save it to ~/.config/nonoka/.env
|
|
56
|
+
nonoka-cli config init
|
|
57
|
+
|
|
58
|
+
# Or set it manually
|
|
59
|
+
export DEEPSEEK_API_KEY=<your-key>
|
|
60
|
+
|
|
61
|
+
nonoka-cli doctor
|
|
62
|
+
opencode
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`nonoka-cli` automatically loads `~/.config/nonoka/.env` and `./.env` on startup,
|
|
66
|
+
so you don't need to `export` every time if you save the key in `.env`.
|
|
67
|
+
|
|
68
|
+
> To use `uv` instead of `pip`, or to run non-interactively, pass flags:
|
|
69
|
+
> `curl -fsSL https://nonoka.dev/install.sh | bash -s -- --uv --yes`.
|
|
70
|
+
|
|
71
|
+
## Manual installation
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# Install nonoka-cli
|
|
75
|
+
pip install nonoka-cli
|
|
76
|
+
# or with uv
|
|
77
|
+
uv pip install nonoka-cli
|
|
78
|
+
|
|
79
|
+
# Install the OpenCode provider globally so OpenCode can load it
|
|
80
|
+
npm install -g nonoka-opencode-provider
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Quick start
|
|
84
|
+
|
|
85
|
+
1. Create your nonoka config (it will ask for your API key and save it to
|
|
86
|
+
`~/.config/nonoka/.env`):
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
nonoka-cli config init
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
For scripted setups, use the non-interactive mode (you'll still need to set the
|
|
93
|
+
API key via `.env` or `export`):
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
nonoka-cli config init --yes --model deepseek-chat
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
2. Generate an OpenCode config in the current project or globally:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
# Project-level
|
|
103
|
+
nonoka-cli opencode init
|
|
104
|
+
|
|
105
|
+
# User-level
|
|
106
|
+
nonoka-cli opencode init --global
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
3. Make sure your model API key is exported, then run:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
opencode
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## `nonoka-cli doctor`
|
|
116
|
+
|
|
117
|
+
Diagnose your installation and configuration:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
nonoka-cli doctor
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Example output:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
nonoka-cli doctor
|
|
127
|
+
✓ nonoka-cli 0.2.1
|
|
128
|
+
✓ Python 3.11
|
|
129
|
+
✓ opencode 1.16.2
|
|
130
|
+
✓ provider nonoka-opencode-provider@0.2.0
|
|
131
|
+
✓ config ~/.config/nonoka/config.yaml
|
|
132
|
+
✓ API key DEEPSEEK_API_KEY set
|
|
133
|
+
✓ OpenCode provider config in /home/user/.config/opencode/opencode.json
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
If anything is wrong, `doctor` prints a remedy line. To also verify the LLM API
|
|
137
|
+
key with a real (small) call, use:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
nonoka-cli doctor --check-llm
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Configuration
|
|
144
|
+
|
|
145
|
+
### `nonoka-cli config init`
|
|
146
|
+
|
|
147
|
+
Interactive wizard that writes `~/.config/nonoka/config.yaml`. It asks for a
|
|
148
|
+
model identifier (e.g. `deepseek-chat`, `openai/gpt-4o`, `ollama/llama3.3`), a
|
|
149
|
+
masked API key, and whether to save it to `~/.config/nonoka/.env` (recommended),
|
|
150
|
+
directly in `config.yaml`, or skip saving. It also asks for a system prompt and
|
|
151
|
+
whether to auto-approve all tool calls.
|
|
152
|
+
|
|
153
|
+
Non-interactive example:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
nonoka-cli config init --yes --model openai/gpt-4o
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### `nonoka-cli config set <key> <value>`
|
|
160
|
+
|
|
161
|
+
Update a single config value. Dotted keys are supported:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
nonoka-cli config set model openai/gpt-4o
|
|
165
|
+
nonoka-cli config set cli.theme light
|
|
166
|
+
nonoka-cli config set hitl.dangerous_tools '["write_file", "execute_command"]'
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### `nonoka-cli config show`
|
|
170
|
+
|
|
171
|
+
Print the resolved configuration and its file path.
|
|
172
|
+
|
|
173
|
+
### `nonoka-cli opencode init`
|
|
174
|
+
|
|
175
|
+
Generate or merge an `opencode.json` in the current directory. The generated
|
|
176
|
+
config points OpenCode at the `nonoka-opencode-provider` package and passes the
|
|
177
|
+
nonoka config path to the backend.
|
|
178
|
+
|
|
179
|
+
## OpenCode configuration
|
|
180
|
+
|
|
181
|
+
A typical generated `opencode.json` looks like:
|
|
182
|
+
|
|
183
|
+
```json
|
|
184
|
+
{
|
|
185
|
+
"$schema": "https://opencode.ai/config.json",
|
|
186
|
+
"model": "nonoka/default",
|
|
187
|
+
"provider": {
|
|
188
|
+
"nonoka": {
|
|
189
|
+
"npm": "nonoka-opencode-provider",
|
|
190
|
+
"name": "Nonoka",
|
|
191
|
+
"options": {
|
|
192
|
+
"serverCommand": ["nonoka-cli", "--server"],
|
|
193
|
+
"cwd": ".",
|
|
194
|
+
"configPath": "~/.config/nonoka/config.yaml"
|
|
195
|
+
},
|
|
196
|
+
"models": {
|
|
197
|
+
"default": { "name": "Nonoka deepseek-chat" }
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
"permission": {
|
|
202
|
+
"edit": "ask",
|
|
203
|
+
"bash": "ask"
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Human-in-the-loop
|
|
209
|
+
|
|
210
|
+
When a tool call matches the `hitl.dangerous_tools` list in `nonoka.yaml`,
|
|
211
|
+
nonoka pauses the turn and sends a `tool-approval-request` to OpenCode.
|
|
212
|
+
OpenCode shows the tool card with an approval dialog; after the user decides,
|
|
213
|
+
nonoka resumes the turn, executes approved tools, and returns the final answer.
|
|
214
|
+
|
|
215
|
+
Example `nonoka.yaml`:
|
|
216
|
+
|
|
217
|
+
```yaml
|
|
218
|
+
model: "deepseek-chat"
|
|
219
|
+
|
|
220
|
+
cli:
|
|
221
|
+
auto_approve: false
|
|
222
|
+
|
|
223
|
+
hitl:
|
|
224
|
+
policy: interactive
|
|
225
|
+
dangerous_tools:
|
|
226
|
+
- write_file
|
|
227
|
+
- edit_file
|
|
228
|
+
- delete_file
|
|
229
|
+
- execute_command
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Set `cli.auto_approve: true` (or `hitl.policy: auto`) to skip approval dialogs.
|
|
233
|
+
|
|
234
|
+
## Development
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
# Install in editable mode
|
|
238
|
+
uv pip install -e .
|
|
239
|
+
|
|
240
|
+
# Run the bridge server
|
|
241
|
+
nonoka-cli --server --config ./nonoka.yaml
|
|
242
|
+
|
|
243
|
+
# Lint and test
|
|
244
|
+
uv run --no-sync ruff check .
|
|
245
|
+
uv run --no-sync pytest tests/unit
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Project layout
|
|
249
|
+
|
|
250
|
+
```text
|
|
251
|
+
src/nonoka_cli/
|
|
252
|
+
├── bridge/ # NDJSON protocol, request handler, server
|
|
253
|
+
├── commands/ # CLI subcommands (config, doctor, opencode)
|
|
254
|
+
├── config/ # YAML config loading and Pydantic models
|
|
255
|
+
├── core/ # Orchestrator, RunnerService, SessionService, ToolService, MCPService
|
|
256
|
+
├── mcp/ # MCP server lifecycle manager
|
|
257
|
+
├── sessions/ # Session metadata persistence
|
|
258
|
+
├── skills/ # Skill loading and application
|
|
259
|
+
├── tools/ # Built-in and local tool loader
|
|
260
|
+
└── utils/ # Errors, logging
|
|
261
|
+
|
|
262
|
+
packages/nonoka-opencode-provider/ # TypeScript provider for OpenCode
|
|
263
|
+
install.sh # One-line installer
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## License and attribution
|
|
267
|
+
|
|
268
|
+
`nonoka-cli` and `nonoka-opencode-provider` are released under the MIT License.
|
|
269
|
+
|
|
270
|
+
The terminal TUI and OpenCode client/server architecture are provided by
|
|
271
|
+
[OpenCode](https://github.com/anomalyco/opencode) (MIT License). The agent
|
|
272
|
+
core is provided by the [Nonoka](https://pypi.org/project/nonoka/) framework.
|
|
273
|
+
|
|
274
|
+
See `LICENSE` and `NOTICE` for full details.
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# nonoka-cli
|
|
2
|
+
|
|
3
|
+
OpenCode backend for the [Nonoka](https://pypi.org/project/nonoka/) Agent framework.
|
|
4
|
+
|
|
5
|
+
`nonoka-cli` runs as a stdio NDJSON bridge server (`nonoka-cli --server`) that
|
|
6
|
+
talks to the `nonoka-opencode-provider` TypeScript package. OpenCode uses the
|
|
7
|
+
provider to drive Nonoka agents, with full support for tool cards and
|
|
8
|
+
human-in-the-loop (HITL) approval.
|
|
9
|
+
|
|
10
|
+
## Quick install
|
|
11
|
+
|
|
12
|
+
The easiest way to get nonoka + OpenCode is the one-line installer:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
curl -fsSL https://nonoka.dev/install.sh | bash
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The installer will:
|
|
19
|
+
|
|
20
|
+
1. Check Python 3.10+ and Node/npm.
|
|
21
|
+
2. Install or update OpenCode.
|
|
22
|
+
3. Install `nonoka-cli` and the OpenCode provider.
|
|
23
|
+
4. Generate `~/.config/nonoka/config.yaml` and `~/.config/opencode/opencode.json`.
|
|
24
|
+
|
|
25
|
+
After installing, configure your API key and run `opencode`:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Interactive: it will ask for your key and save it to ~/.config/nonoka/.env
|
|
29
|
+
nonoka-cli config init
|
|
30
|
+
|
|
31
|
+
# Or set it manually
|
|
32
|
+
export DEEPSEEK_API_KEY=<your-key>
|
|
33
|
+
|
|
34
|
+
nonoka-cli doctor
|
|
35
|
+
opencode
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`nonoka-cli` automatically loads `~/.config/nonoka/.env` and `./.env` on startup,
|
|
39
|
+
so you don't need to `export` every time if you save the key in `.env`.
|
|
40
|
+
|
|
41
|
+
> To use `uv` instead of `pip`, or to run non-interactively, pass flags:
|
|
42
|
+
> `curl -fsSL https://nonoka.dev/install.sh | bash -s -- --uv --yes`.
|
|
43
|
+
|
|
44
|
+
## Manual installation
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Install nonoka-cli
|
|
48
|
+
pip install nonoka-cli
|
|
49
|
+
# or with uv
|
|
50
|
+
uv pip install nonoka-cli
|
|
51
|
+
|
|
52
|
+
# Install the OpenCode provider globally so OpenCode can load it
|
|
53
|
+
npm install -g nonoka-opencode-provider
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick start
|
|
57
|
+
|
|
58
|
+
1. Create your nonoka config (it will ask for your API key and save it to
|
|
59
|
+
`~/.config/nonoka/.env`):
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
nonoka-cli config init
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
For scripted setups, use the non-interactive mode (you'll still need to set the
|
|
66
|
+
API key via `.env` or `export`):
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
nonoka-cli config init --yes --model deepseek-chat
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
2. Generate an OpenCode config in the current project or globally:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# Project-level
|
|
76
|
+
nonoka-cli opencode init
|
|
77
|
+
|
|
78
|
+
# User-level
|
|
79
|
+
nonoka-cli opencode init --global
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
3. Make sure your model API key is exported, then run:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
opencode
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## `nonoka-cli doctor`
|
|
89
|
+
|
|
90
|
+
Diagnose your installation and configuration:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
nonoka-cli doctor
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Example output:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
nonoka-cli doctor
|
|
100
|
+
✓ nonoka-cli 0.2.1
|
|
101
|
+
✓ Python 3.11
|
|
102
|
+
✓ opencode 1.16.2
|
|
103
|
+
✓ provider nonoka-opencode-provider@0.2.0
|
|
104
|
+
✓ config ~/.config/nonoka/config.yaml
|
|
105
|
+
✓ API key DEEPSEEK_API_KEY set
|
|
106
|
+
✓ OpenCode provider config in /home/user/.config/opencode/opencode.json
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
If anything is wrong, `doctor` prints a remedy line. To also verify the LLM API
|
|
110
|
+
key with a real (small) call, use:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
nonoka-cli doctor --check-llm
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Configuration
|
|
117
|
+
|
|
118
|
+
### `nonoka-cli config init`
|
|
119
|
+
|
|
120
|
+
Interactive wizard that writes `~/.config/nonoka/config.yaml`. It asks for a
|
|
121
|
+
model identifier (e.g. `deepseek-chat`, `openai/gpt-4o`, `ollama/llama3.3`), a
|
|
122
|
+
masked API key, and whether to save it to `~/.config/nonoka/.env` (recommended),
|
|
123
|
+
directly in `config.yaml`, or skip saving. It also asks for a system prompt and
|
|
124
|
+
whether to auto-approve all tool calls.
|
|
125
|
+
|
|
126
|
+
Non-interactive example:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
nonoka-cli config init --yes --model openai/gpt-4o
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### `nonoka-cli config set <key> <value>`
|
|
133
|
+
|
|
134
|
+
Update a single config value. Dotted keys are supported:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
nonoka-cli config set model openai/gpt-4o
|
|
138
|
+
nonoka-cli config set cli.theme light
|
|
139
|
+
nonoka-cli config set hitl.dangerous_tools '["write_file", "execute_command"]'
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### `nonoka-cli config show`
|
|
143
|
+
|
|
144
|
+
Print the resolved configuration and its file path.
|
|
145
|
+
|
|
146
|
+
### `nonoka-cli opencode init`
|
|
147
|
+
|
|
148
|
+
Generate or merge an `opencode.json` in the current directory. The generated
|
|
149
|
+
config points OpenCode at the `nonoka-opencode-provider` package and passes the
|
|
150
|
+
nonoka config path to the backend.
|
|
151
|
+
|
|
152
|
+
## OpenCode configuration
|
|
153
|
+
|
|
154
|
+
A typical generated `opencode.json` looks like:
|
|
155
|
+
|
|
156
|
+
```json
|
|
157
|
+
{
|
|
158
|
+
"$schema": "https://opencode.ai/config.json",
|
|
159
|
+
"model": "nonoka/default",
|
|
160
|
+
"provider": {
|
|
161
|
+
"nonoka": {
|
|
162
|
+
"npm": "nonoka-opencode-provider",
|
|
163
|
+
"name": "Nonoka",
|
|
164
|
+
"options": {
|
|
165
|
+
"serverCommand": ["nonoka-cli", "--server"],
|
|
166
|
+
"cwd": ".",
|
|
167
|
+
"configPath": "~/.config/nonoka/config.yaml"
|
|
168
|
+
},
|
|
169
|
+
"models": {
|
|
170
|
+
"default": { "name": "Nonoka deepseek-chat" }
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
"permission": {
|
|
175
|
+
"edit": "ask",
|
|
176
|
+
"bash": "ask"
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Human-in-the-loop
|
|
182
|
+
|
|
183
|
+
When a tool call matches the `hitl.dangerous_tools` list in `nonoka.yaml`,
|
|
184
|
+
nonoka pauses the turn and sends a `tool-approval-request` to OpenCode.
|
|
185
|
+
OpenCode shows the tool card with an approval dialog; after the user decides,
|
|
186
|
+
nonoka resumes the turn, executes approved tools, and returns the final answer.
|
|
187
|
+
|
|
188
|
+
Example `nonoka.yaml`:
|
|
189
|
+
|
|
190
|
+
```yaml
|
|
191
|
+
model: "deepseek-chat"
|
|
192
|
+
|
|
193
|
+
cli:
|
|
194
|
+
auto_approve: false
|
|
195
|
+
|
|
196
|
+
hitl:
|
|
197
|
+
policy: interactive
|
|
198
|
+
dangerous_tools:
|
|
199
|
+
- write_file
|
|
200
|
+
- edit_file
|
|
201
|
+
- delete_file
|
|
202
|
+
- execute_command
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Set `cli.auto_approve: true` (or `hitl.policy: auto`) to skip approval dialogs.
|
|
206
|
+
|
|
207
|
+
## Development
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
# Install in editable mode
|
|
211
|
+
uv pip install -e .
|
|
212
|
+
|
|
213
|
+
# Run the bridge server
|
|
214
|
+
nonoka-cli --server --config ./nonoka.yaml
|
|
215
|
+
|
|
216
|
+
# Lint and test
|
|
217
|
+
uv run --no-sync ruff check .
|
|
218
|
+
uv run --no-sync pytest tests/unit
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Project layout
|
|
222
|
+
|
|
223
|
+
```text
|
|
224
|
+
src/nonoka_cli/
|
|
225
|
+
├── bridge/ # NDJSON protocol, request handler, server
|
|
226
|
+
├── commands/ # CLI subcommands (config, doctor, opencode)
|
|
227
|
+
├── config/ # YAML config loading and Pydantic models
|
|
228
|
+
├── core/ # Orchestrator, RunnerService, SessionService, ToolService, MCPService
|
|
229
|
+
├── mcp/ # MCP server lifecycle manager
|
|
230
|
+
├── sessions/ # Session metadata persistence
|
|
231
|
+
├── skills/ # Skill loading and application
|
|
232
|
+
├── tools/ # Built-in and local tool loader
|
|
233
|
+
└── utils/ # Errors, logging
|
|
234
|
+
|
|
235
|
+
packages/nonoka-opencode-provider/ # TypeScript provider for OpenCode
|
|
236
|
+
install.sh # One-line installer
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## License and attribution
|
|
240
|
+
|
|
241
|
+
`nonoka-cli` and `nonoka-opencode-provider` are released under the MIT License.
|
|
242
|
+
|
|
243
|
+
The terminal TUI and OpenCode client/server architecture are provided by
|
|
244
|
+
[OpenCode](https://github.com/anomalyco/opencode) (MIT License). The agent
|
|
245
|
+
core is provided by the [Nonoka](https://pypi.org/project/nonoka/) framework.
|
|
246
|
+
|
|
247
|
+
See `LICENSE` and `NOTICE` for full details.
|
nonoka_cli-0.2.2/TODO.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# nonoka-cli / OpenCode Provider — 已知未实现项
|
|
2
|
+
|
|
3
|
+
> 当前为 Phase 1 验证版本,端到端文本回复已跑通。下面列出还需要补全或优化的地方,供后续迭代参考。
|
|
4
|
+
|
|
5
|
+
## 1. OpenCode Provider 层
|
|
6
|
+
|
|
7
|
+
### 1.1 Tool-call / Tool-result 透传
|
|
8
|
+
- 现状:provider 只处理 `text_delta`、`finish`、`error` 三种 NDJSON 事件。
|
|
9
|
+
- nonoka 后端自己有一个工具循环(read/bash/grep 等),它调用工具后会把结果写回自己的上下文,然后继续生成文本。
|
|
10
|
+
- 问题:OpenCode 看不到 nonoka 的工具调用过程,也无法用 OpenCode 统一的工具权限/审批去管理。
|
|
11
|
+
- 目标:把 nonoka 的 `tool_call` / `tool_result` 事件映射为 Vercel AI SDK 的 `tool-call` / `tool-result` stream parts,让 OpenCode 接管工具循环;或者提供一个开关让 nonoka 在 server 模式下禁用自带工具。
|
|
12
|
+
|
|
13
|
+
### 1.2 Session 持久化
|
|
14
|
+
- 现状:provider 每次 `doStream` 都会 `spawn` 一个新的 `nonoka-cli --server` 进程,旧的 session 上下文随着进程退出而丢失。
|
|
15
|
+
- 影响:多轮对话时 nonoka 后端无法记住之前的对话内容(虽然 OpenCode 会把历史消息拼进 prompt,但 nonoka 内部的 agent 状态会丢失)。
|
|
16
|
+
- 目标:让 provider 复用同一个 long-running server 进程,或在 `session_init` 后通过持久化存储恢复 session。
|
|
17
|
+
|
|
18
|
+
### 1.3 错误与取消处理
|
|
19
|
+
- `abortSignal` 目前会 kill 子进程,但 nonoka 后端对 SIGTERM/SIGKILL 的清理逻辑未充分测试。
|
|
20
|
+
- 需要规范 `error` 事件的格式,并在 provider 里生成正确的 `error` stream part。
|
|
21
|
+
- 子进程 stdout 解析失败的行当前被静默丢弃,应该记录日志或抛出。
|
|
22
|
+
|
|
23
|
+
### 1.4 构建与分发
|
|
24
|
+
- 当前只有 ESM 输出(`tsc` 编译到 `dist/`)。
|
|
25
|
+
- 建议增加 CJS / dual-build,或直接用 `bun build` 打成单文件 bundle,避免用户环境里出现 `@ai-sdk/provider` 等依赖解析问题。
|
|
26
|
+
- `package.json` 需要补齐 `exports`、`keywords`、`repository`、`bugs`、`homepage` 等字段。
|
|
27
|
+
|
|
28
|
+
### 1.5 Provider 配置校验
|
|
29
|
+
- `serverCommand` 目前支持字符串和数组,但没有校验命令是否为空、是否可执行。
|
|
30
|
+
- `configPath` / `cwd` 等路径未做 exists 检查。
|
|
31
|
+
- 建议用 `zod` 做一次配置 schema 校验。
|
|
32
|
+
|
|
33
|
+
## 2. nonoka-cli `--server` 后端
|
|
34
|
+
|
|
35
|
+
### 2.1 协议扩展
|
|
36
|
+
- 当前 NDJSON 协议只有 `chat` 请求和 `session_init` / `text_delta` / `finish` / `error` 响应。
|
|
37
|
+
- 需要增加:
|
|
38
|
+
- `tool_call` / `tool_result` 事件(配合 1.1)。
|
|
39
|
+
- `approval_request` / `approval_response` 事件,让 OpenCode 侧决定敏感操作。
|
|
40
|
+
- `thinking` / `reasoning` 事件(如果模型支持)。
|
|
41
|
+
- `usage` 字段(input/output tokens),让 OpenCode 统计消耗。
|
|
42
|
+
|
|
43
|
+
### 2.2 并发与生命周期
|
|
44
|
+
- `BridgeServer` 目前一个进程只处理一条请求然后退出。
|
|
45
|
+
- 需要支持多条 NDJSON 请求顺序或并发处理,并正确维护 Orchestrator 生命周期。
|
|
46
|
+
- 需要处理客户端断开、stdin EOF、子进程异常退出等边界情况。
|
|
47
|
+
|
|
48
|
+
### 2.3 配置与模型
|
|
49
|
+
- `nonoka.yaml` 里的 `model: deepseek-chat` 在 LiteLLM 某些版本下需要写成 `deepseek/deepseek-chat`。
|
|
50
|
+
- 建议把 provider / base_url / api_key 也显式暴露到配置里,而不是只依赖环境变量。
|
|
51
|
+
|
|
52
|
+
## 3. OpenCode 集成体验
|
|
53
|
+
|
|
54
|
+
### 3.1 本地路径 vs npm 包名
|
|
55
|
+
- 现在 `opencode.json` 里用绝对路径指向 provider 包,只是为了避免 OpenCode 去 npm registry 安装时卡死(当前环境有代理问题)。
|
|
56
|
+
- 发布 npm 后应改回 `"npm": "@nonoka/opencode-provider"`,并验证 OpenCode 能自动安装。
|
|
57
|
+
|
|
58
|
+
### 3.2 模型元数据
|
|
59
|
+
- `models.default` 目前只有 `name`。
|
|
60
|
+
- 应补齐 `limit.context`、`limit.output`、`modalities` 等,让 OpenCode 正确计算上下文窗口和费用。
|
|
61
|
+
|
|
62
|
+
### 3.3 TUI 验证
|
|
63
|
+
- 目前主要用 `opencode run` 非交互验证。
|
|
64
|
+
- 需要在 TUI 里手动验证 `/models` 选择、`/connect` 流程、多轮对话渲染等。
|
|
65
|
+
|
|
66
|
+
## 4. 测试
|
|
67
|
+
|
|
68
|
+
- [ ] provider 单元测试(stream transformer、协议编解码)。
|
|
69
|
+
- [ ] `nonoka-cli --server` 端到端测试(发送 NDJSON 请求,断言事件顺序)。
|
|
70
|
+
- [ ] OpenCode 集成测试(用本地 registry 安装 provider 后跑 `opencode run`)。
|
|
71
|
+
- [ ] 错误场景测试(无效命令、模型不可用、网络超时)。
|
|
72
|
+
|
|
73
|
+
## 5. 文档
|
|
74
|
+
|
|
75
|
+
- [ ] provider README(安装、配置、options 说明)。
|
|
76
|
+
- [ ] nonoka-cli README 增加 `--server` 模式说明。
|
|
77
|
+
- [ ] OpenCode 配置示例(本地路径 / npm 包名 / 私有 registry)。
|