497f92a268
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>
61 lines
1.7 KiB
Bash
61 lines
1.7 KiB
Bash
#!/usr/bin/env bash
|
||
# 單一 component 註冊到 registry index
|
||
# SDD: matrix/arcrun/.agents/specs/component-registry-canon/design.md Phase 2
|
||
#
|
||
# 用法:
|
||
# bash scripts/register-component.sh <component_name>
|
||
# REGISTRY_URL=https://registry.arcrun.dev bash scripts/register-component.sh kbdb_ingest
|
||
#
|
||
# CI deploy 流程內也使用同樣邏輯(見 .github/workflows/deploy.yml 的 Register step)
|
||
# 此 script 是「本地 / hook 一致性」的 SSOT,CI 改邏輯時 script 跟著改
|
||
|
||
set -uo pipefail
|
||
|
||
REGISTRY_URL="${REGISTRY_URL:-https://registry.arcrun.dev}"
|
||
COMPONENT_NAME="${1:-}"
|
||
|
||
if [[ -z "$COMPONENT_NAME" ]]; then
|
||
echo "Usage: $0 <component_name>" >&2
|
||
exit 1
|
||
fi
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
COMPONENT_DIR="$SCRIPT_DIR/../components/$COMPONENT_NAME"
|
||
CONTRACT="$COMPONENT_DIR/component.contract.yaml"
|
||
|
||
if [[ ! -f "$CONTRACT" ]]; then
|
||
echo "::warning::no component.contract.yaml at $COMPONENT_DIR" >&2
|
||
exit 0
|
||
fi
|
||
|
||
python3 -c "import yaml" 2>/dev/null || {
|
||
echo "需要 python3 + pyyaml" >&2
|
||
exit 1
|
||
}
|
||
|
||
contract_json=$(python3 -c "
|
||
import yaml, json
|
||
with open('$CONTRACT') as f:
|
||
c = yaml.safe_load(f)
|
||
print(json.dumps({'contract': c}))
|
||
") || {
|
||
echo "::warning::無法解析 $CONTRACT" >&2
|
||
exit 0
|
||
}
|
||
|
||
echo "Registering $COMPONENT_NAME to $REGISTRY_URL ..."
|
||
http_code=$(curl -s -o /tmp/reg-response.json -w "%{http_code}" \
|
||
-X POST "$REGISTRY_URL/components/index-only" \
|
||
-H "Content-Type: application/json" \
|
||
-d "$contract_json")
|
||
|
||
if [[ "$http_code" =~ ^(200|201)$ ]]; then
|
||
echo "✓ $COMPONENT_NAME registered (HTTP $http_code)"
|
||
cat /tmp/reg-response.json
|
||
echo
|
||
else
|
||
echo "::warning::Registry 註冊失敗 HTTP $http_code" >&2
|
||
cat /tmp/reg-response.json || true
|
||
exit 1
|
||
fi
|