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);
}

View File

@@ -0,0 +1,417 @@
#!/bin/bash
# 腾讯云 COS Skill 自动设置脚本
# 用法:
# setup.sh --check-only 仅检查环境状态
# setup.sh --secret-id <ID> --secret-key <KEY> --region <REGION> --bucket <BUCKET> [--dataset <NAME>]
set -e
# 颜色
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'
ok() { echo -e "${GREEN}${NC} $1"; }
fail() { echo -e "${RED}${NC} $1"; }
warn() { echo -e "${YELLOW}!${NC} $1"; }
# 获取脚本所在目录skill baseDir
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
BASE_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
# ========== 检查函数 ==========
check_node() {
if command -v node &>/dev/null; then
ok "Node.js $(node --version)"
return 0
else
fail "Node.js 未安装"
return 1
fi
}
check_npm() {
if command -v npm &>/dev/null; then
ok "npm $(npm --version)"
return 0
else
fail "npm 未安装"
return 1
fi
}
check_mcporter() {
if command -v mcporter &>/dev/null; then
ok "mcporter $(mcporter --version 2>/dev/null || echo '已安装')"
return 0
else
fail "mcporter 未安装"
return 1
fi
}
check_mcporter_config() {
if [ -f ~/.mcporter/mcporter.json ]; then
if grep -q '"cos-mcp"' ~/.mcporter/mcporter.json 2>/dev/null; then
ok "mcporter 已配置 cos-mcp 服务器"
return 0
else
warn "mcporter.json 存在但未配置 cos-mcp"
return 1
fi
else
fail "~/.mcporter/mcporter.json 不存在"
return 1
fi
}
check_cos_mcp() {
if command -v npx &>/dev/null && npx cos-mcp --help &>/dev/null 2>&1; then
ok "cos-mcp 可用"
return 0
else
fail "cos-mcp 未安装或不可用"
return 1
fi
}
check_cos_sdk() {
if node -e "require('cos-nodejs-sdk-v5')" &>/dev/null 2>&1; then
ok "cos-nodejs-sdk-v5 已安装"
return 0
else
fail "cos-nodejs-sdk-v5 未安装"
return 1
fi
}
check_coscmd() {
if command -v coscmd &>/dev/null; then
ok "coscmd 可用"
return 0
else
warn "coscmd 未安装(可选)"
return 1
fi
}
check_env_vars() {
local all_set=true
for var in TENCENT_COS_SECRET_ID TENCENT_COS_SECRET_KEY TENCENT_COS_REGION TENCENT_COS_BUCKET; do
if [ -n "${!var}" ]; then
ok "$var 已设置"
else
fail "$var 未设置"
all_set=false
fi
done
$all_set
}
check_cos_conf() {
if [ -f ~/.cos.conf ]; then
ok "~/.cos.conf 已存在"
return 0
else
warn "~/.cos.conf 不存在"
return 1
fi
}
# ========== 检查模式 ==========
do_check() {
echo "=== 腾讯云 COS Skill 环境检查 ==="
echo ""
echo "--- 基础环境 ---"
check_node || true
check_npm || true
echo ""
echo "--- 方式一: cos-mcp MCP ---"
check_mcporter || true
check_mcporter_config || true
check_cos_mcp || true
echo ""
echo "--- 方式二: Node.js SDK ---"
check_cos_sdk || true
check_env_vars || true
echo ""
echo "--- 方式三: COSCMD ---"
check_coscmd || true
check_cos_conf || true
echo ""
echo "--- Skill 文件 ---"
[ -f "$BASE_DIR/SKILL.md" ] && ok "SKILL.md" || fail "SKILL.md 不存在"
[ -f "$BASE_DIR/scripts/cos_node.mjs" ] && ok "scripts/cos_node.mjs" || fail "scripts/cos_node.mjs 不存在"
[ -f "$BASE_DIR/references/config_template.json" ] && ok "references/config_template.json" || fail "references/config_template.json 不存在"
echo ""
}
# ========== 设置模式 ==========
do_setup() {
local SECRET_ID=""
local SECRET_KEY=""
local REGION=""
local BUCKET=""
local DATASET=""
local DOMAIN=""
local SERVICE_DOMAIN=""
local PROTOCOL=""
while [[ $# -gt 0 ]]; do
case "$1" in
--secret-id) SECRET_ID="$2"; shift 2;;
--secret-key) SECRET_KEY="$2"; shift 2;;
--region) REGION="$2"; shift 2;;
--bucket) BUCKET="$2"; shift 2;;
--dataset) DATASET="$2"; shift 2;;
--domain) DOMAIN="$2"; shift 2;;
--service-domain) SERVICE_DOMAIN="$2"; shift 2;;
--protocol) PROTOCOL="$2"; shift 2;;
*) shift;;
esac
done
if [ -z "$SECRET_ID" ] || [ -z "$SECRET_KEY" ] || [ -z "$REGION" ] || [ -z "$BUCKET" ]; then
echo "错误: 缺少必需参数"
echo "用法: setup.sh --secret-id <ID> --secret-key <KEY> --region <REGION> --bucket <BUCKET> [--dataset <NAME>]"
exit 1
fi
echo "=== 腾讯云 COS Skill 自动设置 ==="
echo ""
# 1. 检查 Node.js
echo "--- 步骤 1: 检查 Node.js ---"
if ! check_node; then
fail "请先安装 Node.js: https://nodejs.org/"
exit 1
fi
# 2. 确保 package.json 存在
echo ""
echo "--- 步骤 2: 初始化项目 ---"
if [ ! -f "$BASE_DIR/package.json" ]; then
(cd "$BASE_DIR" && npm init -y &>/dev/null)
ok "已创建 package.json"
else
ok "package.json 已存在"
fi
# 3. 安装 cos-mcp、cos-nodejs-sdk-v5 和 mcporter
echo ""
echo "--- 步骤 3: 安装依赖 ---"
(cd "$BASE_DIR" && npm install cos-mcp cos-nodejs-sdk-v5 --no-progress 2>&1 | tail -3)
ok "cos-mcp + cos-nodejs-sdk-v5 安装完成"
# 安装 mcporter全局
if ! command -v mcporter &>/dev/null; then
echo "正在安装 mcporter..."
npm install -g mcporter --no-progress 2>&1 | tail -3
if command -v mcporter &>/dev/null; then
ok "mcporter 全局安装完成"
else
warn "mcporter 全局安装失败,尝试本地安装..."
(cd "$BASE_DIR" && npm install mcporter --no-progress 2>&1 | tail -3)
ok "mcporter 本地安装完成(使用 npx mcporter 调用)"
fi
else
ok "mcporter 已安装"
fi
# 4. 写入环境变量到 shell 配置
echo ""
echo "--- 步骤 4: 持久化凭证 ---"
# 判断 shell 配置文件
local SHELL_RC=""
if [ -n "$ZSH_VERSION" ] || [ "$SHELL" = "/bin/zsh" ]; then
SHELL_RC="$HOME/.zshrc"
else
SHELL_RC="$HOME/.bashrc"
fi
# 先清理旧的 COS 配置
if [ -f "$SHELL_RC" ]; then
sed -i.bak '/^# --- Tencent COS Skill ---$/,/^# --- End Tencent COS Skill ---$/d' "$SHELL_RC"
rm -f "${SHELL_RC}.bak"
fi
# 写入新配置
cat >> "$SHELL_RC" << EOF
# --- Tencent COS Skill ---
export TENCENT_COS_SECRET_ID="$SECRET_ID"
export TENCENT_COS_SECRET_KEY="$SECRET_KEY"
export TENCENT_COS_REGION="$REGION"
export TENCENT_COS_BUCKET="$BUCKET"
EOF
if [ -n "$DATASET" ]; then
sed -i.bak '/^# --- End Tencent COS Skill ---$/d' "$SHELL_RC"
rm -f "${SHELL_RC}.bak"
cat >> "$SHELL_RC" << EOF
export TENCENT_COS_DATASET_NAME="$DATASET"
EOF
fi
if [ -n "$DOMAIN" ]; then
sed -i.bak '/^# --- End Tencent COS Skill ---$/d' "$SHELL_RC"
rm -f "${SHELL_RC}.bak"
cat >> "$SHELL_RC" << EOF
export TENCENT_COS_DOMAIN="$DOMAIN"
EOF
fi
if [ -n "$SERVICE_DOMAIN" ]; then
sed -i.bak '/^# --- End Tencent COS Skill ---$/d' "$SHELL_RC"
rm -f "${SHELL_RC}.bak"
cat >> "$SHELL_RC" << EOF
export TENCENT_COS_SERVICE_DOMAIN="$SERVICE_DOMAIN"
EOF
fi
if [ -n "$PROTOCOL" ]; then
sed -i.bak '/^# --- End Tencent COS Skill ---$/d' "$SHELL_RC"
rm -f "${SHELL_RC}.bak"
cat >> "$SHELL_RC" << EOF
export TENCENT_COS_PROTOCOL="$PROTOCOL"
EOF
fi
echo "# --- End Tencent COS Skill ---" >> "$SHELL_RC"
ok "凭证已写入 $SHELL_RC"
# 同时导出到当前 session
export TENCENT_COS_SECRET_ID="$SECRET_ID"
export TENCENT_COS_SECRET_KEY="$SECRET_KEY"
export TENCENT_COS_REGION="$REGION"
export TENCENT_COS_BUCKET="$BUCKET"
[ -n "$DATASET" ] && export TENCENT_COS_DATASET_NAME="$DATASET"
[ -n "$DOMAIN" ] && export TENCENT_COS_DOMAIN="$DOMAIN"
[ -n "$SERVICE_DOMAIN" ] && export TENCENT_COS_SERVICE_DOMAIN="$SERVICE_DOMAIN"
[ -n "$PROTOCOL" ] && export TENCENT_COS_PROTOCOL="$PROTOCOL"
# 5. 配置 mcporter
echo ""
echo "--- 步骤 5: 配置 mcporter ---"
local MCPORTER_DIR="$HOME/.mcporter"
local MCPORTER_CONFIG="$MCPORTER_DIR/mcporter.json"
mkdir -p "$MCPORTER_DIR"
# 构建 cos-mcp 的 args 列表
local COS_MCP_ARGS="\"cos-mcp\", \"--Region=$REGION\", \"--Bucket=$BUCKET\", \"--SecretId=$SECRET_ID\", \"--SecretKey=$SECRET_KEY\""
if [ -n "$DATASET" ]; then
COS_MCP_ARGS="$COS_MCP_ARGS, \"--DatasetName=$DATASET\""
fi
if [ -n "$DOMAIN" ]; then
COS_MCP_ARGS="$COS_MCP_ARGS, \"--Domain=$DOMAIN\""
fi
if [ -n "$SERVICE_DOMAIN" ]; then
COS_MCP_ARGS="$COS_MCP_ARGS, \"--ServiceDomain=$SERVICE_DOMAIN\""
fi
if [ -n "$PROTOCOL" ]; then
COS_MCP_ARGS="$COS_MCP_ARGS, \"--Protocol=$PROTOCOL\""
fi
COS_MCP_ARGS="$COS_MCP_ARGS, \"--connectType=stdio\""
if [ -f "$MCPORTER_CONFIG" ]; then
# 已有配置文件,检查是否已配置 cos-mcp
if grep -q '"cos-mcp"' "$MCPORTER_CONFIG" 2>/dev/null; then
warn "mcporter.json 中已存在 cos-mcp 配置,将更新"
fi
# 使用 node 合并配置(保留其他 MCP 服务器配置)
node -e "
const fs = require('fs');
const configPath = '$MCPORTER_CONFIG';
let config = {};
try { config = JSON.parse(fs.readFileSync(configPath, 'utf-8')); } catch(e) {}
if (!config.mcpServers) config.mcpServers = {};
config.mcpServers['cos-mcp'] = {
command: 'npx',
args: [$COS_MCP_ARGS]
};
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
" 2>/dev/null
ok "mcporter.json 已更新 cos-mcp 配置"
else
# 创建全新的配置文件
cat > "$MCPORTER_CONFIG" << MCPEOF
{
"mcpServers": {
"cos-mcp": {
"command": "npx",
"args": [$COS_MCP_ARGS]
}
}
}
MCPEOF
ok "mcporter.json 已创建"
fi
# 6. 配置 COSCMD如果有 Python
echo ""
echo "--- 步骤 6: 配置 COSCMD可选 ---"
if command -v pip3 &>/dev/null || command -v pip &>/dev/null; then
local PIP_CMD
PIP_CMD=$(command -v pip3 || command -v pip)
$PIP_CMD install coscmd -q 2>/dev/null
# 构建 coscmd config 命令
local COSCMD_ARGS="-a $SECRET_ID -s $SECRET_KEY -b $BUCKET -r $REGION"
if [ -n "$SERVICE_DOMAIN" ]; then
COSCMD_ARGS="$COSCMD_ARGS -e $SERVICE_DOMAIN"
fi
if [ -n "$PROTOCOL" ] && [ "$PROTOCOL" = "http" ]; then
COSCMD_ARGS="$COSCMD_ARGS --do-not-use-ssl"
fi
eval coscmd config $COSCMD_ARGS 2>/dev/null && \
ok "coscmd 已配置" || \
warn "coscmd 安装/配置失败(非关键)"
else
warn "Python/pip 未安装,跳过 coscmd"
fi
# 7. 验证
echo ""
echo "--- 步骤 7: 验证连接 ---"
if (cd "$BASE_DIR" && node scripts/cos_node.mjs list --max-keys 1 2>/dev/null | grep -q '"success": true'); then
ok "COS 连接验证成功"
else
warn "COS 连接验证失败,请检查凭证和网络"
fi
echo ""
echo "=== 设置完成 ==="
echo "现在可以使用以下方式操作 COS"
echo " 方式一: mcporter call cos-mcp.<tool> --config ~/.mcporter/mcporter.json --output json"
echo " 方式一(备选): cos-mcp MCP 工具(通过客户端直接调用)"
echo " 方式二: node $BASE_DIR/scripts/cos_node.mjs <action>"
echo " 方式三: coscmd <command>"
}
# ========== 主入口 ==========
case "$1" in
--check-only)
do_check
;;
--secret-id|--secret-key|--region|--bucket)
do_setup "$@"
;;
*)
echo "腾讯云 COS Skill 设置工具"
echo ""
echo "用法:"
echo " $0 --check-only"
echo " 仅检查环境状态"
echo ""
echo " $0 --secret-id <ID> --secret-key <KEY> --region <REGION> --bucket <BUCKET> [--dataset <NAME>] [--domain <DOMAIN>] [--service-domain <DOMAIN>] [--protocol <PROTOCOL>]"
echo " 自动设置环境(安装依赖 + 配置凭证 + 验证连接)"
;;
esac