solana-traderclaw 1.0.42 → 1.0.43
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 +7 -1
- package/bin/installer-step-engine.mjs +108 -5
- package/bin/openclaw-trader.mjs +60 -0
- package/openclaw.plugin.json +9 -0
- package/package.json +1 -1
- package/skills/solana-trader/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -44,6 +44,11 @@ Or install directly into OpenClaw:
|
|
|
44
44
|
openclaw plugins install solana-traderclaw
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
+
Install name and config id are intentionally different:
|
|
48
|
+
- npm package / install command: `solana-traderclaw`
|
|
49
|
+
- OpenClaw plugin id in `openclaw.json`: `solana-trader`
|
|
50
|
+
- OpenClaw allowlist entry: `plugins.allow: ["solana-trader"]`
|
|
51
|
+
|
|
47
52
|
### 2. Run setup
|
|
48
53
|
|
|
49
54
|
```bash
|
|
@@ -143,7 +148,7 @@ traderclaw config set <key> <v> # Update a value
|
|
|
143
148
|
traderclaw config reset # Remove all plugin config
|
|
144
149
|
```
|
|
145
150
|
|
|
146
|
-
Available config keys: `orchestratorUrl`, `walletId`, `apiKey`, `apiTimeout`, `refreshToken`, `walletPublicKey`, `walletPrivateKey`, `gatewayBaseUrl`, `gatewayToken`, `agentId`
|
|
151
|
+
Available config keys: `orchestratorUrl`, `walletId`, `apiKey`, `apiTimeout`, `refreshToken`, `recoverySecret`, `walletPublicKey`, `walletPrivateKey`, `gatewayBaseUrl`, `gatewayToken`, `agentId`
|
|
147
152
|
|
|
148
153
|
### `traderclaw --help`
|
|
149
154
|
|
|
@@ -160,6 +165,7 @@ If you prefer to configure manually instead of using the CLI, add to `~/.opencla
|
|
|
160
165
|
```json5
|
|
161
166
|
{
|
|
162
167
|
plugins: {
|
|
168
|
+
allow: ["solana-trader"],
|
|
163
169
|
entries: {
|
|
164
170
|
"solana-trader": {
|
|
165
171
|
enabled: true,
|
|
@@ -55,8 +55,105 @@ function getNpmGlobalInstallCwd() {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
/** Older `plugins.entries` keys / npm-era ids
|
|
59
|
-
const LEGACY_TRADER_PLUGIN_IDS = ["traderclaw-v1", "solana-traderclaw-v1", "solana-
|
|
58
|
+
/** Older `plugins.entries` keys / npm-era ids for the v1 plugin. */
|
|
59
|
+
const LEGACY_TRADER_PLUGIN_IDS = ["traderclaw-v1", "solana-traderclaw-v1", "solana-traderclaw"];
|
|
60
|
+
|
|
61
|
+
function isRecord(value) {
|
|
62
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getLegacyTraderPluginIds(pluginId) {
|
|
66
|
+
return pluginId === "solana-trader" ? LEGACY_TRADER_PLUGIN_IDS : [];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function normalizeTraderPluginEntries(config, pluginId) {
|
|
70
|
+
if (!isRecord(config)) return false;
|
|
71
|
+
if (!isRecord(config.plugins)) config.plugins = {};
|
|
72
|
+
if (!isRecord(config.plugins.entries)) config.plugins.entries = {};
|
|
73
|
+
|
|
74
|
+
const entries = config.plugins.entries;
|
|
75
|
+
const legacyIds = getLegacyTraderPluginIds(pluginId);
|
|
76
|
+
if (legacyIds.length === 0) return false;
|
|
77
|
+
|
|
78
|
+
let touched = false;
|
|
79
|
+
let hasSource = false;
|
|
80
|
+
let enabledSeen = false;
|
|
81
|
+
let enabledValue = false;
|
|
82
|
+
let mergedConfig = {};
|
|
83
|
+
|
|
84
|
+
for (const sourceId of [...legacyIds, pluginId]) {
|
|
85
|
+
const entry = entries[sourceId];
|
|
86
|
+
if (!isRecord(entry)) continue;
|
|
87
|
+
hasSource = true;
|
|
88
|
+
if (typeof entry.enabled === "boolean") {
|
|
89
|
+
enabledSeen = true;
|
|
90
|
+
enabledValue = enabledValue || entry.enabled;
|
|
91
|
+
}
|
|
92
|
+
if (isRecord(entry.config)) {
|
|
93
|
+
mergedConfig = { ...mergedConfig, ...entry.config };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!hasSource) return false;
|
|
98
|
+
|
|
99
|
+
const canonicalEntry = isRecord(entries[pluginId]) ? entries[pluginId] : {};
|
|
100
|
+
const nextEntry = {
|
|
101
|
+
...canonicalEntry,
|
|
102
|
+
enabled: typeof canonicalEntry.enabled === "boolean" ? canonicalEntry.enabled : (enabledSeen ? enabledValue : true),
|
|
103
|
+
config: mergedConfig,
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
if (entries[pluginId] !== nextEntry) {
|
|
107
|
+
entries[pluginId] = nextEntry;
|
|
108
|
+
touched = true;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
for (const legacyId of legacyIds) {
|
|
112
|
+
if (Object.prototype.hasOwnProperty.call(entries, legacyId)) {
|
|
113
|
+
delete entries[legacyId];
|
|
114
|
+
touched = true;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return touched;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function normalizeTraderAllowlist(config, pluginId) {
|
|
122
|
+
if (!isRecord(config?.plugins)) return false;
|
|
123
|
+
const legacyIds = new Set(getLegacyTraderPluginIds(pluginId));
|
|
124
|
+
if (legacyIds.size === 0 || !Array.isArray(config.plugins.allow)) return false;
|
|
125
|
+
|
|
126
|
+
const nextAllow = [];
|
|
127
|
+
const seen = new Set();
|
|
128
|
+
let touched = false;
|
|
129
|
+
|
|
130
|
+
for (const id of config.plugins.allow) {
|
|
131
|
+
if (typeof id !== "string") {
|
|
132
|
+
touched = true;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const trimmed = id.trim();
|
|
136
|
+
if (!trimmed) {
|
|
137
|
+
touched = true;
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (legacyIds.has(trimmed)) {
|
|
141
|
+
touched = true;
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (seen.has(trimmed)) {
|
|
145
|
+
touched = true;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
seen.add(trimmed);
|
|
149
|
+
nextAllow.push(trimmed);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (touched) {
|
|
153
|
+
config.plugins.allow = nextAllow;
|
|
154
|
+
}
|
|
155
|
+
return touched;
|
|
156
|
+
}
|
|
60
157
|
|
|
61
158
|
function stripAnsi(text) {
|
|
62
159
|
if (typeof text !== "string") return text;
|
|
@@ -433,6 +530,9 @@ function seedPluginConfig(modeConfig, orchestratorUrl, configPath = CONFIG_FILE)
|
|
|
433
530
|
if (!config.plugins || typeof config.plugins !== "object") config.plugins = {};
|
|
434
531
|
if (!config.plugins.entries || typeof config.plugins.entries !== "object") config.plugins.entries = {};
|
|
435
532
|
|
|
533
|
+
normalizeTraderPluginEntries(config, modeConfig.pluginId);
|
|
534
|
+
normalizeTraderAllowlist(config, modeConfig.pluginId);
|
|
535
|
+
|
|
436
536
|
const entries = config.plugins.entries;
|
|
437
537
|
|
|
438
538
|
const mergeOrchestratorForId = (pluginId) => {
|
|
@@ -453,9 +553,6 @@ function seedPluginConfig(modeConfig, orchestratorUrl, configPath = CONFIG_FILE)
|
|
|
453
553
|
};
|
|
454
554
|
|
|
455
555
|
mergeOrchestratorForId(modeConfig.pluginId);
|
|
456
|
-
for (const legacyId of LEGACY_TRADER_PLUGIN_IDS) {
|
|
457
|
-
if (entries[legacyId]) mergeOrchestratorForId(legacyId);
|
|
458
|
-
}
|
|
459
556
|
|
|
460
557
|
// Do not set plugins.allow here: OpenClaw validates allow[] against the plugin registry, and
|
|
461
558
|
// the id is not registered until after `openclaw plugins install`. Pre-seeding allow caused:
|
|
@@ -596,6 +693,8 @@ function mergePluginsAllowlist(modeConfig, configPath = CONFIG_FILE) {
|
|
|
596
693
|
return;
|
|
597
694
|
}
|
|
598
695
|
if (!config.plugins || typeof config.plugins !== "object") config.plugins = {};
|
|
696
|
+
normalizeTraderPluginEntries(config, modeConfig.pluginId);
|
|
697
|
+
normalizeTraderAllowlist(config, modeConfig.pluginId);
|
|
599
698
|
const allowSet = new Set(
|
|
600
699
|
Array.isArray(config.plugins.allow) ? config.plugins.allow.filter((id) => typeof id === "string" && id.trim()) : [],
|
|
601
700
|
);
|
|
@@ -972,6 +1071,8 @@ function seedXConfig(modeConfig, configPath = CONFIG_FILE, wizardOpts = {}) {
|
|
|
972
1071
|
|
|
973
1072
|
if (!config.plugins || typeof config.plugins !== "object") config.plugins = {};
|
|
974
1073
|
if (!config.plugins.entries || typeof config.plugins.entries !== "object") config.plugins.entries = {};
|
|
1074
|
+
normalizeTraderPluginEntries(config, modeConfig.pluginId);
|
|
1075
|
+
normalizeTraderAllowlist(config, modeConfig.pluginId);
|
|
975
1076
|
|
|
976
1077
|
const entry = config.plugins.entries[modeConfig.pluginId];
|
|
977
1078
|
if (!entry || typeof entry !== "object") return { skipped: true, reason: "plugin entry not found" };
|
|
@@ -1047,6 +1148,8 @@ function persistXProfileIdentities(configPath, modeConfig, identities) {
|
|
|
1047
1148
|
} catch {
|
|
1048
1149
|
return { written: 0 };
|
|
1049
1150
|
}
|
|
1151
|
+
normalizeTraderPluginEntries(config, modeConfig.pluginId);
|
|
1152
|
+
normalizeTraderAllowlist(config, modeConfig.pluginId);
|
|
1050
1153
|
const entry = config?.plugins?.entries?.[modeConfig.pluginId];
|
|
1051
1154
|
if (!entry?.config?.x?.profiles || typeof entry.config.x.profiles !== "object") return { written: 0 };
|
|
1052
1155
|
|
package/bin/openclaw-trader.mjs
CHANGED
|
@@ -13,6 +13,7 @@ const PACKAGE_JSON = JSON.parse(readFileSync(new URL("../package.json", import.m
|
|
|
13
13
|
const VERSION = PACKAGE_JSON.version;
|
|
14
14
|
const NPM_PACKAGE_NAME = typeof PACKAGE_JSON.name === "string" ? PACKAGE_JSON.name : "solana-traderclaw";
|
|
15
15
|
const PLUGIN_ID = "solana-trader";
|
|
16
|
+
const LEGACY_PLUGIN_IDS = ["traderclaw-v1", "solana-traderclaw-v1", "solana-traderclaw"];
|
|
16
17
|
const CONFIG_DIR = join(homedir(), ".openclaw");
|
|
17
18
|
const CONFIG_FILE = join(CONFIG_DIR, "openclaw.json");
|
|
18
19
|
const WALLET_PRIVATE_KEY_ENV = "TRADERCLAW_WALLET_PRIVATE_KEY";
|
|
@@ -166,11 +167,69 @@ function readConfig() {
|
|
|
166
167
|
}
|
|
167
168
|
|
|
168
169
|
function writeConfig(config) {
|
|
170
|
+
normalizePluginConfigShape(config);
|
|
169
171
|
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
170
172
|
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
171
173
|
}
|
|
172
174
|
|
|
175
|
+
function isRecord(value) {
|
|
176
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function normalizePluginConfigShape(config) {
|
|
180
|
+
if (!isRecord(config)) return config;
|
|
181
|
+
if (!isRecord(config.plugins)) config.plugins = {};
|
|
182
|
+
const plugins = config.plugins;
|
|
183
|
+
if (!isRecord(plugins.entries)) plugins.entries = {};
|
|
184
|
+
const entries = plugins.entries;
|
|
185
|
+
|
|
186
|
+
let enabledSeen = false;
|
|
187
|
+
let enabledValue = false;
|
|
188
|
+
let mergedConfig = {};
|
|
189
|
+
let found = false;
|
|
190
|
+
|
|
191
|
+
for (const sourceId of [...LEGACY_PLUGIN_IDS, PLUGIN_ID]) {
|
|
192
|
+
const entry = entries[sourceId];
|
|
193
|
+
if (!isRecord(entry)) continue;
|
|
194
|
+
found = true;
|
|
195
|
+
if (typeof entry.enabled === "boolean") {
|
|
196
|
+
enabledSeen = true;
|
|
197
|
+
enabledValue = enabledValue || entry.enabled;
|
|
198
|
+
}
|
|
199
|
+
if (isRecord(entry.config)) {
|
|
200
|
+
mergedConfig = { ...mergedConfig, ...entry.config };
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (found) {
|
|
205
|
+
const canonical = isRecord(entries[PLUGIN_ID]) ? entries[PLUGIN_ID] : {};
|
|
206
|
+
entries[PLUGIN_ID] = {
|
|
207
|
+
...canonical,
|
|
208
|
+
enabled: typeof canonical.enabled === "boolean" ? canonical.enabled : (enabledSeen ? enabledValue : true),
|
|
209
|
+
config: mergedConfig,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
for (const legacyId of LEGACY_PLUGIN_IDS) {
|
|
214
|
+
delete entries[legacyId];
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (Array.isArray(plugins.allow)) {
|
|
218
|
+
const seen = new Set();
|
|
219
|
+
plugins.allow = plugins.allow.filter((id) => {
|
|
220
|
+
if (typeof id !== "string") return false;
|
|
221
|
+
const trimmed = id.trim();
|
|
222
|
+
if (!trimmed || LEGACY_PLUGIN_IDS.includes(trimmed) || seen.has(trimmed)) return false;
|
|
223
|
+
seen.add(trimmed);
|
|
224
|
+
return true;
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return config;
|
|
229
|
+
}
|
|
230
|
+
|
|
173
231
|
function getPluginConfig(config) {
|
|
232
|
+
normalizePluginConfigShape(config);
|
|
174
233
|
const plugins = config.plugins;
|
|
175
234
|
if (!plugins) return null;
|
|
176
235
|
const entries = plugins.entries;
|
|
@@ -181,6 +240,7 @@ function getPluginConfig(config) {
|
|
|
181
240
|
}
|
|
182
241
|
|
|
183
242
|
function setPluginConfig(config, pluginConfig) {
|
|
243
|
+
normalizePluginConfigShape(config);
|
|
184
244
|
if (!config.plugins) config.plugins = {};
|
|
185
245
|
if (!config.plugins.entries) config.plugins.entries = {};
|
|
186
246
|
config.plugins.entries[PLUGIN_ID] = {
|
package/openclaw.plugin.json
CHANGED
|
@@ -28,6 +28,10 @@
|
|
|
28
28
|
"type": "string",
|
|
29
29
|
"description": "Refresh token from last session (auto-populated after authentication)"
|
|
30
30
|
},
|
|
31
|
+
"recoverySecret": {
|
|
32
|
+
"type": "string",
|
|
33
|
+
"description": "Consumable recovery secret used to restore a session after refresh-token failure"
|
|
34
|
+
},
|
|
31
35
|
"walletPublicKey": {
|
|
32
36
|
"type": "string",
|
|
33
37
|
"description": "Solana wallet public key (auto-populated after session establishment)"
|
|
@@ -128,6 +132,11 @@
|
|
|
128
132
|
"sensitive": true,
|
|
129
133
|
"advanced": true
|
|
130
134
|
},
|
|
135
|
+
"recoverySecret": {
|
|
136
|
+
"label": "Recovery Secret",
|
|
137
|
+
"sensitive": true,
|
|
138
|
+
"advanced": true
|
|
139
|
+
},
|
|
131
140
|
"walletPublicKey": {
|
|
132
141
|
"label": "Wallet Public Key",
|
|
133
142
|
"advanced": true
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "solana-traderclaw",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.43",
|
|
4
4
|
"description": "TraderClaw V1-Upgraded — Solana trading for OpenClaw with intelligence lab, tool envelopes, prompt scrubbing, read-only X social intel, and split skill docs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -35,7 +35,7 @@ https://docs.traderclaw.ai/docs/installation#troubleshooting-session-expired-aut
|
|
|
35
35
|
- **Wallet proof** is NOT account signup. It is a cryptographic step proving wallet control.
|
|
36
36
|
- **`traderclaw login`** reuses the saved refresh token when valid.
|
|
37
37
|
- **OpenClaw gateway ≠ your SSH shell.** Exporting env vars in SSH does NOT inject them into the gateway service process.
|
|
38
|
-
- **Plugin id vs npm name:** `solana-traderclaw
|
|
38
|
+
- **Plugin id vs npm name:** `solana-traderclaw` is the npm package name, while `solana-trader` is the OpenClaw plugin id used in `plugins.entries` and `plugins.allow`.
|
|
39
39
|
|
|
40
40
|
---
|
|
41
41
|
|