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.
Files changed (95) hide show
  1. {nonoka_cli-0.1.0 → nonoka_cli-0.2.2}/.gitignore +11 -1
  2. nonoka_cli-0.2.2/LICENSE +21 -0
  3. nonoka_cli-0.2.2/NOTICE +41 -0
  4. nonoka_cli-0.2.2/PKG-INFO +274 -0
  5. nonoka_cli-0.2.2/README.md +247 -0
  6. nonoka_cli-0.2.2/TODO.md +77 -0
  7. nonoka_cli-0.2.2/install.sh +306 -0
  8. nonoka_cli-0.2.2/nonoka.yaml +15 -0
  9. nonoka_cli-0.2.2/nonoka.yaml.example +49 -0
  10. nonoka_cli-0.2.2/packages/nonoka-opencode-provider/.gitignore +34 -0
  11. nonoka_cli-0.2.2/packages/nonoka-opencode-provider/LICENSE +21 -0
  12. nonoka_cli-0.2.2/packages/nonoka-opencode-provider/README.md +77 -0
  13. nonoka_cli-0.2.2/packages/nonoka-opencode-provider/bun.lock +43 -0
  14. nonoka_cli-0.2.2/packages/nonoka-opencode-provider/nonoka-opencode-provider-0.2.0.tgz +0 -0
  15. nonoka_cli-0.2.2/packages/nonoka-opencode-provider/package.json +53 -0
  16. nonoka_cli-0.2.2/packages/nonoka-opencode-provider/src/index.ts +116 -0
  17. nonoka_cli-0.2.2/packages/nonoka-opencode-provider/src/nonoka-language-model.ts +378 -0
  18. nonoka_cli-0.2.2/packages/nonoka-opencode-provider/src/protocol.ts +133 -0
  19. nonoka_cli-0.2.2/packages/nonoka-opencode-provider/src/stream.ts +164 -0
  20. nonoka_cli-0.2.2/packages/nonoka-opencode-provider/tests/language-model.test.ts +38 -0
  21. nonoka_cli-0.2.2/packages/nonoka-opencode-provider/tests/protocol.test.ts +73 -0
  22. nonoka_cli-0.2.2/packages/nonoka-opencode-provider/tests/stream.test.ts +70 -0
  23. nonoka_cli-0.2.2/packages/nonoka-opencode-provider/tsconfig.json +24 -0
  24. {nonoka_cli-0.1.0 → nonoka_cli-0.2.2}/pyproject.toml +15 -5
  25. nonoka_cli-0.2.2/src/nonoka_cli/bridge/__init__.py +19 -0
  26. nonoka_cli-0.2.2/src/nonoka_cli/bridge/events.py +94 -0
  27. nonoka_cli-0.2.2/src/nonoka_cli/bridge/handler.py +252 -0
  28. nonoka_cli-0.2.2/src/nonoka_cli/bridge/protocol.py +159 -0
  29. nonoka_cli-0.2.2/src/nonoka_cli/bridge/server.py +189 -0
  30. nonoka_cli-0.2.2/src/nonoka_cli/cli.py +122 -0
  31. nonoka_cli-0.2.2/src/nonoka_cli/commands/__init__.py +1 -0
  32. nonoka_cli-0.2.2/src/nonoka_cli/commands/config_cmd.py +356 -0
  33. nonoka_cli-0.2.2/src/nonoka_cli/commands/doctor_cmd.py +351 -0
  34. nonoka_cli-0.2.2/src/nonoka_cli/commands/opencode_cmd.py +149 -0
  35. {nonoka_cli-0.1.0 → nonoka_cli-0.2.2}/src/nonoka_cli/config/__init__.py +3 -2
  36. nonoka_cli-0.2.2/src/nonoka_cli/config/loader.py +279 -0
  37. nonoka_cli-0.2.2/src/nonoka_cli/config/manager.py +163 -0
  38. {nonoka_cli-0.1.0 → nonoka_cli-0.2.2}/src/nonoka_cli/config/models.py +5 -3
  39. nonoka_cli-0.2.2/src/nonoka_cli/core/agent_factory.py +220 -0
  40. nonoka_cli-0.2.2/src/nonoka_cli/core/mcp_service.py +52 -0
  41. nonoka_cli-0.2.2/src/nonoka_cli/core/orchestrator.py +399 -0
  42. nonoka_cli-0.2.2/src/nonoka_cli/core/runner_service.py +91 -0
  43. nonoka_cli-0.2.2/src/nonoka_cli/core/session_service.py +87 -0
  44. nonoka_cli-0.2.2/src/nonoka_cli/core/tool_service.py +32 -0
  45. nonoka_cli-0.2.2/src/nonoka_cli/mcp/__init__.py +6 -0
  46. nonoka_cli-0.2.2/src/nonoka_cli/mcp/manager.py +373 -0
  47. nonoka_cli-0.2.2/src/nonoka_cli/mcp/models.py +19 -0
  48. nonoka_cli-0.2.2/src/nonoka_cli/sessions/__init__.py +8 -0
  49. nonoka_cli-0.2.2/src/nonoka_cli/sessions/manager.py +315 -0
  50. nonoka_cli-0.2.2/src/nonoka_cli/sessions/models.py +24 -0
  51. nonoka_cli-0.2.2/src/nonoka_cli/skills/__init__.py +7 -0
  52. nonoka_cli-0.2.2/src/nonoka_cli/skills/manager.py +204 -0
  53. nonoka_cli-0.2.2/src/nonoka_cli/tools/__init__.py +7 -0
  54. nonoka_cli-0.2.2/src/nonoka_cli/tools/builtins/__init__.py +12 -0
  55. nonoka_cli-0.2.2/src/nonoka_cli/tools/builtins/file_tools.py +488 -0
  56. nonoka_cli-0.2.2/src/nonoka_cli/tools/loader.py +206 -0
  57. nonoka_cli-0.2.2/src/nonoka_cli/utils/errors.py +48 -0
  58. {nonoka_cli-0.1.0 → nonoka_cli-0.2.2}/src/nonoka_cli/utils/logging.py +3 -2
  59. nonoka_cli-0.2.2/tests/conftest.py +10 -0
  60. nonoka_cli-0.2.2/tests/unit/bridge/test_events.py +118 -0
  61. nonoka_cli-0.2.2/tests/unit/bridge/test_handler.py +79 -0
  62. nonoka_cli-0.2.2/tests/unit/bridge/test_protocol.py +63 -0
  63. nonoka_cli-0.2.2/tests/unit/commands/test_config_cmd.py +99 -0
  64. nonoka_cli-0.2.2/tests/unit/commands/test_doctor_cmd.py +210 -0
  65. nonoka_cli-0.2.2/tests/unit/commands/test_opencode_cmd.py +51 -0
  66. nonoka_cli-0.2.2/tests/unit/config/test_loader.py +76 -0
  67. nonoka_cli-0.2.2/tests/unit/config/test_models.py +55 -0
  68. nonoka_cli-0.2.2/tests/unit/sessions/test_manager.py +58 -0
  69. {nonoka_cli-0.1.0 → nonoka_cli-0.2.2}/uv.lock +536 -480
  70. nonoka_cli-0.1.0/PKG-INFO +0 -69
  71. nonoka_cli-0.1.0/README.md +0 -46
  72. nonoka_cli-0.1.0/config.yaml.example +0 -40
  73. nonoka_cli-0.1.0/src/nonoka_cli/cli.py +0 -134
  74. nonoka_cli-0.1.0/src/nonoka_cli/config/loader.py +0 -130
  75. nonoka_cli-0.1.0/src/nonoka_cli/core/agent_factory.py +0 -78
  76. nonoka_cli-0.1.0/src/nonoka_cli/core/orchestrator.py +0 -138
  77. nonoka_cli-0.1.0/src/nonoka_cli/shell/__init__.py +0 -5
  78. nonoka_cli-0.1.0/src/nonoka_cli/shell/repl.py +0 -164
  79. nonoka_cli-0.1.0/src/nonoka_cli/ui/__init__.py +0 -5
  80. nonoka_cli-0.1.0/src/nonoka_cli/ui/renderer.py +0 -78
  81. nonoka_cli-0.1.0/src/nonoka_cli/utils/errors.py +0 -28
  82. nonoka_cli-0.1.0/tests/__init__.py +0 -1
  83. nonoka_cli-0.1.0/tests/conftest.py +0 -72
  84. nonoka_cli-0.1.0/tests/integration/__init__.py +0 -1
  85. nonoka_cli-0.1.0/tests/integration/test_real_llm.py +0 -215
  86. nonoka_cli-0.1.0/tests/unit/__init__.py +0 -1
  87. nonoka_cli-0.1.0/tests/unit/test_config.py +0 -151
  88. nonoka_cli-0.1.0/tests/unit/test_core.py +0 -193
  89. nonoka_cli-0.1.0/tests/unit/test_shell.py +0 -158
  90. nonoka_cli-0.1.0/tests/unit/test_ui.py +0 -164
  91. {nonoka_cli-0.1.0 → nonoka_cli-0.2.2}/src/nonoka_cli/__init__.py +0 -0
  92. {nonoka_cli-0.1.0 → nonoka_cli-0.2.2}/src/nonoka_cli/__main__.py +0 -0
  93. {nonoka_cli-0.1.0 → nonoka_cli-0.2.2}/src/nonoka_cli/core/__init__.py +1 -1
  94. {nonoka_cli-0.1.0 → nonoka_cli-0.2.2}/src/nonoka_cli/core/context.py +0 -0
  95. {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
@@ -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.
@@ -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.
@@ -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)。