Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## 0.5.1 — 2026-05-14

### Fixed

- `vk create` now exits **5** (business failure) when the backend rejects
`POST /v1/tasks/init` with `insufficient_credits` (envelope code 100001),
matching the stream-side path's existing behavior. Previously this case
exited 1 (cobra's generic error code), inconsistent with the documented
exit-code contract and with the same condition surfacing later in the
pipeline. Caught while running real-backend smoke tests during 0.5.0
validation.

## 0.5.0 — 2026-05-14

### New
Expand Down
4 changes: 3 additions & 1 deletion cmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,9 @@ var createCmd = &cobra.Command{
task, err := fc.InitTask(ctx, initParams)
if err != nil {
if errs.HasCode(err, "insufficient_credits") {
return fmt.Errorf("%s", i18n.T("credits.insufficient"))
// Mirror the stream-side path's exit code: business failure → 5.
fmt.Fprintln(os.Stderr, i18n.T("credits.insufficient"))
os.Exit(5)
}
if errs.HasCode(err, "script_invalid") {
// Backend's localized message already lives on the error.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vibeknow-cli",
"version": "0.5.0",
"version": "0.5.1",
"description": "VibeKnow CLI — turn docs / URLs into videos",
"license": "MIT",
"bin": {
Expand Down
2 changes: 1 addition & 1 deletion skills/vibeknow-core/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: vibeknow-core
version: 0.5.0
version: 0.5.1
description: "vibeknow CLI setup, authentication, profile management, and diagnostics. Use when: first-time setup, auth errors, switching environments, diagnosing connection issues."
metadata:
requires:
Expand Down
2 changes: 1 addition & 1 deletion skills/vibeknow-create/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: vibeknow-create
version: 0.5.0
version: 0.5.1
description: "Generate videos from documents/URLs/files, track video task progress, download results, list voice templates. Use when: user wants to create a video, check task status, download video, or browse voices."
metadata:
requires:
Expand Down
2 changes: 1 addition & 1 deletion skills/vibeknow-doc/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: vibeknow-doc
version: 0.5.0
version: 0.5.1
description: "Upload documents to vectoria and check processing status. Use when: user wants to upload a document, check if a document is ready, or get a doc_id for use with vibeknow create."
metadata:
requires:
Expand Down
60 changes: 60 additions & 0 deletions tests/integration/create_credits_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package integration

import (
"encoding/json"
"net/http"
"net/http/httptest"
"os"
"os/exec"
"strings"
"testing"
)

// TestCreate_InsufficientCreditsOnInit_Exits5 covers the bug fixed in 0.5.1:
// when the backend rejects InitTask with envelope code 100001 (insufficient
// credits), the CLI must exit 5 (business failure) to match the stream-side
// path's behavior, not exit 1 from cobra's default error handler.
func TestCreate_InsufficientCreditsOnInit_Exits5(t *testing.T) {
if testing.Short() {
t.Skip("integration test")
}

mux := http.NewServeMux()
mux.HandleFunc("/v1/tasks/init", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusPaymentRequired) // 402, matches backend
_ = json.NewEncoder(w).Encode(map[string]any{
"code": 100001,
"message": "insufficient credits",
})
})
srv := httptest.NewServer(mux)
defer srv.Close()

bin := build(t)
configHome := buildVideoProfile(t, srv.URL)

cmd := exec.Command(bin, "create", "--from", "doc_abc12345")
var stdout, stderr strings.Builder
cmd.Stdout = &stdout
cmd.Stderr = &stderr
cmd.Env = append(os.Environ(),
"VIBEKNOW_TOKEN=fake-token",
"VIBEKNOW_CONFIG_HOME="+configHome,
)

err := cmd.Run()
code := 0
if ee, ok := err.(*exec.ExitError); ok {
code = ee.ExitCode()
} else if err != nil {
t.Fatalf("run: %v\nstderr: %s", err, stderr.String())
}

if code != 5 {
t.Fatalf("exit code = %d, want 5 (business failure)\nstderr: %s", code, stderr.String())
}
if !strings.Contains(stderr.String(), "insufficient credits") {
t.Fatalf("stderr missing insufficient-credits message:\n%s", stderr.String())
}
}
Loading