From c4c9f961172faadacca7b4cdd14a778b89b6da40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=A9=98?= Date: Mon, 18 May 2026 13:24:19 +0000 Subject: [PATCH] fix: uwf cas commands output JSON, include meta-schema in schema list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All cas subcommands now output JSON via writeJson(), consistent with other uwf commands. schema list includes meta-schema. Removed --json flag and --format tree (tree is human-only, not machine-friendly). Refs #319 小橘 🍊(NEKO Team) --- packages/cli-uwf/src/cli.ts | 51 ++++++++----- packages/cli-uwf/src/commands/cas.ts | 109 ++++++++++----------------- 2 files changed, 71 insertions(+), 89 deletions(-) diff --git a/packages/cli-uwf/src/cli.ts b/packages/cli-uwf/src/cli.ts index 0b97562..e9d7013 100755 --- a/packages/cli-uwf/src/cli.ts +++ b/packages/cli-uwf/src/cli.ts @@ -184,10 +184,11 @@ cas .command("get") .description("Read a CAS node as JSON") .argument("", "CAS hash (13 char)") - .option("--json", "Compact JSON output") - .action((hash: string, opts: { json?: boolean }) => { + .action((hash: string) => { const storageRoot = resolveStorageRoot(); - runAction(() => cmdCasGet(storageRoot, hash, opts)); + runAction(async () => { + writeJson(await cmdCasGet(storageRoot, hash)); + }); }); cas @@ -195,10 +196,11 @@ cas .description("Output a CAS node (--payload for payload only)") .argument("", "CAS hash (13 char)") .option("--payload", "Output only the payload") - .option("--json", "Compact JSON output") - .action((hash: string, opts: { payload?: boolean; json?: boolean }) => { + .action((hash: string, opts: { payload?: boolean }) => { const storageRoot = resolveStorageRoot(); - runAction(() => cmdCasCat(storageRoot, hash, opts)); + runAction(async () => { + writeJson(await cmdCasCat(storageRoot, hash, opts)); + }); }); cas @@ -206,19 +208,22 @@ cas .description("Store a node, print its hash") .argument("", "Type (schema) hash") .argument("", "JSON file path or inline JSON string") - .option("--json", "Compact JSON output") - .action((typeHash: string, data: string, opts: { json?: boolean }) => { + .action((typeHash: string, data: string) => { const storageRoot = resolveStorageRoot(); - runAction(() => cmdCasPut(storageRoot, typeHash, data, opts)); + runAction(async () => { + writeJson(await cmdCasPut(storageRoot, typeHash, data)); + }); }); cas .command("has") - .description("Check if a hash exists (prints true/false)") + .description("Check if a hash exists") .argument("", "CAS hash (13 char)") .action((hash: string) => { const storageRoot = resolveStorageRoot(); - runAction(() => cmdCasHas(storageRoot, hash)); + runAction(async () => { + writeJson(await cmdCasHas(storageRoot, hash)); + }); }); cas @@ -227,37 +232,43 @@ cas .argument("", "CAS hash (13 char)") .action((hash: string) => { const storageRoot = resolveStorageRoot(); - runAction(() => cmdCasRefs(storageRoot, hash)); + runAction(async () => { + writeJson(await cmdCasRefs(storageRoot, hash)); + }); }); cas .command("walk") .description("Recursive traversal from a node") .argument("", "CAS hash (13 char)") - .option("--format ", "Output format: flat (default) or tree") - .action((hash: string, opts: { format?: string }) => { + .action((hash: string) => { const storageRoot = resolveStorageRoot(); - runAction(() => cmdCasWalk(storageRoot, hash, opts)); + runAction(async () => { + writeJson(await cmdCasWalk(storageRoot, hash)); + }); }); const casSchema = cas.command("schema").description("CAS schema operations"); casSchema .command("list") - .description("List all registered schemas (hash + name)") + .description("List all registered schemas") .action(() => { const storageRoot = resolveStorageRoot(); - runAction(() => cmdCasSchemaList(storageRoot)); + runAction(async () => { + writeJson(await cmdCasSchemaList(storageRoot)); + }); }); casSchema .command("get") .description("Show a schema by its type hash") .argument("", "Schema type hash") - .option("--json", "Compact JSON output") - .action((hash: string, opts: { json?: boolean }) => { + .action((hash: string) => { const storageRoot = resolveStorageRoot(); - runAction(() => cmdCasSchemaGet(storageRoot, hash, opts)); + runAction(async () => { + writeJson(await cmdCasSchemaGet(storageRoot, hash)); + }); }); program.parseAsync(process.argv).catch((e: unknown) => { diff --git a/packages/cli-uwf/src/commands/cas.ts b/packages/cli-uwf/src/commands/cas.ts index 06bfcb2..934da7a 100644 --- a/packages/cli-uwf/src/commands/cas.ts +++ b/packages/cli-uwf/src/commands/cas.ts @@ -11,12 +11,7 @@ function openStore(storageRoot: string): Store { return createFsStore(join(storageRoot, "cas")); } -function out(data: unknown, compact = false): void { - console.log(compact ? JSON.stringify(data) : JSON.stringify(data, null, 2)); -} - function readJsonArg(fileOrInline: string): unknown { - // Try as inline JSON first, then as file path try { return JSON.parse(fileOrInline); } catch { @@ -28,138 +23,114 @@ function readJsonArg(fileOrInline: string): unknown { } } -// ---- Commands ---- +// ---- Commands (all return JSON-serializable data) ---- export async function cmdCasGet( storageRoot: string, hash: string, - opts: { json?: boolean }, -): Promise { +): Promise { const store = openStore(storageRoot); const node = store.get(hash); if (node === null) { throw new Error(`Node not found: ${hash}`); } - out(node, opts.json); + return node; } export async function cmdCasCat( storageRoot: string, hash: string, - opts: { payload?: boolean; json?: boolean }, -): Promise { + opts: { payload?: boolean }, +): Promise { const store = openStore(storageRoot); const node = store.get(hash); if (node === null) { throw new Error(`Node not found: ${hash}`); } - out(opts.payload ? node.payload : node, opts.json); + return opts.payload ? node.payload : node; } export async function cmdCasPut( storageRoot: string, typeHash: string, data: string, - opts: { json?: boolean }, -): Promise { +): Promise<{ hash: string }> { const store = openStore(storageRoot); const payload = readJsonArg(data); - const hash = store.put(typeHash, payload); - console.log(hash); + const hash = await store.put(typeHash, payload); + return { hash }; } export async function cmdCasHas( storageRoot: string, hash: string, -): Promise { +): Promise<{ exists: boolean }> { const store = openStore(storageRoot); - console.log(String(store.has(hash))); + return { exists: store.has(hash) }; } -export async function cmdCasList(storageRoot: string): Promise { - const store = openStore(storageRoot); - for (const hash of store.list()) { - console.log(hash); - } -} - -export async function cmdCasRefs(storageRoot: string, hash: string): Promise { +export async function cmdCasRefs( + storageRoot: string, + hash: string, +): Promise<{ refs: string[] }> { const store = openStore(storageRoot); const node = store.get(hash); if (node === null) { throw new Error(`Node not found: ${hash}`); } - const refHashes = refs(store, node); - for (const r of refHashes) { - console.log(r); - } + return { refs: refs(store, node) }; } export async function cmdCasWalk( storageRoot: string, hash: string, - opts: { format?: string }, -): Promise { +): Promise<{ hashes: string[] }> { const store = openStore(storageRoot); - - if (opts.format === "tree") { - const childMap = new Map(); - walk(store, hash, (h, node) => { - childMap.set(h, refs(store, node)); - }); - - const printed = new Set(); - - function printNode(h: Hash, prefix: string, isLast: boolean): void { - const connector = prefix === "" ? "" : isLast ? "└── " : "├── "; - if (printed.has(h)) { - console.log(`${prefix}${connector}${h} (seen)`); - return; - } - printed.add(h); - console.log(`${prefix}${connector}${h}`); - - const kids = childMap.get(h) ?? []; - const childPrefix = prefix === "" ? "" : prefix + (isLast ? " " : "│ "); - for (let i = 0; i < kids.length; i++) { - printNode(kids[i] as Hash, childPrefix, i === kids.length - 1); - } - } - - printNode(hash, "", true); - } else { - walk(store, hash, (h) => { - console.log(h); - }); - } + const result: string[] = []; + walk(store, hash, (h) => { + result.push(h); + }); + return { hashes: result }; } -export async function cmdCasSchemaList(storageRoot: string): Promise { +export type SchemaListEntry = { + hash: string; + title: string; +}; + +export async function cmdCasSchemaList( + storageRoot: string, +): Promise { const store = openStore(storageRoot); const metaHash = await bootstrap(store); + const entries: SchemaListEntry[] = []; + + // Include meta-schema itself + entries.push({ hash: metaHash, title: "(meta-schema)" }); + for (const hash of store.list()) { if (hash === metaHash) continue; const node = store.get(hash); if (node !== null && node.type === metaHash) { const schema = node.payload as JSONSchema; - const name = + const title = (schema.title as string | undefined) ?? (schema.description as string | undefined) ?? "(unnamed)"; - console.log(`${hash} ${name}`); + entries.push({ hash, title }); } } + return entries; } export async function cmdCasSchemaGet( storageRoot: string, hash: string, - opts: { json?: boolean }, -): Promise { +): Promise { const store = openStore(storageRoot); const schema = getSchema(store, hash); if (schema === null) { throw new Error(`Schema not found: ${hash}`); } - out(schema, opts.json); + return schema; } -- 2.43.0