@tvbs-ai/news-rd 0.1.2 → 0.2.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/dist/cli.js +238 -67
- package/package.json +1 -1
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,87 @@ 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
|
+
case "-v":
|
|
39
|
+
console.log(`@tvbs-ai/news-rd v${CLI_VERSION}`);
|
|
40
|
+
process.exit(0);
|
|
41
|
+
case "--variables":
|
|
42
|
+
options.variables = rawArgs[++i];
|
|
43
|
+
break;
|
|
44
|
+
case "--help":
|
|
45
|
+
case "-h":
|
|
46
|
+
break;
|
|
47
|
+
default:
|
|
48
|
+
console.error(`Unknown option: ${arg}`);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (!group) {
|
|
54
|
+
group = arg;
|
|
55
|
+
} else if (!command) {
|
|
56
|
+
command = arg;
|
|
57
|
+
} else {
|
|
58
|
+
positional.push(arg);
|
|
58
59
|
}
|
|
59
60
|
}
|
|
61
|
+
if (rawArgs.includes("--help") || rawArgs.includes("-h")) {
|
|
62
|
+
if (group) {
|
|
63
|
+
showGroupHelp(group);
|
|
64
|
+
} else {
|
|
65
|
+
showHelp();
|
|
66
|
+
}
|
|
67
|
+
process.exit(0);
|
|
68
|
+
}
|
|
60
69
|
return { group, command, positional, options };
|
|
61
70
|
}
|
|
71
|
+
var DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
72
|
+
var VALID_TIMESLOTS = ["0600", "0700", "0800", "1400", "1500", "1600"];
|
|
73
|
+
function requireDateTimeslot(positional, group, command) {
|
|
74
|
+
const [date, timeslot] = positional;
|
|
75
|
+
if (!date || !timeslot) {
|
|
76
|
+
console.error(`Usage: news-rd ${group} ${command} <date> <timeslot>`);
|
|
77
|
+
console.error(` date: YYYY-MM-DD (e.g. 2026-03-10)`);
|
|
78
|
+
console.error(` timeslot: ${VALID_TIMESLOTS.join(" | ")}`);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
if (!DATE_RE.test(date)) {
|
|
82
|
+
console.error(`Invalid date format: "${date}"`);
|
|
83
|
+
console.error(` Expected YYYY-MM-DD (e.g. 2026-03-10)`);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
if (!VALID_TIMESLOTS.includes(timeslot)) {
|
|
87
|
+
console.error(`Invalid timeslot: "${timeslot}"`);
|
|
88
|
+
console.error(` Available: ${VALID_TIMESLOTS.join(", ")}`);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
return [date, timeslot];
|
|
92
|
+
}
|
|
62
93
|
function showHelp() {
|
|
63
94
|
console.log(`
|
|
64
|
-
tvbs-news-rd \u2014 TVBS News Rundown AI CLI
|
|
95
|
+
@tvbs-ai/news-rd v${CLI_VERSION} \u2014 TVBS News Rundown AI CLI
|
|
65
96
|
|
|
66
97
|
Usage: news-rd <group> <command> [args] [options]
|
|
67
98
|
|
|
@@ -71,11 +102,13 @@ Groups:
|
|
|
71
102
|
news \u5019\u9078\u65B0\u805E\u8207\u8DA8\u52E2\u95DC\u9375\u5B57
|
|
72
103
|
prompt Prompt \u6A21\u677F\u3001\u8B8A\u6578\u8207\u7DE8\u8B6F
|
|
73
104
|
token JWT Token \u7BA1\u7406
|
|
105
|
+
completion Shell auto-completion
|
|
74
106
|
|
|
75
107
|
Global Options:
|
|
76
108
|
--base-url URL API base URL (default: https://news-rundown.tvbs.ai)
|
|
77
109
|
--token TOKEN JWT token (or RD_TOKEN env)
|
|
78
110
|
--json Raw JSON output
|
|
111
|
+
--version, -v Show version
|
|
79
112
|
--help, -h Show help
|
|
80
113
|
|
|
81
114
|
Run 'news-rd <group> --help' for group-specific commands.
|
|
@@ -146,10 +179,25 @@ Examples:
|
|
|
146
179
|
token \u2014 JWT Token \u7BA1\u7406
|
|
147
180
|
|
|
148
181
|
Commands:
|
|
149
|
-
generate Generate a new admin JWT token
|
|
182
|
+
generate Generate a new admin JWT token
|
|
183
|
+
|
|
184
|
+
Note: Token generation requires a Clerk session cookie.
|
|
185
|
+
The easiest way is to use the Web UI \u2014 log in and click "API Token"
|
|
186
|
+
in the header. The CLI command is for scripting with an existing session.
|
|
150
187
|
|
|
151
188
|
Examples:
|
|
152
189
|
news-rd token generate
|
|
190
|
+
`,
|
|
191
|
+
completion: `
|
|
192
|
+
completion \u2014 Shell auto-completion
|
|
193
|
+
|
|
194
|
+
Commands:
|
|
195
|
+
bash Output bash completion script
|
|
196
|
+
zsh Output zsh completion script
|
|
197
|
+
|
|
198
|
+
Setup:
|
|
199
|
+
news-rd completion bash >> ~/.bashrc && source ~/.bashrc
|
|
200
|
+
news-rd completion zsh >> ~/.zshrc && source ~/.zshrc
|
|
153
201
|
`
|
|
154
202
|
};
|
|
155
203
|
function showGroupHelp(group) {
|
|
@@ -223,8 +271,7 @@ async function apiCall(path, options, method = "GET") {
|
|
|
223
271
|
console.error(` # or`);
|
|
224
272
|
console.error(` export RD_TOKEN=YOUR_TOKEN
|
|
225
273
|
`);
|
|
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).
|
|
274
|
+
console.error(` To generate a token, log in to the web UI and click "API Token".
|
|
228
275
|
`);
|
|
229
276
|
} else {
|
|
230
277
|
console.error(` ${errorMsg}
|
|
@@ -259,14 +306,6 @@ function printTable(rows, columns) {
|
|
|
259
306
|
console.log(cols.map((c, i) => String(row[c] ?? "").padEnd(widths[i])).join(" "));
|
|
260
307
|
}
|
|
261
308
|
}
|
|
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
309
|
async function handleConfig(command, _positional, options) {
|
|
271
310
|
switch (command) {
|
|
272
311
|
case "timeslots": {
|
|
@@ -275,12 +314,12 @@ async function handleConfig(command, _positional, options) {
|
|
|
275
314
|
printJson(data);
|
|
276
315
|
return;
|
|
277
316
|
}
|
|
278
|
-
printTable(data.timeslots, ["slot_code", "description"
|
|
317
|
+
printTable(data.timeslots, ["slot_code", "description"]);
|
|
279
318
|
return;
|
|
280
319
|
}
|
|
281
320
|
default:
|
|
282
321
|
showGroupHelp("config");
|
|
283
|
-
process.exit(
|
|
322
|
+
process.exit(0);
|
|
284
323
|
}
|
|
285
324
|
}
|
|
286
325
|
async function handleRundown(command, positional, options) {
|
|
@@ -292,10 +331,20 @@ async function handleRundown(command, positional, options) {
|
|
|
292
331
|
printJson(data);
|
|
293
332
|
return;
|
|
294
333
|
}
|
|
295
|
-
console.log(`Rundown: ${data.rundown_id}`);
|
|
296
334
|
const items = data.rundown.items || [];
|
|
297
|
-
console.log(`
|
|
298
|
-
|
|
335
|
+
console.log(`Rundown: ${data.rundown_id}`);
|
|
336
|
+
console.log(`Items: ${items.length}
|
|
337
|
+
`);
|
|
338
|
+
printTable(items.map((item, i) => {
|
|
339
|
+
const newsItem = item.news_item;
|
|
340
|
+
return {
|
|
341
|
+
"#": item.sequence ?? i + 1,
|
|
342
|
+
type: item.item_type,
|
|
343
|
+
title: newsItem ? String(newsItem.title ?? "").substring(0, 45) : item.placeholder?.caption ?? "-",
|
|
344
|
+
score: newsItem ? newsItem.scoring?.rundown_final_score ?? "-" : "-",
|
|
345
|
+
video_id: newsItem?.video_id ?? "-"
|
|
346
|
+
};
|
|
347
|
+
}), ["#", "type", "title", "score", "video_id"]);
|
|
299
348
|
return;
|
|
300
349
|
}
|
|
301
350
|
case "history": {
|
|
@@ -316,7 +365,7 @@ async function handleRundown(command, positional, options) {
|
|
|
316
365
|
}
|
|
317
366
|
default:
|
|
318
367
|
showGroupHelp("rundown");
|
|
319
|
-
process.exit(
|
|
368
|
+
process.exit(0);
|
|
320
369
|
}
|
|
321
370
|
}
|
|
322
371
|
async function handleNews(command, positional, options) {
|
|
@@ -373,7 +422,7 @@ ${window} keywords (${trends.keywords.length}):`);
|
|
|
373
422
|
}
|
|
374
423
|
default:
|
|
375
424
|
showGroupHelp("news");
|
|
376
|
-
process.exit(
|
|
425
|
+
process.exit(0);
|
|
377
426
|
}
|
|
378
427
|
}
|
|
379
428
|
async function handlePrompt(command, positional, options) {
|
|
@@ -460,7 +509,7 @@ ${data.compiled_prompt}
|
|
|
460
509
|
}
|
|
461
510
|
default:
|
|
462
511
|
showGroupHelp("prompt");
|
|
463
|
-
process.exit(
|
|
512
|
+
process.exit(0);
|
|
464
513
|
}
|
|
465
514
|
}
|
|
466
515
|
async function handleToken(command, _positional, options) {
|
|
@@ -479,14 +528,133 @@ Set env: export RD_TOKEN="${data.token}"`);
|
|
|
479
528
|
}
|
|
480
529
|
default:
|
|
481
530
|
showGroupHelp("token");
|
|
482
|
-
process.exit(
|
|
531
|
+
process.exit(0);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
function handleCompletion(command) {
|
|
535
|
+
switch (command) {
|
|
536
|
+
case "bash":
|
|
537
|
+
console.log(generateBashCompletion());
|
|
538
|
+
return;
|
|
539
|
+
case "zsh":
|
|
540
|
+
console.log(generateZshCompletion());
|
|
541
|
+
return;
|
|
542
|
+
default:
|
|
543
|
+
showGroupHelp("completion");
|
|
544
|
+
process.exit(0);
|
|
483
545
|
}
|
|
484
546
|
}
|
|
547
|
+
function generateBashCompletion() {
|
|
548
|
+
return `# bash completion for news-rd
|
|
549
|
+
_news_rd_completions() {
|
|
550
|
+
local cur prev groups
|
|
551
|
+
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
552
|
+
prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
553
|
+
groups="config rundown news prompt token completion"
|
|
554
|
+
|
|
555
|
+
case "\${COMP_WORDS[1]}" in
|
|
556
|
+
config)
|
|
557
|
+
COMPREPLY=($(compgen -W "timeslots" -- "$cur"))
|
|
558
|
+
;;
|
|
559
|
+
rundown)
|
|
560
|
+
COMPREPLY=($(compgen -W "get history" -- "$cur"))
|
|
561
|
+
;;
|
|
562
|
+
news)
|
|
563
|
+
COMPREPLY=($(compgen -W "candidates trends keywords" -- "$cur"))
|
|
564
|
+
;;
|
|
565
|
+
prompt)
|
|
566
|
+
COMPREPLY=($(compgen -W "list show variables resolve compile" -- "$cur"))
|
|
567
|
+
;;
|
|
568
|
+
token)
|
|
569
|
+
COMPREPLY=($(compgen -W "generate" -- "$cur"))
|
|
570
|
+
;;
|
|
571
|
+
completion)
|
|
572
|
+
COMPREPLY=($(compgen -W "bash zsh" -- "$cur"))
|
|
573
|
+
;;
|
|
574
|
+
*)
|
|
575
|
+
if [[ \${COMP_CWORD} -eq 1 ]]; then
|
|
576
|
+
COMPREPLY=($(compgen -W "$groups --help --version --json" -- "$cur"))
|
|
577
|
+
fi
|
|
578
|
+
;;
|
|
579
|
+
esac
|
|
580
|
+
|
|
581
|
+
case "$prev" in
|
|
582
|
+
--base-url|--token|--category|--content-type|--limit|--version|--variables)
|
|
583
|
+
COMPREPLY=()
|
|
584
|
+
;;
|
|
585
|
+
get|history|candidates|trends|keywords|resolve|compile)
|
|
586
|
+
# Suggest timeslots after date
|
|
587
|
+
if [[ \${COMP_CWORD} -ge 4 ]]; then
|
|
588
|
+
COMPREPLY=($(compgen -W "0600 0700 0800 1400 1500 1600" -- "$cur"))
|
|
589
|
+
fi
|
|
590
|
+
;;
|
|
591
|
+
esac
|
|
592
|
+
}
|
|
593
|
+
complete -F _news_rd_completions news-rd`;
|
|
594
|
+
}
|
|
595
|
+
function generateZshCompletion() {
|
|
596
|
+
return `# zsh completion for news-rd
|
|
597
|
+
#compdef news-rd
|
|
598
|
+
|
|
599
|
+
_news_rd() {
|
|
600
|
+
local -a groups
|
|
601
|
+
groups=(
|
|
602
|
+
'config:\u6642\u6BB5\u8207\u74B0\u5883\u8A2D\u5B9A'
|
|
603
|
+
'rundown:Rundown \u67E5\u8A62\u8207\u7248\u672C\u6BD4\u5C0D'
|
|
604
|
+
'news:\u5019\u9078\u65B0\u805E\u8207\u8DA8\u52E2\u95DC\u9375\u5B57'
|
|
605
|
+
'prompt:Prompt \u6A21\u677F\u3001\u8B8A\u6578\u8207\u7DE8\u8B6F'
|
|
606
|
+
'token:JWT Token \u7BA1\u7406'
|
|
607
|
+
'completion:Shell auto-completion'
|
|
608
|
+
)
|
|
609
|
+
|
|
610
|
+
local -a timeslots
|
|
611
|
+
timeslots=(0600 0700 0800 1400 1500 1600)
|
|
612
|
+
|
|
613
|
+
_arguments -C \\
|
|
614
|
+
'--base-url[API base URL]:url:' \\
|
|
615
|
+
'--token[JWT token]:token:' \\
|
|
616
|
+
'--json[Raw JSON output]' \\
|
|
617
|
+
'--version[Show version]' \\
|
|
618
|
+
'--help[Show help]' \\
|
|
619
|
+
'1:group:->group' \\
|
|
620
|
+
'*::arg:->args'
|
|
621
|
+
|
|
622
|
+
case $state in
|
|
623
|
+
group)
|
|
624
|
+
_describe 'group' groups
|
|
625
|
+
;;
|
|
626
|
+
args)
|
|
627
|
+
case \${words[1]} in
|
|
628
|
+
config)
|
|
629
|
+
_values 'command' 'timeslots[List timeslots]'
|
|
630
|
+
;;
|
|
631
|
+
rundown)
|
|
632
|
+
_values 'command' 'get[Get rundown]' 'history[Version history]'
|
|
633
|
+
;;
|
|
634
|
+
news)
|
|
635
|
+
_values 'command' 'candidates[Scored candidates]' 'trends[Google Trends]' 'keywords[NewsRadar keywords]'
|
|
636
|
+
;;
|
|
637
|
+
prompt)
|
|
638
|
+
_values 'command' 'list[List prompts]' 'show[Get template]' 'variables[List variables]' 'resolve[Resolve variables]' 'compile[Compiled prompt]'
|
|
639
|
+
;;
|
|
640
|
+
token)
|
|
641
|
+
_values 'command' 'generate[Generate JWT token]'
|
|
642
|
+
;;
|
|
643
|
+
completion)
|
|
644
|
+
_values 'command' 'bash[Bash completion]' 'zsh[Zsh completion]'
|
|
645
|
+
;;
|
|
646
|
+
esac
|
|
647
|
+
;;
|
|
648
|
+
esac
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
_news_rd "$@"`;
|
|
652
|
+
}
|
|
485
653
|
async function main() {
|
|
486
654
|
const { group, command, positional, options } = parseArgs();
|
|
487
655
|
if (!group) {
|
|
488
656
|
showHelp();
|
|
489
|
-
process.exit(
|
|
657
|
+
process.exit(0);
|
|
490
658
|
}
|
|
491
659
|
try {
|
|
492
660
|
switch (group) {
|
|
@@ -505,6 +673,9 @@ async function main() {
|
|
|
505
673
|
case "token":
|
|
506
674
|
await handleToken(command, positional, options);
|
|
507
675
|
break;
|
|
676
|
+
case "completion":
|
|
677
|
+
handleCompletion(command);
|
|
678
|
+
break;
|
|
508
679
|
default:
|
|
509
680
|
console.error(`Unknown group: ${group}`);
|
|
510
681
|
showHelp();
|