protocol

package
v0.2.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 23, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Index

Constants

View Source
const (
	NotifySuccess = "success" // run 正常結束(done / pending-review)
	NotifyError   = "error"   // 失敗或 guard 攔截
	NotifyWarning = "warning" // 中斷或 escalation
)

通知等級常量,供 server 端標注 Event.Notify 及前端判斷顯示樣式,避免散落字串。

View Source
const (
	BatchOutcomeCompleted   = "completed"   // 主迴圈自然跑完排程(含失敗達上限被跳過),非被停止/中斷/crash
	BatchOutcomeStopped     = "stopped"     // 使用者按 Stop / 衝突暫停等 graceful 提前結束
	BatchOutcomeInterrupted = "interrupted" // 收到 SIGTERM/SIGINT 中斷
	BatchOutcomeCrashed     = "crashed"     // 行程 panic
)

Batch run 的結束結果(BatchReport.Outcome)列舉值,描述「批次如何終止」而非「是否全數成功」。 即使 outcome=completed,仍可能有 feature 失敗被跳過(看 Failed/Remaining 計數判斷實際結果)。

View Source
const (
	DirName            = ".4x"
	UserConfigDir      = ".4x"
	UserConfigFile     = "settings.json"
	BacklogFile        = "feature_list.json"
	ConfigFile         = "settings.json"
	FeaturesDir        = "features"
	StateFile          = "state.json"
	EventsFile         = "events.jsonl"
	BaselineFile       = "baseline.json"
	RoundsDir          = "rounds"
	FinalReport        = "final-report.md"
	TaskBrief          = "task-brief.md"
	Criteria           = "acceptance-criteria.md"
	TestStratFile      = "test-strategy.yaml"
	DesignReviewReport = "design-review-report.md"
	ReviewReport       = "review-report.md"
	DeepReviewReport   = "deep-review-report.md"
	CoderReport        = "coder-report.md"
	TestReport         = "test-report.md"
	VerifyFile         = "verify.json"
	EscalationFile     = "escalation.json"
	StopFile           = "stop"
	BatchStopFile      = "batch-stop"
	BatchConflictFile  = "batch-conflict.json"
	BatchReportFile    = "batch-report.json"
	BatchPIDFile       = "batch-pid"

	// CandidatesFile 是 .4x/candidates.json,history miner(4x mine)掃描歷史失敗訊號後
	// 產出的 candidate pool(候選 feature + 候選 learnings),供後續 F097 閘門決定是否升級。
	RunDir         = "run"
	CandidatesFile = "candidates.json"

	// F097 evolve 價值閘門相關檔名(皆在 .4x/ 根,CandidatePool 格式)。
	GateInputFile          = "gate-input.json"          // PRE-veto 倖存者,供 gate role 讀
	GateVerdictsFile       = "gate-verdicts.json"       // gate role 產出的價值判斷
	AcceptedCandidatesFile = "accepted-candidates.json" // POST-veto 通過者,附 value_score/why_not_hack

	// F099 evolve driver 相關檔名(皆在 .4x/ 根,非 per-feature)。
	EvolveReportFile = "evolve-report.md"  // 每輪 evolve pipeline 的摘要報告(dashboard surface)
	EvolveStateFile  = "evolve-state.json" // anti-spin 防空轉跨呼叫持久化計數

	// retro learnings 相關檔名。
	LearningsFile         = "learnings.json"          // .4x/learnings.json,跨 feature 累積的 learnings 庫
	RetroLearningsFile    = "retro-learnings.json"    // .4x/{feature-id}/retro-learnings.json,Acceptor 產出
	SelectedLearningsFile = "selected-learnings.json" // .4x/{feature-id}/selected-learnings.json,Designer 選出
)
View Source
const DeepReviewAngleCount = 11

DeepReviewAngleCount 是 deep-reviewer 模板定義的 review angle 總數(angle 1..11)。 平行 deep review 依此把 angle 平均分配給各 sub-reviewer。

View Source
const DefaultDeepTier = "opus"

DefaultDeepTier 是 deep_model 未設定時的 fallback tier。 full profile 包含 deep-reviewing,即使未明確設定 deep_model, 只要 runner 能解析此 tier 就會自動啟用 deep review。

View Source
const DefaultFailPatternThreshold = 3

DefaultFailPatternThreshold 是 fail-pattern 掃描器把一群相似 issue 升級為 candidate 所需的「不同 feature 數」門檻預設值。由 4x mine 的 --min-occurrences flag 覆寫。

Variables

This section is empty.

Functions

func AtomicWriteFile added in v0.2.0

func AtomicWriteFile(dir, finalName, tmpPattern string, data []byte, perm os.FileMode) error

AtomicWriteFile 以「同目錄 temp file + os.Rename」原子寫入 finalName。

直接 os.WriteFile 會先 truncate 再寫,這段空窗期內 concurrent 的讀者可能讀到 截斷或半寫的內容而解析失敗。改用同目錄 temp file(tmpPattern 為 os.CreateTemp 的 pattern)寫完再 atomic rename 覆蓋,讓讀者永遠看到完整的舊檔或完整的新檔。

temp file 必須與目標同目錄以確保位於同一 filesystem,os.Rename 才保證 atomic。 payload 的結尾換行等差異由呼叫端在 data 內自行決定。

func BoolPtr

func BoolPtr(b bool) *bool

BoolPtr 建立 *bool 指標,用於 RunnerConfig 布林欄位的初始化

func BoolVal

func BoolVal(p *bool) bool

BoolVal 安全取 *bool 的值,nil 視為 false

func DefaultProfiles

func DefaultProfiles() map[string]ProfileConfig

DefaultProfiles 回傳內建三組 pipeline profile,作為 auto-select 與 fallback 用。 full 跑完整 7 phase;normal 省略 designing、design-reviewing 與 deep-reviewing;quick 只跑 coding 與 reviewing。

func EffectiveHubRepos

func EffectiveHubRepos(cfg Config) []string

EffectiveHubRepos 合併 Config.HubRepos 與 workspace config 中 Hub: true 的 repo。

func EffectiveManual added in v0.2.0

func EffectiveManual(runOverrides map[Phase]PhaseSpec, phase Phase, manualRunner string) (runnerManual, modelManual string)

EffectiveManual 計算某 phase 的「有效手動覆寫」:把本次 run 的 per-phase 臨時覆寫 (runOverrides,覆寫優先序最高層)疊在全域 manualRunner(--runner)之上。

  • runnerManual:該 phase 有覆寫且 Runner 非空時取覆寫值,否則沿用 manualRunner。
  • modelManual:該 phase 有覆寫且 Model 非空時取覆寫值,否則為空(沿用下層解析)。

計算結果作為 ResolvePhaseRunner / ResolvePhaseModel 的 manual 參數傳入, 不改動 F090 既有的解析語意——只是在最高層多疊一層臨時覆寫。

func GroupReviewAngles

func GroupReviewAngles(parallelReviewers, anglesPerReviewer, totalAngles int) [][]int

GroupReviewAngles 把 1..totalAngles 的 review angle 切分給 parallelReviewers 個 sub-reviewer, 回傳每個 sub-reviewer 負責的 angle 編號清單(1-based、連續、不重複、完整覆蓋)。

切分規則:anglesPerReviewer > 0 時以它為每組固定大小依序切(最後一組可能較少); anglesPerReviewer <= 0 時用 ceil(totalAngles/parallelReviewers) 平均分配。 parallelReviewers <= 1 或 totalAngles <= 0 時回傳 nil(由 caller 走 fallback 單 agent)。 實際產生的非空組數可能少於 parallelReviewers(angle 不夠分時)。

func HumanSize

func HumanSize(bytes int64) string

HumanSize 將位元組數轉為人類可讀格式(如 "3.9M"、"124K"、"512B")。

func Init

func Init(root string, cfg Config) error

Init 建立 .4x/ 目錄和初始 config

func IsSelectablePhase added in v0.2.0

func IsSelectablePhase(phase Phase) bool

IsSelectablePhase 回報某 phase 是否屬於 profile 可選的工作 phase 白名單。

func IsSimilarFeature

func IsSimilarFeature(a, b string) bool

IsSimilarFeature 判斷兩段文字是否相似:將文字正規化(小寫、去標點、切 token)後 計算 Jaccard token overlap,>= similarityThreshold(0.6)視為相似。

func IsSimilarFeatureThreshold added in v0.2.0

func IsSimilarFeatureThreshold(a, b string, threshold float64) bool

IsSimilarFeatureThreshold 同 IsSimilarFeature,但相似門檻可由呼叫端指定(如 F097 的 dedup_threshold)。 任一方無 token 或 union 為 0 時回 false。

func MergeHooks

