Files
Arcrun/cli/src/commands/list.ts
T
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

69 lines
2.1 KiB
TypeScript

/**
* acr list — 列出 USER_KV 中所有已上傳的 workflow
*/
import chalk from 'chalk';
import ora from 'ora';
import { loadConfig } from '../lib/config.js';
import { CfKvClient } from '../lib/cf-api.js';
export async function cmdList(): Promise<void> {
const config = loadConfig();
if (!config.cloudflare_account_id || !config.cf_api_token) {
console.error(chalk.red('缺少 Cloudflare 設定,請執行 acr init'));
process.exit(1);
}
const namespaceId = config.mode === 'standard'
? config.user_kv_namespace_id!
: config.webhooks_kv_namespace_id!;
if (!namespaceId) {
console.error(chalk.red('缺少 KV Namespace ID,請執行 acr init'));
process.exit(1);
}
const kv = new CfKvClient({
accountId: config.cloudflare_account_id,
namespaceId,
apiToken: config.cf_api_token,
});
const spinner = ora('讀取 workflow 清單').start();
try {
const keys = await kv.list('workflow:');
spinner.stop();
if (keys.length === 0) {
console.log(chalk.yellow('\n 沒有已部署的 workflow。執行 acr push <workflow.yaml> 部署第一個。\n'));
return;
}
console.log(chalk.bold(`\n 已部署 ${keys.length} 個 workflow\n`));
for (const key of keys) {
const name = key.name.replace('workflow:', '');
// 嘗試讀取 workflow 定義取得 created_at
try {
const raw = await kv.get(key.name);
if (raw) {
const def = JSON.parse(raw) as { name: string; description?: string; created_at?: string };
const date = def.created_at ? new Date(def.created_at).toLocaleString('zh-TW') : '未知';
const desc = def.description ? chalk.gray(` — ${def.description}`) : '';
console.log(` • ${chalk.cyan(name.padEnd(25))} ${date}${desc}`);
} else {
console.log(` • ${chalk.cyan(name)}`);
}
} catch {
console.log(` • ${chalk.cyan(name)}`);
}
}
console.log('');
} catch (e) {
spinner.fail(chalk.red(`KV 讀取失敗:${e instanceof Error ? e.message : e}`));
process.exit(1);
}
}