@pippit-dev/cli 0.0.5 → 0.0.6
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 +3 -3
- package/checksums.txt +6 -6
- package/cmd/short_drama/short_drama.go +4 -4
- package/cmd/short_drama_test.go +33 -15
- package/internal/common/download_results.go +8 -8
- package/package.json +1 -1
- package/skills/short-drama/SKILL.md +13 -13
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ export XYQ_ACCESS_KEY="<access-key>"
|
|
|
13
13
|
pippit-cli short-drama +submit-run --message "写一个赛博朋克短剧开头"
|
|
14
14
|
pippit-cli short-drama +upload-file --path ./story.md
|
|
15
15
|
pippit-cli short-drama +get-thread --thread-id thread_123 --run-id run_456 --after-seq 0
|
|
16
|
-
pippit-cli short-drama +download-result --output-
|
|
16
|
+
pippit-cli short-drama +download-result --output-path ./thread_123/results/result.mp4 --url URL
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
NPM package names must be lowercase, so the publishable package name is
|
|
@@ -26,7 +26,7 @@ export XYQ_ACCESS_KEY="<access-key>"
|
|
|
26
26
|
go run . short-drama +submit-run --message "写一个赛博朋克短剧开头"
|
|
27
27
|
go run . short-drama +upload-file --path ./story.md
|
|
28
28
|
go run . short-drama +get-thread --thread-id thread_123 --run-id run_456 --after-seq 0
|
|
29
|
-
go run . short-drama +download-result --output-
|
|
29
|
+
go run . short-drama +download-result --output-path ./thread_123/results/result.mp4 --url URL
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
`+submit-run` calls `/api/biz/v1/skill/submit_run` and prints `thread_id`,
|
|
@@ -34,7 +34,7 @@ go run . short-drama +download-result --output-dir ./thread_123/results/result.m
|
|
|
34
34
|
`+get-thread` calls
|
|
35
35
|
`/api/biz/v1/skill/get_thread` and prints extracted `messages`.
|
|
36
36
|
`+download-result` downloads the result URL to
|
|
37
|
-
the `--output-
|
|
37
|
+
the `--output-path` file path. `+upload-file` is still mocked while
|
|
38
38
|
its real service contract is wired.
|
|
39
39
|
|
|
40
40
|
## HTTP Client
|
package/checksums.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
2d6ebc213dd8401622a5315846a1f2125b321ca55ed3689b661268ae0cdc7bb4 pippit-cli-0.0.6-darwin-amd64.tar.gz
|
|
2
|
+
2bedf7ed2f9afd313e8b983763e90e66a835b2f340fcda905cae8c82ba553735 pippit-cli-0.0.6-darwin-arm64.tar.gz
|
|
3
|
+
37ecf71b5d701dc257c0287983b511e403ff0cfc7690a07a0c4bcd32837c365e pippit-cli-0.0.6-linux-amd64.tar.gz
|
|
4
|
+
b6e41054960723d18809e1bad498f59fb7f68550e07c11e867f9580ac91a42da pippit-cli-0.0.6-linux-arm64.tar.gz
|
|
5
|
+
2103cb871134ec47f34b53b53e93d95d7190888bc035b8c78d48b925a3ace9eb pippit-cli-0.0.6-windows-amd64.zip
|
|
6
|
+
263fbabede0ad9c266ef23cdad2292297a35b67d2301c14f400308198bab4655 pippit-cli-0.0.6-windows-arm64.zip
|
|
@@ -96,9 +96,9 @@ func newShortDramaDownloadResultCommand(stdout, stderr io.Writer, runner *common
|
|
|
96
96
|
Short: "Download a generated result URL",
|
|
97
97
|
Args: cobra.NoArgs,
|
|
98
98
|
RunE: func(cmd *cobra.Command, _ []string) error {
|
|
99
|
-
opts.
|
|
100
|
-
if opts.
|
|
101
|
-
return fmt.Errorf("--output-
|
|
99
|
+
opts.OutputPath = strings.TrimSpace(opts.OutputPath)
|
|
100
|
+
if opts.OutputPath == "" {
|
|
101
|
+
return fmt.Errorf("--output-path is required")
|
|
102
102
|
}
|
|
103
103
|
opts.URL = strings.TrimSpace(opts.URL)
|
|
104
104
|
if opts.URL == "" {
|
|
@@ -118,7 +118,7 @@ func newShortDramaDownloadResultCommand(stdout, stderr io.Writer, runner *common
|
|
|
118
118
|
cmd.SetOut(stdout)
|
|
119
119
|
cmd.SetErr(stderr)
|
|
120
120
|
cmd.Flags().StringVar(&opts.URL, "url", "", "URL to download")
|
|
121
|
-
cmd.Flags().StringVar(&opts.
|
|
121
|
+
cmd.Flags().StringVar(&opts.OutputPath, "output-path", "", "local output file path")
|
|
122
122
|
cmd.Flags().IntVar(&opts.Workers, "workers", 5, "parallel download workers")
|
|
123
123
|
return cmd
|
|
124
124
|
}
|
package/cmd/short_drama_test.go
CHANGED
|
@@ -181,7 +181,7 @@ func TestShortDramaDownloadResult(t *testing.T) {
|
|
|
181
181
|
outputPath := filepath.Join("results", "cover.jpeg")
|
|
182
182
|
root.SetArgs([]string{
|
|
183
183
|
"short-drama", "+download-result",
|
|
184
|
-
"--output-
|
|
184
|
+
"--output-path", outputPath,
|
|
185
185
|
"--workers", "2",
|
|
186
186
|
"--url", server.URL + "/image?filename=ignored.jpeg",
|
|
187
187
|
})
|
|
@@ -191,8 +191,8 @@ func TestShortDramaDownloadResult(t *testing.T) {
|
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
got := decodeJSON(t, stdout.Bytes())
|
|
194
|
-
if got["
|
|
195
|
-
t.Fatalf("
|
|
194
|
+
if got["output_path"] != outputPath {
|
|
195
|
+
t.Fatalf("output_path = %v, want %s", got["output_path"], outputPath)
|
|
196
196
|
}
|
|
197
197
|
if got["total"] != float64(1) {
|
|
198
198
|
t.Fatalf("total = %v, want 1", got["total"])
|
|
@@ -233,7 +233,7 @@ func TestShortDramaDownloadResultSkipsExistingFile(t *testing.T) {
|
|
|
233
233
|
root := NewRootCommand(&stdout, &stderr)
|
|
234
234
|
root.SetArgs([]string{
|
|
235
235
|
"short-drama", "+download-result",
|
|
236
|
-
"--output-
|
|
236
|
+
"--output-path", outputPath,
|
|
237
237
|
"--url", server.URL + "/image",
|
|
238
238
|
})
|
|
239
239
|
|
|
@@ -245,8 +245,8 @@ func TestShortDramaDownloadResultSkipsExistingFile(t *testing.T) {
|
|
|
245
245
|
}
|
|
246
246
|
|
|
247
247
|
got := decodeJSON(t, stdout.Bytes())
|
|
248
|
-
if got["
|
|
249
|
-
t.Fatalf("
|
|
248
|
+
if got["output_path"] != outputPath {
|
|
249
|
+
t.Fatalf("output_path = %v, want %s", got["output_path"], outputPath)
|
|
250
250
|
}
|
|
251
251
|
if got["total"] != float64(0) {
|
|
252
252
|
t.Fatalf("total = %v, want 0", got["total"])
|
|
@@ -258,7 +258,7 @@ func TestShortDramaDownloadResultSkipsExistingFile(t *testing.T) {
|
|
|
258
258
|
assertFileContent(t, outputPath, "existing-data")
|
|
259
259
|
}
|
|
260
260
|
|
|
261
|
-
func
|
|
261
|
+
func TestShortDramaDownloadResultRequiresOutputPath(t *testing.T) {
|
|
262
262
|
var stdout, stderr bytes.Buffer
|
|
263
263
|
root := NewRootCommand(&stdout, &stderr)
|
|
264
264
|
root.SetArgs([]string{"short-drama", "+download-result", "--url", "https://example.com/image.png"})
|
|
@@ -267,15 +267,33 @@ func TestShortDramaDownloadResultRequiresOutputDir(t *testing.T) {
|
|
|
267
267
|
if err == nil {
|
|
268
268
|
t.Fatal("Execute() error = nil, want validation error")
|
|
269
269
|
}
|
|
270
|
-
if !strings.Contains(err.Error(), "--output-
|
|
271
|
-
t.Fatalf("error = %q, want output-
|
|
270
|
+
if !strings.Contains(err.Error(), "--output-path is required") {
|
|
271
|
+
t.Fatalf("error = %q, want output-path validation", err)
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
func TestShortDramaDownloadResultRejectsOutputDirFlag(t *testing.T) {
|
|
276
|
+
var stdout, stderr bytes.Buffer
|
|
277
|
+
root := NewRootCommand(&stdout, &stderr)
|
|
278
|
+
root.SetArgs([]string{
|
|
279
|
+
"short-drama", "+download-result",
|
|
280
|
+
"--output-dir", filepath.Join("results", "image.png"),
|
|
281
|
+
"--url", "https://example.com/image.png",
|
|
282
|
+
})
|
|
283
|
+
|
|
284
|
+
err := root.Execute()
|
|
285
|
+
if err == nil {
|
|
286
|
+
t.Fatal("Execute() error = nil, want unknown flag error")
|
|
287
|
+
}
|
|
288
|
+
if !strings.Contains(err.Error(), "unknown flag: --output-dir") {
|
|
289
|
+
t.Fatalf("error = %q, want output-dir rejection", err)
|
|
272
290
|
}
|
|
273
291
|
}
|
|
274
292
|
|
|
275
293
|
func TestShortDramaDownloadResultRequiresURL(t *testing.T) {
|
|
276
294
|
var stdout, stderr bytes.Buffer
|
|
277
295
|
root := NewRootCommand(&stdout, &stderr)
|
|
278
|
-
root.SetArgs([]string{"short-drama", "+download-result", "--output-
|
|
296
|
+
root.SetArgs([]string{"short-drama", "+download-result", "--output-path", filepath.Join("results", "image.png")})
|
|
279
297
|
|
|
280
298
|
err := root.Execute()
|
|
281
299
|
if err == nil {
|
|
@@ -289,7 +307,7 @@ func TestShortDramaDownloadResultRequiresURL(t *testing.T) {
|
|
|
289
307
|
func TestShortDramaDownloadResultRejectsInvalidScheme(t *testing.T) {
|
|
290
308
|
var stdout, stderr bytes.Buffer
|
|
291
309
|
root := NewRootCommand(&stdout, &stderr)
|
|
292
|
-
root.SetArgs([]string{"short-drama", "+download-result", "--output-
|
|
310
|
+
root.SetArgs([]string{"short-drama", "+download-result", "--output-path", filepath.Join("results", "image.png"), "--url", "file:///etc/passwd"})
|
|
293
311
|
|
|
294
312
|
err := root.Execute()
|
|
295
313
|
if err == nil {
|
|
@@ -311,7 +329,7 @@ func TestShortDramaDownloadResultAllFailed(t *testing.T) {
|
|
|
311
329
|
root := NewRootCommand(&stdout, &stderr)
|
|
312
330
|
root.SetArgs([]string{
|
|
313
331
|
"short-drama", "+download-result",
|
|
314
|
-
"--output-
|
|
332
|
+
"--output-path", filepath.Join("results", "missing.png"),
|
|
315
333
|
"--url", server.URL + "/notfound",
|
|
316
334
|
})
|
|
317
335
|
|
|
@@ -337,7 +355,7 @@ func TestShortDramaDownloadResultOutputPath(t *testing.T) {
|
|
|
337
355
|
outputPath := filepath.Join("custom", "nested", "cover.png")
|
|
338
356
|
root.SetArgs([]string{
|
|
339
357
|
"short-drama", "+download-result",
|
|
340
|
-
"--output-
|
|
358
|
+
"--output-path", outputPath,
|
|
341
359
|
"--url", server.URL + "/image.png",
|
|
342
360
|
})
|
|
343
361
|
|
|
@@ -346,8 +364,8 @@ func TestShortDramaDownloadResultOutputPath(t *testing.T) {
|
|
|
346
364
|
}
|
|
347
365
|
|
|
348
366
|
got := decodeJSON(t, stdout.Bytes())
|
|
349
|
-
if got["
|
|
350
|
-
t.Fatalf("
|
|
367
|
+
if got["output_path"] != outputPath {
|
|
368
|
+
t.Fatalf("output_path = %v, want %s", got["output_path"], outputPath)
|
|
351
369
|
}
|
|
352
370
|
assertFileContent(t, outputPath, "image-data")
|
|
353
371
|
}
|
|
@@ -21,9 +21,9 @@ import (
|
|
|
21
21
|
|
|
22
22
|
// DownloadResultOptions is the command-facing shape for downloading one result URL.
|
|
23
23
|
type DownloadResultOptions struct {
|
|
24
|
-
URL
|
|
25
|
-
|
|
26
|
-
Workers
|
|
24
|
+
URL string `json:"url"`
|
|
25
|
+
OutputPath string `json:"output_path"`
|
|
26
|
+
Workers int `json:"workers"`
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
type DownloadResultError struct {
|
|
@@ -33,7 +33,7 @@ type DownloadResultError struct {
|
|
|
33
33
|
|
|
34
34
|
// DownloadResultResponse is the JSON envelope printed by `pippit-cli short-drama +download-result`.
|
|
35
35
|
type DownloadResultResponse struct {
|
|
36
|
-
|
|
36
|
+
OutputPath string `json:"output_path"`
|
|
37
37
|
Downloaded []string `json:"downloaded"`
|
|
38
38
|
AlreadyExist []string `json:"already_exist,omitempty"`
|
|
39
39
|
Total int `json:"total"`
|
|
@@ -64,9 +64,9 @@ func DownloadResult(ctx context.Context, opts DownloadResultOptions, runner *Run
|
|
|
64
64
|
return nil, fmt.Errorf("download url is required")
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
outputPath := strings.TrimSpace(opts.
|
|
67
|
+
outputPath := strings.TrimSpace(opts.OutputPath)
|
|
68
68
|
if outputPath == "" {
|
|
69
|
-
return nil, fmt.Errorf("
|
|
69
|
+
return nil, fmt.Errorf("output_path is required")
|
|
70
70
|
}
|
|
71
71
|
// check if the output path exists and is a file
|
|
72
72
|
if info, err := os.Stat(outputPath); err == nil {
|
|
@@ -74,7 +74,7 @@ func DownloadResult(ctx context.Context, opts DownloadResultOptions, runner *Run
|
|
|
74
74
|
return nil, fmt.Errorf("output path %q is a directory", outputPath)
|
|
75
75
|
}
|
|
76
76
|
return &DownloadResultResponse{
|
|
77
|
-
|
|
77
|
+
OutputPath: outputPath,
|
|
78
78
|
AlreadyExist: []string{outputPath},
|
|
79
79
|
Total: 0,
|
|
80
80
|
}, nil
|
|
@@ -159,7 +159,7 @@ func DownloadResult(ctx context.Context, opts DownloadResultOptions, runner *Run
|
|
|
159
159
|
})
|
|
160
160
|
|
|
161
161
|
result := &DownloadResultResponse{
|
|
162
|
-
|
|
162
|
+
OutputPath: outputPath,
|
|
163
163
|
Downloaded: downloaded,
|
|
164
164
|
Total: len(downloaded),
|
|
165
165
|
Errors: errorList,
|
package/package.json
CHANGED
|
@@ -27,7 +27,7 @@ metadata:
|
|
|
27
27
|
2. **查询会话进展** - 根据 `thread_id`、`run_id`、`after_seq` 拉取短剧任务消息列表。
|
|
28
28
|
3. **上传文件** - 上传短剧相关参考文件,得到文件 ID,供后续任务引用。
|
|
29
29
|
4. **获取会话文件** - 根据 `thread_id` 拉取会话文件列表,得到 `file_path`、`file_name`、`download_url`。
|
|
30
|
-
5. **下载文件资源** - 使用文件列表中的 `download_url` 下载资源,并按 `file_path`
|
|
30
|
+
5. **下载文件资源** - 使用文件列表中的 `download_url` 下载资源,并按 `file_path` 写入用户本地目标文件路径。
|
|
31
31
|
|
|
32
32
|
## 前置要求
|
|
33
33
|
|
|
@@ -90,11 +90,11 @@ pippit-cli short-drama +list-thread-file --thread-id THREAD_ID --page-num 1 --pa
|
|
|
90
90
|
### 5. 下载文件资源
|
|
91
91
|
|
|
92
92
|
```bash
|
|
93
|
-
#
|
|
94
|
-
pippit-cli short-drama +download-result --url DOWNLOAD_URL --output-
|
|
93
|
+
# 下载文件资源到指定文件路径
|
|
94
|
+
pippit-cli short-drama +download-result --url DOWNLOAD_URL --output-path FILE_PATH
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
`+download-result`
|
|
97
|
+
`FILE_PATH` 必须直接使用 `+list-thread-file` 返回的完整 `file_path`,包含文件名,不要取父目录。`+download-result` 负责把会话产生的文件通过 URL 下载到该目标文件路径;如果目标文件已存在,跳过下载。
|
|
98
98
|
|
|
99
99
|
## 典型工作流
|
|
100
100
|
|
|
@@ -112,11 +112,11 @@ pippit-cli short-drama +download-result --url DOWNLOAD_URL --output-dir FILE_PAT
|
|
|
112
112
|
- 如果后端 Agent 提出问题:展示问题,等待用户回复
|
|
113
113
|
5. 解析 `list-thread-file` 返回的 files,只获取文件元信息:
|
|
114
114
|
- 对每个文件取 file_path、file_name、download_url
|
|
115
|
-
-
|
|
116
|
-
-
|
|
115
|
+
- 将 file_path 作为本地目标文件路径,包含文件名
|
|
116
|
+
- 如果 file_path 已存在:跳过下载
|
|
117
117
|
6. 对缺失的本地文件,调用 +download-result 并行下载资源:
|
|
118
118
|
- 使用第 5 步获取的 download_url 作为 --url
|
|
119
|
-
- 使用第 5
|
|
119
|
+
- 使用第 5 步获取的完整 file_path 作为 --output-path
|
|
120
120
|
7. 如用户继续追加需求,使用同一 thread_id 再次 submit-run
|
|
121
121
|
```
|
|
122
122
|
|
|
@@ -212,8 +212,8 @@ pippit-cli short-drama +download-result --url DOWNLOAD_URL --output-dir FILE_PAT
|
|
|
212
212
|
|
|
213
213
|
```json
|
|
214
214
|
{
|
|
215
|
-
"
|
|
216
|
-
"downloaded": ["/
|
|
215
|
+
"output_path": "./{thread-id}/{file_path}/{file_name}",
|
|
216
|
+
"downloaded": ["./{thread-id}/{file_path}/{file_name}"],
|
|
217
217
|
"total": 1
|
|
218
218
|
}
|
|
219
219
|
```
|
|
@@ -231,14 +231,14 @@ pippit-cli short-drama +download-result --url DOWNLOAD_URL --output-dir FILE_PAT
|
|
|
231
231
|
→ 跳过
|
|
232
232
|
2. file_path在本地不存在
|
|
233
233
|
→ 记录该file_path和URL
|
|
234
|
-
→
|
|
234
|
+
→ 使用 +download-result 将URL资源下载到该file_path
|
|
235
235
|
```
|
|
236
236
|
|
|
237
237
|
### 并行下载文件资源
|
|
238
238
|
|
|
239
239
|
只对目标路径不存在的文件调用下载工具,可并行:
|
|
240
240
|
|
|
241
|
-
1. 调用 `pippit-cli short-drama +download-result --url DOWNLOAD_URL --output-
|
|
241
|
+
1. 调用 `pippit-cli short-drama +download-result --url DOWNLOAD_URL --output-path FILE_PATH`。
|
|
242
242
|
2. 下载完成后,向用户展示本地文件路径;如果某个文件下载失败,只报告该文件错误,不阻塞已成功落盘的文件展示。
|
|
243
243
|
|
|
244
244
|
## 向用户展示内容
|
|
@@ -276,5 +276,5 @@ pippit-cli short-drama +download-result --url DOWNLOAD_URL --output-dir FILE_PAT
|
|
|
276
276
|
- `--after-seq` 用于增量拉取消息,首次查询可设置为 `0`。
|
|
277
277
|
- `+upload-file` 当前用于短剧场景文件上传链路,上传后将返回可传给 `+submit-run` 的文件 ID。
|
|
278
278
|
- `+list-thread-file` 只需要 `thread_id`;分页参数默认 `--page-num 1 --page-size 100`。
|
|
279
|
-
- `+list-thread-file` 和 `+download-result` 是两个不同的 CLI 指令:前者获取会话文件元信息,后者下载 URL
|
|
280
|
-
- `+download-result` 接收 `--url`、`--output-
|
|
279
|
+
- `+list-thread-file` 和 `+download-result` 是两个不同的 CLI 指令:前者获取会话文件元信息,后者下载 URL 资源并写入到本地目标文件路径。
|
|
280
|
+
- `+download-result` 接收 `--url`、`--output-path`、`--workers`;`--output-path` 必须是包含文件名的目标文件路径。
|