@9000ai/cli 0.5.4 → 0.5.5

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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## What's new in v0.5.5
2
+
3
+ - `--format csv` — search keyword, batch-result, monitor fetch 均支持 CSV 输出,省 token
4
+ - `--skills-path` — `config set --skills-path <dir>` 自定义 skills 安装路径
5
+ - `9000ai update --path <dir>` — 指定 skills 同步目标路径
6
+ - 统一字段名:monitor fetch 返回 `desc`/`create_time`(与 search 一致)
7
+
1
8
  ## What's new in v0.5.3
2
9
 
3
10
  - `9000ai update` — sync skills after npm update, shows what changed
package/dist/client.d.ts CHANGED
@@ -16,4 +16,5 @@ export declare function pollUntilDone(path: string, opts?: {
16
16
  export declare function printJson(data: unknown, opts?: {
17
17
  fields?: string;
18
18
  compact?: boolean;
19
+ format?: string;
19
20
  }): void;
package/dist/client.js CHANGED
@@ -64,6 +64,25 @@ export async function pollUntilDone(path, opts) {
64
64
  }
65
65
  export function printJson(data, opts) {
66
66
  let output = data;
67
+ // --format csv: extract items array, pick fields, output as CSV
68
+ if (opts?.format === "csv") {
69
+ const arr = extractArray(output);
70
+ if (arr && arr.length > 0) {
71
+ const fieldList = opts.fields
72
+ ? opts.fields.split(",").map((f) => f.trim())
73
+ : Object.keys(arr[0]);
74
+ const picked = arr.map((item) => pick(item, fieldList));
75
+ const header = fieldList.join(",");
76
+ const lines = picked.map((row) => fieldList.map((k) => {
77
+ const v = String(row[k] ?? "");
78
+ return v.includes(",") || v.includes('"') || v.includes("\n")
79
+ ? `"${v.replace(/"/g, '""')}"`
80
+ : v;
81
+ }).join(","));
82
+ console.log([header, ...lines].join("\n"));
83
+ return;
84
+ }
85
+ }
67
86
  // --fields: extract specified fields from items/data
68
87
  if (opts?.fields) {
69
88
  const fieldList = opts.fields.split(",").map((f) => f.trim());
@@ -110,6 +110,7 @@ export function registerMonitorCommands(parent) {
110
110
  .requiredOption("--sec-user <id>", "User sec_user_id or homepage URL")
111
111
  .option("--count <n>", "Number of videos to fetch", "20")
112
112
  .option("--sort <n>", "Sort: 0=newest 1=hottest", "0")
113
+ .option("--format <fmt>", "Output format: csv|json", "json")
113
114
  .option("--fields <list>", "Comma-separated fields to extract")
114
115
  .option("--compact", "One JSON object per line")
115
116
  .action(async (opts) => {
@@ -119,6 +120,6 @@ export function registerMonitorCommands(parent) {
119
120
  sort_type: opts.sort,
120
121
  });
121
122
  const data = await request({ method: "GET", path: `/api/v1/douyin/monitor/user-posts?${params}` });
122
- printJson(data, { fields: opts.fields, compact: opts.compact });
123
+ printJson(data, { fields: opts.fields, compact: opts.compact, format: opts.format });
123
124
  });
124
125
  }
@@ -68,6 +68,7 @@ export function registerSearchCommands(parent) {
68
68
  .option("--min-likes <n>", "Minimum likes", "0")
69
69
  .option("--min-comments <n>", "Minimum comments", "0")
70
70
  .option("--wait", "Poll until batch completes then print results")
71
+ .option("--format <fmt>", "Output format: csv|json", "json")
71
72
  .option("--fields <list>", "Comma-separated fields to extract (used with --wait)")
72
73
  .option("--compact", "One JSON object per line (used with --wait)")
73
74
  .action(async (keywords, opts) => {
@@ -114,12 +115,13 @@ export function registerSearchCommands(parent) {
114
115
  writeTsv(`latest_search_${slug}.tsv`, items);
115
116
  console.error(`${items.length} items → output/latest_search.json`);
116
117
  }
117
- printJson(resultInner, { fields: opts.fields, compact: opts.compact });
118
+ printJson(resultInner, { fields: opts.fields, compact: opts.compact, format: opts.format });
118
119
  });
119
120
  cmd
120
121
  .command("batch-result")
121
122
  .description("Query async search batch results")
122
123
  .requiredOption("--batch-id <id>", "Batch ID")
124
+ .option("--format <fmt>", "Output format: csv|json", "json")
123
125
  .option("--fields <list>", "Comma-separated fields to extract (e.g. desc,author_name,likes,video_url)")
124
126
  .option("--compact", "One JSON object per line, no indentation")
125
127
  .action(async (opts) => {
@@ -138,7 +140,7 @@ export function registerSearchCommands(parent) {
138
140
  writeTsv(`latest_search_${slug}.tsv`, items);
139
141
  console.log(`${items.length} items → output/latest_search.json`);
140
142
  }
141
- printJson(inner, { fields: opts.fields, compact: opts.compact });
143
+ printJson(inner, { fields: opts.fields, compact: opts.compact, format: opts.format });
142
144
  });
143
145
  cmd
144
146
  .command("zhihu-hot")
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ const program = new Command();
14
14
  program
15
15
  .name("9000ai")
16
16
  .description("9000AI Toolbox CLI — unified interface for 9000AI platform")
17
- .version("0.5.4");
17
+ .version("0.5.5");
18
18
  registerConfigCommands(program);
19
19
  registerAuthCommands(program);
20
20
  registerSearchCommands(program);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@9000ai/cli",
3
- "version": "0.5.4",
3
+ "version": "0.5.5",
4
4
  "description": "9000AI Toolbox CLI — unified command-line interface for 9000AI platform",
5
5
  "type": "module",
6
6
  "bin": {
@@ -25,10 +25,11 @@ output-format: routing-only
25
25
  2. **异步任务用 `--wait`。** 搜索和转写加 `--wait`,一条命令拿到最终结果
26
26
  3. **有依赖的操作串行。** 上一步输出是下一步输入时,必须等
27
27
  4. **用 `--fields` 只取需要的字段。** 永远不要全量读取
28
+ 5. **列表数据用 `--format csv`。** 比 JSON 省 token,适合视频列表、搜索结果等
28
29
 
29
30
  ```bash
30
31
  # 单任务
31
- 9000ai search keyword "美食探店" --wait --fields desc,likes,author_name
32
+ 9000ai search keyword "美食探店" --wait --format csv --fields desc,likes,author_name
32
33
 
33
34
  # 多数据源并行
34
35
  并行 {
@@ -99,7 +99,7 @@ output-format: task-oriented
99
99
  9000ai config set --base-url http://127.0.0.1:8025 --api-key <key>
100
100
  9000ai auth whoami
101
101
  9000ai auth capabilities
102
- 9000ai monitor fetch --sec-user <sec_user_id> --fields description,likes,comments,plays
102
+ 9000ai monitor fetch --sec-user <sec_user_id> --fields desc,likes,comments,plays
103
103
  9000ai monitor list-creators
104
104
  9000ai monitor create-creator --json-file creator.json
105
105
  9000ai monitor update-creator --creator-id <creator_id> --json-file creator_update.json
@@ -118,7 +118,7 @@ output-format: task-oriented
118
118
 
119
119
  ### 数据精简
120
120
 
121
- 任务结果和监控详情都支持 `--fields` 和 `--compact`。**默认必须用 `--fields` 只取需要的字段,禁止全量读取。**
121
+ 任务结果和监控详情都支持 `--fields`、`--compact` 和 `--format csv`。**默认必须用 `--fields` 只取需要的字段,禁止全量读取。**
122
122
 
123
123
  ```bash
124
124
  # 错误 — 返回全量 JSON,浪费上下文
@@ -127,7 +127,10 @@ output-format: task-oriented
127
127
  # 正确 — 只取监控摘要字段
128
128
  9000ai task results --task-id <id> --fields desc,author_name,likes,comments,create_time
129
129
 
130
- # 更紧凑每条一行
130
+ # CSV 格式 省 token,适合列表数据
131
+ 9000ai monitor fetch --sec-user <id> --format csv --fields desc,likes,shares,create_time
132
+
133
+ # 更紧凑 — 每条一行 JSON
131
134
  9000ai task results --task-id <id> --fields desc,author_name,likes --compact
132
135
  ```
133
136
 
@@ -145,7 +145,7 @@ output/
145
145
 
146
146
  ### 数据精简
147
147
 
148
- 搜索结果和任务结果都支持 `--fields` 和 `--compact`。**默认必须用 `--fields` 只取需要的字段,禁止全量读取。**
148
+ 搜索结果和任务结果都支持 `--fields`、`--compact` 和 `--format csv`。**默认必须用 `--fields` 只取需要的字段,禁止全量读取。**
149
149
 
150
150
  ```bash
151
151
  # 错误 — 返回全量 JSON,浪费上下文
@@ -154,7 +154,10 @@ output/
154
154
  # 正确 — 只取选题需要的字段
155
155
  9000ai search batch-result --batch-id <id> --fields desc,author_name,likes,duration
156
156
 
157
- # 更紧凑每条一行
157
+ # CSV 格式 省 token,适合列表数据
158
+ 9000ai search keyword "美食探店" --wait --format csv --fields desc,author_name,author_sec_uid,likes
159
+
160
+ # 更紧凑 — 每条一行 JSON
158
161
  9000ai search batch-result --batch-id <id> --fields desc,author_name,likes --compact
159
162
  ```
160
163