🐛 fix(vscode): 移交终审修正:schema 墓碑、顶层兜底、前置复查、分支保护、清单校验

Claude-Session: https://claude.ai/code/session_011cEyL6k351U2BzX1Qmygph
This commit is contained in:
cruldra committed 2026-08-26 17:09:39 +08:00
1 parent aa98dfb4e1
commit 0acfd04b54
10 files changed
+299 -220

No files matched your search

+5 -2
View File
@@ -39,6 +39,9 @@ export function handoffAttachmentName(issueNumber: number): string {
const KINDS: ReadonlySet<string> = new Set<ClaudeSessionKind>(['brainstorm', 'implement', 'test'])
// Claude / Codex 会话 id 都是 UUID;顺手挡掉路径穿越(如 `../x`)之类的伪造条目。
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
function optString(v: unknown): string | undefined {
return typeof v === 'string' && v.length > 0 ? v : undefined
}
@@ -63,7 +66,7 @@ export function parseHandoffManifest(json: string, expectedIssue: number): Hando
const o = e as Record<string, unknown>
const id = optString(o.id)
const kind = optString(o.kind)
if (!id || !kind || !KINDS.has(kind))
if (!id || !kind || !KINDS.has(kind) || !UUID_RE.test(id))
throw new Error(`handoff.json claude 条目非法:${JSON.stringify(e)}`)
return { id, kind: kind as ClaudeSessionKind }
})
@@ -71,7 +74,7 @@ export function parseHandoffManifest(json: string, expectedIssue: number): Hando
const o = e as Record<string, unknown>
const id = optString(o.id)
const relPath = optString(o.relPath)
if (!id || !relPath || relPath.startsWith('/') || relPath.includes('..'))
if (!id || !relPath || relPath.startsWith('/') || relPath.includes('..') || !UUID_RE.test(id))
throw new Error(`handoff.json codex 条目非法:${JSON.stringify(e)}`)
return { id, relPath }
})