dexbot 1.4.19 → 1.4.21

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.
Files changed (302) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +22 -12
  3. package/analysis/ama_fitting/analyze_lambda_vs_slow.ts +2 -2
  4. package/analysis/ama_fitting/calibrate_convergence_er.ts +1 -1
  5. package/analysis/ama_fitting/optimizer_high_resolution.ts +2 -1
  6. package/analysis/ama_fitting/package.json +1 -1
  7. package/analysis/analyze_derivatives.ts +4 -2
  8. package/analysis/analyze_dynamic_weight.ts +3 -1
  9. package/analysis/analyze_kalman.ts +3 -1
  10. package/analysis/analyze_regime.ts +3 -1
  11. package/analysis/analyze_regime_windows.ts +3 -1
  12. package/analysis/analyze_volatility.ts +2 -2
  13. package/analysis/bot_fitting/backtest_ama_sweep.ts +2 -1
  14. package/analysis/bot_fitting/backtest_bot_fitting.ts +17 -12
  15. package/analysis/bot_fitting/shared_utils.ts +1 -1
  16. package/analysis/bot_key_utils.ts +1 -5
  17. package/analysis/bot_usage/kibana_bot_queries.ts +1 -256
  18. package/analysis/chart_css.ts +1 -1
  19. package/analysis/chart_utils.ts +24 -0
  20. package/analysis/derivative_chart_generator.ts +3 -2
  21. package/analysis/math_utils.ts +1 -8
  22. package/analysis/trend_detection/DYNAMIC_WEIGHT_RESEARCH.md +1 -1
  23. package/analysis/trend_detection/dynamic_weight_chart_generator.ts +91 -55
  24. package/analysis/trend_detection/package.json +1 -1
  25. package/claw/ecosystem.config.cjs +2 -3
  26. package/claw/examples/claw_profiles_example.ts +4 -1
  27. package/claw/examples/memu_integration_example.ts +17 -17
  28. package/claw/modules/chain_actions.ts +51 -54
  29. package/claw/modules/chain_broadcast.ts +66 -104
  30. package/claw/modules/claw_bridge.ts +60 -80
  31. package/claw/modules/claw_catalog.ts +48 -17
  32. package/claw/modules/claw_infra.ts +1 -5
  33. package/claw/modules/claw_launcher.ts +47 -49
  34. package/claw/modules/claw_skill_md.ts +14 -16
  35. package/claw/modules/credit_runtime_adapter.ts +2 -18
  36. package/claw/modules/decision_loop.ts +4 -0
  37. package/claw/modules/dexbot_bridge.ts +1 -1
  38. package/claw/modules/dexbot_profiles.ts +8 -22
  39. package/claw/modules/honest_ecosystem.ts +24 -8
  40. package/claw/modules/launcher_paths.ts +4 -2
  41. package/claw/modules/liquidity_pools.ts +10 -3
  42. package/claw/modules/mcp_utils.ts +109 -0
  43. package/claw/modules/memu_bridge.ts +76 -54
  44. package/claw/modules/mpa_utils.ts +26 -3
  45. package/claw/modules/position_discovery.ts +16 -27
  46. package/claw/modules/position_manager.ts +32 -41
  47. package/claw/modules/position_manager_watch.ts +3 -2
  48. package/claw/modules/short_mpa_strategy.ts +1 -9
  49. package/claw/modules/skill_utils.ts +5 -3
  50. package/claw/modules/utils.ts +9 -1
  51. package/claw/package.json +1 -1
  52. package/claw/runtimes/openclaw-plugin/index.ts +27 -10
  53. package/claw/runtimes/openclaw-plugin/openclaw.plugin.json +1 -1
  54. package/claw/runtimes/openclaw-plugin/package.json +1 -1
  55. package/claw/scripts/claw_bridge.ts +1 -1
  56. package/claw/scripts/claw_mcp_server.ts +19 -78
  57. package/claw/scripts/honest_assets_report.ts +19 -84
  58. package/claw/scripts/memu_mcp_server.ts +57 -155
  59. package/claw/tests/test_claw_bridge.ts +6 -2
  60. package/claw/tests/test_claw_mcp_transport.ts +2 -2
  61. package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.js +2 -2
  62. package/dist/analysis/ama_fitting/analyze_lambda_vs_slow.js.map +1 -1
  63. package/dist/analysis/ama_fitting/calibrate_convergence_er.js +1 -1
  64. package/dist/analysis/ama_fitting/calibrate_convergence_er.js.map +1 -1
  65. package/dist/analysis/ama_fitting/optimizer_high_resolution.d.ts.map +1 -1
  66. package/dist/analysis/ama_fitting/optimizer_high_resolution.js +2 -1
  67. package/dist/analysis/ama_fitting/optimizer_high_resolution.js.map +1 -1
  68. package/dist/analysis/analyze_derivatives.d.ts.map +1 -1
  69. package/dist/analysis/analyze_derivatives.js +4 -2
  70. package/dist/analysis/analyze_derivatives.js.map +1 -1
  71. package/dist/analysis/analyze_dynamic_weight.js +3 -1
  72. package/dist/analysis/analyze_dynamic_weight.js.map +1 -1
  73. package/dist/analysis/analyze_kalman.js +3 -1
  74. package/dist/analysis/analyze_kalman.js.map +1 -1
  75. package/dist/analysis/analyze_regime.js +3 -1
  76. package/dist/analysis/analyze_regime.js.map +1 -1
  77. package/dist/analysis/analyze_regime_windows.js +3 -1
  78. package/dist/analysis/analyze_regime_windows.js.map +1 -1
  79. package/dist/analysis/analyze_volatility.js +2 -2
  80. package/dist/analysis/analyze_volatility.js.map +1 -1
  81. package/dist/analysis/bot_fitting/backtest_ama_sweep.d.ts.map +1 -1
  82. package/dist/analysis/bot_fitting/backtest_ama_sweep.js +2 -1
  83. package/dist/analysis/bot_fitting/backtest_ama_sweep.js.map +1 -1
  84. package/dist/analysis/bot_fitting/backtest_bot_fitting.js +18 -13
  85. package/dist/analysis/bot_fitting/backtest_bot_fitting.js.map +1 -1
  86. package/dist/analysis/bot_fitting/shared_utils.d.ts +1 -12
  87. package/dist/analysis/bot_fitting/shared_utils.d.ts.map +1 -1
  88. package/dist/analysis/bot_fitting/shared_utils.js +1 -1
  89. package/dist/analysis/bot_fitting/shared_utils.js.map +1 -1
  90. package/dist/analysis/bot_key_utils.d.ts +1 -1
  91. package/dist/analysis/bot_key_utils.d.ts.map +1 -1
  92. package/dist/analysis/bot_key_utils.js +1 -5
  93. package/dist/analysis/bot_key_utils.js.map +1 -1
  94. package/dist/analysis/bot_usage/kibana_bot_queries.d.ts +1 -337
  95. package/dist/analysis/bot_usage/kibana_bot_queries.d.ts.map +1 -1
  96. package/dist/analysis/bot_usage/kibana_bot_queries.js +1 -241
  97. package/dist/analysis/bot_usage/kibana_bot_queries.js.map +1 -1
  98. package/dist/analysis/chart_css.d.ts +1 -15
  99. package/dist/analysis/chart_css.d.ts.map +1 -1
  100. package/dist/analysis/chart_css.js +1 -1
  101. package/dist/analysis/chart_css.js.map +1 -1
  102. package/dist/analysis/chart_utils.d.ts +0 -3
  103. package/dist/analysis/chart_utils.d.ts.map +1 -1
  104. package/dist/analysis/chart_utils.js +25 -0
  105. package/dist/analysis/chart_utils.js.map +1 -1
  106. package/dist/analysis/derivative_chart_generator.d.ts.map +1 -1
  107. package/dist/analysis/derivative_chart_generator.js +3 -2
  108. package/dist/analysis/derivative_chart_generator.js.map +1 -1
  109. package/dist/analysis/math_utils.d.ts +3 -5
  110. package/dist/analysis/math_utils.d.ts.map +1 -1
  111. package/dist/analysis/math_utils.js +3 -5
  112. package/dist/analysis/math_utils.js.map +1 -1
  113. package/dist/analysis/trend_detection/dynamic_weight_chart_generator.d.ts.map +1 -1
  114. package/dist/analysis/trend_detection/dynamic_weight_chart_generator.js +82 -50
  115. package/dist/analysis/trend_detection/dynamic_weight_chart_generator.js.map +1 -1
  116. package/dist/bot.js +2 -2
  117. package/dist/bot.js.map +1 -1
  118. package/dist/credential-daemon.js +1 -1
  119. package/dist/credential-daemon.js.map +1 -1
  120. package/dist/dexbot.d.ts.map +1 -1
  121. package/dist/dexbot.js +20 -17
  122. package/dist/dexbot.js.map +1 -1
  123. package/dist/market_adapter/ama_signal_runner.js +3 -3
  124. package/dist/market_adapter/core/kibana_client.d.ts +1 -3
  125. package/dist/market_adapter/core/kibana_client.d.ts.map +1 -1
  126. package/dist/market_adapter/core/kibana_client.js +1 -1
  127. package/dist/market_adapter/core/kibana_client.js.map +1 -1
  128. package/dist/market_adapter/core/market_adapter_service.d.ts +1 -2
  129. package/dist/market_adapter/core/market_adapter_service.d.ts.map +1 -1
  130. package/dist/market_adapter/core/market_adapter_service.js +9 -4
  131. package/dist/market_adapter/core/market_adapter_service.js.map +1 -1
  132. package/dist/market_adapter/core/strategies/regime_gate.d.ts +1 -2
  133. package/dist/market_adapter/core/strategies/regime_gate.d.ts.map +1 -1
  134. package/dist/market_adapter/core/strategies/regime_gate.js +1 -1
  135. package/dist/market_adapter/core/strategies/regime_gate.js.map +1 -1
  136. package/dist/market_adapter/inputs/fetch_cex_synthetic_data.js +2 -2
  137. package/dist/market_adapter/inputs/fetch_cex_synthetic_data.js.map +1 -1
  138. package/dist/market_adapter/inputs/fetch_lp_data.d.ts +5 -5
  139. package/dist/market_adapter/inputs/fetch_lp_data.js +5 -5
  140. package/dist/market_adapter/inputs/kibana_source.d.ts +1 -2
  141. package/dist/market_adapter/inputs/kibana_source.d.ts.map +1 -1
  142. package/dist/market_adapter/inputs/kibana_source.js +1 -1
  143. package/dist/market_adapter/inputs/kibana_source.js.map +1 -1
  144. package/dist/market_adapter/lp_chart_strategy_loader.d.ts +1 -2
  145. package/dist/market_adapter/lp_chart_strategy_loader.d.ts.map +1 -1
  146. package/dist/market_adapter/lp_chart_strategy_loader.js +4 -4
  147. package/dist/market_adapter/lp_chart_strategy_loader.js.map +1 -1
  148. package/dist/market_adapter/market_adapter.d.ts.map +1 -1
  149. package/dist/market_adapter/market_adapter.js +2 -1
  150. package/dist/market_adapter/market_adapter.js.map +1 -1
  151. package/dist/modules/account_bots.d.ts +3 -0
  152. package/dist/modules/account_bots.d.ts.map +1 -1
  153. package/dist/modules/account_bots.js +156 -46
  154. package/dist/modules/account_bots.js.map +1 -1
  155. package/dist/modules/account_orders.d.ts +1 -7
  156. package/dist/modules/account_orders.d.ts.map +1 -1
  157. package/dist/modules/account_orders.js +9 -17
  158. package/dist/modules/account_orders.js.map +1 -1
  159. package/dist/modules/bitshares_client.d.ts +2 -14
  160. package/dist/modules/bitshares_client.d.ts.map +1 -1
  161. package/dist/modules/bitshares_client.js +22 -31
  162. package/dist/modules/bitshares_client.js.map +1 -1
  163. package/dist/modules/bot_settings.js +1 -1
  164. package/dist/modules/bot_settings.js.map +1 -1
  165. package/dist/modules/chain_keys.js +2 -2
  166. package/dist/modules/chain_keys.js.map +1 -1
  167. package/dist/modules/chain_orders.d.ts +2 -3
  168. package/dist/modules/chain_orders.d.ts.map +1 -1
  169. package/dist/modules/chain_orders.js +8 -25
  170. package/dist/modules/chain_orders.js.map +1 -1
  171. package/dist/modules/config.d.ts +2 -0
  172. package/dist/modules/config.d.ts.map +1 -1
  173. package/dist/modules/config.js +6 -1
  174. package/dist/modules/config.js.map +1 -1
  175. package/dist/modules/constants.d.ts +0 -1
  176. package/dist/modules/constants.d.ts.map +1 -1
  177. package/dist/modules/constants.js +1 -5
  178. package/dist/modules/constants.js.map +1 -1
  179. package/dist/modules/credential_policy.js +1 -1
  180. package/dist/modules/credential_policy.js.map +1 -1
  181. package/dist/modules/dexbot_class.d.ts.map +1 -1
  182. package/dist/modules/dexbot_class.js +3 -2
  183. package/dist/modules/dexbot_class.js.map +1 -1
  184. package/dist/modules/dexbot_cow_runtime.d.ts +0 -7
  185. package/dist/modules/dexbot_cow_runtime.d.ts.map +1 -1
  186. package/dist/modules/dexbot_cow_runtime.js +95 -0
  187. package/dist/modules/dexbot_cow_runtime.js.map +1 -1
  188. package/dist/modules/dexbot_state_recovery.d.ts.map +1 -1
  189. package/dist/modules/dexbot_state_recovery.js +22 -2
  190. package/dist/modules/dexbot_state_recovery.js.map +1 -1
  191. package/dist/modules/fund_registry.d.ts.map +1 -1
  192. package/dist/modules/fund_registry.js +5 -2
  193. package/dist/modules/fund_registry.js.map +1 -1
  194. package/dist/modules/launcher/bot_supervisor.d.ts.map +1 -1
  195. package/dist/modules/launcher/bot_supervisor.js +6 -7
  196. package/dist/modules/launcher/bot_supervisor.js.map +1 -1
  197. package/dist/modules/launcher/foreign_cred_daemon.d.ts.map +1 -1
  198. package/dist/modules/launcher/foreign_cred_daemon.js +6 -0
  199. package/dist/modules/launcher/foreign_cred_daemon.js.map +1 -1
  200. package/dist/modules/launcher/market_adapter_runtime.d.ts +2 -3
  201. package/dist/modules/launcher/market_adapter_runtime.d.ts.map +1 -1
  202. package/dist/modules/launcher/market_adapter_runtime.js +7 -15
  203. package/dist/modules/launcher/market_adapter_runtime.js.map +1 -1
  204. package/dist/modules/launcher/monolithic_runtime.d.ts.map +1 -1
  205. package/dist/modules/launcher/monolithic_runtime.js +1 -0
  206. package/dist/modules/launcher/monolithic_runtime.js.map +1 -1
  207. package/dist/modules/launcher/status_reporting.d.ts +1 -2
  208. package/dist/modules/launcher/status_reporting.d.ts.map +1 -1
  209. package/dist/modules/launcher/status_reporting.js +1 -4
  210. package/dist/modules/launcher/status_reporting.js.map +1 -1
  211. package/dist/modules/order/accounting.js +2 -2
  212. package/dist/modules/order/accounting.js.map +1 -1
  213. package/dist/modules/order/format.d.ts +0 -8
  214. package/dist/modules/order/format.d.ts.map +1 -1
  215. package/dist/modules/order/format.js +0 -8
  216. package/dist/modules/order/format.js.map +1 -1
  217. package/dist/modules/order/grid.d.ts.map +1 -1
  218. package/dist/modules/order/grid.js +146 -32
  219. package/dist/modules/order/grid.js.map +1 -1
  220. package/dist/modules/order/logger.js +1 -1
  221. package/dist/modules/order/logger.js.map +1 -1
  222. package/dist/modules/order/logger_state.d.ts +1 -13
  223. package/dist/modules/order/logger_state.d.ts.map +1 -1
  224. package/dist/modules/order/logger_state.js +1 -11
  225. package/dist/modules/order/logger_state.js.map +1 -1
  226. package/dist/modules/order/manager.d.ts +13 -0
  227. package/dist/modules/order/manager.d.ts.map +1 -1
  228. package/dist/modules/order/manager.js +75 -2
  229. package/dist/modules/order/manager.js.map +1 -1
  230. package/dist/modules/order/processed_fill_store.d.ts +0 -5
  231. package/dist/modules/order/processed_fill_store.d.ts.map +1 -1
  232. package/dist/modules/order/processed_fill_store.js +1 -12
  233. package/dist/modules/order/processed_fill_store.js.map +1 -1
  234. package/dist/modules/order/sync_engine.d.ts.map +1 -1
  235. package/dist/modules/order/sync_engine.js +10 -3
  236. package/dist/modules/order/sync_engine.js.map +1 -1
  237. package/dist/modules/order/utils/math.d.ts +80 -1
  238. package/dist/modules/order/utils/math.d.ts.map +1 -1
  239. package/dist/modules/order/utils/math.js +138 -2
  240. package/dist/modules/order/utils/math.js.map +1 -1
  241. package/dist/modules/order/utils/order.d.ts.map +1 -1
  242. package/dist/modules/order/utils/order.js +10 -2
  243. package/dist/modules/order/utils/order.js.map +1 -1
  244. package/dist/modules/paths.d.ts +26 -1
  245. package/dist/modules/paths.d.ts.map +1 -1
  246. package/dist/modules/paths.js +39 -6
  247. package/dist/modules/paths.js.map +1 -1
  248. package/dist/modules/runtime_settings.js +3 -1
  249. package/dist/modules/runtime_settings.js.map +1 -1
  250. package/dist/modules/settings_merge.d.ts.map +1 -1
  251. package/dist/modules/settings_merge.js +3 -1
  252. package/dist/modules/settings_merge.js.map +1 -1
  253. package/dist/modules/storage/browser_adapter.d.ts +8 -3
  254. package/dist/modules/storage/browser_adapter.d.ts.map +1 -1
  255. package/dist/modules/storage/browser_adapter.js +53 -4
  256. package/dist/modules/storage/browser_adapter.js.map +1 -1
  257. package/dist/modules/utils/sanitize_key.d.ts +7 -0
  258. package/dist/modules/utils/sanitize_key.d.ts.map +1 -0
  259. package/dist/modules/utils/sanitize_key.js +15 -0
  260. package/dist/modules/utils/sanitize_key.js.map +1 -0
  261. package/dist/pm2.js +6 -6
  262. package/dist/pm2.js.map +1 -1
  263. package/dist/scripts/analyze-git.js +2 -1
  264. package/dist/scripts/analyze-git.js.map +1 -1
  265. package/dist/scripts/analyze-orders.d.ts +2 -2
  266. package/dist/scripts/analyze-orders.d.ts.map +1 -1
  267. package/dist/scripts/analyze-orders.js +6 -14
  268. package/dist/scripts/analyze-orders.js.map +1 -1
  269. package/dist/scripts/runner.js +1 -1
  270. package/dist/scripts/runner.js.map +1 -1
  271. package/dist/scripts/update.js +1 -1
  272. package/dist/scripts/update.js.map +1 -1
  273. package/docs/BITSHARES_ONBOARDING.md +63 -18
  274. package/docs/COPY_ON_WRITE_MASTER_PLAN.md +5 -14
  275. package/docs/COW_INVARIANTS.md +4 -4
  276. package/docs/CREDENTIAL_SECURITY.md +0 -11
  277. package/docs/DEXBOT_COMPARISON.md +11 -11
  278. package/docs/EVOLUTION.md +12 -10
  279. package/docs/FUND_MOVEMENT_AND_ACCOUNTING.md +27 -83
  280. package/docs/GRID_RECALCULATION.md +1 -13
  281. package/docs/GRID_RECONCILE.md +24 -24
  282. package/docs/LIFECYCLE.md +4 -4
  283. package/docs/LOGGING.md +1 -1
  284. package/docs/MPA_CREDIT_USAGE.md +3 -3
  285. package/docs/README.md +2 -2
  286. package/docs/WORKFLOW.md +2 -2
  287. package/docs/architecture.md +43 -38
  288. package/docs/developer_guide.md +16 -18
  289. package/market_adapter/README.md +0 -2
  290. package/modules/README.md +2 -1
  291. package/package.json +2 -3
  292. package/scripts/README.md +1 -1
  293. package/scripts/lib/dexbot-paths.sh +20 -11
  294. package/claw/openclaw.plugin.json +0 -13
  295. package/dist/market_adapter/merge_lp_data.d.ts +0 -3
  296. package/dist/market_adapter/merge_lp_data.d.ts.map +0 -1
  297. package/dist/market_adapter/merge_lp_data.js +0 -125
  298. package/dist/market_adapter/merge_lp_data.js.map +0 -1
  299. package/dist/market_adapter/utils/paths.d.ts +0 -3
  300. package/dist/market_adapter/utils/paths.d.ts.map +0 -1
  301. package/dist/market_adapter/utils/paths.js +0 -5
  302. package/dist/market_adapter/utils/paths.js.map +0 -1
