@moltbankhq/openclaw 0.1.11 → 0.1.13
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/index.ts +353 -28
- package/package.json +1 -1
package/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn, spawnSync } from 'child_process';
|
|
2
2
|
import { chmodSync, chownSync, existsSync, mkdirSync, readdirSync, readFileSync, unlinkSync, writeFileSync, type Dirent } from 'fs';
|
|
3
|
-
import { join, dirname } from 'path';
|
|
3
|
+
import { join, dirname, basename } from 'path';
|
|
4
4
|
import { homedir, userInfo } from 'os';
|
|
5
5
|
const IS_WIN = process.platform === 'win32';
|
|
6
6
|
|
|
@@ -16,6 +16,7 @@ interface CredentialsOrganization {
|
|
|
16
16
|
name?: string;
|
|
17
17
|
access_token?: string;
|
|
18
18
|
x402_signer_private_key?: string;
|
|
19
|
+
x402_wallet?: Record<string, unknown>;
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
interface CredentialsFile {
|
|
@@ -365,10 +366,136 @@ function getExecErrorMessage(error: unknown): string {
|
|
|
365
366
|
return String(error);
|
|
366
367
|
}
|
|
367
368
|
|
|
369
|
+
function getPathEnvKey(env: NodeJS.ProcessEnv): string {
|
|
370
|
+
const existing = Object.keys(env).find((key) => key.toLowerCase() === 'path');
|
|
371
|
+
return existing ?? 'Path';
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function splitPathEntries(value: string): string[] {
|
|
375
|
+
return value
|
|
376
|
+
.split(IS_WIN ? ';' : ':')
|
|
377
|
+
.map((entry) => entry.trim())
|
|
378
|
+
.filter(Boolean);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function prependPathEntries(env: NodeJS.ProcessEnv, entries: string[]): void {
|
|
382
|
+
if (entries.length === 0) return;
|
|
383
|
+
|
|
384
|
+
const pathKey = getPathEnvKey(env);
|
|
385
|
+
const existing = splitPathEntries(asString(env[pathKey]));
|
|
386
|
+
const seen = new Set<string>();
|
|
387
|
+
const ordered: string[] = [];
|
|
388
|
+
|
|
389
|
+
for (const entry of [...entries, ...existing]) {
|
|
390
|
+
const normalized = IS_WIN ? entry.toLowerCase() : entry;
|
|
391
|
+
if (seen.has(normalized)) continue;
|
|
392
|
+
seen.add(normalized);
|
|
393
|
+
ordered.push(entry);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
env[pathKey] = ordered.join(IS_WIN ? ';' : ':');
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function isExplicitCommandPath(command: string): boolean {
|
|
400
|
+
return command.includes('/') || command.includes('\\') || /^[A-Za-z]:/.test(command);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function getWindowsCommandExtensions(env: NodeJS.ProcessEnv): string[] {
|
|
404
|
+
const fromEnv = asString(env.PATHEXT || process.env.PATHEXT)
|
|
405
|
+
.split(';')
|
|
406
|
+
.map((value) => value.trim().toLowerCase())
|
|
407
|
+
.filter(Boolean);
|
|
408
|
+
|
|
409
|
+
const preferred = ['.exe', '.com', '.ps1', '.cmd', '.bat'];
|
|
410
|
+
const out: string[] = [];
|
|
411
|
+
for (const ext of [...preferred, ...fromEnv]) {
|
|
412
|
+
const normalized = ext.startsWith('.') ? ext : `.${ext}`;
|
|
413
|
+
if (!out.includes(normalized)) {
|
|
414
|
+
out.push(normalized);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
return out;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function resolveWindowsCommandPath(command: string, env: NodeJS.ProcessEnv): string {
|
|
421
|
+
const extensions = getWindowsCommandExtensions(env);
|
|
422
|
+
|
|
423
|
+
const tryCandidates = (basePath: string): string => {
|
|
424
|
+
if (existsSync(basePath)) return basePath;
|
|
425
|
+
|
|
426
|
+
const lower = basePath.toLowerCase();
|
|
427
|
+
for (const ext of extensions) {
|
|
428
|
+
if (lower.endsWith(ext)) continue;
|
|
429
|
+
const candidate = `${basePath}${ext}`;
|
|
430
|
+
if (existsSync(candidate)) {
|
|
431
|
+
return candidate;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return '';
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
if (isExplicitCommandPath(command)) {
|
|
439
|
+
return tryCandidates(command);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const pathValue = asString(env[getPathEnvKey(env)]);
|
|
443
|
+
for (const entry of splitPathEntries(pathValue)) {
|
|
444
|
+
const resolved = tryCandidates(join(entry, command));
|
|
445
|
+
if (resolved) {
|
|
446
|
+
return resolved;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
return '';
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function quoteCmdArgument(value: string): string {
|
|
454
|
+
if (!value) return '""';
|
|
455
|
+
|
|
456
|
+
const escaped = value
|
|
457
|
+
.replace(/([()%!^"<>&|])/g, '^$1')
|
|
458
|
+
.replace(/\r/g, ' ')
|
|
459
|
+
.replace(/\n/g, ' ');
|
|
460
|
+
|
|
461
|
+
return /[\s()%!^"<>&|]/.test(value) ? `"${escaped}"` : escaped;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function prepareCommandForSpawn(command: string, args: string[], env: NodeJS.ProcessEnv): { command: string; args: string[] } {
|
|
465
|
+
if (!IS_WIN) {
|
|
466
|
+
return { command, args };
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const resolved = resolveWindowsCommandPath(command, env);
|
|
470
|
+
if (!resolved) {
|
|
471
|
+
return { command, args };
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
const lower = resolved.toLowerCase();
|
|
475
|
+
if (lower.endsWith('.ps1')) {
|
|
476
|
+
return {
|
|
477
|
+
command: 'powershell.exe',
|
|
478
|
+
args: ['-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-File', resolved, ...args]
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
if (lower.endsWith('.cmd') || lower.endsWith('.bat')) {
|
|
483
|
+
const cmdExe = asString(env.ComSpec || env.COMSPEC, 'cmd.exe');
|
|
484
|
+
const commandLine = [resolved, ...args].map((value) => quoteCmdArgument(value)).join(' ');
|
|
485
|
+
return {
|
|
486
|
+
command: cmdExe,
|
|
487
|
+
args: ['/d', '/s', '/c', commandLine]
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return { command: resolved, args };
|
|
492
|
+
}
|
|
493
|
+
|
|
368
494
|
function runCommand(command: string, args: string[], opts: RunOptions = {}): RunResult {
|
|
369
495
|
try {
|
|
370
496
|
const mergedEnv: NodeJS.ProcessEnv = { ...process.env, ...(opts.env ?? {}) };
|
|
371
|
-
const
|
|
497
|
+
const prepared = prepareCommandForSpawn(command, args, mergedEnv);
|
|
498
|
+
const result = spawnSync(prepared.command, prepared.args, {
|
|
372
499
|
cwd: opts.cwd,
|
|
373
500
|
env: mergedEnv,
|
|
374
501
|
encoding: 'utf8',
|
|
@@ -563,6 +690,122 @@ function applyRecursiveMode(rootDir: string, mode: number): void {
|
|
|
563
690
|
});
|
|
564
691
|
}
|
|
565
692
|
|
|
693
|
+
function applyRecursiveModes(rootDir: string, dirMode: number, fileMode: number): void {
|
|
694
|
+
try {
|
|
695
|
+
chmodSync(rootDir, dirMode);
|
|
696
|
+
} catch {
|
|
697
|
+
// ignore
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
visitFiles(rootDir, (fullPath, entry) => {
|
|
701
|
+
try {
|
|
702
|
+
chmodSync(fullPath, entry.isDirectory() ? dirMode : fileMode);
|
|
703
|
+
} catch {
|
|
704
|
+
// ignore
|
|
705
|
+
}
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
type CommandSpec = {
|
|
710
|
+
command: string;
|
|
711
|
+
args: string[];
|
|
712
|
+
env?: Record<string, string | undefined>;
|
|
713
|
+
};
|
|
714
|
+
|
|
715
|
+
function withOptionalSudo(command: string, args: string[], env?: Record<string, string | undefined>): CommandSpec {
|
|
716
|
+
const isRoot = typeof process.getuid === 'function' ? process.getuid() === 0 : false;
|
|
717
|
+
if (isRoot || !hasBin('sudo')) {
|
|
718
|
+
return { command, args, env };
|
|
719
|
+
}
|
|
720
|
+
return { command: 'sudo', args: [command, ...args], env };
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
function getUnixJqInstallPlan(): { name: string; steps: CommandSpec[] } | null {
|
|
724
|
+
if (hasBin('apt-get')) {
|
|
725
|
+
return {
|
|
726
|
+
name: 'apt-get',
|
|
727
|
+
steps: [
|
|
728
|
+
withOptionalSudo('apt-get', ['update', '-qq'], { DEBIAN_FRONTEND: 'noninteractive' }),
|
|
729
|
+
withOptionalSudo('apt-get', ['install', '-y', 'jq'], { DEBIAN_FRONTEND: 'noninteractive' })
|
|
730
|
+
]
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
if (hasBin('dnf')) {
|
|
735
|
+
return {
|
|
736
|
+
name: 'dnf',
|
|
737
|
+
steps: [withOptionalSudo('dnf', ['install', '-y', 'jq'])]
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
if (hasBin('yum')) {
|
|
742
|
+
return {
|
|
743
|
+
name: 'yum',
|
|
744
|
+
steps: [withOptionalSudo('yum', ['install', '-y', 'jq'])]
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
if (hasBin('pacman')) {
|
|
749
|
+
return {
|
|
750
|
+
name: 'pacman',
|
|
751
|
+
steps: [withOptionalSudo('pacman', ['-Sy', '--noconfirm', 'jq'])]
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
if (hasBin('apk')) {
|
|
756
|
+
return {
|
|
757
|
+
name: 'apk',
|
|
758
|
+
steps: [withOptionalSudo('apk', ['add', 'jq'])]
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
if (hasBin('zypper')) {
|
|
763
|
+
return {
|
|
764
|
+
name: 'zypper',
|
|
765
|
+
steps: [withOptionalSudo('zypper', ['install', '-y', 'jq'])]
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
if (hasBin('brew')) {
|
|
770
|
+
return {
|
|
771
|
+
name: 'brew',
|
|
772
|
+
steps: [{ command: 'brew', args: ['install', 'jq'] }]
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
return null;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
function ensureUnixJq(api: LoggerApi): boolean {
|
|
780
|
+
const plan = getUnixJqInstallPlan();
|
|
781
|
+
if (!plan) {
|
|
782
|
+
return false;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
api.logger.info(`[moltbank] jq not found — attempting install via ${plan.name}...`);
|
|
786
|
+
|
|
787
|
+
for (const step of plan.steps) {
|
|
788
|
+
const result = runCommand(step.command, step.args, {
|
|
789
|
+
env: step.env,
|
|
790
|
+
timeoutMs: 180000
|
|
791
|
+
});
|
|
792
|
+
|
|
793
|
+
if (!result.ok) {
|
|
794
|
+
api.logger.warn(`[moltbank] jq install via ${plan.name} failed: ${result.stderr}`);
|
|
795
|
+
return false;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
if (!hasBin('jq')) {
|
|
800
|
+
api.logger.warn(`[moltbank] jq install via ${plan.name} finished, but jq is still not visible in PATH`);
|
|
801
|
+
return false;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
const version = runCommand('jq', ['--version'], { silent: true });
|
|
805
|
+
api.logger.info(`[moltbank] ✓ jq installed via ${plan.name} (${version.stdout || 'unknown version'})`);
|
|
806
|
+
return true;
|
|
807
|
+
}
|
|
808
|
+
|
|
566
809
|
function findWindowsJqBinaryPath(): string {
|
|
567
810
|
if (!IS_WIN) return '';
|
|
568
811
|
|
|
@@ -652,6 +895,7 @@ function ensureWindowsJqShim(api: LoggerApi): boolean {
|
|
|
652
895
|
const shimBody = `@echo off\r\n"${escapedSource}" %*\r\n`;
|
|
653
896
|
writeFileSync(shimPath, shimBody, 'utf8');
|
|
654
897
|
}
|
|
898
|
+
prependPathEntries(process.env, [npmBinDir]);
|
|
655
899
|
} catch (e) {
|
|
656
900
|
api.logger.warn('[moltbank] could not create jq shim in npm global bin: ' + String(e));
|
|
657
901
|
return false;
|
|
@@ -709,6 +953,77 @@ function getCredentialsPath(): string {
|
|
|
709
953
|
return process.env.MOLTBANK_CREDENTIALS_PATH || join(homedir(), '.MoltBank', 'credentials.json');
|
|
710
954
|
}
|
|
711
955
|
|
|
956
|
+
function getSandboxCredentialsHostPath(skillDir: string): string {
|
|
957
|
+
return join(skillDir, '.sandbox', 'credentials.json');
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
function getSandboxCredentialsContainerPath(skillName: string): string {
|
|
961
|
+
return `/workspace/skills/${skillName}/.sandbox/credentials.json`;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
function writeSandboxCredentialsFile(
|
|
965
|
+
skillDir: string,
|
|
966
|
+
activeOrg: string,
|
|
967
|
+
org: CredentialsOrganization,
|
|
968
|
+
privateKey: string,
|
|
969
|
+
api: LoggerApi
|
|
970
|
+
): boolean {
|
|
971
|
+
const sandboxDir = dirname(getSandboxCredentialsHostPath(skillDir));
|
|
972
|
+
const sandboxCredentialsPath = getSandboxCredentialsHostPath(skillDir);
|
|
973
|
+
const sandboxOrg: Record<string, unknown> = {
|
|
974
|
+
name: activeOrg,
|
|
975
|
+
access_token: org.access_token ?? ''
|
|
976
|
+
};
|
|
977
|
+
|
|
978
|
+
if (privateKey) {
|
|
979
|
+
sandboxOrg.x402_signer_private_key = privateKey;
|
|
980
|
+
}
|
|
981
|
+
if (isRecord(org.x402_wallet)) {
|
|
982
|
+
sandboxOrg.x402_wallet = org.x402_wallet;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
const sandboxCredentials = {
|
|
986
|
+
active_organization: activeOrg,
|
|
987
|
+
organizations: [sandboxOrg]
|
|
988
|
+
};
|
|
989
|
+
|
|
990
|
+
try {
|
|
991
|
+
mkdirSync(sandboxDir, { recursive: true });
|
|
992
|
+
writeFileSync(sandboxCredentialsPath, JSON.stringify(sandboxCredentials, null, 2) + '\n', 'utf8');
|
|
993
|
+
|
|
994
|
+
if (!IS_WIN) {
|
|
995
|
+
try {
|
|
996
|
+
chmodSync(sandboxDir, 0o700);
|
|
997
|
+
} catch {
|
|
998
|
+
// ignore
|
|
999
|
+
}
|
|
1000
|
+
try {
|
|
1001
|
+
chmodSync(sandboxCredentialsPath, 0o600);
|
|
1002
|
+
} catch {
|
|
1003
|
+
// ignore
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
api.logger.info('[moltbank] ✓ sandbox credentials file updated');
|
|
1008
|
+
return true;
|
|
1009
|
+
} catch (e) {
|
|
1010
|
+
api.logger.warn('[moltbank] ✗ could not write sandbox credentials file: ' + String(e));
|
|
1011
|
+
return false;
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
function removeSandboxSecretEnvKeys(envObj: Record<string, string>, api: LoggerApi): boolean {
|
|
1016
|
+
let changed = false;
|
|
1017
|
+
for (const key of ['MOLTBANK', 'SIGNER']) {
|
|
1018
|
+
if (key in envObj) {
|
|
1019
|
+
delete envObj[key];
|
|
1020
|
+
changed = true;
|
|
1021
|
+
api.logger.info(`[moltbank] ✓ removed legacy sandbox secret env key ${key}`);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
return changed;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
712
1027
|
function readOpenclawConfig(): OpenclawConfig {
|
|
713
1028
|
const configPath = join(homedir(), '.openclaw', 'openclaw.json');
|
|
714
1029
|
try {
|
|
@@ -816,6 +1131,10 @@ function ensureJq(api: LoggerApi) {
|
|
|
816
1131
|
}
|
|
817
1132
|
|
|
818
1133
|
if (!IS_WIN) {
|
|
1134
|
+
if (ensureUnixJq(api)) {
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
819
1138
|
api.logger.warn('[moltbank] ✗ jq not found in PATH (required by MoltBank wrapper on host mode)');
|
|
820
1139
|
api.logger.warn(`[moltbank] install jq (${getJqInstallHint()}) and rerun setup`);
|
|
821
1140
|
return;
|
|
@@ -1111,20 +1430,20 @@ function ensureSkillPermissions(skillDir: string, api: LoggerApi) {
|
|
|
1111
1430
|
}
|
|
1112
1431
|
|
|
1113
1432
|
if (existsSync(assetsDir)) {
|
|
1114
|
-
|
|
1115
|
-
api.logger.info('[moltbank] ✓ assets/ permissions →
|
|
1433
|
+
applyRecursiveModes(assetsDir, 0o750, 0o640);
|
|
1434
|
+
api.logger.info('[moltbank] ✓ assets/ permissions → 750 dirs, 640 files');
|
|
1116
1435
|
}
|
|
1117
1436
|
if (existsSync(configFile)) {
|
|
1118
1437
|
try {
|
|
1119
|
-
chmodSync(configFile,
|
|
1438
|
+
chmodSync(configFile, 0o600);
|
|
1120
1439
|
} catch {
|
|
1121
1440
|
// ignore
|
|
1122
1441
|
}
|
|
1123
|
-
api.logger.info('[moltbank] ✓ mcporter.json permissions →
|
|
1442
|
+
api.logger.info('[moltbank] ✓ mcporter.json permissions → 600');
|
|
1124
1443
|
}
|
|
1125
1444
|
if (existsSync(scriptsDir)) {
|
|
1126
|
-
|
|
1127
|
-
api.logger.info('[moltbank] ✓ scripts/ permissions →
|
|
1445
|
+
applyRecursiveModes(scriptsDir, 0o750, 0o750);
|
|
1446
|
+
api.logger.info('[moltbank] ✓ scripts/ permissions → 750');
|
|
1128
1447
|
normalizeFilesMatching(scriptsDir, () => true);
|
|
1129
1448
|
api.logger.info('[moltbank] ✓ scripts/ line endings normalized (CRLF → LF)');
|
|
1130
1449
|
}
|
|
@@ -1659,6 +1978,7 @@ export function ensureMcporterConfig(skillDir: string, appBaseUrl: string, api:
|
|
|
1659
1978
|
|
|
1660
1979
|
export function injectSandboxEnv(skillDir: string, api: LoggerApi): boolean {
|
|
1661
1980
|
const credsPath = getCredentialsPath();
|
|
1981
|
+
const skillName = basename(skillDir);
|
|
1662
1982
|
|
|
1663
1983
|
if (!existsSync(credsPath)) {
|
|
1664
1984
|
api.logger.info('[moltbank] no credentials.json found — skipping sandbox env injection');
|
|
@@ -1686,14 +2006,7 @@ export function injectSandboxEnv(skillDir: string, api: LoggerApi): boolean {
|
|
|
1686
2006
|
const envPath = ['agents', 'defaults', 'sandbox', 'docker', 'env'];
|
|
1687
2007
|
setNestedValue(config, envPath, getNestedValue(config, envPath) ?? {});
|
|
1688
2008
|
const envObj = getNestedValue(config, envPath) as Record<string, string>;
|
|
1689
|
-
|
|
1690
|
-
if (envObj.MOLTBANK !== org.access_token) {
|
|
1691
|
-
envObj.MOLTBANK = org.access_token;
|
|
1692
|
-
api.logger.info(`[moltbank] ✓ MOLTBANK injected (org: ${activeOrg})`);
|
|
1693
|
-
changed = true;
|
|
1694
|
-
} else {
|
|
1695
|
-
api.logger.info(`[moltbank] ✓ MOLTBANK already injected (org: ${activeOrg})`);
|
|
1696
|
-
}
|
|
2009
|
+
changed = removeSandboxSecretEnvKeys(envObj, api) || changed;
|
|
1697
2010
|
|
|
1698
2011
|
if (envObj.ACTIVE_ORG_OVERRIDE !== activeOrg) {
|
|
1699
2012
|
envObj.ACTIVE_ORG_OVERRIDE = activeOrg;
|
|
@@ -1729,21 +2042,28 @@ export function injectSandboxEnv(skillDir: string, api: LoggerApi): boolean {
|
|
|
1729
2042
|
}
|
|
1730
2043
|
}
|
|
1731
2044
|
|
|
2045
|
+
if (!writeSandboxCredentialsFile(skillDir, activeOrg, org, privateKey, api)) {
|
|
2046
|
+
return false;
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2049
|
+
const sandboxCredentialsContainerPath = getSandboxCredentialsContainerPath(skillName);
|
|
2050
|
+
if (envObj.MOLTBANK_CREDENTIALS_PATH !== sandboxCredentialsContainerPath) {
|
|
2051
|
+
envObj.MOLTBANK_CREDENTIALS_PATH = sandboxCredentialsContainerPath;
|
|
2052
|
+
api.logger.info(`[moltbank] ✓ MOLTBANK_CREDENTIALS_PATH injected (${sandboxCredentialsContainerPath})`);
|
|
2053
|
+
changed = true;
|
|
2054
|
+
} else {
|
|
2055
|
+
api.logger.info(`[moltbank] ✓ MOLTBANK_CREDENTIALS_PATH already set (${sandboxCredentialsContainerPath})`);
|
|
2056
|
+
}
|
|
2057
|
+
|
|
1732
2058
|
if (privateKey) {
|
|
1733
|
-
|
|
1734
|
-
envObj.SIGNER = privateKey;
|
|
1735
|
-
api.logger.info('[moltbank] ✓ SIGNER injected');
|
|
1736
|
-
changed = true;
|
|
1737
|
-
} else {
|
|
1738
|
-
api.logger.info('[moltbank] ✓ SIGNER already injected');
|
|
1739
|
-
}
|
|
2059
|
+
api.logger.info('[moltbank] ✓ sandbox x402 signer available via sandbox credentials file');
|
|
1740
2060
|
} else {
|
|
1741
|
-
api.logger.info('[moltbank] ℹ
|
|
2061
|
+
api.logger.info('[moltbank] ℹ sandbox x402 signer not available yet — helper scripts will use sandbox credentials path if generated later');
|
|
1742
2062
|
}
|
|
1743
2063
|
|
|
1744
2064
|
if (changed) {
|
|
1745
2065
|
writeOpenclawConfig(config);
|
|
1746
|
-
api.logger.info('[moltbank] ✓ openclaw.json updated with sandbox
|
|
2066
|
+
api.logger.info('[moltbank] ✓ openclaw.json updated with sandbox auth path only (no token/private key persisted)');
|
|
1747
2067
|
}
|
|
1748
2068
|
|
|
1749
2069
|
return changed;
|
|
@@ -1965,7 +2285,7 @@ export async function runSetup(
|
|
|
1965
2285
|
api.logger.info('[moltbank] [sandbox 8/10] configuring sandbox docker settings...');
|
|
1966
2286
|
const sandboxChanged = configureSandbox(api);
|
|
1967
2287
|
|
|
1968
|
-
api.logger.info('[moltbank] [sandbox 9/10] injecting sandbox env
|
|
2288
|
+
api.logger.info('[moltbank] [sandbox 9/10] injecting sandbox auth env (MOLTBANK_CREDENTIALS_PATH, ACTIVE_ORG_OVERRIDE)...');
|
|
1969
2289
|
const envChanged = injectSandboxEnv(skillDir, api);
|
|
1970
2290
|
|
|
1971
2291
|
api.logger.info('[moltbank] [sandbox 10/10] apply sandbox changes (recreate + gateway stop)...');
|
|
@@ -2132,13 +2452,18 @@ export async function runSetup(
|
|
|
2132
2452
|
const finalEnv = asStringRecord(getNestedValue(finalConfig, ['agents', 'defaults', 'sandbox', 'docker', 'env']));
|
|
2133
2453
|
const finalNetwork = asString(getNestedValue(finalConfig, ['agents', 'defaults', 'sandbox', 'docker', 'network']));
|
|
2134
2454
|
const finalCmd = asString(getNestedValue(finalConfig, ['agents', 'defaults', 'sandbox', 'docker', 'setupCommand']));
|
|
2455
|
+
const sandboxCredentialsPath = getSandboxCredentialsHostPath(skillDir);
|
|
2135
2456
|
|
|
2136
2457
|
api.logger.info(`[moltbank] openclaw.json sandbox env:`);
|
|
2137
|
-
api.logger.info(
|
|
2458
|
+
api.logger.info(
|
|
2459
|
+
`[moltbank] MOLTBANK_CREDENTIALS_PATH: ${finalEnv.MOLTBANK_CREDENTIALS_PATH ? `✓ ${finalEnv.MOLTBANK_CREDENTIALS_PATH}` : '✗ missing'}`
|
|
2460
|
+
);
|
|
2138
2461
|
api.logger.info(
|
|
2139
2462
|
`[moltbank] ACTIVE_ORG_OVERRIDE: ${finalEnv.ACTIVE_ORG_OVERRIDE ? `✓ "${finalEnv.ACTIVE_ORG_OVERRIDE}"` : '✗ missing'}`
|
|
2140
2463
|
);
|
|
2141
|
-
api.logger.info(
|
|
2464
|
+
api.logger.info(
|
|
2465
|
+
`[moltbank] sandbox credentials: ${existsSync(sandboxCredentialsPath) ? '✓ present (skill-local, 600)' : '✗ missing'}`
|
|
2466
|
+
);
|
|
2142
2467
|
api.logger.info(`[moltbank] sandbox docker:`);
|
|
2143
2468
|
api.logger.info(
|
|
2144
2469
|
`[moltbank] network: ${finalNetwork === 'bridge' ? '✓ bridge' : `✗ "${finalNetwork}" (expected bridge)`}`
|