From 36a58d074425d6935d4249ef7693b6fa6df1db8b Mon Sep 17 00:00:00 2001 From: EthanHuo Date: Thu, 12 Nov 2026 23:49:16 +0800 Subject: [PATCH] chore: argc 11 flat @schema, trim examples to what types cannot show (3.1.0) - @celados/argc ^11.0.0: @schema renders flat ### blocks - drop 13 examples that only restated the input shape or repeated a form - schema tests assert the flat format --- bun.lock | 4 ++-- package.json | 4 ++-- src/main.test.ts | 39 +++++++++++++++++++++------------------ src/schema.ts | 20 +++----------------- 4 files changed, 28 insertions(+), 39 deletions(-) diff --git a/bun.lock b/bun.lock index c8d266e..8f293c6 100644 --- a/bun.lock +++ b/bun.lock @@ -5,7 +5,7 @@ "": { "name": "vox", "dependencies": { - "@celados/argc": "^10.3.1", + "@celados/argc": "^11.0.0", "@celados/argc-latch": "^1.0.0", "@valibot/to-json-schema": "^1.8.0", "valibot": "^1.5.0", @@ -19,7 +19,7 @@ }, }, "packages": { - "@celados/argc": ["@celados/argc@10.3.1", "https://npm.celados.com/@celados/argc/-/@celados/argc-10.3.1.tgz", { "dependencies": { "yaml": "^2.9.1" }, "peerDependencies": { "@standard-schema/spec": "^1.0.0", "@valibot/to-json-schema": "^1.8.0", "valibot": "^1.5.0" } }, "sha512-rIkiVqoICQVAdmz+G2EpqwKeU2UfvF3R2Y7+kmOTlnO4JaxR4rYndcYCj2k3f+w3f7FR/aldKCXFcKrTMg1ljg=="], + "@celados/argc": ["@celados/argc@11.0.0", "https://npm.celados.com/@celados/argc/-/@celados/argc-11.0.0.tgz", { "dependencies": { "yaml": "^2.9.1" }, "peerDependencies": { "@standard-schema/spec": "^1.0.0", "@valibot/to-json-schema": "^1.8.0", "valibot": "^1.5.0" } }, "sha512-376S0EpKHXV00RLGmQuMfuYYZBLgWIAHngpdmGAbGAn5FBhHNeKd5Lg9XNdv/qtTfIwlONOLnfyt4QTM1Gw3ZA=="], "@celados/argc-latch": ["@celados/argc-latch@1.0.0", "https://npm.celados.com/@celados/argc-latch/-/@celados/argc-latch-1.0.0.tgz", { "peerDependencies": { "@celados/argc": ">=10.0.0" } }, "sha512-Ewch1u44WzWQKhzqZ6i19B4dI0d01YDzBaL3kencCOr63Sm8xwIcqeMxS0/BKInsQKm1fWoHnntQn56HDDoFug=="], diff --git a/package.json b/package.json index 9b8c4a5..7a6e52f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vox", - "version": "3.0.0", + "version": "3.1.0", "description": "Agent-facing speech to text and text to speech over Alibaba Model Studio.", "repository": "https://github.com/celados/vox", "bin": { @@ -18,7 +18,7 @@ "build": "bun build src/main.ts --outfile=dist/vox --target=bun --minify && chmod +x dist/vox" }, "dependencies": { - "@celados/argc": "^10.3.1", + "@celados/argc": "^11.0.0", "@celados/argc-latch": "^1.0.0", "@valibot/to-json-schema": "^1.8.0", "valibot": "^1.5.0", diff --git a/src/main.test.ts b/src/main.test.ts index 00e48e7..47247b4 100644 --- a/src/main.test.ts +++ b/src/main.test.ts @@ -39,31 +39,33 @@ test("@schema exposes the dotted command surface", async () => { const { stdout, stderr, exitCode } = await run(["@schema"]); expect(exitCode, stderr).toBe(0); for (const fragment of [ - "status()", - "hear(input: {", - "session:", - "list(", - "remove(", - "export(input: {", - "vocab:", - "sync(", - "prune(", - "say(input: {", - "voice:", - "record(", - "cache:", + "### status\n", + "### hear\n", + "### session.*\n", + "### session.list\n", + "### session.remove\n", + "### export\n", + "### vocab.*\n", + "### vocab.sync\n", + "### vocab.prune\n", + "### say\n", + "### voice.*\n", + "### voice.record\n", + "### cache.*\n", ]) { expect(stdout).toContain(fragment); } - expect(stdout).not.toContain("dashscope("); - expect(stdout).not.toContain("auth:"); + expect(stdout).not.toContain("### dashscope"); + expect(stdout).not.toContain("### auth"); expect(stdout).not.toContain("values:"); // Key fields are named once (addGlobalDefs), not repeated per command. expect(stdout).toContain( "type DashScopeKey = string | { ref: `env:${string}` | `bw://${string}/${string}` }", ); - expect(stdout).toContain("prune(input: { apiKey?: DashScopeKey;"); - expect(stdout).toContain("list(input: { apiKey?: ProviderKey })"); + expect(stdout).toContain("{ apiKey?: DashScopeKey; dryRun?: boolean = false }"); + expect(stdout).toContain( + "### vocab.list\nList local vocabularies, sync state, and remote quota\n{ apiKey?: ProviderKey }", + ); expect(stdout).toContain("text: string | { ref: `file:${string}` }"); expect(stdout).toContain("env:DASHSCOPE_API_KEY → bw://"); expect(stdout).toContain("env:MIMO_API_KEY → bw://"); @@ -163,7 +165,8 @@ test("speaker command schemas preserve enrollment, matching settings, and identi const home = await mkdtemp(join(tmpdir(), "vox-speaker-cli-")); const schema = await run(["@schema", ".speaker"], home); expect(schema.exitCode, schema.stderr).toBe(0); - expect(schema.stdout).toContain("enroll(input: { id: string; name: string; file: string;"); + expect(schema.stdout).toContain("### speaker.enroll\n"); + expect(schema.stdout).toMatch(/\n id: string\n name: string\n file: string\n/); expect(schema.stdout).toContain("threshold?: number"); const config = await run(["speaker.config", "{ threshold: 0.72, margin: 0.12 }"], home); expect(config.exitCode, config.stderr).toBe(0); diff --git a/src/schema.ts b/src/schema.ts index b5401d5..059cd93 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -14,7 +14,6 @@ const status = c .meta({ description: "Preflight: whether each provider key resolves (env, then vault), with sources tried. Never prints key material", - examples: ["vox status"], }) .input(s(v.object({}))); @@ -22,10 +21,7 @@ const hear = c .meta({ description: "Transcribe audio into a cached run and Markdown file, optionally identify enrolled speakers", - examples: [ - "vox hear --file meeting.m4a", - "vox hear \"{ file: 'lecture.mp3', lang: ['zh'], speakers: true }\"", - ], + examples: ["vox hear \"{ file: 'lecture.mp3', lang: ['zh'], speakers: true }\""], }) .input( s( @@ -54,7 +50,6 @@ const speaker = group( enroll: c .meta({ description: "Enroll a named speaker from 3–30 seconds of clean solo audio", - examples: ["vox speaker.enroll \"{ id: 'ethan', name: 'Ethan', file: 'ethan.wav' }\""], }) .input( s( @@ -81,7 +76,6 @@ const speaker = group( identify: c .meta({ description: "Identify speakers in a stored run without uploading or repeating ASR", - examples: ["vox speaker.identify \"{ sid: 'a3f1c2', output: 'meeting.transcript.md' }\""], }) .input( s( @@ -102,7 +96,6 @@ const session = group( list: c .meta({ description: "List run envelopes, newest first. No transcript — use export for content", - examples: ["vox session.list", "vox session.list --file meeting.m4a"], }) .input( s( @@ -115,7 +108,6 @@ const session = group( remove: c .meta({ description: "Delete one run by unique sid prefix, or every run with all", - examples: ["vox session.remove --sid a3f1c2", "vox session.remove --all"], }) .input( s( @@ -133,10 +125,7 @@ const exportCmd = c .meta({ description: "Render a stored run as srt, vtt, md, txt, or json. stdout is the document unless output is set", - examples: [ - "vox export --sid a3f1c2 --format md", - "vox export --sid a3f1c2 --format srt --output meeting.srt", - ], + examples: ["vox export --sid a3f1c2 --format srt --output meeting.srt"], }) .input( s( @@ -159,7 +148,7 @@ const vocab = group( .meta({ description: "Push local YAML to the server for a target model. hear --vocab syncs on demand", - examples: ["vox vocab.sync --name meeting", "vox vocab.sync --all --model qwen"], + examples: ["vox vocab.sync --all --model qwen"], }) .input( s( @@ -176,7 +165,6 @@ const vocab = group( prune: c .meta({ description: "Delete server-side lists no local YAML claims", - examples: ["vox vocab.prune --dryRun"], }) .input(s(v.objectAsync({ ...dashscopeAuth, dryRun: v.optional(v.boolean(), false) }))), }, @@ -187,7 +175,6 @@ const say = c description: "Speak text with TTS. Multi-line text: whole input as YAML with text: |, or a file with text: { ref: 'file:…' }", examples: [ - "vox say --text 'Hello world' --voice Cherry", "vox say - <<'EOF'\nvoice: Cherry\ntext: |\n First line.\n Slow and clear.\nEOF", "vox say \"{ text: { ref: 'file:script.txt' }, voice: 'Cherry' }\"", ], @@ -219,7 +206,6 @@ const voice = group( record: c .meta({ description: "Enroll a cloned voice from a file, or record from the mic on a TTY", - examples: ["vox voice.record --file sample.wav --name myvoice"], }) .input( s(