From 5fc7277c3ce8cfccc1e53aee6990fe99b11f80a1 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 7 Jul 2026 05:21:34 +0000 Subject: [PATCH 1/2] =?UTF-8?q?refactor(mcp):=20u6u=5F*=20tool=20=E5=85=A8?= =?UTF-8?q?=E9=9D=A2=20rename=20=E7=82=BA=20arcrun=5F*=20+=20=E5=89=8D?= =?UTF-8?q?=E7=B6=B4=E6=94=B6=E6=96=82=E5=96=AE=E4=B8=80=E4=BE=86=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 零 u6u 洩漏(leo 要求 1):connector tool 清單只剩 arcrun_*,並移除壞掉/ 重複的 u6u_ workflow tool(deploy/execute/get/list_workflows 由 arcrun_ push/run/get/list_workflows 取代);MCP server name 也由 u6u-mcp-server 改 arcrun-mcp-server。 前綴單一真相源(leo 要求 2):新增 mcp/src/brand.ts(TOOL_PREFIX + toolName() helper),所有 server.tool() 註冊一律走 toolName("suffix"),前綴不再明碼散寫。 未來 rebrand 只改 brand.ts 一行。 - 12 個獨有能力 tool rename(component/tag/gui/search_workflows) - 4 個重複/壞掉 tool 移除 - inter-tool hint、描述字串、註解內 u6u_ 名字全數更新 - tsc exit 0;vitest 19/19 綠 Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk --- cli/src/commands/list.ts | 2 +- mcp/src/brand.ts | 25 ++++++ mcp/src/mcp-handler.ts | 2 +- ...u6u_create_tag.ts => arcrun_create_tag.ts} | 3 +- ...u6u_delete_tag.ts => arcrun_delete_tag.ts} | 3 +- ...t_component.ts => arcrun_get_component.ts} | 7 +- ...guide.ts => arcrun_get_component_guide.ts} | 7 +- ...i_context.ts => arcrun_get_gui_context.ts} | 3 +- mcp/src/tools/arcrun_introspection.ts | 9 ++- ...omponents.ts => arcrun_list_components.ts} | 3 +- .../{u6u_list_tags.ts => arcrun_list_tags.ts} | 3 +- ...mponent.ts => arcrun_publish_component.ts} | 9 ++- mcp/src/tools/arcrun_recipe.ts | 13 +-- mcp/src/tools/arcrun_report_feedback.ts | 6 +- ...ponents.ts => arcrun_search_components.ts} | 7 +- ...orkflows.ts => arcrun_search_workflows.ts} | 9 ++- mcp/src/tools/arcrun_skills_examples.ts | 11 +-- ...tag_resource.ts => arcrun_tag_resource.ts} | 3 +- ...g_resource.ts => arcrun_untag_resource.ts} | 3 +- mcp/src/tools/arcrun_whoami.ts | 3 +- mcp/src/tools/arcrun_workflow_crud.ts | 21 +++-- mcp/src/tools/registry.ts | 37 ++++----- mcp/src/tools/u6u_deploy_workflow.ts | 81 ------------------- mcp/src/tools/u6u_execute_workflow.ts | 54 ------------- mcp/src/tools/u6u_get_workflow.ts | 33 -------- mcp/src/tools/u6u_list_workflows.ts | 62 -------------- 26 files changed, 111 insertions(+), 308 deletions(-) create mode 100644 mcp/src/brand.ts rename mcp/src/tools/{u6u_create_tag.ts => arcrun_create_tag.ts} (96%) rename mcp/src/tools/{u6u_delete_tag.ts => arcrun_delete_tag.ts} (95%) rename mcp/src/tools/{u6u_get_component.ts => arcrun_get_component.ts} (90%) rename mcp/src/tools/{u6u_get_component_guide.ts => arcrun_get_component_guide.ts} (78%) rename mcp/src/tools/{u6u_get_gui_context.ts => arcrun_get_gui_context.ts} (97%) rename mcp/src/tools/{u6u_list_components.ts => arcrun_list_components.ts} (96%) rename mcp/src/tools/{u6u_list_tags.ts => arcrun_list_tags.ts} (94%) rename mcp/src/tools/{u6u_publish_component.ts => arcrun_publish_component.ts} (92%) rename mcp/src/tools/{u6u_search_components.ts => arcrun_search_components.ts} (92%) rename mcp/src/tools/{u6u_search_workflows.ts => arcrun_search_workflows.ts} (91%) rename mcp/src/tools/{u6u_tag_resource.ts => arcrun_tag_resource.ts} (97%) rename mcp/src/tools/{u6u_untag_resource.ts => arcrun_untag_resource.ts} (96%) delete mode 100644 mcp/src/tools/u6u_deploy_workflow.ts delete mode 100644 mcp/src/tools/u6u_execute_workflow.ts delete mode 100644 mcp/src/tools/u6u_get_workflow.ts delete mode 100644 mcp/src/tools/u6u_list_workflows.ts diff --git a/cli/src/commands/list.ts b/cli/src/commands/list.ts index 7903b42..8b6bc91 100644 --- a/cli/src/commands/list.ts +++ b/cli/src/commands/list.ts @@ -4,7 +4,7 @@ * thin-shell-alignment P1(issue #11):原本直連 CF KV 讀 `workflow:` 前綴(CfKvClient), * 有兩個漂移:① 前綴對不上(部署寫 `{apiKey}:wf:` → 永遠列不到新部署)② 薄殼直碰底層儲存 * (self-hosted 用戶需 CF API token 才能 list)。改走 cypher `GET /webhooks/named`(KV 源,與 - * MCP u6u_list_workflows 同源),薄殼不再直連 KV、key 前綴 bug 自然消失。 + * MCP arcrun_list_workflows 同源),薄殼不再直連 KV、key 前綴 bug 自然消失。 */ import chalk from 'chalk'; import ora from 'ora'; diff --git a/mcp/src/brand.ts b/mcp/src/brand.ts new file mode 100644 index 0000000..1b600bb --- /dev/null +++ b/mcp/src/brand.ts @@ -0,0 +1,25 @@ +/** + * brand.ts — MCP tool 名前綴的單一真相源(single source of truth)。 + * + * 為什麼存在(leo 硬要求 2): + * 歷史上 tool 名前綴(早期 "u6u_"、對外改名後應為 "arcrun_")被明碼散寫在 + * ~39 個 tool 檔裡,每次 rebrand 都得逐檔手改、極易漏 → u6u 洩漏給用戶。 + * 收斂成這一個常數後,未來再 rebrand「只改這一行」。 + * + * 用法: + * import { toolName } from "../brand.js"; + * server.tool(toolName("push_workflow"), ...) // → "arcrun_push_workflow" + * + * 語意後綴(push_workflow / list_tags …)保留可讀,只有「品牌前綴」被變數化。 + * + * 可用環境變數 ARCRUN_TOOL_PREFIX 覆蓋(測試 / 未來 rebrand 過渡用),預設 "arcrun"。 + * (Workers runtime 無 process 全域,故用 globalThis 安全取值,取不到就 fallback。) + */ + +const envPrefix = (globalThis as { process?: { env?: Record } }) + .process?.env?.ARCRUN_TOOL_PREFIX; + +export const TOOL_PREFIX = envPrefix || "arcrun"; + +/** 把語意後綴組成完整 tool 名,例:toolName("whoami") → "arcrun_whoami"。 */ +export const toolName = (suffix: string): string => `${TOOL_PREFIX}_${suffix}`; diff --git a/mcp/src/mcp-handler.ts b/mcp/src/mcp-handler.ts index c5f17fa..d062552 100644 --- a/mcp/src/mcp-handler.ts +++ b/mcp/src/mcp-handler.ts @@ -10,7 +10,7 @@ export async function handleMcpRequest( partnerToken: string, ): Promise { const transport = new WebStandardStreamableHTTPServerTransport({ sessionIdGenerator: undefined }); - const server = new McpServer({ name: "u6u-mcp-server", version: "1.0.0" }); + const server = new McpServer({ name: "arcrun-mcp-server", version: "1.0.0" }); registerAllTools(server, env, orgNamespace, partnerToken); await server.connect(transport); diff --git a/mcp/src/tools/u6u_create_tag.ts b/mcp/src/tools/arcrun_create_tag.ts similarity index 96% rename from mcp/src/tools/u6u_create_tag.ts rename to mcp/src/tools/arcrun_create_tag.ts index 21e3091..0dc9e60 100644 --- a/mcp/src/tools/u6u_create_tag.ts +++ b/mcp/src/tools/arcrun_create_tag.ts @@ -1,11 +1,12 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; import { kbdbFetch } from "../lib/kbdb-client.js"; export function registerCreateTag(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_create_tag", + toolName("create_tag"), "在當前命名空間下建立新的 tag,用於分類工作流與零件。", { name: z.string().describe("Tag 名稱(在當前 org_namespace 下唯一)"), diff --git a/mcp/src/tools/u6u_delete_tag.ts b/mcp/src/tools/arcrun_delete_tag.ts similarity index 95% rename from mcp/src/tools/u6u_delete_tag.ts rename to mcp/src/tools/arcrun_delete_tag.ts index 8627ea5..3b0ccf8 100644 --- a/mcp/src/tools/u6u_delete_tag.ts +++ b/mcp/src/tools/arcrun_delete_tag.ts @@ -1,11 +1,12 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; import { kbdbFetch } from "../lib/kbdb-client.js"; export function registerDeleteTag(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_delete_tag", + toolName("delete_tag"), "刪除當前命名空間下的指定 tag。", { tag_name: z.string().describe("要刪除的 Tag 名稱") }, async ({ tag_name }) => { diff --git a/mcp/src/tools/u6u_get_component.ts b/mcp/src/tools/arcrun_get_component.ts similarity index 90% rename from mcp/src/tools/u6u_get_component.ts rename to mcp/src/tools/arcrun_get_component.ts index 92cf23a..d2f9e6c 100644 --- a/mcp/src/tools/u6u_get_component.ts +++ b/mcp/src/tools/arcrun_get_component.ts @@ -1,14 +1,15 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; /** - * u6u_get_component — 取得零件完整合約 + * arcrun_get_component — 取得零件完整合約 * 呼叫 Component Registry GET /components/:id */ export function registerGetComponent(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_get_component", + toolName("get_component"), "取得指定零件的完整合約,包含 canonical_id、display_name、category、version、stability、input_schema、output_schema、gherkin_tests、評分統計等。", { canonical_id: z.string().describe("零件 canonical_id(如 validate_json)"), @@ -29,7 +30,7 @@ export function registerGetComponent(server: McpServer, env: Env, orgNamespace: if (response.status === 404) { return { - content: [{ type: "text", text: `零件 '${canonical_id}' 不存在。可用 u6u_search_components 搜尋相似零件。` }], + content: [{ type: "text", text: `零件 '${canonical_id}' 不存在。可用 arcrun_search_components 搜尋相似零件。` }], isError: true, }; } diff --git a/mcp/src/tools/u6u_get_component_guide.ts b/mcp/src/tools/arcrun_get_component_guide.ts similarity index 78% rename from mcp/src/tools/u6u_get_component_guide.ts rename to mcp/src/tools/arcrun_get_component_guide.ts index c3b753d..c1e8fea 100644 --- a/mcp/src/tools/u6u_get_component_guide.ts +++ b/mcp/src/tools/arcrun_get_component_guide.ts @@ -1,15 +1,16 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { Env } from "../types.js"; /** - * u6u_get_component_guide — 取得零件開發指引 + * arcrun_get_component_guide — 取得零件開發指引 * 呼叫 Component Registry GET /components/guide * AI 在開發新零件前應先讀取此指引 */ export function registerGetComponentGuide(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_get_component_guide", - "取得 u6u 零件開發指引(Markdown 格式)。包含 TinyGo 白名單 import、禁止行為、component.contract.yaml 完整範例、本地測試指令。開發新零件前必須先讀取此指引。", + toolName("get_component_guide"), + "取得 arcrun 零件開發指引(Markdown 格式)。包含 TinyGo 白名單 import、禁止行為、component.contract.yaml 完整範例、本地測試指令。開發新零件前必須先讀取此指引。", {}, async () => { try { diff --git a/mcp/src/tools/u6u_get_gui_context.ts b/mcp/src/tools/arcrun_get_gui_context.ts similarity index 97% rename from mcp/src/tools/u6u_get_gui_context.ts rename to mcp/src/tools/arcrun_get_gui_context.ts index 7955128..e1584a2 100644 --- a/mcp/src/tools/u6u_get_gui_context.ts +++ b/mcp/src/tools/arcrun_get_gui_context.ts @@ -1,4 +1,5 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; import { kbdbFetch } from "../lib/kbdb-client.js"; @@ -17,7 +18,7 @@ interface ActionLogRecord { export function registerGetGuiContext(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_get_gui_context", + toolName("get_gui_context"), "查詢用戶在 GUI 上的最近操作記錄,了解用戶的當前意圖與操作上下文。" + "回傳最近 N 條操作記錄(從新到舊),以及用戶當前所在頁面和正在編輯的 Workflow ID。", { diff --git a/mcp/src/tools/arcrun_introspection.ts b/mcp/src/tools/arcrun_introspection.ts index 9beabb5..f7ab4f8 100644 --- a/mcp/src/tools/arcrun_introspection.ts +++ b/mcp/src/tools/arcrun_introspection.ts @@ -11,6 +11,7 @@ */ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import type { Env } from "../types.js"; import { cypherFetch, errorResponse, successResponse } from "../lib/cypher-client.js"; @@ -20,7 +21,7 @@ const apiKeyDesc = export function registerValidateYaml(server: McpServer, env: Env) { server.tool( - "arcrun_validate_yaml", + toolName("validate_yaml"), "Dry-run YAML 校驗。不部署、無 side effect。回 {valid, errors?, nodeCount, edgeCount}。**永遠先 call 此 tool 再 push_workflow**,避免反覆 deploy 失敗。", { api_key: z.string().describe(apiKeyDesc), @@ -73,7 +74,7 @@ export function registerValidateYaml(server: McpServer, env: Env) { export function registerListPausedExecutions(server: McpServer, env: Env) { server.tool( - "arcrun_list_paused_executions", + toolName("list_paused_executions"), "列當前 api_key 下所有 paused workflow(等 daemon callback resume 的)。給 debug 用:claude_api 等 async 零件會把 workflow 暫停,此 tool 告訴你哪些還沒回來。", { api_key: z.string().describe(apiKeyDesc), @@ -108,7 +109,7 @@ export function registerListPausedExecutions(server: McpServer, env: Env) { export function registerGetExecutionTrace(server: McpServer, env: Env) { server.tool( - "arcrun_get_execution_trace", + toolName("get_execution_trace"), "看單一 paused workflow 的 state 細節(trace、graph、context、pending_result)。task_id 從 paused 錯誤訊息或 list_paused_executions 取得。", { api_key: z.string().describe(apiKeyDesc), @@ -156,7 +157,7 @@ export function registerGetExecutionTrace(server: McpServer, env: Env) { export function registerListRecentExecutions(server: McpServer, env: Env) { server.tool( - "arcrun_list_recent_executions", + toolName("list_recent_executions"), "列某 workflow 最近 N 次執行 verdict(成功 / 失敗 / duration)。資料來源是 ANALYTICS_KV 90 天保留期。", { api_key: z.string().describe(apiKeyDesc), diff --git a/mcp/src/tools/u6u_list_components.ts b/mcp/src/tools/arcrun_list_components.ts similarity index 96% rename from mcp/src/tools/u6u_list_components.ts rename to mcp/src/tools/arcrun_list_components.ts index 2f136fa..a715621 100644 --- a/mcp/src/tools/u6u_list_components.ts +++ b/mcp/src/tools/arcrun_list_components.ts @@ -1,11 +1,12 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; import { kbdbFetch } from "../lib/kbdb-client.js"; export function registerListComponents(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_list_components", + toolName("list_components"), "列出當前命名空間下所有已發佈的零件,可選擇按 tag 篩選。", { tag: z.string().optional().describe("按 tag 名稱篩選(選填)") }, async ({ tag }) => { diff --git a/mcp/src/tools/u6u_list_tags.ts b/mcp/src/tools/arcrun_list_tags.ts similarity index 94% rename from mcp/src/tools/u6u_list_tags.ts rename to mcp/src/tools/arcrun_list_tags.ts index 2674c1b..0244f6e 100644 --- a/mcp/src/tools/u6u_list_tags.ts +++ b/mcp/src/tools/arcrun_list_tags.ts @@ -1,10 +1,11 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { Env } from "../types.js"; import { kbdbFetch } from "../lib/kbdb-client.js"; export function registerListTags(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_list_tags", + toolName("list_tags"), "列出當前命名空間下所有的 tag。", {}, async () => { diff --git a/mcp/src/tools/u6u_publish_component.ts b/mcp/src/tools/arcrun_publish_component.ts similarity index 92% rename from mcp/src/tools/u6u_publish_component.ts rename to mcp/src/tools/arcrun_publish_component.ts index eb1c88a..4332703 100644 --- a/mcp/src/tools/u6u_publish_component.ts +++ b/mcp/src/tools/arcrun_publish_component.ts @@ -1,20 +1,21 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; /** - * u6u_publish_component — 提交 TinyGo WASM 零件至 Component Registry + * arcrun_publish_component — 提交 TinyGo WASM 零件至 Component Registry * * AI 工作流: - * 1. 先呼叫 u6u_get_component_guide 取得開發指引 + * 1. 先呼叫 arcrun_get_component_guide 取得開發指引 * 2. 依指引用 TinyGo 撰寫零件(stdin/stdout JSON I/O) * 3. 編譯為 .wasm,base64 編碼後提交 * 4. Registry 自動執行沙盒驗收(體積、syscall 掃描、Gherkin 測試) */ export function registerPublishComponent(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_publish_component", - "提交 TinyGo WASM 零件至 Component Registry。需提供 component.contract.yaml 內容與編譯後的 .wasm base64。提交前請先呼叫 u6u_get_component_guide 取得開發規範。", + toolName("publish_component"), + "提交 TinyGo WASM 零件至 Component Registry。需提供 component.contract.yaml 內容與編譯後的 .wasm base64。提交前請先呼叫 arcrun_get_component_guide 取得開發規範。", { contract: z.object({ canonical_id: z.string().describe("零件功能名稱(小寫底線,如 validate_json)"), diff --git a/mcp/src/tools/arcrun_recipe.ts b/mcp/src/tools/arcrun_recipe.ts index e90d497..e7c97cc 100644 --- a/mcp/src/tools/arcrun_recipe.ts +++ b/mcp/src/tools/arcrun_recipe.ts @@ -11,6 +11,7 @@ */ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import type { Env } from "../types.js"; import { cypherFetch, errorResponse, successResponse } from "../lib/cypher-client.js"; @@ -30,7 +31,7 @@ export function registerAllRecipeTools(server: McpServer, env: Env) { /** arcrun_recipe_search — 搜尋公庫 recipe(同名可多作者,附市場數據)。落空回創作引導。 */ export function registerRecipeSearch(server: McpServer, env: Env) { server.tool( - "arcrun_recipe_search", + toolName("recipe_search"), "搜尋公庫 recipe(API 整合配方)。同 canonical_id 可有多作者版本,各附市場數據(成功/失敗次數),依數據選最佳。找不到時會提示可自己做一個 recipe 投稿成為作者。", { api_key: z.string().describe(apiKeyDesc), @@ -58,7 +59,7 @@ export function registerRecipeSearch(server: McpServer, env: Env) { /** arcrun_recipe_pull — 從公庫取一份 recipe 寫進自己私庫。 */ export function registerRecipePull(server: McpServer, env: Env) { server.tool( - "arcrun_recipe_pull", + toolName("recipe_pull"), "從公庫取一份 recipe 寫進自己私庫(按需取用,非全量同步)。不指定 author 取市場最佳版本。取回後可在 workflow 用 component: 。", { api_key: z.string().describe(apiKeyDesc), @@ -108,7 +109,7 @@ export function registerRecipePull(server: McpServer, env: Env) { /** arcrun_recipe_submit_p — 把私庫某 recipe 投稿到公庫(新增作者版本)。 */ export function registerRecipeSubmitP(server: McpServer, env: Env) { server.tool( - "arcrun_recipe_submit_p", + toolName("recipe_submit_p"), "把私庫某 recipe 投稿到公庫(app-store 模型:新增一個作者版本,不覆蓋別人的)。投稿 = 把 recipe 暴露給全網,需帶 exposure_consent 明示同意。別人能搜到並 pull,市場數據決定它被不被選用。", { api_key: z.string().describe(apiKeyDesc), @@ -160,7 +161,7 @@ export function registerRecipeSubmitP(server: McpServer, env: Env) { /** arcrun_recipe_push — 上傳/更新私庫 recipe(就地更新自己的版本)。 */ export function registerRecipePush(server: McpServer, env: Env) { server.tool( - "arcrun_recipe_push", + toolName("recipe_push"), "上傳一份 recipe 到自己私庫(或就地更新自己既有版本)。recipe = 「http_request + 參數模板」的具名封裝,不需 deploy Worker。要投稿到公庫用 arcrun_recipe_submit_p。", { api_key: z.string().describe(apiKeyDesc), @@ -192,7 +193,7 @@ export function registerRecipePush(server: McpServer, env: Env) { /** arcrun_recipe_list — 列出自己私庫的 recipe。 */ export function registerRecipeList(server: McpServer, env: Env) { server.tool( - "arcrun_recipe_list", + toolName("recipe_list"), "列出自己私庫(本部署)的 recipe。要找公庫的用 arcrun_recipe_search。", { api_key: z.string().describe(apiKeyDesc), @@ -213,7 +214,7 @@ export function registerRecipeList(server: McpServer, env: Env) { /** arcrun_recipe_delete — 刪除私庫某 recipe。 */ export function registerRecipeDelete(server: McpServer, env: Env) { server.tool( - "arcrun_recipe_delete", + toolName("recipe_delete"), "刪除自己私庫某 recipe(canonical_id / rec_hash / uuid)。不影響公庫別人的版本。", { api_key: z.string().describe(apiKeyDesc), diff --git a/mcp/src/tools/arcrun_report_feedback.ts b/mcp/src/tools/arcrun_report_feedback.ts index 6f61fe1..1041d11 100644 --- a/mcp/src/tools/arcrun_report_feedback.ts +++ b/mcp/src/tools/arcrun_report_feedback.ts @@ -8,11 +8,11 @@ * * 後續 M4 weekly_review workflow 聚合這些 block 產出 arcrun-roadmap。 * - * 命名注意:M5 全面 rename u6u → arcrun 前,本 tool 直接用新名 arcrun_ prefix - * 立下範例。其他 u6u_* tool 等 M5 一次切。 + * tool 名前綴走 brand.ts 的 toolName() helper(single source of truth)。 */ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; import { kbdbFetch } from "../lib/kbdb-client.js"; @@ -28,7 +28,7 @@ const ISSUE_TYPES = [ export function registerReportFeedback(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "arcrun_report_feedback", + toolName("report_feedback"), "AI agent 完成 workflow 任務 / 卡住 / 解掉問題後 **必須** call 此 tool 回報。即使順利也要 call (issue_type=success_story),那是告訴平台「這 pattern 已 work,可推廣」。回饋會寫進 KBDB type=agent-feedback,週報自動聚合產出平台改善 roadmap。", { issue_type: z.enum(ISSUE_TYPES).describe( diff --git a/mcp/src/tools/u6u_search_components.ts b/mcp/src/tools/arcrun_search_components.ts similarity index 92% rename from mcp/src/tools/u6u_search_components.ts rename to mcp/src/tools/arcrun_search_components.ts index 96896f8..9286561 100644 --- a/mcp/src/tools/u6u_search_components.ts +++ b/mcp/src/tools/arcrun_search_components.ts @@ -1,14 +1,15 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; /** - * u6u_search_components — 語意搜尋零件庫 + * arcrun_search_components — 語意搜尋零件庫 * 呼叫 Component Registry GET /components/search?q=... */ export function registerSearchComponents(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_search_components", + toolName("search_components"), "用自然語言語意搜尋零件庫,找出符合需求的零件。例如:「查詢 Google Sheets 資料」、「發送 LINE 訊息」、「驗證 JSON 格式」。回傳零件清單含 canonical_id、描述、評分。", { query: z.string().describe("自然語言搜尋詞,如「查詢 Google Sheets 資料」"), @@ -43,7 +44,7 @@ export function registerSearchComponents(server: McpServer, env: Env, orgNamespa return { content: [{ type: "text", - text: `找不到符合「${query}」的零件。可以用 u6u_publish_component 提交新零件。`, + text: `找不到符合「${query}」的零件。可以用 arcrun_publish_component 提交新零件。`, }], }; } diff --git a/mcp/src/tools/u6u_search_workflows.ts b/mcp/src/tools/arcrun_search_workflows.ts similarity index 91% rename from mcp/src/tools/u6u_search_workflows.ts rename to mcp/src/tools/arcrun_search_workflows.ts index fb68881..2ec83fd 100644 --- a/mcp/src/tools/u6u_search_workflows.ts +++ b/mcp/src/tools/arcrun_search_workflows.ts @@ -1,15 +1,16 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; /** - * u6u_search_workflows — 用自然語言找現成工作流(workflow-discovery R2) + * arcrun_search_workflows — 用自然語言找現成工作流(workflow-discovery R2) * * 北極星入口:AI 先查「有沒有現成工作流能做這件事」→ 找到就執行,別重造。 * 呼叫 cypher GET /workflows/search → 轉發 KBDB /entries/search(entry_type=workflow + 本租戶)。 * 優先語意搜尋;KBDB 未開 Vectorize → 自動降級關鍵字 + 回 capability_hint(不假裝語義)。 * - * 薄殼(rule 07):只做參數轉換 + 呼叫 + 格式化,零業務邏輯。形態對齊 u6u_search_components。 + * 薄殼(rule 07):只做參數轉換 + 呼叫 + 格式化,零業務邏輯。形態對齊 arcrun_search_components。 * flag 安全:AI 收到意圖時主動 call 一次,無輪詢/排程。 */ export function registerSearchWorkflows( @@ -19,7 +20,7 @@ export function registerSearchWorkflows( partnerToken: string, ) { server.tool( - "u6u_search_workflows", + toolName("search_workflows"), "用自然語言找現成的工作流(先查有沒有現成的能做這件事,找到就用,別重造)。例如:「把資料寫進 Google Sheets」、「每天抓 RSS 發通知」、「webhook 轉發到別的 API」。回傳本帳號下符合的工作流清單。", { query: z.string().describe("自然語言描述要找的工作流,如「把資料寫進 Google Sheets」"), @@ -60,7 +61,7 @@ export function registerSearchWorkflows( return { content: [{ type: "text", - text: `找不到符合「${query}」的現成工作流。可以用 u6u_deploy_workflow 部署一個新的。${hint}`, + text: `找不到符合「${query}」的現成工作流。可以用 arcrun_push_workflow 部署一個新的。${hint}`, }], }; } diff --git a/mcp/src/tools/arcrun_skills_examples.ts b/mcp/src/tools/arcrun_skills_examples.ts index 943ea92..5ac1539 100644 --- a/mcp/src/tools/arcrun_skills_examples.ts +++ b/mcp/src/tools/arcrun_skills_examples.ts @@ -25,6 +25,7 @@ */ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import type { Env } from "../types.js"; import { kbdbFetch } from "../lib/kbdb-client.js"; @@ -68,7 +69,7 @@ function parseTags(tagsJson?: string): string[] { export function registerListSkills(server: McpServer, env: Env) { server.tool( - "arcrun_list_skills", + toolName("list_skills"), "列所有 agent-skill blocks(從 arcrun/registry/skills/ 同步進 KBDB)。每個 skill 是個 markdown playbook,描述 AI 面對 X 問題該怎麼想 + 該用哪個 example。回 [{slug, title, tags}]。call get_skill(slug) 拿完整內文。", { tag: z.string().optional().describe("optional 標籤過濾。如 'rag' / 'watcher' / 'debug'"), @@ -115,7 +116,7 @@ export function registerListSkills(server: McpServer, env: Env) { export function registerGetSkill(server: McpServer, env: Env) { server.tool( - "arcrun_get_skill", + toolName("get_skill"), "拿單一 agent-skill 完整 markdown playbook。slug 從 list_skills 取得。", { slug: z.string().describe("skill slug,例如 'build_watcher_workflow' / 'rag_with_arcrun'"), @@ -153,7 +154,7 @@ export function registerGetSkill(server: McpServer, env: Env) { export function registerListExamples(server: McpServer, env: Env) { server.tool( - "arcrun_list_examples", + toolName("list_examples"), "列所有 workflow-example blocks(從 arcrun/registry/examples/ 同步進 KBDB)。每個 example 是可直接 push 的 workflow YAML 範本 + description。回 [{slug, tags}]。call get_example / search_examples 拿細節。", { tag: z.string().optional().describe("optional 標籤過濾。如 'rag' / 'cron' / 'llm' / 'webhook'"), @@ -194,7 +195,7 @@ export function registerListExamples(server: McpServer, env: Env) { export function registerGetExample(server: McpServer, env: Env) { server.tool( - "arcrun_get_example", + toolName("get_example"), "拿單一 workflow-example 完整 YAML + description。slug 從 list_examples / search_examples 取得。可直接拿 YAML 改成你自己的 → push。", { slug: z.string().describe("example slug,例如 'rag-search-answer' / 'cron-watcher'"), @@ -243,7 +244,7 @@ export function registerGetExample(server: McpServer, env: Env) { export function registerSearchExamples(server: McpServer, env: Env) { server.tool( - "arcrun_search_examples", + toolName("search_examples"), "用 use case 關鍵字搜 workflow examples,回最相關 N 個。" + "注意:基本盤目前是 D1 LIKE 關鍵字搜尋(非語義 embedding;語義是 kbdb-base Phase 1 的 embed 模組,尚未上)。" + "→ 用具體詞('email'、'cron'、'rag')比整句自然語言命中率高。也會比對 slug/tag。", diff --git a/mcp/src/tools/u6u_tag_resource.ts b/mcp/src/tools/arcrun_tag_resource.ts similarity index 97% rename from mcp/src/tools/u6u_tag_resource.ts rename to mcp/src/tools/arcrun_tag_resource.ts index 40adc2f..6844b79 100644 --- a/mcp/src/tools/u6u_tag_resource.ts +++ b/mcp/src/tools/arcrun_tag_resource.ts @@ -1,11 +1,12 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; import { kbdbFetch } from "../lib/kbdb-client.js"; export function registerTagResource(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_tag_resource", + toolName("tag_resource"), "為當前命名空間下的工作流或零件加上 tag 標籤。", { resource_type: z.enum(["workflow", "component"]).describe("資源類型:workflow 或 component"), diff --git a/mcp/src/tools/u6u_untag_resource.ts b/mcp/src/tools/arcrun_untag_resource.ts similarity index 96% rename from mcp/src/tools/u6u_untag_resource.ts rename to mcp/src/tools/arcrun_untag_resource.ts index 6f58632..b8bcc95 100644 --- a/mcp/src/tools/u6u_untag_resource.ts +++ b/mcp/src/tools/arcrun_untag_resource.ts @@ -1,11 +1,12 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import { Env } from "../types.js"; import { kbdbFetch } from "../lib/kbdb-client.js"; export function registerUntagResource(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "u6u_untag_resource", + toolName("untag_resource"), "移除當前命名空間下工作流或零件的 tag 標籤。", { resource_type: z.enum(["workflow", "component"]).describe("資源類型:workflow 或 component"), diff --git a/mcp/src/tools/arcrun_whoami.ts b/mcp/src/tools/arcrun_whoami.ts index eba73c1..24ee23c 100644 --- a/mcp/src/tools/arcrun_whoami.ts +++ b/mcp/src/tools/arcrun_whoami.ts @@ -8,11 +8,12 @@ * 薄殼:只回報 MCP 已解析的 orgNamespace(綁哪個帳號)+ cypher binding 連向,無業務邏輯。 */ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { Env } from "../types.js"; export function registerWhoami(server: McpServer, env: Env, orgNamespace: string) { server.tool( - "arcrun_whoami", + toolName("whoami"), "回報這個 MCP 連線目前生效的身份:綁哪個帳號 / namespace、cypher 連向哪。" + "部署 / 觸發 / 查 workflow 前先 call 此 tool 確認帳號,**不要自己 curl 猜帳號 URL**(會打到錯帳號)。", {}, diff --git a/mcp/src/tools/arcrun_workflow_crud.ts b/mcp/src/tools/arcrun_workflow_crud.ts index e56836e..96d2553 100644 --- a/mcp/src/tools/arcrun_workflow_crud.ts +++ b/mcp/src/tools/arcrun_workflow_crud.ts @@ -3,9 +3,8 @@ * * 對應 .agents/specs/llm-interface/ Milestone 2.2。 * - * 取代既有 u6u_deploy_workflow(呼叫 /workflows/deploy — 該 endpoint 不存在, - * 是壞掉的 tool)+ u6u_list_workflows / u6u_get_workflow 透過 KBDB 撈 metadata - * 而非直接問 cypher-executor 的真實狀態。 + * 取代早期壞掉的 deploy_workflow(呼叫 /workflows/deploy — 該 endpoint 不存在), + * 以及舊的 list/get workflow(透過 KBDB 撈 metadata 而非直接問 cypher-executor 真實狀態)。 * * 新 tool 直打 cypher-executor /webhooks/named*: * - arcrun_push_workflow @@ -14,11 +13,11 @@ * - arcrun_delete_workflow * - arcrun_run_workflow * - * 舊 u6u_* 待 M5 一次 rename + 退場(leo 2026-05-16 拍板)。在此之前, - * AI 看到兩套 tool — 用 arcrun_* 為主,u6u_* 有 deprecation hint。 + * tool 名前綴一律走 brand.ts 的 toolName() helper(single source of truth)。 */ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { toolName } from "../brand.js"; import { z } from "zod"; import type { Env } from "../types.js"; import { cypherFetch, errorResponse, successResponse } from "../lib/cypher-client.js"; @@ -34,8 +33,8 @@ const apiKeyDesc = */ export function registerPushWorkflow(server: McpServer, env: Env) { server.tool( - "arcrun_push_workflow", - "部署 workflow 到 arcrun(取代 u6u_deploy_workflow,後者打不存在的 endpoint)。輸入可以是 YAML 字串或 graph 物件。**建議先 call arcrun_validate_yaml 確認 schema**。", + toolName("push_workflow"), + "部署 workflow 到 arcrun。輸入可以是 YAML 字串或 graph 物件。**建議先 call arcrun_validate_yaml 確認 schema**。", { api_key: z.string().describe(apiKeyDesc), yaml_content: z.string().optional().describe( @@ -147,7 +146,7 @@ export function registerPushWorkflow(server: McpServer, env: Env) { export function registerListWorkflows(server: McpServer, env: Env) { server.tool( - "arcrun_list_workflows", + toolName("list_workflows"), "列出你 (api_key 對應 namespace) 已部署的所有 workflow。回 [{name}]。", { api_key: z.string().describe(apiKeyDesc), @@ -185,7 +184,7 @@ export function registerListWorkflows(server: McpServer, env: Env) { export function registerGetWorkflow(server: McpServer, env: Env) { server.tool( - "arcrun_get_workflow", + toolName("get_workflow"), "看單一 workflow 的完整定義(graph + config)。", { api_key: z.string().describe(apiKeyDesc), @@ -248,7 +247,7 @@ export function registerGetWorkflow(server: McpServer, env: Env) { export function registerDeleteWorkflow(server: McpServer, env: Env) { server.tool( - "arcrun_delete_workflow", + toolName("delete_workflow"), "刪除 workflow。**不可逆,確認後再做**。會清掉對應 cron index 與 webhook URL。", { api_key: z.string().describe(apiKeyDesc), @@ -292,7 +291,7 @@ export function registerDeleteWorkflow(server: McpServer, env: Env) { export function registerRunWorkflow(server: McpServer, env: Env) { server.tool( - "arcrun_run_workflow", + toolName("run_workflow"), "觸發 workflow 執行。input 物件帶進 trigger context。回 {success, data, trace?, duration_ms}。", { api_key: z.string().describe(apiKeyDesc), diff --git a/mcp/src/tools/registry.ts b/mcp/src/tools/registry.ts index d333296..3790ab4 100644 --- a/mcp/src/tools/registry.ts +++ b/mcp/src/tools/registry.ts @@ -1,21 +1,17 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { Env } from "../types.js"; -import { registerSearchComponents } from "./u6u_search_components.js"; -import { registerExecuteWorkflow } from "./u6u_execute_workflow.js"; -import { registerDeployWorkflow } from "./u6u_deploy_workflow.js"; -import { registerPublishComponent } from "./u6u_publish_component.js"; -import { registerListWorkflows } from "./u6u_list_workflows.js"; -import { registerGetWorkflow } from "./u6u_get_workflow.js"; -import { registerSearchWorkflows } from "./u6u_search_workflows.js"; -import { registerListComponents } from "./u6u_list_components.js"; -import { registerGetComponent } from "./u6u_get_component.js"; -import { registerGetComponentGuide } from "./u6u_get_component_guide.js"; -import { registerCreateTag } from "./u6u_create_tag.js"; -import { registerListTags } from "./u6u_list_tags.js"; -import { registerDeleteTag } from "./u6u_delete_tag.js"; -import { registerTagResource } from "./u6u_tag_resource.js"; -import { registerUntagResource } from "./u6u_untag_resource.js"; -import { registerGetGuiContext } from "./u6u_get_gui_context.js"; +import { registerSearchComponents } from "./arcrun_search_components.js"; +import { registerPublishComponent } from "./arcrun_publish_component.js"; +import { registerSearchWorkflows } from "./arcrun_search_workflows.js"; +import { registerListComponents } from "./arcrun_list_components.js"; +import { registerGetComponent } from "./arcrun_get_component.js"; +import { registerGetComponentGuide } from "./arcrun_get_component_guide.js"; +import { registerCreateTag } from "./arcrun_create_tag.js"; +import { registerListTags } from "./arcrun_list_tags.js"; +import { registerDeleteTag } from "./arcrun_delete_tag.js"; +import { registerTagResource } from "./arcrun_tag_resource.js"; +import { registerUntagResource } from "./arcrun_untag_resource.js"; +import { registerGetGuiContext } from "./arcrun_get_gui_context.js"; import { registerReportFeedback } from "./arcrun_report_feedback.js"; import { registerAllIntrospectionTools } from "./arcrun_introspection.js"; import { registerAllWorkflowCrudTools } from "./arcrun_workflow_crud.js"; @@ -26,11 +22,7 @@ import { registerWhoami } from "./arcrun_whoami.js"; export function registerAllTools(server: McpServer, env: Env, orgNamespace: string, partnerToken: string) { registerSearchComponents(server, env, orgNamespace); - registerExecuteWorkflow(server, env, orgNamespace, partnerToken); - registerDeployWorkflow(server, env, orgNamespace); registerPublishComponent(server, env, orgNamespace); - registerListWorkflows(server, env, orgNamespace, partnerToken); // thin-shell-alignment P1: list 改讀 /webhooks/named - registerGetWorkflow(server, env, orgNamespace); registerSearchWorkflows(server, env, orgNamespace, partnerToken); // workflow-discovery R2 registerListComponents(server, env, orgNamespace); registerGetComponent(server, env, orgNamespace); @@ -41,12 +33,13 @@ export function registerAllTools(server: McpServer, env: Env, orgNamespace: stri registerTagResource(server, env, orgNamespace); registerUntagResource(server, env, orgNamespace); registerGetGuiContext(server, env, orgNamespace); - // LI SDD M1.3: explicit feedback tool (新命名規範 arcrun_*) + // LI SDD M1.3: explicit feedback tool(arcrun_* 命名規範) registerReportFeedback(server, env, orgNamespace); // LI SDD M2.2: introspection tools (validate / paused / trace / recent executions) registerAllIntrospectionTools(server, env); // LI SDD M2.2: workflow CRUD (push / list / get / delete / run) - // 取代既有 u6u_deploy_workflow (打不存在的 /workflows/deploy endpoint) + // 取代早期壞掉的 deploy_workflow(打不存在的 /workflows/deploy endpoint), + // 以及重複的 list/get workflow(改直問 cypher-executor 真實狀態,不從 KBDB 撈 metadata)。 registerAllWorkflowCrudTools(server, env); // LI SDD M3.2: skills + examples lookup(KBDB-backed) // 走 sync-registry-to-kbdb.py 把 registry/{skills,examples} 同步進 KBDB diff --git a/mcp/src/tools/u6u_deploy_workflow.ts b/mcp/src/tools/u6u_deploy_workflow.ts deleted file mode 100644 index a2ef9ac..0000000 --- a/mcp/src/tools/u6u_deploy_workflow.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { z } from "zod"; -import { Env } from "../types.js"; -import { kbdbFetch } from "../lib/kbdb-client.js"; - -export function registerDeployWorkflow(server: McpServer, env: Env, orgNamespace: string) { - server.tool( - "u6u_deploy_workflow", - "將工作流 YAML 配置正式部署至雲端引擎,完成註冊與排程設定。", - { - yaml_content: z.string().describe("工作流的 YAML 配置內容") - }, - async ({ yaml_content }) => { - try { - if (!env.CYPHER_EXECUTOR) { - return { - content: [{ type: "text", text: "Error: CYPHER_EXECUTOR service binding is not configured." }], - isError: true - }; - } - - const response = await env.CYPHER_EXECUTOR.fetch("http://cypher-executor/workflows/deploy", { - method: "POST", - headers: { "Content-Type": "application/yaml" }, - body: yaml_content - }); - - if (!response.ok) { - const errorText = await response.text(); - return { - content: [{ type: "text", text: `Deployment failed: ${errorText}` }], - isError: true - }; - } - - const result = await response.json<{ workflow_id?: string; [key: string]: unknown }>(); - const workflowId = result.workflow_id ?? crypto.randomUUID(); - - // Parse workflow name from YAML - const nameMatch = yaml_content.match(/^name:\s*(.+)$/m); - const workflowName = nameMatch ? nameMatch[1].trim() : workflowId; - - // Store workflow metadata in KBDB - if (env.KBDB) { - const kbdbResp = await kbdbFetch(env, "/records", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - template: "workflow_metadata", - record_id: `wf-${workflowId}`, - user_id: orgNamespace, - values: { - workflow_id: workflowId, - name: workflowName, - deployed_at: new Date().toISOString(), - org_namespace: orgNamespace - } - }) - }); - - if (!kbdbResp.ok) { - const errText = await kbdbResp.text(); - return { - content: [{ type: "text", text: `Deployment succeeded but failed to store metadata: ${errText}` }], - isError: true - }; - } - } - - return { - content: [{ type: "text", text: `Successfully deployed workflow: ${JSON.stringify(result, null, 2)}` }] - }; - } catch (error) { - return { - content: [{ type: "text", text: `Internal Error: ${error instanceof Error ? error.message : String(error)}` }], - isError: true - }; - } - } - ); -} diff --git a/mcp/src/tools/u6u_execute_workflow.ts b/mcp/src/tools/u6u_execute_workflow.ts deleted file mode 100644 index 0164643..0000000 --- a/mcp/src/tools/u6u_execute_workflow.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { z } from "zod"; -import { Env } from "../types.js"; - -export function registerExecuteWorkflow(server: McpServer, env: Env, orgNamespace: string, partnerToken: string) { - server.tool( - "u6u_execute_workflow", - "在沙盒環境中即時執行工作流,驗證 triplets 邏輯是否正確。每個 config 鍵對應 triplets 中的節點名,內含 component(零件 canonical_id)、recipe(prompt_recipe:xxx,選用)、與該節點的其他靜態參數。", - { - triplets: z.array(z.string()).describe("工作流三元組,例:['input >> 完成後 >> synth']"), - context: z.record(z.string(), z.any()).describe("初始變數(測試資料 / 上游節點輸出模擬)"), - config: z.record(z.string(), z.record(z.string(), z.any())).optional().describe("每節點配置:{ node_name: { component, recipe?, ...params } }") - }, - async ({ triplets, context, config }) => { - try { - if (!env.CYPHER_EXECUTOR) { - return { - content: [{ type: "text", text: "Error: CYPHER_EXECUTOR service binding is not configured." }], - isError: true - }; - } - - // KI-12 修:改打 /cypher/execute(吃 triplets+config),原 /execute 是吃完整 graph 的舊路徑 - // KI-15 修:轉發 partner token 給 cypher-executor,讓 recipe expander 能用 ak_ key 抓 KBDB - const response = await env.CYPHER_EXECUTOR.fetch("http://cypher-executor/cypher/execute", { - method: "POST", - headers: { - "Content-Type": "application/json", - "X-Arcrun-API-Key": partnerToken - }, - body: JSON.stringify({ triplets, context, config }) - }); - - if (!response.ok) { - const errorText = await response.text(); - return { - content: [{ type: "text", text: `Execution failed: ${errorText}` }], - isError: true - }; - } - - const result = await response.json(); - return { - content: [{ type: "text", text: JSON.stringify(result, null, 2) }] - }; - } catch (error) { - return { - content: [{ type: "text", text: `Internal Error: ${error instanceof Error ? error.message : String(error)}` }], - isError: true - }; - } - } - ); -} diff --git a/mcp/src/tools/u6u_get_workflow.ts b/mcp/src/tools/u6u_get_workflow.ts deleted file mode 100644 index 4f261dc..0000000 --- a/mcp/src/tools/u6u_get_workflow.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { z } from "zod"; -import { Env } from "../types.js"; -import { kbdbFetch } from "../lib/kbdb-client.js"; - -export function registerGetWorkflow(server: McpServer, env: Env, orgNamespace: string) { - server.tool( - "u6u_get_workflow", - "取得指定工作流的 metadata,包含名稱、部署時間與 tag 列表。", - { workflow_id: z.string().describe("工作流 ID") }, - async ({ workflow_id }) => { - try { - if (!env.KBDB) { - return { content: [{ type: "text", text: "Error: KBDB service binding unavailable" }], isError: true }; - } - const resp = await kbdbFetch(env, `/records/wf-${encodeURIComponent(workflow_id)}`); - if (resp.status === 404) { - return { content: [{ type: "text", text: `Error: Workflow '${workflow_id}' not found` }], isError: true }; - } - if (!resp.ok) { - return { content: [{ type: "text", text: `Error querying workflow: ${await resp.text()}` }], isError: true }; - } - const record = await resp.json<{ slots: { workflow_id: string; name: string; deployed_at: string; org_namespace: string } }>(); - if (record.slots.org_namespace !== orgNamespace) { - return { content: [{ type: "text", text: `Error: Workflow '${workflow_id}' not found` }], isError: true }; - } - return { content: [{ type: "text", text: JSON.stringify(record.slots, null, 2) }] }; - } catch (error) { - return { content: [{ type: "text", text: `Internal Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; - } - } - ); -} diff --git a/mcp/src/tools/u6u_list_workflows.ts b/mcp/src/tools/u6u_list_workflows.ts deleted file mode 100644 index c7197c3..0000000 --- a/mcp/src/tools/u6u_list_workflows.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { z } from "zod"; -import { Env } from "../types.js"; -import { kbdbFetch } from "../lib/kbdb-client.js"; - -/** - * u6u_list_workflows — 列出本帳號已部署的工作流 - * - * thin-shell-alignment P1(issue #11):原讀 KBDB `/records?template=workflow_metadata`, - * 與 CLI `acr list`(讀 KV)不同源 → 列出的東西不一樣。改讀 cypher `GET /webhooks/named` - * (KV 源,與 CLI 收斂同源)。job 分:list 讀 KV(部署寫入處,權威),search 讀 KBDB entry。 - * tag 過濾仍走 KBDB resource_tag(另一維度,非 workflow 清單來源)。 - */ -export function registerListWorkflows(server: McpServer, env: Env, orgNamespace: string, partnerToken: string) { - server.tool( - "u6u_list_workflows", - "列出當前命名空間下所有已部署的工作流,可選擇按 tag 篩選。", - { tag: z.string().optional().describe("按 tag 名稱篩選(選填)") }, - async ({ tag }) => { - try { - if (!env.CYPHER_EXECUTOR) { - return { content: [{ type: "text", text: "Error: CYPHER_EXECUTOR service binding is not configured." }], isError: true }; - } - - // tag 過濾(選填):先從 KBDB resource_tag 查出該 tag 下的 workflow_id 白名單。 - let tagFilter: Set | null = null; - if (tag) { - if (!env.KBDB) { - return { content: [{ type: "text", text: "Error: KBDB service binding unavailable (tag 過濾需要)" }], isError: true }; - } - const tagResp = await kbdbFetch(env, `/records/search?template=resource_tag&user_id=${encodeURIComponent(orgNamespace)}&tag_name=${encodeURIComponent(tag)}&resource_type=workflow`); - if (!tagResp.ok) { - return { content: [{ type: "text", text: `Error querying tags: ${await tagResp.text()}` }], isError: true }; - } - const tagData = await tagResp.json<{ records: Array<{ slots: { resource_id: string } }> }>(); - tagFilter = new Set(tagData.records.map(r => r.slots.resource_id)); - if (tagFilter.size === 0) return { content: [{ type: "text", text: JSON.stringify([], null, 2) }] }; - } - - // 主清單:讀 cypher GET /webhooks/named(KV 源,與 CLI acr list 同源)。 - const resp = await env.CYPHER_EXECUTOR.fetch("http://cypher-executor/webhooks/named", { - method: "GET", - headers: { "X-Arcrun-API-Key": partnerToken }, - }); - if (!resp.ok) { - return { content: [{ type: "text", text: `Error listing workflows: ${await resp.text()}` }], isError: true }; - } - const data = await resp.json<{ workflows: Array<{ name: string; description?: string; created_at?: string; webhook_url?: string }> }>(); - let workflows = data.workflows ?? []; - // tag 過濾用 name 比對(KV 源主鍵=name)。 - // ⚠️ 語意債(SDD §4 記):舊 tag 的 resource_id 可能存 UUID(舊 workflow_metadata workflow_id) - // 或 name,語意不明確。方向①收斂到 KV(主鍵=name)後,resource_id 應統一為 name。 - // 過渡期先用 name 比對(KV 源唯一鍵);舊用 UUID tag 的會在 backfill/re-tag 後對齊。待總管確認 tag 收斂。 - if (tagFilter !== null) workflows = workflows.filter(w => tagFilter!.has(w.name)); - - return { content: [{ type: "text", text: JSON.stringify(workflows, null, 2) }] }; - } catch (error) { - return { content: [{ type: "text", text: `Internal Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; - } - } - ); -} From 53080ffa53d30e1e9e6d1cef1cc6fb1c8ac801ca Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 7 Jul 2026 05:37:54 +0000 Subject: [PATCH 2/2] =?UTF-8?q?docs(mcp):=20GUIDE/README=20=E5=85=A8?= =?UTF-8?q?=E9=9D=A2=E6=94=B9=E6=95=99=20arcrun=5F*=EF=BC=8C=E6=B8=85?= =?UTF-8?q?=E6=8E=89=E6=AD=BB=20u6u=5F=20=E5=B7=A5=E5=85=B7=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 死文件治理:GUIDE.md(25 處)與 README.md(21 處)仍在教 u6u_* 工具名, 含本 PR 已刪的 4 個 tool(deploy/execute/get/list_workflows),下個 CC 照著走會撞牆。 - 全部 u6u_* → 現役 arcrun_*(component/tag/gui 那批用新名) - 已刪 tool 改指現役:execute→run、deploy→push、get/list_workflows→crud 版 - 修正因換工具而失真的流程與參數:沙盒測試段改為 arcrun_validate_yaml(部署前 schema 驗證)→ arcrun_push_workflow(部署)→ arcrun_run_workflow(觸發,帶 api_key/name/input);get_workflow 參數 workflow_id→name - 順帶把兩處品牌 prose "u6u" 改 "Arcrun" - grep 確認兩檔零 u6u brand.ts:釐清 ARCRUN_TOOL_PREFIX 覆蓋僅內部 rebrand 過渡 / 測試鉤子, Workers runtime 無 process 全域基本不生效、勿當對外特性。 Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_015d5jDbuqT5Htwv3Q88XXKk --- mcp/GUIDE.md | 85 ++++++++++++++++++++++++++---------------------- mcp/README.md | 54 ++++++++++++++++-------------- mcp/src/brand.ts | 6 ++-- 3 files changed, 79 insertions(+), 66 deletions(-) diff --git a/mcp/GUIDE.md b/mcp/GUIDE.md index 4ad0d18..b88f02e 100644 --- a/mcp/GUIDE.md +++ b/mcp/GUIDE.md @@ -3,8 +3,7 @@ > Arcrun 是 **AI 優先(AI-First)** 的工作流自動化平台。 > 跟 AI 描述你的意圖,Arcrun 幫你把它變成可重複執行、不需要 AI 的自動化工作流。 > -> 註:本指南部分工具仍以舊 `u6u_` 前綴記載(registry/component 管理那組);現役 workflow 工具是 -> `arcrun_*`(見 `mcp/src/tools/`)。連線設定見 `mcp/README.md`(用 `acr mcp-setup`)。 +> 註:所有工具一律 `arcrun_*` 前綴(見 `mcp/src/tools/`)。連線設定見 `mcp/README.md`(用 `acr mcp-setup`)。 --- @@ -23,7 +22,7 @@ ## 核心概念:三元組(Triplet) -u6u 的一切都建立在「三元組」上。三元組是描述業務邏輯的最小單位,格式極度簡單,AI 不會出錯,人也能一眼看懂。 +Arcrun 的一切都建立在「三元組」上。三元組是描述業務邏輯的最小單位,格式極度簡單,AI 不會出錯,人也能一眼看懂。 ### 格式 @@ -55,7 +54,7 @@ system sends telegram-notification ### 為什麼這麼簡單? -因為 AI 擅長理解意圖,三元組擅長表達意圖。你跟 AI 說「去抓銀行匯率,用 Telegram 通知我」,AI 把它拆成三元組,u6u 查零件庫、組裝、執行。第一次需要 AI,之後自動跑,不再花 Token。 +因為 AI 擅長理解意圖,三元組擅長表達意圖。你跟 AI 說「去抓銀行匯率,用 Telegram 通知我」,AI 把它拆成三元組,Arcrun 查零件庫、組裝、執行。第一次需要 AI,之後自動跑,不再花 Token。 --- @@ -66,13 +65,15 @@ system sends telegram-notification ↓ AI 產出 Workflow_Plan_YAML(每次規劃新專案) ↓ -u6u_search_components(查零件庫) +arcrun_search_components(查零件庫) ↓ -有缺件?→ AI 產出 Component_Plan_YAML → u6u_publish_component +有缺件?→ AI 產出 Component_Plan_YAML → arcrun_publish_component ↓ -u6u_execute_workflow(沙盒測試) +arcrun_validate_yaml(部署前 schema 驗證) ↓ -u6u_deploy_workflow(正式部署) +arcrun_push_workflow(正式部署) + ↓ +arcrun_run_workflow(觸發執行,帶 input) ↓ (選填)建立 tag,為工作流與零件分類 ``` @@ -214,7 +215,7 @@ workflow: ## Component_Plan_YAML 格式 -**產出時機:** 只有當 `u6u_search_components` 回報有缺件時,AI 才會產出此 YAML。不是每次都需要。 +**產出時機:** 只有當 `arcrun_search_components` 回報有缺件時,AI 才會產出此 YAML。不是每次都需要。 ### 格式說明 @@ -325,7 +326,7 @@ components: ### 步驟二:確認零件完整性 -呼叫 `u6u_search_components`,傳入所有 triplet: +呼叫 `arcrun_search_components`,傳入所有 triplet: ```json { @@ -339,38 +340,45 @@ components: 回應會告知哪些零件已存在、哪些缺失。若有缺件,先完成[零件開發流程](#零件component開發流程)。 -### 步驟三:沙盒測試 +### 步驟三:部署前 schema 驗證 ```json -// u6u_execute_workflow +// arcrun_validate_yaml { - "triplets": [ - "system fetches exchange-rate", - "system parses rate-data", - "system sends telegram-notification" - ], - "context": { - "currency_pair": "USD/TWD", - "chat_id": "123456789" - } + "yaml_content": "workflow:\n name: exchange-rate-notify\n ..." } ``` ### 步驟四:正式部署 ```json -// u6u_deploy_workflow +// arcrun_push_workflow { + "api_key": "ak_xxx", "yaml_content": "workflow:\n name: exchange-rate-notify\n ..." } ``` 部署成功後,系統回傳 `workflow_id`,並自動記錄 metadata 至 KBDB。 -### 步驟五:加上 Tag(選填) +### 步驟五:觸發執行 ```json -// u6u_tag_resource +// arcrun_run_workflow — 觸發已部署的 workflow,input 帶進 trigger context +{ + "api_key": "ak_xxx", + "name": "exchange-rate-notify", + "input": { + "currency_pair": "USD/TWD", + "chat_id": "123456789" + } +} +``` + +### 步驟六:加上 Tag(選填) + +```json +// arcrun_tag_resource { "resource_type": "workflow", "resource_id": "wf-abc123", @@ -381,9 +389,8 @@ components: ### 查詢已部署的工作流 ``` -u6u_list_workflows → 列出所有工作流 -u6u_list_workflows(tag=finance) → 按 tag 篩選 -u6u_get_workflow(workflow_id) → 取得特定工作流 metadata +arcrun_list_workflows → 列出所有工作流 +arcrun_get_workflow(name) → 取得特定工作流 metadata ``` --- @@ -392,12 +399,12 @@ u6u_get_workflow(workflow_id) → 取得特定工作流 metadata ### 步驟一:確認缺件 -`u6u_search_components` 回報缺件後,AI 產出 Component_Plan_YAML。存入 `components/` 目錄。 +`arcrun_search_components` 回報缺件後,AI 產出 Component_Plan_YAML。存入 `components/` 目錄。 ### 步驟二:發佈零件 ```json -// u6u_publish_component(API Config 方式) +// arcrun_publish_component(API Config 方式) { "component_id": "system-fetches-exchange-rate", "api_config": { @@ -408,7 +415,7 @@ u6u_get_workflow(workflow_id) → 取得特定工作流 metadata ``` ```json -// u6u_publish_component(Gherkin 方式) +// arcrun_publish_component(Gherkin 方式) { "component_id": "system-sends-confirmation-email", "gherkin": "Feature: 訂單確認信\n Scenario: ..." @@ -418,7 +425,7 @@ u6u_get_workflow(workflow_id) → 取得特定工作流 metadata ### 步驟三:加上 Tag(選填) ```json -// u6u_tag_resource +// arcrun_tag_resource { "resource_type": "component", "resource_id": "system-fetches-exchange-rate", @@ -429,9 +436,9 @@ u6u_get_workflow(workflow_id) → 取得特定工作流 metadata ### 查詢已發佈的零件 ``` -u6u_list_components → 列出所有零件 -u6u_list_components(tag=payment) → 按 tag 篩選 -u6u_get_component(component_id) → 取得特定零件 metadata +arcrun_list_components → 列出所有零件 +arcrun_list_components(tag=payment) → 按 tag 篩選 +arcrun_get_component(component_id) → 取得特定零件 metadata ``` --- @@ -444,19 +451,19 @@ Tag 是用戶自訂的標籤,可附加至工作流或零件,用於分類與 ```json // 建立 tag -// u6u_create_tag +// arcrun_create_tag { "name": "finance", "description": "金融相關" } // 列出所有 tag -// u6u_list_tags(無需參數) +// arcrun_list_tags(無需參數) {} // 刪除 tag(不影響已打上此 tag 的資源關聯) -// u6u_delete_tag +// arcrun_delete_tag { "tag_name": "deprecated-tag" } // 為資源加上 tag -// u6u_tag_resource +// arcrun_tag_resource { "resource_type": "workflow", // 或 "component" "resource_id": "wf-abc123", @@ -464,7 +471,7 @@ Tag 是用戶自訂的標籤,可附加至工作流或零件,用於分類與 } // 移除資源的 tag -// u6u_untag_resource +// arcrun_untag_resource { "resource_type": "component", "resource_id": "system-fetches-exchange-rate", diff --git a/mcp/README.md b/mcp/README.md index ac99203..cd7acb1 100644 --- a/mcp/README.md +++ b/mcp/README.md @@ -53,40 +53,41 @@ Claude Code 進此資料夾就連對的 MCP。`acr init` 也會自動順帶跑 | Tool | 說明 | |------|------| -| `u6u_get_component_guide` | **開發新零件前必須先呼叫。** 取得 TinyGo 開發指引,包含白名單 import、禁止行為、contract YAML 範例、本地測試指令。 | -| `u6u_search_components` | 用自然語言語意搜尋零件庫。例如:「查詢 Google Sheets 資料」、「發送 LINE 訊息」。回傳零件清單含 canonical_id、描述、評分。 | -| `u6u_get_component` | 取得指定零件的完整合約(input_schema、output_schema、gherkin_tests、評分統計等)。 | -| `u6u_publish_component` | 提交 TinyGo WASM 零件。需提供 `contract`(合約物件)與 `wasm_base64`(編譯後的 .wasm base64)。Registry 自動執行沙盒驗收。 | +| `arcrun_get_component_guide` | **開發新零件前必須先呼叫。** 取得 TinyGo 開發指引,包含白名單 import、禁止行為、contract YAML 範例、本地測試指令。 | +| `arcrun_search_components` | 用自然語言語意搜尋零件庫。例如:「查詢 Google Sheets 資料」、「發送 LINE 訊息」。回傳零件清單含 canonical_id、描述、評分。 | +| `arcrun_get_component` | 取得指定零件的完整合約(input_schema、output_schema、gherkin_tests、評分統計等)。 | +| `arcrun_publish_component` | 提交 TinyGo WASM 零件。需提供 `contract`(合約物件)與 `wasm_base64`(編譯後的 .wasm base64)。Registry 自動執行沙盒驗收。 | ### 工作流執行 | Tool | 說明 | |------|------| -| `u6u_execute_workflow` | 在沙盒中執行工作流。輸入 `triplets`(三元組陣列)與 `context`,用於部署前驗證。 | -| `u6u_deploy_workflow` | 將工作流 YAML 部署至雲端引擎。輸入 `yaml_content`。 | +| `arcrun_validate_yaml` | 部署前驗證工作流 YAML 的 schema。輸入 `yaml_content`。 | +| `arcrun_push_workflow` | 將工作流 YAML 部署至雲端引擎。輸入 `api_key` 與 `yaml_content`。 | +| `arcrun_run_workflow` | 觸發已部署的工作流執行。輸入 `api_key`、`name`,選填 `input`(帶進 trigger context)。 | ### 工作流管理 | Tool | 說明 | |------|------| -| `u6u_list_workflows` | 列出已部署的工作流。可傳入選填的 `tag` 參數篩選。 | -| `u6u_get_workflow` | 取得指定工作流的 metadata。輸入 `workflow_id`。 | +| `arcrun_list_workflows` | 列出已部署的工作流。可傳入選填的 `tag` 參數篩選。 | +| `arcrun_get_workflow` | 取得指定工作流的 metadata。輸入 `name`。 | ### 零件管理 | Tool | 說明 | |------|------| -| `u6u_list_components` | 列出已發佈的零件。可傳入選填的 `tag` 參數篩選。 | +| `arcrun_list_components` | 列出已發佈的零件。可傳入選填的 `tag` 參數篩選。 | ### Tag 管理 | Tool | 說明 | |------|------| -| `u6u_create_tag` | 建立新 tag。輸入 `name`(必填)與 `description`(選填)。 | -| `u6u_list_tags` | 列出當前命名空間下所有 tag。 | -| `u6u_delete_tag` | 刪除指定 tag。輸入 `tag_name`。 | -| `u6u_tag_resource` | 為工作流或零件加上 tag。輸入 `resource_type`、`resource_id`、`tag_name`。 | -| `u6u_untag_resource` | 移除工作流或零件的 tag。 | +| `arcrun_create_tag` | 建立新 tag。輸入 `name`(必填)與 `description`(選填)。 | +| `arcrun_list_tags` | 列出當前命名空間下所有 tag。 | +| `arcrun_delete_tag` | 刪除指定 tag。輸入 `tag_name`。 | +| `arcrun_tag_resource` | 為工作流或零件加上 tag。輸入 `resource_type`、`resource_id`、`tag_name`。 | +| `arcrun_untag_resource` | 移除工作流或零件的 tag。 | --- @@ -97,7 +98,7 @@ Arcrun 的零件是 TinyGo 編譯的 `.wasm`,透過 stdin/stdout JSON 通訊 ### 步驟一:取得開發指引 ``` -u6u_get_component_guide +arcrun_get_component_guide ``` 指引包含:TinyGo 白名單 import、禁止行為、`component.contract.yaml` 完整範例、本地測試指令。 @@ -105,7 +106,7 @@ u6u_get_component_guide ### 步驟二:搜尋現有零件 ``` -u6u_search_components("查詢 Google Sheets 資料") +arcrun_search_components("查詢 Google Sheets 資料") ``` 若已有符合的零件,直接使用,不需要重新開發。 @@ -137,7 +138,7 @@ echo '{"input_field":"value"}' | wasmtime my_component.wasm ### 步驟四:提交零件 ``` -u6u_publish_component( +arcrun_publish_component( contract={...}, // component.contract.yaml 內容 wasm_base64="..." // base64(my_component.wasm) ) @@ -152,23 +153,26 @@ Registry 自動執行沙盒驗收(體積、syscall 掃描、Gherkin 測試) ### 步驟一:搜尋零件 ``` -u6u_search_components("查詢匯率") -u6u_search_components("發送 Telegram 訊息") +arcrun_search_components("查詢匯率") +arcrun_search_components("發送 Telegram 訊息") ``` -### 步驟二:沙盒測試 +### 步驟二:部署前驗證 ``` -u6u_execute_workflow( - triplets=["system >> 查詢匯率 >> get-exchange-rate", ...], - context={"currency_pair": "USD/TWD"} -) +arcrun_validate_yaml(yaml_content="...") ``` ### 步驟三:部署 ``` -u6u_deploy_workflow(yaml_content="...") +arcrun_push_workflow(api_key="ak_xxx", yaml_content="...") +``` + +### 步驟四:觸發執行 + +``` +arcrun_run_workflow(api_key="ak_xxx", name="exchange-rate-notify", input={"currency_pair": "USD/TWD"}) ``` --- diff --git a/mcp/src/brand.ts b/mcp/src/brand.ts index 1b600bb..3ae4ac8 100644 --- a/mcp/src/brand.ts +++ b/mcp/src/brand.ts @@ -12,8 +12,10 @@ * * 語意後綴(push_workflow / list_tags …)保留可讀,只有「品牌前綴」被變數化。 * - * 可用環境變數 ARCRUN_TOOL_PREFIX 覆蓋(測試 / 未來 rebrand 過渡用),預設 "arcrun"。 - * (Workers runtime 無 process 全域,故用 globalThis 安全取值,取不到就 fallback。) + * 前綴預設 "arcrun"。內部另留一個 rebrand 過渡 / 單元測試用的覆蓋鉤子 + * (ARCRUN_TOOL_PREFIX,經 globalThis.process 安全取值)——但 Cloudflare + * Workers runtime 沒有 process 全域,部署後此覆蓋「基本不生效」、一律 fallback 到 + * "arcrun"。**這不是對外 / 用戶可用特性,勿寫進對外文件**;正式 rebrand 請直接改本檔預設值。 */ const envPrefix = (globalThis as { process?: { env?: Record } })