import { HELP_ESCALATION_STATUS, createHelpEscalationService, deliverHelpEscalationResult, parseHelpEscalationAgentResult, resolveCursorHelpAgentBin, resolveCursorHelpWorkspace, runCursorHelpAgent, } from './help-escalation.mjs'; import { runHelpPageDeliveryRemediationScript, shouldAutoRemediateHelpViaGoose, } from './help-page-delivery-remediation.mjs'; function envFlag(value, fallback = false) { const raw = String(value ?? '').trim().toLowerCase(); if (!raw) return fallback; return ['1', 'true', 'yes', 'on'].includes(raw); } export function isCursorHelpWorkerEnabled(env = process.env) { return envFlag(env.MEMIND_CURSOR_HELP_WORKER_ENABLED, false); } export async function processOneHelpEscalation({ helpEscalationService, scheduleService = null, sendWechatTextToUser = null, logger = console, env = process.env, workerId = 'cursor-help-worker', } = {}) { const escalation = await helpEscalationService.claimNext(workerId); if (!escalation) return null; const workspace = resolveCursorHelpWorkspace(env, helpEscalationService.memindRoot); const agentBin = resolveCursorHelpAgentBin(env); const prompt = helpEscalationService.buildPrompt(escalation); try { const { stdout, stderr } = await runCursorHelpAgent({ prompt, workspace, agentBin, env, logger, }); const parsed = parseHelpEscalationAgentResult(stdout); let resultText = parsed.userMessage; let agentOutput = stdout; if ( parsed.status === HELP_ESCALATION_STATUS.SUCCEEDED && shouldAutoRemediateHelpViaGoose(escalation, env) ) { try { const remediated = await runHelpPageDeliveryRemediationScript({ escalation, env, logger, viaGoose: true, }); if (remediated?.userMessage) { resultText = remediated.userMessage; agentOutput = `${stdout}\n\n--- auto goose remediation ---\n${JSON.stringify(remediated)}`; } } catch (remediationError) { logger.warn?.( '[cursor-help] auto goose remediation failed:', remediationError instanceof Error ? remediationError.message : remediationError, ); } } const completed = await helpEscalationService.complete(escalation.id, { status: parsed.status, resultText, agentOutput, errorMessage: parsed.status === HELP_ESCALATION_STATUS.FAILED ? stderr || parsed.userMessage : null, }); await deliverHelpEscalationResult({ escalation: completed, scheduleService, sendWechatTextToUser, logger, }); return completed; } catch (error) { const message = error instanceof Error ? error.message : String(error); const completed = await helpEscalationService.complete(escalation.id, { status: HELP_ESCALATION_STATUS.FAILED, resultText: '工程师处理失败,请稍后重试或联系平台管理员。', agentOutput: error?.stdout ?? null, errorMessage: message, }); await deliverHelpEscalationResult({ escalation: completed, scheduleService, sendWechatTextToUser, logger, }); return completed; } } export function startCursorHelpWorker({ pool, scheduleService = null, sendWechatTextToUser = null, logger = console, env = process.env, pollMs = Number(env.MEMIND_CURSOR_HELP_POLL_MS ?? 2000), runOnStart = true, } = {}) { const helpEscalationService = createHelpEscalationService({ pool, logger, env }); if (!helpEscalationService.enabled || !isCursorHelpWorkerEnabled(env)) { return { stop() {}, helpEscalationService }; } let stopped = false; let running = false; let timer = null; const tick = async () => { if (stopped || running) return; running = true; try { await processOneHelpEscalation({ helpEscalationService, scheduleService, sendWechatTextToUser, logger, env, }); } catch (error) { logger.error?.('[cursor-help] worker tick failed:', error); } finally { running = false; } }; timer = setInterval(() => { void tick(); }, pollMs); timer.unref?.(); if (runOnStart) { void tick(); } logger.log?.('[cursor-help] worker enabled'); return { helpEscalationService, stop() { stopped = true; if (timer) clearInterval(timer); }, async processOnce() { return processOneHelpEscalation({ helpEscalationService, scheduleService, sendWechatTextToUser, logger, env, }); }, }; }