@pippit-dev/cli 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Pippit-dev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # pippit-cli
2
+
3
+ Minimal demo CLI for Pippit workflows.
4
+
5
+ ## Short Drama Run Demo
6
+
7
+ Install from npm after the package is published. The installer downloads the
8
+ matching prebuilt binary for macOS, Linux, or Windows:
9
+
10
+ ```bash
11
+ npx @pippit-dev/cli@latest install
12
+ export XYQ_ACCESS_KEY="<access-key>"
13
+ pippit-cli short-drama +submit-run --message "写一个赛博朋克短剧开头"
14
+ pippit-cli short-drama +upload-file --path ./story.md
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-dir ./thread_123/results/result.mp4 --url URL
17
+ ```
18
+
19
+ NPM package names must be lowercase, so the publishable package name is
20
+ `@pippit-dev/cli` rather than `@Pippit-dev/cli`.
21
+
22
+ Submit a Run task for the short drama scene:
23
+
24
+ ```bash
25
+ export XYQ_ACCESS_KEY="<access-key>"
26
+ go run . short-drama +submit-run --message "写一个赛博朋克短剧开头"
27
+ go run . short-drama +upload-file --path ./story.md
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-dir ./thread_123/results/result.mp4 --url URL
30
+ ```
31
+
32
+ `+submit-run` calls `/api/biz/v1/skill/submit_run` and prints `thread_id`,
33
+ `run_id`, and `web_thread_link`; `--message` is required.
34
+ `+get-thread` calls
35
+ `/api/biz/v1/skill/get_thread` and prints extracted `messages`.
36
+ `+download-result` downloads the result URL to
37
+ the `--output-dir` file path. `+upload-file` is still mocked while
38
+ its real service contract is wired.
39
+
40
+ ## HTTP Client
41
+
42
+ Command modules should receive `common.Runner` for service calls. Runtime
43
+ settings such as base URL, HTTP timeout, and API paths are loaded by
44
+ `internal/config` and paired with `common.Client` in the runner.
45
+
46
+ ## Auth
47
+
48
+ `short-drama +submit-run` and `short-drama +get-thread` authenticate with
49
+ `Authorization: Bearer <XYQ_ACCESS_KEY>`. OAuth command code remains available,
50
+ but runtime short drama requests do not use it.
@@ -0,0 +1,144 @@
1
+ package authcmd
2
+
3
+ import (
4
+ "fmt"
5
+ "io"
6
+ "strings"
7
+ "time"
8
+
9
+ "github.com/Pippit-dev/pippit-cli/internal/auth"
10
+ "github.com/Pippit-dev/pippit-cli/internal/common"
11
+ "github.com/bytedance/sonic"
12
+ "github.com/spf13/cobra"
13
+ )
14
+
15
+ type checkResult struct {
16
+ Pending bool `json:"pending"`
17
+ State any `json:"state,omitempty"`
18
+ }
19
+
20
+ func NewCommand(stdout, stderr io.Writer, runner *common.Runner) *cobra.Command {
21
+ cmd := &cobra.Command{
22
+ Use: "auth",
23
+ Short: "Manage Pippit OAuth login state",
24
+ }
25
+ cmd.SetOut(stdout)
26
+ cmd.SetErr(stderr)
27
+ cmd.AddCommand(newLoginCommand(stdout, stderr, runner))
28
+ cmd.AddCommand(newCheckCommand(stdout, stderr, runner))
29
+ cmd.AddCommand(newStatusCommand(stdout, stderr, runner))
30
+ cmd.AddCommand(newLogoutCommand(stdout, stderr, runner))
31
+ return cmd
32
+ }
33
+
34
+ func newLoginCommand(stdout, stderr io.Writer, runner *common.Runner) *cobra.Command {
35
+ cmd := &cobra.Command{
36
+ Use: "login",
37
+ Short: "Start an OAuth device login flow",
38
+ Args: cobra.NoArgs,
39
+ RunE: func(cmd *cobra.Command, _ []string) error {
40
+ if runner == nil || runner.AuthAuthorizer == nil {
41
+ return fmt.Errorf("auth manager is required")
42
+ }
43
+ flow, err := runner.AuthAuthorizer.NewLoginFlow(cmd.Context())
44
+ if err != nil {
45
+ return err
46
+ }
47
+ return writeJSON(stdout, flow)
48
+ },
49
+ }
50
+ cmd.SetOut(stdout)
51
+ cmd.SetErr(stderr)
52
+ return cmd
53
+ }
54
+
55
+ func newCheckCommand(stdout, stderr io.Writer, runner *common.Runner) *cobra.Command {
56
+ var deviceCode string
57
+ cmd := &cobra.Command{
58
+ Use: "check",
59
+ Short: "Check whether an OAuth device login has completed",
60
+ Args: cobra.NoArgs,
61
+ RunE: func(cmd *cobra.Command, _ []string) error {
62
+ deviceCode = strings.TrimSpace(deviceCode)
63
+ if deviceCode == "" {
64
+ return fmt.Errorf("--device-code is required")
65
+ }
66
+ if runner == nil || runner.AuthAuthorizer == nil {
67
+ return fmt.Errorf("auth manager is required")
68
+ }
69
+ state, err := runner.AuthAuthorizer.CheckLogin(cmd.Context(), deviceCode)
70
+ if auth.IsLoginPending(err) {
71
+ return writeJSON(stdout, checkResult{Pending: true})
72
+ }
73
+ if err != nil {
74
+ return err
75
+ }
76
+ v := map[string]any{
77
+ "logged_in": state.LoggedIn,
78
+ "expires_at": state.ExpiresAt.Format(time.RFC3339),
79
+ }
80
+ return writeJSON(stdout, checkResult{State: v})
81
+ },
82
+ }
83
+ cmd.SetOut(stdout)
84
+ cmd.SetErr(stderr)
85
+ cmd.Flags().StringVar(&deviceCode, "device-code", "", "device code returned by auth login")
86
+ return cmd
87
+ }
88
+
89
+ func newStatusCommand(stdout, stderr io.Writer, runner *common.Runner) *cobra.Command {
90
+ cmd := &cobra.Command{
91
+ Use: "status",
92
+ Short: "Show current OAuth login state",
93
+ Args: cobra.NoArgs,
94
+ RunE: func(cmd *cobra.Command, _ []string) error {
95
+ if runner == nil || runner.AuthAuthorizer == nil {
96
+ return fmt.Errorf("auth manager is required")
97
+ }
98
+ state, err := runner.AuthAuthorizer.State(cmd.Context())
99
+ if err != nil {
100
+ return err
101
+ }
102
+ if !state.LoggedIn {
103
+ return fmt.Errorf("not logged in")
104
+ }
105
+ v := map[string]any{
106
+ "logged_in": state.LoggedIn,
107
+ "expires_at": state.ExpiresAt.Format(time.RFC3339),
108
+ }
109
+ return writeJSON(stdout, v)
110
+ },
111
+ }
112
+ cmd.SetOut(stdout)
113
+ cmd.SetErr(stderr)
114
+ return cmd
115
+ }
116
+
117
+ func newLogoutCommand(stdout, stderr io.Writer, runner *common.Runner) *cobra.Command {
118
+ cmd := &cobra.Command{
119
+ Use: "logout",
120
+ Short: "Clear local OAuth login state",
121
+ Args: cobra.NoArgs,
122
+ RunE: func(cmd *cobra.Command, _ []string) error {
123
+ if runner == nil || runner.AuthAuthorizer == nil {
124
+ return fmt.Errorf("auth manager is required")
125
+ }
126
+ if err := runner.AuthAuthorizer.Logout(cmd.Context()); err != nil {
127
+ return err
128
+ }
129
+ return writeJSON(stdout, map[string]bool{"logged_out": true})
130
+ },
131
+ }
132
+ cmd.SetOut(stdout)
133
+ cmd.SetErr(stderr)
134
+ return cmd
135
+ }
136
+
137
+ func writeJSON(w io.Writer, v any) error {
138
+ data, err := sonic.Marshal(v)
139
+ if err != nil {
140
+ return err
141
+ }
142
+ _, err = fmt.Fprintln(w, string(data))
143
+ return err
144
+ }
package/cmd/root.go ADDED
@@ -0,0 +1,42 @@
1
+ package cmd
2
+
3
+ import (
4
+ "io"
5
+ "os"
6
+
7
+ // authcmd "github.com/Pippit-dev/pippit-cli/cmd/auth"
8
+ "github.com/Pippit-dev/pippit-cli/cmd/short_drama"
9
+ updatecmd "github.com/Pippit-dev/pippit-cli/cmd/update"
10
+ "github.com/Pippit-dev/pippit-cli/internal/auth"
11
+ "github.com/Pippit-dev/pippit-cli/internal/common"
12
+ "github.com/Pippit-dev/pippit-cli/internal/config"
13
+ "github.com/spf13/cobra"
14
+ )
15
+
16
+ // Execute runs the pippit-cli command tree.
17
+ func Execute() error {
18
+ return NewRootCommand(os.Stdout, os.Stderr).Execute()
19
+ }
20
+
21
+ func NewRootCommand(stdout, stderr io.Writer) *cobra.Command {
22
+ cfg := config.Load()
23
+ authManager := auth.NewManager(cfg)
24
+ client := common.NewHTTPClient(cfg.BaseURL, cfg.HTTPTimeout, common.NewAccessKeyAuthorizer(cfg.AccessKey))
25
+ runner := common.NewRunner(cfg, client, authManager)
26
+ return newRootCommand(stdout, stderr, runner)
27
+ }
28
+
29
+ func newRootCommand(stdout, stderr io.Writer, runner *common.Runner) *cobra.Command {
30
+ root := &cobra.Command{
31
+ Use: "pippit-cli",
32
+ Short: "Pippit CLI",
33
+ SilenceUsage: true,
34
+ SilenceErrors: true,
35
+ }
36
+ root.SetOut(stdout)
37
+ root.SetErr(stderr)
38
+ // root.AddCommand(authcmd.NewCommand(stdout, stderr, runner)) // temporarily disabled; auth is via access key injection
39
+ root.AddCommand(short_drama.NewCommand(stdout, stderr, runner))
40
+ root.AddCommand(updatecmd.NewCommand(stdout, stderr))
41
+ return root
42
+ }
@@ -0,0 +1,196 @@
1
+ package short_drama
2
+
3
+ import (
4
+ "fmt"
5
+ "io"
6
+ "path/filepath"
7
+ "strings"
8
+
9
+ "github.com/Pippit-dev/pippit-cli/internal/common"
10
+ "github.com/Pippit-dev/pippit-cli/internal/short_drama"
11
+ "github.com/bytedance/sonic"
12
+ "github.com/spf13/cobra"
13
+ )
14
+
15
+ // NewCommand builds the short_drama scene command tree.
16
+ func NewCommand(stdout, stderr io.Writer, runner *common.Runner) *cobra.Command {
17
+ cmd := &cobra.Command{
18
+ Use: "short-drama",
19
+ Short: "Short drama generation workflows",
20
+ }
21
+
22
+ cmd.SetOut(stdout)
23
+ cmd.SetErr(stderr)
24
+ cmd.AddCommand(newShortDramaSubmitRunCommand(stdout, stderr, runner))
25
+ cmd.AddCommand(newShortDramaUploadFileCommand(stdout, stderr, runner))
26
+ cmd.AddCommand(newShortDramaDownloadResultCommand(stdout, stderr, runner))
27
+ cmd.AddCommand(newShortDramaGetThreadCommand(stdout, stderr, runner))
28
+ cmd.AddCommand(newShortDramaListThreadFileCommand(stdout, stderr, runner))
29
+ return cmd
30
+ }
31
+
32
+ func newShortDramaSubmitRunCommand(stdout, stderr io.Writer, runner *common.Runner) *cobra.Command {
33
+ var opts short_drama.SubmitRunOptions
34
+
35
+ cmd := &cobra.Command{
36
+ Use: "+submit-run",
37
+ Short: "Submit a Run task for the short drama scene",
38
+ Args: cobra.NoArgs,
39
+ RunE: func(cmd *cobra.Command, _ []string) error {
40
+ opts.Message = strings.TrimSpace(opts.Message)
41
+ opts.ThreadID = strings.TrimSpace(opts.ThreadID)
42
+
43
+ if opts.Message == "" {
44
+ return fmt.Errorf("--message is required")
45
+ }
46
+
47
+ result, err := short_drama.SubmitRun(cmd.Context(), &opts, runner)
48
+ if err != nil {
49
+ return err
50
+ }
51
+ return writeJSON(stdout, result)
52
+ },
53
+ }
54
+ cmd.SetOut(stdout)
55
+ cmd.SetErr(stderr)
56
+ cmd.Flags().StringVar(&opts.Message, "message", "", "message to send to the short drama agent")
57
+ cmd.Flags().StringVar(&opts.ThreadID, "thread-id", "", "existing thread ID; omit to create a new thread")
58
+ cmd.Flags().StringArrayVar(&opts.AssetIDs, "asset-ids", nil, "asset ID to attach; repeat for multiple assets")
59
+ return cmd
60
+ }
61
+
62
+ func newShortDramaUploadFileCommand(stdout, stderr io.Writer, runner *common.Runner) *cobra.Command {
63
+ var opts common.UploadFileOptions
64
+
65
+ cmd := &cobra.Command{
66
+ Use: "+upload-file",
67
+ Short: "Upload a file for the short drama scene",
68
+ Args: cobra.NoArgs,
69
+ RunE: func(cmd *cobra.Command, _ []string) error {
70
+ opts.Path = strings.TrimSpace(opts.Path)
71
+
72
+ if opts.Path == "" {
73
+ return fmt.Errorf("--path is required")
74
+ }
75
+ opts.FileName = filepath.Base(opts.Path)
76
+ opts.Mock = true
77
+
78
+ result, err := common.UploadFile(cmd.Context(), opts, runner)
79
+ if err != nil {
80
+ return err
81
+ }
82
+ return writeJSON(stdout, result)
83
+ },
84
+ }
85
+ cmd.SetOut(stdout)
86
+ cmd.SetErr(stderr)
87
+ cmd.Flags().StringVar(&opts.Path, "path", "", "local file path to upload")
88
+ return cmd
89
+ }
90
+
91
+ func newShortDramaDownloadResultCommand(stdout, stderr io.Writer, runner *common.Runner) *cobra.Command {
92
+ var opts common.DownloadResultOptions
93
+
94
+ cmd := &cobra.Command{
95
+ Use: "+download-result",
96
+ Short: "Download a generated result URL",
97
+ Args: cobra.NoArgs,
98
+ RunE: func(cmd *cobra.Command, _ []string) error {
99
+ opts.OutputDir = strings.TrimSpace(opts.OutputDir)
100
+ if opts.OutputDir == "" {
101
+ return fmt.Errorf("--output-dir is required")
102
+ }
103
+ opts.URL = strings.TrimSpace(opts.URL)
104
+ if opts.URL == "" {
105
+ return fmt.Errorf("--url is required")
106
+ }
107
+ if opts.Workers <= 0 {
108
+ return fmt.Errorf("--workers must be greater than 0")
109
+ }
110
+
111
+ result, err := common.DownloadResult(cmd.Context(), opts, runner)
112
+ if err != nil {
113
+ return err
114
+ }
115
+ return writeJSON(stdout, result)
116
+ },
117
+ }
118
+ cmd.SetOut(stdout)
119
+ cmd.SetErr(stderr)
120
+ cmd.Flags().StringVar(&opts.URL, "url", "", "URL to download")
121
+ cmd.Flags().StringVar(&opts.OutputDir, "output-dir", "", "output file path")
122
+ cmd.Flags().IntVar(&opts.Workers, "workers", 5, "parallel download workers")
123
+ return cmd
124
+ }
125
+
126
+ func newShortDramaGetThreadCommand(stdout, stderr io.Writer, runner *common.Runner) *cobra.Command {
127
+ var opts short_drama.GetThreadOptions
128
+
129
+ cmd := &cobra.Command{
130
+ Use: "+get-thread",
131
+ Short: "Get a short drama thread detail",
132
+ Args: cobra.NoArgs,
133
+ RunE: func(cmd *cobra.Command, _ []string) error {
134
+ opts.ThreadID = strings.TrimSpace(opts.ThreadID)
135
+ if opts.ThreadID == "" {
136
+ return fmt.Errorf("--thread-id is required")
137
+ }
138
+ opts.RunID = strings.TrimSpace(opts.RunID)
139
+
140
+ result, err := short_drama.GetThread(cmd.Context(), &opts, runner)
141
+ if err != nil {
142
+ return err
143
+ }
144
+ return writeJSON(stdout, result)
145
+ },
146
+ }
147
+ cmd.SetOut(stdout)
148
+ cmd.SetErr(stderr)
149
+ cmd.Flags().StringVar(&opts.ThreadID, "thread-id", "", "thread ID to fetch")
150
+ cmd.Flags().StringVar(&opts.RunID, "run-id", "", "run ID to fetch")
151
+ cmd.Flags().IntVar(&opts.AfterSeq, "after-seq", 0, "return messages whose sequence is greater than or equal to this value")
152
+ return cmd
153
+ }
154
+
155
+ func newShortDramaListThreadFileCommand(stdout, stderr io.Writer, runner *common.Runner) *cobra.Command {
156
+ var opts common.ListThreadFileOptions
157
+
158
+ cmd := &cobra.Command{
159
+ Use: "+list-thread-file",
160
+ Short: "List files in a short drama thread",
161
+ Args: cobra.NoArgs,
162
+ RunE: func(cmd *cobra.Command, _ []string) error {
163
+ opts.ThreadID = strings.TrimSpace(opts.ThreadID)
164
+ if opts.ThreadID == "" {
165
+ return fmt.Errorf("--thread-id is required")
166
+ }
167
+ if opts.PageSize <= 0 || opts.PageSize > 100 {
168
+ return fmt.Errorf("--page-size must be between 1 and 100")
169
+ }
170
+ if opts.PageNum <= 0 {
171
+ return fmt.Errorf("--page-num must be greater than 0")
172
+ }
173
+
174
+ result, err := common.ListThreadFile(cmd.Context(), &opts, runner)
175
+ if err != nil {
176
+ return err
177
+ }
178
+ return writeJSON(stdout, result)
179
+ },
180
+ }
181
+ cmd.SetOut(stdout)
182
+ cmd.SetErr(stderr)
183
+ cmd.Flags().StringVar(&opts.ThreadID, "thread-id", "", "thread ID to list files for")
184
+ cmd.Flags().IntVar(&opts.PageNum, "page-num", 1, "page number (1-based)")
185
+ cmd.Flags().IntVar(&opts.PageSize, "page-size", 100, "number of files per page (between 1 and 100)")
186
+ return cmd
187
+ }
188
+
189
+ func writeJSON(w io.Writer, v any) error {
190
+ data, err := sonic.Marshal(v)
191
+ if err != nil {
192
+ return err
193
+ }
194
+ _, err = fmt.Fprintln(w, string(data))
195
+ return err
196
+ }