func MergeHooks(global, featureHooks map[string][]feature.HookEntry) map[string][]feature.HookEntry

MergeHooks 合併全域和 feature 的 hooks,feature 同名 key 整組替換全域。 兩者皆為 nil 時回傳 nil;否則複製 global 所有 key,再由 featureHooks 的 key 整組覆蓋。

func NotificationsEnabled added in v0.1.10

func NotificationsEnabled(cfg Config) bool

NotificationsEnabled 回報合併後設定是否啟用 OS 通知。 Notifications 為 nil(使用者未設定)時預設啟用,回傳 true。

func ParseReportIssues added in v0.2.0

func ParseReportIssues(report string) (passed bool, issues []string)

ParseReportIssues 解析 review-report.md / deep-review-report.md,回傳 verdict 是否 PASS 及所有 issue 標題。issue 取行首 [CRITICAL] / ### [CRITICAL] / #### [CRITICAL](WARNING 同規則) 之後的文字;verdict 取 "## Verdict" 段第一個非空行是否以 PASS / CONDITIONAL PASS 開頭。 在 protocol 層獨立實作,不依賴 cmd/4x 的 parseReviewVerdict。

func PhaseToStatus

func PhaseToStatus(phase Phase) feature.Status

PhaseToStatus 將 state machine 的 Phase 映射為面向 dashboard 的 feature.Status

func ProcessAlive

func ProcessAlive(pid int) bool

ProcessAlive 檢查 PID 是否仍在執行中

func ResolveAnglesPerReviewer

func ResolveAnglesPerReviewer(cfg Config, role Role) int

ResolveAnglesPerReviewer 解析每個 sub-reviewer 負責的 review angle 數量。 讀取 cfg.Roles[role].AnglesPerReviewer(role 一般為 RoleDeepReviewer); 未設定或 <= 0 時回傳 0,由 GroupReviewAngles 改用 ceil(總 angle/N) 平均分配。

func ResolveDeepModel

func ResolveDeepModel(cfg Config, runnerName string, role Role) (string, error)

ResolveDeepModel 解析 role 的 deep_model tier,回傳 runner 認識的 model name。 若 role 未設 deep_model,回傳空字串與 nil error(表示不需要 deep model)。 caller(如 runDeepReviewPhase)可自行用 ResolveTierModel + DefaultDeepTier 做 fallback。

func ResolveFeatureRepoPaths

func ResolveFeatureRepoPaths(f feature.Feature, cfg Config, root string) map[string]string

ResolveFeatureRepoPaths 解析 feature 涉及的 repo name → absolute path。 feature.Repos 為空時:multi-repo 回傳所有 workspace repos,monorepo 回傳 {".": root}。

func ResolveMaxDiscoveredFeatures

func ResolveMaxDiscoveredFeatures(cfg Config) int

ResolveMaxDiscoveredFeatures 回傳自動建立 feature 的數量上限: cfg.MaxDiscoveredFeatures > 0 時用該值,否則套預設值(3)。

func ResolveMaxFixRounds

func ResolveMaxFixRounds(cfg Config, role Role) int

ResolveMaxFixRounds 解析 deep-reviewing phase 自癒循環的最大修正輪數。 讀取 cfg.Roles[role].MaxFixRounds(role 一般為 RoleDeepReviewer); 未設定或 <= 0 時回傳預設 defaultMaxFixRounds(2)。

func ResolveModel

func ResolveModel(cfg Config, runnerName string, role Role) (string, error)

ResolveModel 根據抽象 tier 解析出指定 runner 認識的 model name。 優先序:runners[name].tiers[tier] > model_tiers[tier][runner] > error。 若 tier 在兩處都找不到對應,回傳 error 而非 pass through tier name。

func ResolveParallelReviewers

func ResolveParallelReviewers(cfg Config, role Role) int

ResolveParallelReviewers 解析平行 deep review 要 spawn 的 sub-reviewer 數量。 讀取 cfg.Roles[role].ParallelReviewers(role 一般為 RoleDeepReviewer); 未設定或 <= 0 時回傳 1,代表 fallback 單 agent 模式(不分檔、不跑 synthesizer)。

func ResolvePhaseModel added in v0.2.0

func ResolvePhaseModel(cfg Config, f feature.Feature, pc ProfileConfig, phase Phase, role Role, runnerName, manual string) (string, error)

ResolvePhaseModel 依統一覆寫優先序解析某 phase 實際使用的 model name。

tier 優先序(高→低):

  • manual:4x run 手動帶入的 model tier,空字串代表未手動指定。
  • f.PhaseOverrides[phase].Model:feature YAML 對此 phase 的覆寫。
  • profile 對應 PhaseSpec.Model:profile 對此 phase 的覆寫。
  • 以上皆空 → fallback 回 ResolveModel(roles[role].Model → runner.Model → defaultTier)。

取得 tier 後一律用 runner 的 tiers / model_tiers 解析為實際 model name; 解析不到回 error(沿用 ResolveModel 的錯誤語意)。

func ResolvePhaseRunner added in v0.2.0

func ResolvePhaseRunner(cfg Config, f feature.Feature, pc ProfileConfig, phase Phase, manual string) (string, error)

ResolvePhaseRunner 依統一覆寫優先序解析某 phase 實際使用的 runner 名稱。

優先序(高→低):

  • manual:4x run 手動帶入(--runner flag),空字串代表未手動指定。
  • f.PhaseOverrides[phase].Runner:feature YAML 對此 phase 的覆寫。
  • profile 對應 PhaseSpec.Runner:profile 對此 phase 的覆寫。
  • cfg.Default:default_runner。

解析結果必須存在於 cfg.Runners,否則回 error。

func ResolveRepoPaths

func ResolveRepoPaths(cfg Config, root string) map[string]string

ResolveRepoPaths 從 workspace config 解析 repo name → absolute path。 monorepo 模式回傳 {"." : root}。

func ResolveTierModel added in v0.2.2

func ResolveTierModel(cfg Config, runnerName, tier string) (string, error)

ResolveTierModel 把抽象 tier 解析為指定 runner 認識的實際 model name。 優先序:runners[name].tiers[tier] > model_tiers[tier][runner] > error。 供 ResolveModel、ResolvePhaseModel 共用,也供 caller 對 DefaultDeepTier 做 fallback 解析。

func ScanFailPatterns added in v0.2.0

func ScanFailPatterns(ws *Workspace, features []feature.Feature, minOccurrences int) ([]Candidate, []CandidateLearning)

ScanFailPatterns 走訪每個 feature 每個 round 的 review-report.md 與 deep-review-report.md, 對 verdict 非 PASS 的報告蒐集其 issue 標題,用 IsSimilarFeature(Jaccard)跨 feature 聚類, 統計每群涵蓋的「不同 feature 數」(同一 feature 多輪只算一次)。涵蓋數 >= minOccurrences 的群 升級為一筆 candidate,並同時產出一筆 CategoryReview 的 CandidateLearning。 best-effort:讀檔失敗只 slog.Warn 後略過。 features 由呼叫端傳入,避免重複呼叫 ListFeatures。

func ScreenshotDir

func ScreenshotDir(cfg Config) string

ScreenshotDir 從 config 取得 tester 的截圖目錄,fallback 到 feature.DefaultScreenshotDir。

func SupportedRunnerMap

func SupportedRunnerMap() map[string]RunnerConfig

SupportedRunnerMap 回傳 name → RunnerConfig 的 map

func UserConfigPath

func UserConfigPath() (string, error)

UserConfigPath 回傳 ~/.4x/settings.json 的路徑

func ValidateConfig added in v0.1.11

func ValidateConfig(c Config) error

ValidateConfig 驗證 Config 結構的合法性,回傳所有錯誤的彙整。

func ValidateState added in v0.1.11

func ValidateState(s State) error

ValidateState 驗證 State 結構的關鍵欄位。

func WriteConfig

func WriteConfig(dotDir string, cfg Config) error

WriteConfig 寫入 .4x/settings.json

func WriteUserConfig

func WriteUserConfig(cfg UserConfig) error

WriteUserConfig 寫入 ~/.4x/settings.json

Types

type Baseline

type Baseline struct {
	CreatedAt time.Time      `json:"createdAt"`
	Repos     []BaselineRepo `json:"repos"`
}

Baseline 是 baseline.json 的結構

type BaselineRepo

type BaselineRepo struct {
	Name       string   `json:"name"`
	Path       string   `json:"path"`
	Branch     string   `json:"branch"`
	Head       string   `json:"head"`
	DirtyFiles []string `json:"dirtyFiles"`
}

BaselineRepo 是 baseline 中每個 repo 的快照

type BatchConflict

