mnemospark 1.2.2 → 1.4.0

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/dist/index.d.ts CHANGED
@@ -715,17 +715,14 @@ type OpenClawCronPayload = {
715
715
  kind: "agentTurn";
716
716
  message: string;
717
717
  };
718
- type OpenClawCronDelivery = {
719
- mode: "announce";
720
- text: string;
721
- };
722
718
  type OpenClawCronJobEntry = {
723
719
  jobId: string;
724
720
  name: string;
725
721
  schedule: OpenClawCronSchedule;
726
722
  payload: OpenClawCronPayload;
727
723
  sessionTarget: "isolated";
728
- delivery: OpenClawCronDelivery;
724
+ /** OpenClaw 2026.4.x: bind isolated renewal work to the dedicated agent. */
725
+ agentId: string;
729
726
  };
730
727
  type OpenClawCronJobForLookup = {
731
728
  jobId: string;
@@ -740,6 +737,23 @@ type OpenClawCronAdapter = {
740
737
  };
741
738
  declare function createCloudCommand(options?: CreateCloudCommandOptions): OpenClawPluginCommandDefinition;
742
739
 
740
+ declare function getRenewalAgentId(): string;
741
+ /** Absolute path to node for renewal exec (override with MNEMOSPARK_CRON_NODE_BIN). */
742
+ declare function getRenewalNodeBinary(): string;
743
+ type EnsureOpenClawRenewalPrerequisitesOptions = {
744
+ homeDir?: string;
745
+ /** Skip all OpenClaw mutations (tests). */
746
+ disabled?: boolean;
747
+ };
748
+ /**
749
+ * Apply the Mnemospark Renewal Agent Runbook (install/update / plugin load):
750
+ * - `agents.list` entry via `openclaw config set` + `openclaw config validate`
751
+ * - `~/.openclaw/exec-approvals.json` merge for the node binary
752
+ *
753
+ * Gateway restart is not performed here; OpenClaw restarts the gateway when a plugin is installed or updated.
754
+ */
755
+ declare function ensureOpenClawRenewalPrerequisites(options?: EnsureOpenClawRenewalPrerequisitesOptions): Promise<void>;
756
+
743
757
  type RunMnemosparkSlashHandlerOptions = {
744
758
  cloudCommandHandler?: PluginCommandHandler;
745
759
  };
@@ -757,4 +771,4 @@ declare function runMnemosparkSlashHandler(ctx: PluginCommandContext, options?:
757
771
 
758
772
  declare const plugin: OpenClawPluginDefinition;
759
773
 
760
- export { BALANCE_THRESHOLDS, type BalanceInfo, BalanceMonitor, type CachedPaymentParams, DEFAULT_RETRY_CONFIG, EmptyWalletError, InsufficientFundsError, type InsufficientFundsInfo, type LowBalanceInfo, PaymentCache, type PaymentFetchResult, type PreAuthParams, type ProxyHandle, type ProxyOptions, type RetryConfig, RpcError, type SufficiencyResult, createCloudCommand, createPaymentFetch, plugin as default, fetchWithRetry, getProxyPort, isBalanceError, isEmptyWalletError, isInsufficientFundsError, isRetryable, isRpcError, runMnemosparkSlashHandler, startProxy };
774
+ export { BALANCE_THRESHOLDS, type BalanceInfo, BalanceMonitor, type CachedPaymentParams, DEFAULT_RETRY_CONFIG, EmptyWalletError, type EnsureOpenClawRenewalPrerequisitesOptions, InsufficientFundsError, type InsufficientFundsInfo, type LowBalanceInfo, PaymentCache, type PaymentFetchResult, type PreAuthParams, type ProxyHandle, type ProxyOptions, type RetryConfig, RpcError, type SufficiencyResult, createCloudCommand, createPaymentFetch, plugin as default, ensureOpenClawRenewalPrerequisites, fetchWithRetry, getProxyPort, getRenewalAgentId, getRenewalNodeBinary, isBalanceError, isEmptyWalletError, isInsufficientFundsError, isRetryable, isRpcError, runMnemosparkSlashHandler, startProxy };
package/dist/index.js CHANGED
@@ -3049,17 +3049,17 @@ var CLOUD_ONBOARDING_BLOCK_LINES = [
3049
3049
  ];
3050
3050
 
3051
3051
  // src/cloud-command.ts
3052
- import { spawn } from "child_process";
3052
+ import { spawn as spawn2 } from "child_process";
3053
3053
  import {
3054
3054
  createCipheriv,
3055
3055
  createHash as createHash2,
3056
3056
  randomBytes as randomBytesNode,
3057
- randomUUID as randomUUID3
3057
+ randomUUID as randomUUID4
3058
3058
  } from "crypto";
3059
3059
  import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, statfsSync } from "fs";
3060
- import { lstat, mkdir as mkdir5, readFile as readFile3, readdir as readdir2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
3061
- import { homedir as homedir6, tmpdir } from "os";
3062
- import { basename as basename2, dirname as dirname5, join as join8, resolve as resolve2 } from "path";
3060
+ import { lstat, mkdir as mkdir6, readFile as readFile4, readdir as readdir2, rm, stat as stat2, writeFile as writeFile4 } from "fs/promises";
3061
+ import { homedir as homedir7, tmpdir } from "os";
3062
+ import { basename as basename2, dirname as dirname6, join as join10, resolve as resolve2 } from "path";
3063
3063
  import { Readable } from "stream";
3064
3064
  import { finished } from "stream/promises";
3065
3065
  import { privateKeyToAccount as privateKeyToAccount5 } from "viem/accounts";
@@ -4264,12 +4264,219 @@ var opStatusSchema = {
4264
4264
  ]
4265
4265
  };
4266
4266
 
4267
+ // src/openclaw-cli.ts
4268
+ import { spawn } from "child_process";
4269
+ import { join as join8 } from "path";
4270
+ async function runOpenClawCli(args, homeDir) {
4271
+ return await new Promise((resolvePromise, rejectPromise) => {
4272
+ let stdout = "";
4273
+ let stderr = "";
4274
+ const child = spawn("openclaw", args, {
4275
+ stdio: ["ignore", "pipe", "pipe"],
4276
+ env: {
4277
+ ...process.env,
4278
+ HOME: homeDir ?? process.env.HOME
4279
+ }
4280
+ });
4281
+ child.stdout.on("data", (chunk) => {
4282
+ stdout += chunk.toString();
4283
+ });
4284
+ child.stderr.on("data", (chunk) => {
4285
+ stderr += chunk.toString();
4286
+ });
4287
+ child.on("error", rejectPromise);
4288
+ child.on("close", (code) => {
4289
+ if (code === 0) {
4290
+ resolvePromise({ stdout, stderr });
4291
+ return;
4292
+ }
4293
+ rejectPromise(
4294
+ new Error(
4295
+ stderr.trim() || stdout.trim() || `openclaw ${args.join(" ")} exited with code ${code ?? "unknown"}`
4296
+ )
4297
+ );
4298
+ });
4299
+ });
4300
+ }
4301
+ function parseOpenClawCliJson(stdout, commandLabel) {
4302
+ const trimmed = stdout.trim();
4303
+ if (!trimmed) {
4304
+ throw new Error(`openclaw ${commandLabel} returned empty JSON output`);
4305
+ }
4306
+ try {
4307
+ return JSON.parse(trimmed);
4308
+ } catch {
4309
+ throw new Error(`openclaw ${commandLabel} returned invalid JSON output`);
4310
+ }
4311
+ }
4312
+ async function resolveOpenClawConfigFilePath(homeDir) {
4313
+ const { stdout } = await runOpenClawCli(["config", "file"], homeDir);
4314
+ const trimmed = stdout.trim();
4315
+ if (trimmed.startsWith("~/")) {
4316
+ return join8(homeDir, trimmed.slice(2));
4317
+ }
4318
+ if (trimmed.startsWith("~\\")) {
4319
+ return join8(homeDir, trimmed.slice(2));
4320
+ }
4321
+ return trimmed;
4322
+ }
4323
+
4324
+ // src/openclaw-renewal-runbook.ts
4325
+ import { mkdir as mkdir5, readFile as readFile3, rename as rename2, writeFile as writeFile3 } from "fs/promises";
4326
+ import { homedir as homedir6 } from "os";
4327
+ import { dirname as dirname5, join as join9 } from "path";
4328
+ import { randomUUID as randomUUID3 } from "crypto";
4329
+ var DEFAULT_RENEWAL_AGENT_ID = "mnemospark-renewal";
4330
+ var RENEWAL_NODE_ALLOWLIST_ID = "node-usr-bin-node";
4331
+ function getRenewalAgentId() {
4332
+ const fromEnv = process.env.MNEMOSPARK_CRON_AGENT_ID?.trim();
4333
+ return fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_RENEWAL_AGENT_ID;
4334
+ }
4335
+ function getRenewalNodeBinary() {
4336
+ const fromEnv = process.env.MNEMOSPARK_CRON_NODE_BIN?.trim();
4337
+ return fromEnv && fromEnv.length > 0 ? fromEnv : "/usr/bin/node";
4338
+ }
4339
+ function runbookRenewalAgentEntry(agentId = getRenewalAgentId()) {
4340
+ return {
4341
+ id: agentId,
4342
+ tools: {
4343
+ deny: ["subagents"],
4344
+ exec: { ask: "off" }
4345
+ }
4346
+ };
4347
+ }
4348
+ function isRecord(value) {
4349
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
4350
+ }
4351
+ function renewalAgentEntrySatisfied(existing, desired) {
4352
+ if (!isRecord(existing)) {
4353
+ return false;
4354
+ }
4355
+ if (existing.id !== desired.id) {
4356
+ return false;
4357
+ }
4358
+ const tools = existing.tools;
4359
+ if (!isRecord(tools)) {
4360
+ return false;
4361
+ }
4362
+ const deny = tools.deny;
4363
+ if (!Array.isArray(deny) || !deny.includes("subagents")) {
4364
+ return false;
4365
+ }
4366
+ const exec = tools.exec;
4367
+ if (!isRecord(exec) || exec.ask !== "off") {
4368
+ return false;
4369
+ }
4370
+ return true;
4371
+ }
4372
+ function mergeRenewalAgentIntoAgentsList(list, desired) {
4373
+ const arr = Array.isArray(list) ? [...list] : [];
4374
+ const idx = arr.findIndex((e) => isRecord(e) && typeof e.id === "string" && e.id === desired.id);
4375
+ if (idx === -1) {
4376
+ return { list: [...arr, desired], changed: true };
4377
+ }
4378
+ if (renewalAgentEntrySatisfied(arr[idx], desired)) {
4379
+ return { list: arr, changed: false };
4380
+ }
4381
+ const next = [...arr];
4382
+ next[idx] = desired;
4383
+ return { list: next, changed: true };
4384
+ }
4385
+ function mergeExecApprovalsAllowlist(doc, agentId, nodeBinary) {
4386
+ const prevAgents = doc.agents && isRecord(doc.agents) ? doc.agents : {};
4387
+ const block = prevAgents[agentId];
4388
+ const allowlist = Array.isArray(block?.allowlist) ? [...block.allowlist] : [];
4389
+ const hasPattern = allowlist.some((e) => e?.pattern === nodeBinary);
4390
+ if (hasPattern) {
4391
+ return { doc, changed: false };
4392
+ }
4393
+ allowlist.push({
4394
+ id: RENEWAL_NODE_ALLOWLIST_ID,
4395
+ pattern: nodeBinary,
4396
+ source: "manual",
4397
+ lastUsedAt: Date.now()
4398
+ });
4399
+ const nextAgents = {
4400
+ ...prevAgents,
4401
+ [agentId]: {
4402
+ ...block && isRecord(block) ? block : {},
4403
+ allowlist
4404
+ }
4405
+ };
4406
+ return { doc: { ...doc, agents: nextAgents }, changed: true };
4407
+ }
4408
+ async function readJsonFile(path) {
4409
+ const raw = await readFile3(path, "utf-8");
4410
+ return JSON.parse(raw);
4411
+ }
4412
+ async function writeFileAtomic(path, contents) {
4413
+ await mkdir5(dirname5(path), { recursive: true });
4414
+ const tmp = join9(dirname5(path), `.tmp-${randomUUID3()}`);
4415
+ await writeFile3(tmp, contents, "utf-8");
4416
+ await rename2(tmp, path);
4417
+ }
4418
+ async function ensureOpenClawRenewalPrerequisites(options = {}) {
4419
+ if (options.disabled ?? process.env.MNEMOSPARK_DISABLE_OPENCLAW_PREREQ === "1") {
4420
+ return;
4421
+ }
4422
+ const homeDir = options.homeDir ?? homedir6();
4423
+ const agentId = getRenewalAgentId();
4424
+ const desired = runbookRenewalAgentEntry(agentId);
4425
+ const nodeBinary = getRenewalNodeBinary();
4426
+ const configPath = await resolveOpenClawConfigFilePath(homeDir);
4427
+ let configRaw = "{}";
4428
+ try {
4429
+ configRaw = await readFile3(configPath, "utf-8");
4430
+ } catch (err) {
4431
+ if (err.code !== "ENOENT") {
4432
+ throw err;
4433
+ }
4434
+ }
4435
+ let parsed;
4436
+ try {
4437
+ parsed = JSON.parse(configRaw);
4438
+ } catch {
4439
+ throw new Error(
4440
+ `openclaw.json at ${configPath} is not valid JSON; fix or remove it before applying renewal prerequisites.`
4441
+ );
4442
+ }
4443
+ const agents = isRecord(parsed.agents) ? parsed.agents : {};
4444
+ const { list: mergedList, changed: agentChanged } = mergeRenewalAgentIntoAgentsList(
4445
+ agents.list,
4446
+ desired
4447
+ );
4448
+ if (agentChanged) {
4449
+ const listJson = JSON.stringify(mergedList);
4450
+ await runOpenClawCli(["config", "set", "agents.list", listJson, "--strict-json"], homeDir);
4451
+ await runOpenClawCli(["config", "validate"], homeDir);
4452
+ }
4453
+ const execPath = join9(homeDir, ".openclaw", "exec-approvals.json");
4454
+ let execDoc = {};
4455
+ try {
4456
+ const raw = await readJsonFile(execPath);
4457
+ execDoc = isRecord(raw) ? raw : {};
4458
+ } catch (err) {
4459
+ if (err.code !== "ENOENT") {
4460
+ throw err;
4461
+ }
4462
+ }
4463
+ const { doc: mergedExec, changed: execChanged } = mergeExecApprovalsAllowlist(
4464
+ execDoc,
4465
+ agentId,
4466
+ nodeBinary
4467
+ );
4468
+ if (execChanged) {
4469
+ await writeFileAtomic(execPath, `${JSON.stringify(mergedExec, null, 2)}
4470
+ `);
4471
+ }
4472
+ }
4473
+
4267
4474
  // src/cloud-command.ts
4268
4475
  var SUPPORTED_BACKUP_PLATFORMS = /* @__PURE__ */ new Set(["darwin", "linux"]);
4269
- var BACKUP_DIR_SUBPATH = join8(".openclaw", "mnemospark", "backup");
4270
- var DEFAULT_BACKUP_DIR = join8(homedir6(), BACKUP_DIR_SUBPATH);
4271
- var BLOCKRUN_WALLET_KEY_SUBPATH = join8(".openclaw", "blockrun", "wallet.key");
4272
- var MNEMOSPARK_WALLET_KEY_SUBPATH = join8(".openclaw", "mnemospark", "wallet", "wallet.key");
4476
+ var BACKUP_DIR_SUBPATH = join10(".openclaw", "mnemospark", "backup");
4477
+ var DEFAULT_BACKUP_DIR = join10(homedir7(), BACKUP_DIR_SUBPATH);
4478
+ var BLOCKRUN_WALLET_KEY_SUBPATH = join10(".openclaw", "blockrun", "wallet.key");
4479
+ var MNEMOSPARK_WALLET_KEY_SUBPATH = join10(".openclaw", "mnemospark", "wallet", "wallet.key");
4273
4480
  var INLINE_UPLOAD_MAX_BYTES = 45e5;
4274
4481
  var NODE_FS_MAX_READFILE_BYTES = 2147483648;
4275
4482
  var PAYMENT_CRON_SCHEDULE = "0 0 1 * *";
@@ -4287,10 +4494,10 @@ var ORCHESTRATOR_MODES = /* @__PURE__ */ new Set(["inline", "subagent"]);
4287
4494
  function expandTilde(path) {
4288
4495
  const trimmed = path.trim();
4289
4496
  if (trimmed === "~") {
4290
- return homedir6();
4497
+ return homedir7();
4291
4498
  }
4292
4499
  if (trimmed.startsWith("~/") || trimmed.startsWith("~\\")) {
4293
- return join8(homedir6(), trimmed.slice(2));
4500
+ return join10(homedir7(), trimmed.slice(2));
4294
4501
  }
4295
4502
  return path;
4296
4503
  }
@@ -4858,7 +5065,7 @@ async function calculateInputSizeBytes(targetPath) {
4858
5065
  let total = 0;
4859
5066
  const entries = await readdir2(targetPath, { withFileTypes: true });
4860
5067
  for (const entry of entries) {
4861
- total += await calculateInputSizeBytes(join8(targetPath, entry.name));
5068
+ total += await calculateInputSizeBytes(join10(targetPath, entry.name));
4862
5069
  }
4863
5070
  return total;
4864
5071
  }
@@ -4870,11 +5077,11 @@ function getAvailableDiskBytes(tmpDir, options) {
4870
5077
  return stats.bavail * stats.bsize;
4871
5078
  }
4872
5079
  async function runTarGzip(archivePath, sourcePath) {
4873
- const sourceDir = dirname5(sourcePath);
5080
+ const sourceDir = dirname6(sourcePath);
4874
5081
  const sourceName = basename2(sourcePath);
4875
5082
  await new Promise((resolvePromise, rejectPromise) => {
4876
5083
  let stderr = "";
4877
- const child = spawn("tar", ["-czf", archivePath, "-C", sourceDir, sourceName], {
5084
+ const child = spawn2("tar", ["-czf", archivePath, "-C", sourceDir, sourceName], {
4878
5085
  stdio: ["ignore", "ignore", "pipe"]
4879
5086
  });
4880
5087
  child.stderr.on("data", (chunk) => {
@@ -4904,7 +5111,7 @@ async function resolveLocalUploadArchivePath(backupDir, objectId, friendlyName)
4904
5111
  if (friendlyName?.trim()) {
4905
5112
  try {
4906
5113
  const sanitized = sanitizeFriendlyNameForLocalBasename(friendlyName);
4907
- const candidate = join8(backupDir, sanitized);
5114
+ const candidate = join10(backupDir, sanitized);
4908
5115
  try {
4909
5116
  const st = await stat2(candidate);
4910
5117
  if (st.isFile()) {
@@ -4915,7 +5122,7 @@ async function resolveLocalUploadArchivePath(backupDir, objectId, friendlyName)
4915
5122
  } catch {
4916
5123
  }
4917
5124
  }
4918
- const legacyPath = join8(backupDir, objectId);
5125
+ const legacyPath = join10(backupDir, objectId);
4919
5126
  try {
4920
5127
  const legacyStats = await stat2(legacyPath);
4921
5128
  if (!legacyStats.isFile()) {
@@ -4953,7 +5160,7 @@ async function buildBackupObject(targetPathArg, options = {}) {
4953
5160
  tmpStats = await stat2(tmpDir);
4954
5161
  } catch (error) {
4955
5162
  if (error.code === "ENOENT") {
4956
- await mkdir5(tmpDir, { recursive: true });
5163
+ await mkdir6(tmpDir, { recursive: true });
4957
5164
  tmpStats = await stat2(tmpDir);
4958
5165
  } else {
4959
5166
  throw error;
@@ -4970,7 +5177,7 @@ async function buildBackupObject(targetPathArg, options = {}) {
4970
5177
  }
4971
5178
  const objectId = createObjectId(options);
4972
5179
  const archiveBaseSegment = options.archiveBasename?.trim() || objectId;
4973
- const archivePath = join8(tmpDir, archiveBaseSegment);
5180
+ const archivePath = join10(tmpDir, archiveBaseSegment);
4974
5181
  if (options.archiveBasename?.trim()) {
4975
5182
  try {
4976
5183
  const existing = await stat2(archivePath);
@@ -5026,48 +5233,6 @@ function normalizeOpenClawCronJobForLookup(value) {
5026
5233
  message: payloadMessage
5027
5234
  };
5028
5235
  }
5029
- async function runOpenClawCli(args, homeDir) {
5030
- return await new Promise((resolvePromise, rejectPromise) => {
5031
- let stdout = "";
5032
- let stderr = "";
5033
- const child = spawn("openclaw", args, {
5034
- stdio: ["ignore", "pipe", "pipe"],
5035
- env: {
5036
- ...process.env,
5037
- HOME: homeDir ?? process.env.HOME
5038
- }
5039
- });
5040
- child.stdout.on("data", (chunk) => {
5041
- stdout += chunk.toString();
5042
- });
5043
- child.stderr.on("data", (chunk) => {
5044
- stderr += chunk.toString();
5045
- });
5046
- child.on("error", rejectPromise);
5047
- child.on("close", (code) => {
5048
- if (code === 0) {
5049
- resolvePromise({ stdout, stderr });
5050
- return;
5051
- }
5052
- rejectPromise(
5053
- new Error(
5054
- stderr.trim() || stdout.trim() || `openclaw ${args.join(" ")} exited with code ${code ?? "unknown"}`
5055
- )
5056
- );
5057
- });
5058
- });
5059
- }
5060
- function parseOpenClawCliJson(stdout, commandLabel) {
5061
- const trimmed = stdout.trim();
5062
- if (!trimmed) {
5063
- throw new Error(`openclaw ${commandLabel} returned empty JSON output`);
5064
- }
5065
- try {
5066
- return JSON.parse(trimmed);
5067
- } catch {
5068
- throw new Error(`openclaw ${commandLabel} returned invalid JSON output`);
5069
- }
5070
- }
5071
5236
  function createOpenClawCliCronAdapter(homeDir) {
5072
5237
  return {
5073
5238
  add: async (job) => {
@@ -5083,11 +5248,11 @@ function createOpenClawCliCronAdapter(homeDir) {
5083
5248
  job.schedule.tz,
5084
5249
  "--session",
5085
5250
  job.sessionTarget,
5251
+ "--agent",
5252
+ job.agentId,
5086
5253
  "--message",
5087
5254
  job.payload.message,
5088
- "--announce",
5089
- "--description",
5090
- job.delivery.text,
5255
+ "--no-deliver",
5091
5256
  "--json"
5092
5257
  ],
5093
5258
  homeDir
@@ -5152,8 +5317,9 @@ function buildStoragePaymentCronCommand(job) {
5152
5317
  return `/mnemospark cloud ${buildStoragePaymentRenewalArgs(job)}`;
5153
5318
  }
5154
5319
  function buildOpenClawRenewalAgentMessage(openClawHome, renewalArgs) {
5155
- const cliPath = join8(openClawHome, ".openclaw/extensions/mnemospark/dist/cli.js");
5156
- return `Execute: node ${cliPath} cloud ${renewalArgs}`;
5320
+ const cliPath = join10(openClawHome, ".openclaw/extensions/mnemospark/dist/cli.js");
5321
+ const nodeBin = getRenewalNodeBinary();
5322
+ return `Command: ${nodeBin} ${cliPath} cloud ${renewalArgs}`;
5157
5323
  }
5158
5324
  function parseStoragePaymentCronCommand(command) {
5159
5325
  const objectIdMatch = command.match(/--object-id\s+("([^"\\]|\\.)*"|'([^'\\]|\\.)*'|\S+)/);
@@ -5199,10 +5365,7 @@ async function appendStoragePaymentCronJob(cronJob, adapter, payloadMessage) {
5199
5365
  message: payloadMessage
5200
5366
  },
5201
5367
  sessionTarget: "isolated",
5202
- delivery: {
5203
- mode: "announce",
5204
- text: "Thank you for using mnemospark cloud storage. Your renewal has been processed."
5205
- }
5368
+ agentId: getRenewalAgentId()
5206
5369
  };
5207
5370
  return adapter.add(openClawJob);
5208
5371
  }
@@ -5217,7 +5380,7 @@ async function createStoragePaymentCronJob(upload, storagePrice, openClawCronAda
5217
5380
  storagePrice
5218
5381
  };
5219
5382
  const renewalArgs = buildStoragePaymentRenewalArgs(renewalFields);
5220
- const provisionalCronId = randomUUID3();
5383
+ const provisionalCronId = randomUUID4();
5221
5384
  const cronJob = {
5222
5385
  cronId: provisionalCronId,
5223
5386
  createdAt: nowDateFn().toISOString(),
@@ -5241,7 +5404,7 @@ async function createStoragePaymentCronJob(upload, storagePrice, openClawCronAda
5241
5404
  }
5242
5405
  async function readWalletKeyIfPresent(walletPath) {
5243
5406
  try {
5244
- const key = (await readFile3(walletPath, "utf-8")).trim();
5407
+ const key = (await readFile4(walletPath, "utf-8")).trim();
5245
5408
  return isValidWalletPrivateKey(key) ? key : null;
5246
5409
  } catch (error) {
5247
5410
  if (error.code === "ENOENT") {
@@ -5255,9 +5418,9 @@ async function resolveWalletPrivateKey(homeDir) {
5255
5418
  if (isValidWalletPrivateKey(envKey)) {
5256
5419
  return envKey;
5257
5420
  }
5258
- const baseHome = homeDir ?? homedir6();
5259
- const primaryWalletPath = join8(baseHome, MNEMOSPARK_WALLET_KEY_SUBPATH);
5260
- const fallbackWalletPath = join8(baseHome, BLOCKRUN_WALLET_KEY_SUBPATH);
5421
+ const baseHome = homeDir ?? homedir7();
5422
+ const primaryWalletPath = join10(baseHome, MNEMOSPARK_WALLET_KEY_SUBPATH);
5423
+ const fallbackWalletPath = join10(baseHome, BLOCKRUN_WALLET_KEY_SUBPATH);
5261
5424
  const fromPrimary = await readWalletKeyIfPresent(primaryWalletPath);
5262
5425
  if (fromPrimary) {
5263
5426
  return fromPrimary;
@@ -5321,9 +5484,9 @@ async function encryptPlaintextFileToAesGcmPath(plaintextPath, dek, outPath, ran
5321
5484
  }
5322
5485
  async function loadOrCreateKek(walletAddress, homeDir) {
5323
5486
  const keyPath = resolveWalletKekPath(walletAddress, homeDir);
5324
- await mkdir5(dirname5(keyPath), { recursive: true });
5487
+ await mkdir6(dirname6(keyPath), { recursive: true });
5325
5488
  try {
5326
- const existing = await readFile3(keyPath);
5489
+ const existing = await readFile4(keyPath);
5327
5490
  return { kek: parseStoredAes256Key(existing), keyPath };
5328
5491
  } catch (error) {
5329
5492
  if (error.code !== "ENOENT") {
@@ -5331,7 +5494,7 @@ async function loadOrCreateKek(walletAddress, homeDir) {
5331
5494
  }
5332
5495
  }
5333
5496
  const generated = randomBytesNode(32);
5334
- await writeFile3(keyPath, generated, { mode: 384 });
5497
+ await writeFile4(keyPath, generated, { mode: 384 });
5335
5498
  return { kek: generated, keyPath };
5336
5499
  }
5337
5500
  async function prepareUploadPayload(archivePath, walletAddress, homeDir) {
@@ -5343,7 +5506,7 @@ async function prepareUploadPayload(archivePath, walletAddress, homeDir) {
5343
5506
  const dek = randomBytesNode(32);
5344
5507
  const wrappedDek = encryptAesGcm(dek, kek);
5345
5508
  if (archiveStat.size >= NODE_FS_MAX_READFILE_BYTES) {
5346
- const encryptedTempPath = join8(tmpdir(), `mnemospark-upload-${randomUUID3()}.enc`);
5509
+ const encryptedTempPath = join10(tmpdir(), `mnemospark-upload-${randomUUID4()}.enc`);
5347
5510
  try {
5348
5511
  await encryptPlaintextFileToAesGcmPath(archivePath, dek, encryptedTempPath);
5349
5512
  const encStat = await stat2(encryptedTempPath);
@@ -5369,7 +5532,7 @@ async function prepareUploadPayload(archivePath, walletAddress, homeDir) {
5369
5532
  throw err;
5370
5533
  }
5371
5534
  }
5372
- const plaintext = await readFile3(archivePath);
5535
+ const plaintext = await readFile4(archivePath);
5373
5536
  const encryptedContent = encryptAesGcm(plaintext, dek);
5374
5537
  const payloadHash = sha256Buffer(encryptedContent);
5375
5538
  const payload = {
@@ -5614,7 +5777,7 @@ function createInProcessSubagentOrchestrator() {
5614
5777
  };
5615
5778
  return {
5616
5779
  dispatch: async (input) => {
5617
- const sessionId = `agent:mnemospark:subagent:${randomUUID3()}`;
5780
+ const sessionId = `agent:mnemospark:subagent:${randomUUID4()}`;
5618
5781
  const state = {
5619
5782
  terminal: false,
5620
5783
  cancelRequested: false,
@@ -5716,7 +5879,7 @@ function createCloudCommand(options = {}) {
5716
5879
  createPaymentFetchFn: options.createPaymentFetchFn ?? createPaymentFetch,
5717
5880
  fetchImpl: options.fetchImpl ?? fetch,
5718
5881
  nowDateFn: options.nowDateFn ?? (() => /* @__PURE__ */ new Date()),
5719
- idempotencyKeyFn: options.idempotencyKeyFn ?? randomUUID3,
5882
+ idempotencyKeyFn: options.idempotencyKeyFn ?? randomUUID4,
5720
5883
  requestStorageLsFn: options.requestStorageLsFn ?? requestStorageLsViaProxy,
5721
5884
  requestStorageDownloadFn: options.requestStorageDownloadFn ?? requestStorageDownloadViaProxy,
5722
5885
  requestStorageDeleteFn: options.requestStorageDeleteFn ?? requestStorageDeleteViaProxy,
@@ -5860,8 +6023,8 @@ async function emitOperationEventBestEffort(eventType, context, homeDir) {
5860
6023
  }
5861
6024
  }
5862
6025
  function buildRequestCorrelation(forcedOperationId, forcedTraceId) {
5863
- const operationId = forcedOperationId?.trim() || randomUUID3();
5864
- const traceId = forcedTraceId?.trim() || randomUUID3();
6026
+ const operationId = forcedOperationId?.trim() || randomUUID4();
6027
+ const traceId = forcedTraceId?.trim() || randomUUID4();
5865
6028
  return { operationId, traceId };
5866
6029
  }
5867
6030
  function parseTransIdFromPaymentSettleBody(bodyText) {
@@ -6149,7 +6312,7 @@ ${operation.result_text}` : meta;
6149
6312
  };
6150
6313
  }
6151
6314
  if (!isTerminalOperationStatus(operation.status)) {
6152
- const traceId = operation.trace_id ?? randomUUID3();
6315
+ const traceId = operation.trace_id ?? randomUUID4();
6153
6316
  const cancelRequestedAt = (/* @__PURE__ */ new Date()).toISOString();
6154
6317
  await datastore.upsertOperation({
6155
6318
  operation_id: operation.operation_id,
@@ -6747,7 +6910,7 @@ operation-id: ${operationId}`,
6747
6910
  await emitCloudEventBestEffort(
6748
6911
  "backup.completed",
6749
6912
  {
6750
- operation_id: executionContext.forcedOperationId?.trim() || randomUUID3(),
6913
+ operation_id: executionContext.forcedOperationId?.trim() || randomUUID4(),
6751
6914
  object_id: result.objectId,
6752
6915
  status: "succeeded",
6753
6916
  details: {
@@ -7034,7 +7197,7 @@ operation-id: ${operationId}`,
7034
7197
  finalizedUploadResponse,
7035
7198
  cronStoragePrice,
7036
7199
  openClawCronAdapter,
7037
- mnemosparkHomeDir ?? homedir6(),
7200
+ mnemosparkHomeDir ?? homedir7(),
7038
7201
  nowDateFn
7039
7202
  );
7040
7203
  await datastore.upsertObject({
@@ -7764,6 +7927,13 @@ var plugin = {
7764
7927
  if (isCompletionMode()) {
7765
7928
  return;
7766
7929
  }
7930
+ try {
7931
+ await ensureOpenClawRenewalPrerequisites();
7932
+ } catch (err) {
7933
+ api.logger.warn(
7934
+ `mnemospark renewal prerequisites: ${err instanceof Error ? err.message : String(err)}`
7935
+ );
7936
+ }
7767
7937
  try {
7768
7938
  api.registerCommand({
7769
7939
  name: "mnemospark",
@@ -7828,8 +7998,11 @@ export {
7828
7998
  createCloudCommand,
7829
7999
  createPaymentFetch,
7830
8000
  index_default as default,
8001
+ ensureOpenClawRenewalPrerequisites,
7831
8002
  fetchWithRetry,
7832
8003
  getProxyPort,
8004
+ getRenewalAgentId,
8005
+ getRenewalNodeBinary,
7833
8006
  isBalanceError,
7834
8007
  isEmptyWalletError,
7835
8008
  isInsufficientFundsError,