@xdevops/issue-auto-finish 1.0.96 → 1.0.97

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/{PtyRunner-UD3M7GNM.js → PtyRunner-XMWDMH3L.js} +2 -2
  2. package/dist/ai-runner/AIRunner.d.ts +0 -4
  3. package/dist/ai-runner/AIRunner.d.ts.map +1 -1
  4. package/dist/ai-runner/PlanFileResolver.d.ts +0 -1
  5. package/dist/ai-runner/PlanFileResolver.d.ts.map +1 -1
  6. package/dist/ai-runner/PtyRunner.d.ts.map +1 -1
  7. package/dist/{ai-runner-6OQYGU56.js → ai-runner-S2ATTGWX.js} +2 -2
  8. package/dist/{analyze-LZHS3MHW.js → analyze-DAVYPBHK.js} +2 -2
  9. package/dist/{braindump-7QDUYUZW.js → braindump-A4R3A4QT.js} +2 -2
  10. package/dist/{chunk-AFGUFM6H.js → chunk-2XACBKPB.js} +2 -2
  11. package/dist/{chunk-P6KYWBMT.js → chunk-BPVRMZU4.js} +9 -9
  12. package/dist/{chunk-SJSVO46Z.js → chunk-HD6V7KPE.js} +43 -102
  13. package/dist/chunk-HD6V7KPE.js.map +1 -0
  14. package/dist/{chunk-W553OKAJ.js → chunk-OPWP73PW.js} +31 -66
  15. package/dist/{chunk-W553OKAJ.js.map → chunk-OPWP73PW.js.map} +1 -1
  16. package/dist/{chunk-75ANI33A.js → chunk-SNSEW7DS.js} +1 -1
  17. package/dist/cli.js +5 -5
  18. package/dist/hooks/HookInjector.d.ts +0 -6
  19. package/dist/hooks/HookInjector.d.ts.map +1 -1
  20. package/dist/index.js +4 -4
  21. package/dist/{init-Q4DTX6JN.js → init-OD7CLRWK.js} +2 -2
  22. package/dist/lib.js +2 -2
  23. package/dist/orchestrator/steps/PhaseHelpers.d.ts +1 -1
  24. package/dist/orchestrator/steps/PhaseHelpers.d.ts.map +1 -1
  25. package/dist/orchestrator/steps/SetupStep.d.ts +0 -7
  26. package/dist/orchestrator/steps/SetupStep.d.ts.map +1 -1
  27. package/dist/{restart-CEFVMQLL.js → restart-JVVOYC6C.js} +2 -2
  28. package/dist/run.js +4 -4
  29. package/dist/{start-JYVFJZCL.js → start-INU24RRG.js} +2 -2
  30. package/package.json +1 -1
  31. package/dist/chunk-SJSVO46Z.js.map +0 -1
  32. /package/dist/{PtyRunner-UD3M7GNM.js.map → PtyRunner-XMWDMH3L.js.map} +0 -0
  33. /package/dist/{ai-runner-6OQYGU56.js.map → ai-runner-S2ATTGWX.js.map} +0 -0
  34. /package/dist/{analyze-LZHS3MHW.js.map → analyze-DAVYPBHK.js.map} +0 -0
  35. /package/dist/{braindump-7QDUYUZW.js.map → braindump-A4R3A4QT.js.map} +0 -0
  36. /package/dist/{chunk-AFGUFM6H.js.map → chunk-2XACBKPB.js.map} +0 -0
  37. /package/dist/{chunk-P6KYWBMT.js.map → chunk-BPVRMZU4.js.map} +0 -0
  38. /package/dist/{chunk-75ANI33A.js.map → chunk-SNSEW7DS.js.map} +0 -0
  39. /package/dist/{init-Q4DTX6JN.js.map → init-OD7CLRWK.js.map} +0 -0
  40. /package/dist/{restart-CEFVMQLL.js.map → restart-JVVOYC6C.js.map} +0 -0
  41. /package/dist/{start-JYVFJZCL.js.map → start-INU24RRG.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/clients/GongfengClient.ts","../src/utils/CircuitBreaker.ts","../src/utils/RetryPolicy.ts","../src/tracker/IssueState.ts","../src/lifecycle/ActionLifecycleManager.ts","../src/tracker/IssueTracker.ts","../src/persistence/PlanPersistence.ts","../src/phases/BasePhase.ts","../src/rules/RuleResolver.ts","../src/verify/VerifyReportParser.ts","../src/phases/VerifyPhase.ts","../src/phases/PlanPhase.ts","../src/phases/BuildPhase.ts","../src/release/ReleaseDetectCache.ts","../src/prompts/release-templates.ts","../src/phases/ReleasePhase.ts","../src/phases/UatPhase.ts","../src/phases/PhaseFactory.ts","../src/pipeline/PipelineDefinition.ts","../src/workspace/WorkspaceConfig.ts","../src/workspace/WorkspaceManager.ts","../src/orchestrator/PipelineOrchestrator.ts","../src/demand/adapters/GongfengAdapter.ts","../src/utils/MergeRequestHelper.ts","../src/deploy/PortAllocator.ts","../src/deploy/DevServerManager.ts","../src/e2e/E2eSettings.ts","../src/e2e/ScreenshotCollector.ts","../src/e2e/ScreenshotPublisher.ts","../src/metrics/MetricsCollector.ts","../src/orchestrator/steps/SetupStep.ts","../src/lifecycle/FeedbackTypes.ts","../src/notesync/NoteSyncSettings.ts","../src/orchestrator/PendingDialogStore.ts","../src/orchestrator/steps/PhaseHelpers.ts","../src/lifecycle/DefaultLifecycleHook.ts","../src/orchestrator/strategies/GateStrategy.ts","../src/orchestrator/strategies/AiPhaseStrategy.ts","../src/orchestrator/strategies/VerifyFixStrategy.ts","../src/orchestrator/strategies/index.ts","../src/orchestrator/steps/PhaseLoopStep.ts","../src/orchestrator/steps/CompletionStep.ts","../src/orchestrator/steps/FailureHandler.ts","../src/services/BrainstormService.ts","../src/prompts/brainstorm-templates.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { GongfengApiError, GongfengUploadError } from '../errors/index.js';\nimport { logger as rootLogger } from '../logger.js';\nimport { CircuitBreaker } from '../utils/CircuitBreaker.js';\nimport { RetryPolicy } from '../utils/RetryPolicy.js';\n\nconst logger = rootLogger.child('GongfengClient');\n\nexport interface GongfengIssue {\n id: number;\n iid: number;\n title: string;\n description: string;\n state: string;\n labels: string[];\n created_at: string;\n updated_at: string;\n author: { username: string; name: string };\n /** 工蜂 API 返回的负责人列表(字段名可能是 assignees 或 assignee_users) */\n assignees?: Array<{ username: string; name: string }>;\n assignee_users?: Array<{ username: string; name: string }>;\n}\n\nexport interface GongfengUser {\n id: number;\n username: string;\n name: string;\n}\n\nexport interface GongfengConfig {\n apiUrl: string;\n privateToken: string;\n projectPath: string;\n}\n\nexport interface CreateMergeRequestOptions {\n sourceBranch: string;\n targetBranch: string;\n title: string;\n description?: string;\n}\n\nexport interface GongfengMergeRequest {\n id: number;\n iid: number;\n title: string;\n web_url: string;\n state: string;\n source_branch?: string;\n target_branch?: string;\n}\n\nexport interface GongfengMergeRequestDetail extends GongfengMergeRequest {\n has_conflicts: boolean;\n merge_status: string;\n}\n\nexport interface UploadResult {\n alt: string;\n url: string;\n markdown: string;\n}\n\nexport interface GongfengNote {\n id: number;\n body: string;\n author: { username: string; name: string };\n created_at: string;\n}\n\nexport const AGENT_NOTE_MARKER = '\\n\\n<!-- issue-auto-finish-agent -->';\nconst AGENT_NOTE_MARKER_PATTERN = '<!-- issue-auto-finish-agent -->';\n\nexport class GongfengClient {\n private apiUrl: string;\n private token: string;\n private projectPath: string;\n private readonly retryPolicy: RetryPolicy;\n private readonly circuitBreaker: CircuitBreaker;\n\n constructor(config: GongfengConfig) {\n this.apiUrl = config.apiUrl.replace(/\\/$/, '');\n this.token = config.privateToken;\n this.projectPath = config.projectPath;\n\n this.retryPolicy = new RetryPolicy({\n maxRetries: 3,\n baseDelayMs: 1000,\n maxDelayMs: 30000,\n jitterFactor: 0.2,\n isRetryable: (err: unknown) => {\n if (err instanceof GongfengApiError) {\n return err.isRetryable;\n }\n // Network errors (e.g. fetch failures) are retryable\n if (err instanceof TypeError && (err.message.includes('fetch') || err.message.includes('network'))) {\n return true;\n }\n return false;\n },\n });\n\n this.circuitBreaker = new CircuitBreaker('GongfengAPI', {\n failureThreshold: 5,\n resetTimeoutMs: 60000,\n successThreshold: 2,\n });\n }\n\n private get projectApiBase(): string {\n const encoded = encodeURIComponent(this.projectPath);\n return `${this.apiUrl}/api/v3/projects/${encoded}`;\n }\n\n private async requestRaw(path: string, options: RequestInit = {}): Promise<Response> {\n const url = `${this.projectApiBase}${path}`;\n logger.debug('API request', { method: options.method || 'GET', url });\n\n return this.circuitBreaker.execute(() =>\n this.retryPolicy.execute(async () => {\n const resp = await fetch(url, {\n ...options,\n headers: {\n 'PRIVATE-TOKEN': this.token,\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n });\n\n if (!resp.ok) {\n const body = await resp.text();\n throw new GongfengApiError(resp.status, `Gongfeng API error ${resp.status}: ${body}`, body);\n }\n\n return resp;\n }, `requestRaw ${options.method || 'GET'} ${path}`),\n );\n }\n\n private async request<T>(path: string, options: RequestInit = {}): Promise<T> {\n const resp = await this.requestRaw(path, options);\n return resp.json() as Promise<T>;\n }\n\n async createIssue(\n title: string,\n description: string,\n labels?: string[],\n ): Promise<GongfengIssue> {\n const body: Record<string, string> = { title, description };\n if (labels && labels.length > 0) {\n body.labels = labels.join(',');\n }\n const issue = await this.request<GongfengIssue>('/issues', {\n method: 'POST',\n body: JSON.stringify(body),\n });\n logger.info('Issue created', { id: issue.id, iid: issue.iid, title });\n return issue;\n }\n\n async listIssues(state: string = 'opened', labels?: string): Promise<GongfengIssue[]> {\n const params = new URLSearchParams({ state, per_page: '100' });\n if (labels) {\n params.set('labels', labels);\n }\n return this.request<GongfengIssue[]>(`/issues?${params.toString()}`);\n }\n\n async listIssuesAdvanced(options: {\n state?: string;\n labels?: string;\n search?: string;\n page?: number;\n perPage?: number;\n } = {}): Promise<{ issues: GongfengIssue[]; total: number }> {\n const params = new URLSearchParams({\n state: options.state || 'opened',\n page: String(options.page || 1),\n per_page: String(options.perPage || 20),\n });\n if (options.labels) {\n params.set('labels', options.labels);\n }\n if (options.search) {\n params.set('search', options.search);\n }\n const resp = await this.requestRaw(`/issues?${params.toString()}`);\n const total = parseInt(resp.headers.get('x-total') || '0', 10);\n const issues = (await resp.json()) as GongfengIssue[];\n return { issues, total: total || issues.length };\n }\n\n async getIssueDetail(issueId: number): Promise<GongfengIssue> {\n return this.request<GongfengIssue>(`/issues/${issueId}`);\n }\n\n async createIssueNote(issueId: number, body: string): Promise<void> {\n const markedBody = body + AGENT_NOTE_MARKER;\n await this.request(`/issues/${issueId}/notes`, {\n method: 'POST',\n body: JSON.stringify({ body: markedBody }),\n });\n logger.info('Issue note created', { issueId });\n }\n\n async updateIssueLabels(issueId: number, labels: string[]): Promise<void> {\n await this.request(`/issues/${issueId}`, {\n method: 'PUT',\n body: JSON.stringify({ labels: labels.join(',') }),\n });\n logger.info('Issue labels updated', { issueId, labels });\n }\n\n async createMergeRequest(options: CreateMergeRequestOptions): Promise<GongfengMergeRequest> {\n const mr = await this.request<GongfengMergeRequest>('/merge_requests', {\n method: 'POST',\n body: JSON.stringify({\n source_branch: options.sourceBranch,\n target_branch: options.targetBranch,\n title: options.title,\n description: options.description ?? '',\n }),\n });\n if (!mr.web_url && mr.iid) {\n mr.web_url = this.buildMergeRequestUrl(mr.iid);\n }\n logger.info('Merge request created', { iid: mr.iid, webUrl: mr.web_url });\n return mr;\n }\n\n async findMergeRequestByBranch(\n sourceBranch: string,\n targetBranch: string,\n state: string = 'opened',\n ): Promise<GongfengMergeRequest | null> {\n const params = new URLSearchParams({\n state,\n source_branch: sourceBranch,\n target_branch: targetBranch,\n });\n const mrs = await this.request<GongfengMergeRequest[]>(\n `/merge_requests?${params.toString()}`,\n );\n if (mrs.length === 0) return null;\n const mr = mrs[0];\n if (!mr.web_url && mr.iid) {\n mr.web_url = this.buildMergeRequestUrl(mr.iid);\n }\n return mr;\n }\n\n private buildMergeRequestUrl(mrIid: number): string {\n return `${this.apiUrl}/${this.projectPath}/merge_requests/${mrIid}`;\n }\n\n async uploadFile(filePath: string): Promise<UploadResult> {\n const fileData = fs.readFileSync(filePath);\n const fileName = path.basename(filePath);\n const mimeType = fileName.endsWith('.png') ? 'image/png' : 'application/octet-stream';\n const blob = new Blob([fileData], { type: mimeType });\n\n const formData = new FormData();\n formData.append('file', blob, fileName);\n\n const url = `${this.projectApiBase}/uploads`;\n logger.debug('Upload request', { url, fileName });\n\n const resp = await fetch(url, {\n method: 'POST',\n headers: { 'PRIVATE-TOKEN': this.token },\n body: formData,\n });\n\n if (!resp.ok) {\n const body = await resp.text();\n throw new GongfengUploadError(resp.status, `Gongfeng upload error ${resp.status}: ${body}`, body);\n }\n\n const result = (await resp.json()) as UploadResult;\n logger.info('File uploaded', { fileName, url: result.url });\n return result;\n }\n\n async createMergeRequestNote(mrIid: number, body: string): Promise<void> {\n const markedBody = body + AGENT_NOTE_MARKER;\n await this.request(`/merge_requests/${mrIid}/notes`, {\n method: 'POST',\n body: JSON.stringify({ body: markedBody }),\n });\n logger.info('Merge request note created', { mrIid });\n }\n\n async closeMergeRequest(mrIid: number): Promise<void> {\n await this.request(`/merge_requests/${mrIid}`, {\n method: 'PUT',\n body: JSON.stringify({ state_event: 'close' }),\n });\n logger.info('Merge request closed', { mrIid });\n }\n\n async deleteIssue(issueId: number): Promise<void> {\n await this.request(`/issues/${issueId}`, { method: 'DELETE' });\n logger.info('Issue deleted', { issueId });\n }\n\n async closeIssue(issueId: number): Promise<void> {\n await this.request(`/issues/${issueId}`, {\n method: 'PUT',\n body: JSON.stringify({ state_event: 'close' }),\n });\n logger.info('Issue closed', { issueId });\n }\n\n async listIssueNotes(issueId: number): Promise<GongfengNote[]> {\n const allNotes: GongfengNote[] = [];\n let page = 1;\n while (true) {\n const params = new URLSearchParams({ per_page: '100', page: String(page) });\n const batch = await this.request<GongfengNote[]>(\n `/issues/${issueId}/notes?${params.toString()}`,\n );\n allNotes.push(...batch);\n if (batch.length < 100) break;\n page++;\n }\n return allNotes;\n }\n\n async deleteIssueNote(issueId: number, noteId: number): Promise<void> {\n // 工蜂 API 不支持 DELETE notes (返回 405),改用 PUT 清空内容使其失效(软删除)\n await this.request(`/issues/${issueId}/notes/${noteId}`, {\n method: 'PUT',\n body: JSON.stringify({ body: '<!-- iaf-note-deleted -->' }),\n });\n logger.debug('Issue note invalidated (soft-delete)', { issueId, noteId });\n }\n\n async cleanupAgentNotes(issueId: number): Promise<number> {\n const notes = await this.listIssueNotes(issueId);\n const agentNotes = notes.filter(n => n.body.includes(AGENT_NOTE_MARKER_PATTERN));\n for (const note of agentNotes) {\n await this.deleteIssueNote(issueId, note.id);\n }\n if (agentNotes.length > 0) {\n logger.info('Agent notes cleaned up', { issueId, deleted: agentNotes.length });\n }\n return agentNotes.length;\n }\n\n async getMergeRequestDetail(mrIid: number): Promise<GongfengMergeRequestDetail> {\n const mr = await this.request<GongfengMergeRequestDetail>(`/merge_requests/${mrIid}`);\n if (!mr.web_url && mr.iid) {\n mr.web_url = this.buildMergeRequestUrl(mr.iid);\n }\n return mr;\n }\n\n private async requestGlobal<T>(path: string, options: RequestInit = {}): Promise<T> {\n const url = `${this.apiUrl}${path}`;\n logger.debug('API request (global)', { method: options.method || 'GET', url });\n\n const resp = await this.circuitBreaker.execute(() =>\n this.retryPolicy.execute(async () => {\n const r = await fetch(url, {\n ...options,\n headers: {\n 'PRIVATE-TOKEN': this.token,\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n });\n\n if (!r.ok) {\n const body = await r.text();\n throw new GongfengApiError(r.status, `Gongfeng API error ${r.status}: ${body}`, body);\n }\n\n return r;\n }, `requestGlobal ${options.method || 'GET'} ${path}`),\n );\n\n return resp.json() as Promise<T>;\n }\n\n /** 获取当前 Token 对应的用户信息 */\n async getCurrentUser(): Promise<GongfengUser> {\n return this.requestGlobal<GongfengUser>('/api/v3/user');\n }\n\n /** 设置 Issue 负责人 */\n async setIssueAssignee(issueId: number, username: string): Promise<void> {\n await this.request(`/issues/${issueId}`, {\n method: 'PUT',\n body: JSON.stringify({ assignee_users: username }),\n });\n logger.info('Issue assignee updated', { issueId, username });\n }\n\n /** 清除 Issue 负责人 */\n async clearIssueAssignee(issueId: number): Promise<void> {\n await this.request(`/issues/${issueId}`, {\n method: 'PUT',\n body: JSON.stringify({ assignee_users: '' }),\n });\n logger.info('Issue assignee cleared', { issueId });\n }\n\n /** 更新 Issue 评论内容(用于心跳刷新锁评论) */\n async updateIssueNote(issueId: number, noteId: number, body: string): Promise<void> {\n await this.request(`/issues/${issueId}/notes/${noteId}`, {\n method: 'PUT',\n body: JSON.stringify({ body }),\n });\n logger.debug('Issue note updated', { issueId, noteId });\n }\n\n /** 创建 Issue 评论(不带 AGENT_NOTE_MARKER),返回含 id 的 note */\n async createIssueNotePlain(issueId: number, body: string): Promise<GongfengNote> {\n const note = await this.request<GongfengNote>(`/issues/${issueId}/notes`, {\n method: 'POST',\n body: JSON.stringify({ body }),\n });\n logger.debug('Issue note created (plain)', { issueId, noteId: note.id });\n return note;\n }\n\n /** Update connection config at runtime (for hot-reload) */\n updateConfig(config: GongfengConfig): void {\n this.apiUrl = config.apiUrl.replace(/\\/$/, '');\n this.token = config.privateToken;\n this.projectPath = config.projectPath;\n logger.info('GongfengClient config updated', { apiUrl: this.apiUrl, projectPath: this.projectPath });\n }\n\n /** 移除指定前缀的所有标签(精确匹配 prefix 和 prefix:* 前缀) */\n async removeLabelsWithPrefix(issueId: number, prefix: string): Promise<void> {\n const issue = await this.getIssueDetail(issueId);\n const filtered = issue.labels.filter(l => l !== prefix && !l.startsWith(prefix + ':'));\n if (filtered.length === issue.labels.length) return; // 没有需要移除的标签\n await this.updateIssueLabels(issueId, filtered);\n }\n\n async addLabel(issueId: number, label: string): Promise<void> {\n const issue = await this.getIssueDetail(issueId);\n if (issue.labels.includes(label)) {\n logger.info('Label already exists, skipping', { issueId, label });\n return;\n }\n const newLabels = [...issue.labels, label];\n await this.updateIssueLabels(issueId, newLabels);\n }\n}\n","import { logger as rootLogger } from '../logger.js';\n\nconst logger = rootLogger.child('CircuitBreaker');\n\nexport enum CircuitState {\n Closed = 'closed',\n Open = 'open',\n HalfOpen = 'half-open',\n}\n\nexport interface CircuitBreakerOptions {\n /** Number of failures before opening (default: 5) */\n failureThreshold?: number;\n /** Time in ms before trying half-open (default: 60000) */\n resetTimeoutMs?: number;\n /** Number of successes needed to close from half-open (default: 2) */\n successThreshold?: number;\n}\n\nexport class CircuitBreaker {\n private state: CircuitState = CircuitState.Closed;\n private failureCount = 0;\n private successCount = 0;\n private lastFailureTime = 0;\n private readonly failureThreshold: number;\n private readonly resetTimeoutMs: number;\n private readonly successThreshold: number;\n\n constructor(\n private readonly name: string,\n options?: CircuitBreakerOptions,\n ) {\n this.failureThreshold = options?.failureThreshold ?? 5;\n this.resetTimeoutMs = options?.resetTimeoutMs ?? 60000;\n this.successThreshold = options?.successThreshold ?? 2;\n }\n\n getState(): CircuitState {\n return this.state;\n }\n\n async execute<T>(fn: () => Promise<T>): Promise<T> {\n if (this.state === CircuitState.Open) {\n if (Date.now() - this.lastFailureTime >= this.resetTimeoutMs) {\n this.transitionTo(CircuitState.HalfOpen);\n } else {\n throw new Error(`Circuit breaker '${this.name}' is open`);\n }\n }\n\n try {\n const result = await fn();\n this.onSuccess();\n return result;\n } catch (err) {\n this.onFailure();\n throw err;\n }\n }\n\n /** Reset to closed state (e.g., for testing or manual recovery) */\n reset(): void {\n this.failureCount = 0;\n this.successCount = 0;\n this.lastFailureTime = 0;\n this.transitionTo(CircuitState.Closed);\n }\n\n private onSuccess(): void {\n if (this.state === CircuitState.HalfOpen) {\n this.successCount++;\n if (this.successCount >= this.successThreshold) {\n this.transitionTo(CircuitState.Closed);\n }\n } else {\n // In closed state, reset failure count on success\n this.failureCount = 0;\n }\n }\n\n private onFailure(): void {\n this.failureCount++;\n this.lastFailureTime = Date.now();\n\n if (this.state === CircuitState.HalfOpen) {\n // Any failure in half-open goes back to open\n this.transitionTo(CircuitState.Open);\n } else if (this.failureCount >= this.failureThreshold) {\n this.transitionTo(CircuitState.Open);\n }\n }\n\n private transitionTo(newState: CircuitState): void {\n if (this.state === newState) return;\n const oldState = this.state;\n this.state = newState;\n\n if (newState === CircuitState.Closed) {\n this.failureCount = 0;\n this.successCount = 0;\n } else if (newState === CircuitState.HalfOpen) {\n this.successCount = 0;\n }\n\n logger.info('Circuit breaker state transition', {\n name: this.name,\n from: oldState,\n to: newState,\n });\n }\n}\n","import { logger as rootLogger } from '../logger.js';\n\nconst logger = rootLogger.child('RetryPolicy');\n\nexport interface RetryPolicyOptions {\n /** Maximum number of retry attempts (default: 3) */\n maxRetries?: number;\n /** Initial delay in ms (default: 1000) */\n baseDelayMs?: number;\n /** Maximum delay in ms (default: 30000) */\n maxDelayMs?: number;\n /** Jitter factor 0-1 (default: 0.2) */\n jitterFactor?: number;\n /** Function to determine if error is retryable */\n isRetryable?: (error: unknown) => boolean;\n}\n\nexport class RetryPolicy {\n private readonly maxRetries: number;\n private readonly baseDelayMs: number;\n private readonly maxDelayMs: number;\n private readonly jitterFactor: number;\n private readonly isRetryable: (error: unknown) => boolean;\n\n constructor(options?: RetryPolicyOptions) {\n this.maxRetries = options?.maxRetries ?? 3;\n this.baseDelayMs = options?.baseDelayMs ?? 1000;\n this.maxDelayMs = options?.maxDelayMs ?? 30000;\n this.jitterFactor = options?.jitterFactor ?? 0.2;\n this.isRetryable = options?.isRetryable ?? (() => true);\n }\n\n /** Execute fn with retry. Returns the result or throws the last error. */\n async execute<T>(fn: () => Promise<T>, context?: string): Promise<T> {\n let lastError: unknown;\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err;\n if (attempt >= this.maxRetries || !this.isRetryable(err)) {\n throw err;\n }\n const delay = this.calculateDelay(attempt);\n logger.warn('Retrying after error', {\n context,\n attempt: attempt + 1,\n maxRetries: this.maxRetries,\n delayMs: delay,\n error: (err as Error).message,\n });\n await this.sleep(delay);\n }\n }\n throw lastError; // unreachable but satisfies TS\n }\n\n private calculateDelay(attempt: number): number {\n // Exponential backoff: base * 2^attempt\n const exponential = this.baseDelayMs * Math.pow(2, attempt);\n const capped = Math.min(exponential, this.maxDelayMs);\n // Add jitter\n const jitter = capped * this.jitterFactor * (Math.random() * 2 - 1);\n return Math.max(0, Math.round(capped + jitter));\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}\n","import type { DemandSpec } from '../demand/DemandSpec.js';\n\nexport enum IssueState {\n Pending = 'pending',\n Skipped = 'skipped',\n BranchCreated = 'branch_created',\n // ── 通用阶段状态 ──\n /** AI 阶段执行中(配合 currentPhase 使用) */\n PhaseRunning = 'phase_running',\n /** AI 阶段执行完毕(配合 currentPhase 使用) */\n PhaseDone = 'phase_done',\n /** Gate 阶段等待中(配合 currentPhase 使用) */\n PhaseWaiting = 'phase_waiting',\n /** Gate 阶段已批准(配合 currentPhase 使用) */\n PhaseApproved = 'phase_approved',\n // Conflict resolution (post-completion)\n ResolvingConflict = 'resolving_conflict',\n /** 用户主动中止,保留 worktree/分支/session,可继续或重做 */\n Paused = 'paused',\n // Terminal\n Completed = 'completed',\n Failed = 'failed',\n Deployed = 'deployed',\n}\n\nexport type PipelineMode = string;\n\nexport interface PortPairRecord {\n backendPort: number;\n frontendPort: number;\n}\n\n/** 生命周期状态 — 由 IssueTracker 管理 */\nexport interface IssueLifecycle {\n state: IssueState;\n /** 当 state 为 PhaseRunning/PhaseDone/PhaseWaiting/PhaseApproved 时,记录具体阶段名 */\n currentPhase?: string;\n attempts: number;\n lastError?: string;\n failedAtState?: IssueState;\n /** 最后一次错误是否可重试。undefined 视为可重试(向后兼容旧记录) */\n lastErrorRetryable?: boolean;\n /** 中止时的阶段名(Paused 状态下有值) */\n pausedAtPhase?: string;\n /** 持久化处理锁,防止 poller 并发拾取同一 issue。向后兼容:旧记录无此字段 = 无锁 */\n processingLock?: {\n correlationId: string;\n ts: string;\n };\n}\n\n/** 流水线配置 */\nexport interface IssuePipeline {\n pipelineMode?: PipelineMode;\n}\n\n/** 分支信息 */\nexport interface IssueBranch {\n branchName: string;\n}\n\n/** Issue 级别的功能开关 */\nexport interface IssueFeatureFlags {\n /** undefined = follow system setting */\n issueNoteSyncEnabled?: boolean;\n /** undefined = follow system setting */\n e2eEnabled?: boolean;\n}\n\n/** 部署/预览信息 */\nexport interface IssueDeployment {\n /** Allocated ports for preview/E2E (persisted for recovery) */\n ports?: PortPairRecord;\n /** Preview servers started at */\n previewStartedAt?: string;\n}\n\n/** 结果信息 */\nexport interface IssueResult {\n mrUrl?: string;\n /** 多仓模式下关联仓库的 MR URL(repo name -> URL) */\n linkedMrUrls?: Record<string, string>;\n}\n\n/** 审计时间戳 */\nexport interface IssueAudit {\n createdAt: string;\n updatedAt: string;\n}\n\n/** 需求规格(知识域),新建 Issue 时填充 */\nexport interface IssueDemand {\n demandSpec?: DemandSpec;\n}\n\n/** 阶段进度(真实事件记录,非推导) */\nexport interface IssuePhaseProgress {\n /** 各阶段的实际进度记录,key 为阶段名 */\n phaseProgress?: Record<string, PhaseProgress>;\n}\n\n/** 完整的 IssueRecord — 持久化格式不变 */\nexport type IssueRecord =\n IssueLifecycle &\n IssuePipeline &\n IssueBranch &\n IssueFeatureFlags &\n IssueDeployment &\n IssueResult &\n IssueDemand &\n IssueAudit &\n IssuePhaseProgress;\n\nexport type PhaseStatus = 'pending' | 'in_progress' | 'completed' | 'failed' | 'gate_waiting';\n\nexport interface PhaseProgress {\n status: PhaseStatus;\n startedAt?: string;\n completedAt?: string;\n error?: string;\n /** AI 会话 ID,用于断点续跑(--resume) */\n sessionId?: string;\n}\n\nexport interface ProgressData {\n displayId: number;\n title: string;\n branchName: string;\n pipelineMode?: PipelineMode;\n currentPhase: string;\n phases: Record<string, PhaseProgress>;\n}\n","import { IssueState } from '../tracker/IssueState.js';\nimport type { PipelineDef, PhaseSpec, PlanFileSpec } from '../pipeline/PipelineDefinition.js';\nimport type { ActionState, ActionStatus } from './ActionLifecycle.js';\nimport { t } from '../i18n/index.js';\n\n/**\n * ActionLifecycleManager — 查询层抽象。\n *\n * 从 PipelineDef 自动构建 IssueState ↔ ActionState 双向映射表,\n * 集中散布在 IssueTracker/PipelineOrchestrator/BasePhase 中的状态分类逻辑。\n *\n * 不改变持久化格式(tracker.json 中的状态字符串值完全保留)。\n */\nexport class ActionLifecycleManager {\n /** IssueState → ActionState */\n private readonly stateToAction: Map<IssueState, ActionState>;\n /** \"action:status\" → IssueState */\n private readonly actionToState: Map<string, IssueState>;\n /** phase name → { startState, doneState, approvedState? } */\n private readonly phaseStatesMap: Map<string, { startState: IssueState; doneState: IssueState; approvedState?: IssueState }>;\n /** Ordered phase indices by IssueState for determineResumePhaseIndex */\n private readonly def: PipelineDef;\n\n constructor(def: PipelineDef) {\n this.def = def;\n this.stateToAction = new Map();\n this.actionToState = new Map();\n this.phaseStatesMap = new Map();\n\n this.buildMappings(def);\n }\n\n private buildMappings(def: PipelineDef): void {\n // Fixed mappings\n this.addMapping(IssueState.Pending, 'init', 'idle');\n this.addMapping(IssueState.Skipped, 'init', 'skipped');\n this.addMapping(IssueState.BranchCreated, 'init', 'ready');\n this.addMapping(IssueState.Failed, 'init', 'failed');\n this.addMapping(IssueState.Paused, 'init', 'paused');\n this.addMapping(IssueState.Deployed, 'init', 'done');\n this.addMapping(IssueState.ResolvingConflict, 'conflict', 'running');\n\n // Phase-driven mappings\n for (const spec of def.phases) {\n this.phaseStatesMap.set(spec.name, {\n startState: spec.startState,\n doneState: spec.doneState,\n approvedState: spec.approvedState,\n });\n\n if (spec.kind === 'ai') {\n // For generic PhaseRunning/PhaseDone, don't add to stateToAction map\n // (since multiple phases share the same IssueState value).\n // Only add non-generic states.\n if (spec.startState !== IssueState.PhaseRunning) {\n this.addMapping(spec.startState, spec.name, 'running');\n }\n if (spec.doneState === IssueState.Completed) {\n this.addMapping(spec.doneState, spec.name, 'done');\n } else if (spec.doneState !== IssueState.PhaseDone) {\n this.addMapping(spec.doneState, spec.name, 'ready');\n }\n } else if (spec.kind === 'gate') {\n // For generic PhaseWaiting/PhaseApproved, don't add to stateToAction map\n // (since multiple gate phases could share the same IssueState value).\n if (spec.startState !== IssueState.PhaseWaiting) {\n this.addMapping(spec.startState, spec.name, 'waiting');\n }\n if (spec.approvedState && spec.approvedState !== IssueState.PhaseApproved) {\n this.addMapping(spec.approvedState, spec.name, 'ready');\n }\n }\n }\n }\n\n private addMapping(state: IssueState, action: string, status: ActionStatus): void {\n // Avoid overwriting — first mapping wins (e.g. Completed mapped by verify phase)\n if (!this.stateToAction.has(state)) {\n this.stateToAction.set(state, { action, status });\n }\n const key = `${action}:${status}`;\n if (!this.actionToState.has(key)) {\n this.actionToState.set(key, state);\n }\n }\n\n // ─── Query API ───\n\n /**\n * 将 IssueState 解析为语义化的 ActionState。\n *\n * 对于通用状态 PhaseRunning/PhaseDone,需额外传入 currentPhase 来区分具体阶段。\n */\n resolve(state: IssueState, currentPhase?: string): ActionState {\n // Paused:用 pausedAtPhase(传入的 currentPhase)作为 action 名\n if (state === IssueState.Paused && currentPhase) {\n return { action: currentPhase, status: 'paused' };\n }\n // 通用阶段状态:用 currentPhase 作为 action 名\n if (state === IssueState.PhaseRunning && currentPhase) {\n return { action: currentPhase, status: 'running' };\n }\n if (state === IssueState.PhaseDone && currentPhase) {\n return { action: currentPhase, status: 'ready' };\n }\n if (state === IssueState.PhaseWaiting && currentPhase) {\n return { action: currentPhase, status: 'waiting' };\n }\n if (state === IssueState.PhaseApproved && currentPhase) {\n return { action: currentPhase, status: 'ready' };\n }\n\n const mapped = this.stateToAction.get(state);\n if (mapped) return mapped;\n // Fallback: unknown states (from another pipeline mode) treated as idle\n return { action: 'init', status: 'idle' };\n }\n\n /**\n * 将 action + status 反向映射为 IssueState。\n */\n toIssueState(action: string, status: ActionStatus): IssueState | undefined {\n return this.actionToState.get(`${action}:${status}`);\n }\n\n // ─── Classification predicates (替代 3 个 Set 常量 + getDrivableIssues) ───\n\n /**\n * 终态:done | failed | skipped\n */\n isTerminal(state: IssueState): boolean {\n const as = this.resolve(state);\n return as.status === 'done' || as.status === 'failed' || as.status === 'skipped';\n }\n\n /**\n * 进行中:running (包含通用 PhaseRunning)\n */\n isInProgress(state: IssueState): boolean {\n if (state === IssueState.PhaseRunning) return true;\n return this.resolve(state).status === 'running';\n }\n\n /**\n * 阻塞中:waiting\n */\n isBlocked(state: IssueState): boolean {\n if (state === IssueState.PhaseWaiting) return true;\n return this.resolve(state).status === 'waiting';\n }\n\n /**\n * 可驱动判断(集中化 getDrivableIssues 的过滤逻辑)。\n *\n * - idle → 可驱动 (Pending)\n * - ready → 可驱动 (BranchCreated, PhaseDone, PhaseApproved)\n * - failed && attempts < maxRetries → 可驱动\n * - waiting → 不可驱动 (PhaseWaiting)\n * - running → 不可驱动(stalled 由外部叠加)\n * - done/skipped → 不可驱动\n */\n isDrivable(state: IssueState, attempts: number, maxRetries: number, lastErrorRetryable?: boolean): boolean {\n // Paused is never drivable (user must explicitly continue/redo)\n if (state === IssueState.Paused) return false;\n // PhaseDone is always drivable (triggers next phase)\n if (state === IssueState.PhaseDone) return true;\n // PhaseApproved is always drivable (gate approved, triggers next phase)\n if (state === IssueState.PhaseApproved) return true;\n // PhaseRunning is never drivable (something is executing)\n if (state === IssueState.PhaseRunning) return false;\n // PhaseWaiting is never drivable (waiting for external input)\n if (state === IssueState.PhaseWaiting) return false;\n const as = this.resolve(state);\n switch (as.status) {\n case 'idle':\n case 'ready':\n return true;\n case 'failed':\n if (lastErrorRetryable === false) return false;\n return attempts < maxRetries;\n case 'waiting':\n case 'running':\n case 'done':\n case 'skipped':\n case 'paused':\n return false;\n }\n }\n\n // ─── Phase navigation (替代 determineStartIndex + getPhasePreState) ───\n\n /**\n * 确定从哪个阶段索引恢复执行(替代 PipelineOrchestrator.determineStartIndex)。\n *\n * 从后向前扫描 phases,匹配 currentState 或 failedAtState。\n * 支持通用状态 PhaseRunning/PhaseDone + currentPhase 的组合。\n */\n determineResumePhaseIndex(currentState: IssueState, failedAtState?: IssueState, currentPhase?: string): number {\n const target = failedAtState || currentState;\n const phases = this.def.phases;\n\n // 通用阶段状态:通过 currentPhase 名称匹配\n if ((target === IssueState.PhaseRunning || target === IssueState.PhaseDone) && currentPhase) {\n const idx = phases.findIndex(p => p.name === currentPhase);\n if (idx >= 0) {\n return target === IssueState.PhaseDone ? idx + 1 : idx;\n }\n }\n if ((target === IssueState.PhaseWaiting || target === IssueState.PhaseApproved) && currentPhase) {\n const idx = phases.findIndex(p => p.name === currentPhase);\n if (idx >= 0) {\n if (target === IssueState.PhaseApproved) {\n const spec = phases[idx];\n // AI phase with approvedState: re-execute same phase (detection done, execution pending)\n return (spec.kind === 'ai' && spec.approvedState) ? idx : idx + 1;\n }\n return idx;\n }\n }\n\n for (let i = phases.length - 1; i >= 0; i--) {\n const spec = phases[i];\n\n if (spec.kind === 'gate' && spec.approvedState === target) {\n return i + 1;\n }\n\n if (spec.startState === target || spec.doneState === target) {\n return spec.doneState === target ? i + 1 : i;\n }\n }\n return 0;\n }\n\n /**\n * 获取某个 phase 的前驱状态(即重置到该 phase 需要设置的状态)。\n * 第一个 phase 的前驱是 BranchCreated;后续 phase 的前驱是上一个 phase 的 approvedState 或 doneState。\n */\n getPhasePreState(phaseName: string): IssueState | undefined {\n const phases = this.def.phases;\n const idx = phases.findIndex(p => p.name === phaseName);\n if (idx < 0) return undefined;\n if (idx === 0) return IssueState.BranchCreated;\n const prev = phases[idx - 1];\n return prev.approvedState ?? prev.doneState;\n }\n\n /**\n * 获取某个 phase 的状态三元组。\n */\n getPhaseStates(phaseName: string): { startState: IssueState; doneState: IssueState; approvedState?: IssueState } | undefined {\n return this.phaseStatesMap.get(phaseName);\n }\n\n // ─── Display helpers (替代 collectStateLabels + derivePhaseStatuses) ───\n\n /**\n * 解析单条状态的展示标签。\n *\n * 对通用状态 PhaseRunning/PhaseDone,需传入 currentPhase 以生成具体标签(如\"分析中\");\n * 缺少 currentPhase 时回退到泛化标签(如\"阶段执行中\")。\n */\n resolveLabel(state: IssueState, currentPhase?: string): string {\n if ((state === IssueState.PhaseRunning || state === IssueState.PhaseDone) && currentPhase) {\n const phaseLabel = t(`pipeline.phase.${currentPhase}`);\n return state === IssueState.PhaseRunning\n ? t('state.phaseDoing', { label: phaseLabel })\n : t('state.phaseDone', { label: phaseLabel });\n }\n if ((state === IssueState.PhaseWaiting || state === IssueState.PhaseApproved) && currentPhase) {\n const phaseLabel = t(`pipeline.phase.${currentPhase}`);\n return state === IssueState.PhaseWaiting\n ? t('state.phaseWaiting', { label: phaseLabel })\n : t('state.phaseApproved', { label: phaseLabel });\n }\n const labels = this.collectStateLabels();\n return labels.get(state) ?? state;\n }\n\n /**\n * 收集所有状态及其展示标签。\n * 为通用状态 PhaseRunning/PhaseDone 生成每个阶段的复合 key 条目。\n */\n collectStateLabels(): Map<string, string> {\n const labels = new Map<string, string>();\n labels.set(IssueState.Pending, t('state.pending'));\n labels.set(IssueState.Skipped, t('state.skipped'));\n labels.set(IssueState.BranchCreated, t('state.branchCreated'));\n\n for (const phase of this.def.phases) {\n const phaseLabel = t(`pipeline.phase.${phase.name}`);\n\n // AI 阶段: PhaseRunning/PhaseDone → composite key\n if (phase.startState === IssueState.PhaseRunning) {\n labels.set(`phase_running:${phase.name}`, t('state.phaseDoing', { label: phaseLabel }));\n } else if (phase.startState === IssueState.PhaseWaiting) {\n // Gate 阶段: PhaseWaiting → composite key\n labels.set(`phase_waiting:${phase.name}`, t('state.phaseWaiting', { label: phaseLabel }));\n } else {\n labels.set(phase.startState, t('state.phaseDoing', { label: phaseLabel }));\n }\n\n if (phase.doneState === IssueState.PhaseDone) {\n labels.set(`phase_done:${phase.name}`, t('state.phaseDone', { label: phaseLabel }));\n } else if (phase.doneState === IssueState.PhaseApproved) {\n // Gate 阶段: PhaseApproved → composite key\n labels.set(`phase_approved:${phase.name}`, t('state.phaseApproved', { label: phaseLabel }));\n } else if (phase.doneState !== IssueState.Completed) {\n labels.set(phase.doneState, t('state.phaseDone', { label: phaseLabel }));\n }\n\n // 非通用 approvedState(保留,支持自定义状态)\n if (phase.approvedState\n && phase.approvedState !== IssueState.PhaseApproved\n && phase.approvedState !== phase.doneState) {\n labels.set(phase.approvedState, t('state.phaseApproved', { label: phaseLabel }));\n }\n }\n\n labels.set(IssueState.Completed, t('state.completed'));\n labels.set(IssueState.Failed, t('state.failed'));\n labels.set(IssueState.Paused, t('state.paused'));\n labels.set(IssueState.ResolvingConflict, t('state.resolvingConflict'));\n return labels;\n }\n\n /**\n * 根据当前 state,推导每个 phase 的进度状态。\n * 支持通用状态 PhaseRunning/PhaseDone + currentPhase。\n */\n derivePhaseStatuses(currentState: string, currentPhase?: string): Record<string, 'pending' | 'in_progress' | 'completed' | 'failed'> {\n const result: Record<string, 'pending' | 'in_progress' | 'completed' | 'failed'> = {};\n let passedCurrent = false;\n\n // Failed 状态:基于 currentPhase 推导哪个阶段失败\n if (currentState === IssueState.Failed && currentPhase) {\n for (const phase of this.def.phases) {\n if (passedCurrent) {\n result[phase.name] = 'pending';\n } else if (phase.name === currentPhase) {\n result[phase.name] = 'failed';\n passedCurrent = true;\n } else {\n result[phase.name] = 'completed';\n }\n }\n return result;\n }\n\n // Paused 状态:暂停阶段显示为 in_progress,之前 completed,之后 pending\n if (currentState === IssueState.Paused && currentPhase) {\n for (const phase of this.def.phases) {\n if (passedCurrent) {\n result[phase.name] = 'pending';\n } else if (phase.name === currentPhase) {\n result[phase.name] = 'in_progress';\n passedCurrent = true;\n } else {\n result[phase.name] = 'completed';\n }\n }\n return result;\n }\n\n // 通用阶段状态:基于 currentPhase 名称推导\n if ((currentState === IssueState.PhaseRunning || currentState === IssueState.PhaseDone) && currentPhase) {\n for (const phase of this.def.phases) {\n if (passedCurrent) {\n result[phase.name] = 'pending';\n } else if (phase.name === currentPhase) {\n result[phase.name] = currentState === IssueState.PhaseRunning ? 'in_progress' : 'completed';\n passedCurrent = currentState === IssueState.PhaseRunning;\n // PhaseDone 意味着该阶段完成,后续为 pending\n if (currentState === IssueState.PhaseDone) passedCurrent = true;\n } else {\n result[phase.name] = 'completed';\n }\n }\n return result;\n }\n\n // 通用 gate 阶段状态:基于 currentPhase 名称推导\n if ((currentState === IssueState.PhaseWaiting || currentState === IssueState.PhaseApproved) && currentPhase) {\n for (const phase of this.def.phases) {\n if (passedCurrent) {\n result[phase.name] = 'pending';\n } else if (phase.name === currentPhase) {\n // AI phase with approvedState: PhaseApproved 意味着即将执行,显示 in_progress\n const isGatedAi = phase.kind === 'ai' && phase.approvedState;\n result[phase.name] = (currentState === IssueState.PhaseWaiting\n || (currentState === IssueState.PhaseApproved && isGatedAi))\n ? 'in_progress' : 'completed';\n passedCurrent = true;\n } else {\n result[phase.name] = 'completed';\n }\n }\n return result;\n }\n\n // 终态:所有阶段标记为 completed\n if (currentState === IssueState.Completed || currentState === IssueState.ResolvingConflict) {\n for (const phase of this.def.phases) {\n result[phase.name] = 'completed';\n }\n return result;\n }\n\n // 非通用阶段状态(传统 startState/doneState 匹配,如 BranchCreated 等)\n for (const phase of this.def.phases) {\n if (passedCurrent) {\n result[phase.name] = 'pending';\n continue;\n }\n if (phase.startState === currentState) {\n result[phase.name] = 'in_progress';\n passedCurrent = true;\n } else if (phase.doneState === currentState || phase.approvedState === currentState) {\n result[phase.name] = 'completed';\n } else {\n // 未匹配任何阶段的状态(Pending/Skipped/BranchCreated/Failed)→ pending\n result[phase.name] = 'pending';\n }\n }\n return result;\n }\n\n // ─── Pipeline Protocol queries (P1) ───\n\n /**\n * 返回可被用户单独重试的阶段名列表。\n * 优先使用 spec.retryable,未声明时默认 kind === 'ai'。\n */\n getRetryablePhases(): string[] {\n return this.def.phases\n .filter(spec => spec.retryable ?? (spec.kind === 'ai'))\n .map(spec => spec.name);\n }\n\n /**\n * 判断指定阶段是否可重试。\n */\n isRetryable(phaseName: string): boolean {\n const spec = this.def.phases.find(p => p.name === phaseName);\n if (!spec) return false;\n return spec.retryable ?? (spec.kind === 'ai');\n }\n\n /**\n * 查找 gate 类型的阶段。\n */\n getGatePhase(): PhaseSpec | undefined {\n return this.def.phases.find(p => p.kind === 'gate');\n }\n\n /**\n * 判断指定阶段完成后是否应启动预览服务器。\n */\n shouldDeployPreview(phaseName: string): boolean {\n const spec = this.def.phases.find(p => p.name === phaseName);\n return spec?.deploysPreview ?? false;\n }\n\n /**\n * 收集所有阶段的产物文件,扁平化为单一列表。\n */\n collectArtifacts(): PlanFileSpec[] {\n return this.def.phases.flatMap(spec => spec.artifacts ?? []);\n }\n\n /**\n * 返回所有阶段的名称和标签(保持定义顺序)。\n */\n getPhaseDefs(): { name: string; label: string }[] {\n return this.def.phases.map(p => ({ name: p.name, label: p.label }));\n }\n\n /**\n * 返回所有 kind === 'ai' 的阶段名(可执行阶段)。\n */\n getExecutablePhaseNames(): string[] {\n return this.def.phases\n .filter(spec => spec.kind === 'ai')\n .map(spec => spec.name);\n }\n}\n","import { IssueRecord, IssueState, type PhaseProgress } from './IssueState.js';\nimport { type PipelineDef } from '../pipeline/PipelineDefinition.js';\nimport { IssueNotFoundError } from '../errors/index.js';\nimport { ActionLifecycleManager } from '../lifecycle/ActionLifecycleManager.js';\nimport { BaseTracker } from './BaseTracker.js';\nimport { type ExecutableTask, issueToExecutableTask } from './ExecutableTask.js';\nimport { getIid } from './IssueRecordHelper.js';\nimport { logger as rootLogger } from '../logger.js';\nimport { eventBus } from '../events/EventBus.js';\n\nconst logger = rootLogger.child('IssueTracker');\n\n/**\n * 旧阶段专属状态 → 通用状态的映射表。\n * 使用字符串字面量,不引用 IssueState 枚举(删枚举后不受影响)。\n */\nconst STATE_MIGRATION_MAP: Record<string, { state: string; currentPhase: string }> = {\n analyzing: { state: 'phase_running', currentPhase: 'analysis' },\n analysis_done: { state: 'phase_done', currentPhase: 'analysis' },\n designing: { state: 'phase_running', currentPhase: 'design' },\n design_done: { state: 'phase_done', currentPhase: 'design' },\n implementing: { state: 'phase_running', currentPhase: 'implement' },\n implement_done: { state: 'phase_done', currentPhase: 'implement' },\n planning: { state: 'phase_running', currentPhase: 'plan' },\n plan_done: { state: 'phase_done', currentPhase: 'plan' },\n building: { state: 'phase_running', currentPhase: 'build' },\n build_done: { state: 'phase_done', currentPhase: 'build' },\n verifying: { state: 'phase_running', currentPhase: 'verify' },\n // 旧 gate 硬编码状态 → 通用 gate 状态\n waiting_for_review: { state: 'phase_waiting', currentPhase: 'review' },\n review_approved: { state: 'phase_approved', currentPhase: 'review' },\n};\n\nexport class IssueTracker extends BaseTracker<IssueRecord> {\n private lifecycleManagers: Map<string, ActionLifecycleManager>;\n readonly tenantId: string;\n\n constructor(\n dataDir: string,\n lifecycleManagers: Map<string, ActionLifecycleManager>,\n tenantId?: string,\n ) {\n const tid = tenantId ?? 'default';\n const filename = tid === 'default' ? 'tracker.json' : `tracker-${tid}.json`;\n super(dataDir, filename, 'issues', 'tracker');\n this.lifecycleManagers = lifecycleManagers;\n this.tenantId = tid;\n this.migrateRecords();\n }\n\n /**\n * 迁移旧格式记录到新格式:\n * 1. 旧阶段专属状态 → PhaseRunning/PhaseDone + currentPhase\n * 2. failedAtState 同步迁移\n * 3. 为缺少 demandSpec 的旧记录回填\n *\n * 幂等:已迁移的记录不会重复处理。\n */\n private migrateRecords(): void {\n let migrated = 0;\n for (const record of this.getAllRecords()) {\n const raw = record as unknown as Record<string, unknown>;\n\n // 1. 迁移主状态\n const stateStr = raw.state as string;\n const migration = STATE_MIGRATION_MAP[stateStr];\n if (migration) {\n raw.state = migration.state;\n raw.currentPhase = migration.currentPhase;\n migrated++;\n }\n\n // 2. 迁移 failedAtState\n const failedAtStr = raw.failedAtState as string | undefined;\n if (failedAtStr) {\n const failedMigration = STATE_MIGRATION_MAP[failedAtStr];\n if (failedMigration) {\n raw.failedAtState = failedMigration.state;\n // 如果 failedAtState 迁移了,也需要记录 currentPhase(除非主状态已设置)\n if (!raw.currentPhase) {\n raw.currentPhase = failedMigration.currentPhase;\n }\n }\n }\n\n // 3. 回填 demandSpec(兼容旧记录)\n if (!raw.demandSpec && raw.issueIid) {\n raw.demandSpec = {\n demandId: `gf-${raw.issueIid}`,\n sourceRef: {\n source: 'gongfeng-issue',\n externalId: String(raw.issueId ?? raw.issueIid),\n displayId: String(raw.issueIid),\n },\n title: (raw.issueTitle as string) || '',\n description: '',\n createdAt: (raw.createdAt as string) || new Date().toISOString(),\n };\n }\n\n // 4. 删除 IssueIdentity 旧字段\n if (raw.issueId !== undefined || raw.issueIid !== undefined || raw.issueTitle !== undefined) {\n delete raw.issueId;\n delete raw.issueIid;\n delete raw.issueTitle;\n migrated++;\n }\n }\n if (migrated > 0) {\n this.save();\n logger.info('Migrated tracker records', { migrated });\n }\n }\n\n private lifecycleFor(record: IssueRecord): ActionLifecycleManager {\n if (record.pipelineMode) {\n const lm = this.lifecycleManagers.get(record.pipelineMode);\n if (lm) return lm;\n }\n // Fallback: 'plan-mode' or first registered manager\n return this.lifecycleManagers.get('plan-mode') ?? this.lifecycleManagers.values().next().value!;\n }\n\n private key(issueIid: number): string {\n return String(issueIid);\n }\n\n get(issueIid: number): IssueRecord | undefined {\n return this.getByKey(this.key(issueIid));\n }\n\n create(record: Omit<IssueRecord, 'createdAt' | 'updatedAt' | 'attempts'>): IssueRecord {\n const now = new Date().toISOString();\n const full: IssueRecord = {\n ...record,\n attempts: 0,\n createdAt: now,\n updatedAt: now,\n };\n this.setRecord(this.key(getIid(full)), full);\n this.save();\n logger.info('Issue tracked', { issueIid: getIid(full), state: record.state });\n eventBus.emitTyped('issue:created', full);\n return full;\n }\n\n updateState(issueIid: number, state: IssueState, extra?: Partial<IssueRecord>): void {\n const record = this.collection[this.key(issueIid)];\n if (!record) {\n throw new IssueNotFoundError(issueIid);\n }\n record.state = state;\n record.updatedAt = new Date().toISOString();\n if (state === IssueState.Completed) {\n record.lastError = undefined;\n record.failedAtState = undefined;\n }\n if (extra) {\n Object.assign(record, extra);\n }\n this.save();\n logger.info('Issue state updated', { issueIid, state });\n eventBus.emitTyped('issue:stateChanged', { issueIid, state, record });\n }\n\n /** 初始化阶段进度(流水线启动时调用) */\n initPhaseProgress(issueIid: number, def: PipelineDef): void {\n const record = this.collection[this.key(issueIid)];\n if (!record) return;\n const phases: Record<string, PhaseProgress> = {};\n for (const spec of def.phases) {\n phases[spec.name] = { status: 'pending' };\n }\n record.phaseProgress = phases;\n record.updatedAt = new Date().toISOString();\n this.save();\n }\n\n /** 更新单个阶段的进度(原子保存 + SSE 推送) */\n updatePhaseProgress(issueIid: number, phase: string, update: Partial<PhaseProgress>): void {\n const record = this.collection[this.key(issueIid)];\n if (!record?.phaseProgress) return;\n const pp = record.phaseProgress[phase];\n if (!pp) return;\n Object.assign(pp, update);\n record.updatedAt = new Date().toISOString();\n this.save();\n eventBus.emitTyped('issue:stateChanged', { issueIid, state: record.state, record });\n }\n\n markFailed(issueIid: number, error: string, failedAtState: IssueState, isRetryable?: boolean): void {\n const record = this.collection[this.key(issueIid)];\n if (!record) return;\n record.state = IssueState.Failed;\n record.lastError = error;\n record.failedAtState = failedAtState;\n record.lastErrorRetryable = isRetryable;\n record.attempts += 1;\n record.updatedAt = new Date().toISOString();\n this.save();\n logger.warn('Issue marked as failed', { issueIid, error, failedAtState, attempts: record.attempts, isRetryable });\n eventBus.emitTyped('issue:failed', { issueIid, error, failedAtState, record });\n }\n\n /**\n * Mark as failed WITHOUT incrementing attempts. Used when the agent was still\n * actively producing output at timeout — a slow-but-progressing run should not\n * consume the retry budget.\n */\n markFailedSoft(issueIid: number, error: string, failedAtState: IssueState): void {\n const record = this.collection[this.key(issueIid)];\n if (!record) return;\n record.state = IssueState.Failed;\n record.lastError = error;\n record.failedAtState = failedAtState;\n record.lastErrorRetryable = true;\n record.updatedAt = new Date().toISOString();\n this.save();\n logger.warn('Issue marked as failed (soft — no attempt increment)', {\n issueIid, error, failedAtState, attempts: record.attempts,\n });\n eventBus.emitTyped('issue:failed', { issueIid, error, failedAtState, record });\n }\n\n pauseIssue(issueIid: number, currentPhase: string): void {\n const record = this.collection[this.key(issueIid)];\n if (!record) return;\n record.state = IssueState.Paused;\n record.pausedAtPhase = currentPhase;\n // 非失败,清除失败痕迹\n record.failedAtState = undefined;\n record.lastError = undefined;\n record.processingLock = undefined;\n record.updatedAt = new Date().toISOString();\n this.save();\n logger.info('Issue paused', { issueIid, pausedAtPhase: currentPhase });\n eventBus.emitTyped('issue:paused', { issueIid, pausedAtPhase: currentPhase, record });\n }\n\n resumeFromPause(issueIid: number, def: PipelineDef, clearSession: boolean): boolean {\n const record = this.collection[this.key(issueIid)];\n if (!record || record.state !== IssueState.Paused || !record.pausedAtPhase) return false;\n\n const lm = new ActionLifecycleManager(def);\n const preState = lm.getPhasePreState(record.pausedAtPhase);\n if (!preState) return false;\n\n const phase = record.pausedAtPhase;\n record.state = preState;\n // 设置 currentPhase 为前驱阶段名(与 resetToPhase 逻辑一致)\n if (preState === IssueState.PhaseDone || preState === IssueState.PhaseApproved) {\n const phases = def.phases;\n const idx = phases.findIndex(p => p.name === phase);\n if (idx > 0) {\n record.currentPhase = phases[idx - 1].name;\n }\n }\n record.pausedAtPhase = undefined;\n record.updatedAt = new Date().toISOString();\n this.save();\n\n const eventType = clearSession ? 'issue:redone' : 'issue:continued';\n logger.info('Issue resumed from pause', { issueIid, phase, clearSession, state: preState });\n eventBus.emitTyped(eventType, { issueIid, phase, record });\n return true;\n }\n\n // ── processingLock 管理 ──\n\n /** 持久化锁超时阈值(默认 30 分钟,与 PHASE_TIMEOUT 一致) */\n private static readonly LOCK_TIMEOUT_MS = 30 * 60 * 1000;\n\n /**\n * 获取持久化处理锁。\n * - 无锁或超时锁 → 写入并返回 true\n * - 有未超时锁(其他 correlationId)→ 返回 false\n */\n acquireProcessingLock(issueIid: number, correlationId: string): boolean {\n const record = this.collection[this.key(issueIid)];\n if (!record) return false;\n\n const existing = record.processingLock;\n if (existing) {\n const age = Date.now() - new Date(existing.ts).getTime();\n if (age < IssueTracker.LOCK_TIMEOUT_MS) {\n logger.warn('Processing lock held, rejecting acquire', {\n issueIid,\n existingCorrelationId: existing.correlationId,\n ageMs: age,\n });\n return false;\n }\n logger.warn('Processing lock timed out, forcibly acquiring', {\n issueIid,\n staleCorrelationId: existing.correlationId,\n ageMs: age,\n });\n }\n\n record.processingLock = { correlationId, ts: new Date().toISOString() };\n record.updatedAt = new Date().toISOString();\n this.save();\n return true;\n }\n\n /**\n * 释放持久化处理锁。仅当 correlationId 匹配时才清除,防止旧协程误释放新锁。\n */\n releaseProcessingLock(issueIid: number, correlationId: string): void {\n const record = this.collection[this.key(issueIid)];\n if (!record?.processingLock) return;\n\n if (record.processingLock.correlationId !== correlationId) {\n logger.warn('Processing lock correlationId mismatch, skipping release', {\n issueIid,\n ownCorrelationId: correlationId,\n actualCorrelationId: record.processingLock.correlationId,\n });\n return;\n }\n\n record.processingLock = undefined;\n record.updatedAt = new Date().toISOString();\n this.save();\n }\n\n /** 强制清除持久化处理锁(管理员操作:restart/cancel/retryFromPhase) */\n clearProcessingLock(issueIid: number): void {\n const record = this.collection[this.key(issueIid)];\n if (!record?.processingLock) return;\n record.processingLock = undefined;\n record.updatedAt = new Date().toISOString();\n this.save();\n }\n\n isProcessing(issueIid: number): boolean {\n const record = this.get(issueIid);\n if (!record) return false;\n return !this.lifecycleFor(record).isTerminal(record.state);\n }\n\n isCompleted(issueIid: number): boolean {\n const record = this.get(issueIid);\n return record?.state === IssueState.Completed;\n }\n\n canRetry(issueIid: number, maxRetries: number): boolean {\n const record = this.get(issueIid);\n if (!record || record.state !== IssueState.Failed) return false;\n return record.attempts < maxRetries;\n }\n\n getRetryState(issueIid: number): IssueState | undefined {\n const record = this.get(issueIid);\n return record?.failedAtState;\n }\n\n isStalled(issueIid: number, thresholdMs: number = 5 * 60 * 1000): boolean {\n const record = this.get(issueIid);\n if (!record) return false;\n if (this.lifecycleFor(record).isBlocked(record.state)) return false;\n if (!this.isProcessing(issueIid)) return false;\n const elapsed = Date.now() - new Date(record.updatedAt).getTime();\n return elapsed > thresholdMs;\n }\n\n getDrivableIssues(maxRetries: number, stalledThresholdMs?: number): IssueRecord[] {\n return this.getAllRecords().filter((record) => {\n const lm = this.lifecycleFor(record);\n const drivable = lm.isDrivable(record.state, record.attempts, maxRetries, record.lastErrorRetryable)\n || this.isStalled(getIid(record), stalledThresholdMs);\n if (!drivable) return false;\n\n // 持久化锁检查:有未超时的锁则跳过(正在被某协程处理)\n if (record.processingLock) {\n const age = Date.now() - new Date(record.processingLock.ts).getTime();\n if (age < IssueTracker.LOCK_TIMEOUT_MS) {\n return false;\n }\n // 超时锁不拦截 — 交由 acquireProcessingLock 覆盖\n }\n\n return true;\n });\n }\n\n getAllActive(): IssueRecord[] {\n return this.getAllRecords().filter(\n (r) => !this.lifecycleFor(r).isTerminal(r.state),\n );\n }\n\n getAll(): IssueRecord[] {\n return this.getAllRecords();\n }\n\n startSkipped(issueIid: number): boolean {\n const record = this.collection[this.key(issueIid)];\n if (!record || record.state !== IssueState.Skipped) return false;\n record.state = IssueState.Pending;\n record.updatedAt = new Date().toISOString();\n this.save();\n logger.info('Skipped issue started', { issueIid });\n eventBus.emitTyped('issue:stateChanged', { issueIid, state: IssueState.Pending, record });\n return true;\n }\n\n resetFull(issueIid: number): boolean {\n const record = this.collection[this.key(issueIid)];\n if (!record) return false;\n record.state = IssueState.Pending;\n record.currentPhase = undefined;\n record.attempts = 0;\n record.failedAtState = undefined;\n record.lastError = undefined;\n record.phaseProgress = undefined;\n record.processingLock = undefined;\n record.updatedAt = new Date().toISOString();\n this.save();\n logger.info('Issue fully reset', { issueIid });\n eventBus.emitTyped('issue:restarted', { issueIid, record });\n return true;\n }\n\n resetToPhase(issueIid: number, phase: string, def: PipelineDef): boolean {\n const record = this.collection[this.key(issueIid)];\n if (!record) return false;\n // Always create a fresh lifecycle manager from the provided def.\n // The cached lifecycleManagers may be stale (e.g., missing dynamically added phases like 'uat').\n const lm = new ActionLifecycleManager(def);\n const targetState = lm.getPhasePreState(phase);\n if (!targetState) return false;\n record.state = targetState;\n // When resetting to a generic phase state, also set currentPhase\n if (targetState === IssueState.PhaseRunning || targetState === IssueState.PhaseDone\n || targetState === IssueState.PhaseWaiting || targetState === IssueState.PhaseApproved) {\n // The phase we're resetting to is the one *before* the given phase (its preState).\n // But since preState is BranchCreated for idx 0 or prev phase's doneState,\n // we need to find the actual phase name that this preState corresponds to.\n // For PhaseDone preState, the currentPhase should be the prev phase name.\n const phases = def.phases;\n const idx = phases.findIndex(p => p.name === phase);\n if (idx > 0) {\n record.currentPhase = phases[idx - 1].name;\n }\n }\n record.failedAtState = undefined;\n record.lastError = undefined;\n record.processingLock = undefined;\n // 重置目标阶段及后续阶段的 phaseProgress\n if (record.phaseProgress) {\n const phaseIdx = def.phases.findIndex(p => p.name === phase);\n if (phaseIdx >= 0) {\n for (let i = phaseIdx; i < def.phases.length; i++) {\n const pp = record.phaseProgress[def.phases[i].name];\n if (pp) {\n pp.status = 'pending';\n pp.startedAt = undefined;\n pp.completedAt = undefined;\n pp.error = undefined;\n }\n }\n }\n }\n record.updatedAt = new Date().toISOString();\n this.save();\n logger.info('Issue reset to phase', { issueIid, phase, state: targetState });\n eventBus.emitTyped('issue:retryFromPhase', { issueIid, phase, record });\n return true;\n }\n\n resetForRetry(issueIid: number): boolean {\n const record = this.collection[this.key(issueIid)];\n if (!record || record.state !== IssueState.Failed) return false;\n\n const restoreState = record.failedAtState ?? IssueState.Pending;\n record.state = restoreState;\n record.lastError = undefined;\n record.processingLock = undefined;\n // 重置 failed 阶段的 phaseProgress\n if (record.phaseProgress && record.currentPhase) {\n const pp = record.phaseProgress[record.currentPhase];\n if (pp && pp.status === 'failed') {\n pp.status = 'pending';\n pp.startedAt = undefined;\n pp.completedAt = undefined;\n pp.error = undefined;\n }\n }\n record.updatedAt = new Date().toISOString();\n this.save();\n logger.info('Issue reset for retry', { issueIid, restoreState });\n eventBus.emitTyped('issue:resetForRetry', { issueIid, restoreState, record });\n return true;\n }\n\n delete(issueIid: number): boolean {\n const key = this.key(issueIid);\n const record = this.collection[key];\n if (!record) return false;\n delete this.collection[key];\n this.save();\n logger.info('Issue deleted from tracker', { issueIid });\n eventBus.emitTyped('issue:deleted', { issueIid, record });\n return true;\n }\n\n recoverInterruptedIssues(): number {\n let count = 0;\n for (const record of this.getAllRecords()) {\n const lm = this.lifecycleFor(record);\n if (lm.isInProgress(record.state)) {\n const iid = getIid(record);\n logger.warn('Recovering interrupted issue', {\n issueIid: iid,\n state: record.state,\n });\n record.failedAtState = record.state;\n record.state = IssueState.Failed;\n record.lastError = 'Interrupted by service restart';\n record.lastErrorRetryable = false;\n record.attempts += 1;\n record.processingLock = undefined;\n record.updatedAt = new Date().toISOString();\n count++;\n eventBus.emitTyped('issue:failed', {\n issueIid: iid,\n error: 'Interrupted by service restart',\n failedAtState: record.failedAtState,\n record,\n });\n } else if (record.state === IssueState.Failed && record.lastErrorRetryable !== false) {\n // Prevent auto-retry of pre-existing failures after restart;\n // user must manually trigger retry via UI or webhook.\n const iid = getIid(record);\n logger.info('Marking pre-existing failed issue as non-retryable after restart', {\n issueIid: iid,\n currentPhase: record.currentPhase,\n attempts: record.attempts,\n });\n record.lastErrorRetryable = false;\n record.processingLock = undefined;\n record.updatedAt = new Date().toISOString();\n count++;\n }\n }\n if (count > 0) {\n this.save();\n logger.info('Recovered interrupted issues', { count });\n }\n return count;\n }\n\n /** 将所有 IssueRecord 投影为 ExecutableTask[] */\n toExecutableTasks(): ExecutableTask[] {\n return this.getAllRecords().map((record) => {\n const lm = this.lifecycleFor(record);\n return issueToExecutableTask(record, lm);\n });\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { ProgressData, PhaseProgress, type PhaseStatus } from '../tracker/IssueState.js';\nimport type { PipelineDef } from '../pipeline/PipelineDefinition.js';\nimport { logger as rootLogger } from '../logger.js';\n\nconst logger = rootLogger.child('PlanPersistence');\n\nconst PLAN_DIR = '.claude-plan';\n\nexport interface ReviewRound {\n round: number;\n feedback: string;\n timestamp: string;\n}\n\nexport class PlanPersistence {\n private workDir: string;\n private issueIid: number;\n\n constructor(workDir: string, issueIid: number) {\n this.workDir = workDir;\n this.issueIid = issueIid;\n }\n\n get baseDir(): string {\n return this.workDir;\n }\n\n get planDir(): string {\n return path.join(this.workDir, PLAN_DIR, `issue-${this.issueIid}`);\n }\n\n ensureDir(): void {\n if (!fs.existsSync(this.planDir)) {\n fs.mkdirSync(this.planDir, { recursive: true });\n }\n }\n\n writeIssueMeta(meta: { id: number; iid: number; title: string; labels: string[]; state: string }): void {\n this.ensureDir();\n const filePath = path.join(this.planDir, 'issue-meta.json');\n fs.writeFileSync(filePath, JSON.stringify(meta, null, 2), 'utf-8');\n logger.info('Issue meta written');\n }\n\n writeProgress(data: ProgressData): void {\n this.ensureDir();\n const filePath = path.join(this.planDir, 'progress.json');\n fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');\n logger.debug('Progress written', { currentPhase: data.currentPhase });\n }\n\n readProgress(): ProgressData | null {\n const filePath = path.join(this.planDir, 'progress.json');\n if (!fs.existsSync(filePath)) return null;\n try {\n return JSON.parse(fs.readFileSync(filePath, 'utf-8'));\n } catch {\n return null;\n }\n }\n\n writeAnalysis(content: string): void {\n this.ensureDir();\n fs.writeFileSync(path.join(this.planDir, '01-analysis.md'), content, 'utf-8');\n logger.info('Analysis document written');\n }\n\n writeDesign(content: string): void {\n this.ensureDir();\n fs.writeFileSync(path.join(this.planDir, '02-design.md'), content, 'utf-8');\n logger.info('Design document written');\n }\n\n writeTodolist(content: string): void {\n this.ensureDir();\n fs.writeFileSync(path.join(this.planDir, '03-todolist.md'), content, 'utf-8');\n logger.info('Todolist written');\n }\n\n writeVerifyReport(content: string, filename = '04-verify-report.md'): void {\n this.ensureDir();\n fs.writeFileSync(path.join(this.planDir, filename), content, 'utf-8');\n logger.info('Verify report written', { filename });\n }\n\n getAllPlanFiles(): string[] {\n if (!fs.existsSync(this.planDir)) return [];\n return fs.readdirSync(this.planDir).map((f) => path.join(PLAN_DIR, `issue-${this.issueIid}`, f));\n }\n\n createInitialProgress(displayId: number, title: string, branchName: string, def?: PipelineDef): ProgressData {\n const pending: PhaseProgress = { status: 'pending' };\n if (def) {\n const phases: Record<string, PhaseProgress> = {};\n for (const spec of def.phases) {\n phases[spec.name] = { ...pending };\n }\n return {\n displayId,\n title,\n branchName,\n pipelineMode: def.mode,\n currentPhase: def.phases[0].name,\n phases,\n };\n }\n return {\n displayId,\n title,\n branchName,\n currentPhase: 'analysis',\n phases: {\n analysis: { ...pending },\n design: { ...pending },\n implement: { ...pending },\n verify: { ...pending },\n },\n };\n }\n\n writePlan(content: string): void {\n this.ensureDir();\n fs.writeFileSync(path.join(this.planDir, '01-plan.md'), content, 'utf-8');\n logger.info('Plan document written');\n }\n\n writeReviewFeedback(content: string): void {\n this.ensureDir();\n const history = this.readReviewHistory();\n const round: ReviewRound = {\n round: history.length + 1,\n feedback: content,\n timestamp: new Date().toISOString(),\n };\n history.push(round);\n fs.writeFileSync(\n path.join(this.planDir, 'review-history.json'),\n JSON.stringify(history, null, 2),\n 'utf-8',\n );\n fs.writeFileSync(\n path.join(this.planDir, 'review-feedback.md'),\n PlanPersistence.renderReviewHistoryMarkdown(history),\n 'utf-8',\n );\n logger.info('Review feedback appended', { round: round.round });\n }\n\n readReviewFeedback(): string | null {\n const filePath = path.join(this.planDir, 'review-feedback.md');\n if (!fs.existsSync(filePath)) return null;\n try {\n return fs.readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n }\n\n readReviewHistory(): ReviewRound[] {\n const filePath = path.join(this.planDir, 'review-history.json');\n if (!fs.existsSync(filePath)) return [];\n try {\n const data = JSON.parse(fs.readFileSync(filePath, 'utf-8'));\n return Array.isArray(data) ? data : [];\n } catch {\n return [];\n }\n }\n\n static renderReviewHistoryMarkdown(history: ReviewRound[]): string {\n if (history.length === 0) return '';\n const lines = ['# 审核反馈历史', ''];\n for (const r of history) {\n lines.push(`## 第 ${r.round} 轮审核反馈`);\n lines.push(`> 时间: ${r.timestamp}`);\n lines.push('');\n lines.push(r.feedback);\n lines.push('');\n }\n return lines.join('\\n');\n }\n\n updatePhaseProgress(\n phaseName: string,\n status: PhaseStatus,\n error?: string,\n options?: { preserveSessionId?: boolean },\n ): void {\n const progress = this.readProgress();\n if (!progress) {\n logger.warn('Cannot update phase progress: progress.json not found', {\n issueIid: this.issueIid, phase: phaseName, targetStatus: status,\n });\n return;\n }\n\n const now = new Date().toISOString();\n if (!progress.phases[phaseName]) {\n progress.phases[phaseName] = { status: 'pending' };\n }\n const phase = progress.phases[phaseName];\n\n phase.status = status;\n if (status === 'in_progress') {\n phase.startedAt = now;\n progress.currentPhase = phaseName;\n if (!options?.preserveSessionId) {\n delete phase.sessionId;\n }\n } else if (status === 'completed') {\n phase.completedAt = now;\n } else if (status === 'failed') {\n phase.error = error;\n }\n\n this.writeProgress(progress);\n }\n\n updatePhaseSessionId(phaseName: string, sessionId: string): void {\n const progress = this.readProgress();\n if (!progress?.phases[phaseName]) return;\n progress.phases[phaseName].sessionId = sessionId;\n this.writeProgress(progress);\n }\n\n getPhaseSessionId(phaseName: string): string | undefined {\n const progress = this.readProgress();\n return progress?.phases[phaseName]?.sessionId;\n }\n\n // ---------------------------------------------------------------------------\n // 通用文件操作 — 替代阶段中散落的 fs 直接调用\n // ---------------------------------------------------------------------------\n\n /** 读取 planDir 下指定文件,不存在返回 null */\n readFile(filename: string): string | null {\n const filePath = path.join(this.planDir, filename);\n if (!fs.existsSync(filePath)) return null;\n try {\n return fs.readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n }\n\n /** 检查 planDir 下指定文件是否就绪(存在 + 大于 minBytes) */\n isArtifactReady(filename: string, minBytes = 50): boolean {\n const filePath = path.join(this.planDir, filename);\n if (!fs.existsSync(filePath)) return false;\n try {\n return fs.statSync(filePath).size >= minBytes;\n } catch {\n return false;\n }\n }\n\n /** 写入 planDir 下指定文件(自动 ensureDir) */\n writeFile(filename: string, content: string): void {\n this.ensureDir();\n fs.writeFileSync(path.join(this.planDir, filename), content, 'utf-8');\n }\n\n /**\n * Copy a plan file from an external source (e.g. ~/.claude/plans/) into planDir.\n * Returns the destination path, or null if the source is empty/unreadable.\n */\n copyPlanFromExternal(sourcePath: string, targetFilename = '01-plan.md'): string | null {\n try {\n const content = fs.readFileSync(sourcePath, 'utf-8');\n if (content.trim().length === 0) {\n logger.warn('External plan file is empty', { sourcePath });\n return null;\n }\n this.ensureDir();\n const destPath = path.join(this.planDir, targetFilename);\n fs.writeFileSync(destPath, content, 'utf-8');\n logger.info('Plan copied from external source', {\n source: sourcePath,\n dest: destPath,\n size: content.length,\n });\n return destPath;\n } catch (err) {\n logger.error('Failed to copy plan from external source', { sourcePath, err });\n return null;\n }\n }\n}\n","import path from 'node:path';\nimport type { AIRunner, RunResult, InputRequest, StreamEvent } from '../ai-runner/index.js';\nimport { GitOperations } from '../git/GitOperations.js';\nimport { PlanPersistence } from '../persistence/PlanPersistence.js';\nimport { AIExecutionError } from '../errors/index.js';\nimport { RuleResolver } from '../rules/index.js';\nimport { getProjectKnowledge } from '../knowledge/index.js';\nimport { HookInjector } from '../hooks/index.js';\nimport { Config } from '../config.js';\nimport { buildWorkspaceSection } from '../prompts/templates.js';\nimport type { PortPair } from '../deploy/PortAllocator.js';\nimport type { DemandSpec } from '../demand/DemandSpec.js';\nimport type { WorkspaceLayout } from '../prompts/templates.js';\nimport type { PhaseOutcome, PhaseCallbacks } from './PhaseOutcome.js';\nimport { logger as rootLogger, Logger } from '../logger.js';\nimport { t } from '../i18n/index.js';\n\n/** verify-fix loop 的修复上下文 — 当验证失败回退到 build 阶段时注入 */\nexport interface FixContext {\n /** 当前修复迭代轮次(1-based) */\n iteration: number;\n /** 上一轮验证中未通过的检查项描述 */\n verifyFailures: string[];\n /** 上一轮验证报告原文(截断) */\n rawReport: string;\n}\n\nexport interface PhaseContext {\n demand: DemandSpec;\n branchName: string;\n pipelineMode?: string;\n ports?: PortPair;\n fixContext?: FixContext;\n workspace?: WorkspaceLayout;\n}\n\nexport abstract class BasePhase {\n static readonly MIN_ARTIFACT_BYTES = 50;\n\n protected aiRunner: AIRunner;\n protected git: GitOperations;\n protected plan: PlanPersistence;\n protected config: Config;\n protected logger: Logger;\n /** 多仓模式下所有 repo 的 GitOperations(repo name → GitOperations) */\n protected wtGitMap?: Map<string, GitOperations>;\n\n abstract readonly phaseName: string;\n\n constructor(\n aiRunner: AIRunner,\n git: GitOperations,\n plan: PlanPersistence,\n config: Config,\n ) {\n this.aiRunner = aiRunner;\n this.git = git;\n this.plan = plan;\n this.config = config;\n this.logger = rootLogger.child(this.constructor.name);\n }\n\n /** 注入多仓库 GitOperations map(由编排器在创建 phase 后调用) */\n setWtGitMap(map: Map<string, GitOperations>): void {\n this.wtGitMap = map;\n }\n\n protected abstract buildPrompt(ctx: PhaseContext): string;\n\n protected getRunMode(): 'plan' | 'agent' | undefined {\n return undefined;\n }\n\n /** 获取阶段预期的产物文件列表。编排器需通过此方法同步产物到 Issue。 */\n getResultFiles(_ctx?: PhaseContext): Array<{ filename: string; label: string }> {\n return [];\n }\n\n /**\n * 纯逻辑执行 — 零副作用,返回 PhaseOutcome。\n *\n * 阶段内部仅做:构建 prompt → AI 执行 → 验证产物 → 返回结果。\n * 所有副作用(状态转换、Git commit、Issue 评论、事件推送)由编排器统一处理。\n */\n async run(ctx: PhaseContext, callbacks?: PhaseCallbacks): Promise<PhaseOutcome> {\n const displayId = Number(ctx.demand.sourceRef.displayId);\n const expectedResultFiles = this.getResultFiles(ctx);\n\n // 1. 构建完整 prompt\n let prompt = this.buildPrompt(ctx);\n const wsSection = buildWorkspaceSection(ctx.workspace);\n if (wsSection) prompt += `\\n\\n${wsSection}`;\n const rules = await this.resolveRules(ctx);\n if (rules) prompt += `\\n\\n${t('basePhase.rulesSection', { rules })}`;\n\n // 2. AI 执行(含 session resume fallback)\n const resumeInfo = this.resolveResumeInfo();\n let result: RunResult;\n\n if (resumeInfo.resumable) {\n this.logger.info('Attempting session resume', {\n issueIid: displayId,\n phase: this.phaseName,\n sessionId: resumeInfo.sessionId,\n });\n result = await this.runWithResumeFallback(\n displayId, resumeInfo.sessionId!, t('basePhase.resumePrompt'),\n prompt, callbacks?.onInputRequired, ctx, callbacks?.onStreamEvent,\n );\n } else {\n result = await this.runAI(\n displayId, prompt, callbacks?.onInputRequired,\n undefined, ctx, callbacks?.onStreamEvent,\n );\n }\n\n // 3. 失败 → 返回 failed outcome(不抛异常)\n if (!result.success) {\n this.persistSessionId(result.sessionId);\n return {\n status: 'failed',\n output: result.output,\n sessionId: result.sessionId,\n exitCode: result.exitCode,\n error: {\n message: (result.errorMessage || result.output).slice(0, 500),\n isRetryable: this.classifyRetryable(result),\n rawOutput: result.output,\n wasActiveAtTimeout: result.wasActiveAtTimeout,\n },\n };\n }\n\n this.persistSessionId(result.sessionId);\n\n // 4. 验证产物\n try {\n await this.validatePhaseOutput(ctx, displayId, expectedResultFiles);\n } catch (err) {\n return {\n status: 'failed',\n output: result.output,\n sessionId: result.sessionId,\n error: { message: (err as Error).message, isRetryable: false, rawOutput: result.output },\n };\n }\n\n // 5. 返回 completed(零副作用)\n return {\n status: 'completed',\n output: result.output,\n sessionId: result.sessionId,\n exitCode: result.exitCode,\n };\n }\n\n // ── Session resume helpers ──\n\n protected resolveResumeInfo(): { resumable: boolean; sessionId?: string } {\n if (this.isAcpMode()) {\n return { resumable: false };\n }\n const previousSessionId = this.plan.getPhaseSessionId(this.phaseName);\n if (!previousSessionId) {\n return { resumable: false };\n }\n const progress = this.plan.readProgress();\n const phaseStatus = progress?.phases[this.phaseName]?.status;\n if (phaseStatus !== 'failed' && phaseStatus !== 'in_progress') {\n return { resumable: false };\n }\n return { resumable: true, sessionId: previousSessionId };\n }\n\n private isAcpMode(): boolean {\n return this.config.ai.mode === 'codebuddy-acp';\n }\n\n protected resolveAIWorkDir(ctx?: PhaseContext): string {\n if (ctx?.workspace && ctx.workspace.repos.length > 1) {\n return ctx.workspace.workspaceRoot;\n }\n return this.plan.baseDir;\n }\n\n /** 检查预期产物文件是否已就绪(存在且满足最小字节数),不抛异常 */\n private checkArtifactsReady(ctx: PhaseContext | undefined, _displayId: number): boolean {\n const resultFiles = this.getResultFiles(ctx);\n if (resultFiles.length === 0) return true;\n\n for (const file of resultFiles) {\n if (!this.plan.isArtifactReady(file.filename, BasePhase.MIN_ARTIFACT_BYTES)) return false;\n }\n return true;\n }\n\n protected async runAI(\n displayId: number,\n prompt: string,\n onInputRequired?: (request: InputRequest) => Promise<string>,\n options?: { sessionId?: string; continueSession?: boolean },\n ctx?: PhaseContext,\n onStreamEvent?: (event: StreamEvent) => void,\n ): Promise<RunResult> {\n // Capture file list once — getResultFiles() may return different results\n // after the AI writes files (e.g. ReleasePhase switches from detect→exec mode).\n const resultFiles = this.getResultFiles(ctx);\n const snapshotFilenames = resultFiles.map(f => f.filename);\n const artifactCheck = snapshotFilenames.length > 0\n ? () => snapshotFilenames.every(fn => this.plan.isArtifactReady(fn, BasePhase.MIN_ARTIFACT_BYTES))\n : undefined;\n const artifactPaths = snapshotFilenames.length > 0\n ? snapshotFilenames.map(fn => path.join(this.plan.planDir, fn))\n : undefined;\n\n let capturedSessionId: string | undefined;\n const result = await this.aiRunner.run({\n prompt,\n workDir: this.resolveAIWorkDir(ctx),\n timeoutMs: this.config.ai.phaseTimeoutMs,\n idleTimeoutMs: this.config.ai.idleTimeoutMs,\n timeoutGraceMs: this.config.ai.timeoutGraceMs,\n timeoutExtensionMs: this.config.ai.timeoutExtensionMs,\n timeoutMaxExtensions: this.config.ai.timeoutMaxExtensions,\n mode: this.getRunMode(),\n phaseName: this.phaseName,\n artifactCheck,\n artifactPaths,\n sessionId: options?.sessionId,\n continueSession: options?.continueSession,\n onStreamEvent: (event) => {\n if (!capturedSessionId && event.type !== 'raw') {\n const content = event.content as Record<string, unknown>;\n if (content?.session_id && typeof content.session_id === 'string') {\n capturedSessionId = content.session_id;\n this.persistSessionId(capturedSessionId);\n }\n }\n onStreamEvent?.(event);\n },\n onInputRequired,\n });\n if (result.sessionId) {\n this.persistSessionId(result.sessionId);\n }\n return result;\n }\n\n protected async runWithResumeFallback(\n displayId: number,\n sessionId: string,\n resumePrompt: string,\n fullPrompt: string,\n onInputRequired?: (request: InputRequest) => Promise<string>,\n ctx?: PhaseContext,\n onStreamEvent?: (event: StreamEvent) => void,\n ): Promise<RunResult> {\n const result = await this.runAI(displayId, resumePrompt, onInputRequired, {\n sessionId,\n continueSession: true,\n }, ctx, onStreamEvent);\n\n if (!result.success && this.isResumeFailure(result)) {\n this.logger.warn(t('basePhase.resumeFallback'), {\n issueIid: displayId,\n phase: this.phaseName,\n exitCode: result.exitCode,\n });\n onStreamEvent?.({\n type: 'system',\n content: t('basePhase.resumeFallback'),\n timestamp: new Date().toISOString(),\n });\n return this.runAI(displayId, fullPrompt, onInputRequired, undefined, ctx, onStreamEvent);\n }\n\n return result;\n }\n\n /**\n * 判断 AI 执行失败是否为永久性错误(不可重试)。\n * 模型不存在、API key 无效等配置问题重试不会成功。\n */\n protected classifyRetryable(result: RunResult): boolean {\n const msg = (result.errorMessage ?? result.output ?? '').toLowerCase();\n const permanentPatterns = [\n /model\\b.*\\b(?:not found|not supported|unavailable|service info not found)/,\n /invalid.?api.?key/,\n /authentication.*(?:failed|denied|error)/,\n /permission.?denied/,\n /billing/,\n /quota.*exceeded/,\n ];\n return !permanentPatterns.some(p => p.test(msg));\n }\n\n /**\n * Heuristic: a resume failure is typically an immediate process exit\n * (exit code != 0, empty output) caused by an invalid/expired session ID.\n */\n private isResumeFailure(result: RunResult): boolean {\n if (result.success) return false;\n const msg = (result.errorMessage ?? '').toLowerCase();\n\n // Specific session-related patterns\n if (msg.includes('session') || msg.includes('resume') || msg.includes('session_id')) {\n return true;\n }\n\n // Empty output + non-zero exit: likely immediate crash from broken session ID,\n // but NOT if the error looks like a model/config problem.\n if (result.output.length === 0 && result.exitCode !== null && result.exitCode !== 0) {\n const isConfigError = msg.includes('model') || msg.includes('api key') || msg.includes('authentication');\n return !isConfigError;\n }\n\n return false;\n }\n\n protected persistSessionId(sessionId: string | undefined): void {\n if (sessionId) {\n this.plan.updatePhaseSessionId(this.phaseName, sessionId);\n }\n }\n\n protected async resolveRules(ctx: PhaseContext): Promise<string | null> {\n try {\n const knowledge = getProjectKnowledge();\n const resolver = new RuleResolver(knowledge?.ruleTriggers);\n const context = `${ctx.demand.title} ${ctx.demand.description} ${ctx.demand.supplement ? JSON.stringify(ctx.demand.supplement) : ''}`;\n\n // Load rules from all repos in workspace mode\n if (ctx.workspace && ctx.workspace.repos.length > 1) {\n for (const repo of ctx.workspace.repos) {\n const rulesDir = path.join(repo.gitRootDir, '.cursor', 'rules');\n try {\n await resolver.loadRules(rulesDir);\n } catch {\n // Some repos may not have rules\n }\n }\n } else {\n const rulesDir = path.join(this.plan.baseDir, '.cursor', 'rules');\n await resolver.loadRules(rulesDir);\n }\n\n const matched = resolver.matchRules(context);\n if (matched.length > 0) {\n this.logger.info(`Matched ${matched.length} MDC rules`, {\n rules: matched.map(r => r.filename),\n });\n return resolver.formatForPrompt(matched);\n }\n } catch (err) {\n this.logger.warn('Failed to resolve MDC rules', { error: (err as Error).message });\n }\n return null;\n }\n\n protected async validatePhaseOutput(\n ctx: PhaseContext,\n _displayId: number,\n resultFiles = this.getResultFiles(ctx),\n ): Promise<void> {\n if (resultFiles.length === 0) return;\n\n const missing: string[] = [];\n\n for (const file of resultFiles) {\n if (!this.plan.isArtifactReady(file.filename, BasePhase.MIN_ARTIFACT_BYTES)) {\n const content = this.plan.readFile(file.filename);\n if (content === null) {\n missing.push(file.filename);\n } else {\n missing.push(`${file.filename} (${Buffer.byteLength(content, 'utf-8')} bytes, 内容不足)`);\n }\n }\n }\n\n if (missing.length > 0) {\n const msg = `AI 进程成功退出但未生成预期产物: ${missing.join(', ')}`;\n this.logger.error(msg, { phase: this.phaseName, displayId: _displayId });\n throw new AIExecutionError(this.phaseName, msg, { output: '', exitCode: 0 });\n }\n\n this.logHookManifest();\n }\n\n /** 读取 hook manifest 并记录产物写入历史(P1 增强层,不影响主流程) */\n private logHookManifest(): void {\n try {\n const injector = new HookInjector();\n const entries = injector.readManifest(this.plan.baseDir);\n if (entries.length === 0) return;\n\n const artifactWrites = entries.filter(e => 'file' in e && e.event === 'write');\n if (artifactWrites.length > 0) {\n this.logger.info('Hook manifest: artifact writes recorded', {\n phase: this.phaseName,\n writes: artifactWrites.length,\n files: artifactWrites.map(e => ('file' in e ? e.file : 'unknown')),\n });\n }\n } catch {\n // Hook manifest is best-effort; never block phase validation\n }\n }\n}\n","import { readdir, readFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport type { RuleTriggerConfig } from '../knowledge/ProjectKnowledge.js';\n\nexport interface MdcRule {\n filename: string;\n description: string;\n alwaysApply: boolean;\n content: string;\n}\n\nfunction parseFrontmatter(raw: string): { description: string; alwaysApply: boolean; content: string } {\n const fmRegex = /^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n/;\n const match = raw.match(fmRegex);\n if (!match) {\n return { description: '', alwaysApply: false, content: raw.trim() };\n }\n\n const yamlBlock = match[1];\n const content = raw.slice(match[0].length).trim();\n\n let description = '';\n const descMatch = yamlBlock.match(/description:\\s*(.+)/);\n if (descMatch) {\n description = descMatch[1].trim();\n }\n\n let alwaysApply = false;\n const applyMatch = yamlBlock.match(/alwaysApply:\\s*(true|false)/i);\n if (applyMatch) {\n alwaysApply = applyMatch[1].toLowerCase() === 'true';\n }\n\n return { description, alwaysApply, content };\n}\n\nexport class RuleResolver {\n private rules: MdcRule[] = [];\n private triggers: RuleTriggerConfig[] | undefined;\n\n constructor(ruleTriggers?: RuleTriggerConfig[]) {\n this.triggers = ruleTriggers;\n }\n\n public async loadRules(rulesDir: string): Promise<void> {\n this.rules = [];\n let files: string[];\n try {\n files = await readdir(rulesDir);\n } catch {\n return;\n }\n\n const mdcFiles = files.filter(f => f.endsWith('.mdc'));\n\n const loadPromises = mdcFiles.map(async (filename) => {\n try {\n const raw = await readFile(path.join(rulesDir, filename), 'utf-8');\n const { description, alwaysApply, content } = parseFrontmatter(raw);\n if (content) {\n this.rules.push({ filename, description, alwaysApply, content });\n }\n } catch {\n // skip unreadable files\n }\n });\n\n await Promise.all(loadPromises);\n }\n\n public getRules(): MdcRule[] {\n return this.rules;\n }\n\n public matchRules(text: string): MdcRule[] {\n const lowerText = text.toLowerCase();\n const matched = new Map<string, MdcRule>();\n\n // Always include alwaysApply rules\n for (const rule of this.rules) {\n if (rule.alwaysApply) {\n matched.set(rule.filename, rule);\n }\n }\n\n if (this.triggers && this.triggers.length > 0) {\n // Use configured triggers for keyword matching\n for (const trigger of this.triggers) {\n if (matched.has(trigger.filename)) continue;\n const isTriggered = trigger.keywords.some(kw => lowerText.includes(kw.toLowerCase()));\n if (!isTriggered) continue;\n\n const rule = this.rules.find(r => r.filename === trigger.filename);\n if (rule) {\n matched.set(rule.filename, rule);\n }\n }\n } else {\n // Fallback: match based on frontmatter description words\n for (const rule of this.rules) {\n if (matched.has(rule.filename)) continue;\n if (!rule.description) continue;\n\n const descWords = rule.description\n .split(/[\\s,,;;、/|]+/)\n .filter(w => w.length >= 2);\n const isMatched = descWords.some(word => lowerText.includes(word.toLowerCase()));\n if (isMatched) {\n matched.set(rule.filename, rule);\n }\n }\n }\n\n return Array.from(matched.values());\n }\n\n public formatForPrompt(rules: MdcRule[]): string {\n if (rules.length === 0) return '';\n\n return rules.map(rule => {\n const header = rule.description\n ? `### ${rule.description} (${rule.filename})`\n : `### ${rule.filename}`;\n return `${header}\\n\\n${rule.content}`;\n }).join('\\n\\n---\\n\\n');\n }\n}\n","/**\n * 解析验证阶段生成的报告,提取通过/失败状态和失败原因。\n *\n * 解析逻辑基于验证 prompt 要求 AI 输出的结构化格式,\n * 同时兼容中英文和多种常见写法。\n */\n\nexport interface TodolistStats {\n completed: number;\n total: number;\n}\n\nexport interface VerifyReportResult {\n /** 综合判定:所有检查项均通过 */\n passed: boolean;\n lintPassed: boolean;\n buildPassed: boolean;\n testPassed: boolean;\n todolistComplete: boolean;\n todolistStats?: TodolistStats;\n /** 未通过的检查项及其原因 */\n failureReasons: string[];\n /** 原始报告内容 */\n rawReport: string;\n}\n\n// -- 匹配模式 --\n\n// \"Lint 结果: 失败\" / \"**Lint 结果**: 失败\" / \"Lint Result: Failed\"\nconst LINT_FAIL_RE = /\\*{0,2}Lint\\s*(?:结果|Result)\\*{0,2}\\s*[::]\\s*(?:失败|failed|fail|未通过)/i;\nconst BUILD_FAIL_RE = /\\*{0,2}Build\\s*(?:结果|Result)\\*{0,2}\\s*[::]\\s*(?:失败|failed|fail|未通过)/i;\nconst TEST_FAIL_RE = /\\*{0,2}Test\\s*(?:结果|Result)\\*{0,2}\\s*[::]\\s*(?:失败|failed|fail|未通过)/i;\n\n// \"总结: 验证失败\" / \"**总结**: 验证失败\" / \"Summary: Verification Failed\"\nconst SUMMARY_FAIL_RE = /\\*{0,2}(?:总结|Summary)\\*{0,2}\\s*[::].*(?:验证失败|verification\\s+failed|failed|失败)/i;\n\n// \"Todolist 检查: 3/5 项完成\" 或 \"**Todolist 检查**: 3/5\" 或 \"Todolist: 3/5\"\nconst TODOLIST_STATS_RE = /\\*{0,2}(?:Todolist|Todo)\\s*(?:检查|check)?\\*{0,2}\\s*[::]\\s*(\\d+)\\s*[//]\\s*(\\d+)/i;\n\nexport class VerifyReportParser {\n /**\n * 解析验证报告内容。\n *\n * @param reportContent 验证报告的完整 Markdown 文本\n */\n parse(reportContent: string): VerifyReportResult {\n const lintPassed = !LINT_FAIL_RE.test(reportContent);\n const buildPassed = !BUILD_FAIL_RE.test(reportContent);\n const testPassed = !TEST_FAIL_RE.test(reportContent);\n\n const todolistStats = this.parseTodolistStats(reportContent);\n const todolistComplete = todolistStats\n ? todolistStats.total === 0 || todolistStats.completed === todolistStats.total\n : true; // 无统计数据时默认视为完成(不误判)\n\n const failureReasons: string[] = [];\n if (!lintPassed) failureReasons.push('Lint 检查失败');\n if (!buildPassed) failureReasons.push('Build 编译失败');\n if (!testPassed) failureReasons.push('测试未通过');\n if (!todolistComplete) {\n const statsText = todolistStats\n ? `(${todolistStats.completed}/${todolistStats.total})`\n : '';\n failureReasons.push(`Todolist 未全部完成${statsText}`);\n }\n\n // 如果上面各项都看似通过,但总结中明确写了\"验证失败\",依然判为失败\n const summaryFailed = SUMMARY_FAIL_RE.test(reportContent);\n if (failureReasons.length === 0 && summaryFailed) {\n failureReasons.push('验证报告总结判定为失败');\n }\n\n const passed = failureReasons.length === 0;\n\n return {\n passed,\n lintPassed,\n buildPassed,\n testPassed,\n todolistComplete,\n todolistStats: todolistStats ?? undefined,\n failureReasons,\n rawReport: reportContent,\n };\n }\n\n /**\n * 从 plan 文件中解析 Todolist 完成度。\n * 统计 `- [x]` (已完成) 和 `- [ ]` (未完成) 的数量。\n */\n parseTodolistFromPlan(planContent: string): TodolistStats {\n const completedRe = /^[ \\t]*-\\s+\\[x\\]/gim;\n const uncompletedRe = /^[ \\t]*-\\s+\\[\\s\\]/gm;\n\n const completedMatches = planContent.match(completedRe);\n const uncompletedMatches = planContent.match(uncompletedRe);\n\n const completed = completedMatches?.length ?? 0;\n const uncompleted = uncompletedMatches?.length ?? 0;\n\n return {\n completed,\n total: completed + uncompleted,\n };\n }\n\n /**\n * 从报告中提取 Todolist 统计数据。\n * 格式: \"Todolist 检查: X/Y 项完成\"\n */\n private parseTodolistStats(reportContent: string): TodolistStats | null {\n const match = reportContent.match(TODOLIST_STATS_RE);\n if (match) {\n return {\n completed: parseInt(match[1], 10),\n total: parseInt(match[2], 10),\n };\n }\n return null;\n }\n}\n","import { BasePhase, PhaseContext } from './BasePhase.js';\nimport { verifyPrompt, planModeVerifyPrompt, demandToPromptContext } from '../prompts/templates.js';\nimport { VerifyReportParser } from '../verify/index.js';\nimport type { VerifyReportResult } from '../verify/index.js';\nimport type { PhaseOutcome, PhaseCallbacks } from './PhaseOutcome.js';\n\nexport interface VerifyRunResult {\n verifyReport?: VerifyReportResult;\n}\n\nexport class VerifyPhase extends BasePhase {\n readonly phaseName = 'verify' as const;\n private readonly reportParser = new VerifyReportParser();\n\n getResultFiles(ctx?: PhaseContext) {\n const filename = ctx?.pipelineMode === 'plan-mode' ? '02-verify-report.md' : '04-verify-report.md';\n return [{ filename, label: '验证报告' }];\n }\n\n async run(ctx: PhaseContext, callbacks?: PhaseCallbacks): Promise<PhaseOutcome> {\n const outcome = await super.run(ctx, callbacks);\n if (outcome.status !== 'completed') return outcome;\n\n // AI 进程成功退出后,读取并解析验证报告\n const report = this.readVerifyReport(ctx);\n if (report) {\n const parsed = this.reportParser.parse(report);\n\n // 如果启用了 todolist 检查,从 plan 文件补充统计\n if (this.config.verifyFixLoop.todolistCheckEnabled && !parsed.todolistStats) {\n const planContent = this.readPlanFile();\n if (planContent) {\n const todoStats = this.reportParser.parseTodolistFromPlan(planContent);\n if (todoStats.total > 0) {\n parsed.todolistStats = todoStats;\n parsed.todolistComplete = todoStats.completed === todoStats.total;\n if (!parsed.todolistComplete) {\n parsed.failureReasons.push(\n `Todolist 未全部完成(${todoStats.completed}/${todoStats.total})`,\n );\n parsed.passed = false;\n }\n }\n }\n }\n\n this.logger.info('Verify report parsed', {\n passed: parsed.passed,\n lintPassed: parsed.lintPassed,\n buildPassed: parsed.buildPassed,\n testPassed: parsed.testPassed,\n todolistComplete: parsed.todolistComplete,\n todolistStats: parsed.todolistStats,\n failureCount: parsed.failureReasons.length,\n });\n\n return { ...outcome, data: { ...outcome.data, verifyReport: parsed } };\n }\n\n return outcome;\n }\n\n protected buildPrompt(ctx: PhaseContext): string {\n const pc = demandToPromptContext(ctx.demand);\n const promptCtx = {\n issueTitle: pc.title,\n issueDescription: pc.description,\n issueIid: Number(pc.displayId),\n workspace: ctx.workspace,\n };\n return ctx.pipelineMode === 'plan-mode'\n ? planModeVerifyPrompt(promptCtx)\n : verifyPrompt(promptCtx);\n }\n\n private readVerifyReport(ctx: PhaseContext): string | null {\n const files = this.getResultFiles(ctx);\n if (files.length === 0) return null;\n return this.plan.readFile(files[0].filename);\n }\n\n private readPlanFile(): string | null {\n return this.plan.readFile('01-plan.md');\n }\n}\n","import { BasePhase, PhaseContext } from './BasePhase.js';\nimport { planPrompt, rePlanPrompt, demandToPromptContext } from '../prompts/templates.js';\nimport { getRunnerCapabilities, usesDeterministicPlanCopy } from '../ai-runner/index.js';\nimport { t } from '../i18n/index.js';\n\nexport class PlanPhase extends BasePhase {\n readonly phaseName = 'plan' as const;\n\n getResultFiles() {\n return [{ filename: '01-plan.md', label: '实施计划' }];\n }\n\n protected getRunMode(): 'plan' | 'agent' | undefined {\n return 'plan';\n }\n\n protected buildPrompt(ctx: PhaseContext): string {\n const pc = demandToPromptContext(ctx.demand);\n const history = this.plan.readReviewHistory();\n const detCopy = usesDeterministicPlanCopy(this.config.ai.mode);\n const promptCtx = {\n issueTitle: pc.title,\n issueDescription: pc.description,\n issueIid: Number(pc.displayId),\n supplementText: pc.supplementText || undefined,\n workspace: ctx.workspace,\n };\n\n let basePrompt: string;\n if (history.length > 0) {\n basePrompt = rePlanPrompt(promptCtx, history, detCopy);\n } else {\n basePrompt = planPrompt(promptCtx, detCopy);\n }\n\n const caps = getRunnerCapabilities(this.config.ai.mode);\n if (!caps?.nativePlanMode) {\n const preambleKey = detCopy ? 'prompt.planModeNative' : 'prompt.planModeFallback';\n basePrompt = `${t(preambleKey)}\\n\\n${basePrompt}`;\n }\n\n return basePrompt;\n }\n}\n","import { BasePhase, PhaseContext } from './BasePhase.js';\nimport { buildPrompt, demandToPromptContext } from '../prompts/templates.js';\nimport { AIExecutionError } from '../errors/index.js';\nimport { t } from '../i18n/index.js';\n\nexport class BuildPhase extends BasePhase {\n readonly phaseName = 'build' as const;\n\n protected async validatePhaseOutput(ctx: PhaseContext, _displayId: number): Promise<void> {\n let hasAnyChanges = false;\n\n if (ctx.workspace && ctx.workspace.repos.length > 1) {\n for (const repo of ctx.workspace.repos) {\n const repoGit = this.wtGitMap?.get(repo.name);\n if (!repoGit) {\n this.logger.warn('Missing GitOperations for repo in validation', { repo: repo.name });\n continue;\n }\n if (await repoGit.hasChanges()) {\n hasAnyChanges = true;\n break;\n }\n }\n } else {\n hasAnyChanges = await this.git.hasChanges();\n }\n\n if (!hasAnyChanges) {\n const msg = 'AI 进程成功退出但未产生任何代码变更';\n this.logger.error(msg, { phase: this.phaseName });\n throw new AIExecutionError(this.phaseName, msg, { output: '', exitCode: 0 });\n }\n }\n\n protected buildPrompt(ctx: PhaseContext): string {\n const pc = demandToPromptContext(ctx.demand);\n const base = buildPrompt({\n issueTitle: pc.title,\n issueDescription: pc.description,\n issueIid: Number(pc.displayId),\n workspace: ctx.workspace,\n });\n\n if (ctx.fixContext) {\n return base + t('prompt.buildFixSuffix', {\n iteration: ctx.fixContext.iteration,\n failures: ctx.fixContext.verifyFailures.map((f, i) => `${i + 1}. ${f}`).join('\\n'),\n rawReport: ctx.fixContext.rawReport.slice(0, 2000),\n });\n }\n\n return base;\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { createHash } from 'node:crypto';\nimport { logger as rootLogger } from '../logger.js';\n\nconst logger = rootLogger.child('ReleaseDetectCache');\n\n/**\n * AI 探索目标项目后输出的发布检测结果。\n */\nexport interface ReleaseDetectResult {\n /** 目标项目路径(用于校验缓存归属) */\n projectPath: string;\n /** 检测时间 ISO 字符串 */\n detectedAt: string;\n /** 是否具备发布能力 */\n hasReleaseCapability: boolean;\n /** 发布方式 */\n releaseMethod?: string;\n /** 检测到的发布相关文件路径 */\n artifacts: string[];\n /** AI 提取的发布步骤说明 */\n instructions?: string;\n}\n\nfunction hashProjectPath(projectPath: string): string {\n return createHash('sha256').update(projectPath).digest('hex').slice(0, 16);\n}\n\n/**\n * 全局发布检测结果缓存。\n *\n * 位置:{dataDir}/release-detect/{hash}.json\n * 按 projectPath 隔离,支持 TTL 过期。\n */\nexport class ReleaseDetectCache {\n private readonly cacheDir: string;\n\n constructor(dataDir: string) {\n this.cacheDir = path.join(dataDir, 'release-detect');\n }\n\n private filePath(projectPath: string): string {\n return path.join(this.cacheDir, `${hashProjectPath(projectPath)}.json`);\n }\n\n /**\n * 读取缓存。返回 null 如果不存在、已过期或校验失败。\n */\n get(projectPath: string, ttlMs: number): ReleaseDetectResult | null {\n const fp = this.filePath(projectPath);\n try {\n if (!fs.existsSync(fp)) return null;\n const raw = fs.readFileSync(fp, 'utf-8');\n const data: ReleaseDetectResult = JSON.parse(raw);\n\n // 校验 projectPath 一致\n if (data.projectPath !== projectPath) {\n logger.warn('Cache projectPath mismatch, ignoring', { expected: projectPath, got: data.projectPath });\n return null;\n }\n\n // 检查 TTL\n const age = Date.now() - new Date(data.detectedAt).getTime();\n if (age > ttlMs) {\n logger.debug('Cache expired', { projectPath, ageMs: age, ttlMs });\n return null;\n }\n\n return data;\n } catch (err) {\n logger.warn('Failed to read release detect cache', { path: fp, error: (err as Error).message });\n return null;\n }\n }\n\n /**\n * 写入缓存。\n */\n set(result: ReleaseDetectResult): void {\n const fp = this.filePath(result.projectPath);\n try {\n if (!fs.existsSync(this.cacheDir)) {\n fs.mkdirSync(this.cacheDir, { recursive: true });\n }\n fs.writeFileSync(fp, JSON.stringify(result, null, 2), 'utf-8');\n logger.debug('Release detect cache written', { projectPath: result.projectPath, path: fp });\n } catch (err) {\n logger.warn('Failed to write release detect cache', { path: fp, error: (err as Error).message });\n }\n }\n\n /**\n * 手动失效缓存。\n */\n invalidate(projectPath: string): boolean {\n const fp = this.filePath(projectPath);\n try {\n if (fs.existsSync(fp)) {\n fs.unlinkSync(fp);\n logger.info('Release detect cache invalidated', { projectPath });\n return true;\n }\n return false;\n } catch (err) {\n logger.warn('Failed to invalidate release detect cache', { path: fp, error: (err as Error).message });\n return false;\n }\n }\n}\n","import type { PromptContext } from './templates.js';\nimport type { ReleaseDetectResult } from '../release/index.js';\n\n/**\n * 发布检测 prompt — 指导 AI 探索目标项目的发布机制。\n */\nexport function releaseDetectPrompt(ctx: PromptContext): string {\n const pd = `.claude-plan/issue-${ctx.issueIid}`;\n\n return `你是一个专业的 DevOps 分析师。你的任务是探索当前项目,判断是否存在 **AI 可以在本地直接执行的发布流程**。\n\n## 关键判定原则\n\n\\`hasReleaseCapability\\` 仅在以下情况为 \\`true\\`:\n- 存在 **AI 可以在当前工作目录直接运行** 的发布命令或脚本\n- 例如:\\`npm publish\\`、\\`make release\\`、\\`scripts/release.sh\\`、带明确步骤的 Skill 文件\n\n以下情况必须设为 \\`false\\`:\n- **仅有 Dockerfile** — Docker 镜像由外部 CI/CD 系统(蓝盾/Landun/Jenkins/GitHub Actions)构建和推送,AI 无法替代\n- **仅有外部 CI/CD 配置** — \\`.gitlab-ci.yml\\` 等定义了流水线,但需要 CI 环境执行,AI 无法触发\n- **项目是 private 包且不发布到 registry** — \\`package.json\\` 中 \\`\"private\": true\\` 且无 publish 脚本\n- **发布相关代码属于业务域** — 项目本身是部署平台/编排系统,其代码是为其他服务编排发布,不是本项目的发布流程\n- **仅有构建脚本无发布步骤** — \\`build.sh\\` 等只构建产物但不实际发布\n\n## 探索范围\n\n请按优先级依次检查:\n\n1. **Skill / Rule 文件**(最高优先级)\n - \\`.cursor/skills/\\` 下与 release/deploy/publish 相关的 skill\n - \\`.cursor/rules/\\` 下与 release/deploy 相关的 \\`.mdc\\` 规则\n - ⚠️ 注意区分:为项目自身发布的 skill vs 为业务域(如\"添加制品类型\")的 skill\n\n2. **Package Manager 发布**\n - \\`package.json\\` 的 \\`scripts\\` 中是否有 \\`publish\\`、\\`release\\` 命令\n - \\`package.json\\` 是否为 \\`\"private\": true\\`(私有包通常不发布)\n\n3. **发布脚本**\n - \\`scripts/release.*\\`、\\`scripts/deploy.*\\`、\\`scripts/publish.*\\`\n - \\`Makefile\\` 中的 release/deploy target\n\n4. **CI/CD 配置**(仅记录,通常不算 AI 可执行)\n - \\`.gitlab-ci.yml\\` / \\`Jenkinsfile\\` / \\`.github/workflows/\\`\n\n5. **容器化**(仅记录,通常不算 AI 可执行)\n - \\`Dockerfile\\`、\\`docker-compose*.yml\\`\n\n## 输出要求\n\n将检测结果以 **严格 JSON** 格式写入 \\`${pd}/05-release-detect.json\\`:\n\n\\`\\`\\`json\n{\n \"hasReleaseCapability\": false,\n \"releaseMethod\": \"ci-pipeline\",\n \"artifacts\": [\"Dockerfile\", \".gitlab-ci.yml\"],\n \"instructions\": \"项目通过外部 CI/CD 流水线构建 Docker 镜像并部署,AI 无法直接执行发布。\"\n}\n\\`\\`\\`\n\n字段说明:\n- \\`hasReleaseCapability\\`: **AI 是否能直接执行发布**(boolean)— 仅当有可在本地运行的发布命令时为 true\n- \\`releaseMethod\\`: 发布方式描述:\"npm-publish\" | \"ci-pipeline\" | \"makefile\" | \"custom-script\" | \"skill\" | \"docker\" | 其他\n- \\`artifacts\\`: 发现的发布相关文件路径数组(无论 capability 是否为 true 都列出)\n- \\`instructions\\`: 发布步骤说明。capability 为 false 时说明原因\n\n**重要**:\n- 大多数项目依赖外部 CI/CD,\\`hasReleaseCapability\\` 应为 \\`false\\`\n- 如果找到了 skill 或 rule 文件,请在 \\`instructions\\` 中完整保留原文内容\n- 只输出 JSON 文件,不要执行任何发布操作`;\n}\n\n/**\n * 发布执行 prompt — 基于检测结果执行发布。\n */\nexport function releaseExecPrompt(ctx: PromptContext, detectResult: ReleaseDetectResult): string {\n const pd = `.claude-plan/issue-${ctx.issueIid}`;\n\n const artifactList = detectResult.artifacts.length > 0\n ? detectResult.artifacts.map(a => `- \\`${a}\\``).join('\\n')\n : '(无)';\n\n const instructionSection = detectResult.instructions\n ? `\\n## 发布指引(来自项目 skill/rule/文档)\\n\\n${detectResult.instructions}`\n : '';\n\n return `你是一个专业的发布工程师。请根据以下检测结果,执行项目的发布流程。\n\n## 检测结果\n\n- **发布方式**: ${detectResult.releaseMethod ?? '未知'}\n- **相关文件**:\n${artifactList}\n${instructionSection}\n\n## 任务\n\n1. 阅读上述发布指引和相关文件\n2. 按照项目定义的发布流程执行发布操作\n3. 将发布结果写入 \\`${pd}/06-release-report.md\\`\n\n## 发布报告格式\n\n\\`\\`\\`markdown\n# 发布报告\n\n## 发布方式\n<使用的发布方式>\n\n## 执行步骤\n<逐步记录执行的操作>\n\n## 结果\n<成功/失败及详情>\n\\`\\`\\`\n\n**重要**:\n- 严格按照项目自身的发布流程操作\n- 如有任何错误或异常,记录在报告中\n- 不要跳过任何发布前的检查步骤`;\n}\n","import type { PhaseContext } from './BasePhase.js';\nimport { BasePhase } from './BasePhase.js';\nimport type { PhaseOutcome, PhaseCallbacks } from './PhaseOutcome.js';\nimport { ReleaseDetectCache, type ReleaseDetectResult } from '../release/index.js';\nimport { releaseDetectPrompt, releaseExecPrompt } from '../prompts/release-templates.js';\nimport { demandToPromptContext } from '../prompts/templates.js';\nimport { resolveDataDir } from '../paths.js';\n\nconst DETECT_FILENAME = '05-release-detect.json';\nconst REPORT_FILENAME = '06-release-report.md';\n\n/**\n * 发布阶段 — 异步委托模型。\n *\n * 模式判定:plan 目录中是否已存在 05-release-detect.json。\n * - 无 → 检测:先查全局缓存,未命中则 AI 检测\n * - 有 → 执行:AI 读取检测结果执行发布\n *\n * 返回 `data.hasReleaseCapability`,编排器据此决定是否暂停等待审批。\n */\nexport class ReleasePhase extends BasePhase {\n readonly phaseName = 'release' as const;\n\n /**\n * 检测结果是否已存在(即是否处于执行模式)。\n */\n private hasDetectionResult(): boolean {\n return this.plan.readFile(DETECT_FILENAME) !== null;\n }\n\n private readDetectionFile(): ReleaseDetectResult | null {\n const raw = this.plan.readFile(DETECT_FILENAME);\n if (raw === null) return null;\n try {\n return JSON.parse(raw);\n } catch {\n return null;\n }\n }\n\n private writeDetectionFile(result: ReleaseDetectResult): void {\n this.plan.writeFile(DETECT_FILENAME, JSON.stringify(result, null, 2));\n }\n\n getResultFiles(_ctx?: PhaseContext): Array<{ filename: string; label: string }> {\n if (this.hasDetectionResult()) {\n return [{ filename: REPORT_FILENAME, label: '发布报告' }];\n }\n return [{ filename: DETECT_FILENAME, label: '发布检测报告' }];\n }\n\n protected buildPrompt(ctx: PhaseContext): string {\n const dc = demandToPromptContext(ctx.demand);\n const pc = {\n issueTitle: dc.title,\n issueDescription: dc.description,\n issueIid: Number(dc.displayId),\n supplementText: dc.supplementText || undefined,\n workspace: ctx.workspace,\n };\n if (this.hasDetectionResult()) {\n const detect = this.readDetectionFile()!;\n return releaseExecPrompt(pc, detect);\n }\n return releaseDetectPrompt(pc);\n }\n\n async run(ctx: PhaseContext, callbacks?: PhaseCallbacks): Promise<PhaseOutcome> {\n const needsDetection = !this.hasDetectionResult();\n\n // ── 检测阶段:先查缓存 ──\n if (needsDetection) {\n const cache = new ReleaseDetectCache(resolveDataDir());\n const projectPath = this.config.gongfeng.projectPath;\n const ttlMs = this.config.release.detectCacheTtlMs;\n const cached = cache.get(projectPath, ttlMs);\n\n if (cached) {\n this.logger.info('Using cached release detection result', {\n projectPath,\n hasCapability: cached.hasReleaseCapability,\n method: cached.releaseMethod,\n });\n\n // 缓存命中 → 写入 plan 目录,直接 completed\n this.writeDetectionFile(cached);\n\n return {\n status: 'completed',\n output: `Release detection cached: ${cached.hasReleaseCapability ? cached.releaseMethod ?? 'found' : 'no capability'}`,\n data: { hasReleaseCapability: cached.hasReleaseCapability },\n };\n }\n }\n\n // ── AI 执行(检测或发布) ──\n const outcome = await super.run(ctx, callbacks);\n if (outcome.status !== 'completed') return outcome;\n\n // ── 检测模式后处理:缓存结果并返回能力标记 ──\n if (needsDetection) {\n const detected = this.readDetectionFile();\n if (detected) {\n // 写入全局缓存\n const cache = new ReleaseDetectCache(resolveDataDir());\n const projectPath = this.config.gongfeng.projectPath;\n cache.set({\n ...detected,\n projectPath,\n detectedAt: new Date().toISOString(),\n });\n\n this.logger.info('Release detection completed', {\n hasCapability: detected.hasReleaseCapability,\n method: detected.releaseMethod,\n artifacts: detected.artifacts,\n });\n\n return {\n ...outcome,\n data: { ...outcome.data, hasReleaseCapability: detected.hasReleaseCapability },\n };\n }\n\n // 未产出检测文件 → 视为无发布能力\n return { ...outcome, data: { ...outcome.data, hasReleaseCapability: false } };\n }\n\n return outcome;\n }\n}\n","import { BasePhase, type PhaseContext } from './BasePhase.js';\nimport type { PhaseOutcome, PhaseCallbacks } from './PhaseOutcome.js';\nimport { e2eVerifyPromptSuffix, demandToPromptContext } from '../prompts/templates.js';\nimport { getLocalIP } from '../utils/network.js';\n\nfunction getDefaultHost(): string {\n return getLocalIP();\n}\n\n/**\n * UAT/E2E 验证阶段 — 异步委托模型。\n *\n * 模式判定:plan 目录中是否已存在 03-uat-report.md。\n * - 有 → completed:验证产物并直接完成\n * - 无 → running:启动异步 AI,返回 awaitCompletion Promise\n */\nexport class UatPhase extends BasePhase {\n readonly phaseName = 'uat' as const;\n\n getResultFiles(_ctx?: PhaseContext) {\n return [{ filename: '03-uat-report.md', label: 'UAT 报告' }];\n }\n\n /**\n * 检查产物是否已存在且内容足够。\n */\n private hasArtifact(_displayId: number): boolean {\n return this.plan.isArtifactReady('03-uat-report.md', BasePhase.MIN_ARTIFACT_BYTES);\n }\n\n async run(ctx: PhaseContext, callbacks?: PhaseCallbacks): Promise<PhaseOutcome> {\n const displayId = Number(ctx.demand.sourceRef.displayId);\n\n // 产物已就绪(gate 批准后重入)→ 验证后直接 completed\n if (this.hasArtifact(displayId)) {\n this.logger.info('UAT artifact found, completing phase', { iid: displayId });\n try {\n await this.validatePhaseOutput(ctx, displayId);\n } catch (err) {\n return {\n status: 'failed',\n output: '',\n error: { message: (err as Error).message, isRetryable: false },\n };\n }\n return { status: 'completed', output: 'UAT report validated' };\n }\n\n // 产物未就绪 → 启动异步 AI,返回 running\n return this.launchAsync(ctx, displayId, callbacks);\n }\n\n private async launchAsync(\n ctx: PhaseContext,\n displayId: number,\n callbacks?: PhaseCallbacks,\n ): Promise<PhaseOutcome> {\n this.logger.info('Launching async UAT', { iid: displayId });\n\n const prompt = this.buildPrompt(ctx);\n\n // Fire-and-forget: 启动 AI 但不 await\n const runPromise = this.aiRunner.run({\n prompt,\n workDir: this.resolveAIWorkDir(ctx),\n timeoutMs: this.config.ai.phaseTimeoutMs,\n idleTimeoutMs: this.config.ai.idleTimeoutMs,\n onStreamEvent: callbacks?.onStreamEvent,\n });\n\n // awaitCompletion:编排器可 await 此 Promise 获取最终结果\n const awaitCompletion = runPromise\n .then(async (result): Promise<PhaseOutcome> => {\n if (result.success && this.hasArtifact(displayId)) {\n return {\n status: 'completed',\n output: result.output,\n sessionId: result.sessionId,\n };\n }\n const reason = result.errorMessage || 'UAT failed or artifact 03-uat-report.md missing';\n return {\n status: 'failed',\n output: result.output,\n error: { message: reason, isRetryable: false },\n };\n })\n .catch(async (err: Error): Promise<PhaseOutcome> => ({\n status: 'failed',\n output: '',\n error: { message: err.message, isRetryable: false },\n }));\n\n return {\n status: 'running',\n output: 'UAT launched asynchronously',\n awaitCompletion,\n };\n }\n\n protected buildPrompt(ctx: PhaseContext): string {\n const pc = demandToPromptContext(ctx.demand);\n const promptCtx = {\n issueTitle: pc.title,\n issueDescription: pc.description,\n issueIid: Number(pc.displayId),\n workspace: ctx.workspace,\n };\n\n const hasUatTool = !!this.config.e2e.uatVendorDir;\n\n const e2ePorts = ctx.ports\n ? {\n backendPort: ctx.ports.backendPort,\n frontendPort: ctx.ports.frontendPort,\n host: this.config.preview.host || getDefaultHost(),\n }\n : undefined;\n\n const uatTool = hasUatTool\n ? { vendorDir: this.config.e2e.uatVendorDir!, configFile: this.config.e2e.uatConfigFile }\n : undefined;\n\n const e2eSuffix = e2eVerifyPromptSuffix(promptCtx, e2ePorts, uatTool);\n\n return `# UAT/E2E 验证阶段\n\n## 任务背景\n- Issue: #${promptCtx.issueIid} ${promptCtx.issueTitle}\n- 本阶段专注于 E2E/UAT 端对端验证,lint/build/test 检查已在上一验证阶段完成。\n\n## 产物要求\n请将 E2E 验证结果写入 \\`.claude-plan/issue-${promptCtx.issueIid}/03-uat-report.md\\`,包含:\n- 测试场景清单\n- 执行结果(通过/失败)\n- 截图路径(如有)\n- 失败原因分析(如有失败)\n\n${e2eSuffix}`;\n }\n}\n","import type { AIRunner } from '../ai-runner/index.js';\nimport { GitOperations } from '../git/GitOperations.js';\nimport { PlanPersistence } from '../persistence/PlanPersistence.js';\nimport { Config } from '../config.js';\nimport { PhaseNotRegisteredError, UnregisteredPhasesError } from '../errors/index.js';\nimport { BasePhase } from './BasePhase.js';\nimport { VerifyPhase } from './VerifyPhase.js';\nimport { PlanPhase } from './PlanPhase.js';\nimport { BuildPhase } from './BuildPhase.js';\nimport { ReleasePhase } from './ReleasePhase.js';\nimport { UatPhase } from './UatPhase.js';\n\ntype PhaseArgs = [AIRunner, GitOperations, PlanPersistence, Config];\nexport type PhaseConstructor = new (...args: PhaseArgs) => BasePhase;\n\n// ---------------------------------------------------------------------------\n// Phase Registry\n// ---------------------------------------------------------------------------\n\nconst PHASE_REGISTRY = new Map<string, PhaseConstructor>();\n\n/** 注册一个阶段构造器。重复注册同一 name 会覆盖。 */\nexport function registerPhase(name: string, ctor: PhaseConstructor): void {\n PHASE_REGISTRY.set(name, ctor);\n}\n\n/** 用于测试隔离:重置注册表并重新注册内置阶段 */\nexport function _resetPhaseRegistry(): void {\n PHASE_REGISTRY.clear();\n registerBuiltinPhases();\n}\n\n// ---------------------------------------------------------------------------\n// Self-register built-in phases\n// ---------------------------------------------------------------------------\n\nfunction registerBuiltinPhases(): void {\n PHASE_REGISTRY.set('plan', PlanPhase);\n PHASE_REGISTRY.set('build', BuildPhase);\n PHASE_REGISTRY.set('verify', VerifyPhase);\n PHASE_REGISTRY.set('uat', UatPhase);\n PHASE_REGISTRY.set('release', ReleasePhase);\n}\n\nregisterBuiltinPhases();\n\n// ---------------------------------------------------------------------------\n// Factory / validation\n// ---------------------------------------------------------------------------\n\nexport function createPhase(name: string, ...args: PhaseArgs): BasePhase {\n const Ctor = PHASE_REGISTRY.get(name);\n if (!Ctor) {\n throw new PhaseNotRegisteredError(name, [...PHASE_REGISTRY.keys()]);\n }\n return new Ctor(...args);\n}\n\n/** 校验 PipelineDef 中的所有 AI phase 都已注册,应在启动时调用 */\nexport function validatePhaseRegistry(phaseNames: string[]): void {\n const missing = phaseNames.filter(name => !PHASE_REGISTRY.has(name));\n if (missing.length > 0) {\n throw new UnregisteredPhasesError(missing, [...PHASE_REGISTRY.keys()]);\n }\n}\n","import { IssueState } from '../tracker/IssueState.js';\nimport { ActionLifecycleManager } from '../lifecycle/ActionLifecycleManager.js';\nimport { PipelineNotFoundError } from '../errors/index.js';\nimport { t } from '../i18n/index.js';\nimport { registerPhase, type PhaseConstructor } from '../phases/PhaseFactory.js';\n\nexport type PipelineMode = string;\nexport type KnownPipelineMode = 'plan-mode';\n\nexport interface PhaseSpec {\n name: string;\n label: string;\n startState: IssueState;\n doneState: IssueState;\n kind: 'ai' | 'gate';\n approvedState?: IssueState;\n /** 此阶段是否可被用户单独重试。默认:kind === 'ai' */\n retryable?: boolean;\n /** 此阶段完成后是否应启动预览服务器。默认:false */\n deploysPreview?: boolean;\n /** 此阶段产出的文件列表。默认:[] */\n artifacts?: PlanFileSpec[];\n}\n\nexport interface PlanFileSpec {\n filename: string;\n label: string;\n editable: boolean;\n}\n\nexport interface PipelineDef {\n mode: PipelineMode;\n phases: PhaseSpec[];\n}\n\n// ---------------------------------------------------------------------------\n// Pipeline Registry\n// ---------------------------------------------------------------------------\n\nconst pipelineRegistry = new Map<string, PipelineDef>();\n\n/**\n * 注册一条流水线定义。可选同时注册其阶段构造器。\n * 重复注册同一 mode 会覆盖。\n */\nexport function registerPipeline(\n def: PipelineDef,\n phases?: Record<string, PhaseConstructor>,\n): void {\n pipelineRegistry.set(def.mode, def);\n if (phases) {\n for (const [name, ctor] of Object.entries(phases)) {\n registerPhase(name, ctor);\n }\n }\n}\n\n/** 获取所有已注册的流水线模式名 */\nexport function getRegisteredModes(): string[] {\n return [...pipelineRegistry.keys()];\n}\n\n/** 获取所有已注册的 PipelineDef */\nexport function getAllPipelineDefs(): PipelineDef[] {\n return [...pipelineRegistry.values()];\n}\n\n/** 用于测试隔离:重置注册表并重新注册内置流水线 */\nexport function _resetPipelineRegistry(): void {\n pipelineRegistry.clear();\n pipelineRegistry.set(PLAN_MODE_PIPELINE.mode, PLAN_MODE_PIPELINE);\n}\n\n// ---------------------------------------------------------------------------\n// Built-in pipeline definitions\n// ---------------------------------------------------------------------------\n\nexport const PLAN_MODE_PIPELINE: PipelineDef = {\n mode: 'plan-mode',\n phases: [\n { name: 'plan', label: '规划', startState: IssueState.PhaseRunning,\n doneState: IssueState.PhaseDone, kind: 'ai',\n artifacts: [{ filename: '01-plan.md', label: '实施计划', editable: true }] },\n { name: 'review', label: '审核', startState: IssueState.PhaseWaiting,\n doneState: IssueState.PhaseApproved, approvedState: IssueState.PhaseApproved,\n kind: 'gate', retryable: false,\n artifacts: [\n { filename: 'review-feedback.md', label: '审核反馈', editable: false },\n { filename: 'review-history.json', label: '审核历史', editable: false },\n ] },\n { name: 'build', label: '实施', startState: IssueState.PhaseRunning,\n doneState: IssueState.PhaseDone, kind: 'ai', deploysPreview: true },\n { name: 'verify', label: '验证', startState: IssueState.PhaseRunning,\n doneState: IssueState.Completed, kind: 'ai',\n artifacts: [{ filename: '02-verify-report.md', label: '验证报告', editable: false }] },\n ],\n};\n\n// Self-register built-in pipelines\npipelineRegistry.set(PLAN_MODE_PIPELINE.mode, PLAN_MODE_PIPELINE);\n\n// ---------------------------------------------------------------------------\n// Dynamic pipeline builder\n// ---------------------------------------------------------------------------\n\n/**\n * 根据配置动态构建 plan-mode 流水线。\n * 当 releaseEnabled 为 true 时,在 verify 之后追加 release 阶段。\n */\nexport function buildPlanModePipeline(opts: { releaseEnabled: boolean; e2eEnabled: boolean }): PipelineDef {\n const phases = [...PLAN_MODE_PIPELINE.phases];\n\n if (opts.e2eEnabled) {\n // verify 的 doneState: Completed → PhaseDone(后续由 uat 接管 Completed)\n const vi = phases.findIndex(p => p.name === 'verify');\n if (vi >= 0) {\n phases[vi] = { ...phases[vi], doneState: IssueState.PhaseDone };\n }\n // 在 verify 后插入 uat 阶段(异步执行,带 gate 机制)\n phases.splice(vi + 1, 0, {\n name: 'uat', label: 'UAT验证', kind: 'ai',\n startState: IssueState.PhaseRunning,\n doneState: IssueState.Completed,\n approvedState: IssueState.PhaseApproved,\n retryable: true,\n artifacts: [\n { filename: '03-uat-report.md', label: 'UAT报告', editable: false },\n ],\n });\n }\n\n if (opts.releaseEnabled) {\n // 当前终态阶段 doneState: Completed → PhaseDone(release 接管 Completed)\n const termIdx = phases.findIndex(p => p.doneState === IssueState.Completed);\n if (termIdx >= 0) {\n phases[termIdx] = { ...phases[termIdx], doneState: IssueState.PhaseDone };\n }\n // 追加 release 阶段(AI 类型 + approvedState 赋予可选 gate 能力)\n phases.push({\n name: 'release', label: '发布', kind: 'ai',\n startState: IssueState.PhaseRunning,\n doneState: IssueState.Completed,\n approvedState: IssueState.PhaseApproved,\n retryable: true,\n artifacts: [\n { filename: '05-release-detect.json', label: '发布检测报告', editable: false },\n { filename: '06-release-report.md', label: '发布报告', editable: false },\n ],\n });\n }\n return { mode: 'plan-mode', phases };\n}\n\n// ---------------------------------------------------------------------------\n// Lookup functions\n// ---------------------------------------------------------------------------\n\nexport function resolvePipelineMode(aiMode: string, explicit?: string): PipelineMode {\n if (explicit && pipelineRegistry.has(explicit)) return explicit;\n return 'plan-mode';\n}\n\nexport function getPipelineDef(mode: PipelineMode): PipelineDef {\n const def = pipelineRegistry.get(mode);\n if (!def) {\n throw new PipelineNotFoundError(mode);\n }\n return def;\n}\n\n/**\n * 从 PipelineDef 创建 ActionLifecycleManager 实例。\n */\nexport function createLifecycleManager(def: PipelineDef): ActionLifecycleManager {\n return new ActionLifecycleManager(def);\n}\n\nexport function getPhaseLabel(phaseName: string): string {\n return t(`pipeline.phase.${phaseName}`);\n}\n\nexport function getPlanFileLabel(filename: string): string {\n return t(`planFile.${filename}`);\n}\n","import { z } from 'zod';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { logger as rootLogger } from '../logger.js';\n\nconst logger = rootLogger.child('WorkspaceConfig');\n\n// ---------------------------------------------------------------------------\n// Schema\n// ---------------------------------------------------------------------------\n\nexport const repoConfigSchema = z.object({\n name: z.string().min(1, 'Repo name is required'),\n projectPath: z.string().min(1, 'Gongfeng project path is required'),\n localGitRoot: z.string().min(1, 'Local git root is required'),\n projectSubDir: z.string().optional().default(''),\n baseBranch: z.string().optional(),\n branchPrefix: z.string().optional(),\n role: z.string().optional().default(''),\n});\n\nexport const workspaceConfigSchema = z.object({\n primary: repoConfigSchema,\n associates: z.array(repoConfigSchema).default([]),\n});\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type RepoConfig = z.infer<typeof repoConfigSchema>;\nexport type WorkspaceConfig = z.infer<typeof workspaceConfigSchema>;\n\n// ---------------------------------------------------------------------------\n// Loader\n// ---------------------------------------------------------------------------\n\n/**\n * Load workspace configuration from a JSON file.\n * Returns null if the path is not provided or the file does not exist.\n */\nexport function loadWorkspaceConfig(configPath?: string): WorkspaceConfig | null {\n if (!configPath) return null;\n\n if (!fs.existsSync(configPath)) {\n logger.warn('Workspace config file not found, falling back to single-repo mode', {\n path: configPath,\n });\n return null;\n }\n\n try {\n const raw = fs.readFileSync(configPath, 'utf-8');\n const json = JSON.parse(raw);\n const result = workspaceConfigSchema.safeParse(json);\n if (!result.success) {\n const issues = result.error.issues\n .map(i => ` - ${i.path.join('.')}: ${i.message}`)\n .join('\\n');\n logger.error(`Workspace config validation failed:\\n${issues}`);\n return null;\n }\n logger.info('Workspace config loaded', {\n primary: result.data.primary.name,\n associates: result.data.associates.map(a => a.name),\n });\n return result.data;\n } catch (err) {\n logger.error('Failed to parse workspace config', {\n path: configPath,\n error: (err as Error).message,\n });\n return null;\n }\n}\n\n/**\n * Build a WorkspaceConfig from the existing single-repo Config.project fields.\n * Used when no workspace.json is configured — preserves backward compatibility.\n */\nexport function buildSingleRepoWorkspace(project: {\n workDir: string;\n gitRootDir: string;\n projectSubDir: string;\n baseBranch: string;\n branchPrefix: string;\n}, gongfengProjectPath: string): WorkspaceConfig {\n return {\n primary: {\n name: 'primary',\n projectPath: gongfengProjectPath,\n localGitRoot: project.gitRootDir,\n projectSubDir: project.projectSubDir,\n baseBranch: project.baseBranch,\n branchPrefix: project.branchPrefix,\n role: '',\n },\n associates: [],\n };\n}\n\n/**\n * Get all repo configs (primary + associates) as a flat array.\n */\nexport function getAllRepos(ws: WorkspaceConfig): RepoConfig[] {\n return [ws.primary, ...ws.associates];\n}\n\n/**\n * Check if a workspace config has associated repositories.\n */\nexport function isMultiRepo(ws: WorkspaceConfig): boolean {\n return ws.associates.length > 0;\n}\n\n/**\n * Persist a WorkspaceConfig to disk. Used to auto-generate workspace.json\n * when upgrading from a single-repo .env setup.\n */\nexport function persistWorkspaceConfig(ws: WorkspaceConfig, filePath: string): void {\n try {\n const dir = path.dirname(filePath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n fs.writeFileSync(filePath, JSON.stringify(ws, null, 2) + '\\n', 'utf-8');\n logger.info('Workspace config auto-generated from .env', { path: filePath });\n } catch (err) {\n logger.warn('Failed to persist workspace config', {\n path: filePath,\n error: (err as Error).message,\n });\n }\n}\n","import path from 'node:path';\nimport fs from 'node:fs/promises';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { GitOperations } from '../git/GitOperations.js';\nimport type { WorkspaceConfig, RepoConfig } from './WorkspaceConfig.js';\nimport { isMultiRepo } from './WorkspaceConfig.js';\nimport type { AsyncMutex } from '../utils/AsyncMutex.js';\nimport { logger as rootLogger } from '../logger.js';\n\nconst execFileAsync = promisify(execFile);\nconst logger = rootLogger.child('WorkspaceManager');\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Per-repo runtime context within an issue workspace. */\nexport interface RepoContext {\n name: string;\n projectPath: string;\n role: string;\n /** Absolute path: the git root for this repo within the issue workspace. */\n gitRootDir: string;\n /** Absolute path: the project sub-directory (AI cwd when single-repo). */\n workDir: string;\n /** The repo's base branch. */\n baseBranch: string;\n /** Branch prefix for this repo (e.g. \"feat/issue\"). */\n branchPrefix: string;\n /** Whether this is the primary repository. */\n isPrimary: boolean;\n}\n\n/** Full workspace context for an issue — replaces the old single WorktreeContext. */\nexport interface WorkspaceContext {\n /** Issue IID this workspace belongs to. */\n issueIid: number;\n /** The branch name used across all repos. */\n branchName: string;\n /** Root directory of the workspace: WORKTREE_BASE_DIR/issue-{iid}/ */\n workspaceRoot: string;\n /** Primary repo context. */\n primary: RepoContext;\n /** Associate repo contexts (may be empty). */\n associates: RepoContext[];\n}\n\n// ---------------------------------------------------------------------------\n// WorkspaceManager\n// ---------------------------------------------------------------------------\n\nexport class WorkspaceManager {\n private wsConfig: WorkspaceConfig;\n private worktreeBaseDir: string;\n private mainGit: GitOperations;\n private mainGitMutex: AsyncMutex;\n private gongfengApiUrl: string;\n\n constructor(opts: {\n wsConfig: WorkspaceConfig;\n worktreeBaseDir: string;\n mainGit: GitOperations;\n mainGitMutex: AsyncMutex;\n gongfengApiUrl: string;\n }) {\n this.wsConfig = opts.wsConfig;\n this.worktreeBaseDir = opts.worktreeBaseDir;\n this.mainGit = opts.mainGit;\n this.mainGitMutex = opts.mainGitMutex;\n this.gongfengApiUrl = opts.gongfengApiUrl;\n }\n\n isMultiRepo(): boolean {\n return isMultiRepo(this.wsConfig);\n }\n\n getWorkspaceConfig(): WorkspaceConfig {\n return this.wsConfig;\n }\n\n // ── Workspace lifecycle ──\n\n /**\n * Prepare the full workspace for an issue:\n * - Create the workspace root directory.\n * - For the primary repo: create a git worktree.\n * - For each associate: clone (or reuse) and checkout the branch.\n */\n async prepareWorkspace(\n issueIid: number,\n branchName: string,\n globalBaseBranch: string,\n globalBranchPrefix: string,\n ): Promise<WorkspaceContext> {\n const wsRoot = this.getWorkspaceRoot(issueIid);\n await fs.mkdir(wsRoot, { recursive: true });\n\n const primaryCtx = await this.preparePrimaryRepo(\n issueIid, branchName, wsRoot, globalBaseBranch,\n );\n\n const associateCtxs: RepoContext[] = [];\n for (const assoc of this.wsConfig.associates) {\n const ctx = await this.prepareAssociateRepo(\n assoc, issueIid, branchName, wsRoot, globalBaseBranch, globalBranchPrefix,\n );\n associateCtxs.push(ctx);\n }\n\n logger.info('Workspace prepared', {\n issueIid,\n wsRoot,\n repos: [primaryCtx.name, ...associateCtxs.map(a => a.name)],\n });\n\n return {\n issueIid,\n branchName,\n workspaceRoot: wsRoot,\n primary: primaryCtx,\n associates: associateCtxs,\n };\n }\n\n /**\n * Commit and push changes across all repos that have modifications.\n */\n async commitAll(\n wsCtx: WorkspaceContext,\n message: string,\n ): Promise<{ reposCommitted: string[] }> {\n const committed: string[] = [];\n\n for (const repo of [wsCtx.primary, ...wsCtx.associates]) {\n const git = new GitOperations(repo.gitRootDir);\n if (await git.hasChanges()) {\n await git.add(['.']);\n await git.commit(message);\n await git.push(wsCtx.branchName);\n committed.push(repo.name);\n logger.info('Committed and pushed changes', {\n repo: repo.name,\n branch: wsCtx.branchName,\n });\n }\n }\n\n return { reposCommitted: committed };\n }\n\n /**\n * Clean up workspace: remove worktree for primary, remove clone dirs for associates.\n */\n async cleanupWorkspace(wsCtx: WorkspaceContext): Promise<void> {\n // Clean primary worktree\n try {\n await this.mainGit.worktreeRemove(wsCtx.primary.gitRootDir, true);\n logger.info('Primary worktree removed', { dir: wsCtx.primary.gitRootDir });\n } catch (err) {\n logger.warn('Failed to remove primary worktree', {\n dir: wsCtx.primary.gitRootDir,\n error: (err as Error).message,\n });\n }\n\n // Clean associate clone directories\n for (const assoc of wsCtx.associates) {\n try {\n await fs.rm(assoc.gitRootDir, { recursive: true, force: true });\n logger.info('Associate repo dir removed', { name: assoc.name, dir: assoc.gitRootDir });\n } catch (err) {\n logger.warn('Failed to remove associate repo dir', {\n name: assoc.name,\n dir: assoc.gitRootDir,\n error: (err as Error).message,\n });\n }\n }\n\n // Remove workspace root if empty\n try {\n const entries = await fs.readdir(wsCtx.workspaceRoot);\n if (entries.length === 0) {\n await fs.rmdir(wsCtx.workspaceRoot);\n }\n } catch { /* ignore */ }\n }\n\n /**\n * Get all repo contexts for an already-prepared workspace (reconstructed from config).\n */\n buildRepoContexts(issueIid: number, branchName: string, globalBaseBranch: string, globalBranchPrefix?: string): RepoContext[] {\n const wsRoot = this.getWorkspaceRoot(issueIid);\n const primary = this.wsConfig.primary;\n const defaultPrefix = globalBranchPrefix ?? primary.branchPrefix ?? 'feat/issue';\n const primaryDir = path.join(wsRoot, primary.name);\n const repos: RepoContext[] = [{\n name: primary.name,\n projectPath: primary.projectPath,\n role: primary.role ?? '',\n gitRootDir: primaryDir,\n workDir: path.join(primaryDir, primary.projectSubDir ?? ''),\n baseBranch: primary.baseBranch ?? globalBaseBranch,\n branchPrefix: primary.branchPrefix ?? defaultPrefix,\n isPrimary: true,\n }];\n\n for (const assoc of this.wsConfig.associates) {\n repos.push({\n name: assoc.name,\n projectPath: assoc.projectPath,\n role: assoc.role ?? '',\n gitRootDir: path.join(wsRoot, assoc.name),\n workDir: path.join(wsRoot, assoc.name, assoc.projectSubDir ?? ''),\n baseBranch: assoc.baseBranch ?? globalBaseBranch,\n branchPrefix: assoc.branchPrefix ?? defaultPrefix,\n isPrimary: false,\n });\n }\n\n return repos;\n }\n\n getWorkspaceRoot(issueIid: number): string {\n return path.join(this.worktreeBaseDir, `issue-${issueIid}`);\n }\n\n // ── Internal helpers ──\n\n private async preparePrimaryRepo(\n issueIid: number,\n branchName: string,\n wsRoot: string,\n globalBaseBranch: string,\n ): Promise<RepoContext> {\n const primary = this.wsConfig.primary;\n const repoDir = path.join(wsRoot, primary.name);\n const baseBranch = primary.baseBranch ?? globalBaseBranch;\n\n await this.ensurePrimaryWorktree(repoDir, branchName, baseBranch);\n\n return {\n name: primary.name,\n projectPath: primary.projectPath,\n role: primary.role ?? '',\n gitRootDir: repoDir,\n workDir: path.join(repoDir, primary.projectSubDir ?? ''),\n baseBranch,\n branchPrefix: primary.branchPrefix ?? 'feat/issue',\n isPrimary: true,\n };\n }\n\n private async ensurePrimaryWorktree(\n repoDir: string,\n branchName: string,\n baseBranch: string,\n ): Promise<void> {\n // Migrate legacy worktree: issue-{iid}/ -> issue-{iid}/primary/\n const wsRoot = path.dirname(repoDir);\n if (wsRoot !== repoDir) {\n try {\n await fs.access(path.join(wsRoot, '.git'));\n logger.info('Migrating legacy worktree to primary subdir', { from: wsRoot, to: repoDir });\n await this.mainGit.worktreeRemove(wsRoot, true);\n await this.mainGit.worktreePrune();\n await this.cleanStaleDir(wsRoot);\n } catch {\n // No legacy worktree at wsRoot — normal path\n }\n }\n\n const worktrees = await this.mainGit.worktreeList();\n\n if (worktrees.includes(repoDir)) {\n try {\n await fs.access(path.join(repoDir, '.git'));\n logger.info('Reusing existing primary worktree', { dir: repoDir });\n return;\n } catch {\n logger.warn('Primary worktree registered but .git missing, recreating', { dir: repoDir });\n await this.mainGit.worktreeRemove(repoDir, true);\n await this.mainGit.worktreePrune();\n }\n }\n\n await this.cleanStaleDir(repoDir);\n\n const localExists = await this.mainGit.branchExists(branchName);\n if (localExists) {\n await this.mainGit.worktreeAddExisting(repoDir, branchName);\n return;\n }\n\n const remoteExists = await this.mainGit.remoteBranchExists(branchName);\n if (remoteExists) {\n await this.mainGit.worktreeAddTracking(repoDir, branchName);\n return;\n }\n\n await this.mainGit.worktreeAdd(repoDir, branchName, `origin/${baseBranch}`);\n }\n\n private async prepareAssociateRepo(\n assoc: RepoConfig,\n _issueIid: number,\n branchName: string,\n wsRoot: string,\n globalBaseBranch: string,\n globalBranchPrefix: string,\n ): Promise<RepoContext> {\n const repoDir = path.join(wsRoot, assoc.name);\n const baseBranch = assoc.baseBranch ?? globalBaseBranch;\n const cloneUrl = `${this.gongfengApiUrl}/${assoc.projectPath}.git`;\n\n // Clone or reuse\n const gitDirExists = await this.dirExists(path.join(repoDir, '.git'));\n if (!gitDirExists) {\n await this.cleanStaleDir(repoDir);\n logger.info('Cloning associate repo', { name: assoc.name, url: cloneUrl });\n await execFileAsync('git', ['clone', '--depth', '50', cloneUrl, repoDir], {\n timeout: 300_000,\n maxBuffer: 10 * 1024 * 1024,\n });\n } else {\n logger.info('Reusing existing associate clone', { name: assoc.name, dir: repoDir });\n }\n\n // Checkout or create branch\n const assocGit = new GitOperations(repoDir);\n await assocGit.fetch();\n\n const remoteExists = await assocGit.remoteBranchExists(branchName);\n if (remoteExists) {\n try {\n await assocGit.checkout(branchName);\n } catch {\n await assocGit.checkoutTrack(branchName);\n }\n } else {\n try {\n await assocGit.createBranch(branchName, baseBranch);\n } catch {\n await assocGit.checkout(branchName);\n }\n }\n\n return {\n name: assoc.name,\n projectPath: assoc.projectPath,\n role: assoc.role ?? '',\n gitRootDir: repoDir,\n workDir: path.join(repoDir, assoc.projectSubDir ?? ''),\n baseBranch,\n branchPrefix: assoc.branchPrefix ?? globalBranchPrefix,\n isPrimary: false,\n };\n }\n\n private async cleanStaleDir(dir: string): Promise<void> {\n if (await this.dirExists(dir)) {\n logger.warn('Removing stale directory', { dir });\n await fs.rm(dir, { recursive: true, force: true });\n }\n }\n\n private async dirExists(dir: string): Promise<boolean> {\n try {\n await fs.access(dir);\n return true;\n } catch {\n return false;\n }\n }\n}\n","import path from 'node:path';\nimport fs from 'node:fs/promises';\nimport fsSync from 'node:fs';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { Config } from '../config.js';\nimport { IssueNotFoundError, InvalidPhaseError, InvalidStateError, PhaseAbortedError } from '../errors/index.js';\nimport { GongfengClient, GongfengIssue } from '../clients/GongfengClient.js';\nimport { GitOperations } from '../git/GitOperations.js';\nimport type { AIRunner } from '../ai-runner/index.js';\nimport { IssueTracker } from '../tracker/IssueTracker.js';\nimport { IssueState } from '../tracker/IssueState.js';\nimport type { PipelineModeView } from '../tracker/IssueViews.js';\nimport { PlanPersistence } from '../persistence/PlanPersistence.js';\nimport type { WorktreeContext } from '../git/WorktreeContext.js';\nimport { getLocalIP } from '../utils/network.js';\nimport type { PhaseContext } from '../phases/BasePhase.js';\nimport { createPhase } from '../phases/PhaseFactory.js';\nimport { resolvePipelineMode, getPipelineDef, buildPlanModePipeline, registerPipeline, createLifecycleManager, PipelineDef } from '../pipeline/PipelineDefinition.js';\nimport { ActionLifecycleManager } from '../lifecycle/ActionLifecycleManager.js';\nimport { SupplementStore } from '../supplement/SupplementStore.js';\nimport { gongfengIssueToDemandSpec } from '../demand/adapters/GongfengAdapter.js';\nimport { getIid, getExternalId, getTitle } from '../tracker/IssueRecordHelper.js';\nimport { eventBus as defaultEventBus, type EventBus } from '../events/EventBus.js';\nimport { AsyncMutex } from '../utils/AsyncMutex.js';\nimport { extractTapdId, generateMRTitle, generateMRDescription } from '../utils/MergeRequestHelper.js';\nimport { PortAllocator, type PortPair } from '../deploy/PortAllocator.js';\nimport { DevServerManager } from '../deploy/DevServerManager.js';\nimport { isE2eEnabledForIssue } from '../e2e/E2eSettings.js';\nimport { ScreenshotPublisher } from '../e2e/ScreenshotPublisher.js';\nimport { ConflictResolver } from '../git/ConflictResolver.js';\nimport { getProjectKnowledge } from '../knowledge/index.js';\nimport { KNOWLEDGE_DEFAULTS } from '../knowledge/KnowledgeDefaults.js';\nimport { logger as rootLogger } from '../logger.js';\nimport { runWithIssueContext } from '../context/IssueContext.js';\nimport { metrics } from '../metrics/MetricsCollector.js';\nimport { t } from '../i18n/index.js';\nimport type { OrchestratorDeps, IssueProcessingContext } from './IssueProcessingContext.js';\nimport { WorkspaceManager, buildSingleRepoWorkspace } from '../workspace/index.js';\nimport type { WorkspaceConfig } from '../workspace/index.js';\nimport { executeSetup } from './steps/SetupStep.js';\nimport { executePhaseLoop } from './steps/PhaseLoopStep.js';\nimport { executeCompletion } from './steps/CompletionStep.js';\nimport { handleFailure } from './steps/FailureHandler.js';\n\nexport interface MergeRequestResult {\n url: string;\n iid: number;\n}\n\nconst execFileAsync = promisify(execFile);\nconst logger = rootLogger.child('PipelineOrchestrator');\n\nexport class PipelineOrchestrator {\n private config: Config;\n private gongfeng: GongfengClient;\n private mainGit: GitOperations;\n private aiRunner: AIRunner;\n private e2eAiRunner?: AIRunner;\n private tracker: IssueTracker;\n private supplementStore?: SupplementStore;\n private mainGitMutex: AsyncMutex;\n private conflictResolver: ConflictResolver;\n private pipelineDef: PipelineDef;\n private lifecycleManager: ActionLifecycleManager;\n private portAllocator: PortAllocator;\n private devServerManager: DevServerManager;\n private screenshotPublisher: ScreenshotPublisher;\n private eventBus: EventBus;\n private claimer: import('../coordination/IssueClaimer.js').IssueClaimer | null = null;\n private workspaceManager: WorkspaceManager;\n readonly tenantId: string;\n private readonly effectiveWorktreeBaseDir: string;\n private pendingActions = new Map<number, 'abort' | 'redo' | 'restart'>();\n\n /** 暴露 AIRunner 给外部(如 CommandExecutor 取消进程时使用) */\n getAIRunner(): AIRunner {\n return this.aiRunner;\n }\n\n /** 替换 AIRunner(用于配置热重载) */\n setAIRunner(runner: AIRunner): void {\n this.aiRunner = runner;\n this.conflictResolver = new ConflictResolver(runner);\n logger.info('AIRunner replaced via hot-reload');\n }\n\n constructor(\n config: Config,\n gongfeng: GongfengClient,\n git: GitOperations,\n aiRunner: AIRunner,\n tracker: IssueTracker,\n supplementStore?: SupplementStore,\n mainGitMutex?: AsyncMutex,\n eventBusInstance?: EventBus,\n wsConfig?: WorkspaceConfig | null,\n tenantId?: string,\n e2eAiRunner?: AIRunner,\n ) {\n this.config = config;\n this.gongfeng = gongfeng;\n this.mainGit = git;\n this.aiRunner = aiRunner;\n this.e2eAiRunner = e2eAiRunner;\n this.tracker = tracker;\n this.supplementStore = supplementStore;\n this.mainGitMutex = mainGitMutex ?? new AsyncMutex();\n this.eventBus = eventBusInstance ?? defaultEventBus;\n this.conflictResolver = new ConflictResolver(aiRunner);\n this.tenantId = tenantId ?? 'default';\n\n const mode = resolvePipelineMode(config.ai.mode, config.pipeline?.mode === 'auto' ? undefined : config.pipeline?.mode);\n this.pipelineDef = mode === 'plan-mode'\n ? buildPlanModePipeline({ releaseEnabled: config.release.enabled, e2eEnabled: config.e2e.enabled })\n : getPipelineDef(mode);\n registerPipeline(this.pipelineDef);\n this.lifecycleManager = createLifecycleManager(this.pipelineDef);\n logger.info('Pipeline mode resolved', { tenantId: this.tenantId, mode: this.pipelineDef.mode, aiMode: config.ai.mode });\n\n this.portAllocator = new PortAllocator({\n backendPortBase: config.e2e.backendPortBase,\n frontendPortBase: config.e2e.frontendPortBase,\n });\n this.devServerManager = new DevServerManager();\n this.screenshotPublisher = new ScreenshotPublisher(gongfeng);\n\n this.effectiveWorktreeBaseDir = this.tenantId === 'default'\n ? config.project.worktreeBaseDir\n : path.join(config.project.worktreeBaseDir, this.tenantId);\n\n const effectiveWsConfig = wsConfig ?? buildSingleRepoWorkspace(config.project, config.gongfeng.projectPath);\n this.workspaceManager = new WorkspaceManager({\n wsConfig: effectiveWsConfig,\n worktreeBaseDir: this.effectiveWorktreeBaseDir,\n mainGit: git,\n mainGitMutex: this.mainGitMutex,\n gongfengApiUrl: config.gongfeng.apiUrl,\n });\n logger.info('WorkspaceManager initialized', {\n tenantId: this.tenantId,\n primary: effectiveWsConfig.primary.name,\n associates: effectiveWsConfig.associates.map(a => a.name),\n });\n\n this.restorePortAllocations();\n }\n\n getPortAllocator(): PortAllocator { return this.portAllocator; }\n getDevServerManager(): DevServerManager { return this.devServerManager; }\n getMainGitMutex(): AsyncMutex { return this.mainGitMutex; }\n\n /** 注入 IssueClaimer 实例(在 index.ts 中获取 currentUser 后调用) */\n setClaimer(claimer: import('../coordination/IssueClaimer.js').IssueClaimer | null): void {\n this.claimer = claimer;\n }\n\n async cleanupStaleState(): Promise<void> {\n logger.info('Cleaning up stale worktree state...');\n let cleaned = 0;\n const repoGitRoot = this.config.project.gitRootDir;\n\n try {\n const worktrees = await this.mainGit.worktreeList();\n for (const wtDir of worktrees) {\n if (wtDir === repoGitRoot) continue;\n if (!wtDir.includes('/issue-')) continue;\n\n try {\n const gitFile = path.join(wtDir, '.git');\n try {\n await fs.access(gitFile);\n } catch {\n logger.warn('Worktree corrupted (.git missing), force removing', { dir: wtDir });\n await this.mainGit.worktreeRemove(wtDir, true).catch(() => {});\n await this.mainGit.worktreePrune();\n cleaned++;\n continue;\n }\n\n const wtGit = new GitOperations(wtDir);\n\n if (await wtGit.isRebaseInProgress()) {\n logger.warn('Aborting residual rebase in worktree', { dir: wtDir });\n await wtGit.rebaseAbort();\n cleaned++;\n }\n\n const indexLock = path.join(wtDir, '.git', 'index.lock');\n try {\n await fs.unlink(indexLock);\n logger.warn('Removed stale index.lock', { path: indexLock });\n cleaned++;\n } catch {\n // No lock file — normal\n }\n } catch (err) {\n logger.warn('Failed to clean worktree state', { dir: wtDir, error: (err as Error).message });\n }\n }\n } catch (err) {\n logger.warn('Failed to list worktrees for cleanup', { error: (err as Error).message });\n }\n\n const mainIndexLock = path.join(repoGitRoot, '.git', 'index.lock');\n try {\n await fs.unlink(mainIndexLock);\n logger.warn('Removed stale main repo index.lock', { path: mainIndexLock });\n cleaned++;\n } catch {\n // No lock file — normal\n }\n\n logger.info('Stale state cleanup complete', { cleaned });\n }\n\n /**\n * 重启后清理幽灵端口分配。\n *\n * DevServerManager 的进程句柄仅存于内存,重启后全部丢失。\n * 此时 tracker 中残留的 ports 字段指向不可控的孤儿进程,\n * 必须清理以避免前端误显示 preview 状态。\n */\n private restorePortAllocations(): void {\n for (const record of this.tracker.getAll()) {\n if (record.ports) {\n const iid = getIid(record);\n logger.info('Clearing stale port allocation after restart', { iid, ports: record.ports });\n this.tracker.updateState(iid, record.state, {\n ports: undefined,\n previewStartedAt: undefined,\n } as any);\n }\n }\n }\n\n getPipelineDef(): PipelineDef {\n return this.pipelineDef;\n }\n\n private emitProgress(issueIid: number, step: string, message: string): void {\n this.eventBus.emitTyped('pipeline:progress', { issueIid, step, message });\n }\n\n private computeWorktreeContext(issueIid: number, branchName: string): WorktreeContext {\n const repos = this.workspaceManager.buildRepoContexts(\n issueIid, branchName, this.config.project.baseBranch, this.config.project.branchPrefix,\n );\n const primary = repos.find(r => r.isPrimary)!;\n return {\n gitRootDir: primary.gitRootDir,\n workDir: primary.workDir,\n branchName,\n issueIid,\n };\n }\n\n private async ensureWorktree(wtCtx: WorktreeContext): Promise<void> {\n const wsCtx = await this.workspaceManager.prepareWorkspace(\n wtCtx.issueIid,\n wtCtx.branchName,\n this.config.project.baseBranch,\n this.config.project.branchPrefix,\n );\n wtCtx.workspace = wsCtx;\n }\n\n private async cleanupWorktree(wtCtx: WorktreeContext): Promise<void> {\n if (wtCtx.workspace) {\n await this.workspaceManager.cleanupWorkspace(wtCtx.workspace);\n return;\n }\n try {\n await this.mainGit.worktreeRemove(wtCtx.gitRootDir, true);\n logger.info('Worktree cleaned up', { dir: wtCtx.gitRootDir });\n } catch (err) {\n logger.warn('Failed to cleanup worktree', { dir: wtCtx.gitRootDir, error: (err as Error).message });\n }\n }\n\n private async installDependencies(workDir: string): Promise<void> {\n logger.info('Installing dependencies in worktree', { workDir });\n\n const knowledge = getProjectKnowledge() ?? KNOWLEDGE_DEFAULTS;\n const pkgMgr = knowledge.toolchain.packageManager.toLowerCase();\n const isNodeProject = ['npm', 'pnpm', 'yarn', 'bun'].some(m => pkgMgr.includes(m));\n\n if (isNodeProject) {\n const ready = await this.ensureNodeModules(workDir);\n if (ready) {\n logger.info('node_modules ready — skipping install');\n return;\n }\n }\n\n const installCmd = knowledge.toolchain.installCommand;\n const fallbackCmd = knowledge.toolchain.installFallbackCommand;\n const [bin, ...args] = installCmd.split(/\\s+/);\n\n try {\n await execFileAsync(bin, args, {\n cwd: workDir,\n maxBuffer: 10 * 1024 * 1024,\n timeout: 300_000,\n });\n logger.info('Dependencies installed');\n } catch (err) {\n if (fallbackCmd) {\n logger.warn(`${installCmd} failed, retrying with fallback command`, {\n error: (err as Error).message,\n });\n const [fallbackBin, ...fallbackArgs] = fallbackCmd.split(/\\s+/);\n try {\n await execFileAsync(fallbackBin, fallbackArgs, {\n cwd: workDir,\n maxBuffer: 10 * 1024 * 1024,\n timeout: 300_000,\n });\n logger.info('Dependencies installed (fallback)');\n } catch (retryErr) {\n logger.warn('Fallback install also failed', {\n error: (retryErr as Error).message,\n });\n }\n } else {\n logger.warn('Install failed, no fallback configured', {\n error: (err as Error).message,\n });\n }\n }\n }\n\n private async ensureNodeModules(workDir: string): Promise<boolean> {\n const targetBin = path.join(workDir, 'node_modules', '.bin');\n try {\n await fs.access(targetBin);\n logger.info('node_modules already complete (has .bin/)');\n return true;\n } catch {\n // .bin/ missing — need to seed or install\n }\n\n const sourceNM = path.join(this.config.project.workDir, 'node_modules');\n const targetNM = path.join(workDir, 'node_modules');\n try {\n await fs.access(sourceNM);\n } catch {\n logger.warn('Main repo node_modules not found, skipping seed', { sourceNM });\n return false;\n }\n\n logger.info('Seeding node_modules from main repo via reflink copy', { sourceNM, targetNM });\n try {\n await execFileAsync('rm', ['-rf', targetNM], { timeout: 60_000 });\n // btrfs reflink: zero-copy CoW, near-instant; falls back to regular copy on non-btrfs\n await execFileAsync('cp', ['-a', '--reflink=auto', sourceNM, targetNM], {\n timeout: 120_000,\n });\n logger.info('node_modules seeded from main repo');\n return true;\n } catch (err) {\n logger.warn('Failed to seed node_modules from main repo', {\n error: (err as Error).message,\n });\n return false;\n }\n }\n\n async restartIssue(issueIid: number): Promise<void> {\n const record = this.tracker.get(issueIid);\n if (!record) throw new IssueNotFoundError(issueIid);\n\n const wtCtx = this.computeWorktreeContext(issueIid, record.branchName);\n logger.info('Restarting issue — cleaning context', { issueIid, branchName: record.branchName });\n\n // 设置 pending action,防止旧的 processIssue 循环在 kill 后覆盖状态\n this.pendingActions.set(issueIid, 'restart');\n\n this.aiRunner.killByWorkDir(wtCtx.workDir);\n this.e2eAiRunner?.killByWorkDir(wtCtx.workDir);\n\n this.stopPreviewServers(issueIid);\n\n try {\n const deleted = await this.gongfeng.cleanupAgentNotes(getExternalId(record));\n logger.info('Agent notes cleaned up', { issueIid, deleted });\n } catch (err) {\n logger.warn('Failed to cleanup agent notes', { issueIid, error: (err as Error).message });\n }\n\n await this.mainGitMutex.runExclusive(async () => {\n await this.cleanupWorktree(wtCtx);\n await this.cleanupWorkspaceRoot(issueIid);\n try { await this.mainGit.deleteBranch(record.branchName); } catch { /* branch may not exist */ }\n try { await this.mainGit.deleteRemoteBranch(record.branchName); } catch { /* remote branch may not exist */ }\n });\n\n await this.cleanupE2eOutputs(issueIid);\n\n this.tracker.resetFull(issueIid);\n // 清理完毕,删除 pendingAction 防止新的 processIssue 被误拦截\n this.pendingActions.delete(issueIid);\n logger.info('Issue restarted', { issueIid });\n }\n\n async cancelIssue(issueIid: number): Promise<void> {\n const record = this.tracker.get(issueIid);\n if (!record) throw new IssueNotFoundError(issueIid);\n\n const wtCtx = this.computeWorktreeContext(issueIid, record.branchName);\n logger.info('Cancelling issue — cleaning all resources', { issueIid, branchName: record.branchName });\n\n // 1. 终止 AI 进程\n this.aiRunner.killByWorkDir(wtCtx.workDir);\n\n // 2. 停止预览服务器\n this.stopPreviewServers(issueIid);\n\n // 3. 移除工蜂标签(关键步骤!防止 discovery 循环重新发现)\n try {\n await this.gongfeng.removeLabelsWithPrefix(getExternalId(record), 'auto-finish');\n } catch (err) {\n logger.warn('Failed to remove labels on cancel', { issueIid, error: (err as Error).message });\n }\n\n // 4. 清理 worktree + 分支\n await this.mainGitMutex.runExclusive(async () => {\n await this.cleanupWorktree(wtCtx);\n await this.cleanupWorkspaceRoot(issueIid);\n try { await this.mainGit.deleteBranch(record.branchName); } catch { /* branch may not exist */ }\n try { await this.mainGit.deleteRemoteBranch(record.branchName); } catch { /* remote branch may not exist */ }\n });\n\n // 5. 标记为 Skipped(保留记录防止 discovery 重新拾取)\n this.tracker.clearProcessingLock(issueIid);\n this.tracker.updateState(issueIid, IssueState.Skipped);\n // 6. 清理 E2E 产物\n await this.cleanupE2eOutputs(issueIid);\n logger.info('Issue cancelled', { issueIid });\n }\n\n /**\n * Remove the E2E output directory for an issue: {uatVendorDir}/outputs/issue-{iid}\n */\n private async cleanupE2eOutputs(issueIid: number): Promise<void> {\n const vendorDir = this.config.e2e.uatVendorDir;\n if (!vendorDir) return;\n\n const abs = path.isAbsolute(vendorDir)\n ? vendorDir\n : path.resolve(this.config.project.workDir, vendorDir);\n const outputDir = path.join(abs, 'outputs', `issue-${issueIid}`);\n\n try {\n await fs.rm(outputDir, { recursive: true, force: true });\n logger.info('E2E outputs cleaned up', { issueIid, dir: outputDir });\n } catch (err) {\n logger.warn('Failed to cleanup E2E outputs', { issueIid, dir: outputDir, error: (err as Error).message });\n }\n }\n\n /**\n * When WorkspaceManager is active, the workspace root (which contains\n * associate repo clone dirs) may survive after cleanupWorktree removes\n * only the primary worktree. Force-remove the whole workspace root.\n */\n private async cleanupWorkspaceRoot(issueIid: number): Promise<void> {\n if (!this.workspaceManager) return;\n\n const wsRoot = this.workspaceManager.getWorkspaceRoot(issueIid);\n try {\n await fs.rm(wsRoot, { recursive: true, force: true });\n logger.info('Workspace root cleaned up', { issueIid, dir: wsRoot });\n } catch (err) {\n logger.warn('Failed to cleanup workspace root', { issueIid, dir: wsRoot, error: (err as Error).message });\n }\n }\n\n retryFromPhase(issueIid: number, phase: string): void {\n const record = this.tracker.get(issueIid);\n if (!record) throw new IssueNotFoundError(issueIid);\n\n const issueDef = this.getIssueSpecificPipelineDef(record);\n const issueLM = createLifecycleManager(issueDef);\n if (!issueLM.isRetryable(phase)) {\n throw new InvalidPhaseError(phase);\n }\n\n // Interrupt stale AI processes to prevent them from overwriting the reset state.\n // Prefer soft interrupt (Ctrl+C) to preserve the PTY session for reuse —\n // avoids the costly cold-start of a new agent process on retry.\n const wtCtx = this.computeWorktreeContext(issueIid, record.branchName);\n if (!this.aiRunner.interruptByWorkDir?.(wtCtx.workDir)) {\n this.aiRunner.killByWorkDir(wtCtx.workDir);\n }\n this.e2eAiRunner?.killByWorkDir(wtCtx.workDir);\n\n logger.info('Retrying issue from phase', { issueIid, phase });\n const ok = this.tracker.resetToPhase(issueIid, phase, issueDef);\n if (!ok) {\n throw new InvalidPhaseError(phase);\n }\n }\n\n // ── 阶段级中止/继续/重做 ──\n\n abortIssue(issueIid: number): void {\n const record = this.tracker.get(issueIid);\n if (!record) throw new IssueNotFoundError(issueIid);\n\n const ABORTABLE = new Set([\n IssueState.PhaseRunning, IssueState.PhaseDone,\n IssueState.PhaseWaiting, IssueState.PhaseApproved,\n ]);\n if (!ABORTABLE.has(record.state)) {\n throw new InvalidStateError(record.state, `Issue #${issueIid} not in abortable state`);\n }\n\n const wtCtx = this.computeWorktreeContext(issueIid, record.branchName);\n\n if (record.state === IssueState.PhaseRunning) {\n // AI 进程运行中 — 设标记后 kill,由 catch 块完成状态转换\n this.pendingActions.set(issueIid, 'abort');\n this.aiRunner.killByWorkDir(wtCtx.workDir);\n this.e2eAiRunner?.killByWorkDir(wtCtx.workDir);\n } else {\n // 无进程运行(PhaseDone/PhaseWaiting/PhaseApproved)— 直接暂停\n this.tracker.pauseIssue(issueIid, record.currentPhase ?? '');\n }\n\n logger.info('Issue abort requested', { issueIid, state: record.state });\n }\n\n continueIssue(issueIid: number): void {\n const record = this.tracker.get(issueIid);\n if (!record) throw new IssueNotFoundError(issueIid);\n if (record.state !== IssueState.Paused) {\n throw new InvalidStateError(record.state, `Issue #${issueIid} not in paused state`);\n }\n\n const issueDef = this.getIssueSpecificPipelineDef(record);\n this.tracker.resumeFromPause(issueIid, issueDef, false);\n logger.info('Issue continued from pause', { issueIid });\n }\n\n redoPhase(issueIid: number): void {\n const record = this.tracker.get(issueIid);\n if (!record) throw new IssueNotFoundError(issueIid);\n\n const REDOABLE = new Set([\n IssueState.Paused, IssueState.PhaseRunning, IssueState.PhaseDone,\n IssueState.PhaseWaiting, IssueState.PhaseApproved,\n ]);\n if (!REDOABLE.has(record.state)) {\n throw new InvalidStateError(record.state, `Issue #${issueIid} not in redoable state`);\n }\n\n const issueDef = this.getIssueSpecificPipelineDef(record);\n const wtCtx = this.computeWorktreeContext(issueIid, record.branchName);\n\n if (record.state === IssueState.PhaseRunning) {\n // AI 进程运行中 — 设标记后 kill,由 catch 块完成状态转换\n this.pendingActions.set(issueIid, 'redo');\n this.aiRunner.killByWorkDir(wtCtx.workDir);\n this.e2eAiRunner?.killByWorkDir(wtCtx.workDir);\n } else if (record.state === IssueState.Paused) {\n const phase = record.pausedAtPhase;\n if (phase) {\n const wtPlan = new PlanPersistence(wtCtx.workDir, issueIid);\n wtPlan.updatePhaseProgress(phase, 'pending');\n this.tracker.updatePhaseProgress(issueIid, phase, {\n status: 'pending', startedAt: undefined, completedAt: undefined, error: undefined,\n });\n }\n this.tracker.resumeFromPause(issueIid, issueDef, true);\n this.eventBus.emitTyped('issue:redone', { issueIid });\n } else {\n // PhaseDone/PhaseWaiting/PhaseApproved — 重置到当前阶段前驱\n const phase = record.currentPhase;\n if (phase) {\n const wtPlan = new PlanPersistence(wtCtx.workDir, issueIid);\n wtPlan.updatePhaseProgress(phase, 'pending');\n // resetToPhase 内部已重置 tracker 的 phaseProgress\n this.tracker.resetToPhase(issueIid, phase, issueDef);\n }\n this.eventBus.emitTyped('issue:redone', { issueIid });\n }\n\n logger.info('Issue redo requested', { issueIid, state: record.state });\n }\n\n /**\n * 处理中止/重做的共享逻辑:\n * - abort: 暂停 Issue(保留 session)\n * - redo: 重置阶段(清除 session)\n *\n * 由 catch 块的两条路径(PhaseAbortedError / pendingActions)共用。\n */\n private applyPendingAction(\n action: 'abort' | 'redo',\n issueIid: number,\n wtCtx: WorktreeContext,\n pipelineDef: PipelineDef,\n ): void {\n const rec = this.tracker.get(issueIid);\n // 若 onPhaseFailed 已递增 attempts(state === Failed 时),需回滚\n if (rec?.state === IssueState.Failed && rec.attempts > 0) {\n rec.attempts -= 1;\n }\n\n if (action === 'abort') {\n this.tracker.pauseIssue(issueIid, rec?.currentPhase ?? '');\n } else {\n const phase = rec?.currentPhase;\n if (phase) {\n const wtPlan = new PlanPersistence(wtCtx.workDir, issueIid);\n wtPlan.updatePhaseProgress(phase, 'pending');\n // resetToPhase 内部已重置 tracker 的 phaseProgress\n this.tracker.resetToPhase(issueIid, phase, pipelineDef);\n }\n this.eventBus.emitTyped('issue:redone', { issueIid: issueIid });\n }\n }\n\n private getIssueSpecificPipelineDef(record: PipelineModeView): PipelineDef {\n if (record.pipelineMode) {\n return getPipelineDef(record.pipelineMode);\n }\n return this.pipelineDef;\n }\n\n async processIssue(issue: GongfengIssue): Promise<void> {\n return runWithIssueContext(issue.iid, () => this._processIssueImpl(issue));\n }\n\n private buildDeps(): OrchestratorDeps {\n return {\n tenantId: this.tenantId,\n config: this.config,\n gongfeng: this.gongfeng,\n mainGit: this.mainGit,\n mainGitMutex: this.mainGitMutex,\n aiRunner: this.aiRunner,\n e2eAiRunner: this.e2eAiRunner,\n tracker: this.tracker,\n supplementStore: this.supplementStore,\n screenshotPublisher: this.screenshotPublisher,\n portAllocator: this.portAllocator,\n devServerManager: this.devServerManager,\n eventBus: this.eventBus,\n claimer: this.claimer,\n workspaceManager: this.workspaceManager,\n emitProgress: (iid, step, msg) => this.emitProgress(iid, step, msg),\n ensureWorktree: (wtCtx) => this.ensureWorktree(wtCtx),\n installDependencies: (workDir) => this.installDependencies(workDir),\n shouldAutoApprove: (labels) => this.shouldAutoApprove(labels),\n shouldDeployServers: (iid) => this.shouldDeployServers(iid),\n startPreviewServers: (wtCtx, issue) => this.startPreviewServers(wtCtx, issue),\n stopPreviewServers: (iid) => this.stopPreviewServers(iid),\n tryCreateMergeRequest: (issue, branch, workDir, previewUrl) =>\n this.tryCreateMergeRequest(issue, branch, workDir, previewUrl),\n buildPreviewUrl: (iid) => this.buildPreviewUrl(iid),\n getPortsForIssue: (iid) => this.portAllocator.getPortsForIssue(iid),\n isPreviewRunning: (iid) => this.devServerManager.getStatus(iid).running,\n consumePendingAction: (iid) => {\n const action = this.pendingActions.get(iid);\n if (action) this.pendingActions.delete(iid);\n return action;\n },\n };\n }\n\n private async _processIssueImpl(issue: GongfengIssue): Promise<void> {\n const branchName = `${this.config.project.branchPrefix}-${issue.iid}`;\n const wtCtx = this.computeWorktreeContext(issue.iid, branchName);\n\n logger.info('Processing issue', {\n iid: issue.iid, title: issue.title, branchName,\n worktree: wtCtx.gitRootDir,\n multiRepo: this.workspaceManager.isMultiRepo(),\n });\n metrics.incCounter('iaf_issues_total', { pipeline: this.pipelineDef.mode });\n\n const supplement = this.supplementStore?.get(issue.iid);\n const demand = gongfengIssueToDemandSpec(issue, supplement);\n\n let record = this.tracker.get(issue.iid);\n const isRetry = record?.state === IssueState.Failed;\n if (isRetry) {\n metrics.incCounter('iaf_issues_retried_total');\n }\n\n if (!record) {\n record = this.tracker.create({\n state: IssueState.Pending,\n branchName,\n pipelineMode: this.pipelineDef.mode,\n demandSpec: demand,\n });\n }\n\n if (!record.pipelineMode) {\n this.tracker.updateState(issue.iid, record.state, { pipelineMode: this.pipelineDef.mode } as any);\n record.pipelineMode = this.pipelineDef.mode;\n }\n\n const issuePipelineDef = this.getIssueSpecificPipelineDef(record);\n const issueLM = createLifecycleManager(issuePipelineDef);\n const phaseCtx: PhaseContext = {\n demand, branchName, pipelineMode: issuePipelineDef.mode,\n };\n if (record.ports) {\n phaseCtx.ports = record.ports;\n }\n\n const ctx: IssueProcessingContext = {\n issue, branchName, wtCtx, record, isRetry,\n pipelineDef: issuePipelineDef,\n lifecycleManager: issueLM,\n demand, phaseCtx,\n };\n\n const deps = this.buildDeps();\n\n try {\n const { wtGit, wtPlan, wtGitMap } = await executeSetup(ctx, deps);\n\n // Inject workspace layout into phaseCtx after worktree/workspace is prepared\n if (wtCtx.workspace) {\n const repos = this.workspaceManager.buildRepoContexts(\n issue.iid, branchName, this.config.project.baseBranch, this.config.project.branchPrefix,\n );\n phaseCtx.workspace = {\n repos,\n workspaceRoot: wtCtx.workspace.workspaceRoot,\n };\n }\n const phaseResult = await executePhaseLoop(ctx, deps, wtGit, wtPlan, wtGitMap);\n if (phaseResult.paused) return;\n await executeCompletion(ctx, deps, phaseResult, wtGitMap);\n } catch (err) {\n // ── 拦截用户发起的中止/重做,在 handleFailure 之前处理 ──\n\n // Path A: PhaseAbortedError — 来自 PhaseLoopStep 阶段间检查(无 AI 运行时)\n if (err instanceof PhaseAbortedError) {\n if (err.action === 'restart') return; // restartIssue 已自行处理所有清理\n this.applyPendingAction(err.action, issue.iid, wtCtx, issuePipelineDef);\n return;\n }\n\n // Path B: pendingActions — AI 进程被 kill 后由 catch 拾取\n const pendingAction = this.pendingActions.get(issue.iid);\n if (pendingAction) {\n this.pendingActions.delete(issue.iid);\n if (pendingAction === 'restart') return; // restartIssue 已自行处理所有清理\n this.applyPendingAction(pendingAction, issue.iid, wtCtx, issuePipelineDef);\n return;\n }\n\n await handleFailure(err, issue, wtCtx, deps);\n }\n }\n\n private async tryCreateMergeRequest(\n issue: GongfengIssue,\n branchName: string,\n workDir: string,\n previewUrl?: string | null,\n ): Promise<MergeRequestResult | null> {\n try {\n const supplement = this.supplementStore?.get(issue.iid);\n const tapdId = supplement?.tapdId?.trim()\n || extractTapdId(issue.description || '');\n\n const title = generateMRTitle(issue.iid, issue.title, tapdId);\n let description = generateMRDescription({\n issueIid: issue.iid,\n issueTitle: issue.title,\n issueDescription: issue.description || '',\n branchName,\n planDir: workDir,\n });\n\n if (previewUrl) {\n description += `\\n\\n## Preview Environment\\n\\n🌐 ${previewUrl}`;\n }\n\n const mr = await this.gongfeng.createMergeRequest({\n sourceBranch: branchName,\n targetBranch: this.config.project.baseBranch,\n title,\n description,\n });\n\n logger.info('Merge request created successfully', {\n iid: issue.iid, mrIid: mr.iid, mrUrl: mr.web_url,\n });\n return { url: mr.web_url, iid: mr.iid };\n } catch (err) {\n const errorMsg = (err as Error).message;\n logger.warn('Failed to create merge request, trying to find existing one', {\n iid: issue.iid, error: errorMsg,\n });\n\n if (errorMsg.includes('already exists')) {\n return this.tryFindExistingMergeRequest(issue.iid, branchName);\n }\n return null;\n }\n }\n\n private async tryFindExistingMergeRequest(\n issueIid: number,\n branchName: string,\n ): Promise<MergeRequestResult | null> {\n try {\n const existing = await this.gongfeng.findMergeRequestByBranch(\n branchName,\n this.config.project.baseBranch,\n );\n if (existing) {\n logger.info('Found existing merge request', {\n iid: issueIid, mrIid: existing.iid, mrUrl: existing.web_url,\n });\n return { url: existing.web_url, iid: existing.iid };\n }\n } catch (findErr) {\n logger.warn('Failed to find existing merge request', {\n iid: issueIid, error: (findErr as Error).message,\n });\n }\n return null;\n }\n\n // TODO: Multi-repo MR support — when associates are enabled, iterate over\n // wsCtx.associates and create per-repo MRs using per-repo GongfengClients.\n\n private shouldDeployServers(issueIid: number): boolean {\n return isE2eEnabledForIssue(issueIid, this.tracker, this.config)\n || this.config.preview.enabled;\n }\n\n private shouldAutoApprove(issueLabels: string[]): boolean {\n const autoLabels = this.config.review.autoApproveLabels;\n if (!autoLabels.length) return false;\n return issueLabels.some(l => autoLabels.includes(l));\n }\n\n private async startPreviewServers(\n wtCtx: WorktreeContext,\n issue: GongfengIssue,\n ): Promise<PortPair | null> {\n try {\n this.emitProgress(issue.iid, 'deploy', t('orchestrator.deployProgress'));\n const ports = await this.portAllocator.allocate(issue.iid);\n wtCtx.ports = ports;\n\n this.tracker.updateState(issue.iid, this.tracker.get(issue.iid)!.state, {\n ports,\n previewStartedAt: new Date().toISOString(),\n } as any);\n\n await this.devServerManager.startServers(wtCtx, ports);\n\n const previewUrl = this.buildPreviewUrl(issue.iid);\n if (previewUrl) {\n try {\n await this.gongfeng.createIssueNote(\n issue.id,\n this.buildPreviewComment(ports, previewUrl),\n );\n } catch {\n // ignore comment failure\n }\n }\n\n this.emitProgress(issue.iid, 'deploy_done', t('orchestrator.deployDoneProgress', { url: previewUrl ?? 'N/A' }));\n this.eventBus.emitTyped('pipeline:progress', {\n issueIid: issue.iid,\n step: 'preview_ready',\n message: previewUrl ?? '',\n });\n\n return ports;\n } catch (err) {\n logger.error('Failed to start preview servers', {\n iid: issue.iid,\n error: (err as Error).message,\n });\n this.portAllocator.release(issue.iid);\n try {\n await this.gongfeng.createIssueNote(issue.id,\n `⚠️ Preview 服务启动失败: ${(err as Error).message}\\nE2E 测试将尝试使用 config.json 中的默认端口。`);\n } catch { /* ignore */ }\n return null;\n }\n }\n\n stopPreviewServers(issueIid: number): void {\n this.devServerManager.stopServers(issueIid);\n this.portAllocator.release(issueIid);\n const record = this.tracker.get(issueIid);\n if (record?.ports) {\n this.tracker.updateState(issueIid, record.state, {\n ports: undefined,\n previewStartedAt: undefined,\n } as any);\n }\n }\n\n async stopPreviewAndCleanWorktree(issueIid: number): Promise<void> {\n const record = this.tracker.get(issueIid);\n if (!record) return;\n\n this.stopPreviewServers(issueIid);\n\n const wtCtx = this.computeWorktreeContext(issueIid, record.branchName);\n await this.mainGitMutex.runExclusive(async () => {\n await this.cleanupWorktree(wtCtx);\n });\n logger.info('Preview stopped and worktree cleaned', { iid: issueIid });\n }\n\n async markDeployed(issueIid: number): Promise<void> {\n const record = this.tracker.get(issueIid);\n if (!record) throw new IssueNotFoundError(issueIid);\n if (record.state !== IssueState.Completed) {\n throw new InvalidStateError(record.state, `Issue #${issueIid} not in completed state`);\n }\n\n // 1. Stop preview servers\n this.stopPreviewServers(issueIid);\n\n // 2. Clean worktree (keep remote branch for MR)\n const wtCtx = this.computeWorktreeContext(issueIid, record.branchName);\n await this.mainGitMutex.runExclusive(async () => {\n await this.cleanupWorktree(wtCtx);\n });\n\n // 3. Close issue on Gongfeng\n const externalId = getExternalId(record);\n try {\n await this.gongfeng.closeIssue(externalId);\n } catch (err) {\n logger.warn('Failed to close issue on Gongfeng', { iid: issueIid, error: (err as Error).message });\n }\n\n // 4. Update labels\n try {\n const issue = await this.gongfeng.getIssueDetail(externalId);\n const labels = issue.labels.filter(l => !l.startsWith('auto-finish:') && l !== 'auto-finish');\n labels.push('auto-finish:deployed');\n await this.gongfeng.updateIssueLabels(externalId, labels);\n } catch (err) {\n logger.warn('Failed to update labels', { iid: issueIid, error: (err as Error).message });\n }\n\n // 5. Transition to Deployed\n this.tracker.updateState(issueIid, IssueState.Deployed);\n logger.info('Issue marked as deployed', { iid: issueIid });\n }\n\n async restartPreview(issueIid: number): Promise<string> {\n const record = this.tracker.get(issueIid);\n if (!record) throw new IssueNotFoundError(issueIid);\n\n const wtCtx = this.computeWorktreeContext(issueIid, record.branchName);\n if (!fsSync.existsSync(wtCtx.workDir)) {\n throw new InvalidStateError(record.state, 'Worktree no longer exists');\n }\n\n this.stopPreviewServers(issueIid);\n\n const ports = await this.portAllocator.allocate(issueIid);\n wtCtx.ports = ports;\n\n try {\n this.tracker.updateState(issueIid, record.state, {\n ports,\n previewStartedAt: new Date().toISOString(),\n } as any);\n await this.devServerManager.startServers(wtCtx, ports);\n } catch (err) {\n this.portAllocator.release(issueIid);\n this.tracker.updateState(issueIid, record.state, {\n ports: undefined,\n previewStartedAt: undefined,\n } as any);\n throw err;\n }\n\n const url = this.buildPreviewUrl(issueIid)!;\n logger.info('Preview restarted', { iid: issueIid, url });\n return url;\n }\n\n getPreviewHost(): string {\n if (this.config.preview.host) return this.config.preview.host;\n return getLocalIP();\n }\n\n buildPreviewUrl(issueIid: number): string | null {\n const ports = this.portAllocator.getPortsForIssue(issueIid);\n if (!ports) return null;\n const host = this.getPreviewHost();\n return `https://${host}:${ports.frontendPort}`;\n }\n\n private buildPreviewComment(ports: PortPair, previewUrl: string): string {\n const host = this.getPreviewHost();\n const ttlHours = Math.round(this.config.preview.ttlMs / (60 * 60 * 1000));\n return [\n t('orchestrator.previewComment.title'),\n '',\n t('orchestrator.previewComment.tableHeader'),\n t('orchestrator.previewComment.tableSep'),\n `| ${t('orchestrator.previewComment.frontend')} | ${previewUrl} |`,\n `| ${t('orchestrator.previewComment.backendApi')} | http://${host}:${ports.backendPort}/api |`,\n '',\n t('orchestrator.previewComment.hint'),\n t('orchestrator.previewComment.expiry', { hours: ttlHours }),\n ].join('\\n');\n }\n\n async resolveConflict(issueIid: number): Promise<void> {\n const record = this.tracker.get(issueIid);\n if (!record) throw new IssueNotFoundError(issueIid);\n\n const baseBranch = this.config.project.baseBranch;\n const branchName = record.branchName;\n\n logger.info('Starting conflict resolution', { issueIid, branchName, baseBranch });\n\n // 1. Update state\n this.tracker.updateState(issueIid, IssueState.ResolvingConflict);\n this.eventBus.emitTyped('conflict:started', { issueIid });\n\n // 2. Comment on issue\n try {\n await this.gongfeng.createIssueNote(\n getExternalId(record),\n t('conflict.startComment', { branch: branchName, baseBranch }),\n );\n } catch { /* ignore */ }\n\n const wtCtx = this.computeWorktreeContext(issueIid, branchName);\n\n try {\n // 3. Fetch + ensure worktree\n await this.mainGitMutex.runExclusive(async () => {\n await this.mainGit.fetch();\n await this.ensureWorktree(wtCtx);\n });\n\n const wtGit = new GitOperations(wtCtx.gitRootDir);\n\n // 4. Checkout branch\n await wtGit.checkout(branchName);\n\n // 5–6. Rebase + resolve conflicts using shared ConflictResolver\n await this.conflictResolver.resolve({\n wtGit,\n targetRef: `origin/${baseBranch}`,\n workDir: wtCtx.workDir,\n branchName,\n contextId: issueIid,\n phaseTimeoutMs: this.config.ai.phaseTimeoutMs,\n onEvent: (event) => {\n this.eventBus.emitTyped('agent:output', {\n issueIid,\n phase: 'conflict-resolve',\n event,\n });\n },\n });\n\n // If resolve() returned without throwing, rebase succeeded (with or without conflict resolution).\n\n // 7. Run verification\n logger.info('Running verification after conflict resolution', { issueIid });\n const wtPlan = new PlanPersistence(wtCtx.workDir, issueIid);\n wtPlan.ensureDir();\n\n const verifyPhase = createPhase('verify', this.aiRunner, wtGit, wtPlan, this.config);\n\n const verifyCtx: PhaseContext = {\n demand: {\n demandId: `gf-${issueIid}`,\n sourceRef: {\n source: 'gongfeng-issue',\n externalId: String(getExternalId(record)),\n displayId: String(issueIid),\n },\n title: getTitle(record),\n description: '',\n createdAt: record.createdAt,\n },\n branchName,\n pipelineMode: record.pipelineMode,\n };\n\n const verifyOutcome = await verifyPhase.run(verifyCtx);\n if (verifyOutcome.status === 'failed') {\n const errMsg = verifyOutcome.error?.message ?? 'Verification failed after conflict resolution';\n throw new (await import('../errors/index.js')).AIExecutionError('verify', errMsg, {\n output: verifyOutcome.error?.rawOutput ?? verifyOutcome.output,\n exitCode: verifyOutcome.exitCode ?? 1,\n });\n }\n\n // 8. Force push\n await wtGit.forcePush(branchName);\n\n // 9. Update state\n this.tracker.updateState(issueIid, IssueState.Completed);\n this.eventBus.emitTyped('conflict:resolved', { issueIid });\n\n // 10. Comment on Issue/MR\n try {\n await this.gongfeng.createIssueNote(\n getExternalId(record),\n t('conflict.resolvedComment', { branch: branchName, baseBranch }),\n );\n } catch { /* ignore */ }\n\n await this.commentOnMr(record.mrUrl, t('conflict.mrResolvedComment'));\n\n logger.info('Conflict resolution completed', { issueIid });\n } catch (err) {\n const errorMsg = (err as Error).message;\n logger.error('Conflict resolution failed', { issueIid, error: errorMsg });\n\n // Try to abort any in-progress rebase\n try {\n const wtGit = new GitOperations(wtCtx.gitRootDir);\n if (await wtGit.isRebaseInProgress()) {\n await wtGit.rebaseAbort();\n }\n } catch { /* ignore abort failure */ }\n\n this.tracker.markFailed(issueIid, errorMsg.slice(0, 500), IssueState.ResolvingConflict);\n this.eventBus.emitTyped('conflict:failed', { issueIid, error: errorMsg });\n\n try {\n await this.gongfeng.createIssueNote(\n getExternalId(record),\n t('conflict.failedComment', { error: errorMsg }),\n );\n } catch { /* ignore */ }\n }\n }\n\n private extractMrIidFromUrl(mrUrl: string): number | null {\n const match = mrUrl.match(/merge_requests\\/(\\d+)/);\n return match ? parseInt(match[1], 10) : null;\n }\n\n private async commentOnMr(mrUrl: string | undefined, body: string): Promise<void> {\n if (!mrUrl) return;\n const mrIid = this.extractMrIidFromUrl(mrUrl);\n if (!mrIid) return;\n try {\n await this.gongfeng.createMergeRequestNote(mrIid, body);\n } catch (err) {\n logger.warn('Failed to comment on MR', { mrIid, error: (err as Error).message });\n }\n }\n}\n","import type { GongfengIssue } from '../../clients/GongfengClient.js';\nimport type { DemandSpec } from '../DemandSpec.js';\nimport type { SupplementInfo } from '../../supplement/SupplementStore.js';\n\n/**\n * 将工蜂 Issue 转换为 DemandSpec 值对象。\n *\n * @param issue 工蜂 Issue 原始数据\n * @param supplement 可选的补充信息(来自 SupplementStore)\n */\nexport function gongfengIssueToDemandSpec(\n issue: GongfengIssue,\n supplement?: SupplementInfo | null,\n): DemandSpec {\n return {\n demandId: `gf-${issue.iid}`,\n sourceRef: {\n source: 'gongfeng-issue',\n externalId: String(issue.id),\n displayId: String(issue.iid),\n },\n title: issue.title,\n description: issue.description ?? '',\n supplement: supplement ? mapSupplement(supplement) : undefined,\n createdAt: issue.created_at ?? new Date().toISOString(),\n };\n}\n\nfunction mapSupplement(s: SupplementInfo): DemandSpec['supplement'] {\n const result: Record<string, string | undefined> = {};\n if (s.requirements?.trim()) result.requirements = s.requirements.trim();\n if (s.acceptanceCriteria?.trim()) result.acceptanceCriteria = s.acceptanceCriteria.trim();\n if (s.scope?.trim()) result.scope = s.scope.trim();\n if (s.constraints?.trim()) result.constraints = s.constraints.trim();\n if (s.references?.trim()) result.references = s.references.trim();\n if (s.freeText?.trim()) result.freeText = s.freeText.trim();\n if (s.tapdId?.trim()) result.tapdId = s.tapdId.trim();\n return Object.keys(result).length > 0 ? result : undefined;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { t } from '../i18n/index.js';\n\nconst TAPD_PATTERNS = [\n /--story=(\\d+)/i,\n /--bug=(\\d+)/i,\n /tapd[:\\s-]+(\\d+)/i,\n /tapd单号[:\\s]*(\\d+)/i,\n];\n\nexport function extractTapdId(text: string): string | null {\n for (const pattern of TAPD_PATTERNS) {\n const match = text.match(pattern);\n if (match) return match[1];\n }\n return null;\n}\n\nexport function generateMRTitle(issueIid: number, issueTitle: string, tapdId?: string | null): string {\n const base = `feat(#${issueIid}): ${issueTitle}`;\n if (tapdId) {\n return `${base} --story=${tapdId}`;\n }\n return base;\n}\n\nexport function generateMRDescription(options: {\n issueIid: number;\n issueTitle: string;\n issueDescription: string;\n branchName: string;\n planDir?: string;\n}): string {\n const { issueIid, issueTitle, issueDescription, branchName, planDir } = options;\n\n const sections: string[] = [\n t('mr.relatedIssue'),\n ``,\n `- Issue: #${issueIid}`,\n `- ${t('mr.title')}: ${issueTitle}`,\n `- ${t('mr.branch')}: \\`${branchName}\\``,\n ``,\n t('mr.issueDescription'),\n ``,\n issueDescription || t('mr.noDescription'),\n ];\n\n if (planDir) {\n const summaryFiles = [\n { filename: '01-analysis.md', label: t('mr.summaryFiles.01-analysis.md') },\n { filename: '01-plan.md', label: t('mr.summaryFiles.01-plan.md') },\n { filename: '02-design.md', label: t('mr.summaryFiles.02-design.md') },\n { filename: '04-verify-report.md', label: t('mr.summaryFiles.04-verify-report.md') },\n { filename: '02-verify-report.md', label: t('mr.summaryFiles.02-verify-report.md') },\n ];\n\n const planSections: string[] = [];\n for (const { filename, label } of summaryFiles) {\n const filePath = path.join(planDir, '.claude-plan', `issue-${issueIid}`, filename);\n if (fs.existsSync(filePath)) {\n const content = fs.readFileSync(filePath, 'utf-8');\n const summary = extractSummary(content);\n if (summary) {\n planSections.push(`### ${label}\\n\\n${summary}`);\n }\n }\n }\n\n if (planSections.length > 0) {\n sections.push('', t('mr.aiSummary'), '', ...planSections);\n }\n }\n\n sections.push('', '---', t('mr.autoCreated'));\n return sections.join('\\n');\n}\n\nfunction extractSummary(content: string, maxLines = 20): string {\n const lines = content.split('\\n');\n if (lines.length <= maxLines) return content.trim();\n return lines.slice(0, maxLines).join('\\n').trim() + '\\n\\n' + t('mr.truncated');\n}\n","import net from 'node:net';\nimport { PortExhaustionError } from '../errors/index.js';\nimport { logger as rootLogger } from '../logger.js';\n\nconst logger = rootLogger.child('PortAllocator');\n\nexport interface PortPair {\n backendPort: number;\n frontendPort: number;\n}\n\nexport interface PortAllocatorOptions {\n backendPortBase: number;\n frontendPortBase: number;\n maxPorts: number;\n}\n\nconst DEFAULT_OPTIONS: PortAllocatorOptions = {\n backendPortBase: 4000,\n frontendPortBase: 9000,\n maxPorts: 100,\n};\n\nfunction checkPortAvailable(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const server = net.createServer();\n server.once('error', () => resolve(false));\n server.once('listening', () => {\n server.close(() => resolve(true));\n });\n server.listen(port, '0.0.0.0');\n });\n}\n\nexport class PortAllocator {\n private allocated = new Map<number, PortPair>();\n private options: PortAllocatorOptions;\n\n constructor(options?: Partial<PortAllocatorOptions>) {\n this.options = { ...DEFAULT_OPTIONS, ...options };\n }\n\n async allocate(issueIid: number): Promise<PortPair> {\n const existing = this.allocated.get(issueIid);\n if (existing) {\n logger.info('Returning already allocated ports', { issueIid, ports: existing });\n return existing;\n }\n\n const usedBackend = new Set([...this.allocated.values()].map((p) => p.backendPort));\n const usedFrontend = new Set([...this.allocated.values()].map((p) => p.frontendPort));\n\n for (let offset = 1; offset <= this.options.maxPorts; offset++) {\n const backendPort = this.options.backendPortBase + offset;\n const frontendPort = this.options.frontendPortBase + offset;\n\n if (usedBackend.has(backendPort) || usedFrontend.has(frontendPort)) {\n continue;\n }\n\n const [beOk, feOk] = await Promise.all([\n checkPortAvailable(backendPort),\n checkPortAvailable(frontendPort),\n ]);\n\n if (beOk && feOk) {\n const pair: PortPair = { backendPort, frontendPort };\n this.allocated.set(issueIid, pair);\n logger.info('Ports allocated', { issueIid, ...pair });\n return pair;\n }\n\n logger.debug('Port pair unavailable, trying next', {\n backendPort,\n frontendPort,\n beOk,\n feOk,\n });\n }\n\n throw new PortExhaustionError(\n `No available port pair found for issue #${issueIid} ` +\n `(scanned ${this.options.maxPorts} offsets from ` +\n `backend=${this.options.backendPortBase} frontend=${this.options.frontendPortBase})`,\n );\n }\n\n release(issueIid: number): void {\n const pair = this.allocated.get(issueIid);\n if (pair) {\n this.allocated.delete(issueIid);\n logger.info('Ports released', { issueIid, ...pair });\n }\n }\n\n getPortsForIssue(issueIid: number): PortPair | undefined {\n return this.allocated.get(issueIid);\n }\n\n getAllAllocated(): Map<number, PortPair> {\n return new Map(this.allocated);\n }\n\n restore(issueIid: number, ports: PortPair): void {\n this.allocated.set(issueIid, ports);\n logger.info('Ports restored from persistence', { issueIid, ...ports });\n }\n}\n","import { spawn, ChildProcess } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport type { PortPair } from './PortAllocator.js';\nimport type { WorktreeContext } from '../git/WorktreeContext.js';\nimport { logger as rootLogger } from '../logger.js';\nimport { resolveDataDir } from '../paths.js';\n\nconst logger = rootLogger.child('DevServerManager');\n\ninterface ServerSet {\n backend: ChildProcess;\n frontend: ChildProcess;\n ports: PortPair;\n workDir: string;\n startedAt: string;\n backendLog: fs.WriteStream;\n frontendLog: fs.WriteStream;\n}\n\nexport interface DevServerManagerOptions {\n backendCommand?: { bin: string; args: string[] };\n frontendCommand?: { bin: string; args: string[] };\n}\n\nconst DEFAULT_OPTIONS: DevServerManagerOptions = {};\n\nexport class DevServerManager {\n private servers = new Map<number, ServerSet>();\n private options: DevServerManagerOptions;\n private logDir: string;\n\n constructor(options?: Partial<DevServerManagerOptions>) {\n this.options = { ...DEFAULT_OPTIONS, ...options };\n this.logDir = path.join(resolveDataDir(), 'preview-logs');\n if (!fs.existsSync(this.logDir)) {\n fs.mkdirSync(this.logDir, { recursive: true });\n }\n }\n\n getLogPath(issueIid: number, type: 'backend' | 'frontend'): string | null {\n const filePath = path.join(this.logDir, `${issueIid}-${type}.log`);\n return fs.existsSync(filePath) ? filePath : null;\n }\n\n async startServers(wtCtx: WorktreeContext, ports: PortPair): Promise<void> {\n if (this.servers.has(wtCtx.issueIid)) {\n logger.info('Servers already running for issue', { issueIid: wtCtx.issueIid });\n return;\n }\n\n logger.info('Starting dev servers', { issueIid: wtCtx.issueIid, ...ports });\n\n const backendLogPath = path.join(this.logDir, `${wtCtx.issueIid}-backend.log`);\n const frontendLogPath = path.join(this.logDir, `${wtCtx.issueIid}-frontend.log`);\n const backendLog = fs.createWriteStream(backendLogPath, { flags: 'a' });\n const frontendLog = fs.createWriteStream(frontendLogPath, { flags: 'a' });\n\n const tsLine = (stream: string, data: Buffer) =>\n `[${new Date().toISOString()}] [${stream}] ${data.toString().trimEnd()}\\n`;\n\n const backendEnv: Record<string, string> = {\n ...process.env as Record<string, string>,\n PORT: String(ports.backendPort),\n E2E_PORT_OVERRIDE: '1',\n ENV_PATH: '.env.development.local',\n };\n\n const backendCmd = this.options.backendCommand ?? { bin: 'node', args: ['ace', 'serve', '--watch'] };\n const backend = spawn(backendCmd.bin, backendCmd.args, {\n cwd: wtCtx.workDir,\n env: backendEnv,\n stdio: ['ignore', 'pipe', 'pipe'],\n detached: true,\n });\n\n backend.unref();\n backend.stdout?.on('data', (data: Buffer) => {\n backendLog.write(tsLine('stdout', data));\n });\n backend.stderr?.on('data', (data: Buffer) => {\n backendLog.write(tsLine('stderr', data));\n });\n backend.on('exit', (code) => {\n logger.info('Backend process exited', { issueIid: wtCtx.issueIid, code });\n });\n\n const frontendDir = path.join(wtCtx.workDir, 'frontend');\n const frontendEnv: Record<string, string> = {\n ...process.env as Record<string, string>,\n BACKEND_PORT: String(ports.backendPort),\n FRONTEND_PORT: String(ports.frontendPort),\n VITE_API_PORT: String(ports.backendPort),\n };\n\n const frontendCmd = this.options.frontendCommand\n ?? { bin: 'pnpm', args: ['dev', '--', '--port', String(ports.frontendPort), '--host'] };\n const frontend = spawn(frontendCmd.bin, frontendCmd.args, {\n cwd: frontendDir,\n env: frontendEnv,\n stdio: ['ignore', 'pipe', 'pipe'],\n detached: true,\n });\n\n frontend.unref();\n frontend.stdout?.on('data', (data: Buffer) => {\n frontendLog.write(tsLine('stdout', data));\n });\n frontend.stderr?.on('data', (data: Buffer) => {\n frontendLog.write(tsLine('stderr', data));\n });\n frontend.on('exit', (code) => {\n logger.info('Frontend process exited', { issueIid: wtCtx.issueIid, code });\n });\n\n const serverSet: ServerSet = {\n backend,\n frontend,\n ports,\n workDir: wtCtx.workDir,\n startedAt: new Date().toISOString(),\n backendLog,\n frontendLog,\n };\n this.servers.set(wtCtx.issueIid, serverSet);\n logger.info('Dev servers spawned, waiting for startup', { issueIid: wtCtx.issueIid, ...ports });\n\n await new Promise((r) => setTimeout(r, 10_000));\n logger.info('Dev servers startup grace period done', { issueIid: wtCtx.issueIid });\n }\n\n stopServers(issueIid: number): void {\n const set = this.servers.get(issueIid);\n if (!set) return;\n\n logger.info('Stopping dev servers', { issueIid, ports: set.ports });\n\n killProcess(set.backend, `backend #${issueIid}`);\n killProcess(set.frontend, `frontend #${issueIid}`);\n set.backendLog.end();\n set.frontendLog.end();\n\n this.servers.delete(issueIid);\n }\n\n stopAll(): void {\n for (const [iid] of this.servers) {\n this.stopServers(iid);\n }\n }\n\n getStatus(issueIid: number): { running: boolean; ports?: PortPair; startedAt?: string } {\n const set = this.servers.get(issueIid);\n if (!set) return { running: false };\n return {\n running: true,\n ports: set.ports,\n startedAt: set.startedAt,\n };\n }\n\n getRunningIssues(): number[] {\n return [...this.servers.keys()];\n }\n}\n\nfunction killProcess(proc: ChildProcess, label: string): void {\n try {\n if (proc.killed || proc.exitCode !== null) return;\n const pid = proc.pid;\n if (!pid) return;\n\n // detached: true 使子进程成为进程组长,-pid 杀死整个进程组(含 pnpm 的子 vite 等)\n try { process.kill(-pid, 'SIGTERM'); } catch { proc.kill('SIGTERM'); }\n\n setTimeout(() => {\n if (!proc.killed && proc.exitCode === null) {\n logger.warn(`Force killing ${label}`);\n try { process.kill(-pid, 'SIGKILL'); } catch { proc.kill('SIGKILL'); }\n }\n }, 5_000);\n } catch (err) {\n logger.warn(`Failed to kill ${label}`, { error: (err as Error).message });\n }\n}\n","import type { Config } from '../config.js';\nimport type { IssueTracker } from '../tracker/IssueTracker.js';\n\nlet e2eOverride: boolean | undefined;\n\nexport function getE2eEnabled(cfg: Config): boolean {\n return e2eOverride ?? cfg.e2e.enabled;\n}\n\nexport function setE2eOverride(value: boolean | undefined): void {\n e2eOverride = value;\n}\n\nexport function isE2eEnabledForIssue(\n issueIid: number,\n tracker: IssueTracker,\n cfg: Config,\n): boolean {\n const record = tracker.get(issueIid);\n if (record?.e2eEnabled !== undefined) return record.e2eEnabled;\n return getE2eEnabled(cfg);\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { logger as rootLogger } from '../logger.js';\n\nconst logger = rootLogger.child('ScreenshotCollector');\n\nconst MAX_SCREENSHOTS = 20;\n\nexport interface ScreenshotFile {\n filePath: string;\n testName: string;\n}\n\nfunction walkDir(dir: string, files: string[] = []): string[] {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n walkDir(full, files);\n } else if (entry.isFile() && entry.name.endsWith('.png')) {\n files.push(full);\n }\n }\n return files;\n}\n\n/**\n * 从 worktree 的 frontend/test-results/ 目录收集 E2E 截图。\n * Playwright 以 `screenshot: 'on'` 运行时,每个测试的截图保存在\n * `test-results/<project>-<test-name>-<browser>/` 子目录下。\n */\nexport function collectScreenshots(workDir: string): ScreenshotFile[] {\n const testResultsDir = path.join(workDir, 'frontend', 'test-results');\n if (!fs.existsSync(testResultsDir)) {\n logger.debug('test-results directory not found', { dir: testResultsDir });\n return [];\n }\n\n const pngFiles = walkDir(testResultsDir);\n if (pngFiles.length === 0) {\n logger.debug('No screenshots found');\n return [];\n }\n\n const screenshots: ScreenshotFile[] = pngFiles.map((filePath) => {\n const relative = path.relative(testResultsDir, filePath);\n const testName = relative.split(path.sep)[0] || path.basename(filePath, '.png');\n return { filePath, testName };\n });\n\n if (screenshots.length > MAX_SCREENSHOTS) {\n logger.warn('Too many screenshots, truncating', {\n total: screenshots.length,\n max: MAX_SCREENSHOTS,\n });\n return screenshots.slice(0, MAX_SCREENSHOTS);\n }\n\n logger.info('Screenshots collected', { count: screenshots.length });\n return screenshots;\n}\n","import { GongfengClient, UploadResult } from '../clients/GongfengClient.js';\nimport { collectScreenshots, ScreenshotFile } from './ScreenshotCollector.js';\nimport { logger as rootLogger } from '../logger.js';\nimport { t } from '../i18n/index.js';\n\nconst logger = rootLogger.child('ScreenshotPublisher');\n\nexport interface PublishOptions {\n workDir: string;\n issueIid: number;\n issueId: number;\n mrIid?: number;\n}\n\ninterface UploadedScreenshot {\n testName: string;\n markdown: string;\n}\n\nfunction buildComment(uploaded: UploadedScreenshot[], truncated: boolean): string {\n const lines: string[] = [t('screenshot.title'), ''];\n\n for (const item of uploaded) {\n lines.push(`### ${item.testName}`, '', item.markdown, '');\n }\n\n if (truncated) {\n lines.push(t('screenshot.truncated'), '');\n }\n\n return lines.join('\\n');\n}\n\nexport class ScreenshotPublisher {\n constructor(private gongfeng: GongfengClient) {}\n\n async publish(options: PublishOptions): Promise<void> {\n const { workDir, issueIid, issueId, mrIid } = options;\n\n const screenshots = collectScreenshots(workDir);\n if (screenshots.length === 0) {\n logger.info('No E2E screenshots to publish', { issueIid });\n return;\n }\n\n const uploaded = await this.uploadAll(screenshots);\n if (uploaded.length === 0) {\n logger.warn('All screenshot uploads failed', { issueIid });\n return;\n }\n\n const truncated = screenshots.length >= 20;\n const comment = buildComment(uploaded, truncated);\n\n await this.postToIssue(issueId, comment);\n\n if (mrIid) {\n await this.postToMergeRequest(mrIid, comment);\n }\n\n logger.info('E2E screenshots published', {\n issueIid,\n mrIid,\n count: uploaded.length,\n });\n }\n\n private async uploadAll(screenshots: ScreenshotFile[]): Promise<UploadedScreenshot[]> {\n const results: UploadedScreenshot[] = [];\n\n for (const screenshot of screenshots) {\n try {\n const result: UploadResult = await this.gongfeng.uploadFile(screenshot.filePath);\n results.push({\n testName: screenshot.testName,\n markdown: result.markdown,\n });\n } catch (err) {\n logger.warn('Failed to upload screenshot', {\n filePath: screenshot.filePath,\n error: (err as Error).message,\n });\n }\n }\n\n return results;\n }\n\n private async postToIssue(issueId: number, comment: string): Promise<void> {\n try {\n await this.gongfeng.createIssueNote(issueId, comment);\n } catch (err) {\n logger.warn('Failed to post screenshots to issue', {\n issueId,\n error: (err as Error).message,\n });\n }\n }\n\n private async postToMergeRequest(mrIid: number, comment: string): Promise<void> {\n try {\n await this.gongfeng.createMergeRequestNote(mrIid, comment);\n } catch (err) {\n logger.warn('Failed to post screenshots to merge request', {\n mrIid,\n error: (err as Error).message,\n });\n }\n }\n}\n","/**\n * Lightweight Prometheus-compatible metrics collector.\n *\n * Provides counters and histograms without external dependencies.\n * Expose via the `/metrics` endpoint in the Web server.\n */\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface MetricLabels {\n [key: string]: string;\n}\n\ninterface CounterEntry {\n type: 'counter';\n help: string;\n values: Map<string, number>;\n}\n\ninterface HistogramEntry {\n type: 'histogram';\n help: string;\n buckets: number[];\n /** key → { counts per bucket, sum, count } */\n values: Map<string, { bucketCounts: number[]; sum: number; count: number }>;\n}\n\ntype MetricEntry = CounterEntry | HistogramEntry;\n\n// ---------------------------------------------------------------------------\n// Label helpers\n// ---------------------------------------------------------------------------\n\nfunction labelsToKey(labels: MetricLabels): string {\n const pairs = Object.entries(labels).sort(([a], [b]) => a.localeCompare(b));\n if (pairs.length === 0) return '';\n return pairs.map(([k, v]) => `${k}=\"${v}\"`).join(',');\n}\n\nfunction keyToPromLabels(key: string): string {\n return key ? `{${key}}` : '';\n}\n\n// ---------------------------------------------------------------------------\n// Default histogram bucket boundaries\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_BUCKETS = [\n 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 30, 60, 120, 300, 600,\n];\n\n// ---------------------------------------------------------------------------\n// Collector\n// ---------------------------------------------------------------------------\n\nexport class MetricsCollector {\n private readonly metrics = new Map<string, MetricEntry>();\n\n // ── Counter ─────────────────────────────────────────────────────────\n\n /** Register a new counter. Idempotent if name already exists. */\n registerCounter(name: string, help: string): void {\n if (this.metrics.has(name)) return;\n this.metrics.set(name, { type: 'counter', help, values: new Map() });\n }\n\n /** Increment a counter by `delta` (default 1). */\n incCounter(name: string, labels: MetricLabels = {}, delta = 1): void {\n const entry = this.metrics.get(name);\n if (!entry || entry.type !== 'counter') return;\n const key = labelsToKey(labels);\n entry.values.set(key, (entry.values.get(key) ?? 0) + delta);\n }\n\n /** Read current value (for testing). */\n getCounter(name: string, labels: MetricLabels = {}): number {\n const entry = this.metrics.get(name);\n if (!entry || entry.type !== 'counter') return 0;\n return entry.values.get(labelsToKey(labels)) ?? 0;\n }\n\n // ── Histogram ───────────────────────────────────────────────────────\n\n /** Register a new histogram with optional custom buckets. */\n registerHistogram(name: string, help: string, buckets?: number[]): void {\n if (this.metrics.has(name)) return;\n const sortedBuckets = [...(buckets ?? DEFAULT_BUCKETS)].sort((a, b) => a - b);\n this.metrics.set(name, { type: 'histogram', help, buckets: sortedBuckets, values: new Map() });\n }\n\n /** Observe a value in a histogram. */\n observeHistogram(name: string, value: number, labels: MetricLabels = {}): void {\n const entry = this.metrics.get(name);\n if (!entry || entry.type !== 'histogram') return;\n const key = labelsToKey(labels);\n let data = entry.values.get(key);\n if (!data) {\n data = { bucketCounts: new Array(entry.buckets.length).fill(0), sum: 0, count: 0 };\n entry.values.set(key, data);\n }\n data.sum += value;\n data.count += 1;\n // Store in the smallest bucket that fits (non-cumulative)\n for (let i = 0; i < entry.buckets.length; i++) {\n if (value <= entry.buckets[i]) {\n data.bucketCounts[i] += 1;\n break;\n }\n }\n }\n\n // ── Timer helper ────────────────────────────────────────────────────\n\n /** Start a timer. Returns a function that, when called, observes the elapsed seconds. */\n startTimer(histogramName: string, labels: MetricLabels = {}): () => number {\n const start = performance.now();\n return () => {\n const elapsed = (performance.now() - start) / 1000;\n this.observeHistogram(histogramName, elapsed, labels);\n return elapsed;\n };\n }\n\n // ── Prometheus exposition ───────────────────────────────────────────\n\n /** Render all metrics in Prometheus text exposition format. */\n serialize(): string {\n const lines: string[] = [];\n\n for (const [name, entry] of this.metrics) {\n if (entry.type === 'counter') {\n lines.push(`# HELP ${name} ${entry.help}`);\n lines.push(`# TYPE ${name} counter`);\n for (const [key, value] of entry.values) {\n lines.push(`${name}${keyToPromLabels(key)} ${value}`);\n }\n } else if (entry.type === 'histogram') {\n lines.push(`# HELP ${name} ${entry.help}`);\n lines.push(`# TYPE ${name} histogram`);\n for (const [key, data] of entry.values) {\n const lblStr = key ? `,${key}` : '';\n let cumulative = 0;\n for (let i = 0; i < entry.buckets.length; i++) {\n cumulative += data.bucketCounts[i];\n lines.push(`${name}_bucket{le=\"${entry.buckets[i]}\"${lblStr}} ${cumulative}`);\n }\n lines.push(`${name}_bucket{le=\"+Inf\"${lblStr}} ${data.count}`);\n lines.push(`${name}_sum${keyToPromLabels(key)} ${data.sum}`);\n lines.push(`${name}_count${keyToPromLabels(key)} ${data.count}`);\n }\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n }\n\n /** Reset all metric values (for testing). */\n reset(): void {\n for (const entry of this.metrics.values()) {\n if (entry.type === 'counter') {\n entry.values.clear();\n } else if (entry.type === 'histogram') {\n entry.values.clear();\n }\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Singleton + pre-registered metrics\n// ---------------------------------------------------------------------------\n\nexport const metrics = new MetricsCollector();\n\n// Issue processing\nmetrics.registerCounter('iaf_issues_total', 'Total number of issues processed');\nmetrics.registerCounter('iaf_issues_succeeded_total', 'Number of successfully completed issues');\nmetrics.registerCounter('iaf_issues_failed_total', 'Number of failed issues');\nmetrics.registerCounter('iaf_issues_retried_total', 'Number of issue retries');\n\n// Phase execution\nmetrics.registerCounter('iaf_phases_total', 'Total number of phase executions');\nmetrics.registerCounter('iaf_phases_failed_total', 'Number of failed phase executions');\nmetrics.registerHistogram('iaf_phase_duration_seconds', 'Duration of phase execution in seconds', [\n 1, 5, 10, 30, 60, 120, 300, 600, 900, 1800,\n]);\n\n// AI runner\nmetrics.registerCounter('iaf_ai_calls_total', 'Total AI runner invocations');\nmetrics.registerCounter('iaf_ai_errors_total', 'AI runner errors');\nmetrics.registerHistogram('iaf_ai_duration_seconds', 'AI runner call duration in seconds', [\n 1, 5, 10, 30, 60, 120, 300, 600, 900, 1800,\n]);\n\n// Gongfeng API\nmetrics.registerCounter('iaf_gongfeng_requests_total', 'Total Gongfeng API requests');\nmetrics.registerCounter('iaf_gongfeng_errors_total', 'Gongfeng API errors');\nmetrics.registerHistogram('iaf_gongfeng_request_duration_seconds', 'Gongfeng API request duration in seconds', [\n 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10,\n]);\n\n// Webhook\nmetrics.registerCounter('iaf_webhook_commands_total', 'Total webhook commands received');\n\n// Braindump\nmetrics.registerCounter('iaf_braindump_batches_total', 'Total braindump batches');\nmetrics.registerCounter('iaf_braindump_tasks_total', 'Total braindump tasks');\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { GitOperations } from '../../git/GitOperations.js';\nimport { PlanPersistence } from '../../persistence/PlanPersistence.js';\nimport { IssueState } from '../../tracker/IssueState.js';\nimport type { IssueProcessingContext, OrchestratorDeps, SetupResult } from '../IssueProcessingContext.js';\nimport { HookInjector } from '../../hooks/index.js';\nimport { logger as rootLogger } from '../../logger.js';\nimport { t } from '../../i18n/index.js';\n\nconst logger = rootLogger.child('SetupStep');\n\nconst PLAN_DIR_NAME = '.claude-plan';\n\n/**\n * 清理 worktree 中不属于当前 Issue 的 .claude-plan/issue-* 目录。\n *\n * 当 base branch 包含已合并的旧 Issue plan 文件时,新 worktree 会继承它们,\n * 导致 AI agent 可能读取到错误 Issue 的计划内容。\n */\nexport function cleanupStalePlanDirs(workDir: string, currentIid: number): void {\n const claudePlanDir = path.join(workDir, PLAN_DIR_NAME);\n if (!fs.existsSync(claudePlanDir)) return;\n\n const currentDirName = `issue-${currentIid}`;\n let entries: string[];\n try {\n entries = fs.readdirSync(claudePlanDir);\n } catch {\n return;\n }\n\n for (const entry of entries) {\n if (entry.startsWith('issue-') && entry !== currentDirName) {\n const stalePath = path.join(claudePlanDir, entry);\n try {\n fs.rmSync(stalePath, { recursive: true, force: true });\n logger.info('Removed stale plan directory from worktree', {\n removed: entry, currentIid,\n });\n } catch (err) {\n logger.warn('Failed to remove stale plan directory', {\n path: stalePath, error: (err as Error).message,\n });\n }\n }\n }\n}\n\n/**\n * 执行 Issue 处理的初始化步骤:\n * - 更新标签为 processing\n * - fetch + 创建 worktree(受 mutex 保护,通过 WorkspaceManager)\n * - 更新状态为 BranchCreated\n * - 安装依赖\n * - 初始化 PlanPersistence(ensureDir, writeIssueMeta, writeProgress)\n */\nexport async function executeSetup(\n ctx: IssueProcessingContext,\n deps: OrchestratorDeps,\n): Promise<SetupResult> {\n const { issue, wtCtx, record, pipelineDef, branchName } = ctx;\n\n // 1. 更新标签\n try {\n await deps.gongfeng.updateIssueLabels(issue.id, [\n ...issue.labels.filter(l => !l.startsWith('auto-finish:')),\n 'auto-finish:processing',\n ]);\n } catch (err) {\n logger.warn('Failed to update issue labels', { error: (err as Error).message });\n }\n\n // 2. fetch + worktree (always via WorkspaceManager)\n await deps.mainGitMutex.runExclusive(async () => {\n deps.emitProgress(issue.iid, 'fetch', t('orchestrator.fetchProgress'));\n await deps.mainGit.fetch();\n deps.emitProgress(issue.iid, 'worktree', t('orchestrator.worktreeProgress'));\n await deps.ensureWorktree(wtCtx);\n });\n\n // 3. 更新状态为 BranchCreated\n if (record.state === IssueState.Pending) {\n deps.tracker.updateState(issue.iid, IssueState.BranchCreated);\n }\n\n // 4. 安装依赖\n deps.emitProgress(issue.iid, 'install', t('orchestrator.installProgress'));\n if (wtCtx.workspace) {\n await deps.installDependencies(wtCtx.workspace.primary.workDir);\n for (const assoc of wtCtx.workspace.associates) {\n await deps.installDependencies(assoc.workDir);\n }\n } else {\n await deps.installDependencies(wtCtx.workDir);\n }\n\n // 5. 初始化 PlanPersistence(在 primary repo)\n deps.emitProgress(issue.iid, 'init_plan', t('orchestrator.initPlanProgress'));\n const primaryWorkDir = wtCtx.workspace ? wtCtx.workspace.primary.workDir : wtCtx.workDir;\n const primaryGitRoot = wtCtx.workspace ? wtCtx.workspace.primary.gitRootDir : wtCtx.gitRootDir;\n const wtGit = new GitOperations(primaryGitRoot);\n const wtPlan = new PlanPersistence(primaryWorkDir, issue.iid);\n\n cleanupStalePlanDirs(primaryWorkDir, issue.iid);\n wtPlan.ensureDir();\n wtPlan.writeIssueMeta({\n id: issue.id,\n iid: issue.iid,\n title: issue.title,\n labels: issue.labels,\n state: issue.state,\n });\n\n const existingProgress = wtPlan.readProgress();\n if (!existingProgress || !ctx.isRetry) {\n wtPlan.writeProgress(\n wtPlan.createInitialProgress(issue.iid, issue.title, branchName, pipelineDef),\n );\n }\n\n // 同步阶段进度到 tracker(处理旧记录无 phaseProgress 的情况)\n if (!record.phaseProgress) {\n deps.tracker.initPhaseProgress(issue.iid, pipelineDef);\n }\n\n // 5b. 注入 Claude Code hooks(PTY 模式下自动加载)\n const allArtifacts = pipelineDef.phases\n .flatMap(p => p.artifacts ?? [])\n .map(a => a.filename);\n if (allArtifacts.length > 0) {\n try {\n const firstPhase = pipelineDef.phases.find(p => p.kind === 'ai');\n const firstPhaseArtifacts = (firstPhase?.artifacts ?? []).map(a => a.filename);\n const hookInjector = new HookInjector();\n hookInjector.inject({\n workDir: primaryWorkDir,\n planDir: wtPlan.planDir,\n expectedArtifacts: allArtifacts,\n phaseExpectedArtifacts: firstPhaseArtifacts,\n issueIid: issue.iid,\n phaseName: firstPhase?.name,\n issueTitle: issue.title,\n issueDescription: issue.description,\n });\n } catch (err) {\n logger.warn('Failed to inject Claude Code hooks (non-blocking)', {\n error: (err as Error).message,\n });\n }\n }\n\n // 6. 构建 wtGitMap\n const wtGitMap = new Map<string, GitOperations>();\n if (wtCtx.workspace) {\n wtGitMap.set(wtCtx.workspace.primary.name, wtGit);\n for (const assoc of wtCtx.workspace.associates) {\n wtGitMap.set(assoc.name, new GitOperations(assoc.gitRootDir));\n }\n } else {\n wtGitMap.set('primary', wtGit);\n }\n\n return { wtGit, wtPlan, wtGitMap };\n}\n","import type { DialogOption, InputRequest } from '../ai-runner/AIRunner.js';\n\n// ── PhaseFeedback: 统一的中间反馈模型 ──\n\nexport type PhaseFeedback =\n | InteractiveDialogFeedback\n | ApprovalRequiredFeedback\n | PermissionRequestFeedback\n | GenericFeedback;\n\nexport interface InteractiveDialogFeedback {\n kind: 'interactive-dialog';\n question: string;\n options: DialogOption[];\n}\n\nexport interface ApprovalRequiredFeedback {\n kind: 'approval-required';\n scope: 'plan' | 'release' | 'uat';\n}\n\nexport interface PermissionRequestFeedback {\n kind: 'permission-request';\n tool: string;\n detail: unknown;\n}\n\nexport interface GenericFeedback {\n kind: 'generic';\n content: string;\n}\n\n// ── FeedbackResponse: 外部对反馈的统一应答 ──\n\nexport type FeedbackResponse =\n | { action: 'approve' }\n | { action: 'reject'; reason?: string }\n | { action: 'select'; value: string }\n | { action: 'dismiss' }\n | { action: 'pause' };\n\n// ── ErrorDecision: hook 对阶段失败的处置决策 ──\n\nexport type ErrorDecision =\n | { action: 'fail'; softFail: boolean }\n | { action: 'retry' }\n | { action: 'skip' };\n\n// ── PhaseError: 传递给 onError hook 的结构化错误信息 ──\n\nexport interface PhaseError {\n message: string;\n isRetryable: boolean;\n rawOutput: string;\n wasActiveAtTimeout: boolean;\n}\n\n// ── InputRequest ↔ PhaseFeedback 双向转换 ──\n\nexport function inputRequestToFeedback(request: InputRequest): PhaseFeedback {\n switch (request.type) {\n case 'interactive-dialog':\n return {\n kind: 'interactive-dialog',\n question: request.content,\n options: request.options ?? [],\n };\n case 'plan-approval':\n return { kind: 'approval-required', scope: 'plan' };\n case 'generic':\n return { kind: 'generic', content: request.content };\n }\n}\n\nexport function feedbackToInputRequest(feedback: PhaseFeedback): InputRequest {\n switch (feedback.kind) {\n case 'interactive-dialog':\n return { type: 'interactive-dialog', content: feedback.question, options: feedback.options };\n case 'approval-required':\n return { type: 'plan-approval', content: feedback.scope };\n case 'permission-request':\n return { type: 'generic', content: JSON.stringify(feedback.detail) };\n case 'generic':\n return { type: 'generic', content: feedback.content };\n }\n}\n\nexport function feedbackResponseToString(response: FeedbackResponse): string {\n switch (response.action) {\n case 'approve': return 'allow';\n case 'reject': return 'reject';\n case 'select': return response.value;\n case 'dismiss': return '';\n case 'pause': return '';\n }\n}\n\nexport function stringToFeedbackResponse(str: string, originalFeedback: PhaseFeedback): FeedbackResponse {\n if (str === 'allow') return { action: 'approve' };\n if (str === 'reject') return { action: 'reject' };\n if (str === '') {\n return originalFeedback.kind === 'interactive-dialog'\n ? { action: 'dismiss' }\n : { action: 'approve' };\n }\n return { action: 'select', value: str };\n}\n","import type { Config } from '../config.js';\nimport type { IssueTracker } from '../tracker/IssueTracker.js';\nimport { t } from '../i18n/index.js';\n\nlet noteSyncOverride: boolean | undefined;\n\nexport function getNoteSyncEnabled(cfg: Config): boolean {\n return noteSyncOverride ?? cfg.issueNoteSync.enabled;\n}\n\nexport function setNoteSyncOverride(value: boolean | undefined): void {\n noteSyncOverride = value;\n}\n\nexport function isNoteSyncEnabledForIssue(\n issueIid: number,\n tracker: IssueTracker,\n cfg: Config,\n): boolean {\n const record = tracker.get(issueIid);\n if (record?.issueNoteSyncEnabled !== undefined) return record.issueNoteSyncEnabled;\n return getNoteSyncEnabled(cfg);\n}\n\nconst SUMMARY_MAX_LENGTH = 500;\n\nexport function truncateToSummary(content: string): string {\n if (content.length <= SUMMARY_MAX_LENGTH) return content;\n const cut = content.slice(0, SUMMARY_MAX_LENGTH);\n const lastNewline = cut.lastIndexOf('\\n\\n');\n const boundary = lastNewline > SUMMARY_MAX_LENGTH * 0.3 ? lastNewline : cut.lastIndexOf('\\n');\n const summary = boundary > SUMMARY_MAX_LENGTH * 0.3 ? cut.slice(0, boundary) : cut;\n return summary + '\\n\\n...';\n}\n\nexport interface ResultFileSpec {\n filename: string;\n label: string;\n}\n\nexport function buildNoteSyncComment(\n phaseName: string,\n phaseLabel: string,\n docUrl: string,\n dashboardUrl: string,\n summary: string,\n): string {\n const emoji: Record<string, string> = {\n analysis: '🔍', design: '📐', implement: '💻', verify: '✅',\n plan: '📋', review: '👀', build: '🔨',\n };\n const icon = emoji[phaseName] || '📋';\n return [\n t('notesync.phaseCompleted', { icon, label: phaseLabel }),\n '',\n summary,\n '',\n '---',\n t('notesync.viewDoc', { label: phaseLabel, url: docUrl }),\n t('notesync.viewDashboard', { url: dashboardUrl }),\n ].join('\\n');\n}\n","import type { DialogOption } from '../ai-runner/AIRunner.js';\n\nexport interface PendingDialogInfo {\n issueIid: number;\n question: string;\n options: DialogOption[];\n phase: string;\n timestamp: string;\n}\n\n/**\n * In-memory store for pending interactive dialogs.\n *\n * SSE events are ephemeral — if the browser misses one (page refresh,\n * reconnect, slow load) the dialog is lost and the backend blocks forever.\n * This store keeps the dialog queryable via REST so the frontend can\n * recover it on load / reconnect.\n */\nconst store = new Map<number, PendingDialogInfo>();\n\nexport function setPendingDialog(info: PendingDialogInfo): void {\n store.set(info.issueIid, info);\n}\n\nexport function getPendingDialog(issueIid: number): PendingDialogInfo | undefined {\n return store.get(issueIid);\n}\n\nexport function clearPendingDialog(issueIid: number): void {\n store.delete(issueIid);\n}\n","/**\n * 从 PhaseLoopStep 提取的编排级辅助函数。\n *\n * 供 PhaseLoopStep、DefaultLifecycleHook、各 PhaseStrategy 共用,\n * 避免循环依赖。\n */\nimport type { GitOperations } from '../../git/GitOperations.js';\nimport type { PlanPersistence } from '../../persistence/PlanPersistence.js';\nimport type { AIRunner, InputRequest } from '../../ai-runner/index.js';\nimport type { BasePhase, PhaseContext } from '../../phases/BasePhase.js';\nimport type { PhaseSpec, PipelineDef } from '../../pipeline/PipelineDefinition.js';\nimport type { IssueProcessingContext, OrchestratorDeps } from '../IssueProcessingContext.js';\nimport { HookInjector } from '../../hooks/index.js';\nimport { isE2eEnabledForIssue } from '../../e2e/E2eSettings.js';\nimport { isNoteSyncEnabledForIssue } from '../../notesync/NoteSyncSettings.js';\nimport { truncateToSummary, buildNoteSyncComment } from '../../notesync/NoteSyncSettings.js';\nimport { issueProgressComment } from '../../prompts/templates.js';\nimport { setPendingDialog, clearPendingDialog } from '../PendingDialogStore.js';\nimport { cleanupStalePlanDirs } from './SetupStep.js';\nimport { logger as rootLogger } from '../../logger.js';\nimport { t } from '../../i18n/index.js';\n\nconst logger = rootLogger.child('PhaseHelpers');\n\n// ── 安全评论 ──\n\nexport async function safeComment(deps: OrchestratorDeps, issueId: number, message: string): Promise<void> {\n try {\n await deps.gongfeng.createIssueNote(issueId, message);\n } catch { /* ignore */ }\n}\n\n// ── Runner 解析 ──\n\nexport function resolveVerifyRunner(deps: OrchestratorDeps): AIRunner {\n return deps.aiRunner;\n}\n\nexport function resolveUatRunner(deps: OrchestratorDeps, issueIid: number): AIRunner {\n if (deps.e2eAiRunner && isE2eEnabledForIssue(issueIid, deps.tracker, deps.config)) {\n return deps.e2eAiRunner;\n }\n return deps.aiRunner;\n}\n\n// ── Git 提交 ──\n\nexport async function commitPlanFiles(\n ctx: PhaseContext,\n wtGit: GitOperations,\n wtGitMap: Map<string, GitOperations> | undefined,\n phaseName: string,\n displayId: number,\n planWorkDir?: string,\n): Promise<void> {\n if (planWorkDir) {\n cleanupStalePlanDirs(planWorkDir, displayId);\n }\n\n const commitMsg = `chore(auto): ${phaseName} phase completed for issue #${displayId}`;\n\n if (ctx.workspace && ctx.workspace.repos.length > 1) {\n for (const repo of ctx.workspace.repos) {\n const repoGit = wtGitMap?.get(repo.name);\n if (!repoGit) {\n logger.warn('Missing GitOperations for repo, skipping commit', { repo: repo.name });\n continue;\n }\n const branch = repo.branchPrefix\n ? `${repo.branchPrefix}-${displayId}`\n : ctx.branchName;\n try {\n if (await repoGit.hasChanges()) {\n await repoGit.add(['.']);\n await repoGit.commit(commitMsg);\n await repoGit.push(branch);\n logger.info('Committed changes for repo', { repo: repo.name, branch });\n }\n } catch (err) {\n logger.warn('Failed to commit/push for repo', {\n repo: repo.name,\n error: (err as Error).message,\n });\n }\n }\n } else {\n if (await wtGit.hasChanges()) {\n await wtGit.add(['.']);\n await wtGit.commit(commitMsg);\n await wtGit.push(ctx.branchName);\n }\n }\n}\n\n// ── 产物同步到 Issue ──\n\nexport async function syncResultToIssue(\n phase: BasePhase,\n ctx: PhaseContext,\n displayId: number,\n phaseName: string,\n deps: OrchestratorDeps,\n issueId: number,\n wtPlan: PlanPersistence,\n): Promise<void> {\n try {\n const enabled = isNoteSyncEnabledForIssue(displayId, deps.tracker, deps.config);\n const resultFiles = phase.getResultFiles(ctx);\n\n if (!enabled || resultFiles.length === 0) {\n await safeComment(deps, issueId, issueProgressComment(phaseName, 'completed'));\n return;\n }\n\n const baseUrl = deps.config.issueNoteSync.webBaseUrl.replace(/\\/$/, '');\n const phaseLabel = t(`phase.${phaseName}`) || phaseName;\n const dashboardUrl = `${baseUrl}/?issue=${displayId}`;\n\n for (const file of resultFiles) {\n const content = wtPlan.readFile(file.filename);\n if (!content) continue;\n\n const summary = truncateToSummary(content);\n const docUrl = `${baseUrl}/doc/${displayId}/${file.filename}`;\n const comment = buildNoteSyncComment(\n phaseName, file.label || phaseLabel, docUrl, dashboardUrl, summary,\n );\n\n await safeComment(deps, issueId, comment);\n logger.info('Result synced to issue', { issueIid: displayId, file: file.filename });\n }\n } catch (err) {\n logger.warn('Failed to sync result to issue', { error: (err as Error).message });\n await safeComment(deps, issueId, issueProgressComment(phaseName, 'completed'));\n }\n}\n\n// ── 输入请求处理 ──\n\nexport function handlePlanApproval(\n displayId: number,\n phaseName: string,\n deps: OrchestratorDeps,\n): Promise<string> {\n logger.info('ACP plan-approval requested, delegating to review gate', {\n issueIid: displayId, phase: phaseName,\n });\n deps.eventBus.emitTyped('review:requested', { issueIid: displayId });\n\n return new Promise<string>((resolve) => {\n const onApproved = (payload: { data: unknown }) => {\n const data = payload.data as { issueIid?: number };\n if (data.issueIid !== displayId) return;\n cleanup();\n logger.info('ACP plan-approval approved via review gate', { issueIid: displayId });\n resolve('allow');\n };\n const onRejected = (payload: { data: unknown }) => {\n const data = payload.data as { issueIid?: number };\n if (data.issueIid !== displayId) return;\n cleanup();\n logger.info('ACP plan-approval rejected via review gate', { issueIid: displayId });\n resolve('reject');\n };\n const cleanup = () => {\n deps.eventBus.removeListener('review:approved', onApproved);\n deps.eventBus.removeListener('review:rejected', onRejected);\n };\n deps.eventBus.on('review:approved', onApproved);\n deps.eventBus.on('review:rejected', onRejected);\n });\n}\n\nexport function handleInteractiveDialog(\n displayId: number,\n phaseName: string,\n deps: OrchestratorDeps,\n request: InputRequest,\n): Promise<string> {\n logger.info('Interactive dialog forwarded to frontend', {\n issueIid: displayId, phase: phaseName,\n question: request.content.slice(0, 80),\n optionCount: request.options?.length,\n });\n\n const options = request.options ?? [];\n\n setPendingDialog({\n issueIid: displayId,\n question: request.content,\n options,\n phase: phaseName,\n timestamp: new Date().toISOString(),\n });\n\n deps.eventBus.emitTyped('agent:inputRequired', {\n issueIid: displayId,\n phase: phaseName,\n question: request.content,\n options,\n });\n\n return new Promise<string>((resolve) => {\n const cleanup = () => {\n deps.eventBus.removeListener('agent:inputResponse', onResponse);\n deps.eventBus.removeListener('agent:dialogDismissed', onDismiss);\n };\n\n const onResponse = (payload: { data: unknown }) => {\n const data = payload.data as { issueIid?: number; response?: string };\n if (data.issueIid !== displayId) return;\n cleanup();\n clearPendingDialog(displayId);\n logger.info('Interactive dialog response received from frontend', {\n issueIid: displayId, response: data.response,\n });\n resolve(data.response ?? '1');\n };\n\n const onDismiss = (payload: { data: unknown }) => {\n const data = payload.data as { issueIid?: number };\n if (data.issueIid !== displayId) return;\n cleanup();\n logger.info('Interactive dialog dismissed by user (false positive)', { issueIid: displayId });\n resolve('');\n };\n\n deps.eventBus.on('agent:inputResponse', onResponse);\n deps.eventBus.on('agent:dialogDismissed', onDismiss);\n });\n}\n\n// ── Hooks 更新 ──\n\nexport function updateHooksForPhase(\n spec: PhaseSpec,\n pipelineDef: PipelineDef,\n ctx: IssueProcessingContext,\n wtPlan: PlanPersistence,\n): void {\n const phaseArtifacts = (spec.artifacts ?? []).map(a => a.filename);\n if (phaseArtifacts.length === 0 && spec.kind !== 'ai') return;\n\n try {\n const allArtifacts = pipelineDef.phases\n .flatMap(p => p.artifacts ?? [])\n .map(a => a.filename);\n const hookInjector = new HookInjector();\n hookInjector.updateForPhase({\n workDir: wtPlan.baseDir,\n planDir: wtPlan.planDir,\n expectedArtifacts: allArtifacts.length > 0 ? allArtifacts : phaseArtifacts,\n phaseExpectedArtifacts: phaseArtifacts,\n issueIid: ctx.issue.iid,\n phaseName: spec.name,\n issueTitle: ctx.issue.title,\n issueDescription: ctx.issue.description,\n });\n } catch (err) {\n logger.warn('Failed to update hooks for phase (non-blocking)', {\n phase: spec.name,\n error: (err as Error).message,\n });\n }\n}\n\n// ── 工具函数 ──\n\nexport function findPreviousAiPhaseIndex(\n phases: readonly { kind: string }[],\n currentIdx: number,\n): number {\n for (let j = currentIdx - 1; j >= 0; j--) {\n if (phases[j].kind === 'ai') return j;\n }\n return -1;\n}\n","/**\n * 默认阶段生命周期 Hook 实现。\n *\n * 从 `runPhaseWithLifecycle` 提取的 Pre/Execute/Post 逻辑,\n * 行为与重构前完全一致。\n */\nimport { IssueState } from '../tracker/IssueState.js';\nimport { issueProgressComment } from '../prompts/templates.js';\nimport { logger as rootLogger } from '../logger.js';\nimport { t } from '../i18n/index.js';\nimport type { StreamEvent } from '../ai-runner/AIRunner.js';\nimport type { PhaseOutcome } from '../phases/PhaseOutcome.js';\nimport type { PhaseLifecycleHook, PhaseExecutionContext } from './PhaseLifecycleHook.js';\nimport type { PhaseFeedback, FeedbackResponse, PhaseError, ErrorDecision } from './FeedbackTypes.js';\nimport {\n inputRequestToFeedback,\n feedbackResponseToString,\n stringToFeedbackResponse,\n} from './FeedbackTypes.js';\nimport {\n safeComment,\n commitPlanFiles,\n syncResultToIssue,\n handlePlanApproval,\n handleInteractiveDialog,\n} from '../orchestrator/steps/PhaseHelpers.js';\n\nconst logger = rootLogger.child('DefaultLifecycleHook');\n\nexport class DefaultLifecycleHook implements PhaseLifecycleHook {\n async beforePhase(ctx: PhaseExecutionContext): Promise<void> {\n const { spec, issueCtx, deps, wtPlan } = ctx;\n const { issue } = issueCtx;\n const displayId = issue.iid;\n\n deps.tracker.updateState(displayId, spec.startState, { currentPhase: spec.name });\n deps.tracker.updatePhaseProgress(displayId, spec.name, {\n status: 'in_progress', startedAt: new Date().toISOString(),\n });\n wtPlan.updatePhaseProgress(spec.name, 'in_progress');\n await safeComment(deps, issue.id, issueProgressComment(spec.name, 'in_progress'));\n\n const phaseLabel = t(`phase.${spec.name}`) || spec.name;\n deps.eventBus.emitTyped('agent:output', {\n issueIid: displayId,\n phase: spec.name,\n event: {\n type: 'system',\n content: t('basePhase.aiStarting', { label: phaseLabel }),\n timestamp: new Date().toISOString(),\n },\n });\n }\n\n onStream(ctx: PhaseExecutionContext, event: StreamEvent): void {\n const { spec, issueCtx, deps } = ctx;\n deps.eventBus.emitTyped('agent:output', {\n issueIid: issueCtx.issue.iid,\n phase: spec.name,\n event,\n });\n }\n\n beforeExecute?: undefined;\n\n afterExecute?: undefined;\n\n async onFeedback(ctx: PhaseExecutionContext, feedback: PhaseFeedback): Promise<FeedbackResponse> {\n const { deps, displayId, spec } = ctx;\n\n if (feedback.kind === 'interactive-dialog') {\n const result = await handleInteractiveDialog(displayId, spec.name, deps, {\n type: 'interactive-dialog',\n content: feedback.question,\n options: feedback.options,\n });\n return stringToFeedbackResponse(result, feedback);\n }\n\n if (feedback.kind === 'approval-required' && feedback.scope === 'plan') {\n const useAcpGate = deps.config.ai.codebuddyAcpAutoApprove === false;\n if (useAcpGate) {\n const result = await handlePlanApproval(displayId, spec.name, deps);\n return result === 'allow' ? { action: 'approve' } : { action: 'reject' };\n }\n return { action: 'approve' };\n }\n\n return { action: 'approve' };\n }\n\n async afterPhase(ctx: PhaseExecutionContext, outcome: PhaseOutcome): Promise<void> {\n const { spec, issueCtx, deps, wtGit, wtPlan, wtGitMap, phase } = ctx;\n const { issue, phaseCtx } = issueCtx;\n const displayId = issue.iid;\n\n if (outcome.sessionId) {\n wtPlan.updatePhaseSessionId(spec.name, outcome.sessionId);\n }\n\n deps.tracker.updateState(displayId, spec.doneState, { currentPhase: spec.name });\n deps.tracker.updatePhaseProgress(displayId, spec.name, {\n status: 'completed', completedAt: new Date().toISOString(),\n });\n wtPlan.updatePhaseProgress(spec.name, 'completed');\n\n await commitPlanFiles(phaseCtx, wtGit, wtGitMap, spec.name, displayId, wtPlan.baseDir);\n\n if (phase) {\n await syncResultToIssue(phase, phaseCtx, displayId, spec.name, deps, issue.id, wtPlan);\n }\n }\n\n async onError(ctx: PhaseExecutionContext, error: PhaseError): Promise<ErrorDecision> {\n const { spec, issueCtx, deps, wtPlan } = ctx;\n const { issue } = issueCtx;\n const displayId = issue.iid;\n\n wtPlan.updatePhaseProgress(spec.name, 'failed', error.message);\n deps.tracker.updatePhaseProgress(displayId, spec.name, { status: 'failed' });\n\n if (error.wasActiveAtTimeout) {\n deps.tracker.markFailedSoft(displayId, error.message, IssueState.PhaseRunning);\n } else {\n deps.tracker.markFailed(displayId, error.message, IssueState.PhaseRunning);\n }\n\n const shortErr = error.message.slice(0, 200);\n await safeComment(deps, issue.id, issueProgressComment(spec.name, 'failed', shortErr));\n\n return { action: 'fail', softFail: error.wasActiveAtTimeout };\n }\n}\n\n/**\n * 从 PhaseLifecycleHook 创建 PhaseCallbacks(供 BasePhase.run() 使用)。\n *\n * 将标准化的 hook 接口适配为 BasePhase 期望的旧式回调,\n * 实现了 PhaseFeedback/FeedbackResponse ↔ InputRequest/string 的双向转换。\n */\nexport function createCallbacksFromHook(\n hook: PhaseLifecycleHook,\n ctx: PhaseExecutionContext,\n): import('../phases/PhaseOutcome.js').PhaseCallbacks {\n return {\n onStreamEvent: hook.onStream\n ? (event) => hook.onStream!(ctx, event)\n : undefined,\n onInputRequired: hook.onFeedback\n ? async (request) => {\n const feedback = inputRequestToFeedback(request);\n const response = await hook.onFeedback!(ctx, feedback);\n return feedbackResponseToString(response);\n }\n : undefined,\n };\n}\n","import type { PhaseExecutionContext, PhaseLifecycleHook, PhaseStepResult } from '../../lifecycle/PhaseLifecycleHook.js';\nimport type { PhaseStrategy } from './PhaseStrategy.js';\nimport { logger as rootLogger } from '../../logger.js';\nimport { t } from '../../i18n/index.js';\n\nconst logger = rootLogger.child('GateStrategy');\n\n/**\n * Gate 阶段策略 — 处理审核门禁(如 review 阶段)。\n *\n * 两种路径:\n * 1. 标签匹配自动批准 → 标记完成并继续\n * 2. 暂停等待人工审核 → 发事件后返回 paused=true\n */\nexport class GateStrategy implements PhaseStrategy {\n readonly name = 'gate';\n\n shouldSkip(): boolean {\n return false;\n }\n\n async execute(ctx: PhaseExecutionContext, _hooks: PhaseLifecycleHook): Promise<PhaseStepResult> {\n const { spec, issueCtx, deps, wtPlan } = ctx;\n const { issue } = issueCtx;\n\n if (deps.shouldAutoApprove(issue.labels)) {\n logger.info('Auto-approving review gate (matched autoApproveLabels)', {\n iid: issue.iid,\n labels: issue.labels,\n autoApproveLabels: deps.config.review.autoApproveLabels,\n });\n\n if (spec.approvedState) {\n deps.tracker.updateState(issue.iid, spec.approvedState, { currentPhase: spec.name });\n }\n wtPlan.updatePhaseProgress(spec.name, 'completed');\n deps.tracker.updatePhaseProgress(issue.iid, spec.name, {\n status: 'completed', completedAt: new Date().toISOString(),\n });\n\n try {\n await deps.gongfeng.createIssueNote(issue.id, t('orchestrator.autoApproveComment'));\n } catch { /* ignore */ }\n\n return { paused: false };\n }\n\n deps.tracker.updateState(issue.iid, spec.startState, { currentPhase: spec.name });\n wtPlan.updatePhaseProgress(spec.name, 'in_progress');\n deps.tracker.updatePhaseProgress(issue.iid, spec.name, {\n status: 'in_progress', startedAt: new Date().toISOString(),\n });\n deps.eventBus.emitTyped('review:requested', { issueIid: issue.iid });\n logger.info('Review gate reached, pausing', { iid: issue.iid });\n\n return { paused: true };\n }\n}\n","import { IssueState } from '../../tracker/IssueState.js';\nimport { AIExecutionError } from '../../errors/index.js';\nimport { createPhase } from '../../phases/PhaseFactory.js';\nimport { isE2eEnabledForIssue } from '../../e2e/E2eSettings.js';\nimport type { PhaseOutcome } from '../../phases/PhaseOutcome.js';\nimport type { PhaseExecutionContext, PhaseLifecycleHook, PhaseStepResult } from '../../lifecycle/PhaseLifecycleHook.js';\nimport type { PhaseStrategy } from './PhaseStrategy.js';\nimport { runPhaseWithLifecycle } from '../steps/PhaseLoopStep.js';\nimport {\n resolveVerifyRunner,\n resolveUatRunner,\n commitPlanFiles,\n syncResultToIssue,\n updateHooksForPhase,\n safeComment,\n} from '../steps/PhaseHelpers.js';\nimport { issueProgressComment } from '../../prompts/templates.js';\nimport { logger as rootLogger } from '../../logger.js';\n\nconst logger = rootLogger.child('AiPhaseStrategy');\n\n/**\n * 标准 AI 阶段策略 — 处理所有 kind='ai' 的阶段。\n *\n * 覆盖:plan、build、uat(非 verify-fix 循环的 verify 也走这里)。\n * 处理异步阶段(awaitCompletion)、gate 请求(hasReleaseCapability)。\n */\nexport class AiPhaseStrategy implements PhaseStrategy {\n readonly name = 'ai';\n\n shouldSkip(ctx: PhaseExecutionContext): boolean {\n const { spec, issueCtx, deps } = ctx;\n if (spec.name === 'uat' && !isE2eEnabledForIssue(issueCtx.issue.iid, deps.tracker, deps.config)) {\n logger.info('UAT phase skipped (E2E not enabled for this issue)', { iid: issueCtx.issue.iid });\n return true;\n }\n return false;\n }\n\n async execute(ctx: PhaseExecutionContext, hooks: PhaseLifecycleHook): Promise<PhaseStepResult> {\n const { spec, issueCtx, deps, wtGit, wtPlan, wtGitMap } = ctx;\n const { issue, phaseCtx } = issueCtx;\n\n // 跳过逻辑(shouldSkip=true 时由调用方标记完成,但保险起见也在这里检查)\n if (this.shouldSkip(ctx)) {\n deps.tracker.updateState(issue.iid, spec.doneState, { currentPhase: spec.name });\n wtPlan.updatePhaseProgress(spec.name, 'completed');\n deps.tracker.updatePhaseProgress(issue.iid, spec.name, {\n status: 'completed', completedAt: new Date().toISOString(),\n });\n return { paused: false };\n }\n\n updateHooksForPhase(spec, issueCtx.pipelineDef, issueCtx, wtPlan);\n\n const runner = this.resolveRunner(ctx);\n\n if (spec.name === 'uat') {\n const runnerName = runner === deps.e2eAiRunner ? 'e2eAiRunner (CodeBuddy)' : 'mainRunner';\n logger.info('UAT phase starting', { iid: issue.iid, runner: runnerName });\n }\n\n const phase = createPhase(spec.name, runner, wtGit, wtPlan, deps.config);\n if (wtGitMap) phase.setWtGitMap(wtGitMap);\n ctx.phase = phase;\n\n const outcome = await runPhaseWithLifecycle(\n phase, phaseCtx, spec, issueCtx, deps, wtGit, wtPlan, wtGitMap, hooks,\n );\n\n // ── 异步阶段(status='running')──\n if (outcome.status === 'running') {\n return this.handleAsyncOutcome(ctx, outcome);\n }\n\n // ── AI 阶段请求 gate 暂停(如 release 检测到发布能力) ──\n if (spec.approvedState && outcome.data?.hasReleaseCapability) {\n return this.handleGateRequest(ctx);\n }\n\n return { paused: false };\n }\n\n private resolveRunner(ctx: PhaseExecutionContext) {\n const { spec, deps, displayId } = ctx;\n if (spec.name === 'verify') return resolveVerifyRunner(deps);\n if (spec.name === 'uat') return resolveUatRunner(deps, displayId);\n return deps.aiRunner;\n }\n\n private async handleAsyncOutcome(\n ctx: PhaseExecutionContext,\n outcome: PhaseOutcome,\n ): Promise<PhaseStepResult> {\n const { spec, issueCtx, deps, wtGit, wtPlan, wtGitMap } = ctx;\n const { issue, phaseCtx } = issueCtx;\n\n if (outcome.awaitCompletion) {\n logger.info('Async phase running, awaiting completion', { iid: issue.iid, phase: spec.name });\n const finalOutcome = await outcome.awaitCompletion;\n\n if (finalOutcome.sessionId) {\n wtPlan.updatePhaseSessionId(spec.name, finalOutcome.sessionId);\n }\n\n if (finalOutcome.status === 'completed') {\n deps.tracker.updateState(issue.iid, spec.doneState, { currentPhase: spec.name });\n deps.tracker.updatePhaseProgress(issue.iid, spec.name, {\n status: 'completed', completedAt: new Date().toISOString(),\n });\n wtPlan.updatePhaseProgress(spec.name, 'completed');\n await commitPlanFiles(phaseCtx, wtGit, wtGitMap, spec.name, issue.iid, wtPlan.baseDir);\n\n const runner = this.resolveRunner(ctx);\n const phase = createPhase(spec.name, runner, wtGit, wtPlan, deps.config);\n await syncResultToIssue(phase, phaseCtx, issue.iid, spec.name, deps, issue.id, wtPlan);\n\n logger.info('Async phase completed successfully', { iid: issue.iid, phase: spec.name });\n return { paused: false };\n }\n\n // failed\n const errMsg = finalOutcome.error?.message ?? 'Unknown error';\n const shortErr = errMsg.slice(0, 200);\n const wasActive = finalOutcome.error?.wasActiveAtTimeout ?? false;\n wtPlan.updatePhaseProgress(spec.name, 'failed', errMsg);\n deps.tracker.updatePhaseProgress(issue.iid, spec.name, { status: 'failed' });\n if (wasActive) {\n deps.tracker.markFailedSoft(issue.iid, errMsg, IssueState.PhaseRunning);\n } else {\n deps.tracker.markFailed(issue.iid, errMsg, IssueState.PhaseRunning);\n }\n await safeComment(deps, issue.id, issueProgressComment(spec.name, 'failed', shortErr));\n\n throw new AIExecutionError(spec.name, `Phase ${spec.name} failed: ${shortErr}`, {\n output: finalOutcome.error?.rawOutput ?? finalOutcome.output,\n exitCode: finalOutcome.exitCode ?? 1,\n isRetryable: finalOutcome.error?.isRetryable,\n wasActiveAtTimeout: wasActive,\n });\n }\n\n // 无 awaitCompletion 的 running 阶段 → 暂停等待外部触发\n deps.tracker.updateState(issue.iid, IssueState.PhaseWaiting, { currentPhase: spec.name });\n wtPlan.updatePhaseProgress(spec.name, 'gate_waiting');\n deps.tracker.updatePhaseProgress(issue.iid, spec.name, { status: 'gate_waiting' });\n const gateEvent = spec.name === 'uat' ? 'uat:gateRequested' : 'release:gateRequested';\n deps.eventBus.emitTyped(gateEvent, { issueIid: issue.iid });\n logger.info('Async phase running (no awaitCompletion), pausing pipeline', {\n iid: issue.iid, phase: spec.name,\n });\n\n return { paused: true };\n }\n\n private handleGateRequest(ctx: PhaseExecutionContext): PhaseStepResult {\n const { spec, issueCtx, deps, wtPlan } = ctx;\n const { issue } = issueCtx;\n\n deps.tracker.updateState(issue.iid, IssueState.PhaseWaiting, { currentPhase: spec.name });\n wtPlan.updatePhaseProgress(spec.name, 'gate_waiting');\n deps.tracker.updatePhaseProgress(issue.iid, spec.name, { status: 'gate_waiting' });\n deps.eventBus.emitTyped('release:gateRequested', { issueIid: issue.iid });\n logger.info('Phase requested gate, pausing', { iid: issue.iid, phase: spec.name });\n\n return { paused: true };\n }\n}\n","import { ServiceShutdownError, AIExecutionError } from '../../errors/index.js';\nimport { isShuttingDown } from '../../shutdown/ShutdownSignal.js';\nimport { createPhase } from '../../phases/PhaseFactory.js';\nimport type { PhaseOutcome } from '../../phases/PhaseOutcome.js';\nimport type { GitOperations } from '../../git/GitOperations.js';\nimport type { PlanPersistence } from '../../persistence/PlanPersistence.js';\nimport type { PhaseExecutionContext, PhaseLifecycleHook, PhaseStepResult } from '../../lifecycle/PhaseLifecycleHook.js';\nimport type { PhaseStrategy } from './PhaseStrategy.js';\nimport type { IssueProcessingContext, OrchestratorDeps } from '../IssueProcessingContext.js';\nimport { runPhaseWithLifecycle } from '../steps/PhaseLoopStep.js';\nimport { resolveVerifyRunner, updateHooksForPhase } from '../steps/PhaseHelpers.js';\nimport { logger as rootLogger } from '../../logger.js';\n\nconst logger = rootLogger.child('VerifyFixStrategy');\n\n/**\n * Verify-Fix 循环策略。\n *\n * 多次迭代 verify → build fix → verify,直到验证通过或达到最大迭代次数。\n */\nexport class VerifyFixStrategy implements PhaseStrategy {\n readonly name = 'verify-fix';\n\n shouldSkip(): boolean {\n return false;\n }\n\n async execute(ctx: PhaseExecutionContext, hooks: PhaseLifecycleHook): Promise<PhaseStepResult> {\n const { issueCtx, deps, wtGit, wtPlan, wtGitMap } = ctx;\n const { issue, phaseCtx, pipelineDef } = issueCtx;\n const maxIterations = deps.config.verifyFixLoop.maxIterations;\n const verifySpec = ctx.spec;\n\n const verifyPhaseIdx = pipelineDef.phases.findIndex(p => p.name === verifySpec.name);\n const buildPhaseIdx = this.findPreviousAiPhaseIndex(pipelineDef.phases, verifyPhaseIdx);\n\n deps.eventBus.emitTyped('verify:loopStarted', {\n issueIid: issue.iid,\n maxIterations,\n });\n\n logger.info('Verify-fix loop started', {\n iid: issue.iid,\n maxIterations,\n buildPhaseIdx,\n });\n\n for (let iteration = 1; iteration <= maxIterations; iteration++) {\n if (isShuttingDown()) throw new ServiceShutdownError();\n\n logger.info('Verify-fix loop iteration', { iteration, maxIterations, iid: issue.iid });\n\n updateHooksForPhase(verifySpec, pipelineDef, issueCtx, wtPlan);\n\n const verifyRunner = resolveVerifyRunner(deps);\n const verifyPhase = createPhase('verify', verifyRunner, wtGit, wtPlan, deps.config);\n if (wtGitMap) verifyPhase.setWtGitMap(wtGitMap);\n\n let verifyOutcome: PhaseOutcome;\n try {\n verifyOutcome = await runPhaseWithLifecycle(\n verifyPhase, phaseCtx, verifySpec, issueCtx, deps, wtGit, wtPlan, wtGitMap, hooks,\n );\n } catch (err) {\n logger.warn('Verify phase execution failed', {\n iteration, iid: issue.iid, error: (err as Error).message,\n });\n\n deps.eventBus.emitTyped('verify:iterationComplete', {\n issueIid: issue.iid, iteration, passed: false,\n failures: ['AI runner execution failed'],\n });\n\n if (iteration === maxIterations) throw err;\n\n if (buildPhaseIdx >= 0) {\n await this.executeBuildFix(issueCtx, deps, wtGit, wtPlan, buildPhaseIdx, {\n iteration,\n verifyFailures: ['AI runner execution failed: ' + (err as Error).message],\n rawReport: '',\n }, wtGitMap, hooks);\n }\n continue;\n }\n\n const report = verifyOutcome.data?.verifyReport as import('../../verify/index.js').VerifyReportResult | undefined;\n const passed = report ? report.passed : true;\n\n deps.eventBus.emitTyped('verify:iterationComplete', {\n issueIid: issue.iid, iteration, passed,\n failures: report?.failureReasons,\n });\n\n if (passed) {\n logger.info('Verify-fix loop passed', { iteration, iid: issue.iid });\n return { paused: false };\n }\n\n logger.info('Verify failed, issues found', {\n iteration, iid: issue.iid,\n failures: report?.failureReasons,\n todolistStats: report?.todolistStats,\n });\n\n if (iteration === maxIterations) {\n deps.eventBus.emitTyped('verify:loopExhausted', {\n issueIid: issue.iid,\n totalIterations: iteration,\n failures: report?.failureReasons ?? [],\n });\n\n const failMsg = `Verify-fix loop exhausted after ${maxIterations} iterations. ` +\n `Remaining issues: ${report?.failureReasons?.join('; ') ?? 'unknown'}`;\n logger.warn(failMsg, { iid: issue.iid });\n\n throw new AIExecutionError('verify', failMsg, {\n output: report?.rawReport ?? '',\n exitCode: 0,\n });\n }\n\n if (buildPhaseIdx >= 0) {\n await this.executeBuildFix(issueCtx, deps, wtGit, wtPlan, buildPhaseIdx, {\n iteration,\n verifyFailures: report?.failureReasons ?? [],\n rawReport: report?.rawReport ?? '',\n }, wtGitMap, hooks);\n }\n }\n\n return { paused: false };\n }\n\n private async executeBuildFix(\n ctx: IssueProcessingContext,\n deps: OrchestratorDeps,\n wtGit: GitOperations,\n wtPlan: PlanPersistence,\n buildPhaseIdx: number,\n fixContext: { iteration: number; verifyFailures: string[]; rawReport: string },\n wtGitMap: Map<string, GitOperations> | undefined,\n hooks: PhaseLifecycleHook,\n ): Promise<void> {\n const { issue, phaseCtx, pipelineDef } = ctx;\n const buildSpec = pipelineDef.phases[buildPhaseIdx];\n\n logger.info('Looping back to build for fix', {\n iteration: fixContext.iteration, iid: issue.iid,\n failures: fixContext.verifyFailures,\n });\n\n phaseCtx.fixContext = fixContext;\n\n try {\n updateHooksForPhase(buildSpec, pipelineDef, ctx, wtPlan);\n\n const buildPhase = createPhase('build', deps.aiRunner, wtGit, wtPlan, deps.config);\n if (wtGitMap) buildPhase.setWtGitMap(wtGitMap);\n\n await runPhaseWithLifecycle(\n buildPhase, phaseCtx, buildSpec, ctx, deps, wtGit, wtPlan, wtGitMap, hooks,\n );\n } finally {\n delete phaseCtx.fixContext;\n }\n }\n\n private findPreviousAiPhaseIndex(\n phases: readonly { kind: string }[],\n currentIdx: number,\n ): number {\n for (let j = currentIdx - 1; j >= 0; j--) {\n if (phases[j].kind === 'ai') return j;\n }\n return -1;\n }\n}\n","import type { PhaseSpec } from '../../pipeline/PipelineDefinition.js';\nimport type { Config } from '../../config.js';\nimport type { PhaseStrategy } from './PhaseStrategy.js';\nimport { GateStrategy } from './GateStrategy.js';\nimport { AiPhaseStrategy } from './AiPhaseStrategy.js';\nimport { VerifyFixStrategy } from './VerifyFixStrategy.js';\n\nexport type { PhaseStrategy } from './PhaseStrategy.js';\nexport { GateStrategy } from './GateStrategy.js';\nexport { AiPhaseStrategy } from './AiPhaseStrategy.js';\nexport { VerifyFixStrategy } from './VerifyFixStrategy.js';\n\n// ── 策略单例 ──\n\nconst gateStrategy = new GateStrategy();\nconst aiStrategy = new AiPhaseStrategy();\nconst verifyFixStrategy = new VerifyFixStrategy();\n\n/**\n * 根据阶段规格和配置解析对应的执行策略。\n *\n * 解析优先级:\n * 1. kind='gate' → GateStrategy\n * 2. name='verify' + verifyFixLoop.enabled → VerifyFixStrategy\n * 3. 其它 kind='ai' → AiPhaseStrategy(含 uat/release 等特殊处理)\n */\nexport function resolveStrategy(spec: PhaseSpec, config: Config): PhaseStrategy {\n if (spec.kind === 'gate') {\n return gateStrategy;\n }\n\n if (spec.name === 'verify' && config.verifyFixLoop.enabled) {\n return verifyFixStrategy;\n }\n\n return aiStrategy;\n}\n","import type { GitOperations } from '../../git/GitOperations.js';\nimport type { PlanPersistence } from '../../persistence/PlanPersistence.js';\nimport type { BasePhase } from '../../phases/BasePhase.js';\nimport type { PhaseOutcome } from '../../phases/PhaseOutcome.js';\nimport type { PhaseSpec } from '../../pipeline/PipelineDefinition.js';\nimport { ServiceShutdownError, AIExecutionError, PhaseAbortedError } from '../../errors/index.js';\nimport { isShuttingDown } from '../../shutdown/ShutdownSignal.js';\nimport type { IssueProcessingContext, OrchestratorDeps, PhaseLoopResult } from '../IssueProcessingContext.js';\nimport type { PhaseLifecycleHook, PhaseExecutionContext } from '../../lifecycle/PhaseLifecycleHook.js';\nimport type { PhaseError } from '../../lifecycle/FeedbackTypes.js';\nimport { DefaultLifecycleHook, createCallbacksFromHook } from '../../lifecycle/DefaultLifecycleHook.js';\nimport { resolveStrategy } from '../strategies/index.js';\nimport { logger as rootLogger } from '../../logger.js';\nimport { t } from '../../i18n/index.js';\n\nconst logger = rootLogger.child('PhaseLoopStep');\n\n/**\n * 统一的阶段执行包装器 — 通过 PhaseLifecycleHook 驱动完整生命周期。\n *\n * beforePhase → Execute (phase.run with callbacks) → afterPhase / onError\n */\nexport async function runPhaseWithLifecycle(\n phase: BasePhase,\n phaseCtx: import('../../phases/BasePhase.js').PhaseContext,\n spec: PhaseSpec,\n ctx: IssueProcessingContext,\n deps: OrchestratorDeps,\n wtGit: GitOperations,\n wtPlan: PlanPersistence,\n wtGitMap?: Map<string, GitOperations>,\n hook?: PhaseLifecycleHook,\n): Promise<PhaseOutcome> {\n const lifecycleHook = hook ?? new DefaultLifecycleHook();\n const execCtx: PhaseExecutionContext = {\n spec,\n issueCtx: ctx,\n deps,\n wtGit,\n wtPlan,\n wtGitMap,\n phase,\n displayId: ctx.issue.iid,\n };\n\n // ── 1. beforePhase ──\n await lifecycleHook.beforePhase(execCtx);\n\n // ── 2. beforeExecute (optional) ──\n if (lifecycleHook.beforeExecute) {\n await lifecycleHook.beforeExecute(execCtx);\n }\n\n // ── 3. Execute: 从 hook 创建 PhaseCallbacks 并执行 ──\n const callbacks = createCallbacksFromHook(lifecycleHook, execCtx);\n const outcome = await phase.run(phaseCtx, callbacks);\n\n // ── 4. Session 持久化 ──\n if (outcome.sessionId) wtPlan.updatePhaseSessionId(spec.name, outcome.sessionId);\n\n // ── 5. afterExecute (optional) — 可注入自定义验证 ──\n const finalOutcome = lifecycleHook.afterExecute\n ? await lifecycleHook.afterExecute(execCtx, outcome)\n : outcome;\n\n // ── 6. 根据结果路由 ──\n if (finalOutcome.status === 'completed') {\n await lifecycleHook.afterPhase(execCtx, finalOutcome);\n return finalOutcome;\n }\n\n if (finalOutcome.status === 'running') {\n return finalOutcome;\n }\n\n // status === 'failed'\n const errMsg = finalOutcome.error?.message ?? 'Unknown error';\n const phaseError: PhaseError = {\n message: errMsg,\n isRetryable: finalOutcome.error?.isRetryable ?? true,\n rawOutput: finalOutcome.error?.rawOutput ?? finalOutcome.output,\n wasActiveAtTimeout: finalOutcome.error?.wasActiveAtTimeout ?? false,\n };\n\n await lifecycleHook.onError(execCtx, phaseError);\n\n const shortErr = errMsg.slice(0, 200);\n throw new AIExecutionError(spec.name, `Phase ${spec.name} failed: ${shortErr}`, {\n output: finalOutcome.error?.rawOutput ?? finalOutcome.output,\n exitCode: finalOutcome.exitCode ?? 1,\n isRetryable: finalOutcome.error?.isRetryable,\n wasActiveAtTimeout: finalOutcome.error?.wasActiveAtTimeout ?? false,\n });\n}\n\n/**\n * 执行流水线阶段循环:\n * - 确定恢复阶段索引\n * - 逐个执行阶段\n * - 处理 gate 阶段(自动批准或等待审核)\n * - 执行 AI 阶段(通过 runPhaseWithLifecycle)\n * - 按需启动预览服务器\n * - verify 阶段支持 verify-fix loop(验证失败自动回退 build 修复)\n *\n * 如果到达 gate 阶段且不自动批准,该函数 return 且 `paused` 为 true。\n */\nexport async function executePhaseLoop(\n ctx: IssueProcessingContext,\n deps: OrchestratorDeps,\n wtGit: GitOperations,\n wtPlan: PlanPersistence,\n wtGitMap?: Map<string, GitOperations>,\n): Promise<PhaseLoopResult & { paused: boolean }> {\n const { issue, pipelineDef, lifecycleManager, record, isRetry, phaseCtx } = ctx;\n\n const startIdx = lifecycleManager.determineResumePhaseIndex(\n record.state,\n isRetry ? record.failedAtState : undefined,\n record.currentPhase,\n );\n\n deps.emitProgress(\n issue.iid,\n 'phase_start',\n t('orchestrator.phaseStartProgress', {\n phase: pipelineDef.phases[startIdx]?.name ?? 'start',\n }),\n );\n\n const needsDeployment = deps.shouldDeployServers(issue.iid);\n let serversStarted = false;\n\n if (needsDeployment && startIdx > 0) {\n const skippedDeployPhase = pipelineDef.phases\n .slice(0, startIdx)\n .some(p => p.deploysPreview);\n\n if (skippedDeployPhase && !phaseCtx.ports) {\n const existingPorts = deps.getPortsForIssue(issue.iid);\n if (existingPorts && deps.isPreviewRunning(issue.iid)) {\n logger.info('Restored preview ports from allocator', { iid: issue.iid, ...existingPorts });\n phaseCtx.ports = existingPorts;\n ctx.wtCtx.ports = existingPorts;\n serversStarted = true;\n } else {\n if (existingPorts) {\n logger.info('Ports allocated but servers not running, restarting', { iid: issue.iid });\n } else {\n logger.info('Restarting preview servers for resumed pipeline', { iid: issue.iid });\n }\n const ports = await deps.startPreviewServers(ctx.wtCtx, issue);\n if (ports) {\n phaseCtx.ports = ports;\n ctx.wtCtx.ports = ports;\n serversStarted = true;\n }\n }\n }\n }\n\n // 自愈:恢复执行时,确保所有前置阶段的 progress 已标记为 completed。\n if (startIdx > 0) {\n healStaleProgress(ctx, deps, wtPlan, startIdx);\n }\n\n // ── 策略调度循环 ──\n const hooks = new DefaultLifecycleHook();\n\n for (let i = startIdx; i < pipelineDef.phases.length; i++) {\n if (isShuttingDown()) throw new ServiceShutdownError();\n\n const spec = pipelineDef.phases[i];\n\n const pendingAction = deps.consumePendingAction?.(issue.iid);\n if (pendingAction) throw new PhaseAbortedError(spec.name, pendingAction);\n\n const strategy = resolveStrategy(spec, deps.config);\n\n const execCtx: PhaseExecutionContext = {\n spec,\n issueCtx: ctx,\n deps,\n wtGit,\n wtPlan,\n wtGitMap,\n displayId: issue.iid,\n };\n\n // 跳过检查\n if (strategy.shouldSkip(execCtx)) {\n deps.tracker.updateState(issue.iid, spec.doneState, { currentPhase: spec.name });\n wtPlan.updatePhaseProgress(spec.name, 'completed');\n deps.tracker.updatePhaseProgress(issue.iid, spec.name, {\n status: 'completed', completedAt: new Date().toISOString(),\n });\n continue;\n }\n\n // 策略执行\n const result = await strategy.execute(execCtx, hooks);\n\n if (result.paused) {\n return { serversStarted: serversStarted || !!result.serversStarted, paused: true };\n }\n\n if (result.serversStarted) {\n serversStarted = true;\n }\n\n // 按需启动预览服务器\n if (needsDeployment && !serversStarted && lifecycleManager.shouldDeployPreview(spec.name)) {\n const ports = await deps.startPreviewServers(ctx.wtCtx, issue);\n if (ports) {\n phaseCtx.ports = ports;\n ctx.wtCtx.ports = ports;\n serversStarted = true;\n }\n }\n }\n\n return { serversStarted, paused: false };\n}\n\n// ── 内部辅助函数 ──\n\n/**\n * 自愈:恢复执行时,确保所有前置阶段的 progress 已标记为 completed。\n */\nfunction healStaleProgress(\n ctx: IssueProcessingContext,\n deps: OrchestratorDeps,\n wtPlan: PlanPersistence,\n startIdx: number,\n): void {\n const { issue, pipelineDef, record } = ctx;\n\n const currentProgress = wtPlan.readProgress();\n if (currentProgress) {\n let patched = false;\n for (let i = 0; i < startIdx; i++) {\n const prevSpec = pipelineDef.phases[i];\n const pp = currentProgress.phases[prevSpec.name];\n if (pp && pp.status !== 'completed') {\n logger.warn('Fixing stale phase progress', {\n iid: issue.iid, phase: prevSpec.name, was: pp.status, now: 'completed',\n });\n pp.status = 'completed';\n if (!pp.completedAt) {\n pp.completedAt = new Date().toISOString();\n }\n patched = true;\n }\n }\n if (patched) {\n wtPlan.writeProgress(currentProgress);\n }\n }\n\n if (record.phaseProgress) {\n for (let i = 0; i < startIdx; i++) {\n const prevSpec = pipelineDef.phases[i];\n const tp = record.phaseProgress[prevSpec.name];\n if (tp && tp.status !== 'completed') {\n deps.tracker.updatePhaseProgress(issue.iid, prevSpec.name, {\n status: 'completed',\n completedAt: tp.completedAt ?? new Date().toISOString(),\n });\n }\n }\n }\n}\n\n","import { IssueState } from '../../tracker/IssueState.js';\nimport { isE2eEnabledForIssue } from '../../e2e/E2eSettings.js';\nimport type { GitOperations } from '../../git/GitOperations.js';\nimport { metrics } from '../../metrics/MetricsCollector.js';\n\nimport type { IssueProcessingContext, OrchestratorDeps, PhaseLoopResult } from '../IssueProcessingContext.js';\nimport { logger as rootLogger } from '../../logger.js';\nimport { t } from '../../i18n/index.js';\n\nconst logger = rootLogger.child('CompletionStep');\n\nexport async function executeCompletion(\n ctx: IssueProcessingContext,\n deps: OrchestratorDeps,\n phaseResult: PhaseLoopResult,\n _wtGitMap?: Map<string, GitOperations>,\n): Promise<void> {\n const { issue, branchName, wtCtx } = ctx;\n\n deps.emitProgress(issue.iid, 'create_mr', t('orchestrator.createMrProgress'));\n const previewUrl = phaseResult.serversStarted ? deps.buildPreviewUrl(issue.iid) : null;\n\n const mrResult = await deps.tryCreateMergeRequest(issue, branchName, wtCtx.workDir, previewUrl);\n const mrUrl = mrResult?.url ?? null;\n\n const stateExtra: Record<string, unknown> = {};\n if (mrUrl) stateExtra.mrUrl = mrUrl;\n deps.tracker.updateState(\n issue.iid,\n IssueState.Completed,\n Object.keys(stateExtra).length > 0 ? stateExtra : undefined,\n );\n metrics.incCounter('iaf_issues_succeeded_total', { pipeline: ctx.pipelineDef.mode });\n\n try {\n await deps.gongfeng.updateIssueLabels(issue.id, [\n ...issue.labels.filter(l => !l.startsWith('auto-finish:') && l !== 'auto-finish'),\n 'auto-finish:done',\n ]);\n } catch { /* ignore */ }\n\n if (isE2eEnabledForIssue(issue.iid, deps.tracker, deps.config)) {\n deps.emitProgress(issue.iid, 'screenshots', t('orchestrator.uploadScreenshotsProgress'));\n try {\n await deps.screenshotPublisher.publish({\n workDir: wtCtx.workDir,\n issueIid: issue.iid,\n issueId: issue.id,\n mrIid: undefined,\n });\n } catch (err) {\n logger.warn('Failed to publish E2E screenshots', {\n iid: issue.iid,\n error: (err as Error).message,\n });\n }\n }\n\n const mrSection = mrUrl\n ? t('orchestrator.mrSection', { mrUrl })\n : t('orchestrator.mrFailSection');\n const previewSection = previewUrl ? `\\n\\ud83c\\udf10 Preview: ${previewUrl}` : '';\n try {\n await deps.gongfeng.createIssueNote(\n issue.id,\n t('orchestrator.completedComment', { branch: branchName, mrSection, previewSection }),\n );\n } catch { /* ignore */ }\n\n if (deps.claimer) {\n await deps.claimer.releaseClaim(issue.id, issue.iid, 'completed');\n }\n\n if (phaseResult.serversStarted && deps.config.preview.keepAfterComplete) {\n logger.info('Preview servers kept running after completion', { iid: issue.iid });\n } else {\n deps.stopPreviewServers(issue.iid);\n await deps.mainGitMutex.runExclusive(async () => {\n if (wtCtx.workspace) {\n await deps.workspaceManager.cleanupWorkspace(wtCtx.workspace);\n logger.info('Workspace cleaned up', { dir: wtCtx.workspace.workspaceRoot });\n } else {\n try {\n await deps.mainGit.worktreeRemove(wtCtx.gitRootDir, true);\n logger.info('Worktree cleaned up', { dir: wtCtx.gitRootDir });\n } catch (err) {\n logger.warn('Failed to cleanup worktree', {\n dir: wtCtx.gitRootDir,\n error: (err as Error).message,\n });\n }\n }\n });\n }\n\n logger.info('Issue processing completed', { iid: issue.iid });\n}\n","import { IssueState } from '../../tracker/IssueState.js';\nimport type { GongfengIssue } from '../../clients/GongfengClient.js';\nimport type { WorktreeContext } from '../../git/WorktreeContext.js';\nimport { metrics } from '../../metrics/MetricsCollector.js';\nimport type { OrchestratorDeps } from '../IssueProcessingContext.js';\nimport { AIExecutionError } from '../../errors/index.js';\nimport { logger as rootLogger } from '../../logger.js';\nimport { t } from '../../i18n/index.js';\n\nconst logger = rootLogger.child('FailureHandler');\n\nexport async function handleFailure(\n err: unknown,\n issue: GongfengIssue,\n wtCtx: WorktreeContext,\n deps: OrchestratorDeps,\n): Promise<void> {\n const errorMsg = (err as Error).message;\n const isRetryable = err instanceof AIExecutionError ? err.isRetryable : true;\n const wasActiveAtTimeout = err instanceof AIExecutionError && err.wasActiveAtTimeout;\n logger.error('Issue processing failed', { iid: issue.iid, error: errorMsg, isRetryable, wasActiveAtTimeout });\n metrics.incCounter('iaf_issues_failed_total');\n\n const currentRecord = deps.tracker.get(issue.iid);\n const failedAtState = currentRecord?.state || IssueState.Pending;\n const wasReset = failedAtState === IssueState.Pending && currentRecord?.attempts === 0;\n\n if (failedAtState !== IssueState.Failed && !wasReset) {\n if (wasActiveAtTimeout) {\n deps.tracker.markFailedSoft(issue.iid, errorMsg.slice(0, 500), failedAtState);\n } else {\n deps.tracker.markFailed(issue.iid, errorMsg.slice(0, 500), failedAtState, isRetryable);\n }\n }\n\n if (wasReset) {\n logger.info('Issue was reset during processing, skipping failure marking', { iid: issue.iid });\n throw err;\n }\n\n // 中止操作已在 catch 块中将状态设为 Paused,此处跳过失败处理(含 preview 停止)\n if (failedAtState === IssueState.Paused) {\n logger.info('Issue was paused during processing, skipping failure handling', { iid: issue.iid });\n throw err;\n }\n\n try {\n await deps.gongfeng.updateIssueLabels(issue.id, [\n ...issue.labels.filter(l => !l.startsWith('auto-finish:') && l !== 'auto-finish'),\n 'auto-finish', 'auto-finish:failed',\n ]);\n } catch { /* ignore */ }\n\n try {\n await deps.gongfeng.createIssueNote(\n issue.id,\n t('orchestrator.failedComment', { error: errorMsg }),\n );\n } catch { /* ignore */ }\n\n if (deps.claimer) {\n try {\n await deps.claimer.releaseClaim(issue.id, issue.iid, 'failed');\n } catch (releaseErr) {\n logger.warn('Failed to release lock on failure', {\n iid: issue.iid,\n error: (releaseErr as Error).message,\n });\n }\n }\n\n deps.stopPreviewServers(issue.iid);\n\n const preservedDirs = wtCtx.workspace\n ? [wtCtx.workspace.primary.gitRootDir, ...wtCtx.workspace.associates.map(a => a.gitRootDir)]\n : [wtCtx.gitRootDir];\n logger.info('Worktree(s) preserved for debugging', {\n primary: wtCtx.gitRootDir,\n all: preservedDirs,\n });\n throw err;\n}\n","import { randomUUID } from 'node:crypto';\nimport { logger as rootLogger } from '../logger.js';\nimport type { AIRunner, RunResult, StreamEvent } from '../ai-runner/AIRunner.js';\nimport { createAIRunner, type AIConfig } from '../ai-runner/index.js';\nimport type { BrainstormAgentConfig, Config } from '../config.js';\nimport {\n buildGeneratePrompt,\n buildReviewPrompt,\n buildRefinePrompt,\n} from '../prompts/brainstorm-templates.js';\n\nconst logger = rootLogger.child('Brainstorm');\n\nexport interface BrainstormRound {\n round: number;\n questions: string;\n refinedSdd: string;\n}\n\nexport type BrainstormStatus =\n | 'idle'\n | 'generating'\n | 'reviewing'\n | 'refining'\n | 'done'\n | 'error';\n\nexport interface BrainstormSession {\n id: string;\n transcript: string;\n currentSdd: string;\n rounds: BrainstormRound[];\n status: BrainstormStatus;\n error?: string;\n generatorSessionId?: string;\n createdAt: string;\n}\n\nexport interface BrainstormStreamEvent {\n type: 'sdd:chunk' | 'sdd:complete' | 'review:chunk' | 'review:complete'\n | 'round:start' | 'round:complete' | 'error';\n data: unknown;\n round?: number;\n}\n\nfunction agentConfigToAIConfig(\n agentCfg: BrainstormAgentConfig,\n timeoutMs: number,\n): AIConfig {\n return {\n mode: agentCfg.mode,\n binary: agentCfg.binary,\n phaseTimeoutMs: timeoutMs,\n nvmNodeVersion: agentCfg.nvmNodeVersion,\n model: agentCfg.model,\n };\n}\n\nexport class BrainstormService {\n private sessions = new Map<string, BrainstormSession>();\n private generatorRunner: AIRunner;\n private reviewerRunner: AIRunner;\n private config: Config['brainstorm'];\n private workDir: string;\n\n constructor(config: Config) {\n this.config = config.brainstorm;\n this.workDir = config.project.workDir;\n this.generatorRunner = createAIRunner(\n agentConfigToAIConfig(this.config.generator, this.config.timeoutMs),\n );\n this.reviewerRunner = createAIRunner(\n agentConfigToAIConfig(this.config.reviewer, this.config.timeoutMs),\n );\n }\n\n createSession(transcript: string): BrainstormSession {\n const session: BrainstormSession = {\n id: randomUUID(),\n transcript,\n currentSdd: '',\n rounds: [],\n status: 'idle',\n createdAt: new Date().toISOString(),\n };\n this.sessions.set(session.id, session);\n logger.info('Created brainstorm session', { sessionId: session.id });\n return session;\n }\n\n getSession(id: string): BrainstormSession | undefined {\n return this.sessions.get(id);\n }\n\n async generate(\n sessionId: string,\n onEvent?: (event: BrainstormStreamEvent) => void,\n ): Promise<RunResult> {\n const session = this.requireSession(sessionId);\n session.status = 'generating';\n logger.info('Generating SDD', { sessionId });\n\n const prompt = buildGeneratePrompt(session.transcript);\n const result = await this.generatorRunner.run({\n prompt,\n workDir: this.workDir,\n timeoutMs: this.config.timeoutMs,\n onStreamEvent: (evt: StreamEvent) => {\n onEvent?.({ type: 'sdd:chunk', data: evt });\n },\n });\n\n if (result.success) {\n session.currentSdd = result.output;\n session.generatorSessionId = result.sessionId;\n session.status = 'idle';\n onEvent?.({ type: 'sdd:complete', data: { sdd: result.output } });\n } else {\n session.status = 'error';\n session.error = result.output;\n onEvent?.({ type: 'error', data: { message: result.output } });\n }\n\n return result;\n }\n\n async review(\n sessionId: string,\n onEvent?: (event: BrainstormStreamEvent) => void,\n ): Promise<RunResult> {\n const session = this.requireSession(sessionId);\n const roundNum = session.rounds.length + 1;\n session.status = 'reviewing';\n logger.info('Reviewing SDD', { sessionId, round: roundNum });\n onEvent?.({ type: 'round:start', data: { round: roundNum, phase: 'review' }, round: roundNum });\n\n const prompt = buildReviewPrompt(session.currentSdd, roundNum);\n const result = await this.reviewerRunner.run({\n prompt,\n workDir: this.workDir,\n timeoutMs: this.config.timeoutMs,\n onStreamEvent: (evt: StreamEvent) => {\n onEvent?.({ type: 'review:chunk', data: evt, round: roundNum });\n },\n });\n\n if (result.success) {\n session.rounds.push({\n round: roundNum,\n questions: result.output,\n refinedSdd: '',\n });\n session.status = 'idle';\n onEvent?.({ type: 'review:complete', data: { round: roundNum, questions: result.output }, round: roundNum });\n } else {\n session.status = 'error';\n session.error = result.output;\n onEvent?.({ type: 'error', data: { message: result.output, round: roundNum }, round: roundNum });\n }\n\n return result;\n }\n\n async refine(\n sessionId: string,\n onEvent?: (event: BrainstormStreamEvent) => void,\n ): Promise<RunResult> {\n const session = this.requireSession(sessionId);\n const currentRound = session.rounds[session.rounds.length - 1];\n if (!currentRound) {\n throw new Error('No review round to refine from');\n }\n\n session.status = 'refining';\n logger.info('Refining SDD', { sessionId, round: currentRound.round });\n\n const prompt = buildRefinePrompt(currentRound.questions);\n const result = await this.generatorRunner.run({\n prompt,\n workDir: this.workDir,\n timeoutMs: this.config.timeoutMs,\n sessionId: session.generatorSessionId,\n continueSession: !!session.generatorSessionId,\n onStreamEvent: (evt: StreamEvent) => {\n onEvent?.({ type: 'sdd:chunk', data: evt, round: currentRound.round });\n },\n });\n\n if (result.success) {\n currentRound.refinedSdd = result.output;\n session.currentSdd = result.output;\n session.generatorSessionId = result.sessionId ?? session.generatorSessionId;\n session.status = 'idle';\n onEvent?.({\n type: 'round:complete',\n data: { round: currentRound.round, sdd: result.output },\n round: currentRound.round,\n });\n } else {\n session.status = 'error';\n session.error = result.output;\n onEvent?.({ type: 'error', data: { message: result.output, round: currentRound.round }, round: currentRound.round });\n }\n\n return result;\n }\n\n async autoRefine(\n sessionId: string,\n rounds?: number,\n onEvent?: (event: BrainstormStreamEvent) => void,\n ): Promise<void> {\n const maxRounds = Math.min(rounds ?? this.config.maxRefinementRounds, this.config.maxRefinementRounds);\n const session = this.requireSession(sessionId);\n\n if (!session.currentSdd) {\n await this.generate(sessionId, onEvent);\n if (session.status === 'error') return;\n }\n\n for (let i = 0; i < maxRounds; i++) {\n const reviewResult = await this.review(sessionId, onEvent);\n if (!reviewResult.success) break;\n\n const refineResult = await this.refine(sessionId, onEvent);\n if (!refineResult.success) break;\n }\n\n if (session.status !== 'error') {\n session.status = 'done';\n }\n }\n\n private requireSession(id: string): BrainstormSession {\n const session = this.sessions.get(id);\n if (!session) {\n throw new Error(`Brainstorm session not found: ${id}`);\n }\n return session;\n }\n}\n","export function buildGeneratePrompt(transcript: string): string {\n return `你是一个资深软件架构师。下面是用户通过语音倾倒的一段关于软件需求的想法,内容可能不连贯、有重复、夹杂语气词——这是正常的。\n\n**核心原则——第一性原理思考:**\n- 不要假设用户非常清楚自己想要什么以及该怎么得到。用户往往只有模糊的意图,你的工作是从原始需求和底层问题出发,帮他厘清真正的目标。\n- 如果用户的动机和目标不清晰,在 SDD 中明确标注 [待澄清],说明为什么这里需要进一步讨论,并给出你的理解和建议。\n- 如果目标清晰但用户描述的路径不是最优解,指出来,并建议更好的方案。用 [更优路径] 标注这类建议。\n- 回到问题的本质:先问\"用户真正要解决的问题是什么\",再想\"最简单有效的方案是什么\",避免过度设计。\n\n请你:\n1. 首先使用 Read、Grep、Glob 等工具浏览项目代码库,了解现有架构、技术栈和代码风格\n2. 分析用户想法的底层动机——他要解决什么问题?为什么要解决?现有方案为什么不够?\n3. 基于对代码库的理解和用户的真实需求,生成一份结构化的软件设计文档 (SDD)\n\nSDD 输出要求:\n- 使用 Markdown 格式\n- 包含以下章节:概述、目标与范围、技术方案(含架构设计、数据模型、接口设计)、实施计划、风险与约束\n- 在\"概述\"章节中,先用 2-3 句话阐明你理解的用户核心诉求和底层动机,再展开方案\n- 结合项目现有代码结构给出具体的文件路径和模块建议\n- 如果用户的想法中有模糊或矛盾的地方,先做合理推断并标注 [推断]\n- 如果发现更短的实现路径或更简洁的方案,用 [更优路径] 标注并说明理由\n\n用户的想法原文:\n---\n${transcript}\n---\n\n请直接输出完整的 SDD 文档内容(纯 Markdown 文本),不要输出任何多余解释。`;\n}\n\nexport function buildReviewPrompt(sdd: string, round: number): string {\n return `你是一个严谨的技术评审专家。请你仔细审查以下软件设计文档 (SDD)。\n\n请你:\n1. 使用 Read、Grep、Glob 等工具浏览项目代码库,验证 SDD 中提到的模块、路径、接口是否与现有代码一致\n2. 用第一性原理审视:需求本身是否合理?目标是否清晰?是否存在更简单直接的实现路径被忽略了?\n3. 站在实际实施者的角度,找出文档中**未说清楚、含糊不清、缺失、或可能导致实施困难**的地方\n4. 列出恰好 20 个问题,按严重程度排序(最重要的在前)\n\n这是第 ${round} 轮审查${round > 1 ? ',请关注比之前更细粒度的问题,特别是边界条件、错误处理、性能、安全等方面' : ''}。\n\nSDD 文档:\n---\n${sdd}\n---\n\n输出格式要求:\n每个问题用编号列出,格式为:\n1. [类别] 问题描述\n\n类别包括:[缺失]、[模糊]、[矛盾]、[风险]、[建议]、[动机](需求动机或目标本身需要质疑时)、[过度设计](存在更简单路径时)\n\n请直接输出 20 个问题,不要输出多余解释。`;\n}\n\nexport function buildRefinePrompt(questions: string): string {\n return `一位技术评审专家审查了你之前生成的 SDD,发现了以下问题:\n\n${questions}\n\n请你:\n1. 逐一回应每个问题,在 SDD 中修复或补充对应内容\n2. 如果某个问题需要查看代码来回答,请使用 Read、Grep、Glob 等工具查看项目代码后再作答\n3. 对无法确定的问题,给出多种方案并标注推荐方案\n\n请输出修复后的完整 SDD 文档(纯 Markdown 文本),不要输出对比说明,直接给出最新版本。`;\n}\n"],"mappings":"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","names":["logger","logger","logger","logger","path","IssueState","logger","fs","path","logger","path","fs","path","path","path","fs","path","logger","path","fs","fs","path","logger","fs","path","fs","logger","path","fs","logger","fs","path","path","fs","execFile","promisify","fs","path","path","fs","logger","fs","path","logger","DEFAULT_OPTIONS","path","fs","fs","path","logger","fs","path","logger","fs","path","logger","path","fs","logger","logger","logger","logger","logger","logger","logger","logger","execFileAsync","promisify","execFile","logger","path","fs","logger"]}
1
+ {"version":3,"sources":["../src/clients/GongfengClient.ts","../src/utils/CircuitBreaker.ts","../src/utils/RetryPolicy.ts","../src/tracker/IssueState.ts","../src/lifecycle/ActionLifecycleManager.ts","../src/tracker/IssueTracker.ts","../src/persistence/PlanPersistence.ts","../src/phases/BasePhase.ts","../src/rules/RuleResolver.ts","../src/verify/VerifyReportParser.ts","../src/phases/VerifyPhase.ts","../src/phases/PlanPhase.ts","../src/phases/BuildPhase.ts","../src/release/ReleaseDetectCache.ts","../src/prompts/release-templates.ts","../src/phases/ReleasePhase.ts","../src/phases/UatPhase.ts","../src/phases/PhaseFactory.ts","../src/pipeline/PipelineDefinition.ts","../src/workspace/WorkspaceConfig.ts","../src/workspace/WorkspaceManager.ts","../src/orchestrator/PipelineOrchestrator.ts","../src/demand/adapters/GongfengAdapter.ts","../src/utils/MergeRequestHelper.ts","../src/deploy/PortAllocator.ts","../src/deploy/DevServerManager.ts","../src/e2e/E2eSettings.ts","../src/e2e/ScreenshotCollector.ts","../src/e2e/ScreenshotPublisher.ts","../src/metrics/MetricsCollector.ts","../src/orchestrator/steps/SetupStep.ts","../src/lifecycle/FeedbackTypes.ts","../src/notesync/NoteSyncSettings.ts","../src/orchestrator/PendingDialogStore.ts","../src/orchestrator/steps/PhaseHelpers.ts","../src/lifecycle/DefaultLifecycleHook.ts","../src/orchestrator/strategies/GateStrategy.ts","../src/orchestrator/strategies/AiPhaseStrategy.ts","../src/orchestrator/strategies/VerifyFixStrategy.ts","../src/orchestrator/strategies/index.ts","../src/orchestrator/steps/PhaseLoopStep.ts","../src/orchestrator/steps/CompletionStep.ts","../src/orchestrator/steps/FailureHandler.ts","../src/services/BrainstormService.ts","../src/prompts/brainstorm-templates.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { GongfengApiError, GongfengUploadError } from '../errors/index.js';\nimport { logger as rootLogger } from '../logger.js';\nimport { CircuitBreaker } from '../utils/CircuitBreaker.js';\nimport { RetryPolicy } from '../utils/RetryPolicy.js';\n\nconst logger = rootLogger.child('GongfengClient');\n\nexport interface GongfengIssue {\n id: number;\n iid: number;\n title: string;\n description: string;\n state: string;\n labels: string[];\n created_at: string;\n updated_at: string;\n author: { username: string; name: string };\n /** 工蜂 API 返回的负责人列表(字段名可能是 assignees 或 assignee_users) */\n assignees?: Array<{ username: string; name: string }>;\n assignee_users?: Array<{ username: string; name: string }>;\n}\n\nexport interface GongfengUser {\n id: number;\n username: string;\n name: string;\n}\n\nexport interface GongfengConfig {\n apiUrl: string;\n privateToken: string;\n projectPath: string;\n}\n\nexport interface CreateMergeRequestOptions {\n sourceBranch: string;\n targetBranch: string;\n title: string;\n description?: string;\n}\n\nexport interface GongfengMergeRequest {\n id: number;\n iid: number;\n title: string;\n web_url: string;\n state: string;\n source_branch?: string;\n target_branch?: string;\n}\n\nexport interface GongfengMergeRequestDetail extends GongfengMergeRequest {\n has_conflicts: boolean;\n merge_status: string;\n}\n\nexport interface UploadResult {\n alt: string;\n url: string;\n markdown: string;\n}\n\nexport interface GongfengNote {\n id: number;\n body: string;\n author: { username: string; name: string };\n created_at: string;\n}\n\nexport const AGENT_NOTE_MARKER = '\\n\\n<!-- issue-auto-finish-agent -->';\nconst AGENT_NOTE_MARKER_PATTERN = '<!-- issue-auto-finish-agent -->';\n\nexport class GongfengClient {\n private apiUrl: string;\n private token: string;\n private projectPath: string;\n private readonly retryPolicy: RetryPolicy;\n private readonly circuitBreaker: CircuitBreaker;\n\n constructor(config: GongfengConfig) {\n this.apiUrl = config.apiUrl.replace(/\\/$/, '');\n this.token = config.privateToken;\n this.projectPath = config.projectPath;\n\n this.retryPolicy = new RetryPolicy({\n maxRetries: 3,\n baseDelayMs: 1000,\n maxDelayMs: 30000,\n jitterFactor: 0.2,\n isRetryable: (err: unknown) => {\n if (err instanceof GongfengApiError) {\n return err.isRetryable;\n }\n // Network errors (e.g. fetch failures) are retryable\n if (err instanceof TypeError && (err.message.includes('fetch') || err.message.includes('network'))) {\n return true;\n }\n return false;\n },\n });\n\n this.circuitBreaker = new CircuitBreaker('GongfengAPI', {\n failureThreshold: 5,\n resetTimeoutMs: 60000,\n successThreshold: 2,\n });\n }\n\n private get projectApiBase(): string {\n const encoded = encodeURIComponent(this.projectPath);\n return `${this.apiUrl}/api/v3/projects/${encoded}`;\n }\n\n private async requestRaw(path: string, options: RequestInit = {}): Promise<Response> {\n const url = `${this.projectApiBase}${path}`;\n logger.debug('API request', { method: options.method || 'GET', url });\n\n return this.circuitBreaker.execute(() =>\n this.retryPolicy.execute(async () => {\n const resp = await fetch(url, {\n ...options,\n headers: {\n 'PRIVATE-TOKEN': this.token,\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n });\n\n if (!resp.ok) {\n const body = await resp.text();\n throw new GongfengApiError(resp.status, `Gongfeng API error ${resp.status}: ${body}`, body);\n }\n\n return resp;\n }, `requestRaw ${options.method || 'GET'} ${path}`),\n );\n }\n\n private async request<T>(path: string, options: RequestInit = {}): Promise<T> {\n const resp = await this.requestRaw(path, options);\n return resp.json() as Promise<T>;\n }\n\n async createIssue(\n title: string,\n description: string,\n labels?: string[],\n ): Promise<GongfengIssue> {\n const body: Record<string, string> = { title, description };\n if (labels && labels.length > 0) {\n body.labels = labels.join(',');\n }\n const issue = await this.request<GongfengIssue>('/issues', {\n method: 'POST',\n body: JSON.stringify(body),\n });\n logger.info('Issue created', { id: issue.id, iid: issue.iid, title });\n return issue;\n }\n\n async listIssues(state: string = 'opened', labels?: string): Promise<GongfengIssue[]> {\n const params = new URLSearchParams({ state, per_page: '100' });\n if (labels) {\n params.set('labels', labels);\n }\n return this.request<GongfengIssue[]>(`/issues?${params.toString()}`);\n }\n\n async listIssuesAdvanced(options: {\n state?: string;\n labels?: string;\n search?: string;\n page?: number;\n perPage?: number;\n } = {}): Promise<{ issues: GongfengIssue[]; total: number }> {\n const params = new URLSearchParams({\n state: options.state || 'opened',\n page: String(options.page || 1),\n per_page: String(options.perPage || 20),\n });\n if (options.labels) {\n params.set('labels', options.labels);\n }\n if (options.search) {\n params.set('search', options.search);\n }\n const resp = await this.requestRaw(`/issues?${params.toString()}`);\n const total = parseInt(resp.headers.get('x-total') || '0', 10);\n const issues = (await resp.json()) as GongfengIssue[];\n return { issues, total: total || issues.length };\n }\n\n async getIssueDetail(issueId: number): Promise<GongfengIssue> {\n return this.request<GongfengIssue>(`/issues/${issueId}`);\n }\n\n async createIssueNote(issueId: number, body: string): Promise<void> {\n const markedBody = body + AGENT_NOTE_MARKER;\n await this.request(`/issues/${issueId}/notes`, {\n method: 'POST',\n body: JSON.stringify({ body: markedBody }),\n });\n logger.info('Issue note created', { issueId });\n }\n\n async updateIssueLabels(issueId: number, labels: string[]): Promise<void> {\n await this.request(`/issues/${issueId}`, {\n method: 'PUT',\n body: JSON.stringify({ labels: labels.join(',') }),\n });\n logger.info('Issue labels updated', { issueId, labels });\n }\n\n async createMergeRequest(options: CreateMergeRequestOptions): Promise<GongfengMergeRequest> {\n const mr = await this.request<GongfengMergeRequest>('/merge_requests', {\n method: 'POST',\n body: JSON.stringify({\n source_branch: options.sourceBranch,\n target_branch: options.targetBranch,\n title: options.title,\n description: options.description ?? '',\n }),\n });\n if (!mr.web_url && mr.iid) {\n mr.web_url = this.buildMergeRequestUrl(mr.iid);\n }\n logger.info('Merge request created', { iid: mr.iid, webUrl: mr.web_url });\n return mr;\n }\n\n async findMergeRequestByBranch(\n sourceBranch: string,\n targetBranch: string,\n state: string = 'opened',\n ): Promise<GongfengMergeRequest | null> {\n const params = new URLSearchParams({\n state,\n source_branch: sourceBranch,\n target_branch: targetBranch,\n });\n const mrs = await this.request<GongfengMergeRequest[]>(\n `/merge_requests?${params.toString()}`,\n );\n if (mrs.length === 0) return null;\n const mr = mrs[0];\n if (!mr.web_url && mr.iid) {\n mr.web_url = this.buildMergeRequestUrl(mr.iid);\n }\n return mr;\n }\n\n private buildMergeRequestUrl(mrIid: number): string {\n return `${this.apiUrl}/${this.projectPath}/merge_requests/${mrIid}`;\n }\n\n async uploadFile(filePath: string): Promise<UploadResult> {\n const fileData = fs.readFileSync(filePath);\n const fileName = path.basename(filePath);\n const mimeType = fileName.endsWith('.png') ? 'image/png' : 'application/octet-stream';\n const blob = new Blob([fileData], { type: mimeType });\n\n const formData = new FormData();\n formData.append('file', blob, fileName);\n\n const url = `${this.projectApiBase}/uploads`;\n logger.debug('Upload request', { url, fileName });\n\n const resp = await fetch(url, {\n method: 'POST',\n headers: { 'PRIVATE-TOKEN': this.token },\n body: formData,\n });\n\n if (!resp.ok) {\n const body = await resp.text();\n throw new GongfengUploadError(resp.status, `Gongfeng upload error ${resp.status}: ${body}`, body);\n }\n\n const result = (await resp.json()) as UploadResult;\n logger.info('File uploaded', { fileName, url: result.url });\n return result;\n }\n\n async createMergeRequestNote(mrIid: number, body: string): Promise<void> {\n const markedBody = body + AGENT_NOTE_MARKER;\n await this.request(`/merge_requests/${mrIid}/notes`, {\n method: 'POST',\n body: JSON.stringify({ body: markedBody }),\n });\n logger.info('Merge request note created', { mrIid });\n }\n\n async closeMergeRequest(mrIid: number): Promise<void> {\n await this.request(`/merge_requests/${mrIid}`, {\n method: 'PUT',\n body: JSON.stringify({ state_event: 'close' }),\n });\n logger.info('Merge request closed', { mrIid });\n }\n\n async deleteIssue(issueId: number): Promise<void> {\n await this.request(`/issues/${issueId}`, { method: 'DELETE' });\n logger.info('Issue deleted', { issueId });\n }\n\n async closeIssue(issueId: number): Promise<void> {\n await this.request(`/issues/${issueId}`, {\n method: 'PUT',\n body: JSON.stringify({ state_event: 'close' }),\n });\n logger.info('Issue closed', { issueId });\n }\n\n async listIssueNotes(issueId: number): Promise<GongfengNote[]> {\n const allNotes: GongfengNote[] = [];\n let page = 1;\n while (true) {\n const params = new URLSearchParams({ per_page: '100', page: String(page) });\n const batch = await this.request<GongfengNote[]>(\n `/issues/${issueId}/notes?${params.toString()}`,\n );\n allNotes.push(...batch);\n if (batch.length < 100) break;\n page++;\n }\n return allNotes;\n }\n\n async deleteIssueNote(issueId: number, noteId: number): Promise<void> {\n // 工蜂 API 不支持 DELETE notes (返回 405),改用 PUT 清空内容使其失效(软删除)\n await this.request(`/issues/${issueId}/notes/${noteId}`, {\n method: 'PUT',\n body: JSON.stringify({ body: '<!-- iaf-note-deleted -->' }),\n });\n logger.debug('Issue note invalidated (soft-delete)', { issueId, noteId });\n }\n\n async cleanupAgentNotes(issueId: number): Promise<number> {\n const notes = await this.listIssueNotes(issueId);\n const agentNotes = notes.filter(n => n.body.includes(AGENT_NOTE_MARKER_PATTERN));\n for (const note of agentNotes) {\n await this.deleteIssueNote(issueId, note.id);\n }\n if (agentNotes.length > 0) {\n logger.info('Agent notes cleaned up', { issueId, deleted: agentNotes.length });\n }\n return agentNotes.length;\n }\n\n async getMergeRequestDetail(mrIid: number): Promise<GongfengMergeRequestDetail> {\n const mr = await this.request<GongfengMergeRequestDetail>(`/merge_requests/${mrIid}`);\n if (!mr.web_url && mr.iid) {\n mr.web_url = this.buildMergeRequestUrl(mr.iid);\n }\n return mr;\n }\n\n private async requestGlobal<T>(path: string, options: RequestInit = {}): Promise<T> {\n const url = `${this.apiUrl}${path}`;\n logger.debug('API request (global)', { method: options.method || 'GET', url });\n\n const resp = await this.circuitBreaker.execute(() =>\n this.retryPolicy.execute(async () => {\n const r = await fetch(url, {\n ...options,\n headers: {\n 'PRIVATE-TOKEN': this.token,\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n });\n\n if (!r.ok) {\n const body = await r.text();\n throw new GongfengApiError(r.status, `Gongfeng API error ${r.status}: ${body}`, body);\n }\n\n return r;\n }, `requestGlobal ${options.method || 'GET'} ${path}`),\n );\n\n return resp.json() as Promise<T>;\n }\n\n /** 获取当前 Token 对应的用户信息 */\n async getCurrentUser(): Promise<GongfengUser> {\n return this.requestGlobal<GongfengUser>('/api/v3/user');\n }\n\n /** 设置 Issue 负责人 */\n async setIssueAssignee(issueId: number, username: string): Promise<void> {\n await this.request(`/issues/${issueId}`, {\n method: 'PUT',\n body: JSON.stringify({ assignee_users: username }),\n });\n logger.info('Issue assignee updated', { issueId, username });\n }\n\n /** 清除 Issue 负责人 */\n async clearIssueAssignee(issueId: number): Promise<void> {\n await this.request(`/issues/${issueId}`, {\n method: 'PUT',\n body: JSON.stringify({ assignee_users: '' }),\n });\n logger.info('Issue assignee cleared', { issueId });\n }\n\n /** 更新 Issue 评论内容(用于心跳刷新锁评论) */\n async updateIssueNote(issueId: number, noteId: number, body: string): Promise<void> {\n await this.request(`/issues/${issueId}/notes/${noteId}`, {\n method: 'PUT',\n body: JSON.stringify({ body }),\n });\n logger.debug('Issue note updated', { issueId, noteId });\n }\n\n /** 创建 Issue 评论(不带 AGENT_NOTE_MARKER),返回含 id 的 note */\n async createIssueNotePlain(issueId: number, body: string): Promise<GongfengNote> {\n const note = await this.request<GongfengNote>(`/issues/${issueId}/notes`, {\n method: 'POST',\n body: JSON.stringify({ body }),\n });\n logger.debug('Issue note created (plain)', { issueId, noteId: note.id });\n return note;\n }\n\n /** Update connection config at runtime (for hot-reload) */\n updateConfig(config: GongfengConfig): void {\n this.apiUrl = config.apiUrl.replace(/\\/$/, '');\n this.token = config.privateToken;\n this.projectPath = config.projectPath;\n logger.info('GongfengClient config updated', { apiUrl: this.apiUrl, projectPath: this.projectPath });\n }\n\n /** 移除指定前缀的所有标签(精确匹配 prefix 和 prefix:* 前缀) */\n async removeLabelsWithPrefix(issueId: number, prefix: string): Promise<void> {\n const issue = await this.getIssueDetail(issueId);\n const filtered = issue.labels.filter(l => l !== prefix && !l.startsWith(prefix + ':'));\n if (filtered.length === issue.labels.length) return; // 没有需要移除的标签\n await this.updateIssueLabels(issueId, filtered);\n }\n\n async addLabel(issueId: number, label: string): Promise<void> {\n const issue = await this.getIssueDetail(issueId);\n if (issue.labels.includes(label)) {\n logger.info('Label already exists, skipping', { issueId, label });\n return;\n }\n const newLabels = [...issue.labels, label];\n await this.updateIssueLabels(issueId, newLabels);\n }\n}\n","import { logger as rootLogger } from '../logger.js';\n\nconst logger = rootLogger.child('CircuitBreaker');\n\nexport enum CircuitState {\n Closed = 'closed',\n Open = 'open',\n HalfOpen = 'half-open',\n}\n\nexport interface CircuitBreakerOptions {\n /** Number of failures before opening (default: 5) */\n failureThreshold?: number;\n /** Time in ms before trying half-open (default: 60000) */\n resetTimeoutMs?: number;\n /** Number of successes needed to close from half-open (default: 2) */\n successThreshold?: number;\n}\n\nexport class CircuitBreaker {\n private state: CircuitState = CircuitState.Closed;\n private failureCount = 0;\n private successCount = 0;\n private lastFailureTime = 0;\n private readonly failureThreshold: number;\n private readonly resetTimeoutMs: number;\n private readonly successThreshold: number;\n\n constructor(\n private readonly name: string,\n options?: CircuitBreakerOptions,\n ) {\n this.failureThreshold = options?.failureThreshold ?? 5;\n this.resetTimeoutMs = options?.resetTimeoutMs ?? 60000;\n this.successThreshold = options?.successThreshold ?? 2;\n }\n\n getState(): CircuitState {\n return this.state;\n }\n\n async execute<T>(fn: () => Promise<T>): Promise<T> {\n if (this.state === CircuitState.Open) {\n if (Date.now() - this.lastFailureTime >= this.resetTimeoutMs) {\n this.transitionTo(CircuitState.HalfOpen);\n } else {\n throw new Error(`Circuit breaker '${this.name}' is open`);\n }\n }\n\n try {\n const result = await fn();\n this.onSuccess();\n return result;\n } catch (err) {\n this.onFailure();\n throw err;\n }\n }\n\n /** Reset to closed state (e.g., for testing or manual recovery) */\n reset(): void {\n this.failureCount = 0;\n this.successCount = 0;\n this.lastFailureTime = 0;\n this.transitionTo(CircuitState.Closed);\n }\n\n private onSuccess(): void {\n if (this.state === CircuitState.HalfOpen) {\n this.successCount++;\n if (this.successCount >= this.successThreshold) {\n this.transitionTo(CircuitState.Closed);\n }\n } else {\n // In closed state, reset failure count on success\n this.failureCount = 0;\n }\n }\n\n private onFailure(): void {\n this.failureCount++;\n this.lastFailureTime = Date.now();\n\n if (this.state === CircuitState.HalfOpen) {\n // Any failure in half-open goes back to open\n this.transitionTo(CircuitState.Open);\n } else if (this.failureCount >= this.failureThreshold) {\n this.transitionTo(CircuitState.Open);\n }\n }\n\n private transitionTo(newState: CircuitState): void {\n if (this.state === newState) return;\n const oldState = this.state;\n this.state = newState;\n\n if (newState === CircuitState.Closed) {\n this.failureCount = 0;\n this.successCount = 0;\n } else if (newState === CircuitState.HalfOpen) {\n this.successCount = 0;\n }\n\n logger.info('Circuit breaker state transition', {\n name: this.name,\n from: oldState,\n to: newState,\n });\n }\n}\n","import { logger as rootLogger } from '../logger.js';\n\nconst logger = rootLogger.child('RetryPolicy');\n\nexport interface RetryPolicyOptions {\n /** Maximum number of retry attempts (default: 3) */\n maxRetries?: number;\n /** Initial delay in ms (default: 1000) */\n baseDelayMs?: number;\n /** Maximum delay in ms (default: 30000) */\n maxDelayMs?: number;\n /** Jitter factor 0-1 (default: 0.2) */\n jitterFactor?: number;\n /** Function to determine if error is retryable */\n isRetryable?: (error: unknown) => boolean;\n}\n\nexport class RetryPolicy {\n private readonly maxRetries: number;\n private readonly baseDelayMs: number;\n private readonly maxDelayMs: number;\n private readonly jitterFactor: number;\n private readonly isRetryable: (error: unknown) => boolean;\n\n constructor(options?: RetryPolicyOptions) {\n this.maxRetries = options?.maxRetries ?? 3;\n this.baseDelayMs = options?.baseDelayMs ?? 1000;\n this.maxDelayMs = options?.maxDelayMs ?? 30000;\n this.jitterFactor = options?.jitterFactor ?? 0.2;\n this.isRetryable = options?.isRetryable ?? (() => true);\n }\n\n /** Execute fn with retry. Returns the result or throws the last error. */\n async execute<T>(fn: () => Promise<T>, context?: string): Promise<T> {\n let lastError: unknown;\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err;\n if (attempt >= this.maxRetries || !this.isRetryable(err)) {\n throw err;\n }\n const delay = this.calculateDelay(attempt);\n logger.warn('Retrying after error', {\n context,\n attempt: attempt + 1,\n maxRetries: this.maxRetries,\n delayMs: delay,\n error: (err as Error).message,\n });\n await this.sleep(delay);\n }\n }\n throw lastError; // unreachable but satisfies TS\n }\n\n private calculateDelay(attempt: number): number {\n // Exponential backoff: base * 2^attempt\n const exponential = this.baseDelayMs * Math.pow(2, attempt);\n const capped = Math.min(exponential, this.maxDelayMs);\n // Add jitter\n const jitter = capped * this.jitterFactor * (Math.random() * 2 - 1);\n return Math.max(0, Math.round(capped + jitter));\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}\n","import type { DemandSpec } from '../demand/DemandSpec.js';\n\nexport enum IssueState {\n Pending = 'pending',\n Skipped = 'skipped',\n BranchCreated = 'branch_created',\n // ── 通用阶段状态 ──\n /** AI 阶段执行中(配合 currentPhase 使用) */\n PhaseRunning = 'phase_running',\n /** AI 阶段执行完毕(配合 currentPhase 使用) */\n PhaseDone = 'phase_done',\n /** Gate 阶段等待中(配合 currentPhase 使用) */\n PhaseWaiting = 'phase_waiting',\n /** Gate 阶段已批准(配合 currentPhase 使用) */\n PhaseApproved = 'phase_approved',\n // Conflict resolution (post-completion)\n ResolvingConflict = 'resolving_conflict',\n /** 用户主动中止,保留 worktree/分支/session,可继续或重做 */\n Paused = 'paused',\n // Terminal\n Completed = 'completed',\n Failed = 'failed',\n Deployed = 'deployed',\n}\n\nexport type PipelineMode = string;\n\nexport interface PortPairRecord {\n backendPort: number;\n frontendPort: number;\n}\n\n/** 生命周期状态 — 由 IssueTracker 管理 */\nexport interface IssueLifecycle {\n state: IssueState;\n /** 当 state 为 PhaseRunning/PhaseDone/PhaseWaiting/PhaseApproved 时,记录具体阶段名 */\n currentPhase?: string;\n attempts: number;\n lastError?: string;\n failedAtState?: IssueState;\n /** 最后一次错误是否可重试。undefined 视为可重试(向后兼容旧记录) */\n lastErrorRetryable?: boolean;\n /** 中止时的阶段名(Paused 状态下有值) */\n pausedAtPhase?: string;\n /** 持久化处理锁,防止 poller 并发拾取同一 issue。向后兼容:旧记录无此字段 = 无锁 */\n processingLock?: {\n correlationId: string;\n ts: string;\n };\n}\n\n/** 流水线配置 */\nexport interface IssuePipeline {\n pipelineMode?: PipelineMode;\n}\n\n/** 分支信息 */\nexport interface IssueBranch {\n branchName: string;\n}\n\n/** Issue 级别的功能开关 */\nexport interface IssueFeatureFlags {\n /** undefined = follow system setting */\n issueNoteSyncEnabled?: boolean;\n /** undefined = follow system setting */\n e2eEnabled?: boolean;\n}\n\n/** 部署/预览信息 */\nexport interface IssueDeployment {\n /** Allocated ports for preview/E2E (persisted for recovery) */\n ports?: PortPairRecord;\n /** Preview servers started at */\n previewStartedAt?: string;\n}\n\n/** 结果信息 */\nexport interface IssueResult {\n mrUrl?: string;\n /** 多仓模式下关联仓库的 MR URL(repo name -> URL) */\n linkedMrUrls?: Record<string, string>;\n}\n\n/** 审计时间戳 */\nexport interface IssueAudit {\n createdAt: string;\n updatedAt: string;\n}\n\n/** 需求规格(知识域),新建 Issue 时填充 */\nexport interface IssueDemand {\n demandSpec?: DemandSpec;\n}\n\n/** 阶段进度(真实事件记录,非推导) */\nexport interface IssuePhaseProgress {\n /** 各阶段的实际进度记录,key 为阶段名 */\n phaseProgress?: Record<string, PhaseProgress>;\n}\n\n/** 完整的 IssueRecord — 持久化格式不变 */\nexport type IssueRecord =\n IssueLifecycle &\n IssuePipeline &\n IssueBranch &\n IssueFeatureFlags &\n IssueDeployment &\n IssueResult &\n IssueDemand &\n IssueAudit &\n IssuePhaseProgress;\n\nexport type PhaseStatus = 'pending' | 'in_progress' | 'completed' | 'failed' | 'gate_waiting';\n\nexport interface PhaseProgress {\n status: PhaseStatus;\n startedAt?: string;\n completedAt?: string;\n error?: string;\n /** AI 会话 ID,用于断点续跑(--resume) */\n sessionId?: string;\n}\n\nexport interface ProgressData {\n displayId: number;\n title: string;\n branchName: string;\n pipelineMode?: PipelineMode;\n currentPhase: string;\n phases: Record<string, PhaseProgress>;\n}\n","import { IssueState } from '../tracker/IssueState.js';\nimport type { PipelineDef, PhaseSpec, PlanFileSpec } from '../pipeline/PipelineDefinition.js';\nimport type { ActionState, ActionStatus } from './ActionLifecycle.js';\nimport { t } from '../i18n/index.js';\n\n/**\n * ActionLifecycleManager — 查询层抽象。\n *\n * 从 PipelineDef 自动构建 IssueState ↔ ActionState 双向映射表,\n * 集中散布在 IssueTracker/PipelineOrchestrator/BasePhase 中的状态分类逻辑。\n *\n * 不改变持久化格式(tracker.json 中的状态字符串值完全保留)。\n */\nexport class ActionLifecycleManager {\n /** IssueState → ActionState */\n private readonly stateToAction: Map<IssueState, ActionState>;\n /** \"action:status\" → IssueState */\n private readonly actionToState: Map<string, IssueState>;\n /** phase name → { startState, doneState, approvedState? } */\n private readonly phaseStatesMap: Map<string, { startState: IssueState; doneState: IssueState; approvedState?: IssueState }>;\n /** Ordered phase indices by IssueState for determineResumePhaseIndex */\n private readonly def: PipelineDef;\n\n constructor(def: PipelineDef) {\n this.def = def;\n this.stateToAction = new Map();\n this.actionToState = new Map();\n this.phaseStatesMap = new Map();\n\n this.buildMappings(def);\n }\n\n private buildMappings(def: PipelineDef): void {\n // Fixed mappings\n this.addMapping(IssueState.Pending, 'init', 'idle');\n this.addMapping(IssueState.Skipped, 'init', 'skipped');\n this.addMapping(IssueState.BranchCreated, 'init', 'ready');\n this.addMapping(IssueState.Failed, 'init', 'failed');\n this.addMapping(IssueState.Paused, 'init', 'paused');\n this.addMapping(IssueState.Deployed, 'init', 'done');\n this.addMapping(IssueState.ResolvingConflict, 'conflict', 'running');\n\n // Phase-driven mappings\n for (const spec of def.phases) {\n this.phaseStatesMap.set(spec.name, {\n startState: spec.startState,\n doneState: spec.doneState,\n approvedState: spec.approvedState,\n });\n\n if (spec.kind === 'ai') {\n // For generic PhaseRunning/PhaseDone, don't add to stateToAction map\n // (since multiple phases share the same IssueState value).\n // Only add non-generic states.\n if (spec.startState !== IssueState.PhaseRunning) {\n this.addMapping(spec.startState, spec.name, 'running');\n }\n if (spec.doneState === IssueState.Completed) {\n this.addMapping(spec.doneState, spec.name, 'done');\n } else if (spec.doneState !== IssueState.PhaseDone) {\n this.addMapping(spec.doneState, spec.name, 'ready');\n }\n } else if (spec.kind === 'gate') {\n // For generic PhaseWaiting/PhaseApproved, don't add to stateToAction map\n // (since multiple gate phases could share the same IssueState value).\n if (spec.startState !== IssueState.PhaseWaiting) {\n this.addMapping(spec.startState, spec.name, 'waiting');\n }\n if (spec.approvedState && spec.approvedState !== IssueState.PhaseApproved) {\n this.addMapping(spec.approvedState, spec.name, 'ready');\n }\n }\n }\n }\n\n private addMapping(state: IssueState, action: string, status: ActionStatus): void {\n // Avoid overwriting — first mapping wins (e.g. Completed mapped by verify phase)\n if (!this.stateToAction.has(state)) {\n this.stateToAction.set(state, { action, status });\n }\n const key = `${action}:${status}`;\n if (!this.actionToState.has(key)) {\n this.actionToState.set(key, state);\n }\n }\n\n // ─── Query API ───\n\n /**\n * 将 IssueState 解析为语义化的 ActionState。\n *\n * 对于通用状态 PhaseRunning/PhaseDone,需额外传入 currentPhase 来区分具体阶段。\n */\n resolve(state: IssueState, currentPhase?: string): ActionState {\n // Paused:用 pausedAtPhase(传入的 currentPhase)作为 action 名\n if (state === IssueState.Paused && currentPhase) {\n return { action: currentPhase, status: 'paused' };\n }\n // 通用阶段状态:用 currentPhase 作为 action 名\n if (state === IssueState.PhaseRunning && currentPhase) {\n return { action: currentPhase, status: 'running' };\n }\n if (state === IssueState.PhaseDone && currentPhase) {\n return { action: currentPhase, status: 'ready' };\n }\n if (state === IssueState.PhaseWaiting && currentPhase) {\n return { action: currentPhase, status: 'waiting' };\n }\n if (state === IssueState.PhaseApproved && currentPhase) {\n return { action: currentPhase, status: 'ready' };\n }\n\n const mapped = this.stateToAction.get(state);\n if (mapped) return mapped;\n // Fallback: unknown states (from another pipeline mode) treated as idle\n return { action: 'init', status: 'idle' };\n }\n\n /**\n * 将 action + status 反向映射为 IssueState。\n */\n toIssueState(action: string, status: ActionStatus): IssueState | undefined {\n return this.actionToState.get(`${action}:${status}`);\n }\n\n // ─── Classification predicates (替代 3 个 Set 常量 + getDrivableIssues) ───\n\n /**\n * 终态:done | failed | skipped\n */\n isTerminal(state: IssueState): boolean {\n const as = this.resolve(state);\n return as.status === 'done' || as.status === 'failed' || as.status === 'skipped';\n }\n\n /**\n * 进行中:running (包含通用 PhaseRunning)\n */\n isInProgress(state: IssueState): boolean {\n if (state === IssueState.PhaseRunning) return true;\n return this.resolve(state).status === 'running';\n }\n\n /**\n * 阻塞中:waiting\n */\n isBlocked(state: IssueState): boolean {\n if (state === IssueState.PhaseWaiting) return true;\n return this.resolve(state).status === 'waiting';\n }\n\n /**\n * 可驱动判断(集中化 getDrivableIssues 的过滤逻辑)。\n *\n * - idle → 可驱动 (Pending)\n * - ready → 可驱动 (BranchCreated, PhaseDone, PhaseApproved)\n * - failed && attempts < maxRetries → 可驱动\n * - waiting → 不可驱动 (PhaseWaiting)\n * - running → 不可驱动(stalled 由外部叠加)\n * - done/skipped → 不可驱动\n */\n isDrivable(state: IssueState, attempts: number, maxRetries: number, lastErrorRetryable?: boolean): boolean {\n // Paused is never drivable (user must explicitly continue/redo)\n if (state === IssueState.Paused) return false;\n // PhaseDone is always drivable (triggers next phase)\n if (state === IssueState.PhaseDone) return true;\n // PhaseApproved is always drivable (gate approved, triggers next phase)\n if (state === IssueState.PhaseApproved) return true;\n // PhaseRunning is never drivable (something is executing)\n if (state === IssueState.PhaseRunning) return false;\n // PhaseWaiting is never drivable (waiting for external input)\n if (state === IssueState.PhaseWaiting) return false;\n const as = this.resolve(state);\n switch (as.status) {\n case 'idle':\n case 'ready':\n return true;\n case 'failed':\n if (lastErrorRetryable === false) return false;\n return attempts < maxRetries;\n case 'waiting':\n case 'running':\n case 'done':\n case 'skipped':\n case 'paused':\n return false;\n }\n }\n\n // ─── Phase navigation (替代 determineStartIndex + getPhasePreState) ───\n\n /**\n * 确定从哪个阶段索引恢复执行(替代 PipelineOrchestrator.determineStartIndex)。\n *\n * 从后向前扫描 phases,匹配 currentState 或 failedAtState。\n * 支持通用状态 PhaseRunning/PhaseDone + currentPhase 的组合。\n */\n determineResumePhaseIndex(currentState: IssueState, failedAtState?: IssueState, currentPhase?: string): number {\n const target = failedAtState || currentState;\n const phases = this.def.phases;\n\n // 通用阶段状态:通过 currentPhase 名称匹配\n if ((target === IssueState.PhaseRunning || target === IssueState.PhaseDone) && currentPhase) {\n const idx = phases.findIndex(p => p.name === currentPhase);\n if (idx >= 0) {\n return target === IssueState.PhaseDone ? idx + 1 : idx;\n }\n }\n if ((target === IssueState.PhaseWaiting || target === IssueState.PhaseApproved) && currentPhase) {\n const idx = phases.findIndex(p => p.name === currentPhase);\n if (idx >= 0) {\n if (target === IssueState.PhaseApproved) {\n const spec = phases[idx];\n // AI phase with approvedState: re-execute same phase (detection done, execution pending)\n return (spec.kind === 'ai' && spec.approvedState) ? idx : idx + 1;\n }\n return idx;\n }\n }\n\n for (let i = phases.length - 1; i >= 0; i--) {\n const spec = phases[i];\n\n if (spec.kind === 'gate' && spec.approvedState === target) {\n return i + 1;\n }\n\n if (spec.startState === target || spec.doneState === target) {\n return spec.doneState === target ? i + 1 : i;\n }\n }\n return 0;\n }\n\n /**\n * 获取某个 phase 的前驱状态(即重置到该 phase 需要设置的状态)。\n * 第一个 phase 的前驱是 BranchCreated;后续 phase 的前驱是上一个 phase 的 approvedState 或 doneState。\n */\n getPhasePreState(phaseName: string): IssueState | undefined {\n const phases = this.def.phases;\n const idx = phases.findIndex(p => p.name === phaseName);\n if (idx < 0) return undefined;\n if (idx === 0) return IssueState.BranchCreated;\n const prev = phases[idx - 1];\n return prev.approvedState ?? prev.doneState;\n }\n\n /**\n * 获取某个 phase 的状态三元组。\n */\n getPhaseStates(phaseName: string): { startState: IssueState; doneState: IssueState; approvedState?: IssueState } | undefined {\n return this.phaseStatesMap.get(phaseName);\n }\n\n // ─── Display helpers (替代 collectStateLabels + derivePhaseStatuses) ───\n\n /**\n * 解析单条状态的展示标签。\n *\n * 对通用状态 PhaseRunning/PhaseDone,需传入 currentPhase 以生成具体标签(如\"分析中\");\n * 缺少 currentPhase 时回退到泛化标签(如\"阶段执行中\")。\n */\n resolveLabel(state: IssueState, currentPhase?: string): string {\n if ((state === IssueState.PhaseRunning || state === IssueState.PhaseDone) && currentPhase) {\n const phaseLabel = t(`pipeline.phase.${currentPhase}`);\n return state === IssueState.PhaseRunning\n ? t('state.phaseDoing', { label: phaseLabel })\n : t('state.phaseDone', { label: phaseLabel });\n }\n if ((state === IssueState.PhaseWaiting || state === IssueState.PhaseApproved) && currentPhase) {\n const phaseLabel = t(`pipeline.phase.${currentPhase}`);\n return state === IssueState.PhaseWaiting\n ? t('state.phaseWaiting', { label: phaseLabel })\n : t('state.phaseApproved', { label: phaseLabel });\n }\n const labels = this.collectStateLabels();\n return labels.get(state) ?? state;\n }\n\n /**\n * 收集所有状态及其展示标签。\n * 为通用状态 PhaseRunning/PhaseDone 生成每个阶段的复合 key 条目。\n */\n collectStateLabels(): Map<string, string> {\n const labels = new Map<string, string>();\n labels.set(IssueState.Pending, t('state.pending'));\n labels.set(IssueState.Skipped, t('state.skipped'));\n labels.set(IssueState.BranchCreated, t('state.branchCreated'));\n\n for (const phase of this.def.phases) {\n const phaseLabel = t(`pipeline.phase.${phase.name}`);\n\n // AI 阶段: PhaseRunning/PhaseDone → composite key\n if (phase.startState === IssueState.PhaseRunning) {\n labels.set(`phase_running:${phase.name}`, t('state.phaseDoing', { label: phaseLabel }));\n } else if (phase.startState === IssueState.PhaseWaiting) {\n // Gate 阶段: PhaseWaiting → composite key\n labels.set(`phase_waiting:${phase.name}`, t('state.phaseWaiting', { label: phaseLabel }));\n } else {\n labels.set(phase.startState, t('state.phaseDoing', { label: phaseLabel }));\n }\n\n if (phase.doneState === IssueState.PhaseDone) {\n labels.set(`phase_done:${phase.name}`, t('state.phaseDone', { label: phaseLabel }));\n } else if (phase.doneState === IssueState.PhaseApproved) {\n // Gate 阶段: PhaseApproved → composite key\n labels.set(`phase_approved:${phase.name}`, t('state.phaseApproved', { label: phaseLabel }));\n } else if (phase.doneState !== IssueState.Completed) {\n labels.set(phase.doneState, t('state.phaseDone', { label: phaseLabel }));\n }\n\n // 非通用 approvedState(保留,支持自定义状态)\n if (phase.approvedState\n && phase.approvedState !== IssueState.PhaseApproved\n && phase.approvedState !== phase.doneState) {\n labels.set(phase.approvedState, t('state.phaseApproved', { label: phaseLabel }));\n }\n }\n\n labels.set(IssueState.Completed, t('state.completed'));\n labels.set(IssueState.Failed, t('state.failed'));\n labels.set(IssueState.Paused, t('state.paused'));\n labels.set(IssueState.ResolvingConflict, t('state.resolvingConflict'));\n return labels;\n }\n\n /**\n * 根据当前 state,推导每个 phase 的进度状态。\n * 支持通用状态 PhaseRunning/PhaseDone + currentPhase。\n */\n derivePhaseStatuses(currentState: string, currentPhase?: string): Record<string, 'pending' | 'in_progress' | 'completed' | 'failed'> {\n const result: Record<string, 'pending' | 'in_progress' | 'completed' | 'failed'> = {};\n let passedCurrent = false;\n\n // Failed 状态:基于 currentPhase 推导哪个阶段失败\n if (currentState === IssueState.Failed && currentPhase) {\n for (const phase of this.def.phases) {\n if (passedCurrent) {\n result[phase.name] = 'pending';\n } else if (phase.name === currentPhase) {\n result[phase.name] = 'failed';\n passedCurrent = true;\n } else {\n result[phase.name] = 'completed';\n }\n }\n return result;\n }\n\n // Paused 状态:暂停阶段显示为 in_progress,之前 completed,之后 pending\n if (currentState === IssueState.Paused && currentPhase) {\n for (const phase of this.def.phases) {\n if (passedCurrent) {\n result[phase.name] = 'pending';\n } else if (phase.name === currentPhase) {\n result[phase.name] = 'in_progress';\n passedCurrent = true;\n } else {\n result[phase.name] = 'completed';\n }\n }\n return result;\n }\n\n // 通用阶段状态:基于 currentPhase 名称推导\n if ((currentState === IssueState.PhaseRunning || currentState === IssueState.PhaseDone) && currentPhase) {\n for (const phase of this.def.phases) {\n if (passedCurrent) {\n result[phase.name] = 'pending';\n } else if (phase.name === currentPhase) {\n result[phase.name] = currentState === IssueState.PhaseRunning ? 'in_progress' : 'completed';\n passedCurrent = currentState === IssueState.PhaseRunning;\n // PhaseDone 意味着该阶段完成,后续为 pending\n if (currentState === IssueState.PhaseDone) passedCurrent = true;\n } else {\n result[phase.name] = 'completed';\n }\n }\n return result;\n }\n\n // 通用 gate 阶段状态:基于 currentPhase 名称推导\n if ((currentState === IssueState.PhaseWaiting || currentState === IssueState.PhaseApproved) && currentPhase) {\n for (const phase of this.def.phases) {\n if (passedCurrent) {\n result[phase.name] = 'pending';\n } else if (phase.name === currentPhase) {\n // AI phase with approvedState: PhaseApproved 意味着即将执行,显示 in_progress\n const isGatedAi = phase.kind === 'ai' && phase.approvedState;\n result[phase.name] = (currentState === IssueState.PhaseWaiting\n || (currentState === IssueState.PhaseApproved && isGatedAi))\n ? 'in_progress' : 'completed';\n passedCurrent = true;\n } else {\n result[phase.name] = 'completed';\n }\n }\n return result;\n }\n\n // 终态:所有阶段标记为 completed\n if (currentState === IssueState.Completed || currentState === IssueState.ResolvingConflict) {\n for (const phase of this.def.phases) {\n result[phase.name] = 'completed';\n }\n return result;\n }\n\n // 非通用阶段状态(传统 startState/doneState 匹配,如 BranchCreated 等)\n for (const phase of this.def.phases) {\n if (passedCurrent) {\n result[phase.name] = 'pending';\n continue;\n }\n if (phase.startState === currentState) {\n result[phase.name] = 'in_progress';\n passedCurrent = true;\n } else if (phase.doneState === currentState || phase.approvedState === currentState) {\n result[phase.name] = 'completed';\n } else {\n // 未匹配任何阶段的状态(Pending/Skipped/BranchCreated/Failed)→ pending\n result[phase.name] = 'pending';\n }\n }\n return result;\n }\n\n // ─── Pipeline Protocol queries (P1) ───\n\n /**\n * 返回可被用户单独重试的阶段名列表。\n * 优先使用 spec.retryable,未声明时默认 kind === 'ai'。\n */\n getRetryablePhases(): string[] {\n return this.def.phases\n .filter(spec => spec.retryable ?? (spec.kind === 'ai'))\n .map(spec => spec.name);\n }\n\n /**\n * 判断指定阶段是否可重试。\n */\n isRetryable(phaseName: string): boolean {\n const spec = this.def.phases.find(p => p.name === phaseName);\n if (!spec) return false;\n return spec.retryable ?? (spec.kind === 'ai');\n }\n\n /**\n * 查找 gate 类型的阶段。\n */\n getGatePhase(): PhaseSpec | undefined {\n return this.def.phases.find(p => p.kind === 'gate');\n }\n\n /**\n * 判断指定阶段完成后是否应启动预览服务器。\n */\n shouldDeployPreview(phaseName: string): boolean {\n const spec = this.def.phases.find(p => p.name === phaseName);\n return spec?.deploysPreview ?? false;\n }\n\n /**\n * 收集所有阶段的产物文件,扁平化为单一列表。\n */\n collectArtifacts(): PlanFileSpec[] {\n return this.def.phases.flatMap(spec => spec.artifacts ?? []);\n }\n\n /**\n * 返回所有阶段的名称和标签(保持定义顺序)。\n */\n getPhaseDefs(): { name: string; label: string }[] {\n return this.def.phases.map(p => ({ name: p.name, label: p.label }));\n }\n\n /**\n * 返回所有 kind === 'ai' 的阶段名(可执行阶段)。\n */\n getExecutablePhaseNames(): string[] {\n return this.def.phases\n .filter(spec => spec.kind === 'ai')\n .map(spec => spec.name);\n }\n}\n","import { IssueRecord, IssueState, type PhaseProgress } from './IssueState.js';\nimport { type PipelineDef } from '../pipeline/PipelineDefinition.js';\nimport { IssueNotFoundError } from '../errors/index.js';\nimport { ActionLifecycleManager } from '../lifecycle/ActionLifecycleManager.js';\nimport { BaseTracker } from './BaseTracker.js';\nimport { type ExecutableTask, issueToExecutableTask } from './ExecutableTask.js';\nimport { getIid } from './IssueRecordHelper.js';\nimport { logger as rootLogger } from '../logger.js';\nimport { eventBus } from '../events/EventBus.js';\n\nconst logger = rootLogger.child('IssueTracker');\n\n/**\n * 旧阶段专属状态 → 通用状态的映射表。\n * 使用字符串字面量,不引用 IssueState 枚举(删枚举后不受影响)。\n */\nconst STATE_MIGRATION_MAP: Record<string, { state: string; currentPhase: string }> = {\n analyzing: { state: 'phase_running', currentPhase: 'analysis' },\n analysis_done: { state: 'phase_done', currentPhase: 'analysis' },\n designing: { state: 'phase_running', currentPhase: 'design' },\n design_done: { state: 'phase_done', currentPhase: 'design' },\n implementing: { state: 'phase_running', currentPhase: 'implement' },\n implement_done: { state: 'phase_done', currentPhase: 'implement' },\n planning: { state: 'phase_running', currentPhase: 'plan' },\n plan_done: { state: 'phase_done', currentPhase: 'plan' },\n building: { state: 'phase_running', currentPhase: 'build' },\n build_done: { state: 'phase_done', currentPhase: 'build' },\n verifying: { state: 'phase_running', currentPhase: 'verify' },\n // 旧 gate 硬编码状态 → 通用 gate 状态\n waiting_for_review: { state: 'phase_waiting', currentPhase: 'review' },\n review_approved: { state: 'phase_approved', currentPhase: 'review' },\n};\n\nexport class IssueTracker extends BaseTracker<IssueRecord> {\n private lifecycleManagers: Map<string, ActionLifecycleManager>;\n readonly tenantId: string;\n\n constructor(\n dataDir: string,\n lifecycleManagers: Map<string, ActionLifecycleManager>,\n tenantId?: string,\n ) {\n const tid = tenantId ?? 'default';\n const filename = tid === 'default' ? 'tracker.json' : `tracker-${tid}.json`;\n super(dataDir, filename, 'issues', 'tracker');\n this.lifecycleManagers = lifecycleManagers;\n this.tenantId = tid;\n this.migrateRecords();\n }\n\n /**\n * 迁移旧格式记录到新格式:\n * 1. 旧阶段专属状态 → PhaseRunning/PhaseDone + currentPhase\n * 2. failedAtState 同步迁移\n * 3. 为缺少 demandSpec 的旧记录回填\n *\n * 幂等:已迁移的记录不会重复处理。\n */\n private migrateRecords(): void {\n let migrated = 0;\n for (const record of this.getAllRecords()) {\n const raw = record as unknown as Record<string, unknown>;\n\n // 1. 迁移主状态\n const stateStr = raw.state as string;\n const migration = STATE_MIGRATION_MAP[stateStr];\n if (migration) {\n raw.state = migration.state;\n raw.currentPhase = migration.currentPhase;\n migrated++;\n }\n\n // 2. 迁移 failedAtState\n const failedAtStr = raw.failedAtState as string | undefined;\n if (failedAtStr) {\n const failedMigration = STATE_MIGRATION_MAP[failedAtStr];\n if (failedMigration) {\n raw.failedAtState = failedMigration.state;\n // 如果 failedAtState 迁移了,也需要记录 currentPhase(除非主状态已设置)\n if (!raw.currentPhase) {\n raw.currentPhase = failedMigration.currentPhase;\n }\n }\n }\n\n // 3. 回填 demandSpec(兼容旧记录)\n if (!raw.demandSpec && raw.issueIid) {\n raw.demandSpec = {\n demandId: `gf-${raw.issueIid}`,\n sourceRef: {\n source: 'gongfeng-issue',\n externalId: String(raw.issueId ?? raw.issueIid),\n displayId: String(raw.issueIid),\n },\n title: (raw.issueTitle as string) || '',\n description: '',\n createdAt: (raw.createdAt as string) || new Date().toISOString(),\n };\n }\n\n // 4. 删除 IssueIdentity 旧字段\n if (raw.issueId !== undefined || raw.issueIid !== undefined || raw.issueTitle !== undefined) {\n delete raw.issueId;\n delete raw.issueIid;\n delete raw.issueTitle;\n migrated++;\n }\n }\n if (migrated > 0) {\n this.save();\n logger.info('Migrated tracker records', { migrated });\n }\n }\n\n private lifecycleFor(record: IssueRecord): ActionLifecycleManager {\n if (record.pipelineMode) {\n const lm = this.lifecycleManagers.get(record.pipelineMode);\n if (lm) return lm;\n }\n // Fallback: 'plan-mode' or first registered manager\n return this.lifecycleManagers.get('plan-mode') ?? this.lifecycleManagers.values().next().value!;\n }\n\n private key(issueIid: number): string {\n return String(issueIid);\n }\n\n get(issueIid: number): IssueRecord | undefined {\n return this.getByKey(this.key(issueIid));\n }\n\n create(record: Omit<IssueRecord, 'createdAt' | 'updatedAt' | 'attempts'>): IssueRecord {\n const now = new Date().toISOString();\n const full: IssueRecord = {\n ...record,\n attempts: 0,\n createdAt: now,\n updatedAt: now,\n };\n this.setRecord(this.key(getIid(full)), full);\n this.save();\n logger.info('Issue tracked', { issueIid: getIid(full), state: record.state });\n eventBus.emitTyped('issue:created', full);\n return full;\n }\n\n updateState(issueIid: number, state: IssueState, extra?: Partial<IssueRecord>): void {\n const record = this.collection[this.key(issueIid)];\n if (!record) {\n throw new IssueNotFoundError(issueIid);\n }\n record.state = state;\n record.updatedAt = new Date().toISOString();\n if (state === IssueState.Completed) {\n record.lastError = undefined;\n record.failedAtState = undefined;\n }\n if (extra) {\n Object.assign(record, extra);\n }\n this.save();\n logger.info('Issue state updated', { issueIid, state });\n eventBus.emitTyped('issue:stateChanged', { issueIid, state, record });\n }\n\n /** 初始化阶段进度(流水线启动时调用) */\n initPhaseProgress(issueIid: number, def: PipelineDef): void {\n const record = this.collection[this.key(issueIid)];\n if (!record) return;\n const phases: Record<string, PhaseProgress> = {};\n for (const spec of def.phases) {\n phases[spec.name] = { status: 'pending' };\n }\n record.phaseProgress = phases;\n record.updatedAt = new Date().toISOString();\n this.save();\n }\n\n /** 更新单个阶段的进度(原子保存 + SSE 推送) */\n updatePhaseProgress(issueIid: number, phase: string, update: Partial<PhaseProgress>): void {\n const record = this.collection[this.key(issueIid)];\n if (!record?.phaseProgress) return;\n const pp = record.phaseProgress[phase];\n if (!pp) return;\n Object.assign(pp, update);\n record.updatedAt = new Date().toISOString();\n this.save();\n eventBus.emitTyped('issue:stateChanged', { issueIid, state: record.state, record });\n }\n\n markFailed(issueIid: number, error: string, failedAtState: IssueState, isRetryable?: boolean): void {\n const record = this.collection[this.key(issueIid)];\n if (!record) return;\n record.state = IssueState.Failed;\n record.lastError = error;\n record.failedAtState = failedAtState;\n record.lastErrorRetryable = isRetryable;\n record.attempts += 1;\n record.updatedAt = new Date().toISOString();\n this.save();\n logger.warn('Issue marked as failed', { issueIid, error, failedAtState, attempts: record.attempts, isRetryable });\n eventBus.emitTyped('issue:failed', { issueIid, error, failedAtState, record });\n }\n\n /**\n * Mark as failed WITHOUT incrementing attempts. Used when the agent was still\n * actively producing output at timeout — a slow-but-progressing run should not\n * consume the retry budget.\n */\n markFailedSoft(issueIid: number, error: string, failedAtState: IssueState): void {\n const record = this.collection[this.key(issueIid)];\n if (!record) return;\n record.state = IssueState.Failed;\n record.lastError = error;\n record.failedAtState = failedAtState;\n record.lastErrorRetryable = true;\n record.updatedAt = new Date().toISOString();\n this.save();\n logger.warn('Issue marked as failed (soft — no attempt increment)', {\n issueIid, error, failedAtState, attempts: record.attempts,\n });\n eventBus.emitTyped('issue:failed', { issueIid, error, failedAtState, record });\n }\n\n pauseIssue(issueIid: number, currentPhase: string): void {\n const record = this.collection[this.key(issueIid)];\n if (!record) return;\n record.state = IssueState.Paused;\n record.pausedAtPhase = currentPhase;\n // 非失败,清除失败痕迹\n record.failedAtState = undefined;\n record.lastError = undefined;\n record.processingLock = undefined;\n record.updatedAt = new Date().toISOString();\n this.save();\n logger.info('Issue paused', { issueIid, pausedAtPhase: currentPhase });\n eventBus.emitTyped('issue:paused', { issueIid, pausedAtPhase: currentPhase, record });\n }\n\n resumeFromPause(issueIid: number, def: PipelineDef, clearSession: boolean): boolean {\n const record = this.collection[this.key(issueIid)];\n if (!record || record.state !== IssueState.Paused || !record.pausedAtPhase) return false;\n\n const lm = new ActionLifecycleManager(def);\n const preState = lm.getPhasePreState(record.pausedAtPhase);\n if (!preState) return false;\n\n const phase = record.pausedAtPhase;\n record.state = preState;\n // 设置 currentPhase 为前驱阶段名(与 resetToPhase 逻辑一致)\n if (preState === IssueState.PhaseDone || preState === IssueState.PhaseApproved) {\n const phases = def.phases;\n const idx = phases.findIndex(p => p.name === phase);\n if (idx > 0) {\n record.currentPhase = phases[idx - 1].name;\n }\n }\n record.pausedAtPhase = undefined;\n record.updatedAt = new Date().toISOString();\n this.save();\n\n const eventType = clearSession ? 'issue:redone' : 'issue:continued';\n logger.info('Issue resumed from pause', { issueIid, phase, clearSession, state: preState });\n eventBus.emitTyped(eventType, { issueIid, phase, record });\n return true;\n }\n\n // ── processingLock 管理 ──\n\n /** 持久化锁超时阈值(默认 30 分钟,与 PHASE_TIMEOUT 一致) */\n private static readonly LOCK_TIMEOUT_MS = 30 * 60 * 1000;\n\n /**\n * 获取持久化处理锁。\n * - 无锁或超时锁 → 写入并返回 true\n * - 有未超时锁(其他 correlationId)→ 返回 false\n */\n acquireProcessingLock(issueIid: number, correlationId: string): boolean {\n const record = this.collection[this.key(issueIid)];\n if (!record) return false;\n\n const existing = record.processingLock;\n if (existing) {\n const age = Date.now() - new Date(existing.ts).getTime();\n if (age < IssueTracker.LOCK_TIMEOUT_MS) {\n logger.warn('Processing lock held, rejecting acquire', {\n issueIid,\n existingCorrelationId: existing.correlationId,\n ageMs: age,\n });\n return false;\n }\n logger.warn('Processing lock timed out, forcibly acquiring', {\n issueIid,\n staleCorrelationId: existing.correlationId,\n ageMs: age,\n });\n }\n\n record.processingLock = { correlationId, ts: new Date().toISOString() };\n record.updatedAt = new Date().toISOString();\n this.save();\n return true;\n }\n\n /**\n * 释放持久化处理锁。仅当 correlationId 匹配时才清除,防止旧协程误释放新锁。\n */\n releaseProcessingLock(issueIid: number, correlationId: string): void {\n const record = this.collection[this.key(issueIid)];\n if (!record?.processingLock) return;\n\n if (record.processingLock.correlationId !== correlationId) {\n logger.warn('Processing lock correlationId mismatch, skipping release', {\n issueIid,\n ownCorrelationId: correlationId,\n actualCorrelationId: record.processingLock.correlationId,\n });\n return;\n }\n\n record.processingLock = undefined;\n record.updatedAt = new Date().toISOString();\n this.save();\n }\n\n /** 强制清除持久化处理锁(管理员操作:restart/cancel/retryFromPhase) */\n clearProcessingLock(issueIid: number): void {\n const record = this.collection[this.key(issueIid)];\n if (!record?.processingLock) return;\n record.processingLock = undefined;\n record.updatedAt = new Date().toISOString();\n this.save();\n }\n\n isProcessing(issueIid: number): boolean {\n const record = this.get(issueIid);\n if (!record) return false;\n return !this.lifecycleFor(record).isTerminal(record.state);\n }\n\n isCompleted(issueIid: number): boolean {\n const record = this.get(issueIid);\n return record?.state === IssueState.Completed;\n }\n\n canRetry(issueIid: number, maxRetries: number): boolean {\n const record = this.get(issueIid);\n if (!record || record.state !== IssueState.Failed) return false;\n return record.attempts < maxRetries;\n }\n\n getRetryState(issueIid: number): IssueState | undefined {\n const record = this.get(issueIid);\n return record?.failedAtState;\n }\n\n isStalled(issueIid: number, thresholdMs: number = 5 * 60 * 1000): boolean {\n const record = this.get(issueIid);\n if (!record) return false;\n if (this.lifecycleFor(record).isBlocked(record.state)) return false;\n if (!this.isProcessing(issueIid)) return false;\n const elapsed = Date.now() - new Date(record.updatedAt).getTime();\n return elapsed > thresholdMs;\n }\n\n getDrivableIssues(maxRetries: number, stalledThresholdMs?: number): IssueRecord[] {\n return this.getAllRecords().filter((record) => {\n const lm = this.lifecycleFor(record);\n const drivable = lm.isDrivable(record.state, record.attempts, maxRetries, record.lastErrorRetryable)\n || this.isStalled(getIid(record), stalledThresholdMs);\n if (!drivable) return false;\n\n // 持久化锁检查:有未超时的锁则跳过(正在被某协程处理)\n if (record.processingLock) {\n const age = Date.now() - new Date(record.processingLock.ts).getTime();\n if (age < IssueTracker.LOCK_TIMEOUT_MS) {\n return false;\n }\n // 超时锁不拦截 — 交由 acquireProcessingLock 覆盖\n }\n\n return true;\n });\n }\n\n getAllActive(): IssueRecord[] {\n return this.getAllRecords().filter(\n (r) => !this.lifecycleFor(r).isTerminal(r.state),\n );\n }\n\n getAll(): IssueRecord[] {\n return this.getAllRecords();\n }\n\n startSkipped(issueIid: number): boolean {\n const record = this.collection[this.key(issueIid)];\n if (!record || record.state !== IssueState.Skipped) return false;\n record.state = IssueState.Pending;\n record.updatedAt = new Date().toISOString();\n this.save();\n logger.info('Skipped issue started', { issueIid });\n eventBus.emitTyped('issue:stateChanged', { issueIid, state: IssueState.Pending, record });\n return true;\n }\n\n resetFull(issueIid: number): boolean {\n const record = this.collection[this.key(issueIid)];\n if (!record) return false;\n record.state = IssueState.Pending;\n record.currentPhase = undefined;\n record.attempts = 0;\n record.failedAtState = undefined;\n record.lastError = undefined;\n record.phaseProgress = undefined;\n record.processingLock = undefined;\n record.updatedAt = new Date().toISOString();\n this.save();\n logger.info('Issue fully reset', { issueIid });\n eventBus.emitTyped('issue:restarted', { issueIid, record });\n return true;\n }\n\n resetToPhase(issueIid: number, phase: string, def: PipelineDef): boolean {\n const record = this.collection[this.key(issueIid)];\n if (!record) return false;\n // Always create a fresh lifecycle manager from the provided def.\n // The cached lifecycleManagers may be stale (e.g., missing dynamically added phases like 'uat').\n const lm = new ActionLifecycleManager(def);\n const targetState = lm.getPhasePreState(phase);\n if (!targetState) return false;\n record.state = targetState;\n // When resetting to a generic phase state, also set currentPhase\n if (targetState === IssueState.PhaseRunning || targetState === IssueState.PhaseDone\n || targetState === IssueState.PhaseWaiting || targetState === IssueState.PhaseApproved) {\n // The phase we're resetting to is the one *before* the given phase (its preState).\n // But since preState is BranchCreated for idx 0 or prev phase's doneState,\n // we need to find the actual phase name that this preState corresponds to.\n // For PhaseDone preState, the currentPhase should be the prev phase name.\n const phases = def.phases;\n const idx = phases.findIndex(p => p.name === phase);\n if (idx > 0) {\n record.currentPhase = phases[idx - 1].name;\n }\n }\n record.failedAtState = undefined;\n record.lastError = undefined;\n record.processingLock = undefined;\n // 重置目标阶段及后续阶段的 phaseProgress\n if (record.phaseProgress) {\n const phaseIdx = def.phases.findIndex(p => p.name === phase);\n if (phaseIdx >= 0) {\n for (let i = phaseIdx; i < def.phases.length; i++) {\n const pp = record.phaseProgress[def.phases[i].name];\n if (pp) {\n pp.status = 'pending';\n pp.startedAt = undefined;\n pp.completedAt = undefined;\n pp.error = undefined;\n }\n }\n }\n }\n record.updatedAt = new Date().toISOString();\n this.save();\n logger.info('Issue reset to phase', { issueIid, phase, state: targetState });\n eventBus.emitTyped('issue:retryFromPhase', { issueIid, phase, record });\n return true;\n }\n\n resetForRetry(issueIid: number): boolean {\n const record = this.collection[this.key(issueIid)];\n if (!record || record.state !== IssueState.Failed) return false;\n\n const restoreState = record.failedAtState ?? IssueState.Pending;\n record.state = restoreState;\n record.lastError = undefined;\n record.processingLock = undefined;\n // 重置 failed 阶段的 phaseProgress\n if (record.phaseProgress && record.currentPhase) {\n const pp = record.phaseProgress[record.currentPhase];\n if (pp && pp.status === 'failed') {\n pp.status = 'pending';\n pp.startedAt = undefined;\n pp.completedAt = undefined;\n pp.error = undefined;\n }\n }\n record.updatedAt = new Date().toISOString();\n this.save();\n logger.info('Issue reset for retry', { issueIid, restoreState });\n eventBus.emitTyped('issue:resetForRetry', { issueIid, restoreState, record });\n return true;\n }\n\n delete(issueIid: number): boolean {\n const key = this.key(issueIid);\n const record = this.collection[key];\n if (!record) return false;\n delete this.collection[key];\n this.save();\n logger.info('Issue deleted from tracker', { issueIid });\n eventBus.emitTyped('issue:deleted', { issueIid, record });\n return true;\n }\n\n recoverInterruptedIssues(): number {\n let count = 0;\n for (const record of this.getAllRecords()) {\n const lm = this.lifecycleFor(record);\n if (lm.isInProgress(record.state)) {\n const iid = getIid(record);\n logger.warn('Recovering interrupted issue', {\n issueIid: iid,\n state: record.state,\n });\n record.failedAtState = record.state;\n record.state = IssueState.Failed;\n record.lastError = 'Interrupted by service restart';\n record.lastErrorRetryable = false;\n record.attempts += 1;\n record.processingLock = undefined;\n record.updatedAt = new Date().toISOString();\n count++;\n eventBus.emitTyped('issue:failed', {\n issueIid: iid,\n error: 'Interrupted by service restart',\n failedAtState: record.failedAtState,\n record,\n });\n } else if (record.state === IssueState.Failed && record.lastErrorRetryable !== false) {\n // Prevent auto-retry of pre-existing failures after restart;\n // user must manually trigger retry via UI or webhook.\n const iid = getIid(record);\n logger.info('Marking pre-existing failed issue as non-retryable after restart', {\n issueIid: iid,\n currentPhase: record.currentPhase,\n attempts: record.attempts,\n });\n record.lastErrorRetryable = false;\n record.processingLock = undefined;\n record.updatedAt = new Date().toISOString();\n count++;\n }\n }\n if (count > 0) {\n this.save();\n logger.info('Recovered interrupted issues', { count });\n }\n return count;\n }\n\n /** 将所有 IssueRecord 投影为 ExecutableTask[] */\n toExecutableTasks(): ExecutableTask[] {\n return this.getAllRecords().map((record) => {\n const lm = this.lifecycleFor(record);\n return issueToExecutableTask(record, lm);\n });\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { ProgressData, PhaseProgress, type PhaseStatus } from '../tracker/IssueState.js';\nimport type { PipelineDef } from '../pipeline/PipelineDefinition.js';\nimport { logger as rootLogger } from '../logger.js';\n\nconst logger = rootLogger.child('PlanPersistence');\n\nconst PLAN_DIR = '.claude-plan';\n\nexport interface ReviewRound {\n round: number;\n feedback: string;\n timestamp: string;\n}\n\nexport class PlanPersistence {\n private workDir: string;\n private issueIid: number;\n\n constructor(workDir: string, issueIid: number) {\n this.workDir = workDir;\n this.issueIid = issueIid;\n }\n\n get baseDir(): string {\n return this.workDir;\n }\n\n get planDir(): string {\n return path.join(this.workDir, PLAN_DIR, `issue-${this.issueIid}`);\n }\n\n ensureDir(): void {\n if (!fs.existsSync(this.planDir)) {\n fs.mkdirSync(this.planDir, { recursive: true });\n }\n }\n\n writeIssueMeta(meta: { id: number; iid: number; title: string; labels: string[]; state: string }): void {\n this.ensureDir();\n const filePath = path.join(this.planDir, 'issue-meta.json');\n fs.writeFileSync(filePath, JSON.stringify(meta, null, 2), 'utf-8');\n logger.info('Issue meta written');\n }\n\n writeProgress(data: ProgressData): void {\n this.ensureDir();\n const filePath = path.join(this.planDir, 'progress.json');\n fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8');\n logger.debug('Progress written', { currentPhase: data.currentPhase });\n }\n\n readProgress(): ProgressData | null {\n const filePath = path.join(this.planDir, 'progress.json');\n if (!fs.existsSync(filePath)) return null;\n try {\n return JSON.parse(fs.readFileSync(filePath, 'utf-8'));\n } catch {\n return null;\n }\n }\n\n writeAnalysis(content: string): void {\n this.ensureDir();\n fs.writeFileSync(path.join(this.planDir, '01-analysis.md'), content, 'utf-8');\n logger.info('Analysis document written');\n }\n\n writeDesign(content: string): void {\n this.ensureDir();\n fs.writeFileSync(path.join(this.planDir, '02-design.md'), content, 'utf-8');\n logger.info('Design document written');\n }\n\n writeTodolist(content: string): void {\n this.ensureDir();\n fs.writeFileSync(path.join(this.planDir, '03-todolist.md'), content, 'utf-8');\n logger.info('Todolist written');\n }\n\n writeVerifyReport(content: string, filename = '04-verify-report.md'): void {\n this.ensureDir();\n fs.writeFileSync(path.join(this.planDir, filename), content, 'utf-8');\n logger.info('Verify report written', { filename });\n }\n\n getAllPlanFiles(): string[] {\n if (!fs.existsSync(this.planDir)) return [];\n return fs.readdirSync(this.planDir).map((f) => path.join(PLAN_DIR, `issue-${this.issueIid}`, f));\n }\n\n createInitialProgress(displayId: number, title: string, branchName: string, def?: PipelineDef): ProgressData {\n const pending: PhaseProgress = { status: 'pending' };\n if (def) {\n const phases: Record<string, PhaseProgress> = {};\n for (const spec of def.phases) {\n phases[spec.name] = { ...pending };\n }\n return {\n displayId,\n title,\n branchName,\n pipelineMode: def.mode,\n currentPhase: def.phases[0].name,\n phases,\n };\n }\n return {\n displayId,\n title,\n branchName,\n currentPhase: 'analysis',\n phases: {\n analysis: { ...pending },\n design: { ...pending },\n implement: { ...pending },\n verify: { ...pending },\n },\n };\n }\n\n writePlan(content: string): void {\n this.ensureDir();\n fs.writeFileSync(path.join(this.planDir, '01-plan.md'), content, 'utf-8');\n logger.info('Plan document written');\n }\n\n writeReviewFeedback(content: string): void {\n this.ensureDir();\n const history = this.readReviewHistory();\n const round: ReviewRound = {\n round: history.length + 1,\n feedback: content,\n timestamp: new Date().toISOString(),\n };\n history.push(round);\n fs.writeFileSync(\n path.join(this.planDir, 'review-history.json'),\n JSON.stringify(history, null, 2),\n 'utf-8',\n );\n fs.writeFileSync(\n path.join(this.planDir, 'review-feedback.md'),\n PlanPersistence.renderReviewHistoryMarkdown(history),\n 'utf-8',\n );\n logger.info('Review feedback appended', { round: round.round });\n }\n\n readReviewFeedback(): string | null {\n const filePath = path.join(this.planDir, 'review-feedback.md');\n if (!fs.existsSync(filePath)) return null;\n try {\n return fs.readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n }\n\n readReviewHistory(): ReviewRound[] {\n const filePath = path.join(this.planDir, 'review-history.json');\n if (!fs.existsSync(filePath)) return [];\n try {\n const data = JSON.parse(fs.readFileSync(filePath, 'utf-8'));\n return Array.isArray(data) ? data : [];\n } catch {\n return [];\n }\n }\n\n static renderReviewHistoryMarkdown(history: ReviewRound[]): string {\n if (history.length === 0) return '';\n const lines = ['# 审核反馈历史', ''];\n for (const r of history) {\n lines.push(`## 第 ${r.round} 轮审核反馈`);\n lines.push(`> 时间: ${r.timestamp}`);\n lines.push('');\n lines.push(r.feedback);\n lines.push('');\n }\n return lines.join('\\n');\n }\n\n updatePhaseProgress(\n phaseName: string,\n status: PhaseStatus,\n error?: string,\n options?: { preserveSessionId?: boolean },\n ): void {\n const progress = this.readProgress();\n if (!progress) {\n logger.warn('Cannot update phase progress: progress.json not found', {\n issueIid: this.issueIid, phase: phaseName, targetStatus: status,\n });\n return;\n }\n\n const now = new Date().toISOString();\n if (!progress.phases[phaseName]) {\n progress.phases[phaseName] = { status: 'pending' };\n }\n const phase = progress.phases[phaseName];\n\n phase.status = status;\n if (status === 'in_progress') {\n phase.startedAt = now;\n progress.currentPhase = phaseName;\n if (!options?.preserveSessionId) {\n delete phase.sessionId;\n }\n } else if (status === 'completed') {\n phase.completedAt = now;\n } else if (status === 'failed') {\n phase.error = error;\n }\n\n this.writeProgress(progress);\n }\n\n updatePhaseSessionId(phaseName: string, sessionId: string): void {\n const progress = this.readProgress();\n if (!progress?.phases[phaseName]) return;\n progress.phases[phaseName].sessionId = sessionId;\n this.writeProgress(progress);\n }\n\n getPhaseSessionId(phaseName: string): string | undefined {\n const progress = this.readProgress();\n return progress?.phases[phaseName]?.sessionId;\n }\n\n // ---------------------------------------------------------------------------\n // 通用文件操作 — 替代阶段中散落的 fs 直接调用\n // ---------------------------------------------------------------------------\n\n /** 读取 planDir 下指定文件,不存在返回 null */\n readFile(filename: string): string | null {\n const filePath = path.join(this.planDir, filename);\n if (!fs.existsSync(filePath)) return null;\n try {\n return fs.readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n }\n\n /** 检查 planDir 下指定文件是否就绪(存在 + 大于 minBytes) */\n isArtifactReady(filename: string, minBytes = 50): boolean {\n const filePath = path.join(this.planDir, filename);\n if (!fs.existsSync(filePath)) return false;\n try {\n return fs.statSync(filePath).size >= minBytes;\n } catch {\n return false;\n }\n }\n\n /** 写入 planDir 下指定文件(自动 ensureDir) */\n writeFile(filename: string, content: string): void {\n this.ensureDir();\n fs.writeFileSync(path.join(this.planDir, filename), content, 'utf-8');\n }\n\n /**\n * Copy a plan file from an external source (e.g. ~/.claude/plans/) into planDir.\n * Returns the destination path, or null if the source is empty/unreadable.\n */\n copyPlanFromExternal(sourcePath: string, targetFilename = '01-plan.md'): string | null {\n try {\n const content = fs.readFileSync(sourcePath, 'utf-8');\n if (content.trim().length === 0) {\n logger.warn('External plan file is empty', { sourcePath });\n return null;\n }\n this.ensureDir();\n const destPath = path.join(this.planDir, targetFilename);\n fs.writeFileSync(destPath, content, 'utf-8');\n logger.info('Plan copied from external source', {\n source: sourcePath,\n dest: destPath,\n size: content.length,\n });\n return destPath;\n } catch (err) {\n logger.error('Failed to copy plan from external source', { sourcePath, err });\n return null;\n }\n }\n}\n","import path from 'node:path';\nimport type { AIRunner, RunResult, InputRequest, StreamEvent } from '../ai-runner/index.js';\nimport { GitOperations } from '../git/GitOperations.js';\nimport { PlanPersistence } from '../persistence/PlanPersistence.js';\nimport { AIExecutionError } from '../errors/index.js';\nimport { RuleResolver } from '../rules/index.js';\nimport { getProjectKnowledge } from '../knowledge/index.js';\nimport { HookInjector } from '../hooks/index.js';\nimport { Config } from '../config.js';\nimport { buildWorkspaceSection } from '../prompts/templates.js';\nimport type { PortPair } from '../deploy/PortAllocator.js';\nimport type { DemandSpec } from '../demand/DemandSpec.js';\nimport type { WorkspaceLayout } from '../prompts/templates.js';\nimport type { PhaseOutcome, PhaseCallbacks } from './PhaseOutcome.js';\nimport { logger as rootLogger, Logger } from '../logger.js';\nimport { t } from '../i18n/index.js';\n\n/** verify-fix loop 的修复上下文 — 当验证失败回退到 build 阶段时注入 */\nexport interface FixContext {\n /** 当前修复迭代轮次(1-based) */\n iteration: number;\n /** 上一轮验证中未通过的检查项描述 */\n verifyFailures: string[];\n /** 上一轮验证报告原文(截断) */\n rawReport: string;\n}\n\nexport interface PhaseContext {\n demand: DemandSpec;\n branchName: string;\n pipelineMode?: string;\n ports?: PortPair;\n fixContext?: FixContext;\n workspace?: WorkspaceLayout;\n}\n\nexport abstract class BasePhase {\n static readonly MIN_ARTIFACT_BYTES = 50;\n\n protected aiRunner: AIRunner;\n protected git: GitOperations;\n protected plan: PlanPersistence;\n protected config: Config;\n protected logger: Logger;\n /** 多仓模式下所有 repo 的 GitOperations(repo name → GitOperations) */\n protected wtGitMap?: Map<string, GitOperations>;\n\n abstract readonly phaseName: string;\n\n constructor(\n aiRunner: AIRunner,\n git: GitOperations,\n plan: PlanPersistence,\n config: Config,\n ) {\n this.aiRunner = aiRunner;\n this.git = git;\n this.plan = plan;\n this.config = config;\n this.logger = rootLogger.child(this.constructor.name);\n }\n\n /** 注入多仓库 GitOperations map(由编排器在创建 phase 后调用) */\n setWtGitMap(map: Map<string, GitOperations>): void {\n this.wtGitMap = map;\n }\n\n protected abstract buildPrompt(ctx: PhaseContext): string;\n\n protected getRunMode(): 'plan' | 'agent' | undefined {\n return undefined;\n }\n\n /** 获取阶段预期的产物文件列表。编排器需通过此方法同步产物到 Issue。 */\n getResultFiles(_ctx?: PhaseContext): Array<{ filename: string; label: string }> {\n return [];\n }\n\n /**\n * 纯逻辑执行 — 零副作用,返回 PhaseOutcome。\n *\n * 阶段内部仅做:构建 prompt → AI 执行 → 验证产物 → 返回结果。\n * 所有副作用(状态转换、Git commit、Issue 评论、事件推送)由编排器统一处理。\n */\n async run(ctx: PhaseContext, callbacks?: PhaseCallbacks): Promise<PhaseOutcome> {\n const displayId = Number(ctx.demand.sourceRef.displayId);\n const expectedResultFiles = this.getResultFiles(ctx);\n\n // 1. 构建完整 prompt\n let prompt = this.buildPrompt(ctx);\n const wsSection = buildWorkspaceSection(ctx.workspace);\n if (wsSection) prompt += `\\n\\n${wsSection}`;\n const rules = await this.resolveRules(ctx);\n if (rules) prompt += `\\n\\n${t('basePhase.rulesSection', { rules })}`;\n\n // 2. AI 执行(含 session resume fallback)\n const resumeInfo = this.resolveResumeInfo();\n let result: RunResult;\n\n if (resumeInfo.resumable) {\n this.logger.info('Attempting session resume', {\n issueIid: displayId,\n phase: this.phaseName,\n sessionId: resumeInfo.sessionId,\n });\n result = await this.runWithResumeFallback(\n displayId, resumeInfo.sessionId!, t('basePhase.resumePrompt'),\n prompt, callbacks?.onInputRequired, ctx, callbacks?.onStreamEvent,\n );\n } else {\n result = await this.runAI(\n displayId, prompt, callbacks?.onInputRequired,\n undefined, ctx, callbacks?.onStreamEvent,\n );\n }\n\n // 3. 失败 → 返回 failed outcome(不抛异常)\n if (!result.success) {\n this.persistSessionId(result.sessionId);\n return {\n status: 'failed',\n output: result.output,\n sessionId: result.sessionId,\n exitCode: result.exitCode,\n error: {\n message: (result.errorMessage || result.output).slice(0, 500),\n isRetryable: this.classifyRetryable(result),\n rawOutput: result.output,\n wasActiveAtTimeout: result.wasActiveAtTimeout,\n },\n };\n }\n\n this.persistSessionId(result.sessionId);\n\n // 4. 验证产物\n try {\n await this.validatePhaseOutput(ctx, displayId, expectedResultFiles);\n } catch (err) {\n return {\n status: 'failed',\n output: result.output,\n sessionId: result.sessionId,\n error: { message: (err as Error).message, isRetryable: false, rawOutput: result.output },\n };\n }\n\n // 5. 返回 completed(零副作用)\n return {\n status: 'completed',\n output: result.output,\n sessionId: result.sessionId,\n exitCode: result.exitCode,\n };\n }\n\n // ── Session resume helpers ──\n\n protected resolveResumeInfo(): { resumable: boolean; sessionId?: string } {\n if (this.isAcpMode()) {\n return { resumable: false };\n }\n const previousSessionId = this.plan.getPhaseSessionId(this.phaseName);\n if (!previousSessionId) {\n return { resumable: false };\n }\n const progress = this.plan.readProgress();\n const phaseStatus = progress?.phases[this.phaseName]?.status;\n if (phaseStatus !== 'failed' && phaseStatus !== 'in_progress') {\n return { resumable: false };\n }\n return { resumable: true, sessionId: previousSessionId };\n }\n\n private isAcpMode(): boolean {\n return this.config.ai.mode === 'codebuddy-acp';\n }\n\n protected resolveAIWorkDir(ctx?: PhaseContext): string {\n if (ctx?.workspace && ctx.workspace.repos.length > 1) {\n return ctx.workspace.workspaceRoot;\n }\n return this.plan.baseDir;\n }\n\n /** 检查预期产物文件是否已就绪(存在且满足最小字节数),不抛异常 */\n private checkArtifactsReady(ctx: PhaseContext | undefined, _displayId: number): boolean {\n const resultFiles = this.getResultFiles(ctx);\n if (resultFiles.length === 0) return true;\n\n for (const file of resultFiles) {\n if (!this.plan.isArtifactReady(file.filename, BasePhase.MIN_ARTIFACT_BYTES)) return false;\n }\n return true;\n }\n\n protected async runAI(\n displayId: number,\n prompt: string,\n onInputRequired?: (request: InputRequest) => Promise<string>,\n options?: { sessionId?: string; continueSession?: boolean },\n ctx?: PhaseContext,\n onStreamEvent?: (event: StreamEvent) => void,\n ): Promise<RunResult> {\n // Capture file list once — getResultFiles() may return different results\n // after the AI writes files (e.g. ReleasePhase switches from detect→exec mode).\n const resultFiles = this.getResultFiles(ctx);\n const snapshotFilenames = resultFiles.map(f => f.filename);\n const artifactCheck = snapshotFilenames.length > 0\n ? () => snapshotFilenames.every(fn => this.plan.isArtifactReady(fn, BasePhase.MIN_ARTIFACT_BYTES))\n : undefined;\n const artifactPaths = snapshotFilenames.length > 0\n ? snapshotFilenames.map(fn => path.join(this.plan.planDir, fn))\n : undefined;\n\n let capturedSessionId: string | undefined;\n const result = await this.aiRunner.run({\n prompt,\n workDir: this.resolveAIWorkDir(ctx),\n timeoutMs: this.config.ai.phaseTimeoutMs,\n idleTimeoutMs: this.config.ai.idleTimeoutMs,\n timeoutGraceMs: this.config.ai.timeoutGraceMs,\n timeoutExtensionMs: this.config.ai.timeoutExtensionMs,\n timeoutMaxExtensions: this.config.ai.timeoutMaxExtensions,\n mode: this.getRunMode(),\n phaseName: this.phaseName,\n artifactCheck,\n artifactPaths,\n sessionId: options?.sessionId,\n continueSession: options?.continueSession,\n onStreamEvent: (event) => {\n if (!capturedSessionId && event.type !== 'raw') {\n const content = event.content as Record<string, unknown>;\n if (content?.session_id && typeof content.session_id === 'string') {\n capturedSessionId = content.session_id;\n this.persistSessionId(capturedSessionId);\n }\n }\n onStreamEvent?.(event);\n },\n onInputRequired,\n });\n if (result.sessionId) {\n this.persistSessionId(result.sessionId);\n }\n return result;\n }\n\n protected async runWithResumeFallback(\n displayId: number,\n sessionId: string,\n resumePrompt: string,\n fullPrompt: string,\n onInputRequired?: (request: InputRequest) => Promise<string>,\n ctx?: PhaseContext,\n onStreamEvent?: (event: StreamEvent) => void,\n ): Promise<RunResult> {\n const result = await this.runAI(displayId, resumePrompt, onInputRequired, {\n sessionId,\n continueSession: true,\n }, ctx, onStreamEvent);\n\n if (!result.success && this.isResumeFailure(result)) {\n this.logger.warn(t('basePhase.resumeFallback'), {\n issueIid: displayId,\n phase: this.phaseName,\n exitCode: result.exitCode,\n });\n onStreamEvent?.({\n type: 'system',\n content: t('basePhase.resumeFallback'),\n timestamp: new Date().toISOString(),\n });\n return this.runAI(displayId, fullPrompt, onInputRequired, undefined, ctx, onStreamEvent);\n }\n\n return result;\n }\n\n /**\n * 判断 AI 执行失败是否为永久性错误(不可重试)。\n * 模型不存在、API key 无效等配置问题重试不会成功。\n */\n protected classifyRetryable(result: RunResult): boolean {\n const msg = (result.errorMessage ?? result.output ?? '').toLowerCase();\n const permanentPatterns = [\n /model\\b.*\\b(?:not found|not supported|unavailable|service info not found)/,\n /invalid.?api.?key/,\n /authentication.*(?:failed|denied|error)/,\n /permission.?denied/,\n /billing/,\n /quota.*exceeded/,\n ];\n return !permanentPatterns.some(p => p.test(msg));\n }\n\n /**\n * Heuristic: a resume failure is typically an immediate process exit\n * (exit code != 0, empty output) caused by an invalid/expired session ID.\n */\n private isResumeFailure(result: RunResult): boolean {\n if (result.success) return false;\n const msg = (result.errorMessage ?? '').toLowerCase();\n\n // Specific session-related patterns\n if (msg.includes('session') || msg.includes('resume') || msg.includes('session_id')) {\n return true;\n }\n\n // Empty output + non-zero exit: likely immediate crash from broken session ID,\n // but NOT if the error looks like a model/config problem.\n if (result.output.length === 0 && result.exitCode !== null && result.exitCode !== 0) {\n const isConfigError = msg.includes('model') || msg.includes('api key') || msg.includes('authentication');\n return !isConfigError;\n }\n\n return false;\n }\n\n protected persistSessionId(sessionId: string | undefined): void {\n if (sessionId) {\n this.plan.updatePhaseSessionId(this.phaseName, sessionId);\n }\n }\n\n protected async resolveRules(ctx: PhaseContext): Promise<string | null> {\n try {\n const knowledge = getProjectKnowledge();\n const resolver = new RuleResolver(knowledge?.ruleTriggers);\n const context = `${ctx.demand.title} ${ctx.demand.description} ${ctx.demand.supplement ? JSON.stringify(ctx.demand.supplement) : ''}`;\n\n // Load rules from all repos in workspace mode\n if (ctx.workspace && ctx.workspace.repos.length > 1) {\n for (const repo of ctx.workspace.repos) {\n const rulesDir = path.join(repo.gitRootDir, '.cursor', 'rules');\n try {\n await resolver.loadRules(rulesDir);\n } catch {\n // Some repos may not have rules\n }\n }\n } else {\n const rulesDir = path.join(this.plan.baseDir, '.cursor', 'rules');\n await resolver.loadRules(rulesDir);\n }\n\n const matched = resolver.matchRules(context);\n if (matched.length > 0) {\n this.logger.info(`Matched ${matched.length} MDC rules`, {\n rules: matched.map(r => r.filename),\n });\n return resolver.formatForPrompt(matched);\n }\n } catch (err) {\n this.logger.warn('Failed to resolve MDC rules', { error: (err as Error).message });\n }\n return null;\n }\n\n protected async validatePhaseOutput(\n ctx: PhaseContext,\n _displayId: number,\n resultFiles = this.getResultFiles(ctx),\n ): Promise<void> {\n if (resultFiles.length === 0) return;\n\n const missing: string[] = [];\n\n for (const file of resultFiles) {\n if (!this.plan.isArtifactReady(file.filename, BasePhase.MIN_ARTIFACT_BYTES)) {\n const content = this.plan.readFile(file.filename);\n if (content === null) {\n missing.push(file.filename);\n } else {\n missing.push(`${file.filename} (${Buffer.byteLength(content, 'utf-8')} bytes, 内容不足)`);\n }\n }\n }\n\n if (missing.length > 0) {\n const msg = `AI 进程成功退出但未生成预期产物: ${missing.join(', ')}`;\n this.logger.error(msg, { phase: this.phaseName, displayId: _displayId });\n throw new AIExecutionError(this.phaseName, msg, { output: '', exitCode: 0 });\n }\n\n this.logHookManifest();\n }\n\n /** 读取 hook manifest 并记录产物写入历史(P1 增强层,不影响主流程) */\n private logHookManifest(): void {\n try {\n const injector = new HookInjector();\n const entries = injector.readManifest(this.plan.baseDir);\n if (entries.length === 0) return;\n\n const artifactWrites = entries.filter(e => 'file' in e && e.event === 'write');\n if (artifactWrites.length > 0) {\n this.logger.info('Hook manifest: artifact writes recorded', {\n phase: this.phaseName,\n writes: artifactWrites.length,\n files: artifactWrites.map(e => ('file' in e ? e.file : 'unknown')),\n });\n }\n } catch {\n // Hook manifest is best-effort; never block phase validation\n }\n }\n}\n","import { readdir, readFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport type { RuleTriggerConfig } from '../knowledge/ProjectKnowledge.js';\n\nexport interface MdcRule {\n filename: string;\n description: string;\n alwaysApply: boolean;\n content: string;\n}\n\nfunction parseFrontmatter(raw: string): { description: string; alwaysApply: boolean; content: string } {\n const fmRegex = /^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n/;\n const match = raw.match(fmRegex);\n if (!match) {\n return { description: '', alwaysApply: false, content: raw.trim() };\n }\n\n const yamlBlock = match[1];\n const content = raw.slice(match[0].length).trim();\n\n let description = '';\n const descMatch = yamlBlock.match(/description:\\s*(.+)/);\n if (descMatch) {\n description = descMatch[1].trim();\n }\n\n let alwaysApply = false;\n const applyMatch = yamlBlock.match(/alwaysApply:\\s*(true|false)/i);\n if (applyMatch) {\n alwaysApply = applyMatch[1].toLowerCase() === 'true';\n }\n\n return { description, alwaysApply, content };\n}\n\nexport class RuleResolver {\n private rules: MdcRule[] = [];\n private triggers: RuleTriggerConfig[] | undefined;\n\n constructor(ruleTriggers?: RuleTriggerConfig[]) {\n this.triggers = ruleTriggers;\n }\n\n public async loadRules(rulesDir: string): Promise<void> {\n this.rules = [];\n let files: string[];\n try {\n files = await readdir(rulesDir);\n } catch {\n return;\n }\n\n const mdcFiles = files.filter(f => f.endsWith('.mdc'));\n\n const loadPromises = mdcFiles.map(async (filename) => {\n try {\n const raw = await readFile(path.join(rulesDir, filename), 'utf-8');\n const { description, alwaysApply, content } = parseFrontmatter(raw);\n if (content) {\n this.rules.push({ filename, description, alwaysApply, content });\n }\n } catch {\n // skip unreadable files\n }\n });\n\n await Promise.all(loadPromises);\n }\n\n public getRules(): MdcRule[] {\n return this.rules;\n }\n\n public matchRules(text: string): MdcRule[] {\n const lowerText = text.toLowerCase();\n const matched = new Map<string, MdcRule>();\n\n // Always include alwaysApply rules\n for (const rule of this.rules) {\n if (rule.alwaysApply) {\n matched.set(rule.filename, rule);\n }\n }\n\n if (this.triggers && this.triggers.length > 0) {\n // Use configured triggers for keyword matching\n for (const trigger of this.triggers) {\n if (matched.has(trigger.filename)) continue;\n const isTriggered = trigger.keywords.some(kw => lowerText.includes(kw.toLowerCase()));\n if (!isTriggered) continue;\n\n const rule = this.rules.find(r => r.filename === trigger.filename);\n if (rule) {\n matched.set(rule.filename, rule);\n }\n }\n } else {\n // Fallback: match based on frontmatter description words\n for (const rule of this.rules) {\n if (matched.has(rule.filename)) continue;\n if (!rule.description) continue;\n\n const descWords = rule.description\n .split(/[\\s,,;;、/|]+/)\n .filter(w => w.length >= 2);\n const isMatched = descWords.some(word => lowerText.includes(word.toLowerCase()));\n if (isMatched) {\n matched.set(rule.filename, rule);\n }\n }\n }\n\n return Array.from(matched.values());\n }\n\n public formatForPrompt(rules: MdcRule[]): string {\n if (rules.length === 0) return '';\n\n return rules.map(rule => {\n const header = rule.description\n ? `### ${rule.description} (${rule.filename})`\n : `### ${rule.filename}`;\n return `${header}\\n\\n${rule.content}`;\n }).join('\\n\\n---\\n\\n');\n }\n}\n","/**\n * 解析验证阶段生成的报告,提取通过/失败状态和失败原因。\n *\n * 解析逻辑基于验证 prompt 要求 AI 输出的结构化格式,\n * 同时兼容中英文和多种常见写法。\n */\n\nexport interface TodolistStats {\n completed: number;\n total: number;\n}\n\nexport interface VerifyReportResult {\n /** 综合判定:所有检查项均通过 */\n passed: boolean;\n lintPassed: boolean;\n buildPassed: boolean;\n testPassed: boolean;\n todolistComplete: boolean;\n todolistStats?: TodolistStats;\n /** 未通过的检查项及其原因 */\n failureReasons: string[];\n /** 原始报告内容 */\n rawReport: string;\n}\n\n// -- 匹配模式 --\n\n// \"Lint 结果: 失败\" / \"**Lint 结果**: 失败\" / \"Lint Result: Failed\"\nconst LINT_FAIL_RE = /\\*{0,2}Lint\\s*(?:结果|Result)\\*{0,2}\\s*[::]\\s*(?:失败|failed|fail|未通过)/i;\nconst BUILD_FAIL_RE = /\\*{0,2}Build\\s*(?:结果|Result)\\*{0,2}\\s*[::]\\s*(?:失败|failed|fail|未通过)/i;\nconst TEST_FAIL_RE = /\\*{0,2}Test\\s*(?:结果|Result)\\*{0,2}\\s*[::]\\s*(?:失败|failed|fail|未通过)/i;\n\n// \"总结: 验证失败\" / \"**总结**: 验证失败\" / \"Summary: Verification Failed\"\nconst SUMMARY_FAIL_RE = /\\*{0,2}(?:总结|Summary)\\*{0,2}\\s*[::].*(?:验证失败|verification\\s+failed|failed|失败)/i;\n\n// \"Todolist 检查: 3/5 项完成\" 或 \"**Todolist 检查**: 3/5\" 或 \"Todolist: 3/5\"\nconst TODOLIST_STATS_RE = /\\*{0,2}(?:Todolist|Todo)\\s*(?:检查|check)?\\*{0,2}\\s*[::]\\s*(\\d+)\\s*[//]\\s*(\\d+)/i;\n\nexport class VerifyReportParser {\n /**\n * 解析验证报告内容。\n *\n * @param reportContent 验证报告的完整 Markdown 文本\n */\n parse(reportContent: string): VerifyReportResult {\n const lintPassed = !LINT_FAIL_RE.test(reportContent);\n const buildPassed = !BUILD_FAIL_RE.test(reportContent);\n const testPassed = !TEST_FAIL_RE.test(reportContent);\n\n const todolistStats = this.parseTodolistStats(reportContent);\n const todolistComplete = todolistStats\n ? todolistStats.total === 0 || todolistStats.completed === todolistStats.total\n : true; // 无统计数据时默认视为完成(不误判)\n\n const failureReasons: string[] = [];\n if (!lintPassed) failureReasons.push('Lint 检查失败');\n if (!buildPassed) failureReasons.push('Build 编译失败');\n if (!testPassed) failureReasons.push('测试未通过');\n if (!todolistComplete) {\n const statsText = todolistStats\n ? `(${todolistStats.completed}/${todolistStats.total})`\n : '';\n failureReasons.push(`Todolist 未全部完成${statsText}`);\n }\n\n // 如果上面各项都看似通过,但总结中明确写了\"验证失败\",依然判为失败\n const summaryFailed = SUMMARY_FAIL_RE.test(reportContent);\n if (failureReasons.length === 0 && summaryFailed) {\n failureReasons.push('验证报告总结判定为失败');\n }\n\n const passed = failureReasons.length === 0;\n\n return {\n passed,\n lintPassed,\n buildPassed,\n testPassed,\n todolistComplete,\n todolistStats: todolistStats ?? undefined,\n failureReasons,\n rawReport: reportContent,\n };\n }\n\n /**\n * 从 plan 文件中解析 Todolist 完成度。\n * 统计 `- [x]` (已完成) 和 `- [ ]` (未完成) 的数量。\n */\n parseTodolistFromPlan(planContent: string): TodolistStats {\n const completedRe = /^[ \\t]*-\\s+\\[x\\]/gim;\n const uncompletedRe = /^[ \\t]*-\\s+\\[\\s\\]/gm;\n\n const completedMatches = planContent.match(completedRe);\n const uncompletedMatches = planContent.match(uncompletedRe);\n\n const completed = completedMatches?.length ?? 0;\n const uncompleted = uncompletedMatches?.length ?? 0;\n\n return {\n completed,\n total: completed + uncompleted,\n };\n }\n\n /**\n * 从报告中提取 Todolist 统计数据。\n * 格式: \"Todolist 检查: X/Y 项完成\"\n */\n private parseTodolistStats(reportContent: string): TodolistStats | null {\n const match = reportContent.match(TODOLIST_STATS_RE);\n if (match) {\n return {\n completed: parseInt(match[1], 10),\n total: parseInt(match[2], 10),\n };\n }\n return null;\n }\n}\n","import { BasePhase, PhaseContext } from './BasePhase.js';\nimport { verifyPrompt, planModeVerifyPrompt, demandToPromptContext } from '../prompts/templates.js';\nimport { VerifyReportParser } from '../verify/index.js';\nimport type { VerifyReportResult } from '../verify/index.js';\nimport type { PhaseOutcome, PhaseCallbacks } from './PhaseOutcome.js';\n\nexport interface VerifyRunResult {\n verifyReport?: VerifyReportResult;\n}\n\nexport class VerifyPhase extends BasePhase {\n readonly phaseName = 'verify' as const;\n private readonly reportParser = new VerifyReportParser();\n\n getResultFiles(ctx?: PhaseContext) {\n const filename = ctx?.pipelineMode === 'plan-mode' ? '02-verify-report.md' : '04-verify-report.md';\n return [{ filename, label: '验证报告' }];\n }\n\n async run(ctx: PhaseContext, callbacks?: PhaseCallbacks): Promise<PhaseOutcome> {\n const outcome = await super.run(ctx, callbacks);\n if (outcome.status !== 'completed') return outcome;\n\n // AI 进程成功退出后,读取并解析验证报告\n const report = this.readVerifyReport(ctx);\n if (report) {\n const parsed = this.reportParser.parse(report);\n\n // 如果启用了 todolist 检查,从 plan 文件补充统计\n if (this.config.verifyFixLoop.todolistCheckEnabled && !parsed.todolistStats) {\n const planContent = this.readPlanFile();\n if (planContent) {\n const todoStats = this.reportParser.parseTodolistFromPlan(planContent);\n if (todoStats.total > 0) {\n parsed.todolistStats = todoStats;\n parsed.todolistComplete = todoStats.completed === todoStats.total;\n if (!parsed.todolistComplete) {\n parsed.failureReasons.push(\n `Todolist 未全部完成(${todoStats.completed}/${todoStats.total})`,\n );\n parsed.passed = false;\n }\n }\n }\n }\n\n this.logger.info('Verify report parsed', {\n passed: parsed.passed,\n lintPassed: parsed.lintPassed,\n buildPassed: parsed.buildPassed,\n testPassed: parsed.testPassed,\n todolistComplete: parsed.todolistComplete,\n todolistStats: parsed.todolistStats,\n failureCount: parsed.failureReasons.length,\n });\n\n return { ...outcome, data: { ...outcome.data, verifyReport: parsed } };\n }\n\n return outcome;\n }\n\n protected buildPrompt(ctx: PhaseContext): string {\n const pc = demandToPromptContext(ctx.demand);\n const promptCtx = {\n issueTitle: pc.title,\n issueDescription: pc.description,\n issueIid: Number(pc.displayId),\n workspace: ctx.workspace,\n };\n return ctx.pipelineMode === 'plan-mode'\n ? planModeVerifyPrompt(promptCtx)\n : verifyPrompt(promptCtx);\n }\n\n private readVerifyReport(ctx: PhaseContext): string | null {\n const files = this.getResultFiles(ctx);\n if (files.length === 0) return null;\n return this.plan.readFile(files[0].filename);\n }\n\n private readPlanFile(): string | null {\n return this.plan.readFile('01-plan.md');\n }\n}\n","import { BasePhase, PhaseContext } from './BasePhase.js';\nimport { planPrompt, rePlanPrompt, demandToPromptContext } from '../prompts/templates.js';\nimport { getRunnerCapabilities, usesDeterministicPlanCopy } from '../ai-runner/index.js';\nimport { t } from '../i18n/index.js';\n\nexport class PlanPhase extends BasePhase {\n readonly phaseName = 'plan' as const;\n\n getResultFiles() {\n return [{ filename: '01-plan.md', label: '实施计划' }];\n }\n\n protected getRunMode(): 'plan' | 'agent' | undefined {\n return 'plan';\n }\n\n protected buildPrompt(ctx: PhaseContext): string {\n const pc = demandToPromptContext(ctx.demand);\n const history = this.plan.readReviewHistory();\n const detCopy = usesDeterministicPlanCopy(this.config.ai.mode);\n const promptCtx = {\n issueTitle: pc.title,\n issueDescription: pc.description,\n issueIid: Number(pc.displayId),\n supplementText: pc.supplementText || undefined,\n workspace: ctx.workspace,\n };\n\n let basePrompt: string;\n if (history.length > 0) {\n basePrompt = rePlanPrompt(promptCtx, history, detCopy);\n } else {\n basePrompt = planPrompt(promptCtx, detCopy);\n }\n\n const caps = getRunnerCapabilities(this.config.ai.mode);\n if (!caps?.nativePlanMode) {\n const preambleKey = detCopy ? 'prompt.planModeNative' : 'prompt.planModeFallback';\n basePrompt = `${t(preambleKey)}\\n\\n${basePrompt}`;\n }\n\n return basePrompt;\n }\n}\n","import { BasePhase, PhaseContext } from './BasePhase.js';\nimport { buildPrompt, demandToPromptContext } from '../prompts/templates.js';\nimport { AIExecutionError } from '../errors/index.js';\nimport { t } from '../i18n/index.js';\n\nexport class BuildPhase extends BasePhase {\n readonly phaseName = 'build' as const;\n\n protected async validatePhaseOutput(ctx: PhaseContext, _displayId: number): Promise<void> {\n let hasAnyChanges = false;\n\n if (ctx.workspace && ctx.workspace.repos.length > 1) {\n for (const repo of ctx.workspace.repos) {\n const repoGit = this.wtGitMap?.get(repo.name);\n if (!repoGit) {\n this.logger.warn('Missing GitOperations for repo in validation', { repo: repo.name });\n continue;\n }\n if (await repoGit.hasChanges()) {\n hasAnyChanges = true;\n break;\n }\n }\n } else {\n hasAnyChanges = await this.git.hasChanges();\n }\n\n if (!hasAnyChanges) {\n const msg = 'AI 进程成功退出但未产生任何代码变更';\n this.logger.error(msg, { phase: this.phaseName });\n throw new AIExecutionError(this.phaseName, msg, { output: '', exitCode: 0 });\n }\n }\n\n protected buildPrompt(ctx: PhaseContext): string {\n const pc = demandToPromptContext(ctx.demand);\n const base = buildPrompt({\n issueTitle: pc.title,\n issueDescription: pc.description,\n issueIid: Number(pc.displayId),\n workspace: ctx.workspace,\n });\n\n if (ctx.fixContext) {\n return base + t('prompt.buildFixSuffix', {\n iteration: ctx.fixContext.iteration,\n failures: ctx.fixContext.verifyFailures.map((f, i) => `${i + 1}. ${f}`).join('\\n'),\n rawReport: ctx.fixContext.rawReport.slice(0, 2000),\n });\n }\n\n return base;\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { createHash } from 'node:crypto';\nimport { logger as rootLogger } from '../logger.js';\n\nconst logger = rootLogger.child('ReleaseDetectCache');\n\n/**\n * AI 探索目标项目后输出的发布检测结果。\n */\nexport interface ReleaseDetectResult {\n /** 目标项目路径(用于校验缓存归属) */\n projectPath: string;\n /** 检测时间 ISO 字符串 */\n detectedAt: string;\n /** 是否具备发布能力 */\n hasReleaseCapability: boolean;\n /** 发布方式 */\n releaseMethod?: string;\n /** 检测到的发布相关文件路径 */\n artifacts: string[];\n /** AI 提取的发布步骤说明 */\n instructions?: string;\n}\n\nfunction hashProjectPath(projectPath: string): string {\n return createHash('sha256').update(projectPath).digest('hex').slice(0, 16);\n}\n\n/**\n * 全局发布检测结果缓存。\n *\n * 位置:{dataDir}/release-detect/{hash}.json\n * 按 projectPath 隔离,支持 TTL 过期。\n */\nexport class ReleaseDetectCache {\n private readonly cacheDir: string;\n\n constructor(dataDir: string) {\n this.cacheDir = path.join(dataDir, 'release-detect');\n }\n\n private filePath(projectPath: string): string {\n return path.join(this.cacheDir, `${hashProjectPath(projectPath)}.json`);\n }\n\n /**\n * 读取缓存。返回 null 如果不存在、已过期或校验失败。\n */\n get(projectPath: string, ttlMs: number): ReleaseDetectResult | null {\n const fp = this.filePath(projectPath);\n try {\n if (!fs.existsSync(fp)) return null;\n const raw = fs.readFileSync(fp, 'utf-8');\n const data: ReleaseDetectResult = JSON.parse(raw);\n\n // 校验 projectPath 一致\n if (data.projectPath !== projectPath) {\n logger.warn('Cache projectPath mismatch, ignoring', { expected: projectPath, got: data.projectPath });\n return null;\n }\n\n // 检查 TTL\n const age = Date.now() - new Date(data.detectedAt).getTime();\n if (age > ttlMs) {\n logger.debug('Cache expired', { projectPath, ageMs: age, ttlMs });\n return null;\n }\n\n return data;\n } catch (err) {\n logger.warn('Failed to read release detect cache', { path: fp, error: (err as Error).message });\n return null;\n }\n }\n\n /**\n * 写入缓存。\n */\n set(result: ReleaseDetectResult): void {\n const fp = this.filePath(result.projectPath);\n try {\n if (!fs.existsSync(this.cacheDir)) {\n fs.mkdirSync(this.cacheDir, { recursive: true });\n }\n fs.writeFileSync(fp, JSON.stringify(result, null, 2), 'utf-8');\n logger.debug('Release detect cache written', { projectPath: result.projectPath, path: fp });\n } catch (err) {\n logger.warn('Failed to write release detect cache', { path: fp, error: (err as Error).message });\n }\n }\n\n /**\n * 手动失效缓存。\n */\n invalidate(projectPath: string): boolean {\n const fp = this.filePath(projectPath);\n try {\n if (fs.existsSync(fp)) {\n fs.unlinkSync(fp);\n logger.info('Release detect cache invalidated', { projectPath });\n return true;\n }\n return false;\n } catch (err) {\n logger.warn('Failed to invalidate release detect cache', { path: fp, error: (err as Error).message });\n return false;\n }\n }\n}\n","import type { PromptContext } from './templates.js';\nimport type { ReleaseDetectResult } from '../release/index.js';\n\n/**\n * 发布检测 prompt — 指导 AI 探索目标项目的发布机制。\n */\nexport function releaseDetectPrompt(ctx: PromptContext): string {\n const pd = `.claude-plan/issue-${ctx.issueIid}`;\n\n return `你是一个专业的 DevOps 分析师。你的任务是探索当前项目,判断是否存在 **AI 可以在本地直接执行的发布流程**。\n\n## 关键判定原则\n\n\\`hasReleaseCapability\\` 仅在以下情况为 \\`true\\`:\n- 存在 **AI 可以在当前工作目录直接运行** 的发布命令或脚本\n- 例如:\\`npm publish\\`、\\`make release\\`、\\`scripts/release.sh\\`、带明确步骤的 Skill 文件\n\n以下情况必须设为 \\`false\\`:\n- **仅有 Dockerfile** — Docker 镜像由外部 CI/CD 系统(蓝盾/Landun/Jenkins/GitHub Actions)构建和推送,AI 无法替代\n- **仅有外部 CI/CD 配置** — \\`.gitlab-ci.yml\\` 等定义了流水线,但需要 CI 环境执行,AI 无法触发\n- **项目是 private 包且不发布到 registry** — \\`package.json\\` 中 \\`\"private\": true\\` 且无 publish 脚本\n- **发布相关代码属于业务域** — 项目本身是部署平台/编排系统,其代码是为其他服务编排发布,不是本项目的发布流程\n- **仅有构建脚本无发布步骤** — \\`build.sh\\` 等只构建产物但不实际发布\n\n## 探索范围\n\n请按优先级依次检查:\n\n1. **Skill / Rule 文件**(最高优先级)\n - \\`.cursor/skills/\\` 下与 release/deploy/publish 相关的 skill\n - \\`.cursor/rules/\\` 下与 release/deploy 相关的 \\`.mdc\\` 规则\n - ⚠️ 注意区分:为项目自身发布的 skill vs 为业务域(如\"添加制品类型\")的 skill\n\n2. **Package Manager 发布**\n - \\`package.json\\` 的 \\`scripts\\` 中是否有 \\`publish\\`、\\`release\\` 命令\n - \\`package.json\\` 是否为 \\`\"private\": true\\`(私有包通常不发布)\n\n3. **发布脚本**\n - \\`scripts/release.*\\`、\\`scripts/deploy.*\\`、\\`scripts/publish.*\\`\n - \\`Makefile\\` 中的 release/deploy target\n\n4. **CI/CD 配置**(仅记录,通常不算 AI 可执行)\n - \\`.gitlab-ci.yml\\` / \\`Jenkinsfile\\` / \\`.github/workflows/\\`\n\n5. **容器化**(仅记录,通常不算 AI 可执行)\n - \\`Dockerfile\\`、\\`docker-compose*.yml\\`\n\n## 输出要求\n\n将检测结果以 **严格 JSON** 格式写入 \\`${pd}/05-release-detect.json\\`:\n\n\\`\\`\\`json\n{\n \"hasReleaseCapability\": false,\n \"releaseMethod\": \"ci-pipeline\",\n \"artifacts\": [\"Dockerfile\", \".gitlab-ci.yml\"],\n \"instructions\": \"项目通过外部 CI/CD 流水线构建 Docker 镜像并部署,AI 无法直接执行发布。\"\n}\n\\`\\`\\`\n\n字段说明:\n- \\`hasReleaseCapability\\`: **AI 是否能直接执行发布**(boolean)— 仅当有可在本地运行的发布命令时为 true\n- \\`releaseMethod\\`: 发布方式描述:\"npm-publish\" | \"ci-pipeline\" | \"makefile\" | \"custom-script\" | \"skill\" | \"docker\" | 其他\n- \\`artifacts\\`: 发现的发布相关文件路径数组(无论 capability 是否为 true 都列出)\n- \\`instructions\\`: 发布步骤说明。capability 为 false 时说明原因\n\n**重要**:\n- 大多数项目依赖外部 CI/CD,\\`hasReleaseCapability\\` 应为 \\`false\\`\n- 如果找到了 skill 或 rule 文件,请在 \\`instructions\\` 中完整保留原文内容\n- 只输出 JSON 文件,不要执行任何发布操作`;\n}\n\n/**\n * 发布执行 prompt — 基于检测结果执行发布。\n */\nexport function releaseExecPrompt(ctx: PromptContext, detectResult: ReleaseDetectResult): string {\n const pd = `.claude-plan/issue-${ctx.issueIid}`;\n\n const artifactList = detectResult.artifacts.length > 0\n ? detectResult.artifacts.map(a => `- \\`${a}\\``).join('\\n')\n : '(无)';\n\n const instructionSection = detectResult.instructions\n ? `\\n## 发布指引(来自项目 skill/rule/文档)\\n\\n${detectResult.instructions}`\n : '';\n\n return `你是一个专业的发布工程师。请根据以下检测结果,执行项目的发布流程。\n\n## 检测结果\n\n- **发布方式**: ${detectResult.releaseMethod ?? '未知'}\n- **相关文件**:\n${artifactList}\n${instructionSection}\n\n## 任务\n\n1. 阅读上述发布指引和相关文件\n2. 按照项目定义的发布流程执行发布操作\n3. 将发布结果写入 \\`${pd}/06-release-report.md\\`\n\n## 发布报告格式\n\n\\`\\`\\`markdown\n# 发布报告\n\n## 发布方式\n<使用的发布方式>\n\n## 执行步骤\n<逐步记录执行的操作>\n\n## 结果\n<成功/失败及详情>\n\\`\\`\\`\n\n**重要**:\n- 严格按照项目自身的发布流程操作\n- 如有任何错误或异常,记录在报告中\n- 不要跳过任何发布前的检查步骤`;\n}\n","import type { PhaseContext } from './BasePhase.js';\nimport { BasePhase } from './BasePhase.js';\nimport type { PhaseOutcome, PhaseCallbacks } from './PhaseOutcome.js';\nimport { ReleaseDetectCache, type ReleaseDetectResult } from '../release/index.js';\nimport { releaseDetectPrompt, releaseExecPrompt } from '../prompts/release-templates.js';\nimport { demandToPromptContext } from '../prompts/templates.js';\nimport { resolveDataDir } from '../paths.js';\n\nconst DETECT_FILENAME = '05-release-detect.json';\nconst REPORT_FILENAME = '06-release-report.md';\n\n/**\n * 发布阶段 — 异步委托模型。\n *\n * 模式判定:plan 目录中是否已存在 05-release-detect.json。\n * - 无 → 检测:先查全局缓存,未命中则 AI 检测\n * - 有 → 执行:AI 读取检测结果执行发布\n *\n * 返回 `data.hasReleaseCapability`,编排器据此决定是否暂停等待审批。\n */\nexport class ReleasePhase extends BasePhase {\n readonly phaseName = 'release' as const;\n\n /**\n * 检测结果是否已存在(即是否处于执行模式)。\n */\n private hasDetectionResult(): boolean {\n return this.plan.readFile(DETECT_FILENAME) !== null;\n }\n\n private readDetectionFile(): ReleaseDetectResult | null {\n const raw = this.plan.readFile(DETECT_FILENAME);\n if (raw === null) return null;\n try {\n return JSON.parse(raw);\n } catch {\n return null;\n }\n }\n\n private writeDetectionFile(result: ReleaseDetectResult): void {\n this.plan.writeFile(DETECT_FILENAME, JSON.stringify(result, null, 2));\n }\n\n getResultFiles(_ctx?: PhaseContext): Array<{ filename: string; label: string }> {\n if (this.hasDetectionResult()) {\n return [{ filename: REPORT_FILENAME, label: '发布报告' }];\n }\n return [{ filename: DETECT_FILENAME, label: '发布检测报告' }];\n }\n\n protected buildPrompt(ctx: PhaseContext): string {\n const dc = demandToPromptContext(ctx.demand);\n const pc = {\n issueTitle: dc.title,\n issueDescription: dc.description,\n issueIid: Number(dc.displayId),\n supplementText: dc.supplementText || undefined,\n workspace: ctx.workspace,\n };\n if (this.hasDetectionResult()) {\n const detect = this.readDetectionFile()!;\n return releaseExecPrompt(pc, detect);\n }\n return releaseDetectPrompt(pc);\n }\n\n async run(ctx: PhaseContext, callbacks?: PhaseCallbacks): Promise<PhaseOutcome> {\n const needsDetection = !this.hasDetectionResult();\n\n // ── 检测阶段:先查缓存 ──\n if (needsDetection) {\n const cache = new ReleaseDetectCache(resolveDataDir());\n const projectPath = this.config.gongfeng.projectPath;\n const ttlMs = this.config.release.detectCacheTtlMs;\n const cached = cache.get(projectPath, ttlMs);\n\n if (cached) {\n this.logger.info('Using cached release detection result', {\n projectPath,\n hasCapability: cached.hasReleaseCapability,\n method: cached.releaseMethod,\n });\n\n // 缓存命中 → 写入 plan 目录,直接 completed\n this.writeDetectionFile(cached);\n\n return {\n status: 'completed',\n output: `Release detection cached: ${cached.hasReleaseCapability ? cached.releaseMethod ?? 'found' : 'no capability'}`,\n data: { hasReleaseCapability: cached.hasReleaseCapability },\n };\n }\n }\n\n // ── AI 执行(检测或发布) ──\n const outcome = await super.run(ctx, callbacks);\n if (outcome.status !== 'completed') return outcome;\n\n // ── 检测模式后处理:缓存结果并返回能力标记 ──\n if (needsDetection) {\n const detected = this.readDetectionFile();\n if (detected) {\n // 写入全局缓存\n const cache = new ReleaseDetectCache(resolveDataDir());\n const projectPath = this.config.gongfeng.projectPath;\n cache.set({\n ...detected,\n projectPath,\n detectedAt: new Date().toISOString(),\n });\n\n this.logger.info('Release detection completed', {\n hasCapability: detected.hasReleaseCapability,\n method: detected.releaseMethod,\n artifacts: detected.artifacts,\n });\n\n return {\n ...outcome,\n data: { ...outcome.data, hasReleaseCapability: detected.hasReleaseCapability },\n };\n }\n\n // 未产出检测文件 → 视为无发布能力\n return { ...outcome, data: { ...outcome.data, hasReleaseCapability: false } };\n }\n\n return outcome;\n }\n}\n","import { BasePhase, type PhaseContext } from './BasePhase.js';\nimport type { PhaseOutcome, PhaseCallbacks } from './PhaseOutcome.js';\nimport { e2eVerifyPromptSuffix, demandToPromptContext } from '../prompts/templates.js';\nimport { getLocalIP } from '../utils/network.js';\n\nfunction getDefaultHost(): string {\n return getLocalIP();\n}\n\n/**\n * UAT/E2E 验证阶段 — 异步委托模型。\n *\n * 模式判定:plan 目录中是否已存在 03-uat-report.md。\n * - 有 → completed:验证产物并直接完成\n * - 无 → running:启动异步 AI,返回 awaitCompletion Promise\n */\nexport class UatPhase extends BasePhase {\n readonly phaseName = 'uat' as const;\n\n getResultFiles(_ctx?: PhaseContext) {\n return [{ filename: '03-uat-report.md', label: 'UAT 报告' }];\n }\n\n /**\n * 检查产物是否已存在且内容足够。\n */\n private hasArtifact(_displayId: number): boolean {\n return this.plan.isArtifactReady('03-uat-report.md', BasePhase.MIN_ARTIFACT_BYTES);\n }\n\n async run(ctx: PhaseContext, callbacks?: PhaseCallbacks): Promise<PhaseOutcome> {\n const displayId = Number(ctx.demand.sourceRef.displayId);\n\n // 产物已就绪(gate 批准后重入)→ 验证后直接 completed\n if (this.hasArtifact(displayId)) {\n this.logger.info('UAT artifact found, completing phase', { iid: displayId });\n try {\n await this.validatePhaseOutput(ctx, displayId);\n } catch (err) {\n return {\n status: 'failed',\n output: '',\n error: { message: (err as Error).message, isRetryable: false },\n };\n }\n return { status: 'completed', output: 'UAT report validated' };\n }\n\n // 产物未就绪 → 启动异步 AI,返回 running\n return this.launchAsync(ctx, displayId, callbacks);\n }\n\n private async launchAsync(\n ctx: PhaseContext,\n displayId: number,\n callbacks?: PhaseCallbacks,\n ): Promise<PhaseOutcome> {\n this.logger.info('Launching async UAT', { iid: displayId });\n\n const prompt = this.buildPrompt(ctx);\n\n // Fire-and-forget: 启动 AI 但不 await\n const runPromise = this.aiRunner.run({\n prompt,\n workDir: this.resolveAIWorkDir(ctx),\n timeoutMs: this.config.ai.phaseTimeoutMs,\n idleTimeoutMs: this.config.ai.idleTimeoutMs,\n onStreamEvent: callbacks?.onStreamEvent,\n });\n\n // awaitCompletion:编排器可 await 此 Promise 获取最终结果\n const awaitCompletion = runPromise\n .then(async (result): Promise<PhaseOutcome> => {\n if (result.success && this.hasArtifact(displayId)) {\n return {\n status: 'completed',\n output: result.output,\n sessionId: result.sessionId,\n };\n }\n const reason = result.errorMessage || 'UAT failed or artifact 03-uat-report.md missing';\n return {\n status: 'failed',\n output: result.output,\n error: { message: reason, isRetryable: false },\n };\n })\n .catch(async (err: Error): Promise<PhaseOutcome> => ({\n status: 'failed',\n output: '',\n error: { message: err.message, isRetryable: false },\n }));\n\n return {\n status: 'running',\n output: 'UAT launched asynchronously',\n awaitCompletion,\n };\n }\n\n protected buildPrompt(ctx: PhaseContext): string {\n const pc = demandToPromptContext(ctx.demand);\n const promptCtx = {\n issueTitle: pc.title,\n issueDescription: pc.description,\n issueIid: Number(pc.displayId),\n workspace: ctx.workspace,\n };\n\n const hasUatTool = !!this.config.e2e.uatVendorDir;\n\n const e2ePorts = ctx.ports\n ? {\n backendPort: ctx.ports.backendPort,\n frontendPort: ctx.ports.frontendPort,\n host: this.config.preview.host || getDefaultHost(),\n }\n : undefined;\n\n const uatTool = hasUatTool\n ? { vendorDir: this.config.e2e.uatVendorDir!, configFile: this.config.e2e.uatConfigFile }\n : undefined;\n\n const e2eSuffix = e2eVerifyPromptSuffix(promptCtx, e2ePorts, uatTool);\n\n return `# UAT/E2E 验证阶段\n\n## 任务背景\n- Issue: #${promptCtx.issueIid} ${promptCtx.issueTitle}\n- 本阶段专注于 E2E/UAT 端对端验证,lint/build/test 检查已在上一验证阶段完成。\n\n## 产物要求\n请将 E2E 验证结果写入 \\`.claude-plan/issue-${promptCtx.issueIid}/03-uat-report.md\\`,包含:\n- 测试场景清单\n- 执行结果(通过/失败)\n- 截图路径(如有)\n- 失败原因分析(如有失败)\n\n${e2eSuffix}`;\n }\n}\n","import type { AIRunner } from '../ai-runner/index.js';\nimport { GitOperations } from '../git/GitOperations.js';\nimport { PlanPersistence } from '../persistence/PlanPersistence.js';\nimport { Config } from '../config.js';\nimport { PhaseNotRegisteredError, UnregisteredPhasesError } from '../errors/index.js';\nimport { BasePhase } from './BasePhase.js';\nimport { VerifyPhase } from './VerifyPhase.js';\nimport { PlanPhase } from './PlanPhase.js';\nimport { BuildPhase } from './BuildPhase.js';\nimport { ReleasePhase } from './ReleasePhase.js';\nimport { UatPhase } from './UatPhase.js';\n\ntype PhaseArgs = [AIRunner, GitOperations, PlanPersistence, Config];\nexport type PhaseConstructor = new (...args: PhaseArgs) => BasePhase;\n\n// ---------------------------------------------------------------------------\n// Phase Registry\n// ---------------------------------------------------------------------------\n\nconst PHASE_REGISTRY = new Map<string, PhaseConstructor>();\n\n/** 注册一个阶段构造器。重复注册同一 name 会覆盖。 */\nexport function registerPhase(name: string, ctor: PhaseConstructor): void {\n PHASE_REGISTRY.set(name, ctor);\n}\n\n/** 用于测试隔离:重置注册表并重新注册内置阶段 */\nexport function _resetPhaseRegistry(): void {\n PHASE_REGISTRY.clear();\n registerBuiltinPhases();\n}\n\n// ---------------------------------------------------------------------------\n// Self-register built-in phases\n// ---------------------------------------------------------------------------\n\nfunction registerBuiltinPhases(): void {\n PHASE_REGISTRY.set('plan', PlanPhase);\n PHASE_REGISTRY.set('build', BuildPhase);\n PHASE_REGISTRY.set('verify', VerifyPhase);\n PHASE_REGISTRY.set('uat', UatPhase);\n PHASE_REGISTRY.set('release', ReleasePhase);\n}\n\nregisterBuiltinPhases();\n\n// ---------------------------------------------------------------------------\n// Factory / validation\n// ---------------------------------------------------------------------------\n\nexport function createPhase(name: string, ...args: PhaseArgs): BasePhase {\n const Ctor = PHASE_REGISTRY.get(name);\n if (!Ctor) {\n throw new PhaseNotRegisteredError(name, [...PHASE_REGISTRY.keys()]);\n }\n return new Ctor(...args);\n}\n\n/** 校验 PipelineDef 中的所有 AI phase 都已注册,应在启动时调用 */\nexport function validatePhaseRegistry(phaseNames: string[]): void {\n const missing = phaseNames.filter(name => !PHASE_REGISTRY.has(name));\n if (missing.length > 0) {\n throw new UnregisteredPhasesError(missing, [...PHASE_REGISTRY.keys()]);\n }\n}\n","import { IssueState } from '../tracker/IssueState.js';\nimport { ActionLifecycleManager } from '../lifecycle/ActionLifecycleManager.js';\nimport { PipelineNotFoundError } from '../errors/index.js';\nimport { t } from '../i18n/index.js';\nimport { registerPhase, type PhaseConstructor } from '../phases/PhaseFactory.js';\n\nexport type PipelineMode = string;\nexport type KnownPipelineMode = 'plan-mode';\n\nexport interface PhaseSpec {\n name: string;\n label: string;\n startState: IssueState;\n doneState: IssueState;\n kind: 'ai' | 'gate';\n approvedState?: IssueState;\n /** 此阶段是否可被用户单独重试。默认:kind === 'ai' */\n retryable?: boolean;\n /** 此阶段完成后是否应启动预览服务器。默认:false */\n deploysPreview?: boolean;\n /** 此阶段产出的文件列表。默认:[] */\n artifacts?: PlanFileSpec[];\n}\n\nexport interface PlanFileSpec {\n filename: string;\n label: string;\n editable: boolean;\n}\n\nexport interface PipelineDef {\n mode: PipelineMode;\n phases: PhaseSpec[];\n}\n\n// ---------------------------------------------------------------------------\n// Pipeline Registry\n// ---------------------------------------------------------------------------\n\nconst pipelineRegistry = new Map<string, PipelineDef>();\n\n/**\n * 注册一条流水线定义。可选同时注册其阶段构造器。\n * 重复注册同一 mode 会覆盖。\n */\nexport function registerPipeline(\n def: PipelineDef,\n phases?: Record<string, PhaseConstructor>,\n): void {\n pipelineRegistry.set(def.mode, def);\n if (phases) {\n for (const [name, ctor] of Object.entries(phases)) {\n registerPhase(name, ctor);\n }\n }\n}\n\n/** 获取所有已注册的流水线模式名 */\nexport function getRegisteredModes(): string[] {\n return [...pipelineRegistry.keys()];\n}\n\n/** 获取所有已注册的 PipelineDef */\nexport function getAllPipelineDefs(): PipelineDef[] {\n return [...pipelineRegistry.values()];\n}\n\n/** 用于测试隔离:重置注册表并重新注册内置流水线 */\nexport function _resetPipelineRegistry(): void {\n pipelineRegistry.clear();\n pipelineRegistry.set(PLAN_MODE_PIPELINE.mode, PLAN_MODE_PIPELINE);\n}\n\n// ---------------------------------------------------------------------------\n// Built-in pipeline definitions\n// ---------------------------------------------------------------------------\n\nexport const PLAN_MODE_PIPELINE: PipelineDef = {\n mode: 'plan-mode',\n phases: [\n { name: 'plan', label: '规划', startState: IssueState.PhaseRunning,\n doneState: IssueState.PhaseDone, kind: 'ai',\n artifacts: [{ filename: '01-plan.md', label: '实施计划', editable: true }] },\n { name: 'review', label: '审核', startState: IssueState.PhaseWaiting,\n doneState: IssueState.PhaseApproved, approvedState: IssueState.PhaseApproved,\n kind: 'gate', retryable: false,\n artifacts: [\n { filename: 'review-feedback.md', label: '审核反馈', editable: false },\n { filename: 'review-history.json', label: '审核历史', editable: false },\n ] },\n { name: 'build', label: '实施', startState: IssueState.PhaseRunning,\n doneState: IssueState.PhaseDone, kind: 'ai', deploysPreview: true },\n { name: 'verify', label: '验证', startState: IssueState.PhaseRunning,\n doneState: IssueState.Completed, kind: 'ai',\n artifacts: [{ filename: '02-verify-report.md', label: '验证报告', editable: false }] },\n ],\n};\n\n// Self-register built-in pipelines\npipelineRegistry.set(PLAN_MODE_PIPELINE.mode, PLAN_MODE_PIPELINE);\n\n// ---------------------------------------------------------------------------\n// Dynamic pipeline builder\n// ---------------------------------------------------------------------------\n\n/**\n * 根据配置动态构建 plan-mode 流水线。\n * 当 releaseEnabled 为 true 时,在 verify 之后追加 release 阶段。\n */\nexport function buildPlanModePipeline(opts: { releaseEnabled: boolean; e2eEnabled: boolean }): PipelineDef {\n const phases = [...PLAN_MODE_PIPELINE.phases];\n\n if (opts.e2eEnabled) {\n // verify 的 doneState: Completed → PhaseDone(后续由 uat 接管 Completed)\n const vi = phases.findIndex(p => p.name === 'verify');\n if (vi >= 0) {\n phases[vi] = { ...phases[vi], doneState: IssueState.PhaseDone };\n }\n // 在 verify 后插入 uat 阶段(异步执行,带 gate 机制)\n phases.splice(vi + 1, 0, {\n name: 'uat', label: 'UAT验证', kind: 'ai',\n startState: IssueState.PhaseRunning,\n doneState: IssueState.Completed,\n approvedState: IssueState.PhaseApproved,\n retryable: true,\n artifacts: [\n { filename: '03-uat-report.md', label: 'UAT报告', editable: false },\n ],\n });\n }\n\n if (opts.releaseEnabled) {\n // 当前终态阶段 doneState: Completed → PhaseDone(release 接管 Completed)\n const termIdx = phases.findIndex(p => p.doneState === IssueState.Completed);\n if (termIdx >= 0) {\n phases[termIdx] = { ...phases[termIdx], doneState: IssueState.PhaseDone };\n }\n // 追加 release 阶段(AI 类型 + approvedState 赋予可选 gate 能力)\n phases.push({\n name: 'release', label: '发布', kind: 'ai',\n startState: IssueState.PhaseRunning,\n doneState: IssueState.Completed,\n approvedState: IssueState.PhaseApproved,\n retryable: true,\n artifacts: [\n { filename: '05-release-detect.json', label: '发布检测报告', editable: false },\n { filename: '06-release-report.md', label: '发布报告', editable: false },\n ],\n });\n }\n return { mode: 'plan-mode', phases };\n}\n\n// ---------------------------------------------------------------------------\n// Lookup functions\n// ---------------------------------------------------------------------------\n\nexport function resolvePipelineMode(aiMode: string, explicit?: string): PipelineMode {\n if (explicit && pipelineRegistry.has(explicit)) return explicit;\n return 'plan-mode';\n}\n\nexport function getPipelineDef(mode: PipelineMode): PipelineDef {\n const def = pipelineRegistry.get(mode);\n if (!def) {\n throw new PipelineNotFoundError(mode);\n }\n return def;\n}\n\n/**\n * 从 PipelineDef 创建 ActionLifecycleManager 实例。\n */\nexport function createLifecycleManager(def: PipelineDef): ActionLifecycleManager {\n return new ActionLifecycleManager(def);\n}\n\nexport function getPhaseLabel(phaseName: string): string {\n return t(`pipeline.phase.${phaseName}`);\n}\n\nexport function getPlanFileLabel(filename: string): string {\n return t(`planFile.${filename}`);\n}\n","import { z } from 'zod';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { logger as rootLogger } from '../logger.js';\n\nconst logger = rootLogger.child('WorkspaceConfig');\n\n// ---------------------------------------------------------------------------\n// Schema\n// ---------------------------------------------------------------------------\n\nexport const repoConfigSchema = z.object({\n name: z.string().min(1, 'Repo name is required'),\n projectPath: z.string().min(1, 'Gongfeng project path is required'),\n localGitRoot: z.string().min(1, 'Local git root is required'),\n projectSubDir: z.string().optional().default(''),\n baseBranch: z.string().optional(),\n branchPrefix: z.string().optional(),\n role: z.string().optional().default(''),\n});\n\nexport const workspaceConfigSchema = z.object({\n primary: repoConfigSchema,\n associates: z.array(repoConfigSchema).default([]),\n});\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type RepoConfig = z.infer<typeof repoConfigSchema>;\nexport type WorkspaceConfig = z.infer<typeof workspaceConfigSchema>;\n\n// ---------------------------------------------------------------------------\n// Loader\n// ---------------------------------------------------------------------------\n\n/**\n * Load workspace configuration from a JSON file.\n * Returns null if the path is not provided or the file does not exist.\n */\nexport function loadWorkspaceConfig(configPath?: string): WorkspaceConfig | null {\n if (!configPath) return null;\n\n if (!fs.existsSync(configPath)) {\n logger.warn('Workspace config file not found, falling back to single-repo mode', {\n path: configPath,\n });\n return null;\n }\n\n try {\n const raw = fs.readFileSync(configPath, 'utf-8');\n const json = JSON.parse(raw);\n const result = workspaceConfigSchema.safeParse(json);\n if (!result.success) {\n const issues = result.error.issues\n .map(i => ` - ${i.path.join('.')}: ${i.message}`)\n .join('\\n');\n logger.error(`Workspace config validation failed:\\n${issues}`);\n return null;\n }\n logger.info('Workspace config loaded', {\n primary: result.data.primary.name,\n associates: result.data.associates.map(a => a.name),\n });\n return result.data;\n } catch (err) {\n logger.error('Failed to parse workspace config', {\n path: configPath,\n error: (err as Error).message,\n });\n return null;\n }\n}\n\n/**\n * Build a WorkspaceConfig from the existing single-repo Config.project fields.\n * Used when no workspace.json is configured — preserves backward compatibility.\n */\nexport function buildSingleRepoWorkspace(project: {\n workDir: string;\n gitRootDir: string;\n projectSubDir: string;\n baseBranch: string;\n branchPrefix: string;\n}, gongfengProjectPath: string): WorkspaceConfig {\n return {\n primary: {\n name: 'primary',\n projectPath: gongfengProjectPath,\n localGitRoot: project.gitRootDir,\n projectSubDir: project.projectSubDir,\n baseBranch: project.baseBranch,\n branchPrefix: project.branchPrefix,\n role: '',\n },\n associates: [],\n };\n}\n\n/**\n * Get all repo configs (primary + associates) as a flat array.\n */\nexport function getAllRepos(ws: WorkspaceConfig): RepoConfig[] {\n return [ws.primary, ...ws.associates];\n}\n\n/**\n * Check if a workspace config has associated repositories.\n */\nexport function isMultiRepo(ws: WorkspaceConfig): boolean {\n return ws.associates.length > 0;\n}\n\n/**\n * Persist a WorkspaceConfig to disk. Used to auto-generate workspace.json\n * when upgrading from a single-repo .env setup.\n */\nexport function persistWorkspaceConfig(ws: WorkspaceConfig, filePath: string): void {\n try {\n const dir = path.dirname(filePath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n fs.writeFileSync(filePath, JSON.stringify(ws, null, 2) + '\\n', 'utf-8');\n logger.info('Workspace config auto-generated from .env', { path: filePath });\n } catch (err) {\n logger.warn('Failed to persist workspace config', {\n path: filePath,\n error: (err as Error).message,\n });\n }\n}\n","import path from 'node:path';\nimport fs from 'node:fs/promises';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { GitOperations } from '../git/GitOperations.js';\nimport type { WorkspaceConfig, RepoConfig } from './WorkspaceConfig.js';\nimport { isMultiRepo } from './WorkspaceConfig.js';\nimport type { AsyncMutex } from '../utils/AsyncMutex.js';\nimport { logger as rootLogger } from '../logger.js';\n\nconst execFileAsync = promisify(execFile);\nconst logger = rootLogger.child('WorkspaceManager');\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Per-repo runtime context within an issue workspace. */\nexport interface RepoContext {\n name: string;\n projectPath: string;\n role: string;\n /** Absolute path: the git root for this repo within the issue workspace. */\n gitRootDir: string;\n /** Absolute path: the project sub-directory (AI cwd when single-repo). */\n workDir: string;\n /** The repo's base branch. */\n baseBranch: string;\n /** Branch prefix for this repo (e.g. \"feat/issue\"). */\n branchPrefix: string;\n /** Whether this is the primary repository. */\n isPrimary: boolean;\n}\n\n/** Full workspace context for an issue — replaces the old single WorktreeContext. */\nexport interface WorkspaceContext {\n /** Issue IID this workspace belongs to. */\n issueIid: number;\n /** The branch name used across all repos. */\n branchName: string;\n /** Root directory of the workspace: WORKTREE_BASE_DIR/issue-{iid}/ */\n workspaceRoot: string;\n /** Primary repo context. */\n primary: RepoContext;\n /** Associate repo contexts (may be empty). */\n associates: RepoContext[];\n}\n\n// ---------------------------------------------------------------------------\n// WorkspaceManager\n// ---------------------------------------------------------------------------\n\nexport class WorkspaceManager {\n private wsConfig: WorkspaceConfig;\n private worktreeBaseDir: string;\n private mainGit: GitOperations;\n private mainGitMutex: AsyncMutex;\n private gongfengApiUrl: string;\n\n constructor(opts: {\n wsConfig: WorkspaceConfig;\n worktreeBaseDir: string;\n mainGit: GitOperations;\n mainGitMutex: AsyncMutex;\n gongfengApiUrl: string;\n }) {\n this.wsConfig = opts.wsConfig;\n this.worktreeBaseDir = opts.worktreeBaseDir;\n this.mainGit = opts.mainGit;\n this.mainGitMutex = opts.mainGitMutex;\n this.gongfengApiUrl = opts.gongfengApiUrl;\n }\n\n isMultiRepo(): boolean {\n return isMultiRepo(this.wsConfig);\n }\n\n getWorkspaceConfig(): WorkspaceConfig {\n return this.wsConfig;\n }\n\n // ── Workspace lifecycle ──\n\n /**\n * Prepare the full workspace for an issue:\n * - Create the workspace root directory.\n * - For the primary repo: create a git worktree.\n * - For each associate: clone (or reuse) and checkout the branch.\n */\n async prepareWorkspace(\n issueIid: number,\n branchName: string,\n globalBaseBranch: string,\n globalBranchPrefix: string,\n ): Promise<WorkspaceContext> {\n const wsRoot = this.getWorkspaceRoot(issueIid);\n await fs.mkdir(wsRoot, { recursive: true });\n\n const primaryCtx = await this.preparePrimaryRepo(\n issueIid, branchName, wsRoot, globalBaseBranch,\n );\n\n const associateCtxs: RepoContext[] = [];\n for (const assoc of this.wsConfig.associates) {\n const ctx = await this.prepareAssociateRepo(\n assoc, issueIid, branchName, wsRoot, globalBaseBranch, globalBranchPrefix,\n );\n associateCtxs.push(ctx);\n }\n\n logger.info('Workspace prepared', {\n issueIid,\n wsRoot,\n repos: [primaryCtx.name, ...associateCtxs.map(a => a.name)],\n });\n\n return {\n issueIid,\n branchName,\n workspaceRoot: wsRoot,\n primary: primaryCtx,\n associates: associateCtxs,\n };\n }\n\n /**\n * Commit and push changes across all repos that have modifications.\n */\n async commitAll(\n wsCtx: WorkspaceContext,\n message: string,\n ): Promise<{ reposCommitted: string[] }> {\n const committed: string[] = [];\n\n for (const repo of [wsCtx.primary, ...wsCtx.associates]) {\n const git = new GitOperations(repo.gitRootDir);\n if (await git.hasChanges()) {\n await git.add(['.']);\n await git.commit(message);\n await git.push(wsCtx.branchName);\n committed.push(repo.name);\n logger.info('Committed and pushed changes', {\n repo: repo.name,\n branch: wsCtx.branchName,\n });\n }\n }\n\n return { reposCommitted: committed };\n }\n\n /**\n * Clean up workspace: remove worktree for primary, remove clone dirs for associates.\n */\n async cleanupWorkspace(wsCtx: WorkspaceContext): Promise<void> {\n // Clean primary worktree\n try {\n await this.mainGit.worktreeRemove(wsCtx.primary.gitRootDir, true);\n logger.info('Primary worktree removed', { dir: wsCtx.primary.gitRootDir });\n } catch (err) {\n logger.warn('Failed to remove primary worktree', {\n dir: wsCtx.primary.gitRootDir,\n error: (err as Error).message,\n });\n }\n\n // Clean associate clone directories\n for (const assoc of wsCtx.associates) {\n try {\n await fs.rm(assoc.gitRootDir, { recursive: true, force: true });\n logger.info('Associate repo dir removed', { name: assoc.name, dir: assoc.gitRootDir });\n } catch (err) {\n logger.warn('Failed to remove associate repo dir', {\n name: assoc.name,\n dir: assoc.gitRootDir,\n error: (err as Error).message,\n });\n }\n }\n\n // Remove workspace root if empty\n try {\n const entries = await fs.readdir(wsCtx.workspaceRoot);\n if (entries.length === 0) {\n await fs.rmdir(wsCtx.workspaceRoot);\n }\n } catch { /* ignore */ }\n }\n\n /**\n * Get all repo contexts for an already-prepared workspace (reconstructed from config).\n */\n buildRepoContexts(issueIid: number, branchName: string, globalBaseBranch: string, globalBranchPrefix?: string): RepoContext[] {\n const wsRoot = this.getWorkspaceRoot(issueIid);\n const primary = this.wsConfig.primary;\n const defaultPrefix = globalBranchPrefix ?? primary.branchPrefix ?? 'feat/issue';\n const primaryDir = path.join(wsRoot, primary.name);\n const repos: RepoContext[] = [{\n name: primary.name,\n projectPath: primary.projectPath,\n role: primary.role ?? '',\n gitRootDir: primaryDir,\n workDir: path.join(primaryDir, primary.projectSubDir ?? ''),\n baseBranch: primary.baseBranch ?? globalBaseBranch,\n branchPrefix: primary.branchPrefix ?? defaultPrefix,\n isPrimary: true,\n }];\n\n for (const assoc of this.wsConfig.associates) {\n repos.push({\n name: assoc.name,\n projectPath: assoc.projectPath,\n role: assoc.role ?? '',\n gitRootDir: path.join(wsRoot, assoc.name),\n workDir: path.join(wsRoot, assoc.name, assoc.projectSubDir ?? ''),\n baseBranch: assoc.baseBranch ?? globalBaseBranch,\n branchPrefix: assoc.branchPrefix ?? defaultPrefix,\n isPrimary: false,\n });\n }\n\n return repos;\n }\n\n getWorkspaceRoot(issueIid: number): string {\n return path.join(this.worktreeBaseDir, `issue-${issueIid}`);\n }\n\n // ── Internal helpers ──\n\n private async preparePrimaryRepo(\n issueIid: number,\n branchName: string,\n wsRoot: string,\n globalBaseBranch: string,\n ): Promise<RepoContext> {\n const primary = this.wsConfig.primary;\n const repoDir = path.join(wsRoot, primary.name);\n const baseBranch = primary.baseBranch ?? globalBaseBranch;\n\n await this.ensurePrimaryWorktree(repoDir, branchName, baseBranch);\n\n return {\n name: primary.name,\n projectPath: primary.projectPath,\n role: primary.role ?? '',\n gitRootDir: repoDir,\n workDir: path.join(repoDir, primary.projectSubDir ?? ''),\n baseBranch,\n branchPrefix: primary.branchPrefix ?? 'feat/issue',\n isPrimary: true,\n };\n }\n\n private async ensurePrimaryWorktree(\n repoDir: string,\n branchName: string,\n baseBranch: string,\n ): Promise<void> {\n // Migrate legacy worktree: issue-{iid}/ -> issue-{iid}/primary/\n const wsRoot = path.dirname(repoDir);\n if (wsRoot !== repoDir) {\n try {\n await fs.access(path.join(wsRoot, '.git'));\n logger.info('Migrating legacy worktree to primary subdir', { from: wsRoot, to: repoDir });\n await this.mainGit.worktreeRemove(wsRoot, true);\n await this.mainGit.worktreePrune();\n await this.cleanStaleDir(wsRoot);\n } catch {\n // No legacy worktree at wsRoot — normal path\n }\n }\n\n const worktrees = await this.mainGit.worktreeList();\n\n if (worktrees.includes(repoDir)) {\n try {\n await fs.access(path.join(repoDir, '.git'));\n logger.info('Reusing existing primary worktree', { dir: repoDir });\n return;\n } catch {\n logger.warn('Primary worktree registered but .git missing, recreating', { dir: repoDir });\n await this.mainGit.worktreeRemove(repoDir, true);\n await this.mainGit.worktreePrune();\n }\n }\n\n await this.cleanStaleDir(repoDir);\n\n const localExists = await this.mainGit.branchExists(branchName);\n if (localExists) {\n await this.mainGit.worktreeAddExisting(repoDir, branchName);\n return;\n }\n\n const remoteExists = await this.mainGit.remoteBranchExists(branchName);\n if (remoteExists) {\n await this.mainGit.worktreeAddTracking(repoDir, branchName);\n return;\n }\n\n await this.mainGit.worktreeAdd(repoDir, branchName, `origin/${baseBranch}`);\n }\n\n private async prepareAssociateRepo(\n assoc: RepoConfig,\n _issueIid: number,\n branchName: string,\n wsRoot: string,\n globalBaseBranch: string,\n globalBranchPrefix: string,\n ): Promise<RepoContext> {\n const repoDir = path.join(wsRoot, assoc.name);\n const baseBranch = assoc.baseBranch ?? globalBaseBranch;\n const cloneUrl = `${this.gongfengApiUrl}/${assoc.projectPath}.git`;\n\n // Clone or reuse\n const gitDirExists = await this.dirExists(path.join(repoDir, '.git'));\n if (!gitDirExists) {\n await this.cleanStaleDir(repoDir);\n logger.info('Cloning associate repo', { name: assoc.name, url: cloneUrl });\n await execFileAsync('git', ['clone', '--depth', '50', cloneUrl, repoDir], {\n timeout: 300_000,\n maxBuffer: 10 * 1024 * 1024,\n });\n } else {\n logger.info('Reusing existing associate clone', { name: assoc.name, dir: repoDir });\n }\n\n // Checkout or create branch\n const assocGit = new GitOperations(repoDir);\n await assocGit.fetch();\n\n const remoteExists = await assocGit.remoteBranchExists(branchName);\n if (remoteExists) {\n try {\n await assocGit.checkout(branchName);\n } catch {\n await assocGit.checkoutTrack(branchName);\n }\n } else {\n try {\n await assocGit.createBranch(branchName, baseBranch);\n } catch {\n await assocGit.checkout(branchName);\n }\n }\n\n return {\n name: assoc.name,\n projectPath: assoc.projectPath,\n role: assoc.role ?? '',\n gitRootDir: repoDir,\n workDir: path.join(repoDir, assoc.projectSubDir ?? ''),\n baseBranch,\n branchPrefix: assoc.branchPrefix ?? globalBranchPrefix,\n isPrimary: false,\n };\n }\n\n private async cleanStaleDir(dir: string): Promise<void> {\n if (await this.dirExists(dir)) {\n logger.warn('Removing stale directory', { dir });\n await fs.rm(dir, { recursive: true, force: true });\n }\n }\n\n private async dirExists(dir: string): Promise<boolean> {\n try {\n await fs.access(dir);\n return true;\n } catch {\n return false;\n }\n }\n}\n","import path from 'node:path';\nimport fs from 'node:fs/promises';\nimport fsSync from 'node:fs';\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { Config } from '../config.js';\nimport { IssueNotFoundError, InvalidPhaseError, InvalidStateError, PhaseAbortedError } from '../errors/index.js';\nimport { GongfengClient, GongfengIssue } from '../clients/GongfengClient.js';\nimport { GitOperations } from '../git/GitOperations.js';\nimport type { AIRunner } from '../ai-runner/index.js';\nimport { IssueTracker } from '../tracker/IssueTracker.js';\nimport { IssueState } from '../tracker/IssueState.js';\nimport type { PipelineModeView } from '../tracker/IssueViews.js';\nimport { PlanPersistence } from '../persistence/PlanPersistence.js';\nimport type { WorktreeContext } from '../git/WorktreeContext.js';\nimport { getLocalIP } from '../utils/network.js';\nimport type { PhaseContext } from '../phases/BasePhase.js';\nimport { createPhase } from '../phases/PhaseFactory.js';\nimport { resolvePipelineMode, getPipelineDef, buildPlanModePipeline, registerPipeline, createLifecycleManager, PipelineDef } from '../pipeline/PipelineDefinition.js';\nimport { ActionLifecycleManager } from '../lifecycle/ActionLifecycleManager.js';\nimport { SupplementStore } from '../supplement/SupplementStore.js';\nimport { gongfengIssueToDemandSpec } from '../demand/adapters/GongfengAdapter.js';\nimport { getIid, getExternalId, getTitle } from '../tracker/IssueRecordHelper.js';\nimport { eventBus as defaultEventBus, type EventBus } from '../events/EventBus.js';\nimport { AsyncMutex } from '../utils/AsyncMutex.js';\nimport { extractTapdId, generateMRTitle, generateMRDescription } from '../utils/MergeRequestHelper.js';\nimport { PortAllocator, type PortPair } from '../deploy/PortAllocator.js';\nimport { DevServerManager } from '../deploy/DevServerManager.js';\nimport { isE2eEnabledForIssue } from '../e2e/E2eSettings.js';\nimport { ScreenshotPublisher } from '../e2e/ScreenshotPublisher.js';\nimport { ConflictResolver } from '../git/ConflictResolver.js';\nimport { getProjectKnowledge } from '../knowledge/index.js';\nimport { KNOWLEDGE_DEFAULTS } from '../knowledge/KnowledgeDefaults.js';\nimport { logger as rootLogger } from '../logger.js';\nimport { runWithIssueContext } from '../context/IssueContext.js';\nimport { metrics } from '../metrics/MetricsCollector.js';\nimport { t } from '../i18n/index.js';\nimport type { OrchestratorDeps, IssueProcessingContext } from './IssueProcessingContext.js';\nimport { WorkspaceManager, buildSingleRepoWorkspace } from '../workspace/index.js';\nimport type { WorkspaceConfig } from '../workspace/index.js';\nimport { executeSetup } from './steps/SetupStep.js';\nimport { executePhaseLoop } from './steps/PhaseLoopStep.js';\nimport { executeCompletion } from './steps/CompletionStep.js';\nimport { handleFailure } from './steps/FailureHandler.js';\n\nexport interface MergeRequestResult {\n url: string;\n iid: number;\n}\n\nconst execFileAsync = promisify(execFile);\nconst logger = rootLogger.child('PipelineOrchestrator');\n\nexport class PipelineOrchestrator {\n private config: Config;\n private gongfeng: GongfengClient;\n private mainGit: GitOperations;\n private aiRunner: AIRunner;\n private e2eAiRunner?: AIRunner;\n private tracker: IssueTracker;\n private supplementStore?: SupplementStore;\n private mainGitMutex: AsyncMutex;\n private conflictResolver: ConflictResolver;\n private pipelineDef: PipelineDef;\n private lifecycleManager: ActionLifecycleManager;\n private portAllocator: PortAllocator;\n private devServerManager: DevServerManager;\n private screenshotPublisher: ScreenshotPublisher;\n private eventBus: EventBus;\n private claimer: import('../coordination/IssueClaimer.js').IssueClaimer | null = null;\n private workspaceManager: WorkspaceManager;\n readonly tenantId: string;\n private readonly effectiveWorktreeBaseDir: string;\n private pendingActions = new Map<number, 'abort' | 'redo' | 'restart'>();\n\n /** 暴露 AIRunner 给外部(如 CommandExecutor 取消进程时使用) */\n getAIRunner(): AIRunner {\n return this.aiRunner;\n }\n\n /** 替换 AIRunner(用于配置热重载) */\n setAIRunner(runner: AIRunner): void {\n this.aiRunner = runner;\n this.conflictResolver = new ConflictResolver(runner);\n logger.info('AIRunner replaced via hot-reload');\n }\n\n constructor(\n config: Config,\n gongfeng: GongfengClient,\n git: GitOperations,\n aiRunner: AIRunner,\n tracker: IssueTracker,\n supplementStore?: SupplementStore,\n mainGitMutex?: AsyncMutex,\n eventBusInstance?: EventBus,\n wsConfig?: WorkspaceConfig | null,\n tenantId?: string,\n e2eAiRunner?: AIRunner,\n ) {\n this.config = config;\n this.gongfeng = gongfeng;\n this.mainGit = git;\n this.aiRunner = aiRunner;\n this.e2eAiRunner = e2eAiRunner;\n this.tracker = tracker;\n this.supplementStore = supplementStore;\n this.mainGitMutex = mainGitMutex ?? new AsyncMutex();\n this.eventBus = eventBusInstance ?? defaultEventBus;\n this.conflictResolver = new ConflictResolver(aiRunner);\n this.tenantId = tenantId ?? 'default';\n\n const mode = resolvePipelineMode(config.ai.mode, config.pipeline?.mode === 'auto' ? undefined : config.pipeline?.mode);\n this.pipelineDef = mode === 'plan-mode'\n ? buildPlanModePipeline({ releaseEnabled: config.release.enabled, e2eEnabled: config.e2e.enabled })\n : getPipelineDef(mode);\n registerPipeline(this.pipelineDef);\n this.lifecycleManager = createLifecycleManager(this.pipelineDef);\n logger.info('Pipeline mode resolved', { tenantId: this.tenantId, mode: this.pipelineDef.mode, aiMode: config.ai.mode });\n\n this.portAllocator = new PortAllocator({\n backendPortBase: config.e2e.backendPortBase,\n frontendPortBase: config.e2e.frontendPortBase,\n });\n this.devServerManager = new DevServerManager();\n this.screenshotPublisher = new ScreenshotPublisher(gongfeng);\n\n this.effectiveWorktreeBaseDir = this.tenantId === 'default'\n ? config.project.worktreeBaseDir\n : path.join(config.project.worktreeBaseDir, this.tenantId);\n\n const effectiveWsConfig = wsConfig ?? buildSingleRepoWorkspace(config.project, config.gongfeng.projectPath);\n this.workspaceManager = new WorkspaceManager({\n wsConfig: effectiveWsConfig,\n worktreeBaseDir: this.effectiveWorktreeBaseDir,\n mainGit: git,\n mainGitMutex: this.mainGitMutex,\n gongfengApiUrl: config.gongfeng.apiUrl,\n });\n logger.info('WorkspaceManager initialized', {\n tenantId: this.tenantId,\n primary: effectiveWsConfig.primary.name,\n associates: effectiveWsConfig.associates.map(a => a.name),\n });\n\n this.restorePortAllocations();\n }\n\n getPortAllocator(): PortAllocator { return this.portAllocator; }\n getDevServerManager(): DevServerManager { return this.devServerManager; }\n getMainGitMutex(): AsyncMutex { return this.mainGitMutex; }\n\n /** 注入 IssueClaimer 实例(在 index.ts 中获取 currentUser 后调用) */\n setClaimer(claimer: import('../coordination/IssueClaimer.js').IssueClaimer | null): void {\n this.claimer = claimer;\n }\n\n async cleanupStaleState(): Promise<void> {\n logger.info('Cleaning up stale worktree state...');\n let cleaned = 0;\n const repoGitRoot = this.config.project.gitRootDir;\n\n try {\n const worktrees = await this.mainGit.worktreeList();\n for (const wtDir of worktrees) {\n if (wtDir === repoGitRoot) continue;\n if (!wtDir.includes('/issue-')) continue;\n\n try {\n const gitFile = path.join(wtDir, '.git');\n try {\n await fs.access(gitFile);\n } catch {\n logger.warn('Worktree corrupted (.git missing), force removing', { dir: wtDir });\n await this.mainGit.worktreeRemove(wtDir, true).catch(() => {});\n await this.mainGit.worktreePrune();\n cleaned++;\n continue;\n }\n\n const wtGit = new GitOperations(wtDir);\n\n if (await wtGit.isRebaseInProgress()) {\n logger.warn('Aborting residual rebase in worktree', { dir: wtDir });\n await wtGit.rebaseAbort();\n cleaned++;\n }\n\n const indexLock = path.join(wtDir, '.git', 'index.lock');\n try {\n await fs.unlink(indexLock);\n logger.warn('Removed stale index.lock', { path: indexLock });\n cleaned++;\n } catch {\n // No lock file — normal\n }\n } catch (err) {\n logger.warn('Failed to clean worktree state', { dir: wtDir, error: (err as Error).message });\n }\n }\n } catch (err) {\n logger.warn('Failed to list worktrees for cleanup', { error: (err as Error).message });\n }\n\n const mainIndexLock = path.join(repoGitRoot, '.git', 'index.lock');\n try {\n await fs.unlink(mainIndexLock);\n logger.warn('Removed stale main repo index.lock', { path: mainIndexLock });\n cleaned++;\n } catch {\n // No lock file — normal\n }\n\n logger.info('Stale state cleanup complete', { cleaned });\n }\n\n /**\n * 重启后清理幽灵端口分配。\n *\n * DevServerManager 的进程句柄仅存于内存,重启后全部丢失。\n * 此时 tracker 中残留的 ports 字段指向不可控的孤儿进程,\n * 必须清理以避免前端误显示 preview 状态。\n */\n private restorePortAllocations(): void {\n for (const record of this.tracker.getAll()) {\n if (record.ports) {\n const iid = getIid(record);\n logger.info('Clearing stale port allocation after restart', { iid, ports: record.ports });\n this.tracker.updateState(iid, record.state, {\n ports: undefined,\n previewStartedAt: undefined,\n } as any);\n }\n }\n }\n\n getPipelineDef(): PipelineDef {\n return this.pipelineDef;\n }\n\n private emitProgress(issueIid: number, step: string, message: string): void {\n this.eventBus.emitTyped('pipeline:progress', { issueIid, step, message });\n }\n\n private computeWorktreeContext(issueIid: number, branchName: string): WorktreeContext {\n const repos = this.workspaceManager.buildRepoContexts(\n issueIid, branchName, this.config.project.baseBranch, this.config.project.branchPrefix,\n );\n const primary = repos.find(r => r.isPrimary)!;\n return {\n gitRootDir: primary.gitRootDir,\n workDir: primary.workDir,\n branchName,\n issueIid,\n };\n }\n\n private async ensureWorktree(wtCtx: WorktreeContext): Promise<void> {\n const wsCtx = await this.workspaceManager.prepareWorkspace(\n wtCtx.issueIid,\n wtCtx.branchName,\n this.config.project.baseBranch,\n this.config.project.branchPrefix,\n );\n wtCtx.workspace = wsCtx;\n }\n\n private async cleanupWorktree(wtCtx: WorktreeContext): Promise<void> {\n if (wtCtx.workspace) {\n await this.workspaceManager.cleanupWorkspace(wtCtx.workspace);\n return;\n }\n try {\n await this.mainGit.worktreeRemove(wtCtx.gitRootDir, true);\n logger.info('Worktree cleaned up', { dir: wtCtx.gitRootDir });\n } catch (err) {\n logger.warn('Failed to cleanup worktree', { dir: wtCtx.gitRootDir, error: (err as Error).message });\n }\n }\n\n private async installDependencies(workDir: string): Promise<void> {\n logger.info('Installing dependencies in worktree', { workDir });\n\n const knowledge = getProjectKnowledge() ?? KNOWLEDGE_DEFAULTS;\n const pkgMgr = knowledge.toolchain.packageManager.toLowerCase();\n const isNodeProject = ['npm', 'pnpm', 'yarn', 'bun'].some(m => pkgMgr.includes(m));\n\n if (isNodeProject) {\n const ready = await this.ensureNodeModules(workDir);\n if (ready) {\n logger.info('node_modules ready — skipping install');\n return;\n }\n }\n\n const installCmd = knowledge.toolchain.installCommand;\n const fallbackCmd = knowledge.toolchain.installFallbackCommand;\n const [bin, ...args] = installCmd.split(/\\s+/);\n\n try {\n await execFileAsync(bin, args, {\n cwd: workDir,\n maxBuffer: 10 * 1024 * 1024,\n timeout: 300_000,\n });\n logger.info('Dependencies installed');\n } catch (err) {\n if (fallbackCmd) {\n logger.warn(`${installCmd} failed, retrying with fallback command`, {\n error: (err as Error).message,\n });\n const [fallbackBin, ...fallbackArgs] = fallbackCmd.split(/\\s+/);\n try {\n await execFileAsync(fallbackBin, fallbackArgs, {\n cwd: workDir,\n maxBuffer: 10 * 1024 * 1024,\n timeout: 300_000,\n });\n logger.info('Dependencies installed (fallback)');\n } catch (retryErr) {\n logger.warn('Fallback install also failed', {\n error: (retryErr as Error).message,\n });\n }\n } else {\n logger.warn('Install failed, no fallback configured', {\n error: (err as Error).message,\n });\n }\n }\n }\n\n private async ensureNodeModules(workDir: string): Promise<boolean> {\n const targetBin = path.join(workDir, 'node_modules', '.bin');\n try {\n await fs.access(targetBin);\n logger.info('node_modules already complete (has .bin/)');\n return true;\n } catch {\n // .bin/ missing — need to seed or install\n }\n\n const sourceNM = path.join(this.config.project.workDir, 'node_modules');\n const targetNM = path.join(workDir, 'node_modules');\n try {\n await fs.access(sourceNM);\n } catch {\n logger.warn('Main repo node_modules not found, skipping seed', { sourceNM });\n return false;\n }\n\n logger.info('Seeding node_modules from main repo via reflink copy', { sourceNM, targetNM });\n try {\n await execFileAsync('rm', ['-rf', targetNM], { timeout: 60_000 });\n // btrfs reflink: zero-copy CoW, near-instant; falls back to regular copy on non-btrfs\n await execFileAsync('cp', ['-a', '--reflink=auto', sourceNM, targetNM], {\n timeout: 120_000,\n });\n logger.info('node_modules seeded from main repo');\n return true;\n } catch (err) {\n logger.warn('Failed to seed node_modules from main repo', {\n error: (err as Error).message,\n });\n return false;\n }\n }\n\n async restartIssue(issueIid: number): Promise<void> {\n const record = this.tracker.get(issueIid);\n if (!record) throw new IssueNotFoundError(issueIid);\n\n const wtCtx = this.computeWorktreeContext(issueIid, record.branchName);\n logger.info('Restarting issue — cleaning context', { issueIid, branchName: record.branchName });\n\n // 设置 pending action,防止旧的 processIssue 循环在 kill 后覆盖状态\n this.pendingActions.set(issueIid, 'restart');\n\n this.aiRunner.killByWorkDir(wtCtx.workDir);\n this.e2eAiRunner?.killByWorkDir(wtCtx.workDir);\n\n this.stopPreviewServers(issueIid);\n\n try {\n const deleted = await this.gongfeng.cleanupAgentNotes(getExternalId(record));\n logger.info('Agent notes cleaned up', { issueIid, deleted });\n } catch (err) {\n logger.warn('Failed to cleanup agent notes', { issueIid, error: (err as Error).message });\n }\n\n await this.mainGitMutex.runExclusive(async () => {\n await this.cleanupWorktree(wtCtx);\n await this.cleanupWorkspaceRoot(issueIid);\n try { await this.mainGit.deleteBranch(record.branchName); } catch { /* branch may not exist */ }\n try { await this.mainGit.deleteRemoteBranch(record.branchName); } catch { /* remote branch may not exist */ }\n });\n\n await this.cleanupE2eOutputs(issueIid);\n\n this.tracker.resetFull(issueIid);\n // 清理完毕,删除 pendingAction 防止新的 processIssue 被误拦截\n this.pendingActions.delete(issueIid);\n logger.info('Issue restarted', { issueIid });\n }\n\n async cancelIssue(issueIid: number): Promise<void> {\n const record = this.tracker.get(issueIid);\n if (!record) throw new IssueNotFoundError(issueIid);\n\n const wtCtx = this.computeWorktreeContext(issueIid, record.branchName);\n logger.info('Cancelling issue — cleaning all resources', { issueIid, branchName: record.branchName });\n\n // 1. 终止 AI 进程\n this.aiRunner.killByWorkDir(wtCtx.workDir);\n\n // 2. 停止预览服务器\n this.stopPreviewServers(issueIid);\n\n // 3. 移除工蜂标签(关键步骤!防止 discovery 循环重新发现)\n try {\n await this.gongfeng.removeLabelsWithPrefix(getExternalId(record), 'auto-finish');\n } catch (err) {\n logger.warn('Failed to remove labels on cancel', { issueIid, error: (err as Error).message });\n }\n\n // 4. 清理 worktree + 分支\n await this.mainGitMutex.runExclusive(async () => {\n await this.cleanupWorktree(wtCtx);\n await this.cleanupWorkspaceRoot(issueIid);\n try { await this.mainGit.deleteBranch(record.branchName); } catch { /* branch may not exist */ }\n try { await this.mainGit.deleteRemoteBranch(record.branchName); } catch { /* remote branch may not exist */ }\n });\n\n // 5. 标记为 Skipped(保留记录防止 discovery 重新拾取)\n this.tracker.clearProcessingLock(issueIid);\n this.tracker.updateState(issueIid, IssueState.Skipped);\n // 6. 清理 E2E 产物\n await this.cleanupE2eOutputs(issueIid);\n logger.info('Issue cancelled', { issueIid });\n }\n\n /**\n * Remove the E2E output directory for an issue: {uatVendorDir}/outputs/issue-{iid}\n */\n private async cleanupE2eOutputs(issueIid: number): Promise<void> {\n const vendorDir = this.config.e2e.uatVendorDir;\n if (!vendorDir) return;\n\n const abs = path.isAbsolute(vendorDir)\n ? vendorDir\n : path.resolve(this.config.project.workDir, vendorDir);\n const outputDir = path.join(abs, 'outputs', `issue-${issueIid}`);\n\n try {\n await fs.rm(outputDir, { recursive: true, force: true });\n logger.info('E2E outputs cleaned up', { issueIid, dir: outputDir });\n } catch (err) {\n logger.warn('Failed to cleanup E2E outputs', { issueIid, dir: outputDir, error: (err as Error).message });\n }\n }\n\n /**\n * When WorkspaceManager is active, the workspace root (which contains\n * associate repo clone dirs) may survive after cleanupWorktree removes\n * only the primary worktree. Force-remove the whole workspace root.\n */\n private async cleanupWorkspaceRoot(issueIid: number): Promise<void> {\n if (!this.workspaceManager) return;\n\n const wsRoot = this.workspaceManager.getWorkspaceRoot(issueIid);\n try {\n await fs.rm(wsRoot, { recursive: true, force: true });\n logger.info('Workspace root cleaned up', { issueIid, dir: wsRoot });\n } catch (err) {\n logger.warn('Failed to cleanup workspace root', { issueIid, dir: wsRoot, error: (err as Error).message });\n }\n }\n\n retryFromPhase(issueIid: number, phase: string): void {\n const record = this.tracker.get(issueIid);\n if (!record) throw new IssueNotFoundError(issueIid);\n\n const issueDef = this.getIssueSpecificPipelineDef(record);\n const issueLM = createLifecycleManager(issueDef);\n if (!issueLM.isRetryable(phase)) {\n throw new InvalidPhaseError(phase);\n }\n\n // Interrupt stale AI processes to prevent them from overwriting the reset state.\n // Prefer soft interrupt (Ctrl+C) to preserve the PTY session for reuse —\n // avoids the costly cold-start of a new agent process on retry.\n const wtCtx = this.computeWorktreeContext(issueIid, record.branchName);\n if (!this.aiRunner.interruptByWorkDir?.(wtCtx.workDir)) {\n this.aiRunner.killByWorkDir(wtCtx.workDir);\n }\n this.e2eAiRunner?.killByWorkDir(wtCtx.workDir);\n\n logger.info('Retrying issue from phase', { issueIid, phase });\n const ok = this.tracker.resetToPhase(issueIid, phase, issueDef);\n if (!ok) {\n throw new InvalidPhaseError(phase);\n }\n }\n\n // ── 阶段级中止/继续/重做 ──\n\n abortIssue(issueIid: number): void {\n const record = this.tracker.get(issueIid);\n if (!record) throw new IssueNotFoundError(issueIid);\n\n const ABORTABLE = new Set([\n IssueState.PhaseRunning, IssueState.PhaseDone,\n IssueState.PhaseWaiting, IssueState.PhaseApproved,\n ]);\n if (!ABORTABLE.has(record.state)) {\n throw new InvalidStateError(record.state, `Issue #${issueIid} not in abortable state`);\n }\n\n const wtCtx = this.computeWorktreeContext(issueIid, record.branchName);\n\n if (record.state === IssueState.PhaseRunning) {\n // AI 进程运行中 — 设标记后 kill,由 catch 块完成状态转换\n this.pendingActions.set(issueIid, 'abort');\n this.aiRunner.killByWorkDir(wtCtx.workDir);\n this.e2eAiRunner?.killByWorkDir(wtCtx.workDir);\n } else {\n // 无进程运行(PhaseDone/PhaseWaiting/PhaseApproved)— 直接暂停\n this.tracker.pauseIssue(issueIid, record.currentPhase ?? '');\n }\n\n logger.info('Issue abort requested', { issueIid, state: record.state });\n }\n\n continueIssue(issueIid: number): void {\n const record = this.tracker.get(issueIid);\n if (!record) throw new IssueNotFoundError(issueIid);\n if (record.state !== IssueState.Paused) {\n throw new InvalidStateError(record.state, `Issue #${issueIid} not in paused state`);\n }\n\n const issueDef = this.getIssueSpecificPipelineDef(record);\n this.tracker.resumeFromPause(issueIid, issueDef, false);\n logger.info('Issue continued from pause', { issueIid });\n }\n\n redoPhase(issueIid: number): void {\n const record = this.tracker.get(issueIid);\n if (!record) throw new IssueNotFoundError(issueIid);\n\n const REDOABLE = new Set([\n IssueState.Paused, IssueState.PhaseRunning, IssueState.PhaseDone,\n IssueState.PhaseWaiting, IssueState.PhaseApproved,\n ]);\n if (!REDOABLE.has(record.state)) {\n throw new InvalidStateError(record.state, `Issue #${issueIid} not in redoable state`);\n }\n\n const issueDef = this.getIssueSpecificPipelineDef(record);\n const wtCtx = this.computeWorktreeContext(issueIid, record.branchName);\n\n if (record.state === IssueState.PhaseRunning) {\n // AI 进程运行中 — 设标记后 kill,由 catch 块完成状态转换\n this.pendingActions.set(issueIid, 'redo');\n this.aiRunner.killByWorkDir(wtCtx.workDir);\n this.e2eAiRunner?.killByWorkDir(wtCtx.workDir);\n } else if (record.state === IssueState.Paused) {\n const phase = record.pausedAtPhase;\n if (phase) {\n const wtPlan = new PlanPersistence(wtCtx.workDir, issueIid);\n wtPlan.updatePhaseProgress(phase, 'pending');\n this.tracker.updatePhaseProgress(issueIid, phase, {\n status: 'pending', startedAt: undefined, completedAt: undefined, error: undefined,\n });\n }\n this.tracker.resumeFromPause(issueIid, issueDef, true);\n this.eventBus.emitTyped('issue:redone', { issueIid });\n } else {\n // PhaseDone/PhaseWaiting/PhaseApproved — 重置到当前阶段前驱\n const phase = record.currentPhase;\n if (phase) {\n const wtPlan = new PlanPersistence(wtCtx.workDir, issueIid);\n wtPlan.updatePhaseProgress(phase, 'pending');\n // resetToPhase 内部已重置 tracker 的 phaseProgress\n this.tracker.resetToPhase(issueIid, phase, issueDef);\n }\n this.eventBus.emitTyped('issue:redone', { issueIid });\n }\n\n logger.info('Issue redo requested', { issueIid, state: record.state });\n }\n\n /**\n * 处理中止/重做的共享逻辑:\n * - abort: 暂停 Issue(保留 session)\n * - redo: 重置阶段(清除 session)\n *\n * 由 catch 块的两条路径(PhaseAbortedError / pendingActions)共用。\n */\n private applyPendingAction(\n action: 'abort' | 'redo',\n issueIid: number,\n wtCtx: WorktreeContext,\n pipelineDef: PipelineDef,\n ): void {\n const rec = this.tracker.get(issueIid);\n // 若 onPhaseFailed 已递增 attempts(state === Failed 时),需回滚\n if (rec?.state === IssueState.Failed && rec.attempts > 0) {\n rec.attempts -= 1;\n }\n\n if (action === 'abort') {\n this.tracker.pauseIssue(issueIid, rec?.currentPhase ?? '');\n } else {\n const phase = rec?.currentPhase;\n if (phase) {\n const wtPlan = new PlanPersistence(wtCtx.workDir, issueIid);\n wtPlan.updatePhaseProgress(phase, 'pending');\n // resetToPhase 内部已重置 tracker 的 phaseProgress\n this.tracker.resetToPhase(issueIid, phase, pipelineDef);\n }\n this.eventBus.emitTyped('issue:redone', { issueIid: issueIid });\n }\n }\n\n private getIssueSpecificPipelineDef(record: PipelineModeView): PipelineDef {\n if (record.pipelineMode) {\n return getPipelineDef(record.pipelineMode);\n }\n return this.pipelineDef;\n }\n\n async processIssue(issue: GongfengIssue): Promise<void> {\n return runWithIssueContext(issue.iid, () => this._processIssueImpl(issue));\n }\n\n private buildDeps(): OrchestratorDeps {\n return {\n tenantId: this.tenantId,\n config: this.config,\n gongfeng: this.gongfeng,\n mainGit: this.mainGit,\n mainGitMutex: this.mainGitMutex,\n aiRunner: this.aiRunner,\n e2eAiRunner: this.e2eAiRunner,\n tracker: this.tracker,\n supplementStore: this.supplementStore,\n screenshotPublisher: this.screenshotPublisher,\n portAllocator: this.portAllocator,\n devServerManager: this.devServerManager,\n eventBus: this.eventBus,\n claimer: this.claimer,\n workspaceManager: this.workspaceManager,\n emitProgress: (iid, step, msg) => this.emitProgress(iid, step, msg),\n ensureWorktree: (wtCtx) => this.ensureWorktree(wtCtx),\n installDependencies: (workDir) => this.installDependencies(workDir),\n shouldAutoApprove: (labels) => this.shouldAutoApprove(labels),\n shouldDeployServers: (iid) => this.shouldDeployServers(iid),\n startPreviewServers: (wtCtx, issue) => this.startPreviewServers(wtCtx, issue),\n stopPreviewServers: (iid) => this.stopPreviewServers(iid),\n tryCreateMergeRequest: (issue, branch, workDir, previewUrl) =>\n this.tryCreateMergeRequest(issue, branch, workDir, previewUrl),\n buildPreviewUrl: (iid) => this.buildPreviewUrl(iid),\n getPortsForIssue: (iid) => this.portAllocator.getPortsForIssue(iid),\n isPreviewRunning: (iid) => this.devServerManager.getStatus(iid).running,\n consumePendingAction: (iid) => {\n const action = this.pendingActions.get(iid);\n if (action) this.pendingActions.delete(iid);\n return action;\n },\n };\n }\n\n private async _processIssueImpl(issue: GongfengIssue): Promise<void> {\n const branchName = `${this.config.project.branchPrefix}-${issue.iid}`;\n const wtCtx = this.computeWorktreeContext(issue.iid, branchName);\n\n logger.info('Processing issue', {\n iid: issue.iid, title: issue.title, branchName,\n worktree: wtCtx.gitRootDir,\n multiRepo: this.workspaceManager.isMultiRepo(),\n });\n metrics.incCounter('iaf_issues_total', { pipeline: this.pipelineDef.mode });\n\n const supplement = this.supplementStore?.get(issue.iid);\n const demand = gongfengIssueToDemandSpec(issue, supplement);\n\n let record = this.tracker.get(issue.iid);\n const isRetry = record?.state === IssueState.Failed;\n if (isRetry) {\n metrics.incCounter('iaf_issues_retried_total');\n }\n\n if (!record) {\n record = this.tracker.create({\n state: IssueState.Pending,\n branchName,\n pipelineMode: this.pipelineDef.mode,\n demandSpec: demand,\n });\n }\n\n if (!record.pipelineMode) {\n this.tracker.updateState(issue.iid, record.state, { pipelineMode: this.pipelineDef.mode } as any);\n record.pipelineMode = this.pipelineDef.mode;\n }\n\n const issuePipelineDef = this.getIssueSpecificPipelineDef(record);\n const issueLM = createLifecycleManager(issuePipelineDef);\n const phaseCtx: PhaseContext = {\n demand, branchName, pipelineMode: issuePipelineDef.mode,\n };\n if (record.ports) {\n phaseCtx.ports = record.ports;\n }\n\n const ctx: IssueProcessingContext = {\n issue, branchName, wtCtx, record, isRetry,\n pipelineDef: issuePipelineDef,\n lifecycleManager: issueLM,\n demand, phaseCtx,\n };\n\n const deps = this.buildDeps();\n\n try {\n const { wtGit, wtPlan, wtGitMap } = await executeSetup(ctx, deps);\n\n // Inject workspace layout into phaseCtx after worktree/workspace is prepared\n if (wtCtx.workspace) {\n const repos = this.workspaceManager.buildRepoContexts(\n issue.iid, branchName, this.config.project.baseBranch, this.config.project.branchPrefix,\n );\n phaseCtx.workspace = {\n repos,\n workspaceRoot: wtCtx.workspace.workspaceRoot,\n };\n }\n const phaseResult = await executePhaseLoop(ctx, deps, wtGit, wtPlan, wtGitMap);\n if (phaseResult.paused) return;\n await executeCompletion(ctx, deps, phaseResult, wtGitMap);\n } catch (err) {\n // ── 拦截用户发起的中止/重做,在 handleFailure 之前处理 ──\n\n // Path A: PhaseAbortedError — 来自 PhaseLoopStep 阶段间检查(无 AI 运行时)\n if (err instanceof PhaseAbortedError) {\n if (err.action === 'restart') return; // restartIssue 已自行处理所有清理\n this.applyPendingAction(err.action, issue.iid, wtCtx, issuePipelineDef);\n return;\n }\n\n // Path B: pendingActions — AI 进程被 kill 后由 catch 拾取\n const pendingAction = this.pendingActions.get(issue.iid);\n if (pendingAction) {\n this.pendingActions.delete(issue.iid);\n if (pendingAction === 'restart') return; // restartIssue 已自行处理所有清理\n this.applyPendingAction(pendingAction, issue.iid, wtCtx, issuePipelineDef);\n return;\n }\n\n await handleFailure(err, issue, wtCtx, deps);\n }\n }\n\n private async tryCreateMergeRequest(\n issue: GongfengIssue,\n branchName: string,\n workDir: string,\n previewUrl?: string | null,\n ): Promise<MergeRequestResult | null> {\n try {\n const supplement = this.supplementStore?.get(issue.iid);\n const tapdId = supplement?.tapdId?.trim()\n || extractTapdId(issue.description || '');\n\n const title = generateMRTitle(issue.iid, issue.title, tapdId);\n let description = generateMRDescription({\n issueIid: issue.iid,\n issueTitle: issue.title,\n issueDescription: issue.description || '',\n branchName,\n planDir: workDir,\n });\n\n if (previewUrl) {\n description += `\\n\\n## Preview Environment\\n\\n🌐 ${previewUrl}`;\n }\n\n const mr = await this.gongfeng.createMergeRequest({\n sourceBranch: branchName,\n targetBranch: this.config.project.baseBranch,\n title,\n description,\n });\n\n logger.info('Merge request created successfully', {\n iid: issue.iid, mrIid: mr.iid, mrUrl: mr.web_url,\n });\n return { url: mr.web_url, iid: mr.iid };\n } catch (err) {\n const errorMsg = (err as Error).message;\n logger.warn('Failed to create merge request, trying to find existing one', {\n iid: issue.iid, error: errorMsg,\n });\n\n if (errorMsg.includes('already exists')) {\n return this.tryFindExistingMergeRequest(issue.iid, branchName);\n }\n return null;\n }\n }\n\n private async tryFindExistingMergeRequest(\n issueIid: number,\n branchName: string,\n ): Promise<MergeRequestResult | null> {\n try {\n const existing = await this.gongfeng.findMergeRequestByBranch(\n branchName,\n this.config.project.baseBranch,\n );\n if (existing) {\n logger.info('Found existing merge request', {\n iid: issueIid, mrIid: existing.iid, mrUrl: existing.web_url,\n });\n return { url: existing.web_url, iid: existing.iid };\n }\n } catch (findErr) {\n logger.warn('Failed to find existing merge request', {\n iid: issueIid, error: (findErr as Error).message,\n });\n }\n return null;\n }\n\n // TODO: Multi-repo MR support — when associates are enabled, iterate over\n // wsCtx.associates and create per-repo MRs using per-repo GongfengClients.\n\n private shouldDeployServers(issueIid: number): boolean {\n return isE2eEnabledForIssue(issueIid, this.tracker, this.config)\n || this.config.preview.enabled;\n }\n\n private shouldAutoApprove(issueLabels: string[]): boolean {\n const autoLabels = this.config.review.autoApproveLabels;\n if (!autoLabels.length) return false;\n return issueLabels.some(l => autoLabels.includes(l));\n }\n\n private async startPreviewServers(\n wtCtx: WorktreeContext,\n issue: GongfengIssue,\n ): Promise<PortPair | null> {\n try {\n this.emitProgress(issue.iid, 'deploy', t('orchestrator.deployProgress'));\n const ports = await this.portAllocator.allocate(issue.iid);\n wtCtx.ports = ports;\n\n this.tracker.updateState(issue.iid, this.tracker.get(issue.iid)!.state, {\n ports,\n previewStartedAt: new Date().toISOString(),\n } as any);\n\n await this.devServerManager.startServers(wtCtx, ports);\n\n const previewUrl = this.buildPreviewUrl(issue.iid);\n if (previewUrl) {\n try {\n await this.gongfeng.createIssueNote(\n issue.id,\n this.buildPreviewComment(ports, previewUrl),\n );\n } catch {\n // ignore comment failure\n }\n }\n\n this.emitProgress(issue.iid, 'deploy_done', t('orchestrator.deployDoneProgress', { url: previewUrl ?? 'N/A' }));\n this.eventBus.emitTyped('pipeline:progress', {\n issueIid: issue.iid,\n step: 'preview_ready',\n message: previewUrl ?? '',\n });\n\n return ports;\n } catch (err) {\n logger.error('Failed to start preview servers', {\n iid: issue.iid,\n error: (err as Error).message,\n });\n this.portAllocator.release(issue.iid);\n try {\n await this.gongfeng.createIssueNote(issue.id,\n `⚠️ Preview 服务启动失败: ${(err as Error).message}\\nE2E 测试将尝试使用 config.json 中的默认端口。`);\n } catch { /* ignore */ }\n return null;\n }\n }\n\n stopPreviewServers(issueIid: number): void {\n this.devServerManager.stopServers(issueIid);\n this.portAllocator.release(issueIid);\n const record = this.tracker.get(issueIid);\n if (record?.ports) {\n this.tracker.updateState(issueIid, record.state, {\n ports: undefined,\n previewStartedAt: undefined,\n } as any);\n }\n }\n\n async stopPreviewAndCleanWorktree(issueIid: number): Promise<void> {\n const record = this.tracker.get(issueIid);\n if (!record) return;\n\n this.stopPreviewServers(issueIid);\n\n const wtCtx = this.computeWorktreeContext(issueIid, record.branchName);\n await this.mainGitMutex.runExclusive(async () => {\n await this.cleanupWorktree(wtCtx);\n });\n logger.info('Preview stopped and worktree cleaned', { iid: issueIid });\n }\n\n async markDeployed(issueIid: number): Promise<void> {\n const record = this.tracker.get(issueIid);\n if (!record) throw new IssueNotFoundError(issueIid);\n if (record.state !== IssueState.Completed) {\n throw new InvalidStateError(record.state, `Issue #${issueIid} not in completed state`);\n }\n\n // 1. Stop preview servers\n this.stopPreviewServers(issueIid);\n\n // 2. Clean worktree (keep remote branch for MR)\n const wtCtx = this.computeWorktreeContext(issueIid, record.branchName);\n await this.mainGitMutex.runExclusive(async () => {\n await this.cleanupWorktree(wtCtx);\n });\n\n // 3. Close issue on Gongfeng\n const externalId = getExternalId(record);\n try {\n await this.gongfeng.closeIssue(externalId);\n } catch (err) {\n logger.warn('Failed to close issue on Gongfeng', { iid: issueIid, error: (err as Error).message });\n }\n\n // 4. Update labels\n try {\n const issue = await this.gongfeng.getIssueDetail(externalId);\n const labels = issue.labels.filter(l => !l.startsWith('auto-finish:') && l !== 'auto-finish');\n labels.push('auto-finish:deployed');\n await this.gongfeng.updateIssueLabels(externalId, labels);\n } catch (err) {\n logger.warn('Failed to update labels', { iid: issueIid, error: (err as Error).message });\n }\n\n // 5. Transition to Deployed\n this.tracker.updateState(issueIid, IssueState.Deployed);\n logger.info('Issue marked as deployed', { iid: issueIid });\n }\n\n async restartPreview(issueIid: number): Promise<string> {\n const record = this.tracker.get(issueIid);\n if (!record) throw new IssueNotFoundError(issueIid);\n\n const wtCtx = this.computeWorktreeContext(issueIid, record.branchName);\n if (!fsSync.existsSync(wtCtx.workDir)) {\n throw new InvalidStateError(record.state, 'Worktree no longer exists');\n }\n\n this.stopPreviewServers(issueIid);\n\n const ports = await this.portAllocator.allocate(issueIid);\n wtCtx.ports = ports;\n\n try {\n this.tracker.updateState(issueIid, record.state, {\n ports,\n previewStartedAt: new Date().toISOString(),\n } as any);\n await this.devServerManager.startServers(wtCtx, ports);\n } catch (err) {\n this.portAllocator.release(issueIid);\n this.tracker.updateState(issueIid, record.state, {\n ports: undefined,\n previewStartedAt: undefined,\n } as any);\n throw err;\n }\n\n const url = this.buildPreviewUrl(issueIid)!;\n logger.info('Preview restarted', { iid: issueIid, url });\n return url;\n }\n\n getPreviewHost(): string {\n if (this.config.preview.host) return this.config.preview.host;\n return getLocalIP();\n }\n\n buildPreviewUrl(issueIid: number): string | null {\n const ports = this.portAllocator.getPortsForIssue(issueIid);\n if (!ports) return null;\n const host = this.getPreviewHost();\n return `https://${host}:${ports.frontendPort}`;\n }\n\n private buildPreviewComment(ports: PortPair, previewUrl: string): string {\n const host = this.getPreviewHost();\n const ttlHours = Math.round(this.config.preview.ttlMs / (60 * 60 * 1000));\n return [\n t('orchestrator.previewComment.title'),\n '',\n t('orchestrator.previewComment.tableHeader'),\n t('orchestrator.previewComment.tableSep'),\n `| ${t('orchestrator.previewComment.frontend')} | ${previewUrl} |`,\n `| ${t('orchestrator.previewComment.backendApi')} | http://${host}:${ports.backendPort}/api |`,\n '',\n t('orchestrator.previewComment.hint'),\n t('orchestrator.previewComment.expiry', { hours: ttlHours }),\n ].join('\\n');\n }\n\n async resolveConflict(issueIid: number): Promise<void> {\n const record = this.tracker.get(issueIid);\n if (!record) throw new IssueNotFoundError(issueIid);\n\n const baseBranch = this.config.project.baseBranch;\n const branchName = record.branchName;\n\n logger.info('Starting conflict resolution', { issueIid, branchName, baseBranch });\n\n // 1. Update state\n this.tracker.updateState(issueIid, IssueState.ResolvingConflict);\n this.eventBus.emitTyped('conflict:started', { issueIid });\n\n // 2. Comment on issue\n try {\n await this.gongfeng.createIssueNote(\n getExternalId(record),\n t('conflict.startComment', { branch: branchName, baseBranch }),\n );\n } catch { /* ignore */ }\n\n const wtCtx = this.computeWorktreeContext(issueIid, branchName);\n\n try {\n // 3. Fetch + ensure worktree\n await this.mainGitMutex.runExclusive(async () => {\n await this.mainGit.fetch();\n await this.ensureWorktree(wtCtx);\n });\n\n const wtGit = new GitOperations(wtCtx.gitRootDir);\n\n // 4. Checkout branch\n await wtGit.checkout(branchName);\n\n // 5–6. Rebase + resolve conflicts using shared ConflictResolver\n await this.conflictResolver.resolve({\n wtGit,\n targetRef: `origin/${baseBranch}`,\n workDir: wtCtx.workDir,\n branchName,\n contextId: issueIid,\n phaseTimeoutMs: this.config.ai.phaseTimeoutMs,\n onEvent: (event) => {\n this.eventBus.emitTyped('agent:output', {\n issueIid,\n phase: 'conflict-resolve',\n event,\n });\n },\n });\n\n // If resolve() returned without throwing, rebase succeeded (with or without conflict resolution).\n\n // 7. Run verification\n logger.info('Running verification after conflict resolution', { issueIid });\n const wtPlan = new PlanPersistence(wtCtx.workDir, issueIid);\n wtPlan.ensureDir();\n\n const verifyPhase = createPhase('verify', this.aiRunner, wtGit, wtPlan, this.config);\n\n const verifyCtx: PhaseContext = {\n demand: {\n demandId: `gf-${issueIid}`,\n sourceRef: {\n source: 'gongfeng-issue',\n externalId: String(getExternalId(record)),\n displayId: String(issueIid),\n },\n title: getTitle(record),\n description: '',\n createdAt: record.createdAt,\n },\n branchName,\n pipelineMode: record.pipelineMode,\n };\n\n const verifyOutcome = await verifyPhase.run(verifyCtx);\n if (verifyOutcome.status === 'failed') {\n const errMsg = verifyOutcome.error?.message ?? 'Verification failed after conflict resolution';\n throw new (await import('../errors/index.js')).AIExecutionError('verify', errMsg, {\n output: verifyOutcome.error?.rawOutput ?? verifyOutcome.output,\n exitCode: verifyOutcome.exitCode ?? 1,\n });\n }\n\n // 8. Force push\n await wtGit.forcePush(branchName);\n\n // 9. Update state\n this.tracker.updateState(issueIid, IssueState.Completed);\n this.eventBus.emitTyped('conflict:resolved', { issueIid });\n\n // 10. Comment on Issue/MR\n try {\n await this.gongfeng.createIssueNote(\n getExternalId(record),\n t('conflict.resolvedComment', { branch: branchName, baseBranch }),\n );\n } catch { /* ignore */ }\n\n await this.commentOnMr(record.mrUrl, t('conflict.mrResolvedComment'));\n\n logger.info('Conflict resolution completed', { issueIid });\n } catch (err) {\n const errorMsg = (err as Error).message;\n logger.error('Conflict resolution failed', { issueIid, error: errorMsg });\n\n // Try to abort any in-progress rebase\n try {\n const wtGit = new GitOperations(wtCtx.gitRootDir);\n if (await wtGit.isRebaseInProgress()) {\n await wtGit.rebaseAbort();\n }\n } catch { /* ignore abort failure */ }\n\n this.tracker.markFailed(issueIid, errorMsg.slice(0, 500), IssueState.ResolvingConflict);\n this.eventBus.emitTyped('conflict:failed', { issueIid, error: errorMsg });\n\n try {\n await this.gongfeng.createIssueNote(\n getExternalId(record),\n t('conflict.failedComment', { error: errorMsg }),\n );\n } catch { /* ignore */ }\n }\n }\n\n private extractMrIidFromUrl(mrUrl: string): number | null {\n const match = mrUrl.match(/merge_requests\\/(\\d+)/);\n return match ? parseInt(match[1], 10) : null;\n }\n\n private async commentOnMr(mrUrl: string | undefined, body: string): Promise<void> {\n if (!mrUrl) return;\n const mrIid = this.extractMrIidFromUrl(mrUrl);\n if (!mrIid) return;\n try {\n await this.gongfeng.createMergeRequestNote(mrIid, body);\n } catch (err) {\n logger.warn('Failed to comment on MR', { mrIid, error: (err as Error).message });\n }\n }\n}\n","import type { GongfengIssue } from '../../clients/GongfengClient.js';\nimport type { DemandSpec } from '../DemandSpec.js';\nimport type { SupplementInfo } from '../../supplement/SupplementStore.js';\n\n/**\n * 将工蜂 Issue 转换为 DemandSpec 值对象。\n *\n * @param issue 工蜂 Issue 原始数据\n * @param supplement 可选的补充信息(来自 SupplementStore)\n */\nexport function gongfengIssueToDemandSpec(\n issue: GongfengIssue,\n supplement?: SupplementInfo | null,\n): DemandSpec {\n return {\n demandId: `gf-${issue.iid}`,\n sourceRef: {\n source: 'gongfeng-issue',\n externalId: String(issue.id),\n displayId: String(issue.iid),\n },\n title: issue.title,\n description: issue.description ?? '',\n supplement: supplement ? mapSupplement(supplement) : undefined,\n createdAt: issue.created_at ?? new Date().toISOString(),\n };\n}\n\nfunction mapSupplement(s: SupplementInfo): DemandSpec['supplement'] {\n const result: Record<string, string | undefined> = {};\n if (s.requirements?.trim()) result.requirements = s.requirements.trim();\n if (s.acceptanceCriteria?.trim()) result.acceptanceCriteria = s.acceptanceCriteria.trim();\n if (s.scope?.trim()) result.scope = s.scope.trim();\n if (s.constraints?.trim()) result.constraints = s.constraints.trim();\n if (s.references?.trim()) result.references = s.references.trim();\n if (s.freeText?.trim()) result.freeText = s.freeText.trim();\n if (s.tapdId?.trim()) result.tapdId = s.tapdId.trim();\n return Object.keys(result).length > 0 ? result : undefined;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { t } from '../i18n/index.js';\n\nconst TAPD_PATTERNS = [\n /--story=(\\d+)/i,\n /--bug=(\\d+)/i,\n /tapd[:\\s-]+(\\d+)/i,\n /tapd单号[:\\s]*(\\d+)/i,\n];\n\nexport function extractTapdId(text: string): string | null {\n for (const pattern of TAPD_PATTERNS) {\n const match = text.match(pattern);\n if (match) return match[1];\n }\n return null;\n}\n\nexport function generateMRTitle(issueIid: number, issueTitle: string, tapdId?: string | null): string {\n const base = `feat(#${issueIid}): ${issueTitle}`;\n if (tapdId) {\n return `${base} --story=${tapdId}`;\n }\n return base;\n}\n\nexport function generateMRDescription(options: {\n issueIid: number;\n issueTitle: string;\n issueDescription: string;\n branchName: string;\n planDir?: string;\n}): string {\n const { issueIid, issueTitle, issueDescription, branchName, planDir } = options;\n\n const sections: string[] = [\n t('mr.relatedIssue'),\n ``,\n `- Issue: #${issueIid}`,\n `- ${t('mr.title')}: ${issueTitle}`,\n `- ${t('mr.branch')}: \\`${branchName}\\``,\n ``,\n t('mr.issueDescription'),\n ``,\n issueDescription || t('mr.noDescription'),\n ];\n\n if (planDir) {\n const summaryFiles = [\n { filename: '01-analysis.md', label: t('mr.summaryFiles.01-analysis.md') },\n { filename: '01-plan.md', label: t('mr.summaryFiles.01-plan.md') },\n { filename: '02-design.md', label: t('mr.summaryFiles.02-design.md') },\n { filename: '04-verify-report.md', label: t('mr.summaryFiles.04-verify-report.md') },\n { filename: '02-verify-report.md', label: t('mr.summaryFiles.02-verify-report.md') },\n ];\n\n const planSections: string[] = [];\n for (const { filename, label } of summaryFiles) {\n const filePath = path.join(planDir, '.claude-plan', `issue-${issueIid}`, filename);\n if (fs.existsSync(filePath)) {\n const content = fs.readFileSync(filePath, 'utf-8');\n const summary = extractSummary(content);\n if (summary) {\n planSections.push(`### ${label}\\n\\n${summary}`);\n }\n }\n }\n\n if (planSections.length > 0) {\n sections.push('', t('mr.aiSummary'), '', ...planSections);\n }\n }\n\n sections.push('', '---', t('mr.autoCreated'));\n return sections.join('\\n');\n}\n\nfunction extractSummary(content: string, maxLines = 20): string {\n const lines = content.split('\\n');\n if (lines.length <= maxLines) return content.trim();\n return lines.slice(0, maxLines).join('\\n').trim() + '\\n\\n' + t('mr.truncated');\n}\n","import net from 'node:net';\nimport { PortExhaustionError } from '../errors/index.js';\nimport { logger as rootLogger } from '../logger.js';\n\nconst logger = rootLogger.child('PortAllocator');\n\nexport interface PortPair {\n backendPort: number;\n frontendPort: number;\n}\n\nexport interface PortAllocatorOptions {\n backendPortBase: number;\n frontendPortBase: number;\n maxPorts: number;\n}\n\nconst DEFAULT_OPTIONS: PortAllocatorOptions = {\n backendPortBase: 4000,\n frontendPortBase: 9000,\n maxPorts: 100,\n};\n\nfunction checkPortAvailable(port: number): Promise<boolean> {\n return new Promise((resolve) => {\n const server = net.createServer();\n server.once('error', () => resolve(false));\n server.once('listening', () => {\n server.close(() => resolve(true));\n });\n server.listen(port, '0.0.0.0');\n });\n}\n\nexport class PortAllocator {\n private allocated = new Map<number, PortPair>();\n private options: PortAllocatorOptions;\n\n constructor(options?: Partial<PortAllocatorOptions>) {\n this.options = { ...DEFAULT_OPTIONS, ...options };\n }\n\n async allocate(issueIid: number): Promise<PortPair> {\n const existing = this.allocated.get(issueIid);\n if (existing) {\n logger.info('Returning already allocated ports', { issueIid, ports: existing });\n return existing;\n }\n\n const usedBackend = new Set([...this.allocated.values()].map((p) => p.backendPort));\n const usedFrontend = new Set([...this.allocated.values()].map((p) => p.frontendPort));\n\n for (let offset = 1; offset <= this.options.maxPorts; offset++) {\n const backendPort = this.options.backendPortBase + offset;\n const frontendPort = this.options.frontendPortBase + offset;\n\n if (usedBackend.has(backendPort) || usedFrontend.has(frontendPort)) {\n continue;\n }\n\n const [beOk, feOk] = await Promise.all([\n checkPortAvailable(backendPort),\n checkPortAvailable(frontendPort),\n ]);\n\n if (beOk && feOk) {\n const pair: PortPair = { backendPort, frontendPort };\n this.allocated.set(issueIid, pair);\n logger.info('Ports allocated', { issueIid, ...pair });\n return pair;\n }\n\n logger.debug('Port pair unavailable, trying next', {\n backendPort,\n frontendPort,\n beOk,\n feOk,\n });\n }\n\n throw new PortExhaustionError(\n `No available port pair found for issue #${issueIid} ` +\n `(scanned ${this.options.maxPorts} offsets from ` +\n `backend=${this.options.backendPortBase} frontend=${this.options.frontendPortBase})`,\n );\n }\n\n release(issueIid: number): void {\n const pair = this.allocated.get(issueIid);\n if (pair) {\n this.allocated.delete(issueIid);\n logger.info('Ports released', { issueIid, ...pair });\n }\n }\n\n getPortsForIssue(issueIid: number): PortPair | undefined {\n return this.allocated.get(issueIid);\n }\n\n getAllAllocated(): Map<number, PortPair> {\n return new Map(this.allocated);\n }\n\n restore(issueIid: number, ports: PortPair): void {\n this.allocated.set(issueIid, ports);\n logger.info('Ports restored from persistence', { issueIid, ...ports });\n }\n}\n","import { spawn, ChildProcess } from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport type { PortPair } from './PortAllocator.js';\nimport type { WorktreeContext } from '../git/WorktreeContext.js';\nimport { logger as rootLogger } from '../logger.js';\nimport { resolveDataDir } from '../paths.js';\n\nconst logger = rootLogger.child('DevServerManager');\n\ninterface ServerSet {\n backend: ChildProcess;\n frontend: ChildProcess;\n ports: PortPair;\n workDir: string;\n startedAt: string;\n backendLog: fs.WriteStream;\n frontendLog: fs.WriteStream;\n}\n\nexport interface DevServerManagerOptions {\n backendCommand?: { bin: string; args: string[] };\n frontendCommand?: { bin: string; args: string[] };\n}\n\nconst DEFAULT_OPTIONS: DevServerManagerOptions = {};\n\nexport class DevServerManager {\n private servers = new Map<number, ServerSet>();\n private options: DevServerManagerOptions;\n private logDir: string;\n\n constructor(options?: Partial<DevServerManagerOptions>) {\n this.options = { ...DEFAULT_OPTIONS, ...options };\n this.logDir = path.join(resolveDataDir(), 'preview-logs');\n if (!fs.existsSync(this.logDir)) {\n fs.mkdirSync(this.logDir, { recursive: true });\n }\n }\n\n getLogPath(issueIid: number, type: 'backend' | 'frontend'): string | null {\n const filePath = path.join(this.logDir, `${issueIid}-${type}.log`);\n return fs.existsSync(filePath) ? filePath : null;\n }\n\n async startServers(wtCtx: WorktreeContext, ports: PortPair): Promise<void> {\n if (this.servers.has(wtCtx.issueIid)) {\n logger.info('Servers already running for issue', { issueIid: wtCtx.issueIid });\n return;\n }\n\n logger.info('Starting dev servers', { issueIid: wtCtx.issueIid, ...ports });\n\n const backendLogPath = path.join(this.logDir, `${wtCtx.issueIid}-backend.log`);\n const frontendLogPath = path.join(this.logDir, `${wtCtx.issueIid}-frontend.log`);\n const backendLog = fs.createWriteStream(backendLogPath, { flags: 'a' });\n const frontendLog = fs.createWriteStream(frontendLogPath, { flags: 'a' });\n\n const tsLine = (stream: string, data: Buffer) =>\n `[${new Date().toISOString()}] [${stream}] ${data.toString().trimEnd()}\\n`;\n\n const backendEnv: Record<string, string> = {\n ...process.env as Record<string, string>,\n PORT: String(ports.backendPort),\n E2E_PORT_OVERRIDE: '1',\n ENV_PATH: '.env.development.local',\n };\n\n const backendCmd = this.options.backendCommand ?? { bin: 'node', args: ['ace', 'serve', '--watch'] };\n const backend = spawn(backendCmd.bin, backendCmd.args, {\n cwd: wtCtx.workDir,\n env: backendEnv,\n stdio: ['ignore', 'pipe', 'pipe'],\n detached: true,\n });\n\n backend.unref();\n backend.stdout?.on('data', (data: Buffer) => {\n backendLog.write(tsLine('stdout', data));\n });\n backend.stderr?.on('data', (data: Buffer) => {\n backendLog.write(tsLine('stderr', data));\n });\n backend.on('exit', (code) => {\n logger.info('Backend process exited', { issueIid: wtCtx.issueIid, code });\n });\n\n const frontendDir = path.join(wtCtx.workDir, 'frontend');\n const frontendEnv: Record<string, string> = {\n ...process.env as Record<string, string>,\n BACKEND_PORT: String(ports.backendPort),\n FRONTEND_PORT: String(ports.frontendPort),\n VITE_API_PORT: String(ports.backendPort),\n };\n\n const frontendCmd = this.options.frontendCommand\n ?? { bin: 'pnpm', args: ['dev', '--', '--port', String(ports.frontendPort), '--host'] };\n const frontend = spawn(frontendCmd.bin, frontendCmd.args, {\n cwd: frontendDir,\n env: frontendEnv,\n stdio: ['ignore', 'pipe', 'pipe'],\n detached: true,\n });\n\n frontend.unref();\n frontend.stdout?.on('data', (data: Buffer) => {\n frontendLog.write(tsLine('stdout', data));\n });\n frontend.stderr?.on('data', (data: Buffer) => {\n frontendLog.write(tsLine('stderr', data));\n });\n frontend.on('exit', (code) => {\n logger.info('Frontend process exited', { issueIid: wtCtx.issueIid, code });\n });\n\n const serverSet: ServerSet = {\n backend,\n frontend,\n ports,\n workDir: wtCtx.workDir,\n startedAt: new Date().toISOString(),\n backendLog,\n frontendLog,\n };\n this.servers.set(wtCtx.issueIid, serverSet);\n logger.info('Dev servers spawned, waiting for startup', { issueIid: wtCtx.issueIid, ...ports });\n\n await new Promise((r) => setTimeout(r, 10_000));\n logger.info('Dev servers startup grace period done', { issueIid: wtCtx.issueIid });\n }\n\n stopServers(issueIid: number): void {\n const set = this.servers.get(issueIid);\n if (!set) return;\n\n logger.info('Stopping dev servers', { issueIid, ports: set.ports });\n\n killProcess(set.backend, `backend #${issueIid}`);\n killProcess(set.frontend, `frontend #${issueIid}`);\n set.backendLog.end();\n set.frontendLog.end();\n\n this.servers.delete(issueIid);\n }\n\n stopAll(): void {\n for (const [iid] of this.servers) {\n this.stopServers(iid);\n }\n }\n\n getStatus(issueIid: number): { running: boolean; ports?: PortPair; startedAt?: string } {\n const set = this.servers.get(issueIid);\n if (!set) return { running: false };\n return {\n running: true,\n ports: set.ports,\n startedAt: set.startedAt,\n };\n }\n\n getRunningIssues(): number[] {\n return [...this.servers.keys()];\n }\n}\n\nfunction killProcess(proc: ChildProcess, label: string): void {\n try {\n if (proc.killed || proc.exitCode !== null) return;\n const pid = proc.pid;\n if (!pid) return;\n\n // detached: true 使子进程成为进程组长,-pid 杀死整个进程组(含 pnpm 的子 vite 等)\n try { process.kill(-pid, 'SIGTERM'); } catch { proc.kill('SIGTERM'); }\n\n setTimeout(() => {\n if (!proc.killed && proc.exitCode === null) {\n logger.warn(`Force killing ${label}`);\n try { process.kill(-pid, 'SIGKILL'); } catch { proc.kill('SIGKILL'); }\n }\n }, 5_000);\n } catch (err) {\n logger.warn(`Failed to kill ${label}`, { error: (err as Error).message });\n }\n}\n","import type { Config } from '../config.js';\nimport type { IssueTracker } from '../tracker/IssueTracker.js';\n\nlet e2eOverride: boolean | undefined;\n\nexport function getE2eEnabled(cfg: Config): boolean {\n return e2eOverride ?? cfg.e2e.enabled;\n}\n\nexport function setE2eOverride(value: boolean | undefined): void {\n e2eOverride = value;\n}\n\nexport function isE2eEnabledForIssue(\n issueIid: number,\n tracker: IssueTracker,\n cfg: Config,\n): boolean {\n const record = tracker.get(issueIid);\n if (record?.e2eEnabled !== undefined) return record.e2eEnabled;\n return getE2eEnabled(cfg);\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { logger as rootLogger } from '../logger.js';\n\nconst logger = rootLogger.child('ScreenshotCollector');\n\nconst MAX_SCREENSHOTS = 20;\n\nexport interface ScreenshotFile {\n filePath: string;\n testName: string;\n}\n\nfunction walkDir(dir: string, files: string[] = []): string[] {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const full = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n walkDir(full, files);\n } else if (entry.isFile() && entry.name.endsWith('.png')) {\n files.push(full);\n }\n }\n return files;\n}\n\n/**\n * 从 worktree 的 frontend/test-results/ 目录收集 E2E 截图。\n * Playwright 以 `screenshot: 'on'` 运行时,每个测试的截图保存在\n * `test-results/<project>-<test-name>-<browser>/` 子目录下。\n */\nexport function collectScreenshots(workDir: string): ScreenshotFile[] {\n const testResultsDir = path.join(workDir, 'frontend', 'test-results');\n if (!fs.existsSync(testResultsDir)) {\n logger.debug('test-results directory not found', { dir: testResultsDir });\n return [];\n }\n\n const pngFiles = walkDir(testResultsDir);\n if (pngFiles.length === 0) {\n logger.debug('No screenshots found');\n return [];\n }\n\n const screenshots: ScreenshotFile[] = pngFiles.map((filePath) => {\n const relative = path.relative(testResultsDir, filePath);\n const testName = relative.split(path.sep)[0] || path.basename(filePath, '.png');\n return { filePath, testName };\n });\n\n if (screenshots.length > MAX_SCREENSHOTS) {\n logger.warn('Too many screenshots, truncating', {\n total: screenshots.length,\n max: MAX_SCREENSHOTS,\n });\n return screenshots.slice(0, MAX_SCREENSHOTS);\n }\n\n logger.info('Screenshots collected', { count: screenshots.length });\n return screenshots;\n}\n","import { GongfengClient, UploadResult } from '../clients/GongfengClient.js';\nimport { collectScreenshots, ScreenshotFile } from './ScreenshotCollector.js';\nimport { logger as rootLogger } from '../logger.js';\nimport { t } from '../i18n/index.js';\n\nconst logger = rootLogger.child('ScreenshotPublisher');\n\nexport interface PublishOptions {\n workDir: string;\n issueIid: number;\n issueId: number;\n mrIid?: number;\n}\n\ninterface UploadedScreenshot {\n testName: string;\n markdown: string;\n}\n\nfunction buildComment(uploaded: UploadedScreenshot[], truncated: boolean): string {\n const lines: string[] = [t('screenshot.title'), ''];\n\n for (const item of uploaded) {\n lines.push(`### ${item.testName}`, '', item.markdown, '');\n }\n\n if (truncated) {\n lines.push(t('screenshot.truncated'), '');\n }\n\n return lines.join('\\n');\n}\n\nexport class ScreenshotPublisher {\n constructor(private gongfeng: GongfengClient) {}\n\n async publish(options: PublishOptions): Promise<void> {\n const { workDir, issueIid, issueId, mrIid } = options;\n\n const screenshots = collectScreenshots(workDir);\n if (screenshots.length === 0) {\n logger.info('No E2E screenshots to publish', { issueIid });\n return;\n }\n\n const uploaded = await this.uploadAll(screenshots);\n if (uploaded.length === 0) {\n logger.warn('All screenshot uploads failed', { issueIid });\n return;\n }\n\n const truncated = screenshots.length >= 20;\n const comment = buildComment(uploaded, truncated);\n\n await this.postToIssue(issueId, comment);\n\n if (mrIid) {\n await this.postToMergeRequest(mrIid, comment);\n }\n\n logger.info('E2E screenshots published', {\n issueIid,\n mrIid,\n count: uploaded.length,\n });\n }\n\n private async uploadAll(screenshots: ScreenshotFile[]): Promise<UploadedScreenshot[]> {\n const results: UploadedScreenshot[] = [];\n\n for (const screenshot of screenshots) {\n try {\n const result: UploadResult = await this.gongfeng.uploadFile(screenshot.filePath);\n results.push({\n testName: screenshot.testName,\n markdown: result.markdown,\n });\n } catch (err) {\n logger.warn('Failed to upload screenshot', {\n filePath: screenshot.filePath,\n error: (err as Error).message,\n });\n }\n }\n\n return results;\n }\n\n private async postToIssue(issueId: number, comment: string): Promise<void> {\n try {\n await this.gongfeng.createIssueNote(issueId, comment);\n } catch (err) {\n logger.warn('Failed to post screenshots to issue', {\n issueId,\n error: (err as Error).message,\n });\n }\n }\n\n private async postToMergeRequest(mrIid: number, comment: string): Promise<void> {\n try {\n await this.gongfeng.createMergeRequestNote(mrIid, comment);\n } catch (err) {\n logger.warn('Failed to post screenshots to merge request', {\n mrIid,\n error: (err as Error).message,\n });\n }\n }\n}\n","/**\n * Lightweight Prometheus-compatible metrics collector.\n *\n * Provides counters and histograms without external dependencies.\n * Expose via the `/metrics` endpoint in the Web server.\n */\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface MetricLabels {\n [key: string]: string;\n}\n\ninterface CounterEntry {\n type: 'counter';\n help: string;\n values: Map<string, number>;\n}\n\ninterface HistogramEntry {\n type: 'histogram';\n help: string;\n buckets: number[];\n /** key → { counts per bucket, sum, count } */\n values: Map<string, { bucketCounts: number[]; sum: number; count: number }>;\n}\n\ntype MetricEntry = CounterEntry | HistogramEntry;\n\n// ---------------------------------------------------------------------------\n// Label helpers\n// ---------------------------------------------------------------------------\n\nfunction labelsToKey(labels: MetricLabels): string {\n const pairs = Object.entries(labels).sort(([a], [b]) => a.localeCompare(b));\n if (pairs.length === 0) return '';\n return pairs.map(([k, v]) => `${k}=\"${v}\"`).join(',');\n}\n\nfunction keyToPromLabels(key: string): string {\n return key ? `{${key}}` : '';\n}\n\n// ---------------------------------------------------------------------------\n// Default histogram bucket boundaries\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_BUCKETS = [\n 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 30, 60, 120, 300, 600,\n];\n\n// ---------------------------------------------------------------------------\n// Collector\n// ---------------------------------------------------------------------------\n\nexport class MetricsCollector {\n private readonly metrics = new Map<string, MetricEntry>();\n\n // ── Counter ─────────────────────────────────────────────────────────\n\n /** Register a new counter. Idempotent if name already exists. */\n registerCounter(name: string, help: string): void {\n if (this.metrics.has(name)) return;\n this.metrics.set(name, { type: 'counter', help, values: new Map() });\n }\n\n /** Increment a counter by `delta` (default 1). */\n incCounter(name: string, labels: MetricLabels = {}, delta = 1): void {\n const entry = this.metrics.get(name);\n if (!entry || entry.type !== 'counter') return;\n const key = labelsToKey(labels);\n entry.values.set(key, (entry.values.get(key) ?? 0) + delta);\n }\n\n /** Read current value (for testing). */\n getCounter(name: string, labels: MetricLabels = {}): number {\n const entry = this.metrics.get(name);\n if (!entry || entry.type !== 'counter') return 0;\n return entry.values.get(labelsToKey(labels)) ?? 0;\n }\n\n // ── Histogram ───────────────────────────────────────────────────────\n\n /** Register a new histogram with optional custom buckets. */\n registerHistogram(name: string, help: string, buckets?: number[]): void {\n if (this.metrics.has(name)) return;\n const sortedBuckets = [...(buckets ?? DEFAULT_BUCKETS)].sort((a, b) => a - b);\n this.metrics.set(name, { type: 'histogram', help, buckets: sortedBuckets, values: new Map() });\n }\n\n /** Observe a value in a histogram. */\n observeHistogram(name: string, value: number, labels: MetricLabels = {}): void {\n const entry = this.metrics.get(name);\n if (!entry || entry.type !== 'histogram') return;\n const key = labelsToKey(labels);\n let data = entry.values.get(key);\n if (!data) {\n data = { bucketCounts: new Array(entry.buckets.length).fill(0), sum: 0, count: 0 };\n entry.values.set(key, data);\n }\n data.sum += value;\n data.count += 1;\n // Store in the smallest bucket that fits (non-cumulative)\n for (let i = 0; i < entry.buckets.length; i++) {\n if (value <= entry.buckets[i]) {\n data.bucketCounts[i] += 1;\n break;\n }\n }\n }\n\n // ── Timer helper ────────────────────────────────────────────────────\n\n /** Start a timer. Returns a function that, when called, observes the elapsed seconds. */\n startTimer(histogramName: string, labels: MetricLabels = {}): () => number {\n const start = performance.now();\n return () => {\n const elapsed = (performance.now() - start) / 1000;\n this.observeHistogram(histogramName, elapsed, labels);\n return elapsed;\n };\n }\n\n // ── Prometheus exposition ───────────────────────────────────────────\n\n /** Render all metrics in Prometheus text exposition format. */\n serialize(): string {\n const lines: string[] = [];\n\n for (const [name, entry] of this.metrics) {\n if (entry.type === 'counter') {\n lines.push(`# HELP ${name} ${entry.help}`);\n lines.push(`# TYPE ${name} counter`);\n for (const [key, value] of entry.values) {\n lines.push(`${name}${keyToPromLabels(key)} ${value}`);\n }\n } else if (entry.type === 'histogram') {\n lines.push(`# HELP ${name} ${entry.help}`);\n lines.push(`# TYPE ${name} histogram`);\n for (const [key, data] of entry.values) {\n const lblStr = key ? `,${key}` : '';\n let cumulative = 0;\n for (let i = 0; i < entry.buckets.length; i++) {\n cumulative += data.bucketCounts[i];\n lines.push(`${name}_bucket{le=\"${entry.buckets[i]}\"${lblStr}} ${cumulative}`);\n }\n lines.push(`${name}_bucket{le=\"+Inf\"${lblStr}} ${data.count}`);\n lines.push(`${name}_sum${keyToPromLabels(key)} ${data.sum}`);\n lines.push(`${name}_count${keyToPromLabels(key)} ${data.count}`);\n }\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n }\n\n /** Reset all metric values (for testing). */\n reset(): void {\n for (const entry of this.metrics.values()) {\n if (entry.type === 'counter') {\n entry.values.clear();\n } else if (entry.type === 'histogram') {\n entry.values.clear();\n }\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Singleton + pre-registered metrics\n// ---------------------------------------------------------------------------\n\nexport const metrics = new MetricsCollector();\n\n// Issue processing\nmetrics.registerCounter('iaf_issues_total', 'Total number of issues processed');\nmetrics.registerCounter('iaf_issues_succeeded_total', 'Number of successfully completed issues');\nmetrics.registerCounter('iaf_issues_failed_total', 'Number of failed issues');\nmetrics.registerCounter('iaf_issues_retried_total', 'Number of issue retries');\n\n// Phase execution\nmetrics.registerCounter('iaf_phases_total', 'Total number of phase executions');\nmetrics.registerCounter('iaf_phases_failed_total', 'Number of failed phase executions');\nmetrics.registerHistogram('iaf_phase_duration_seconds', 'Duration of phase execution in seconds', [\n 1, 5, 10, 30, 60, 120, 300, 600, 900, 1800,\n]);\n\n// AI runner\nmetrics.registerCounter('iaf_ai_calls_total', 'Total AI runner invocations');\nmetrics.registerCounter('iaf_ai_errors_total', 'AI runner errors');\nmetrics.registerHistogram('iaf_ai_duration_seconds', 'AI runner call duration in seconds', [\n 1, 5, 10, 30, 60, 120, 300, 600, 900, 1800,\n]);\n\n// Gongfeng API\nmetrics.registerCounter('iaf_gongfeng_requests_total', 'Total Gongfeng API requests');\nmetrics.registerCounter('iaf_gongfeng_errors_total', 'Gongfeng API errors');\nmetrics.registerHistogram('iaf_gongfeng_request_duration_seconds', 'Gongfeng API request duration in seconds', [\n 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10,\n]);\n\n// Webhook\nmetrics.registerCounter('iaf_webhook_commands_total', 'Total webhook commands received');\n\n// Braindump\nmetrics.registerCounter('iaf_braindump_batches_total', 'Total braindump batches');\nmetrics.registerCounter('iaf_braindump_tasks_total', 'Total braindump tasks');\n","import { GitOperations } from '../../git/GitOperations.js';\nimport { PlanPersistence } from '../../persistence/PlanPersistence.js';\nimport { IssueState } from '../../tracker/IssueState.js';\nimport type { IssueProcessingContext, OrchestratorDeps, SetupResult } from '../IssueProcessingContext.js';\nimport { HookInjector } from '../../hooks/index.js';\nimport { logger as rootLogger } from '../../logger.js';\nimport { t } from '../../i18n/index.js';\n\nconst logger = rootLogger.child('SetupStep');\n\n/**\n * 执行 Issue 处理的初始化步骤:\n * - 更新标签为 processing\n * - fetch + 创建 worktree(受 mutex 保护,通过 WorkspaceManager)\n * - 更新状态为 BranchCreated\n * - 安装依赖\n * - 初始化 PlanPersistence(ensureDir, writeIssueMeta, writeProgress)\n */\nexport async function executeSetup(\n ctx: IssueProcessingContext,\n deps: OrchestratorDeps,\n): Promise<SetupResult> {\n const { issue, wtCtx, record, pipelineDef, branchName } = ctx;\n\n // 1. 更新标签\n try {\n await deps.gongfeng.updateIssueLabels(issue.id, [\n ...issue.labels.filter(l => !l.startsWith('auto-finish:')),\n 'auto-finish:processing',\n ]);\n } catch (err) {\n logger.warn('Failed to update issue labels', { error: (err as Error).message });\n }\n\n // 2. fetch + worktree (always via WorkspaceManager)\n await deps.mainGitMutex.runExclusive(async () => {\n deps.emitProgress(issue.iid, 'fetch', t('orchestrator.fetchProgress'));\n await deps.mainGit.fetch();\n deps.emitProgress(issue.iid, 'worktree', t('orchestrator.worktreeProgress'));\n await deps.ensureWorktree(wtCtx);\n });\n\n // 3. 更新状态为 BranchCreated\n if (record.state === IssueState.Pending) {\n deps.tracker.updateState(issue.iid, IssueState.BranchCreated);\n }\n\n // 4. 安装依赖\n deps.emitProgress(issue.iid, 'install', t('orchestrator.installProgress'));\n if (wtCtx.workspace) {\n await deps.installDependencies(wtCtx.workspace.primary.workDir);\n for (const assoc of wtCtx.workspace.associates) {\n await deps.installDependencies(assoc.workDir);\n }\n } else {\n await deps.installDependencies(wtCtx.workDir);\n }\n\n // 5. 初始化 PlanPersistence(在 primary repo)\n deps.emitProgress(issue.iid, 'init_plan', t('orchestrator.initPlanProgress'));\n const primaryWorkDir = wtCtx.workspace ? wtCtx.workspace.primary.workDir : wtCtx.workDir;\n const primaryGitRoot = wtCtx.workspace ? wtCtx.workspace.primary.gitRootDir : wtCtx.gitRootDir;\n const wtGit = new GitOperations(primaryGitRoot);\n const wtPlan = new PlanPersistence(primaryWorkDir, issue.iid);\n\n wtPlan.ensureDir();\n wtPlan.writeIssueMeta({\n id: issue.id,\n iid: issue.iid,\n title: issue.title,\n labels: issue.labels,\n state: issue.state,\n });\n\n const existingProgress = wtPlan.readProgress();\n if (!existingProgress || !ctx.isRetry) {\n wtPlan.writeProgress(\n wtPlan.createInitialProgress(issue.iid, issue.title, branchName, pipelineDef),\n );\n }\n\n // 同步阶段进度到 tracker(处理旧记录无 phaseProgress 的情况)\n if (!record.phaseProgress) {\n deps.tracker.initPhaseProgress(issue.iid, pipelineDef);\n }\n\n // 5b. 注入 Claude Code hooks(PTY 模式下自动加载)\n const allArtifacts = pipelineDef.phases\n .flatMap(p => p.artifacts ?? [])\n .map(a => a.filename);\n if (allArtifacts.length > 0) {\n try {\n const firstPhase = pipelineDef.phases.find(p => p.kind === 'ai');\n const firstPhaseArtifacts = (firstPhase?.artifacts ?? []).map(a => a.filename);\n const hookInjector = new HookInjector();\n hookInjector.inject({\n workDir: primaryWorkDir,\n planDir: wtPlan.planDir,\n expectedArtifacts: allArtifacts,\n phaseExpectedArtifacts: firstPhaseArtifacts,\n issueIid: issue.iid,\n phaseName: firstPhase?.name,\n issueTitle: issue.title,\n issueDescription: issue.description,\n });\n } catch (err) {\n logger.warn('Failed to inject Claude Code hooks (non-blocking)', {\n error: (err as Error).message,\n });\n }\n }\n\n // 6. 构建 wtGitMap\n const wtGitMap = new Map<string, GitOperations>();\n if (wtCtx.workspace) {\n wtGitMap.set(wtCtx.workspace.primary.name, wtGit);\n for (const assoc of wtCtx.workspace.associates) {\n wtGitMap.set(assoc.name, new GitOperations(assoc.gitRootDir));\n }\n } else {\n wtGitMap.set('primary', wtGit);\n }\n\n return { wtGit, wtPlan, wtGitMap };\n}\n","import type { DialogOption, InputRequest } from '../ai-runner/AIRunner.js';\n\n// ── PhaseFeedback: 统一的中间反馈模型 ──\n\nexport type PhaseFeedback =\n | InteractiveDialogFeedback\n | ApprovalRequiredFeedback\n | PermissionRequestFeedback\n | GenericFeedback;\n\nexport interface InteractiveDialogFeedback {\n kind: 'interactive-dialog';\n question: string;\n options: DialogOption[];\n}\n\nexport interface ApprovalRequiredFeedback {\n kind: 'approval-required';\n scope: 'plan' | 'release' | 'uat';\n}\n\nexport interface PermissionRequestFeedback {\n kind: 'permission-request';\n tool: string;\n detail: unknown;\n}\n\nexport interface GenericFeedback {\n kind: 'generic';\n content: string;\n}\n\n// ── FeedbackResponse: 外部对反馈的统一应答 ──\n\nexport type FeedbackResponse =\n | { action: 'approve' }\n | { action: 'reject'; reason?: string }\n | { action: 'select'; value: string }\n | { action: 'dismiss' }\n | { action: 'pause' };\n\n// ── ErrorDecision: hook 对阶段失败的处置决策 ──\n\nexport type ErrorDecision =\n | { action: 'fail'; softFail: boolean }\n | { action: 'retry' }\n | { action: 'skip' };\n\n// ── PhaseError: 传递给 onError hook 的结构化错误信息 ──\n\nexport interface PhaseError {\n message: string;\n isRetryable: boolean;\n rawOutput: string;\n wasActiveAtTimeout: boolean;\n}\n\n// ── InputRequest ↔ PhaseFeedback 双向转换 ──\n\nexport function inputRequestToFeedback(request: InputRequest): PhaseFeedback {\n switch (request.type) {\n case 'interactive-dialog':\n return {\n kind: 'interactive-dialog',\n question: request.content,\n options: request.options ?? [],\n };\n case 'plan-approval':\n return { kind: 'approval-required', scope: 'plan' };\n case 'generic':\n return { kind: 'generic', content: request.content };\n }\n}\n\nexport function feedbackToInputRequest(feedback: PhaseFeedback): InputRequest {\n switch (feedback.kind) {\n case 'interactive-dialog':\n return { type: 'interactive-dialog', content: feedback.question, options: feedback.options };\n case 'approval-required':\n return { type: 'plan-approval', content: feedback.scope };\n case 'permission-request':\n return { type: 'generic', content: JSON.stringify(feedback.detail) };\n case 'generic':\n return { type: 'generic', content: feedback.content };\n }\n}\n\nexport function feedbackResponseToString(response: FeedbackResponse): string {\n switch (response.action) {\n case 'approve': return 'allow';\n case 'reject': return 'reject';\n case 'select': return response.value;\n case 'dismiss': return '';\n case 'pause': return '';\n }\n}\n\nexport function stringToFeedbackResponse(str: string, originalFeedback: PhaseFeedback): FeedbackResponse {\n if (str === 'allow') return { action: 'approve' };\n if (str === 'reject') return { action: 'reject' };\n if (str === '') {\n return originalFeedback.kind === 'interactive-dialog'\n ? { action: 'dismiss' }\n : { action: 'approve' };\n }\n return { action: 'select', value: str };\n}\n","import type { Config } from '../config.js';\nimport type { IssueTracker } from '../tracker/IssueTracker.js';\nimport { t } from '../i18n/index.js';\n\nlet noteSyncOverride: boolean | undefined;\n\nexport function getNoteSyncEnabled(cfg: Config): boolean {\n return noteSyncOverride ?? cfg.issueNoteSync.enabled;\n}\n\nexport function setNoteSyncOverride(value: boolean | undefined): void {\n noteSyncOverride = value;\n}\n\nexport function isNoteSyncEnabledForIssue(\n issueIid: number,\n tracker: IssueTracker,\n cfg: Config,\n): boolean {\n const record = tracker.get(issueIid);\n if (record?.issueNoteSyncEnabled !== undefined) return record.issueNoteSyncEnabled;\n return getNoteSyncEnabled(cfg);\n}\n\nconst SUMMARY_MAX_LENGTH = 500;\n\nexport function truncateToSummary(content: string): string {\n if (content.length <= SUMMARY_MAX_LENGTH) return content;\n const cut = content.slice(0, SUMMARY_MAX_LENGTH);\n const lastNewline = cut.lastIndexOf('\\n\\n');\n const boundary = lastNewline > SUMMARY_MAX_LENGTH * 0.3 ? lastNewline : cut.lastIndexOf('\\n');\n const summary = boundary > SUMMARY_MAX_LENGTH * 0.3 ? cut.slice(0, boundary) : cut;\n return summary + '\\n\\n...';\n}\n\nexport interface ResultFileSpec {\n filename: string;\n label: string;\n}\n\nexport function buildNoteSyncComment(\n phaseName: string,\n phaseLabel: string,\n docUrl: string,\n dashboardUrl: string,\n summary: string,\n): string {\n const emoji: Record<string, string> = {\n analysis: '🔍', design: '📐', implement: '💻', verify: '✅',\n plan: '📋', review: '👀', build: '🔨',\n };\n const icon = emoji[phaseName] || '📋';\n return [\n t('notesync.phaseCompleted', { icon, label: phaseLabel }),\n '',\n summary,\n '',\n '---',\n t('notesync.viewDoc', { label: phaseLabel, url: docUrl }),\n t('notesync.viewDashboard', { url: dashboardUrl }),\n ].join('\\n');\n}\n","import type { DialogOption } from '../ai-runner/AIRunner.js';\n\nexport interface PendingDialogInfo {\n issueIid: number;\n question: string;\n options: DialogOption[];\n phase: string;\n timestamp: string;\n}\n\n/**\n * In-memory store for pending interactive dialogs.\n *\n * SSE events are ephemeral — if the browser misses one (page refresh,\n * reconnect, slow load) the dialog is lost and the backend blocks forever.\n * This store keeps the dialog queryable via REST so the frontend can\n * recover it on load / reconnect.\n */\nconst store = new Map<number, PendingDialogInfo>();\n\nexport function setPendingDialog(info: PendingDialogInfo): void {\n store.set(info.issueIid, info);\n}\n\nexport function getPendingDialog(issueIid: number): PendingDialogInfo | undefined {\n return store.get(issueIid);\n}\n\nexport function clearPendingDialog(issueIid: number): void {\n store.delete(issueIid);\n}\n","/**\n * 从 PhaseLoopStep 提取的编排级辅助函数。\n *\n * 供 PhaseLoopStep、DefaultLifecycleHook、各 PhaseStrategy 共用,\n * 避免循环依赖。\n */\nimport type { GitOperations } from '../../git/GitOperations.js';\nimport type { PlanPersistence } from '../../persistence/PlanPersistence.js';\nimport type { AIRunner, InputRequest } from '../../ai-runner/index.js';\nimport type { BasePhase, PhaseContext } from '../../phases/BasePhase.js';\nimport type { PhaseSpec, PipelineDef } from '../../pipeline/PipelineDefinition.js';\nimport type { IssueProcessingContext, OrchestratorDeps } from '../IssueProcessingContext.js';\nimport { HookInjector } from '../../hooks/index.js';\nimport { isE2eEnabledForIssue } from '../../e2e/E2eSettings.js';\nimport { isNoteSyncEnabledForIssue } from '../../notesync/NoteSyncSettings.js';\nimport { truncateToSummary, buildNoteSyncComment } from '../../notesync/NoteSyncSettings.js';\nimport { issueProgressComment } from '../../prompts/templates.js';\nimport { setPendingDialog, clearPendingDialog } from '../PendingDialogStore.js';\nimport { logger as rootLogger } from '../../logger.js';\nimport { t } from '../../i18n/index.js';\n\nconst logger = rootLogger.child('PhaseHelpers');\n\n// ── 安全评论 ──\n\nexport async function safeComment(deps: OrchestratorDeps, issueId: number, message: string): Promise<void> {\n try {\n await deps.gongfeng.createIssueNote(issueId, message);\n } catch { /* ignore */ }\n}\n\n// ── Runner 解析 ──\n\nexport function resolveVerifyRunner(deps: OrchestratorDeps): AIRunner {\n return deps.aiRunner;\n}\n\nexport function resolveUatRunner(deps: OrchestratorDeps, issueIid: number): AIRunner {\n if (deps.e2eAiRunner && isE2eEnabledForIssue(issueIid, deps.tracker, deps.config)) {\n return deps.e2eAiRunner;\n }\n return deps.aiRunner;\n}\n\n// ── Git 提交 ──\n\nexport async function commitPlanFiles(\n ctx: PhaseContext,\n wtGit: GitOperations,\n wtGitMap: Map<string, GitOperations> | undefined,\n phaseName: string,\n displayId: number,\n): Promise<void> {\n const commitMsg = `chore(auto): ${phaseName} phase completed for issue #${displayId}`;\n\n if (ctx.workspace && ctx.workspace.repos.length > 1) {\n for (const repo of ctx.workspace.repos) {\n const repoGit = wtGitMap?.get(repo.name);\n if (!repoGit) {\n logger.warn('Missing GitOperations for repo, skipping commit', { repo: repo.name });\n continue;\n }\n const branch = repo.branchPrefix\n ? `${repo.branchPrefix}-${displayId}`\n : ctx.branchName;\n try {\n if (await repoGit.hasChanges()) {\n await repoGit.add(['.']);\n await repoGit.commit(commitMsg);\n await repoGit.push(branch);\n logger.info('Committed changes for repo', { repo: repo.name, branch });\n }\n } catch (err) {\n logger.warn('Failed to commit/push for repo', {\n repo: repo.name,\n error: (err as Error).message,\n });\n }\n }\n } else {\n if (await wtGit.hasChanges()) {\n await wtGit.add(['.']);\n await wtGit.commit(commitMsg);\n await wtGit.push(ctx.branchName);\n }\n }\n}\n\n// ── 产物同步到 Issue ──\n\nexport async function syncResultToIssue(\n phase: BasePhase,\n ctx: PhaseContext,\n displayId: number,\n phaseName: string,\n deps: OrchestratorDeps,\n issueId: number,\n wtPlan: PlanPersistence,\n): Promise<void> {\n try {\n const enabled = isNoteSyncEnabledForIssue(displayId, deps.tracker, deps.config);\n const resultFiles = phase.getResultFiles(ctx);\n\n if (!enabled || resultFiles.length === 0) {\n await safeComment(deps, issueId, issueProgressComment(phaseName, 'completed'));\n return;\n }\n\n const baseUrl = deps.config.issueNoteSync.webBaseUrl.replace(/\\/$/, '');\n const phaseLabel = t(`phase.${phaseName}`) || phaseName;\n const dashboardUrl = `${baseUrl}/?issue=${displayId}`;\n\n for (const file of resultFiles) {\n const content = wtPlan.readFile(file.filename);\n if (!content) continue;\n\n const summary = truncateToSummary(content);\n const docUrl = `${baseUrl}/doc/${displayId}/${file.filename}`;\n const comment = buildNoteSyncComment(\n phaseName, file.label || phaseLabel, docUrl, dashboardUrl, summary,\n );\n\n await safeComment(deps, issueId, comment);\n logger.info('Result synced to issue', { issueIid: displayId, file: file.filename });\n }\n } catch (err) {\n logger.warn('Failed to sync result to issue', { error: (err as Error).message });\n await safeComment(deps, issueId, issueProgressComment(phaseName, 'completed'));\n }\n}\n\n// ── 输入请求处理 ──\n\nexport function handlePlanApproval(\n displayId: number,\n phaseName: string,\n deps: OrchestratorDeps,\n): Promise<string> {\n logger.info('ACP plan-approval requested, delegating to review gate', {\n issueIid: displayId, phase: phaseName,\n });\n deps.eventBus.emitTyped('review:requested', { issueIid: displayId });\n\n return new Promise<string>((resolve) => {\n const onApproved = (payload: { data: unknown }) => {\n const data = payload.data as { issueIid?: number };\n if (data.issueIid !== displayId) return;\n cleanup();\n logger.info('ACP plan-approval approved via review gate', { issueIid: displayId });\n resolve('allow');\n };\n const onRejected = (payload: { data: unknown }) => {\n const data = payload.data as { issueIid?: number };\n if (data.issueIid !== displayId) return;\n cleanup();\n logger.info('ACP plan-approval rejected via review gate', { issueIid: displayId });\n resolve('reject');\n };\n const cleanup = () => {\n deps.eventBus.removeListener('review:approved', onApproved);\n deps.eventBus.removeListener('review:rejected', onRejected);\n };\n deps.eventBus.on('review:approved', onApproved);\n deps.eventBus.on('review:rejected', onRejected);\n });\n}\n\nexport function handleInteractiveDialog(\n displayId: number,\n phaseName: string,\n deps: OrchestratorDeps,\n request: InputRequest,\n): Promise<string> {\n logger.info('Interactive dialog forwarded to frontend', {\n issueIid: displayId, phase: phaseName,\n question: request.content.slice(0, 80),\n optionCount: request.options?.length,\n });\n\n const options = request.options ?? [];\n\n setPendingDialog({\n issueIid: displayId,\n question: request.content,\n options,\n phase: phaseName,\n timestamp: new Date().toISOString(),\n });\n\n deps.eventBus.emitTyped('agent:inputRequired', {\n issueIid: displayId,\n phase: phaseName,\n question: request.content,\n options,\n });\n\n return new Promise<string>((resolve) => {\n const cleanup = () => {\n deps.eventBus.removeListener('agent:inputResponse', onResponse);\n deps.eventBus.removeListener('agent:dialogDismissed', onDismiss);\n };\n\n const onResponse = (payload: { data: unknown }) => {\n const data = payload.data as { issueIid?: number; response?: string };\n if (data.issueIid !== displayId) return;\n cleanup();\n clearPendingDialog(displayId);\n logger.info('Interactive dialog response received from frontend', {\n issueIid: displayId, response: data.response,\n });\n resolve(data.response ?? '1');\n };\n\n const onDismiss = (payload: { data: unknown }) => {\n const data = payload.data as { issueIid?: number };\n if (data.issueIid !== displayId) return;\n cleanup();\n logger.info('Interactive dialog dismissed by user (false positive)', { issueIid: displayId });\n resolve('');\n };\n\n deps.eventBus.on('agent:inputResponse', onResponse);\n deps.eventBus.on('agent:dialogDismissed', onDismiss);\n });\n}\n\n// ── Hooks 更新 ──\n\nexport function updateHooksForPhase(\n spec: PhaseSpec,\n pipelineDef: PipelineDef,\n ctx: IssueProcessingContext,\n wtPlan: PlanPersistence,\n): void {\n const phaseArtifacts = (spec.artifacts ?? []).map(a => a.filename);\n if (phaseArtifacts.length === 0 && spec.kind !== 'ai') return;\n\n try {\n const allArtifacts = pipelineDef.phases\n .flatMap(p => p.artifacts ?? [])\n .map(a => a.filename);\n const hookInjector = new HookInjector();\n hookInjector.updateForPhase({\n workDir: wtPlan.baseDir,\n planDir: wtPlan.planDir,\n expectedArtifacts: allArtifacts.length > 0 ? allArtifacts : phaseArtifacts,\n phaseExpectedArtifacts: phaseArtifacts,\n issueIid: ctx.issue.iid,\n phaseName: spec.name,\n issueTitle: ctx.issue.title,\n issueDescription: ctx.issue.description,\n });\n } catch (err) {\n logger.warn('Failed to update hooks for phase (non-blocking)', {\n phase: spec.name,\n error: (err as Error).message,\n });\n }\n}\n\n// ── 工具函数 ──\n\nexport function findPreviousAiPhaseIndex(\n phases: readonly { kind: string }[],\n currentIdx: number,\n): number {\n for (let j = currentIdx - 1; j >= 0; j--) {\n if (phases[j].kind === 'ai') return j;\n }\n return -1;\n}\n","/**\n * 默认阶段生命周期 Hook 实现。\n *\n * 从 `runPhaseWithLifecycle` 提取的 Pre/Execute/Post 逻辑,\n * 行为与重构前完全一致。\n */\nimport { IssueState } from '../tracker/IssueState.js';\nimport { issueProgressComment } from '../prompts/templates.js';\nimport { logger as rootLogger } from '../logger.js';\nimport { t } from '../i18n/index.js';\nimport type { StreamEvent } from '../ai-runner/AIRunner.js';\nimport type { PhaseOutcome } from '../phases/PhaseOutcome.js';\nimport type { PhaseLifecycleHook, PhaseExecutionContext } from './PhaseLifecycleHook.js';\nimport type { PhaseFeedback, FeedbackResponse, PhaseError, ErrorDecision } from './FeedbackTypes.js';\nimport {\n inputRequestToFeedback,\n feedbackResponseToString,\n stringToFeedbackResponse,\n} from './FeedbackTypes.js';\nimport {\n safeComment,\n commitPlanFiles,\n syncResultToIssue,\n handlePlanApproval,\n handleInteractiveDialog,\n} from '../orchestrator/steps/PhaseHelpers.js';\n\nconst logger = rootLogger.child('DefaultLifecycleHook');\n\nexport class DefaultLifecycleHook implements PhaseLifecycleHook {\n async beforePhase(ctx: PhaseExecutionContext): Promise<void> {\n const { spec, issueCtx, deps, wtPlan } = ctx;\n const { issue } = issueCtx;\n const displayId = issue.iid;\n\n deps.tracker.updateState(displayId, spec.startState, { currentPhase: spec.name });\n deps.tracker.updatePhaseProgress(displayId, spec.name, {\n status: 'in_progress', startedAt: new Date().toISOString(),\n });\n wtPlan.updatePhaseProgress(spec.name, 'in_progress');\n await safeComment(deps, issue.id, issueProgressComment(spec.name, 'in_progress'));\n\n const phaseLabel = t(`phase.${spec.name}`) || spec.name;\n deps.eventBus.emitTyped('agent:output', {\n issueIid: displayId,\n phase: spec.name,\n event: {\n type: 'system',\n content: t('basePhase.aiStarting', { label: phaseLabel }),\n timestamp: new Date().toISOString(),\n },\n });\n }\n\n onStream(ctx: PhaseExecutionContext, event: StreamEvent): void {\n const { spec, issueCtx, deps } = ctx;\n deps.eventBus.emitTyped('agent:output', {\n issueIid: issueCtx.issue.iid,\n phase: spec.name,\n event,\n });\n }\n\n beforeExecute?: undefined;\n\n afterExecute?: undefined;\n\n async onFeedback(ctx: PhaseExecutionContext, feedback: PhaseFeedback): Promise<FeedbackResponse> {\n const { deps, displayId, spec } = ctx;\n\n if (feedback.kind === 'interactive-dialog') {\n const result = await handleInteractiveDialog(displayId, spec.name, deps, {\n type: 'interactive-dialog',\n content: feedback.question,\n options: feedback.options,\n });\n return stringToFeedbackResponse(result, feedback);\n }\n\n if (feedback.kind === 'approval-required' && feedback.scope === 'plan') {\n const useAcpGate = deps.config.ai.codebuddyAcpAutoApprove === false;\n if (useAcpGate) {\n const result = await handlePlanApproval(displayId, spec.name, deps);\n return result === 'allow' ? { action: 'approve' } : { action: 'reject' };\n }\n return { action: 'approve' };\n }\n\n return { action: 'approve' };\n }\n\n async afterPhase(ctx: PhaseExecutionContext, outcome: PhaseOutcome): Promise<void> {\n const { spec, issueCtx, deps, wtGit, wtPlan, wtGitMap, phase } = ctx;\n const { issue, phaseCtx } = issueCtx;\n const displayId = issue.iid;\n\n if (outcome.sessionId) {\n wtPlan.updatePhaseSessionId(spec.name, outcome.sessionId);\n }\n\n deps.tracker.updateState(displayId, spec.doneState, { currentPhase: spec.name });\n deps.tracker.updatePhaseProgress(displayId, spec.name, {\n status: 'completed', completedAt: new Date().toISOString(),\n });\n wtPlan.updatePhaseProgress(spec.name, 'completed');\n\n await commitPlanFiles(phaseCtx, wtGit, wtGitMap, spec.name, displayId);\n\n if (phase) {\n await syncResultToIssue(phase, phaseCtx, displayId, spec.name, deps, issue.id, wtPlan);\n }\n }\n\n async onError(ctx: PhaseExecutionContext, error: PhaseError): Promise<ErrorDecision> {\n const { spec, issueCtx, deps, wtPlan } = ctx;\n const { issue } = issueCtx;\n const displayId = issue.iid;\n\n wtPlan.updatePhaseProgress(spec.name, 'failed', error.message);\n deps.tracker.updatePhaseProgress(displayId, spec.name, { status: 'failed' });\n\n if (error.wasActiveAtTimeout) {\n deps.tracker.markFailedSoft(displayId, error.message, IssueState.PhaseRunning);\n } else {\n deps.tracker.markFailed(displayId, error.message, IssueState.PhaseRunning);\n }\n\n const shortErr = error.message.slice(0, 200);\n await safeComment(deps, issue.id, issueProgressComment(spec.name, 'failed', shortErr));\n\n return { action: 'fail', softFail: error.wasActiveAtTimeout };\n }\n}\n\n/**\n * 从 PhaseLifecycleHook 创建 PhaseCallbacks(供 BasePhase.run() 使用)。\n *\n * 将标准化的 hook 接口适配为 BasePhase 期望的旧式回调,\n * 实现了 PhaseFeedback/FeedbackResponse ↔ InputRequest/string 的双向转换。\n */\nexport function createCallbacksFromHook(\n hook: PhaseLifecycleHook,\n ctx: PhaseExecutionContext,\n): import('../phases/PhaseOutcome.js').PhaseCallbacks {\n return {\n onStreamEvent: hook.onStream\n ? (event) => hook.onStream!(ctx, event)\n : undefined,\n onInputRequired: hook.onFeedback\n ? async (request) => {\n const feedback = inputRequestToFeedback(request);\n const response = await hook.onFeedback!(ctx, feedback);\n return feedbackResponseToString(response);\n }\n : undefined,\n };\n}\n","import type { PhaseExecutionContext, PhaseLifecycleHook, PhaseStepResult } from '../../lifecycle/PhaseLifecycleHook.js';\nimport type { PhaseStrategy } from './PhaseStrategy.js';\nimport { logger as rootLogger } from '../../logger.js';\nimport { t } from '../../i18n/index.js';\n\nconst logger = rootLogger.child('GateStrategy');\n\n/**\n * Gate 阶段策略 — 处理审核门禁(如 review 阶段)。\n *\n * 两种路径:\n * 1. 标签匹配自动批准 → 标记完成并继续\n * 2. 暂停等待人工审核 → 发事件后返回 paused=true\n */\nexport class GateStrategy implements PhaseStrategy {\n readonly name = 'gate';\n\n shouldSkip(): boolean {\n return false;\n }\n\n async execute(ctx: PhaseExecutionContext, _hooks: PhaseLifecycleHook): Promise<PhaseStepResult> {\n const { spec, issueCtx, deps, wtPlan } = ctx;\n const { issue } = issueCtx;\n\n if (deps.shouldAutoApprove(issue.labels)) {\n logger.info('Auto-approving review gate (matched autoApproveLabels)', {\n iid: issue.iid,\n labels: issue.labels,\n autoApproveLabels: deps.config.review.autoApproveLabels,\n });\n\n if (spec.approvedState) {\n deps.tracker.updateState(issue.iid, spec.approvedState, { currentPhase: spec.name });\n }\n wtPlan.updatePhaseProgress(spec.name, 'completed');\n deps.tracker.updatePhaseProgress(issue.iid, spec.name, {\n status: 'completed', completedAt: new Date().toISOString(),\n });\n\n try {\n await deps.gongfeng.createIssueNote(issue.id, t('orchestrator.autoApproveComment'));\n } catch { /* ignore */ }\n\n return { paused: false };\n }\n\n deps.tracker.updateState(issue.iid, spec.startState, { currentPhase: spec.name });\n wtPlan.updatePhaseProgress(spec.name, 'in_progress');\n deps.tracker.updatePhaseProgress(issue.iid, spec.name, {\n status: 'in_progress', startedAt: new Date().toISOString(),\n });\n deps.eventBus.emitTyped('review:requested', { issueIid: issue.iid });\n logger.info('Review gate reached, pausing', { iid: issue.iid });\n\n return { paused: true };\n }\n}\n","import { IssueState } from '../../tracker/IssueState.js';\nimport { AIExecutionError } from '../../errors/index.js';\nimport { createPhase } from '../../phases/PhaseFactory.js';\nimport { isE2eEnabledForIssue } from '../../e2e/E2eSettings.js';\nimport type { PhaseOutcome } from '../../phases/PhaseOutcome.js';\nimport type { PhaseExecutionContext, PhaseLifecycleHook, PhaseStepResult } from '../../lifecycle/PhaseLifecycleHook.js';\nimport type { PhaseStrategy } from './PhaseStrategy.js';\nimport { runPhaseWithLifecycle } from '../steps/PhaseLoopStep.js';\nimport {\n resolveVerifyRunner,\n resolveUatRunner,\n commitPlanFiles,\n syncResultToIssue,\n updateHooksForPhase,\n safeComment,\n} from '../steps/PhaseHelpers.js';\nimport { issueProgressComment } from '../../prompts/templates.js';\nimport { logger as rootLogger } from '../../logger.js';\n\nconst logger = rootLogger.child('AiPhaseStrategy');\n\n/**\n * 标准 AI 阶段策略 — 处理所有 kind='ai' 的阶段。\n *\n * 覆盖:plan、build、uat(非 verify-fix 循环的 verify 也走这里)。\n * 处理异步阶段(awaitCompletion)、gate 请求(hasReleaseCapability)。\n */\nexport class AiPhaseStrategy implements PhaseStrategy {\n readonly name = 'ai';\n\n shouldSkip(ctx: PhaseExecutionContext): boolean {\n const { spec, issueCtx, deps } = ctx;\n if (spec.name === 'uat' && !isE2eEnabledForIssue(issueCtx.issue.iid, deps.tracker, deps.config)) {\n logger.info('UAT phase skipped (E2E not enabled for this issue)', { iid: issueCtx.issue.iid });\n return true;\n }\n return false;\n }\n\n async execute(ctx: PhaseExecutionContext, hooks: PhaseLifecycleHook): Promise<PhaseStepResult> {\n const { spec, issueCtx, deps, wtGit, wtPlan, wtGitMap } = ctx;\n const { issue, phaseCtx } = issueCtx;\n\n // 跳过逻辑(shouldSkip=true 时由调用方标记完成,但保险起见也在这里检查)\n if (this.shouldSkip(ctx)) {\n deps.tracker.updateState(issue.iid, spec.doneState, { currentPhase: spec.name });\n wtPlan.updatePhaseProgress(spec.name, 'completed');\n deps.tracker.updatePhaseProgress(issue.iid, spec.name, {\n status: 'completed', completedAt: new Date().toISOString(),\n });\n return { paused: false };\n }\n\n updateHooksForPhase(spec, issueCtx.pipelineDef, issueCtx, wtPlan);\n\n const runner = this.resolveRunner(ctx);\n\n if (spec.name === 'uat') {\n const runnerName = runner === deps.e2eAiRunner ? 'e2eAiRunner (CodeBuddy)' : 'mainRunner';\n logger.info('UAT phase starting', { iid: issue.iid, runner: runnerName });\n }\n\n const phase = createPhase(spec.name, runner, wtGit, wtPlan, deps.config);\n if (wtGitMap) phase.setWtGitMap(wtGitMap);\n ctx.phase = phase;\n\n const outcome = await runPhaseWithLifecycle(\n phase, phaseCtx, spec, issueCtx, deps, wtGit, wtPlan, wtGitMap, hooks,\n );\n\n // ── 异步阶段(status='running')──\n if (outcome.status === 'running') {\n return this.handleAsyncOutcome(ctx, outcome);\n }\n\n // ── AI 阶段请求 gate 暂停(如 release 检测到发布能力) ──\n if (spec.approvedState && outcome.data?.hasReleaseCapability) {\n return this.handleGateRequest(ctx);\n }\n\n return { paused: false };\n }\n\n private resolveRunner(ctx: PhaseExecutionContext) {\n const { spec, deps, displayId } = ctx;\n if (spec.name === 'verify') return resolveVerifyRunner(deps);\n if (spec.name === 'uat') return resolveUatRunner(deps, displayId);\n return deps.aiRunner;\n }\n\n private async handleAsyncOutcome(\n ctx: PhaseExecutionContext,\n outcome: PhaseOutcome,\n ): Promise<PhaseStepResult> {\n const { spec, issueCtx, deps, wtGit, wtPlan, wtGitMap } = ctx;\n const { issue, phaseCtx } = issueCtx;\n\n if (outcome.awaitCompletion) {\n logger.info('Async phase running, awaiting completion', { iid: issue.iid, phase: spec.name });\n const finalOutcome = await outcome.awaitCompletion;\n\n if (finalOutcome.sessionId) {\n wtPlan.updatePhaseSessionId(spec.name, finalOutcome.sessionId);\n }\n\n if (finalOutcome.status === 'completed') {\n deps.tracker.updateState(issue.iid, spec.doneState, { currentPhase: spec.name });\n deps.tracker.updatePhaseProgress(issue.iid, spec.name, {\n status: 'completed', completedAt: new Date().toISOString(),\n });\n wtPlan.updatePhaseProgress(spec.name, 'completed');\n await commitPlanFiles(phaseCtx, wtGit, wtGitMap, spec.name, issue.iid);\n\n const runner = this.resolveRunner(ctx);\n const phase = createPhase(spec.name, runner, wtGit, wtPlan, deps.config);\n await syncResultToIssue(phase, phaseCtx, issue.iid, spec.name, deps, issue.id, wtPlan);\n\n logger.info('Async phase completed successfully', { iid: issue.iid, phase: spec.name });\n return { paused: false };\n }\n\n // failed\n const errMsg = finalOutcome.error?.message ?? 'Unknown error';\n const shortErr = errMsg.slice(0, 200);\n const wasActive = finalOutcome.error?.wasActiveAtTimeout ?? false;\n wtPlan.updatePhaseProgress(spec.name, 'failed', errMsg);\n deps.tracker.updatePhaseProgress(issue.iid, spec.name, { status: 'failed' });\n if (wasActive) {\n deps.tracker.markFailedSoft(issue.iid, errMsg, IssueState.PhaseRunning);\n } else {\n deps.tracker.markFailed(issue.iid, errMsg, IssueState.PhaseRunning);\n }\n await safeComment(deps, issue.id, issueProgressComment(spec.name, 'failed', shortErr));\n\n throw new AIExecutionError(spec.name, `Phase ${spec.name} failed: ${shortErr}`, {\n output: finalOutcome.error?.rawOutput ?? finalOutcome.output,\n exitCode: finalOutcome.exitCode ?? 1,\n isRetryable: finalOutcome.error?.isRetryable,\n wasActiveAtTimeout: wasActive,\n });\n }\n\n // 无 awaitCompletion 的 running 阶段 → 暂停等待外部触发\n deps.tracker.updateState(issue.iid, IssueState.PhaseWaiting, { currentPhase: spec.name });\n wtPlan.updatePhaseProgress(spec.name, 'gate_waiting');\n deps.tracker.updatePhaseProgress(issue.iid, spec.name, { status: 'gate_waiting' });\n const gateEvent = spec.name === 'uat' ? 'uat:gateRequested' : 'release:gateRequested';\n deps.eventBus.emitTyped(gateEvent, { issueIid: issue.iid });\n logger.info('Async phase running (no awaitCompletion), pausing pipeline', {\n iid: issue.iid, phase: spec.name,\n });\n\n return { paused: true };\n }\n\n private handleGateRequest(ctx: PhaseExecutionContext): PhaseStepResult {\n const { spec, issueCtx, deps, wtPlan } = ctx;\n const { issue } = issueCtx;\n\n deps.tracker.updateState(issue.iid, IssueState.PhaseWaiting, { currentPhase: spec.name });\n wtPlan.updatePhaseProgress(spec.name, 'gate_waiting');\n deps.tracker.updatePhaseProgress(issue.iid, spec.name, { status: 'gate_waiting' });\n deps.eventBus.emitTyped('release:gateRequested', { issueIid: issue.iid });\n logger.info('Phase requested gate, pausing', { iid: issue.iid, phase: spec.name });\n\n return { paused: true };\n }\n}\n","import { ServiceShutdownError, AIExecutionError } from '../../errors/index.js';\nimport { isShuttingDown } from '../../shutdown/ShutdownSignal.js';\nimport { createPhase } from '../../phases/PhaseFactory.js';\nimport type { PhaseOutcome } from '../../phases/PhaseOutcome.js';\nimport type { GitOperations } from '../../git/GitOperations.js';\nimport type { PlanPersistence } from '../../persistence/PlanPersistence.js';\nimport type { PhaseExecutionContext, PhaseLifecycleHook, PhaseStepResult } from '../../lifecycle/PhaseLifecycleHook.js';\nimport type { PhaseStrategy } from './PhaseStrategy.js';\nimport type { IssueProcessingContext, OrchestratorDeps } from '../IssueProcessingContext.js';\nimport { runPhaseWithLifecycle } from '../steps/PhaseLoopStep.js';\nimport { resolveVerifyRunner, updateHooksForPhase } from '../steps/PhaseHelpers.js';\nimport { logger as rootLogger } from '../../logger.js';\n\nconst logger = rootLogger.child('VerifyFixStrategy');\n\n/**\n * Verify-Fix 循环策略。\n *\n * 多次迭代 verify → build fix → verify,直到验证通过或达到最大迭代次数。\n */\nexport class VerifyFixStrategy implements PhaseStrategy {\n readonly name = 'verify-fix';\n\n shouldSkip(): boolean {\n return false;\n }\n\n async execute(ctx: PhaseExecutionContext, hooks: PhaseLifecycleHook): Promise<PhaseStepResult> {\n const { issueCtx, deps, wtGit, wtPlan, wtGitMap } = ctx;\n const { issue, phaseCtx, pipelineDef } = issueCtx;\n const maxIterations = deps.config.verifyFixLoop.maxIterations;\n const verifySpec = ctx.spec;\n\n const verifyPhaseIdx = pipelineDef.phases.findIndex(p => p.name === verifySpec.name);\n const buildPhaseIdx = this.findPreviousAiPhaseIndex(pipelineDef.phases, verifyPhaseIdx);\n\n deps.eventBus.emitTyped('verify:loopStarted', {\n issueIid: issue.iid,\n maxIterations,\n });\n\n logger.info('Verify-fix loop started', {\n iid: issue.iid,\n maxIterations,\n buildPhaseIdx,\n });\n\n for (let iteration = 1; iteration <= maxIterations; iteration++) {\n if (isShuttingDown()) throw new ServiceShutdownError();\n\n logger.info('Verify-fix loop iteration', { iteration, maxIterations, iid: issue.iid });\n\n updateHooksForPhase(verifySpec, pipelineDef, issueCtx, wtPlan);\n\n const verifyRunner = resolveVerifyRunner(deps);\n const verifyPhase = createPhase('verify', verifyRunner, wtGit, wtPlan, deps.config);\n if (wtGitMap) verifyPhase.setWtGitMap(wtGitMap);\n\n let verifyOutcome: PhaseOutcome;\n try {\n verifyOutcome = await runPhaseWithLifecycle(\n verifyPhase, phaseCtx, verifySpec, issueCtx, deps, wtGit, wtPlan, wtGitMap, hooks,\n );\n } catch (err) {\n logger.warn('Verify phase execution failed', {\n iteration, iid: issue.iid, error: (err as Error).message,\n });\n\n deps.eventBus.emitTyped('verify:iterationComplete', {\n issueIid: issue.iid, iteration, passed: false,\n failures: ['AI runner execution failed'],\n });\n\n if (iteration === maxIterations) throw err;\n\n if (buildPhaseIdx >= 0) {\n await this.executeBuildFix(issueCtx, deps, wtGit, wtPlan, buildPhaseIdx, {\n iteration,\n verifyFailures: ['AI runner execution failed: ' + (err as Error).message],\n rawReport: '',\n }, wtGitMap, hooks);\n }\n continue;\n }\n\n const report = verifyOutcome.data?.verifyReport as import('../../verify/index.js').VerifyReportResult | undefined;\n const passed = report ? report.passed : true;\n\n deps.eventBus.emitTyped('verify:iterationComplete', {\n issueIid: issue.iid, iteration, passed,\n failures: report?.failureReasons,\n });\n\n if (passed) {\n logger.info('Verify-fix loop passed', { iteration, iid: issue.iid });\n return { paused: false };\n }\n\n logger.info('Verify failed, issues found', {\n iteration, iid: issue.iid,\n failures: report?.failureReasons,\n todolistStats: report?.todolistStats,\n });\n\n if (iteration === maxIterations) {\n deps.eventBus.emitTyped('verify:loopExhausted', {\n issueIid: issue.iid,\n totalIterations: iteration,\n failures: report?.failureReasons ?? [],\n });\n\n const failMsg = `Verify-fix loop exhausted after ${maxIterations} iterations. ` +\n `Remaining issues: ${report?.failureReasons?.join('; ') ?? 'unknown'}`;\n logger.warn(failMsg, { iid: issue.iid });\n\n throw new AIExecutionError('verify', failMsg, {\n output: report?.rawReport ?? '',\n exitCode: 0,\n });\n }\n\n if (buildPhaseIdx >= 0) {\n await this.executeBuildFix(issueCtx, deps, wtGit, wtPlan, buildPhaseIdx, {\n iteration,\n verifyFailures: report?.failureReasons ?? [],\n rawReport: report?.rawReport ?? '',\n }, wtGitMap, hooks);\n }\n }\n\n return { paused: false };\n }\n\n private async executeBuildFix(\n ctx: IssueProcessingContext,\n deps: OrchestratorDeps,\n wtGit: GitOperations,\n wtPlan: PlanPersistence,\n buildPhaseIdx: number,\n fixContext: { iteration: number; verifyFailures: string[]; rawReport: string },\n wtGitMap: Map<string, GitOperations> | undefined,\n hooks: PhaseLifecycleHook,\n ): Promise<void> {\n const { issue, phaseCtx, pipelineDef } = ctx;\n const buildSpec = pipelineDef.phases[buildPhaseIdx];\n\n logger.info('Looping back to build for fix', {\n iteration: fixContext.iteration, iid: issue.iid,\n failures: fixContext.verifyFailures,\n });\n\n phaseCtx.fixContext = fixContext;\n\n try {\n updateHooksForPhase(buildSpec, pipelineDef, ctx, wtPlan);\n\n const buildPhase = createPhase('build', deps.aiRunner, wtGit, wtPlan, deps.config);\n if (wtGitMap) buildPhase.setWtGitMap(wtGitMap);\n\n await runPhaseWithLifecycle(\n buildPhase, phaseCtx, buildSpec, ctx, deps, wtGit, wtPlan, wtGitMap, hooks,\n );\n } finally {\n delete phaseCtx.fixContext;\n }\n }\n\n private findPreviousAiPhaseIndex(\n phases: readonly { kind: string }[],\n currentIdx: number,\n ): number {\n for (let j = currentIdx - 1; j >= 0; j--) {\n if (phases[j].kind === 'ai') return j;\n }\n return -1;\n }\n}\n","import type { PhaseSpec } from '../../pipeline/PipelineDefinition.js';\nimport type { Config } from '../../config.js';\nimport type { PhaseStrategy } from './PhaseStrategy.js';\nimport { GateStrategy } from './GateStrategy.js';\nimport { AiPhaseStrategy } from './AiPhaseStrategy.js';\nimport { VerifyFixStrategy } from './VerifyFixStrategy.js';\n\nexport type { PhaseStrategy } from './PhaseStrategy.js';\nexport { GateStrategy } from './GateStrategy.js';\nexport { AiPhaseStrategy } from './AiPhaseStrategy.js';\nexport { VerifyFixStrategy } from './VerifyFixStrategy.js';\n\n// ── 策略单例 ──\n\nconst gateStrategy = new GateStrategy();\nconst aiStrategy = new AiPhaseStrategy();\nconst verifyFixStrategy = new VerifyFixStrategy();\n\n/**\n * 根据阶段规格和配置解析对应的执行策略。\n *\n * 解析优先级:\n * 1. kind='gate' → GateStrategy\n * 2. name='verify' + verifyFixLoop.enabled → VerifyFixStrategy\n * 3. 其它 kind='ai' → AiPhaseStrategy(含 uat/release 等特殊处理)\n */\nexport function resolveStrategy(spec: PhaseSpec, config: Config): PhaseStrategy {\n if (spec.kind === 'gate') {\n return gateStrategy;\n }\n\n if (spec.name === 'verify' && config.verifyFixLoop.enabled) {\n return verifyFixStrategy;\n }\n\n return aiStrategy;\n}\n","import type { GitOperations } from '../../git/GitOperations.js';\nimport type { PlanPersistence } from '../../persistence/PlanPersistence.js';\nimport type { BasePhase } from '../../phases/BasePhase.js';\nimport type { PhaseOutcome } from '../../phases/PhaseOutcome.js';\nimport type { PhaseSpec } from '../../pipeline/PipelineDefinition.js';\nimport { ServiceShutdownError, AIExecutionError, PhaseAbortedError } from '../../errors/index.js';\nimport { isShuttingDown } from '../../shutdown/ShutdownSignal.js';\nimport type { IssueProcessingContext, OrchestratorDeps, PhaseLoopResult } from '../IssueProcessingContext.js';\nimport type { PhaseLifecycleHook, PhaseExecutionContext } from '../../lifecycle/PhaseLifecycleHook.js';\nimport type { PhaseError } from '../../lifecycle/FeedbackTypes.js';\nimport { DefaultLifecycleHook, createCallbacksFromHook } from '../../lifecycle/DefaultLifecycleHook.js';\nimport { resolveStrategy } from '../strategies/index.js';\nimport { logger as rootLogger } from '../../logger.js';\nimport { t } from '../../i18n/index.js';\n\nconst logger = rootLogger.child('PhaseLoopStep');\n\n/**\n * 统一的阶段执行包装器 — 通过 PhaseLifecycleHook 驱动完整生命周期。\n *\n * beforePhase → Execute (phase.run with callbacks) → afterPhase / onError\n */\nexport async function runPhaseWithLifecycle(\n phase: BasePhase,\n phaseCtx: import('../../phases/BasePhase.js').PhaseContext,\n spec: PhaseSpec,\n ctx: IssueProcessingContext,\n deps: OrchestratorDeps,\n wtGit: GitOperations,\n wtPlan: PlanPersistence,\n wtGitMap?: Map<string, GitOperations>,\n hook?: PhaseLifecycleHook,\n): Promise<PhaseOutcome> {\n const lifecycleHook = hook ?? new DefaultLifecycleHook();\n const execCtx: PhaseExecutionContext = {\n spec,\n issueCtx: ctx,\n deps,\n wtGit,\n wtPlan,\n wtGitMap,\n phase,\n displayId: ctx.issue.iid,\n };\n\n // ── 1. beforePhase ──\n await lifecycleHook.beforePhase(execCtx);\n\n // ── 2. beforeExecute (optional) ──\n if (lifecycleHook.beforeExecute) {\n await lifecycleHook.beforeExecute(execCtx);\n }\n\n // ── 3. Execute: 从 hook 创建 PhaseCallbacks 并执行 ──\n const callbacks = createCallbacksFromHook(lifecycleHook, execCtx);\n const outcome = await phase.run(phaseCtx, callbacks);\n\n // ── 4. Session 持久化 ──\n if (outcome.sessionId) wtPlan.updatePhaseSessionId(spec.name, outcome.sessionId);\n\n // ── 5. afterExecute (optional) — 可注入自定义验证 ──\n const finalOutcome = lifecycleHook.afterExecute\n ? await lifecycleHook.afterExecute(execCtx, outcome)\n : outcome;\n\n // ── 6. 根据结果路由 ──\n if (finalOutcome.status === 'completed') {\n await lifecycleHook.afterPhase(execCtx, finalOutcome);\n return finalOutcome;\n }\n\n if (finalOutcome.status === 'running') {\n return finalOutcome;\n }\n\n // status === 'failed'\n const errMsg = finalOutcome.error?.message ?? 'Unknown error';\n const phaseError: PhaseError = {\n message: errMsg,\n isRetryable: finalOutcome.error?.isRetryable ?? true,\n rawOutput: finalOutcome.error?.rawOutput ?? finalOutcome.output,\n wasActiveAtTimeout: finalOutcome.error?.wasActiveAtTimeout ?? false,\n };\n\n await lifecycleHook.onError(execCtx, phaseError);\n\n const shortErr = errMsg.slice(0, 200);\n throw new AIExecutionError(spec.name, `Phase ${spec.name} failed: ${shortErr}`, {\n output: finalOutcome.error?.rawOutput ?? finalOutcome.output,\n exitCode: finalOutcome.exitCode ?? 1,\n isRetryable: finalOutcome.error?.isRetryable,\n wasActiveAtTimeout: finalOutcome.error?.wasActiveAtTimeout ?? false,\n });\n}\n\n/**\n * 执行流水线阶段循环:\n * - 确定恢复阶段索引\n * - 逐个执行阶段\n * - 处理 gate 阶段(自动批准或等待审核)\n * - 执行 AI 阶段(通过 runPhaseWithLifecycle)\n * - 按需启动预览服务器\n * - verify 阶段支持 verify-fix loop(验证失败自动回退 build 修复)\n *\n * 如果到达 gate 阶段且不自动批准,该函数 return 且 `paused` 为 true。\n */\nexport async function executePhaseLoop(\n ctx: IssueProcessingContext,\n deps: OrchestratorDeps,\n wtGit: GitOperations,\n wtPlan: PlanPersistence,\n wtGitMap?: Map<string, GitOperations>,\n): Promise<PhaseLoopResult & { paused: boolean }> {\n const { issue, pipelineDef, lifecycleManager, record, isRetry, phaseCtx } = ctx;\n\n const startIdx = lifecycleManager.determineResumePhaseIndex(\n record.state,\n isRetry ? record.failedAtState : undefined,\n record.currentPhase,\n );\n\n deps.emitProgress(\n issue.iid,\n 'phase_start',\n t('orchestrator.phaseStartProgress', {\n phase: pipelineDef.phases[startIdx]?.name ?? 'start',\n }),\n );\n\n const needsDeployment = deps.shouldDeployServers(issue.iid);\n let serversStarted = false;\n\n if (needsDeployment && startIdx > 0) {\n const skippedDeployPhase = pipelineDef.phases\n .slice(0, startIdx)\n .some(p => p.deploysPreview);\n\n if (skippedDeployPhase && !phaseCtx.ports) {\n const existingPorts = deps.getPortsForIssue(issue.iid);\n if (existingPorts && deps.isPreviewRunning(issue.iid)) {\n logger.info('Restored preview ports from allocator', { iid: issue.iid, ...existingPorts });\n phaseCtx.ports = existingPorts;\n ctx.wtCtx.ports = existingPorts;\n serversStarted = true;\n } else {\n if (existingPorts) {\n logger.info('Ports allocated but servers not running, restarting', { iid: issue.iid });\n } else {\n logger.info('Restarting preview servers for resumed pipeline', { iid: issue.iid });\n }\n const ports = await deps.startPreviewServers(ctx.wtCtx, issue);\n if (ports) {\n phaseCtx.ports = ports;\n ctx.wtCtx.ports = ports;\n serversStarted = true;\n }\n }\n }\n }\n\n // 自愈:恢复执行时,确保所有前置阶段的 progress 已标记为 completed。\n if (startIdx > 0) {\n healStaleProgress(ctx, deps, wtPlan, startIdx);\n }\n\n // ── 策略调度循环 ──\n const hooks = new DefaultLifecycleHook();\n\n for (let i = startIdx; i < pipelineDef.phases.length; i++) {\n if (isShuttingDown()) throw new ServiceShutdownError();\n\n const spec = pipelineDef.phases[i];\n\n const pendingAction = deps.consumePendingAction?.(issue.iid);\n if (pendingAction) throw new PhaseAbortedError(spec.name, pendingAction);\n\n const strategy = resolveStrategy(spec, deps.config);\n\n const execCtx: PhaseExecutionContext = {\n spec,\n issueCtx: ctx,\n deps,\n wtGit,\n wtPlan,\n wtGitMap,\n displayId: issue.iid,\n };\n\n // 跳过检查\n if (strategy.shouldSkip(execCtx)) {\n deps.tracker.updateState(issue.iid, spec.doneState, { currentPhase: spec.name });\n wtPlan.updatePhaseProgress(spec.name, 'completed');\n deps.tracker.updatePhaseProgress(issue.iid, spec.name, {\n status: 'completed', completedAt: new Date().toISOString(),\n });\n continue;\n }\n\n // 策略执行\n const result = await strategy.execute(execCtx, hooks);\n\n if (result.paused) {\n return { serversStarted: serversStarted || !!result.serversStarted, paused: true };\n }\n\n if (result.serversStarted) {\n serversStarted = true;\n }\n\n // 按需启动预览服务器\n if (needsDeployment && !serversStarted && lifecycleManager.shouldDeployPreview(spec.name)) {\n const ports = await deps.startPreviewServers(ctx.wtCtx, issue);\n if (ports) {\n phaseCtx.ports = ports;\n ctx.wtCtx.ports = ports;\n serversStarted = true;\n }\n }\n }\n\n return { serversStarted, paused: false };\n}\n\n// ── 内部辅助函数 ──\n\n/**\n * 自愈:恢复执行时,确保所有前置阶段的 progress 已标记为 completed。\n */\nfunction healStaleProgress(\n ctx: IssueProcessingContext,\n deps: OrchestratorDeps,\n wtPlan: PlanPersistence,\n startIdx: number,\n): void {\n const { issue, pipelineDef, record } = ctx;\n\n const currentProgress = wtPlan.readProgress();\n if (currentProgress) {\n let patched = false;\n for (let i = 0; i < startIdx; i++) {\n const prevSpec = pipelineDef.phases[i];\n const pp = currentProgress.phases[prevSpec.name];\n if (pp && pp.status !== 'completed') {\n logger.warn('Fixing stale phase progress', {\n iid: issue.iid, phase: prevSpec.name, was: pp.status, now: 'completed',\n });\n pp.status = 'completed';\n if (!pp.completedAt) {\n pp.completedAt = new Date().toISOString();\n }\n patched = true;\n }\n }\n if (patched) {\n wtPlan.writeProgress(currentProgress);\n }\n }\n\n if (record.phaseProgress) {\n for (let i = 0; i < startIdx; i++) {\n const prevSpec = pipelineDef.phases[i];\n const tp = record.phaseProgress[prevSpec.name];\n if (tp && tp.status !== 'completed') {\n deps.tracker.updatePhaseProgress(issue.iid, prevSpec.name, {\n status: 'completed',\n completedAt: tp.completedAt ?? new Date().toISOString(),\n });\n }\n }\n }\n}\n\n","import { IssueState } from '../../tracker/IssueState.js';\nimport { isE2eEnabledForIssue } from '../../e2e/E2eSettings.js';\nimport type { GitOperations } from '../../git/GitOperations.js';\nimport { metrics } from '../../metrics/MetricsCollector.js';\n\nimport type { IssueProcessingContext, OrchestratorDeps, PhaseLoopResult } from '../IssueProcessingContext.js';\nimport { logger as rootLogger } from '../../logger.js';\nimport { t } from '../../i18n/index.js';\n\nconst logger = rootLogger.child('CompletionStep');\n\nexport async function executeCompletion(\n ctx: IssueProcessingContext,\n deps: OrchestratorDeps,\n phaseResult: PhaseLoopResult,\n _wtGitMap?: Map<string, GitOperations>,\n): Promise<void> {\n const { issue, branchName, wtCtx } = ctx;\n\n deps.emitProgress(issue.iid, 'create_mr', t('orchestrator.createMrProgress'));\n const previewUrl = phaseResult.serversStarted ? deps.buildPreviewUrl(issue.iid) : null;\n\n const mrResult = await deps.tryCreateMergeRequest(issue, branchName, wtCtx.workDir, previewUrl);\n const mrUrl = mrResult?.url ?? null;\n\n const stateExtra: Record<string, unknown> = {};\n if (mrUrl) stateExtra.mrUrl = mrUrl;\n deps.tracker.updateState(\n issue.iid,\n IssueState.Completed,\n Object.keys(stateExtra).length > 0 ? stateExtra : undefined,\n );\n metrics.incCounter('iaf_issues_succeeded_total', { pipeline: ctx.pipelineDef.mode });\n\n try {\n await deps.gongfeng.updateIssueLabels(issue.id, [\n ...issue.labels.filter(l => !l.startsWith('auto-finish:') && l !== 'auto-finish'),\n 'auto-finish:done',\n ]);\n } catch { /* ignore */ }\n\n if (isE2eEnabledForIssue(issue.iid, deps.tracker, deps.config)) {\n deps.emitProgress(issue.iid, 'screenshots', t('orchestrator.uploadScreenshotsProgress'));\n try {\n await deps.screenshotPublisher.publish({\n workDir: wtCtx.workDir,\n issueIid: issue.iid,\n issueId: issue.id,\n mrIid: undefined,\n });\n } catch (err) {\n logger.warn('Failed to publish E2E screenshots', {\n iid: issue.iid,\n error: (err as Error).message,\n });\n }\n }\n\n const mrSection = mrUrl\n ? t('orchestrator.mrSection', { mrUrl })\n : t('orchestrator.mrFailSection');\n const previewSection = previewUrl ? `\\n\\ud83c\\udf10 Preview: ${previewUrl}` : '';\n try {\n await deps.gongfeng.createIssueNote(\n issue.id,\n t('orchestrator.completedComment', { branch: branchName, mrSection, previewSection }),\n );\n } catch { /* ignore */ }\n\n if (deps.claimer) {\n await deps.claimer.releaseClaim(issue.id, issue.iid, 'completed');\n }\n\n if (phaseResult.serversStarted && deps.config.preview.keepAfterComplete) {\n logger.info('Preview servers kept running after completion', { iid: issue.iid });\n } else {\n deps.stopPreviewServers(issue.iid);\n await deps.mainGitMutex.runExclusive(async () => {\n if (wtCtx.workspace) {\n await deps.workspaceManager.cleanupWorkspace(wtCtx.workspace);\n logger.info('Workspace cleaned up', { dir: wtCtx.workspace.workspaceRoot });\n } else {\n try {\n await deps.mainGit.worktreeRemove(wtCtx.gitRootDir, true);\n logger.info('Worktree cleaned up', { dir: wtCtx.gitRootDir });\n } catch (err) {\n logger.warn('Failed to cleanup worktree', {\n dir: wtCtx.gitRootDir,\n error: (err as Error).message,\n });\n }\n }\n });\n }\n\n logger.info('Issue processing completed', { iid: issue.iid });\n}\n","import { IssueState } from '../../tracker/IssueState.js';\nimport type { GongfengIssue } from '../../clients/GongfengClient.js';\nimport type { WorktreeContext } from '../../git/WorktreeContext.js';\nimport { metrics } from '../../metrics/MetricsCollector.js';\nimport type { OrchestratorDeps } from '../IssueProcessingContext.js';\nimport { AIExecutionError } from '../../errors/index.js';\nimport { logger as rootLogger } from '../../logger.js';\nimport { t } from '../../i18n/index.js';\n\nconst logger = rootLogger.child('FailureHandler');\n\nexport async function handleFailure(\n err: unknown,\n issue: GongfengIssue,\n wtCtx: WorktreeContext,\n deps: OrchestratorDeps,\n): Promise<void> {\n const errorMsg = (err as Error).message;\n const isRetryable = err instanceof AIExecutionError ? err.isRetryable : true;\n const wasActiveAtTimeout = err instanceof AIExecutionError && err.wasActiveAtTimeout;\n logger.error('Issue processing failed', { iid: issue.iid, error: errorMsg, isRetryable, wasActiveAtTimeout });\n metrics.incCounter('iaf_issues_failed_total');\n\n const currentRecord = deps.tracker.get(issue.iid);\n const failedAtState = currentRecord?.state || IssueState.Pending;\n const wasReset = failedAtState === IssueState.Pending && currentRecord?.attempts === 0;\n\n if (failedAtState !== IssueState.Failed && !wasReset) {\n if (wasActiveAtTimeout) {\n deps.tracker.markFailedSoft(issue.iid, errorMsg.slice(0, 500), failedAtState);\n } else {\n deps.tracker.markFailed(issue.iid, errorMsg.slice(0, 500), failedAtState, isRetryable);\n }\n }\n\n if (wasReset) {\n logger.info('Issue was reset during processing, skipping failure marking', { iid: issue.iid });\n throw err;\n }\n\n // 中止操作已在 catch 块中将状态设为 Paused,此处跳过失败处理(含 preview 停止)\n if (failedAtState === IssueState.Paused) {\n logger.info('Issue was paused during processing, skipping failure handling', { iid: issue.iid });\n throw err;\n }\n\n try {\n await deps.gongfeng.updateIssueLabels(issue.id, [\n ...issue.labels.filter(l => !l.startsWith('auto-finish:') && l !== 'auto-finish'),\n 'auto-finish', 'auto-finish:failed',\n ]);\n } catch { /* ignore */ }\n\n try {\n await deps.gongfeng.createIssueNote(\n issue.id,\n t('orchestrator.failedComment', { error: errorMsg }),\n );\n } catch { /* ignore */ }\n\n if (deps.claimer) {\n try {\n await deps.claimer.releaseClaim(issue.id, issue.iid, 'failed');\n } catch (releaseErr) {\n logger.warn('Failed to release lock on failure', {\n iid: issue.iid,\n error: (releaseErr as Error).message,\n });\n }\n }\n\n deps.stopPreviewServers(issue.iid);\n\n const preservedDirs = wtCtx.workspace\n ? [wtCtx.workspace.primary.gitRootDir, ...wtCtx.workspace.associates.map(a => a.gitRootDir)]\n : [wtCtx.gitRootDir];\n logger.info('Worktree(s) preserved for debugging', {\n primary: wtCtx.gitRootDir,\n all: preservedDirs,\n });\n throw err;\n}\n","import { randomUUID } from 'node:crypto';\nimport { logger as rootLogger } from '../logger.js';\nimport type { AIRunner, RunResult, StreamEvent } from '../ai-runner/AIRunner.js';\nimport { createAIRunner, type AIConfig } from '../ai-runner/index.js';\nimport type { BrainstormAgentConfig, Config } from '../config.js';\nimport {\n buildGeneratePrompt,\n buildReviewPrompt,\n buildRefinePrompt,\n} from '../prompts/brainstorm-templates.js';\n\nconst logger = rootLogger.child('Brainstorm');\n\nexport interface BrainstormRound {\n round: number;\n questions: string;\n refinedSdd: string;\n}\n\nexport type BrainstormStatus =\n | 'idle'\n | 'generating'\n | 'reviewing'\n | 'refining'\n | 'done'\n | 'error';\n\nexport interface BrainstormSession {\n id: string;\n transcript: string;\n currentSdd: string;\n rounds: BrainstormRound[];\n status: BrainstormStatus;\n error?: string;\n generatorSessionId?: string;\n createdAt: string;\n}\n\nexport interface BrainstormStreamEvent {\n type: 'sdd:chunk' | 'sdd:complete' | 'review:chunk' | 'review:complete'\n | 'round:start' | 'round:complete' | 'error';\n data: unknown;\n round?: number;\n}\n\nfunction agentConfigToAIConfig(\n agentCfg: BrainstormAgentConfig,\n timeoutMs: number,\n): AIConfig {\n return {\n mode: agentCfg.mode,\n binary: agentCfg.binary,\n phaseTimeoutMs: timeoutMs,\n nvmNodeVersion: agentCfg.nvmNodeVersion,\n model: agentCfg.model,\n };\n}\n\nexport class BrainstormService {\n private sessions = new Map<string, BrainstormSession>();\n private generatorRunner: AIRunner;\n private reviewerRunner: AIRunner;\n private config: Config['brainstorm'];\n private workDir: string;\n\n constructor(config: Config) {\n this.config = config.brainstorm;\n this.workDir = config.project.workDir;\n this.generatorRunner = createAIRunner(\n agentConfigToAIConfig(this.config.generator, this.config.timeoutMs),\n );\n this.reviewerRunner = createAIRunner(\n agentConfigToAIConfig(this.config.reviewer, this.config.timeoutMs),\n );\n }\n\n createSession(transcript: string): BrainstormSession {\n const session: BrainstormSession = {\n id: randomUUID(),\n transcript,\n currentSdd: '',\n rounds: [],\n status: 'idle',\n createdAt: new Date().toISOString(),\n };\n this.sessions.set(session.id, session);\n logger.info('Created brainstorm session', { sessionId: session.id });\n return session;\n }\n\n getSession(id: string): BrainstormSession | undefined {\n return this.sessions.get(id);\n }\n\n async generate(\n sessionId: string,\n onEvent?: (event: BrainstormStreamEvent) => void,\n ): Promise<RunResult> {\n const session = this.requireSession(sessionId);\n session.status = 'generating';\n logger.info('Generating SDD', { sessionId });\n\n const prompt = buildGeneratePrompt(session.transcript);\n const result = await this.generatorRunner.run({\n prompt,\n workDir: this.workDir,\n timeoutMs: this.config.timeoutMs,\n onStreamEvent: (evt: StreamEvent) => {\n onEvent?.({ type: 'sdd:chunk', data: evt });\n },\n });\n\n if (result.success) {\n session.currentSdd = result.output;\n session.generatorSessionId = result.sessionId;\n session.status = 'idle';\n onEvent?.({ type: 'sdd:complete', data: { sdd: result.output } });\n } else {\n session.status = 'error';\n session.error = result.output;\n onEvent?.({ type: 'error', data: { message: result.output } });\n }\n\n return result;\n }\n\n async review(\n sessionId: string,\n onEvent?: (event: BrainstormStreamEvent) => void,\n ): Promise<RunResult> {\n const session = this.requireSession(sessionId);\n const roundNum = session.rounds.length + 1;\n session.status = 'reviewing';\n logger.info('Reviewing SDD', { sessionId, round: roundNum });\n onEvent?.({ type: 'round:start', data: { round: roundNum, phase: 'review' }, round: roundNum });\n\n const prompt = buildReviewPrompt(session.currentSdd, roundNum);\n const result = await this.reviewerRunner.run({\n prompt,\n workDir: this.workDir,\n timeoutMs: this.config.timeoutMs,\n onStreamEvent: (evt: StreamEvent) => {\n onEvent?.({ type: 'review:chunk', data: evt, round: roundNum });\n },\n });\n\n if (result.success) {\n session.rounds.push({\n round: roundNum,\n questions: result.output,\n refinedSdd: '',\n });\n session.status = 'idle';\n onEvent?.({ type: 'review:complete', data: { round: roundNum, questions: result.output }, round: roundNum });\n } else {\n session.status = 'error';\n session.error = result.output;\n onEvent?.({ type: 'error', data: { message: result.output, round: roundNum }, round: roundNum });\n }\n\n return result;\n }\n\n async refine(\n sessionId: string,\n onEvent?: (event: BrainstormStreamEvent) => void,\n ): Promise<RunResult> {\n const session = this.requireSession(sessionId);\n const currentRound = session.rounds[session.rounds.length - 1];\n if (!currentRound) {\n throw new Error('No review round to refine from');\n }\n\n session.status = 'refining';\n logger.info('Refining SDD', { sessionId, round: currentRound.round });\n\n const prompt = buildRefinePrompt(currentRound.questions);\n const result = await this.generatorRunner.run({\n prompt,\n workDir: this.workDir,\n timeoutMs: this.config.timeoutMs,\n sessionId: session.generatorSessionId,\n continueSession: !!session.generatorSessionId,\n onStreamEvent: (evt: StreamEvent) => {\n onEvent?.({ type: 'sdd:chunk', data: evt, round: currentRound.round });\n },\n });\n\n if (result.success) {\n currentRound.refinedSdd = result.output;\n session.currentSdd = result.output;\n session.generatorSessionId = result.sessionId ?? session.generatorSessionId;\n session.status = 'idle';\n onEvent?.({\n type: 'round:complete',\n data: { round: currentRound.round, sdd: result.output },\n round: currentRound.round,\n });\n } else {\n session.status = 'error';\n session.error = result.output;\n onEvent?.({ type: 'error', data: { message: result.output, round: currentRound.round }, round: currentRound.round });\n }\n\n return result;\n }\n\n async autoRefine(\n sessionId: string,\n rounds?: number,\n onEvent?: (event: BrainstormStreamEvent) => void,\n ): Promise<void> {\n const maxRounds = Math.min(rounds ?? this.config.maxRefinementRounds, this.config.maxRefinementRounds);\n const session = this.requireSession(sessionId);\n\n if (!session.currentSdd) {\n await this.generate(sessionId, onEvent);\n if (session.status === 'error') return;\n }\n\n for (let i = 0; i < maxRounds; i++) {\n const reviewResult = await this.review(sessionId, onEvent);\n if (!reviewResult.success) break;\n\n const refineResult = await this.refine(sessionId, onEvent);\n if (!refineResult.success) break;\n }\n\n if (session.status !== 'error') {\n session.status = 'done';\n }\n }\n\n private requireSession(id: string): BrainstormSession {\n const session = this.sessions.get(id);\n if (!session) {\n throw new Error(`Brainstorm session not found: ${id}`);\n }\n return session;\n }\n}\n","export function buildGeneratePrompt(transcript: string): string {\n return `你是一个资深软件架构师。下面是用户通过语音倾倒的一段关于软件需求的想法,内容可能不连贯、有重复、夹杂语气词——这是正常的。\n\n**核心原则——第一性原理思考:**\n- 不要假设用户非常清楚自己想要什么以及该怎么得到。用户往往只有模糊的意图,你的工作是从原始需求和底层问题出发,帮他厘清真正的目标。\n- 如果用户的动机和目标不清晰,在 SDD 中明确标注 [待澄清],说明为什么这里需要进一步讨论,并给出你的理解和建议。\n- 如果目标清晰但用户描述的路径不是最优解,指出来,并建议更好的方案。用 [更优路径] 标注这类建议。\n- 回到问题的本质:先问\"用户真正要解决的问题是什么\",再想\"最简单有效的方案是什么\",避免过度设计。\n\n请你:\n1. 首先使用 Read、Grep、Glob 等工具浏览项目代码库,了解现有架构、技术栈和代码风格\n2. 分析用户想法的底层动机——他要解决什么问题?为什么要解决?现有方案为什么不够?\n3. 基于对代码库的理解和用户的真实需求,生成一份结构化的软件设计文档 (SDD)\n\nSDD 输出要求:\n- 使用 Markdown 格式\n- 包含以下章节:概述、目标与范围、技术方案(含架构设计、数据模型、接口设计)、实施计划、风险与约束\n- 在\"概述\"章节中,先用 2-3 句话阐明你理解的用户核心诉求和底层动机,再展开方案\n- 结合项目现有代码结构给出具体的文件路径和模块建议\n- 如果用户的想法中有模糊或矛盾的地方,先做合理推断并标注 [推断]\n- 如果发现更短的实现路径或更简洁的方案,用 [更优路径] 标注并说明理由\n\n用户的想法原文:\n---\n${transcript}\n---\n\n请直接输出完整的 SDD 文档内容(纯 Markdown 文本),不要输出任何多余解释。`;\n}\n\nexport function buildReviewPrompt(sdd: string, round: number): string {\n return `你是一个严谨的技术评审专家。请你仔细审查以下软件设计文档 (SDD)。\n\n请你:\n1. 使用 Read、Grep、Glob 等工具浏览项目代码库,验证 SDD 中提到的模块、路径、接口是否与现有代码一致\n2. 用第一性原理审视:需求本身是否合理?目标是否清晰?是否存在更简单直接的实现路径被忽略了?\n3. 站在实际实施者的角度,找出文档中**未说清楚、含糊不清、缺失、或可能导致实施困难**的地方\n4. 列出恰好 20 个问题,按严重程度排序(最重要的在前)\n\n这是第 ${round} 轮审查${round > 1 ? ',请关注比之前更细粒度的问题,特别是边界条件、错误处理、性能、安全等方面' : ''}。\n\nSDD 文档:\n---\n${sdd}\n---\n\n输出格式要求:\n每个问题用编号列出,格式为:\n1. [类别] 问题描述\n\n类别包括:[缺失]、[模糊]、[矛盾]、[风险]、[建议]、[动机](需求动机或目标本身需要质疑时)、[过度设计](存在更简单路径时)\n\n请直接输出 20 个问题,不要输出多余解释。`;\n}\n\nexport function buildRefinePrompt(questions: string): string {\n return `一位技术评审专家审查了你之前生成的 SDD,发现了以下问题:\n\n${questions}\n\n请你:\n1. 逐一回应每个问题,在 SDD 中修复或补充对应内容\n2. 如果某个问题需要查看代码来回答,请使用 Read、Grep、Glob 等工具查看项目代码后再作答\n3. 对无法确定的问题,给出多种方案并标注推荐方案\n\n请输出修复后的完整 SDD 文档(纯 Markdown 文本),不要输出对比说明,直接给出最新版本。`;\n}\n"],"mappings":"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","names":["logger","logger","logger","logger","path","IssueState","logger","fs","path","logger","path","fs","path","path","path","fs","path","logger","path","fs","fs","path","logger","fs","path","fs","logger","path","fs","logger","fs","path","path","fs","execFile","promisify","fs","path","path","fs","logger","fs","path","logger","DEFAULT_OPTIONS","path","fs","fs","path","logger","fs","path","logger","logger","logger","logger","logger","logger","logger","logger","logger","logger","execFileAsync","promisify","execFile","logger","path","fs","logger"]}