type BatchConflict struct {
	FeatureID    string    `json:"featureId"`
	FeatureName  string    `json:"featureName"`
	ConflictRepo string    `json:"conflictRepo"`
	Files        []string  `json:"files"`
	DetectedAt   time.Time `json:"detectedAt"`
}

BatchConflict 是 batch auto-merge 遇衝突暫停時寫入的信號(.4x/batch-conflict.json)。 dashboard 讀此檔得知是哪個 feature、哪個 repo、哪些檔案發生衝突,供使用者解完後 Continue Batch。

type BatchFeatureReport

type BatchFeatureReport struct {
	ID          string         `json:"id"`
	Name        string         `json:"name"`
	FinalStatus feature.Status `json:"finalStatus"`
	DurationMs  int64          `json:"durationMs"`
	Rounds      int            `json:"rounds"`
	StopReason  string         `json:"stopReason,omitempty"`
}

BatchFeatureReport 是 BatchReport 內單一 feature 的最終狀態快照。

type BatchReport

type BatchReport struct {
	StartedAt      time.Time            `json:"startedAt"`
	FinishedAt     time.Time            `json:"finishedAt"`
	DurationMs     int64                `json:"durationMs"`
	Outcome        string               `json:"outcome"`
	Total          int                  `json:"total"`
	Completed      int                  `json:"completed"`
	Failed         int                  `json:"failed"`
	Remaining      int                  `json:"remaining"`
	Runner         string               `json:"runner"`
	Features       []BatchFeatureReport `json:"features"`
	PanicMessage   string               `json:"panicMessage,omitempty"`   // 僅 crashed
	RunningFeature string               `json:"runningFeature,omitempty"` // interrupted/crashed 時正在跑的 feature id
}

BatchReport 是一次 batch run 結束後(正常 / stop / interrupt / crash)寫入 .4x/batch-report.json 的整體報告。dashboard 在 batch 沒在跑時讀此檔顯示「上次 batch 報告」摘要與每個 feature 的最終狀態。

type CachedWorkspace

type CachedWorkspace struct {
	*Workspace
	// contains filtered or unexported fields
}

CachedWorkspace 在 *Workspace 上加一層 mtime-based in-memory cache,供 long-running dashboard server 使用,減少每次 API 請求重複 parse 大量 YAML/JSON。

失效策略完全靠檔案 mtime 比對:每次讀取先用 os.Stat / os.ReadDir 取 metadata, 與 cache 記錄的 mtime 相同才回傳 cache,否則重新 parse。因此寫入端(SaveFeature / WriteState 等)無需主動通知 cache,下次讀取自動偵測變動。

為避免 stat→parse 之間檔案被改動造成「cache 記錄的 mtime 與資料版本不一致」 (存舊 mtime → 永久 miss;存新 mtime 配舊資料 → 回傳 stale),所有 override 方法採 stat→parse→stat:唯有 parse 前後兩次 mtime 一致才寫入 cache,不一致則 略過 cache(仍回傳這次讀到的正確資料),由下次讀取重試。

透過 Go embedding 滿足 WorkspaceReader 並沿用 *Workspace 的所有其他方法; 僅 ListFeatures / LoadFeature / ReadConfig 被 override 加上 cache。ReadState 刻意不 cache(頻繁變化、檔案小、parse 快)。

注意:Go embedding 無虛擬分派,*Workspace 內部方法呼叫的 w.ListFeatures() 等 仍走原版、不命中 cache,這是已知且可接受的限制(那些路徑非 server hot-path)。

func NewCachedWorkspace

func NewCachedWorkspace(ws *Workspace) *CachedWorkspace

NewCachedWorkspace 建立一個包裝 ws 的 CachedWorkspace,初始 cache 為空。

func (*CachedWorkspace) ListFeatures

func (c *CachedWorkspace) ListFeatures() ([]feature.Feature, error)

ListFeatures 列出所有 feature;features 目錄內容或任一 .yaml 的 mtime 改變時重新 parse。 回傳的是 cache 的 shallow copy:slice 結構與 value 欄位已隔離(增刪元素、改 Name 等 不影響 cache),但 Feature 的 reference 欄位(Repos / Subtasks / Rules / Depends / Hooks / Priority)仍與 cache 共用底層;呼叫端切勿就地修改這些欄位內容,否則會污染 cache 且不受 c.mu 保護。

func (*CachedWorkspace) LoadFeature

func (c *CachedWorkspace) LoadFeature(id string) (feature.Feature, error)

LoadFeature 讀取單一 feature;對應 YAML 的 mtime 未變時回傳 cache。

短 ID(如 "F078",無 slug 後綴)無法用 id+".yaml" 直接命中檔案,此時委派給 非 cache 版 Workspace.LoadFeature(內含 resolveFeatureFile 短 ID 解析),該路徑 每次重新 parse、不建 cache 條目,目標是「短 ID 至少能正確解析」。

回傳值一律經 Clone 深拷貝,與 cache 內存版本不共用任何 slice/map, 呼叫端就地修改不會污染 cache。

func (*CachedWorkspace) LoadMergedConfig

func (c *CachedWorkspace) LoadMergedConfig() (Config, error)

LoadMergedConfig 讀取 project config(走 cache 版 ReadConfig)並合併 user config。 必須 override 而非沿用 embedded *Workspace 版本——Go embedding 無虛擬分派, *Workspace.LoadMergedConfig 內部呼叫的是非 cache 的 w.ReadConfig,會 bypass cache。 語意與 *Workspace.LoadMergedConfig 一致:project config 失敗回 error 不做 user merge, user config 失敗印 slog.Warn 但不中斷。

func (*CachedWorkspace) ReadConfig

func (c *CachedWorkspace) ReadConfig() (Config, error)

ReadConfig 讀取 .4x/settings.json;settings.json 的 mtime 未變時回傳 cache 副本。

type Candidate added in v0.2.0

type Candidate struct {
	Title       string          `json:"title"`       // 候選 feature 標題
	Description string          `json:"description"` // 描述(含失敗細節)
	Source      CandidateSource `json:"source"`      // 來源分類
	Origin      string          `json:"origin"`      // 追溯字串(feature id / round / reason / pattern)
	// ValueScore 是 F097 gate role 給的價值分數(0–1),僅 gate 接受後(accepted-candidates.json)有值。
	ValueScore float64 `json:"value_score,omitempty"`
	// WhyNotHack 是 F097 gate role 強制要求的「為何此 candidate 真有價值、非為看起來有產出而生」論述,
	// 僅 gate 接受後(accepted-candidates.json)有值。
	WhyNotHack string `json:"why_not_hack,omitempty"`
}

Candidate 是一筆候選 feature,由 history miner 從歷史失敗訊號彙整而成。 只進候選池(candidates.json),是否升級為正式 feature 交由後續 F097 閘門決定。

func DedupeCandidates added in v0.2.0

func DedupeCandidates(cands []Candidate, existingFeatures []feature.Feature, existingCands []Candidate) []Candidate

DedupeCandidates 過濾候選:保留的 candidate 必須與每個 existingFeatures(Name+" "+Description)、 每個 existingCands(前一份 candidates.json 既有 candidate)、及本批次已保留 candidate 都不相似 (沿用 IsSimilarFeature Jaccard 去重)。比對對象是 candidate 的 Title+" "+Description。 回傳順序維持輸入順序(對齊 DedupeDiscovered 行為)。

func ScanEscalations added in v0.2.0

func ScanEscalations(ws *Workspace, features []feature.Feature) []Candidate

ScanEscalations 走訪所有 feature 的所有 round dir,讀取 escalation.json, 對 Needed==true 且 reason 在白名單內的條目產出一筆 candidate。 best-effort:讀檔失敗、JSON 壞掉、reason 不在白名單都只 slog.Warn 後略過, 不 panic、不中斷其他 feature 或其他掃描器。 features 由呼叫端傳入,避免重複呼叫 ListFeatures。

func ScanStuckFeatures added in v0.2.0

func ScanStuckFeatures(ws *Workspace, features []feature.Feature) []Candidate

ScanStuckFeatures 掃描卡在 needs-attention/abandoned/blocked 的 feature,抽出阻塞原因產出 candidate。 阻塞原因優先取 state.json 的 StopReason/StopMessage,皆空時回退讀最新 round 的 escalation.json Detail。 best-effort:state 讀不到或壞掉都只 slog.Warn 後略過。 features 由呼叫端傳入,避免重複呼叫 ListFeatures。

type CandidateLearning added in v0.2.0

type CandidateLearning struct {
	Category learning.Category `json:"category"`
	Content  string            `json:"content"`
	Source   CandidateSource   `json:"source"`
	Origin   string            `json:"origin"`
}

CandidateLearning 是一筆候選 learning,沿用 internal/learning 的 category 白名單。 與 Candidate 同樣只進候選池,promotion 進 learnings.json 屬後續 F097。

