@xdarkicex/openclaw-memory-libravdb 1.6.9 → 1.6.11

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.
@@ -42,4 +42,5 @@ export declare function promoteDreamDiaryFile(client: LibravDBClient, opts: {
42
42
  sourceMtimeMs?: number;
43
43
  }): Promise<DreamPromotionResult>;
44
44
  export declare function parseDreamPromotionCandidates(text: string): DreamPromotionCandidate[];
45
+ export declare function normalizeDiaryPath(value?: string): string;
45
46
  export {};
@@ -357,18 +357,23 @@ function parseInteger(value) {
357
357
  function normalizeSectionName(value) {
358
358
  return value.trim().toLowerCase().replace(/\s+/g, " ");
359
359
  }
360
- function normalizeDiaryPath(value) {
360
+ export function normalizeDiaryPath(value) {
361
361
  const trimmed = value?.trim();
362
362
  if (!trimmed) {
363
363
  return "";
364
364
  }
365
+ // Expand ~ to home directory before resolving. path.resolve does not
366
+ // expand tilde, so "~/dreams.md" would resolve to "<cwd>/~/dreams.md".
367
+ const expanded = trimmed.startsWith("~")
368
+ ? path.join(os.homedir(), trimmed.slice(1))
369
+ : trimmed;
365
370
  // Reject traversal components — even though path.resolve collapses them,
366
371
  // their presence signals an attempt to escape intended boundaries.
367
- const segments = trimmed.split(/[/\\]+/);
372
+ const segments = expanded.split(/[/\\]+/);
368
373
  if (segments.some((s) => s === "..")) {
369
374
  throw new Error(`dream diary path must not contain ".." traversal: ${trimmed}`);
370
375
  }
371
- const resolved = path.resolve(trimmed);
376
+ const resolved = path.resolve(expanded);
372
377
  // Restrict to known-safe locations to prevent arbitrary file reads.
373
378
  // Allowed roots: home directory and the configured OpenClaw state dir.
374
379
  const allowedRoots = [
package/dist/index.js CHANGED
@@ -24949,6 +24949,7 @@ function registerMemoryCliMetadata(api) {
24949
24949
  var SESSION_KEY_NAMESPACE_PREFIX = "session-key:";
24950
24950
  var AGENT_ID_NAMESPACE_PREFIX = "agent-id:";
24951
24951
  var USER_COLLECTION_PREFIX = "user:";
24952
+ var RESERVED_NAMESPACE_PREFIXES = [SESSION_KEY_NAMESPACE_PREFIX, AGENT_ID_NAMESPACE_PREFIX, USER_COLLECTION_PREFIX];
24952
24953
  var COLLECTION_NAME_RE = /^[a-zA-Z][a-zA-Z0-9_.:@#-]{0,127}$/;
24953
24954
  function validateNamespace(name) {
24954
24955
  if (!COLLECTION_NAME_RE.test(name)) {
@@ -24960,7 +24961,16 @@ function validateNamespace(name) {
24960
24961
  }
24961
24962
  function resolveDurableNamespace(params) {
24962
24963
  const explicitUserId = firstNonEmpty(params.userId);
24963
- if (explicitUserId) return validateNamespace(explicitUserId);
24964
+ if (explicitUserId) {
24965
+ for (const prefix of RESERVED_NAMESPACE_PREFIXES) {
24966
+ if (explicitUserId.startsWith(prefix)) {
24967
+ throw new Error(
24968
+ `Invalid userId "${explicitUserId}": must not start with reserved prefix "${prefix}"`
24969
+ );
24970
+ }
24971
+ }
24972
+ return validateNamespace(explicitUserId);
24973
+ }
24964
24974
  const sessionKey = firstNonEmpty(params.sessionKey);
24965
24975
  if (sessionKey) return validateNamespace(`${SESSION_KEY_NAMESPACE_PREFIX}${sessionKey}`);
24966
24976
  const agentId = firstNonEmpty(params.agentId);
@@ -25674,13 +25684,14 @@ function normalizeDiaryPath(value) {
25674
25684
  if (!trimmed) {
25675
25685
  return "";
25676
25686
  }
25677
- const segments = trimmed.split(/[/\\]+/);
25687
+ const expanded = trimmed.startsWith("~") ? path.join(os.homedir(), trimmed.slice(1)) : trimmed;
25688
+ const segments = expanded.split(/[/\\]+/);
25678
25689
  if (segments.some((s) => s === "..")) {
25679
25690
  throw new Error(
25680
25691
  `dream diary path must not contain ".." traversal: ${trimmed}`
25681
25692
  );
25682
25693
  }
25683
- const resolved = path.resolve(trimmed);
25694
+ const resolved = path.resolve(expanded);
25684
25695
  const allowedRoots = [
25685
25696
  os.homedir(),
25686
25697
  process.env.OPENCLAW_STATE_DIR
@@ -36786,14 +36797,15 @@ function extractHost(target) {
36786
36797
  const sep = withoutDns.lastIndexOf(":");
36787
36798
  return sep > 0 ? withoutDns.slice(0, sep) : withoutDns;
36788
36799
  }
36789
- function loadSecretFromEnv() {
36800
+ function loadSecretFromEnv(logger) {
36790
36801
  const secret = process.env.LIBRAVDB_AUTH_SECRET?.trim();
36791
36802
  if (secret) return secret;
36792
36803
  const secretPath = process.env.LIBRAVDB_AUTH_SECRET_FILE;
36793
36804
  if (secretPath) {
36794
36805
  try {
36795
36806
  return fs3.readFileSync(secretPath, "utf8").trim() || void 0;
36796
- } catch {
36807
+ } catch (error2) {
36808
+ logger?.warn?.(`LibraVDB: failed to read auth secret file "${secretPath}": ${formatError(error2)}`);
36797
36809
  return void 0;
36798
36810
  }
36799
36811
  }
@@ -1,5 +1,6 @@
1
1
  import type { Interceptor } from "@connectrpc/connect";
2
2
  import type { PartialMessage } from "@bufbuild/protobuf";
3
+ import type { LoggerLike } from "./types.js";
3
4
  import type { AfterTurnKernelRequest, AfterTurnKernelResponse, AssembleContextInternalRequest, AssembleContextInternalResponse, BootstrapSessionKernelRequest, BootstrapSessionKernelResponse, CompactSessionRequest, CompactSessionResponse, DeleteAuthoredDocumentRequest, DeleteAuthoredDocumentResponse, DreamPromotionResponse, ExportMemoryRequest, ExportMemoryResponse, FlushNamespaceRequest, FlushNamespaceResponse, FlushRequest, FlushResponse, HealthRequest, HealthResponse, IngestMarkdownDocumentRequest, IngestMarkdownDocumentResponse, IngestMessageKernelRequest, IngestMessageKernelResponse, ListCollectionRequest, ListCollectionResponse, ListLifecycleJournalRequest, ListLifecycleJournalResponse, MarkMemorySupersededRequest, MarkMemorySupersededResponse, MemoryStatusRequest, MemoryStatusResponse, PromoteDreamEntriesRequest, RankCandidatesRequest, RankCandidatesResponse, RebuildIndexRequest, RebuildIndexResponse, ReindexAuthoredDocumentRequest, ReindexAuthoredDocumentResponse, SearchTextCollectionsRequest, SearchTextRequest, SearchTextResponse, SessionLifecycleHintRequest, SessionLifecycleHintResponse } from "@xdarkicex/libravdb-contracts";
4
5
  export interface LibravDBClientOptions {
5
6
  endpoint?: string;
@@ -56,5 +57,5 @@ export declare class LibravDBClient {
56
57
  rankCandidates(req: PartialMessage<RankCandidatesRequest>): Promise<RankCandidatesResponse>;
57
58
  close(): void;
58
59
  }
59
- export declare function loadSecretFromEnv(): string | undefined;
60
+ export declare function loadSecretFromEnv(logger?: LoggerLike): string | undefined;
60
61
  export {};
@@ -3,6 +3,7 @@ import { createGrpcTransport } from "@connectrpc/connect-node";
3
3
  import { LibravDB } from "@xdarkicex/libravdb-contracts/client";
4
4
  import { createHmac } from "node:crypto";
5
5
  import fs from "node:fs";
6
+ import { formatError } from "./format-error.js";
6
7
  import net from "node:net";
7
8
  import os from "node:os";
8
9
  import path from "node:path";
@@ -279,7 +280,7 @@ function extractHost(target) {
279
280
  const sep = withoutDns.lastIndexOf(":");
280
281
  return sep > 0 ? withoutDns.slice(0, sep) : withoutDns;
281
282
  }
282
- export function loadSecretFromEnv() {
283
+ export function loadSecretFromEnv(logger) {
283
284
  const secret = process.env.LIBRAVDB_AUTH_SECRET?.trim();
284
285
  if (secret)
285
286
  return secret;
@@ -288,7 +289,8 @@ export function loadSecretFromEnv() {
288
289
  try {
289
290
  return fs.readFileSync(secretPath, "utf8").trim() || undefined;
290
291
  }
291
- catch {
292
+ catch (error) {
293
+ logger?.warn?.(`LibraVDB: failed to read auth secret file "${secretPath}": ${formatError(error)}`);
292
294
  return undefined;
293
295
  }
294
296
  }
@@ -1,6 +1,9 @@
1
1
  const SESSION_KEY_NAMESPACE_PREFIX = "session-key:";
2
2
  const AGENT_ID_NAMESPACE_PREFIX = "agent-id:";
3
3
  const USER_COLLECTION_PREFIX = "user:";
4
+ /** Reserved prefixes that must not appear in an explicit userId,
5
+ * to prevent namespace collision with auto-derived namespaces. */
6
+ const RESERVED_NAMESPACE_PREFIXES = [SESSION_KEY_NAMESPACE_PREFIX, AGENT_ID_NAMESPACE_PREFIX, USER_COLLECTION_PREFIX];
4
7
  /** Valid collection names: alphanumeric, underscores, hyphens, dots, colons, at-signs, hashes.
5
8
  * Must start with a letter. Max 128 characters. */
6
9
  const COLLECTION_NAME_RE = /^[a-zA-Z][a-zA-Z0-9_.:@#-]{0,127}$/;
@@ -14,8 +17,14 @@ export function validateNamespace(name) {
14
17
  }
15
18
  export function resolveDurableNamespace(params) {
16
19
  const explicitUserId = firstNonEmpty(params.userId);
17
- if (explicitUserId)
20
+ if (explicitUserId) {
21
+ for (const prefix of RESERVED_NAMESPACE_PREFIXES) {
22
+ if (explicitUserId.startsWith(prefix)) {
23
+ throw new Error(`Invalid userId "${explicitUserId}": must not start with reserved prefix "${prefix}"`);
24
+ }
25
+ }
18
26
  return validateNamespace(explicitUserId);
27
+ }
19
28
  const sessionKey = firstNonEmpty(params.sessionKey);
20
29
  if (sessionKey)
21
30
  return validateNamespace(`${SESSION_KEY_NAMESPACE_PREFIX}${sessionKey}`);
@@ -2,7 +2,7 @@
2
2
  "id": "libravdb-memory",
3
3
  "name": "LibraVDB Memory",
4
4
  "description": "Persistent vector memory with three-tier hybrid scoring",
5
- "version": "1.6.9",
5
+ "version": "1.6.11",
6
6
  "kind": [
7
7
  "memory",
8
8
  "context-engine"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xdarkicex/openclaw-memory-libravdb",
3
- "version": "1.6.9",
3
+ "version": "1.6.11",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",