96 lines
2.9 KiB
TypeScript
96 lines
2.9 KiB
TypeScript
import type { HandoffProfiles, HandoffSessions } from '../../cc/handoffManifest'
|
|
import type { IssueColumn } from '../../gitea/types'
|
|
import { LOCAL_STATE_FIELDS } from '../../issues/localState'
|
|
|
|
export function canStartHandoff(issue: {
|
|
source?: 'gitea' | 'youtrack'
|
|
column: IssueColumn
|
|
handoffAttachmentId?: string
|
|
}): boolean {
|
|
return issue.source !== 'youtrack' && issue.column !== 'done' && !issue.handoffAttachmentId
|
|
}
|
|
|
|
export function canAcceptHandoff(issue: {
|
|
source?: 'gitea' | 'youtrack'
|
|
handoffAttachmentId?: string
|
|
assignees?: string[]
|
|
}, me: string | undefined): boolean {
|
|
return issue.source !== 'youtrack'
|
|
&& !!issue.handoffAttachmentId
|
|
&& me !== undefined
|
|
&& (issue.assignees ?? []).includes(me)
|
|
}
|
|
|
|
/** 移交前 worktree 必须「干净 + 全部 push」,否则接管方从远端重建会丢工作。 */
|
|
export function checkWorktreePushed(input: {
|
|
statusPorcelain: string
|
|
localHead: string
|
|
remoteHead: string
|
|
}): { ok: true } | { ok: false, reason: string } {
|
|
if (input.statusPorcelain.trim().length > 0)
|
|
return { ok: false, reason: '工作区有未提交改动,请先提交并 push' }
|
|
if (input.localHead.trim() !== input.remoteHead.trim())
|
|
return { ok: false, reason: '本地分支与远端不一致,请先 push' }
|
|
return { ok: true }
|
|
}
|
|
|
|
export function handoffStartedStateExtra(attachmentId: number, from: string): Record<string, unknown> {
|
|
const extra: Record<string, unknown> = { handoffAttachmentId: String(attachmentId), handoffFrom: from }
|
|
for (const f of LOCAL_STATE_FIELDS)
|
|
extra[f] = ''
|
|
return extra
|
|
}
|
|
|
|
export function handoffStartedUiPatch(attachmentId: number, from: string, to: string): Record<string, unknown> {
|
|
return {
|
|
handoffAttachmentId: String(attachmentId),
|
|
handoffFrom: from,
|
|
assignees: [to],
|
|
sessionId: null,
|
|
implementSessionId: null,
|
|
reviewSessionId: null,
|
|
testSessionId: null,
|
|
worktreePath: null,
|
|
worktreeExists: false,
|
|
}
|
|
}
|
|
|
|
function definedEntries(o: Record<string, any>): Record<string, string> {
|
|
const out: Record<string, string> = {}
|
|
for (const [k, v] of Object.entries(o)) {
|
|
if (v)
|
|
out[k] = v
|
|
}
|
|
return out
|
|
}
|
|
|
|
export function handoffAcceptedStateExtra(local: {
|
|
sessions: HandoffSessions
|
|
profiles: HandoffProfiles
|
|
worktreePath?: string
|
|
}): Record<string, unknown> {
|
|
return {
|
|
handoffAttachmentId: '',
|
|
handoffFrom: '',
|
|
...definedEntries(local.sessions),
|
|
...definedEntries(local.profiles),
|
|
...(local.worktreePath ? { worktreePath: local.worktreePath } : {}),
|
|
}
|
|
}
|
|
|
|
export function handoffAcceptedUiPatch(local: {
|
|
sessions: HandoffSessions
|
|
profiles: HandoffProfiles
|
|
worktreePath?: string
|
|
worktreeExists: boolean
|
|
}): Record<string, unknown> {
|
|
return {
|
|
handoffAttachmentId: null,
|
|
handoffFrom: null,
|
|
...definedEntries(local.sessions),
|
|
...definedEntries(local.profiles),
|
|
...(local.worktreePath ? { worktreePath: local.worktreePath } : {}),
|
|
worktreeExists: local.worktreeExists,
|
|
}
|
|
}
|