type CandidatePool added in v0.2.0

type CandidatePool struct {
	Version     int                 `json:"version"`     // 固定為 1
	GeneratedAt time.Time           `json:"generatedAt"` // 由 CLI 層 mine 命令設定,protocol 層不取系統時間
	Candidates  []Candidate         `json:"candidates"`
	Learnings   []CandidateLearning `json:"learnings"`
}

CandidatePool 對應 .4x/candidates.json,是 history miner 的輸出容器。

func LoadCandidates added in v0.2.0

func LoadCandidates(path string) (CandidatePool, error)

LoadCandidates 讀取 candidates.json;檔案不存在時回傳空 pool(Version=1),不視為錯誤 (對齊 learning.LoadStore 慣例)。JSON 解析失敗才回傳 error。

func (CandidatePool) Save added in v0.2.0

func (p CandidatePool) Save(path string) error

Save 把 candidate pool 以 indented JSON 寫入指定路徑。

type CandidateSource added in v0.2.0

type CandidateSource string

CandidateSource 標記一筆 candidate 的來源分類,供後續 F097 閘門追溯與分流。

const (
	// SourceEscalation 來自 round dir 的 escalation.json(spec-mismatch/criteria-wrong/blocker/scope-change)。
	SourceEscalation CandidateSource = "escalation"
	// SourceStuck 來自卡在 needs-attention/abandoned/blocked 的 feature。
	SourceStuck CandidateSource = "stuck"
	// SourceFailPattern 來自跨 feature 反覆出現的 reviewer/deep-reviewer FAIL issue。
	SourceFailPattern CandidateSource = "fail-pattern"
)

type ChangedFile added in v0.2.0

type ChangedFile struct {
	// Path 是變更檔案相對 scope root 的路徑。
	Path string
	// Lines 是變更行數:tracked 檔為 added+deleted,untracked 檔為檔案總行數。
	Lines int
}

ChangedFile 是檔案層變更的跨層共用型別(guard 與 gitops 共用,放 protocol 避免 import cycle)。

type CleanCandidate

type CleanCandidate struct {
	FeatureID string
	Size      int64
}

CleanCandidate 描述一個可清理的 feature workspace。

type Config

type Config struct {
	Project           ProjectConfig                  `json:"project"`
	Runners           map[string]RunnerConfig        `json:"runners"`
	Default           string                         `json:"default_runner"`
	Roles             map[string]RoleConfig          `json:"roles,omitempty"`
	Rules             []string                       `json:"rules,omitempty"`
	HubRepos          []string                       `json:"hub_repos,omitempty"`
	Isolation         string                         `json:"isolation,omitempty"`
	MaxConcurrentRuns int                            `json:"max_concurrent_runs,omitempty"`
	Commit            string                         `json:"commit,omitempty"`
	ModelTiers        map[string]map[string]string   `json:"model_tiers,omitempty"`
	Workspace         WorkspaceConfig                `json:"workspace,omitempty"`
	Hooks             map[string][]feature.HookEntry `json:"hooks,omitempty"`
	// Profiles 定義 pipeline profile(名稱 → 啟用的 phase 子集 + 每 phase 的 runner/model 覆寫),
	// 供依 feature priority 自動選擇或 --profile 手動覆蓋;為空時所有 feature 一律走 full(6 phase 全跑)。
	Profiles map[string]ProfileConfig `json:"profiles,omitempty"`
	// DefaultProfile 指定無 --profile flag 且未 resume 時要採用的 profile 名稱(如 full/normal/quick)。
	// 為空時 fallback 既有行為(無 profiles 區段→full;有→依 priority auto-select)。
	DefaultProfile string `json:"default_profile,omitempty"`
	// ParallelReviewTest 啟用後,reviewer 與 tester 在 reviewing phase 並行執行(共用 worktree)。
	ParallelReviewTest bool `json:"parallel_review_test,omitempty"`
	// HealthCheck 是全域(settings.json)的 testing phase 前環境檢查設定,
	// 未設為 nil(跳過);可被 per-feature test-strategy.yaml 整組覆蓋。
	HealthCheck *HealthCheck `json:"health_check,omitempty"`
	// TestProfiles 讓專案覆寫或擴充內建 test profile(key 為 profile 名稱)。
	// 與 Profiles(pipeline profile)語意不同,不可混用。
	TestProfiles map[string]TestProfileOverride `json:"test_profiles,omitempty"`
	// AutoDiscoverFeatures 啟用後,run loop 在 final deep review PASS 後會 parse
	// deep-review-report.md 的 [NEW-FEATURE] 標記並自動建立 feature。預設 false。
	AutoDiscoverFeatures bool `json:"auto_discover_features,omitempty"`
	// MaxDiscoveredFeatures 限制單次 run 最多自動建立幾張 feature;未設定或 <= 0 時套預設值(3)。
	MaxDiscoveredFeatures int `json:"max_discovered_features,omitempty"`
	// EnrichDiscoveredFeatures 啟用後,auto-discover 產出的 candidate 會經 LLM enrichment
	// 補齊 subtasks/repos/rules/priority 後才存入 backlog;關閉時走舊路徑直接存薄 feature。預設 false。
	EnrichDiscoveredFeatures bool `json:"enrich_discovered_features,omitempty"`
	// EnrichAutoApprove 控制 enrich 後的 feature 狀態:true → not-started(全自動),
	// false → draft(需人工 approve)。僅在 EnrichDiscoveredFeatures 開啟時有意義。預設 false。
	EnrichAutoApprove bool `json:"enrich_auto_approve,omitempty"`
	// DesignDocDirs 指定設計文件(spec/plan)的額外搜尋目錄,優先於預設 docs/design/。
	// 例如 ["docs/feature"] 會讓 ResolveDesignDoc 先找 docs/feature/{id}-spec.md。
	DesignDocDirs []string `json:"design_doc_dirs,omitempty"`
	// Notifications 控制 run 結束時是否推送 OS 原生通知;用 pointer 區分「未設定」與「明確 false」,
	// nil(未設定)時 NotificationsEnabled 視為啟用。project 端非 nil 會覆蓋 user 端設定。
	Notifications *bool `json:"notifications,omitempty"`
	// SelfMod 設定 meta-loop 跑自己時對「改自己核心地基」變更的額外保護(受保護路徑、單輪 diff 上限、
	// 是否要求對應測試);nil 時 guard 套用內建預設(見 guard.ResolveSelfMod)。project 端非 nil 會覆蓋 user 端。
	SelfMod *SelfModSettings `json:"self_mod_guard,omitempty"`
	// Evolution 設定 F097 evolve pipeline 的價值閘門與收斂上限;nil 時由 evolution.ResolveEvolution 套全部預設值。
	Evolution *EvolutionConfig `json:"evolution,omitempty"`
}

Config 是 .4x/settings.json 的專案設定

func MergeConfig

func MergeConfig(user UserConfig, project Config) Config

MergeConfig 合併 user-level 和 project-level 設定。 project 非零值欄位覆蓋 user;project-only 欄位(Project、Isolation 等)直接使用 project 的值。

func ReadConfig

func ReadConfig(dotDir string) (Config, error)

ReadConfig 讀取 .4x/settings.json

type DesignDoc

type DesignDoc struct {
	// Content 是檔案內容,找不到時為空字串。
	Content string
	// Source 是相對於 root 的來源路徑(YAML 欄位命中時為原始 YAML 路徑字串),空表示找不到。
	Source string
}

DesignDoc 是設計文件(spec/plan)的解析結果。 找不到對應文件時,Content 與 Source 皆為空字串。

func ResolveDesignDoc

func ResolveDesignDoc(root string, feature feature.Feature, docType string, extraDirs ...string) DesignDoc

ResolveDesignDoc 依優先序解析 feature 的設計文件,docType 為 "spec" 或 "plan"。 此函式統一 server 與 prompt 兩處原本各自不一致的解析邏輯,新增來源時只需改這裡。

extraDirs 為額外搜尋目錄(相對於 root),優先於預設 docs/design/。

解析優先序:

  1. Feature YAML 的 Spec/Plan 欄位(依 docType 選取)。
  2. extraDirs 中各目錄下的 {feature.ID}-{docType}.md 與 {slug}-{docType}.md。
  3. docs/design/{feature.ID}-{docType}.md。
  4. docs/design/{slug}-{docType}.md。
  5. 都找不到 → 回傳零值 DesignDoc{}。

type DiscoveredFeature

type DiscoveredFeature struct {
	Title       string
	Description string
}

DiscoveredFeature 代表從 deep-review-report.md 解析出的一筆候選 feature。

func DedupeDiscovered

func DedupeDiscovered(candidates []DiscoveredFeature, existing []feature.Feature) []DiscoveredFeature

