@casatwy/deyo 0.1.3 → 0.1.4
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 +22 -1
- package/deyo.mjs +270 -67
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -93,6 +93,12 @@ deyo -O ./transcript.txt 'https://www.bilibili.com/video/BVxxxx'
|
|
|
93
93
|
deyo --format srt -O ./transcript.srt 'https://www.youtube.com/watch?v=xxxx'
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
+
为 AI 或日志系统输出结构化进度:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
deyo --progress-format jsonl -O ./transcript.txt 'https://www.youtube.com/watch?v=xxxx'
|
|
100
|
+
```
|
|
101
|
+
|
|
96
102
|
如果输出文件名本身就是 `.srt`,也可以省略 `--format srt`,CLI 会自动识别格式。
|
|
97
103
|
|
|
98
104
|
指定输出英文转写结果:
|
|
@@ -131,6 +137,21 @@ deyo --api-key 'deyo_sk_other' 'https://www.youtube.com/watch?v=xxxx'
|
|
|
131
137
|
- `.vtt` 会自动使用 `vtt`
|
|
132
138
|
- 其他情况默认使用 `text`
|
|
133
139
|
|
|
140
|
+
`--progress-format <value>`
|
|
141
|
+
|
|
142
|
+
指定进度输出格式,支持:
|
|
143
|
+
|
|
144
|
+
- `auto`
|
|
145
|
+
- `text`
|
|
146
|
+
- `jsonl`
|
|
147
|
+
|
|
148
|
+
默认值是 `auto`:
|
|
149
|
+
|
|
150
|
+
- 当 stderr 是 TTY 时,会保留当前的单行原地刷新进度体验
|
|
151
|
+
- 当 stderr 不是 TTY 时,会退化成逐行文本进度,避免控制字符污染日志或代理输出
|
|
152
|
+
|
|
153
|
+
如果你希望 AI 或脚本稳定读取进度事件,建议使用 `--progress-format jsonl`。此时 CLI 会继续把最终结果输出到 stdout 或文件,只把进度事件按 JSON Lines 写到 stderr。
|
|
154
|
+
|
|
134
155
|
`--api-key <key>`
|
|
135
156
|
|
|
136
157
|
为当前这一次命令临时指定 API Key。
|
|
@@ -154,7 +175,7 @@ deyo --api-key 'deyo_sk_other' 'https://www.youtube.com/watch?v=xxxx'
|
|
|
154
175
|
2. 如何向你索取一次 API Key
|
|
155
176
|
3. 如何在你的本地环境执行 `deyo auth login`
|
|
156
177
|
|
|
157
|
-
完成后,你就可以让 AI 直接帮你调用 `deyo`
|
|
178
|
+
完成后,你就可以让 AI 直接帮你调用 `deyo` 提交转写任务。对于需要在对话里持续同步进度的场景,AI 应优先使用 `--progress-format jsonl`,读取 stderr 里的结构化事件,再把任务创建、状态切换、关键百分比和最终结果转述给你。
|
|
158
179
|
|
|
159
180
|
## 更多帮助
|
|
160
181
|
|
package/deyo.mjs
CHANGED
|
@@ -11,9 +11,12 @@ const CLI_VERSION = createRequire(import.meta.url)('./package.json').version
|
|
|
11
11
|
const DEFAULT_BASE_URL = 'https://deyo.miaobi.fun'
|
|
12
12
|
const DEFAULT_LANGUAGE = 'zh'
|
|
13
13
|
const POLL_INTERVAL_MS = 1500
|
|
14
|
+
const PROGRESS_FORMATS = new Set(['auto', 'text', 'jsonl'])
|
|
14
15
|
const RESULT_FORMATS = new Set(['text', 'srt', 'vtt', 'json', 'verbose_json'])
|
|
15
16
|
const TERMINAL_STATUSES = new Set(['completed', 'failed', 'cancelled'])
|
|
16
17
|
|
|
18
|
+
class ReportedCliError extends Error {}
|
|
19
|
+
|
|
17
20
|
function safeJsonParse(value) {
|
|
18
21
|
try {
|
|
19
22
|
return JSON.parse(value)
|
|
@@ -38,6 +41,7 @@ function printUsage() {
|
|
|
38
41
|
--source <name> 可选,显式指定来源
|
|
39
42
|
--language <value> 可选,转写语言,默认 ${DEFAULT_LANGUAGE}
|
|
40
43
|
--format <value> 可选,text | srt | vtt | json | verbose_json
|
|
44
|
+
--progress-format <v> 可选,auto | text | jsonl,默认 auto
|
|
41
45
|
--base-url <url> 可选,默认 ${DEFAULT_BASE_URL}
|
|
42
46
|
-h, --help 显示帮助
|
|
43
47
|
-v, --version 显示 CLI 版本
|
|
@@ -74,6 +78,7 @@ function parseTranscriptionArgs(argv) {
|
|
|
74
78
|
source: '',
|
|
75
79
|
language: '',
|
|
76
80
|
format: '',
|
|
81
|
+
progressFormat: 'auto',
|
|
77
82
|
baseUrl: '',
|
|
78
83
|
url: '',
|
|
79
84
|
}
|
|
@@ -116,6 +121,12 @@ function parseTranscriptionArgs(argv) {
|
|
|
116
121
|
continue
|
|
117
122
|
}
|
|
118
123
|
|
|
124
|
+
if (current === '--progress-format') {
|
|
125
|
+
args.progressFormat = argv[index + 1] || ''
|
|
126
|
+
index += 1
|
|
127
|
+
continue
|
|
128
|
+
}
|
|
129
|
+
|
|
119
130
|
if (current === '--base-url') {
|
|
120
131
|
args.baseUrl = argv[index + 1] || ''
|
|
121
132
|
index += 1
|
|
@@ -456,6 +467,20 @@ function createOutputState() {
|
|
|
456
467
|
}
|
|
457
468
|
}
|
|
458
469
|
|
|
470
|
+
function resolveProgressFormat(progressFormat) {
|
|
471
|
+
const normalized = String(progressFormat || 'auto').trim() || 'auto'
|
|
472
|
+
|
|
473
|
+
if (!PROGRESS_FORMATS.has(normalized)) {
|
|
474
|
+
fail(`--progress-format 不支持:${normalized}`)
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
if (normalized === 'auto') {
|
|
478
|
+
return process.stderr.isTTY ? 'interactive' : 'text'
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return normalized
|
|
482
|
+
}
|
|
483
|
+
|
|
459
484
|
function clearInline(outputState) {
|
|
460
485
|
if (!outputState.inlineActive) {
|
|
461
486
|
return
|
|
@@ -484,6 +509,26 @@ function finishInline(outputState) {
|
|
|
484
509
|
outputState.inlineActive = false
|
|
485
510
|
}
|
|
486
511
|
|
|
512
|
+
function buildStatusChangedMessage(status) {
|
|
513
|
+
return `状态更新:${formatStatus(status)}`
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
function buildTerminalMessage(status, errorMessage) {
|
|
517
|
+
if (status === 'completed') {
|
|
518
|
+
return '任务已完成'
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
if (status === 'failed') {
|
|
522
|
+
return errorMessage ? `任务失败:${errorMessage}` : '任务失败'
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
if (status === 'cancelled') {
|
|
526
|
+
return errorMessage ? `任务已取消:${errorMessage}` : '任务已取消'
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
return errorMessage ? `任务结束:${errorMessage}` : `任务结束:${formatStatus(status)}`
|
|
530
|
+
}
|
|
531
|
+
|
|
487
532
|
function normalizeProgressValue(progress, finishedChunks, totalChunks) {
|
|
488
533
|
if (Number.isFinite(progress) && progress >= 0) {
|
|
489
534
|
return Math.max(0, Math.min(1, progress))
|
|
@@ -521,6 +566,142 @@ function buildTranscribingProgressMessage(input = {}) {
|
|
|
521
566
|
return `转写中 ${percent}%${chunksPart}`
|
|
522
567
|
}
|
|
523
568
|
|
|
569
|
+
function createProgressReporter(progressFormat) {
|
|
570
|
+
const resolvedMode = resolveProgressFormat(progressFormat)
|
|
571
|
+
const outputState = createOutputState()
|
|
572
|
+
let lastTextProgressMessage = ''
|
|
573
|
+
let lastTerminalSignature = ''
|
|
574
|
+
|
|
575
|
+
function writeTextMessage(message) {
|
|
576
|
+
writeStatusLine(outputState, message)
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
function writeJsonEvent(payload) {
|
|
580
|
+
clearInline(outputState)
|
|
581
|
+
process.stderr.write(`${JSON.stringify(payload)}\n`)
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
function emitTextOrJson(message, payload) {
|
|
585
|
+
if (resolvedMode === 'jsonl') {
|
|
586
|
+
writeJsonEvent({
|
|
587
|
+
...payload,
|
|
588
|
+
message,
|
|
589
|
+
})
|
|
590
|
+
return
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
writeTextMessage(message)
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
return {
|
|
597
|
+
mode: resolvedMode,
|
|
598
|
+
reportTaskCreated(task) {
|
|
599
|
+
if (resolvedMode === 'jsonl') {
|
|
600
|
+
writeJsonEvent({
|
|
601
|
+
event: 'task.created',
|
|
602
|
+
message: `任务已创建:${task.taskId}`,
|
|
603
|
+
taskId: task.taskId,
|
|
604
|
+
title: task.title,
|
|
605
|
+
sourceType: task.sourceType,
|
|
606
|
+
status: task.status,
|
|
607
|
+
statusLabel: formatStatus(task.status),
|
|
608
|
+
consumedMinutes: task.consumedMinutes,
|
|
609
|
+
remainingMinutes: task.remainingMinutes,
|
|
610
|
+
mode: task.mode,
|
|
611
|
+
resultReady: task.resultReady,
|
|
612
|
+
})
|
|
613
|
+
return
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
writeTextMessage(`任务已创建:${task.taskId}`)
|
|
617
|
+
writeTextMessage(`标题:${task.title}`)
|
|
618
|
+
writeTextMessage(`来源:${task.sourceType}`)
|
|
619
|
+
writeTextMessage(`状态:${formatStatus(task.status)}`)
|
|
620
|
+
writeTextMessage(`本次消耗分钟:${task.consumedMinutes}`)
|
|
621
|
+
writeTextMessage(`剩余分钟:${task.remainingMinutes}`)
|
|
622
|
+
},
|
|
623
|
+
reportStatusChanged(status) {
|
|
624
|
+
emitTextOrJson(buildStatusChangedMessage(status), {
|
|
625
|
+
event: 'task.status_changed',
|
|
626
|
+
status,
|
|
627
|
+
statusLabel: formatStatus(status),
|
|
628
|
+
})
|
|
629
|
+
},
|
|
630
|
+
reportProgress(input = {}) {
|
|
631
|
+
const finishedChunks = Number(input.finishedChunks)
|
|
632
|
+
const totalChunks = Number(input.totalChunks)
|
|
633
|
+
const normalizedProgress = normalizeProgressValue(
|
|
634
|
+
Number(input.progress),
|
|
635
|
+
finishedChunks,
|
|
636
|
+
totalChunks,
|
|
637
|
+
)
|
|
638
|
+
const message = buildTranscribingProgressMessage(input)
|
|
639
|
+
|
|
640
|
+
lastTerminalSignature = ''
|
|
641
|
+
|
|
642
|
+
if (resolvedMode === 'interactive') {
|
|
643
|
+
writeInline(outputState, message)
|
|
644
|
+
return
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
if (resolvedMode === 'jsonl') {
|
|
648
|
+
writeJsonEvent({
|
|
649
|
+
event: 'task.progress',
|
|
650
|
+
message,
|
|
651
|
+
status: 'transcribing',
|
|
652
|
+
progress: normalizedProgress,
|
|
653
|
+
percent: normalizedProgress === null ? null : Math.round(normalizedProgress * 100),
|
|
654
|
+
finishedChunks: Number.isFinite(finishedChunks) ? Math.max(0, finishedChunks) : null,
|
|
655
|
+
totalChunks: Number.isFinite(totalChunks) && totalChunks > 0 ? totalChunks : null,
|
|
656
|
+
})
|
|
657
|
+
return
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
if (message === lastTextProgressMessage) {
|
|
661
|
+
return
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
lastTextProgressMessage = message
|
|
665
|
+
writeTextMessage(message)
|
|
666
|
+
},
|
|
667
|
+
reportTerminal(status, errorMessage) {
|
|
668
|
+
if (!status) {
|
|
669
|
+
return
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
finishInline(outputState)
|
|
673
|
+
const signature = `${status}:${errorMessage || ''}`
|
|
674
|
+
|
|
675
|
+
if (lastTerminalSignature === signature) {
|
|
676
|
+
return
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
lastTerminalSignature = signature
|
|
680
|
+
emitTextOrJson(buildTerminalMessage(status, errorMessage), {
|
|
681
|
+
event: `task.${status}`,
|
|
682
|
+
status,
|
|
683
|
+
statusLabel: formatStatus(status),
|
|
684
|
+
error: errorMessage || null,
|
|
685
|
+
})
|
|
686
|
+
},
|
|
687
|
+
reportResultWritten(outputPath, format) {
|
|
688
|
+
emitTextOrJson(`结果已写入:${outputPath}`, {
|
|
689
|
+
event: 'task.result_written',
|
|
690
|
+
outputPath,
|
|
691
|
+
format,
|
|
692
|
+
})
|
|
693
|
+
},
|
|
694
|
+
reportNotice(message) {
|
|
695
|
+
emitTextOrJson(message, {
|
|
696
|
+
event: 'task.notice',
|
|
697
|
+
})
|
|
698
|
+
},
|
|
699
|
+
close() {
|
|
700
|
+
finishInline(outputState)
|
|
701
|
+
},
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
524
705
|
function parseSseBlock(block) {
|
|
525
706
|
const lines = block.split('\n')
|
|
526
707
|
let event = 'message'
|
|
@@ -547,7 +728,7 @@ function parseSseBlock(block) {
|
|
|
547
728
|
}
|
|
548
729
|
}
|
|
549
730
|
|
|
550
|
-
async function consumeTaskEvents(baseUrl, apiKey, taskId, initialTask,
|
|
731
|
+
async function consumeTaskEvents(baseUrl, apiKey, taskId, initialTask, reporter) {
|
|
551
732
|
const response = await fetch(`${baseUrl}/api/cli/transcriptions/${encodeURIComponent(taskId)}/events`, {
|
|
552
733
|
method: 'GET',
|
|
553
734
|
headers: {
|
|
@@ -577,7 +758,13 @@ async function consumeTaskEvents(baseUrl, apiKey, taskId, initialTask, outputSta
|
|
|
577
758
|
...task,
|
|
578
759
|
status: nextStatus,
|
|
579
760
|
}
|
|
580
|
-
|
|
761
|
+
|
|
762
|
+
if (TERMINAL_STATUSES.has(nextStatus)) {
|
|
763
|
+
reporter.reportTerminal(nextStatus, task.error || null)
|
|
764
|
+
return
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
reporter.reportStatusChanged(nextStatus)
|
|
581
768
|
}
|
|
582
769
|
|
|
583
770
|
function applyTerminal(nextStatus, errorMessage) {
|
|
@@ -587,7 +774,7 @@ async function consumeTaskEvents(baseUrl, apiKey, taskId, initialTask, outputSta
|
|
|
587
774
|
status: nextStatus,
|
|
588
775
|
error: errorMessage || task.error || null,
|
|
589
776
|
}
|
|
590
|
-
|
|
777
|
+
reporter.reportTerminal(nextStatus, task.error || null)
|
|
591
778
|
}
|
|
592
779
|
|
|
593
780
|
function renderProgress(data) {
|
|
@@ -596,7 +783,7 @@ async function consumeTaskEvents(baseUrl, apiKey, taskId, initialTask, outputSta
|
|
|
596
783
|
...task,
|
|
597
784
|
status: 'transcribing',
|
|
598
785
|
}
|
|
599
|
-
|
|
786
|
+
reporter.reportProgress(data)
|
|
600
787
|
}
|
|
601
788
|
|
|
602
789
|
while (true) {
|
|
@@ -625,6 +812,8 @@ async function consumeTaskEvents(baseUrl, apiKey, taskId, initialTask, outputSta
|
|
|
625
812
|
if (event === 'job.snapshot') {
|
|
626
813
|
if (data?.status === 'transcribing') {
|
|
627
814
|
renderProgress(data)
|
|
815
|
+
} else if (TERMINAL_STATUSES.has(data?.status)) {
|
|
816
|
+
applyTerminal(data.status, data?.error || data?.message || null)
|
|
628
817
|
} else {
|
|
629
818
|
applyStatus(data?.status)
|
|
630
819
|
}
|
|
@@ -658,7 +847,7 @@ async function consumeTaskEvents(baseUrl, apiKey, taskId, initialTask, outputSta
|
|
|
658
847
|
}
|
|
659
848
|
}
|
|
660
849
|
|
|
661
|
-
|
|
850
|
+
reporter.close()
|
|
662
851
|
return task
|
|
663
852
|
}
|
|
664
853
|
|
|
@@ -743,85 +932,95 @@ async function handleAuthCommand(argv) {
|
|
|
743
932
|
|
|
744
933
|
async function handleTranscription(argv) {
|
|
745
934
|
const args = parseTranscriptionArgs(argv)
|
|
746
|
-
const
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
printUsage()
|
|
751
|
-
fail('缺少 API key。请传 --api-key、设置 DEYO_API_KEY,或先执行 deyo auth login')
|
|
752
|
-
}
|
|
935
|
+
const reporter = createProgressReporter(args.progressFormat)
|
|
936
|
+
try {
|
|
937
|
+
const storedConfig = await readStoredConfig()
|
|
938
|
+
const resolvedApiKey = resolveApiKey(args.apiKey, storedConfig)
|
|
753
939
|
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
940
|
+
if (!resolvedApiKey) {
|
|
941
|
+
printUsage()
|
|
942
|
+
fail('缺少 API key。请传 --api-key、设置 DEYO_API_KEY,或先执行 deyo auth login')
|
|
943
|
+
}
|
|
758
944
|
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
language: args.language || DEFAULT_LANGUAGE,
|
|
764
|
-
}
|
|
945
|
+
if (!args.url) {
|
|
946
|
+
printUsage()
|
|
947
|
+
fail('缺少内容链接')
|
|
948
|
+
}
|
|
765
949
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
950
|
+
const { baseUrl } = resolveBaseUrl(args.baseUrl, storedConfig)
|
|
951
|
+
const format = inferFormat(args.output, args.format)
|
|
952
|
+
const createPayload = {
|
|
953
|
+
url: args.url,
|
|
954
|
+
language: args.language || DEFAULT_LANGUAGE,
|
|
955
|
+
}
|
|
769
956
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
})
|
|
774
|
-
const outputState = createOutputState()
|
|
957
|
+
if (args.source) {
|
|
958
|
+
createPayload.source = args.source
|
|
959
|
+
}
|
|
775
960
|
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
961
|
+
const created = await requestJson(baseUrl, resolvedApiKey.apiKey, '/api/cli/transcriptions', {
|
|
962
|
+
method: 'POST',
|
|
963
|
+
body: createPayload,
|
|
964
|
+
})
|
|
965
|
+
reporter.reportTaskCreated(created)
|
|
966
|
+
|
|
967
|
+
let task = created
|
|
968
|
+
let lastStatus = created.status
|
|
969
|
+
|
|
970
|
+
if (task.mode === 'transcription' && !TERMINAL_STATUSES.has(task.status)) {
|
|
971
|
+
try {
|
|
972
|
+
task = await consumeTaskEvents(baseUrl, resolvedApiKey.apiKey, task.taskId, task, reporter)
|
|
973
|
+
lastStatus = task.status
|
|
974
|
+
} catch (error) {
|
|
975
|
+
reporter.reportNotice(`事件流中断,回退到轮询状态:${error instanceof Error ? error.message : String(error)}`)
|
|
976
|
+
}
|
|
977
|
+
}
|
|
782
978
|
|
|
783
|
-
|
|
784
|
-
|
|
979
|
+
while (!TERMINAL_STATUSES.has(task.status)) {
|
|
980
|
+
await sleep(POLL_INTERVAL_MS)
|
|
981
|
+
task = await requestJson(baseUrl, resolvedApiKey.apiKey, `/api/cli/transcriptions/${encodeURIComponent(task.taskId)}`)
|
|
785
982
|
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
983
|
+
if (task.status !== lastStatus) {
|
|
984
|
+
if (TERMINAL_STATUSES.has(task.status)) {
|
|
985
|
+
reporter.reportTerminal(task.status, task.error || null)
|
|
986
|
+
} else {
|
|
987
|
+
reporter.reportStatusChanged(task.status)
|
|
988
|
+
}
|
|
989
|
+
lastStatus = task.status
|
|
990
|
+
}
|
|
793
991
|
}
|
|
794
|
-
}
|
|
795
992
|
|
|
796
|
-
|
|
797
|
-
await sleep(POLL_INTERVAL_MS)
|
|
798
|
-
task = await requestJson(baseUrl, resolvedApiKey.apiKey, `/api/cli/transcriptions/${encodeURIComponent(task.taskId)}`)
|
|
993
|
+
reporter.reportTerminal(task.status, task.error || null)
|
|
799
994
|
|
|
800
|
-
if (task.status !==
|
|
801
|
-
|
|
802
|
-
process.stderr.write(`状态更新:${formatStatus(task.status)}\n`)
|
|
803
|
-
lastStatus = task.status
|
|
995
|
+
if (task.status !== 'completed') {
|
|
996
|
+
throw new ReportedCliError(task.error || `任务未成功完成:${formatStatus(task.status)}`)
|
|
804
997
|
}
|
|
805
|
-
}
|
|
806
998
|
|
|
807
|
-
|
|
999
|
+
const result = await requestResult(baseUrl, resolvedApiKey.apiKey, task.taskId, format)
|
|
808
1000
|
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
1001
|
+
if (args.output) {
|
|
1002
|
+
const outputPath = await writeOutput(args.output, result)
|
|
1003
|
+
reporter.reportResultWritten(outputPath, format)
|
|
1004
|
+
return
|
|
1005
|
+
}
|
|
812
1006
|
|
|
813
|
-
|
|
1007
|
+
reporter.close()
|
|
1008
|
+
process.stdout.write(result)
|
|
814
1009
|
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
1010
|
+
if (!result.endsWith('\n')) {
|
|
1011
|
+
process.stdout.write('\n')
|
|
1012
|
+
}
|
|
1013
|
+
} catch (error) {
|
|
1014
|
+
if (error instanceof ReportedCliError) {
|
|
1015
|
+
throw error
|
|
1016
|
+
}
|
|
820
1017
|
|
|
821
|
-
|
|
1018
|
+
if (reporter.mode === 'jsonl') {
|
|
1019
|
+
reporter.reportNotice(`执行失败:${error instanceof Error ? error.message : String(error)}`)
|
|
1020
|
+
throw new ReportedCliError('执行失败')
|
|
1021
|
+
}
|
|
822
1022
|
|
|
823
|
-
|
|
824
|
-
process.stdout.write('\n')
|
|
1023
|
+
throw error
|
|
825
1024
|
}
|
|
826
1025
|
}
|
|
827
1026
|
|
|
@@ -848,6 +1047,10 @@ async function main() {
|
|
|
848
1047
|
}
|
|
849
1048
|
|
|
850
1049
|
main().catch((error) => {
|
|
1050
|
+
if (error instanceof ReportedCliError) {
|
|
1051
|
+
process.exit(1)
|
|
1052
|
+
}
|
|
1053
|
+
|
|
851
1054
|
const message = error instanceof Error ? error.message : String(error)
|
|
852
1055
|
fail(`执行失败:${message}`)
|
|
853
1056
|
})
|