@@ -41,17 +41,7 @@ const DEXBOT_VERSION = (() => {
41
41
  })();
42
42
 
43
43
  function resolveMemuScript() {
44
- const candidates = [
45
- PATHS.CLAW.MEMU_RUNNER_SCRIPT,
46
- ];
47
-
48
- for (const candidate of candidates) {
49
- if (storage.exists(candidate)) {
50
- return candidate;
51
- }
52
- }
53
-
54
- return candidates[0];
44
+ return PATHS.CLAW.MEMU_RUNNER_SCRIPT;
55
45
  }
56
46
 
57
47
  function ensureMemuDir(dir: any) {
@@ -132,6 +122,11 @@ function runMemuPython(args: string[], options: Record<string, any> = {}) {
132
122
  });
133
123
 
134
124
  if (options.stdin) {
125
+ // The child may exit before it drains stdin (bad args, crash); without
126
+ // an 'error' listener the resulting EPIPE crashes the host process.
127
+ child.stdin.on('error', () => {
128
+ // Best-effort write; the close handler reports the real exit status.
129
+ });
135
130
  child.stdin.write(JSON.stringify(options.stdin));
136
131
  child.stdin.end();
137
132
  }
@@ -431,26 +426,78 @@ function describeMemuBridge(options: Record<string, any> = {}) {
431
426
  };