DedupeDiscovered 過濾候選 feature:保留的 candidate 必須與每個 existing feature (Name+" "+Description)都不相似,且與已保留的 candidate 也不相似(batch 內去重)。 比對對象是 candidate 的 Title+" "+Description。回傳順序維持輸入順序。

func ParseDiscoveredFeatures

func ParseDiscoveredFeatures(report string) []DiscoveredFeature

ParseDiscoveredFeatures 掃描 deep-review-report.md 文字,抽出所有 [NEW-FEATURE] block。 每個 block 的標題取 [NEW-FEATURE] 之後的文字(trim);描述為其後續行,直到遇到空行、 下一個 [NEW-FEATURE] 或下一個 "##" heading 為止。標題為空的 block 整個丟棄。 回傳順序與在 report 中出現的順序一致。

type Escalation

type Escalation struct {
	Needed bool   `json:"needed"`
	Reason string `json:"reason"`
	Detail string `json:"detail"`
}

Escalation 是 Coder/Tester 觸發 Designer 重新介入

type Event

type Event struct {
	Timestamp string `json:"ts"`
	Phase     Phase  `json:"phase"`
	Type      string `json:"type"`
	Role      Role   `json:"role,omitempty"`
	Round     int    `json:"round,omitempty"`
	Action    string `json:"action,omitempty"`
	Command   string `json:"cmd,omitempty"`
	Status    string `json:"status,omitempty"`
	Detail    string `json:"detail,omitempty"`
	Runner    string `json:"runner,omitempty"`
	Model     string `json:"model,omitempty"`
	// Notify 為前端統一判斷通知等級的提示,值域 NotifySuccess / NotifyError / NotifyWarning,
	// 空字串代表不通知。新增欄位向下相容(omitempty),不改既有 event 的 Status 語意。
	Notify string `json:"notify,omitempty"`
}

Event 是 events.jsonl 的一行

type EvolutionConfig added in v0.2.0

type EvolutionConfig struct {
	// ValueFloor 為 gate role 給的 value_score 最低門檻,低於此一律拒;0 時套預設 0.6。
	ValueFloor float64 `json:"value_floor,omitempty"`
	// MaxAcceptPerRun 限制單次 gate 最多接受幾筆 candidate(convergence cap);0 時套預設 3。
	MaxAcceptPerRun int `json:"max_accept_per_run,omitempty"`
	// MaxBacklogUndone 為 backlog 未做數上限,超過即停止接受新 candidate;0 時套預設 15。
	MaxBacklogUndone int `json:"max_backlog_undone,omitempty"`
	// GateRunner 指定 gate role 用哪個 runner;空字串不補預設(由下游決定)。
	GateRunner string `json:"gate_runner,omitempty"`
	// GateModel 指定 gate role 用哪個 model;空字串用 runner 預設。
	GateModel string `json:"gate_model,omitempty"`
	// DedupThreshold 為 candidate 去重的 Jaccard 門檻;0 時套預設 0.6。
	DedupThreshold float64 `json:"dedup_threshold,omitempty"`
	// MaxIdleRounds 控制 anti-spin 防空轉:連續這麼多輪未接受任何 candidate 即早退停跑。
	// 用 pointer 區分「未設定」(nil → evolution.ResolveEvolution 套預設 3)與「明確設值」;
	// 明確設為 <= 0 表示停用 halt(永遠跑),正數才啟用門檻。
	MaxIdleRounds *int `json:"max_idle_rounds,omitempty"`
}

EvolutionConfig 是 .4x/settings.json 內 evolution 區段的設定,描述 candidate feature 進 backlog 前的價值閘門門檻與收斂上限。各數值欄位為零值時由 evolution.ResolveEvolution 套預設。

type HealthCheck

type HealthCheck struct {
	Commands []string `yaml:"commands" json:"commands"`
	Recovery []string `yaml:"recovery,omitempty" json:"recovery,omitempty"`
	Timeout  int      `yaml:"timeout,omitempty" json:"timeout,omitempty"`
}

HealthCheck 是 testing phase 啟動前的環境檢查設定。 Commands 逐一執行任一失敗即停;失敗時若有 Recovery 則逐一執行後重跑一次 Commands。 Timeout 為每個 command 的逾時秒數,未設定(0)時由呼叫端套用預設 30 秒。

type Phase

type Phase string

Phase 表示 4x 狀態機的各階段

const (
	PhaseInit            Phase = "init"
	PhaseDesigning       Phase = "designing"
	PhaseDesignReviewing Phase = "design-reviewing"
	PhaseCoding          Phase = "coding"
	PhaseReviewing       Phase = "reviewing"
	PhaseDeepReviewing   Phase = "deep-reviewing"
	PhaseTesting         Phase = "testing"
	PhaseAmending        Phase = "amending"
	PhaseAccepting       Phase = "accepting"
	PhasePendingReview   Phase = "pending-review"
	PhaseDone            Phase = "done"
	PhaseAbandoned       Phase = "abandoned"
	PhaseBlocked         Phase = "blocked"
	PhaseNeedsAttention  Phase = "needs-attention"
)

func SelectablePhases added in v0.2.0

func SelectablePhases() []Phase

SelectablePhases 回傳 profile 可選 phase 的 canonical pipeline 順序清單, 供 UI 列舉與 doctor 驗證使用。

type PhaseSpec added in v0.2.0

type PhaseSpec struct {
	// Phase 必須屬於 profileSelectablePhases 白名單(designing/coding/reviewing/
	// deep-reviewing/testing/accepting)。
	Phase string `json:"phase"`
	// Runner 覆寫此 phase 使用的 runner,空字串代表繼承下層(default_runner)。
	Runner string `json:"runner,omitempty"`
	// Model 覆寫此 phase 的 model tier,空字串代表繼承下層(roles model)。
	Model string `json:"model,omitempty"`
}

PhaseSpec 描述一個 profile 內某個 phase 的設定:是否啟用該 phase,以及覆寫該 phase 的 runner 與 model tier。Runner / Model 為空時代表繼承下層(feature override → default_runner、 roles model → runner model → defaultTier)。

type ProfileConfig

type ProfileConfig struct {
	// Phases 是啟用的 phase 規格列表;順序不影響行為(執行順序由 canonical pipeline 決定)。
	Phases []PhaseSpec `json:"phases,omitempty"`
	// Roles Deprecated:舊格式啟用的 role 名稱列表,僅供向後相容解析(normalize 轉成 Phases)。
	Roles []string `json:"roles,omitempty"`
	// CoderModel Deprecated:舊格式 coder 的 model tier 覆寫,僅供向後相容解析(轉成 coding phase 的 Model)。
	CoderModel string `json:"coder_model,omitempty"`
}

ProfileConfig 描述一個 pipeline profile:啟用哪些 phase、以及每個 phase 的 runner/model 覆寫。 未列入 Phases 的 phase(對應的 role)在 run loop 中以 pass-through 方式沿合法 state 邊跳過、 不呼叫 runner。coding phase 為唯一必要 phase。

Roles / CoderModel 為已廢棄欄位,僅供向後相容解析:載入舊格式 settings.json 時由 normalize 自動轉成 Phases(見 profile.go),不再被任何解析路徑直接讀取。

func ResolveProfile

func ResolveProfile(cfg Config, f feature.Feature, override string) (string, ProfileConfig, error)

ResolveProfile 決定本次 run 使用的 profile 名稱與設定。

解析優先序:

  • override 非空(--profile / resume 沿用):先查 cfg.Profiles,再退 DefaultProfiles;都找不到回 error。
  • override 為空且 feature YAML profile 欄位非空:用 f.Profile(查 cfg.Profiles 再退 DefaultProfiles,找不到回 error),供 batch per-feature 套用不同 profile。
  • override 為空且 cfg.DefaultProfile 非空:用 cfg.DefaultProfile(查 cfg.Profiles 再退 DefaultProfiles,找不到印 warning 退 full)。
  • override 為空且 cfg.DefaultProfile 為空:維持既有 fallback——cfg.Profiles 為空回 full; 非空時依 feature.Priority auto-select(nil/0/1→full、2→normal、>=3→quick)。

解析出的 profile 若不含 coding phase 視為設定錯誤,回 error(coding 為唯一必要 phase)。

func (ProfileConfig) EnablesPhase added in v0.2.0

func (pc ProfileConfig) EnablesPhase(phase Phase) bool

EnablesPhase 判斷某 phase 是否啟用於 profile 的 Phases 列表中。

func (ProfileConfig) EnablesRole

func (pc ProfileConfig) EnablesRole(role Role) bool

EnablesRole 判斷某 role 是否啟用:把 role 映射到工作 phase,再檢查該 phase 是否在 Phases 中。 無對應 phase 的 role(如 deep-reviewing 內的子 role)一律回 false。

