@pippit-dev/cli 1.0.18 → 1.0.20

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
@@ -207,6 +207,7 @@ python3 skills/xyq-nest-skill/scripts/download_results.py \
207
207
  npx @pippit-dev/cli@latest install
208
208
  pippit-tool-cli login
209
209
  pippit-tool-cli --version
210
+ pippit-tool-cli get-credit-balance
210
211
  pippit-tool-cli short-drama +submit-run --message "写一个赛博朋克短剧开头"
211
212
  pippit-tool-cli short-drama +upload-file --path ./reference.doc
212
213
  pippit-tool-cli get-thread --thread-id thread_123 --run-id run_456
@@ -214,6 +215,8 @@ pippit-tool-cli list-thread-file --thread-id thread_123 --page-num 1 --page-size
214
215
  pippit-tool-cli download-result --output-path ./thread_123/results/result.mp4 --url URL --updated-at 1779716734
215
216
  ```
216
217
 
218
+ `get-credit-balance`: 使用当前登录凭证查询个人有效积分余额,并输出 `{"total_remain_amount":"123"}`;零余额会显式输出为 `"0"`。加 `--with-log-id` 可在输出中同时保留本次请求的 `log_id`。
219
+
217
220
  `+submit-run`: 输出 `thread_id`、`run_id` 和 `web_thread_link`;其中 `--message` 为必填参数。
218
221
  `get-thread`: 请求中带 `version=v2`,并输出 `readable_text`。
219
222
  `list-thread-file`: 输出会话文件列表、分页提示和可直接传给下载命令的 `file_path`。
@@ -241,6 +244,21 @@ pippit-tool-cli canvas apply --project-id PROJECT_ID --file ./patch.json
241
244
 
242
245
  五个命令均输出单行 JSON,资源 ID 保持字符串。`allocate` 只预留 ID,实际资产仍由后续 `apply` transaction 创建。`create` 的 `request_id` 用于追踪,不是跨服务崩溃窗口的严格幂等键;写请求结果不明确时不要盲目重放,应先使用 `canvas get` 回读确认。`apply` 当前只接受一个 transaction,但该 transaction 可以包含多个 patches;CLI 会严格检查 transaction ACK 和每个目标资产的新版本。
243
246
 
247
+ 通过 npm 安装的 CLI 还提供基于同一 Canvas SDK 的语义命令目录:
248
+
249
+ ```bash
250
+ # 查看全部公开命令及其参数说明
251
+ pippit-tool-cli canvas command list
252
+ pippit-tool-cli canvas command describe create_biz_node
253
+
254
+ # 由 SDK 业务工厂创建角色节点;修改会通过现有 canvas apply 原子提交
255
+ pippit-tool-cli canvas command run create_biz_node \
256
+ --canvas-id PIPPIT_CANVAS_ASSET_ID \
257
+ --input '{"nodeKind":"role","initialData":{"nodeName":"测试角色"}}'
258
+ ```
259
+
260
+ `canvas command` 由 npm 包内固定的 Canvas SDK 运行时提供,复用网页登录、`canvas get`、`canvas allocate` 和 `canvas apply`;不会读取或打印 Access Key,也不直接选择服务端地址。公开目录只包含已登记的 mutation 和业务命令,不开放任意内部 command 调用。
261
+
244
262
  ## 生图 CLI
245
263
 
246
264
  `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
+ 8bbce765a6e25262d7b65c426f74809cb1b56f38e8509c821cff8a5b06d59ba9 pippit-tool-cli-1.0.20-darwin-amd64.tar.gz
2
+ 0cc1d8f2cf1197dcc2992f19e593279e9bc4fb1c72f25f220a933288ab7c8877 pippit-tool-cli-1.0.20-darwin-arm64.tar.gz
3
+ 38e1fb6590cbe62876625ffbc027099992db1a0cb42099c4b3b64e1cc5aae5b3 pippit-tool-cli-1.0.20-linux-amd64.tar.gz
4
+ d44a96fa3cadd7da7e9e1279cb49659d2d9ab7da12f8695267deeb4fd08b33bc pippit-tool-cli-1.0.20-linux-arm64.tar.gz
5
+ 53d350752fcacb60667f0a1733b9edc0be4e2b77744e042f90726584493fb506 pippit-tool-cli-1.0.20-windows-amd64.zip
6
+ 2c04a6f002f3aa0005e6cab4eb18dba5d87bc4f1e158b432bf19c658e4f59b1f pippit-tool-cli-1.0.20-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
+ 8bbce765a6e25262d7b65c426f74809cb1b56f38e8509c821cff8a5b06d59ba9 pippit-tool-cli-1.0.20-darwin-amd64.tar.gz
2
+ 0cc1d8f2cf1197dcc2992f19e593279e9bc4fb1c72f25f220a933288ab7c8877 pippit-tool-cli-1.0.20-darwin-arm64.tar.gz
3
+ 38e1fb6590cbe62876625ffbc027099992db1a0cb42099c4b3b64e1cc5aae5b3 pippit-tool-cli-1.0.20-linux-amd64.tar.gz
4
+ d44a96fa3cadd7da7e9e1279cb49659d2d9ab7da12f8695267deeb4fd08b33bc pippit-tool-cli-1.0.20-linux-arm64.tar.gz
5
+ 53d350752fcacb60667f0a1733b9edc0be4e2b77744e042f90726584493fb506 pippit-tool-cli-1.0.20-windows-amd64.zip
6
+ 2c04a6f002f3aa0005e6cab4eb18dba5d87bc4f1e158b432bf19c658e4f59b1f pippit-tool-cli-1.0.20-windows-arm64.zip