first commit

This commit is contained in:
douboer
2026-03-21 18:57:10 +08:00
commit c49aa1a5e9
570 changed files with 107167 additions and 0 deletions

View File

@@ -0,0 +1,123 @@
import { describe, expect, it } from "vitest";
const {
buildSpeakableTerminalText,
isSpeakableTextLikelyComplete,
splitSpeakableTextForTts,
stripTerminalAnsi
} = require("./terminalSpeakableText.js");
describe("terminalSpeakableText", () => {
it("应提取最近一段自然语言并跳过命令与代码", () => {
const source = [
"$ codex ask",
"正在分析项目结构...",
"const answer = computeResult();",
"",
"请先检查 gateway 的环境变量配置。",
"确认 TTS_SECRET_ID、TTS_SECRET_KEY 与 TTS_REGION 是否一致。"
].join("\n");
expect(buildSpeakableTerminalText(source)).toBe(
"请先检查 gateway 的环境变量配置。确认 TTS_SECRET_ID、TTS_SECRET_KEY 与 TTS_REGION 是否一致。"
);
});
it("只有命令、路径和进度条时应返回空文本", () => {
const source = [
"$ npm run build",
"/Users/demo/project/src/index.ts",
"[====== ] 60%",
"spinner loading"
].join("\n");
expect(buildSpeakableTerminalText(source)).toBe("");
});
it("应跳过 Codex 输入行、状态行与底部 footer只保留回答正文", () => {
const source = [
" Summarize recent commits",
"Working (0s · esc to interrupt)",
"■ Conversation interrupted - tell the model what to do differently.",
"Something went wrong? Hit `/feedback` to report the issue.",
"本次修改主要收口了 TTS 播放链路。",
"同时移除了小程序侧重复下载缓存文件的绕路实现。",
"gpt-5.4 xhigh · 100% left · ~/remoteconn"
].join("\n");
expect(buildSpeakableTerminalText(source)).toBe(
"本次修改主要收口了 TTS 播放链路。同时移除了小程序侧重复下载缓存文件的绕路实现。"
);
});
it("应跳过被终端换行拆开的 footer 残片", () => {
const source = [
"本次修改已经完成。",
"42% left · ~/remoteconn"
].join("\n");
expect(buildSpeakableTerminalText(source)).toBe("本次修改已经完成。");
});
it("应去掉列表项目符号,避免 TTS 在首句前卡住", () => {
const source = [
"• 第一条消息。",
" 第二条消息。",
" 第三条消息。",
" 第四条消息。"
].join("\n");
expect(buildSpeakableTerminalText(source)).toBe("第一条消息。第二条消息。第三条消息。第四条消息。");
});
it("应去掉紧贴正文的项目符号前缀", () => {
const source = ["•第一条消息。", "•第二条消息。"].join("\n");
expect(buildSpeakableTerminalText(source)).toBe("第一条消息。第二条消息。");
});
it("中间夹杂代码块时应继续向上回收同轮正文,而不是只读最后一小段", () => {
const source = [
"第一段说明,先交代修复背景。",
"第二段说明,描述影响范围。",
"```ts",
"const demo = true;",
"```",
"第三段说明,给出处理方式。",
"第四段说明,提醒重启服务。"
].join("\n");
expect(buildSpeakableTerminalText(source, { maxChars: 200 })).toBe(
"第一段说明,先交代修复背景。第二段说明,描述影响范围。第三段说明,给出处理方式。第四段说明,提醒重启服务。"
);
});
it("长中文文本应保留到总量配置上限,并支持后续分段", () => {
const source = "这是一个较长的测试输出。".repeat(40);
const result = buildSpeakableTerminalText(source);
const segments = splitSpeakableTextForTts(result);
expect(Buffer.byteLength(result, "utf8")).toBeLessThanOrEqual(1500);
expect(result.length).toBeLessThanOrEqual(500);
expect(result.length).toBeGreaterThan(0);
expect(segments.length).toBeGreaterThan(1);
segments.forEach((segment: string) => {
expect(Buffer.byteLength(segment, "utf8")).toBeLessThanOrEqual(240);
expect(segment.length).toBeLessThanOrEqual(80);
});
});
it("应支持按自定义总长度提取正文", () => {
const source = "这是一个较长的测试输出。".repeat(40);
const result = buildSpeakableTerminalText(source, { maxChars: 120 });
expect(result.length).toBeLessThanOrEqual(120);
expect(Buffer.byteLength(result, "utf8")).toBeLessThanOrEqual(360);
});
it("应支持去除 ANSI 并判断句子是否收束", () => {
expect(stripTerminalAnsi("\u001b[32m请先检查配置。\u001b[0m")).toBe("请先检查配置。");
expect(isSpeakableTextLikelyComplete("请先检查配置。")).toBe(true);
expect(isSpeakableTextLikelyComplete("请先检查配置")).toBe(false);
});
});