func (ProfileConfig) HasPhase added in v0.2.2

func (pc ProfileConfig) HasPhase(phase Phase) bool

HasPhase 回報此 profile 是否包含指定 phase。

func (*ProfileConfig) UnmarshalJSON added in v0.2.0

func (pc *ProfileConfig) UnmarshalJSON(data []byte) error

UnmarshalJSON 解析 ProfileConfig 並在載入後自動 normalize, 把舊格式 Roles[]string / CoderModel 轉成新的 Phases 結構,達成向後相容。

type ProjectConfig

type ProjectConfig struct {
	Name        string   `json:"name"`
	Description string   `json:"description,omitempty"`
	Language    string   `json:"language,omitempty"`
	Setup       []string `json:"setup,omitempty"`
	Build       []string `json:"build,omitempty"`
	Test        []string `json:"test,omitempty"`
	Lint        []string `json:"lint,omitempty"`
	Docs        []string `json:"docs,omitempty"`
	Rules       []string `json:"rules,omitempty"`
	Includes    []string `json:"includes,omitempty"`
}

ProjectConfig 是專案基本設定,包含既有工具鏈的描述

type RepoConfig

type RepoConfig struct {
	Path string `json:"path"`
	Hub  bool   `json:"hub,omitempty"`
}

RepoConfig 描述 workspace 中單一 repo 的設定。

type ResolvedPhase added in v0.2.0

type ResolvedPhase struct {
	// Phase 是 canonical pipeline 中的 phase 名稱(designing/coding/...)。
	Phase string `json:"phase"`
	// Role 是該 phase 對應的 role(designer/coder/...)。
	Role string `json:"role"`
	// Runner 是解析後實際使用的 runner 名稱。
	Runner string `json:"runner"`
	// Model 是解析後實際使用的 model name(非 tier,已透過 runner tiers 解析)。
	Model string `json:"model"`
}

ResolvedPhase 描述 pipeline 中某個啟用 phase 解析後的最終結果: 合併所有覆寫層級(per-phase 臨時覆寫 > --runner > feature YAML > profile > roles > default) 後,該 phase 實際會用哪個 role / runner / model。供 dashboard pipeline 預覽顯示, 也作為「preview 與實際 run loop 解析一致」的共用真相源。

func ResolvePipeline added in v0.2.0

func ResolvePipeline(cfg Config, f feature.Feature, profileName string, manualRunner string, runOverrides map[Phase]PhaseSpec) ([]ResolvedPhase, error)

ResolvePipeline 解析給定 profile + 臨時覆寫下的完整 pipeline,回傳依 canonical 順序、 僅含 profile 啟用 phase 的 []ResolvedPhase。dashboard preview 與實際 run loop 共用此解析 路徑(透過 EffectiveManual 與 ResolvePhaseRunner / ResolvePhaseModel),確保預覽結果與 實際執行採用的 runner/model 完全一致。

profileName 為空時走 ResolveProfile 既有 fallback(feature YAML / default_profile / priority auto-select)。任一 phase 的 runner/model 解析失敗即回 error。

type ReviewIssue

type ReviewIssue struct {
	Severity Severity `json:"severity"`
	Rule     string   `json:"rule"`
	File     string   `json:"file"`
	Detail   string   `json:"detail"`
}

ReviewIssue 是 reviewer 發現的問題

type ReviewResult

type ReviewResult struct {
	Passed        bool `json:"passed"`
	CriticalCount int  `json:"criticalCount"`
	WarningCount  int  `json:"warningCount"`
}

ReviewResult 是 review verdict 的結構化結果,包含通過與否及 critical/warning issue 計數

type Role

type Role string

Role 表示 4x pipeline 中的角色

const (
	RoleDesigner       Role = "designer"
	RoleDesignReviewer Role = "design-reviewer"
	RoleCoder          Role = "coder"
	RoleReviewer       Role = "reviewer"
	RoleDeepReviewer   Role = "deep-reviewer"
	RoleTester         Role = "tester"
	RoleAcceptor       Role = "acceptor"
	// RoleMiniCoder 與 RoleReVerifier 是 deep-reviewing phase 內自癒循環的子 role,
	// 不對應任何 state machine phase(全程維持 deep-reviewing),僅用於 prompt template
	// 與 event/log 辨識。
	RoleMiniCoder  Role = "mini-coder"
	RoleReVerifier Role = "re-verifier"
	// RoleSynthesizer 是平行 deep review 模式下合併多份 partial report 的子 role,
	// 同樣全程維持 deep-reviewing phase,僅用於 prompt template 與 event/log 辨識。
	RoleSynthesizer Role = "synthesizer"
	// RoleGate 是 F097 evolve 價值閘門 role,判斷 candidate feature 是否值得進 backlog 並強制寫
	// why_not_hack。不對應任何 state machine phase,由 evolve driver(F099)在 CLI veto 之間執行。
	RoleGate Role = "gate"
)

func PhaseRole added in v0.2.0

func PhaseRole(phase Phase) Role

PhaseRole 回傳工作 phase 對應的 role;非 profile 工作 phase 回空字串。

type RoleConfig

type RoleConfig struct {
	Model         string   `json:"model,omitempty"`
	DeepModel     string   `json:"deep_model,omitempty"`
	ScreenshotDir string   `json:"screenshot_dir,omitempty"`
	Instructions  []string `json:"instructions,omitempty"`
	Includes      []string `json:"includes,omitempty"`
	// MaxFixRounds 限制 deep-reviewing phase 內自癒循環(mini-coder + re-verifier)
	// 的最大迭代次數,僅對 deep-reviewer role 有意義;未設定時由 ResolveMaxFixRounds 套預設值。
	MaxFixRounds int `json:"max_fix_rounds,omitempty"`
	// ParallelReviewers 設定平行 deep review 要 spawn 幾個 sub-reviewer,僅對 deep-reviewer
	// role 有意義;未設定或 <=1 時走 fallback 單 agent 模式(不分檔、不跑 synthesizer)。
	ParallelReviewers int `json:"parallel_reviewers,omitempty"`
	// AnglesPerReviewer 設定每個 sub-reviewer 負責的 review angle 數量,僅對 deep-reviewer
	// role 有意義;未設定時由 ResolveAnglesPerReviewer 回 0,改用 ceil(總 angle/N) 平均分配。
	AnglesPerReviewer int `json:"angles_per_reviewer,omitempty"`
}

RoleConfig 是各角色的模型與行為設定

type RunnerConfig

type RunnerConfig struct {
	Command      string            `json:"command"`
	Args         []string          `json:"args"`
	Model        string            `json:"model,omitempty"`
	Tiers        map[string]string `json:"tiers,omitempty"`
	Stdin        *bool             `json:"stdin,omitempty"`
	Tty          *bool             `json:"tty,omitempty"`
	Quiet        *bool             `json:"quiet,omitempty"`
	OutputFormat string            `json:"output_format,omitempty"`
	// TransientRetries 設定暫態錯誤(socket closed、connection reset、rate limit、5xx 等)的
	// 自動重試上限:nil 表示用預設 3 次、0 表示停用重試、>0 為自訂上限。
	TransientRetries *int `json:"transient_retries,omitempty"`
}

RunnerConfig 是 LLM runner 的設定

type RunnerPreset

type RunnerPreset struct {
	Name   string       `json:"name"`
	Config RunnerConfig `json:"config"`
}

RunnerPreset 描述一個受支援 runner 的預設設定

func SupportedRunners

func SupportedRunners() []RunnerPreset

SupportedRunners 回傳所有受支援 runner 的預設設定,作為 init 和 dashboard 的單一真相源

type SelfModSettings added in v0.2.0

type SelfModSettings struct {
	// ProtectedPaths 是受保護路徑前綴白名單(相對 scope root),如 "internal/state/"。
	ProtectedPaths []string `json:"protected_paths,omitempty"`
	// MaxDiffLines 是受保護路徑單輪 diff 行數上限,超過即擋下轉 needs-attention;<= 0 視為未設定。
	MaxDiffLines int `json:"max_diff_lines,omitempty"`
	// RequireTests 控制改受保護路徑是否必須附帶對應測試才能進 accepting;
	// 用 pointer 區分「未設定」(預設 true)與「明確 false」。
	RequireTests *bool `json:"require_tests,omitempty"`
}

SelfModSettings 是 .4x/settings.json 內 self_mod_guard 區段的設定, 描述哪些路徑視為「核心地基」受保護、單輪 diff 行數上限、以及是否要求對應測試。 各欄位零值(含 nil)代表「未設定」,由 guard.ResolveSelfMod 退回內建預設。

type Severity

type Severity string

Severity 表示 review issue 的嚴重等級

