Skip to content

Commit 36fa750

Browse files
committed
docs(openspec): restore spec-first review gate for runtime integration
Add a documentation-only review package derived from existing drafts. Define six capabilities, 28 requirements, 60 scenarios and 43 pending tasks. Keep prior implementation separate and mark official validation as not run.
1 parent 99974ef commit 36fa750

14 files changed

Lines changed: 785 additions & 0 deletions

File tree

openspec/AGENTS.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# OpenSpec 工作约定
2+
3+
本仓库采用 `spec-driven`:proposal → specs → design → tasks → review → implementation → verification → archive。
4+
OpenSpec 的工件依赖判断只证明文件是否齐备,不代表用户批准;本项目另外使用 change 中的 `review.md` 记录批准状态。
5+
6+
## 执行门禁
7+
8+
1. 读取 `config.yaml`、目标 change 全部工件和相关主规范;没有主规范时不得凭空使用 MODIFIED。
9+
2. 将可观察契约写入 `specs/<capability>/spec.md`,技术选择写入 design,任务和验证写入 tasks。
10+
3. 在项目目录执行 `openspec validate <change-id> --strict`,保存工具版本、命令、退出码与完整输出;失败或未执行都不是通过。
11+
4. 用户明确批准书面范围与计划后才能进入实现。此前只允许只读调查和文档修改。
12+
5. 已有提前实现的代码保留在原分支,逐条映射规范、补失败用例并复验;不能通过倒填勾选框追认完成。
13+
6. 三条兼容线分别记录提交和测试证据。只允许 Java/Jackson/构建适配差异,不允许悄悄删功能。
14+
7. 所有实现与验证门禁满足后,再同步主规范并归档。不得将提案直接复制成“已经实现”的主规范。
15+
16+
## 本轮状态
17+
18+
当前 change:`harden-opencode-runtime-integration`
19+
纯文档评审分支与 `fix/runtime-integration-hardening` 分开;不强推、不回滚、不合并现有实现分支。
20+
正式 CLI 校验或运行测试受环境限制时,准确记录 `NOT_RUN` 和原因,保留未勾选任务。
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
schema: spec-driven
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# 技术设计(评审稿)
2+
3+
## Context
4+
5+
目标是可靠的 Java 接入层,不是再次铺开命令列表。原始三个版本线与提前实现分支必须分开:后者已经存在代码和测试文件,但没有本轮执行证据。详见 evidence.md。
6+
7+
## Goals / Non-Goals
8+
9+
实现 proposal 的六项能力并保证同一可观察契约在三线成立。完整 ACP 协议客户端、内嵌 PTY 和 Web UI 不在范围;环境隔离不等于租户安全边界。
10+
11+
## Approaches
12+
13+
A. 只补 CLI 参数:改动小,但不能解决生命周期和流式可靠性,拒绝作为完整方案。
14+
B. 保留现有门面并增加执行模式、生命周期与事件归约层:兼容成本可控,作为本稿建议。
15+
C. 改成全新多模块 SDK:范围和迁移成本过大,暂不采用。
16+
下列决策均为待批准的设计,不追认既有代码为正确实现。
17+
18+
## Decisions
19+
20+
### D1. CLI 契约与执行模式分离
21+
22+
`OpenCodeRunOptions``OpenCodeTuiOptions` 只负责经过版本核对的 argv;全局选项与 SDK 日志分开。
23+
候选补齐项:run 的 auto/interactive;TUI 的 auto/mdns/mdns-domain/cors;serve 的 mdns-domain;ACP 的网络选项;全局 print-logs/log-level/pure;stats 的“省略/全部/前 N 个”模型统计。每项先核对目标 tag 的命令解析器和帮助输出,不把滚动网页当成固定版本证明。
24+
`share(boolean)` 为新入口;废弃但保留 `share(String)`,null/"false" 不启用、"true" 启用,忽略大小写和首尾空白,其他值抛参数错误;不得静默把 "org" 变为 true。
25+
CAPTURE 适用于普通命令;STREAM 适用于增量输出;INHERIT_TERMINAL 只在调用方提供可用终端时使用;MANAGED 适用于常驻服务。交互选项不得在无 stdin 的捕获模式下悄悄执行。
26+
保留旧方法签名;新的重载和句柄由调用者显式采用。捕获结果保留原始 UTF-8 空白,展示层自行 trim,并说明 2/3 线此前 trim 的行为变化。
27+
28+
### D2. 资源与准入
29+
30+
`OpenCodeCliExecutor` 的每个实例管理自己的并发额度;同一实例的同步、流式、managed 调用共用额度。不承诺 JVM 或集群全局限流。
31+
提供有界等待的准入超时;排队取消不启动进程。额度从准入成功持有到进程、管道和监听资源完成清理,所有终态最多释放一次。
32+
`OpenCodeCliExecutionContext` 在调用开始时复制环境与目录;允许不继承环境、覆盖或移除变量,不修改 JVM 环境。可执行文件路径是一个独立 argv 元素,不解析为 shell 命令。
33+
拟定默认值供评审:普通命令沿用 300 秒执行超时;准入等待 30 秒;stdout/stderr 各保留最多 1 MiB;managed 使用同上限日志尾部;单帧默认最大 256 KiB、派发队列最大 4 MiB。限制可配置但必须可验证,不能用无限队列规避溢出。
34+
短命令保留前缀并记录截断字节;managed 保留尾部;持续排空两条管道避免死锁。CLI 协议帧超限或消费队列超限默认显式失败,不静默丢事件;日志可截断并标记。
35+
36+
### D3. 结果与流式句柄
37+
38+
建议复用并扩展现有 `OpenCodeCliResult`,增加结果分类、实际退出码(存在时)、错误原因及截断元数据;不得把全部异常折叠为 -1 和空 stdout。
39+
`OpenCodeCliStreamHandle` 暴露增量 stdout/stderr、独立退出完成、取消与幂等 close。`runStream` 在此之上进行版本受控 JSON 帧解析。UTF-8 解码器跨块保留状态;无换行超长输出同样受限。
40+
用户回调在受限派发边界执行;回调抛错与 JSON 解码失败明确区分。主动取消、超时和进程自行失败保留不同原因;最终结果要等待可控范围内的管道排空和清理。
41+
42+
### D4. Web/Serve 生命周期及安全
43+
44+
建议新增 `OpenCodeServerHandle`:STARTING → READY → STOPPING → EXITED;启动或运行失败进入 FAILED。记录退出事实和失败原因,不能把 spawn 成功直接当成 READY。
45+
启动超时 30 秒、关闭宽限 5 秒是本稿默认建议;存活时间默认无上限,不继承 300 秒普通命令超时。
46+
首版 managed API 要求明确、非零端口;没有已验证机器可读地址发现契约前不支持随机端口。CLI raw/原有 web 调用不因此删除。IPv6 地址使用合法 URI 表达,监听地址与客户端访问地址分开。
47+
就绪必须与所启动子进程关联:启动前发现端口已被占用就失败,不把旧服务的健康返回当成本次成功;就绪时同时检查子进程仍存活、预期地址及身份/版本信息。健康探测认证与服务端启动认证分别传递。
48+
默认 loopback。非 loopback/mDNS 要求显式开放和认证;确需无认证局域网模式时另外显式选择不安全策略并提示风险。CORS 不代替认证。日志不输出密码、token、完整环境或内联配置;子进程原始输出本身可能包含敏感信息,交付调用者的数据与 SDK 诊断日志使用不同策略。
49+
SDK 自建进程由句柄关闭;外部连接句柄关闭只能释放客户端资源。启动失败要回收自建进程;优雅退出超时后按明确策略强制终止。JDK 8 的进程树清理必须单独验证,不能把 17/21 的 ProcessHandle 直接复制过去。
50+
51+
### D5. ACP 与终端边界
52+
53+
ACP launcher 只承诺双向 stdio、独立 stderr、进程状态和关闭;不把 stdout 当日志打印或提前全部消费。进程 STARTED 不等于 ACP 协议初始化 READY;握手由外部协议客户端负责。
54+
完整 JSON-RPC/ACP 请求关联与会话管理、内嵌 PTY/窗口 resize 分别另提变更。本次允许继承调用方终端,但不得声称“支持 interactive flag”就已经提供完整终端产品。
55+
56+
### D6. SSE 聊天状态机
57+
58+
流程:校验请求 → 解析会话 → 建立订阅 → 等待就绪 → 提交 prompt_async → 消费当前请求事件 → 完成/失败/取消 → 清理。
59+
连接阶段和生成阶段分别有界;建立会话失败、调度器拒绝任务、subscribe 同步异常也必须完成返回 Future。订阅就绪至少绑定 onOpen,并用固定版本真实首片测试核实服务端监听已经建立;如果上游需要 server.connected 等握手,纳入版本适配器,不能仅用“创建了句柄”作保证。
60+
`message.part.delta` 按 session/message/part/field 归约;只向正文回调发送正文增量。`message.part.updated` 更新快照状态,不重复追加。优先精确事件类型匹配,版本事件别名由适配器处理。status 同时按目标契约读取对象中的 type,不把 Map.toString 当状态枚举。
61+
同一客户端同一会话只允许一个高层生成;再次提交明确忙错误。外部并发不能靠本地锁解决,必须使用消息/请求关联;不能关联时要求专用会话,不能把其他客户端事件混入答案。
62+
终态错误与 EOF 必须区分:生成中无正常终态的 EOF 视为失败;正常完成后的断连不覆盖成功。仅靠计时器兜底不算错误传播。
63+
取消默认只取消本地订阅与尚未发送的请求;不自动 abort 共享服务端会话。显式 abort 是另一个操作。所有竞争终态只完成一次;完成后不再回调,不遗留 timeout、订阅或持有内容的监听器。
64+
不自动重发 prompt;断线后不承诺没有服务端证据的精确一次恢复。delta/快照去重与传输级重放不是一回事。
65+
66+
### D7. 配置往返
67+
68+
`OpenCodeConfig.server` 使用可扩展的 `OpenCodeServerConfig`;根和 server 内未知字段保留原结构。Jackson 2/3 分支分别实现正确 any-setter/any-getter,不能把 JSON 键改名为 extra 或让未知字段覆盖已知字段。
69+
读取整个对象后序列化用于往返测试,不代表应当自动 PATCH 全部配置。保留动态 Object 提交;未设置、显式 null、空值和删除按固定上游 PATCH 契约区分。已有 agent/provider 的对象形状也纳入 fixture,不能只测新增 server 字段。
70+
注入资源保持外部所有权;SDK 自建资源失败时回收。单 HTTP/CLI 构造器的实际启用行为与文档冲突需要复现,若修复另补 delta 后再编码,不趁本提案无规格扩张。
71+
72+
## Migration / Rollback
73+
74+
按 cli-contract → cli-runtime → server-lifecycle、chat-streaming、configuration-model → contract-verification 的依赖分批实施;SSE 与配置可以独立测试。先验证 3.0.x,再按同一语义移植到 2.0.x、1.0.x。
75+
不直接合并整个已实现分支:先把既有改动逐条关联规范、检查旧错误测试(例如 --share org),补红绿测试后再按功能单元接纳。
76+
回滚使用明确的 revert 提交而非 reset/force-push;不删除调用方配置、不隐式重启外部服务。不得因回滚重新引入默认自动批准权限。
77+
78+
## Validation
79+
80+
测试分为纯 argv、真实 Java 子进程、MockWebServer/SSE、固定 OpenCode 二进制、跨 OS/JDK/Jackson 矩阵。无模型凭据的测试默认运行;需要模型或付费调用的测试显式开启,SKIPPED 必须独立报告。
81+
OpenSpec CLI 的严格校验与本地结构检查是不同证据;命令和状态记录在 review.md。验收场景及任务映射见 tasks.md。
82+
83+
## Open Questions / Blocking Gates
84+
85+
- 用户尚未批准本书面稿与任务计划:阻塞所有新业务代码实现。
86+
- 1.0.x 的 Java 8 声明/release 17 冲突:阻塞该分支移植与发布;需要另行批准基线决定并实测依赖字节码。
87+
- 候选 CLI flag 的固定版本接受性、OpenSpec CLI 严格校验和真实 OpenCode 运行未完成:阻塞对应完成声明。
88+
- 完整 ACP/PTY 已明确排除,不再作为本次“待实现但默认承诺”的隐含范围。
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# 源码基线、出处与修订说明
2+
3+
核对日期:2026-09-20。以下是本次读取时的快照,分支后续可能移动。
4+
5+
## 仓库锚点
6+
7+
仓库:https://github.com/easy-4-java/opencode-java-sdk
8+
9+
| 分支 | 固定提交 | 本轮用途 |
10+
|---|---|---|
11+
| feature/1.0.x | 05702c10fc2533c9dfb4f58be2b97f1247a4c9b3 | 兼容契约参照;JDK 基线冲突未解决 |
12+
| feature/2.0.x | 13f68b1b506dfb0aa274d388f7f5a028d340b67b | Java 17/Jackson 2 兼容线参照 |
13+
| feature/3.0.x | 99974efc311ba8c0aabad8c9471ed803d155e534 | 本次纯文档分支基线 |
14+
| fix/runtime-integration-hardening | 6c590c3a9af2a595d729cb6e50b1fd6d3458459e | 已有草稿与提前实现的来源,不纳入本次代码变更 |
15+
16+
比较最后两项:实现分支领先 34 个提交,净变更 29 个文件,其中 OpenSpec 文档 11 个、主代码 11 个、测试 7 个。这是文件/提交差异统计,不是已完成能力或测试通过数量。
17+
原始源码树:b778e00248132beda29e73138df454204b5e6209。
18+
原草稿 openspec 树:cd382f6f06f399e03a5b191a2f3f28913a68e774。
19+
20+
## 已有实现的核验范围
21+
22+
主代码:OpenCodeCliConfig、OpenCodeChatClient、OpenCodeSseClient、OpenCodeConfig、OpenCodeServerConfig、SseSubscription、OpenCodeCliExecutionContext、OpenCodeCliExecutor、OpenCodeCliResult、OpenCodeCliStreamHandle、OpenCodeRunOptions。
23+
测试:OpenCodeChatClientStreamingContractTest、OpenCodeSseReadinessContractTest、OpenCodeConfigContractTest、OpenCodeCliExecutorRuntimeContractTest、OpenCodeCliStreamingContractTest、OpenCodeCliTest、OpenCodeRunOptionsContractTest。
24+
这些文件只证明改动存在。本轮没有运行它们,也没有把它们带入文档分支。
25+
26+
## 原草稿问题及本稿处理
27+
28+
1. 只有 changes,没有对应主 specs;cli-contract、chat-streaming、configuration-model 却使用 MODIFIED。本稿保留同一个 change id,六项首次纳管契约统一声明 New/ADDED。
29+
2. contract-verification 的跨分支 Requirement 没有 Scenario。本稿为每条 Requirement 补齐可观察 WHEN/THEN 场景。
30+
3. config.yaml 原有 project/conventions 自定义键不能代替官方文档约定的 context/rules 注入。本稿改用 schema/context/rules;不声称已运行官方验证证明旧 YAML 被拒绝。
31+
4. 原任务缺少明确书面批准门禁,部分项没有自己的验证方法。本稿加入 review.md、逐项需求编号和验收证据,所有任务保持未勾选。
32+
5. 原稿部分决策仍是二选一。本稿明确首版 managed 要求固定端口、share 迁移规则、默认资源策略;这些设计仍待用户批准。
33+
34+
## 外部参考
35+
36+
- 用户参考 CLI:https://open-code.ai/en/docs/cli
37+
- 用户参考 Web:https://open-code.ai/en/docs/web
38+
- 上游 CLI:https://opencode.ai/docs/cli/
39+
- 上游 Web:https://opencode.ai/docs/web/
40+
- 目标版本 run 解析器:https://github.com/anomalyco/opencode/blob/v1.17.18/packages/opencode/src/cli/cmd/run.ts
41+
- 目标版本事件类型:https://github.com/anomalyco/opencode/blob/v1.17.18/packages/sdk/js/src/v2/gen/types.gen.ts
42+
- OpenSpec 工作流 schema:https://github.com/Fission-AI/OpenSpec/blob/main/schemas/spec-driven/schema.yaml
43+
- OpenSpec 配置说明:https://github.com/Fission-AI/OpenSpec/blob/main/docs/opsx.md
44+
- OpenSpec 规范约定:https://github.com/Fission-AI/OpenSpec/blob/main/openspec/specs/openspec-conventions/spec.md
45+
46+
网页与 main 文档会变化;实施时记录读取版本和二进制摘要。当前 v1.17.18 是候选固定契约基线,不是已运行认证结果。
47+
48+
## 证据边界
49+
50+
已做:GitHub 分支/树/文件/差异读取;形成纯文档评审稿。
51+
未做:本机 CodeGraph、Java 构建、真实 OpenCode、OpenSpec 官方 CLI 严格校验、漏洞/泄漏动态验证。
52+
环境探测:node/npm/git 可用,openspec 未安装;npm registry DNS 解析失败。不得用自写检查替代官方校验或行为测试。
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# OpenCode 运行时集成加固提案
2+
3+
## Why
4+
5+
已有 SDK 命令入口较多,但原始基线存在参数契约、流式事件处理、子进程管理和配置往返的缺口。此次先将这些行为写成可评审、可测试的 OpenSpec,再决定实现,避免以“已有方法或提交”替代完成证明。
6+
7+
## What Changes
8+
9+
- 精确建模 CLI 参数:布尔 `--share`、显式启用的 `--auto`、交互参数和版本受控的网络/全局选项;保留 raw argv。
10+
- 补有界输出、并发准入、每次调用独立环境、退出分类、取消与实时 CLI 输出。
11+
- 为 Web/Serve 建立启动、就绪、退出和关闭契约,分离启动超时与进程存活时间。
12+
- 为 ACP 提供双向 stdio 启动边界,不声称已经实现完整 ACP Java 协议客户端。
13+
- 修正 SSE 文本增量/快照、连接就绪、终态错误、取消、会话关联与资源释放。
14+
- 补 server 配置及未知 JSON 字段保留,同时保留通用配置提交入口。
15+
- 建立固定版本的上游契约、真实子进程及三兼容分支验证。
16+
- **BREAKING(行为纠错)**:旧 `share(String)` 只兼容 null/true/false;其他值明确拒绝,不再把任意字符串当作分享范围。新接口使用 boolean。
17+
- 有界缓冲和明确错误分类可能改变旧调用者观察到的截断、空白及失败结果,必须提供迁移说明,不删除原有方法签名。
18+
19+
## Capabilities
20+
21+
### New Capabilities
22+
23+
此处 New 表示首次进入 OpenSpec 主规范体系,不代表对应业务以前完全不存在。读取的草稿只有 change,没有 `openspec/specs` 主规范,因此六份 delta 都用 ADDED,不伪造 MODIFIED 基线。
24+
25+
- `cli-contract`:类型化参数、原始参数、危险开关与终端模式边界。
26+
- `cli-runtime`:并发、输出界限、调用环境、流式执行与错误分类。
27+
- `server-lifecycle`:Web/Serve 管理、认证、资源所有权及 ACP 启动边界。
28+
- `chat-streaming`:SSE 就绪、事件归约、失败、取消与同会话隔离。
29+
- `configuration-model`:强类型 server、未知字段和 PATCH 边界。
30+
- `contract-verification`:证据、评审门禁、固定上游版本及三线兼容验证。
31+
32+
### Modified Capabilities
33+
34+
无。后续已有主规范且需求改变时,才使用 MODIFIED 并完整保留既有场景。
35+
36+
## Scope and Non-Goals
37+
38+
本提案覆盖上面六个能力。完整 ACP 协议客户端、内嵌 PTY/终端尺寸控制、Web UI 重做、跨主机服务注册、多租户安全平台、无服务端支持的 SSE 精确一次重放均不在本次范围;这些内容需要独立 proposal。
39+
40+
## Impact
41+
42+
源码锚点:`feature/1.0.x@05702c10fc2533c9dfb4f58be2b97f1247a4c9b3``feature/2.0.x@13f68b1b506dfb0aa274d388f7f5a028d340b67b``feature/3.0.x@99974efc311ba8c0aabad8c9471ed803d155e534`
43+
本轮纯文档分支基于第三个提交;从已有实现分支复用草稿,但不带入其代码提交。
44+
建议以 OpenCode `v1.17.18` 为契约目标;真实二进制、摘要和测试证据尚未记录,不声称通过兼容验证。
45+
1.0.x 的 JDK 基线冲突是该分支实现与发布的阻塞条件,不能擅自用提高版本号代替解决。
46+
47+
## Approval Status
48+
49+
DRAFT / NOT_APPROVED。现有实现仅为待核验候选,不作为规范已经满足的证据。
50+
本轮只交付规范和计划;下一次实施前完成 `review.md` 门禁。事实及出处见 `evidence.md`,技术方案见 `design.md`

0 commit comments

Comments
 (0)