feat: 初始化黄小瓜AI助手记忆仓库

- 核心配置: IDENTITY, USER, SOUL, AGENTS, TOOLS, HEARTBEAT, MEMORY
- memory/: 每日总结和临时记录
- skills/: 所有已安装技能
- notes/: 语音配置笔记
This commit is contained in:
root
2026-04-04 02:42:48 +08:00
parent 2d24fe9b50
commit 691b8cdd0c
115 changed files with 18198 additions and 0 deletions

View File

@@ -0,0 +1,323 @@
#!/usr/bin/env node
/**
* 腾讯云 COS Node.js SDK 操作脚本
* 作为 cos-mcp MCP 工具不可用时的降级方案
*
* 依赖npm install cos-nodejs-sdk-v5
* 凭证通过环境变量读取:
* TENCENT_COS_SECRET_ID / TENCENT_COS_SECRET_KEY / TENCENT_COS_REGION / TENCENT_COS_BUCKET
*
* 用法node cos_node.mjs <action> [options]
*/
import { createRequire } from 'module';
import { createReadStream, createWriteStream, existsSync } from 'fs';
import { basename, resolve } from 'path';
import { pipeline } from 'stream/promises';
const require = createRequire(import.meta.url);
const COS = require('cos-nodejs-sdk-v5');
// 读取环境变量
const SecretId = process.env.TENCENT_COS_SECRET_ID;
const SecretKey = process.env.TENCENT_COS_SECRET_KEY;
const Region = process.env.TENCENT_COS_REGION;
const Bucket = process.env.TENCENT_COS_BUCKET;
// 可选的自定义域名配置
const Domain = process.env.TENCENT_COS_DOMAIN;
const ServiceDomain = process.env.TENCENT_COS_SERVICE_DOMAIN;
const Protocol = process.env.TENCENT_COS_PROTOCOL;
if (!SecretId || !SecretKey || !Region || !Bucket) {
console.error(JSON.stringify({
success: false,
error: '缺少环境变量需要TENCENT_COS_SECRET_ID, TENCENT_COS_SECRET_KEY, TENCENT_COS_REGION, TENCENT_COS_BUCKET',
}));
process.exit(1);
}
const cosOptions = { SecretId, SecretKey };
if (Domain) {
cosOptions.Domain = Domain;
}
if (ServiceDomain) {
cosOptions.ServiceDomain = ServiceDomain;
}
if (Protocol) {
cosOptions.Protocol = Protocol;
}
const cos = new COS(cosOptions);
// 解析命令行参数
function parseArgs(args) {
const result = {};
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (arg.startsWith('--')) {
const key = arg.slice(2);
const next = args[i + 1];
if (next && !next.startsWith('--')) {
result[key] = next;
i++;
} else {
result[key] = true;
}
}
}
return result;
}
// 输出 JSON 结果
function output(data) {
console.log(JSON.stringify(data, null, 2));
}
// 封装 COS SDK 回调为 Promise
function cosPromise(method, params) {
return new Promise((resolve, reject) => {
cos[method]({ Bucket, Region, ...params }, (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
// ========== 操作实现 ==========
async function upload(opts) {
const filePath = opts.file;
const key = opts.key || basename(filePath);
if (!filePath) {
throw new Error('缺少 --file 参数');
}
if (!existsSync(filePath)) {
throw new Error(`文件不存在:${filePath}`);
}
const data = await cosPromise('putObject', {
Key: key,
Body: createReadStream(filePath),
});
output({
success: true,
action: 'upload',
key,
etag: data.ETag,
location: data.Location,
statusCode: data.statusCode,
});
}
async function putString(opts) {
const content = opts.content;
const key = opts.key;
const contentType = opts['content-type'] || 'text/plain';
if (!content) {
throw new Error('缺少 --content 参数');
}
if (!key) {
throw new Error('缺少 --key 参数');
}
const data = await cosPromise('putObject', {
Key: key,
Body: content,
ContentType: contentType,
});
output({
success: true,
action: 'put-string',
key,
etag: data.ETag,
location: data.Location,
statusCode: data.statusCode,
});
}
async function download(opts) {
const key = opts.key;
const outputPath = opts.output || basename(key);
if (!key) {
throw new Error('缺少 --key 参数');
}
const data = await cosPromise('getObject', {
Key: key,
});
const resolvedPath = resolve(outputPath);
const ws = createWriteStream(resolvedPath);
if (data.Body instanceof Buffer) {
ws.write(data.Body);
ws.end();
} else if (data.Body && typeof data.Body.pipe === 'function') {
await pipeline(data.Body, ws);
} else {
ws.write(String(data.Body));
ws.end();
}
output({
success: true,
action: 'download',
key,
savedTo: resolvedPath,
contentLength: data.headers?.['content-length'],
statusCode: data.statusCode,
});
}
async function list(opts) {
const prefix = opts.prefix || '';
const maxKeys = parseInt(opts['max-keys'], 10) || 100;
const data = await cosPromise('getBucket', {
Prefix: prefix,
MaxKeys: maxKeys,
});
const files = (data.Contents || []).map(item => ({
key: item.Key,
size: parseInt(item.Size, 10),
lastModified: item.LastModified,
etag: item.ETag,
storageClass: item.StorageClass,
}));
output({
success: true,
action: 'list',
prefix,
count: files.length,
isTruncated: data.IsTruncated === 'true',
files,
});
}
async function signUrl(opts) {
const key = opts.key;
const expires = parseInt(opts.expires, 10) || 3600;
if (!key) {
throw new Error('缺少 --key 参数');
}
const url = await new Promise((resolve, reject) => {
cos.getObjectUrl({
Bucket,
Region,
Key: key,
Expires: expires,
Sign: true,
}, (err, data) => {
if (err) {
reject(err);
} else {
resolve(data.Url);
}
});
});
output({
success: true,
action: 'sign-url',
key,
expires,
url,
});
}
async function deleteObject(opts) {
const key = opts.key;
if (!key) {
throw new Error('缺少 --key 参数');
}
const data = await cosPromise('deleteObject', {
Key: key,
});
output({
success: true,
action: 'delete',
key,
statusCode: data.statusCode,
});
}
async function head(opts) {
const key = opts.key;
if (!key) {
throw new Error('缺少 --key 参数');
}
const data = await cosPromise('headObject', {
Key: key,
});
output({
success: true,
action: 'head',
key,
contentLength: parseInt(data.headers?.['content-length'], 10),
contentType: data.headers?.['content-type'],
etag: data.headers?.etag,
lastModified: data.headers?.['last-modified'],
storageClass: data.headers?.['x-cos-storage-class'] || 'STANDARD',
statusCode: data.statusCode,
});
}
// ========== 主入口 ==========
const args = process.argv.slice(2);
const action = args[0];
const opts = parseArgs(args.slice(1));
const actions = {
upload,
'put-string': putString,
download,
list,
'sign-url': signUrl,
delete: deleteObject,
head,
};
if (!action || !actions[action]) {
output({
success: false,
error: `未知操作:${action || '(空)'}`,
availableActions: Object.keys(actions),
usage: 'node cos_node.mjs <action> [--option value ...]',
});
process.exit(1);
}
try {
await actions[action](opts);
} catch (err) {
output({
success: false,
action,
error: err.message || String(err),
code: err.code,
});
process.exit(1);
}