const (
	SeverityCritical Severity = "critical"
	SeverityWarning  Severity = "warning"
	SeverityLow      Severity = "low"
)

type State

type State struct {
	FeatureID             string    `json:"featureId"`
	Phase                 Phase     `json:"phase"`
	Role                  Role      `json:"role"`
	SubPhase              SubPhase  `json:"subPhase,omitempty"`
	Round                 int       `json:"round"`
	MaxRounds             int       `json:"maxRounds"`
	Active                bool      `json:"active"`
	Pid                   int       `json:"pid,omitempty"`
	Runner                string    `json:"runner"`
	Label                 string    `json:"label,omitempty"`
	CreatedAt             time.Time `json:"createdAt"`
	UpdatedAt             time.Time `json:"updatedAt"`
	Since                 time.Time `json:"since,omitempty"`
	ConsecutiveNoProgress int       `json:"consecutiveNoProgress"`
	LastFailCount         int       `json:"lastFailCount"`
	StopReason            string    `json:"stopReason,omitempty"`
	StopMessage           string    `json:"stopMessage,omitempty"`
	Runners               []string  `json:"runners,omitempty"`
	// Profile 記錄本次 run 使用的 pipeline profile 名稱,供 dashboard 顯示與 resume 沿用。
	Profile string `json:"profile,omitempty"`
	// SelfModTouched 標記本 feature 最新一輪 coding/amending 是否觸及受保護路徑(self-mod guard)。
	// 由 guard.Check 在 coding 後偵測並持久化,供後續 test-gate 與 done/merge 的人工 approve 關卡讀取。
	SelfModTouched bool `json:"selfModTouched,omitempty"`
	// SelfModPaths 記錄最新一輪觸及的受保護檔案路徑(相對 scope root),test-gate 以此判斷是否附帶對應測試。
	SelfModPaths []string `json:"selfModPaths,omitempty"`
	// SelfModApproved 表示人工已透過 --approve-self-mod 核可此 feature 的受保護路徑變更,允許 merge。
	SelfModApproved bool `json:"selfModApproved,omitempty"`
}

State 是 .4x/{feature-id}/state.json 的權威狀態

type SubPhase added in v0.1.14

type SubPhase string

SubPhase 表示 deep-reviewing phase 內的子步驟,僅在 phase==deep-reviewing 時有意義; 其餘 phase 一律為空字串。用於 dashboard 顯示細部進度與 crash recovery 推斷重跑起點。

const (
	SubPhaseReviewing    SubPhase = "reviewing"    // sub-reviewer 平行審查中
	SubPhaseSynthesizing SubPhase = "synthesizing" // synthesizer 合併 partial 中
	SubPhaseFixing       SubPhase = "fixing"       // mini-coder 修正 issue 中
	SubPhaseReverifying  SubPhase = "reverifying"  // re-verifier 複驗中
)

type TestProfileOverride

type TestProfileOverride struct {
	Content string `json:"content,omitempty"`
	Include string `json:"include,omitempty"`
}

TestProfileOverride 允許專案在 settings.json 覆寫或新增 test profile。 Content 直接指定內容;Include 指定相對於 workspace root 的檔案路徑。兩者擇一,整組取代內建。

type TestStrategy

type TestStrategy struct {
	Web          bool                `yaml:"web" json:"web"`
	API          bool                `yaml:"api" json:"api"`
	Gate         bool                `yaml:"gate" json:"gate"`
	CoderOnly    bool                `yaml:"coder_only" json:"coder_only"`
	Verify       []string            `yaml:"verify_commands" json:"verify_commands"`
	HealthCheck  *HealthCheck        `yaml:"health_check,omitempty" json:"health_check,omitempty"`
	VerifyGroups map[string][]string `yaml:"verify_groups,omitempty" json:"verify_groups,omitempty"`
	// Profiles 標記本 feature 適用的測試 profile(如 unit/web/api/e2e),
	// Tester prompt 會依此自動注入對應的測試方法論;為空時行為與舊版一致。
	Profiles []string `yaml:"profiles,omitempty" json:"profiles,omitempty"`
}

TestStrategy 是 test-strategy.yaml 的結構

type UserConfig

type UserConfig struct {
	Locale        string                  `json:"locale,omitempty"`
	Theme         string                  `json:"theme,omitempty"`
	DefaultRunner string                  `json:"default_runner,omitempty"`
	Runners       map[string]RunnerConfig `json:"runners,omitempty"`
	Roles         map[string]RoleConfig   `json:"roles,omitempty"`
	// LogLevel 設定 structured logging 的最低輸出等級(debug/info/warn/error),
	// 為空時預設 "info";可被環境變數 FOURX_LOG_LEVEL 覆蓋。
	LogLevel string `json:"logLevel,omitempty"`
	// LogRetainDays 設定 ~/.4x/logs/ 下 log 檔的保留天數,
	// 超過此天數的 log 檔會在 Init() 時自動清除;為零時預設 7 天。
	LogRetainDays int `json:"logRetainDays,omitempty"`
	// Notifications 為使用者層級的 OS 通知開關;用 pointer 區分「未設定」與「明確 false」,
	// 會被 project 端非 nil 的設定覆蓋(見 MergeConfig)。
	Notifications *bool `json:"notifications,omitempty"`
	// SelfMod 為使用者層級的 self-mod guard 設定,project 端非 nil 時被覆蓋(見 MergeConfig)。
	SelfMod *SelfModSettings `json:"self_mod_guard,omitempty"`
}

UserConfig 是 ~/.4x/settings.json 的使用者層級設定

func ReadUserConfig

func ReadUserConfig() (UserConfig, error)

ReadUserConfig 讀取 ~/.4x/settings.json,不存在時回傳零值

type VerifyCommand

type VerifyCommand struct {
	Command          string    `json:"command"`
	ExitCode         int       `json:"exitCode"`
	ExpectedExitCode *int      `json:"expectedExitCode,omitempty"`
	DurationMs       int64     `json:"durationMs"`
	Summary          string    `json:"summary"`
	StartedAt        time.Time `json:"startedAt"`
	FinishedAt       time.Time `json:"finishedAt"`
	Group            string    `json:"group,omitempty"`
	Skipped          bool      `json:"skipped,omitempty"`
}

VerifyCommand 是單一 verify command 的結果

type VerifyEvidence

type VerifyEvidence struct {
	Passed      bool                 `json:"passed"`
	Round       int                  `json:"round"`
	Role        Role                 `json:"role"`
	Commands    []VerifyCommand      `json:"commands"`
	Screenshots []feature.Screenshot `json:"screenshots,omitempty"`
}

VerifyEvidence 是 rounds/round-N/verify.json 的結構

type Workspace

type Workspace struct {
	Root string
	// SkipAutoCommit 為 true 時,SyncFeatureStatus 只寫入檔案不自動 commit。
	// worktree 模式下主 repo 不應 commit feature YAML status,避免與 branch merge 衝突。
	SkipAutoCommit bool
}

Workspace 管理 .4x/ 目錄的讀寫

func Find

func Find(startDir string) (*Workspace, error)

Find 從目前目錄往上找 .4x/ 目錄

func (*Workspace) AppendEvent

func (w *Workspace) AppendEvent(featureID string, evt Event) error

AppendEvent 追加一行到 events.jsonl

func (*Workspace) CleanFeature

func (w *Workspace) CleanFeature(featureID string) (int64, error)

CleanFeature 刪除指定 feature 的 workspace 目錄,回傳釋放的位元組數。 僅允許 done 或 abandoned 且非 active 的 feature;非 terminal 或仍在執行中皆回 error。 feature 定義(.4x/features/{id}.yaml)不受影響。

func (*Workspace) CleanableFeatures

func (w *Workspace) CleanableFeatures() ([]CleanCandidate, error)

CleanableFeatures 列出所有可清理的 feature workspace。 僅納入 done 或 abandoned、有 workspace 目錄、且目前非 active 的 feature, 供 4x clean 與 POST /api/clean 在實際刪除前向使用者預覽清理對象與預估空間。

func (*Workspace) ClearBatchConflict

func (w *Workspace) ClearBatchConflict() error

ClearBatchConflict 刪除 .4x/batch-conflict.json;檔案不存在時不視為錯誤。

func (*Workspace) ClearBatchPID

func (w *Workspace) ClearBatchPID() error

ClearBatchPID 刪除 .4x/batch-pid;檔案不存在時不視為錯誤。

func (*Workspace) ClearStopSignal added in v0.1.17

func (w *Workspace) ClearStopSignal(featureID string) error

ClearStopSignal 刪除 feature 的 stop signal 檔;檔案不存在時不視為錯誤(比照 ClearBatchConflict)。

func (*Workspace) CompareBacklogMirror

func (w *Workspace) CompareBacklogMirror() ([]feature.BacklogDrift, error)

