@wiimdy/openfunderse 1.1.4 → 1.1.5

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/README.md CHANGED
@@ -22,6 +22,9 @@ set -a; source .env.strategy; set +a
22
22
  set -a; source .env.participant; set +a
23
23
  ```
24
24
 
25
+ By default, `install` and `bot-init` also sync env keys into OpenClaw config (`~/.openclaw/openclaw.json > env.vars`).
26
+ Disable this with `--no-sync-openclaw-env`.
27
+
25
28
  ## Where Files Are Stored
26
29
 
27
30
  - In OpenClaw, skills are installed under `~/.openclaw/workspace/skills`.
@@ -71,8 +71,10 @@ function printUsage() {
71
71
  Usage:
72
72
  openfunderse list
73
73
  openfunderse bot-init [--role <strategy|participant>] [--skill-name <name>] [--env-path <path>] [--wallet-dir <dir>] [--wallet-name <name>] [--force] [--yes]
74
+ [--no-sync-openclaw-env]
74
75
  openfunderse install <pack-name> [--dest <skills-dir>] [--codex-home <dir>] [--force] [--with-runtime]
75
76
  [--no-init-env] [--env-path <path>] [--env-profile <strategy|participant|all>]
77
+ [--no-sync-openclaw-env]
76
78
  [--runtime-package <name>] [--runtime-dir <dir>] [--runtime-manager <npm|pnpm|yarn|bun>]
77
79
 
78
80
  Examples:
@@ -105,6 +107,7 @@ function parseArgs(argv) {
105
107
  skillName: "",
106
108
  walletDir: "",
107
109
  walletName: "",
110
+ syncOpenclawEnv: true,
108
111
  yes: false
109
112
  };
110
113
  const positionals = [];
@@ -137,6 +140,14 @@ function parseArgs(argv) {
137
140
  options.withRuntime = true;
138
141
  continue;
139
142
  }
143
+ if (token === "--sync-openclaw-env") {
144
+ options.syncOpenclawEnv = true;
145
+ continue;
146
+ }
147
+ if (token === "--no-sync-openclaw-env") {
148
+ options.syncOpenclawEnv = false;
149
+ continue;
150
+ }
140
151
  if (token === "--init-env") {
141
152
  options.initEnv = true;
142
153
  options.initEnvExplicit = true;
@@ -317,6 +328,11 @@ function runtimeEnvExamplePath(runtimeDir, runtimePackage) {
317
328
  return path.join(runtimeDir, "node_modules", ...runtimePackage.split("/"), ".env.example");
318
329
  }
319
330
 
331
+ function openclawConfigPath(codexHome) {
332
+ const resolvedCodexHome = path.resolve(codexHome);
333
+ return path.join(path.dirname(resolvedCodexHome), "openclaw.json");
334
+ }
335
+
320
336
  function defaultEnvFileNameForProfile(profile) {
321
337
  if (profile === "strategy") {
322
338
  return ".env.strategy";
@@ -411,6 +427,86 @@ function readAssignedEnvValue(content, key) {
411
427
  return "";
412
428
  }
413
429
 
430
+ function parseEnvAssignments(content) {
431
+ const result = {};
432
+ const lines = String(content || "").replace(/^\uFEFF/, "").split(/\r?\n/);
433
+ for (const rawLine of lines) {
434
+ const line = rawLine.trim();
435
+ if (!line || line.startsWith("#")) continue;
436
+ const match = line.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)$/);
437
+ if (!match) continue;
438
+ const key = match[1];
439
+ let value = (match[2] || "").trim();
440
+ if (
441
+ ((value.startsWith("\"") && value.endsWith("\"")) ||
442
+ (value.startsWith("'") && value.endsWith("'"))) &&
443
+ value.length >= 2
444
+ ) {
445
+ value = value.slice(1, -1);
446
+ }
447
+ result[key] = value;
448
+ }
449
+ return result;
450
+ }
451
+
452
+ async function syncOpenclawEnvVarsFromFile(envFile, codexHome) {
453
+ const configPath = openclawConfigPath(codexHome);
454
+ if (!existsSync(configPath)) {
455
+ return {
456
+ synced: false,
457
+ reason: "openclaw-config-not-found",
458
+ configPath,
459
+ envFile,
460
+ writtenKeys: []
461
+ };
462
+ }
463
+
464
+ const envContent = await readFile(envFile, "utf8");
465
+ const assignments = parseEnvAssignments(envContent);
466
+ const keys = Object.keys(assignments);
467
+ if (keys.length === 0) {
468
+ return {
469
+ synced: false,
470
+ reason: "empty-env-file",
471
+ configPath,
472
+ envFile,
473
+ writtenKeys: []
474
+ };
475
+ }
476
+
477
+ const rawConfig = await readFile(configPath, "utf8");
478
+ const parsedConfig = JSON.parse(rawConfig);
479
+ if (!parsedConfig || typeof parsedConfig !== "object" || Array.isArray(parsedConfig)) {
480
+ throw new Error(`invalid openclaw config json object: ${configPath}`);
481
+ }
482
+
483
+ const nextConfig = { ...parsedConfig };
484
+ const envSection =
485
+ nextConfig.env && typeof nextConfig.env === "object" && !Array.isArray(nextConfig.env)
486
+ ? { ...nextConfig.env }
487
+ : {};
488
+ const varsSection =
489
+ envSection.vars && typeof envSection.vars === "object" && !Array.isArray(envSection.vars)
490
+ ? { ...envSection.vars }
491
+ : {};
492
+
493
+ for (const [key, value] of Object.entries(assignments)) {
494
+ varsSection[key] = value;
495
+ }
496
+
497
+ envSection.vars = varsSection;
498
+ nextConfig.env = envSection;
499
+ await writeFile(configPath, `${JSON.stringify(nextConfig, null, 2)}\n`);
500
+
501
+ return {
502
+ synced: true,
503
+ reason: "ok",
504
+ configPath,
505
+ envFile,
506
+ writtenKeys: keys
507
+ };
508
+ }
509
+
414
510
  function isPlaceholderEnvValue(value) {
415
511
  const normalized = (value || "").trim();
416
512
  if (!normalized) return true;
@@ -596,11 +692,27 @@ async function runBotInit(options) {
596
692
  await mkdir(path.dirname(envFile), { recursive: true });
597
693
  await writeFile(envFile, nextEnvContent);
598
694
  await chmod(envFile, 0o600);
695
+ let syncMeta = null;
696
+ if (options.syncOpenclawEnv) {
697
+ const codexHome = options.codexHome ? path.resolve(options.codexHome) : defaultCodexHome();
698
+ syncMeta = await syncOpenclawEnvVarsFromFile(envFile, codexHome);
699
+ }
599
700
  const sourceCommand = `set -a; source ${shellQuote(envFile)}; set +a`;
600
701
 
601
702
  console.log(`Initialized ${role} bot wallet for Monad testnet (${DEFAULT_MONAD_CHAIN_ID}).`);
602
703
  console.log(`Address: ${wallet.address}`);
603
704
  console.log(`Env file updated: ${envFile}`);
705
+ if (syncMeta) {
706
+ if (syncMeta.synced) {
707
+ console.log(
708
+ `Synced env vars to OpenClaw config: ${syncMeta.configPath} (${syncMeta.writtenKeys.length} keys)`
709
+ );
710
+ } else {
711
+ console.log(
712
+ `Skipped OpenClaw env sync (${syncMeta.reason}): ${syncMeta.configPath}`
713
+ );
714
+ }
715
+ }
604
716
  console.log(`Wallet backup (keep secret): ${walletFiles.walletPath}`);
605
717
  console.log(`Private key backup (keep secret): ${walletFiles.privateKeyPath}`);
606
718
  console.log(`Load env now: ${sourceCommand}`);
@@ -776,6 +888,10 @@ async function installPack(packName, options) {
776
888
  };
777
889
  envScaffoldMeta = await writeEnvScaffold(envOptions);
778
890
  }
891
+ let openclawSyncMeta = null;
892
+ if (envScaffoldMeta && options.syncOpenclawEnv) {
893
+ openclawSyncMeta = await syncOpenclawEnvVarsFromFile(envScaffoldMeta.envFile, codexHome);
894
+ }
779
895
 
780
896
  console.log(`Installed pack: ${packName}`);
781
897
  console.log(`Skills root: ${skillsRoot}`);
@@ -796,6 +912,17 @@ async function installPack(packName, options) {
796
912
  );
797
913
  }
798
914
  }
915
+ if (openclawSyncMeta) {
916
+ if (openclawSyncMeta.synced) {
917
+ console.log(
918
+ `Synced env vars to OpenClaw config: ${openclawSyncMeta.configPath} (${openclawSyncMeta.writtenKeys.length} keys)`
919
+ );
920
+ } else {
921
+ console.log(
922
+ `Skipped OpenClaw env sync (${openclawSyncMeta.reason}): ${openclawSyncMeta.configPath}`
923
+ );
924
+ }
925
+ }
799
926
  console.log("Restart Codex to pick up new skills.");
800
927
  }
801
928
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wiimdy/openfunderse",
3
- "version": "1.1.4",
3
+ "version": "1.1.5",
4
4
  "description": "Install OpenFunderse skill packs into Codex",
5
5
  "type": "module",
6
6
  "bin": {
@@ -51,6 +51,10 @@ npx @wiimdy/openfunderse@latest bot-init \
51
51
  set -a; source .env.participant; set +a
52
52
  ```
53
53
 
54
+ OpenClaw note:
55
+ - `install` / `bot-init` sync env keys into `~/.openclaw/openclaw.json` (`env.vars`) by default.
56
+ - Use `--no-sync-openclaw-env` if you want file-only behavior.
57
+
54
58
  Note:
55
59
  - The scaffold includes a temporary public key placeholder by default.
56
60
  - Always run `bot-init` before funding or running production actions.
@@ -73,6 +73,10 @@ npx @wiimdy/openfunderse@latest bot-init \
73
73
  set -a; source .env.strategy; set +a
74
74
  ```
75
75
 
76
+ OpenClaw note:
77
+ - `install` / `bot-init` sync env keys into `~/.openclaw/openclaw.json` (`env.vars`) by default.
78
+ - Use `--no-sync-openclaw-env` if you want file-only behavior.
79
+
76
80
  Note:
77
81
  - The scaffold includes a temporary public key placeholder by default.
78
82
  - Always run `bot-init` before funding or running production actions.