protocol

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Jul 8, 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 (
	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"
	// DesignRoundsDir 存放 designer/design-reviewer 循環(design-reviewing FAIL 打回
	// designing)每一輪的 task-brief.md/acceptance-criteria.md/design-review-report.md
	// 快照,避免這些固定檔名的 artifact 被下一輪覆寫、dashboard message 區看不到歷史。
	DesignRoundsDir    = "design-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"
	FixerReport        = "fixer-report.md"
	TestReport         = "test-report.md"
	VerifyFile         = "verify.json"
	BuildGateFile      = "build-gate.json"
	DocsGateFile       = "docs-gate.json"
	GuardFeedback      = "guard-feedback.json"
	EscalationFile     = "escalation.json"
	StopFile           = "stop"

	// 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 庫
	LearningsContextFile  = "learnings-context.md"    // .4x/learnings-context.md,active learnings 的 markdown snapshot
	RetroLearningsFile    = "retro-learnings.json"    // .4x/{feature-id}/retro-learnings.json,Acceptor 產出
	RoleLearningsFileName = "role-learnings.json"     // 舊版單一固定檔名,harvester 仍讀取以相容既有 run 目錄
	RoleLearningsGlob     = "*-learnings.json"        // rounds/round-{n}/{role}-learnings.json,各角色獨立檔名的 glob
	ConsolidateInputFile  = "consolidate-input.json"  // .4x/consolidate-input.json,供 consolidate runner 讀
	ConsolidateResultFile = "consolidate-result.json" // .4x/consolidate-result.json,consolidate runner 產出

	// RoundsSummaryFile 是舊輪次摘要,在 round ≥ 3 進入 accepting 前由 round-summarizer 產出。
	// Acceptor 讀此檔取代讀取所有輪次全文,節省 context。
	RoundsSummaryFile = "rounds-summary.md"

	// DeepReviewAnglesFile 是 deep review 角度選擇結果的 artifact,記錄本次選了哪些角度及原因。
	DeepReviewAnglesFile = "deep-review-angles.json"

	// ReviewPackage 是 orchestrator 在 coding/amending → reviewing 轉換時預算的 diff 彙整檔
	// (commits/file-stat/full-diff),供 reviewer/deep-reviewer 讀檔取代自跑 git diff/log。
	ReviewPackage = "review-package.md"

	// AcceptanceSummaryFile 是 orchestrator 在進 accepting 前彙整各報告產出的檔案,
	// 供 Acceptor 讀取取代重複讀取 review/test/deep-review report 全文。
	AcceptanceSummaryFile = "acceptance-summary.md"
)
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 AllAngles added in v0.3.0

func AllAngles() []int

AllAngles 回傳完整的 1..DeepReviewAngleCount angle 清單。

func AllEventTypes added in v0.3.6

func AllEventTypes() []string

AllEventTypes 回傳 production 實際發出的 event type 集合(enum SoT)。 以全庫 grep production 程式碼(Type: "..." composite literal 與 pipeOutput(...,type) helper)為準,不以現有 schema enum 為準;schema 曾列出的 phase-end/step/verify/scope-check/blocked/heartbeat/subtask-done 在 production 無任何 emitter,故不列入。

func AllNotifyLevels added in v0.3.6

func AllNotifyLevels() []string

AllNotifyLevels 回傳 Event.Notify 的合法值(enum SoT)。

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 DefaultAngleMapping added in v0.3.0

func DefaultAngleMapping() map[string][]int

DefaultAngleMapping 回傳預設的 diff 路徑到 deep review angle 的映射表。 key 為路徑前綴;以 "*" 開頭的 key 為後綴匹配(如 "*_test.go")。

func DefaultProfiles

func DefaultProfiles() map[string]ProfileConfig

DefaultProfiles 回傳內建 pipeline profile,作為 auto-select 與 fallback 用。

  • full:完整 8 phase,適合高風險功能(金流、結算、核心協議)
  • lite:designing → coding → testing,有設計有驗證但省略所有 review 層,token 約 full 的 40%
  • normal:coding → reviewing → testing → accepting,已知要做什麼時跳過設計階段
  • quick:coding → reviewing,最精簡的 code + review

刻意不在此預填各 phase 的 Model tier:PhaseSpec.Model 的消費路徑(ResolvePhaseModel, 見 override.go)已確認存在且正確運作——resolveRunnerAndModel 呼叫它,per-phase/per-feature 的 model 覆寫today就能生效。但把具體 tier 值(如 "opus")寫死進這裡會是影響所有未自訂 settings.json 專案的全域預設變更:測試過程中發現,Model tier 名稱與 deep-reviewing 的 DefaultDeepTier fallback(見 deep_review.go)共用同一份 runner tiers 設定,導致原本因缺少 "opus" tier 而略過 deep-review 的既有測試/部署,會在毫無預警下開始執行 deep-review、 進而影響 phase 數量與流程;且對 coding/testing/fixing/accepting 填 "sonnet" 也是 no-op (defaultTier 本就是 "sonnet")。故建議 per-role model 路由交由專案 settings.json 的 roles/profiles 區塊自行設定(本專案 .4x/settings.json 已這樣做:designer.model=opus、 reviewer.deep_model=opus),而非在 Go 內建預設值寫死,避免非預期的全域行為變更。

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 GroupSelectedAngles added in v0.3.0

func GroupSelectedAngles(parallelReviewers, anglesPerReviewer int, angles []int) [][]int

GroupSelectedAngles 把指定的 angle 清單切分給 parallelReviewers 個 sub-reviewer, 回傳每個 sub-reviewer 負責的 angle 編號清單。 parallelReviewers <= 1 或 angles 為空時回傳 nil(走 fallback 單 agent)。

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 ResolveAngleMapping added in v0.3.0

func ResolveAngleMapping(cfg Config) map[string][]int

ResolveAngleMapping 從 config 讀取 deep-reviewer 的 angle mapping; 未設定時回傳 DefaultAngleMapping。

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 ResolveMiniCoderModel added in v0.4.0

func ResolveMiniCoderModel(cfg Config, runnerName, fallbackModel string) (string, error)

ResolveMiniCoderModel 解析 deep-reviewing / reviewing 自癒循環中 mini-coder 使用的 model name。 mini-coder 是 coding 性質的子 role,預設沿用 coder 已解析出的 model(fallbackModel),確保未特別 設定時行為不變;若使用者在 roles.mini-coder.model 明確設定 tier,則以該設定優先,讓 mini-coder 可 獨立於 coder 做 per-role model 路由。fallbackModel 由 caller 以 coder 的 ResolvePhaseModel 結果傳入。

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 ACEvidence added in v0.3.0

type ACEvidence struct {
	ID         string   `json:"id"`
	Passed     bool     `json:"passed"`
	Evidence   []string `json:"evidence"`
	VerifyType string   `json:"verify_type,omitempty"` // Tester 寫入供記錄;Guard 從 TestStrategy.ACVerifyMap 判斷
}

ACEvidence 是單一 acceptance criterion 的驗證結果

type AngleMatch added in v0.3.0

type AngleMatch struct {
	File   string `json:"file"`
	Rule   string `json:"rule"`
	Angles []int  `json:"angles"`
}

AngleMatch 描述單一變更檔案匹配到的 mapping 規則與其貢獻的 angle 編號。

func SelectDeepReviewAngles added in v0.3.0

func SelectDeepReviewAngles(mapping map[string][]int, files []ChangedFile) ([]int, []AngleMatch)

SelectDeepReviewAngles 根據變更檔案路徑和 mapping 表選出應執行的 deep review angle。 每個檔案匹配最長前綴(或後綴規則),取該規則的 angle 清單; 所有檔案的 angle 取聯集並升冪排序。無任何檔案匹配時回傳全部 1..DeepReviewAngleCount。

type AngleSelection added in v0.3.0

type AngleSelection struct {
	SelectedAngles []int        `json:"selected_angles"`
	TotalAngles    int          `json:"total_angles"`
	ForceAll       bool         `json:"force_all"`
	Matches        []AngleMatch `json:"matches"`
}

AngleSelection 是 deep review 角度選擇結果,序列化為 deep-review-angles.json 供 resume 與稽核。

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 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"`
	// FeatureIDPrefix 設定 feature ID 的前綴字串(如 "F"、"ws-"),預設 "F"。
	FeatureIDPrefix string `json:"feature_id_prefix,omitempty"`
	// FeatureIDDigits 設定 feature ID 流水號的最小位數(零補齊),預設 3。
	FeatureIDDigits int `json:"feature_id_digits,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"`
	// IssueTracker 控制 `4x new`/`4x done` 是否串接 GitHub/GitLab issue 與 MR/PR。
	// 純 project-level 欄位,預設 false,關閉時所有既有行為零改動。
	IssueTracker IssueTrackerConfig `json:"issue_tracker,omitempty"`
	// Worktree 是 scaffold worktree 相關的設定(如 post-scaffold hook)。
	Worktree WorktreeConfig `json:"worktree,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"`
	// TokensUsed 記錄本次 runner invocation 使用的 token 數量(從 runner log 解析),
	// 0 表示該 runner 未回報或解析失敗。僅 run-end event 填寫。
	TokensUsed int     `json:"tokens_used,omitempty"`
	CostUSD    float64 `json:"cost_usd,omitempty"`
	DurationMs int64   `json:"duration_ms,omitempty"`
	// Index 標記同一 round 內平行執行的同 role 事件屬於第幾個子任務(1-based),
	// 目前僅 deep-reviewer 的平行 sub-reviewer 使用。多個平行事件共用同一個 Role
	// 字串時,消費端不能再用單一遞增計數器區分 phase-start/run-end 配對(多個
	// phase-start 會連續推高計數器,導致之後的 run-end 全部收斂到同一格互相覆蓋),
	// 必須靠這個明確的索引還原正確配對。0(zero value)表示不適用,沿用既有的
	// 循序重試(如 designer 被打回重做)計數器邏輯。
	Index int `json:"index,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"`
	// CandidateMaxIdleDays 為「從未使用的 candidate」老化為 stale 的天數門檻,僅 `4x learn prune` 消費。
	// 用 pointer 區分「未設定」(nil → 套預設 30)與「明確設值」;明確設為 0 表示停用老化,正數為閾值。
	CandidateMaxIdleDays *int `json:"candidate_max_idle_days,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 IssueTrackerConfig added in v0.3.10

type IssueTrackerConfig struct {
	// Enabled 為 true 時,`4x new` 建/連 issue,`4x done` 改成 push + 開 MR/PR 取代本地 squash-merge。
	Enabled bool `json:"enabled"`
}

IssueTrackerConfig 控制 issue-first MR flow 是否啟用。

type ManualCheck added in v0.3.3

type ManualCheck struct {
	ID          string   `yaml:"id" json:"id"`
	ACRef       string   `yaml:"ac_ref,omitempty" json:"ac_ref,omitempty"`
	Description string   `yaml:"description" json:"description"`
	Steps       []string `yaml:"steps" json:"steps"`
}

ManualCheck 是 Designer 在 test-strategy.yaml 定義的手動驗證步驟。 Tester 必須逐步執行 Steps 並記錄實際輸出,不能只讀 code 判定。

type ManualCheckResult added in v0.3.3

type ManualCheckResult struct {
	ID       string   `json:"id"`
	Passed   bool     `json:"passed"`
	Evidence []string `json:"evidence"`
}

ManualCheckResult 是 Tester 對單一 ManualCheck 的執行結果。

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"
	PhaseFixing          Phase = "fixing"
	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 AllPhases added in v0.3.6

func AllPhases() []Phase

AllPhases 回傳所有可持久化於 state.json 的 Phase 值(enum SoT)。 依 internal/state/machine.go 的 CanTransition 裁定:fixing 是合法 to-phase (deep-reviewing→fixing、fixing→{accepting,amending}),abandoned/done 為終態, blocked/needs-attention 為 universal target,皆可寫入 phase,故 15 個全含。

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) EnabledPhaseNames added in v0.4.0

func (pc ProfileConfig) EnabledPhaseNames() []string

EnabledPhaseNames 以 canonical pipeline 順序回傳本 profile 已啟用的 phase 名稱清單, 供 prompt 段落列出 profile 的 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) RoleArtifactView added in v0.4.0

func (pc ProfileConfig) RoleArtifactView(role Role) RoleArtifactView

RoleArtifactView 計算某角色在此 profile 下的產出物視圖(見 RoleArtifactView 型別說明)。 未列入契約表的角色回傳零值。

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"`
	// DocsCheck 是文件/多語系同步的驗證指令(如 make check-docs-sync、check-i18n)。
	// 由 coding/amending phase 的 docs-gate 於框架層自動執行,結果寫入 docs-gate.json,
	// 讓 coder 在 coder-report 中對這些驗證的聲明可被獨立核對(見 F136)。
	// 未設定時 docs-gate 完全跳過,非 4x 專案(無此類指令)不受影響。
	DocsCheck []string `json:"docs_check,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"
	RoleFixer          Role = "fixer"
	// 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"
	// RoleConsolidator 是 learnings consolidator role,在 harvest 後判斷語意重複的 learnings 並合併/移除。
	RoleConsolidator Role = "consolidator"
	// RoleRoundSummarizer 是 round summarizer role,在進入 accepting 前將舊輪次的 review/test report
	// 壓縮為 rounds-summary.md,供 Acceptor 取代讀取所有輪次全文。
	RoleRoundSummarizer Role = "round-summarizer"
)

func AllRoles added in v0.3.6

func AllRoles() []Role

AllRoles 回傳所有可出現在 state.json.role 的 Role 值(enum SoT)。 即 internal/state/machine.go 的 PhaseToRole() 會指派(非空)的 8 個 pipeline 角色。 排除 sub-role(mini-coder/re-verifier/synthesizer,全程維持 deep-reviewing,僅用於 event/log 辨識,不佔 state.role)與非 pipeline 角色(gate/consolidator/round-summarizer)。

func ConfigurableRoles added in v0.4.0

func ConfigurableRoles() []Role

ConfigurableRoles 回傳可在 settings.json roles 區塊設定 per-role model 的 Role 集合(白名單 SoT)。 即全部 pipeline 角色(AllRoles,含 fixer)再加上 deep-reviewing / reviewing 自癒循環的 mini-coder 子 role——mini-coder 可透過 roles.mini-coder.model 做獨立 model 路由,故納入白名單。 其餘子 role(re-verifier/synthesizer)與非 pipeline 角色(gate/consolidator/round-summarizer) 目前不支援 per-role model 設定,故不列入。

func PhaseRole added in v0.2.0

func PhaseRole(phase Phase) Role

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

type RoleArtifactView added in v0.4.0

type RoleArtifactView struct {
	// Required 是本 profile 下本角色必須產出的 artifact 檔名(排序去重)。
	Required []string
	// Forbidden 是本 profile 其他啟用角色的產出物,本角色不應寫入(排序去重)。
	Forbidden []string
	// AbsentUpstream 是本角色消費的上游 artifact 中,本 profile 不會產出者,缺席屬正常(排序去重)。
	AbsentUpstream []string
}

RoleArtifactView 是某角色在特定 profile 下的產出物視圖: Required 為本 profile 下必須產出的 artifact;Forbidden 為本 profile 其他啟用角色 的產出物(不含本角色共產者);AbsentUpstream 為本角色會消費、但本 profile 不會 產出(所有 producer 角色的 phase 都未啟用)的上游 artifact,其缺席屬正常。

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"`
	// AngleMapping 定義 diff 檔案路徑前綴到 deep review angle 編號的映射,僅對 deep-reviewer
	// role 有意義。key 為路徑前綴(如 "internal/state/");以 "*" 開頭的 key 為後綴匹配
	// (如 "*_test.go")。value 為該路徑應啟動的 angle 編號清單(1-based)。
	// 未設定時由 DefaultAngleMapping 提供預設映射。
	AngleMapping map[string][]int `json:"angle_mapping,omitempty"`
}

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