CompareBacklogMirror 比對 canonical feature YAML 與 legacy feature_list.json mirror。

func (*Workspace) DiscoverScreenshots

func (w *Workspace) DiscoverScreenshots(featureID, screenshotDir string) ([]feature.ScreenshotGroup, error)

DiscoverScreenshots 會合併 verify.json 與截圖目錄掃描結果,並按 round 分組回傳。

func (*Workspace) DotDir

func (w *Workspace) DotDir() string

DotDir 回傳 .4x/ 的完整路徑

func (*Workspace) FeatureDir

func (w *Workspace) FeatureDir(featureID string) string

FeatureDir 回傳 .4x/run/{featureId}/ 的路徑

func (*Workspace) InitFeatureDir

func (w *Workspace) InitFeatureDir(featureID string) error

InitFeatureDir 建立 feature 的運行時目錄

func (*Workspace) ListFeatures

func (w *Workspace) ListFeatures() ([]feature.Feature, error)

ListFeatures 列出所有 feature。 使用寬鬆驗證:格式有問題的 YAML 仍會載入並附帶 Warnings,只有完全無法解析的才跳過。

func (*Workspace) LoadFeature

func (w *Workspace) LoadFeature(id string) (feature.Feature, error)

LoadFeature 讀取 .4x/features/{id}.yaml

func (*Workspace) LoadMergedConfig

func (w *Workspace) LoadMergedConfig() (Config, error)

LoadMergedConfig 讀取 project config 並合併 user config,封裝散落各處的三行 boilerplate。 project config 讀取失敗時回傳 error 由呼叫端決定如何處理; user config 讀取失敗時印 slog.Warn 但不中斷(沿用既有各站點的處理慣例)。

func (*Workspace) ReadBacklogMirror

func (w *Workspace) ReadBacklogMirror() (feature.BacklogMirror, bool, error)

ReadBacklogMirror 讀取根目錄 feature_list.json;不存在時回傳 present=false。

func (*Workspace) ReadBatchConflict

func (w *Workspace) ReadBatchConflict() (*BatchConflict, error)

ReadBatchConflict 讀取 .4x/batch-conflict.json;檔案不存在時回 (nil, nil) 代表目前無衝突。

func (*Workspace) ReadBatchPID

func (w *Workspace) ReadBatchPID() (int, error)

ReadBatchPID 讀取 .4x/batch-pid 並解析為 PID;檔案不存在時回 (0, nil) 代表目前無 batch run 紀錄, 內容無法解析時回 (0, error)。

func (*Workspace) ReadBatchReport

func (w *Workspace) ReadBatchReport() (*BatchReport, error)

ReadBatchReport 讀取 .4x/batch-report.json;檔案不存在時回 (nil, nil) 代表尚無 batch 報告。

func (*Workspace) ReadConfig

func (w *Workspace) ReadConfig() (Config, error)

ReadConfig 讀取 .4x/settings.json

func (*Workspace) ReadState

func (w *Workspace) ReadState(featureID string) (State, error)

ReadState 讀取 feature 的 state.json

func (*Workspace) ReadTestStrategy

func (w *Workspace) ReadTestStrategy(featureID string) (TestStrategy, error)

ReadTestStrategy 讀取 .4x/{featureId}/test-strategy.yaml 並解析為 TestStrategy。 檔案不存在時回傳零值 TestStrategy 與 nil error,方便呼叫端把「沒設定」與「解析失敗」分開處理。

func (*Workspace) ReconcileActive

func (w *Workspace) ReconcileActive(featureID string, s *State) error

ReconcileActive 以 process 存在為權威來源校正 Active 欄位。 若 state 記錄 Active=true 但 PID 已不存在,自動將 Active 設為 false 並回寫。

func (*Workspace) RequestStop added in v0.1.17

func (w *Workspace) RequestStop(featureID string) error

RequestStop 在 feature dir 下原子寫入 stop signal 檔,請求 run loop 停止該 feature。

採 signal file(對齊既有 BatchStopFile 機制)而非直接改寫 state.json:state.json 的唯一 writer 收斂為 run loop,外部(如 MCP stop)只下「請求停止」信號,避免兩個 writer 競寫整份 state.json 而用過時快照覆蓋掉 loop 剛寫入的 phase/round 進度。

語意上 stop 為「請求」:若目標 feature 已無存活 loop,signal 不會被消費, 留待既有 ReconcileActive 在下次 ReadState 校正 Active。

func (*Workspace) ResolveFeatureID

func (w *Workspace) ResolveFeatureID(prefix string) (string, error)

ResolveFeatureID 用前綴比對找出唯一 feature ID(大小寫不敏感)

func (*Workspace) RoundDir

func (w *Workspace) RoundDir(featureID string, round int) string

RoundDir 回傳 .4x/{featureId}/rounds/round-{n}/ 的路徑

func (*Workspace) SaveFeature

func (w *Workspace) SaveFeature(f feature.Feature) error

SaveFeature 寫入 feature YAML,採用 write-to-temp + rename 確保原子性

func (*Workspace) StopRequested added in v0.1.17

func (w *Workspace) StopRequested(featureID string) bool

StopRequested 回傳 feature dir 下是否存在 stop signal 檔。

func (*Workspace) SyncFeatureStatus

func (w *Workspace) SyncFeatureStatus(featureID string, phase Phase) error

SyncFeatureStatus 將 feature YAML 的 Status 欄位同步為對應 phase 的狀態。 內部依序執行 LoadFeature → PhaseToStatus → SaveFeature,供 cmd/4x 與 internal/server 共用,避免 status 同步邏輯分散兩處。 若 feature YAML 被 git 追蹤,會自動 commit 狀態變更。

func (*Workspace) WorktreePath

func (w *Workspace) WorktreePath(featureID string) string

WorktreePath 從 events.jsonl 解析 feature 的 worktree 路徑。 若 feature 未使用 worktree 或 events.jsonl 不存在,回傳空字串。

掃描整個 events.jsonl 並回傳「最後一個」符合 `type==run-output` 且 detail 以 "worktree: " 開頭的路徑(最近一次 run 的 worktree)。re-run 多次後舊事件 會被新事件推到後段,只看前幾行會掃不到或回到已被移除的舊 worktree,故須掃全部行。

func (*Workspace) WriteBatchConflict

func (w *Workspace) WriteBatchConflict(c BatchConflict) error

WriteBatchConflict 將 batch auto-merge 衝突信號寫入 .4x/batch-conflict.json, 供 dashboard 顯示衝突細節並提供 Continue Batch 操作。

func (*Workspace) WriteBatchPID

func (w *Workspace) WriteBatchPID(pid int) error

WriteBatchPID 將 batch run 子程序的 PID 以十進位字串寫入 .4x/batch-pid, 供 server 重啟後辨識並 adopt 仍存活的孤兒子程序。

func (*Workspace) WriteBatchReport

func (w *Workspace) WriteBatchReport(r BatchReport) error

WriteBatchReport 原子寫入 .4x/batch-report.json(同目錄 temp file + os.Rename,仿 WriteState), 確保 dashboard 在 batch run 收尾/中斷的同時讀到的永遠是完整 JSON,不會撞上半寫狀態。

func (*Workspace) WriteState

func (w *Workspace) WriteState(featureID string, s State) error

WriteState 寫入 feature 的 state.json。

採用 write-to-temp + rename 而非直接 os.WriteFile:後者會先 truncate 再寫, 在這段時間內 concurrent 的 ReadState 可能讀到截斷或半寫的 JSON 而 Unmarshal 失敗。 改用同目錄 temp file 寫完再 atomic rename 覆蓋,讓讀者永遠看到完整的舊檔或完整的新檔。

type WorkspaceConfig

type WorkspaceConfig struct {
	Repos map[string]RepoConfig `json:"repos,omitempty"`
}

WorkspaceConfig 描述 multi-repo workspace 的 repo 映射。 沒有設定時代表 monorepo 模式。

type WorkspaceReader

type WorkspaceReader interface {
	// ListFeatures 列出所有 feature。
	ListFeatures() ([]feature.Feature, error)
	// LoadFeature 讀取單一 feature YAML。
	LoadFeature(id string) (feature.Feature, error)
	// ReadState 讀取 feature 的 state.json。
	ReadState(featureID string) (State, error)
	// ReadConfig 讀取 .4x/settings.json。
	ReadConfig() (Config, error)
}

WorkspaceReader 定義 Workspace 的唯讀操作集合,用於抽象出可被 cache 層包裝的讀取介面。 long-running server 透過此介面操作,便於以 CachedWorkspace 替換而不影響呼叫端; CLI 短命程序則直接用 *Workspace。寫入方法刻意不納入介面,避免 cache 層被誤用於寫入。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL