initial: 七牛云上传 OpenClaw Skill

功能特性:
- 支持 /upload, /u 命令上传文件到七牛云
- 支持 /qiniu-config 配置管理
- 支持飞书卡片交互
- 支持指定上传路径和存储桶
- 自动刷新 CDN 缓存
- 支持文件覆盖上传

包含组件:
- OpenClaw 处理器 (openclaw-processor.js)
- 独立监听器 (scripts/feishu-listener.js)
- 核心上传脚本 (scripts/upload-to-qiniu.js)
- 部署脚本 (deploy.sh)
- 完整文档

部署方式:
1. 复制 skill 到 ~/.openclaw/workspace/skills/
2. 配置 ~/.openclaw/credentials/qiniu-config.json
3. 重启 OpenClaw Gateway
This commit is contained in:
daoqi
2026-03-07 16:02:18 +08:00
commit 1aeae9cc51
36 changed files with 6826 additions and 0 deletions

83
test-feishu-upload.js Normal file
View File

@@ -0,0 +1,83 @@
#!/usr/bin/env node
/**
* 模拟飞书上传测试
*/
const { exec } = require('child_process');
const path = require('path');
const CONFIG = {
scriptDir: __dirname,
tempFile: path.join(__dirname, 'test-file.txt'),
tempFileV2: path.join(__dirname, 'test-file-v2.txt')
};
async function testUpload(targetKey, file) {
return new Promise((resolve, reject) => {
const uploadScript = path.join(CONFIG.scriptDir, 'scripts/upload-to-qiniu.js');
const cmd = `node "${uploadScript}" upload --file "${file}" --key "${targetKey}" --bucket default`;
console.log(`\n📤 测试上传:`);
console.log(` 文件:${file}`);
console.log(` 目标 key: ${targetKey}`);
console.log(` 命令:${cmd}\n`);
exec(cmd, (error, stdout, stderr) => {
if (error) {
console.log('❌ 上传失败:', stderr || error.message);
resolve({ success: false, error: stderr || error.message });
} else {
console.log('✅ 上传成功:');
console.log(stdout);
resolve({ success: true, output: stdout });
}
});
});
}
async function main() {
console.log('═══════════════════════════════════════════════════════════');
console.log('🧪 七牛云覆盖上传测试 - 模拟飞书流程');
console.log('═══════════════════════════════════════════════════════════\n');
const testKey = 'feishu-test/override-file.txt';
// 第一次上传
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
console.log('第 1 次上传(新增)');
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
const result1 = await testUpload(testKey, CONFIG.tempFile);
if (!result1.success) {
console.log('\n❌ 第一次上传失败,测试终止');
process.exit(1);
}
// 等待 2 秒
await new Promise(r => setTimeout(r, 2000));
// 第二次上传(覆盖)
console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
console.log('第 2 次上传(覆盖测试)');
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
const result2 = await testUpload(testKey, CONFIG.tempFileV2);
if (!result2.success) {
console.log('\n❌ 覆盖上传失败!');
console.log('问题scope 参数可能没有包含 key');
process.exit(1);
}
// 验证内容
console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
console.log('✅ 覆盖上传成功!');
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
console.log('📋 测试总结:');
console.log(' 第 1 次上传:✅ 成功');
console.log(' 第 2 次上传:✅ 成功(已覆盖)');
console.log('\n结论覆盖上传功能正常工作');
}
main().catch(console.error);