type RoleContract added in v0.4.0

type RoleContract struct {
	// Produces 是本角色負責產出的 artifact 檔名(canonical 排序)。
	Produces []string
	// Consumes 是本角色會讀取的上游 artifact 檔名(canonical 排序)。
	Consumes []string
}

RoleContract 描述一個 pipeline 角色的產出物契約:Produces 為該角色負責寫入的 artifact 檔名清單,Consumes 為該角色會讀取的上游 artifact 檔名清單。 檔名一律使用 workspace.go 定義的常量(如 TaskBrief / ReviewReport), 不使用字面字串,確保與實際 runtime 檔名同步。

func ArtifactContract added in v0.4.0

func ArtifactContract(role Role) (RoleContract, bool)

ArtifactContract 查表回傳某角色的產出物契約。未列入本表的角色 (mini-coder / synthesizer 等子角色)回傳 (RoleContract{}, false), 代表不注入 profile-aware 段落。回傳的 slice 為 canonical 排序後的副本。

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"`
	// GuardRetries 記錄全域 guard retry 次數(跨 round 累計),超過上限時停止重試。
	GuardRetries int `json:"guardRetries,omitempty"`
	// BaseCommit 記錄 feature 首次進入 coding phase 時的 HEAD commit sha,供 review-package.md
	// 計算 diff 使用。amending 階段沿用同一個 base,讓 review package 累積本 feature 的完整 diff。
	BaseCommit string `json:"baseCommit,omitempty"`
	// ManualPhase 標記本次 phase 是由 `4x transition` / `4x retry` 手動設定,供 RecoverState
	// 尊重人為介入:偵測到此旗標時直接照 state.json 的 phase 派對應 role,不進 SmartResumePhase
	// 依磁碟 artifacts 重推導,並在消費後清除(避免下一輪真 crash 時仍被當成人為介入)。
	// 正常 run loop 內部的 state.Transition 不設置此旗標,故 recovery 對真 crash 的行為維持不變。
	ManualPhase bool `json:"manualPhase,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 複驗中
)

func AllSubPhases added in v0.3.6

func AllSubPhases() []SubPhase

AllSubPhases 回傳全部 4 個 SubPhase 常量(enum SoT)。

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"`
	// ManualChecks 定義 Tester 必須實際執行(非讀 code)的驗證步驟。
	// Guard 會驗證 verify.json 含有對應的 manual_check_results。
	ManualChecks []ManualCheck `yaml:"manual_checks,omitempty" json:"manual_checks,omitempty"`
	// ACVerifyMap 標記每條 AC 的驗證類型(unit-test / integration / inspection / skip)。
	// Guard 依此決定 evidence 品質要求;未列出的 AC 預設 execution(從嚴)。
	ACVerifyMap map[string]string `yaml:"ac_verify_map,omitempty" json:"ac_verify_map,omitempty"`
	// E2ERepos 列出本 feature 的 e2e 測試產出所在的獨立 repo 名稱(如 kairos-e2e)。
	// testing phase 起(含 testing 之後回到的 amending),這些 repo 的變更不算 scope violation
	// (Tester 必要寫入放行);為空時行為與舊版完全一致。granularity 為 repo 層級,比照 Config.HubRepos。
	E2ERepos []string `yaml:"e2e_repos,omitempty" json:"e2e_repos,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"`
	ACResults          []ACEvidence         `json:"ac_results,omitempty"`
	ManualCheckResults []ManualCheckResult  `json:"manual_check_results,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) 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) 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) TotalCost added in v0.3.10

func (w *Workspace) TotalCost(featureID string) (float64, error)

TotalCost 加總 events.jsonl 中所有 run-end 事件的 cost_usd,作為該 feature 跨行程(含中斷重啟)的權威總花費,不依賴 per-role/iteration 比對。 events.jsonl 不存在時回傳 (0, nil)(新 feature 尚無歷史)。

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) 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 層被誤用於寫入。

type WorktreeConfig added in v0.4.0

type WorktreeConfig struct {
	// PostScaffold 宣告 scaffold 建立 worktree 後、在 worktree 根目錄依序執行的命令清單;
	// 單一命令失敗只 warn 不中止 scaffold。內容由使用端專案自理(4x 不內建專案特定邏輯)。
	PostScaffold []string `json:"post_scaffold,omitempty"`
}

WorktreeConfig 是 settings.json 內 worktree 區段的設定。

Jump to

Keyboard shortcuts

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