mnemospark 0.5.0 → 0.7.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/cli.js CHANGED
@@ -1602,8 +1602,8 @@ import { homedir as homedir2 } from "os";
1602
1602
  import { basename, dirname as dirname2, join as join3 } from "path";
1603
1603
  import { pipeline } from "stream/promises";
1604
1604
  var BASE_DIR = join3(homedir2(), ".openclaw", "mnemospark");
1605
- var MAX_BYTES = 10 * 1024 * 1024;
1606
- var KEEP_ROTATED = 10;
1605
+ var MAX_BYTES = 15 * 1024 * 1024;
1606
+ var KEEP_ROTATED = 12;
1607
1607
  function resolvePath(fileName, homeDir) {
1608
1608
  const baseDir = homeDir ? join3(homeDir, ".openclaw", "mnemospark") : BASE_DIR;
1609
1609
  return join3(baseDir, fileName);
@@ -1694,10 +1694,11 @@ function logProxyEvent(level, event, fields = {}) {
1694
1694
  console.info(message);
1695
1695
  }
1696
1696
  function emitProxyEvent(eventType, status, correlation, details = {}) {
1697
- void appendJsonlEvent("proxy-events.jsonl", {
1697
+ void appendJsonlEvent("events.jsonl", {
1698
1698
  ts: (/* @__PURE__ */ new Date()).toISOString(),
1699
1699
  event_type: eventType,
1700
1700
  status,
1701
+ source: "proxy",
1701
1702
  trace_id: correlation.trace_id,
1702
1703
  operation_id: correlation.operation_id,
1703
1704
  quote_id: correlation.quote_id ?? null,
@@ -2890,7 +2891,14 @@ import { CronExpressionParser } from "cron-parser";
2890
2891
  var LS_NAME_DISPLAY_MAX = 72;
2891
2892
  var LS_PAY_DISPLAY_MAX = 28;
2892
2893
  var LS_CRON_ID_MAX = 14;
2893
- var LS_TIME_FIELD_WIDTH = 12;
2894
+ var LS_S3_COL_WIDTH = 12;
2895
+ var LS_NEXT_COL_WIDTH = Math.max(LS_S3_COL_WIDTH, "NEXT PAYMENT DATE".length);
2896
+ var HDR_SIZE = "SIZE";
2897
+ var HDR_S3_TIME = "S3_TIME";
2898
+ var HDR_CRON_JOB = "CRON JOB";
2899
+ var HDR_NEXT_PAYMENT = "NEXT PAYMENT DATE";
2900
+ var HDR_AMOUNT_DUE = "AMOUNT DUE";
2901
+ var HDR_FILE_OR_KEY = "FILE NAME OR OBJECT-KEY";
2894
2902
  var MONTHS_SHORT = [
2895
2903
  "Jan",
2896
2904
  "Feb",
@@ -2905,14 +2913,14 @@ var MONTHS_SHORT = [
2905
2913
  "Nov",
2906
2914
  "Dec"
2907
2915
  ];
2908
- function formatLsTimeFieldUtc(iso, now) {
2909
- const placeholder = " - ".slice(0, LS_TIME_FIELD_WIDTH);
2916
+ function formatLsTimeFieldUtc(iso, now, fieldWidth = LS_S3_COL_WIDTH) {
2917
+ const placeholder = " - ".slice(0, fieldWidth);
2910
2918
  if (!iso) {
2911
- return placeholder.padEnd(LS_TIME_FIELD_WIDTH, " ");
2919
+ return placeholder.padEnd(fieldWidth, " ");
2912
2920
  }
2913
2921
  const d = new Date(iso);
2914
2922
  if (Number.isNaN(d.getTime())) {
2915
- return placeholder.padEnd(LS_TIME_FIELD_WIDTH, " ");
2923
+ return placeholder.padEnd(fieldWidth, " ");
2916
2924
  }
2917
2925
  const mon = MONTHS_SHORT[d.getUTCMonth()] ?? "???";
2918
2926
  const day = String(d.getUTCDate()).padStart(2, " ");
@@ -2926,7 +2934,7 @@ function formatLsTimeFieldUtc(iso, now) {
2926
2934
  } else {
2927
2935
  core = `${mon} ${day} ${y}`;
2928
2936
  }
2929
- return core.padEnd(LS_TIME_FIELD_WIDTH, " ");
2937
+ return core.padEnd(fieldWidth, " ");
2930
2938
  }
2931
2939
  function truncateEnd(value, max) {
2932
2940
  if (value.length <= max) {
@@ -2966,18 +2974,26 @@ function formatPaymentCell(amount, network, maxWidth) {
2966
2974
  return truncateEnd(s, maxWidth).padStart(maxWidth, " ");
2967
2975
  }
2968
2976
  function formatNextCronUtc(schedule, cronStatus, now) {
2969
- const blank = " - ".slice(0, LS_TIME_FIELD_WIDTH).padEnd(LS_TIME_FIELD_WIDTH, " ");
2977
+ const blank = " - ".slice(0, LS_NEXT_COL_WIDTH).padEnd(LS_NEXT_COL_WIDTH, " ");
2970
2978
  if (cronStatus !== "active") {
2971
2979
  return blank;
2972
2980
  }
2973
2981
  try {
2974
2982
  const expr = CronExpressionParser.parse(schedule, { tz: "UTC", currentDate: now });
2975
2983
  const next = expr.next().toDate();
2976
- return formatLsTimeFieldUtc(next.toISOString(), now);
2984
+ return formatLsTimeFieldUtc(next.toISOString(), now, LS_NEXT_COL_WIDTH);
2977
2985
  } catch {
2978
- return "?".padEnd(LS_TIME_FIELD_WIDTH, " ");
2986
+ return "?".padEnd(LS_NEXT_COL_WIDTH, " ");
2979
2987
  }
2980
2988
  }
2989
+ function buildLsProseIntro(bucket) {
2990
+ return [
2991
+ "\u2601\uFE0F mnemospark cloud files",
2992
+ `S3 bucket: ${bucket}`,
2993
+ "The columns: CRON JOB, NEXT PAYMENT DATE, AMOUNT DUE, FILE NAME are from this host's mnemospark SQLite catalog",
2994
+ "mnemospark cloud only stores the OBJECT-KEY for privacy"
2995
+ ];
2996
+ }
2981
2997
  async function prepareRows(objects, walletAddress, datastore, now) {
2982
2998
  const sorted = [...objects].sort((a, b) => {
2983
2999
  const ta = a.last_modified ? Date.parse(a.last_modified) : Number.NaN;
@@ -3000,9 +3016,9 @@ async function prepareRows(objects, walletAddress, datastore, now) {
3000
3016
  const friendly = await datastore.findLatestFriendlyNameForObjectKey(walletAddress, obj.key);
3001
3017
  const cp = await datastore.findCronAndPaymentForObjectKey(walletAddress, obj.key);
3002
3018
  const sizeStr = formatBytesForDisplay(obj.size_bytes);
3003
- const s3time = formatLsTimeFieldUtc(obj.last_modified, now);
3019
+ const s3time = formatLsTimeFieldUtc(obj.last_modified, now, LS_S3_COL_WIDTH);
3004
3020
  let cronIdDisp = null;
3005
- let nextRun = " - ".slice(0, LS_TIME_FIELD_WIDTH).padEnd(LS_TIME_FIELD_WIDTH, " ");
3021
+ let nextRun = " - ".slice(0, LS_NEXT_COL_WIDTH).padEnd(LS_NEXT_COL_WIDTH, " ");
3006
3022
  let payCell = "";
3007
3023
  if (cp) {
3008
3024
  cronIdDisp = cp.cronId;
@@ -3013,10 +3029,6 @@ async function prepareRows(objects, walletAddress, datastore, now) {
3013
3029
  }
3014
3030
  const nameRaw = friendly ? `${friendly} (${obj.key})` : obj.key;
3015
3031
  rows.push({
3016
- perm: "----------",
3017
- ln: " 1",
3018
- user: "- ",
3019
- grp: "- ",
3020
3032
  sizeStr,
3021
3033
  s3time,
3022
3034
  cronIdRaw: cronIdDisp,
@@ -3028,68 +3040,57 @@ async function prepareRows(objects, walletAddress, datastore, now) {
3028
3040
  return rows;
3029
3041
  }
3030
3042
  function columnWidths(rows) {
3031
- let sizeW = 4;
3032
- let cronW = 4;
3033
- let payW = 3;
3043
+ let sizeW = HDR_SIZE.length;
3044
+ let s3W = Math.max(LS_S3_COL_WIDTH, HDR_S3_TIME.length);
3045
+ let nextW = LS_NEXT_COL_WIDTH;
3046
+ let cronW = HDR_CRON_JOB.length;
3047
+ let payW = HDR_AMOUNT_DUE.length;
3034
3048
  for (const r of rows) {
3035
3049
  sizeW = Math.max(sizeW, r.sizeStr.length);
3050
+ s3W = Math.max(s3W, r.s3time.length);
3051
+ nextW = Math.max(nextW, r.nextRun.length);
3036
3052
  const cid = r.cronIdRaw ? truncateEnd(r.cronIdRaw, LS_CRON_ID_MAX) : "";
3037
3053
  cronW = Math.max(cronW, cid.length || 1);
3038
3054
  payW = Math.max(payW, r.payRaw.length);
3039
3055
  }
3040
- cronW = Math.min(Math.max(cronW, 4), LS_CRON_ID_MAX);
3041
- payW = Math.min(Math.max(payW, 3), LS_PAY_DISPLAY_MAX);
3042
- return { sizeW, cronW, payW };
3056
+ cronW = Math.min(Math.max(cronW, HDR_CRON_JOB.length), LS_CRON_ID_MAX);
3057
+ payW = Math.min(Math.max(payW, HDR_AMOUNT_DUE.length), LS_PAY_DISPLAY_MAX);
3058
+ return { sizeW, s3W, cronW, nextW, payW };
3043
3059
  }
3044
3060
  function renderRow(r, w) {
3045
3061
  const cronPadded = formatCronIdCell(r.cronIdRaw, w.cronW);
3046
- const sizePadded = r.sizeStr.padStart(w.sizeW, " ");
3047
- const payPadded = r.payRaw.padStart(w.payW, " ");
3048
3062
  return [
3049
- r.perm,
3050
- r.ln,
3051
- r.user,
3052
- r.grp,
3053
- sizePadded,
3054
- r.s3time,
3063
+ r.sizeStr.padStart(w.sizeW, " "),
3064
+ r.s3time.padEnd(w.s3W, " "),
3055
3065
  cronPadded,
3056
- r.nextRun,
3057
- payPadded,
3066
+ r.nextRun.padEnd(w.nextW, " "),
3067
+ r.payRaw.padStart(w.payW, " "),
3058
3068
  r.nameRaw
3059
3069
  ].join(" ");
3060
3070
  }
3061
3071
  function renderHeader(w) {
3062
3072
  return [
3063
- "PERM ",
3064
- "LN",
3065
- "USER ",
3066
- "GRP ",
3067
- "SIZE".padStart(w.sizeW, " "),
3068
- "S3_TIME ".slice(0, LS_TIME_FIELD_WIDTH).padEnd(LS_TIME_FIELD_WIDTH, " "),
3069
- "CRON".padStart(w.cronW, " "),
3070
- "NEXT ".slice(0, LS_TIME_FIELD_WIDTH).padEnd(LS_TIME_FIELD_WIDTH, " "),
3071
- "PAY".padStart(w.payW, " "),
3072
- "NAME"
3073
+ HDR_SIZE.padStart(w.sizeW, " "),
3074
+ HDR_S3_TIME.padEnd(w.s3W, " "),
3075
+ HDR_CRON_JOB.padStart(w.cronW, " "),
3076
+ HDR_NEXT_PAYMENT.padEnd(w.nextW, " "),
3077
+ HDR_AMOUNT_DUE.padStart(w.payW, " "),
3078
+ HDR_FILE_OR_KEY
3073
3079
  ].join(" ");
3074
3080
  }
3075
3081
  async function buildMnemosparkLsMessage(result, ctx) {
3076
3082
  const now = ctx.now ?? /* @__PURE__ */ new Date();
3077
3083
  if (isStorageLsListResponse(result)) {
3078
- const disclaimer2 = "Names, cron, and payment columns come from this machine's SQLite catalog when available; `-` means unknown locally. S3 is authoritative for which keys exist.";
3079
- const legend2 = "Legend: S3_TIME and NEXT are UTC. NEXT is the next cron fire from the stored expression.";
3080
- const bucketLine = `bucket: ${result.bucket}`;
3081
- const sortLine = "sorted by: S3 last_modified descending (missing dates last), then key ascending.";
3084
+ const intro = buildLsProseIntro(result.bucket);
3082
3085
  if (result.objects.length === 0) {
3083
- const lines = [disclaimer2, "", bucketLine, "", "No objects in this bucket."];
3084
- return lines.join("\n");
3086
+ return [...intro, "", "No objects in this bucket."].join("\n");
3085
3087
  }
3086
3088
  const rows = await prepareRows(result.objects, ctx.walletAddress, ctx.datastore, now);
3087
3089
  const w2 = columnWidths(rows);
3088
3090
  const header2 = renderHeader(w2);
3089
3091
  const bodyLines = rows.map((r) => renderRow(r, w2));
3090
- const totalLine = `total ${String(result.objects.length)}`;
3091
3092
  const truncLine = result.is_truncated ? "List truncated; more objects in bucket." : null;
3092
- const prose2 = [disclaimer2, legend2, bucketLine, sortLine, totalLine, truncLine].filter((x) => Boolean(x)).join("\n");
3093
+ const prose2 = [...intro, ...truncLine ? [truncLine] : []].join("\n");
3093
3094
  const fence2 = ["```", [header2, ...bodyLines].join("\n"), "```"].join("\n");
3094
3095
  return `${prose2}
3095
3096
 
@@ -3101,10 +3102,10 @@ ${fence2}`;
3101
3102
  );
3102
3103
  const cp = await ctx.datastore.findCronAndPaymentForObjectKey(ctx.walletAddress, result.key);
3103
3104
  const sizeStr = formatBytesForDisplay(result.size_bytes);
3104
- const s3time = formatLsTimeFieldUtc(void 0, now);
3105
+ const s3time = formatLsTimeFieldUtc(void 0, now, LS_S3_COL_WIDTH);
3105
3106
  let payCell = formatPaymentCell(null, null, LS_PAY_DISPLAY_MAX);
3106
3107
  let cronIdDisp = null;
3107
- let nextRun = " - ".slice(0, LS_TIME_FIELD_WIDTH).padEnd(LS_TIME_FIELD_WIDTH, " ");
3108
+ let nextRun = " - ".slice(0, LS_NEXT_COL_WIDTH).padEnd(LS_NEXT_COL_WIDTH, " ");
3108
3109
  if (cp) {
3109
3110
  cronIdDisp = cp.cronId;
3110
3111
  nextRun = formatNextCronUtc(cp.schedule, cp.cronStatus, now);
@@ -3116,10 +3117,6 @@ ${fence2}`;
3116
3117
  8
3117
3118
  );
3118
3119
  const prep = {
3119
- perm: "----------",
3120
- ln: " 1",
3121
- user: "- ",
3122
- grp: "- ",
3123
3120
  sizeStr,
3124
3121
  s3time,
3125
3122
  cronIdRaw: cronIdDisp,
@@ -3130,11 +3127,10 @@ ${fence2}`;
3130
3127
  const w = columnWidths([prep]);
3131
3128
  const header = renderHeader(w);
3132
3129
  const line = renderRow(prep, w);
3133
- const disclaimer = "Names, cron, and payment columns come from this machine's SQLite catalog when available; `-` means unknown locally.";
3134
- const legend = "Legend: S3_TIME and NEXT are UTC.";
3135
- const prose = [disclaimer, legend, `bucket: ${result.bucket}`, ""].join("\n");
3130
+ const prose = buildLsProseIntro(result.bucket).join("\n");
3136
3131
  const fence = ["```", [header, line].join("\n"), "```"].join("\n");
3137
3132
  return `${prose}
3133
+
3138
3134
  ${fence}`;
3139
3135
  }
3140
3136
 
@@ -3645,7 +3641,6 @@ async function createCloudDatastore(homeDir) {
3645
3641
  var SUPPORTED_BACKUP_PLATFORMS = /* @__PURE__ */ new Set(["darwin", "linux"]);
3646
3642
  var BACKUP_DIR_SUBPATH = join8(".openclaw", "mnemospark", "backup");
3647
3643
  var DEFAULT_BACKUP_DIR = join8(homedir6(), BACKUP_DIR_SUBPATH);
3648
- var OBJECT_LOG_SUBPATH = join8(".openclaw", "mnemospark", "object.log");
3649
3644
  var CRON_TABLE_SUBPATH = join8(".openclaw", "mnemospark", "crontab.txt");
3650
3645
  var BLOCKRUN_WALLET_KEY_SUBPATH = join8(".openclaw", "blockrun", "wallet.key");
3651
3646
  var MNEMOSPARK_WALLET_KEY_SUBPATH = join8(".openclaw", "mnemospark", "wallet", "wallet.key");
@@ -3653,8 +3648,10 @@ var INLINE_UPLOAD_MAX_BYTES = 45e5;
3653
3648
  var PAYMENT_REMINDER_INTERVAL_DAYS = 30;
3654
3649
  var PAYMENT_DELETE_DEADLINE_DAYS = 32;
3655
3650
  var PAYMENT_CRON_SCHEDULE = "0 0 1 * *";
3656
- var CRON_LOG_ROW_PREFIX = "cron";
3657
3651
  var TAR_OVERHEAD_BYTES = 10 * 1024 * 1024;
3652
+ var QUOTE_VALIDITY_USER_NOTE = "Quotes are valid for one hour. Please run price-storage again if you need a new quote.";
3653
+ var MNEMOSPARK_SUPPORT_EMAIL = "pluggedin@mnemospark.ai";
3654
+ var CLOUD_HELP_FOOTER_STATE = "Local state: mnemospark records quotes, objects, payments, cron jobs, friendly names, and operation metadata in ~/.openclaw/mnemospark/state.db (SQLite). For troubleshooting and correlation, commands and the HTTP proxy append structured JSON lines to ~/.openclaw/mnemospark/events.jsonl. Monthly storage billing jobs are listed in ~/.openclaw/mnemospark/crontab.txt for your system scheduler.";
3658
3655
  var REQUIRED_PRICE_STORAGE = "--wallet-address, --object-id, --object-id-hash, --gb, --provider, --region";
3659
3656
  var REQUIRED_UPLOAD = "--quote-id, --wallet-address, --object-id, --object-id-hash";
3660
3657
  var REQUIRED_PAYMENT_SETTLE = "--quote-id and --wallet-address";
@@ -3683,12 +3680,14 @@ function expandTilde(path) {
3683
3680
  return path;
3684
3681
  }
3685
3682
  var CLOUD_HELP_TEXT = [
3686
- "\u2601\uFE0F **mnemospark Cloud Commands**",
3683
+ "\u2601\uFE0F **mnemospark - Wallet and go.** \u{1F499}",
3684
+ "",
3685
+ "**Cloud Commands**",
3687
3686
  "",
3688
3687
  "\u2022 `/mnemospark_cloud` or `/mnemospark_cloud help` \u2014 show this message",
3689
3688
  "",
3690
3689
  "\u2022 `/mnemospark_cloud backup <file|directory> [--name <friendly-name>] [--async] [--orchestrator <inline|subagent>] [--timeout-seconds <n>]`",
3691
- " Purpose: create a local tar+gzip backup object and index it for later upload.",
3690
+ " Purpose: create a local tar+gzip archive under ~/.openclaw/mnemospark/backup and record metadata in SQLite for later price-storage and upload.",
3692
3691
  " Required: <file|directory>",
3693
3692
  "",
3694
3693
  "\u2022 `/mnemospark_cloud price-storage --wallet-address <addr> --object-id <id> --object-id-hash <hash> --gb <gb> --provider <provider> --region <region>`",
@@ -3737,7 +3736,9 @@ var CLOUD_HELP_TEXT = [
3737
3736
  "\u2022 `/mnemospark_cloud op-status --operation-id <id>`",
3738
3737
  "\u2022 `/mnemospark_cloud op-status --operation-id <id> --cancel`",
3739
3738
  "",
3740
- "Backup creates a tar+gzip object in ~/.openclaw/mnemospark/backup and appends object metadata to ~/.openclaw/mnemospark/object.log. Upload appends storage rows and cron-tracking rows to object.log, and keeps job entries in ~/.openclaw/mnemospark/crontab.txt. Commands price-storage, upload, ls, download, delete, and payment-settle require --wallet-address."
3739
+ CLOUD_HELP_FOOTER_STATE,
3740
+ "",
3741
+ "Commands price-storage, upload, ls, download, delete, and payment-settle require --wallet-address."
3741
3742
  ].join("\n");
3742
3743
  var UnsupportedBackupPlatformError = class extends Error {
3743
3744
  constructor(platform) {
@@ -4110,19 +4111,9 @@ function parseCloudArgs(args) {
4110
4111
  }
4111
4112
  return { mode: "unknown" };
4112
4113
  }
4113
- function resolveObjectLogPath(homeDir) {
4114
- return join8(homeDir ?? homedir6(), OBJECT_LOG_SUBPATH);
4115
- }
4116
4114
  function resolveCronTablePath(homeDir) {
4117
4115
  return join8(homeDir ?? homedir6(), CRON_TABLE_SUBPATH);
4118
4116
  }
4119
- async function appendObjectLogLine(line, homeDir) {
4120
- const objectLogPath = resolveObjectLogPath(homeDir);
4121
- await mkdir5(dirname5(objectLogPath), { recursive: true });
4122
- await appendFile2(objectLogPath, `${line}
4123
- `, "utf-8");
4124
- return objectLogPath;
4125
- }
4126
4117
  async function calculateInputSizeBytes(targetPath) {
4127
4118
  const targetStats = await lstat(targetPath);
4128
4119
  if (targetStats.isFile() || targetStats.isSymbolicLink()) {
@@ -4219,38 +4210,17 @@ async function buildBackupObject(targetPathArg, options = {}) {
4219
4210
  const archiveStats = await stat2(archivePath);
4220
4211
  const objectIdHash = await sha256File(archivePath);
4221
4212
  const objectSizeGb = toGbString(archiveStats.size);
4222
- const objectLogPath = await appendObjectLogLine(
4223
- `${objectId},${objectIdHash},${objectSizeGb}`,
4224
- options.homeDir
4225
- );
4226
4213
  return {
4227
4214
  objectId,
4228
4215
  objectIdHash,
4229
4216
  objectSizeGb,
4230
- archivePath,
4231
- objectLogPath
4217
+ archivePath
4232
4218
  };
4233
4219
  } catch (error) {
4234
4220
  await rm(archivePath, { force: true }).catch(() => void 0);
4235
4221
  throw error;
4236
4222
  }
4237
4223
  }
4238
- async function appendPriceStorageQuoteLog(quote, homeDir) {
4239
- return appendObjectLogLine(
4240
- [
4241
- quote.timestamp,
4242
- quote.quote_id,
4243
- quote.storage_price.toString(),
4244
- quote.addr,
4245
- quote.object_id,
4246
- quote.object_id_hash,
4247
- quote.object_size_gb.toString(),
4248
- quote.provider,
4249
- quote.location
4250
- ].join(","),
4251
- homeDir
4252
- );
4253
- }
4254
4224
  function formatTimestamp(date) {
4255
4225
  const pad = (value) => value.toString().padStart(2, "0");
4256
4226
  return [
@@ -4267,55 +4237,6 @@ function formatTimestamp(date) {
4267
4237
  pad(date.getSeconds())
4268
4238
  ].join("");
4269
4239
  }
4270
- function parseLoggedPriceStorageQuote(line) {
4271
- const parts = line.split(",");
4272
- if (parts.length < 9) {
4273
- return null;
4274
- }
4275
- const quoteId = parts[1]?.trim() ?? "";
4276
- const storagePriceRaw = parts[2]?.trim() ?? "";
4277
- const walletAddress = parts[3]?.trim() ?? "";
4278
- const objectId = parts[4]?.trim() ?? "";
4279
- const objectIdHash = parts[5]?.trim() ?? "";
4280
- const provider = parts[7]?.trim() ?? "";
4281
- const location = parts[8]?.trim() ?? "";
4282
- const storagePrice = Number.parseFloat(storagePriceRaw);
4283
- if (!quoteId || !walletAddress || !objectId || !objectIdHash || !provider || !location) {
4284
- return null;
4285
- }
4286
- if (!Number.isFinite(storagePrice) || storagePrice <= 0) {
4287
- return null;
4288
- }
4289
- return {
4290
- quoteId,
4291
- storagePrice,
4292
- walletAddress,
4293
- objectId,
4294
- objectIdHash,
4295
- provider,
4296
- location
4297
- };
4298
- }
4299
- function parseLoggedStoragePaymentCron(line) {
4300
- const parts = line.split(",");
4301
- if (parts.length < 5) {
4302
- return null;
4303
- }
4304
- if ((parts[0]?.trim() ?? "").toLowerCase() !== CRON_LOG_ROW_PREFIX) {
4305
- return null;
4306
- }
4307
- const cronId = parts[2]?.trim() ?? "";
4308
- const objectId = parts[3]?.trim() ?? "";
4309
- const objectKey = parts[4]?.trim() ?? "";
4310
- if (!cronId || !objectId || !objectKey) {
4311
- return null;
4312
- }
4313
- return {
4314
- cronId,
4315
- objectId,
4316
- objectKey
4317
- };
4318
- }
4319
4240
  function parseStoragePaymentCronJobLine(line) {
4320
4241
  const trimmed = line.trim();
4321
4242
  if (!trimmed) {
@@ -4361,31 +4282,11 @@ function parseStoragePaymentCronJobLine(line) {
4361
4282
  location
4362
4283
  };
4363
4284
  }
4364
- async function findLoggedPriceStorageQuote(quoteId, homeDir) {
4365
- const objectLogPath = resolveObjectLogPath(homeDir);
4366
- let content;
4367
- try {
4368
- content = await readFile3(objectLogPath, "utf-8");
4369
- } catch (error) {
4370
- if (error.code === "ENOENT") {
4371
- return null;
4372
- }
4373
- throw error;
4374
- }
4375
- const lines = content.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
4376
- for (let idx = lines.length - 1; idx >= 0; idx -= 1) {
4377
- const parsed = parseLoggedPriceStorageQuote(lines[idx]);
4378
- if (parsed && parsed.quoteId === quoteId) {
4379
- return parsed;
4380
- }
4381
- }
4382
- return null;
4383
- }
4384
- async function findLoggedStoragePaymentCronByObjectKey(objectKey, homeDir) {
4385
- const objectLogPath = resolveObjectLogPath(homeDir);
4285
+ async function findCronJobInCrontabByObjectKey(objectKey, homeDir) {
4286
+ const cronTablePath = resolveCronTablePath(homeDir);
4386
4287
  let content;
4387
4288
  try {
4388
- content = await readFile3(objectLogPath, "utf-8");
4289
+ content = await readFile3(cronTablePath, "utf-8");
4389
4290
  } catch (error) {
4390
4291
  if (error.code === "ENOENT") {
4391
4292
  return null;
@@ -4394,9 +4295,13 @@ async function findLoggedStoragePaymentCronByObjectKey(objectKey, homeDir) {
4394
4295
  }
4395
4296
  const lines = content.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
4396
4297
  for (let idx = lines.length - 1; idx >= 0; idx -= 1) {
4397
- const parsed = parseLoggedStoragePaymentCron(lines[idx]);
4298
+ const parsed = parseStoragePaymentCronJobLine(lines[idx]);
4398
4299
  if (parsed && parsed.objectKey === objectKey) {
4399
- return parsed;
4300
+ return {
4301
+ cronId: parsed.cronId,
4302
+ objectId: parsed.objectId,
4303
+ objectKey: parsed.objectKey
4304
+ };
4400
4305
  }
4401
4306
  }
4402
4307
  return null;
@@ -4420,20 +4325,6 @@ function buildStoragePaymentCronCommand(job) {
4420
4325
  quoteCronArgument(job.storagePrice)
4421
4326
  ].join(" ");
4422
4327
  }
4423
- async function appendStoragePaymentCronLog(cronJob, homeDir) {
4424
- return appendObjectLogLine(
4425
- [
4426
- CRON_LOG_ROW_PREFIX,
4427
- cronJob.createdAt,
4428
- cronJob.cronId,
4429
- cronJob.objectId,
4430
- cronJob.objectKey,
4431
- cronJob.quoteId,
4432
- cronJob.storagePrice.toString()
4433
- ].join(","),
4434
- homeDir
4435
- );
4436
- }
4437
4328
  async function appendStoragePaymentCronJob(cronJob, homeDir) {
4438
4329
  const cronTablePath = resolveCronTablePath(homeDir);
4439
4330
  await mkdir5(dirname5(cronTablePath), { recursive: true });
@@ -4500,7 +4391,6 @@ async function createStoragePaymentCronJob(upload, storagePrice, homeDir, nowDat
4500
4391
  location: upload.location
4501
4392
  };
4502
4393
  await appendStoragePaymentCronJob(cronJob, homeDir);
4503
- await appendStoragePaymentCronLog(cronJob, homeDir);
4504
4394
  return cronJob;
4505
4395
  }
4506
4396
  async function readWalletKeyIfPresent(walletPath) {
@@ -4630,24 +4520,6 @@ async function uploadPresignedObjectIfNeeded(uploadResponse, uploadMode, encrypt
4630
4520
  `Presigned upload failed with status ${firstAttempt.status}${details ? `: ${details}` : ""}`
4631
4521
  );
4632
4522
  }
4633
- async function appendStorageUploadLog(upload, homeDir, nowDateFn = () => /* @__PURE__ */ new Date()) {
4634
- return appendObjectLogLine(
4635
- [
4636
- formatTimestamp(nowDateFn()),
4637
- upload.quote_id,
4638
- upload.addr,
4639
- upload.addr_hash ?? "",
4640
- upload.trans_id ?? "",
4641
- upload.storage_price?.toString() ?? "",
4642
- upload.object_id,
4643
- upload.object_key,
4644
- upload.provider,
4645
- upload.bucket_name,
4646
- upload.location
4647
- ].join(","),
4648
- homeDir
4649
- );
4650
- }
4651
4523
  async function maybeCleanupLocalBackupArchive(archivePath) {
4652
4524
  const flag = process.env.MNEMOSPARK_DELETE_BACKUP_AFTER_UPLOAD;
4653
4525
  if (!flag) {
@@ -4663,10 +4535,18 @@ async function maybeCleanupLocalBackupArchive(archivePath) {
4663
4535
  }
4664
4536
  }
4665
4537
  function formatStorageUploadUserMessage(upload, cronJobId) {
4538
+ const lsLine = `/mnemospark_cloud ls --wallet-address \`${upload.addr}\``;
4666
4539
  return [
4667
4540
  `Your file \`${upload.object_id}\` with key \`${upload.object_key}\` has been stored using \`${upload.provider}\` in \`${upload.bucket_name}\` \`${upload.location}\``,
4668
- `A cron job \`${cronJobId}\` has been configured to send payment monthly (on the 1st) for storage services. If payment is not sent, your \`${upload.object_id}\` will be deleted after the **${PAYMENT_DELETE_DEADLINE_DAYS}-day deadline** (${PAYMENT_REMINDER_INTERVAL_DAYS}-day billing interval + 2-day grace period).`,
4669
- "Thank you for using mnemospark!"
4541
+ "",
4542
+ `A cron job \`${cronJobId}\` has been configured to send payment monthly (on the 1st) for storage services. If payment is not sent, your \`${upload.object_id}\` will be deleted after the ${PAYMENT_DELETE_DEADLINE_DAYS}-day deadline (${PAYMENT_REMINDER_INTERVAL_DAYS}-day billing interval + 2-day grace period).`,
4543
+ "",
4544
+ "To view your cloud storage run the command:",
4545
+ "",
4546
+ lsLine,
4547
+ "",
4548
+ "Thank you for using mnemospark!",
4549
+ `Reach out if you need anything: ${MNEMOSPARK_SUPPORT_EMAIL}`
4670
4550
  ].join("\n");
4671
4551
  }
4672
4552
  function formatStorageDeleteUserMessage(objectKey, cronId, cronDeleted) {
@@ -4713,9 +4593,39 @@ function extractLsErrorMessage(error) {
4713
4593
  return null;
4714
4594
  }
4715
4595
  function formatPriceStorageUserMessage(quote) {
4596
+ const uploadLine = `/mnemospark_cloud upload --quote-id \`${quote.quote_id}\` --wallet-address \`${quote.addr}\` --object-id \`${quote.object_id}\` --object-id-hash \`${quote.object_id_hash}\``;
4597
+ return [
4598
+ `Your storage quote \`${quote.quote_id}\`: storage price \`${quote.storage_price}\` for \`${quote.object_id}\` with file size \`${quote.object_size_gb}\` in \`${quote.provider}\` \`${quote.location}\`.`,
4599
+ "",
4600
+ "If you accept this quote, run:",
4601
+ "",
4602
+ uploadLine,
4603
+ "",
4604
+ QUOTE_VALIDITY_USER_NOTE
4605
+ ].join("\n");
4606
+ }
4607
+ function quoteLookupMatchesPriceStorageResponse(lookup, quote) {
4608
+ return lookup.quoteId === quote.quote_id && lookup.walletAddress.trim().toLowerCase() === quote.addr.trim().toLowerCase() && lookup.objectId === quote.object_id && lookup.objectIdHash.toLowerCase() === quote.object_id_hash.toLowerCase() && lookup.storagePrice === quote.storage_price && lookup.provider === quote.provider && lookup.location === quote.location;
4609
+ }
4610
+ function formatBackupSuccessUserMessage(result) {
4611
+ const hash = result.objectIdHash.replace(/\s/g, "");
4612
+ const priceStorageLine = `/mnemospark_cloud price-storage --wallet-address <wallet-address> --object-id \`${result.objectId}\` --object-id-hash \`${hash}\` --gb \`${result.objectSizeGb}\` --provider <provider> --region <region>`;
4716
4613
  return [
4717
- `Your storage quote \`${quote.quote_id}\` is valid for 1 hour, the storage price is \`${quote.storage_price}\` for \`${quote.object_id}\` with file size of \`${quote.object_size_gb}\` in \`${quote.provider}\` \`${quote.location}\``,
4718
- `If you accept this quote run the command /mnemospark_cloud upload --quote-id \`${quote.quote_id}\` --wallet-address \`${quote.addr}\` --object-id \`${quote.object_id}\` --object-id-hash \`${quote.object_id_hash}\``
4614
+ `Backup archive: \`${result.archivePath}\``,
4615
+ "",
4616
+ `object-id: ${result.objectId}`,
4617
+ `object-id-hash: ${hash}`,
4618
+ `object-size: ${result.objectSizeGb}`,
4619
+ "",
4620
+ "Next, request a storage quote. Replace `<wallet-address>`, `<provider>`, and `<region>` (one line):",
4621
+ "",
4622
+ priceStorageLine,
4623
+ "",
4624
+ "Region examples (merge into the command above):",
4625
+ "North America: `--provider aws --region us-east-1`",
4626
+ "Europe: `--provider aws --region eu-north-1`",
4627
+ "South America: `--provider aws --region sa-east-1`",
4628
+ "Asia Pacific: `--provider aws --region ap-northeast-1`"
4719
4629
  ].join("\n");
4720
4630
  }
4721
4631
  function createInProcessSubagentOrchestrator() {
@@ -4842,7 +4752,7 @@ function createCloudCommand(options = {}) {
4842
4752
  requestStorageDownloadFn: options.requestStorageDownloadFn ?? requestStorageDownloadViaProxy,
4843
4753
  requestStorageDeleteFn: options.requestStorageDeleteFn ?? requestStorageDeleteViaProxy,
4844
4754
  requestPaymentSettleViaProxyFn: options.requestPaymentSettleViaProxyFn ?? requestPaymentSettleViaProxy,
4845
- objectLogHomeDir: options.objectLogHomeDir ?? options.backupOptions?.homeDir,
4755
+ mnemosparkHomeDir: options.mnemosparkHomeDir ?? options.backupOptions?.homeDir,
4846
4756
  backupOptions: options.backupOptions,
4847
4757
  proxyQuoteOptions: options.proxyQuoteOptions,
4848
4758
  proxyUploadOptions: options.proxyUploadOptions,
@@ -4858,42 +4768,7 @@ function createCloudCommand(options = {}) {
4858
4768
  }
4859
4769
  };
4860
4770
  }
4861
- async function resolveFriendlyNameFromManifest(params, homeDir) {
4862
- const manifestPath = join8(homeDir ?? homedir6(), ".openclaw", "mnemospark", "manifest.jsonl");
4863
- let manifestRaw;
4864
- try {
4865
- manifestRaw = await readFile3(manifestPath, "utf-8");
4866
- } catch {
4867
- return { objectKey: null, matchCount: 0 };
4868
- }
4869
- const wallet = params.walletAddress.trim().toLowerCase();
4870
- const name = params.friendlyName.trim();
4871
- const atMs = params.at ? Date.parse(params.at) : Number.NaN;
4872
- const hasAt = Number.isFinite(atMs);
4873
- const rows = manifestRaw.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((line) => {
4874
- try {
4875
- return JSON.parse(line);
4876
- } catch {
4877
- return null;
4878
- }
4879
- }).filter((row) => Boolean(row)).filter((row) => {
4880
- if (!row.object_key || !row.friendly_name || !row.wallet_address || !row.created_at)
4881
- return false;
4882
- if (row.friendly_name !== name) return false;
4883
- if (row.wallet_address.trim().toLowerCase() !== wallet) return false;
4884
- if (params.latest || !hasAt) return true;
4885
- const createdAtMs = Date.parse(row.created_at);
4886
- return Number.isFinite(createdAtMs) && createdAtMs <= atMs;
4887
- }).sort((a, b) => Date.parse(b.created_at ?? "") - Date.parse(a.created_at ?? ""));
4888
- if (rows.length === 0) {
4889
- return { objectKey: null, matchCount: 0 };
4890
- }
4891
- if (!params.latest && !hasAt && rows.length > 1) {
4892
- return { objectKey: null, matchCount: rows.length };
4893
- }
4894
- return { objectKey: rows[0].object_key ?? null, matchCount: rows.length };
4895
- }
4896
- async function resolveNameSelectorIfNeeded(datastore, request, selector, homeDir) {
4771
+ async function resolveNameSelectorIfNeeded(datastore, request, selector) {
4897
4772
  if (!selector) {
4898
4773
  const walletAddress = request.wallet_address?.trim();
4899
4774
  if (!walletAddress) {
@@ -4917,11 +4792,12 @@ async function resolveNameSelectorIfNeeded(datastore, request, selector, homeDir
4917
4792
  }
4918
4793
  return { request: parsedRequest2 };
4919
4794
  }
4920
- let sqliteUnavailable = false;
4921
4795
  try {
4922
4796
  await datastore.ensureReady();
4923
4797
  } catch {
4924
- sqliteUnavailable = true;
4798
+ return {
4799
+ error: "Cannot resolve --name: local SQLite (~/.openclaw/mnemospark/state.db) is unavailable. Use --object-key or restore SQLite access."
4800
+ };
4925
4801
  }
4926
4802
  const matches = await datastore.countFriendlyNameMatches(request.wallet_address, selector.name);
4927
4803
  if (matches > 1 && !selector.latest && !selector.at) {
@@ -4935,28 +4811,7 @@ async function resolveNameSelectorIfNeeded(datastore, request, selector, homeDir
4935
4811
  latest: selector.latest,
4936
4812
  at: selector.at
4937
4813
  });
4938
- let resolvedObjectKey = resolved?.objectKey ?? null;
4939
- let degradedWarning;
4940
- if (!resolvedObjectKey && sqliteUnavailable) {
4941
- const manifestResolved = await resolveFriendlyNameFromManifest(
4942
- {
4943
- walletAddress: request.wallet_address,
4944
- friendlyName: selector.name,
4945
- latest: selector.latest,
4946
- at: selector.at
4947
- },
4948
- homeDir
4949
- );
4950
- if (manifestResolved.matchCount > 1 && !selector.latest && !selector.at) {
4951
- return {
4952
- error: `Multiple objects match --name ${selector.name}. Add --latest or --at <timestamp>.`
4953
- };
4954
- }
4955
- resolvedObjectKey = manifestResolved.objectKey;
4956
- if (resolvedObjectKey) {
4957
- degradedWarning = "SQLite friendly-name index unavailable; resolved --name via manifest.jsonl fallback.";
4958
- }
4959
- }
4814
+ const resolvedObjectKey = resolved?.objectKey ?? null;
4960
4815
  if (!resolvedObjectKey) {
4961
4816
  return { error: `No object found for --name ${selector.name}.` };
4962
4817
  }
@@ -4967,10 +4822,7 @@ async function resolveNameSelectorIfNeeded(datastore, request, selector, homeDir
4967
4822
  if (!parsedRequest) {
4968
4823
  return { error: "Cannot resolve storage object request." };
4969
4824
  }
4970
- return {
4971
- request: parsedRequest,
4972
- degradedWarning
4973
- };
4825
+ return { request: parsedRequest };
4974
4826
  }
4975
4827
  function toStorageObjectRequestOrError(request, missingKeyMessage) {
4976
4828
  const key = request.object_key?.trim();
@@ -4993,7 +4845,8 @@ async function emitCloudEvent(eventType, details, homeDir) {
4993
4845
  {
4994
4846
  ...details,
4995
4847
  ts: (/* @__PURE__ */ new Date()).toISOString(),
4996
- event_type: eventType
4848
+ event_type: eventType,
4849
+ source: "command"
4997
4850
  },
4998
4851
  homeDir
4999
4852
  );
@@ -5010,6 +4863,7 @@ function toOperationEventPayload(eventType, context) {
5010
4863
  trace_id: context.traceId,
5011
4864
  event_type: eventType,
5012
4865
  status: context.status,
4866
+ source: "command",
5013
4867
  ts: (/* @__PURE__ */ new Date()).toISOString(),
5014
4868
  wallet_address: context.walletAddress ?? void 0,
5015
4869
  object_id: context.objectId ?? void 0,
@@ -5025,10 +4879,7 @@ function toOperationEventPayload(eventType, context) {
5025
4879
  }
5026
4880
  async function emitOperationEvent(eventType, context, homeDir) {
5027
4881
  const payload = toOperationEventPayload(eventType, context);
5028
- await Promise.all([
5029
- appendJsonlEvent("events.jsonl", payload, homeDir),
5030
- appendJsonlEvent("proxy-events.jsonl", payload, homeDir)
5031
- ]);
4882
+ await appendJsonlEvent("events.jsonl", payload, homeDir);
5032
4883
  }
5033
4884
  async function emitOperationEventBestEffort(eventType, context, homeDir) {
5034
4885
  try {
@@ -5054,7 +4905,7 @@ function parseTransIdFromPaymentSettleBody(bodyText) {
5054
4905
  return null;
5055
4906
  }
5056
4907
  }
5057
- async function resolveAmountForPaymentSettle(quoteId, storagePriceFromFlag, datastore, homeDir) {
4908
+ async function resolveAmountForPaymentSettle(quoteId, storagePriceFromFlag, datastore) {
5058
4909
  if (storagePriceFromFlag !== void 0 && Number.isFinite(storagePriceFromFlag)) {
5059
4910
  return storagePriceFromFlag;
5060
4911
  }
@@ -5062,10 +4913,6 @@ async function resolveAmountForPaymentSettle(quoteId, storagePriceFromFlag, data
5062
4913
  if (quoteLookup && Number.isFinite(quoteLookup.storagePrice)) {
5063
4914
  return quoteLookup.storagePrice;
5064
4915
  }
5065
- const logged = await findLoggedPriceStorageQuote(quoteId, homeDir);
5066
- if (logged && Number.isFinite(logged.storagePrice)) {
5067
- return logged.storagePrice;
5068
- }
5069
4916
  const payment = await datastore.findPaymentByQuoteId(quoteId);
5070
4917
  if (payment && Number.isFinite(payment.amount)) {
5071
4918
  return payment.amount;
@@ -5101,18 +4948,19 @@ async function emitPaymentSettleClientObservationBestEffort(params) {
5101
4948
  homeDir
5102
4949
  );
5103
4950
  await appendJsonlEvent(
5104
- "proxy-events.jsonl",
4951
+ "events.jsonl",
5105
4952
  {
5106
4953
  ts,
5107
4954
  event_type: "payment.settle",
5108
4955
  status: "start",
4956
+ source: "command",
5109
4957
  trace_id: correlation.traceId,
5110
4958
  operation_id: correlation.operationId,
5111
4959
  quote_id: quoteId,
5112
4960
  wallet_address: walletAddress,
5113
4961
  object_id: objectId ?? null,
5114
4962
  object_key: objectKey ?? null,
5115
- details: { source: "client" }
4963
+ details: { client_observation: true }
5116
4964
  },
5117
4965
  homeDir
5118
4966
  );
@@ -5134,18 +4982,20 @@ async function emitPaymentSettleClientObservationBestEffort(params) {
5134
4982
  homeDir
5135
4983
  );
5136
4984
  await appendJsonlEvent(
5137
- "proxy-events.jsonl",
4985
+ "events.jsonl",
5138
4986
  {
5139
4987
  ts,
5140
4988
  event_type: "payment.settle",
5141
4989
  status: "result",
4990
+ source: "command",
5142
4991
  trace_id: correlation.traceId,
5143
4992
  operation_id: correlation.operationId,
5144
4993
  quote_id: quoteId,
5145
4994
  wallet_address: walletAddress,
5146
4995
  object_id: objectId ?? null,
5147
4996
  object_key: objectKey ?? null,
5148
- details: { http_status: httpStatus ?? null, source: "client" }
4997
+ http_status: httpStatus ?? null,
4998
+ details: { client_observation: true }
5149
4999
  },
5150
5000
  homeDir
5151
5001
  );
@@ -5154,7 +5004,7 @@ async function emitPaymentSettleClientObservationBestEffort(params) {
5154
5004
  }
5155
5005
  async function runCloudCommandHandler(ctx, options, executionContext = {}) {
5156
5006
  const parsed = parseCloudArgs(ctx.args);
5157
- const objectLogHomeDir = options.objectLogHomeDir;
5007
+ const mnemosparkHomeDir = options.mnemosparkHomeDir;
5158
5008
  const backupBuilder = options.buildBackupObjectFn;
5159
5009
  const requestPriceStorageQuote = options.requestPriceStorageQuoteFn;
5160
5010
  const requestStorageUpload = options.requestStorageUploadFn;
@@ -5241,7 +5091,7 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
5241
5091
  isError: true
5242
5092
  };
5243
5093
  }
5244
- const datastore = await createCloudDatastore(objectLogHomeDir);
5094
+ const datastore = await createCloudDatastore(mnemosparkHomeDir);
5245
5095
  const terminalOperationStatuses = /* @__PURE__ */ new Set(["succeeded", "failed", "cancelled", "timed_out"]);
5246
5096
  const isTerminalOperationStatus = (status) => terminalOperationStatuses.has(status);
5247
5097
  const formatOperationStatus = (operation) => ({
@@ -5303,7 +5153,7 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
5303
5153
  subagentSessionId: operation.subagent_session_id,
5304
5154
  timeoutSeconds: operation.timeout_seconds
5305
5155
  },
5306
- objectLogHomeDir
5156
+ mnemosparkHomeDir
5307
5157
  );
5308
5158
  const cancelResult = await subagentOrchestrator.cancel(
5309
5159
  operation.subagent_session_id,
@@ -5340,7 +5190,7 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
5340
5190
  errorCode: "ASYNC_CANCELLED",
5341
5191
  errorMessage: "Operation cancelled by user request."
5342
5192
  },
5343
- objectLogHomeDir
5193
+ mnemosparkHomeDir
5344
5194
  );
5345
5195
  }
5346
5196
  }
@@ -5359,7 +5209,7 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
5359
5209
  const req = parsed.paymentSettleRequest;
5360
5210
  let walletKey;
5361
5211
  try {
5362
- walletKey = await resolveWalletKey(objectLogHomeDir);
5212
+ walletKey = await resolveWalletKey(mnemosparkHomeDir);
5363
5213
  } catch (err) {
5364
5214
  const message = err instanceof Error ? err.message : String(err);
5365
5215
  return { text: message.trim() || "Cannot resolve wallet key.", isError: true };
@@ -5382,7 +5232,7 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
5382
5232
  walletAddress: req.wallet_address,
5383
5233
  objectId,
5384
5234
  objectKey,
5385
- homeDir: objectLogHomeDir
5235
+ homeDir: mnemosparkHomeDir
5386
5236
  });
5387
5237
  let settleResult;
5388
5238
  try {
@@ -5395,8 +5245,7 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
5395
5245
  const amountErr = await resolveAmountForPaymentSettle(
5396
5246
  req.quote_id,
5397
5247
  req.storage_price,
5398
- datastore,
5399
- objectLogHomeDir
5248
+ datastore
5400
5249
  );
5401
5250
  await datastore.upsertPayment({
5402
5251
  quote_id: req.quote_id,
@@ -5420,16 +5269,11 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
5420
5269
  objectId,
5421
5270
  objectKey,
5422
5271
  outcomeStatus: "failed",
5423
- homeDir: objectLogHomeDir
5272
+ homeDir: mnemosparkHomeDir
5424
5273
  });
5425
5274
  return { text: `Payment settle failed: ${msg}`, isError: true };
5426
5275
  }
5427
- const amount = await resolveAmountForPaymentSettle(
5428
- req.quote_id,
5429
- req.storage_price,
5430
- datastore,
5431
- objectLogHomeDir
5432
- );
5276
+ const amount = await resolveAmountForPaymentSettle(req.quote_id, req.storage_price, datastore);
5433
5277
  const transId = settleResult.status === 200 ? parseTransIdFromPaymentSettleBody(settleResult.bodyText ?? "") : null;
5434
5278
  if (settleResult.status === 200) {
5435
5279
  await datastore.upsertPayment({
@@ -5454,7 +5298,7 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
5454
5298
  objectKey,
5455
5299
  httpStatus: settleResult.status,
5456
5300
  outcomeStatus: "succeeded",
5457
- homeDir: objectLogHomeDir
5301
+ homeDir: mnemosparkHomeDir
5458
5302
  });
5459
5303
  return {
5460
5304
  text: transId ? `Payment settled for quote ${req.quote_id} (trans_id: ${transId}).` : `Payment settled for quote ${req.quote_id}.`
@@ -5482,7 +5326,7 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
5482
5326
  objectKey,
5483
5327
  httpStatus: settleResult.status,
5484
5328
  outcomeStatus: "failed",
5485
- homeDir: objectLogHomeDir
5329
+ homeDir: mnemosparkHomeDir
5486
5330
  });
5487
5331
  const bodySnippet = settleResult.bodyText?.trim();
5488
5332
  const detail = bodySnippet && bodySnippet.length > 500 ? `${bodySnippet.slice(0, 500)}\u2026` : bodySnippet;
@@ -5524,7 +5368,7 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
5524
5368
  await emitOperationEventBestEffort(
5525
5369
  "operation.dispatched",
5526
5370
  { ...eventContextBase, status: "started" },
5527
- objectLogHomeDir
5371
+ mnemosparkHomeDir
5528
5372
  );
5529
5373
  const syncArgs = stripAsyncControlFlags(ctx.args);
5530
5374
  if (orchestratorMode === "subagent") {
@@ -5576,7 +5420,7 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
5576
5420
  subagentSessionId: sessionId,
5577
5421
  progressMessage: "subagent running"
5578
5422
  },
5579
- objectLogHomeDir
5423
+ mnemosparkHomeDir
5580
5424
  );
5581
5425
  },
5582
5426
  onProgress: async (sessionId, message) => {
@@ -5588,7 +5432,7 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
5588
5432
  subagentSessionId: sessionId,
5589
5433
  progressMessage: message
5590
5434
  },
5591
- objectLogHomeDir
5435
+ mnemosparkHomeDir
5592
5436
  );
5593
5437
  },
5594
5438
  onCompleted: async (sessionId) => {
@@ -5612,7 +5456,7 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
5612
5456
  status: "succeeded",
5613
5457
  subagentSessionId: sessionId
5614
5458
  },
5615
- objectLogHomeDir
5459
+ mnemosparkHomeDir
5616
5460
  );
5617
5461
  },
5618
5462
  onFailed: async (sessionId, details) => {
@@ -5638,7 +5482,7 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
5638
5482
  errorCode: details.code,
5639
5483
  errorMessage: details.message
5640
5484
  },
5641
- objectLogHomeDir
5485
+ mnemosparkHomeDir
5642
5486
  );
5643
5487
  },
5644
5488
  onCancelled: async (sessionId, reason) => {
@@ -5665,7 +5509,7 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
5665
5509
  errorCode: "ASYNC_CANCELLED",
5666
5510
  errorMessage: reason ?? "Operation cancelled."
5667
5511
  },
5668
- objectLogHomeDir
5512
+ mnemosparkHomeDir
5669
5513
  );
5670
5514
  },
5671
5515
  onTimedOut: async (sessionId) => {
@@ -5691,7 +5535,7 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
5691
5535
  errorCode: "ASYNC_TIMEOUT",
5692
5536
  errorMessage: "Operation timed out."
5693
5537
  },
5694
- objectLogHomeDir
5538
+ mnemosparkHomeDir
5695
5539
  );
5696
5540
  }
5697
5541
  }
@@ -5743,7 +5587,7 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
5743
5587
  errorCode: "ASYNC_DISPATCH_FAILED",
5744
5588
  errorMessage: dispatchMessage
5745
5589
  },
5746
- objectLogHomeDir
5590
+ mnemosparkHomeDir
5747
5591
  );
5748
5592
  return {
5749
5593
  text: `Cannot dispatch subagent operation: ${dispatchMessage}
@@ -5790,7 +5634,7 @@ operation-id: ${operationId}`,
5790
5634
  errorCode: result.isError ? "ASYNC_FAILED" : null,
5791
5635
  errorMessage: result.isError ? result.text : null
5792
5636
  },
5793
- objectLogHomeDir
5637
+ mnemosparkHomeDir
5794
5638
  );
5795
5639
  }).catch(async (err) => {
5796
5640
  const errorMessage = err instanceof Error ? err.message : String(err);
@@ -5813,7 +5657,7 @@ operation-id: ${operationId}`,
5813
5657
  errorCode: "ASYNC_EXCEPTION",
5814
5658
  errorMessage
5815
5659
  },
5816
- objectLogHomeDir
5660
+ mnemosparkHomeDir
5817
5661
  );
5818
5662
  });
5819
5663
  return {
@@ -5833,9 +5677,14 @@ operation-id: ${operationId}`,
5833
5677
  operation_id: randomUUID3(),
5834
5678
  object_id: result.objectId,
5835
5679
  status: "succeeded",
5836
- details: { friendly_name: parsed.friendlyName ?? basename2(parsed.backupTarget) }
5680
+ details: {
5681
+ friendly_name: parsed.friendlyName ?? basename2(parsed.backupTarget),
5682
+ archive_path: result.archivePath,
5683
+ object_id_hash: result.objectIdHash.replace(/\s/g, ""),
5684
+ object_size_gb: result.objectSizeGb
5685
+ }
5837
5686
  },
5838
- objectLogHomeDir
5687
+ mnemosparkHomeDir
5839
5688
  );
5840
5689
  await datastore.upsertObject({
5841
5690
  object_id: result.objectId,
@@ -5859,11 +5708,7 @@ operation-id: ${operationId}`,
5859
5708
  });
5860
5709
  }
5861
5710
  return {
5862
- text: [
5863
- `object-id: ${result.objectId}`,
5864
- `object-id-hash: ${result.objectIdHash.replace(/\s/g, "")}`,
5865
- `object-size: ${result.objectSizeGb}`
5866
- ].join("\n")
5711
+ text: formatBackupSuccessUserMessage(result)
5867
5712
  };
5868
5713
  } catch (err) {
5869
5714
  if (err instanceof UnsupportedBackupPlatformError) {
@@ -5885,7 +5730,7 @@ operation-id: ${operationId}`,
5885
5730
  ...options.proxyQuoteOptions,
5886
5731
  correlation
5887
5732
  });
5888
- await appendPriceStorageQuoteLog(quote, objectLogHomeDir);
5733
+ await datastore.ensureReady();
5889
5734
  await datastore.upsertObject({
5890
5735
  object_id: quote.object_id,
5891
5736
  object_key: null,
@@ -5905,6 +5750,13 @@ operation-id: ${operationId}`,
5905
5750
  network: null,
5906
5751
  status: "quoted"
5907
5752
  });
5753
+ const verified = await datastore.findQuoteById(quote.quote_id);
5754
+ if (!verified || !quoteLookupMatchesPriceStorageResponse(verified, quote)) {
5755
+ return {
5756
+ text: "Cannot price storage: quote was not saved to local SQLite (~/.openclaw/mnemospark/state.db). Check disk permissions or MNEMOSPARK_DISABLE_SQLITE.",
5757
+ isError: true
5758
+ };
5759
+ }
5908
5760
  await emitCloudEventBestEffort(
5909
5761
  "price-storage.completed",
5910
5762
  {
@@ -5915,7 +5767,7 @@ operation-id: ${operationId}`,
5915
5767
  quote_id: quote.quote_id,
5916
5768
  status: "succeeded"
5917
5769
  },
5918
- objectLogHomeDir
5770
+ mnemosparkHomeDir
5919
5771
  );
5920
5772
  return {
5921
5773
  text: formatPriceStorageUserMessage(quote)
@@ -5930,7 +5782,7 @@ operation-id: ${operationId}`,
5930
5782
  object_id: parsed.priceStorageRequest.object_id,
5931
5783
  status: "failed"
5932
5784
  },
5933
- objectLogHomeDir
5785
+ mnemosparkHomeDir
5934
5786
  );
5935
5787
  const message = err instanceof Error ? err.message : typeof err === "string" ? err : String(err);
5936
5788
  return {
@@ -5945,10 +5797,10 @@ operation-id: ${operationId}`,
5945
5797
  executionContext.forcedTraceId
5946
5798
  );
5947
5799
  try {
5948
- const loggedQuote = await datastore.findQuoteById(parsed.uploadRequest.quote_id) ?? await findLoggedPriceStorageQuote(parsed.uploadRequest.quote_id, objectLogHomeDir);
5800
+ const loggedQuote = await datastore.findQuoteById(parsed.uploadRequest.quote_id);
5949
5801
  if (!loggedQuote) {
5950
5802
  return {
5951
- text: "Cannot upload storage object: quote-id not found in object.log. Run /mnemospark_cloud price-storage first.",
5803
+ text: "Cannot upload storage object: quote-id not found in local SQLite. Run /mnemospark_cloud price-storage first (quotes expire after about one hour on the server).",
5952
5804
  isError: true
5953
5805
  };
5954
5806
  }
@@ -5984,7 +5836,7 @@ operation-id: ${operationId}`,
5984
5836
  isError: true
5985
5837
  };
5986
5838
  }
5987
- const walletKey = await resolveWalletKey(objectLogHomeDir);
5839
+ const walletKey = await resolveWalletKey(mnemosparkHomeDir);
5988
5840
  const walletAccount = privateKeyToAccount5(walletKey);
5989
5841
  if (walletAccount.address.toLowerCase() !== parsed.uploadRequest.wallet_address.toLowerCase()) {
5990
5842
  return {
@@ -5995,7 +5847,7 @@ operation-id: ${operationId}`,
5995
5847
  const preparedPayload = await prepareUploadPayload(
5996
5848
  archivePath,
5997
5849
  parsed.uploadRequest.wallet_address,
5998
- objectLogHomeDir
5850
+ mnemosparkHomeDir
5999
5851
  );
6000
5852
  const idempotencyKey = uploadCorrelation.operationId;
6001
5853
  const shouldSettleBeforeUpload = requestStorageUpload !== requestStorageUploadViaProxy;
@@ -6061,13 +5913,12 @@ operation-id: ${operationId}`,
6061
5913
  );
6062
5914
  }
6063
5915
  }
6064
- await appendStorageUploadLog(finalizedUploadResponse, objectLogHomeDir, nowDateFn);
6065
5916
  const cronStoragePriceCandidate = finalizedUploadResponse.storage_price ?? loggedQuote.storagePrice;
6066
5917
  const cronStoragePrice = Number.isFinite(cronStoragePriceCandidate) && cronStoragePriceCandidate > 0 ? cronStoragePriceCandidate : loggedQuote.storagePrice;
6067
5918
  const cronJob = await createStoragePaymentCronJob(
6068
5919
  finalizedUploadResponse,
6069
5920
  cronStoragePrice,
6070
- objectLogHomeDir,
5921
+ mnemosparkHomeDir,
6071
5922
  nowDateFn
6072
5923
  );
6073
5924
  await datastore.upsertObject({
@@ -6120,7 +5971,7 @@ operation-id: ${operationId}`,
6120
5971
  friendlyNameVerified = false;
6121
5972
  }
6122
5973
  if (!friendlyNameVerified) {
6123
- const warning = "SQLite friendly-name write verification failed; manifest fallback may be required for --name lookups.";
5974
+ const warning = "SQLite friendly-name write verification failed; --name lookups may not resolve until SQLite is healthy.";
6124
5975
  await emitCloudEventBestEffort(
6125
5976
  "friendly_name.write_verification_failed",
6126
5977
  {
@@ -6133,27 +5984,12 @@ operation-id: ${operationId}`,
6133
5984
  friendly_name: normalizedFriendlyName,
6134
5985
  warning
6135
5986
  },
6136
- objectLogHomeDir
5987
+ mnemosparkHomeDir
6137
5988
  );
6138
5989
  if (process.env.MNEMOSPARK_SQLITE_STRICT === "1") {
6139
5990
  throw new Error(warning);
6140
5991
  }
6141
5992
  }
6142
- try {
6143
- await appendJsonlEvent(
6144
- "manifest.jsonl",
6145
- {
6146
- friendly_name: normalizedFriendlyName,
6147
- object_id: finalizedUploadResponse.object_id,
6148
- object_key: finalizedUploadResponse.object_key,
6149
- quote_id: finalizedUploadResponse.quote_id,
6150
- wallet_address: finalizedUploadResponse.addr,
6151
- created_at: (/* @__PURE__ */ new Date()).toISOString()
6152
- },
6153
- objectLogHomeDir
6154
- );
6155
- } catch {
6156
- }
6157
5993
  }
6158
5994
  await emitCloudEventBestEffort(
6159
5995
  "upload.completed",
@@ -6166,7 +6002,7 @@ operation-id: ${operationId}`,
6166
6002
  quote_id: finalizedUploadResponse.quote_id,
6167
6003
  status: "succeeded"
6168
6004
  },
6169
- objectLogHomeDir
6005
+ mnemosparkHomeDir
6170
6006
  );
6171
6007
  await maybeCleanupLocalBackupArchive(archivePath);
6172
6008
  return {
@@ -6183,7 +6019,7 @@ operation-id: ${operationId}`,
6183
6019
  quote_id: parsed.uploadRequest.quote_id,
6184
6020
  status: "failed"
6185
6021
  },
6186
- objectLogHomeDir
6022
+ mnemosparkHomeDir
6187
6023
  );
6188
6024
  const uploadErrorMessage = extractUploadErrorMessage(error);
6189
6025
  return {
@@ -6196,24 +6032,12 @@ operation-id: ${operationId}`,
6196
6032
  const resolved = await resolveNameSelectorIfNeeded(
6197
6033
  datastore,
6198
6034
  parsed.storageObjectRequest,
6199
- parsed.nameSelector,
6200
- objectLogHomeDir
6035
+ parsed.nameSelector
6201
6036
  );
6202
6037
  if (resolved.error || !resolved.request) {
6203
6038
  return { text: resolved.error ?? "Cannot resolve storage object request.", isError: true };
6204
6039
  }
6205
6040
  const resolvedRequest = resolved.request;
6206
- if (resolved.degradedWarning) {
6207
- await emitCloudEventBestEffort(
6208
- "name_resolution.degraded",
6209
- {
6210
- wallet_address: resolvedRequest.wallet_address,
6211
- object_key: resolvedRequest.object_key ?? null,
6212
- warning: resolved.degradedWarning
6213
- },
6214
- objectLogHomeDir
6215
- );
6216
- }
6217
6041
  const objectKeyForLs = resolvedRequest.object_key?.trim();
6218
6042
  const isBucketList = !objectKeyForLs;
6219
6043
  const correlation = buildRequestCorrelation();
@@ -6256,16 +6080,14 @@ operation-id: ${operationId}`,
6256
6080
  status: "succeeded",
6257
6081
  list_mode: isBucketList
6258
6082
  },
6259
- objectLogHomeDir
6083
+ mnemosparkHomeDir
6260
6084
  );
6261
6085
  const lsText = await buildMnemosparkLsMessage(lsResult, {
6262
6086
  walletAddress: resolvedRequest.wallet_address,
6263
6087
  datastore
6264
6088
  });
6265
6089
  return {
6266
- text: resolved.degradedWarning ? `${resolved.degradedWarning}
6267
-
6268
- ${lsText}` : lsText
6090
+ text: lsText
6269
6091
  };
6270
6092
  } catch (error) {
6271
6093
  const lsErrorMessage = extractLsErrorMessage(error) ?? "Cannot list storage object";
@@ -6288,7 +6110,7 @@ ${lsText}` : lsText
6288
6110
  status: "failed",
6289
6111
  list_mode: isBucketList
6290
6112
  },
6291
- objectLogHomeDir
6113
+ mnemosparkHomeDir
6292
6114
  );
6293
6115
  return {
6294
6116
  text: lsErrorMessage,
@@ -6300,8 +6122,7 @@ ${lsText}` : lsText
6300
6122
  const resolved = await resolveNameSelectorIfNeeded(
6301
6123
  datastore,
6302
6124
  parsed.storageObjectRequest,
6303
- parsed.nameSelector,
6304
- objectLogHomeDir
6125
+ parsed.nameSelector
6305
6126
  );
6306
6127
  if (resolved.error || !resolved.request) {
6307
6128
  return { text: resolved.error ?? "Cannot resolve storage object request.", isError: true };
@@ -6314,17 +6135,6 @@ ${lsText}` : lsText
6314
6135
  return { text: narrowed.error, isError: true };
6315
6136
  }
6316
6137
  const resolvedRequest = narrowed.request;
6317
- if (resolved.degradedWarning) {
6318
- await emitCloudEventBestEffort(
6319
- "name_resolution.degraded",
6320
- {
6321
- wallet_address: resolvedRequest.wallet_address,
6322
- object_key: resolvedRequest.object_key,
6323
- warning: resolved.degradedWarning
6324
- },
6325
- objectLogHomeDir
6326
- );
6327
- }
6328
6138
  const correlation = buildRequestCorrelation(
6329
6139
  executionContext.forcedOperationId,
6330
6140
  executionContext.forcedTraceId
@@ -6367,12 +6177,11 @@ ${lsText}` : lsText
6367
6177
  object_key: resolvedRequest.object_key,
6368
6178
  status: "succeeded"
6369
6179
  },
6370
- objectLogHomeDir
6180
+ mnemosparkHomeDir
6371
6181
  );
6372
6182
  const downloadText = `File ${resolvedRequest.object_key} downloaded to ${downloadResult.file_path}`;
6373
6183
  return {
6374
- text: resolved.degradedWarning ? `${resolved.degradedWarning}
6375
- ${downloadText}` : downloadText
6184
+ text: downloadText
6376
6185
  };
6377
6186
  } catch {
6378
6187
  await datastore.upsertOperation({
@@ -6393,7 +6202,7 @@ ${downloadText}` : downloadText
6393
6202
  object_key: resolvedRequest.object_key,
6394
6203
  status: "failed"
6395
6204
  },
6396
- objectLogHomeDir
6205
+ mnemosparkHomeDir
6397
6206
  );
6398
6207
  return {
6399
6208
  text: "Cannot download file",
@@ -6405,8 +6214,7 @@ ${downloadText}` : downloadText
6405
6214
  const resolved = await resolveNameSelectorIfNeeded(
6406
6215
  datastore,
6407
6216
  parsed.storageObjectRequest,
6408
- parsed.nameSelector,
6409
- objectLogHomeDir
6217
+ parsed.nameSelector
6410
6218
  );
6411
6219
  if (resolved.error || !resolved.request) {
6412
6220
  return { text: resolved.error ?? "Cannot resolve storage object request.", isError: true };
@@ -6419,17 +6227,6 @@ ${downloadText}` : downloadText
6419
6227
  return { text: narrowedDelete.error, isError: true };
6420
6228
  }
6421
6229
  const resolvedRequest = narrowedDelete.request;
6422
- if (resolved.degradedWarning) {
6423
- await emitCloudEventBestEffort(
6424
- "name_resolution.degraded",
6425
- {
6426
- wallet_address: resolvedRequest.wallet_address,
6427
- object_key: resolvedRequest.object_key,
6428
- warning: resolved.degradedWarning
6429
- },
6430
- objectLogHomeDir
6431
- );
6432
- }
6433
6230
  const correlation = buildRequestCorrelation();
6434
6231
  const operationId = correlation.operationId;
6435
6232
  const existingObjectByKey = await datastore.findObjectByObjectKey(resolvedRequest.object_key);
@@ -6451,7 +6248,7 @@ ${downloadText}` : downloadText
6451
6248
  object_key: resolvedRequest.object_key,
6452
6249
  status: "failed"
6453
6250
  },
6454
- objectLogHomeDir
6251
+ mnemosparkHomeDir
6455
6252
  );
6456
6253
  return {
6457
6254
  text: "Cannot delete file",
@@ -6470,15 +6267,15 @@ ${downloadText}` : downloadText
6470
6267
  };
6471
6268
  }
6472
6269
  if (!cronEntry) {
6473
- cronEntry = await findLoggedStoragePaymentCronByObjectKey(
6270
+ cronEntry = await findCronJobInCrontabByObjectKey(
6474
6271
  resolvedRequest.object_key,
6475
- objectLogHomeDir
6272
+ mnemosparkHomeDir
6476
6273
  );
6477
6274
  }
6478
6275
  if (cronEntry) {
6479
6276
  const fileCronDeleted = await removeStoragePaymentCronJob(
6480
6277
  cronEntry.cronId,
6481
- objectLogHomeDir
6278
+ mnemosparkHomeDir
6482
6279
  );
6483
6280
  const dbCronDeleted = await datastore.removeCronJob(cronEntry.cronId);
6484
6281
  cronDeleted = fileCronDeleted || dbCronDeleted;
@@ -6509,7 +6306,7 @@ ${downloadText}` : downloadText
6509
6306
  object_key: resolvedRequest.object_key,
6510
6307
  status: "succeeded"
6511
6308
  },
6512
- objectLogHomeDir
6309
+ mnemosparkHomeDir
6513
6310
  );
6514
6311
  const deleteText = formatStorageDeleteUserMessage(
6515
6312
  resolvedRequest.object_key,
@@ -6517,8 +6314,7 @@ ${downloadText}` : downloadText
6517
6314
  cronDeleted
6518
6315
  );
6519
6316
  return {
6520
- text: resolved.degradedWarning ? `${resolved.degradedWarning}
6521
- ${deleteText}` : deleteText
6317
+ text: deleteText
6522
6318
  };
6523
6319
  }
6524
6320
  return {