@pippit-dev/cli 1.0.18 → 1.0.21

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 CHANGED
@@ -9,10 +9,11 @@
9
9
  | 技能 | 说明 | 路径 |
10
10
  |-------|-------------|------|
11
11
  | `xyq-short-drama-skill` | 短剧工作流技能,支持提交创作任务、上传参考文件、查询进度、列出会话文件和下载产物。 | `skills/short-drama/` |
12
- | `xyq-skill` | 通用创作技能,支持 NestAgent 图片/视频生成与编辑,并在视频模型直出时调用 `pippit-tool-cli generate-video`。 | `skills/xyq-nest-skill/` |
12
+ | `xyq-skill` | 通用创作技能,支持 NestAgent 图片/视频生成与编辑、个人积分余额查询,并在视频模型直出时调用 `pippit-tool-cli generate-video`。 | `skills/xyq-nest-skill/` |
13
13
 
14
14
  ### 技能路由
15
15
 
16
+ - 小云雀积分余额、剩余积分或 credits 查询由 `xyq-skill` 调用 `pippit-tool-cli get-credit-balance`,直接展示个人有效积分余额,无需创建会话或轮询。
16
17
  - 通用图片/视频生成、编辑和复杂参考素材编排使用 `xyq-skill`。
17
18
  - 用户明确要求视频模型直出、指定视频模型或直接调用 CLI 时,由 `xyq-skill` 调用 `pippit-tool-cli generate-video`,再用 `query-result` 查询和下载结果。
18
19
  - 短剧生成、续写、改写、人物设定、分集创作和短剧会话文件处理使用 `xyq-short-drama-skill`,不要与通用创作流程混用。
@@ -29,6 +30,7 @@
29
30
  |------|------|
30
31
  | 创建会话 / 发送消息 | 向小云雀发送自然语言指令,生成图片或视频。 |
31
32
  | 查询会话进展 | 增量拉取会话消息,轮询创作进度和产物结果。 |
33
+ | 积分余额查询 | 调用 `get-credit-balance`,读取 `total_remain_amount` 并展示个人有效积分余额。 |
32
34
  | 上传文件 | 上传图片/视频/mp3或wav音频到小云雀资产库,获取 `asset_id` 用于编辑和参考。 |
33
35
  | 下载结果 | 批量下载生成的图片/视频到本地,支持并行下载。 |
34
36
  | 视频模型直出 | 调用 `generate-video` 提交请求,展示 `web_thread_link`,再用 `query-result` 查询并下载视频。 |
@@ -207,6 +209,7 @@ python3 skills/xyq-nest-skill/scripts/download_results.py \
207
209
  npx @pippit-dev/cli@latest install
208
210
  pippit-tool-cli login
209
211
  pippit-tool-cli --version
212
+ pippit-tool-cli get-credit-balance
210
213
  pippit-tool-cli short-drama +submit-run --message "写一个赛博朋克短剧开头"
211
214
  pippit-tool-cli short-drama +upload-file --path ./reference.doc
212
215
  pippit-tool-cli get-thread --thread-id thread_123 --run-id run_456
@@ -214,6 +217,8 @@ pippit-tool-cli list-thread-file --thread-id thread_123 --page-num 1 --page-size
214
217
  pippit-tool-cli download-result --output-path ./thread_123/results/result.mp4 --url URL --updated-at 1779716734
