@moltbankhq/openclaw 0.1.7 → 0.1.9

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 +107 -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';
@@ -498,6 +498,7 @@ const SKILL_FILES = [
498
498
  'SKILL.md',
499
499
  'skill.json',
500
500
  'install.sh',
501
+ 'package.json',
501
502
  'assets/mcporter.json',
502
503
  'references/heartbeat.md',
503
504
  'references/onboarding.md',
@@ -763,6 +764,93 @@ function readPendingOauthCode(skillDir: string): {
763
764
  }
764
765
  }
765
766
 
767
+ function clearPendingOauthCode(skillDir: string): void {
768
+ const pendingPath = join(skillDir, '.oauth_device_code.json');
769
+ try {
770
+ if (existsSync(pendingPath)) unlinkSync(pendingPath);
771
+ } catch {
772
+ // ignore
773
+ }
774
+ }
775
+
776
+ function runProcess(
777
+ command: string,
778
+ args: string[],
779
+ opts: { cwd?: string; silent?: boolean; env?: Record<string, string | undefined> } = {}
780
+ ) {
781
+ try {
782
+ const mergedEnv: NodeJS.ProcessEnv = { ...process.env, ...(opts.env ?? {}) };
783
+ const result = spawnSync(command, args, {
784
+ cwd: opts.cwd,
785
+ env: mergedEnv,
786
+ encoding: 'utf8',
787
+ stdio: opts.silent ? 'pipe' : 'inherit'
788
+ });
789
+ return {
790
+ ok: result.status === 0,
791
+ stdout: (result.stdout ?? '').toString().trim(),
792
+ stderr: (result.stderr ?? '').toString().trim()
793
+ };
794
+ } catch (e: unknown) {
795
+ return {
796
+ ok: false,
797
+ stdout: '',
798
+ stderr: getExecErrorMessage(e)
799
+ };
800
+ }
801
+ }
802
+
803
+ function runMoltbankWrapper(
804
+ skillDir: string,
805
+ args: string[],
806
+ env: Record<string, string | undefined> = {}
807
+ ) {
808
+ if (IS_WIN) {
809
+ const ps1Path = join(skillDir, 'scripts', 'moltbank.ps1');
810
+ return runProcess('powershell', ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', ps1Path, ...args], {
811
+ cwd: skillDir,
812
+ silent: true,
813
+ env
814
+ });
815
+ }
816
+
817
+ return runProcess(join(skillDir, 'scripts', 'moltbank.sh'), args, {
818
+ cwd: skillDir,
819
+ silent: true,
820
+ env
821
+ });
822
+ }
823
+
824
+ function verifyMoltbankOperationalReadiness(skillDir: string, api: LoggerApi): boolean {
825
+ const existing = parseActiveTokenFromCredentials();
826
+ if (!existing.ok || !existing.activeOrg || !existing.token) {
827
+ api.logger.warn('[moltbank] ✗ setup incomplete: authenticated org could not be resolved for balance verification');
828
+ return false;
829
+ }
830
+
831
+ const verification = runMoltbankWrapper(skillDir, [
832
+ 'call',
833
+ 'MoltBank.get_balance',
834
+ `organizationName=${existing.activeOrg}`,
835
+ 'date=today'
836
+ ], {
837
+ MOLTBANK: existing.token,
838
+ ACTIVE_ORG_OVERRIDE: existing.activeOrg
839
+ });
840
+
841
+ if (verification.ok) {
842
+ api.logger.info(`[moltbank] ✓ balance verification passed (org: ${existing.activeOrg})`);
843
+ return true;
844
+ }
845
+
846
+ api.logger.warn('[moltbank] ✗ setup incomplete: auth is linked, but balance verification failed (`MoltBank.get_balance`)');
847
+ const detail = verification.stderr || verification.stdout;
848
+ if (detail) {
849
+ api.logger.warn('[moltbank] verification detail: ' + detail);
850
+ }
851
+ return false;
852
+ }
853
+
766
854
  function startBackgroundOauthPoll(
767
855
  skillDir: string,
768
856
  appBaseUrl: string,
@@ -814,12 +902,7 @@ function startBackgroundOauthPoll(
814
902
  oauthPollers.delete(skillDir);
815
903
  const after = parseActiveTokenFromCredentials();
816
904
  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
- }
905
+ clearPendingOauthCode(skillDir);
823
906
  api.logger.info(`[moltbank] ✓ background onboarding completed (active org: ${after.activeOrg})`);
824
907
  try {
825
908
  startBackgroundFinalizeAfterAuth(skillDir, appBaseUrl, api);
@@ -899,6 +982,8 @@ function ensureMoltbankAuth(skillDir: string, appBaseUrl: string, api: LoggerApi
899
982
  const existing = parseActiveTokenFromCredentials();
900
983
  if (existing.ok) {
901
984
  stopBackgroundOauthPoll(skillDir);
985
+ stopBackgroundFinalize(skillDir);
986
+ clearPendingOauthCode(skillDir);
902
987
  api.logger.info(`[moltbank] ✓ credentials.json already available (active org: ${existing.activeOrg})`);
903
988
  return true;
904
989
  }
@@ -1037,11 +1122,7 @@ function ensureMoltbankAuth(skillDir: string, appBaseUrl: string, api: LoggerApi
1037
1122
 
1038
1123
  if (oauthError === 'invalid_grant') {
1039
1124
  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
- }
1125
+ clearPendingOauthCode(skillDir);
1045
1126
  } else {
1046
1127
  api.logger.warn('[moltbank] ✗ onboarding poll failed or timed out');
1047
1128
  }
@@ -1058,11 +1139,7 @@ function ensureMoltbankAuth(skillDir: string, appBaseUrl: string, api: LoggerApi
1058
1139
  return false;
1059
1140
  }
1060
1141
 
1061
- try {
1062
- if (existsSync(pendingPath)) unlinkSync(pendingPath);
1063
- } catch {
1064
- // ignore
1065
- }
1142
+ clearPendingOauthCode(skillDir);
1066
1143
 
1067
1144
  api.logger.info(`[moltbank] ✓ onboarding completed (active org: ${after.activeOrg})`);
1068
1145
  return true;
@@ -1071,7 +1148,10 @@ function ensureMoltbankAuth(skillDir: string, appBaseUrl: string, api: LoggerApi
1071
1148
  export function printAuthStatus(skillDir: string, appBaseUrl: string, api: LoggerApi): void {
1072
1149
  const now = Math.floor(Date.now() / 1000);
1073
1150
  const existing = parseActiveTokenFromCredentials();
1074
- const pending = readPendingOauthCode(skillDir);
1151
+ if (existing.ok) {
1152
+ clearPendingOauthCode(skillDir);
1153
+ }
1154
+ const pending = existing.ok ? null : readPendingOauthCode(skillDir);
1075
1155
  const poller = oauthPollers.get(skillDir);
1076
1156
  const finalizer = backgroundFinalizers.get(skillDir);
1077
1157
  const pollerRunning = Boolean(poller && poller.exitCode === null && !poller.killed);
@@ -1441,6 +1521,11 @@ export async function runSetup(
1441
1521
  } else {
1442
1522
  api.logger.info('[moltbank] sandbox unchanged — no restart needed');
1443
1523
  }
1524
+
1525
+ api.logger.info('[moltbank] [sandbox 11/11] verifying authenticated balance read...');
1526
+ if (!verifyMoltbankOperationalReadiness(skillDir, api)) {
1527
+ return;
1528
+ }
1444
1529
  } else {
1445
1530
  api.logger.info('[moltbank] [host 1/8] ensuring mcporter on host...');
1446
1531
  ensureMcporter(api);
@@ -1483,19 +1568,11 @@ export async function runSetup(
1483
1568
  api.logger.info('[moltbank] [host 7/8] writing/registering mcporter config...');
1484
1569
  ensureMcporterConfig(skillDir, appBaseUrl, api);
1485
1570
 
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`)');
1571
+ api.logger.info('[moltbank] [host 8/8] verifying authenticated balance read...');
1572
+ hostReady = verifyMoltbankOperationalReadiness(skillDir, api);
1573
+ if (!hostReady) {
1574
+ return;
1497
1575
  }
1498
- hostReady = smoke.ok;
1499
1576
 
1500
1577
  api.logger.info('[moltbank] host mode — setup completed with onboarding flow');
1501
1578
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moltbankhq/openclaw",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "MoltBank stablecoin treasury CLI and OpenClaw plugin",
5
5
  "main": "index.ts",
6
6
  "bin": {