@pippit-dev/cli 0.0.22 → 0.0.24
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 +5 -5
- package/checksums.txt +6 -6
- package/cmd/short_drama_test.go +37 -9
- package/cmd/update/update.go +29 -1
- package/cmd/update/update_test.go +25 -0
- package/internal/common/access_key.go +1 -1
- package/package.json +2 -2
- package/scripts/skills.js +22 -0
- package/skills/short-drama/SKILL.md +9 -1
- package/skills/xyq-nest-skill/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
|
|
9
9
|
| 技能 | 说明 | 路径 |
|
|
10
10
|
|-------|-------------|------|
|
|
11
|
-
| `
|
|
12
|
-
| `xyq-
|
|
11
|
+
| `xyq-short-drama-skill` | 短剧工作流技能,支持提交创作任务、上传参考文件、查询进度、列出会话文件和下载产物。 | `skills/short-drama/` |
|
|
12
|
+
| `xyq-skill` | 通用 NestAgent 技能,支持图片/视频生成、编辑、文件上传、进度查询和结果下载。 | `skills/xyq-nest-skill/` |
|
|
13
13
|
|
|
14
14
|
## 通用 NestAgent 技能
|
|
15
15
|
|
|
16
|
-
`xyq-
|
|
16
|
+
`xyq-skill` 通过接入小云雀 NestAgent 的综合创作能力,实现 AI 图片/视频生成、编辑、风格转换、文件上传、进度查询和结果下载。
|
|
17
17
|
|
|
18
18
|
### 功能特性
|
|
19
19
|
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
|
|
33
33
|
### 配置
|
|
34
34
|
|
|
35
|
-
所有 `xyq-
|
|
35
|
+
所有 `xyq-skill` 脚本都使用 Bearer 令牌鉴权:
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
38
|
export XYQ_ACCESS_KEY="<access-key>"
|
|
@@ -214,4 +214,4 @@ pippit-tool-cli short-drama +download-result --output-path ./thread_123/results/
|
|
|
214
214
|
|
|
215
215
|
## 鉴权
|
|
216
216
|
|
|
217
|
-
`short-drama +submit-run`、`short-drama +get-thread`、`short-drama +upload-file` 以及 `xyq-
|
|
217
|
+
`short-drama +submit-run`、`short-drama +get-thread`、`short-drama +upload-file` 以及 `xyq-skill` Python 脚本都使用 `Authorization: Bearer <XYQ_ACCESS_KEY>` 鉴权。OAuth 命令代码仍保留在仓库中,但短剧运行时请求不使用 OAuth。
|
package/checksums.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
489fab9b2e6334ea206ada098598bf60a63d7930b17e646598414fda2685d0cb pippit-tool-cli-0.0.24-darwin-amd64.tar.gz
|
|
2
|
+
da482045b41ccd8ba12291ba589a38ad4ad72dc20a1b71413d73b8c49ebe8609 pippit-tool-cli-0.0.24-darwin-arm64.tar.gz
|
|
3
|
+
d3720a47492cc73f1118e3f8521e6344b50b5d9405185718a95de7b3df048f94 pippit-tool-cli-0.0.24-linux-amd64.tar.gz
|
|
4
|
+
98bab626d1f985e9a4039e93e96f089da72292e5df98f567dee387b663818d6e pippit-tool-cli-0.0.24-linux-arm64.tar.gz
|
|
5
|
+
81c026da8883962fa74d8f59749cb4987f85911d30cc1df12fdf9811e85d526c pippit-tool-cli-0.0.24-windows-amd64.zip
|
|
6
|
+
cb27d671c861089bb432461d1ec3dab9dca862665f4f0b26351b78b68ae0a211 pippit-tool-cli-0.0.24-windows-arm64.zip
|
package/cmd/short_drama_test.go
CHANGED
|
@@ -184,9 +184,7 @@ func TestShortDramaSubmitRunRequiresAccessKey(t *testing.T) {
|
|
|
184
184
|
if err == nil {
|
|
185
185
|
t.Fatal("Execute() error = nil, want access key error")
|
|
186
186
|
}
|
|
187
|
-
|
|
188
|
-
t.Fatalf("error = %q, want access key guidance", err)
|
|
189
|
-
}
|
|
187
|
+
assertAccessKeyGuidance(t, err)
|
|
190
188
|
}
|
|
191
189
|
|
|
192
190
|
func TestShortDramaUploadFile(t *testing.T) {
|
|
@@ -286,9 +284,7 @@ func TestShortDramaUploadFileRequiresAccessKey(t *testing.T) {
|
|
|
286
284
|
if err == nil {
|
|
287
285
|
t.Fatal("Execute() error = nil, want access key error")
|
|
288
286
|
}
|
|
289
|
-
|
|
290
|
-
t.Fatalf("error = %q, want access key guidance", err)
|
|
291
|
-
}
|
|
287
|
+
assertAccessKeyGuidance(t, err)
|
|
292
288
|
}
|
|
293
289
|
|
|
294
290
|
func TestShortDramaUploadFileRejectsUnsupportedFileType(t *testing.T) {
|
|
@@ -768,9 +764,7 @@ func TestShortDramaGetThreadRequiresAccessKey(t *testing.T) {
|
|
|
768
764
|
if err == nil {
|
|
769
765
|
t.Fatal("Execute() error = nil, want access key error")
|
|
770
766
|
}
|
|
771
|
-
|
|
772
|
-
t.Fatalf("error = %q, want access key guidance", err)
|
|
773
|
-
}
|
|
767
|
+
assertAccessKeyGuidance(t, err)
|
|
774
768
|
}
|
|
775
769
|
|
|
776
770
|
func TestShortDramaListThreadFile(t *testing.T) {
|
|
@@ -892,6 +886,23 @@ func TestShortDramaListThreadFileRequiresThreadID(t *testing.T) {
|
|
|
892
886
|
}
|
|
893
887
|
}
|
|
894
888
|
|
|
889
|
+
func TestShortDramaListThreadFileRequiresAccessKey(t *testing.T) {
|
|
890
|
+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
891
|
+
t.Fatal("server should not receive request without access key")
|
|
892
|
+
}))
|
|
893
|
+
defer server.Close()
|
|
894
|
+
|
|
895
|
+
var stdout, stderr bytes.Buffer
|
|
896
|
+
root := newTestRootCommandWithAccessKey(t, &stdout, &stderr, server.URL, "")
|
|
897
|
+
root.SetArgs([]string{"short-drama", "+list-thread-file", "--thread-id", "thread_123"})
|
|
898
|
+
|
|
899
|
+
err := root.Execute()
|
|
900
|
+
if err == nil {
|
|
901
|
+
t.Fatal("Execute() error = nil, want access key error")
|
|
902
|
+
}
|
|
903
|
+
assertAccessKeyGuidance(t, err)
|
|
904
|
+
}
|
|
905
|
+
|
|
895
906
|
func TestShortDramaListThreadFileRejectsPageSizeAboveMax(t *testing.T) {
|
|
896
907
|
var stdout, stderr bytes.Buffer
|
|
897
908
|
root := NewRootCommand(&stdout, &stderr)
|
|
@@ -925,6 +936,23 @@ func newTestRootCommandWithAccessKey(t *testing.T, stdout, stderr io.Writer, bas
|
|
|
925
936
|
return newRootCommand(stdout, stderr, runner)
|
|
926
937
|
}
|
|
927
938
|
|
|
939
|
+
func assertAccessKeyGuidance(t *testing.T, err error) {
|
|
940
|
+
t.Helper()
|
|
941
|
+
if err == nil {
|
|
942
|
+
t.Fatal("error = nil, want access key guidance")
|
|
943
|
+
}
|
|
944
|
+
msg := err.Error()
|
|
945
|
+
if !strings.Contains(msg, "XYQ_ACCESS_KEY is required") {
|
|
946
|
+
t.Fatalf("error = %q, want access key guidance", err)
|
|
947
|
+
}
|
|
948
|
+
if !strings.Contains(msg, "https://xyq.jianying.com/home?tab_name=home") {
|
|
949
|
+
t.Fatalf("error = %q, want access key settings URL", err)
|
|
950
|
+
}
|
|
951
|
+
if !strings.Contains(msg, `export XYQ_ACCESS_KEY="<access-key>"`) {
|
|
952
|
+
t.Fatalf("error = %q, want setup command guidance", err)
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
928
956
|
func decodeJSON(t *testing.T, data []byte) map[string]any {
|
|
929
957
|
t.Helper()
|
|
930
958
|
var got map[string]any
|
package/cmd/update/update.go
CHANGED
|
@@ -14,6 +14,11 @@ import (
|
|
|
14
14
|
|
|
15
15
|
const defaultPackage = "@pippit-dev/cli"
|
|
16
16
|
|
|
17
|
+
var legacyGlobalSkills = []string{
|
|
18
|
+
"pippit-short-drama-skill",
|
|
19
|
+
"xyq-nest-skill",
|
|
20
|
+
}
|
|
21
|
+
|
|
17
22
|
// NewCommand builds the update command.
|
|
18
23
|
func NewCommand(stdout, stderr io.Writer) *cobra.Command {
|
|
19
24
|
cmd := &cobra.Command{
|
|
@@ -74,7 +79,30 @@ func installSkills(root string, stderr io.Writer) error {
|
|
|
74
79
|
} else if !info.IsDir() {
|
|
75
80
|
return fmt.Errorf("%s is not a directory", filepath.Join(root, "skills"))
|
|
76
81
|
}
|
|
77
|
-
|
|
82
|
+
if err := runInherit(stderr, "npx", "-y", "skills", "add", root, "-g", "-y", "--skill", "*"); err != nil {
|
|
83
|
+
return err
|
|
84
|
+
}
|
|
85
|
+
return cleanupLegacyGlobalSkills(defaultGlobalSkillsDir())
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
func defaultGlobalSkillsDir() string {
|
|
89
|
+
home, err := os.UserHomeDir()
|
|
90
|
+
if err != nil {
|
|
91
|
+
return ""
|
|
92
|
+
}
|
|
93
|
+
return filepath.Join(home, ".agents", "skills")
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
func cleanupLegacyGlobalSkills(globalSkillsDir string) error {
|
|
97
|
+
if globalSkillsDir == "" {
|
|
98
|
+
return nil
|
|
99
|
+
}
|
|
100
|
+
for _, skillName := range legacyGlobalSkills {
|
|
101
|
+
if err := os.RemoveAll(filepath.Join(globalSkillsDir, skillName)); err != nil {
|
|
102
|
+
return err
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return nil
|
|
78
106
|
}
|
|
79
107
|
|
|
80
108
|
func runInherit(stderr io.Writer, name string, args ...string) error {
|
|
@@ -29,6 +29,7 @@ func TestInstallSkillsInstallsAllBundledSkills(t *testing.T) {
|
|
|
29
29
|
|
|
30
30
|
t.Setenv("PATH", binDir+string(os.PathListSeparator)+os.Getenv("PATH"))
|
|
31
31
|
t.Setenv("CAPTURE_ARGS", capturePath)
|
|
32
|
+
t.Setenv("HOME", t.TempDir())
|
|
32
33
|
|
|
33
34
|
var stderr bytes.Buffer
|
|
34
35
|
if err := installSkills(root, &stderr); err != nil {
|
|
@@ -45,3 +46,27 @@ func TestInstallSkillsInstallsAllBundledSkills(t *testing.T) {
|
|
|
45
46
|
t.Fatalf("npx args mismatch\ngot: %#v\nwant: %#v", got, want)
|
|
46
47
|
}
|
|
47
48
|
}
|
|
49
|
+
|
|
50
|
+
func TestCleanupLegacyGlobalSkills(t *testing.T) {
|
|
51
|
+
globalSkillsDir := t.TempDir()
|
|
52
|
+
for _, skillName := range []string{"pippit-short-drama-skill", "xyq-nest-skill", "xyq-short-drama-skill", "xyq-skill"} {
|
|
53
|
+
if err := os.Mkdir(filepath.Join(globalSkillsDir, skillName), 0o755); err != nil {
|
|
54
|
+
t.Fatal(err)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if err := cleanupLegacyGlobalSkills(globalSkillsDir); err != nil {
|
|
59
|
+
t.Fatalf("cleanupLegacyGlobalSkills() error = %v", err)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
for _, skillName := range []string{"pippit-short-drama-skill", "xyq-nest-skill"} {
|
|
63
|
+
if _, err := os.Stat(filepath.Join(globalSkillsDir, skillName)); !os.IsNotExist(err) {
|
|
64
|
+
t.Fatalf("legacy skill %s still exists or stat failed: %v", skillName, err)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
for _, skillName := range []string{"xyq-short-drama-skill", "xyq-skill"} {
|
|
68
|
+
if _, err := os.Stat(filepath.Join(globalSkillsDir, skillName)); err != nil {
|
|
69
|
+
t.Fatalf("new skill %s was not preserved: %v", skillName, err)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -22,7 +22,7 @@ func (a *accessKeyAuthorizer) Inject(ctx context.Context, req *http.Request) err
|
|
|
22
22
|
return err
|
|
23
23
|
}
|
|
24
24
|
if a.accessKey == "" && req.Method == http.MethodPost {
|
|
25
|
-
return fmt.Errorf("%s
|
|
25
|
+
return fmt.Errorf("%s 缺失. 请前往小云雀官网个人设置页创建 Access Key,地址:https://xyq.jianying.com/home?tab_name=home\n配置后重试:\n export %s=\"<your-access-key>\"", config.EnvXYQAccessKey, config.EnvXYQAccessKey)
|
|
26
26
|
}
|
|
27
27
|
if a.accessKey != "" {
|
|
28
28
|
req.Header.Set("Authorization", "Bearer "+a.accessKey)
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pippit-dev/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.24",
|
|
4
4
|
"description": "Pippit CLI",
|
|
5
5
|
"bin": {
|
|
6
6
|
"pippit-tool-cli": "scripts/run.js"
|
|
7
7
|
},
|
|
8
8
|
"scripts": {
|
|
9
9
|
"postinstall": "node scripts/install.js",
|
|
10
|
-
"test": "node scripts/version-check.test.js && go test ./... && go vet ./..."
|
|
10
|
+
"test": "node scripts/version-check.test.js && node scripts/skills.test.js && go test ./... && go vet ./..."
|
|
11
11
|
},
|
|
12
12
|
"os": [
|
|
13
13
|
"darwin",
|
package/scripts/skills.js
CHANGED
|
@@ -1,8 +1,26 @@
|
|
|
1
1
|
const fs = require("fs");
|
|
2
|
+
const os = require("os");
|
|
2
3
|
const path = require("path");
|
|
3
4
|
const { run, runSilent } = require("./platform");
|
|
4
5
|
|
|
5
6
|
const DEFAULT_PKG = "@pippit-dev/cli";
|
|
7
|
+
const LEGACY_GLOBAL_SKILLS = [
|
|
8
|
+
"pippit-short-drama-skill",
|
|
9
|
+
"xyq-nest-skill",
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
function defaultGlobalSkillsDir() {
|
|
13
|
+
return path.join(os.homedir(), ".agents", "skills");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function cleanupLegacyGlobalSkills(globalSkillsDir = defaultGlobalSkillsDir()) {
|
|
17
|
+
for (const skillName of LEGACY_GLOBAL_SKILLS) {
|
|
18
|
+
fs.rmSync(path.join(globalSkillsDir, skillName), {
|
|
19
|
+
force: true,
|
|
20
|
+
recursive: true,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
6
24
|
|
|
7
25
|
function installSkillsFromRoot(root, opts = {}) {
|
|
8
26
|
const source = path.resolve(root);
|
|
@@ -13,6 +31,7 @@ function installSkillsFromRoot(root, opts = {}) {
|
|
|
13
31
|
run("npx", ["-y", "skills", "add", source, "-g", "-y", "--skill", "*"], {
|
|
14
32
|
timeout: opts.timeout || 120000,
|
|
15
33
|
});
|
|
34
|
+
cleanupLegacyGlobalSkills(opts.globalSkillsDir);
|
|
16
35
|
}
|
|
17
36
|
|
|
18
37
|
function globalPackageRoot(pkg = DEFAULT_PKG) {
|
|
@@ -26,6 +45,9 @@ function installGlobalPackageSkills(pkg = DEFAULT_PKG, opts = {}) {
|
|
|
26
45
|
|
|
27
46
|
module.exports = {
|
|
28
47
|
DEFAULT_PKG,
|
|
48
|
+
LEGACY_GLOBAL_SKILLS,
|
|
49
|
+
cleanupLegacyGlobalSkills,
|
|
50
|
+
defaultGlobalSkillsDir,
|
|
29
51
|
globalPackageRoot,
|
|
30
52
|
installGlobalPackageSkills,
|
|
31
53
|
installSkillsFromRoot,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
2
|
+
name: xyq-short-drama-skill
|
|
3
3
|
description: 使用 pippit-tool-cli 的短剧场景能力提交和查询短剧创作任务。覆盖短剧生成、续写、改写、剧情扩展、人物设定、分集草稿、世界观设定、会话文件获取、文件资源下载等创作场景。当用户要求创作短剧、写短剧剧本、续写故事、修改剧情、补充角色设定、查询短剧任务进展、获取短剧会话文件或下载短剧文件资源,或提到 pippit-tool-cli short-drama / 小云雀短剧时触发。
|
|
4
4
|
user-invocable: true
|
|
5
5
|
metadata:
|
|
@@ -67,6 +67,14 @@ metadata:
|
|
|
67
67
|
npx @pippit-dev/cli@latest install
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
+
部分功能需要先配置 `XYQ_ACCESS_KEY`。缺失时 CLI 会直接提示用户先创建 Access Key,此时请等待用户给与Access Key后再继续运行。
|
|
71
|
+
|
|
72
|
+
Access Key 创建地址:https://xyq.jianying.com/home?tab_name=home
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
export XYQ_ACCESS_KEY="<access-key>"
|
|
76
|
+
```
|
|
77
|
+
|
|
70
78
|
## 使用方法
|
|
71
79
|
|
|
72
80
|
### 1. 提交短剧任务
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: xyq-
|
|
2
|
+
name: xyq-skill
|
|
3
3
|
description: 通过小云雀的 AI 能力进行综合创作,支持生成和编辑图片/视频。覆盖场景包括:生成(文生图、文生视频、图生视频、做动画、画一个xxx、来段xxx)、编辑修改(把xxx换成yyy、去掉xxx、加上xxx、改成xxx、调整xxx、局部修改、改镜头)、风格转换(风格迁移、转绘、换风格)、视频续写延长、复刻视频/TVC/宣传片、短剧/短漫剧生成、音乐MV生成、产品广告/展示片制作、分镜/故事板设计、教育视频/短视频制作。当用户提到小云雀、xyq、上传参考图/视频、查看生成进度时也应触发。关键判断:只要用户的请求涉及 AI 视频的创作、生成、编辑、修改,无论措辞如何(如"画只猫"、"做个海报"、"做个视频"、"这个视频帮我改一下"、"帮我复刻这段视频"、"用这首歌做个MV"、"一句话生成短剧"),都必须触发此技能。
|
|
4
4
|
user-invocable: true
|
|
5
5
|
metadata:
|