feat(memory-v2): close Phase A with auto-review, product events, and H5 recall UI.
Add candidate auto-review pipeline, shadow audit tooling, admin metrics page, and user-visible memory recall hints in chat with phase-a readiness checks. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env node
|
||||
import { pathToFileURL } from 'node:url';
|
||||
import { createDbPool, isDatabaseConfigured } from '../db.mjs';
|
||||
import { runCandidateAutoReviewBatch } from '../memory-v2-candidate-auto-review.mjs';
|
||||
|
||||
function usage() {
|
||||
return [
|
||||
'Usage: node scripts/auto-review-memory-v2-candidates.mjs [--apply] [--user-id <id>] [--limit <n>] [--json]',
|
||||
'',
|
||||
'Default is dry-run summary against pending candidates.',
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
function parseArgs(argv) {
|
||||
const options = { apply: false, userId: null, limit: 200, json: false, help: false };
|
||||
for (let index = 0; index < argv.length; index += 1) {
|
||||
const arg = argv[index];
|
||||
if (arg === '--help' || arg === '-h') options.help = true;
|
||||
else if (arg === '--apply') options.apply = true;
|
||||
else if (arg === '--json') options.json = true;
|
||||
else if (arg === '--user-id') options.userId = String(argv[++index] ?? '').trim() || null;
|
||||
else if (arg === '--limit') options.limit = Number(argv[++index]);
|
||||
else throw new Error(`Unknown argument: ${arg}`);
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
export async function runAutoReviewMemoryV2CandidatesCli(
|
||||
argv = process.argv.slice(2),
|
||||
env = process.env,
|
||||
) {
|
||||
const options = parseArgs(argv);
|
||||
if (options.help) {
|
||||
console.log(usage());
|
||||
return { ok: true, mode: 'help' };
|
||||
}
|
||||
if (!isDatabaseConfigured()) {
|
||||
throw new Error('DATABASE_URL or MYSQL_* must be configured');
|
||||
}
|
||||
const pool = createDbPool();
|
||||
try {
|
||||
const result = await runCandidateAutoReviewBatch(pool, {
|
||||
env,
|
||||
userId: options.userId,
|
||||
limit: options.limit,
|
||||
reviewedBy: options.apply ? 'system:auto-review-cli' : 'system:auto-review-dry-run',
|
||||
dryRun: !options.apply,
|
||||
});
|
||||
const payload = {
|
||||
...result,
|
||||
mode: options.apply ? 'apply' : 'dry-run',
|
||||
note: options.apply
|
||||
? 'Auto-review applied to pending candidates'
|
||||
: 'Dry-run only; pass --apply to mutate candidate statuses',
|
||||
};
|
||||
if (options.json) console.log(JSON.stringify(payload, null, 2));
|
||||
else {
|
||||
console.log(`${payload.mode}: scanned=${payload.scanned ?? 0} accept=${payload.accepted ?? 0} reject=${payload.rejected ?? 0} pending=${payload.pending ?? 0}`);
|
||||
if (payload.samples?.length) console.log(JSON.stringify(payload.samples, null, 2));
|
||||
}
|
||||
return payload;
|
||||
} finally {
|
||||
await pool.end?.();
|
||||
}
|
||||
}
|
||||
|
||||
if (import.meta.url === pathToFileURL(process.argv[1]).href) {
|
||||
runAutoReviewMemoryV2CandidatesCli().catch((err) => {
|
||||
console.error(err instanceof Error ? err.message : err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user