✨ feat(vscode): 申请移交时给负责人发系统通知

This commit is contained in:
cruldra committed 2026-10-04 10:01:41 +08:00
1 parent 5bcbb87152
commit a1fac829f8
3 files changed
+108 -1

No files matched your search

+63
View File
@@ -28,6 +28,7 @@ import { hasReviewMarker, parseClosingIssueNumber, stripReviewMarker } from '../
import { hasStateColumn, mergeStateJsonComment, mergeStateJsonCommentGuarded, readStateJsonComment } from '../gitea/stateJson'
import { getLocalIssueState, mergeLocalIssueState, overlayLocalIssueState } from '../issues/localState'
import { logger } from '../logging/logger'
import { handoffRequestSystemNotice } from '../panel/handlers/handoffRequest'
import * as issueChat from '../panel/handlers/issueChat'
import { hasLiveIssueSessionTerminal } from '../panel/handlers/terminals'
import { DEFAULT_KANBAN_SCOPE, KANBAN_SCOPE_KEY } from '../panel/kanbanScope'
@@ -68,6 +69,16 @@ const BODY_MARKERS = [
/** 本次从 body 里扫出来的 marker 值,按 state JSON 字段名索引。 */
type MarkerPatch = { [K in typeof BODY_MARKERS[number]['field']]?: string }
function handoffRequestFromOf(body: string): string {
try {
const obj = JSON.parse(body) as { handoffRequestFrom?: unknown }
return typeof obj.handoffRequestFrom === 'string' ? obj.handoffRequestFrom.trim() : ''
}
catch {
return ''
}
}
function parseBodyMarkers(body: string): MarkerPatch {
const out: MarkerPatch = {}
for (const { type, field, ext } of BODY_MARKERS) {
@@ -100,6 +111,8 @@ class WebhookCoordinator {
private eventSubscription?: { dispose: () => void }
/** 同 issue 自动审查启动中不重入(opened 与 synchronize 常连发)。 */
private reviewInFlight = new Set<number>()
/** 已经为这条移交申请通知过负责人。申请取消后清掉。 */
private handoffRequestSeen = new Map<number, string>()
/** Called once from extension.ts activate(). Idempotent. */
init(ctx: ExtensionContext): void {
@@ -1436,6 +1449,55 @@ class WebhookCoordinator {
* first review and `injectIntoImplTerminal` appends the merge-to-main
* suffix.
*/
/** 申请移交时给负责人发系统通知。看板关着也发。 */
private async notifyHandoffRequest(event: IssueCommentWebhookEvent): Promise<void> {
const from = handoffRequestFromOf(event.commentBody)
if (!from) {
this.handoffRequestSeen.delete(event.issueNumber)
return
}
const seen = this.handoffRequestSeen.get(event.issueNumber) ?? ''
if (from === seen || !this.ctx)
return
const ws = workspace.workspaceFolders?.[0]?.uri.fsPath
if (!ws)
return
const remote = await detectRepo(ws)
if (!remote)
return
const token = await getToken(this.ctx, remote.host)
if (!token)
return
const me = await loginForToken(remote.host, token)
const payload = event.raw as { issue?: { assignees?: Array<{ login?: string } | null> | null } | null } | null
const assignees = (payload?.issue?.assignees ?? []).flatMap(a => (a?.login ? [a.login] : []))
if (!me || assignees.length === 0)
return
const notice = handoffRequestSystemNotice({
issueNumber: event.issueNumber,
me,
assignees,
from,
seenFrom: seen,
})
this.handoffRequestSeen.set(event.issueNumber, from)
if (!notice)
return
execFile('osascript', [
'-e',
`display notification ${JSON.stringify('打开看板同意或拒绝')} with title ${JSON.stringify(notice)}`,
], (err) => {
if (err) {
logger.add({
level: 'warn',
source: 'webhook',
message: `移交申请通知发送失败 #${event.issueNumber}`,
details: err.message,
})
}
})
}
private async handleIssueCommentCreated(event: IssueCommentWebhookEvent): Promise<void> {
if (event.action !== 'created') {
logger.add({
@@ -1519,6 +1581,7 @@ class WebhookCoordinator {
source: 'webhook',
message: `issue_comment 是 state 评论,刷新 #${event.issueNumber} 的卡片`,
})
await this.notifyHandoffRequest(event)
await this.refreshIssueCard({
issueNumber: event.issueNumber,
raw: event.raw,