@tvbs-ai/news-rd 0.1.2 → 0.3.0
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 +25 -4
- package/dist/cli.js +294 -74
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ TVBS News Rundown AI CLI — query rundowns, news candidates, Google Trends, and
|
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install -g @tvbs-ai/news-rd
|
|
9
|
-
# or
|
|
9
|
+
# or run directly
|
|
10
10
|
npx @tvbs-ai/news-rd --help
|
|
11
11
|
```
|
|
12
12
|
|
|
@@ -25,6 +25,7 @@ news-rd <group> <command> [args] [options]
|
|
|
25
25
|
| `news` | 候選新聞與趨勢關鍵字 |
|
|
26
26
|
| `prompt` | Prompt 模板、變數與編譯 |
|
|
27
27
|
| `token` | JWT Token 管理 |
|
|
28
|
+
| `completion` | Shell auto-completion |
|
|
28
29
|
|
|
29
30
|
### Examples
|
|
30
31
|
|
|
@@ -55,7 +56,8 @@ news-rd prompt compile 2026-03-10 0600
|
|
|
55
56
|
| `--base-url URL` | API base URL | `https://news-rundown.tvbs.ai` |
|
|
56
57
|
| `--token TOKEN` | JWT token (or `RD_TOKEN` env) | — |
|
|
57
58
|
| `--json` | Raw JSON output | — |
|
|
58
|
-
| `--
|
|
59
|
+
| `--version, -v` | Show version | — |
|
|
60
|
+
| `--help, -h` | Show help | — |
|
|
59
61
|
|
|
60
62
|
### Environment Variables
|
|
61
63
|
|
|
@@ -64,14 +66,33 @@ news-rd prompt compile 2026-03-10 0600
|
|
|
64
66
|
| `RD_BASE_URL` | API base URL |
|
|
65
67
|
| `RD_TOKEN` | JWT authentication token |
|
|
66
68
|
|
|
69
|
+
### Shell Completion
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Bash
|
|
73
|
+
news-rd completion bash >> ~/.bashrc && source ~/.bashrc
|
|
74
|
+
|
|
75
|
+
# Zsh
|
|
76
|
+
news-rd completion zsh >> ~/.zshrc && source ~/.zshrc
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Update
|
|
80
|
+
|
|
81
|
+
The CLI automatically checks for new versions and shows a hint after command output. To update:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
npm install -g @tvbs-ai/news-rd@latest
|
|
85
|
+
```
|
|
86
|
+
|
|
67
87
|
## Requirements
|
|
68
88
|
|
|
69
89
|
- Node.js >= 18 (uses built-in fetch)
|
|
70
90
|
- A running TVBS News Rundown AI server
|
|
71
91
|
|
|
72
|
-
##
|
|
92
|
+
## Documentation
|
|
73
93
|
|
|
74
|
-
|
|
94
|
+
- [使用教學](../../docs/cli-guide.md) — 完整的操作教學(中文)
|
|
95
|
+
- [發佈指南](../../docs/cli-publishing.md) — 版本更新與 npm 發佈流程
|
|
75
96
|
|
|
76
97
|
## License
|
|
77
98
|
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
-
var
|
|
4
|
+
var CLI_VERSION = "0.2.0";
|
|
5
|
+
var rawArgs = process.argv.slice(2);
|
|
5
6
|
function parseArgs() {
|
|
6
7
|
const options = {
|
|
7
8
|
baseUrl: process.env.RD_BASE_URL || "https://news-rundown.tvbs.ai",
|
|
@@ -11,57 +12,93 @@ function parseArgs() {
|
|
|
11
12
|
const positional = [];
|
|
12
13
|
let group = "";
|
|
13
14
|
let command = "";
|
|
14
|
-
for (let i = 0; i <
|
|
15
|
-
const arg =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
15
|
+
for (let i = 0; i < rawArgs.length; i++) {
|
|
16
|
+
const arg = rawArgs[i];
|
|
17
|
+
if (arg.startsWith("-")) {
|
|
18
|
+
switch (arg) {
|
|
19
|
+
case "--base-url":
|
|
20
|
+
options.baseUrl = rawArgs[++i] || options.baseUrl;
|
|
21
|
+
break;
|
|
22
|
+
case "--token":
|
|
23
|
+
options.token = rawArgs[++i] || "";
|
|
24
|
+
break;
|
|
25
|
+
case "--json":
|
|
26
|
+
options.json = true;
|
|
27
|
+
break;
|
|
28
|
+
case "--category":
|
|
29
|
+
options.category = rawArgs[++i];
|
|
30
|
+
break;
|
|
31
|
+
case "--content-type":
|
|
32
|
+
options.contentType = rawArgs[++i];
|
|
33
|
+
break;
|
|
34
|
+
case "--limit":
|
|
35
|
+
options.limit = rawArgs[++i];
|
|
36
|
+
break;
|
|
37
|
+
case "--version":
|
|
38
|
+
if (!group) {
|
|
39
|
+
console.log(`@tvbs-ai/news-rd v${CLI_VERSION}`);
|
|
40
|
+
process.exit(0);
|
|
41
|
+
}
|
|
42
|
+
options.version = rawArgs[++i];
|
|
43
|
+
break;
|
|
44
|
+
case "-v":
|
|
45
|
+
console.log(`@tvbs-ai/news-rd v${CLI_VERSION}`);
|
|
46
|
+
process.exit(0);
|
|
47
|
+
case "--variables":
|
|
48
|
+
options.variables = rawArgs[++i];
|
|
49
|
+
break;
|
|
50
|
+
case "--help":
|
|
51
|
+
case "-h":
|
|
52
|
+
break;
|
|
53
|
+
default:
|
|
54
|
+
console.error(`Unknown option: ${arg}`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (!group) {
|
|
60
|
+
group = arg;
|
|
61
|
+
} else if (!command) {
|
|
62
|
+
command = arg;
|
|
63
|
+
} else {
|
|
64
|
+
positional.push(arg);
|
|
58
65
|
}
|
|
59
66
|
}
|
|
67
|
+
if (rawArgs.includes("--help") || rawArgs.includes("-h")) {
|
|
68
|
+
if (group) {
|
|
69
|
+
showGroupHelp(group);
|
|
70
|
+
} else {
|
|
71
|
+
showHelp();
|
|
72
|
+
}
|
|
73
|
+
process.exit(0);
|
|
74
|
+
}
|
|
60
75
|
return { group, command, positional, options };
|
|
61
76
|
}
|
|
77
|
+
var DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
78
|
+
var VALID_TIMESLOTS = ["0600", "0700", "0800", "1400", "1500", "1600"];
|
|
79
|
+
function requireDateTimeslot(positional, group, command) {
|
|
80
|
+
const [date, timeslot] = positional;
|
|
81
|
+
if (!date || !timeslot) {
|
|
82
|
+
console.error(`Usage: news-rd ${group} ${command} <date> <timeslot>`);
|
|
83
|
+
console.error(` date: YYYY-MM-DD (e.g. 2026-03-10)`);
|
|
84
|
+
console.error(` timeslot: ${VALID_TIMESLOTS.join(" | ")}`);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
if (!DATE_RE.test(date)) {
|
|
88
|
+
console.error(`Invalid date format: "${date}"`);
|
|
89
|
+
console.error(` Expected YYYY-MM-DD (e.g. 2026-03-10)`);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
if (!VALID_TIMESLOTS.includes(timeslot)) {
|
|
93
|
+
console.error(`Invalid timeslot: "${timeslot}"`);
|
|
94
|
+
console.error(` Available: ${VALID_TIMESLOTS.join(", ")}`);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
return [date, timeslot];
|
|
98
|
+
}
|
|
62
99
|
function showHelp() {
|
|
63
100
|
console.log(`
|
|
64
|
-
tvbs-news-rd \u2014 TVBS News Rundown AI CLI
|
|
101
|
+
@tvbs-ai/news-rd v${CLI_VERSION} \u2014 TVBS News Rundown AI CLI
|
|
65
102
|
|
|
66
103
|
Usage: news-rd <group> <command> [args] [options]
|
|
67
104
|
|
|
@@ -71,11 +108,13 @@ Groups:
|
|
|
71
108
|
news \u5019\u9078\u65B0\u805E\u8207\u8DA8\u52E2\u95DC\u9375\u5B57
|
|
72
109
|
prompt Prompt \u6A21\u677F\u3001\u8B8A\u6578\u8207\u7DE8\u8B6F
|
|
73
110
|
token JWT Token \u7BA1\u7406
|
|
111
|
+
completion Shell auto-completion
|
|
74
112
|
|
|
75
113
|
Global Options:
|
|
76
114
|
--base-url URL API base URL (default: https://news-rundown.tvbs.ai)
|
|
77
115
|
--token TOKEN JWT token (or RD_TOKEN env)
|
|
78
116
|
--json Raw JSON output
|
|
117
|
+
--version, -v Show version
|
|
79
118
|
--help, -h Show help
|
|
80
119
|
|
|
81
120
|
Run 'news-rd <group> --help' for group-specific commands.
|
|
@@ -146,10 +185,25 @@ Examples:
|
|
|
146
185
|
token \u2014 JWT Token \u7BA1\u7406
|
|
147
186
|
|
|
148
187
|
Commands:
|
|
149
|
-
generate Generate a new admin JWT token
|
|
188
|
+
generate Generate a new admin JWT token
|
|
189
|
+
|
|
190
|
+
Note: Token generation requires a Clerk session cookie.
|
|
191
|
+
The easiest way is to use the Web UI \u2014 log in and click "API Token"
|
|
192
|
+
in the header. The CLI command is for scripting with an existing session.
|
|
150
193
|
|
|
151
194
|
Examples:
|
|
152
195
|
news-rd token generate
|
|
196
|
+
`,
|
|
197
|
+
completion: `
|
|
198
|
+
completion \u2014 Shell auto-completion
|
|
199
|
+
|
|
200
|
+
Commands:
|
|
201
|
+
bash Output bash completion script
|
|
202
|
+
zsh Output zsh completion script
|
|
203
|
+
|
|
204
|
+
Setup:
|
|
205
|
+
news-rd completion bash >> ~/.bashrc && source ~/.bashrc
|
|
206
|
+
news-rd completion zsh >> ~/.zshrc && source ~/.zshrc
|
|
153
207
|
`
|
|
154
208
|
};
|
|
155
209
|
function showGroupHelp(group) {
|
|
@@ -223,8 +277,7 @@ async function apiCall(path, options, method = "GET") {
|
|
|
223
277
|
console.error(` # or`);
|
|
224
278
|
console.error(` export RD_TOKEN=YOUR_TOKEN
|
|
225
279
|
`);
|
|
226
|
-
console.error(` To generate a token, log in to the web UI and click "API Token"
|
|
227
|
-
console.error(` or run: news-rd token generate (requires Clerk session).
|
|
280
|
+
console.error(` To generate a token, log in to the web UI and click "API Token".
|
|
228
281
|
`);
|
|
229
282
|
} else {
|
|
230
283
|
console.error(` ${errorMsg}
|
|
@@ -259,14 +312,6 @@ function printTable(rows, columns) {
|
|
|
259
312
|
console.log(cols.map((c, i) => String(row[c] ?? "").padEnd(widths[i])).join(" "));
|
|
260
313
|
}
|
|
261
314
|
}
|
|
262
|
-
function requireDateTimeslot(positional, group, command) {
|
|
263
|
-
const [date, timeslot] = positional;
|
|
264
|
-
if (!date || !timeslot) {
|
|
265
|
-
console.error(`Usage: news-rd ${group} ${command} <date> <timeslot>`);
|
|
266
|
-
process.exit(1);
|
|
267
|
-
}
|
|
268
|
-
return [date, timeslot];
|
|
269
|
-
}
|
|
270
315
|
async function handleConfig(command, _positional, options) {
|
|
271
316
|
switch (command) {
|
|
272
317
|
case "timeslots": {
|
|
@@ -275,12 +320,12 @@ async function handleConfig(command, _positional, options) {
|
|
|
275
320
|
printJson(data);
|
|
276
321
|
return;
|
|
277
322
|
}
|
|
278
|
-
printTable(data.timeslots, ["slot_code", "description"
|
|
323
|
+
printTable(data.timeslots, ["slot_code", "description"]);
|
|
279
324
|
return;
|
|
280
325
|
}
|
|
281
326
|
default:
|
|
282
327
|
showGroupHelp("config");
|
|
283
|
-
process.exit(
|
|
328
|
+
process.exit(0);
|
|
284
329
|
}
|
|
285
330
|
}
|
|
286
331
|
async function handleRundown(command, positional, options) {
|
|
@@ -292,10 +337,30 @@ async function handleRundown(command, positional, options) {
|
|
|
292
337
|
printJson(data);
|
|
293
338
|
return;
|
|
294
339
|
}
|
|
295
|
-
console.log(`Rundown: ${data.rundown_id}`);
|
|
296
340
|
const items = data.rundown.items || [];
|
|
297
|
-
console.log(`
|
|
298
|
-
|
|
341
|
+
console.log(`Rundown: ${data.rundown_id}`);
|
|
342
|
+
console.log(`Items: ${items.length}
|
|
343
|
+
`);
|
|
344
|
+
printTable(items.map((item, i) => {
|
|
345
|
+
const newsItem = item.news_item;
|
|
346
|
+
const scoring = newsItem?.scoring || {};
|
|
347
|
+
const bonus = scoring.rundown_bonus || {};
|
|
348
|
+
return {
|
|
349
|
+
"#": item.sequence ?? i + 1,
|
|
350
|
+
type: item.item_type,
|
|
351
|
+
slug: newsItem?.slug ?? "-",
|
|
352
|
+
category: newsItem?.category ?? "-",
|
|
353
|
+
content_type: newsItem?.content_type ?? "-",
|
|
354
|
+
final: newsItem ? scoring.rundown_final_score?.toFixed?.(1) ?? "-" : "-",
|
|
355
|
+
summary: newsItem ? scoring.summary_score?.toFixed?.(1) ?? "-" : "-",
|
|
356
|
+
visual: newsItem ? scoring.visual_score?.toFixed?.(1) ?? "-" : "-",
|
|
357
|
+
trends: newsItem ? bonus.google_trends_score ?? 0 : "-",
|
|
358
|
+
excl: newsItem ? bonus.exclusivity_score ?? 0 : "-",
|
|
359
|
+
radar: newsItem ? bonus.trending_keywords_score ?? 0 : "-",
|
|
360
|
+
topic: newsItem ? bonus.featured_topic_score ?? 0 : "-",
|
|
361
|
+
title: newsItem ? String(newsItem.title ?? "").substring(0, 40) : item.placeholder?.caption ?? "-"
|
|
362
|
+
};
|
|
363
|
+
}), ["#", "type", "slug", "category", "content_type", "final", "summary", "visual", "trends", "excl", "radar", "topic", "title"]);
|
|
299
364
|
return;
|
|
300
365
|
}
|
|
301
366
|
case "history": {
|
|
@@ -316,7 +381,7 @@ async function handleRundown(command, positional, options) {
|
|
|
316
381
|
}
|
|
317
382
|
default:
|
|
318
383
|
showGroupHelp("rundown");
|
|
319
|
-
process.exit(
|
|
384
|
+
process.exit(0);
|
|
320
385
|
}
|
|
321
386
|
}
|
|
322
387
|
async function handleNews(command, positional, options) {
|
|
@@ -336,13 +401,23 @@ async function handleNews(command, positional, options) {
|
|
|
336
401
|
}
|
|
337
402
|
console.log(`Statistics: total=${data.statistics.total}, with_slug=${data.statistics.with_slug}, without_slug=${data.statistics.without_slug}
|
|
338
403
|
`);
|
|
339
|
-
printTable(data.candidates.map((c) =>
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
404
|
+
printTable(data.candidates.map((c) => {
|
|
405
|
+
const bonus = c.bonus_scoring || {};
|
|
406
|
+
return {
|
|
407
|
+
slug: c.slug || "-",
|
|
408
|
+
category: c.category,
|
|
409
|
+
content_type: c.content_type || "-",
|
|
410
|
+
publish_time: c.publish_time ? String(c.publish_time).substring(0, 16) : "-",
|
|
411
|
+
final: c.final_score?.toFixed(1),
|
|
412
|
+
summary: c.summary_score?.toFixed(1) ?? "-",
|
|
413
|
+
visual: c.visual_score?.toFixed(1) ?? "-",
|
|
414
|
+
trends: bonus.google_trends_score ?? 0,
|
|
415
|
+
excl: bonus.exclusivity_score ?? 0,
|
|
416
|
+
radar: bonus.trending_keywords_score ?? 0,
|
|
417
|
+
topic: bonus.featured_topic_score ?? 0,
|
|
418
|
+
title: String(c.title).substring(0, 40)
|
|
419
|
+
};
|
|
420
|
+
}), ["slug", "category", "content_type", "publish_time", "final", "summary", "visual", "trends", "excl", "radar", "topic", "title"]);
|
|
346
421
|
return;
|
|
347
422
|
}
|
|
348
423
|
case "trends": {
|
|
@@ -373,7 +448,7 @@ ${window} keywords (${trends.keywords.length}):`);
|
|
|
373
448
|
}
|
|
374
449
|
default:
|
|
375
450
|
showGroupHelp("news");
|
|
376
|
-
process.exit(
|
|
451
|
+
process.exit(0);
|
|
377
452
|
}
|
|
378
453
|
}
|
|
379
454
|
async function handlePrompt(command, positional, options) {
|
|
@@ -460,7 +535,7 @@ ${data.compiled_prompt}
|
|
|
460
535
|
}
|
|
461
536
|
default:
|
|
462
537
|
showGroupHelp("prompt");
|
|
463
|
-
process.exit(
|
|
538
|
+
process.exit(0);
|
|
464
539
|
}
|
|
465
540
|
}
|
|
466
541
|
async function handleToken(command, _positional, options) {
|
|
@@ -479,15 +554,156 @@ Set env: export RD_TOKEN="${data.token}"`);
|
|
|
479
554
|
}
|
|
480
555
|
default:
|
|
481
556
|
showGroupHelp("token");
|
|
482
|
-
process.exit(
|
|
557
|
+
process.exit(0);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
function handleCompletion(command) {
|
|
561
|
+
switch (command) {
|
|
562
|
+
case "bash":
|
|
563
|
+
console.log(generateBashCompletion());
|
|
564
|
+
return;
|
|
565
|
+
case "zsh":
|
|
566
|
+
console.log(generateZshCompletion());
|
|
567
|
+
return;
|
|
568
|
+
default:
|
|
569
|
+
showGroupHelp("completion");
|
|
570
|
+
process.exit(0);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
function generateBashCompletion() {
|
|
574
|
+
return `# bash completion for news-rd
|
|
575
|
+
_news_rd_completions() {
|
|
576
|
+
local cur prev groups
|
|
577
|
+
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
578
|
+
prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
579
|
+
groups="config rundown news prompt token completion"
|
|
580
|
+
|
|
581
|
+
case "\${COMP_WORDS[1]}" in
|
|
582
|
+
config)
|
|
583
|
+
COMPREPLY=($(compgen -W "timeslots" -- "$cur"))
|
|
584
|
+
;;
|
|
585
|
+
rundown)
|
|
586
|
+
COMPREPLY=($(compgen -W "get history" -- "$cur"))
|
|
587
|
+
;;
|
|
588
|
+
news)
|
|
589
|
+
COMPREPLY=($(compgen -W "candidates trends keywords" -- "$cur"))
|
|
590
|
+
;;
|
|
591
|
+
prompt)
|
|
592
|
+
COMPREPLY=($(compgen -W "list show variables resolve compile" -- "$cur"))
|
|
593
|
+
;;
|
|
594
|
+
token)
|
|
595
|
+
COMPREPLY=($(compgen -W "generate" -- "$cur"))
|
|
596
|
+
;;
|
|
597
|
+
completion)
|
|
598
|
+
COMPREPLY=($(compgen -W "bash zsh" -- "$cur"))
|
|
599
|
+
;;
|
|
600
|
+
*)
|
|
601
|
+
if [[ \${COMP_CWORD} -eq 1 ]]; then
|
|
602
|
+
COMPREPLY=($(compgen -W "$groups --help --version --json" -- "$cur"))
|
|
603
|
+
fi
|
|
604
|
+
;;
|
|
605
|
+
esac
|
|
606
|
+
|
|
607
|
+
case "$prev" in
|
|
608
|
+
--base-url|--token|--category|--content-type|--limit|--version|--variables)
|
|
609
|
+
COMPREPLY=()
|
|
610
|
+
;;
|
|
611
|
+
get|history|candidates|trends|keywords|resolve|compile)
|
|
612
|
+
# Suggest timeslots after date
|
|
613
|
+
if [[ \${COMP_CWORD} -ge 4 ]]; then
|
|
614
|
+
COMPREPLY=($(compgen -W "0600 0700 0800 1400 1500 1600" -- "$cur"))
|
|
615
|
+
fi
|
|
616
|
+
;;
|
|
617
|
+
esac
|
|
618
|
+
}
|
|
619
|
+
complete -F _news_rd_completions news-rd`;
|
|
620
|
+
}
|
|
621
|
+
function generateZshCompletion() {
|
|
622
|
+
return `# zsh completion for news-rd
|
|
623
|
+
#compdef news-rd
|
|
624
|
+
|
|
625
|
+
_news_rd() {
|
|
626
|
+
local -a groups
|
|
627
|
+
groups=(
|
|
628
|
+
'config:\u6642\u6BB5\u8207\u74B0\u5883\u8A2D\u5B9A'
|
|
629
|
+
'rundown:Rundown \u67E5\u8A62\u8207\u7248\u672C\u6BD4\u5C0D'
|
|
630
|
+
'news:\u5019\u9078\u65B0\u805E\u8207\u8DA8\u52E2\u95DC\u9375\u5B57'
|
|
631
|
+
'prompt:Prompt \u6A21\u677F\u3001\u8B8A\u6578\u8207\u7DE8\u8B6F'
|
|
632
|
+
'token:JWT Token \u7BA1\u7406'
|
|
633
|
+
'completion:Shell auto-completion'
|
|
634
|
+
)
|
|
635
|
+
|
|
636
|
+
local -a timeslots
|
|
637
|
+
timeslots=(0600 0700 0800 1400 1500 1600)
|
|
638
|
+
|
|
639
|
+
_arguments -C \\
|
|
640
|
+
'--base-url[API base URL]:url:' \\
|
|
641
|
+
'--token[JWT token]:token:' \\
|
|
642
|
+
'--json[Raw JSON output]' \\
|
|
643
|
+
'--version[Show version]' \\
|
|
644
|
+
'--help[Show help]' \\
|
|
645
|
+
'1:group:->group' \\
|
|
646
|
+
'*::arg:->args'
|
|
647
|
+
|
|
648
|
+
case $state in
|
|
649
|
+
group)
|
|
650
|
+
_describe 'group' groups
|
|
651
|
+
;;
|
|
652
|
+
args)
|
|
653
|
+
case \${words[1]} in
|
|
654
|
+
config)
|
|
655
|
+
_values 'command' 'timeslots[List timeslots]'
|
|
656
|
+
;;
|
|
657
|
+
rundown)
|
|
658
|
+
_values 'command' 'get[Get rundown]' 'history[Version history]'
|
|
659
|
+
;;
|
|
660
|
+
news)
|
|
661
|
+
_values 'command' 'candidates[Scored candidates]' 'trends[Google Trends]' 'keywords[NewsRadar keywords]'
|
|
662
|
+
;;
|
|
663
|
+
prompt)
|
|
664
|
+
_values 'command' 'list[List prompts]' 'show[Get template]' 'variables[List variables]' 'resolve[Resolve variables]' 'compile[Compiled prompt]'
|
|
665
|
+
;;
|
|
666
|
+
token)
|
|
667
|
+
_values 'command' 'generate[Generate JWT token]'
|
|
668
|
+
;;
|
|
669
|
+
completion)
|
|
670
|
+
_values 'command' 'bash[Bash completion]' 'zsh[Zsh completion]'
|
|
671
|
+
;;
|
|
672
|
+
esac
|
|
673
|
+
;;
|
|
674
|
+
esac
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
_news_rd "$@"`;
|
|
678
|
+
}
|
|
679
|
+
async function checkForUpdates() {
|
|
680
|
+
try {
|
|
681
|
+
const controller = new AbortController();
|
|
682
|
+
const timeout = setTimeout(() => controller.abort(), 3e3);
|
|
683
|
+
const res = await fetch(
|
|
684
|
+
"https://registry.npmjs.org/@tvbs-ai/news-rd/latest",
|
|
685
|
+
{ signal: controller.signal }
|
|
686
|
+
);
|
|
687
|
+
clearTimeout(timeout);
|
|
688
|
+
if (!res.ok) return;
|
|
689
|
+
const data = await res.json();
|
|
690
|
+
const latest = data.version;
|
|
691
|
+
if (latest && latest !== CLI_VERSION) {
|
|
692
|
+
console.error(`
|
|
693
|
+
\u65B0\u7248\u672C\u53EF\u7528: v${latest} (\u76EE\u524D v${CLI_VERSION})`);
|
|
694
|
+
console.error(` \u66F4\u65B0\u6307\u4EE4: npm install -g @tvbs-ai/news-rd@latest
|
|
695
|
+
`);
|
|
696
|
+
}
|
|
697
|
+
} catch {
|
|
483
698
|
}
|
|
484
699
|
}
|
|
485
700
|
async function main() {
|
|
486
701
|
const { group, command, positional, options } = parseArgs();
|
|
487
702
|
if (!group) {
|
|
488
703
|
showHelp();
|
|
489
|
-
process.exit(
|
|
704
|
+
process.exit(0);
|
|
490
705
|
}
|
|
706
|
+
const updateCheck = checkForUpdates();
|
|
491
707
|
try {
|
|
492
708
|
switch (group) {
|
|
493
709
|
case "config":
|
|
@@ -505,6 +721,9 @@ async function main() {
|
|
|
505
721
|
case "token":
|
|
506
722
|
await handleToken(command, positional, options);
|
|
507
723
|
break;
|
|
724
|
+
case "completion":
|
|
725
|
+
handleCompletion(command);
|
|
726
|
+
break;
|
|
508
727
|
default:
|
|
509
728
|
console.error(`Unknown group: ${group}`);
|
|
510
729
|
showHelp();
|
|
@@ -514,5 +733,6 @@ async function main() {
|
|
|
514
733
|
console.error(error instanceof Error ? error.message : String(error));
|
|
515
734
|
process.exit(1);
|
|
516
735
|
}
|
|
736
|
+
await updateCheck;
|
|
517
737
|
}
|
|
518
738
|
main();
|