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.
@@ -0,0 +1,2 @@
1
+ web3>=6.0.0
2
+ eth-account>=0.10.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);
@@ -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
+ }