mnemospark 0.1.22 → 0.2.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.js CHANGED
@@ -1766,7 +1766,7 @@ async function startProxy(options) {
1766
1766
  emitProxyTerminalFromStatus(correlation, 400, { reason: "invalid_json" });
1767
1767
  sendJson(res, 400, {
1768
1768
  error: "Bad request",
1769
- message: "Invalid JSON body for /mnemospark-cloud price-storage"
1769
+ message: "Invalid JSON body for /mnemospark_cloud price-storage"
1770
1770
  });
1771
1771
  return;
1772
1772
  }
@@ -1834,7 +1834,7 @@ async function startProxy(options) {
1834
1834
  });
1835
1835
  sendJson(res, 502, {
1836
1836
  error: "proxy_error",
1837
- message: `Failed to forward /mnemospark-cloud price-storage: ${err instanceof Error ? err.message : String(err)}`
1837
+ message: `Failed to forward /mnemospark_cloud price-storage: ${err instanceof Error ? err.message : String(err)}`
1838
1838
  });
1839
1839
  }
1840
1840
  return;
@@ -1980,7 +1980,7 @@ async function startProxy(options) {
1980
1980
  emitProxyTerminalFromStatus(correlation, 400, { reason: "invalid_json" });
1981
1981
  sendJson(res, 400, {
1982
1982
  error: "Bad request",
1983
- message: "Invalid JSON body for /mnemospark-cloud upload"
1983
+ message: "Invalid JSON body for /mnemospark_cloud upload"
1984
1984
  });
1985
1985
  return;
1986
1986
  }
@@ -2043,7 +2043,7 @@ async function startProxy(options) {
2043
2043
  error: "insufficient_balance",
2044
2044
  message: `Insufficient USDC balance. Current: ${sufficiency.info.balanceUSD}, Required: ${requiredUSD}`,
2045
2045
  wallet: requestPayload.wallet_address,
2046
- help: `Fund wallet ${requestPayload.wallet_address} on Base before running /mnemospark-cloud upload`
2046
+ help: `Fund wallet ${requestPayload.wallet_address} on Base before running /mnemospark_cloud upload`
2047
2047
  });
2048
2048
  return;
2049
2049
  }
@@ -2151,7 +2151,7 @@ async function startProxy(options) {
2151
2151
  });
2152
2152
  sendJson(res, 502, {
2153
2153
  error: "proxy_error",
2154
- message: `Failed to forward /mnemospark-cloud upload: ${err instanceof Error ? err.message : String(err)}`
2154
+ message: `Failed to forward /mnemospark_cloud upload: ${err instanceof Error ? err.message : String(err)}`
2155
2155
  });
2156
2156
  }
2157
2157
  return;
@@ -2169,7 +2169,7 @@ async function startProxy(options) {
2169
2169
  emitProxyTerminalFromStatus(correlation, 400, { reason: "invalid_json" });
2170
2170
  sendJson(res, 400, {
2171
2171
  error: "Bad request",
2172
- message: "Invalid JSON body for /mnemospark-cloud upload/confirm"
2172
+ message: "Invalid JSON body for /mnemospark_cloud upload/confirm"
2173
2173
  });
2174
2174
  return;
2175
2175
  }
@@ -2250,7 +2250,7 @@ async function startProxy(options) {
2250
2250
  });
2251
2251
  sendJson(res, 502, {
2252
2252
  error: "proxy_error",
2253
- message: `Failed to forward /mnemospark-cloud upload/confirm: ${err instanceof Error ? err.message : String(err)}`
2253
+ message: `Failed to forward /mnemospark_cloud upload/confirm: ${err instanceof Error ? err.message : String(err)}`
2254
2254
  });
2255
2255
  }
2256
2256
  return;
@@ -2268,7 +2268,7 @@ async function startProxy(options) {
2268
2268
  emitProxyTerminalFromStatus(correlation, 400, { reason: "invalid_json" });
2269
2269
  sendJson(res, 400, {
2270
2270
  error: "Bad request",
2271
- message: "Invalid JSON body for /mnemospark-cloud ls"
2271
+ message: "Invalid JSON body for /mnemospark_cloud ls"
2272
2272
  });
2273
2273
  return;
2274
2274
  }
@@ -2341,7 +2341,7 @@ async function startProxy(options) {
2341
2341
  });
2342
2342
  sendJson(res, 502, {
2343
2343
  error: "proxy_error",
2344
- message: `Failed to forward /mnemospark-cloud ls: ${err instanceof Error ? err.message : String(err)}`
2344
+ message: `Failed to forward /mnemospark_cloud ls: ${err instanceof Error ? err.message : String(err)}`
2345
2345
  });
2346
2346
  }
2347
2347
  return;
@@ -2361,7 +2361,7 @@ async function startProxy(options) {
2361
2361
  emitProxyTerminalFromStatus(correlation, 400, { reason: "invalid_json" });
2362
2362
  sendJson(res, 400, {
2363
2363
  error: "Bad request",
2364
- message: "Invalid JSON body for /mnemospark-cloud download"
2364
+ message: "Invalid JSON body for /mnemospark_cloud download"
2365
2365
  });
2366
2366
  return;
2367
2367
  }
@@ -2459,7 +2459,7 @@ async function startProxy(options) {
2459
2459
  });
2460
2460
  sendJson(res, 502, {
2461
2461
  error: "proxy_error",
2462
- message: `Failed to forward /mnemospark-cloud download: ${err instanceof Error ? err.message : String(err)}`
2462
+ message: `Failed to forward /mnemospark_cloud download: ${err instanceof Error ? err.message : String(err)}`
2463
2463
  });
2464
2464
  }
2465
2465
  return;
@@ -2477,7 +2477,7 @@ async function startProxy(options) {
2477
2477
  emitProxyTerminalFromStatus(correlation, 400, { reason: "invalid_json" });
2478
2478
  sendJson(res, 400, {
2479
2479
  error: "Bad request",
2480
- message: "Invalid JSON body for /mnemospark-cloud delete"
2480
+ message: "Invalid JSON body for /mnemospark_cloud delete"
2481
2481
  });
2482
2482
  return;
2483
2483
  }
@@ -2554,7 +2554,7 @@ async function startProxy(options) {
2554
2554
  });
2555
2555
  sendJson(res, 502, {
2556
2556
  error: "proxy_error",
2557
- message: `Failed to forward /mnemospark-cloud delete: ${err instanceof Error ? err.message : String(err)}`
2557
+ message: `Failed to forward /mnemospark_cloud delete: ${err instanceof Error ? err.message : String(err)}`
2558
2558
  });
2559
2559
  }
2560
2560
  return;
@@ -2806,7 +2806,7 @@ import { mkdir as mkdir4 } from "fs/promises";
2806
2806
  import { homedir as homedir5 } from "os";
2807
2807
  import { dirname as dirname4, join as join7 } from "path";
2808
2808
  var DB_SUBPATH = join7(".openclaw", "mnemospark", "state.db");
2809
- var SCHEMA_VERSION = 2;
2809
+ var SCHEMA_VERSION = 3;
2810
2810
  function resolveDbPath(homeDir) {
2811
2811
  return join7(homeDir ?? homedir5(), DB_SUBPATH);
2812
2812
  }
