feat(cypher): add scheduled() handler — arcrun-native cron 排程基建

對應 arcrun.md 三-A P1 #3。

緣由:cron 零件存在但只做 expression validation,沒有真正的排程跑。leo 指出
「邊用 arcrun 邊修,不要 workaround」— 撤回前一輪的 /mira/wiki-from-raw
mira-specific route(違反 mira CLAUDE.md §1.5 一律 arcrun-native),改補
真正的 cron infra。

加入:
- src/lib/cron-match.ts — 5 欄位 cron matcher(* / N / */N / a-b / a,b 組合)
- src/scheduled.ts — handler:掃 KV cron-idx: prefix,比對 controller.scheduledTime
  → executeWebhookGraph 背景跑
- routes/webhooks-named.ts — acr push 時偵測首節點 cron → 存 cron_expr 到 record
  + 額外寫 cron-idx:{api_key}:{name} 輕量索引;DELETE 一併清理
- src/index.ts — export default 改 { fetch, scheduled }
- wrangler.toml — [triggers] crons = ["* * * * *"](每分鐘 tick)
- wrangler.toml — workers_dev = true 供 self-fetch self-trigger 用
- tests/arcrun-test/cron_heartbeat.yaml — 健康監控 workflow(每分鐘 fire + set 節點)

撤回:
- 刪 src/routes/mira.ts(mira-specific workaround)
- types.ts 拿掉 MIRA_CONFIG
- index.ts 拿掉 miraRouter wire
- landing/app/mira/feed/page.tsx 拿掉 triggerWikiSynthesis 呼叫

下一輪:mira_feed_watcher.yaml(mira side),可能要先補 kbdb_get filter +
CALLS_SUBFLOW wire(arcrun.md 列為跟進)。
This commit is contained in:
2026-05-14 14:04:57 +08:00
parent 660b32eafd
commit 9560485937
10 changed files with 257 additions and 154 deletions
+2 -27
View File
@@ -158,29 +158,6 @@ export default function MiraPage() {
// ─── AI 回覆觸發器(fire-and-forget)──────────────────────
async function triggerWikiSynthesis(opts: { rawBlockId: string }) {
// 對應 cypher-executor routes/mira.ts POST /mira/wiki-from-raw
// server 端從 MIRA_CONFIG secret 補齊所有 partner key / token / block IDs
// workflow 跑 60-90s,這裡 fire-and-forget 不等結果(拿 202 立刻回)
try {
const res = await fetch(`${API_BASE}/mira/wiki-from-raw`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({ raw_block_id: opts.rawBlockId }),
});
if (!res.ok) {
const data = await res.json().catch(() => ({}));
console.warn('[mira wiki-from-raw] not triggered:', res.status, data);
return;
}
const data = await res.json().catch(() => ({}));
console.log('[mira wiki-from-raw] accepted:', data);
} catch (e) {
console.warn('[mira wiki-from-raw] error:', e);
}
}
async function triggerAiReply(opts: {
apiKey: string;
postContent: string;
@@ -295,10 +272,8 @@ function PostComposer({
parentBlockId: postBlockId,
pageName,
});
// fire-and-forget 觸發 wiki_synthesis7B.3h 簡化版:從 frontend 直接觸發,不走 cron
// 對應 routes/mira.tsserver 端從 MIRA_CONFIG secret 補齊 token / block IDs
void triggerWikiSynthesis({ rawBlockId: postBlockId });
// 7B.3hwiki_synthesis 由 arcrun cron-triggered workflow `mira_feed_watcher`
// 自動處理(每分鐘掃未處理 raw block),不需前端觸發。
onAiTriggered(pageName);
// 給 D1 GROUP BY 查詢看到新資料的時間