Skip to content

refactor(worker): SOLID/DIP — base/conn Claude Code protocol types leak into shared package #375

@hrygo

Description

@hrygo

Background

internal/worker/base/ 是所有 Worker 适配器的共享基础设施包。理想情况下,它应只包含通用的连接管理、生命周期和工具函数。然而 base/conn.go 包含了 Claude Code 专属的协议类型和消息格式构造逻辑,违反了依赖倒置原则 — 通用包不应了解特定适配器的协议细节。

Scope: solid, dry — cycle 51 (module analysis pass 2)
Key files: base/conn.go, claudecode/worker.go, opencodeserver/worker.go


Finding Summary

Category Critical High Medium Low
SOLID/DIP 0 0 1 0
合计 0 0 1 0

Findings

claude-code-protocol-leak-in-base-package

Severity: Medium | Confidence: High | ROI: Medium
Location: base/conn.go:28-41 (claudeUserMessage types), base/conn.go:78-112 (SendUserMessage)

Problem: base/conn.go 定义了 Claude Code 的 stream-json 输入格式类型(claudeUserMessage, claudeUserMsg, claudeTextContent)和 SendUserMessage 方法,该方法构造 Claude Code 专属的 JSON 格式并写入 stdin。这些类型和方法是 Claude Code 适配器的协议实现细节,不应存在于通用基础包中。

OCS 适配器使用完全不同的 conn 结构体(在 opencodeserver/worker.go 中定义),通过 HTTP POST 发送输入,不使用 SendUserMessage。新适配器也不会使用这些类型。

Current Pattern:

// base/conn.go:28-41 — Claude Code-specific types in shared package
type claudeUserMessage struct {
    Type    string        `json:"type"`
    Message claudeUserMsg `json:"message"`
}
type claudeUserMsg struct {
    Role    string              `json:"role"`
    Content []claudeTextContent `json:"content"`
}
type claudeTextContent struct {
    Type string `json:"type"`
    Text string `json:"text"`
}

// base/conn.go:78-112 — Claude Code stream-json format constructor
func (c *Conn) SendUserMessage(ctx context.Context, content string) error {
    // ... constructs claudeUserMessage, marshals to JSON, writes to stdin
}

// claudecode/worker.go:357 — the only caller, via type assertion
if baseConn, ok := conn.(*base.Conn); ok {
    if err := baseConn.SendUserMessage(ctx, content); err != nil { ... }
}

Proposed Fix: 将协议类型和 SendUserMessage 逻辑移至 claudecode 包,base.Conn 保持纯通用:

// claudecode/input.go — protocol types move here
type streamUserMessage struct { ... }

func writeStreamInput(stdin *os.File, mu *sync.Mutex, content string) error {
    // Construct Claude Code stream-json format and write to stdin
}

// claudecode/worker.go:Input — direct call instead of base.Conn method
func (w *Worker) Input(ctx context.Context, content string, metadata map[string]any) error {
    // ...
    if baseConn, ok := conn.(*base.Conn); ok {
        if err := writeStreamInput(baseConn.Stdin(), baseConn.WriteMu(), content); err != nil { ... }
    }
}

// base/conn.go — remains generic: Send (AEP envelope), Recv, Close, TrySend, CloseInput

Estimated Impact: base 包减少 ~35 行适配器专属代码,层次更清晰

Acceptance Criteria:

  • claudeUserMessage, claudeUserMsg, claudeTextContent 移至 claudecode
  • SendUserMessage 逻辑移至 claudecode 包(作为包级函数或 Worker 方法)
  • base.Conn 只保留通用方法:Send, Recv, Close, TrySend, CloseInput, WriteMu, LastInput, UserID, SessionID
  • OCS 适配器不受影响
  • make test 零回归

Implementation Priority

Finding Priority Effort Risk Impact
claude-code-protocol-leak-in-base-package P3 Small Low 层次清晰,base 包真正通用

Out of Scope

  • readOutput god method (207 lines) — already tracked in issue 244
  • OCS Terminate/Kill duplication — already fixed in PR 349
  • Capabilities boilerplate across adapters — Low ROI (only 2 adapters, trivial methods)
  • WriteMu() exposing internal mutex — pragmatic design, acceptable

Verification

  • make test passes, no regression
  • make lint produces no new warnings
  • go test -race ./internal/worker/... passes

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Medium: tech debt, refactoring, improvementsarchitectureDomain: design patterns, coupling, separation of concernsarea/workerScope: Claude Code/OCS/Pi adapters, base workerrefactorRefactor: DRY, SOLID, code quality improvements

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions