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
+54 -1
View File
@@ -76,7 +76,7 @@ test('createTask returns existing active duplicate for same schedule', async ()
let insertCount = 0;
const service = createScheduledTaskService({
async query(sql) {
if (sql.includes('FROM h5_scheduled_tasks') && sql.includes('status = \'active\'')) {
if (sql.includes('FROM h5_scheduled_tasks') && sql.includes("status IN ('active', 'locked')")) {
return [[{
id: 'task-existing',
user_id: 'user-1',
@@ -125,6 +125,59 @@ test('createTask returns existing active duplicate for same schedule', async ()
assert.equal(insertCount, 0);
});
test('createTask returns existing locked duplicate for same schedule', async () => {
let insertCount = 0;
const service = createScheduledTaskService({
async query(sql) {
if (sql.includes('FROM h5_scheduled_tasks') && sql.includes("status IN ('active', 'locked')")) {
return [[{
id: 'task-locked',
user_id: 'user-1',
title: '每日天气预报播报(上海+武穴)',
task_spec: 'running spec',
recurrence: 'daily',
hour: 8,
minute: 0,
weekday: null,
timezone: 'Asia/Shanghai',
next_run_at: 1780000000000,
last_run_at: null,
notify_channel: 'both',
status: 'locked',
attempts: 1,
last_error: null,
last_result_json: null,
source_channel: 'agent',
source_session_id: null,
source_message_id: null,
source_text: null,
created_at: 1780000000000,
updated_at: 1780000000000,
}]];
}
if (sql.includes('INSERT INTO h5_scheduled_tasks')) {
insertCount += 1;
return [{ affectedRows: 1 }];
}
return [[]];
},
}, {
clock: { now: () => 1780000000000 },
});
const task = await service.createTask({
userId: 'user-1',
title: '每日天气预报播报(上海+武穴)',
taskSpec: 'new spec',
recurrence: 'daily',
hour: 8,
minute: 0,
});
assert.equal(task.id, 'task-locked');
assert.equal(insertCount, 0);
});
test('cancelTask updates status to cancelled', async () => {
const service = createScheduledTaskService({
async query(sql, params) {