clawchain-wallet 1.0.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/SKILL.md +243 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +89 -0
- package/dist/src/executor.d.ts +23 -0
- package/dist/src/executor.js +65 -0
- package/dist/src/tools.d.ts +41 -0
- package/dist/src/tools.js +528 -0
- package/dist/src/types.d.ts +40 -0
- package/dist/src/types.js +4 -0
- package/index.ts +103 -0
- package/openclaw.plugin.json +16 -0
- package/package.json +76 -0
- package/python/clawchain_cli.py +1193 -0
- package/python/requirements.txt +2 -0
- package/scripts/postinstall.js +243 -0
- package/src/executor.ts +88 -0
- package/src/tools.ts +623 -0
- package/src/types.ts +45 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* ClawChain Wallet postinstall 脚本
|
|
4
|
+
*
|
|
5
|
+
* 自动完成以下任务:
|
|
6
|
+
* 1. 检测 Python 环境
|
|
7
|
+
* 2. 安装 Python 依赖 (web3, eth-account)
|
|
8
|
+
* 3. 编译 TypeScript
|
|
9
|
+
* 4. 注册到 OpenClaw(如果可用)
|
|
10
|
+
*
|
|
11
|
+
* 支持:
|
|
12
|
+
* - npm install(本地安装)
|
|
13
|
+
* - npm install -g(全局安装)
|
|
14
|
+
* - npx 直接执行
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { execSync, spawnSync } from "node:child_process";
|
|
18
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
19
|
+
import { dirname, join, resolve } from "node:path";
|
|
20
|
+
import { fileURLToPath } from "node:url";
|
|
21
|
+
|
|
22
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
23
|
+
const __dirname = dirname(__filename);
|
|
24
|
+
const rootDir = resolve(join(__dirname, ".."));
|
|
25
|
+
|
|
26
|
+
// 检测是否在 CI 环境或 npm 生命周期中跳过
|
|
27
|
+
if (process.env.CI || process.env.SKIP_POSTINSTALL) {
|
|
28
|
+
console.log("跳过 postinstall(CI 环境或 SKIP_POSTINSTALL 设置)");
|
|
29
|
+
process.exit(0);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 颜色输出
|
|
33
|
+
const colors = {
|
|
34
|
+
reset: "\x1b[0m",
|
|
35
|
+
green: "\x1b[32m",
|
|
36
|
+
yellow: "\x1b[33m",
|
|
37
|
+
red: "\x1b[31m",
|
|
38
|
+
cyan: "\x1b[36m",
|
|
39
|
+
dim: "\x1b[2m",
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
function log(msg, color = "reset") {
|
|
43
|
+
console.log(`${colors[color]}${msg}${colors.reset}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function logStep(step, msg) {
|
|
47
|
+
console.log(`\n${colors.cyan}[${step}]${colors.reset} ${msg}`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function logSuccess(msg) {
|
|
51
|
+
console.log(` ${colors.green}✓${colors.reset} ${msg}`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function logWarning(msg) {
|
|
55
|
+
console.log(` ${colors.yellow}⚠${colors.reset} ${msg}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function logError(msg) {
|
|
59
|
+
console.log(` ${colors.red}✗${colors.reset} ${msg}`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function runCommand(cmd, options = {}) {
|
|
63
|
+
try {
|
|
64
|
+
const result = execSync(cmd, {
|
|
65
|
+
encoding: "utf-8",
|
|
66
|
+
stdio: options.silent ? "pipe" : "inherit",
|
|
67
|
+
...options,
|
|
68
|
+
});
|
|
69
|
+
return { success: true, output: result };
|
|
70
|
+
} catch (error) {
|
|
71
|
+
return { success: false, error: error.message };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function checkCommand(cmd) {
|
|
76
|
+
const result = spawnSync("which", [cmd], { encoding: "utf-8" });
|
|
77
|
+
return result.status === 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function main() {
|
|
81
|
+
console.log("\n" + "=".repeat(60));
|
|
82
|
+
log(" ClawChain Wallet - 安装配置", "cyan");
|
|
83
|
+
console.log("=".repeat(60));
|
|
84
|
+
|
|
85
|
+
// Step 1: 检测 Python
|
|
86
|
+
logStep("1/4", "检测 Python 环境...");
|
|
87
|
+
|
|
88
|
+
let pythonCmd = null;
|
|
89
|
+
for (const cmd of ["python3", "python"]) {
|
|
90
|
+
if (checkCommand(cmd)) {
|
|
91
|
+
const versionResult = spawnSync(cmd, ["--version"], { encoding: "utf-8" });
|
|
92
|
+
if (versionResult.status === 0) {
|
|
93
|
+
const version = versionResult.stdout.trim() || versionResult.stderr.trim();
|
|
94
|
+
if (version.includes("3.")) {
|
|
95
|
+
pythonCmd = cmd;
|
|
96
|
+
logSuccess(`找到 ${version}`);
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (!pythonCmd) {
|
|
104
|
+
logError("未找到 Python 3!");
|
|
105
|
+
logWarning("请先安装 Python 3.8 或更高版本");
|
|
106
|
+
logWarning("macOS: brew install python3");
|
|
107
|
+
logWarning("Ubuntu: sudo apt install python3 python3-pip");
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Step 2: 检测并安装 pip
|
|
112
|
+
logStep("2/4", "检测 pip 并安装 Python 依赖...");
|
|
113
|
+
|
|
114
|
+
let pipCmd = null;
|
|
115
|
+
for (const cmd of ["pip3", "pip"]) {
|
|
116
|
+
if (checkCommand(cmd)) {
|
|
117
|
+
pipCmd = cmd;
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (!pipCmd) {
|
|
123
|
+
logWarning("未找到 pip,尝试使用 python -m pip...");
|
|
124
|
+
pipCmd = `${pythonCmd} -m pip`;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// 安装 Python 依赖
|
|
128
|
+
const requirementsFile = join(rootDir, "python", "requirements.txt");
|
|
129
|
+
if (existsSync(requirementsFile)) {
|
|
130
|
+
log(` 安装 Python 依赖 (web3, eth-account)...`, "dim");
|
|
131
|
+
const pipResult = runCommand(
|
|
132
|
+
`${pipCmd} install -r "${requirementsFile}" --quiet --disable-pip-version-check`,
|
|
133
|
+
{ silent: true }
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
if (pipResult.success) {
|
|
137
|
+
logSuccess("Python 依赖安装成功");
|
|
138
|
+
} else {
|
|
139
|
+
logWarning("Python 依赖安装失败,请手动执行:");
|
|
140
|
+
logWarning(` ${pipCmd} install -r "${requirementsFile}"`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// 验证 web3 是否可用
|
|
145
|
+
const web3Check = spawnSync(pythonCmd, ["-c", "import web3; print(web3.__version__)"], {
|
|
146
|
+
encoding: "utf-8",
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
if (web3Check.status === 0) {
|
|
150
|
+
logSuccess(`web3.py ${web3Check.stdout.trim()} 已就绪`);
|
|
151
|
+
} else {
|
|
152
|
+
logWarning("web3 模块未安装,请手动执行:");
|
|
153
|
+
logWarning(` ${pipCmd} install web3 eth-account`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Step 3: 编译 TypeScript
|
|
157
|
+
logStep("3/4", "编译 TypeScript...");
|
|
158
|
+
|
|
159
|
+
const tscPath = join(rootDir, "node_modules", ".bin", "tsc");
|
|
160
|
+
if (existsSync(tscPath) || checkCommand("tsc")) {
|
|
161
|
+
const buildResult = runCommand("npm run build", { cwd: rootDir, silent: true });
|
|
162
|
+
if (buildResult.success) {
|
|
163
|
+
logSuccess("TypeScript 编译成功");
|
|
164
|
+
} else {
|
|
165
|
+
logWarning("TypeScript 编译失败,可能需要手动执行 npm run build");
|
|
166
|
+
}
|
|
167
|
+
} else {
|
|
168
|
+
logWarning("TypeScript 编译器未找到,跳过编译");
|
|
169
|
+
logWarning("如需编译,请执行: npm install && npm run build");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Step 4: 尝试注册到 OpenClaw
|
|
173
|
+
logStep("4/4", "检测 OpenClaw 并注册插件...");
|
|
174
|
+
|
|
175
|
+
if (checkCommand("openclaw")) {
|
|
176
|
+
logSuccess("找到 OpenClaw CLI");
|
|
177
|
+
|
|
178
|
+
// 检查是否已安装
|
|
179
|
+
const listResult = spawnSync("openclaw", ["plugins", "list"], { encoding: "utf-8" });
|
|
180
|
+
const isInstalled = listResult.stdout && listResult.stdout.includes("clawchain-wallet");
|
|
181
|
+
|
|
182
|
+
if (isInstalled) {
|
|
183
|
+
logSuccess("插件已在 OpenClaw 中注册");
|
|
184
|
+
} else {
|
|
185
|
+
log(` 注册插件到 OpenClaw...`, "dim");
|
|
186
|
+
const installResult = runCommand(`openclaw plugins install "${rootDir}"`, { silent: true });
|
|
187
|
+
|
|
188
|
+
if (installResult.success) {
|
|
189
|
+
// 启用插件
|
|
190
|
+
runCommand(`openclaw plugins enable clawchain-wallet`, { silent: true });
|
|
191
|
+
logSuccess("插件注册并启用成功");
|
|
192
|
+
} else {
|
|
193
|
+
logWarning("自动注册失败,请手动执行:");
|
|
194
|
+
logWarning(` openclaw plugins install "${rootDir}"`);
|
|
195
|
+
logWarning(` openclaw plugins enable clawchain-wallet`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
logWarning("未检测到 OpenClaw CLI");
|
|
200
|
+
logWarning("如需使用 OpenClaw 插件功能,请先安装 OpenClaw:");
|
|
201
|
+
logWarning(" npm install -g openclaw");
|
|
202
|
+
logWarning("然后手动注册插件:");
|
|
203
|
+
logWarning(` openclaw plugins install "${rootDir}"`);
|
|
204
|
+
logWarning(` openclaw plugins enable clawchain-wallet`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// 完成
|
|
208
|
+
console.log("\n" + "=".repeat(60));
|
|
209
|
+
log(" 安装完成!", "green");
|
|
210
|
+
console.log("=".repeat(60));
|
|
211
|
+
|
|
212
|
+
console.log(`
|
|
213
|
+
${colors.cyan}链信息:${colors.reset}
|
|
214
|
+
- 链名称: ClawChain
|
|
215
|
+
- 代币符号: CLAW
|
|
216
|
+
- RPC URL: https://n1.clawchain.net
|
|
217
|
+
- Chain ID: 1911
|
|
218
|
+
|
|
219
|
+
${colors.cyan}可用工具:${colors.reset}
|
|
220
|
+
- clawchain_wallet_create 创建新钱包
|
|
221
|
+
- clawchain_wallet_import 导入钱包
|
|
222
|
+
- clawchain_wallet_list 列出所有钱包
|
|
223
|
+
- clawchain_wallet_info 获取钱包详情
|
|
224
|
+
- clawchain_wallet_delete 删除钱包
|
|
225
|
+
- clawchain_wallet_rename 重命名钱包
|
|
226
|
+
- clawchain_wallet_export 导出钱包私钥
|
|
227
|
+
- clawchain_balance 查询余额
|
|
228
|
+
- clawchain_transfer 转账 CLAW
|
|
229
|
+
- clawchain_tx_info 查询交易详情
|
|
230
|
+
- clawchain_tx_history 查询交易历史
|
|
231
|
+
- clawchain_info 获取链信息
|
|
232
|
+
- clawchain_block_info 查询区块信息
|
|
233
|
+
- clawchain_claim_airdrop 领取 CLAW 空投
|
|
234
|
+
|
|
235
|
+
${colors.cyan}使用方式:${colors.reset}
|
|
236
|
+
1. 在 OpenClaw 中直接使用上述工具
|
|
237
|
+
2. 或阅读 SKILL.md 了解详细用法
|
|
238
|
+
|
|
239
|
+
${colors.dim}如有问题,请查看: ${rootDir}/SKILL.md${colors.reset}
|
|
240
|
+
`);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
main().catch(console.error);
|
package/src/executor.ts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClawChain Python CLI 执行器
|
|
3
|
+
*
|
|
4
|
+
* 使用 JSON stdin 传递参数,避免命令注入风险
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { execSync } from "node:child_process";
|
|
8
|
+
import type { CommandResult } from "./types.js";
|
|
9
|
+
|
|
10
|
+
export interface ExecutorOptions {
|
|
11
|
+
pythonScript: string;
|
|
12
|
+
walletsDir?: string;
|
|
13
|
+
timeout?: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* 命令参数类型定义
|
|
18
|
+
*/
|
|
19
|
+
export interface CommandArgs {
|
|
20
|
+
[key: string]: string | number | boolean | undefined;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 执行 ClawChain CLI 命令
|
|
25
|
+
*
|
|
26
|
+
* 通过 stdin 传递 JSON 格式的参数,避免命令行注入风险
|
|
27
|
+
*/
|
|
28
|
+
export function executeCommand(
|
|
29
|
+
options: ExecutorOptions,
|
|
30
|
+
command: string,
|
|
31
|
+
args: CommandArgs = {}
|
|
32
|
+
): CommandResult {
|
|
33
|
+
const { pythonScript, walletsDir, timeout = 60000 } = options;
|
|
34
|
+
|
|
35
|
+
// 构建 JSON 输入
|
|
36
|
+
const inputData = {
|
|
37
|
+
command,
|
|
38
|
+
wallets_dir: walletsDir,
|
|
39
|
+
args,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const jsonInput = JSON.stringify(inputData);
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const output = execSync(`python3 "${pythonScript}" --json-stdin`, {
|
|
46
|
+
encoding: "utf-8",
|
|
47
|
+
timeout,
|
|
48
|
+
input: jsonInput,
|
|
49
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// 解析 JSON 输出
|
|
53
|
+
try {
|
|
54
|
+
return JSON.parse(output.trim()) as CommandResult;
|
|
55
|
+
} catch {
|
|
56
|
+
// 如果不是 JSON,返回原始输出
|
|
57
|
+
return {
|
|
58
|
+
success: true,
|
|
59
|
+
output: output.trim(),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
} catch (error: unknown) {
|
|
63
|
+
const execError = error as { stderr?: string; stdout?: string; message?: string };
|
|
64
|
+
|
|
65
|
+
// 尝试从 stdout 解析 JSON 结果(某些情况下错误也会输出到 stdout)
|
|
66
|
+
if (execError.stdout) {
|
|
67
|
+
try {
|
|
68
|
+
return JSON.parse(execError.stdout.trim()) as CommandResult;
|
|
69
|
+
} catch {
|
|
70
|
+
// 继续尝试 stderr
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// 尝试从 stderr 解析 JSON 错误
|
|
75
|
+
if (execError.stderr) {
|
|
76
|
+
try {
|
|
77
|
+
return JSON.parse(execError.stderr.trim()) as CommandResult;
|
|
78
|
+
} catch {
|
|
79
|
+
// 返回原始错误
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
success: false,
|
|
85
|
+
error: execError.message || "命令执行失败",
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|