Skip to content

feat(cli)!: migrate generate.* to outputSuccess envelope (Issue #33 — 2c-sweep-1)#195

Merged
kiyeonjeon21 merged 1 commit intomainfrom
2c-sweep-1-generate
Apr 28, 2026
Merged

feat(cli)!: migrate generate.* to outputSuccess envelope (Issue #33 — 2c-sweep-1)#195
kiyeonjeon21 merged 1 commit intomainfrom
2c-sweep-1-generate

Conversation

@kiyeonjeon21
Copy link
Copy Markdown
Contributor

Summary

Sweep 1 of 3. Migrates the 11 remaining `generate.` commands to the new `outputSuccess()` envelope established in #194 (canary on `generate image`). The full `generate.` family — 12 commands — now emits the same shape.

Smoke tests (local)

```
$ vibe generate speech "hi" --dry-run --json
{
"command": "generate speech",
"dryRun": true,
"elapsedMs": 0,
"costUsd": 0.3,
"warnings": [],
"data": { "params": { "text": "hi", "voice": "21m00...", "output": "output.mp3" } }
}

$ vibe generate video "test" --dry-run --json
{
"command": "generate video",
"dryRun": true,
"elapsedMs": 0,
"costUsd": 5,
"warnings": [],
"data": { "params": { "prompt": "test", "provider": "fal", "duration": "5", ... } }
}
```

Files (11)

File Sites
`generate/speech.ts` 1 dry-run + 1 success
`generate/background.ts` 1 dry-run + 1 success
`generate/music.ts` 1 dry-run + 2 success (Suno + ElevenLabs)
`generate/music-status.ts` 1 success (read-only)
`generate/sound-effect.ts` 1 dry-run + 1 success
`generate/storyboard.ts` 1 dry-run + 2 success
`generate/thumbnail.ts` 2 success (no `--dry-run`)
`generate/video.ts` 1 dry-run + 1 success
`generate/video-status.ts` 3 success (read-only, per-provider)
`generate/video-cancel.ts` 2 success (per-provider)
`generate/video-extend.ts` 1 dry-run + 2 success

27 mechanical edits total (1 import + 1 `startedAt` const + N call sites per file).

Transformation pattern (uniform)

```ts
// Before
outputResult({ success: true, ...domain })

// After
outputSuccess({
command: "generate ",
startedAt,
data: { ...domain }, // 'success: true' dropped — exit code is the signal
})
```

Migration for agents (extends canary's table)

Old New
`jq .audio` / `.video` / `.image` / `.audioBuffer` `jq .data.`
`jq .characterCount` / `.duration` / `.taskId` `jq .data.`
`jq .estimatedCost` (string) `jq .costUsd` (number)
`jq .success` drop — exit code 0 is success

What's next

  • `generate.*` family is complete on new envelope
  • 2c-sweep-2 (next PR): edit + audio + detect + project + batch + export + run + init
  • 2c-sweep-3 (after sweep-2): scene + pipeline + analyze (quirks: composite outputs, `--fields` filtering)
  • 2c-coverage (separate): add `--json` to commands that lack it (timeline success path, scene render/build/styles, doctor, export)

Verification

  • `pnpm -F @vibeframe/cli exec tsc --noEmit` — 0 errors
  • `pnpm lint` — 0 errors (8 pre-existing warnings in timeline.ts, unrelated)
  • `pnpm -F @vibeframe/cli exec vitest run` — 700 passed, 9 skipped, 0 failed
  • `bash scripts/sync-counts.sh --check` — green
  • `grep -rn "outputResult" packages/cli/src/commands/generate/` — 0 hits
  • Manual smoke tests above

…eep-1)

BREAKING CHANGE: Migrates the 11 remaining `generate.*` commands to the
new `outputSuccess()` envelope established in #194 (canary on
`generate image`). All 12 generate.* commands now emit the same shape:

```json
{
  "command": "generate <name>",
  "dryRun"?: true,
  "elapsedMs": 1234,
  "costUsd": 0.30,
  "warnings": [],
  "data": { ...domain keys... }
}
```

Files migrated:
- generate/speech.ts (TTS)
- generate/background.ts
- generate/music.ts (Suno + ElevenLabs branches)
- generate/music-status.ts
- generate/sound-effect.ts
- generate/storyboard.ts
- generate/thumbnail.ts (no dry-run; read-only meta + DALL-E branches)
- generate/video.ts
- generate/video-status.ts (3 provider branches)
- generate/video-cancel.ts (2 provider branches)
- generate/video-extend.ts (2 provider branches)

27 mechanical edits (1 import + 1 startedAt + N call sites per file).
The transformation is uniform with the canary's pattern:

  outputResult({ success: true, ...domain })
    →
  outputSuccess({
    command: "generate <name>",
    startedAt,
    data: { ...domain },        // success: true dropped (exit code is signal)
  })

  outputResult({ dryRun: true, command: "...", params: {...} })
    →
  outputSuccess({
    command: "...",
    startedAt,
    dryRun: true,
    data: { params: {...} },
  })

Smoke-tested locally:

  $ vibe generate speech "hi" --dry-run --json
  → costUsd 0.3, dryRun true, data.params.text = "hi"

  $ vibe generate video "test" --dry-run --json
  → costUsd 5.0, data.params.{prompt,provider,...}

Migration for agents (extends the canary's table):
- jq .audio | .video | .image | .audioBuffer  →  jq .data.<same>
- jq .characterCount | .duration | .taskId    →  jq .data.<same>
- jq .estimatedCost (string)                   →  jq .costUsd (number)
- jq .success                                  →  drop, use exit code

The `generate.*` family is now fully on the new envelope. Old
`outputResult()` helper still exists for the remaining 79 commands;
2c-sweep-2 (edit/audio/detect/project/batch/export) and 2c-sweep-3
(scene/pipeline/analyze) finish the migration.

Verification:
- typecheck: 0 errors
- lint: 0 errors (8 pre-existing warnings in timeline.ts)
- tests: 700 passed, 9 skipped, 0 failed
- grep "outputResult" packages/cli/src/commands/generate/: 0 hits

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 28, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
vibeframe Ready Ready Preview, Comment Apr 28, 2026 2:46pm

Request Review

@kiyeonjeon21 kiyeonjeon21 merged commit 128b323 into main Apr 28, 2026
5 checks passed
@kiyeonjeon21 kiyeonjeon21 deleted the 2c-sweep-1-generate branch April 28, 2026 14:55
kiyeonjeon21 added a commit that referenced this pull request Apr 28, 2026
…tputSuccess (Issue #33 — 2c-sweep-2) (#196)

* feat(cli)!: migrate edit/audio/detect/batch/project/export/init/etc. to outputSuccess (#33 — 2c-sweep-2)

BREAKING CHANGE: Sweep 2 of 3 for the new --json envelope. Migrates 13
commands files (~55 outputResult sites) to outputSuccess(). All commands
in this PR now emit the canonical envelope established in #194 / #195.

Files migrated:
- edit-cmd.ts (14 sites — 7 edit subcommands)
- ai-edit-cli.ts (12 sites — more edit subcommands)
- audio.ts (10 sites — 6 audio subcommands)
- batch.ts (4 sites)
- detect.ts (3 sites)
- project.ts (2 sites)
- export.ts (2 sites — threaded `startedAt` through runHyperframesExport helper)
- run.ts (2 sites — pipeline runner)
- ai-motion.ts (1 site — `generate motion`, registered under generateCommand)
- init.ts (1 site)
- doctor.ts (1 site)
- demo.ts (1 site)
- walkthrough.ts (2 sites)

Also fixes 2 test files broken by the envelope change:
- doctor.test.ts: 17 sites updated `json.result.X` → `json.data.X`
- init.test.ts: 7 sites updated `result.X` → `result.data.X` (top-level
  `result.command` left as-is — that's the new top-level key)

Doctor was simplified: previously emitted `data: { result: results }`
(redundant nesting); now emits `data: results` directly. Tests updated
to match. Saves one level of `.data.result.scope` → `.data.scope` for
agents.

Smoke tests (verified locally):

  $ vibe detect scenes /tmp/x.mp4 --dry-run --json
  → { command: "detect scenes", costUsd: 0, dryRun: true, data: { params: {...} } }

  $ vibe project create /tmp/test --dry-run --json
  → { command: "project create", costUsd: 0, dryRun: true, data: { params: {...} } }

  $ vibe doctor --json
  → { command: "doctor", elapsedMs: 87, costUsd: 0, data: { system: {...}, scope: {...}, ... } }

Pipeline / scene / analyze territory deferred to 2c-sweep-3.

Verification:
- typecheck: 0 errors
- lint: 0 errors (8 pre-existing warnings in untouched timeline.ts/scene.ts)
- tests: 700 passed (1 pre-existing flake on `generate music` — fails under
  full-suite parallel load when 30s timeout < cold-start time; passes in
  isolation in 9.8s and is environment-dependent on ELEVENLABS_API_KEY)
- grep "outputResult" across 13 migrated files: 0 hits

Note on `run.ts` — the pipeline runner previously surfaced
`success: result.success` at top level (could be false when steps fail
but the runner completes). The new envelope drops that key per the design.
Pipeline failure is still derivable from `data.error` and per-step
`data.steps[].success`. If we want hard-fail exit codes for partial
pipeline failure, that's a follow-up: set `process.exitCode = 1` in
run.ts when `!result.success`. Filed mentally for later — out of sweep-2
scope.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(cli): doctor.ts spread DiagnosticResults to satisfy Record<string, unknown> (#33 — 2c-sweep-2 fix)

CI's full-repo typecheck (`pnpm -r exec tsc --noEmit`) caught
`error TS2322: Type 'DiagnosticResults' is not assignable to type
'Record<string, unknown>'` in doctor.ts:71. The single-package check
I ran locally (`pnpm -F @vibeframe/cli exec tsc --noEmit`) didn't
catch it because of tsconfig differences.

Spreading the interface (`{ ...results }`) widens it to
`Record<string, unknown>` cleanly without changing observable behavior.
Same JSON output as before.

Updated my local script habit too — sweep-3 will use `pnpm -r exec tsc`
to match CI before push.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
kiyeonjeon21 added a commit that referenced this pull request Apr 28, 2026
Bumps version 0.71.0 → 0.72.0 across all 7 package.json files and adds
the v0.72.0 CHANGELOG entry covering the breaking --json envelope
change shipped in #192/#193/#194/#195/#196/#197.

Auto-tag + auto-publish workflow will fire on merge:
- annotated tag v0.72.0
- @vibeframe/cli 0.72.0 → npm
- @vibeframe/mcp-server 0.72.0 → npm

Breaking summary (full table in CHANGELOG):
- jq .images / .video / .outputPath  →  jq .data.<same>
- jq .estimatedCost (string)         →  jq .costUsd (number)
- jq .success                        →  drop, use exit code

Errors unchanged (stderr StructuredError envelope).
Pre-1.0 → no transition shim, one-line migration via jq .data | …

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
kiyeonjeon21 added a commit that referenced this pull request Apr 28, 2026
…#201)

feat(cli): improve --describe enum extraction (Issue #33 — 2d)

Strengthens `extractEnumFromDescription` in commands/schema.ts so
commander descriptions surface more useful enum values in
`vibe <cmd> --describe` JSON Schema output. Agent prompt-generation
quality scales with how well the schema enumerates valid values.

## Before this PR

Only commander options whose description matched two narrow patterns
got `enum` arrays:
1. `Provider: a, b, c` (case-insensitive)
2. `^[A-Z][a-z]+:\s*a, b, c` (single-word label, lowercase values)

Most options describing valid values via parentheses or oxford-comma
prose did NOT get enums. Pre-PR survey: ~10 commands had enums.

## After this PR

42 options across 28 commands now have proper `enum` arrays. Extractor
now handles:

1. **Pattern 1 (extended)**: parentheticals are stripped before parsing
   so `Provider: openai (default ...), gemini, grok, runway` no longer
   truncates at the first `(`.
2. **Pattern 2 (extended)**: multi-word labels with up to 3 words
   (`Aspect ratio: 16:9, 9:16, 1:1`), and ratio-shaped values like
   `16:9` are accepted.
3. **Pattern 3 (new)**: parenthesized lists like
   `Aspect ratio (16:9, 9:16, 1:1)` extract correctly. Heuristic guards:
   skip `(default: ...)` annotations, reject if any value contains
   whitespace (indicates prose like `5 or 10`).
4. **Oxford comma**: `a, b, or c` properly produces `["a", "b", "c"]`
   (the `or ` prefix is stripped after trimming whitespace from the
   split-token).

## Selected new enums (full table in snapshot diff)

  generate.image --provider     ['openai', 'gemini', 'grok', 'runway']
  generate.video --provider     ['fal', 'grok', 'kling', 'runway', 'veo']
  generate.video --ratio        ['16:9', '9:16', '1:1']
  generate.video --resolution   ['720p', '1080p', '4k']
  generate.music --provider     ['elevenlabs', 'replicate']
  generate.thumbnail --style    ['youtube', 'instagram', 'tiktok', 'twitter']
  edit.caption --style          ['minimal', 'bold', 'outline', 'karaoke']
  edit.reframe --aspect         ['9:16', '1:1', '4:5']
  edit.reframe --focus          ['auto', 'face', 'center', 'action']
  edit.image --provider         ['gemini', 'openai', 'grok']
  edit.translate-srt --provider ['claude', 'openai']
  edit.upscale-video --model    ['real-esrgan', 'topaz']
  audio.transcribe --format     ['json', 'srt', 'vtt']
  pipeline.auto-shorts --aspect ['9:16', '1:1']
  project.create --ratio        ['16:9', '9:16', '1:1', '4:5']
  ... and 27 more

## Snapshot diff

The 2e snapshot tests caught 24 schema changes across 28 commands.
Updated via `vitest -u src/commands/envelope-snapshots.test.ts`. Each
diff shows exactly which option grew an enum array — perfect for PR
review.

## Issue #33 closure

This is the final sub-PR for Issue #33 (CLI UX audit). Status:

- 2a (audit baseline) — #192 ✓
- 2b (exit code enforcement) — #193 ✓
- 2c canary + sweeps — #194 / #195 / #196 / #197 ✓
- 2c-coverage (add --json to commands lacking it) — #199 ✓
- 2e (snapshot tests) — #200 ✓
- **2d (this PR — describe quality)**

After this merges, every leaf command emits a canonical envelope, has
descriptive `--describe` schemas with enum hints, and is gated against
drift by the 2e snapshot tests.

Verification:
- pnpm -r exec tsc --noEmit: 0 errors
- pnpm lint: 0 errors
- pnpm -F @vibeframe/cli exec vitest run: 786 passed, 9 skipped, 0 failed
- 24 snapshot updates accepted and verified idempotent

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant