@pippit-dev/cli 1.0.48 → 1.0.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -9
- package/checksums.txt +6 -6
- package/cmd/generate_video/query_result.go +1 -14
- package/cmd/generate_video_test.go +73 -2
- package/dist/checksums.txt +6 -6
- package/dist/xyq-canvas-command-runtime.cjs +14 -14
- package/dist/xyq-canvas-command-runtime.cjs.LEGAL.txt +1 -27
- package/dist/xyq-canvas-command-runtime.cjs.sha256 +2 -2
- package/internal/canvas/image_binding.go +152 -0
- package/internal/canvas/image_binding_test.go +137 -0
- package/internal/canvas/media_identity.go +21 -12
- package/internal/generate_video/query_result.go +80 -23
- package/package.json +1 -1
- package/scripts/canvas-command-guides.js +13 -21
- package/scripts/canvas-command.js +11 -0
- package/skills/xyq-nest-skill/commands/canvas.md +6 -1
package/README.md
CHANGED
|
@@ -265,16 +265,11 @@ pippit-tool-cli canvas command run create_biz_node \
|
|
|
265
265
|
|
|
266
266
|
`guide [topic]` 提供无需登录的离线帮助。无主题时仅返回索引,可选 `storyboard`、`prompt-references`、`time`、`timeline`、`scene3d`;正文包含单位、ID 来源、前置条件和最小示例。指南不启用新能力,先用 `list` 确认本机运行时支持哪些命令。故事板指南说明原生 `<duration-ms>` 标签累加与引用格式;目前没有公开的故事板脚本编辑、镜头排序或指定镜头生成领域命令,通用视频生成与资产补丁不能替代其业务流程。
|
|
267
267
|
|
|
268
|
-
3D
|
|
268
|
+
当前 SDK 主干的 3D 导演文档已迁移到 V2,旧 CLI 的 `xyq.scene3d.apply/query` 入口已移除。本版本沿用主干能力;3D 节点仍可通过业务工厂创建,内部对象编辑使用 Web 3D 导演台,不通过通用资产补丁改写文档。
|
|
269
269
|
|
|
270
|
-
|
|
271
|
-
pippit-tool-cli canvas command describe xyq.scene3d.apply
|
|
272
|
-
pippit-tool-cli canvas command run xyq.scene3d.query \
|
|
273
|
-
--canvas-id CANVAS_ID --input '{"nodeId":"DIRECTOR_NODE_ID"}'
|
|
274
|
-
pippit-tool-cli canvas command run xyq.scene3d.apply \
|
|
275
|
-
--canvas-id CANVAS_ID \
|
|
276
|
-
--input '{"nodeId":"DIRECTOR_NODE_ID","operations":[{"command":"create_node","args":{"kind":"camera","id":"camera-2","name":"Close-up"}}]}'
|
|
270
|
+
多轨道通过外层画布节点定位,先查询轨道、片段 ID 和版本,再执行编辑:
|
|
277
271
|
|
|
272
|
+
```bash
|
|
278
273
|
pippit-tool-cli canvas command describe xyq.timeline.apply
|
|
279
274
|
pippit-tool-cli canvas command run xyq.timeline.query \
|
|
280
275
|
--canvas-id CANVAS_ID --input '{"nodeId":"TIMELINE_NODE_ID"}'
|
|
@@ -455,7 +450,7 @@ pippit-tool-cli query-result \
|
|
|
455
450
|
--download-dir "./output"
|
|
456
451
|
```
|
|
457
452
|
|
|
458
|
-
`query-result` 会查询指定 Run 并输出 JSON。Run 成功完成后下载视频和图片产物,`completed=true`,`videos` 和 `images` 中各包含 `download_url` 和 `output_path`;图片扩展名取自产物 `metadata.format`,缺省时兜底 `.png
|
|
453
|
+
`query-result` 会查询指定 Run 并输出 JSON。Run 成功完成后下载视频和图片产物,`completed=true`、`status="succeeded"`,`videos` 和 `images` 中各包含 `download_url` 和 `output_path`;图片扩展名取自产物 `metadata.format`,缺省时兜底 `.png`。`status` 是机读状态,共 5 种取值:`running`(运行中,对应服务端已提交、处理中、生成中、程序中断等继续轮询的状态)、`succeeded`(成功)、`failed`(失败并填充 `error_message`)、`canceled`(已取消)、`unknown`(未指定、等待补充输入、人工交互中断等无法自动判定的状态)。`completed` 只表示是否到终态(成功、失败、已取消时为 true),判断成功失败请使用 `status`;查询或下载本身失败时 `status="unknown"`、`completed=false`,具体原因见 `error_message`。
|
|
459
454
|
|
|
460
455
|
## Adapter 接入边界
|
|
461
456
|
|
package/checksums.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
a458435d1197a30b707df6a462f8226a7e0712a68321e80122f94c2adc1de6b5 pippit-tool-cli-1.0.50-darwin-amd64.tar.gz
|
|
2
|
+
f2d521422ef4e4ac1f4a8ce1111f8bffd2b29a70e83cbaf5b931354085894152 pippit-tool-cli-1.0.50-darwin-arm64.tar.gz
|
|
3
|
+
5655d75170e4e6616e12ba2f6c05849381b5eca14b70b4e5273357c457c90d85 pippit-tool-cli-1.0.50-linux-amd64.tar.gz
|
|
4
|
+
c38ae24da3a18c9ce295a67523a3608da4c8fa10a1e125c03b07d635372f1894 pippit-tool-cli-1.0.50-linux-arm64.tar.gz
|
|
5
|
+
a02ee4dfd051201fbbf84188d7969ec3be3ffa8a0ef70e0ac7fd94a307fce6af pippit-tool-cli-1.0.50-windows-amd64.zip
|
|
6
|
+
72f17b0945d8619ff5a80da26d474e8d4e30f56b4c70d0c01f838ae3fd8080b9 pippit-tool-cli-1.0.50-windows-arm64.zip
|
|
@@ -26,7 +26,7 @@ func NewQueryResultCommand(stdout, stderr io.Writer, runner *common.Runner) *cob
|
|
|
26
26
|
"run_id": strings.TrimSpace(opts.RunID),
|
|
27
27
|
"download_dir": strings.TrimSpace(opts.DownloadDir),
|
|
28
28
|
})
|
|
29
|
-
result =
|
|
29
|
+
result = internalgen.NewQueryResultError(err, opts)
|
|
30
30
|
}
|
|
31
31
|
encoder := json.NewEncoder(stdout)
|
|
32
32
|
encoder.SetIndent("", " ")
|
|
@@ -40,16 +40,3 @@ func NewQueryResultCommand(stdout, stderr io.Writer, runner *common.Runner) *cob
|
|
|
40
40
|
cmd.Flags().StringVar(&opts.DownloadDir, "download-dir", "", "directory to download completed videos or images into")
|
|
41
41
|
return cmd
|
|
42
42
|
}
|
|
43
|
-
|
|
44
|
-
func queryResultFromError(err error, opts *internalgen.QueryResultOptions) *internalgen.QueryResultResult {
|
|
45
|
-
result := &internalgen.QueryResultResult{
|
|
46
|
-
ErrorMessage: err.Error(),
|
|
47
|
-
Videos: []internalgen.QueryResultVideo{},
|
|
48
|
-
Images: []internalgen.QueryResultImage{},
|
|
49
|
-
}
|
|
50
|
-
if opts != nil {
|
|
51
|
-
result.ThreadID = strings.TrimSpace(opts.ThreadID)
|
|
52
|
-
result.RunID = strings.TrimSpace(opts.RunID)
|
|
53
|
-
}
|
|
54
|
-
return result
|
|
55
|
-
}
|
|
@@ -2,6 +2,7 @@ package cmd
|
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
4
|
"bytes"
|
|
5
|
+
"fmt"
|
|
5
6
|
"io"
|
|
6
7
|
"net/http"
|
|
7
8
|
"net/http/httptest"
|
|
@@ -496,6 +497,9 @@ func TestQueryResultDownloadsCompletedVideo(t *testing.T) {
|
|
|
496
497
|
if got["completed"] != true {
|
|
497
498
|
t.Fatalf("completed = %v, want true", got["completed"])
|
|
498
499
|
}
|
|
500
|
+
if got["status"] != "succeeded" {
|
|
501
|
+
t.Fatalf("status = %v, want succeeded", got["status"])
|
|
502
|
+
}
|
|
499
503
|
if got["thread_id"] != "thread_123" || got["run_id"] != "run_456" {
|
|
500
504
|
t.Fatalf("ids = (%v, %v), want thread/run ids", got["thread_id"], got["run_id"])
|
|
501
505
|
}
|
|
@@ -600,6 +604,9 @@ func TestQueryResultIgnoresVideoDataWithoutVideoSubType(t *testing.T) {
|
|
|
600
604
|
if got["completed"] != false {
|
|
601
605
|
t.Fatalf("completed = %v, want false", got["completed"])
|
|
602
606
|
}
|
|
607
|
+
if got["status"] != "unknown" {
|
|
608
|
+
t.Fatalf("status = %v, want unknown", got["status"])
|
|
609
|
+
}
|
|
603
610
|
if got["thread_id"] != "thread_123" || got["run_id"] != "run_456" {
|
|
604
611
|
t.Fatalf("ids = (%v, %v), want thread/run ids", got["thread_id"], got["run_id"])
|
|
605
612
|
}
|
|
@@ -628,6 +635,9 @@ func TestQueryResultValidationErrorReturnsJSON(t *testing.T) {
|
|
|
628
635
|
if got["completed"] != false {
|
|
629
636
|
t.Fatalf("completed = %v, want false", got["completed"])
|
|
630
637
|
}
|
|
638
|
+
if got["status"] != "unknown" {
|
|
639
|
+
t.Fatalf("status = %v, want unknown", got["status"])
|
|
640
|
+
}
|
|
631
641
|
if got["thread_id"] != "" || got["run_id"] != "run_456" {
|
|
632
642
|
t.Fatalf("ids = (%v, %v), want empty thread_id and run_id", got["thread_id"], got["run_id"])
|
|
633
643
|
}
|
|
@@ -664,12 +674,15 @@ func TestQueryResultGetThreadBusinessErrorReturnsErrorMessage(t *testing.T) {
|
|
|
664
674
|
t.Fatalf("Execute() error = %v, stderr = %s", err, stderr.String())
|
|
665
675
|
}
|
|
666
676
|
got := decodeJSON(t, stdout.Bytes())
|
|
667
|
-
if got["completed"] !=
|
|
668
|
-
t.Fatalf("completed = %v, want
|
|
677
|
+
if got["completed"] != false {
|
|
678
|
+
t.Fatalf("completed = %v, want false", got["completed"])
|
|
669
679
|
}
|
|
670
680
|
if got["thread_id"] != "thread_123" || got["run_id"] != "run_456" {
|
|
671
681
|
t.Fatalf("ids = (%v, %v), want thread/run ids", got["thread_id"], got["run_id"])
|
|
672
682
|
}
|
|
683
|
+
if got["status"] != "unknown" {
|
|
684
|
+
t.Fatalf("status = %v, want unknown", got["status"])
|
|
685
|
+
}
|
|
673
686
|
if got["error_message"] != "创作失败:暂时无法生成 log_id=log_456" {
|
|
674
687
|
t.Fatalf("error_message = %v, want get_thread business error", got["error_message"])
|
|
675
688
|
}
|
|
@@ -706,6 +719,9 @@ func TestQueryResultFailedReturnsErrorMessage(t *testing.T) {
|
|
|
706
719
|
if got["completed"] != true {
|
|
707
720
|
t.Fatalf("completed = %v, want true", got["completed"])
|
|
708
721
|
}
|
|
722
|
+
if got["status"] != "failed" {
|
|
723
|
+
t.Fatalf("status = %v, want failed", got["status"])
|
|
724
|
+
}
|
|
709
725
|
if _, ok := got["state"]; ok {
|
|
710
726
|
t.Fatalf("state should not be returned: %#v", got)
|
|
711
727
|
}
|
|
@@ -745,6 +761,9 @@ func TestQueryResultPendingDoesNotDownload(t *testing.T) {
|
|
|
745
761
|
if got["completed"] != false {
|
|
746
762
|
t.Fatalf("completed = %v, want false", got["completed"])
|
|
747
763
|
}
|
|
764
|
+
if got["status"] != "running" {
|
|
765
|
+
t.Fatalf("status = %v, want running", got["status"])
|
|
766
|
+
}
|
|
748
767
|
if _, ok := got["state"]; ok {
|
|
749
768
|
t.Fatalf("state should not be returned: %#v", got)
|
|
750
769
|
}
|
|
@@ -757,6 +776,58 @@ func TestQueryResultPendingDoesNotDownload(t *testing.T) {
|
|
|
757
776
|
}
|
|
758
777
|
}
|
|
759
778
|
|
|
779
|
+
func TestQueryResultRunStateMapping(t *testing.T) {
|
|
780
|
+
// state=3 needs artifacts and is covered by the dedicated success tests;
|
|
781
|
+
// every other state must map deterministically, including unknown values.
|
|
782
|
+
tests := []struct {
|
|
783
|
+
state int
|
|
784
|
+
wantStatus string
|
|
785
|
+
wantCompleted bool
|
|
786
|
+
}{
|
|
787
|
+
{0, "unknown", false},
|
|
788
|
+
{1, "running", false},
|
|
789
|
+
{2, "running", false},
|
|
790
|
+
{4, "failed", true},
|
|
791
|
+
{5, "canceled", true},
|
|
792
|
+
{6, "unknown", false},
|
|
793
|
+
{7, "running", false},
|
|
794
|
+
{8, "running", false},
|
|
795
|
+
{9, "unknown", false},
|
|
796
|
+
{99, "unknown", false},
|
|
797
|
+
}
|
|
798
|
+
for _, tt := range tests {
|
|
799
|
+
t.Run(fmt.Sprintf("state=%d", tt.state), func(t *testing.T) {
|
|
800
|
+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
801
|
+
if r.URL.Path != "/api/biz/v1/skill/get_thread" {
|
|
802
|
+
t.Fatalf("unexpected path %s", r.URL.Path)
|
|
803
|
+
}
|
|
804
|
+
payload := fmt.Sprintf(`{"ret":"0","data":{"thread":{"thread_id":"thread_123","run_list":[{"run_id":"run_456","state":%d}]}}}`, tt.state)
|
|
805
|
+
_, _ = w.Write([]byte(payload))
|
|
806
|
+
}))
|
|
807
|
+
defer server.Close()
|
|
808
|
+
|
|
809
|
+
var stdout, stderr bytes.Buffer
|
|
810
|
+
root := newTestRootCommand(t, &stdout, &stderr, server.URL)
|
|
811
|
+
root.SetArgs([]string{
|
|
812
|
+
"query-result",
|
|
813
|
+
"--thread-id", "thread_123",
|
|
814
|
+
"--run-id", "run_456",
|
|
815
|
+
"--download-dir", t.TempDir(),
|
|
816
|
+
})
|
|
817
|
+
if err := root.Execute(); err != nil {
|
|
818
|
+
t.Fatalf("Execute() error = %v, stderr = %s", err, stderr.String())
|
|
819
|
+
}
|
|
820
|
+
got := decodeJSON(t, stdout.Bytes())
|
|
821
|
+
if got["status"] != tt.wantStatus {
|
|
822
|
+
t.Fatalf("status = %v, want %s", got["status"], tt.wantStatus)
|
|
823
|
+
}
|
|
824
|
+
if got["completed"] != tt.wantCompleted {
|
|
825
|
+
t.Fatalf("completed = %v, want %v", got["completed"], tt.wantCompleted)
|
|
826
|
+
}
|
|
827
|
+
})
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
|
|
760
831
|
func serverURL(r *http.Request) string {
|
|
761
832
|
return "http://" + r.Host
|
|
762
833
|
}
|
package/dist/checksums.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
a458435d1197a30b707df6a462f8226a7e0712a68321e80122f94c2adc1de6b5 pippit-tool-cli-1.0.50-darwin-amd64.tar.gz
|
|
2
|
+
f2d521422ef4e4ac1f4a8ce1111f8bffd2b29a70e83cbaf5b931354085894152 pippit-tool-cli-1.0.50-darwin-arm64.tar.gz
|
|
3
|
+
5655d75170e4e6616e12ba2f6c05849381b5eca14b70b4e5273357c457c90d85 pippit-tool-cli-1.0.50-linux-amd64.tar.gz
|
|
4
|
+
c38ae24da3a18c9ce295a67523a3608da4c8fa10a1e125c03b07d635372f1894 pippit-tool-cli-1.0.50-linux-arm64.tar.gz
|
|
5
|
+
a02ee4dfd051201fbbf84188d7969ec3be3ffa8a0ef70e0ac7fd94a307fce6af pippit-tool-cli-1.0.50-windows-amd64.zip
|
|
6
|
+
72f17b0945d8619ff5a80da26d474e8d4e30f56b4c70d0c01f838ae3fd8080b9 pippit-tool-cli-1.0.50-windows-arm64.zip
|