843e4d1002
Memind CI / Test, build, and release guards (push) Successful in 2m58s
Prevent duplicate active scheduled tasks, fail static preparing contracts when HTML is missing, raise MindSpace remote timeout default to 30s, and add 103 repair scripts for inspection follow-ups. Co-authored-by: Cursor <cursoragent@cursor.com>
106 lines
3.0 KiB
JavaScript
106 lines
3.0 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* One-shot 103 production repairs from 2026-08-16 inspection.
|
|
* Dry-run by default; pass --apply to mutate database rows.
|
|
*/
|
|
import process from 'node:process';
|
|
import { reconcileStuckStaticPageDeliveryContracts } from '../scheduled-task-executor.mjs';
|
|
|
|
const TANG_USER_ID = 'a70ff537-8908-486e-9b6c-042e07cc25db';
|
|
const TASKS_TO_CANCEL = [
|
|
'781a77e5-a787-4f37-b864-e21d7e918855',
|
|
'9df3f89a-3a06-434d-8b4c-17b1aeb8911f',
|
|
'7f953d5f-6fc3-4191-b52a-bffcef48e77f',
|
|
'9b537fe8-eea2-4e39-8bcb-e8f169986327',
|
|
];
|
|
|
|
function loadPool() {
|
|
const databaseUrl = process.env.DATABASE_URL;
|
|
if (!databaseUrl) {
|
|
throw new Error('缺少 DATABASE_URL');
|
|
}
|
|
return import('mysql2/promise').then(({ default: mysql }) =>
|
|
mysql.createPool({ uri: databaseUrl, connectionLimit: 2 }));
|
|
}
|
|
|
|
async function main() {
|
|
const apply = process.argv.includes('--apply');
|
|
const h5Root = process.env.H5_ROOT || '/Users/john/Project/Memind';
|
|
const pool = await loadPool();
|
|
const now = Date.now();
|
|
const actions = [];
|
|
|
|
for (const taskId of TASKS_TO_CANCEL) {
|
|
const [rows] = await pool.query(
|
|
`SELECT id, user_id, title, status, hour, minute
|
|
FROM h5_scheduled_tasks WHERE id = ? LIMIT 1`,
|
|
[taskId],
|
|
);
|
|
const row = rows?.[0];
|
|
if (!row) {
|
|
actions.push({ taskId, action: 'skip', reason: 'not_found' });
|
|
continue;
|
|
}
|
|
if (row.status === 'cancelled') {
|
|
actions.push({ taskId, action: 'skip', reason: 'already_cancelled', title: row.title });
|
|
continue;
|
|
}
|
|
actions.push({
|
|
taskId,
|
|
action: apply ? 'cancel' : 'would_cancel',
|
|
title: row.title,
|
|
status: row.status,
|
|
schedule: `${row.hour ?? '?'}:${String(row.minute ?? 0).padStart(2, '0')}`,
|
|
});
|
|
if (apply) {
|
|
await pool.query(
|
|
`UPDATE h5_scheduled_tasks
|
|
SET status = 'cancelled', updated_at = ?, last_error = NULL
|
|
WHERE id = ? AND user_id = ?`,
|
|
[now, taskId, TANG_USER_ID],
|
|
);
|
|
}
|
|
}
|
|
|
|
const [activeWeather] = await pool.query(
|
|
`SELECT id, title, hour, minute, status, last_run_at
|
|
FROM h5_scheduled_tasks
|
|
WHERE user_id = ? AND title LIKE '%天气预报%' AND status = 'active'
|
|
ORDER BY hour, created_at`,
|
|
[TANG_USER_ID],
|
|
);
|
|
|
|
let reconcileSummary = [];
|
|
if (apply) {
|
|
reconcileSummary = await reconcileStuckStaticPageDeliveryContracts({
|
|
pool,
|
|
h5Root,
|
|
limit: 50,
|
|
logger: console,
|
|
});
|
|
} else {
|
|
const [stuck] = await pool.query(
|
|
`SELECT user_id, workspace_relative_path, data_mode, status
|
|
FROM h5_page_delivery_contracts
|
|
WHERE status = 'preparing' AND data_mode = 'static'
|
|
ORDER BY updated_at ASC
|
|
LIMIT 50`,
|
|
);
|
|
reconcileSummary = stuck;
|
|
}
|
|
|
|
console.log(JSON.stringify({
|
|
mode: apply ? 'apply' : 'dry-run',
|
|
cancelledTasks: actions,
|
|
remainingActiveWeatherTasks: activeWeather,
|
|
deliveryContracts: reconcileSummary,
|
|
}, null, 2));
|
|
|
|
await pool.end();
|
|
}
|
|
|
|
main().catch((error) => {
|
|
console.error(error);
|
|
process.exit(1);
|
|
});
|