@pippit-dev/cli 0.0.17 → 0.0.19

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
@@ -41,6 +41,11 @@ Only `.doc`, `.docx`, and `.txt` file extensions are supported.
41
41
  `+download-result` downloads the result URL to
42
42
  the `--output-path` file path.
43
43
 
44
+ Short drama command errors are appended to a daily local log file under
45
+ `~/.pippit_tool_cli/logs/yyyy-mm-dd.log`. The path is built with the current
46
+ user home directory and the platform path separator, so it works on macOS,
47
+ Linux, and Windows.
48
+
44
49
  ## HTTP Client
45
50
 
46
51
  Command modules should receive `common.Runner` for service calls. Runtime
package/checksums.txt CHANGED
@@ -1,6 +1,6 @@
1
- dc08d1d25fe9fb2d2ed4dc5c2dec42b999ffe9f42f7dfac723d50f85d9107099 pippit-tool-cli-0.0.17-darwin-amd64.tar.gz
2
- f696c2aec0901638716b5037231fd47916c557b6157c1dcff559c894d7992c5a pippit-tool-cli-0.0.17-darwin-arm64.tar.gz
3
- ee4386da9ba02e5dfd93786b319e42af2a41c1fa01c20151232b87ebc81ef343 pippit-tool-cli-0.0.17-linux-amd64.tar.gz
4
- 795c624e273acb9edb0f4851d767d4f58b947e8dc056a7246a64bbb30b085bc1 pippit-tool-cli-0.0.17-linux-arm64.tar.gz
5
- 0e3eb11d38fd04686317df1185195e12180265b9bd7bbb1de2b68a145d72f339 pippit-tool-cli-0.0.17-windows-amd64.zip
6
- acccf51f98a58f3d887a6e2c9131b8acbbc246b6c518ebe8c26b28ad20ed0a54 pippit-tool-cli-0.0.17-windows-arm64.zip
1
+ 35669c5443abd32d8318c30a48a4c8f2985c97b9719bdae2cb141cb0d08c8e73 pippit-tool-cli-0.0.19-darwin-amd64.tar.gz
2
+ 168316fdf953f4a22b76281512368d04ab299577b2ee53cf4ce65f254474dd8e pippit-tool-cli-0.0.19-darwin-arm64.tar.gz
3
+ 016af69efae30199ecc117a4e227e47c9c96c2a8ef24b86ac9e7d61108ef73cb pippit-tool-cli-0.0.19-linux-amd64.tar.gz
4
+ 38e096dc71c3509c47943dd1f37076fbc525d2d8874f299fa000885ab34c574a pippit-tool-cli-0.0.19-linux-arm64.tar.gz
5
+ cc3ded92e540d36af090679a95b8fc5ddc81a9d47c6ff56456ed0c89b5518674 pippit-tool-cli-0.0.19-windows-amd64.zip
6
+ 7db4bb48c1fcbd16ca1940dcaa06d7998ddf814a95e377bdbfa80c4075b07ed4 pippit-tool-cli-0.0.19-windows-arm64.zip
@@ -3,6 +3,8 @@ package short_drama
3
3
  import (
4
4
  "fmt"
5
5
  "io"
6
+ "path/filepath"
7
+ "strconv"
6
8
  "strings"
7
9
 
8
10
  "github.com/Pippit-dev/pippit-cli/internal/common"
@@ -35,7 +37,12 @@ func newShortDramaSubmitRunCommand(stdout, stderr io.Writer, runner *common.Runn
35
37
  Use: "+submit-run",
36
38
  Short: "Submit a Run task for the short drama scene",
37
39
  Args: cobra.NoArgs,
38
- RunE: func(cmd *cobra.Command, _ []string) error {
40
+ RunE: withErrorLog("short-drama +submit-run", func() map[string]string {
41
+ return map[string]string{
42
+ "thread_id": opts.ThreadID,
43
+ "asset_count": strconv.Itoa(len(opts.AssetIDs)),
44
+ }
45
+ }, func(cmd *cobra.Command, _ []string) error {
39
46
  opts.Message = strings.TrimSpace(opts.Message)
40
47
  opts.ThreadID = strings.TrimSpace(opts.ThreadID)
41
48
 
@@ -48,7 +55,7 @@ func newShortDramaSubmitRunCommand(stdout, stderr io.Writer, runner *common.Runn
48
55
  return err
49
56
  }
50
57
  return writeJSON(stdout, result)
51
- },
58
+ }),
52
59
  }
53
60
  cmd.SetOut(stdout)
54
61
  cmd.SetErr(stderr)
@@ -65,7 +72,11 @@ func newShortDramaUploadFileCommand(stdout, stderr io.Writer, runner *common.Run
65
72
  Use: "+upload-file",
66
73
  Short: "Upload a file for the short drama scene",
67
74
  Args: cobra.NoArgs,
68
- RunE: func(cmd *cobra.Command, _ []string) error {
75
+ RunE: withErrorLog("short-drama +upload-file", func() map[string]string {
76
+ return map[string]string{
77
+ "file_name": fileNameForLog(opts.Path),
78
+ }
79
+ }, func(cmd *cobra.Command, _ []string) error {
69
80
  opts.Path = strings.TrimSpace(opts.Path)
70
81
 
71
82
  if opts.Path == "" {
@@ -77,7 +88,7 @@ func newShortDramaUploadFileCommand(stdout, stderr io.Writer, runner *common.Run
77
88
  return err
78
89
  }
79
90
  return writeJSON(stdout, result)
80
- },
91
+ }),
81
92
  }
82
93
  cmd.SetOut(stdout)
83
94
  cmd.SetErr(stderr)
@@ -92,7 +103,13 @@ func newShortDramaDownloadResultCommand(stdout, stderr io.Writer, runner *common
92
103
  Use: "+download-result",
93
104
  Short: "Download a generated result URL",
94
105
  Args: cobra.NoArgs,
95
- RunE: func(cmd *cobra.Command, _ []string) error {
106
+ RunE: withErrorLog("short-drama +download-result", func() map[string]string {
107
+ return map[string]string{
108
+ "output_path": opts.OutputPath,
109
+ "has_url": strconv.FormatBool(strings.TrimSpace(opts.URL) != ""),
110
+ "workers": strconv.Itoa(opts.Workers),
111
+ }
112
+ }, func(cmd *cobra.Command, _ []string) error {
96
113
  opts.OutputPath = strings.TrimSpace(opts.OutputPath)
97
114
  if opts.OutputPath == "" {
98
115
  return fmt.Errorf("--output-path is required")
@@ -110,7 +127,7 @@ func newShortDramaDownloadResultCommand(stdout, stderr io.Writer, runner *common
110
127
  return err
111
128
  }
112
129
  return writeJSON(stdout, result)
113
- },
130
+ }),
114
131
  }
115
132
  cmd.SetOut(stdout)
116
133
  cmd.SetErr(stderr)
@@ -127,7 +144,12 @@ func newShortDramaGetThreadCommand(stdout, stderr io.Writer, runner *common.Runn
127
144
  Use: "+get-thread",
128
145
  Short: "Get a short drama thread detail",
129
146
  Args: cobra.NoArgs,
130
- RunE: func(cmd *cobra.Command, _ []string) error {
147
+ RunE: withErrorLog("short-drama +get-thread", func() map[string]string {
148
+ return map[string]string{
149
+ "thread_id": opts.ThreadID,
150
+ "run_id": opts.RunID,
151
+ }
152
+ }, func(cmd *cobra.Command, _ []string) error {
131
153
  opts.ThreadID = strings.TrimSpace(opts.ThreadID)
132
154
  if opts.ThreadID == "" {
133
155
  return fmt.Errorf("--thread-id is required")
@@ -140,7 +162,7 @@ func newShortDramaGetThreadCommand(stdout, stderr io.Writer, runner *common.Runn
140
162
  }
141
163
  _, err = fmt.Fprintln(stdout, result.ReadableText)
142
164
  return err
143
- },
165
+ }),
144
166
  }
145
167
  cmd.SetOut(stdout)
146
168
  cmd.SetErr(stderr)
@@ -156,7 +178,13 @@ func newShortDramaListThreadFileCommand(stdout, stderr io.Writer, runner *common
156
178
  Use: "+list-thread-file",
157
179
  Short: "List files in a short drama thread",
158
180
  Args: cobra.NoArgs,
159
- RunE: func(cmd *cobra.Command, _ []string) error {
181
+ RunE: withErrorLog("short-drama +list-thread-file", func() map[string]string {
182
+ return map[string]string{
183
+ "thread_id": opts.ThreadID,
184
+ "page_num": strconv.Itoa(opts.PageNum),
185
+ "page_size": strconv.Itoa(opts.PageSize),
186
+ }
187
+ }, func(cmd *cobra.Command, _ []string) error {
160
188
  opts.ThreadID = strings.TrimSpace(opts.ThreadID)
161
189
  if opts.ThreadID == "" {
162
190
  return fmt.Errorf("--thread-id is required")
@@ -173,7 +201,7 @@ func newShortDramaListThreadFileCommand(stdout, stderr io.Writer, runner *common
173
201
  return err
174
202
  }
175
203
  return writeJSON(stdout, result)
176
- },
204
+ }),
177
205
  }
178
206
  cmd.SetOut(stdout)
179
207
  cmd.SetErr(stderr)
@@ -183,6 +211,28 @@ func newShortDramaListThreadFileCommand(stdout, stderr io.Writer, runner *common
183
211
  return cmd
184
212
  }
185
213
 
214
+ func withErrorLog(command string, fields func() map[string]string, run func(*cobra.Command, []string) error) func(*cobra.Command, []string) error {
215
+ return func(cmd *cobra.Command, args []string) error {
216
+ err := run(cmd, args)
217
+ if err != nil {
218
+ logFields := map[string]string(nil)
219
+ if fields != nil {
220
+ logFields = fields()
221
+ }
222
+ _ = common.AppendDailyErrorLog(command, err, logFields)
223
+ }
224
+ return err
225
+ }
226
+ }
227
+
228
+ func fileNameForLog(path string) string {
229
+ path = strings.TrimSpace(path)
230
+ if path == "" {
231
+ return ""
232
+ }
233
+ return filepath.Base(path)
234
+ }
235
+
186
236
  func writeJSON(w io.Writer, v any) error {
187
237
  data, err := sonic.Marshal(v)
188
238
  if err != nil {
@@ -9,6 +9,7 @@ import (
9
9
  "path/filepath"
10
10
  "strings"
11
11
  "testing"
12
+ "time"
12
13
 
13
14
  "github.com/Pippit-dev/pippit-cli/internal/common"
14
15
  "github.com/Pippit-dev/pippit-cli/internal/config"
@@ -17,6 +18,19 @@ import (
17
18
  "github.com/spf13/cobra"
18
19
  )
19
20
 
21
+ func TestMain(m *testing.M) {
22
+ home, err := os.MkdirTemp("", "pippit-cli-test-home")
23
+ if err != nil {
24
+ panic(err)
25
+ }
26
+ _ = os.Setenv("HOME", home)
27
+ _ = os.Setenv("USERPROFILE", home)
28
+
29
+ code := m.Run()
30
+ _ = os.RemoveAll(home)
31
+ os.Exit(code)
32
+ }
33
+
20
34
  func TestShortDramaSubmitRun(t *testing.T) {
21
35
  server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
22
36
  if r.Method != http.MethodPost {
@@ -597,6 +611,8 @@ func TestShortDramaGetThread(t *testing.T) {
597
611
  }
598
612
 
599
613
  func TestShortDramaGetThreadRequiresThreadID(t *testing.T) {
614
+ clearDailyErrorLog(t)
615
+
600
616
  var stdout, stderr bytes.Buffer
601
617
  root := NewRootCommand(&stdout, &stderr)
602
618
  root.SetArgs([]string{"short-drama", "+get-thread"})
@@ -608,6 +624,17 @@ func TestShortDramaGetThreadRequiresThreadID(t *testing.T) {
608
624
  if !strings.Contains(err.Error(), "--thread-id is required") {
609
625
  t.Fatalf("error = %q, want thread-id validation", err)
610
626
  }
627
+
628
+ entries := readDailyErrorLog(t)
629
+ if len(entries) != 1 {
630
+ t.Fatalf("log entries = %d, want 1: %#v", len(entries), entries)
631
+ }
632
+ if entries[0]["command"] != "short-drama +get-thread" {
633
+ t.Fatalf("command = %v, want get-thread", entries[0]["command"])
634
+ }
635
+ if entries[0]["error"] != "--thread-id is required" {
636
+ t.Fatalf("error = %v, want thread-id validation", entries[0]["error"])
637
+ }
611
638
  }
612
639
 
613
640
  func TestShortDramaGetThreadRequiresAccessKey(t *testing.T) {
@@ -787,6 +814,41 @@ func decodeJSON(t *testing.T, data []byte) map[string]any {
787
814
  return got
788
815
  }
789
816
 
817
+ func clearDailyErrorLog(t *testing.T) {
818
+ t.Helper()
819
+ if err := os.RemoveAll(filepath.Join(testHomeDir(t), ".pippit_tool_cli", "logs")); err != nil {
820
+ t.Fatalf("RemoveAll logs: %v", err)
821
+ }
822
+ }
823
+
824
+ func readDailyErrorLog(t *testing.T) []map[string]any {
825
+ t.Helper()
826
+ path := filepath.Join(testHomeDir(t), ".pippit_tool_cli", "logs", time.Now().Format("2006-01-02")+".log")
827
+ data, err := os.ReadFile(path)
828
+ if err != nil {
829
+ t.Fatalf("ReadFile(%s): %v", path, err)
830
+ }
831
+ lines := strings.Split(strings.TrimSpace(string(data)), "\n")
832
+ entries := make([]map[string]any, 0, len(lines))
833
+ for _, line := range lines {
834
+ var entry map[string]any
835
+ if err := sonic.Unmarshal([]byte(line), &entry); err != nil {
836
+ t.Fatalf("decode log line: %v\n%s", err, line)
837
+ }
838
+ entries = append(entries, entry)
839
+ }
840
+ return entries
841
+ }
842
+
843
+ func testHomeDir(t *testing.T) string {
844
+ t.Helper()
845
+ home, err := os.UserHomeDir()
846
+ if err != nil {
847
+ t.Fatalf("UserHomeDir(): %v", err)
848
+ }
849
+ return home
850
+ }
851
+
790
852
  func chdirTemp(t *testing.T) string {
791
853
  t.Helper()
792
854
  cwd := t.TempDir()
@@ -0,0 +1,91 @@
1
+ package common
2
+
3
+ import (
4
+ "os"
5
+ "path/filepath"
6
+ "strings"
7
+ "time"
8
+
9
+ "github.com/bytedance/sonic"
10
+ )
11
+
12
+ const (
13
+ errorLogDirName = ".pippit_tool_cli"
14
+ errorLogSubdir = "logs"
15
+ )
16
+
17
+ type errorLogEntry struct {
18
+ Time string `json:"time"`
19
+ Command string `json:"command"`
20
+ Fields map[string]string `json:"fields,omitempty"`
21
+ Error string `json:"error"`
22
+ }
23
+
24
+ // AppendDailyErrorLog appends one CLI error record to ~/.pippit_tool_cli/logs/yyyy-mm-dd.log.
25
+ func AppendDailyErrorLog(command string, err error, fields map[string]string) error {
26
+ if err == nil {
27
+ return nil
28
+ }
29
+ now := time.Now()
30
+ path, pathErr := dailyErrorLogPath(now)
31
+ if pathErr != nil {
32
+ return pathErr
33
+ }
34
+ if mkErr := os.MkdirAll(filepath.Dir(path), 0o700); mkErr != nil {
35
+ return mkErr
36
+ }
37
+
38
+ entry := errorLogEntry{
39
+ Time: now.Format(time.RFC3339),
40
+ Command: strings.TrimSpace(command),
41
+ Fields: cleanErrorLogFields(fields),
42
+ Error: err.Error(),
43
+ }
44
+ data, marshalErr := sonic.Marshal(entry)
45
+ if marshalErr != nil {
46
+ return marshalErr
47
+ }
48
+ data = append(data, '\n')
49
+ file, openErr := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o600)
50
+ if openErr != nil {
51
+ return openErr
52
+ }
53
+ defer file.Close()
54
+ _, writeErr := file.Write(data)
55
+ return writeErr
56
+ }
57
+
58
+ func dailyErrorLogPath(now time.Time) (string, error) {
59
+ home, err := os.UserHomeDir()
60
+ if err != nil {
61
+ return "", err
62
+ }
63
+ return filepath.Join(home, errorLogDirName, errorLogSubdir, now.Format("2006-01-02")+".log"), nil
64
+ }
65
+
66
+ func cleanErrorLogFields(fields map[string]string) map[string]string {
67
+ if len(fields) == 0 {
68
+ return nil
69
+ }
70
+ cleaned := make(map[string]string, len(fields))
71
+ for k, v := range fields {
72
+ key := strings.TrimSpace(k)
73
+ value := strings.TrimSpace(v)
74
+ if key == "" || value == "" || isSensitiveLogField(key) {
75
+ continue
76
+ }
77
+ cleaned[key] = value
78
+ }
79
+ if len(cleaned) == 0 {
80
+ return nil
81
+ }
82
+ return cleaned
83
+ }
84
+
85
+ func isSensitiveLogField(key string) bool {
86
+ key = strings.ToLower(key)
87
+ return strings.Contains(key, "access") ||
88
+ strings.Contains(key, "authorization") ||
89
+ strings.Contains(key, "secret") ||
90
+ strings.Contains(key, "token")
91
+ }
@@ -0,0 +1,61 @@
1
+ package common
2
+
3
+ import (
4
+ "fmt"
5
+ "os"
6
+ "path/filepath"
7
+ "strings"
8
+ "testing"
9
+ "time"
10
+
11
+ "github.com/bytedance/sonic"
12
+ )
13
+
14
+ func TestAppendDailyErrorLog(t *testing.T) {
15
+ home := t.TempDir()
16
+ t.Setenv("HOME", home)
17
+ t.Setenv("USERPROFILE", home)
18
+
19
+ err := AppendDailyErrorLog("short-drama +get-thread", fmt.Errorf("request failed"), map[string]string{
20
+ "thread_id": "thread_123",
21
+ "access_key": "secret",
22
+ "empty": "",
23
+ })
24
+ if err != nil {
25
+ t.Fatalf("AppendDailyErrorLog(): %v", err)
26
+ }
27
+ if err := AppendDailyErrorLog("short-drama +get-thread", fmt.Errorf("second failure"), nil); err != nil {
28
+ t.Fatalf("AppendDailyErrorLog() second call: %v", err)
29
+ }
30
+
31
+ path := filepath.Join(home, ".pippit_tool_cli", "logs", time.Now().Format("2006-01-02")+".log")
32
+ data, err := os.ReadFile(path)
33
+ if err != nil {
34
+ t.Fatalf("ReadFile(%s): %v", path, err)
35
+ }
36
+ lines := strings.Split(strings.TrimSpace(string(data)), "\n")
37
+ if len(lines) != 2 {
38
+ t.Fatalf("log lines = %d, want 2\n%s", len(lines), string(data))
39
+ }
40
+
41
+ var first map[string]any
42
+ if err := sonic.Unmarshal([]byte(lines[0]), &first); err != nil {
43
+ t.Fatalf("decode first log line: %v\n%s", err, lines[0])
44
+ }
45
+ if first["command"] != "short-drama +get-thread" {
46
+ t.Fatalf("command = %v, want get-thread command", first["command"])
47
+ }
48
+ if first["error"] != "request failed" {
49
+ t.Fatalf("error = %v, want request failed", first["error"])
50
+ }
51
+ fields, ok := first["fields"].(map[string]any)
52
+ if !ok {
53
+ t.Fatalf("fields = %#v, want object", first["fields"])
54
+ }
55
+ if fields["thread_id"] != "thread_123" {
56
+ t.Fatalf("thread_id = %v, want thread_123", fields["thread_id"])
57
+ }
58
+ if _, ok := fields["access_key"]; ok {
59
+ t.Fatalf("access_key should be omitted from log fields: %#v", fields)
60
+ }
61
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pippit-dev/cli",
3
- "version": "0.0.17",
3
+ "version": "0.0.19",
4
4
  "description": "Pippit CLI",
5
5
  "bin": {
6
6
  "pippit-tool-cli": "scripts/run.js"
@@ -31,6 +31,34 @@ metadata:
31
31
 
32
32
  重要资产包括但不限于:剧本设计、场景设计、场景图、人物角色设计、人物图、分集草稿、故事板、最终视频产物。只要 `+list-thread-file` 返回了这些资产的 `download_url`,就要及时调用下载工具落盘,不要只展示文件元信息。
33
33
 
34
+ ## 短剧主流程顺序
35
+
36
+ 短剧创作按以下主流程推进。用户侧 Agent 在展示后端 Agent 的表单、问卷、选项或确认问题时,必须先参考这个顺序判断当前阶段和合理下一步。
37
+
38
+ 1. 剧本上传 / AI 剧本生成 / AI 剧本编辑
39
+ 2. 剧本合并与完整剧本确认
40
+ 3. 剧本分析
41
+ 4. 短剧风格推荐确认
42
+ 5. 剧本标准化(可选)
43
+ 6. 场景分析
44
+ 7. 所有必要场景图生成
45
+ 8. 角色分析
46
+ 9. 所有必要角色图生成
47
+ 10. 分镜设计
48
+ 11. 分镜视频生成
49
+ 12. 完整视频合成
50
+
51
+ ## 表单与问卷选项处理原则
52
+
53
+ 后端 Agent 通过 `readable_text` 发出表单、问卷、选项、按钮或询问用户时,用户侧 Agent 不要机械原样转述所有选项。先结合短剧主流程顺序清洗选项,再把合理、必要、当前可执行的流程项呈现给用户。
54
+
55
+ - 保留当前阶段的确认项,以及不会跳过必要阶段的下一步流程项。
56
+ - 剔除跳过必要阶段的选项。例如未完成“剧本合并与完整剧本确认”前,不应让用户直接进入“剧本分析”;未完成“所有必要场景图生成”前,不应让用户直接进入“角色分析”。
57
+ - 剔除倒退到无关阶段的选项。只有用户明确要求返工、修改或重新生成时,才展示回退选项。
58
+ - `剧本标准化` 是可选阶段,只能出现在“短剧风格推荐确认”之后、“场景分析”之前。不要把它包装成任意阶段都可以跳过或补做的通用选项。
59
+ - 不替用户决定创意内容,例如风格、剧情方向、角色设定、镜头方案。只能清洗流程选项,不能代替用户选择创作偏好。
60
+ - 如果服务端问题混入跨度过大的多个流程选项,重新组织成当前阶段可回答的问题,并说明已按主流程剔除不合理或跳跃选项。
61
+
34
62
  ## 前置要求
35
63
 
36
64
  需要已安装 `pippit-tool-cli`:
@@ -167,7 +195,7 @@ pippit-tool-cli short-drama +download-result --url DOWNLOAD_URL --output-path FI
167
195
  - **重要资产识别**:每轮都检查 `+list-thread-file` 返回的文件。剧本设计、场景设计、场景图、人物角色设计、人物图、分集草稿、故事板、最终视频产物都是重要资产。
168
196
  - **文件下载**:解析 `+list-thread-file` 的结果后,对带 `download_url` 的重要资产立即调用 `+download-result` 下载资源;不要在 `list-thread-file` 阶段检查文件是否已存在,存在性检查由下载工具内部处理。
169
197
  - **下载完成标准**:不要把文件元信息展示当成下载完成;必须拿到本地 `file_path`,或明确记录该文件在重试后仍下载失败。
170
- - **用户确认**:如果消息中出现需要用户确认、补充设定或回答问题的内容,先展示给用户,等待用户回复。
198
+ - **用户确认**:如果消息中出现需要用户确认、补充设定或回答问题的内容,先判断是否包含表单、问卷、选项或按钮;包含时按“短剧主流程顺序”和“表单与问卷选项处理原则”清洗选项,再展示给用户并等待回复。
171
199
  - **超时**:如果长时间无结果,告知用户任务仍在生成中,可稍后通过 `web_thread_link` 查看。
172
200
  - **错误处理**:`+get-thread`、`+list-thread-file` 或 `+download-result` 任一调用失败时,记录失败原因和参数,在后续轮询中主动重试;重试期间继续处理其他成功返回的消息和文件。连续多轮失败后再向用户说明仍未完成的查询或下载项。
173
201
 
@@ -178,7 +206,8 @@ pippit-tool-cli short-drama +download-result --url DOWNLOAD_URL --output-path FI
178
206
  1. 已处理 `+get-thread` 返回的最新 `readable_text`、用户确认问题和最终消息。
179
207
  2. 已用 `--page-size 200` 调用 `+list-thread-file` 获取会话文件列表;如果本轮 `total` 达到 200,已在后续轮询中递增 `page-num` 查询新一页。
180
208
  3. 对所有带 `download_url` 的重要资产,已调用 `+download-result` 下载到本地 `file_path`。
181
- 4. 对查询失败或下载失败的资产,已在后续轮询中主动重试,并在最终回复中列出仍失败的文件或命令。
209
+ 4. 已按短剧主流程顺序检查服务端表单、问卷和选项,没有把跳过必要阶段的选项直接呈现给用户;如果跳过 `剧本标准化`,已明确这是可选阶段。
210
+ 5. 对查询失败或下载失败的资产,已在后续轮询中主动重试,并在最终回复中列出仍失败的文件或命令。
182
211
 
183
212
  ## 输出格式
184
213
 
@@ -271,7 +300,7 @@ Thread: thread_...
271
300
 
272
301
  - 任务提交后:立即展示 `web_thread_link`。
273
302
  - 任务进行中:展示后端 Agent 返回的过程消息。
274
- - 需要用户补充信息时:原样展示后端 Agent 的问题,等待用户回复。
303
+ - 需要用户补充信息时:如果是普通问题,展示后端 Agent 的问题并等待用户回复;如果包含表单、问卷、选项或按钮,先按短剧主流程清洗不合理或跳跃的流程选项,再展示给用户。
275
304
  - 任务完成后:展示短剧内容、分集草稿、设定说明或其他结果信息,同时检查是否有未下载的重要资产。
276
305
  - 获取会话文件后:展示或记录文件元信息,不把它当成已下载结果。
277
306
  - 文件资源下载后:展示已落盘的本地文件路径;已存在而跳过下载的文件也要标明。
@@ -285,7 +314,7 @@ Thread: thread_...
285
314
 
286
315
  1. **上传**:如果用户给了本地 `.doc` / `.docx` / `.txt` 参考文件,先调用 `+upload-file`。
287
316
  2. **提交任务**:首次创作时把用户原始短剧需求和唯一剧本 `asset_id` 通过 `+submit-run --asset-ids` 发给后端;同一 `thread_id` 后续续写或修改不再追加新的剧本文件。
288
- 3. **传话、取文件、下载资源**:根据 `+get-thread` 返回的 `readable_text` 展示进展、问题和结果;根据 `+list-thread-file` 获取文件列表;再根据 `download_url` 调用 `+download-result` 把缺失资源下载到用户本地。
317
+ 3. **传话、取文件、下载资源**:根据 `+get-thread` 返回的 `readable_text` 展示进展、问题和结果;遇到表单、问卷、选项或按钮时,只做流程合理性清洗,不替用户决定创作内容;根据 `+list-thread-file` 获取文件列表;再根据 `download_url` 调用 `+download-result` 把缺失资源下载到用户本地。
289
318
 
290
319
  **不要做的事:**
291
320