clawvif 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +120 -0
- package/dist/file-store-Cp6U-dO6.mjs +98 -0
- package/dist/file-store-Cp6U-dO6.mjs.map +1 -0
- package/dist/index.d.mts +35 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +1538 -0
- package/dist/index.mjs.map +1 -0
- package/openclaw.plugin.json +42 -0
- package/package.json +70 -0
- package/skills/clawvif/alert-dispatcher/SKILL.md +40 -0
- package/skills/clawvif/audit-logger/SKILL.md +41 -0
- package/skills/clawvif/onchain-monitor/SKILL.md +86 -0
- package/skills/clawvif/onchain-monitor/references/alert-format.md +47 -0
- package/skills/clawvif/sentiment-radar/SKILL.md +65 -0
- package/skills/clawvif/sentiment-radar/references/scoring.md +38 -0
- package/skills/clawvif/tg-group-scanner/SKILL.md +65 -0
- package/skills/clawvif/whale-tracker/SKILL.md +75 -0
- package/workspace/SOUL.md +22 -0
- package/workspace/USER.md +18 -0
- package/workspace/config/alert-rules.json +37 -0
- package/workspace/config/kol-list.json +3 -0
- package/workspace/config/tg-groups.json +3 -0
- package/workspace/config/watchlist.json +3 -0
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Clawvif
|
|
2
|
+
|
|
3
|
+
**基于 OpenClaw 架构的 Web3 行情分析与市场情报 AI Agent**
|
|
4
|
+
|
|
5
|
+
> "Vif"(法语:敏锐、迅捷)— 敏锐的数据嗅觉 + 多源信号聚合
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 特性
|
|
10
|
+
|
|
11
|
+
- 📡 **Telegram 监听** — Bot API 实时监听群组/频道消息,自动提取 alpha call 和合约地址
|
|
12
|
+
- 📊 **情绪雷达** — 聚合 Twitter/Telegram/Discord 社媒情绪信号
|
|
13
|
+
- 🐋 **鲸鱼追踪** — 大额异动检测、地址行为画像、积累/派发模式识别
|
|
14
|
+
- 🔗 **链上监控** — 实时追踪大额转账、新流动性池、聪明钱活动(可选启用)
|
|
15
|
+
- 🔔 **告警分发** — 多级别告警推送,去重、批量、历史查询
|
|
16
|
+
- 📋 **审计日志** — 所有操作不可篡改记录
|
|
17
|
+
|
|
18
|
+
## 架构
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
22
|
+
│ OpenClaw Gateway │
|
|
23
|
+
│ Telegram / Discord / WebChat / CLI │
|
|
24
|
+
└──────────────────────────────┬───────────────────────────────┘
|
|
25
|
+
│
|
|
26
|
+
▼
|
|
27
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
28
|
+
│ Clawvif Agent Runtime (推理引擎) │
|
|
29
|
+
│ ReAct Reasoning Loop (OpenClaw) │
|
|
30
|
+
│ Reason → Act (call tool/skill) → Observe → Repeat │
|
|
31
|
+
└──────────────────────────────┬───────────────────────────────┘
|
|
32
|
+
│
|
|
33
|
+
▼
|
|
34
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
35
|
+
│ Clawvif Skills & Tools │
|
|
36
|
+
│ ┌──────────────┐ ┌──────────────┐ ┌───────────────────┐ │
|
|
37
|
+
│ │ Intel Skills │ │ TG Skills │ │ Infra Skills │ │
|
|
38
|
+
│ │• sentiment- │ │• tg-group- │ │• audit-logger │ │
|
|
39
|
+
│ │ radar │ │ scanner │ │• alert-dispatcher │ │
|
|
40
|
+
│ │• onchain- │ │• tg-listener │ │ │ │
|
|
41
|
+
│ │ monitor │ │ │ │ │ │
|
|
42
|
+
│ │• whale- │ │ │ │ │ │
|
|
43
|
+
│ │ tracker │ │ │ │ │ │
|
|
44
|
+
│ └──────────────┘ └──────────────┘ └───────────────────┘ │
|
|
45
|
+
└──────────────────────────────────────────────────────────────┘
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 快速开始
|
|
49
|
+
|
|
50
|
+
### 前置要求
|
|
51
|
+
|
|
52
|
+
- Node.js 22+
|
|
53
|
+
- pnpm
|
|
54
|
+
- OpenClaw (`npm install -g openclaw@latest`)
|
|
55
|
+
|
|
56
|
+
### 安装
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# 1. 克隆仓库
|
|
60
|
+
git clone https://github.com/luka2chat/clawvif.git
|
|
61
|
+
cd clawvif
|
|
62
|
+
|
|
63
|
+
# 2. 安装依赖
|
|
64
|
+
pnpm install
|
|
65
|
+
|
|
66
|
+
# 3. 配置环境变量
|
|
67
|
+
cp .env.example .env
|
|
68
|
+
# 编辑 .env 填入 Bot Token
|
|
69
|
+
|
|
70
|
+
# 4. 启动
|
|
71
|
+
openclaw gateway start
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Telegram Bot 配置
|
|
75
|
+
|
|
76
|
+
1. 在 Telegram 找 `@BotFather`,发送 `/newbot`,按提示创建 bot
|
|
77
|
+
2. 复制 bot token 到 `.env` 的 `TG_BOT_TOKEN=`
|
|
78
|
+
3. 把 bot 拉进你想监听的群组/频道,设为管理员
|
|
79
|
+
|
|
80
|
+
插件启动后会自动连接 Telegram 并开始监听消息。
|
|
81
|
+
|
|
82
|
+
## 命令
|
|
83
|
+
|
|
84
|
+
### 信息查询
|
|
85
|
+
|
|
86
|
+
| 命令 | 说明 |
|
|
87
|
+
|------|------|
|
|
88
|
+
| `情绪 BTC` / `sentiment BTC` | 代币情绪分析 |
|
|
89
|
+
| `聪明钱` / `whales` | 近期鲸鱼动态 |
|
|
90
|
+
| `日报` / `daily` | 当日市场摘要 |
|
|
91
|
+
|
|
92
|
+
### Telegram 监听
|
|
93
|
+
|
|
94
|
+
| 命令 | 说明 |
|
|
95
|
+
|------|------|
|
|
96
|
+
| `TG 监听状态` | 查看监听服务状态 |
|
|
97
|
+
| `启动 TG 监听` | 手动启动监听 |
|
|
98
|
+
| `停止 TG 监听` | 停止监听 |
|
|
99
|
+
|
|
100
|
+
### 系统管理
|
|
101
|
+
|
|
102
|
+
| 命令 | 说明 |
|
|
103
|
+
|------|------|
|
|
104
|
+
| `监控 0x... 标签:XXX` | 添加监控地址 |
|
|
105
|
+
| `状态` / `status` | 系统健康检查 |
|
|
106
|
+
|
|
107
|
+
## 开发
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
pnpm install # 安装依赖
|
|
111
|
+
pnpm build # 构建插件
|
|
112
|
+
pnpm test # 运行测试
|
|
113
|
+
pnpm typecheck # 类型检查
|
|
114
|
+
pnpm lint # 代码检查
|
|
115
|
+
pnpm dev # 开发模式 (watch)
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## License
|
|
119
|
+
|
|
120
|
+
MIT
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { dirname } from "node:path";
|
|
2
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
//#region \0rolldown/runtime.js
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __exportAll = (all, no_symbols) => {
|
|
6
|
+
let target = {};
|
|
7
|
+
for (var name in all) __defProp(target, name, {
|
|
8
|
+
get: all[name],
|
|
9
|
+
enumerable: true
|
|
10
|
+
});
|
|
11
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
12
|
+
return target;
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/lib/file-store.ts
|
|
16
|
+
/**
|
|
17
|
+
* File storage utilities for Clawvif.
|
|
18
|
+
*
|
|
19
|
+
* Provides helpers for reading/writing JSON and JSONL files,
|
|
20
|
+
* following OpenClaw's local-first, file-based memory philosophy.
|
|
21
|
+
*/
|
|
22
|
+
var file_store_exports = /* @__PURE__ */ __exportAll({
|
|
23
|
+
appendJsonl: () => appendJsonl,
|
|
24
|
+
ensureDir: () => ensureDir,
|
|
25
|
+
ensureParentDir: () => ensureParentDir,
|
|
26
|
+
readJson: () => readJson,
|
|
27
|
+
readJsonOr: () => readJsonOr,
|
|
28
|
+
readJsonl: () => readJsonl,
|
|
29
|
+
readJsonlTail: () => readJsonlTail,
|
|
30
|
+
writeJson: () => writeJson
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* Ensure a directory exists, creating it recursively if needed.
|
|
34
|
+
*/
|
|
35
|
+
function ensureDir(dirPath) {
|
|
36
|
+
if (!existsSync(dirPath)) mkdirSync(dirPath, { recursive: true });
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Ensure the parent directory of a file path exists.
|
|
40
|
+
*/
|
|
41
|
+
function ensureParentDir(filePath) {
|
|
42
|
+
ensureDir(dirname(filePath));
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Read and parse a JSON file.
|
|
46
|
+
*
|
|
47
|
+
* @param filePath - Absolute path to JSON file
|
|
48
|
+
* @returns Parsed JSON content
|
|
49
|
+
* @throws If file doesn't exist or contains invalid JSON
|
|
50
|
+
*/
|
|
51
|
+
function readJson(filePath) {
|
|
52
|
+
const content = readFileSync(filePath, "utf-8");
|
|
53
|
+
return JSON.parse(content);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Read a JSON file, returning a default value if the file doesn't exist.
|
|
57
|
+
*/
|
|
58
|
+
function readJsonOr(filePath, defaultValue) {
|
|
59
|
+
if (!existsSync(filePath)) return defaultValue;
|
|
60
|
+
return readJson(filePath);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Write data as formatted JSON to a file.
|
|
64
|
+
* Creates parent directories if they don't exist.
|
|
65
|
+
*/
|
|
66
|
+
function writeJson(filePath, data) {
|
|
67
|
+
ensureParentDir(filePath);
|
|
68
|
+
writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Append a single entry to a JSONL (JSON Lines) file.
|
|
72
|
+
* Each entry is written as one JSON object per line.
|
|
73
|
+
* Creates parent directories if they don't exist.
|
|
74
|
+
*/
|
|
75
|
+
function appendJsonl(filePath, entry) {
|
|
76
|
+
ensureParentDir(filePath);
|
|
77
|
+
appendFileSync(filePath, JSON.stringify(entry) + "\n", "utf-8");
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Read all entries from a JSONL file.
|
|
81
|
+
*
|
|
82
|
+
* @param filePath - Absolute path to JSONL file
|
|
83
|
+
* @returns Array of parsed entries
|
|
84
|
+
*/
|
|
85
|
+
function readJsonl(filePath) {
|
|
86
|
+
if (!existsSync(filePath)) return [];
|
|
87
|
+
return readFileSync(filePath, "utf-8").split("\n").filter((line) => line.trim().length > 0).map((line) => JSON.parse(line));
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Read the last N entries from a JSONL file (most recent first).
|
|
91
|
+
*/
|
|
92
|
+
function readJsonlTail(filePath, count) {
|
|
93
|
+
return readJsonl(filePath).slice(-count).reverse();
|
|
94
|
+
}
|
|
95
|
+
//#endregion
|
|
96
|
+
export { readJsonl as a, readJsonOr as i, ensureDir as n, readJsonlTail as o, file_store_exports as r, writeJson as s, appendJsonl as t };
|
|
97
|
+
|
|
98
|
+
//# sourceMappingURL=file-store-Cp6U-dO6.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-store-Cp6U-dO6.mjs","names":[],"sources":["../src/lib/file-store.ts"],"sourcesContent":["/**\n * File storage utilities for Clawvif.\n *\n * Provides helpers for reading/writing JSON and JSONL files,\n * following OpenClaw's local-first, file-based memory philosophy.\n */\n\nimport { readFileSync, writeFileSync, appendFileSync, existsSync, mkdirSync } from 'node:fs';\nimport { dirname } from 'node:path';\n\n/**\n * Ensure a directory exists, creating it recursively if needed.\n */\nexport function ensureDir(dirPath: string): void {\n if (!existsSync(dirPath)) {\n mkdirSync(dirPath, { recursive: true });\n }\n}\n\n/**\n * Ensure the parent directory of a file path exists.\n */\nexport function ensureParentDir(filePath: string): void {\n ensureDir(dirname(filePath));\n}\n\n/**\n * Read and parse a JSON file.\n *\n * @param filePath - Absolute path to JSON file\n * @returns Parsed JSON content\n * @throws If file doesn't exist or contains invalid JSON\n */\nexport function readJson<T>(filePath: string): T {\n const content = readFileSync(filePath, 'utf-8');\n return JSON.parse(content) as T;\n}\n\n/**\n * Read a JSON file, returning a default value if the file doesn't exist.\n */\nexport function readJsonOr<T>(filePath: string, defaultValue: T): T {\n if (!existsSync(filePath)) {\n return defaultValue;\n }\n return readJson<T>(filePath);\n}\n\n/**\n * Write data as formatted JSON to a file.\n * Creates parent directories if they don't exist.\n */\nexport function writeJson(filePath: string, data: unknown): void {\n ensureParentDir(filePath);\n writeFileSync(filePath, JSON.stringify(data, null, 2) + '\\n', 'utf-8');\n}\n\n/**\n * Append a single entry to a JSONL (JSON Lines) file.\n * Each entry is written as one JSON object per line.\n * Creates parent directories if they don't exist.\n */\nexport function appendJsonl(filePath: string, entry: unknown): void {\n ensureParentDir(filePath);\n appendFileSync(filePath, JSON.stringify(entry) + '\\n', 'utf-8');\n}\n\n/**\n * Read all entries from a JSONL file.\n *\n * @param filePath - Absolute path to JSONL file\n * @returns Array of parsed entries\n */\nexport function readJsonl<T>(filePath: string): T[] {\n if (!existsSync(filePath)) {\n return [];\n }\n const content = readFileSync(filePath, 'utf-8');\n return content\n .split('\\n')\n .filter((line) => line.trim().length > 0)\n .map((line) => JSON.parse(line) as T);\n}\n\n/**\n * Read the last N entries from a JSONL file (most recent first).\n */\nexport function readJsonlTail<T>(filePath: string, count: number): T[] {\n const all = readJsonl<T>(filePath);\n return all.slice(-count).reverse();\n}\n\n/**\n * Check if a file exists.\n */\nexport function fileExists(filePath: string): boolean {\n return existsSync(filePath);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAaA,SAAgB,UAAU,SAAuB;AAC/C,KAAI,CAAC,WAAW,QAAQ,CACtB,WAAU,SAAS,EAAE,WAAW,MAAM,CAAC;;;;;AAO3C,SAAgB,gBAAgB,UAAwB;AACtD,WAAU,QAAQ,SAAS,CAAC;;;;;;;;;AAU9B,SAAgB,SAAY,UAAqB;CAC/C,MAAM,UAAU,aAAa,UAAU,QAAQ;AAC/C,QAAO,KAAK,MAAM,QAAQ;;;;;AAM5B,SAAgB,WAAc,UAAkB,cAAoB;AAClE,KAAI,CAAC,WAAW,SAAS,CACvB,QAAO;AAET,QAAO,SAAY,SAAS;;;;;;AAO9B,SAAgB,UAAU,UAAkB,MAAqB;AAC/D,iBAAgB,SAAS;AACzB,eAAc,UAAU,KAAK,UAAU,MAAM,MAAM,EAAE,GAAG,MAAM,QAAQ;;;;;;;AAQxE,SAAgB,YAAY,UAAkB,OAAsB;AAClE,iBAAgB,SAAS;AACzB,gBAAe,UAAU,KAAK,UAAU,MAAM,GAAG,MAAM,QAAQ;;;;;;;;AASjE,SAAgB,UAAa,UAAuB;AAClD,KAAI,CAAC,WAAW,SAAS,CACvB,QAAO,EAAE;AAGX,QADgB,aAAa,UAAU,QAAQ,CAE5C,MAAM,KAAK,CACX,QAAQ,SAAS,KAAK,MAAM,CAAC,SAAS,EAAE,CACxC,KAAK,SAAS,KAAK,MAAM,KAAK,CAAM;;;;;AAMzC,SAAgB,cAAiB,UAAkB,OAAoB;AAErE,QADY,UAAa,SAAS,CACvB,MAAM,CAAC,MAAM,CAAC,SAAS"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/index.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Clawvif — OpenClaw Plugin Entry Point
|
|
4
|
+
*
|
|
5
|
+
* This is the main entry point loaded by OpenClaw's plugin system via jiti.
|
|
6
|
+
* It registers all Clawvif tools that the agent can invoke.
|
|
7
|
+
*
|
|
8
|
+
* IMPORTANT: This default export function must be SYNCHRONOUS.
|
|
9
|
+
* OpenClaw's plugin loader ignores async activate functions.
|
|
10
|
+
*/
|
|
11
|
+
/** OpenClaw Plugin API (minimal typing) */
|
|
12
|
+
interface OpenClawPluginApi {
|
|
13
|
+
registerTool(config: {
|
|
14
|
+
name: string;
|
|
15
|
+
description: string;
|
|
16
|
+
parameters: unknown;
|
|
17
|
+
execute: (id: string, params: Record<string, unknown>) => Promise<{
|
|
18
|
+
content: Array<{
|
|
19
|
+
type: string;
|
|
20
|
+
text: string;
|
|
21
|
+
}>;
|
|
22
|
+
}>;
|
|
23
|
+
}, options?: {
|
|
24
|
+
optional?: boolean;
|
|
25
|
+
}): void;
|
|
26
|
+
/** Plugin-specific config from openclaw.json plugins.entries.<id>.config */
|
|
27
|
+
pluginConfig?: Record<string, unknown>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Plugin entry — called synchronously by OpenClaw at load time.
|
|
31
|
+
*/
|
|
32
|
+
declare function clawvifPlugin(api: OpenClawPluginApi): void;
|
|
33
|
+
//#endregion
|
|
34
|
+
export { clawvifPlugin as default };
|
|
35
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;;UAuBU,iBAAA;EACR,YAAA,CAAa,MAAA;IACX,IAAA;IACA,WAAA;IACA,UAAA;IACA,OAAA,GAAU,EAAA,UAAY,MAAA,EAAQ,MAAA,sBAA4B,OAAA;MACxD,OAAA,EAAS,KAAA;QAAQ,IAAA;QAAc,IAAA;MAAA;IAAA;EAAA,GAEhC,OAAA;IAAY,QAAA;EAAA;EAAA;EAGf,YAAA,GAAe,MAAA;AAAA;;;;iBAMO,aAAA,CAAc,GAAA,EAAK,iBAAA"}
|