test(cursor): add executor routing and help remediation scenarios
Memind CI / Test, build, and release guards (push) Successful in 10m3s
Memind CI / Test, build, and release guards (push) Successful in 10m3s
Add dry-run, e2e, and poem-page remediation scripts for cursor executor and help escalation verification. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
#!/usr/bin/env node
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { setTimeout as sleep } from 'node:timers/promises';
|
||||
import { createDbPool, migrateSchema } from '../db.mjs';
|
||||
import {
|
||||
HELP_ESCALATION_STATUS,
|
||||
createHelpEscalationService,
|
||||
isHelpEscalationIntent,
|
||||
} from '../help-escalation.mjs';
|
||||
import { processOneHelpEscalation } from '../cursor-help-worker.mjs';
|
||||
|
||||
const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||
|
||||
function loadEnvFile(filePath) {
|
||||
if (!fs.existsSync(filePath)) return;
|
||||
for (const line of fs.readFileSync(filePath, 'utf8').split('\n')) {
|
||||
const trimmed = line.trim();
|
||||
if (!trimmed || trimmed.startsWith('#')) continue;
|
||||
const eq = trimmed.indexOf('=');
|
||||
if (eq < 0) continue;
|
||||
const key = trimmed.slice(0, eq).trim();
|
||||
const value = trimmed.slice(eq + 1).trim();
|
||||
if (!process.env[key]) process.env[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
loadEnvFile(path.join(root, '.env'));
|
||||
loadEnvFile(path.join(root, '.env.local'));
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const enqueueOnly = args.includes('--enqueue-only');
|
||||
const processLocally = args.includes('--process-locally');
|
||||
const userIdArg = args.find((item) => item.startsWith('--user-id='))?.slice('--user-id='.length)?.trim() ?? '';
|
||||
const waitMs = Number(
|
||||
args.find((item) => item.startsWith('--wait-ms='))?.slice('--wait-ms='.length)
|
||||
?? process.env.MEMIND_CURSOR_HELP_E2E_WAIT_MS
|
||||
?? 10 * 60 * 1000,
|
||||
);
|
||||
|
||||
const pool = createDbPool();
|
||||
|
||||
async function waitForEscalation(helpEscalationService, escalationId) {
|
||||
const deadline = Date.now() + waitMs;
|
||||
while (Date.now() < deadline) {
|
||||
const current = await helpEscalationService.getById(escalationId);
|
||||
if (
|
||||
current?.status === HELP_ESCALATION_STATUS.SUCCEEDED
|
||||
|| current?.status === HELP_ESCALATION_STATUS.FAILED
|
||||
) {
|
||||
return current;
|
||||
}
|
||||
console.log('waiting for worker...', {
|
||||
id: escalationId,
|
||||
status: current?.status ?? 'missing',
|
||||
});
|
||||
await sleep(2000);
|
||||
}
|
||||
throw new Error(`Timed out after ${waitMs}ms waiting for escalation ${escalationId}`);
|
||||
}
|
||||
|
||||
try {
|
||||
await migrateSchema(pool);
|
||||
|
||||
const helpEscalationService = createHelpEscalationService({ pool });
|
||||
if (!helpEscalationService.enabled) {
|
||||
console.error('MEMIND_CURSOR_HELP_ENABLED is not enabled');
|
||||
process.exitCode = 1;
|
||||
} else {
|
||||
const sampleText = 'help 本机端到端测试:请检查 Portal /api/status 是否正常,并回复一行 JSON 结果。';
|
||||
console.log('help intent:', isHelpEscalationIntent(sampleText));
|
||||
|
||||
let userId = userIdArg;
|
||||
if (!userId) {
|
||||
const [rows] = await pool.query('SELECT id, username FROM h5_users ORDER BY created_at ASC LIMIT 1');
|
||||
userId = rows[0]?.id;
|
||||
}
|
||||
if (!userId) {
|
||||
console.error('No h5_users row found for e2e test');
|
||||
process.exitCode = 1;
|
||||
} else {
|
||||
const escalation = await helpEscalationService.enqueue({
|
||||
userId,
|
||||
channel: 'h5',
|
||||
userText: sampleText,
|
||||
context: {
|
||||
origin: 'e2e-test',
|
||||
requestId: `help-e2e-${Date.now()}`,
|
||||
},
|
||||
});
|
||||
|
||||
console.log('enqueued:', {
|
||||
id: escalation.id,
|
||||
userId: escalation.userId,
|
||||
status: escalation.status,
|
||||
});
|
||||
|
||||
if (!enqueueOnly) {
|
||||
let completed = null;
|
||||
if (processLocally) {
|
||||
console.log('processing locally with agent CLI (portal worker should be disabled)...');
|
||||
completed = await processOneHelpEscalation({
|
||||
helpEscalationService,
|
||||
logger: console,
|
||||
});
|
||||
} else {
|
||||
console.log('waiting for portal/standalone cursor-help worker...');
|
||||
completed = await waitForEscalation(helpEscalationService, escalation.id);
|
||||
}
|
||||
|
||||
console.log('completed:', {
|
||||
id: completed?.id ?? null,
|
||||
status: completed?.status ?? null,
|
||||
resultText: completed?.resultText ?? null,
|
||||
errorMessage: completed?.errorMessage ?? null,
|
||||
});
|
||||
|
||||
if (!completed || completed.status !== HELP_ESCALATION_STATUS.SUCCEEDED) {
|
||||
process.exitCode = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
await pool.end();
|
||||
}
|
||||
Reference in New Issue
Block a user