solana-traderclaw 1.0.25 → 1.0.27

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.
@@ -1,6 +1,6 @@
1
1
  import { execSync, spawn } from "child_process";
2
2
  import { randomBytes } from "crypto";
3
- import { existsSync, mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from "fs";
3
+ import { existsSync, mkdirSync, mkdtempSync, readFileSync, renameSync, statSync, writeFileSync } from "fs";
4
4
  import { homedir, tmpdir } from "os";
5
5
  import { dirname, join } from "path";
6
6
  import { fileURLToPath } from "url";
@@ -13,16 +13,48 @@ const CONFIG_FILE = join(CONFIG_DIR, "openclaw.json");
13
13
  /** Directory containing this package when running from a git checkout or global npm install. */
14
14
  const PLUGIN_PACKAGE_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..");
15
15
 
16
- function resolvePluginInstallSpec(modeConfig) {
17
- const manifest = join(PLUGIN_PACKAGE_ROOT, "openclaw.plugin.json");
18
- const pkgJson = join(PLUGIN_PACKAGE_ROOT, "package.json");
19
- if (existsSync(manifest) && existsSync(pkgJson)) {
20
- return PLUGIN_PACKAGE_ROOT;
16
+ function readPluginPackageVersion() {
17
+ const pkgJsonPath = join(PLUGIN_PACKAGE_ROOT, "package.json");
18
+ if (!existsSync(pkgJsonPath)) return null;
19
+ try {
20
+ const pkg = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
21
+ return typeof pkg.version === "string" && pkg.version.trim().length ? pkg.version.trim() : null;
22
+ } catch {
23
+ return null;
21
24
  }
22
- // Use an explicit registry range so npm does not treat a same-named folder in cwd (e.g. /root/solana-traderclaw) as the install source.
25
+ }
26
+
27
+ /**
28
+ * Spec for `npm install -g` and `openclaw plugins install`.
29
+ * Prefer explicit registry coordinates (`package@version`) so npm never resolves a bare name or `file:`
30
+ * relative to cwd (e.g. /root when TMPDIR or shadow folders break resolution).
31
+ * Local directory install is opt-in for dev/offline: TRADERCLAW_INSTALLER_USE_LOCAL_PACKAGE=1.
32
+ */
33
+ function resolveRegistryPluginInstallSpec(modeConfig) {
34
+ if (process.env.TRADERCLAW_INSTALLER_USE_LOCAL_PACKAGE === "1") {
35
+ const manifest = join(PLUGIN_PACKAGE_ROOT, "openclaw.plugin.json");
36
+ const pkgJson = join(PLUGIN_PACKAGE_ROOT, "package.json");
37
+ if (existsSync(manifest) && existsSync(pkgJson)) {
38
+ return PLUGIN_PACKAGE_ROOT;
39
+ }
40
+ }
41
+ const v = readPluginPackageVersion();
42
+ if (v) return `${modeConfig.pluginPackage}@${v}`;
23
43
  return `${modeConfig.pluginPackage}@latest`;
24
44
  }
25
45
 
46
+ /** Empty per-invocation cwd for npm global installs — avoids TMPDIR=/root and stray ./solana-traderclaw shadowing. */
47
+ function getNpmGlobalInstallCwd() {
48
+ if (process.platform === "win32") {
49
+ return mkdtempSync(join(tmpdir(), "tc-npm-"));
50
+ }
51
+ try {
52
+ return mkdtempSync(join("/tmp", "tc-npm-"));
53
+ } catch {
54
+ return mkdtempSync(join(tmpdir(), "tc-npm-"));
55
+ }
56
+ }
57
+
26
58
  /** Older `plugins.entries` keys / npm-era ids to merge orchestrator URL for. */
27
59
  const LEGACY_TRADER_PLUGIN_IDS = ["traderclaw-v1", "solana-traderclaw-v1", "solana-trader"];
28
60
 
@@ -172,16 +204,17 @@ function gatewayModeUnsetRemediation() {
172
204
 
173
205
  function runCommandWithEvents(cmd, args = [], opts = {}) {
174
206
  return new Promise((resolve, reject) => {
207
+ const { onEvent, ...spawnOpts } = opts;
175
208
  const child = spawn(cmd, args, {
176
209
  stdio: "pipe",
177
210
  shell: true,
178
- ...opts,
211
+ ...spawnOpts,
179
212
  });
180
213
 
181
214
  let stdout = "";
182
215
  let stderr = "";
183
- const onEvent = typeof opts.onEvent === "function" ? opts.onEvent : null;
184
- const emit = (event) => onEvent && onEvent(event);
216
+ const emitFn = typeof onEvent === "function" ? onEvent : null;
217
+ const emit = (event) => emitFn && emitFn(event);
185
218
 
186
219
  child.stdout?.on("data", (d) => {
187
220
  const text = d.toString();
@@ -253,7 +286,7 @@ function npmGlobalInstallArgs(spec, { force = false } = {}) {
253
286
  }
254
287
 
255
288
  async function installPlugin(modeConfig, onEvent) {
256
- const spec = resolvePluginInstallSpec(modeConfig);
289
+ const spec = resolveRegistryPluginInstallSpec(modeConfig);
257
290
  const isLocalPluginRoot =
258
291
  typeof spec === "string" &&
259
292
  existsSync(join(spec, "openclaw.plugin.json")) &&
@@ -265,7 +298,7 @@ async function installPlugin(modeConfig, onEvent) {
265
298
  urls: [],
266
299
  });
267
300
  }
268
- const npmCwd = tmpdir();
301
+ const npmCwd = getNpmGlobalInstallCwd();
269
302
  if (typeof onEvent === "function") {
270
303
  onEvent({
271
304
  type: "stdout",
@@ -322,7 +355,7 @@ async function installAndEnableOpenClawPlugin(modeConfig, onEvent, orchestratorU
322
355
 
323
356
  seedPluginConfig(modeConfig, orchestratorUrl || "https://api.traderclaw.ai");
324
357
 
325
- const pluginInstallSpec = resolvePluginInstallSpec(modeConfig);
358
+ const pluginInstallSpec = resolveRegistryPluginInstallSpec(modeConfig);
326
359
  let recoveredExistingDir = null;
327
360
  try {
328
361
  await runCommandWithEvents("openclaw", ["plugins", "install", pluginInstallSpec], { onEvent });
@@ -781,8 +814,7 @@ function deployGatewayConfig(modeConfig) {
781
814
  const destFile = join(gatewayDir, modeConfig.gatewayConfig);
782
815
  const npmRoot = getCommandOutput("npm root -g");
783
816
  if (!npmRoot) return { deployed: false, dest: destFile };
784
- const spec = resolvePluginInstallSpec(modeConfig);
785
- const src = join(npmRoot, spec, "config", modeConfig.gatewayConfig);
817
+ const src = join(npmRoot, modeConfig.pluginPackage, "config", modeConfig.gatewayConfig);
786
818
  if (!existsSync(src)) return { deployed: false, dest: destFile };
787
819
  writeFileSync(destFile, readFileSync(src));
788
820
  return { deployed: true, source: src, dest: destFile };
@@ -826,8 +858,7 @@ export function resolveAgentWorkspaceDir(configPath = CONFIG_FILE) {
826
858
  export function deployWorkspaceHeartbeat(modeConfig) {
827
859
  const npmRoot = getCommandOutput("npm root -g");
828
860
  if (!npmRoot) return { deployed: false, reason: "npm_root_g_failed" };
829
- const spec = resolvePluginInstallSpec(modeConfig);
830
- const src = join(npmRoot, spec, "skills", "solana-trader", "HEARTBEAT.md");
861
+ const src = join(npmRoot, modeConfig.pluginPackage, "skills", "solana-trader", "HEARTBEAT.md");
831
862
  if (!existsSync(src)) return { deployed: false, reason: "source_missing", src };
832
863
 
833
864
  const workspaceDir = resolveAgentWorkspaceDir(CONFIG_FILE);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "solana-traderclaw",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
4
4
  "description": "TraderClaw V1 — autonomous Solana memecoin trading for OpenClaw (team edition: X/Twitter journal and engagement tools)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",