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 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"}
@@ -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"}