opencode-mcp 1.0.0
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.
- package/CHANGELOG.md +25 -0
- package/LICENSE +21 -0
- package/README.md +241 -0
- package/dist/client.d.ts +49 -0
- package/dist/client.js +197 -0
- package/dist/client.js.map +1 -0
- package/dist/helpers.d.ts +53 -0
- package/dist/helpers.js +132 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +86 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts.d.ts +9 -0
- package/dist/prompts.js +144 -0
- package/dist/prompts.js.map +1 -0
- package/dist/resources.d.ts +10 -0
- package/dist/resources.js +197 -0
- package/dist/resources.js.map +1 -0
- package/dist/tools/config.d.ts +3 -0
- package/dist/tools/config.js +33 -0
- package/dist/tools/config.js.map +1 -0
- package/dist/tools/events.d.ts +6 -0
- package/dist/tools/events.js +59 -0
- package/dist/tools/events.js.map +1 -0
- package/dist/tools/file.d.ts +3 -0
- package/dist/tools/file.js +127 -0
- package/dist/tools/file.js.map +1 -0
- package/dist/tools/global.d.ts +3 -0
- package/dist/tools/global.js +12 -0
- package/dist/tools/global.js.map +1 -0
- package/dist/tools/message.d.ts +3 -0
- package/dist/tools/message.js +151 -0
- package/dist/tools/message.js.map +1 -0
- package/dist/tools/misc.d.ts +3 -0
- package/dist/tools/misc.js +143 -0
- package/dist/tools/misc.js.map +1 -0
- package/dist/tools/project.d.ts +3 -0
- package/dist/tools/project.js +20 -0
- package/dist/tools/project.js.map +1 -0
- package/dist/tools/provider.d.ts +3 -0
- package/dist/tools/provider.js +58 -0
- package/dist/tools/provider.js.map +1 -0
- package/dist/tools/session.d.ts +3 -0
- package/dist/tools/session.js +223 -0
- package/dist/tools/session.js.map +1 -0
- package/dist/tools/tui.d.ts +7 -0
- package/dist/tools/tui.js +106 -0
- package/dist/tools/tui.js.map +1 -0
- package/dist/tools/workflow.d.ts +7 -0
- package/dist/tools/workflow.js +215 -0
- package/dist/tools/workflow.js.map +1 -0
- package/package.json +57 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.0.0] - 2025-02-08
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **70 MCP tools** covering the entire OpenCode headless server API
|
|
13
|
+
- **7 high-level workflow tools** — `opencode_ask`, `opencode_reply`, `opencode_conversation`, `opencode_sessions_overview`, `opencode_context`, `opencode_wait`, `opencode_review_changes`
|
|
14
|
+
- **18 session management tools** — create, list, get, delete, update, fork, share, abort, revert, diff, summarize, permissions
|
|
15
|
+
- **6 message tools** — send prompts (sync/async), list/get messages, slash commands, shell execution
|
|
16
|
+
- **6 file & search tools** — text/regex search, file finder, symbol search, directory listing, file reading, VCS status
|
|
17
|
+
- **8 config & provider tools** — configuration management, provider listing, auth (API keys, OAuth)
|
|
18
|
+
- **9 TUI control tools** — remote-control the OpenCode TUI
|
|
19
|
+
- **13 system & monitoring tools** — health, VCS, LSP, formatters, MCP servers, agents, commands, logging, events
|
|
20
|
+
- **10 MCP resources** — browseable data endpoints for project, config, providers, agents, commands, health, VCS, sessions, MCP servers, file status
|
|
21
|
+
- **5 MCP prompts** — guided workflow templates for code review, debugging, project setup, implementation, session summary
|
|
22
|
+
- **Robust HTTP client** — automatic retry with exponential backoff (429/502/503/504), error categorization, timeout support
|
|
23
|
+
- **Smart response formatting** — extracts meaningful text from message parts, truncation for large outputs
|
|
24
|
+
- **SSE event polling** — monitor real-time server events
|
|
25
|
+
- **`npx` support** — run with `npx opencode-mcp` without installing globally
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Alaeddine Messadi
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# opencode-mcp
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/opencode-mcp)
|
|
4
|
+
[](https://github.com/AlaeddineMessadi/opencode-mcp/blob/main/LICENSE)
|
|
5
|
+
[](https://nodejs.org/)
|
|
6
|
+
|
|
7
|
+
An [MCP](https://modelcontextprotocol.io/) server that gives any MCP-compatible client full access to a running [OpenCode](https://opencode.ai/) instance. Manage sessions, send prompts, search files, review diffs, configure providers, control the TUI, and more.
|
|
8
|
+
|
|
9
|
+
**70 tools** | **10 resources** | **5 prompts**
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
### 1. Start an OpenCode server
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
opencode serve
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### 2. Add to your MCP client
|
|
20
|
+
|
|
21
|
+
**Claude Desktop** (`claude_desktop_config.json`):
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"mcpServers": {
|
|
26
|
+
"opencode": {
|
|
27
|
+
"command": "npx",
|
|
28
|
+
"args": ["-y", "opencode-mcp"]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Claude Code:**
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
claude mcp add opencode -- npx -y opencode-mcp
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Cursor** (`.cursor/mcp.json`):
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"mcpServers": {
|
|
45
|
+
"opencode": {
|
|
46
|
+
"command": "npx",
|
|
47
|
+
"args": ["-y", "opencode-mcp"]
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Windsurf** (`~/.windsurf/mcp.json`):
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"mcpServers": {
|
|
58
|
+
"opencode": {
|
|
59
|
+
"command": "npx",
|
|
60
|
+
"args": ["-y", "opencode-mcp"]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**opencode** (`opencode.json`):
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"mcp": {
|
|
71
|
+
"opencode-mcp": {
|
|
72
|
+
"type": "stdio",
|
|
73
|
+
"command": "npx",
|
|
74
|
+
"args": ["-y", "opencode-mcp"]
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
That's it. Your MCP client now has access to the entire OpenCode API.
|
|
81
|
+
|
|
82
|
+
### Custom server URL or auth
|
|
83
|
+
|
|
84
|
+
If the OpenCode server is on a different host/port or has auth enabled, pass environment variables:
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"mcpServers": {
|
|
89
|
+
"opencode": {
|
|
90
|
+
"command": "npx",
|
|
91
|
+
"args": ["-y", "opencode-mcp"],
|
|
92
|
+
"env": {
|
|
93
|
+
"OPENCODE_BASE_URL": "http://192.168.1.10:4096",
|
|
94
|
+
"OPENCODE_SERVER_USERNAME": "myuser",
|
|
95
|
+
"OPENCODE_SERVER_PASSWORD": "mypass"
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## What Can It Do?
|
|
103
|
+
|
|
104
|
+
### Workflow Tools (start here)
|
|
105
|
+
|
|
106
|
+
High-level tools designed to be the easiest way for an LLM to interact with OpenCode:
|
|
107
|
+
|
|
108
|
+
| Tool | What it does |
|
|
109
|
+
|---|---|
|
|
110
|
+
| `opencode_ask` | Create session + send prompt + get answer in one call |
|
|
111
|
+
| `opencode_reply` | Follow-up message in an existing session |
|
|
112
|
+
| `opencode_conversation` | Formatted conversation history |
|
|
113
|
+
| `opencode_sessions_overview` | Quick overview of all sessions |
|
|
114
|
+
| `opencode_context` | Project + path + VCS + config + agents in one call |
|
|
115
|
+
| `opencode_wait` | Poll an async session until it finishes |
|
|
116
|
+
| `opencode_review_changes` | Formatted diff summary for a session |
|
|
117
|
+
|
|
118
|
+
### Session Tools (18)
|
|
119
|
+
|
|
120
|
+
Create, list, get, delete, update, fork, share, abort, revert sessions. Get diffs, todos, summaries, child sessions, and respond to permission requests.
|
|
121
|
+
|
|
122
|
+
### Message Tools (6)
|
|
123
|
+
|
|
124
|
+
Send prompts (sync or async), list/get messages, execute slash commands, run shell commands.
|
|
125
|
+
|
|
126
|
+
### File & Search Tools (6)
|
|
127
|
+
|
|
128
|
+
Search text/regex across the project, find files by name, find workspace symbols, list directories, read files, check VCS file status.
|
|
129
|
+
|
|
130
|
+
### Config & Provider Tools (8)
|
|
131
|
+
|
|
132
|
+
Get/update config, list providers and models, manage auth (API keys, OAuth).
|
|
133
|
+
|
|
134
|
+
### TUI Control Tools (9)
|
|
135
|
+
|
|
136
|
+
Remote-control the OpenCode TUI: append/submit/clear prompts, execute commands, show toasts, open dialogs (help, sessions, models, themes).
|
|
137
|
+
|
|
138
|
+
### System & Monitoring Tools (13)
|
|
139
|
+
|
|
140
|
+
Health checks, VCS info, LSP/formatter status, MCP server management, agent/command listing, logging, SSE event polling.
|
|
141
|
+
|
|
142
|
+
### Resources (10)
|
|
143
|
+
|
|
144
|
+
Browseable data endpoints:
|
|
145
|
+
|
|
146
|
+
| URI | Description |
|
|
147
|
+
|---|---|
|
|
148
|
+
| `opencode://project/current` | Current active project |
|
|
149
|
+
| `opencode://config` | Current configuration |
|
|
150
|
+
| `opencode://providers` | Providers with models |
|
|
151
|
+
| `opencode://agents` | Available agents |
|
|
152
|
+
| `opencode://commands` | Available commands |
|
|
153
|
+
| `opencode://health` | Server health and version |
|
|
154
|
+
| `opencode://vcs` | Version control info |
|
|
155
|
+
| `opencode://sessions` | All sessions |
|
|
156
|
+
| `opencode://mcp-servers` | MCP server status |
|
|
157
|
+
| `opencode://file-status` | VCS file status |
|
|
158
|
+
|
|
159
|
+
### Prompts (5)
|
|
160
|
+
|
|
161
|
+
Guided workflow templates:
|
|
162
|
+
|
|
163
|
+
| Prompt | Description |
|
|
164
|
+
|---|---|
|
|
165
|
+
| `opencode-code-review` | Structured code review from session diffs |
|
|
166
|
+
| `opencode-debug` | Guided debugging workflow |
|
|
167
|
+
| `opencode-project-setup` | Get oriented in a new project |
|
|
168
|
+
| `opencode-implement` | Have OpenCode implement a feature |
|
|
169
|
+
| `opencode-session-summary` | Summarize a session |
|
|
170
|
+
|
|
171
|
+
## Environment Variables
|
|
172
|
+
|
|
173
|
+
| Variable | Description | Default |
|
|
174
|
+
|---|---|---|
|
|
175
|
+
| `OPENCODE_BASE_URL` | URL of the OpenCode server | `http://127.0.0.1:4096` |
|
|
176
|
+
| `OPENCODE_SERVER_USERNAME` | HTTP basic auth username | `opencode` |
|
|
177
|
+
| `OPENCODE_SERVER_PASSWORD` | HTTP basic auth password | *(none — auth disabled)* |
|
|
178
|
+
|
|
179
|
+
## How It Works
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
MCP Client <--stdio--> opencode-mcp <--HTTP--> OpenCode Server
|
|
183
|
+
(Claude, Cursor, etc.) (this package) (opencode serve)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
The MCP server communicates over **stdio** using the Model Context Protocol. When a client invokes a tool, the server translates it into HTTP calls against the OpenCode headless API. The OpenCode server must be running separately (`opencode serve`).
|
|
187
|
+
|
|
188
|
+
## Architecture
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
src/
|
|
192
|
+
index.ts Entry point — wires everything together
|
|
193
|
+
client.ts HTTP client with retry, SSE, error categorization
|
|
194
|
+
helpers.ts Smart response formatting for LLM-friendly output
|
|
195
|
+
resources.ts MCP Resources (10 browseable data endpoints)
|
|
196
|
+
prompts.ts MCP Prompts (5 guided workflow templates)
|
|
197
|
+
tools/
|
|
198
|
+
workflow.ts High-level workflow tools (7)
|
|
199
|
+
session.ts Session management tools (18)
|
|
200
|
+
message.ts Message/prompt tools (6)
|
|
201
|
+
file.ts File and search tools (6)
|
|
202
|
+
tui.ts TUI remote control tools (9)
|
|
203
|
+
config.ts Config tools (3)
|
|
204
|
+
provider.ts Provider/auth tools (5)
|
|
205
|
+
misc.ts System, agents, LSP, MCP, logging tools (13)
|
|
206
|
+
events.ts SSE event polling (1)
|
|
207
|
+
global.ts Health check (1)
|
|
208
|
+
project.ts Project tools (2)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Development
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
git clone https://github.com/AlaeddineMessadi/opencode-mcp.git
|
|
215
|
+
cd opencode-mcp
|
|
216
|
+
npm install
|
|
217
|
+
npm run build # compiles TypeScript and sets executable permissions
|
|
218
|
+
npm start # runs the MCP server
|
|
219
|
+
npm run dev # watch mode
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Documentation
|
|
223
|
+
|
|
224
|
+
- [Getting Started](docs/getting-started.md) — step-by-step setup guide
|
|
225
|
+
- [Configuration](docs/configuration.md) — all env vars and MCP client configs
|
|
226
|
+
- [Tools Reference](docs/tools.md) — detailed reference for all 70 tools
|
|
227
|
+
- [Resources Reference](docs/resources.md) — all 10 MCP resources
|
|
228
|
+
- [Prompts Reference](docs/prompts.md) — all 5 MCP prompts
|
|
229
|
+
- [Usage Examples](docs/examples.md) — real workflow examples
|
|
230
|
+
- [Architecture](docs/architecture.md) — system design and data flow
|
|
231
|
+
|
|
232
|
+
## References
|
|
233
|
+
|
|
234
|
+
- [OpenCode Documentation](https://opencode.ai/docs/)
|
|
235
|
+
- [OpenCode Server API](https://opencode.ai/docs/server/)
|
|
236
|
+
- [OpenCode SDK](https://opencode.ai/docs/sdk/)
|
|
237
|
+
- [Model Context Protocol](https://modelcontextprotocol.io/)
|
|
238
|
+
|
|
239
|
+
## License
|
|
240
|
+
|
|
241
|
+
[MIT](LICENSE)
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client wrapper for the OpenCode server API.
|
|
3
|
+
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - Basic auth support
|
|
6
|
+
* - Automatic retry with exponential backoff for transient errors
|
|
7
|
+
* - Proper 204 No Content handling on all methods
|
|
8
|
+
* - SSE streaming support
|
|
9
|
+
* - Error categorization (transient vs permanent)
|
|
10
|
+
*/
|
|
11
|
+
export interface OpenCodeClientOptions {
|
|
12
|
+
baseUrl: string;
|
|
13
|
+
username?: string;
|
|
14
|
+
password?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare class OpenCodeError extends Error {
|
|
17
|
+
readonly status: number;
|
|
18
|
+
readonly method: string;
|
|
19
|
+
readonly path: string;
|
|
20
|
+
readonly body: string;
|
|
21
|
+
constructor(message: string, status: number, method: string, path: string, body: string);
|
|
22
|
+
get isTransient(): boolean;
|
|
23
|
+
get isNotFound(): boolean;
|
|
24
|
+
get isAuth(): boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare class OpenCodeClient {
|
|
27
|
+
private baseUrl;
|
|
28
|
+
private authHeader?;
|
|
29
|
+
constructor(options: OpenCodeClientOptions);
|
|
30
|
+
getBaseUrl(): string;
|
|
31
|
+
private buildUrl;
|
|
32
|
+
private headers;
|
|
33
|
+
private request;
|
|
34
|
+
get<T = unknown>(path: string, query?: Record<string, string>): Promise<T>;
|
|
35
|
+
post<T = unknown>(path: string, body?: unknown, opts?: {
|
|
36
|
+
timeout?: number;
|
|
37
|
+
}): Promise<T>;
|
|
38
|
+
patch<T = unknown>(path: string, body?: unknown): Promise<T>;
|
|
39
|
+
put<T = unknown>(path: string, body?: unknown): Promise<T>;
|
|
40
|
+
delete<T = unknown>(path: string, query?: Record<string, string>): Promise<T>;
|
|
41
|
+
/**
|
|
42
|
+
* Subscribe to SSE events. Returns an async iterable of parsed events.
|
|
43
|
+
* The caller should break out of the loop when done.
|
|
44
|
+
*/
|
|
45
|
+
subscribeSSE(path: string): AsyncGenerator<{
|
|
46
|
+
event: string;
|
|
47
|
+
data: string;
|
|
48
|
+
}, void, undefined>;
|
|
49
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client wrapper for the OpenCode server API.
|
|
3
|
+
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - Basic auth support
|
|
6
|
+
* - Automatic retry with exponential backoff for transient errors
|
|
7
|
+
* - Proper 204 No Content handling on all methods
|
|
8
|
+
* - SSE streaming support
|
|
9
|
+
* - Error categorization (transient vs permanent)
|
|
10
|
+
*/
|
|
11
|
+
export class OpenCodeError extends Error {
|
|
12
|
+
status;
|
|
13
|
+
method;
|
|
14
|
+
path;
|
|
15
|
+
body;
|
|
16
|
+
constructor(message, status, method, path, body) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.status = status;
|
|
19
|
+
this.method = method;
|
|
20
|
+
this.path = path;
|
|
21
|
+
this.body = body;
|
|
22
|
+
this.name = "OpenCodeError";
|
|
23
|
+
}
|
|
24
|
+
get isTransient() {
|
|
25
|
+
return (this.status === 429 ||
|
|
26
|
+
this.status === 502 ||
|
|
27
|
+
this.status === 503 ||
|
|
28
|
+
this.status === 504);
|
|
29
|
+
}
|
|
30
|
+
get isNotFound() {
|
|
31
|
+
return this.status === 404;
|
|
32
|
+
}
|
|
33
|
+
get isAuth() {
|
|
34
|
+
return this.status === 401 || this.status === 403;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const MAX_RETRIES = 2;
|
|
38
|
+
const BASE_DELAY_MS = 500;
|
|
39
|
+
export class OpenCodeClient {
|
|
40
|
+
baseUrl;
|
|
41
|
+
authHeader;
|
|
42
|
+
constructor(options) {
|
|
43
|
+
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
44
|
+
if (options.password) {
|
|
45
|
+
const username = options.username ?? "opencode";
|
|
46
|
+
this.authHeader =
|
|
47
|
+
"Basic " +
|
|
48
|
+
Buffer.from(`${username}:${options.password}`).toString("base64");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
getBaseUrl() {
|
|
52
|
+
return this.baseUrl;
|
|
53
|
+
}
|
|
54
|
+
buildUrl(path, query) {
|
|
55
|
+
const url = new URL(path, this.baseUrl);
|
|
56
|
+
if (query) {
|
|
57
|
+
for (const [key, value] of Object.entries(query)) {
|
|
58
|
+
if (value !== undefined && value !== "") {
|
|
59
|
+
url.searchParams.set(key, value);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return url.toString();
|
|
64
|
+
}
|
|
65
|
+
headers(accept) {
|
|
66
|
+
const h = {
|
|
67
|
+
"Content-Type": "application/json",
|
|
68
|
+
Accept: accept ?? "application/json",
|
|
69
|
+
};
|
|
70
|
+
if (this.authHeader) {
|
|
71
|
+
h["Authorization"] = this.authHeader;
|
|
72
|
+
}
|
|
73
|
+
return h;
|
|
74
|
+
}
|
|
75
|
+
async request(method, path, opts) {
|
|
76
|
+
const url = this.buildUrl(path, opts?.query);
|
|
77
|
+
let lastError;
|
|
78
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
79
|
+
if (attempt > 0) {
|
|
80
|
+
const delay = BASE_DELAY_MS * Math.pow(2, attempt - 1);
|
|
81
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const controller = new AbortController();
|
|
85
|
+
const timeoutId = opts?.timeout
|
|
86
|
+
? setTimeout(() => controller.abort(), opts.timeout)
|
|
87
|
+
: undefined;
|
|
88
|
+
const res = await fetch(url, {
|
|
89
|
+
method,
|
|
90
|
+
headers: this.headers(),
|
|
91
|
+
body: opts?.body !== undefined ? JSON.stringify(opts.body) : undefined,
|
|
92
|
+
signal: controller.signal,
|
|
93
|
+
});
|
|
94
|
+
if (timeoutId)
|
|
95
|
+
clearTimeout(timeoutId);
|
|
96
|
+
if (!res.ok) {
|
|
97
|
+
const text = await res.text();
|
|
98
|
+
const err = new OpenCodeError(`${method} ${path} failed (${res.status}): ${text}`, res.status, method, path, text);
|
|
99
|
+
if (err.isTransient && attempt < MAX_RETRIES) {
|
|
100
|
+
lastError = err;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
throw err;
|
|
104
|
+
}
|
|
105
|
+
// Handle 204 No Content
|
|
106
|
+
if (res.status === 204) {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
const contentType = res.headers.get("content-type") ?? "";
|
|
110
|
+
if (contentType.includes("application/json")) {
|
|
111
|
+
return (await res.json());
|
|
112
|
+
}
|
|
113
|
+
// Return text for non-JSON responses
|
|
114
|
+
return (await res.text());
|
|
115
|
+
}
|
|
116
|
+
catch (e) {
|
|
117
|
+
if (e instanceof OpenCodeError)
|
|
118
|
+
throw e;
|
|
119
|
+
lastError = e;
|
|
120
|
+
if (attempt >= MAX_RETRIES)
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
throw lastError ?? new Error(`${method} ${path} failed after retries`);
|
|
125
|
+
}
|
|
126
|
+
async get(path, query) {
|
|
127
|
+
return this.request("GET", path, { query });
|
|
128
|
+
}
|
|
129
|
+
async post(path, body, opts) {
|
|
130
|
+
return this.request("POST", path, { body, timeout: opts?.timeout });
|
|
131
|
+
}
|
|
132
|
+
async patch(path, body) {
|
|
133
|
+
return this.request("PATCH", path, { body });
|
|
134
|
+
}
|
|
135
|
+
async put(path, body) {
|
|
136
|
+
return this.request("PUT", path, { body });
|
|
137
|
+
}
|
|
138
|
+
async delete(path, query) {
|
|
139
|
+
return this.request("DELETE", path, { query });
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Subscribe to SSE events. Returns an async iterable of parsed events.
|
|
143
|
+
* The caller should break out of the loop when done.
|
|
144
|
+
*/
|
|
145
|
+
async *subscribeSSE(path) {
|
|
146
|
+
const url = this.buildUrl(path);
|
|
147
|
+
const res = await fetch(url, {
|
|
148
|
+
method: "GET",
|
|
149
|
+
headers: {
|
|
150
|
+
...this.headers("text/event-stream"),
|
|
151
|
+
Accept: "text/event-stream",
|
|
152
|
+
"Cache-Control": "no-cache",
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
if (!res.ok) {
|
|
156
|
+
const text = await res.text();
|
|
157
|
+
throw new OpenCodeError(`SSE ${path} failed (${res.status}): ${text}`, res.status, "GET", path, text);
|
|
158
|
+
}
|
|
159
|
+
if (!res.body) {
|
|
160
|
+
throw new Error("No response body for SSE stream");
|
|
161
|
+
}
|
|
162
|
+
const reader = res.body.getReader();
|
|
163
|
+
const decoder = new TextDecoder();
|
|
164
|
+
let buffer = "";
|
|
165
|
+
let currentEvent = "";
|
|
166
|
+
let currentData = "";
|
|
167
|
+
try {
|
|
168
|
+
while (true) {
|
|
169
|
+
const { done, value } = await reader.read();
|
|
170
|
+
if (done)
|
|
171
|
+
break;
|
|
172
|
+
buffer += decoder.decode(value, { stream: true });
|
|
173
|
+
const lines = buffer.split("\n");
|
|
174
|
+
buffer = lines.pop() ?? "";
|
|
175
|
+
for (const line of lines) {
|
|
176
|
+
if (line.startsWith("event:")) {
|
|
177
|
+
currentEvent = line.slice(6).trim();
|
|
178
|
+
}
|
|
179
|
+
else if (line.startsWith("data:")) {
|
|
180
|
+
currentData = line.slice(5).trim();
|
|
181
|
+
}
|
|
182
|
+
else if (line === "") {
|
|
183
|
+
if (currentData) {
|
|
184
|
+
yield { event: currentEvent || "message", data: currentData };
|
|
185
|
+
currentEvent = "";
|
|
186
|
+
currentData = "";
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
finally {
|
|
193
|
+
reader.releaseLock();
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart response formatting helpers.
|
|
3
|
+
*
|
|
4
|
+
* Instead of dumping raw JSON to the LLM, these helpers extract the
|
|
5
|
+
* meaningful content from OpenCode API responses so the LLM can reason
|
|
6
|
+
* about them efficiently.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Extract a human-readable summary from a message response.
|
|
10
|
+
* Pulls text content from parts, summarizes tool calls, etc.
|
|
11
|
+
* Accepts any shape — casts internally for safety.
|
|
12
|
+
*/
|
|
13
|
+
export declare function formatMessageResponse(response: unknown): string;
|
|
14
|
+
/**
|
|
15
|
+
* Format a list of messages, extracting text content from each.
|
|
16
|
+
*/
|
|
17
|
+
export declare function formatMessageList(messages: unknown[]): string;
|
|
18
|
+
/**
|
|
19
|
+
* Format a diff response into a readable summary.
|
|
20
|
+
*/
|
|
21
|
+
export declare function formatDiffResponse(diffs: unknown[]): string;
|
|
22
|
+
/**
|
|
23
|
+
* Format session objects for LLM-friendly display.
|
|
24
|
+
*/
|
|
25
|
+
export declare function formatSessionList(sessions: unknown[]): string;
|
|
26
|
+
/**
|
|
27
|
+
* Generic safe JSON stringify with truncation for very large responses.
|
|
28
|
+
*/
|
|
29
|
+
export declare function safeStringify(value: unknown, maxLength?: number): string;
|
|
30
|
+
/**
|
|
31
|
+
* Standard tool response builder.
|
|
32
|
+
*/
|
|
33
|
+
export declare function toolResult(text: string, isError?: boolean): {
|
|
34
|
+
isError?: boolean | undefined;
|
|
35
|
+
content: {
|
|
36
|
+
type: "text";
|
|
37
|
+
text: string;
|
|
38
|
+
}[];
|
|
39
|
+
};
|
|
40
|
+
export declare function toolError(e: unknown): {
|
|
41
|
+
isError?: boolean | undefined;
|
|
42
|
+
content: {
|
|
43
|
+
type: "text";
|
|
44
|
+
text: string;
|
|
45
|
+
}[];
|
|
46
|
+
};
|
|
47
|
+
export declare function toolJson(value: unknown): {
|
|
48
|
+
isError?: boolean | undefined;
|
|
49
|
+
content: {
|
|
50
|
+
type: "text";
|
|
51
|
+
text: string;
|
|
52
|
+
}[];
|
|
53
|
+
};
|