@moltbankhq/openclaw 0.1.7 → 0.1.8

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 (3) hide show
  1. package/README.md +8 -5
  2. package/index.ts +97 -30
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -40,6 +40,8 @@ This package connects your OpenClaw agent to MoltBank's stablecoin treasury infr
40
40
 
41
41
  Once set up, your agent can manage treasury operations, set per-agent spending limits, handle x402 payments, and interact with MoltBank's MCP server — all within OpenClaw.
42
42
 
43
+ The standalone `moltbank` CLI is for install, setup, auth status, and repair flows. Actual treasury operations should run through the installed skill wrapper scripts inside the skill directory.
44
+
43
45
  ## Setup
44
46
 
45
47
  After installing, run:
@@ -48,16 +50,17 @@ After installing, run:
48
50
  moltbank setup
49
51
  ```
50
52
 
51
- The CLI will guide you through linking your MoltBank account via browser-based OAuth. Once approved, setup finalizes automatically.
53
+ The CLI will guide you through linking your MoltBank account via browser-based OAuth. Once approved, setup verifies a real authenticated balance read before reporting success.
52
54
 
53
55
  ## CLI Commands
54
56
 
55
57
  | Command | Description |
56
58
  |---------|-------------|
57
- | `moltbank setup` | Run full setup (nonblocking auth by default) |
58
- | `moltbank setup --blocking` | Run setup and wait for OAuth approval |
59
- | `moltbank setup-blocking` | Run setup and wait for OAuth approval |
60
- | `moltbank auth-status` | Check current auth state |
59
+ | `moltbank setup` | Run full setup and verify readiness |
60
+ | `moltbank setup --verbose` | Run setup with detailed logs |
61
+ | `moltbank setup-blocking` | Alias for setup |
62
+ | `moltbank status` | Check current auth state |
63
+ | `moltbank auth-status` | Alias for `moltbank status` |
61
64
  | `moltbank sandbox-setup` | Reconfigure sandbox Docker settings |
62
65
  | `moltbank inject-key` | Re-inject env vars from credentials |
63
66
  | `moltbank register` | Re-register mcporter MCP server |
package/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { execSync, spawn } from 'child_process';
1
+ import { execSync, spawn, spawnSync } from 'child_process';
2
2
  import { chmodSync, existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'fs';
3
3
  import { join, dirname } from 'path';
4
4
  import { homedir } from 'os';
@@ -763,6 +763,84 @@ function readPendingOauthCode(skillDir: string): {
763
763
  }
764
764
  }
765
765
 
766
+ function clearPendingOauthCode(skillDir: string): void {
767
+ const pendingPath = join(skillDir, '.oauth_device_code.json');
768
+ try {
769
+ if (existsSync(pendingPath)) unlinkSync(pendingPath);
770
+ } catch {
771
+ // ignore
772
+ }
773
+ }
774
+
775
+ function runProcess(
776
+ command: string,
777
+ args: string[],
778
+ opts: { cwd?: string; silent?: boolean; env?: Record<string, string | undefined> } = {}
779
+ ) {
780
+ try {
781
+ const mergedEnv: NodeJS.ProcessEnv = { ...process.env, ...(opts.env ?? {}) };
782
+ const result = spawnSync(command, args, {
783
+ cwd: opts.cwd,
784
+ env: mergedEnv,
785
+ encoding: 'utf8',
786
+ stdio: opts.silent ? 'pipe' : 'inherit'
787
+ });
788
+ return {
789
+ ok: result.status === 0,
790
+ stdout: (result.stdout ?? '').toString().trim(),
791
+ stderr: (result.stderr ?? '').toString().trim()
792
+ };
793
+ } catch (e: unknown) {
794
+ return {
795
+ ok: false,
796
+ stdout: '',
797
+ stderr: getExecErrorMessage(e)
798
+ };
799
+ }
800
+ }
801
+
802
+ function runMoltbankWrapper(skillDir: string, args: string[]) {
803
+ if (IS_WIN) {
804
+ const ps1Path = join(skillDir, 'scripts', 'moltbank.ps1');
805
+ return runProcess('powershell', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', ps1Path, ...args], {
806
+ cwd: skillDir,
807
+ silent: true
808
+ });
809
+ }
810
+
811
+ return runProcess(join(skillDir, 'scripts', 'moltbank.sh'), args, {
812
+ cwd: skillDir,
813
+ silent: true
814
+ });
815
+ }
816
+
817
+ function verifyMoltbankOperationalReadiness(skillDir: string, api: LoggerApi): boolean {
818
+ const existing = parseActiveTokenFromCredentials();
819
+ if (!existing.ok || !existing.activeOrg) {
820
+ api.logger.warn('[moltbank] ✗ setup incomplete: authenticated org could not be resolved for balance verification');
821
+ return false;
822
+ }
823
+
824
+ const verification = runMoltbankWrapper(skillDir, [
825
+ 'call',
826
+ 'MoltBank.get_balance',
827
+ `organizationName=${existing.activeOrg}`,
828
+ 'date=today'
829
+ ]);
830
+
831
+ if (verification.ok) {
832
+ api.logger.info(`[moltbank] ✓ balance verification passed (org: ${existing.activeOrg})`);
833
+ return true;
834
+ }
835
+
836
+ api.logger.warn('[moltbank] ✗ setup incomplete: auth is linked, but balance verification failed (`MoltBank.get_balance`)');
837
+ const detail = verification.stderr || verification.stdout;
838
+ if (detail) {
839
+ api.logger.warn('[moltbank] verification detail: ' + detail);
840
+ }
841
+ return false;
842
+ }
843
+
766
844
  function startBackgroundOauthPoll(
767
845
  skillDir: string,
768
846
  appBaseUrl: string,
@@ -814,12 +892,7 @@ function startBackgroundOauthPoll(
814
892
  oauthPollers.delete(skillDir);
815
893
  const after = parseActiveTokenFromCredentials();
816
894
  if (after.ok) {
817
- const pendingPath = join(skillDir, '.oauth_device_code.json');
818
- try {
819
- if (existsSync(pendingPath)) unlinkSync(pendingPath);
820
- } catch {
821
- // ignore
822
- }
895
+ clearPendingOauthCode(skillDir);
823
896
  api.logger.info(`[moltbank] ✓ background onboarding completed (active org: ${after.activeOrg})`);
824
897
  try {
825
898
  startBackgroundFinalizeAfterAuth(skillDir, appBaseUrl, api);
@@ -899,6 +972,8 @@ function ensureMoltbankAuth(skillDir: string, appBaseUrl: string, api: LoggerApi
899
972
  const existing = parseActiveTokenFromCredentials();
900
973
  if (existing.ok) {
901
974
  stopBackgroundOauthPoll(skillDir);
975
+ stopBackgroundFinalize(skillDir);
976
+ clearPendingOauthCode(skillDir);
902
977
  api.logger.info(`[moltbank] ✓ credentials.json already available (active org: ${existing.activeOrg})`);
903
978
  return true;
904
979
  }
@@ -1037,11 +1112,7 @@ function ensureMoltbankAuth(skillDir: string, appBaseUrl: string, api: LoggerApi
1037
1112
 
1038
1113
  if (oauthError === 'invalid_grant') {
1039
1114
  api.logger.warn('[moltbank] ✗ onboarding code expired or already consumed (invalid_grant)');
1040
- try {
1041
- if (existsSync(pendingPath)) unlinkSync(pendingPath);
1042
- } catch {
1043
- // ignore
1044
- }
1115
+ clearPendingOauthCode(skillDir);
1045
1116
  } else {
1046
1117
  api.logger.warn('[moltbank] ✗ onboarding poll failed or timed out');
1047
1118
  }
@@ -1058,11 +1129,7 @@ function ensureMoltbankAuth(skillDir: string, appBaseUrl: string, api: LoggerApi
1058
1129
  return false;
1059
1130
  }
1060
1131
 
1061
- try {
1062
- if (existsSync(pendingPath)) unlinkSync(pendingPath);
1063
- } catch {
1064
- // ignore
1065
- }
1132
+ clearPendingOauthCode(skillDir);
1066
1133
 
1067
1134
  api.logger.info(`[moltbank] ✓ onboarding completed (active org: ${after.activeOrg})`);
1068
1135
  return true;
@@ -1071,7 +1138,10 @@ function ensureMoltbankAuth(skillDir: string, appBaseUrl: string, api: LoggerApi
1071
1138
  export function printAuthStatus(skillDir: string, appBaseUrl: string, api: LoggerApi): void {
1072
1139
  const now = Math.floor(Date.now() / 1000);
1073
1140
  const existing = parseActiveTokenFromCredentials();
1074
- const pending = readPendingOauthCode(skillDir);
1141
+ if (existing.ok) {
1142
+ clearPendingOauthCode(skillDir);
1143
+ }
1144
+ const pending = existing.ok ? null : readPendingOauthCode(skillDir);
1075
1145
  const poller = oauthPollers.get(skillDir);
1076
1146
  const finalizer = backgroundFinalizers.get(skillDir);
1077
1147
  const pollerRunning = Boolean(poller && poller.exitCode === null && !poller.killed);
@@ -1441,6 +1511,11 @@ export async function runSetup(
1441
1511
  } else {
1442
1512
  api.logger.info('[moltbank] sandbox unchanged — no restart needed');
1443
1513
  }
1514
+
1515
+ api.logger.info('[moltbank] [sandbox 11/11] verifying authenticated balance read...');
1516
+ if (!verifyMoltbankOperationalReadiness(skillDir, api)) {
1517
+ return;
1518
+ }
1444
1519
  } else {
1445
1520
  api.logger.info('[moltbank] [host 1/8] ensuring mcporter on host...');
1446
1521
  ensureMcporter(api);
@@ -1483,19 +1558,11 @@ export async function runSetup(
1483
1558
  api.logger.info('[moltbank] [host 7/8] writing/registering mcporter config...');
1484
1559
  ensureMcporterConfig(skillDir, appBaseUrl, api);
1485
1560
 
1486
- api.logger.info('[moltbank] [host 8/8] running wrapper smoke test...');
1487
- // FIX: usar path absoluto para el .ps1 en Windows
1488
- const ps1Path = join(skillDir, 'scripts', 'moltbank.ps1');
1489
- const smokeCmd = IS_WIN
1490
- ? `powershell -NoProfile -ExecutionPolicy Bypass -File "${ps1Path}" list MoltBank`
1491
- : `"${skillDir}/scripts/moltbank.sh" list MoltBank`;
1492
- const smoke = run(smokeCmd, { cwd: skillDir, silent: true });
1493
- if (!smoke.ok) {
1494
- api.logger.warn('[moltbank] host setup incomplete: smoke test failed (`moltbank list MoltBank` via platform script)');
1495
- } else {
1496
- api.logger.info('[moltbank] host smoke test passed (`moltbank list MoltBank`)');
1561
+ api.logger.info('[moltbank] [host 8/8] verifying authenticated balance read...');
1562
+ hostReady = verifyMoltbankOperationalReadiness(skillDir, api);
1563
+ if (!hostReady) {
1564
+ return;
1497
1565
  }
1498
- hostReady = smoke.ok;
1499
1566
 
1500
1567
  api.logger.info('[moltbank] host mode — setup completed with onboarding flow');
1501
1568
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moltbankhq/openclaw",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "MoltBank stablecoin treasury CLI and OpenClaw plugin",
5
5
  "main": "index.ts",
6
6
  "bin": {