Skip to content

Commit 8340353

Browse files
committed
feat: 同步 3.0.x 对齐——run/tui 全旗标 + MCP 配置模型 + executor 引号修复(Jackson 2 / JDK 17 适配)
1 parent 1442c57 commit 8340353

17 files changed

Lines changed: 783 additions & 42 deletions

README.md

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
[English](./README.md) | [简体中文](./README.zh-CN.md)
44

5-
[![Java](https://img.shields.io/badge/Java-17-orange)](https://github.com/easy-4-java/opencode-java-sdk) [![License](https://img.shields.io/badge/license-Apache%202.0-green)](./LICENSE)
5+
[![Java](https://img.shields.io/badge/Java-21-orange)](https://github.com/easy-4-java/opencode-java-sdk) [![License](https://img.shields.io/badge/license-Apache%202.0-green)](./LICENSE)
66

77
Pure Java SDK (no Spring) for the OpenCode Server: HTTP REST API, SSE event stream and local CLI
88
[简体中文](./README.zh-CN.md)
99

10-
> **Current branch**: `feature/2.0.x`
11-
> **Version**: `2.0.x.x.20260630-SNAPSHOT`
10+
> **Current branch**: `feature/3.0.x`
11+
> **Version**: `3.0.x.x.20260630-SNAPSHOT`
1212
> **JDK baseline**: 8
1313
> **Project status**: stable (1.0.x line). Not yet published to Maven Central; artifacts are distributed via the Aliyun Maven repository and GitHub Releases.
1414
@@ -69,14 +69,15 @@ The current SDK adapts opencode **v1.17.18** CLI + Server HTTP API.
6969
| Misc API | Available | commands, skills, formatters, LSPs, MCP servers, path, VCS, instance dispose, global upgrade |
7070
| Question / permission API | Available | pending questions + permissions, reply/reject |
7171
| SSE event stream | Available | `subscribe`, `subscribeQueue`, `subscribeSession`, `subscribeEventTypes`, typed `EventHandler` |
72-
| CLI wrapper | Available | `run`, `runJson`, sessions, agents, models, providers/auth, MCP, stats, export/import, db, debug, serve/web/attach, github, plugin, console |
72+
| CLI wrapper | Available | `run`, `runJson`, `run(RunOptions)` full-flag, `tui(TuiOptions)`, sessions, agents, models, providers/auth, MCP (`mcp auth list` incl.), stats, export/import, db, debug, serve/web/attach full-flag (`--mdns/--cors/--mdns-domain`), github, plugin, console, `raw` escape hatch |
73+
| MCP config model | Available | `McpServerConfig` (`local` stdio / `remote` HTTP-SSE, environment/headers/oauth/timeout/enabled) wired into `OpenCodeConfig.mcp` |
7374

7475
<a id="3-requirements--compatibility"></a>
7576
## 3. Requirements & Compatibility
7677

7778
| Component | Version | Notes |
7879
|---|---:|---|
79-
| JDK | 17+ | 1.0.x line baseline |
80+
| JDK | 21+ | 1.0.x line baseline |
8081
| Maven | 3.0+ | Enforcer minimum |
8182
| OkHttp / okhttp-sse | 4.12.0 | HTTP + SSE transport |
8283
| Jackson databind | 2.17.x | JSON |
@@ -87,7 +88,7 @@ Version-line matrix:
8788

8889
| Version line | Branch | JDK | Version pattern | Purpose |
8990
|---|---|---:|---|---|
90-
| 1.0.x | `feature/2.0.x` (this branch) | 8 | `1.0.x.*` | Legacy projects, Boot 2.x starter line |
91+
| 1.0.x | `feature/3.0.x` (this branch) | 8 | `1.0.x.*` | Legacy projects, Boot 2.x starter line |
9192
| 2.0.x | `feature/2.0.x` | 17 | `2.0.x.*` | Main line (JDK 17) |
9293
| 3.0.x | `feature/3.0.x` | 21 | `3.0.x.*` | New projects |
9394

@@ -136,14 +137,14 @@ Maven:
136137
<dependency>
137138
<groupId>io.github.easy4j</groupId>
138139
<artifactId>opencode-java-sdk</artifactId>
139-
<version>2.0.x.x.20260630-SNAPSHOT</version>
140+
<version>3.0.x.x.20260630-SNAPSHOT</version>
140141
</dependency>
141142
```
142143

143144
Gradle:
144145

145146
```groovy
146-
implementation 'io.github.easy4j:opencode-java-sdk:2.0.x.x.20260630-SNAPSHOT'
147+
implementation 'io.github.easy4j:opencode-java-sdk:3.0.x.x.20260630-SNAPSHOT'
147148
```
148149

149150
Snapshot builds require an enabled snapshot repository (Aliyun Maven snapshot repository per `distributionManagement` in `pom.xml`).
@@ -242,6 +243,17 @@ OpenCodeCliResult result = cli.run("Explain async/await in JavaScript");
242243
System.out.println(result.getStdout());
243244

244245
cli.run("Hello", "plan", "anthropic/claude-sonnet-4-5"); // agent + model
246+
247+
// 全旗标 run(--command/--continue/--fork/--share/--file/--title/--attach/
248+
// --variant/--thinking/--dir/--port 均可组合)
249+
cli.run(new OpenCodeRunOptions("修复失败的测试")
250+
.model("anthropic/claude-sonnet-4-5")
251+
.format("json")
252+
.attach("http://localhost:4096")
253+
.variant("high"));
254+
255+
// 交互式 TUI
256+
cli.tui(new OpenCodeTuiOptions().project(".").continueLast(true).fork(true));
245257
cli.sessionList();
246258
cli.serve(4096, "127.0.0.1"); // opencode serve --port 4096 --hostname 127.0.0.1
247259
cli.upgrade("v1.18.0", "npm");

README.zh-CN.md

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22

33
[English](./README.md) | [简体中文](./README.zh-CN.md)
44

5-
[![Java](https://img.shields.io/badge/Java-17-orange)](https://github.com/easy-4-java/opencode-java-sdk) [![License](https://img.shields.io/badge/license-Apache%202.0-green)](./LICENSE)
5+
[![Java](https://img.shields.io/badge/Java-21-orange)](https://github.com/easy-4-java/opencode-java-sdk) [![License](https://img.shields.io/badge/license-Apache%202.0-green)](./LICENSE)
66

77
纯 Java 库(无 Spring):通过 HTTP REST API、SSE 事件流与本地 CLI 与 OpenCode Server 交互
88

9-
> **当前分支**`feature/2.0.x`
10-
> **版本**`2.0.x.x.20260630-SNAPSHOT`
9+
> **当前分支**`feature/3.0.x`
10+
> **版本**`3.0.x.x.20260630-SNAPSHOT`
1111
> **JDK 基线**:8
1212
> **项目状态**:稳定(1.0.x 线)。尚未发布 Maven Central;制品通过 Aliyun Maven 仓库与 GitHub Releases 分发。
1313
@@ -68,14 +68,15 @@
6868
| 其他 API | 可用 | commands、skills、formatters、LSPs、MCP servers、path、VCS、instance dispose、global upgrade |
6969
| Question / permission API | 可用 | 待回答问题与权限、reply / reject |
7070
| SSE 事件流 | 可用 | `subscribe``subscribeQueue``subscribeSession``subscribeEventTypes`、类型化 `EventHandler` |
71-
| CLI 封装 | 可用 | `run``runJson`、sessions、agents、models、providers/auth、MCP、stats、export / import、db、debug、serve / web / attach、github、plugin、console |
71+
| CLI 封装 | 可用 | `run``runJson``run(RunOptions)` 全旗标、`tui(TuiOptions)`、sessions、agents、models、providers/auth、MCP(含 `mcp auth list`)、stats、export / import、db、debug、serve / web / attach 全旗标(`--mdns/--cors/--mdns-domain`)、github、plugin、console、`raw` 逃生通道 |
72+
| MCP 配置模型 | 可用 | `McpServerConfig``local` stdio / `remote` HTTP-SSE,environment/headers/oauth/timeout/enabled),接入 `OpenCodeConfig.mcp` |
7273

7374
<a id="3-requirements--compatibility"></a>
7475
## 3. 运行要求与兼容性
7576

7677
| 组件 | 版本 | 说明 |
7778
|---|---:|---|
78-
| JDK | 17+ | 1.0.x 线基线 |
79+
| JDK | 21+ | 1.0.x 线基线 |
7980
| Maven | 3.0+ | Enforcer 下限 |
8081
| OkHttp / okhttp-sse | 4.12.0 | HTTP 与 SSE 传输 |
8182
| Jackson databind | 2.17.x | JSON |
@@ -86,7 +87,7 @@
8687

8788
| 版本线 | 分支 | JDK | 版本模式 | 用途 |
8889
|---|---|---:|---|---|
89-
| 1.0.x | `feature/2.0.x`(当前分支) | 8 | `1.0.x.*` | 存量项目、Boot 2.x Starter 线 |
90+
| 1.0.x | `feature/3.0.x`(当前分支) | 8 | `1.0.x.*` | 存量项目、Boot 2.x Starter 线 |
9091
| 2.0.x | `feature/2.0.x` | 17 | `2.0.x.*` | 主流线(JDK 17) |
9192
| 3.0.x | `feature/3.0.x` | 21 | `3.0.x.*` | 新项目 |
9293

@@ -135,14 +136,14 @@ Maven:
135136
<dependency>
136137
<groupId>io.github.easy4j</groupId>
137138
<artifactId>opencode-java-sdk</artifactId>
138-
<version>2.0.x.x.20260630-SNAPSHOT</version>
139+
<version>3.0.x.x.20260630-SNAPSHOT</version>
139140
</dependency>
140141
```
141142

142143
Gradle:
143144

144145
```groovy
145-
implementation 'io.github.easy4j:opencode-java-sdk:2.0.x.x.20260630-SNAPSHOT'
146+
implementation 'io.github.easy4j:opencode-java-sdk:3.0.x.x.20260630-SNAPSHOT'
146147
```
147148

148149
快照版本需要启用对应快照仓库(`pom.xml``distributionManagement` 指向 Aliyun Maven 仓库)。
@@ -241,6 +242,17 @@ OpenCodeCliResult result = cli.run("Explain async/await in JavaScript");
241242
System.out.println(result.getStdout());
242243

243244
cli.run("Hello", "plan", "anthropic/claude-sonnet-4-5"); // agent + model
245+
246+
// 全旗标 run(--command/--continue/--fork/--share/--file/--title/--attach/
247+
// --variant/--thinking/--dir/--port 均可组合)
248+
cli.run(new OpenCodeRunOptions("修复失败的测试")
249+
.model("anthropic/claude-sonnet-4-5")
250+
.format("json")
251+
.attach("http://localhost:4096")
252+
.variant("high"));
253+
254+
// 交互式 TUI
255+
cli.tui(new OpenCodeTuiOptions().project(".").continueLast(true).fork(true));
244256
cli.sessionList();
245257
cli.serve(4096, "127.0.0.1"); // opencode serve --port 4096 --hostname 127.0.0.1
246258
cli.upgrade("v1.18.0", "npm");

src/main/java/io/github/easy4j/opencode/OpenCodeClient.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.github.easy4j.opencode;
22

33
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import com.fasterxml.jackson.databind.json.JsonMapper;
45
import io.github.easy4j.opencode.api.mapper.ChatMessageMapper;
56
import io.github.easy4j.opencode.api.model.*;
67
import io.github.easy4j.opencode.cli.OpenCodeCli;
@@ -88,7 +89,7 @@ public class OpenCodeClient implements AutoCloseable {
8889
* @throws IllegalStateException 启用启动检查和快速失败后,对应子系统不可用
8990
*/
9091
public OpenCodeClient(OpenCodeHttpClientConfig httpConfig) {
91-
this(httpConfig, new OpenCodeCliConfig(), new ObjectMapper(), null);
92+
this(httpConfig, new OpenCodeCliConfig(), new JsonMapper(), null);
9293
}
9394

9495
/**
@@ -110,7 +111,7 @@ public OpenCodeClient(OpenCodeHttpClientConfig httpConfig, ObjectMapper objectMa
110111
* @throws IllegalStateException 启用启动检查和快速失败后,对应子系统不可用
111112
*/
112113
public OpenCodeClient(OpenCodeCliConfig cliConfig) {
113-
this(new OpenCodeHttpClientConfig(), cliConfig, new ObjectMapper(), null);
114+
this(new OpenCodeHttpClientConfig(), cliConfig, new JsonMapper(), null);
114115
}
115116

116117
/**
@@ -133,7 +134,7 @@ public OpenCodeClient(OpenCodeCliConfig cliConfig, ObjectMapper objectMapper, Ok
133134
* @throws IllegalStateException 启用启动检查和快速失败后,对应子系统不可用
134135
*/
135136
public OpenCodeClient(OpenCodeHttpClientConfig httpConfig, OpenCodeCliConfig cliConfig) {
136-
this(httpConfig, cliConfig, new ObjectMapper(), null);
137+
this(httpConfig, cliConfig, new JsonMapper(), null);
137138
}
138139

139140
/**
@@ -199,7 +200,7 @@ public OpenCodeClient(OpenCodeHttpClientConfig httpConfig, OpenCodeCliConfig cli
199200
* @throws IllegalStateException 启用启动检查和快速失败后,对应子系统不可用
200201
*/
201202
public OpenCodeClient(OpenCodeClientConfig config) {
202-
this(config, new ObjectMapper(), null);
203+
this(config, new JsonMapper(), null);
203204
}
204205

205206
/**

src/main/java/io/github/easy4j/opencode/api/OpenCodeChatClient.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.github.easy4j.opencode.api;
22

33
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import com.fasterxml.jackson.databind.json.JsonMapper;
45
import io.github.easy4j.opencode.HttpCallCancellation;
56
import io.github.easy4j.opencode.OpenCodeHttpClientConfig;
67
import io.github.easy4j.opencode.api.mapper.ChatMessageMapper;
@@ -56,7 +57,7 @@ public class OpenCodeChatClient extends OpenCodeHttpClient {
5657
* @param config 客户端配置;不得为 {@code null}
5758
*/
5859
public OpenCodeChatClient(OpenCodeHttpClientConfig config) {
59-
this(config, new ObjectMapper(), null);
60+
this(config, new JsonMapper(), null);
6061
}
6162

6263
/**

src/main/java/io/github/easy4j/opencode/api/OpenCodeHttpClient.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package io.github.easy4j.opencode.api;
22

3+
import com.fasterxml.jackson.core.JacksonException;
34
import com.fasterxml.jackson.core.type.TypeReference;
45
import com.fasterxml.jackson.databind.DeserializationFeature;
56
import com.fasterxml.jackson.databind.ObjectMapper;
7+
import com.fasterxml.jackson.databind.json.JsonMapper;
68
import io.github.easy4j.opencode.OpenCodeHttpClientConfig;
79
import io.github.easy4j.opencode.HttpCallCancellation;
810
import io.github.easy4j.opencode.OpenCodeOkHttpClientFactory;
@@ -76,8 +78,8 @@ public class OpenCodeHttpClient implements AutoCloseable {
7678
*/
7779
public OpenCodeHttpClient(OpenCodeHttpClientConfig config, ObjectMapper objectMapper, OkHttpClient httpClient) {
7880
this.config = Objects.requireNonNull(config, "config");
79-
this.objectMapper = Objects.isNull(objectMapper) ? new ObjectMapper()
80-
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false): objectMapper;
81+
this.objectMapper = Objects.isNull(objectMapper) ? JsonMapper.builder()
82+
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).build(): objectMapper;
8183
this.httpClient = Objects.isNull(httpClient) ? buildOkHttpClient(config) : httpClient;
8284
if (allows(HttpLogLevel.BASIC)) {
8385
log.debug("OpenCode HTTP client initialized: baseUrl={}, connectTimeoutMs={}, readTimeoutMs={}, "
@@ -485,7 +487,7 @@ public CompletableFuture<Boolean> promptAsync(String sessionId, PromptRequest re
485487
Request httpReq = authedRequest(url("/session/" + sessionId + "/prompt_async"), context)
486488
.post(body).build();
487489
return executeSuccessAsync(httpReq, null);
488-
} catch (IOException e) {
490+
} catch (JacksonException e) {
489491
return failedFuture(new OpenCodeHttpException("promptAsync failed: " + e.getMessage(), e));
490492
}
491493
}
@@ -1397,7 +1399,7 @@ protected <T> CompletableFuture<T> executeAsync(Request request, Class<T> type,
13971399
}
13981400
try {
13991401
return objectMapper.readValue(response.getBody(), type);
1400-
} catch (IOException error) {
1402+
} catch (JacksonException error) {
14011403
throw new OpenCodeHttpException("Failed to parse response: " + error.getMessage(), error);
14021404
}
14031405
});
@@ -1476,7 +1478,7 @@ private <T> CompletableFuture<T> executeListAsync(Request request, TypeReference
14761478
}
14771479
try {
14781480
return objectMapper.readValue(response.getBody(), typeRef);
1479-
} catch (IOException error) {
1481+
} catch (JacksonException error) {
14801482
throw new OpenCodeHttpException("Failed to parse response: " + error.getMessage(), error);
14811483
}
14821484
});
@@ -1618,7 +1620,7 @@ private Headers redactHeaders(Headers headers) {
16181620
private String toJson(Object body) {
16191621
try {
16201622
return objectMapper.writeValueAsString(body);
1621-
} catch (IOException e) {
1623+
} catch (JacksonException e) {
16221624
throw new OpenCodeHttpException("Failed to serialize request body: " + e.getMessage(), e);
16231625
}
16241626
}

src/main/java/io/github/easy4j/opencode/api/OpenCodeSseClient.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.fasterxml.jackson.databind.DeserializationFeature;
44
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import com.fasterxml.jackson.databind.json.JsonMapper;
56
import io.github.easy4j.opencode.OpenCodeHttpClientConfig;
67
import io.github.easy4j.opencode.OpenCodeOkHttpClientFactory;
78
import io.github.easy4j.opencode.api.event.EventHandler;
@@ -63,7 +64,7 @@ public class OpenCodeSseClient implements AutoCloseable {
6364
* @param config 客户端配置;不得为 {@code null}
6465
*/
6566
public OpenCodeSseClient(OpenCodeHttpClientConfig config) {
66-
this(config, new ObjectMapper(), null);
67+
this(config, new JsonMapper(), null);
6768
}
6869

6970
/**
@@ -76,8 +77,8 @@ public OpenCodeSseClient(OpenCodeHttpClientConfig config) {
7677
public OpenCodeSseClient(OpenCodeHttpClientConfig config, ObjectMapper objectMapper,
7778
OkHttpClient httpClient) {
7879
this.config = Objects.requireNonNull(config, "config");
79-
this.mapper = Objects.isNull(objectMapper) ? new ObjectMapper()
80-
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) : objectMapper;
80+
this.mapper = Objects.isNull(objectMapper) ? JsonMapper.builder()
81+
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).build() : objectMapper;
8182
this.ownsHttpClient = Objects.isNull(httpClient);
8283
OkHttpClient baseClient = ownsHttpClient
8384
? OpenCodeOkHttpClientFactory.create(config) : httpClient;

src/main/java/io/github/easy4j/opencode/api/mapper/OpenCodeCallbackParser.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.fasterxml.jackson.core.type.TypeReference;
44
import com.fasterxml.jackson.databind.DeserializationFeature;
55
import com.fasterxml.jackson.databind.ObjectMapper;
6+
import com.fasterxml.jackson.databind.json.JsonMapper;
67
import io.github.easy4j.opencode.api.model.PromptResult;
78
import org.slf4j.Logger;
89
import org.slf4j.LoggerFactory;
@@ -37,8 +38,8 @@ public class OpenCodeCallbackParser {
3738
/**
3839
* 用于解析回调 JSON 的共享映射器,允许注释并忽略服务端新增字段。
3940
*/
40-
private static final ObjectMapper MAPPER = new ObjectMapper()
41-
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
41+
private static final ObjectMapper MAPPER = JsonMapper.builder()
42+
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).build();
4243

4344
/**
4445
* 匹配 ```json ... ``` 代码块中的 JSON。

0 commit comments

Comments
 (0)