Leo
4fd2d3ba6c
fix(cypher-executor): FOREACH iter plural 變體 (entity → entities)
...
舊 getIterableFromContext 只試 'key+s',遇 irregular plural 不命中:
entity + s = entitys ≠ entities (Claude 真實 output)
加變體:
- key + 's' (paragraph → paragraphs)
- key.replace(/y$/, 'ies') (entity → entities)
- key.replace(/(s|x|z|ch|sh)$/, '$1es') (box → boxes)
- key (singular fallback)
對應 mira wiki_synthesis V3 multi-entity 升級需求。
2026-05-17 10:34:12 +08:00
Leo
a7d36933e6
feat(cypher-executor): trigger_workflow status paused_awaiting_resume → running_async (LI roadmap 自評)
...
第一份 arcrun-roadmap (block e924c231) 提的建議:
「paused_awaiting_resume 容易被誤讀成掛起出問題,
考慮改成更清楚的 status(如 completed_with_checkpoint)」
我採折衷命名:running_async — 強調「workflow 已接受,正在背景跑」,
不像 completed_with_checkpoint 容易被誤讀為已完成。
範圍:
- trigger_workflow component-loader.ts status field rename
- AGENTS.md §6 common errors table 同步
- arcrun-mcp arcrun_run_workflow tool 回傳 status 同步
- error_code (telemetry classification) 仍保留 paused_awaiting_resume
(SDD §1.4 error_code enum '可加不可刪' 承諾)
向下相容性:status 是 user-facing field,前面 dogfood 只有 weekly_review
一個 consumer 用 trigger_workflow,已同步更新。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-16 21:54:41 +08:00
Leo
8b54ebb68a
feat(cypher-executor): step-level telemetry (LI roadmap 2026-W19 建議)
...
對應第一份 arcrun-roadmap (block id e924c231) 提的:
「mira_feed_watcher 執行時間偏長(~35秒),無 error 資訊
建議:加入 checkpoint/step-level telemetry,監測瓶頸」
新增 TelemetryEvent:
- node_success — 單一 Component node 跑完
- node_failure — 單一 Component node 失敗
寫入點:GraphExecutor.executeNode catch + 最終 trace.push 之後
- 只記 node.type === 'Component'(Input/Output 跳過避免噪音)
- 含 workflow_name + component_id + duration_ms + (error_code on fail)
- fire-and-forget, 不擋主流程
實測(wiki_synthesis trigger 後):
- 4 個 node_success blocks 寫入 KBDB (4 個 kbdb_get)
- duration 範圍 653ms-2003ms,立刻看到誰是瓶頸
- paused 的 classify (claude_api) 不算 success(trace 已記 paused 狀態)
下次 weekly_review compose_review 會看到 component-level breakdown,
能寫出「kbdb_get 平均 X ms、claude_api 平均 Y ms」等更細的分析。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-16 21:47:15 +08:00
Leo
8e985684f9
feat(cypher-executor): magic vars {{_today}} / {{_iso_week}} / {{_now}} 等
...
對應 LI SDD M2.x improvement,源自 Claude (我) 透過 arcrun_report_feedback
寫的 feedback block c47bf70b 提的「需要內建變數展開」需求。完整閉環:
AI 用 MCP tool 報 bug → KBDB 收 feedback → AI 自己看 → 自己修補 → deploy
新增 cypher-executor/src/lib/magic-vars.ts:
- _today / _yesterday / _now / _now_unix / _now_unix_s
- _iso_week (2026-W20) / _iso_week_num / _iso_year
- _yyyymm / _yyyymmdd
- _year / _month / _day / _hour / _minute / _second(zero-padded)
- _weekday (0-6, 0=日) / _iso_weekday (1-7, 1=一)
全部 UTC,避免 worker 跨時區誤判
GraphExecutor.execute() 入口注入:
ctxWithMagic = { ...initialContext, ...buildMagicVars() }
順序確保 magic vars 永遠 win(防 user 不小心用 _ prefix)
不違反 §2.2(cypher-executor TS 禁實作 secret/JWT 業務邏輯):
magic vars 是公開時間常數,跟既有 interpolateString 的 ctx 變數展開
同層,純 orchestrator routing 職責。
AGENTS.md §10.5 加 magic vars 完整表 + weekly archive 範例。
實測(commit 後 deploy + 觸發 weekly_review):
- KBDB 新建 roadmap-2026-W20 block 正確展開 page_name
- roadmap-latest 同步更新(雙寫 pattern)
- 證明 weekly archive 從此真能累積歷史,不再固定 latest 覆蓋
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-16 21:20:52 +08:00
Leo
4e7880c1cb
fix(cypher-executor): /executions/paused 走 per-user index (強 consistent)
...
對應 LI SDD M2.1 修補。
問題:原 /executions/paused 走 EXEC_CONTEXT.list({prefix:'paused_run:'})。
CF KV list 是強 eventual consistent (30-60s 延遲),剛 paused 的 workflow
list 不會立刻看到。本機 wrangler kv list 也回 [],但 KV.get 同 task_id
能即時拿到 — 證實 list vs get 一致性層級不同。
修補:persistPausedRun 額外維護 per-user index `paused_idx:{api_key}`
(JSON Array),是單一 KV.get 拿全列表,**強 consistent 無延遲**。
consumePausedRun 同步從 index 移除。
新 helper:
- listPausedRunsByApiKey(kv, apiKey, limit) — 走 index
- PausedIndexEntry type — task_id / run_id / paused_node_id / workflow_name /
expires_at / persisted_at
實測:trigger 後立刻 list 即時看到 paused (commit 前是 0)
副作用:index 寫入 + delete 都是 fire-and-forget 在 consume path,失敗
不擋主流程。Index entries 上限 100 防無限長。每次 read 過濾 expired。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-16 17:15:16 +08:00
Leo
989fbeb9ac
feat(cypher-executor): /executions/* introspection (LI SDD M2.1)
...
對應 .agents/specs/llm-interface/ Milestone 2.1。給 AI debug 用的執行
狀態檢視端點。3 個新路由:
GET /executions/paused
- 列當前 api_key 下所有 paused workflow(等 callback resume)
- 走 EXEC_CONTEXT KV `paused_run:*` prefix scan,過濾 state.api_key
- 回 [{task_id, run_id, paused_node_id, workflow_name, expires_at}]
- 限 limit 100,避免 KV N+1 爆
GET /executions/:task_id
- 看單一 paused state 細節(trace_so_far / paused_context / pending_result)
- 隔離租戶(state.api_key !== 用戶 ak → 回 not_found 不洩漏存在性)
- 回完整 state JSON
GET /workflows/:name/executions
- 列某 workflow 最近 N 次執行 verdict(走 ANALYTICS_KV stats:{name}:* prefix)
- 先驗 workflow 屬該 api_key
- 按 timestamp 後綴 desc sort
統一 error contract(LI SDD §1.3 / §1.4 規範):
- ok: bool
- error_code: enum (auth_missing / not_found / internal_error)
- human_message: 描述
- next_actions: 陣列,給 AI 看的下一步
- hints: 成功時的 next-step 建議
不影響既有路由 contract。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-16 15:58:35 +08:00
Leo
04ed722591
chore: gitignore .swarm/ + ruvector.db (Claude Code local artifacts)
...
之前 M1.2 telemetry commit 不小心把 cypher-executor/src/.swarm/ 跟 ruvector.db
commit 進去。這些是 Claude Code 自己的本地工具產物,不該入庫。
- 加 .gitignore 樣式:.swarm/ / ruvector.db / **/.swarm/ / **/ruvector.db
- 撤回上次 commit 進去的 5 個檔案
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-16 15:35:55 +08:00
Leo
d04e34ea35
feat(cypher-executor): implicit telemetry (LI SDD M1.2)
...
對應 .agents/specs/llm-interface/ Milestone 1.2。
新增 lib/telemetry.ts:
- hashApiKey(): SHA-256 截 16 hex 字元(不可逆,可聚合)
- recordTelemetry(): fetch fire-and-forget 寫 KBDB type=agent-telemetry block
- 設計:不阻擋主流程,錯誤 console.warn 不 throw
- 用 ctx.waitUntil 確保即使主 request 已回,背景仍會跑完
寫入點 3 處:
1. routes/webhooks-named.ts POST /webhooks/named (deploy) → deploy_success
2. routes/webhooks-named.ts POST /webhooks/named/:name/trigger →
executeWebhookGraph 帶 ctx + userAgent,內部記 run_success / run_fail
3. routes/validate.ts POST /validate → validation_error (含 schema_failed / edge_node_missing)
executeWebhookGraph 簽名擴張:可選 ctx + userAgent,舊 caller (scheduled /
trigger_workflow / anonymous webhook) 不傳也 OK(telemetry 仍寫但無 ctx 加持)。
paused (workflow 因 claude_api 等等 callback resume) 算 run_success,
不污染 fail metric。
types.ts: 加 PLATFORM_API_KEY env (可選) + re-export ExecutionContext
不違反「業務邏輯走 WASM」鐵律:telemetry 是 orchestrator 觀測自身的能力,
跟 trigger_workflow / scheduled() 同類。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-16 15:33:35 +08:00
Leo
521624261d
fix(cypher-executor): trigger_workflow paused 不算失敗
...
watcher 實測 8/8 raw 跑通後發現 wait=true 把 wiki_synthesis paused
(claude_api 等 callback resume 的正常狀態)回報成 success:false,造成
watcher 看起來「5/8 失敗」實際是「正在背景跑」。
改成:
- isPaused 偵測「workflow paused at node X」error 字串
- isPaused → success:true, status:'paused_awaiting_resume'
- 完整完成 → status:'completed'
- 真失敗 → status:'failed'
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-16 14:04:12 +08:00
Leo
b8ecef0b41
feat(cypher-executor): trigger_workflow 內建零件 — 繞 CF self-fetch
...
mira_feed_watcher 之前用 http_request 自打 cypher.arcrun.dev / 自身 workers.dev URL
都被 CF self-fetch 防護擋(Worker→自身的 subrequest 攔截)。
新增 `trigger_workflow` 內建 orchestration 零件:
- 在 createComponentLoader 最前面攔截 component_id === 'trigger_workflow'
- 從 WEBHOOKS KV 撈 `{api_key}:wf:{name}` 拿 graph
- 動態 import 避循環依賴
- in-process 呼叫 executeWebhookGraph,沒有任何外部 HTTP
- 預設 wait=true(claude_api paused 仍視為 success 回傳)
不違反「業務邏輯走 WASM」鐵律:trigger_workflow 是 orchestrator 自己的 routing
能力(像既有的 CALLS_SUBFLOW),不是業務邏輯。
對應 mira_feed_watcher.yaml 同步改用此零件(在 polaris/mira/ repo)。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-16 13:54:26 +08:00
Leo
8ab6f8a66b
fix(cypher): interpolateString single-ref array/object pass-through (P0 #11 )
...
mira_feed_watcher 第一輪 cron tick 跑 264ms 完成但 0 raw 處理 — 挖到 root cause:
interpolateString 看到模板就 string.replace,非 string 值(如 kbdb_get 回的
blocks 陣列)一律 JSON.stringify。所以 `items: "{{list_raws.blocks}}"` 把
陣列轉成字串給 filter 零件,filter 收到字串 != array → items 被忽略 →
FOREACH 跑 0 次 → watcher 看似成功實則空跑。
修:interpolateString 加 single-ref pass-through —— 若整個值是純單一 `{{x}}`
引用,回 raw value(保留 array / object 型別)。多 ref / 混合文字仍 stringify。
對應 SDD: arcrun.md 三-A P0 #11。
下一輪 cron tick 應該真正處理 raws,加 wiki-processed tag。
2026-05-14 14:54:26 +08:00
Leo
9560485937
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 列為跟進)。
2026-05-14 14:04:57 +08:00
Leo
660b32eafd
feat(mira): 河道 → wiki 自動化(fire-and-forget 觸發 wiki_synthesis)
...
對應 polaris/mira/.agents/specs/mira-app/tasks.md 7B.3h(簡化版)。
原計畫用 arcrun cron 零件 → cypher-executor scheduled() handler,但發現
cron 零件只是 validator,cypher-executor 還沒實作 scheduled()。為了不擋
「河道書寫 → 自動產 wiki」這條 UX,先做 fire-and-forget 版本:
- 新 cypher-executor route POST /mira/wiki-from-raw
- body: { raw_block_id }
- server 端從 MIRA_CONFIG secret 補 partner key / mira_token / 三個 block IDs
- waitUntil 背景跑 executeWebhookGraph,立刻回 202
- landing 河道 post composer 成功寫 raw 後 fire-and-forget triggerWikiSynthesis()
跟既有 triggerAiReply() 同範式
- types.ts 加 MIRA_CONFIG?: string
部署後需手動:
echo '{"service_api_key":"ak_...","data_api_key":"ak_...","schema_block_id":"...","skill_block_id":"...","entities_block_id":"...","mira_token":"..."}' \
| wrangler secret put MIRA_CONFIG
UX:河道貼一則 → AI reply 30s 內 → wiki 60-90s 內出現在 /mira/wiki。
arcrun.md 記 P1 #3:cypher-executor 加 scheduled() handler,那是真正的
cron 路線,封測前不擋。
2026-05-14 13:50:13 +08:00
Leo
d6d2cecfb5
fix(cypher): resumeFromPaused 漏 node-id namespace 導致下游模板找不到 paused 結果
...
mira 7B.3f PATCH 測試踩到:classify 跟 compose 都是 claude_api(兩次 paused/resumed),
upsert_index_entry config 寫 `{{compose_index_entry.data.text}}`,但 PATCH 跑出的
block content 是字面 `{{compose_index_entry.data.text}}` —— 模板沒被替換。
根因:resumeFromPaused 把 callback_result spread 到 top-level,但漏了
`[paused_node_id]: callback_result` 的 namespace 包裝。同步路徑的 propagateCtx
有做這件事,resume 路徑沒做,行為不一致。
修:mergedContext 加 [paused_node_id]: callback_result 一行,跟 propagateCtx 對齊。
arcrun.md 同步補三-B「新零件 checklist」+ 三-C「workers_dev=true 全 component
自動化」收尾紀錄。
2026-05-14 12:06:59 +08:00
Leo
c830897988
fix(cypher): register kbdb_upsert_block + workers_dev=true on all 32 components
...
兩件事一起補:
1. cypher-executor 的 WASM_HTTP_RUNNER_IDS 白名單漏加 kbdb_upsert_block。
mira 7B.3f 端對端 debug 才發現 upsert 節點直接拋「找不到零件」。
建零件時要記得同步註冊到 loader。
2. .component-builds/*/wrangler.toml (×32) 全部加 workers_dev = true。
解決每次新部署 component 都要去 CF Dashboard 手動啟用 workers.dev URL
的痛點(leo 今天踩這個踩了好幾次)。zero-touch deploy + free tier 友好,
符合 arcrun 「fork 後 self-host 用 free tier 跑得起來」的核心目標。
對 mira 端:wiki_synthesis.yaml 還原回完整鏈
(lookup → compose → upsert + 平行的 FOREACH paragraphs/triplets)。
2026-05-14 11:37:28 +08:00
Leo
6f6e31dbee
fix(cypher): deploy P0 #9/#10/#10衍生 fixes (workers.dev URL + nested FOREACH + propagateCtx)
...
arcrun.md 一直標 ✅ 已解決但 fix 在 working tree 沒推。今天 mira 7B.3f 端對端
跑不通才發現 production 還是舊版(fetch *.arcrun.dev 同 zone 自循環 → 522)。
涵蓋:
- P0 #9 : wasmWorkerUrl() 從 *.arcrun.dev 改 arcrun-{kebab}.{WORKER_SUBDOMAIN}.workers.dev
+ types.ts/wrangler.toml 加 WORKER_SUBDOMAIN binding (uncle6-me)
+ auth-dispatcher.ts 用新 signature
- P0 #10A: interpolateData() 拆 interpolateString + interpolateValue 遞迴 nested
- P0 #10B: propagateCtx() helper 把上游 output spread + 用 node id namespace 存
讓下游能 {{node_id.data.text}} 永不被覆蓋。5 個 edge type 全用此 helper
- P0 #10C: FOREACH 找 iterable 先看 result 沒有再看 ctx + 掃 nested object 一層
解雙重 FOREACH(paragraph→triplets)內層跑 0 次
rules/01-tech-stack.md + rules/03-component-architecture.md 同步補 workers.dev 慣例說明。
未推 5 個 worker 改動,今晚才發現實際沒部署過。
2026-05-14 11:02:44 +08:00
Leo
519423cb0d
feat(arcrun): mira wiki page with tag filter + accumulated WIP
...
- landing/app/mira/wiki: tag=mira-wiki list now shows all wiki paragraphs
(depends on KBDB tag filter exposed in matrix/kbdb commit, separate repo)
- landing: app/mira hub + feed split + various WIP from prior sessions
- registry/components: claude_api / kbdb_create_block / kbdb_get / km_writer /
platform_crypto / auth_oauth2 contracts + main.go (accumulated)
- .component-builds: pkg-lock updates + index.ts adjustments (WIP)
- .agents/specs/arcrun/frontend-redesign: design notes
- docs/test_credentials, docs/user_requirements/arcrun-landing-page: WIP docs
- cypher-executor: auth-dispatcher / wasi-shim adjustments (WIP)
Includes accumulated work from prior sessions plus the wiki UI tag-filter
update that surfaces the AI-generated wiki paragraphs at /mira/wiki.
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-07 16:52:01 +08:00
Leo
e8fca33f80
feat(cypher): 3-node wiki workflow end-to-end (FOREACH + nested interp + unified parsing)
...
Three platform-level improvements that together enable the full
"草稿 → LLM 整理 → KBDB" wiki ingest workflow via cypher binding:
## 1. Nested interpolation in node.data
Previously {{var}} only supported top-level keys, so {{item.content}}
literal-passed through. Now supports dot-path:
{{paragraph.content}} → ctx.paragraph.content
{{paragraphs.0.entity}} → ctx.paragraphs[0].entity
Non-string values (object/array) JSON.stringify automatically.
## 2. 對每個 X cypher binding syntax
'A >> 對每個 paragraph >> B' parses into FOREACH edge with
iterator='paragraph'. graph-builder.ts strips the iterator from label
before edge type resolution. Backwards compatible: bare '對每個' still
defaults to item.
## 3. FOREACH preserves outer context
itemContext was previously {...result, [iter]: item}, dropping
top-level api_key etc. Now {...outerCtx, ...result, [iter]: item} so
{{api_key}} interpolation works in foreach body.
## 4. Unified recipe output parsing (sync + resume)
Extracted parseRecipeOutput() helper used by both sync claude_api
result + workflow resume callback. Strips ```json fence, parses,
spreads parsed top-level fields into result so downstream FOREACH
finds 'paragraphs' (not buried in data.paragraphs).
paused state now stores recipe_output_format + required_fields so
resume route can apply same parsing as sync path.
End-to-end verified:
- input(草稿+api_key) → synth(claude_api+recipe) → 對每個 paragraph → write_wiki(kbdb_create_block)
- Real Claude synthesis on Mira daemon: 3 triplets + 2 paragraphs
- Both paragraphs written to KBDB as wiki-page blocks (verified GET)
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-07 16:23:02 +08:00
Leo
497f92a268
feat(arcrun): recipe system + resumable workflow + component registry canon
...
Three new platform capabilities + one component (kbdb_get) to enable
real AI workflow execution through cypher binding YAML.
## Recipe System (容器 + Recipe 模式)
SDD: .agents/specs/recipe-system/
- prompt_recipe schema (Zod): fragments + inputs + assembly + output
- recipe-expander.ts: expand recipe ref → real prompt by fetching KBDB blocks
+ pulling context fields with transforms (pluck_content / extract_field / etc)
- 7 transform whitelist: json_array / to_string / join / markdown_list /
extract_field / first / pluck_content
- graph-executor hooks: detect node.data.recipe → expand → inject into ctx
- output JSON parser (with markdown fence stripping for Claude-wrapped JSON)
- Stored in RECIPES KV under prompt_recipe:{name}
## Resumable Workflow (webhook callback resume)
SDD: .agents/specs/resumable-workflow/
- WorkflowPaused class + paused-runs.ts (persist/load/consume in EXEC_CONTEXT KV, 24h TTL)
- graph-executor: detect {pending:true, task_id} → persist state → throw WorkflowPaused
- cypher-handlers: catch → return {success:true, paused:true, task_id, run_id}
- POST /workflows/resume route: consume KV state → resumeFromPaused()
- Auto-inject callback_url for claude_api nodes (PUBLIC_BASE_URL or default cypher.arcrun.dev)
- claude_api/main.go: forward callback_url to Mira daemon, default timeout 25s→120s
- Idempotent (consume = load+delete)
## Component Registry Canon
SDD: .agents/specs/component-registry-canon/
- Add POST /components/index-only endpoint (metadata-only, no wasm/sandbox)
- Backfill script (mjs): scan registry/components/*/contract.yaml → submit to KV
- register-component.sh: SSOT for local + CI hook (deploy.yml change in next commit)
- Drop R2 dead storage from submitComponent + types + wrangler
- Schema relaxed: category enum + auth/ai/platform; cold_start 50→500ms; size 2→8MB
## kbdb_get component
- registry/components/kbdb_get/: TinyGo WASM, two modes (block_id / page_name list)
- .component-builds/kbdb_get/: WASI shim worker (kbdb-get.arcrun.dev)
End-to-end validation: AI uses MCP execute_workflow with recipe ref →
cypher-executor expands prompt from KBDB schema/skill blocks + drafts →
claude_api calls Mira daemon → daemon callback fires resume route →
workflow continues. Verified with real 2KB+ Karpathy LLM Wiki draft.
🤖 Generated with [Claude Code](https://claude.com/claude-code )
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-05-07 15:52:19 +08:00
Leo
e2221161a8
fix(wasi-shim): re-read memory.buffer after await in all host functions
...
WebAssembly memory can grow (and return a new ArrayBuffer) during an
async host function call. Reading memory.buffer before await and using
it after the await causes host functions (kv_get / crypto_decrypt /
crypto_sign_rs256 / http_request) to write into a detached buffer,
so the WASM side reads zero bytes → empty string → JSON parse failure.
Fix: read inputs before await using the current buffer snapshot,
then call memory.buffer again after the await to write the result.
For crypto_sign_rs256 and http_request, input arrays are copied
before await so the snapshot can be released.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-04-24 17:13:03 +08:00
Leo
83a01fe028
feat(auth_static_key): auto-encode Basic Auth; seed gemini/trello/mailgun recipes
...
- auth_static_key WASM: 偵測 Authorization header "Basic <x>:<y>" (含冒號
的 user:pass 原文), 自動 base64 編碼; 無冒號則維持原樣 (向後相容
已 base64 過的值).
這涵蓋 twilio / jira / mailgun 三個 Basic Auth recipe, 用戶 recipe
只需寫 'Basic {{secret.user}}:{{secret.key}}' 直覺語法.
- 新增 3 個 recipe (auth-recipe-seeds.ts):
• gemini — static_key / header x-goog-api-key (單 secret)
• trello — static_key / QUERY key+token (雙 secret, 第一個 query
injection 測試覆蓋)
• mailgun — static_key / HEADER Basic api:<key> (雙 secret Basic Auth)
- hook fix (pre-write-guard.sh): 放行 auth-recipe-seeds.ts 的 {{secret.X}}
字面值. 該檔是 RECIPES KV 的 seed 資料, 不是 TS 展開邏輯;
真正展開仍在 WASM 完成.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-04-22 08:29:02 +08:00
Leo
258ef38f7a
fix(ci): regenerate tier2 pnpm-lock.yaml after adding wrangler
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-04-20 21:21:18 +08:00
Leo
200a8e14dc
fix(ci): add wrangler to tier2 devDependencies
...
tier2 deploy failed with ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL
because cypher-executor / registry / builtins package.json
didn't list wrangler; local dev worked via global install only.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-04-20 21:05:55 +08:00
Leo
500d796573
feat: 15 logic component Workers + cypher-executor auth/credentials routing
...
Component Workers:
- Deploys if_control, switch, filter, merge, try_catch, wait, set,
array_ops, string_ops, number_ops, date_ops, validate_json,
ai_transform_compile, ai_transform_run, foreach_control as
independent Workers, backing cypher-executor's SVC_* service
bindings (fast internal RPC for logic components).
cypher-executor routing:
- New routes: /auth (recipe resolution), /credentials (CRUD),
/webhooks/named (user-friendly alias for cmp_/rec_ hashes).
- auth-recipe-seeds.ts: 20 pre-built platform auth recipes
(Google Sheets, Gmail, Telegram, etc.) seeded into RECIPES KV.
- graph-executor + cypher-handlers + search-nodes updated for
the new resolution chain.
- scripts/seed-auth-recipes.ts: one-shot tool to push seeds to KV.
- wrangler.toml: 15 SVC_* bindings wired to the new logic Workers.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-04-20 17:40:02 +08:00
Leo
6a3219e51b
feat(components): move 6 API components to independent WASM Workers
...
Deploys gmail, telegram, line_notify, google_sheets, http_request, cron
as independent Cloudflare Workers at {name-kebab}.arcrun.dev. Each
wraps the TinyGo WASM from registry/components/{name}/main.go via
wasi-shim cross-import (Method A).
component-loader no longer carries BUILTIN_API_RECIPES — those
hardcoded gmail.googleapis.com / api.telegram.org / sheets / line-notify
endpoints all lived in TS, violating "all business logic in WASM".
Resolution chain now routes the 6 canonical IDs straight to their
{name}.arcrun.dev Worker URLs via WASM_HTTP_RUNNER_IDS.
Per .agents/specs/arcrun/credential-primitives-wasm Phase 3.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-04-20 17:36:06 +08:00
Leo
8c14562a2f
feat(auth): auth_service_account WASM primitive + remove TS JWT signer
...
- registry/components/auth_service_account: TinyGo impl for Google
Service Account (JWT-bearer → token exchange) and base structure
for AWS SigV4.
- .component-builds/auth_service_account: independent Worker at
auth-service-account.arcrun.dev, extends wasi-shim with an
http_request host function for the token exchange step.
- Delete cypher-executor/src/lib/wasm-executor.ts (legacy, replaced
by component-loader WASM HTTP runner path).
- credential-injector.ts service_account branch now throws — all
service_account recipes must route through auth-dispatcher.
Per .agents/specs/arcrun/credential-primitives-wasm Phase 2.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-04-20 17:34:42 +08:00
Leo
18f04448ce
feat(auth): auth_static_key WASM primitive + host functions
...
- wasi-shim gains kv_get / crypto_decrypt / crypto_sign_rs256 host
functions with strict boundary (ENCRYPTION_KEY never exits Worker).
- registry/components/auth_static_key: TinyGo impl for API-key /
Bearer / Basic Auth recipes (80% of supported services).
- .component-builds/auth_static_key: independent Worker at
auth-static-key.arcrun.dev, imports wasi-shim cross-directory.
- cypher-executor/auth-dispatcher routes static_key recipes to the
new Worker instead of credential-injector TS.
Replaces TS credential injection per
.agents/specs/arcrun/credential-primitives-wasm Phase 1.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com >
2026-04-20 16:54:18 +08:00
Leo
7b18387113
feat: config field in /cypher/execute — node-level component override
...
- /cypher/execute now accepts separate `config` field:
{node_name: {component: "cmp_19e62efd", ...staticParams}}
- graph-builder reads config[node].component to override componentId
(supports cmp_ hash, rec_ hash, or canonical_id)
- config[node] other fields become node.data (static params merged at runtime)
- acr run now sends workflow.config as separate `config` (not flattened into context)
- context is now only --input dynamic params
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-04-16 18:42:26 +08:00
Leo
60d3e41905
feat: component hash IDs + dynamic KV recipe system
...
Hash system:
- cmp_xxxxxxxx: stable ID for logic components (SHA-256 of canonical_id)
- rec_xxxxxxxx: stable ID for API recipe components
- Pre-seeded 15 cmp_ + 6 rec_ hash indexes in KV
RECIPES KV (id: 9cf9db905c6241f78503199e58b2ffe0):
- POST/GET/DELETE /recipes — CRUD for API recipe definitions
- recipe stored as: recipe:{canonical_id} + idx:{rec_hash}
- template interpolation: {{key}} replaced from context
component-loader resolution order:
builtin → external URL → cmp_ hash → rec_ hash →
logic canonical_id → KV recipe → builtin API fallback → error
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-04-16 18:36:51 +08:00
Leo
d8e6964088
feat: use CF Service Bindings for logic components (no public network)
...
- Add 15 [[services]] bindings in cypher-executor wrangler.toml
- component-loader now calls logic Workers via Service Binding (svc.fetch)
instead of public URL fetch (which caused 522 timeout within same zone)
- Fallback to public URL if binding not available (dev/testing)
- Add ServiceBinding type to Bindings
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-04-16 17:01:42 +08:00
Leo
2b89ea8825
feat: component execution via Worker fetch + API recipes
...
- Logic components (15): each deployed as Worker at {name}.arcrun.dev,
cypher-executor fetches them via HTTP POST
- API components (6): gmail, telegram, line_notify, google_sheets,
http_request, cron executed inline via fetch recipes in component-loader
- External URL support: any https:// componentId is fetched directly
(n8n webhooks, MCP endpoints, etc.)
- Add deploy-logic-components.sh script for building/deploying WASM Workers
- Add component-worker-template with inline WASI shim
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-04-16 16:59:12 +08:00
Leo
5534d60b60
fix: component-loader was calling wasm-executor with wrong signature
...
Rewrote createComponentLoader to directly use createWasiShim inline
instead of calling executeWasm(componentId, buffer, ctx) which doesn't
match wasm-executor's actual signature of executeWasm(input, options).
Also adds Module caching to avoid recompiling WASM on every request.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-04-16 16:18:50 +08:00
Leo
9590083851
fix: sink nodes should be Component not Output unless named output/result/end
...
Previously, the last node in any triplet chain was classified as Output type
and skipped by the executor (passthrough only). Now only nodes explicitly named
output/result/end/done are Output; all other sink nodes are Component and
will have their WASM executed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-04-16 16:16:28 +08:00
Leo
65769fc0dd
fix: graphSchema missing ON_SUCCESS edge type + label field
...
- Add all valid EdgeTypes to graphSchema.edges.type enum
- Add label field to graphSchema.nodes (graph-builder passes it)
- Was causing 圖定義產生失敗 for all /cypher/execute calls
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-04-16 16:07:51 +08:00
Leo
2594f8371d
feat: add /register endpoint + fix acr run Mode 1 (inline YAML execution)
...
- POST /register on cypher.arcrun.dev: HMAC-SHA256(email, ENCRYPTION_KEY) → ak_{32hex}, no DB needed
- acr run: Mode 1 (standard/local) now finds local YAML and POSTs to /cypher/execute inline
- acr init: fix register URL → cypher.arcrun.dev/register; fix local mode description
- acr init --local: creates hello.yaml example workflow
- cli v1.0.3 published
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-04-16 16:04:14 +08:00
Leo
9168253357
chore: fill wrangler.toml KV/R2 IDs and routes for production deploy
...
cypher-executor: EXEC_CONTEXT, WEBHOOKS, CREDENTIALS_KV, ANALYTICS_KV KV IDs,
arcrun-wasm R2, route cypher.arcrun.dev/*
registry: SUBMISSIONS_KV, ANALYTICS_KV KV IDs, arcrun-wasm R2,
route registry.arcrun.dev/*
credentials: CREDENTIALS_KV KV ID
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-04-16 15:36:26 +08:00
Leo
e630fca2df
fix(arcrun): address PR #2 review findings
...
Security:
- init.ts: remove cf_api_token from POST /register (only email sent to arcrun.dev)
- cf-api.ts: remove base64 fallback in encryptCredential, throw clear error if key missing
Correctness:
- submitComponent.ts: replace KBDB dependency with SUBMISSIONS_KV + R2 (standalone)
- registry/types.ts: remove KBDB_URL/KBDB_INTERNAL_TOKEN, add SUBMISSIONS_KV/ANALYTICS_KV
- webhooks.ts: add waitUntil(writeExecutionVerdict) for fire-and-forget analytics
- execution-logger.ts: create missing module (was imported but didn't exist)
- cypher-executor/types.ts + wrangler.toml: add ANALYTICS_KV binding
- gmail/telegram/google_sheets/line_notify/http_request: no_network_syscall false (api category)
- init.ts: replace require() with await import() for ES module compatibility
Cleanup:
- Remove arcrun/builtins/ (dead code — initComponents used old HTTP endpoint model,
all 21 components now in TinyGo WASM under registry/components/)
Docs:
- tasks.md: update to reflect completed work and remaining items
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-04-16 13:07:28 +08:00
Claude
2707fca32b
feat(arcrun): implement arcrun MVP — open-source AI workflow engine
...
Phase 1-5 complete per .agents/specs/u6u-core-mvp/:
**Phase 1 — Cherry-pick & cleanup**
- Create arcrun/ from cypher-executor, credentials, builtins, registry
- Remove 9 InkStone Service Bindings (KBDB, REGISTRY, CLINIC_*, AICEO, MINI_ME)
- Rewrite component-loader: 3-layer (builtin → WASM_BUCKET R2 → error)
- Remove autoPublishMissing.ts, proxy.ts (AICEO), execution-logger.ts (KBDB)
- Clean all KV namespace IDs and InkStone internal URLs from config files
**Phase 2 — contract.yaml completeness**
- Add credentials_required to gmail, google_sheets, telegram, line_notify
- Add config_example to all 21 components with annotated field descriptions
**Phase 3 — Credential injection**
- Add credential-injector.ts: AES-GCM decrypt from CREDENTIALS_KV
- Integrate into GraphExecutor before WASM execution
- Structured errors with repair instructions when credential missing
**Phase 4 — CLI (acr)**
- cli/package.json: arcrun package, bin: acr, deps: commander/js-yaml/chalk/ora
- 8 commands: init, creds push, push, run, validate, parts, list, logs
- Standard mode: writes directly to user's CF KV via CF REST API
- acr init: interactive setup with arcrun.dev API Key registration
**Phase 5 — Open source release prep**
- README.md: 5-minute quickstart, component table, workflow YAML syntax
- CONTRIBUTING.md: TinyGo dev env, component scaffolding, submission flow
- Security audit: no InkStone internal URLs/IDs in committed files
- .gitignore: exclude credentials.yaml, .wrangler, *.wasm
https://claude.ai/code/session_01BnCdSLVH8tUed9VrrPavgT
2026-04-16 04:06:25 +00:00