432
427
  }
433
428
 
429
+ /**
430
+ * Required-argument spec shared by runMemuCommand, the memU MCP server, and
431
+ * the claw bridge's memu-* commands, so every surface rejects bad input with
432
+ * the same message instead of maintaining three copies of the checks.
433
+ */
434
+ const MEMU_REQUIRED_ARGS: Record<string, { groups: string[][]; message: string }> = {
435
+ 'memorize': {
436
+ groups: [['resourceUrl'], ['modality']],
437
+ message: 'memorize requires resourceUrl and modality'
438
+ },
439
+ 'retrieve': {
440
+ groups: [['queries']],
441
+ message: 'retrieve requires queries'
442
+ },
443
+ 'create-item': {
444
+ groups: [['categoryId', 'categoryName', 'category'], ['summary']],
445
+ message: 'create-item requires categoryId or categoryName, plus summary'
446
+ },
447
+ 'update-item': {
448
+ groups: [['itemId'], ['updates']],
449
+ message: 'update-item requires itemId and updates'
450
+ },
451
+ 'delete-item': {
452
+ groups: [['itemId']],
453
+ message: 'delete-item requires itemId'
454
+ },
455
+ 'memorize-conversation': {
456
+ groups: [['messages']],
457
+ message: 'memorize-conversation requires messages array'
458
+ },
459
+ 'memorize-trading-context': {
460
+ groups: [['context']],
461
+ message: 'memorize-trading-context requires context'
462
+ },
463
+ 'retrieve-trading-context': {
464
+ groups: [['query']],
465
+ message: 'retrieve-trading-context requires query'
466
+ }
467
+ };
468
+
469
+ /**
470
+ * Throw when a memU command is missing required arguments.
471
+ * Each group lists acceptable alternative field names; every group must be
472
+ * satisfied by at least one present (truthy) field.
473
+ */
474
+ function validateMemuCommandArgs(command: string, options: Record<string, any>) {
475
+ const spec = MEMU_REQUIRED_ARGS[command];
476
+ if (!spec) {
477
+ return;
478
+ }
479
+
480
+ const satisfied = spec.groups.every(
481
+ (group) => group.some((field) => options[field])
482
+ );
483
+ if (!satisfied) {
484
+ throw new Error(spec.message);
485
+ }
486
+ }
487
+
434
488
  async function runMemuCommand(command: string, options: Record<string, any> = {}) {
489
+ validateMemuCommandArgs(command, options);
435
490
  const bridge = createMemuBridge(options);
436
491
 
437
492
  switch (command) {
438
493
  case 'manifest':
439
494
  return describeMemuBridge(options);
440
495
 
441
- case 'memorize': {
442
- if (!options.resourceUrl || !options.modality) {
443
- throw new Error('memorize requires resourceUrl and modality');
444
- }
496
+ case 'memorize':
445
497
  return bridge.memorize(options.resourceUrl, options.modality, options.user);
446
- }
447
498
 
448
- case 'retrieve': {
449
- if (!options.queries) {
450
- throw new Error('retrieve requires queries');
451
- }
499
+ case 'retrieve':
452
500
  return bridge.retrieve(options.queries, options.where, options.method || 'rag');
453
- }
454
501
 
455
502
  case 'list-categories':
456
503
  return bridge.listCategories(normalizeScopeWhere(options.where, options.user));
@@ -458,32 +505,19 @@ async function runMemuCommand(command: string, options: Record<string, any> = {}
458
505
  case 'list-items':
459
506
  return bridge.listItems(normalizeScopeWhere(options.where, options.user));
460
507
 
461
- case 'create-item': {
462
- const categoryRef = options.categoryId || options.categoryName || options.category;
463
- if (!categoryRef || !options.summary) {
464
- throw new Error('create-item requires categoryId or categoryName, plus summary');
465
- }
508
+ case 'create-item':
466
509
  return bridge.createMemoryItem(
467
- categoryRef,
510
+ options.categoryId || options.categoryName || options.category,
468
511
  options.summary,
469
512
  options.memoryType || 'knowledge',
470
513
  options.user
471
514
  );
472
- }
473
515
 
474
- case 'update-item': {
475
- if (!options.itemId || !options.updates) {
476
- throw new Error('update-item requires itemId and updates');
477
- }
516
+ case 'update-item':
478
517
  return bridge.updateMemoryItem(options.itemId, options.updates);
479
- }
480
518
 
481
- case 'delete-item': {
482
- if (!options.itemId) {
483
- throw new Error('delete-item requires itemId');
484
- }
519
+ case 'delete-item':
485
520
  return bridge.deleteMemoryItem(options.itemId);
486
- }
487
521
 
488
522
  case 'clear':
489
523
  return bridge.clearMemory(normalizeScopeWhere(options.where, options.user));
@@ -491,31 +525,19 @@ async function runMemuCommand(command: string, options: Record<string, any> = {}
491
525
  case 'status':
492
526
  return bridge.getStatus(normalizeScopeWhere(options.where, options.user));
493
527
 
494
- case 'memorize-conversation': {
495
- if (!options.messages) {
496
- throw new Error('memorize-conversation requires messages array');
497
- }
528
+ case 'memorize-conversation':
498
529
  return bridge.memorizeConversation(options.messages, options.user);
499
- }
500
530
 
501
- case 'memorize-trading-context': {
502
- if (!options.context) {
503
- throw new Error('memorize-trading-context requires context');
504
- }
531
+ case 'memorize-trading-context':
505
532
  return bridge.memorizeTradingContext(options.context, options.user);
506
- }
507
533
 
508
- case 'retrieve-trading-context': {
509
- if (!options.query) {
510
- throw new Error('retrieve-trading-context requires query');
511
- }
534
+ case 'retrieve-trading-context':
512
535
  return bridge.retrieveTradingContext(options.query, options.user);
513
- }
514
536
 
515
537
  default:
516
538
  throw new Error(`Unsupported memU command: ${command}`);
517
539
  }
518
540
  }
519
541
 
520
- export { createMemuBridge, describeMemuBridge, runMemuCommand, resolveMemuScript, DEFAULT_MEMU_DIR }
542
+ export { createMemuBridge, describeMemuBridge, runMemuCommand, validateMemuCommandArgs }
521
543
 
@@ -5,7 +5,7 @@ import { loadDexbotOrderUtils } from './dexbot_bridge.js';
5
5
 
6
6
  const CORE_SYMBOL = 'BTS';
7
7
 
8
- async function requireBtsBackedMpa(mpaSymbolOrId: any) {
8
+ async function requireBtsBackedMpa(mpaSymbolOrId: any, hint?: string) {
9
9
  const mpaAsset = await getAsset(mpaSymbolOrId);
10
10
  if (!mpaAsset) {
11
11
  throw new Error(`Asset not found: ${mpaSymbolOrId}`);
@@ -19,7 +19,8 @@ async function requireBtsBackedMpa(mpaSymbolOrId: any) {
19
19
  throw new Error(`Could not resolve backing asset for ${mpaSymbolOrId}`);
20
20
  }
21
21
  if (backingAsset.symbol !== CORE_SYMBOL) {
22
- throw new Error(`${mpaAsset.symbol || mpaSymbolOrId} is backed by ${backingAsset.symbol}, not ${CORE_SYMBOL}`);
22
+ const hintSuffix = hint ? `; ${hint}` : '';
23
+ throw new Error(`${mpaAsset.symbol || mpaSymbolOrId} is backed by ${backingAsset.symbol}, not ${CORE_SYMBOL}${hintSuffix}`);
23
24
  }
24
25
 
25
26
  return {
@@ -62,5 +63,27 @@ function computeBtsPerMpa(settlementPrice: any, mpaAsset: any, backingAsset: any
62
63
  return null;
63
64
  }
64
65
 
65
- export { CORE_SYMBOL, computeBtsPerMpa, requireBtsBackedMpa }
66
+ /**
67
+ * Compute the normalized debt/collateral figures for a raw call order.
68
+ * Canonical implementation shared by position discovery and the position
69
+ * manager so both surfaces report identical amounts and ratios.
70
+ */
71
+ function computeCallOrderAmounts(callOrder: any, mpaAsset: any, backingAsset: any, bitassetData: any) {
72
+ const blockchainToFloat = getBlockchainToFloat();
73
+ const debtAmount = blockchainToFloat(callOrder.debt, mpaAsset.precision);
74
+ const collateralAmount = blockchainToFloat(callOrder.collateral, backingAsset.precision);
75
+ const btsPerMpa = computeBtsPerMpa(bitassetData?.current_feed?.settlement_price, mpaAsset, backingAsset);
76
+ const debtValueInBts = debtAmount && btsPerMpa ? debtAmount * btsPerMpa : 0;
77
+ const collateralRatio = debtValueInBts > 0 ? collateralAmount / debtValueInBts : null;
78
+
79
+ return {
80
+ btsPerMpa,
81
+ collateralAmount: collateralAmount || 0,
82
+ collateralRatio,
83
+ debtAmount: debtAmount || 0,
84
+ debtValueInBts
85
+ };
86
+ }
87
+
88
+ export { CORE_SYMBOL, computeBtsPerMpa, computeCallOrderAmounts, getBlockchainToFloat, requireBtsBackedMpa }
66
89
 
@@ -9,16 +9,11 @@
9
9
  */
10
10
 
11
11
 
12
- import { loadDexbotOrderUtils } from './dexbot_bridge.js';
13
- import { computeBtsPerMpa } from './mpa_utils.js';
14
12
  import { roundTo } from '../../modules/order/utils/math.js';
15
13
  'use strict';
16
14
 
17
15
  import { getAsset, getBackingAsset, getBitassetData, getFullAccount } from './chain_queries.js';
18
-
19
- function getBlockchainToFloat() {
20
- return loadDexbotOrderUtils().blockchainToFloat;
21
- }
16
+ import { computeCallOrderAmounts } from './mpa_utils.js';
22
17
 
23
18
  /**
24
19
  * Normalize a raw call order into a position object compatible with
@@ -31,13 +26,7 @@ function getBlockchainToFloat() {
31
26
  * @returns {Object} Normalized position
32
27
  */
33
28
  function normalizeCallOrder(callOrder: any, mpaAsset: any, backingAsset: any, bitassetData: any) {
34
- const blockchainToFloat = getBlockchainToFloat();
35
- const debtAmount = blockchainToFloat(callOrder.debt, mpaAsset.precision);
36
- const collateralAmount = blockchainToFloat(callOrder.collateral, backingAsset.precision);
37
- const settlement = bitassetData?.current_feed?.settlement_price;
38
- const btsPerMpa = computeBtsPerMpa(settlement, mpaAsset, backingAsset);
39
- const debtValueInBts = debtAmount && btsPerMpa ? debtAmount * btsPerMpa : 0;
40
- const collateralRatio = debtValueInBts > 0 ? collateralAmount / debtValueInBts : null;
29
+ const amounts = computeCallOrderAmounts(callOrder, mpaAsset, backingAsset, bitassetData);
41
30
 
42
31
  return {
43
32
  id: callOrder.id,
@@ -48,11 +37,11 @@ function normalizeCallOrder(callOrder: any, mpaAsset: any, backingAsset: any, bi
48
37
  backingSymbol: backingAsset.symbol,
49
38
  onChain: {
50
39
  callOrderId: callOrder.id,
51
- collateralAmount: collateralAmount || 0,
52
- collateralRatio,
53
- debtAmount: debtAmount || 0,
54
- debtValueInBts,
55
- btsPerMpa,
40
+ collateralAmount: amounts.collateralAmount,
41
+ collateralRatio: amounts.collateralRatio,
42
+ debtAmount: amounts.debtAmount,
43
+ debtValueInBts: amounts.debtValueInBts,
44
+ btsPerMpa: amounts.btsPerMpa,
56
45
  feedPublicationTime: bitassetData?.current_feed_publication_time || null,
57
46
  },
58
47
  };
@@ -76,21 +65,21 @@ async function discoverPositions(accountName: string) {
76
65
  callOrders.map((co: any) => co?.call_price?.quote?.asset_id).filter(Boolean)
77
66
  )];
78
67
 
79
- // Resolve all assets in parallel
68
+ // Resolve every debt asset's MPA/backing/bitasset triple in parallel.
80
69
  const assetCache = new Map();
81
70
  const bitassetCache = new Map();
82
71
 
83
- for (const assetId of debtAssetIds) {
84
- const mpaAsset = await getAsset(assetId);
85
- if (!mpaAsset) continue;
86
- assetCache.set(assetId, mpaAsset);
72
+ await Promise.all(debtAssetIds.map(async (assetId) => {
73
+ const [mpaAsset, backingAsset, bitassetData] = await Promise.all([
74
+ getAsset(assetId).catch(() => null),
75
+ getBackingAsset(assetId).catch(() => null),
76
+ getBitassetData(assetId).catch(() => null)
77
+ ]);
87
78
 
88
- const backingAsset = await getBackingAsset(assetId);
79
+ if (mpaAsset) assetCache.set(assetId, mpaAsset);
89
80
  if (backingAsset) assetCache.set(`backing:${assetId}`, backingAsset);
90
-
91
- const bitassetData = await getBitassetData(assetId);
92
81
  if (bitassetData) bitassetCache.set(assetId, bitassetData);
93
- }
82
+ }));
94
83
 
95
84
  // Normalize each call order
96
85
  const positions: any[] = [];
@@ -3,11 +3,10 @@ import { getStorage } from '../../modules/storage/index.js';
3
3
  import { path } from '../../modules/path_api.js';
4
4
  import { PATHS } from '../../modules/paths.js';
5
5
  import { Config } from '../../modules/config.js';
6
- import { requireBtsBackedMpa, computeBtsPerMpa } from './mpa_utils.js';
6
+ import { requireBtsBackedMpa, computeCallOrderAmounts, getBlockchainToFloat } from './mpa_utils.js';
7
7
  import { listenForFills } from './chain_actions.js';
8
8
  import { writeJsonFileAtomic } from './dexbot_profiles.js';
9
- import { loadDexbotOrderUtils } from './dexbot_bridge.js';
10
- import { clone } from './utils.js';
9
+ import { clone, requirePositiveNumber } from './utils.js';
11
10
  const storage = getStorage();
12
11
  import { closeShortOnBts, openShortOnBts, placeTakeProfitBuyOrderOnBts } from './short_mpa_strategy.js';
13
12
  import { getAsset, getBackingAsset, getBalances, getBitassetData, getFullAccount } from './chain_queries.js';
@@ -15,10 +14,6 @@ import { getErrorMessage } from '../../modules/utils/errors.js';
15
14
 
16
15
  import type { ShortPositionOptions, PositionManagerOptions } from './types.js';
17
16
 
18
- function getBlockchainToFloat() {
19
- return loadDexbotOrderUtils().blockchainToFloat;
20
- }
21
-
22
17
  const DEFAULT_STATE_PATH = PATHS.CLAW.POSITIONS_FILE;
23
18
  const STRATEGY_NAME = 'short-mpa-bts';
24
19
 
@@ -38,14 +33,6 @@ function requireString(value: any, fieldName: string) {
38
33
  return value.trim();
39
34
  }
40
35
 
41
- function requirePositiveNumber(value: any, fieldName: string) {
42
- const numericValue = Number(value);
43
- if (!Number.isFinite(numericValue) || numericValue <= 0) {
44
- throw new Error(`${fieldName} must be a positive number`);
45
- }
46
- return numericValue;
47
- }
48
-
49
36
  function almostZero(value: any, epsilon: number = 1e-12) {
50
37
  return Math.abs(Number(value) || 0) <= epsilon;
51
38
  }
@@ -116,18 +103,6 @@ function toTrackedAsset(asset: any) {
116
103
  return asset ? { id: asset.id, precision: asset.precision, symbol: asset.symbol } : null;
117
104
  }
118
105
 
119
- function resolvePositionAssets(position: any) {
120
- const tracked = position?.assets || {};
121
- return {
122
- collateral: tracked.collateral || null,
123
- mpa: tracked.mpa || null
124
- };
125
- }
126
-
127
- function getOrderTracking(position: any, side: string) {
128
- return side === 'entry' ? position.entry : position.exit;
129
- }
130
-
131
106
  function getAssetPrecisionFromTracking(orderTracking: any, assetId: string) {
132
107
  if (orderTracking?.sellAsset?.id === assetId) {
133
108
  return orderTracking.sellAsset.precision;
@@ -265,7 +240,7 @@ function refreshPositionPnl(position: any) {
265
240
  }
266
241
 
267
242
  function normalizeCallPosition(callOrder: any, mpaAsset: any, backingAsset: any, bitassetData: any) {
268
- if (!callOrder) {
243
+ if (!callOrder || !mpaAsset || !backingAsset) {
269
244
  return {
270
245
  collateralAmount: 0,
271
246
  collateralRatio: null,
@@ -276,18 +251,13 @@ function normalizeCallPosition(callOrder: any, mpaAsset: any, backingAsset: any,
276
251
  };
277
252
  }
278
253
 
279
- const blockchainToFloat = getBlockchainToFloat();
280
- const debtAmount = blockchainToFloat(callOrder.debt, mpaAsset.precision);
281
- const collateralAmount = blockchainToFloat(callOrder.collateral, backingAsset.precision);
282
- const btsPerMpa = computeBtsPerMpa(bitassetData?.current_feed?.settlement_price, mpaAsset, backingAsset);
283
- const debtValueInBts = debtAmount && btsPerMpa ? debtAmount * btsPerMpa : 0;
284
- const collateralRatio = debtValueInBts > 0 ? collateralAmount / debtValueInBts : null;
254
+ const amounts = computeCallOrderAmounts(callOrder, mpaAsset, backingAsset, bitassetData);
285
255
 
286
256
  return {
287
- collateralAmount: collateralAmount || 0,
288
- collateralRatio,
289
- debtAmount: debtAmount || 0,
290
- debtValueInBts,
257
+ collateralAmount: amounts.collateralAmount,
258
+ collateralRatio: amounts.collateralRatio,
259
+ debtAmount: amounts.debtAmount,
260
+ debtValueInBts: amounts.debtValueInBts,
291
261
  exists: true,
292
262
  feedPublicationTime: bitassetData?.current_feed_publication_time || null
293
263
  };
@@ -560,7 +530,14 @@ class PositionManager {
560
530
  });
561
531
  position.lastCloseTx = result?.repayResult?.raw || null;
562
532
 
563
- await this.syncPosition(positionId);
533
+ // Persist before syncing: syncPosition can throw (network failure, asset
534
+ // resolution), and losing the close event/tx record after a successful
535
+ // on-chain repay would corrupt the position history. Mirrors openShort.
536
+ await this.saveState();
537
+
538
+ await this.syncPosition(positionId).catch((syncErr: any) => {
539
+ console.warn(`[POSITION] Post-close sync failed for ${positionId}: ${getErrorMessage(syncErr)}`);
540
+ });
564
541
  return this.getPosition(positionId);
565
542
  }
566
543
 
@@ -577,7 +554,15 @@ class PositionManager {
577
554
  const mpaAsset = await getAsset(position.debt.asset);
578
555
  const backingAsset = await getBackingAsset(position.debt.asset);
579
556
  const bitassetData = await getBitassetData(position.debt.asset);
580
- const callOrder = callOrders.find((entry: any) => entry?.call_price?.quote?.asset_id === mpaAsset?.id) || null;
557
+ // Only match a call order when the debt asset resolved; matching against
558
+ // an undefined id could pair the position with an unrelated call order,
559
+ // and normalizing without asset precision would crash.
560
+ if (!mpaAsset) {
561
+ console.warn(`[POSITION] Could not resolve debt asset ${position.debt.asset} for ${positionId}; skipping on-chain debt sync`);
562
+ }
563
+ const callOrder = mpaAsset
564
+ ? callOrders.find((entry: any) => entry?.call_price?.quote?.asset_id === mpaAsset.id) || null
565
+ : null;
581
566
  const debtState = normalizeCallPosition(callOrder, mpaAsset, backingAsset, bitassetData);
582
567
  const openOrderIds = openOrders.map((entry: any) => entry?.id).filter(Boolean);
583
568
  const entryOrderOpen = position.entry.orderId ? openOrderIds.includes(position.entry.orderId) : false;
@@ -692,8 +677,14 @@ class PositionManager {
692
677
  });
693
678
  changed = true;
694
679
 
680
+ // Isolate user callback failures: a rejected onFill must not abort
681
+ // this handler before saveState()/post-fill syncs persist the fill.
695
682
  if (typeof onFill === 'function') {
696
- await onFill(clone(position), fill);
683
+ try {
684
+ await onFill(clone(position), fill);
685
+ } catch (err: any) {
686
+ console.error(`[POSITION] onFill callback failed for ${position.id}: ${getErrorMessage(err)}`);
687
+ }
697
688
  }
698
689
  }
699
690
  }
@@ -1,6 +1,5 @@
1
1
 
2
2
  import { getStorage } from '../../modules/storage/index.js';
3
- import { path } from '../../modules/path_api.js';
4
3
  import { PATHS } from '../../modules/paths.js';
5
4
  import { PositionManager, DEFAULT_STATE_PATH } from './position_manager.js';
6
5
  import * as client from './bitshares_client.js';
@@ -178,12 +177,14 @@ function createPositionManagerWatcher(options: Record<string, any> = {}) {
178
177
  throw new Error('accountName is required. Pass --account or set BITSHARES_ACCOUNT.');
179
178
  }
180
179
 
181
- running = true;
182
180
  logger.info(`[position-manager-watch] starting for ${resolvedOptions.accountName}`);
183
181
 
182
+ // Only flag running once the connection succeeded: a failed start must
183
+ // leave the watcher non-running (and re-startable) with healthy=false.
184
184
  await waitForConnected().catch((err: any) => {
185
185
  throw new Error(`BitShares connection not ready: ${getErrorMessage(err)}`);
186
186
  });
187
+ running = true;
187
188
 
188
189
  await manager.syncAllPositions()
189
190
  .then(() => recordSyncSuccess())
@@ -2,15 +2,7 @@
2
2
  import { Config } from '../../modules/config.js';
3
3
  import { borrowMpa, createLimitOrder, repayMpaDebt } from './chain_actions.js';
4
4
  import { requireBtsBackedMpa } from './mpa_utils.js';
5
-
6
- function requirePositiveNumber(value: any, fieldName: string) {
7
- const numericValue = Number(value);
8
- if (!Number.isFinite(numericValue) || numericValue <= 0) {
9
- throw new Error(`${fieldName} must be a positive number`);
10
- }
11
-
12
- return numericValue;
13
- }
5
+ import { requirePositiveNumber } from './utils.js';
14
6
 
15
7
  function requireNonNegativeNumber(value: any, fieldName: string) {
16
8
  const numericValue = Number(value);
@@ -42,11 +42,13 @@ export function tomlString(value: any) {
42
42
  }
43
43
 
44
44
  export function buildSkillTomlLines(skillName: string, description: string, tags: string[], tools: any[]) {
45
+ // name/description go through tomlString so embedded quotes/backslashes
46
+ // produce valid escaped TOML basic strings.
45
47
  const lines = [
46
48
  '[skill]',
47
- `name = "${skillName}"`,
48
- `description = "${description}"`,
49
- `version = "${DEXBOT_VERSION}"`,
49
+ `name = ${tomlString(skillName)}`,
50
+ `description = ${tomlString(description)}`,
51
+ `version = ${tomlString(DEXBOT_VERSION)}`,
50
52
  `tags = [${tags.map(t => JSON.stringify(t)).join(', ')}]`
51
53
  ];
52
54
 
@@ -5,5 +5,13 @@ function clone(value: any) {
5
5
  return JSON.parse(JSON.stringify(value));
6
6
  }
7
7
 
8
- export { clone }
8
+ function requirePositiveNumber(value: any, fieldName: string) {
9
+ const numericValue = Number(value);
10
+ if (!Number.isFinite(numericValue) || numericValue <= 0) {
11
+ throw new Error(`${fieldName} must be a positive number`);
12
+ }
13
+ return numericValue;
14
+ }
15
+
16
+ export { clone, requirePositiveNumber }
9
17
 
package/claw/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dexbot2-claw",
3
- "version": "1.4.19",
3
+ "version": "1.4.21",
4
4
  "private": true,
5
5
  "description": "Claw bridge and runtime integration layer for BitShares and DEXBot2.",
6
6
  "type": "module",
@@ -3,6 +3,8 @@
3
3
  import definePluginEntry from 'openclaw/plugin-sdk/plugin-entry';
4
4
  import { getClawToolCatalog } from '../../modules/claw_catalog.js';
5
5
  import { runClawCommand } from '../../modules/claw_bridge.js';
6
+ import { getErrorMessage } from '../../../modules/utils/errors.js';
7
+
6
8
  function formatResult(result: any) {
7
9
  return JSON.stringify(result, null, 2);
8
10
  }
@@ -18,16 +20,31 @@ const plugin = definePluginEntry({
18
20
  description: `[${tool.risk}] ${tool.description}`,
19
21
  parameters: tool.inputSchema,
20
22
  async execute(_id: any, params: any) {
21
- const result = await runClawCommand(tool.command, { ...params, runtimeName: 'openclaw' });
22
- return {
23
- content: [
24
- {
25
- type: "text",
26
- text: formatResult(result)
27
- }
28
- ],
29
- structuredContent: result
30
- };
23
+ // Match the MCP servers' convention: tool failures surface as an
24
+ // isError result instead of a raw rejected promise.
25
+ try {
26
+ const result = await runClawCommand(tool.command, { ...params, runtimeName: 'openclaw' });
27
+ return {
28
+ content: [
29
+ {
30
+ type: "text",
31
+ text: formatResult(result)
32
+ }
33
+ ],
34
+ structuredContent: result
35
+ };
36
+ } catch (error: any) {
37
+ const text = error && error.stack ? error.stack : getErrorMessage(error);
38
+ return {
39
+ content: [
40
+ {
41
+ type: "text",
42
+ text
43
+ }
44
+ ],
45
+ isError: true
46
+ };
47
+ }
31
48
  }
32
49
  });
33
50
  }
@@ -2,7 +2,7 @@
2
2
  "id": "bitshares-claw",
3
3
  "name": "BitShares Claw",
4
4
  "description": "Native BitShares and DEXBot2 tools from the DEXBot2 claw integration",
5
- "version": "1.4.19",
5
+ "version": "1.4.21",
6
6
  "skills": [
7
7
  "skills"
8
8
  ],
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bitshares-claw-openclaw-plugin",
3
3
  "private": true,
4
- "version": "1.4.19",
4
+ "version": "1.4.21",
5
5
  "type": "module",
6
6
  "main": "index.js"
7
7
  }
@@ -154,5 +154,5 @@ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href)
154
154
  });
155
155
  }
156
156
 
157
- export { describeScriptRuntimeManifest as describeRuntimeManifest, main }
157
+ export { describeScriptRuntimeManifest as describeRuntimeManifest }
158
158