feat(wechat): add Intent Transaction Layer with unified task schema

Introduce Draft → Confirm → Commit flow for WeChat schedule intents behind
feature flags, plus h5_tasks dual-write/read aggregation and rollout scripts
so reminders and automations get explicit user confirmation before persisting.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-08-24 15:59:17 +08:00
parent b93c92a3e2
commit d58dc2a251
45 changed files with 4972 additions and 30 deletions
+21 -10
View File
@@ -8,10 +8,13 @@ import {
} from './schedule-time.mjs';
function normalizeText(text) {
return String(text ?? '').replace(/\s+/g, '').trim();
return String(text ?? '')
.replace(/^(?:嗯|那个|就是|然后|呃|能不能|请|帮我|麻烦|嗨)+/u, '')
.replace(/\s+/g, '')
.trim();
}
const EXECUTE_VERBS = /(?:做|生成|制作|创建|写|执行|跑|更新|整理|汇总|推送)/u;
const EXECUTE_VERBS = /(?:做|生成|制作|创建|写|执行|跑|更新|整理|汇总|推送|发送|发给|发|看看|检查|监控|瞧瞧)/u;
const SCHEDULE_MARKERS = /(?:定时(?:自动)?任务|scheduled\s*task|scheduled\s*automation|cron\s*job|recurring\s*task)/iu;
const RECURRENCE_MARKERS = /(?:每天|每日|每周|定时|到点|届时|自动)/u;
@@ -44,11 +47,18 @@ function isMetaScheduledTaskSpec(spec) {
function wantsScheduledTaskAutomation(compact) {
if (SCHEDULE_MARKERS.test(compact)) return true;
if (RECURRENCE_MARKERS.test(compact)
&& /(?:看看|检查|监控|瞧瞧).{0,20}(?:有没有|是否有)/u.test(compact)) {
return true;
}
if (!RECURRENCE_MARKERS.test(compact)) return false;
if (!EXECUTE_VERBS.test(compact)) return false;
// Pure reminders/digests stay on schedule-assistant or wechat schedule handler.
if (/(?:提醒我|闹钟|待办记录|待办列表|待办清单|当天待办|一天的待办)/u.test(compact)) return false;
if (/(?:待办|代办|带办|代拜).{0,8}(?:记录|列表|清单|摘要|汇总)/u.test(compact)) return false;
if (/(?:待办|代办|带办|代拜).{0,8}(?:记录|列表|清单|摘要|汇总)/u.test(compact)) {
// 「待办摘要页面 / 待办汇总 HTML」仍是定时自动任务,不是纯 digest 推送。
if (!/(?:页面|网页|html|h5)/iu.test(compact)) return false;
}
return true;
}
@@ -147,13 +157,8 @@ export function parseScheduledTaskIntent(text, { now = Date.now(), timezone = 'A
const original = String(text ?? '').trim();
if (!compact) return { action: 'none' };
if (!wantsScheduledTaskAutomation(compact)) {
return { action: 'none' };
}
const tz = normalizeTimezone(timezone);
const wantsCancel = /(?:取消|停止|关闭|删除).{0,12}(?:定时|自动)/u.test(compact)
const wantsCancel = /(?:取消|停止|关闭|删除).{0,16}(?:定时|自动|每日|每天)/u.test(compact)
|| /(?:取消|停止|关闭|删除).{0,16}(?:新闻|天气).{0,8}任务/u.test(compact)
|| /(?:cancel|stop|disable).{0,12}(?:scheduled|automation|task)/iu.test(compact);
if (wantsCancel) {
return { action: 'cancel_scheduled_task' };
@@ -165,6 +170,12 @@ export function parseScheduledTaskIntent(text, { now = Date.now(), timezone = 'A
return { action: 'list_scheduled_tasks' };
}
if (!wantsScheduledTaskAutomation(compact)) {
return { action: 'none' };
}
const tz = normalizeTimezone(timezone);
const recurrence = /(?:一次|单次|仅一次|once)/iu.test(compact)
? 'once'
: /(?:每周|weekly)/iu.test(compact)