215
218
  ```
216
219
 
220
+ `get-credit-balance`: 使用当前登录凭证查询个人有效积分余额,并输出 `{"total_remain_amount":"123"}`;零余额会显式输出为 `"0"`。加 `--with-log-id` 可在输出中同时保留本次请求的 `log_id`。
221
+
217
222
  `+submit-run`: 输出 `thread_id`、`run_id` 和 `web_thread_link`;其中 `--message` 为必填参数。
218
223
  `get-thread`: 请求中带 `version=v2`,并输出 `readable_text`。
219
224
  `list-thread-file`: 输出会话文件列表、分页提示和可直接传给下载命令的 `file_path`。
@@ -241,6 +246,21 @@ pippit-tool-cli canvas apply --project-id PROJECT_ID --file ./patch.json
241
246
 
242
247
  五个命令均输出单行 JSON,资源 ID 保持字符串。`allocate` 只预留 ID,实际资产仍由后续 `apply` transaction 创建。`create` 的 `request_id` 用于追踪,不是跨服务崩溃窗口的严格幂等键;写请求结果不明确时不要盲目重放,应先使用 `canvas get` 回读确认。`apply` 当前只接受一个 transaction,但该 transaction 可以包含多个 patches;CLI 会严格检查 transaction ACK 和每个目标资产的新版本。
243
248
 
249
+ 通过 npm 安装的 CLI 还提供基于同一 Canvas SDK 的语义命令目录:
250
+
251
+ ```bash
252
+ # 查看全部公开命令及其参数说明
253
+ pippit-tool-cli canvas command list
254
+ pippit-tool-cli canvas command describe create_biz_node
255
+
256
+ # 由 SDK 业务工厂创建角色节点;修改会通过现有 canvas apply 原子提交
257
+ pippit-tool-cli canvas command run create_biz_node \
258
+ --canvas-id PIPPIT_CANVAS_ASSET_ID \
259
+ --input '{"nodeKind":"role","initialData":{"nodeName":"测试角色"}}'
260
+ ```
261
+
262
+ `canvas command` 由 npm 包内固定的 Canvas SDK 运行时提供,复用网页登录、`canvas get`、`canvas allocate` 和 `canvas apply`;不会读取或打印 Access Key,也不直接选择服务端地址。公开目录只包含已登记的 mutation 和业务命令,不开放任意内部 command 调用。
263
+
244
264
  ## 生图 CLI
245
265
 
246
266
  `generate-image` 会上传本地参考图片,然后向综合 Nest Agent 提交生图请求:
package/checksums.txt CHANGED
@@ -1,6 +1,6 @@
1
- 34184e1dab803c7c25acb2ef2b95c0358afe39aaf5423140342b5c12e1e80bb3 pippit-tool-cli-1.0.18-darwin-amd64.tar.gz
2
- 0e66993f2b09950e206ee9e9f36c8a8994f6413fffc6a38ef4808457d66eb218 pippit-tool-cli-1.0.18-darwin-arm64.tar.gz
3
- 24dbe1e620a760d7b43636f881e7716e0beefa32f81e45311983fc6a6fc94acf pippit-tool-cli-1.0.18-linux-amd64.tar.gz
4
- 1cdb7cbf054ef1203579cd1c8e71035ce0c434cbfaed7dd3f1bc35605bfedd72 pippit-tool-cli-1.0.18-linux-arm64.tar.gz
5
- 9028a53a9ac03967e245f4e1348bdea82f03dcd30dc85a72c30bcf744ff1bd56 pippit-tool-cli-1.0.18-windows-amd64.zip
6
- 6fe7de9b87de3bdd41f7eefb6514e9c48acd079fdc4ff2c5e917b03d01a8ecc0 pippit-tool-cli-1.0.18-windows-arm64.zip
1
+ c1657ee91f7f964dd936ecd723ff4985c12be4585f7f64dff96adba0277ec669 pippit-tool-cli-1.0.21-darwin-amd64.tar.gz
2
+ ebfe75d1a8fbd6e76125b49917e97a3a81db6c4bae35ab5a1cb9625c618ea490 pippit-tool-cli-1.0.21-darwin-arm64.tar.gz
3
+ 3d828780c00f985378df61072d633e84dd2bcba3b8f7b7e6619fbd9ee34bf2a2 pippit-tool-cli-1.0.21-linux-amd64.tar.gz
4
+ 14dfb1412da253c62a4a52c27a40ce09c3af8480be9c4a94565952e7eed9afff pippit-tool-cli-1.0.21-linux-arm64.tar.gz
5
+ 0d7b8bc575efb3928f8881cb2ba76f2583c2d4ed3f53c7ab3c98f53cf278d0c3 pippit-tool-cli-1.0.21-windows-amd64.zip
6
+ 3145e59e584bfd618b06d8a4e1586d242ff8c568f7221737f2f06d8f111a2cd7 pippit-tool-cli-1.0.21-windows-arm64.zip
@@ -118,6 +118,7 @@ func newGetCommand(stdout, stderr io.Writer, runner *common.Runner) *cobra.Comma
118
118
  func newApplyCommand(stdout, stderr io.Writer, runner *common.Runner) *cobra.Command {
119
119
  var filePath string
120
120
  var projectID string
121
+ var transportResult bool
121
122
  cmd := &cobra.Command{
122
123
  Use: "apply",
123
124
  Short: "Apply one Canvas patch transaction",
@@ -128,8 +129,9 @@ func newApplyCommand(stdout, stderr io.Writer, runner *common.Runner) *cobra.Com
128
129
  return err
129
130
  }
130
131
  result, err := canvascore.Apply(cmd.Context(), canvascore.ApplyOptions{
131
- ProjectID: projectID,
132
- Request: request,
132
+ ProjectID: projectID,
133
+ Request: request,
134
+ AllowNonAcknowledgedResults: transportResult,
133
135
  }, runner)
134
136
  if err != nil {
135
137
  logCanvasError("canvas apply", err, map[string]string{
@@ -147,6 +149,10 @@ func newApplyCommand(stdout, stderr io.Writer, runner *common.Runner) *cobra.Com
147
149
  flags := cmd.Flags()
148
150
  flags.StringVar(&filePath, "file", "-", "BatchPatch JSON request file, or - for stdin")
149
151
  flags.StringVar(&projectID, "project-id", "", "personal novel project ID as a decimal string")
152
+ flags.BoolVar(&transportResult, "transport-result", false, "return explicit transaction outcomes for transport decoding")
153
+ if err := flags.MarkHidden("transport-result"); err != nil {
154
+ panic(err)
155
+ }
150
156
  return cmd
151
157
  }
152
158
 
@@ -8,6 +8,7 @@ import (
8
8
  "testing"
9
9
 
10
10
  "github.com/Pippit-dev/pippit-cli/internal/common"
11
+ "github.com/spf13/cobra"
11
12
  )
12
13
 
13
14
  type commandFakeClient struct {
@@ -124,3 +125,58 @@ func TestApplyRequestRejectsTeamOrImportExtensions(t *testing.T) {
124
125
  }
125
126
  }
126
127
  }
128
+
129
+ func TestApplyTransportResultFlagIsHiddenAndPrintsExplicitReject(t *testing.T) {
130
+ client := &commandFakeClient{response: `{"ret":"0","log_id":"transport-log","data":{"results":[{"transaction_id":"tx-1","status":"reject","message":"version conflict","current_asset_versions":{"asset-1":9},"server_detail":{"reason":"conflict"}}]}}`}
131
+ var stdout, stderr bytes.Buffer
132
+ cmd := NewCommand(&stdout, &stderr, &common.Runner{Client: client})
133
+ var applyCommand *cobra.Command
134
+ for _, child := range cmd.Commands() {
135
+ if child.Name() == "apply" {
136
+ applyCommand = child
137
+ break
138
+ }
139
+ }
140
+ if applyCommand == nil {
141
+ t.Fatal("apply command not found")
142
+ }
143
+ flag := applyCommand.Flags().Lookup("transport-result")
144
+ if flag == nil || !flag.Hidden {
145
+ t.Fatalf("transport-result flag = %#v, want hidden flag", flag)
146
+ }
147
+
148
+ request := `{"batch_id":"batch-1","client_id":"client-1","transactions":[{"transaction_id":"tx-1","patches":[{"asset_id":"asset-1","op":"replace","path":"","value":{}}]}]}`
149
+ cmd.SetIn(strings.NewReader(request))
150
+ cmd.SetArgs([]string{"apply", "--file", "-", "--transport-result"})
151
+ if err := cmd.Execute(); err != nil {
152
+ t.Fatalf("Execute() error = %v", err)
153
+ }
154
+ var output map[string]any
155
+ if err := json.Unmarshal(bytes.TrimSpace(stdout.Bytes()), &output); err != nil {
156
+ t.Fatalf("stdout = %q, want JSON: %v", stdout.String(), err)
157
+ }
158
+ result := output["results"].([]any)[0].(map[string]any)
159
+ if result["status"] != "reject" || result["message"] != "version conflict" || result["server_detail"] == nil {
160
+ t.Fatalf("result = %#v, want complete explicit reject", result)
161
+ }
162
+ }
163
+
164
+ func TestApplyTransportResultPrintsRootCreateAckWithoutVersion(t *testing.T) {
165
+ client := &commandFakeClient{response: `{"ret":"0","data":{"results":[{"transaction_id":"tx-1","status":"ack","server_detail":{"created":true}}]}}`}
166
+ var stdout, stderr bytes.Buffer
167
+ cmd := NewCommand(&stdout, &stderr, &common.Runner{Client: client})
168
+ request := `{"batch_id":"batch-1","client_id":"client-1","transactions":[{"transaction_id":"tx-1","patches":[{"asset_id":"asset-new","op":"add","path":"","value":{}}]}]}`
169
+ cmd.SetIn(strings.NewReader(request))
170
+ cmd.SetArgs([]string{"apply", "--file", "-", "--transport-result"})
171
+ if err := cmd.Execute(); err != nil {
172
+ t.Fatalf("Execute() error = %v", err)
173
+ }
174
+ var output map[string]any
175
+ if err := json.Unmarshal(bytes.TrimSpace(stdout.Bytes()), &output); err != nil {
176
+ t.Fatalf("stdout = %q, want JSON: %v", stdout.String(), err)
177
+ }
178
+ result := output["results"].([]any)[0].(map[string]any)
179
+ if result["status"] != "ack" || result["asset_versions"] != nil || result["server_detail"] == nil {
180
+ t.Fatalf("result = %#v, want unchanged root-create ACK", result)
181
+ }
182
+ }
@@ -0,0 +1,37 @@
1
+ package cmd
2
+
3
+ import (
4
+ "io"
5
+
6
+ "github.com/Pippit-dev/pippit-cli/internal/common"
7
+ "github.com/spf13/cobra"
8
+ )
9
+
10
+ func newGetCreditBalanceCommand(stdout, stderr io.Writer, runner *common.Runner) *cobra.Command {
11
+ var withLogID bool
12
+ cmd := &cobra.Command{
13
+ Use: "get-credit-balance",
14
+ Short: "Get the effective credit balance",
15
+ Args: cobra.NoArgs,
16
+ RunE: withErrorLog("get-credit-balance", nil, func(cmd *cobra.Command, _ []string) error {
17
+ result, err := common.GetCreditBalance(cmd.Context(), runner)
18
+ if err != nil {
19
+ return err
20
+ }
21
+ if withLogID {
22
+ return common.WriteJSON(stdout, struct {
23
+ TotalRemainAmount int64 `json:"total_remain_amount,string"`
24
+ LogID string `json:"log_id"`
25
+ }{
26
+ TotalRemainAmount: result.TotalRemainAmount,
27
+ LogID: result.LogID,
28
+ })
29
+ }
30
+ return common.WriteJSON(stdout, result)
31
+ }),
32
+ }
33
+ cmd.SetOut(stdout)
34
+ cmd.SetErr(stderr)
35
+ cmd.Flags().BoolVar(&withLogID, "with-log-id", false, "include the request log ID in JSON output")
36
+ return cmd
37
+ }
@@ -0,0 +1,73 @@
1
+ package cmd
2
+
3
+ import (
4
+ "bytes"
5
+ "io"
6
+ "net/http"
7
+ "net/http/httptest"
8
+ "testing"
9
+ )
10
+
11
+ func TestGetCreditBalanceCommand(t *testing.T) {
12
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
13
+ if r.Method != http.MethodPost {
14
+ t.Fatalf("method = %s, want POST", r.Method)
15
+ }
16
+ if r.URL.Path != "/api/biz/v1/skill/get_credit_balance" {
17
+ t.Fatalf("path = %s, want get_credit_balance path", r.URL.Path)
18
+ }
19
+ if r.Header.Get("Authorization") != "Bearer test-token" {
20
+ t.Fatalf("Authorization = %q, want test bearer token", r.Header.Get("Authorization"))
21
+ }
22
+ body, err := io.ReadAll(r.Body)
23
+ if err != nil {
24
+ t.Fatalf("read body: %v", err)
25
+ }
26
+ if string(body) != "{}" {
27
+ t.Fatalf("body = %s, want empty JSON object", body)
28
+ }
29
+ w.Header().Set("Content-Type", "application/json")
30
+ _, _ = w.Write([]byte(`{"ret":"0","data":{"total_remain_amount":"0"}}`))
31
+ }))
32
+ defer server.Close()
33
+
34
+ var stdout, stderr bytes.Buffer
35
+ root := newTestRootCommand(t, &stdout, &stderr, server.URL)
36
+ root.SetArgs([]string{"get-credit-balance"})
37
+
38
+ if err := root.Execute(); err != nil {
39
+ t.Fatalf("Execute() error = %v, stderr = %s", err, stderr.String())
40
+ }
41
+ if got, want := stdout.String(), "{\"total_remain_amount\":\"0\"}\n"; got != want {
42
+ t.Fatalf("stdout = %q, want %q", got, want)
43
+ }
44
+ }
45
+
46
+ func TestGetCreditBalanceCommandRejectsArguments(t *testing.T) {
47
+ var stdout, stderr bytes.Buffer
48
+ root := NewRootCommand(&stdout, &stderr)
49
+ root.SetArgs([]string{"get-credit-balance", "unexpected"})
50
+
51
+ if err := root.Execute(); err == nil {
52
+ t.Fatal("Execute() error = nil, want argument rejection")
53
+ }
54
+ }
55
+
56
+ func TestGetCreditBalanceCommandSupportsLogID(t *testing.T) {
57
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
58
+ w.Header().Set("Content-Type", "application/json")
59
+ _, _ = w.Write([]byte(`{"ret":"0","log_id":"log_123","data":{"total_remain_amount":"48592"}}`))
60
+ }))
61
+ defer server.Close()
62
+
63
+ var stdout, stderr bytes.Buffer
64
+ root := newTestRootCommand(t, &stdout, &stderr, server.URL)
65
+ root.SetArgs([]string{"get-credit-balance", "--with-log-id"})
66
+
67
+ if err := root.Execute(); err != nil {
68
+ t.Fatalf("Execute() error = %v, stderr = %s", err, stderr.String())
69
+ }
70
+ if got, want := stdout.String(), "{\"total_remain_amount\":\"48592\",\"log_id\":\"log_123\"}\n"; got != want {
71
+ t.Fatalf("stdout = %q, want %q", got, want)
72
+ }
73
+ }
package/cmd/root.go CHANGED
@@ -56,7 +56,7 @@ func newRootCommand(stdout, stderr io.Writer, runner *common.Runner) *cobra.Comm
56
56
  root := &cobra.Command{
57
57
  Use: "pippit-tool-cli",
58
58
  Short: "Pippit CLI",
59
- Long: "Pippit CLI generates and processes videos and images, submits short-drama workflows, downloads generated assets, and updates the installed CLI package.",
59
+ Long: "Pippit CLI generates and processes videos and images, queries credit balances, submits short-drama workflows, downloads generated assets, and updates the installed CLI package.",
60
60
  Version: version.Current(),
61
61
  SilenceUsage: true,
62
62
  SilenceErrors: true,
@@ -70,6 +70,7 @@ func newRootCommand(stdout, stderr io.Writer, runner *common.Runner) *cobra.Comm
70
70
  root.AddCommand(authcmd.NewLogoutCommand(stdout, stderr, runner))
71
71
  root.AddCommand(canvascmd.NewCommand(stdout, stderr, runner))
72
72
  root.AddCommand(newDownloadResultCommand(stdout, stderr, runner))
73
+ root.AddCommand(newGetCreditBalanceCommand(stdout, stderr, runner))
73
74
  root.AddCommand(newGetThreadCommand(stdout, stderr, runner))
74
75
  root.AddCommand(newListThreadFileCommand(stdout, stderr, runner))
75
76
  root.AddCommand(generate_image.NewCommand(stdout, stderr, runner))
package/cmd/root_test.go CHANGED
@@ -48,6 +48,15 @@ func TestRootRegistersCanvas(t *testing.T) {
48
48
  }
49
49
  }
50
50
 
51
+ func TestRootRegistersGetCreditBalance(t *testing.T) {
52
+ var stdout, stderr bytes.Buffer
53
+ root := NewRootCommand(&stdout, &stderr)
54
+ command, _, err := root.Find([]string{"get-credit-balance"})
55
+ if err != nil || command == nil || command.Name() != "get-credit-balance" {
56
+ t.Fatalf("root.Find(%q) = %#v, %v", "get-credit-balance", command, err)
57
+ }
58
+ }
59
+
51
60
  func TestRootRegistersTopLevelBrowserAuthCommands(t *testing.T) {
52
61
  var stdout, stderr bytes.Buffer
53
62
  root := NewRootCommand(&stdout, &stderr)
@@ -128,6 +128,7 @@ func TestRootHelpListsSupportedCommands(t *testing.T) {
128
128
  "erase-video-subtitle",
129
129
  "generate-video",
130
130
  "download-result",
131
+ "get-credit-balance",
131
132
  "get-thread",
132
133
  "list-thread-file",
133
134
  "query-result",
@@ -0,0 +1,6 @@
1
+ c1657ee91f7f964dd936ecd723ff4985c12be4585f7f64dff96adba0277ec669 pippit-tool-cli-1.0.21-darwin-amd64.tar.gz
2
+ ebfe75d1a8fbd6e76125b49917e97a3a81db6c4bae35ab5a1cb9625c618ea490 pippit-tool-cli-1.0.21-darwin-arm64.tar.gz
3
+ 3d828780c00f985378df61072d633e84dd2bcba3b8f7b7e6619fbd9ee34bf2a2 pippit-tool-cli-1.0.21-linux-amd64.tar.gz
4
+ 14dfb1412da253c62a4a52c27a40ce09c3af8480be9c4a94565952e7eed9afff pippit-tool-cli-1.0.21-linux-arm64.tar.gz
5
+ 0d7b8bc575efb3928f8881cb2ba76f2583c2d4ed3f53c7ab3c98f53cf278d0c3 pippit-tool-cli-1.0.21-windows-amd64.zip
6
+ 3145e59e584bfd618b06d8a4e1586d242ff8c568f7221737f2f06d8f111a2cd7 pippit-tool-cli-1.0.21-windows-arm64.zip