SnowCat 雪猫底层全源码:NapCat 4.18.28 底座 + SnowLuma 能力移植 + V8 通道适配 9.9.37

26 包 monorepo(TS 全源码):
- snowcat-core: NT 内核 API 封装 + listener(含 9.9.37 六回调适配)+ Packet 发包
- snowcat-onebot: OneBot v11 全动作 + MCP Streamable HTTP 适配器 + 稳定线
- snowcat-webui-frontend/backend: 雪猫控制台(React+HeroUI)
- snowcat-shell: 单文件 bundle 出口(vite inlineDynamicImports)
- snowcat-native: napi2native / MoeHoo / ffmpeg / pty 运行时
- 56 项 SnowLuma 独门动作移植(qzone 全家桶/群相册/装扮/闪照/收藏)
- 工具件: 解包器/启动器/便携制作器/doctor

GitHub 关联已全量指向 DandanLLab/SnowCatQQ
This commit is contained in:
天天的鸟蛋蛋 committed 2026-11-12 06:27:36 +08:00
commit b9655a5ab1
1048 files changed
+130851

No files matched your search

+91
View File
@@ -0,0 +1,91 @@
import { OB11MessageData } from '@/snowcat-onebot/types';
const pattern = /\[CQ:(\w+)((,\w+=[^,\]]*)*)]/;
function unescape (source: string) {
return String(source)
.replace(/[/g, '[')
.replace(/]/g, ']')
.replace(/,/g, ',')
.replace(/&/g, '&');
}
function from (source: string) {
const capture = pattern.exec(source);
if (!capture) return null;
const [, type, attrs] = capture;
const data: Record<string, unknown> = {};
if (attrs) {
attrs.slice(1).split(',').forEach((str) => {
const index = str.indexOf('=');
data[str.slice(0, index)] = unescape(str.slice(index + 1));
});
}
return { type, data, capture };
}
function convert (type: string, data: unknown) {
return {
type,
data,
};
}
export function decodeCQCode (source: string): OB11MessageData[] {
const elements: Array<unknown> = [];
let result: ReturnType<typeof from>;
while ((result = from(source))) {
const { type, data, capture } = result;
if (type) {
if (capture.index) {
elements.push(convert('text', { text: unescape(source.slice(0, capture.index)) }));
}
elements.push(convert(type, data));
source = source.slice(capture.index + capture[0].length);
}
}
if (source) elements.push(convert('text', { text: unescape(source) }));
return elements as OB11MessageData[];
}
function CQCodeEscapeText (text: string) {
return text.replace(/&/g, '&amp;')
.replace(/\[/g, '&#91;')
.replace(/]/g, '&#93;');
}
function CQCodeEscape (text: string) {
return text.replace(/&/g, '&amp;')
.replace(/\[/g, '&#91;')
.replace(/]/g, '&#93;')
.replace(/,/g, '&#44;');
}
export function encodeCQCode (data: OB11MessageData) {
if (data.type === 'text') {
return CQCodeEscapeText(data.data.text);
}
let result = '[CQ:' + data.type;
for (const name in data.data) {
const value = (data.data as Record<string, unknown>)[name];
if (value === undefined) {
continue;
}
try {
let text: string | undefined;
if (typeof value === 'object' && value?.toString === Object.prototype.toString) {
text = JSON.stringify(value);
} else {
text = value?.toString();
}
if (text) {
result += `,${name}=${CQCodeEscape(text)}`;
}
} catch (error) {
console.error(`Error encoding CQCode for ${name}:`, error);
}
}
result += ']';
return result;
}