@@ -2912,6 +2912,21 @@ async function createCloudDatastore(homeDir) {
2912
2912
  CREATE INDEX IF NOT EXISTS idx_friendly_names_wallet ON friendly_names(wallet_address);
2913
2913
  CREATE INDEX IF NOT EXISTS idx_friendly_names_created_at ON friendly_names(created_at);
2914
2914
  `);
2915
+ const addOperationsColumn = (columnName, sqlType) => {
2916
+ try {
2917
+ nextDb.exec(`ALTER TABLE operations ADD COLUMN ${columnName} ${sqlType}`);
2918
+ } catch (error) {
2919
+ const message = error instanceof Error ? error.message.toLowerCase() : String(error);
2920
+ if (!message.includes("duplicate column name")) {
2921
+ throw error;
2922
+ }
2923
+ }
2924
+ };
2925
+ addOperationsColumn("trace_id", "TEXT");
2926
+ addOperationsColumn("orchestrator", "TEXT");
2927
+ addOperationsColumn("subagent_session_id", "TEXT");
2928
+ addOperationsColumn("timeout_seconds", "INTEGER");
2929
+ addOperationsColumn("cancel_requested_at", "TEXT");
2915
2930
  nextDb.prepare(
2916
2931
  `INSERT INTO schema_migrations(version, applied_at)
2917
2932
  VALUES(?, ?)
@@ -2923,7 +2938,10 @@ async function createCloudDatastore(homeDir) {
2923
2938
  try {
2924
2939
  await ensureReady();
2925
2940
  return fn();
2926
- } catch {
2941
+ } catch (error) {
2942
+ if (process.env.MNEMOSPARK_SQLITE_STRICT === "1") {
2943
+ throw error;
2944
+ }
2927
2945
  return fallback;
2928
2946
  }
2929
2947
  };
@@ -3048,13 +3066,19 @@ async function createCloudDatastore(homeDir) {
3048
3066
  upsertOperation: async (row) => {
3049
3067
  await safe(() => {
3050
3068
  const ts = nowIso();
3069
+ const terminalStatuses = /* @__PURE__ */ new Set(["succeeded", "failed", "cancelled", "timed_out"]);
3051
3070
  db.prepare(
3052
- `INSERT INTO operations(operation_id, type, object_id, quote_id, status, error_code, error_message, started_at, finished_at, created_at, updated_at)
3053
- VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
3071
+ `INSERT INTO operations(operation_id, type, object_id, quote_id, trace_id, orchestrator, subagent_session_id, timeout_seconds, cancel_requested_at, status, error_code, error_message, started_at, finished_at, created_at, updated_at)
3072
+ VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
3054
3073
  ON CONFLICT(operation_id) DO UPDATE SET
3055
3074
  type=excluded.type,
3056
3075
  object_id=COALESCE(excluded.object_id, operations.object_id),
3057
- quote_id=excluded.quote_id,
3076
+ quote_id=COALESCE(excluded.quote_id, operations.quote_id),
3077
+ trace_id=COALESCE(excluded.trace_id, operations.trace_id),
3078
+ orchestrator=COALESCE(excluded.orchestrator, operations.orchestrator),
3079
+ subagent_session_id=COALESCE(excluded.subagent_session_id, operations.subagent_session_id),
3080
+ timeout_seconds=COALESCE(excluded.timeout_seconds, operations.timeout_seconds),
3081
+ cancel_requested_at=COALESCE(excluded.cancel_requested_at, operations.cancel_requested_at),
3058
3082
  status=excluded.status,
3059
3083
  error_code=excluded.error_code,
3060
3084
  error_message=excluded.error_message,
@@ -3066,11 +3090,16 @@ async function createCloudDatastore(homeDir) {
3066
3090
  row.type,
3067
3091
  row.object_id,
3068
3092
  row.quote_id,
3093
+ row.trace_id ?? null,
3094
+ row.orchestrator ?? null,
3095
+ row.subagent_session_id ?? null,
3096
+ row.timeout_seconds ?? null,
3097
+ row.cancel_requested_at ?? null,
3069
3098
  row.status,
3070
3099
  row.error_code,
3071
3100
  row.error_message,
3072
3101
  row.status === "started" ? ts : null,
3073
- row.status === "succeeded" || row.status === "failed" ? ts : null,
3102
+ terminalStatuses.has(row.status) ? ts : null,
3074
3103
  ts,
3075
3104
  ts
3076
3105
  );
@@ -3078,7 +3107,7 @@ async function createCloudDatastore(homeDir) {
3078
3107
  },
3079
3108
  findOperationById: async (operationId) => safe(() => {
3080
3109
  const row = db.prepare(
3081
- `SELECT operation_id, type, status, error_code, error_message, started_at, finished_at, updated_at
3110
+ `SELECT operation_id, type, object_id, quote_id, trace_id, orchestrator, subagent_session_id, timeout_seconds, cancel_requested_at, status, error_code, error_message, started_at, finished_at, updated_at
3082
3111
  FROM operations
3083
3112
  WHERE operation_id = ?
3084
3113
  LIMIT 1`
@@ -3180,7 +3209,9 @@ var REQUIRED_UPLOAD = "--quote-id, --wallet-address, --object-id, --object-id-ha
3180
3209
  var REQUIRED_STORAGE_OBJECT = "--wallet-address and one of (--object-key | --name [--latest|--at])";
3181
3210
  var BOOLEAN_SELECTOR_FLAGS = /* @__PURE__ */ new Set(["latest"]);
3182
3211
  var BOOLEAN_ASYNC_FLAGS = /* @__PURE__ */ new Set(["async"]);
3212
+ var BOOLEAN_OP_STATUS_FLAGS = /* @__PURE__ */ new Set(["cancel"]);
3183
3213
  var BOOLEAN_SELECTOR_AND_ASYNC_FLAGS = /* @__PURE__ */ new Set(["latest", "async"]);
3214
+ var ORCHESTRATOR_MODES = /* @__PURE__ */ new Set(["inline", "subagent"]);
3184
3215
  function expandTilde(path) {
3185
3216
  const trimmed = path.trim();
3186
3217
  if (trimmed === "~") {
@@ -3194,29 +3225,54 @@ function expandTilde(path) {
3194
3225
  var CLOUD_HELP_TEXT = [
3195
3226
  "\u2601\uFE0F **mnemospark Cloud Commands**",
3196
3227
  "",
3197
- "\u2022 `/mnemospark-cloud` or `/mnemospark-cloud help` \u2014 show this message",
3228
+ "\u2022 `/mnemospark_cloud` or `/mnemospark_cloud help` \u2014 show this message",
3198
3229
  "",
3199
- "\u2022 `/mnemospark-cloud backup <file>` or `/mnemospark-cloud backup <directory> [--name <friendly-name>]`",
3200
- " Required: <file> or <directory> (path to back up)",
3230
+ "\u2022 `/mnemospark_cloud backup <file|directory> [--name <friendly-name>] [--async] [--orchestrator <inline|subagent>] [--timeout-seconds <n>]`",
3231
+ " Purpose: create a local tar+gzip backup object and index it for later upload.",
3232
+ " Required: <file|directory>",
3201
3233
  "",
3202
- "\u2022 `/mnemospark-cloud price-storage --wallet-address <addr> --object-id <id> --object-id-hash <hash> --gb <gb> --provider <provider> --region <region>`",
3234
+ "\u2022 `/mnemospark_cloud price-storage --wallet-address <addr> --object-id <id> --object-id-hash <hash> --gb <gb> --provider <provider> --region <region>`",
3235
+ " Purpose: request a storage quote before upload.",
3203
3236
  " Required: " + REQUIRED_PRICE_STORAGE,
3204
3237
  "",
3205
- "\u2022 `/mnemospark-cloud upload --quote-id <quote-id> --wallet-address <addr> --object-id <id> --object-id-hash <hash> [--name <friendly-name>] [--async]`",
3238
+ "\u2022 `/mnemospark_cloud upload --quote-id <quote-id> --wallet-address <addr> --object-id <id> --object-id-hash <hash> [--name <friendly-name>] [--async] [--orchestrator <inline|subagent>] [--timeout-seconds <n>]`",
3239
+ " Purpose: upload an encrypted object using a valid quote-id.",
3206
3240
  " Required: " + REQUIRED_UPLOAD,
3207
3241
  "",
3208
- "\u2022 `/mnemospark-cloud ls --wallet-address <addr> [--object-key <object-key> | --name <friendly-name>] [--latest|--at <timestamp>]`",
3242
+ "\u2022 `/mnemospark_cloud ls --wallet-address <addr> [--object-key <object-key> | --name <friendly-name>] [--latest|--at <timestamp>]`",
3243
+ " Purpose: look up remote object metadata.",
3209
3244
  " Required: " + REQUIRED_STORAGE_OBJECT,
3210
3245
  "",
3211
- "\u2022 `/mnemospark-cloud download --wallet-address <addr> [--object-key <object-key> | --name <friendly-name>] [--latest|--at <timestamp>] [--async]`",
3246
+ "\u2022 `/mnemospark_cloud download --wallet-address <addr> [--object-key <object-key> | --name <friendly-name>] [--latest|--at <timestamp>] [--async] [--orchestrator <inline|subagent>] [--timeout-seconds <n>]`",
3247
+ " Purpose: fetch an object to local disk.",
3212
3248
  " Required: " + REQUIRED_STORAGE_OBJECT,
3213
3249
  "",
3214
- "\u2022 `/mnemospark-cloud delete --wallet-address <addr> [--object-key <object-key> | --name <friendly-name>] [--latest|--at <timestamp>]`",
3250
+ "\u2022 `/mnemospark_cloud delete --wallet-address <addr> [--object-key <object-key> | --name <friendly-name>] [--latest|--at <timestamp>]`",
3251
+ " Purpose: remove a remote object and local cron tracking when present.",
3215
3252
  " Required: " + REQUIRED_STORAGE_OBJECT,
3216
3253
  "",
3217
- "\u2022 `/mnemospark-cloud op-status --operation-id <id>`",
3254
+ "\u2022 `/mnemospark_cloud op-status --operation-id <id> [--cancel]`",
3255
+ " Purpose: inspect async operation status, or request cancellation for subagent runs.",
3218
3256
  " Required: --operation-id",
3219
3257
  "",
3258
+ "Async orchestration flags (`backup`, `upload`, `download` only):",
3259
+ "\u2022 `--async`",
3260
+ " Start operation in background and return quickly with operation-id.",
3261
+ "\u2022 `--orchestrator <inline|subagent>`",
3262
+ " Choose async engine. Default when omitted is `inline`.",
3263
+ " Use `subagent` for explicit subagent session tracking and cancellation.",
3264
+ "\u2022 `--timeout-seconds <n>`",
3265
+ " Optional per-operation timeout. Valid only with `--async --orchestrator subagent`.",
3266
+ " `n` must be a positive integer (seconds).",
3267
+ "\u2022 `op-status --cancel`",
3268
+ " Cancel a subagent-orchestrated operation by operation-id (idempotent).",
3269
+ "",
3270
+ "Examples:",
3271
+ "\u2022 `/mnemospark_cloud upload ... --async --orchestrator subagent`",
3272
+ "\u2022 `/mnemospark_cloud download ... --async --orchestrator subagent --timeout-seconds 900`",
3273
+ "\u2022 `/mnemospark_cloud op-status --operation-id <id>`",
3274
+ "\u2022 `/mnemospark_cloud op-status --operation-id <id> --cancel`",
3275
+ "",
3220
3276
  "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. All storage commands (price-storage, upload, ls, download, delete) require --wallet-address."
3221
3277
  ].join("\n");
3222
3278
  var UnsupportedBackupPlatformError = class extends Error {
@@ -3306,9 +3362,73 @@ function parseStorageObjectRequestInput(flags, selector) {
3306
3362
  location
3307
3363
  });
3308
3364
  }
3309
- function stripAsyncFlag(args) {
3365
+ function parseOrchestratorMode(value) {
3366
+ if (!value) {
3367
+ return void 0;
3368
+ }
3369
+ const normalized = value.trim().toLowerCase();
3370
+ if (!normalized) {
3371
+ return null;
3372
+ }
3373
+ if (!ORCHESTRATOR_MODES.has(normalized)) {
3374
+ return null;
3375
+ }
3376
+ return normalized;
3377
+ }
3378
+ function parseTimeoutSeconds(value) {
3379
+ if (!value) {
3380
+ return void 0;
3381
+ }
3382
+ const trimmed = value.trim();
3383
+ if (!/^\d+$/.test(trimmed)) {
3384
+ return null;
3385
+ }
3386
+ const parsed = Number.parseInt(trimmed, 10);
3387
+ if (!Number.isFinite(parsed) || parsed <= 0) {
3388
+ return null;
3389
+ }
3390
+ return parsed;
3391
+ }
3392
+ function parseAsyncOperationArgs(flags) {
3393
+ const asyncRequested = flags.async === "true";
3394
+ const hasOrchestratorFlag = typeof flags.orchestrator === "string";
3395
+ const hasTimeoutFlag = typeof flags["timeout-seconds"] === "string";
3396
+ if (!asyncRequested && (hasOrchestratorFlag || hasTimeoutFlag)) {
3397
+ return null;
3398
+ }
3399
+ const parsedOrchestrator = parseOrchestratorMode(flags.orchestrator);
3400
+ if (parsedOrchestrator === null) {
3401
+ return null;
3402
+ }
3403
+ const parsedTimeoutSeconds = parseTimeoutSeconds(flags["timeout-seconds"]);
3404
+ if (parsedTimeoutSeconds === null) {
3405
+ return null;
3406
+ }
3407
+ if (typeof parsedTimeoutSeconds === "number" && (parsedOrchestrator ?? "inline") !== "subagent") {
3408
+ return null;
3409
+ }
3410
+ return {
3411
+ async: asyncRequested,
3412
+ orchestrator: parsedOrchestrator === void 0 ? void 0 : parsedOrchestrator,
3413
+ timeoutSeconds: parsedTimeoutSeconds === void 0 ? void 0 : parsedTimeoutSeconds
3414
+ };
3415
+ }
3416
+ var INVALID_ASYNC_FLAGS_MESSAGE = "invalid async flags. `--orchestrator`/`--timeout-seconds` require `--async`, and `--timeout-seconds` is only valid with `--orchestrator subagent`.";
3417
+ function stripAsyncControlFlags(args) {
3310
3418
  const tokens = tokenizeArgsRaw(args ?? "");
3311
- const filtered = tokens.filter((token) => token.toLowerCase() !== "--async");
3419
+ const filtered = [];
3420
+ for (let idx = 0; idx < tokens.length; idx += 1) {
3421
+ const token = tokens[idx];
3422
+ const lowerToken = token.toLowerCase();
3423
+ if (lowerToken === "--async") {
3424
+ continue;
3425
+ }
3426
+ if (lowerToken === "--orchestrator" || lowerToken === "--timeout-seconds") {
3427
+ idx += 1;
3428
+ continue;
3429
+ }
3430
+ filtered.push(token);
3431
+ }
3312
3432
  return filtered.join(" ");
3313
3433
  }
3314
3434
  function parseCloudArgs(args) {
@@ -3331,8 +3451,21 @@ function parseCloudArgs(args) {
3331
3451
  if (!backupTarget) {
3332
3452
  return { mode: "unknown" };
3333
3453
  }
3334
- const flags = parseNamedFlagsTokens(tokens.slice(1));
3335
- return { mode: "backup", backupTarget, friendlyName: flags?.name?.trim() || void 0 };
3454
+ const remainingTokens = tokens.slice(1);
3455
+ const flags = remainingTokens.length === 0 ? {} : parseNamedFlagsTokens(remainingTokens, BOOLEAN_ASYNC_FLAGS);
3456
+ if (!flags) {
3457
+ return { mode: "backup-invalid" };
3458
+ }
3459
+ const asyncArgs = parseAsyncOperationArgs(flags);
3460
+ if (!asyncArgs) {
3461
+ return { mode: "backup-invalid-async" };
3462
+ }
3463
+ return {
3464
+ mode: "backup",
3465
+ backupTarget,
3466
+ friendlyName: flags.name?.trim() || void 0,
3467
+ ...asyncArgs
3468
+ };
3336
3469
  }
3337
3470
  if (subcommand === "price-storage") {
3338
3471
  const flags = parseNamedFlags(rest);
@@ -3358,6 +3491,10 @@ function parseCloudArgs(args) {
3358
3491
  if (!flags) {
3359
3492
  return { mode: "upload-invalid" };
3360
3493
  }
3494
+ const asyncArgs = parseAsyncOperationArgs(flags);
3495
+ if (!asyncArgs) {
3496
+ return { mode: "upload-invalid-async" };
3497
+ }
3361
3498
  const quoteId = flags["quote-id"]?.trim();
3362
3499
  const walletAddress = flags["wallet-address"]?.trim();
3363
3500
  const objectId = flags["object-id"]?.trim();
@@ -3368,7 +3505,7 @@ function parseCloudArgs(args) {
3368
3505
  return {
3369
3506
  mode: "upload",
3370
3507
  friendlyName: flags.name?.trim() || void 0,
3371
- async: flags.async === "true",
3508
+ ...asyncArgs,
3372
3509
  uploadRequest: {
3373
3510
  quote_id: quoteId,
3374
3511
  wallet_address: walletAddress,
@@ -3397,6 +3534,10 @@ function parseCloudArgs(args) {
3397
3534
  if (!flags) {
3398
3535
  return { mode: "download-invalid" };
3399
3536
  }
3537
+ const asyncArgs = parseAsyncOperationArgs(flags);
3538
+ if (!asyncArgs) {
3539
+ return { mode: "download-invalid-async" };
3540
+ }
3400
3541
  const selector = parseObjectSelector(flags);
3401
3542
  if (!selector) {
3402
3543
  return { mode: "download-invalid" };
@@ -3409,7 +3550,7 @@ function parseCloudArgs(args) {
3409
3550
  mode: "download",
3410
3551
  storageObjectRequest: request,
3411
3552
  nameSelector: selector.nameSelector,
3412
- async: flags.async === "true"
3553
+ ...asyncArgs
3413
3554
  };
3414
3555
  }
3415
3556
  if (subcommand === "delete") {
@@ -3428,12 +3569,12 @@ function parseCloudArgs(args) {
3428
3569
  return { mode: "delete", storageObjectRequest: request, nameSelector: selector.nameSelector };
3429
3570
  }
3430
3571
  if (subcommand === "op-status") {
3431
- const flags = parseNamedFlags(rest);
3572
+ const flags = parseNamedFlags(rest, BOOLEAN_OP_STATUS_FLAGS);
3432
3573
  const operationId = flags?.["operation-id"]?.trim();
3433
3574
  if (!operationId) {
3434
3575
  return { mode: "op-status-invalid" };
3435
3576
  }
3436
- return { mode: "op-status", operationId };
3577
+ return { mode: "op-status", operationId, cancel: flags?.cancel === "true" };
3437
3578
  }
3438
3579
  return { mode: "unknown" };
3439
3580
  }
@@ -3924,17 +4065,37 @@ async function uploadPresignedObjectIfNeeded(uploadResponse, uploadMode, encrypt
3924
4065
  if (!headers.has("content-type")) {
3925
4066
  headers.set("content-type", "application/octet-stream");
3926
4067
  }
3927
- const response = await fetchImpl(uploadResponse.upload_url, {
4068
+ const putBody = new Uint8Array(encryptedContent);
4069
+ const firstAttempt = await fetchImpl(uploadResponse.upload_url, {
3928
4070
  method: "PUT",
3929
4071
  headers,
3930
- body: new Uint8Array(encryptedContent)
4072
+ body: putBody,
4073
+ redirect: "manual"
3931
4074
  });
3932
- if (!response.ok) {
3933
- const details = (await response.text()).trim();
3934
- throw new Error(
3935
- `Presigned upload failed with status ${response.status}${details ? `: ${details}` : ""}`
3936
- );
4075
+ if (firstAttempt.ok) {
4076
+ return;
4077
+ }
4078
+ if ((firstAttempt.status === 307 || firstAttempt.status === 308) && firstAttempt.headers.has("location")) {
4079
+ const location = firstAttempt.headers.get("location")?.trim();
4080
+ if (location) {
4081
+ const redirectedAttempt = await fetchImpl(location, {
4082
+ method: "PUT",
4083
+ headers,
4084
+ body: putBody
4085
+ });
4086
+ if (redirectedAttempt.ok) {
4087
+ return;
4088
+ }
4089
+ const redirectedDetails = (await redirectedAttempt.text()).trim();
4090
+ throw new Error(
4091
+ `Presigned upload failed after redirect with status ${redirectedAttempt.status}${redirectedDetails ? `: ${redirectedDetails}` : ""}`
4092
+ );
4093
+ }
3937
4094
  }
4095
+ const details = (await firstAttempt.text()).trim();
4096
+ throw new Error(
4097
+ `Presigned upload failed with status ${firstAttempt.status}${details ? `: ${details}` : ""}`
4098
+ );
3938
4099
  }
3939
4100
  async function appendStorageUploadLog(upload, homeDir, nowDateFn = () => /* @__PURE__ */ new Date()) {
3940
4101
  return appendObjectLogLine(
@@ -4005,16 +4166,118 @@ function extractUploadErrorMessage(error) {
4005
4166
  function formatPriceStorageUserMessage(quote) {
4006
4167
  return [
4007
4168
  `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}\``,
4008
- `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}\``
4169
+ `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}\``
4009
4170
  ].join("\n");
4010
4171
  }
4011
4172
  function formatStorageLsUserMessage(result, requestedObjectKey) {
4012
4173
  const objectId = result.object_id ?? result.key;
4013
4174
  return `${objectId} with ${requestedObjectKey} is ${result.size_bytes} in ${result.bucket}`;
4014
4175
  }
4176
+ function createInProcessSubagentOrchestrator() {
4177
+ const sessions = /* @__PURE__ */ new Map();
4178
+ const completeSession = async (sessionId, handler) => {
4179
+ const session = sessions.get(sessionId);
4180
+ if (!session || session.terminal) {
4181
+ return false;
4182
+ }
4183
+ session.terminal = true;
4184
+ if (session.timeoutHandle) {
4185
+ clearTimeout(session.timeoutHandle);
4186
+ }
4187
+ sessions.delete(sessionId);
4188
+ await handler(session.hooks);
4189
+ return true;
4190
+ };
4191
+ return {
4192
+ dispatch: async (input) => {
4193
+ const sessionId = `agent:mnemospark:subagent:${randomUUID3()}`;
4194
+ const state = {
4195
+ terminal: false,
4196
+ cancelRequested: false,
4197
+ hooks: input.hooks
4198
+ };
4199
+ sessions.set(sessionId, state);
4200
+ if (typeof input.timeoutSeconds === "number" && input.timeoutSeconds > 0) {
4201
+ state.timeoutHandle = setTimeout(() => {
4202
+ void completeSession(sessionId, async (hooks) => {
4203
+ await hooks?.onTimedOut?.(sessionId);
4204
+ });
4205
+ }, input.timeoutSeconds * 1e3);
4206
+ }
4207
+ setTimeout(() => {
4208
+ void (async () => {
4209
+ try {
4210
+ await input.hooks?.onRunning?.(sessionId);
4211
+ await input.hooks?.onProgress?.(sessionId, "subagent execution started");
4212
+ const result = await input.runTask();
4213
+ const session = sessions.get(sessionId);
4214
+ if (!session || session.terminal) {
4215
+ return;
4216
+ }
4217
+ if (session.cancelRequested) {
4218
+ await completeSession(sessionId, async (hooks) => {
4219
+ await hooks?.onCancelled?.(sessionId, "cancel requested");
4220
+ });
4221
+ return;
4222
+ }
4223
+ if (result.isError) {
4224
+ await completeSession(sessionId, async (hooks) => {
4225
+ await hooks?.onFailed?.(sessionId, {
4226
+ code: "ASYNC_FAILED",
4227
+ message: result.text
4228
+ });
4229
+ });
4230
+ return;
4231
+ }
4232
+ await completeSession(sessionId, async (hooks) => {
4233
+ await hooks?.onCompleted?.(sessionId, result);
4234
+ });
4235
+ } catch (error) {
4236
+ const message = error instanceof Error ? error.message : String(error);
4237
+ const session = sessions.get(sessionId);
4238
+ if (!session || session.terminal) {
4239
+ return;
4240
+ }
4241
+ if (session.cancelRequested) {
4242
+ await completeSession(sessionId, async (hooks) => {
4243
+ await hooks?.onCancelled?.(sessionId, "cancel requested");
4244
+ });
4245
+ return;
4246
+ }
4247
+ await completeSession(sessionId, async (hooks) => {
4248
+ await hooks?.onFailed?.(sessionId, {
4249
+ code: "ASYNC_EXCEPTION",
4250
+ message
4251
+ });
4252
+ });
4253
+ }
4254
+ })();
4255
+ }, 0);
4256
+ return { sessionId };
4257
+ },
4258
+ cancel: async (sessionId, reason) => {
4259
+ const session = sessions.get(sessionId);
4260
+ if (!session) {
4261
+ return { accepted: false };
4262
+ }
4263
+ if (session.terminal) {
4264
+ return { accepted: false, alreadyTerminal: true };
4265
+ }
4266
+ session.cancelRequested = true;
4267
+ await completeSession(sessionId, async (hooks) => {
4268
+ await hooks?.onCancelled?.(sessionId, reason ?? "cancel requested");
4269
+ });
4270
+ return { accepted: true };
4271
+ }
4272
+ };
4273
+ }
4015
4274
  function createCloudCommand(options = {}) {
4275
+ const subagentOrchestrator = options.subagentOrchestrator ?? createInProcessSubagentOrchestrator();
4016
4276
  return {
4017
- name: "mnemospark-cloud",
4277
+ name: "mnemospark_cloud",
4278
+ nativeNames: {
4279
+ default: "mnemospark_cloud"
4280
+ },
4018
4281
  description: "Manage mnemospark cloud storage workflow commands",
4019
4282
  acceptsArgs: true,
4020
4283
  requireAuth: true,
@@ -4038,6 +4301,7 @@ function createCloudCommand(options = {}) {
4038
4301
  proxyQuoteOptions: options.proxyQuoteOptions,
4039
4302
  proxyUploadOptions: options.proxyUploadOptions,
4040
4303
  proxyUploadConfirmOptions: options.proxyUploadConfirmOptions,
4304
+ subagentOrchestrator,
4041
4305
  proxyStorageOptions: options.proxyStorageOptions
4042
4306
  });
4043
4307
  } catch (outerError) {
@@ -4047,7 +4311,42 @@ function createCloudCommand(options = {}) {
4047
4311
  }
4048
4312
  };
4049
4313
  }
4050
- async function resolveNameSelectorIfNeeded(datastore, request, selector) {
4314
+ async function resolveFriendlyNameFromManifest(params, homeDir) {
4315
+ const manifestPath = join8(homeDir ?? homedir6(), ".openclaw", "mnemospark", "manifest.jsonl");
4316
+ let manifestRaw;
4317
+ try {
4318
+ manifestRaw = await readFile3(manifestPath, "utf-8");
4319
+ } catch {
4320
+ return { objectKey: null, matchCount: 0 };
4321
+ }
4322
+ const wallet = params.walletAddress.trim();
4323
+ const name = params.friendlyName.trim();
4324
+ const atMs = params.at ? Date.parse(params.at) : Number.NaN;
4325
+ const hasAt = Number.isFinite(atMs);
4326
+ const rows = manifestRaw.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((line) => {
4327
+ try {
4328
+ return JSON.parse(line);
4329
+ } catch {
4330
+ return null;
4331
+ }
4332
+ }).filter((row) => Boolean(row)).filter((row) => {
4333
+ if (!row.object_key || !row.friendly_name || !row.wallet_address || !row.created_at)
4334
+ return false;
4335
+ if (row.friendly_name !== name) return false;
4336
+ if (row.wallet_address.trim() !== wallet) return false;
4337
+ if (params.latest || !hasAt) return true;
4338
+ const createdAtMs = Date.parse(row.created_at);
4339
+ return Number.isFinite(createdAtMs) && createdAtMs <= atMs;
4340
+ }).sort((a, b) => Date.parse(b.created_at ?? "") - Date.parse(a.created_at ?? ""));
4341
+ if (rows.length === 0) {
4342
+ return { objectKey: null, matchCount: 0 };
4343
+ }
4344
+ if (!params.latest && !hasAt && rows.length > 1) {
4345
+ return { objectKey: null, matchCount: rows.length };
4346
+ }
4347
+ return { objectKey: rows[0].object_key ?? null, matchCount: rows.length };
4348
+ }
4349
+ async function resolveNameSelectorIfNeeded(datastore, request, selector, homeDir) {
4051
4350
  if (!selector) {
4052
4351
  const parsedRequest2 = parseStorageObjectRequest(request);
4053
4352
  if (!parsedRequest2) {
@@ -4055,6 +4354,12 @@ async function resolveNameSelectorIfNeeded(datastore, request, selector) {
4055
4354
  }
4056
4355
  return { request: parsedRequest2 };
4057
4356
  }
4357
+ let sqliteUnavailable = false;
4358
+ try {
4359
+ await datastore.ensureReady();
4360
+ } catch {
4361
+ sqliteUnavailable = true;
4362
+ }
4058
4363
  const matches = await datastore.countFriendlyNameMatches(request.wallet_address, selector.name);
4059
4364
  if (matches > 1 && !selector.latest && !selector.at) {
4060
4365
  return {
@@ -4067,18 +4372,41 @@ async function resolveNameSelectorIfNeeded(datastore, request, selector) {
4067
4372
  latest: selector.latest,
4068
4373
  at: selector.at
4069
4374
  });
4070
- if (!resolved || !resolved.objectKey) {
4375
+ let resolvedObjectKey = resolved?.objectKey ?? null;
4376
+ let degradedWarning;
4377
+ if (!resolvedObjectKey && sqliteUnavailable) {
4378
+ const manifestResolved = await resolveFriendlyNameFromManifest(
4379
+ {
4380
+ walletAddress: request.wallet_address,
4381
+ friendlyName: selector.name,
4382
+ latest: selector.latest,
4383
+ at: selector.at
4384
+ },
4385
+ homeDir
4386
+ );
4387
+ if (manifestResolved.matchCount > 1 && !selector.latest && !selector.at) {
4388
+ return {
4389
+ error: `Multiple objects match --name ${selector.name}. Add --latest or --at <timestamp>.`
4390
+ };
4391
+ }
4392
+ resolvedObjectKey = manifestResolved.objectKey;
4393
+ if (resolvedObjectKey) {
4394
+ degradedWarning = "SQLite friendly-name index unavailable; resolved --name via manifest.jsonl fallback.";
4395
+ }
4396
+ }
4397
+ if (!resolvedObjectKey) {
4071
4398
  return { error: `No object found for --name ${selector.name}.` };
4072
4399
  }
4073
4400
  const parsedRequest = parseStorageObjectRequest({
4074
4401
  ...request,
4075
- object_key: resolved.objectKey
4402
+ object_key: resolvedObjectKey
4076
4403
  });
4077
4404
  if (!parsedRequest) {
4078
4405
  return { error: "Cannot resolve storage object request." };
4079
4406
  }
4080
4407
  return {
4081
- request: parsedRequest
4408
+ request: parsedRequest,
4409
+ degradedWarning
4082
4410
  };
4083
4411
  }
4084
4412
  async function emitCloudEvent(eventType, details, homeDir) {
@@ -4098,6 +4426,38 @@ async function emitCloudEventBestEffort(eventType, details, homeDir) {
4098
4426
  } catch {
4099
4427
  }
4100
4428
  }
4429
+ function toOperationEventPayload(eventType, context) {
4430
+ return {
4431
+ operation_id: context.operationId,
4432
+ trace_id: context.traceId,
4433
+ event_type: eventType,
4434
+ status: context.status,
4435
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
4436
+ wallet_address: context.walletAddress ?? void 0,
4437
+ object_id: context.objectId ?? void 0,
4438
+ object_key: context.objectKey ?? void 0,
4439
+ quote_id: context.quoteId ?? void 0,
4440
+ orchestrator: context.orchestrator ?? void 0,
4441
+ "subagent-session-id": context.subagentSessionId ?? void 0,
4442
+ "timeout-seconds": context.timeoutSeconds ?? void 0,
4443
+ "error-code": context.errorCode ?? void 0,
4444
+ "error-message": context.errorMessage ?? void 0,
4445
+ progress: context.progressMessage ?? void 0
4446
+ };
4447
+ }
4448
+ async function emitOperationEvent(eventType, context, homeDir) {
4449
+ const payload = toOperationEventPayload(eventType, context);
4450
+ await Promise.all([
4451
+ appendJsonlEvent("events.jsonl", payload, homeDir),
4452
+ appendJsonlEvent("proxy-events.jsonl", payload, homeDir)
4453
+ ]);
4454
+ }
4455
+ async function emitOperationEventBestEffort(eventType, context, homeDir) {
4456
+ try {
4457
+ await emitOperationEvent(eventType, context, homeDir);
4458
+ } catch {
4459
+ }
4460
+ }
4101
4461
  function buildRequestCorrelation(forcedOperationId, forcedTraceId) {
4102
4462
  const operationId = forcedOperationId?.trim() || randomUUID3();
4103
4463
  const traceId = forcedTraceId?.trim() || randomUUID3();
@@ -4118,6 +4478,7 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
4118
4478
  const requestStorageLs = options.requestStorageLsFn;
4119
4479
  const requestStorageDownload = options.requestStorageDownloadFn;
4120
4480
  const requestStorageDelete = options.requestStorageDeleteFn;
4481
+ const subagentOrchestrator = options.subagentOrchestrator;
4121
4482
  if (parsed.mode === "help" || parsed.mode === "unknown") {
4122
4483
  return {
4123
4484
  text: CLOUD_HELP_TEXT,
@@ -4130,12 +4491,30 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
4130
4491
  isError: true
4131
4492
  };
4132
4493
  }
4494
+ if (parsed.mode === "backup-invalid") {
4495
+ return {
4496
+ text: "Cannot build storage object",
4497
+ isError: true
4498
+ };
4499
+ }
4500
+ if (parsed.mode === "backup-invalid-async") {
4501
+ return {
4502
+ text: `Cannot build storage object: ${INVALID_ASYNC_FLAGS_MESSAGE}`,
4503
+ isError: true
4504
+ };
4505
+ }
4133
4506
  if (parsed.mode === "upload-invalid") {
4134
4507
  return {
4135
4508
  text: `Cannot upload storage object: required arguments are ${REQUIRED_UPLOAD}.`,
4136
4509
  isError: true
4137
4510
  };
4138
4511
  }
4512
+ if (parsed.mode === "upload-invalid-async") {
4513
+ return {
4514
+ text: `Cannot upload storage object: ${INVALID_ASYNC_FLAGS_MESSAGE}`,
4515
+ isError: true
4516
+ };
4517
+ }
4139
4518
  if (parsed.mode === "ls-invalid") {
4140
4519
  return {
4141
4520
  text: `Cannot list storage object: required arguments are ${REQUIRED_STORAGE_OBJECT}.`,
@@ -4148,6 +4527,12 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
4148
4527
  isError: true
4149
4528
  };
4150
4529
  }
4530
+ if (parsed.mode === "download-invalid-async") {
4531
+ return {
4532
+ text: `Cannot download file: ${INVALID_ASYNC_FLAGS_MESSAGE}`,
4533
+ isError: true
4534
+ };
4535
+ }
4151
4536
  if (parsed.mode === "delete-invalid") {
4152
4537
  return {
4153
4538
  text: `Cannot delete file: required arguments are ${REQUIRED_STORAGE_OBJECT}.`,
@@ -4161,70 +4546,450 @@ async function runCloudCommandHandler(ctx, options, executionContext = {}) {
4161
4546
  };
4162
4547
  }
4163
4548
  const datastore = await createCloudDatastore(objectLogHomeDir);
4549
+ const terminalOperationStatuses = /* @__PURE__ */ new Set(["succeeded", "failed", "cancelled", "timed_out"]);
4550
+ const isTerminalOperationStatus = (status) => terminalOperationStatuses.has(status);
4551
+ const formatOperationStatus = (operation) => ({
4552
+ text: [
4553
+ `operation-id: ${operation.operation_id}`,
4554
+ `type: ${operation.type}`,
4555
+ `status: ${operation.status}`,
4556
+ `started-at: ${operation.started_at ?? "n/a"}`,
4557
+ `finished-at: ${operation.finished_at ?? "n/a"}`,
4558
+ operation.orchestrator ? `orchestrator: ${operation.orchestrator}` : null,
4559
+ operation.subagent_session_id ? `subagent-session-id: ${operation.subagent_session_id}` : null,
4560
+ operation.timeout_seconds ? `timeout-seconds: ${operation.timeout_seconds}` : null,
4561
+ operation.error_code ? `error-code: ${operation.error_code}` : null,
4562
+ operation.error_message ? `error-message: ${operation.error_message}` : null
4563
+ ].filter((v) => Boolean(v)).join("\n"),
4564
+ isError: operation.status === "failed" || operation.status === "cancelled" || operation.status === "timed_out"
4565
+ });
4164
4566
  if (parsed.mode === "op-status") {
4165
- const operation = await datastore.findOperationById(parsed.operationId);
4567
+ let operation = await datastore.findOperationById(parsed.operationId);
4166
4568
  if (!operation) {
4167
4569
  return {
4168
4570
  text: `Operation not found: ${parsed.operationId}`,
4169
4571
  isError: true
4170
4572
  };
4171
4573
  }
4172
- return {
4173
- text: [
4174
- `operation-id: ${operation.operation_id}`,
4175
- `type: ${operation.type}`,
4176
- `status: ${operation.status}`,
4177
- `started-at: ${operation.started_at ?? "n/a"}`,
4178
- `finished-at: ${operation.finished_at ?? "n/a"}`,
4179
- operation.error_code ? `error-code: ${operation.error_code}` : null,
4180
- operation.error_message ? `error-message: ${operation.error_message}` : null
4181
- ].filter((v) => Boolean(v)).join("\n"),
4182
- isError: operation.status === "failed"
4183
- };
4574
+ if (parsed.cancel) {
4575
+ if (operation.orchestrator !== "subagent" || !operation.subagent_session_id) {
4576
+ return {
4577
+ text: "Cancellation is only supported for subagent-orchestrated operations.",
4578
+ isError: true
4579
+ };
4580
+ }
4581
+ if (!isTerminalOperationStatus(operation.status)) {
4582
+ const traceId = operation.trace_id ?? randomUUID3();
4583
+ const cancelRequestedAt = (/* @__PURE__ */ new Date()).toISOString();
4584
+ await datastore.upsertOperation({
4585
+ operation_id: operation.operation_id,
4586
+ type: operation.type,
4587
+ object_id: operation.object_id,
4588
+ quote_id: operation.quote_id,
4589
+ trace_id: traceId,
4590
+ orchestrator: "subagent",
4591
+ subagent_session_id: operation.subagent_session_id,
4592
+ timeout_seconds: operation.timeout_seconds,
4593
+ cancel_requested_at: cancelRequestedAt,
4594
+ status: "running",
4595
+ error_code: null,
4596
+ error_message: null
4597
+ });
4598
+ await emitOperationEventBestEffort(
4599
+ "operation.cancel.requested",
4600
+ {
4601
+ operationId: operation.operation_id,
4602
+ traceId,
4603
+ status: "running",
4604
+ objectId: operation.object_id,
4605
+ quoteId: operation.quote_id,
4606
+ orchestrator: "subagent",
4607
+ subagentSessionId: operation.subagent_session_id,
4608
+ timeoutSeconds: operation.timeout_seconds
4609
+ },
4610
+ objectLogHomeDir
4611
+ );
4612
+ const cancelResult = await subagentOrchestrator.cancel(
4613
+ operation.subagent_session_id,
4614
+ "cancel requested by op-status"
4615
+ );
4616
+ if (cancelResult.accepted || cancelResult.alreadyTerminal) {
4617
+ const afterCancel = await datastore.findOperationById(parsed.operationId);
4618
+ if (afterCancel && !isTerminalOperationStatus(afterCancel.status)) {
4619
+ await datastore.upsertOperation({
4620
+ operation_id: operation.operation_id,
4621
+ type: operation.type,
4622
+ object_id: operation.object_id,
4623
+ quote_id: operation.quote_id,
4624
+ trace_id: traceId,
4625
+ orchestrator: "subagent",
4626
+ subagent_session_id: operation.subagent_session_id,
4627
+ timeout_seconds: operation.timeout_seconds,
4628
+ cancel_requested_at: cancelRequestedAt,
4629
+ status: "cancelled",
4630
+ error_code: "ASYNC_CANCELLED",
4631
+ error_message: "Operation cancelled by user request."
4632
+ });
4633
+ await emitOperationEventBestEffort(
4634
+ "operation.cancelled",
4635
+ {
4636
+ operationId: operation.operation_id,
4637
+ traceId,
4638
+ status: "cancelled",
4639
+ objectId: operation.object_id,
4640
+ quoteId: operation.quote_id,
4641
+ orchestrator: "subagent",
4642
+ subagentSessionId: operation.subagent_session_id,
4643
+ timeoutSeconds: operation.timeout_seconds,
4644
+ errorCode: "ASYNC_CANCELLED",
4645
+ errorMessage: "Operation cancelled by user request."
4646
+ },
4647
+ objectLogHomeDir
4648
+ );
4649
+ }
4650
+ }
4651
+ }
4652
+ operation = await datastore.findOperationById(parsed.operationId);
4653
+ if (!operation) {
4654
+ return {
4655
+ text: `Operation not found: ${parsed.operationId}`,
4656
+ isError: true
4657
+ };
4658
+ }
4659
+ }
4660
+ return formatOperationStatus(operation);
4184
4661
  }
4185
- if ((parsed.mode === "upload" || parsed.mode === "download") && parsed.async) {
4662
+ if ((parsed.mode === "backup" || parsed.mode === "upload" || parsed.mode === "download") && parsed.async) {
4186
4663
  const asyncCorrelation = buildRequestCorrelation();
4187
4664
  const operationId = asyncCorrelation.operationId;
4188
4665
  const opType = parsed.mode;
4189
4666
  const opObject = parsed.mode === "upload" ? parsed.uploadRequest.object_id : null;
4190
4667
  const opQuote = parsed.mode === "upload" ? parsed.uploadRequest.quote_id : null;
4668
+ const orchestratorMode = parsed.orchestrator ?? "inline";
4669
+ const timeoutSeconds = orchestratorMode === "subagent" ? parsed.timeoutSeconds ?? null : null;
4670
+ const eventContextBase = {
4671
+ operationId,
4672
+ traceId: asyncCorrelation.traceId,
4673
+ walletAddress: parsed.mode === "upload" ? parsed.uploadRequest.wallet_address : parsed.mode === "download" ? parsed.storageObjectRequest.wallet_address : null,
4674
+ objectId: opObject,
4675
+ objectKey: parsed.mode === "download" ? parsed.storageObjectRequest.object_key ?? null : null,
4676
+ quoteId: opQuote,
4677
+ orchestrator: orchestratorMode,
4678
+ timeoutSeconds
4679
+ };
4191
4680
  await datastore.upsertOperation({
4192
4681
  operation_id: operationId,
4193
4682
  type: opType,
4194
4683
  object_id: opObject,
4195
4684
  quote_id: opQuote,
4685
+ trace_id: asyncCorrelation.traceId,
4686
+ orchestrator: orchestratorMode,
4687
+ timeout_seconds: timeoutSeconds,
4196
4688
  status: "started",
4197
4689
  error_code: null,
4198
4690
  error_message: null
4199
4691
  });
4200
- const syncArgs = stripAsyncFlag(ctx.args);
4201
- void runCloudCommandHandler({ args: syncArgs }, options, {
4202
- forcedOperationId: asyncCorrelation.operationId,
4203
- forcedTraceId: asyncCorrelation.traceId
4204
- }).then(async (result) => {
4692
+ await emitOperationEventBestEffort(
4693
+ "operation.dispatched",
4694
+ { ...eventContextBase, status: "started" },
4695
+ objectLogHomeDir
4696
+ );
4697
+ const syncArgs = stripAsyncControlFlags(ctx.args);
4698
+ if (orchestratorMode === "subagent") {
4699
+ const subagentTask = {
4700
+ schema: "mnemospark.subagent-task.v1",
4701
+ operationId,
4702
+ traceId: asyncCorrelation.traceId,
4703
+ command: parsed.mode,
4704
+ args: syncArgs,
4705
+ timeoutSeconds: parsed.timeoutSeconds,
4706
+ requestedBy: {
4707
+ pluginCommand: "mnemospark_cloud",
4708
+ chatId: ctx.channel,
4709
+ senderId: ctx.senderId
4710
+ }
4711
+ };
4712
+ try {
4713
+ const dispatchResult = await subagentOrchestrator.dispatch({
4714
+ task: subagentTask,
4715
+ timeoutSeconds: parsed.timeoutSeconds,
4716
+ runTask: async () => runCloudCommandHandler(
4717
+ { args: syncArgs, channel: ctx.channel, senderId: ctx.senderId },
4718
+ options,
4719
+ {
4720
+ forcedOperationId: asyncCorrelation.operationId,
4721
+ forcedTraceId: asyncCorrelation.traceId
4722
+ }
4723
+ ),
4724
+ hooks: {
4725
+ onRunning: async (sessionId) => {
4726
+ await datastore.upsertOperation({
4727
+ operation_id: operationId,
4728
+ type: opType,
4729
+ object_id: opObject,
4730
+ quote_id: opQuote,
4731
+ trace_id: asyncCorrelation.traceId,
4732
+ orchestrator: "subagent",
4733
+ subagent_session_id: sessionId,
4734
+ timeout_seconds: timeoutSeconds,
4735
+ status: "running",
4736
+ error_code: null,
4737
+ error_message: null
4738
+ });
4739
+ await emitOperationEventBestEffort(
4740
+ "operation.progress",
4741
+ {
4742
+ ...eventContextBase,
4743
+ status: "running",
4744
+ subagentSessionId: sessionId,
4745
+ progressMessage: "subagent running"
4746
+ },
4747
+ objectLogHomeDir
4748
+ );
4749
+ },
4750
+ onProgress: async (sessionId, message) => {
4751
+ await emitOperationEventBestEffort(
4752
+ "operation.progress",
4753
+ {
4754
+ ...eventContextBase,
4755
+ status: "running",
4756
+ subagentSessionId: sessionId,
4757
+ progressMessage: message
4758
+ },
4759
+ objectLogHomeDir
4760
+ );
4761
+ },
4762
+ onCompleted: async (sessionId) => {
4763
+ await datastore.upsertOperation({
4764
+ operation_id: operationId,
4765
+ type: opType,
4766
+ object_id: opObject,
4767
+ quote_id: opQuote,
4768
+ trace_id: asyncCorrelation.traceId,
4769
+ orchestrator: "subagent",
4770
+ subagent_session_id: sessionId,
4771
+ timeout_seconds: timeoutSeconds,
4772
+ status: "succeeded",
4773
+ error_code: null,
4774
+ error_message: null
4775
+ });
4776
+ await emitOperationEventBestEffort(
4777
+ "operation.completed",
4778
+ {
4779
+ ...eventContextBase,
4780
+ status: "succeeded",
4781
+ subagentSessionId: sessionId
4782
+ },
4783
+ objectLogHomeDir
4784
+ );
4785
+ },
4786
+ onFailed: async (sessionId, details) => {
4787
+ await datastore.upsertOperation({
4788
+ operation_id: operationId,
4789
+ type: opType,
4790
+ object_id: opObject,
4791
+ quote_id: opQuote,
4792
+ trace_id: asyncCorrelation.traceId,
4793
+ orchestrator: "subagent",
4794
+ subagent_session_id: sessionId,
4795
+ timeout_seconds: timeoutSeconds,
4796
+ status: "failed",
4797
+ error_code: details.code,
4798
+ error_message: details.message
4799
+ });
4800
+ await emitOperationEventBestEffort(
4801
+ "operation.completed",
4802
+ {
4803
+ ...eventContextBase,
4804
+ status: "failed",
4805
+ subagentSessionId: sessionId,
4806
+ errorCode: details.code,
4807
+ errorMessage: details.message
4808
+ },
4809
+ objectLogHomeDir
4810
+ );
4811
+ },
4812
+ onCancelled: async (sessionId, reason) => {
4813
+ await datastore.upsertOperation({
4814
+ operation_id: operationId,
4815
+ type: opType,
4816
+ object_id: opObject,
4817
+ quote_id: opQuote,
4818
+ trace_id: asyncCorrelation.traceId,
4819
+ orchestrator: "subagent",
4820
+ subagent_session_id: sessionId,
4821
+ timeout_seconds: timeoutSeconds,
4822
+ cancel_requested_at: (/* @__PURE__ */ new Date()).toISOString(),
4823
+ status: "cancelled",
4824
+ error_code: "ASYNC_CANCELLED",
4825
+ error_message: reason ?? "Operation cancelled."
4826
+ });
4827
+ await emitOperationEventBestEffort(
4828
+ "operation.cancelled",
4829
+ {
4830
+ ...eventContextBase,
4831
+ status: "cancelled",
4832
+ subagentSessionId: sessionId,
4833
+ errorCode: "ASYNC_CANCELLED",
4834
+ errorMessage: reason ?? "Operation cancelled."
4835
+ },
4836
+ objectLogHomeDir
4837
+ );
4838
+ },
4839
+ onTimedOut: async (sessionId) => {
4840
+ await datastore.upsertOperation({
4841
+ operation_id: operationId,
4842
+ type: opType,
4843
+ object_id: opObject,
4844
+ quote_id: opQuote,
4845
+ trace_id: asyncCorrelation.traceId,
4846
+ orchestrator: "subagent",
4847
+ subagent_session_id: sessionId,
4848
+ timeout_seconds: timeoutSeconds,
4849
+ status: "timed_out",
4850
+ error_code: "ASYNC_TIMEOUT",
4851
+ error_message: "Operation timed out."
4852
+ });
4853
+ await emitOperationEventBestEffort(
4854
+ "operation.timed_out",
4855
+ {
4856
+ ...eventContextBase,
4857
+ status: "timed_out",
4858
+ subagentSessionId: sessionId,
4859
+ errorCode: "ASYNC_TIMEOUT",
4860
+ errorMessage: "Operation timed out."
4861
+ },
4862
+ objectLogHomeDir
4863
+ );
4864
+ }
4865
+ }
4866
+ });
4867
+ const operationAfterDispatch = await datastore.findOperationById(operationId);
4868
+ if (operationAfterDispatch?.subagent_session_id !== dispatchResult.sessionId) {
4869
+ await datastore.upsertOperation({
4870
+ operation_id: operationId,
4871
+ type: opType,
4872
+ object_id: opObject,
4873
+ quote_id: opQuote,
4874
+ trace_id: asyncCorrelation.traceId,
4875
+ orchestrator: "subagent",
4876
+ subagent_session_id: dispatchResult.sessionId,
4877
+ timeout_seconds: timeoutSeconds,
4878
+ status: operationAfterDispatch?.status ?? "started",
4879
+ error_code: operationAfterDispatch?.error_code ?? null,
4880
+ error_message: operationAfterDispatch?.error_message ?? null
4881
+ });
4882
+ }
4883
+ return {
4884
+ text: [
4885
+ `Operation started in background. operation-id: ${operationId}`,
4886
+ `orchestrator: subagent`,
4887
+ `subagent-session-id: ${dispatchResult.sessionId}`,
4888
+ timeoutSeconds ? `timeout-seconds: ${timeoutSeconds}` : null,
4889
+ `Use /mnemospark_cloud op-status --operation-id ${operationId}`
4890
+ ].filter((line) => Boolean(line)).join("\n")
4891
+ };
4892
+ } catch (dispatchError) {
4893
+ const dispatchMessage = dispatchError instanceof Error ? dispatchError.message : String(dispatchError);
4894
+ await datastore.upsertOperation({
4895
+ operation_id: operationId,
4896
+ type: opType,
4897
+ object_id: opObject,
4898
+ quote_id: opQuote,
4899
+ trace_id: asyncCorrelation.traceId,
4900
+ orchestrator: "subagent",
4901
+ timeout_seconds: timeoutSeconds,
4902
+ status: "failed",
4903
+ error_code: "ASYNC_DISPATCH_FAILED",
4904
+ error_message: dispatchMessage
4905
+ });
4906
+ await emitOperationEventBestEffort(
4907
+ "operation.completed",
4908
+ {
4909
+ ...eventContextBase,
4910
+ status: "failed",
4911
+ errorCode: "ASYNC_DISPATCH_FAILED",
4912
+ errorMessage: dispatchMessage
4913
+ },
4914
+ objectLogHomeDir
4915
+ );
4916
+ return {
4917
+ text: `Cannot dispatch subagent operation: ${dispatchMessage}
4918
+ operation-id: ${operationId}`,
4919
+ isError: true
4920
+ };
4921
+ }
4922
+ }
4923
+ await datastore.upsertOperation({
4924
+ operation_id: operationId,
4925
+ type: opType,
4926
+ object_id: opObject,
4927
+ quote_id: opQuote,
4928
+ trace_id: asyncCorrelation.traceId,
4929
+ orchestrator: "inline",
4930
+ status: "running",
4931
+ error_code: null,
4932
+ error_message: null
4933
+ });
4934
+ void runCloudCommandHandler(
4935
+ { args: syncArgs, channel: ctx.channel, senderId: ctx.senderId },
4936
+ options,
4937
+ {
4938
+ forcedOperationId: asyncCorrelation.operationId,
4939
+ forcedTraceId: asyncCorrelation.traceId
4940
+ }
4941
+ ).then(async (result) => {
4205
4942
  await datastore.upsertOperation({
4206
4943
  operation_id: operationId,
4207
4944
  type: opType,
4208
4945
  object_id: opObject,
4209
4946
  quote_id: opQuote,
4947
+ trace_id: asyncCorrelation.traceId,
4948
+ orchestrator: "inline",
4210
4949
  status: result.isError ? "failed" : "succeeded",
4211
4950
  error_code: result.isError ? "ASYNC_FAILED" : null,
4212
4951
  error_message: result.isError ? result.text : null
4213
4952
  });
4953
+ await emitOperationEventBestEffort(
4954
+ "operation.completed",
4955
+ {
4956
+ ...eventContextBase,
4957
+ status: result.isError ? "failed" : "succeeded",
4958
+ errorCode: result.isError ? "ASYNC_FAILED" : null,
4959
+ errorMessage: result.isError ? result.text : null
4960
+ },
4961
+ objectLogHomeDir
4962
+ );
4214
4963
  }).catch(async (err) => {
4964
+ const errorMessage = err instanceof Error ? err.message : String(err);
4215
4965
  await datastore.upsertOperation({
4216
4966
  operation_id: operationId,
4217
4967
  type: opType,
4218
4968
  object_id: opObject,
4219
4969
  quote_id: opQuote,
4970
+ trace_id: asyncCorrelation.traceId,
4971
+ orchestrator: "inline",
4220
4972
  status: "failed",
4221
4973
  error_code: "ASYNC_EXCEPTION",
4222
- error_message: err instanceof Error ? err.message : String(err)
4974
+ error_message: errorMessage
4223
4975
  });
4976
+ await emitOperationEventBestEffort(
4977
+ "operation.completed",
4978
+ {
4979
+ ...eventContextBase,
4980
+ status: "failed",
4981
+ errorCode: "ASYNC_EXCEPTION",
4982
+ errorMessage
4983
+ },
4984
+ objectLogHomeDir
4985
+ );
4224
4986
  });
4225
4987
  return {
4226
- text: `Operation started in background. operation-id: ${operationId}
4227
- Use /mnemospark-cloud op-status --operation-id ${operationId}`
4988
+ text: [
4989
+ `Operation started in background. operation-id: ${operationId}`,
4990
+ `orchestrator: inline`,
4991
+ `Use /mnemospark_cloud op-status --operation-id ${operationId}`
4992
+ ].join("\n")
4228
4993
  };
4229
4994
  }
4230
4995
  if (parsed.mode === "backup") {
@@ -4351,7 +5116,7 @@ Use /mnemospark-cloud op-status --operation-id ${operationId}`
4351
5116
  const loggedQuote = await datastore.findQuoteById(parsed.uploadRequest.quote_id) ?? await findLoggedPriceStorageQuote(parsed.uploadRequest.quote_id, objectLogHomeDir);
4352
5117
  if (!loggedQuote) {
4353
5118
  return {
4354
- text: "Cannot upload storage object: quote-id not found in object.log. Run /mnemospark-cloud price-storage first.",
5119
+ text: "Cannot upload storage object: quote-id not found in object.log. Run /mnemospark_cloud price-storage first.",
4355
5120
  isError: true
4356
5121
  };
4357
5122
  }
@@ -4370,7 +5135,7 @@ Use /mnemospark-cloud op-status --operation-id ${operationId}`
4370
5135
  archiveStats = await stat2(archivePath);
4371
5136
  } catch {
4372
5137
  return {
4373
- text: `Cannot upload storage object: local archive not found at ${archivePath}. Run /mnemospark-cloud backup first.`,
5138
+ text: `Cannot upload storage object: local archive not found at ${archivePath}. Run /mnemospark_cloud backup first.`,
4374
5139
  isError: true
4375
5140
  };
4376
5141
  }
@@ -4503,18 +5268,50 @@ Use /mnemospark-cloud op-status --operation-id ${operationId}`
4503
5268
  status: "active"
4504
5269
  });
4505
5270
  if (parsed.friendlyName?.trim()) {
5271
+ const normalizedFriendlyName = parsed.friendlyName.trim();
4506
5272
  await datastore.upsertFriendlyName({
4507
- friendly_name: parsed.friendlyName.trim(),
5273
+ friendly_name: normalizedFriendlyName,
4508
5274
  object_id: finalizedUploadResponse.object_id,
4509
5275
  object_key: finalizedUploadResponse.object_key,
4510
5276
  quote_id: finalizedUploadResponse.quote_id,
4511
5277
  wallet_address: finalizedUploadResponse.addr
4512
5278
  });
5279
+ let friendlyNameVerified = false;
5280
+ try {
5281
+ const readBack = await datastore.resolveFriendlyName({
5282
+ walletAddress: finalizedUploadResponse.addr,
5283
+ friendlyName: normalizedFriendlyName,
5284
+ latest: true
5285
+ });
5286
+ friendlyNameVerified = Boolean(readBack?.objectKey) && readBack?.objectKey === finalizedUploadResponse.object_key;
5287
+ } catch {
5288
+ friendlyNameVerified = false;
5289
+ }
5290
+ if (!friendlyNameVerified) {
5291
+ const warning = "SQLite friendly-name write verification failed; manifest fallback may be required for --name lookups.";
5292
+ await emitCloudEventBestEffort(
5293
+ "friendly_name.write_verification_failed",
5294
+ {
5295
+ operation_id: uploadCorrelation.operationId,
5296
+ trace_id: uploadCorrelation.traceId,
5297
+ wallet_address: finalizedUploadResponse.addr,
5298
+ object_id: finalizedUploadResponse.object_id,
5299
+ object_key: finalizedUploadResponse.object_key,
5300
+ quote_id: finalizedUploadResponse.quote_id,
5301
+ friendly_name: normalizedFriendlyName,
5302
+ warning
5303
+ },
5304
+ objectLogHomeDir
5305
+ );
5306
+ if (process.env.MNEMOSPARK_SQLITE_STRICT === "1") {
5307
+ throw new Error(warning);
5308
+ }
5309
+ }
4513
5310
  try {
4514
5311
  await appendJsonlEvent(
4515
5312
  "manifest.jsonl",
4516
5313
  {
4517
- friendly_name: parsed.friendlyName.trim(),
5314
+ friendly_name: normalizedFriendlyName,
4518
5315
  object_id: finalizedUploadResponse.object_id,
4519
5316
  object_key: finalizedUploadResponse.object_key,
4520
5317
  quote_id: finalizedUploadResponse.quote_id,
@@ -4567,12 +5364,24 @@ Use /mnemospark-cloud op-status --operation-id ${operationId}`
4567
5364
  const resolved = await resolveNameSelectorIfNeeded(
4568
5365
  datastore,
4569
5366
  parsed.storageObjectRequest,
4570
- parsed.nameSelector
5367
+ parsed.nameSelector,
5368
+ objectLogHomeDir
4571
5369
  );
4572
5370
  if (resolved.error || !resolved.request) {
4573
5371
  return { text: resolved.error ?? "Cannot resolve storage object request.", isError: true };
4574
5372
  }
4575
5373
  const resolvedRequest = resolved.request;
5374
+ if (resolved.degradedWarning) {
5375
+ await emitCloudEventBestEffort(
5376
+ "name_resolution.degraded",
5377
+ {
5378
+ wallet_address: resolvedRequest.wallet_address,
5379
+ object_key: resolvedRequest.object_key,
5380
+ warning: resolved.degradedWarning
5381
+ },
5382
+ objectLogHomeDir
5383
+ );
5384
+ }
4576
5385
  const correlation = buildRequestCorrelation();
4577
5386
  const operationId = correlation.operationId;
4578
5387
  const knownObject = await datastore.findObjectByObjectKey(resolvedRequest.object_key);
@@ -4614,8 +5423,10 @@ Use /mnemospark-cloud op-status --operation-id ${operationId}`
4614
5423
  },
4615
5424
  objectLogHomeDir
4616
5425
  );
5426
+ const lsText = formatStorageLsUserMessage(lsResult, resolvedRequest.object_key);
4617
5427
  return {
4618
- text: formatStorageLsUserMessage(lsResult, resolvedRequest.object_key)
5428
+ text: resolved.degradedWarning ? `${resolved.degradedWarning}
5429
+ ${lsText}` : lsText
4619
5430
  };
4620
5431
  } catch {
4621
5432
  await datastore.upsertOperation({
@@ -4648,12 +5459,24 @@ Use /mnemospark-cloud op-status --operation-id ${operationId}`
4648
5459
  const resolved = await resolveNameSelectorIfNeeded(
4649
5460
  datastore,
4650
5461
  parsed.storageObjectRequest,
4651
- parsed.nameSelector
5462
+ parsed.nameSelector,
5463
+ objectLogHomeDir
4652
5464
  );
4653
5465
  if (resolved.error || !resolved.request) {
4654
5466
  return { text: resolved.error ?? "Cannot resolve storage object request.", isError: true };
4655
5467
  }
4656
5468
  const resolvedRequest = resolved.request;
5469
+ if (resolved.degradedWarning) {
5470
+ await emitCloudEventBestEffort(
5471
+ "name_resolution.degraded",
5472
+ {
5473
+ wallet_address: resolvedRequest.wallet_address,
5474
+ object_key: resolvedRequest.object_key,
5475
+ warning: resolved.degradedWarning
5476
+ },
5477
+ objectLogHomeDir
5478
+ );
5479
+ }
4657
5480
  const correlation = buildRequestCorrelation(
4658
5481
  executionContext.forcedOperationId,
4659
5482
  executionContext.forcedTraceId
@@ -4698,8 +5521,10 @@ Use /mnemospark-cloud op-status --operation-id ${operationId}`
4698
5521
  },
4699
5522
  objectLogHomeDir
4700
5523
  );
5524
+ const downloadText = `File ${resolvedRequest.object_key} downloaded to ${downloadResult.file_path}`;
4701
5525
  return {
4702
- text: `File ${resolvedRequest.object_key} downloaded to ${downloadResult.file_path}`
5526
+ text: resolved.degradedWarning ? `${resolved.degradedWarning}
5527
+ ${downloadText}` : downloadText
4703
5528
  };
4704
5529
  } catch {
4705
5530
  await datastore.upsertOperation({
@@ -4732,12 +5557,24 @@ Use /mnemospark-cloud op-status --operation-id ${operationId}`
4732
5557
  const resolved = await resolveNameSelectorIfNeeded(
4733
5558
  datastore,
4734
5559
  parsed.storageObjectRequest,
4735
- parsed.nameSelector
5560
+ parsed.nameSelector,
5561
+ objectLogHomeDir
4736
5562
  );
4737
5563
  if (resolved.error || !resolved.request) {
4738
5564
  return { text: resolved.error ?? "Cannot resolve storage object request.", isError: true };
4739
5565
  }
4740
5566
  const resolvedRequest = resolved.request;
5567
+ if (resolved.degradedWarning) {
5568
+ await emitCloudEventBestEffort(
5569
+ "name_resolution.degraded",
5570
+ {
5571
+ wallet_address: resolvedRequest.wallet_address,
5572
+ object_key: resolvedRequest.object_key,
5573
+ warning: resolved.degradedWarning
5574
+ },
5575
+ objectLogHomeDir
5576
+ );
5577
+ }
4741
5578
  const correlation = buildRequestCorrelation();
4742
5579
  const operationId = correlation.operationId;
4743
5580
  const existingObjectByKey = await datastore.findObjectByObjectKey(resolvedRequest.object_key);
@@ -4819,12 +5656,14 @@ Use /mnemospark-cloud op-status --operation-id ${operationId}`
4819
5656
  },
4820
5657
  objectLogHomeDir
4821
5658
  );
5659
+ const deleteText = formatStorageDeleteUserMessage(
5660
+ resolvedRequest.object_key,
5661
+ cronEntry?.cronId ?? null,
5662
+ cronDeleted
5663
+ );
4822
5664
  return {
4823
- text: formatStorageDeleteUserMessage(
4824
- resolvedRequest.object_key,
4825
- cronEntry?.cronId ?? null,
4826
- cronDeleted
4827
- )
5665
+ text: resolved.degradedWarning ? `${resolved.degradedWarning}
5666
+ ${deleteText}` : deleteText
4828
5667
  };
4829
5668
  }
4830
5669
  return {
@@ -4942,7 +5781,10 @@ async function startProxyInBackground(api) {
4942
5781
  }
4943
5782
  async function createWalletCommand() {
4944
5783
  return {
4945
- name: "mnemospark-wallet",
5784
+ name: "mnemospark_wallet",
5785
+ nativeNames: {
5786
+ default: "mnemospark_wallet"
5787
+ },
4946
5788
  description: "Show mnemospark wallet info or export private key for backup",
4947
5789
  acceptsArgs: true,
4948
5790
  requireAuth: true,
@@ -5006,8 +5848,8 @@ async function createWalletCommand() {
5006
5848
  `**Key File:** \`${WALLET_FILE}\``,
5007
5849
  "",
5008
5850
  "**Commands:**",
5009
- "\u2022 `/mnemospark-wallet` - Show this status",
5010
- "\u2022 `/mnemospark-wallet export` - Export private key for backup",
5851
+ "\u2022 `/mnemospark_wallet` - Show this status",
5852
+ "\u2022 `/mnemospark_wallet export` - Export private key for backup",
5011
5853
  "",
5012
5854
  `**Fund with USDC on Base:** https://basescan.org/address/${address}`
5013
5855
  ].join("\n")
@@ -5033,14 +5875,14 @@ var plugin = {
5033
5875
  api.registerCommand(walletCommand);
5034
5876
  }).catch((err) => {
5035
5877
  api.logger.warn(
5036
- `Failed to register /mnemospark-wallet command: ${err instanceof Error ? err.message : String(err)}`
5878
+ `Failed to register /mnemospark_wallet command: ${err instanceof Error ? err.message : String(err)}`
5037
5879
  );
5038
5880
  });
5039
5881
  try {
5040
5882
  api.registerCommand(createCloudCommand());
5041
5883
  } catch (err) {
5042
5884
  api.logger.warn(
5043
- `Failed to register /mnemospark-cloud command: ${err instanceof Error ? err.message : String(err)}`
5885
+ `Failed to register /mnemospark_cloud command: ${err instanceof Error ? err.message : String(err)}`
5044
5886
  );
5045
5887
  }
5046
5888
  api.registerService({