This repository has been archived on 2026-07-17. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
codespace/docs/superpowers/specs/2026-07-02-codespace-design.md
T
2026-07-02 15:07:54 +08:00

391 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# codespace 可运行后端骨架设计
日期:2026-07-02
## 目标
在当前目录 `/Users/taochen/llm/codespace` 生成一个 Go 后端项目骨架。第一版目标是可运行、可测试、边界清晰的 Workspace Service,而不是完整 Web IDE。
核心能力:
- 每个 workspace 对应本地文件系统中的一个目录。
- 文件读写统一通过 `FileSystem` 接口,第一版实现 `LocalFS`
- OpenCode 以本机进程方式启动,工作目录 `cwd` 指向 workspace root。
- HTTP handler 不直接操作文件系统或进程,必须经过 service 层。
- 预留 watcher、Git、LSP、AI Agent 的后续扩展点。
- 不依赖 Docker。
## 非目标
第一版不实现:
- 用户认证和权限系统。
- Docker / 容器隔离。
- Git 集成。
- LSP。
- AI Agent 编排。
- Web 前端。
- 完整 watcher / WebSocket 文件事件推送。
这些能力以后接入,但不能污染第一版的核心边界。
## 目录结构
```text
.
├── cmd/
│ └── server/
│ └── main.go
├── configs/
│ └── config.yaml
├── internal/
│ ├── api/
│ │ ├── router.go
│ │ ├── workspace_handler.go
│ │ ├── file_handler.go
│ │ └── process_handler.go
│ ├── workspace/
│ │ ├── manager.go
│ │ ├── workspace.go
│ │ └── path.go
│ ├── fs/
│ │ ├── filesystem.go
│ │ ├── localfs.go
│ │ └── fileinfo.go
│ ├── process/
│ │ ├── manager.go
│ │ ├── session.go
│ │ └── opencode.go
│ ├── watcher/
│ │ └── watcher.go
│ ├── service/
│ │ ├── workspace_service.go
│ │ ├── file_service.go
│ │ └── process_service.go
│ ├── model/
│ │ ├── workspace.go
│ │ ├── file.go
│ │ └── process.go
│ └── util/
│ ├── path.go
│ └── errors.go
├── pkg/
│ ├── config/
│ ├── logger/
│ └── response/
├── web/
├── docs/
├── Makefile
├── go.mod
└── README.md
```
## 架构
```text
HTTP request
internal/api handler
internal/service
workspace.Manager / fs.FileSystem / process.Manager
local workspace directory + opencode process
```
边界规则:
1. `api` 只负责 HTTP 编解码、路由参数、状态码。
2. `service` 负责业务编排和校验。
3. `workspace` 负责 workspace 元数据和 root 目录管理。
4. `fs` 负责 workspace 内文件操作。
5. `process` 负责进程生命周期。
6. `watcher` 第一版只保留接口/占位,不接入运行链路。
## 核心数据结构
### Workspace
```go
type Workspace struct {
ID string `json:"id"`
Root string `json:"root"`
}
```
含义:
- `ID` 是外部 API 使用的 workspace 标识。
- `Root` 是服务端本地绝对路径。
- 第一版不引入数据库,workspace 是否存在由目录和 manager 判断。
### FileInfo
```go
type FileInfo struct {
Name string `json:"name"`
Path string `json:"path"`
IsDir bool `json:"isDir"`
Size int64 `json:"size"`
ModTime time.Time `json:"modTime"`
}
```
`Path` 始终是 workspace 内相对路径,不向 API 暴露宿主机绝对路径。
### ProcessStatus
```go
type ProcessStatus struct {
WorkspaceID string `json:"workspaceId"`
Running bool `json:"running"`
PID int `json:"pid,omitempty"`
}
```
## Workspace Manager
职责:
- 创建 workspace 目录。
- 查询 workspace。
- 删除 workspace 目录。
- 生成 workspace root 路径。
接口:
```go
type Manager interface {
Create(id string) (*Workspace, error)
Get(id string) (*Workspace, error)
Delete(id string) error
}
```
路径策略:
- 配置项 `workspaceRoot` 默认使用 `./workspaces`
- workspace root 为 `<workspaceRoot>/<workspaceID>`
- workspace ID 第一版限制为安全路径片段,只允许字母、数字、`-``_``.`
## FileSystem
所有文件操作必须走接口:
```go
type FileSystem interface {
List(path string) ([]FileInfo, error)
Read(path string) ([]byte, error)
Write(path string, data []byte) error
Mkdir(path string) error
Remove(path string) error
Rename(oldPath, newPath string) error
Stat(path string) (*FileInfo, error)
}
```
第一版实现 `LocalFS`
- `LocalFS` 绑定一个 workspace root。
- 所有传入路径都是 workspace 内相对路径。
- 解析路径时必须阻止 `../` 逃逸。
- API 不返回宿主机绝对路径。
## Process Manager
职责:按 workspace 管理 OpenCode 进程。
接口:
```go
type Manager interface {
Start(workspaceID string, workspaceRoot string) error
Stop(workspaceID string) error
Restart(workspaceID string, workspaceRoot string) error
Status(workspaceID string) Status
}
```
第一版行为:
- 命令默认是 `opencode`,通过配置项 `opencodeCommand` 可改。
- `cmd.Dir = workspace.Root`
- `HOME` 默认设置为 workspace root,避免不同 workspace 共享 CLI 状态。
- 同一个 workspace 已有运行进程时,再次 start 返回已运行错误,不重复启动。
- stop 使用进程 kill;优雅退出可以后续补。
## Service 层
### WorkspaceService
- `CreateWorkspace(id string)`
- `GetWorkspace(id string)`
- `DeleteWorkspace(id string)`
删除 workspace 前,先停止对应进程,避免目录被运行进程占用。
### FileService
- `List(workspaceID, path string)`
- `Read(workspaceID, path string)`
- `Write(workspaceID, path string, data []byte)`
- `Mkdir(workspaceID, path string)`
- `Remove(workspaceID, path string)`
- `Rename(workspaceID, oldPath, newPath string)`
- `Stat(workspaceID, path string)`
每次通过 workspace manager 取 workspace,再构造绑定该 root 的 `LocalFS`
### ProcessService
- `Start(workspaceID string)`
- `Stop(workspaceID string)`
- `Restart(workspaceID string)`
- `Status(workspaceID string)`
ProcessService 不自己拼路径,只通过 workspace manager 取 root。
## HTTP API
基础路径:`/api`
### 健康检查
```text
GET /healthz
```
返回:
```json
{"status":"ok"}
```
### Workspace
```text
POST /api/workspaces
GET /api/workspaces/{id}
DELETE /api/workspaces/{id}
```
创建请求:
```json
{"id":"user1"}
```
### Files
```text
GET /api/workspaces/{id}/files?path=.
GET /api/workspaces/{id}/files/read?path=main.go
PUT /api/workspaces/{id}/files/write
POST /api/workspaces/{id}/files/mkdir
DELETE /api/workspaces/{id}/files?path=main.go
POST /api/workspaces/{id}/files/rename
```
写文件请求:
```json
{"path":"main.go","content":"package main\n"}
```
重命名请求:
```json
{"oldPath":"old.go","newPath":"new.go"}
```
### Process
```text
POST /api/workspaces/{id}/process/start
POST /api/workspaces/{id}/process/stop
POST /api/workspaces/{id}/process/restart
GET /api/workspaces/{id}/process/status
```
## 配置
`configs/config.yaml`
```yaml
server:
addr: ":8080"
workspace:
root: "./workspaces"
process:
opencodeCommand: "opencode"
```
配置加载规则:
1. 先加载默认值。
2. 如果配置文件存在,覆盖默认值。
3. 环境变量可覆盖:
- `CODESPACE_ADDR`
- `CODESPACE_WORKSPACE_ROOT`
- `CODESPACE_OPENCODE_COMMAND`
## 错误处理
统一 JSON 响应:
```json
{
"error": {
"code": "bad_request",
"message": "invalid workspace id"
}
}
```
常见映射:
- 参数错误:400
- workspace 不存在:404
- 文件不存在:404
- 进程已运行:409
- 内部错误:500
第一版只做简单错误类型,不引入复杂错误框架。
## 测试策略
最小测试:
- workspace ID 校验和路径生成。
- LocalFS 路径逃逸防护。
- LocalFS 基础读写/列表。
- Process manager 状态逻辑使用可配置命令测试,不依赖真实 OpenCode。
- HTTP handler 可做轻量测试,至少覆盖 health 和 workspace 创建。
验收命令:
```sh
go test ./...
go run ./cmd/server
```
## 兼容性与风险
- 当前目录是项目根目录,不再额外创建 `codespace/` 子目录。
- 初始化会创建标准 Go 项目文件;如果目标文件已存在,实施阶段必须先检查,避免覆盖用户已有内容。
- 不改变公共 API,因为这是初始版本。
- 最大安全风险是路径逃逸,必须在 `LocalFS` 和 workspace ID 校验中处理。
- 最大复杂度风险是过早引入 watcher/Git/LSP/Agent;第一版明确不实现。
## 骨架完成标准
完成后应满足:
- 当前目录包含完整 Go module。
- `go test ./...` 通过。
- `go run ./cmd/server` 能启动 HTTP 服务。
- 可以创建 workspace、读写 workspace 内文件、查询/启动/停止进程。
- Handler 不直接调用 `os.*``exec.*`
- 文件路径不能逃逸 workspace root。