feat: 初始化黄小瓜AI助手记忆仓库
- 核心配置: IDENTITY, USER, SOUL, AGENTS, TOOLS, HEARTBEAT, MEMORY - memory/: 每日总结和临时记录 - skills/: 所有已安装技能 - notes/: 语音配置笔记
This commit is contained in:
323
skills/tencent-cos-skill/scripts/cos_node.mjs
Normal file
323
skills/tencent-cos-skill/scripts/cos_node.mjs
Normal 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);
|
||||
}
|
||||
417
skills/tencent-cos-skill/scripts/setup.sh
Normal file
417
skills/tencent-cos-skill/scripts/setup.sh
Normal 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
|
||||
Reference in New Issue
Block a user