♻️ refactor(vscode): 对齐 state schema 与 knownStateFields 漂移

This commit is contained in:
2026-07-16 01:55:35 +08:00
parent b45257a38d
commit a3e557f9ee
5 changed files with 63 additions and 20 deletions
+19 -16
View File
@@ -381,22 +381,25 @@ func mergeAndPostState(rc *runtimeContext, issueNumber int, patch map[string]any
// an object carrying at least one of these — mirrors the TypeScript loader so // an object carrying at least one of these — mirrors the TypeScript loader so
// the two stay in lockstep. // the two stay in lockstep.
var knownStateFields = map[string]struct{}{ var knownStateFields = map[string]struct{}{
"column": {}, "column": {},
"sessionId": {}, "sessionId": {},
"implementSessionId": {}, "implementSessionId": {},
"reviewSessionId": {}, "reviewSessionId": {},
"testSessionId": {}, "testSessionId": {},
"profilePath": {}, "profilePath": {},
"specFile": {}, "brainstormProfilePath": {},
"planFile": {}, "testProfilePath": {},
"prDiffFile": {}, "specFile": {},
"pr": {}, "planFile": {},
"prMerged": {}, "prDiffFile": {},
"branch": {}, "pr": {},
"worktreePath": {}, "prMerged": {},
"implementStatus": {}, "prMergedAt": {},
"color": {}, "branch": {},
"autoReview": {}, "worktreePath": {},
"implementStatus": {},
"color": {},
"autoReview": {},
} }
// parseStateComment returns the parsed map when body is a JSON object carrying // parseStateComment returns the parsed map when body is a JSON object carrying
+16 -1
View File
@@ -36,6 +36,16 @@
"description": "创建工单时使用的 Claude settings 配置文件绝对路径,resume 时作为 --settings 传入。", "description": "创建工单时使用的 Claude settings 配置文件绝对路径,resume 时作为 --settings 传入。",
"minLength": 1 "minLength": 1
}, },
"brainstormProfilePath": {
"type": "string",
"description": "头脑风暴/规划会话使用的 Claude settings 配置文件绝对路径;与实施 profilePath 独立,空则用默认。",
"minLength": 1
},
"testProfilePath": {
"type": "string",
"description": "测试会话使用的 Claude settings 配置文件绝对路径;与实施 profilePath 独立,空则用默认。",
"minLength": 1
},
"specFile": { "specFile": {
"type": "string", "type": "string",
"description": "本工单的 spec 文档路径,相对 workspace,必须形如 `dir/.../name.md`。", "description": "本工单的 spec 文档路径,相对 workspace,必须形如 `dir/.../name.md`。",
@@ -63,6 +73,11 @@
"type": "boolean", "type": "boolean",
"description": "关联 PR 是否已合并;优先以 PR API 实时结果为准,此字段是 fallback。" "description": "关联 PR 是否已合并;优先以 PR API 实时结果为准,此字段是 fallback。"
}, },
"prMergedAt": {
"type": "string",
"description": "关联 PR 合并时间(ISO 8601);webhook 在标记 prMerged 时写入。",
"minLength": 1
},
"branch": { "branch": {
"type": "string", "type": "string",
"description": "实施分支名,例如 `feature/<hash>`。", "description": "实施分支名,例如 `feature/<hash>`。",
@@ -70,7 +85,7 @@
}, },
"worktreePath": { "worktreePath": {
"type": "string", "type": "string",
"description": "实施 worktree 的 workspace 相对路径。", "description": "实施 worktree 路径:通常为绝对路径,也可为 `~/...` 或 workspace 相对路径;扩展端经 resolveWorktreePath 解析。",
"minLength": 1 "minLength": 1
}, },
"implementStatus": { "implementStatus": {
+11 -1
View File
@@ -70,14 +70,18 @@ func TestValidateAcceptsFullState(t *testing.T) {
"sessionId":"abc", "sessionId":"abc",
"implementSessionId":"impl-1", "implementSessionId":"impl-1",
"reviewSessionId":"rev-1", "reviewSessionId":"rev-1",
"testSessionId":"test-1",
"profilePath":"/home/x/.claude/settings.json", "profilePath":"/home/x/.claude/settings.json",
"brainstormProfilePath":"/home/x/.claude/profiles/brainstorm.json",
"testProfilePath":"/home/x/.claude/profiles/test.json",
"specFile":"docs/superpowers/specs/foo.md", "specFile":"docs/superpowers/specs/foo.md",
"planFile":"docs/superpowers/plans/foo.md", "planFile":"docs/superpowers/plans/foo.md",
"prDiffFile":"docs/pr-diff/pr-42-issue-7.md", "prDiffFile":"docs/pr-diff/pr-42-issue-7.md",
"pr":"42", "pr":"42",
"prMerged":true, "prMerged":true,
"prMergedAt":"2026-07-16T01:00:00Z",
"branch":"feature/abc", "branch":"feature/abc",
"worktreePath":".worktrees/foo", "worktreePath":"/home/x/Sources/worktree/proj/slug",
"implementStatus":"done", "implementStatus":"done",
"color":"terminal.ansiBlue", "color":"terminal.ansiBlue",
"autoReview":true "autoReview":true
@@ -86,3 +90,9 @@ func TestValidateAcceptsFullState(t *testing.T) {
t.Fatalf("完整合法 state 应当通过校验,得到: %v", err) t.Fatalf("完整合法 state 应当通过校验,得到: %v", err)
} }
} }
func TestValidateAcceptsBrainstormProfilePathOnly(t *testing.T) {
if err := Validate([]byte(`{"brainstormProfilePath":"/home/x/.claude/profiles/brainstorm.json"}`)); err != nil {
t.Fatalf("仅含 brainstormProfilePath 应当通过校验,得到: %v", err)
}
}
+16 -1
View File
@@ -36,6 +36,16 @@
"description": "创建工单时使用的 Claude settings 配置文件绝对路径,resume 时作为 --settings 传入。", "description": "创建工单时使用的 Claude settings 配置文件绝对路径,resume 时作为 --settings 传入。",
"minLength": 1 "minLength": 1
}, },
"brainstormProfilePath": {
"type": "string",
"description": "头脑风暴/规划会话使用的 Claude settings 配置文件绝对路径;与实施 profilePath 独立,空则用默认。",
"minLength": 1
},
"testProfilePath": {
"type": "string",
"description": "测试会话使用的 Claude settings 配置文件绝对路径;与实施 profilePath 独立,空则用默认。",
"minLength": 1
},
"specFile": { "specFile": {
"type": "string", "type": "string",
"description": "本工单的 spec 文档路径,相对 workspace,必须形如 `dir/.../name.md`。", "description": "本工单的 spec 文档路径,相对 workspace,必须形如 `dir/.../name.md`。",
@@ -63,6 +73,11 @@
"type": "boolean", "type": "boolean",
"description": "关联 PR 是否已合并;优先以 PR API 实时结果为准,此字段是 fallback。" "description": "关联 PR 是否已合并;优先以 PR API 实时结果为准,此字段是 fallback。"
}, },
"prMergedAt": {
"type": "string",
"description": "关联 PR 合并时间(ISO 8601);webhook 在标记 prMerged 时写入。",
"minLength": 1
},
"branch": { "branch": {
"type": "string", "type": "string",
"description": "实施分支名,例如 `feature/<hash>`。", "description": "实施分支名,例如 `feature/<hash>`。",
@@ -70,7 +85,7 @@
}, },
"worktreePath": { "worktreePath": {
"type": "string", "type": "string",
"description": "实施 worktree 的 workspace 相对路径。", "description": "实施 worktree 路径:通常为绝对路径,也可为 `~/...` 或 workspace 相对路径;扩展端经 resolveWorktreePath 解析。",
"minLength": 1 "minLength": 1
}, },
"implementStatus": { "implementStatus": {
+1 -1
View File
@@ -20,7 +20,7 @@ import { addComment, listComments } from './api'
export const STATE_MARKER = '<!--spx-state-->' export const STATE_MARKER = '<!--spx-state-->'
/** Same field set as the Gitea state blob — kept independent to avoid coupling. */ /** Same field set as the Gitea state blob — kept independent to avoid coupling. */
const KNOWN_STATE_FIELDS = ['column', 'sessionId', 'implementSessionId', 'reviewSessionId', 'testSessionId', 'profilePath', 'brainstormProfilePath', 'testProfilePath', 'specFile', 'planFile', 'prDiffFile', 'pr', 'prMerged', 'branch', 'worktreePath', 'implementStatus', 'color', 'autoReview'] as const const KNOWN_STATE_FIELDS = ['column', 'sessionId', 'implementSessionId', 'reviewSessionId', 'testSessionId', 'profilePath', 'brainstormProfilePath', 'testProfilePath', 'specFile', 'planFile', 'prDiffFile', 'pr', 'prMerged', 'prMergedAt', 'branch', 'worktreePath', 'implementStatus', 'color', 'autoReview'] as const
/** /**
* Parse a comment body into a state object, or null if it isn't a state * Parse a comment body into a state object, or null if it isn't a state