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

8.8 KiB
Raw Blame History

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 文件事件推送。

这些能力以后接入,但不能污染第一版的核心边界。

目录结构

.
├── 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

架构

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

type Workspace struct {
    ID   string `json:"id"`
    Root string `json:"root"`
}

含义:

  • ID 是外部 API 使用的 workspace 标识。
  • Root 是服务端本地绝对路径。
  • 第一版不引入数据库,workspace 是否存在由目录和 manager 判断。

FileInfo

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

type ProcessStatus struct {
    WorkspaceID string `json:"workspaceId"`
    Running     bool   `json:"running"`
    PID         int    `json:"pid,omitempty"`
}

Workspace Manager

职责:

  • 创建 workspace 目录。
  • 查询 workspace。
  • 删除 workspace 目录。
  • 生成 workspace root 路径。

接口:

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

所有文件操作必须走接口:

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 进程。

接口:

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

健康检查

GET /healthz

返回:

{"status":"ok"}

Workspace

POST /api/workspaces
GET /api/workspaces/{id}
DELETE /api/workspaces/{id}

创建请求:

{"id":"user1"}

Files

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

写文件请求:

{"path":"main.go","content":"package main\n"}

重命名请求:

{"oldPath":"old.go","newPath":"new.go"}

Process

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

server:
  addr: ":8080"
workspace:
  root: "./workspaces"
process:
  opencodeCommand: "opencode"

配置加载规则:

  1. 先加载默认值。
  2. 如果配置文件存在,覆盖默认值。
  3. 环境变量可覆盖:
    • CODESPACE_ADDR
    • CODESPACE_WORKSPACE_ROOT
    • CODESPACE_OPENCODE_COMMAND

错误处理

统一 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 创建。

验收命令:

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。