Files
Arcrun/cli/src/index.ts
T
uncle6me-web c152f5fc1d feat(onboarding+kbdb): 8.P0 cron 止血 + §7.8 onboarding + .env.example 範本
kbdb-base 8.P0:scheduled.ts cron 每分鐘 KV list → 單一 key get(lib/cron-index.ts);
  webhooks-named 維護單 key + 一次性 migrate-cron-index;acr update 自動遷移。1440 list/日 → 0。

self-hosted-init §7.8 onboarding:
  P0 init 偵測+裝完驗收(lib/preflight.ts,pip 式,冪等)
  P1 acr whoami(+--json)+ MCP arcrun_whoami(AI 不繞 CLI 猜帳號)
  P2 mcp-setup 寫完印「請重啟 client」
  P3(部分)repo .env.example 範本(每格白話說明、值留空)+ llms.txt 教 AI 幫用戶 cp 建 .env

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 19:15:51 +08:00

194 lines
8.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* arcrun CLI — acr
* AI Workflow CLI for Cloudflare Workers + WASM
*
* 安裝:npm i -g arcrun
* 使用:acr <指令>
*/
import { Command } from 'commander';
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
import { cmdInit } from './commands/init.js';
import { cmdConfig } from './commands/config.js';
import { cmdWhoami } from './commands/whoami.js';
import { cmdCredsPush } from './commands/creds.js';
import { cmdPush } from './commands/push.js';
import { cmdRun } from './commands/run.js';
import { cmdValidate } from './commands/validate.js';
import { cmdParts, cmdPartsScaffold, cmdPartsPublish } from './commands/parts.js';
import { cmdRecipePush, cmdRecipeList, cmdRecipeDelete, cmdRecipeSearch, cmdRecipePull, cmdRecipeSubmitP } from './commands/recipe.js';
import { cmdList } from './commands/list.js';
import { cmdLogs } from './commands/logs.js';
import { cmdUpdate } from './commands/update.js';
import { cmdInstallHarness } from './commands/install-harness.js';
import { cmdMcpSetup } from './commands/mcp-setup.js';
import { cmdAuthRecipeList, cmdAuthRecipeInfo, cmdAuthRecipeScaffold } from './commands/auth-recipe.js';
const program = new Command();
// 版本從 package.json 動態讀(dist/index.js 旁的 ../package.json),不 hardcode → 永不漂移。
// 之前 hardcode '1.1.0' 與 package.json '1.2.0' 不一致,正是「忘了改」的反例。
function readVersion(): string {
try {
const here = dirname(fileURLToPath(import.meta.url));
return (JSON.parse(readFileSync(join(here, '..', 'package.json'), 'utf8')) as { version?: string }).version ?? '0.0.0';
} catch {
return '0.0.0';
}
}
program
.name('acr')
.description('arcrun — AI Workflow CLI for Cloudflare Workers + WASM')
.version(readVersion());
// acr init [--self-hosted] [--account-id <id>] [--api-token <token>]
program
.command('init')
.description('互動式初始化設定(建立 ~/.arcrun/config.yaml')
.option('--local', '本機模式:不需要 Cloudflare 帳號,直接在本機測試 workflow')
.option('--self-hosted', '完全 Self-hosted 模式:自行部署所有 Cloudflare Worker')
.option('--account-id <id>', 'self-hostedCF Account ID(非互動;亦可用 CLOUDFLARE_ACCOUNT_ID env')
.option('--api-token <token>', 'self-hostedCF API Token(非互動;亦可用 CLOUDFLARE_API_TOKEN env')
.action((options: { local?: boolean; selfHosted?: boolean; accountId?: string; apiToken?: string }) =>
cmdInit(options),
);
// acr config [--where]:印出目前生效的設定與每個值的來源層(env / 專案層 / 全域)
program
.command('config')
.description('顯示目前生效的設定與來源層(避免在錯的資料夾用錯帳號)')
.option('--where', '顯示每個設定值來自哪一層(env > 專案層 .arcrun.yaml > 全域)')
.action((options: { where?: boolean }) => cmdConfig(options));
// acr whoami [--json]:一眼看當前身份(mode / 連哪台 cypher / 帳號來源層)。§7.8 P1 D2 修法。
program
.command('whoami')
.description('顯示目前生效的身份(帳號、連哪台 cypher、來源層)——AI 別自己 curl 猜帳號')
.option('--json', '結構化輸出(給 AI / 腳本讀取)')
.action((options: { json?: boolean }) => cmdWhoami(options));
// acr creds push [credentials.yaml]
const credsCmd = program.command('creds').description('Credential 管理');
credsCmd
.command('push [file]')
.description('加密上傳 credentials.yaml 至你的 CF KV(不經過 arcrun.dev')
.action((file: string) => cmdCredsPush(file ?? 'credentials.yaml'));
// acr push <workflow.yaml>
program
.command('push <file>')
.description('解析 workflow.yaml 並部署至你的 CF KV')
.action((file: string) => cmdPush(file));
// acr run <workflow_name> [--input key=value...]
program
.command('run <workflow>')
.description('執行指定 workflow')
.option('-i, --input <pairs...>', 'input 參數(格式:key=value')
.action((workflow: string, options: { input?: string[] }) => cmdRun(workflow, options));
// acr validate <workflow.yaml>
program
.command('validate <file>')
.description('執行前驗證 workflow.yaml(格式、關係詞、零件存在性、credentials')
.option('--offline', '離線模式:跳過零件存在性與 credentials 的遠端檢查')
.action((file: string, options: { offline?: boolean }) => cmdValidate(file, options));
// acr parts
// acr parts scaffold <component>
// acr parts publish <component> [--status <submission_id>]
const partsCmd = program.command('parts').description('零件庫管理');
partsCmd
.action(() => cmdParts());
partsCmd
.command('scaffold <component>')
.description('輸出零件的 config 範本(可直接貼入 workflow.yaml')
.action((component: string) => cmdPartsScaffold(component));
partsCmd
.command('publish <component-dir>')
.description('提交零件至 arcrun.dev 公眾 registry')
.option('--status <submission_id>', '查詢提交審核進度')
.action((dir: string, options: { status?: string }) => cmdPartsPublish(dir, options));
// acr recipe push / list / delete
const recipeCmd = program.command('recipe').description('API Recipe 管理');
recipeCmd
.command('push <file>')
.description('上傳 recipe YAML 到 arcrun.dev(不需要 deploy Worker')
.action((file: string) => cmdRecipePush(file));
recipeCmd
.command('list')
.description('列出已上傳的 recipe')
.action(() => cmdRecipeList());
recipeCmd
.command('delete <id>')
.description('刪除 recipecanonical_id 或 rec_hash')
.action((id: string) => cmdRecipeDelete(id));
// 公庫互動(kbdb-base §7.5
recipeCmd
.command('search <query>')
.description('搜尋公庫 recipe(同名可多作者,附市場數據)')
.action((query: string) => cmdRecipeSearch(query));
recipeCmd
.command('pull <canonical_id>')
.description('從公庫取一份 recipe 寫進自己私庫')
.option('--author <name>', '指定作者版本(不指定取市場最佳)')
.action((canonicalId: string, opts: { author?: string }) => cmdRecipePull(canonicalId, opts.author));
recipeCmd
.command('submit-p <canonical_id>')
.description('把私庫某 recipe 投稿到公庫(新增作者版本,需暴露同意)')
.option('--author <name>', '署名作者(預設用 recipe 既有 author')
.action((canonicalId: string, opts: { author?: string }) => cmdRecipeSubmitP(canonicalId, opts.author));
// acr auth-recipe list / info / scaffold
const authRecipeCmd = program.command('auth-recipe').description('第三方服務認證 Recipe(新增服務整合)');
authRecipeCmd
.command('list')
.description('列出所有平台預建的服務整合(Notion、Slack、GitHub 等)')
.action(() => cmdAuthRecipeList());
authRecipeCmd
.command('info <service>')
.description('顯示服務 recipe 詳情(需要哪些 credential')
.action((service: string) => cmdAuthRecipeInfo(service));
authRecipeCmd
.command('scaffold <service>')
.description('輸出 credentials.yaml 範本 + workflow.yaml 使用範例')
.action((service: string) => cmdAuthRecipeScaffold(service));
// acr list
program
.command('list')
.description('列出 CF KV 中所有已部署的 workflow')
.action(() => cmdList());
// acr logs <workflow_name>
program
.command('logs <workflow>')
.description('顯示 workflow 最近執行記錄')
.action((workflow: string) => cmdLogs(workflow));
// acr updateself-hosted:拉新 release 重新部署零件/引擎)
program
.command('update')
.description('self-hosted:拉新 release 並重新部署到你的 Cloudflare')
.action(() => cmdUpdate());
// acr install-harness(把 arcrun 的 CC harness 裝進當前專案)
program
.command('install-harness')
.description('把 arcrun 的 CC harnessmindset/提醒/防做歪 hook/指令)裝進當前專案')
.action(() => cmdInstallHarness());
// acr mcp-setup(依 config 解析的 mcp_url 寫專案 .mcp.json,讓 Claude Code 連對的 MCP
program
.command('mcp-setup')
.description('在目前資料夾寫 .mcp.json 連對的 arcrun MCP(依 config 的 mcp_url;接案切資料夾自動切)')
.action(() => cmdMcpSetup());
program.parse(process.argv);