@revealui/ai 0.1.3 → 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.
Files changed (35) hide show
  1. package/README.md +3 -0
  2. package/dist/ingestion/pipeline.d.ts +2 -1
  3. package/dist/ingestion/pipeline.d.ts.map +1 -1
  4. package/dist/ingestion/pipeline.js +10 -5
  5. package/dist/llm/client.d.ts +12 -2
  6. package/dist/llm/client.d.ts.map +1 -1
  7. package/dist/llm/client.js +35 -6
  8. package/dist/llm/providers/bitnet.d.ts +28 -0
  9. package/dist/llm/providers/bitnet.d.ts.map +1 -0
  10. package/dist/llm/providers/bitnet.js +36 -0
  11. package/dist/llm/semantic-cache.d.ts.map +1 -1
  12. package/dist/llm/semantic-cache.js +4 -4
  13. package/dist/llm/server.d.ts +1 -0
  14. package/dist/llm/server.d.ts.map +1 -1
  15. package/dist/llm/server.js +1 -0
  16. package/dist/memory/persistence/crdt-persistence.d.ts.map +1 -1
  17. package/dist/memory/persistence/crdt-persistence.js +2 -1
  18. package/dist/memory/preferences/user-preferences-manager.d.ts.map +1 -1
  19. package/dist/memory/preferences/user-preferences-manager.js +10 -9
  20. package/dist/memory/stores/episodic-memory.d.ts.map +1 -1
  21. package/dist/memory/stores/episodic-memory.js +2 -1
  22. package/dist/memory/utils/index.d.ts +0 -1
  23. package/dist/memory/utils/index.d.ts.map +1 -1
  24. package/dist/memory/utils/index.js +0 -1
  25. package/dist/memory/vector/vector-memory-service.d.ts +3 -0
  26. package/dist/memory/vector/vector-memory-service.d.ts.map +1 -1
  27. package/dist/memory/vector/vector-memory-service.js +18 -5
  28. package/dist/skills/loader/github-loader.d.ts.map +1 -1
  29. package/dist/skills/loader/github-loader.js +27 -16
  30. package/dist/skills/loader/vercel-loader.d.ts.map +1 -1
  31. package/dist/skills/loader/vercel-loader.js +26 -16
  32. package/package.json +16 -9
  33. package/dist/memory/utils/logger.d.ts +0 -21
  34. package/dist/memory/utils/logger.d.ts.map +0 -1
  35. package/dist/memory/utils/logger.js +0 -62
package/README.md CHANGED
@@ -1,5 +1,8 @@
1
1
  # @revealui/ai
2
2
 
3
+ > **Commercial package** — requires a [RevealUI Pro license](https://revealui.com/pro). Free to install and evaluate; a license key is required for production use.
4
+
5
+
3
6
  AI system for RevealUI - memory, LLM, orchestration, and tools.
4
7
 
5
8
  ## Features
@@ -24,9 +24,10 @@ export interface IngestResult {
24
24
  }
25
25
  export declare class IngestionPipeline {
26
26
  private db;
27
+ private restDb;
27
28
  private embeddingFn;
28
29
  private splitter;
29
- constructor(db: Database, embeddingFn: (text: string) => Promise<number[]>);
30
+ constructor(db: Database, restDb: Database, embeddingFn: (text: string) => Promise<number[]>);
30
31
  ingest(req: IngestRequest): Promise<IngestResult>;
31
32
  ingestBatch(docs: IngestRequest[]): Promise<IngestResult[]>;
32
33
  deleteDocument(documentId: string): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/ingestion/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAMnD,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,gBAAgB,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAA;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAA;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAcD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,EAAE,CAAU;IACpB,OAAO,CAAC,WAAW,CAAqC;IACxD,OAAO,CAAC,QAAQ,CAA4B;gBAEhC,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;IAMpE,MAAM,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IAsEjD,WAAW,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAa3D,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjD,cAAc,CAClB,WAAW,EAAE,MAAM,EACnB,gBAAgB,EAAE,MAAM,EACxB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;CAiBjB"}
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/ingestion/pipeline.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAOnD,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,gBAAgB,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAA;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAA;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAcD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,EAAE,CAAU;IACpB,OAAO,CAAC,MAAM,CAAU;IACxB,OAAO,CAAC,WAAW,CAAqC;IACxD,OAAO,CAAC,QAAQ,CAA4B;gBAEhC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;IAOtF,MAAM,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IA6EjD,WAAW,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAa3D,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjD,cAAc,CAClB,WAAW,EAAE,MAAM,EACnB,gBAAgB,EAAE,MAAM,EACxB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC;CAiBjB"}
@@ -4,12 +4,13 @@
4
4
  * Orchestrates: parse → split → embed → store.
5
5
  * One document produces N chunks, each with a 768-dim embedding.
6
6
  */
7
+ import { safeVectorInsert } from '@revealui/db/validation';
7
8
  import { ragChunks, ragDocuments } from '@revealui/db/schema/rag';
8
9
  import { and, eq } from 'drizzle-orm';
9
10
  import { createParser } from './file-parsers.js';
10
11
  import { RecursiveCharacterSplitter } from './text-splitter.js';
11
12
  function generateId(prefix) {
12
- return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
13
+ return `${prefix}-${crypto.randomUUID()}`;
13
14
  }
14
15
  function estimateWordCount(text) {
15
16
  return text.split(/\s+/).filter((w) => w.length > 0).length;
@@ -19,18 +20,22 @@ function estimateTokens(text) {
19
20
  }
20
21
  export class IngestionPipeline {
21
22
  db;
23
+ restDb;
22
24
  embeddingFn;
23
25
  splitter;
24
- constructor(db, embeddingFn) {
26
+ constructor(db, restDb, embeddingFn) {
25
27
  this.db = db;
28
+ this.restDb = restDb;
26
29
  this.embeddingFn = embeddingFn;
27
30
  this.splitter = new RecursiveCharacterSplitter();
28
31
  }
29
32
  async ingest(req) {
30
33
  const docId = generateId('rdoc');
31
34
  const now = new Date();
32
- // 1. Insert document row with status='processing'
33
- await this.db.insert(ragDocuments).values({
35
+ // 1. Insert document row with status='processing', guarded by cross-DB ref check.
36
+ // safeVectorInsert validates that workspaceId (= site ID) exists in NeonDB before
37
+ // writing to the Supabase vector store, preventing orphaned RAG documents.
38
+ await safeVectorInsert(this.restDb, async () => this.db.insert(ragDocuments).values({
34
39
  id: docId,
35
40
  workspaceId: req.workspaceId,
36
41
  sourceType: req.sourceType,
@@ -44,7 +49,7 @@ export class IngestionPipeline {
44
49
  status: 'processing',
45
50
  createdAt: now,
46
51
  updatedAt: now,
47
- });
52
+ }), { siteId: req.workspaceId });
48
53
  try {
49
54
  // 2. Parse
50
55
  const parser = createParser(req.mimeType ?? 'text/plain');
@@ -12,10 +12,10 @@ export declare function redactSensitiveFields(obj: Record<string, unknown>): Rec
12
12
  import type { Database } from '@revealui/db/client';
13
13
  import type { AuditStore } from '../audit/store.js';
14
14
  import type { ProviderHealthMonitor } from './provider-health.js';
15
- import type { Embedding, LLMChatOptions, LLMChunk, LLMEmbedOptions, LLMResponse, LLMStreamOptions, Message } from './providers/base.js';
15
+ import type { Embedding, LLMChatOptions, LLMChunk, LLMEmbedOptions, LLMProvider, LLMResponse, LLMStreamOptions, Message } from './providers/base.js';
16
16
  import { type CacheStats, type ResponseCacheOptions } from './response-cache.js';
17
17
  import { type SemanticCacheOptions, type SemanticCacheStats } from './semantic-cache.js';
18
- export type LLMProviderType = 'openai' | 'anthropic' | 'vultr' | 'groq' | 'ollama' | 'huggingface' | 'inference-snaps';
18
+ export type LLMProviderType = 'openai' | 'anthropic' | 'vultr' | 'groq' | 'ollama' | 'bitnet' | 'huggingface' | 'inference-snaps';
19
19
  export interface LLMClientConfig {
20
20
  provider: LLMProviderType;
21
21
  apiKey: string;
@@ -27,6 +27,15 @@ export interface LLMClientConfig {
27
27
  apiKeyFn?: () => Promise<string>;
28
28
  baseURL?: string;
29
29
  model?: string;
30
+ /**
31
+ * Dedicated embedding provider. When set, all embed() calls are routed here
32
+ * instead of the primary provider. Required when the primary provider does not
33
+ * support embeddings (e.g. BitNet).
34
+ *
35
+ * Auto-wired by createLLMClientFromEnv() when BITNET_BASE_URL + OLLAMA_BASE_URL
36
+ * are both set.
37
+ */
38
+ embedProvider?: LLMProvider;
30
39
  temperature?: number;
31
40
  maxTokens?: number;
32
41
  fallbackProvider?: LLMProviderType;
@@ -50,6 +59,7 @@ export interface LLMClientConfig {
50
59
  export declare class LLMClient {
51
60
  private provider;
52
61
  private fallbackProvider?;
62
+ private embedProviderOverride?;
53
63
  private config;
54
64
  private rateLimitState;
55
65
  private responseCache?;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/llm/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/llm/client.ts"],"names":[],"mappings":"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"}
@@ -43,6 +43,7 @@ import { decryptApiKey } from '@revealui/db/crypto';
43
43
  import { tenantProviderConfigs, userApiKeys } from '@revealui/db/schema';
44
44
  import { and, eq } from 'drizzle-orm';
45
45
  import { AnthropicProvider } from './providers/anthropic.js';
46
+ import { BitnetProvider } from './providers/bitnet.js';
46
47
  import { GroqProvider } from './providers/groq.js';
47
48
  import { InferenceSnapsProvider, } from './providers/inference-snaps.js';
48
49
  import { OllamaProvider } from './providers/ollama.js';
@@ -54,6 +55,7 @@ import { estimateRequest as _estimateRequestTokens } from './token-counter.js';
54
55
  export class LLMClient {
55
56
  provider;
56
57
  fallbackProvider;
58
+ embedProviderOverride;
57
59
  config;
58
60
  rateLimitState;
59
61
  responseCache;
@@ -79,6 +81,8 @@ export class LLMClient {
79
81
  }
80
82
  // Wire health monitor if provided
81
83
  this.healthMonitor = config.healthMonitor;
84
+ // Wire dedicated embed provider if supplied (e.g. Ollama when BitNet is primary)
85
+ this.embedProviderOverride = config.embedProvider;
82
86
  // Create primary provider
83
87
  this.provider = this.createProvider(config.provider, {
84
88
  apiKey: config.apiKey,
@@ -113,6 +117,8 @@ export class LLMClient {
113
117
  return new GroqProvider(config);
114
118
  case 'ollama':
115
119
  return new OllamaProvider(config);
120
+ case 'bitnet':
121
+ return new BitnetProvider(config);
116
122
  case 'inference-snaps':
117
123
  return new InferenceSnapsProvider(config);
118
124
  default:
@@ -276,13 +282,15 @@ export class LLMClient {
276
282
  if (!this.checkRateLimit()) {
277
283
  throw new Error('Rate limit exceeded');
278
284
  }
285
+ // Use dedicated embed provider if one was configured (e.g. Ollama when BitNet is primary)
286
+ const embedProvider = this.embedProviderOverride ?? this.provider;
279
287
  try {
280
288
  this.recordRequest();
281
- return await this.provider.embed(text, options);
289
+ return await embedProvider.embed(text, options);
282
290
  }
283
291
  catch (error) {
284
- // Try fallback if available
285
- if (this.fallbackProvider) {
292
+ // Try fallback if available (only when using the primary provider path)
293
+ if (!this.embedProviderOverride && this.fallbackProvider) {
286
294
  try {
287
295
  return await this.fallbackProvider.embed(text, options);
288
296
  }
@@ -383,6 +391,9 @@ export function createLLMClientFromEnv() {
383
391
  else if (process.env.INFERENCE_SNAPS_BASE_URL) {
384
392
  provider = 'inference-snaps';
385
393
  }
394
+ else if (process.env.BITNET_BASE_URL) {
395
+ provider = 'bitnet';
396
+ }
386
397
  else if (process.env.GROQ_API_KEY) {
387
398
  provider = 'groq';
388
399
  }
@@ -395,9 +406,10 @@ export function createLLMClientFromEnv() {
395
406
  else {
396
407
  // No provider configured — throw a clear error. OpenAI is intentionally excluded from
397
408
  // auto-detection (no revenue yet). Set LLM_PROVIDER=openai explicitly if needed.
398
- throw new Error('No LLM provider configured. Set one of: INFERENCE_SNAPS_BASE_URL (local snap), ' +
399
- 'GROQ_API_KEY (recommended cloud), OLLAMA_BASE_URL (local Ollama), ' +
400
- 'or ANTHROPIC_API_KEY. Alternatively, set LLM_PROVIDER explicitly.');
409
+ throw new Error('No LLM provider configured. Set one of: BITNET_BASE_URL (local BitNet), ' +
410
+ 'INFERENCE_SNAPS_BASE_URL (local snap), GROQ_API_KEY (recommended cloud), ' +
411
+ 'OLLAMA_BASE_URL (local Ollama), or ANTHROPIC_API_KEY. ' +
412
+ 'Alternatively, set LLM_PROVIDER explicitly.');
401
413
  }
402
414
  let apiKey;
403
415
  let baseURL;
@@ -428,6 +440,11 @@ export function createLLMClientFromEnv() {
428
440
  baseURL = process.env.OLLAMA_BASE_URL;
429
441
  defaultModel = 'llama3.2:3b';
430
442
  }
443
+ else if (provider === 'bitnet') {
444
+ apiKey = 'bitnet'; // llama-server ignores the API key
445
+ baseURL = process.env.BITNET_BASE_URL;
446
+ defaultModel = 'bitnet-b1.58-2B-4T';
447
+ }
431
448
  else if (provider === 'inference-snaps') {
432
449
  apiKey = 'inference-snaps'; // inference-snaps ignores the API key
433
450
  baseURL = process.env.INFERENCE_SNAPS_BASE_URL;
@@ -437,6 +454,17 @@ export function createLLMClientFromEnv() {
437
454
  throw new Error(`API key not found for provider "${provider}". Set the corresponding env var ` +
438
455
  `(INFERENCE_SNAPS_BASE_URL, GROQ_API_KEY, OLLAMA_BASE_URL, ANTHROPIC_API_KEY, or OPENAI_API_KEY).`);
439
456
  }
457
+ // When BitNet is the chat provider, auto-wire Ollama as the embed backend.
458
+ // BitNet does not support /v1/embeddings; Ollama (nomic-embed-text) fills that role.
459
+ // If OLLAMA_BASE_URL is not set, embed() will throw with a helpful message.
460
+ let embedProvider;
461
+ if (provider === 'bitnet' && process.env.OLLAMA_BASE_URL) {
462
+ embedProvider = new OllamaProvider({
463
+ apiKey: 'ollama',
464
+ baseURL: process.env.OLLAMA_BASE_URL,
465
+ embedModel: process.env.OLLAMA_EMBED_MODEL ?? 'nomic-embed-text',
466
+ });
467
+ }
440
468
  return new LLMClient({
441
469
  provider,
442
470
  apiKey,
@@ -449,6 +477,7 @@ export function createLLMClientFromEnv() {
449
477
  process.env.RESPONSE_CACHE_ENABLED === 'true',
450
478
  enableSemanticCache: process.env.LLM_ENABLE_SEMANTIC_CACHE === 'true' ||
451
479
  process.env.SEMANTIC_CACHE_ENABLED === 'true',
480
+ embedProvider,
452
481
  });
453
482
  }
454
483
  /**
@@ -0,0 +1,28 @@
1
+ /**
2
+ * BitNet Provider
3
+ *
4
+ * Local inference via BitNet's OpenAI-compatible llama-server (http://localhost:8080/v1).
5
+ * No API key required. Runs entirely on CPU (AVX2). Zero cost, fully offline.
6
+ *
7
+ * Setup: pnpm bitnet:install (clone + compile + download model)
8
+ * Start: pnpm bitnet:serve (start inference server on :8080)
9
+ *
10
+ * Note: BitNet is a generative model only. It does not expose /v1/embeddings.
11
+ * For vector search, use Ollama (nomic-embed-text) or @xenova/transformers.
12
+ */
13
+ import type { Embedding, LLMChatOptions, LLMChunk, LLMEmbedOptions, LLMProvider, LLMProviderConfig, LLMResponse, LLMStreamOptions, Message } from './base.js';
14
+ export interface BitnetProviderConfig extends Omit<LLMProviderConfig, 'apiKey'> {
15
+ apiKey?: string;
16
+ /** Defaults to http://localhost:8080/v1 */
17
+ baseURL?: string;
18
+ /** Chat model. Defaults to bitnet-b1.58-2B-4T — installed by pnpm bitnet:install */
19
+ model?: string;
20
+ }
21
+ export declare class BitnetProvider implements LLMProvider {
22
+ private inner;
23
+ constructor(config: BitnetProviderConfig);
24
+ chat(messages: Message[], options?: LLMChatOptions): Promise<LLMResponse>;
25
+ stream(messages: Message[], options?: LLMStreamOptions): AsyncIterable<LLMChunk>;
26
+ embed(_text: string | string[], _options?: LLMEmbedOptions): Promise<Embedding | Embedding[]>;
27
+ }
28
+ //# sourceMappingURL=bitnet.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bitnet.d.ts","sourceRoot":"","sources":["../../../src/llm/providers/bitnet.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,SAAS,EACT,cAAc,EACd,QAAQ,EACR,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,WAAW,EACX,gBAAgB,EAChB,OAAO,EACR,MAAM,WAAW,CAAA;AAGlB,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,iBAAiB,EAAE,QAAQ,CAAC;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,2CAA2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,oFAAoF;IACpF,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,qBAAa,cAAe,YAAW,WAAW;IAChD,OAAO,CAAC,KAAK,CAAgB;gBAEjB,MAAM,EAAE,oBAAoB;IAUxC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC;IAIzE,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,aAAa,CAAC,QAAQ,CAAC;IAIhF,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,QAAQ,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,EAAE,CAAC;CAO9F"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * BitNet Provider
3
+ *
4
+ * Local inference via BitNet's OpenAI-compatible llama-server (http://localhost:8080/v1).
5
+ * No API key required. Runs entirely on CPU (AVX2). Zero cost, fully offline.
6
+ *
7
+ * Setup: pnpm bitnet:install (clone + compile + download model)
8
+ * Start: pnpm bitnet:serve (start inference server on :8080)
9
+ *
10
+ * Note: BitNet is a generative model only. It does not expose /v1/embeddings.
11
+ * For vector search, use Ollama (nomic-embed-text) or @xenova/transformers.
12
+ */
13
+ import { OpenAIProvider } from './openai.js';
14
+ export class BitnetProvider {
15
+ inner;
16
+ constructor(config) {
17
+ this.inner = new OpenAIProvider({
18
+ ...config,
19
+ // llama-server ignores the API key but the OpenAI client requires a non-empty value
20
+ apiKey: config.apiKey ?? 'bitnet',
21
+ baseURL: config.baseURL ?? 'http://localhost:8080/v1',
22
+ model: config.model ?? 'bitnet-b1.58-2B-4T',
23
+ });
24
+ }
25
+ chat(messages, options) {
26
+ return this.inner.chat(messages, options);
27
+ }
28
+ stream(messages, options) {
29
+ return this.inner.stream(messages, options);
30
+ }
31
+ embed(_text, _options) {
32
+ throw new Error('BitNet does not support embeddings. Set OLLAMA_BASE_URL to auto-wire Ollama ' +
33
+ '(nomic-embed-text) as the embed backend, or use @xenova/transformers for ' +
34
+ 'fully offline embedding generation.');
35
+ }
36
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"semantic-cache.d.ts","sourceRoot":"","sources":["../../src/llm/semantic-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,MAAM,WAAW,oBAAoB;IACnC,+DAA+D;IAC/D,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,qDAAqD;IACrD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,iDAAiD;IACjD,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE;QACN,YAAY,EAAE,MAAM,CAAA;QACpB,gBAAgB,EAAE,MAAM,CAAA;QACxB,WAAW,EAAE,MAAM,CAAA;KACpB,CAAA;CACF;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,KAAK,CAIZ;IACD,OAAO,CAAC,MAAM,CAAkC;gBAEpC,OAAO,GAAE,oBAAyB;IAiB9C;;;;;OAKG;IACG,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,GAAG,SAAS,CAAC;IAwFrE;;;;;;OAMG;IACG,GAAG,CACP,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE;QACN,YAAY,EAAE,MAAM,CAAA;QACpB,gBAAgB,EAAE,MAAM,CAAA;QACxB,WAAW,EAAE,MAAM,CAAA;KACpB,GACA,OAAO,CAAC,IAAI,CAAC;IAqChB;;;;OAIG;IACH,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM;IAczC;;OAEG;IACH,QAAQ,IAAI,kBAAkB;IAmB9B;;OAEG;IACH,UAAU,IAAI,IAAI;IAQlB;;;;OAIG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAMrC;;;;;;;;;;;;OAYG;IACG,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CAKpF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,kBAAkB,EACzB,OAAO,EAAE;IACP,iBAAiB,EAAE,MAAM,CAAA;IACzB,cAAc,EAAE,MAAM,CAAA;CACvB,GACA;IACD,UAAU,EAAE,MAAM,CAAA;IAClB,cAAc,EAAE,MAAM,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;CACtB,CAUA;AAQD;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,aAAa,CAKpF;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C"}
1
+ {"version":3,"file":"semantic-cache.d.ts","sourceRoot":"","sources":["../../src/llm/semantic-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAKH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAElD,MAAM,WAAW,oBAAoB;IACnC,+DAA+D;IAC/D,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,qDAAqD;IACrD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,iDAAiD;IACjD,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE;QACN,YAAY,EAAE,MAAM,CAAA;QACpB,gBAAgB,EAAE,MAAM,CAAA;QACxB,WAAW,EAAE,MAAM,CAAA;KACpB,CAAA;CACF;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,KAAK,CAIZ;IACD,OAAO,CAAC,MAAM,CAA+C;gBAEjD,OAAO,GAAE,oBAAyB;IAiB9C;;;;;OAKG;IACG,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,GAAG,SAAS,CAAC;IAwFrE;;;;;;OAMG;IACG,GAAG,CACP,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,KAAK,CAAC,EAAE;QACN,YAAY,EAAE,MAAM,CAAA;QACpB,gBAAgB,EAAE,MAAM,CAAA;QACxB,WAAW,EAAE,MAAM,CAAA;KACpB,GACA,OAAO,CAAC,IAAI,CAAC;IAqChB;;;;OAIG;IACH,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM;IAczC;;OAEG;IACH,QAAQ,IAAI,kBAAkB;IAmB9B;;OAEG;IACH,UAAU,IAAI,IAAI;IAQlB;;;;OAIG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAMrC;;;;;;;;;;;;OAYG;IACG,SAAS,CAAC,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CAKpF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,kBAAkB,EACzB,OAAO,EAAE;IACP,iBAAiB,EAAE,MAAM,CAAA;IACzB,cAAc,EAAE,MAAM,CAAA;CACvB,GACA;IACD,UAAU,EAAE,MAAM,CAAA;IAClB,cAAc,EAAE,MAAM,CAAA;IACtB,aAAa,EAAE,MAAM,CAAA;CACtB,CAUA;AAQD;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,aAAa,CAKpF;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C"}
@@ -24,7 +24,7 @@
24
24
  * @see https://redis.io/blog/what-is-semantic-caching/
25
25
  */
26
26
  import { generateEmbedding } from '../embeddings/index.js';
27
- import { createLogger } from '../memory/utils/logger.js';
27
+ import { createLogger } from '@revealui/core/observability/logger';
28
28
  import { VectorMemoryService } from '../memory/vector/vector-memory-service.js';
29
29
  /**
30
30
  * Semantic cache that uses vector similarity for intelligent caching
@@ -50,7 +50,7 @@ export class SemanticCache {
50
50
  vectorService;
51
51
  options;
52
52
  stats;
53
- logger = createLogger('[SemanticCache]');
53
+ logger = createLogger({ component: 'SemanticCache' });
54
54
  constructor(options = {}) {
55
55
  this.vectorService = new VectorMemoryService();
56
56
  this.options = {
@@ -134,7 +134,7 @@ export class SemanticCache {
134
134
  }
135
135
  catch (error) {
136
136
  // Fail gracefully - return undefined on error
137
- this.logger.error('Semantic cache error:', error);
137
+ this.logger.error('Semantic cache error', error instanceof Error ? error : new Error(String(error)));
138
138
  if (this.options.enableStats) {
139
139
  this.stats.misses++;
140
140
  }
@@ -181,7 +181,7 @@ export class SemanticCache {
181
181
  }
182
182
  catch (error) {
183
183
  // Fail gracefully - log error but don't throw
184
- this.logger.error('Failed to store in semantic cache:', error);
184
+ this.logger.error('Failed to store in semantic cache', error instanceof Error ? error : new Error(String(error)));
185
185
  }
186
186
  }
187
187
  /**
@@ -7,6 +7,7 @@
7
7
  export * from './client.js';
8
8
  export * from './providers/anthropic.js';
9
9
  export * from './providers/base.js';
10
+ export * from './providers/bitnet.js';
10
11
  export * from './providers/groq.js';
11
12
  export * from './providers/inference-snaps.js';
12
13
  export * from './providers/ollama.js';
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/llm/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,aAAa,CAAA;AAG3B,cAAc,0BAA0B,CAAA;AACxC,cAAc,qBAAqB,CAAA;AACnC,cAAc,qBAAqB,CAAA;AACnC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,uBAAuB,CAAA;AACrC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/llm/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,aAAa,CAAA;AAG3B,cAAc,0BAA0B,CAAA;AACxC,cAAc,qBAAqB,CAAA;AACnC,cAAc,uBAAuB,CAAA;AACrC,cAAc,qBAAqB,CAAA;AACnC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,uBAAuB,CAAA;AACrC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA"}
@@ -9,6 +9,7 @@ export * from './client.js';
9
9
  // Export provider implementations
10
10
  export * from './providers/anthropic.js';
11
11
  export * from './providers/base.js';
12
+ export * from './providers/bitnet.js';
12
13
  export * from './providers/groq.js';
13
14
  export * from './providers/inference-snaps.js';
14
15
  export * from './providers/ollama.js';
@@ -1 +1 @@
1
- {"version":3,"file":"crdt-persistence.d.ts","sourceRoot":"","sources":["../../../src/memory/persistence/crdt-persistence.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAEnD,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAOjF,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG,QAAQ,GAAG,YAAY,CAAA;AAC/D,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,WAAW,GAAG,WAAW,CAAA;AAEpF,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,QAAQ,CAAA;IAClB,aAAa,EAAE,iBAAiB,CAAA;IAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,CAAC,EAAE,eAAe,CAAC,OAAO,CAAC,CAAA;IACvC,MAAM,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,CAAA;IAC3B,UAAU,CAAC,EAAE,aAAa,CAAA;CAC3B;AAMD;;;;;;GAMG;AACH,qBAAa,eAAe;IACd,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,QAAQ;IAEhC;;;;;;;;;OASG;IACG,aAAa,CACjB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,eAAe,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,aAAa,EACnE,MAAM,GAAE,eAAiC,EACzC,MAAM,GAAE,MAAkB,GACzB,OAAO,CAAC,IAAI,CAAC;IA4ChB;;;;;;OAMG;IACG,aAAa,CACjB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,QAAQ,GACb,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,aAAa,GAAG,IAAI,CAAC;IAiBhF;;;;OAIG;IACG,eAAe,CAAC,SAAS,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAYrE;;;;;;OAMG;IACG,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAiBxF;;;;;;;;OAQG;IACG,kBAAkB,CACtB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,aAAa,CAAC,GACjF,OAAO,CAAC,IAAI,CAAC;IAuChB;;;;;OAKG;IACG,kBAAkB,CACtB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,aAAa,CAAC,CAAC;CAyBvF"}
1
+ {"version":3,"file":"crdt-persistence.d.ts","sourceRoot":"","sources":["../../../src/memory/persistence/crdt-persistence.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAGnD,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAOjF,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG,QAAQ,GAAG,YAAY,CAAA;AAC/D,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,GAAG,WAAW,GAAG,WAAW,CAAA;AAEpF,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,QAAQ,CAAA;IAClB,aAAa,EAAE,iBAAiB,CAAA;IAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,CAAC,EAAE,eAAe,CAAC,OAAO,CAAC,CAAA;IACvC,MAAM,CAAC,EAAE,SAAS,CAAC,OAAO,CAAC,CAAA;IAC3B,UAAU,CAAC,EAAE,aAAa,CAAA;CAC3B;AAMD;;;;;;GAMG;AACH,qBAAa,eAAe;IACd,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,QAAQ;IAEhC;;;;;;;;;OASG;IACG,aAAa,CACjB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,eAAe,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,aAAa,EACnE,MAAM,GAAE,eAAiC,EACzC,MAAM,GAAE,MAAkB,GACzB,OAAO,CAAC,IAAI,CAAC;IA4ChB;;;;;;OAMG;IACG,aAAa,CACjB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,QAAQ,GACb,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,aAAa,GAAG,IAAI,CAAC;IAiBhF;;;;OAIG;IACG,eAAe,CAAC,SAAS,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAYrE;;;;;;OAMG;IACG,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAiBxF;;;;;;;;OAQG;IACG,kBAAkB,CACtB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,aAAa,CAAC,GACjF,OAAO,CAAC,IAAI,CAAC;IAuChB;;;;;OAKG;IACG,kBAAkB,CACtB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,aAAa,CAAC,CAAC;CAyBvF"}
@@ -5,7 +5,8 @@
5
5
  * Supports both state-based (JSONB) and operation-based (operations log) storage.
6
6
  */
7
7
  import { randomUUID } from 'node:crypto';
8
- import { agentContexts, and, crdtOperations, eq, gte } from '@revealui/db/schema';
8
+ import { and, eq, gte } from 'drizzle-orm';
9
+ import { agentContexts, crdtOperations } from '@revealui/db/schema';
9
10
  import { findAgentContextById } from '../utils/sql-helpers.js';
10
11
  // =============================================================================
11
12
  // CRDT Persistence
@@ -1 +1 @@
1
- {"version":3,"file":"user-preferences-manager.d.ts","sourceRoot":"","sources":["../../../src/memory/preferences/user-preferences-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AAEnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAEnD,OAAO,EAAe,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAgB3E;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,EAAE,CAAU;IACpB,OAAO,CAAC,MAAM,CAAoC;IAElD;;;;;;OAMG;gBACS,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ;IAcxD;;;;OAIG;IACH,cAAc,IAAI,eAAe;IAIjC;;;;;OAKG;IACH,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI;IAsB1D;;;;OAIG;IACH,cAAc,CAAC,WAAW,EAAE,eAAe,GAAG,IAAI;IAUlD;;;;;OAKG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAgBnC;;;;;OAKG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAiChD;;;;;;OAMG;IACH,KAAK,CAAC,KAAK,EAAE,sBAAsB,GAAG,sBAAsB;IAM5D;;;;;;;;OAQG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAiF3B;;;;;;;;OAQG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA6E3B;;;;OAIG;IACH,MAAM,IAAI,eAAe,CAAC,eAAe,CAAC;IAI1C;;;;;;;;OAQG;IACH,MAAM,CAAC,QAAQ,CACb,IAAI,EAAE,eAAe,CAAC,eAAe,CAAC,EACtC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,QAAQ,GACX,sBAAsB;IAMzB;;;;OAIG;IACH,KAAK,IAAI,sBAAsB;IAI/B;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,SAAS,IAAI,MAAM;CAGpB"}
1
+ {"version":3,"file":"user-preferences-manager.d.ts","sourceRoot":"","sources":["../../../src/memory/preferences/user-preferences-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AAEnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAGnD,OAAO,EAAe,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAgB3E;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,EAAE,CAAU;IACpB,OAAO,CAAC,MAAM,CAAiD;IAE/D;;;;;;OAMG;gBACS,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ;IAcxD;;;;OAIG;IACH,cAAc,IAAI,eAAe;IAIjC;;;;;OAKG;IACH,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI;IAsB1D;;;;OAIG;IACH,cAAc,CAAC,WAAW,EAAE,eAAe,GAAG,IAAI;IAUlD;;;;;OAKG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAgBnC;;;;;OAKG;IACH,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAiChD;;;;;;OAMG;IACH,KAAK,CAAC,KAAK,EAAE,sBAAsB,GAAG,sBAAsB;IAM5D;;;;;;;;OAQG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAoF3B;;;;;;;;OAQG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAgF3B;;;;OAIG;IACH,MAAM,IAAI,eAAe,CAAC,eAAe,CAAC;IAI1C;;;;;;;;OAQG;IACH,MAAM,CAAC,QAAQ,CACb,IAAI,EAAE,eAAe,CAAC,eAAe,CAAC,EACtC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,QAAQ,GACX,sBAAsB;IAMzB;;;;OAIG;IACH,KAAK,IAAI,sBAAsB;IAI/B;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,SAAS,IAAI,MAAM;CAGpB"}
@@ -5,11 +5,12 @@
5
5
  * from multiple devices. Uses LWWRegister for last-writer-wins semantics.
6
6
  */
7
7
  import { UserPreferencesSchema } from '@revealui/contracts/entities';
8
- import { eq, users } from '@revealui/db/schema';
8
+ import { eq } from 'drizzle-orm';
9
+ import { users } from '@revealui/db/schema';
9
10
  import { LWWRegister } from '../crdt/lww-register.js';
10
11
  import { DatabaseConnectionError, DatabaseConstraintError, DatabaseOperationError, NotFoundError, ValidationError, } from '../errors/index.js';
11
12
  import { deepClone } from '../utils/deep-clone.js';
12
- import { createLogger } from '../utils/logger.js';
13
+ import { createLogger } from '@revealui/core/observability/logger';
13
14
  import { findUserById } from '../utils/sql-helpers.js';
14
15
  // =============================================================================
15
16
  // User Preferences Manager
@@ -36,7 +37,7 @@ export class UserPreferencesManager {
36
37
  userId;
37
38
  nodeId;
38
39
  db;
39
- logger = createLogger('[UserPreferences]');
40
+ logger = createLogger({ component: 'UserPreferences' });
40
41
  /**
41
42
  * Creates a new UserPreferencesManager.
42
43
  *
@@ -217,18 +218,18 @@ export class UserPreferencesManager {
217
218
  errorMessage.includes('timeout') ||
218
219
  errorMessage.includes('econnrefused') ||
219
220
  errorMessage.includes('connect econnrefused')) {
220
- this.logger.error(`Database connection error loading preferences for user ${this.userId}:`, error);
221
+ this.logger.error(`Database connection error loading preferences for user ${this.userId}`, error);
221
222
  throw new DatabaseConnectionError('Failed to load user preferences', error);
222
223
  }
223
224
  if (errorMessage.includes('violates') ||
224
225
  errorMessage.includes('constraint') ||
225
226
  errorMessage.includes('foreign key')) {
226
- this.logger.error(`Database constraint error loading preferences for user ${this.userId}:`, error);
227
+ this.logger.error(`Database constraint error loading preferences for user ${this.userId}`, error);
227
228
  throw new DatabaseConstraintError('Failed to load user preferences', error);
228
229
  }
229
230
  }
230
231
  // Generic database operation error
231
- this.logger.error(`Failed to load preferences for user ${this.userId}:`, error);
232
+ this.logger.error(`Failed to load preferences for user ${this.userId}`, error instanceof Error ? error : new Error(String(error)));
232
233
  throw new DatabaseOperationError('Failed to load user preferences', error instanceof Error ? error : new Error(String(error)));
233
234
  }
234
235
  }
@@ -281,19 +282,19 @@ export class UserPreferencesManager {
281
282
  errorMessage.includes('timeout') ||
282
283
  errorMessage.includes('econnrefused') ||
283
284
  errorMessage.includes('connect econnrefused')) {
284
- this.logger.error(`Database connection error saving preferences for user ${this.userId}:`, error);
285
+ this.logger.error(`Database connection error saving preferences for user ${this.userId}`, error);
285
286
  throw new DatabaseConnectionError('Failed to save user preferences', error);
286
287
  }
287
288
  if (errorMessage.includes('violates') ||
288
289
  errorMessage.includes('constraint') ||
289
290
  errorMessage.includes('foreign key') ||
290
291
  errorMessage.includes('duplicate')) {
291
- this.logger.error(`Database constraint error saving preferences for user ${this.userId}:`, error);
292
+ this.logger.error(`Database constraint error saving preferences for user ${this.userId}`, error);
292
293
  throw new DatabaseConstraintError('Failed to save user preferences', error);
293
294
  }
294
295
  }
295
296
  // Generic database operation error
296
- this.logger.error(`Failed to save preferences for user ${this.userId}:`, error);
297
+ this.logger.error(`Failed to save preferences for user ${this.userId}`, error instanceof Error ? error : new Error(String(error)));
297
298
  throw new DatabaseOperationError('Failed to save user preferences', error instanceof Error ? error : new Error(String(error)));
298
299
  }
299
300
  }
@@ -1 +1 @@
1
- {"version":3,"file":"episodic-memory.d.ts","sourceRoot":"","sources":["../../../src/memory/stores/episodic-memory.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAE7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAGnD,OAAO,EAAS,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,EAAa,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAA;AACzE,OAAO,EAAuB,KAAK,mBAAmB,EAAE,MAAM,oCAAoC,CAAA;AAMlG,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,CAAA;IAC3B,aAAa,EAAE,aAAa,CAAA;CAC7B;AAMD;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,aAAa,CAAW;IAChC,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,EAAE,CAAU;IACpB,OAAO,CAAC,WAAW,CAAC,CAAiB;IACrC,OAAO,CAAC,WAAW,CAAsC;IACzD,OAAO,CAAC,aAAa,CAAqB;IAE1C;;;;;;;OAOG;gBACS,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,eAAe;IAYvF;;;;;;OAMG;IACG,GAAG,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IA+B/C;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAU5B;;;;;;OAMG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAqBnD;;;;OAIG;IACH,YAAY,IAAI,MAAM,EAAE;IAIxB;;;;OAIG;IACG,MAAM,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAwBtC;;;;;OAKG;IACG,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAuBxD;;;;;;;;;;OAUG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;IAgBhF;;;;OAIG;IACG,eAAe,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBvD;;;;OAIG;IACH,cAAc,IAAI,MAAM;IAIxB;;;;;;OAMG;IACG,MAAM,CACV,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,IAAI,CAAC,mBAAmB,EAAE,QAAQ,CAAM,GAChD,OAAO,CAAC,WAAW,EAAE,CAAC;IAsBzB;;;;;OAKG;IACH,KAAK,CAAC,KAAK,EAAE,cAAc,GAAG,cAAc;IAO5C;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA4B3B;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAc3B;;;;OAIG;IACH,MAAM,IAAI,kBAAkB;IAS5B;;;;;;;OAOG;IACH,MAAM,CAAC,QAAQ,CACb,IAAI,EAAE,kBAAkB,EACxB,EAAE,EAAE,QAAQ,EACZ,WAAW,CAAC,EAAE,eAAe,GAC5B,cAAc;IAOjB;;;;OAIG;IACH,KAAK,IAAI,cAAc;IAIvB;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,SAAS,IAAI,MAAM;CAGpB"}
1
+ {"version":3,"file":"episodic-memory.d.ts","sourceRoot":"","sources":["../../../src/memory/stores/episodic-memory.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAE7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAGnD,OAAO,EAAS,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAA;AACzD,OAAO,EAAa,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAA;AACzE,OAAO,EAAuB,KAAK,mBAAmB,EAAE,MAAM,oCAAoC,CAAA;AAMlG,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,CAAA;IAC3B,aAAa,EAAE,aAAa,CAAA;CAC7B;AAMD;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,aAAa,CAAW;IAChC,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,EAAE,CAAU;IACpB,OAAO,CAAC,WAAW,CAAC,CAAiB;IACrC,OAAO,CAAC,WAAW,CAAsC;IACzD,OAAO,CAAC,aAAa,CAAqB;IAE1C;;;;;;;OAOG;gBACS,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,eAAe;IAYvF;;;;;;OAMG;IACG,GAAG,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IA+B/C;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAU5B;;;;;;OAMG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAqBnD;;;;OAIG;IACH,YAAY,IAAI,MAAM,EAAE;IAIxB;;;;OAIG;IACG,MAAM,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAwBtC;;;;;OAKG;IACG,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAuBxD;;;;;;;;;;OAUG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC;IAgBhF;;;;OAIG;IACG,eAAe,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBvD;;;;OAIG;IACH,cAAc,IAAI,MAAM;IAIxB;;;;;;OAMG;IACG,MAAM,CACV,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,IAAI,CAAC,mBAAmB,EAAE,QAAQ,CAAM,GAChD,OAAO,CAAC,WAAW,EAAE,CAAC;IAuBzB;;;;;OAKG;IACH,KAAK,CAAC,KAAK,EAAE,cAAc,GAAG,cAAc;IAO5C;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA4B3B;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAc3B;;;;OAIG;IACH,MAAM,IAAI,kBAAkB;IAS5B;;;;;;;OAOG;IACH,MAAM,CAAC,QAAQ,CACb,IAAI,EAAE,kBAAkB,EACxB,EAAE,EAAE,QAAQ,EACZ,WAAW,CAAC,EAAE,eAAe,GAC5B,cAAc;IAOjB;;;;OAIG;IACH,KAAK,IAAI,cAAc;IAIvB;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,SAAS,IAAI,MAAM;CAGpB"}
@@ -266,10 +266,11 @@ export class EpisodicMemory {
266
266
  // Return memories sorted by similarity
267
267
  return results.map((r) => r.memory);
268
268
  }
269
- catch (_error) {
269
+ catch (error) {
270
270
  // Embedding generation failed (e.g. embedding service unavailable).
271
271
  // Return empty results — do NOT fall back to getAll(), which would dump the
272
272
  // entire memory store into agent context regardless of relevance.
273
+ void (error instanceof Error ? error.message : String(error)); // Semantic search failed — return empty results
273
274
  return [];
274
275
  }
275
276
  }
@@ -2,7 +2,6 @@
2
2
  * Utility functions
3
3
  */
4
4
  export { deepClone } from './deep-clone.js';
5
- export { createLogger, defaultLogger, type Logger } from './logger.js';
6
5
  export { findAgentContextById, findAgentMemoriesByUserId, findAgentMemoryById, findNodeIdMappingByEntity, findNodeIdMappingByHash, findUserById, } from './sql-helpers.js';
7
6
  export { estimateObjectSize, hasCircularReference, validateContext, validateContextKey, validateContextSize, validateContextValue, validateObjectDepth, } from './validation.js';
8
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/memory/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAA;AACtE,OAAO,EACL,oBAAoB,EACpB,yBAAyB,EACzB,mBAAmB,EACnB,yBAAyB,EACzB,uBAAuB,EACvB,YAAY,GACb,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,iBAAiB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/memory/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EACL,oBAAoB,EACpB,yBAAyB,EACzB,mBAAmB,EACnB,yBAAyB,EACzB,uBAAuB,EACvB,YAAY,GACb,MAAM,kBAAkB,CAAA;AACzB,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,iBAAiB,CAAA"}
@@ -2,6 +2,5 @@
2
2
  * Utility functions
3
3
  */
4
4
  export { deepClone } from './deep-clone.js';
5
- export { createLogger, defaultLogger } from './logger.js';
6
5
  export { findAgentContextById, findAgentMemoriesByUserId, findAgentMemoryById, findNodeIdMappingByEntity, findNodeIdMappingByHash, findUserById, } from './sql-helpers.js';
7
6
  export { estimateObjectSize, hasCircularReference, validateContext, validateContextKey, validateContextSize, validateContextValue, validateObjectDepth, } from './validation.js';
@@ -30,11 +30,14 @@ export interface VectorSearchResult {
30
30
  */
31
31
  export declare class VectorMemoryService {
32
32
  private _db;
33
+ private _restDb;
33
34
  /**
34
35
  * Lazy-load database client to avoid connection initialization at module import time.
35
36
  * This allows the module to be imported in test environments without triggering database connections.
36
37
  */
37
38
  private get db();
39
+ /** Lazy-load REST client for cross-DB reference validation. */
40
+ private get restDb();
38
41
  /**
39
42
  * Search for similar memories using vector similarity.
40
43
  *
@@ -1 +1 @@
1
- {"version":3,"file":"vector-memory-service.d.ts","sourceRoot":"","sources":["../../../src/memory/vector/vector-memory-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAK7D,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,WAAW,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED;;GAEG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,GAAG,CAAkD;IAE7D;;;OAGG;IACH,OAAO,KAAK,EAAE,GAKb;IAED;;;;;;;;;;;;;;;;OAgBG;IACG,aAAa,CACjB,cAAc,EAAE,MAAM,EAAE,EACxB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,kBAAkB,EAAE,CAAC;IA2GhC;;;;;OAKG;IACG,MAAM,CACV,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,WAAW,GAAG,YAAY,CAAC,GAAG;QAC7D,EAAE,CAAC,EAAE,MAAM,CAAA;KACZ,GACA,OAAO,CAAC,WAAW,CAAC;IAmEvB;;;;;;OAMG;IACG,MAAM,CACV,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,WAAW,CAAC,CAAC,GACtD,OAAO,CAAC,WAAW,CAAC;IAyEvB;;;;;OAKG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK1C;;;;;OAKG;IACG,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;CA8CvD"}
1
+ {"version":3,"file":"vector-memory-service.d.ts","sourceRoot":"","sources":["../../../src/memory/vector/vector-memory-service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAM7D,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,WAAW,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED;;GAEG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,GAAG,CAAkD;IAC7D,OAAO,CAAC,OAAO,CAAgD;IAE/D;;;OAGG;IACH,OAAO,KAAK,EAAE,GAKb;IAED,+DAA+D;IAC/D,OAAO,KAAK,MAAM,GAKjB;IAED;;;;;;;;;;;;;;;;OAgBG;IACG,aAAa,CACjB,cAAc,EAAE,MAAM,EAAE,EACxB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,kBAAkB,EAAE,CAAC;IA2GhC;;;;;OAKG;IACG,MAAM,CACV,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,WAAW,GAAG,YAAY,CAAC,GAAG;QAC7D,EAAE,CAAC,EAAE,MAAM,CAAA;KACZ,GACA,OAAO,CAAC,WAAW,CAAC;IA4EvB;;;;;;OAMG;IACG,MAAM,CACV,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,WAAW,CAAC,CAAC,GACtD,OAAO,CAAC,WAAW,CAAC;IAyEvB;;;;;OAKG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK1C;;;;;OAKG;IACG,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;CA8CvD"}
@@ -12,7 +12,8 @@
12
12
  * const memories = await service.searchSimilar(embedding, { siteId: 'site-123', limit: 10 })
13
13
  * ```
14
14
  */
15
- import { getVectorClient } from '@revealui/db/client';
15
+ import { getRestClient, getVectorClient } from '@revealui/db/client';
16
+ import { safeVectorInsert } from '@revealui/db/validation';
16
17
  import { agentMemories } from '@revealui/db/schema/vector';
17
18
  import { and, eq, sql } from 'drizzle-orm';
18
19
  /**
@@ -20,6 +21,7 @@ import { and, eq, sql } from 'drizzle-orm';
20
21
  */
21
22
  export class VectorMemoryService {
22
23
  _db = null;
24
+ _restDb = null;
23
25
  /**
24
26
  * Lazy-load database client to avoid connection initialization at module import time.
25
27
  * This allows the module to be imported in test environments without triggering database connections.
@@ -30,6 +32,13 @@ export class VectorMemoryService {
30
32
  }
31
33
  return this._db;
32
34
  }
35
+ /** Lazy-load REST client for cross-DB reference validation. */
36
+ get restDb() {
37
+ if (!this._restDb) {
38
+ this._restDb = getRestClient();
39
+ }
40
+ return this._restDb;
41
+ }
33
42
  /**
34
43
  * Search for similar memories using vector similarity.
35
44
  *
@@ -146,12 +155,16 @@ export class VectorMemoryService {
146
155
  * @returns Created memory with generated id and timestamps
147
156
  */
148
157
  async create(memory) {
149
- const id = memory.id || `mem-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
158
+ const id = memory.id || crypto.randomUUID();
150
159
  const now = new Date();
151
160
  // Pass embedding vector directly - Drizzle's vector type will handle conversion
152
161
  // The vector custom type has toDriver() that converts number[] to string format
153
162
  const embeddingVector = memory.embedding?.vector || null;
154
- const result = await this.db
163
+ const siteId = memory.metadata?.siteId;
164
+ if (!siteId) {
165
+ throw new Error('siteId is required to create an agent memory');
166
+ }
167
+ const result = await safeVectorInsert(this.restDb, async () => this.db
155
168
  .insert(agentMemories)
156
169
  .values({
157
170
  id,
@@ -167,12 +180,12 @@ export class VectorMemoryService {
167
180
  verified: memory.verified,
168
181
  verifiedBy: null, // Can be set via update
169
182
  verifiedAt: null,
170
- siteId: memory.metadata?.siteId || null,
183
+ siteId,
171
184
  agentId: memory.metadata?.custom?.agentId || null,
172
185
  createdAt: now,
173
186
  expiresAt: memory.metadata?.expiresAt ? new Date(memory.metadata.expiresAt) : null,
174
187
  })
175
- .returning();
188
+ .returning(), { siteId: siteId ?? undefined });
176
189
  const row = result[0];
177
190
  if (!row) {
178
191
  throw new Error('Failed to create memory');
@@ -1 +1 @@
1
- {"version":3,"file":"github-loader.d.ts","sourceRoot":"","sources":["../../../src/skills/loader/github-loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAIxC;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CA+B9D;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAA;IAEjB,uCAAuC;IACvC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAAA;IAEzB,sCAAsC;IACtC,QAAQ,EAAE,aAAa,CAAA;IAEvB,6CAA6C;IAC7C,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAE3B,wCAAwC;IACxC,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,KAAK,CAAC,CA8D/F;AAwDD;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAS5B;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAW3E"}
1
+ {"version":3,"file":"github-loader.d.ts","sourceRoot":"","sources":["../../../src/skills/loader/github-loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAaxC;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CA+B9D;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAA;IAEjB,uCAAuC;IACvC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAAA;IAEzB,sCAAsC;IACtC,QAAQ,EAAE,aAAa,CAAA;IAEvB,6CAA6C;IAC7C,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAE3B,wCAAwC;IACxC,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,KAAK,CAAC,CA8D/F;AA2DD;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAS5B;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAY3E"}
@@ -3,12 +3,19 @@
3
3
  *
4
4
  * Install skills from GitHub repositories.
5
5
  */
6
- import { exec } from 'node:child_process';
6
+ import { execFile } from 'node:child_process';
7
7
  import * as fs from 'node:fs';
8
8
  import * as path from 'node:path';
9
9
  import { promisify } from 'node:util';
10
10
  import { parseSkillMd } from '../parser/index.js';
11
- const execAsync = promisify(exec);
11
+ const execFileAsync = promisify(execFile);
12
+ /** Validate shell-unsafe characters in git arguments (R4-C1 fix) */
13
+ const SAFE_GIT_ARG = /^[a-zA-Z0-9._\-/]+$/;
14
+ function validateGitArg(value, name) {
15
+ if (!SAFE_GIT_ARG.test(value)) {
16
+ throw new Error(`Invalid ${name}: "${value}". Only alphanumeric, dots, hyphens, underscores, and slashes allowed.`);
17
+ }
18
+ }
12
19
  /**
13
20
  * Parse a GitHub source string into components.
14
21
  *
@@ -109,19 +116,17 @@ export async function loadFromGitHub(source, options) {
109
116
  * Perform a sparse checkout for a specific path.
110
117
  */
111
118
  async function sparseClone(repoUrl, targetPath, subPath, ref) {
112
- // Create a temp directory for the sparse checkout
119
+ validateGitArg(subPath, 'subPath');
120
+ if (ref)
121
+ validateGitArg(ref, 'ref');
113
122
  const tempDir = `${targetPath}.tmp`;
114
123
  try {
115
- // Initialize sparse checkout
116
- await execAsync(`git clone --depth 1 --filter=blob:none --sparse ${repoUrl} ${tempDir}`);
117
- // Configure sparse checkout
118
- await execAsync(`git -C ${tempDir} sparse-checkout set ${subPath}`);
119
- // Checkout specific ref if provided
124
+ await execFileAsync('git', ['clone', '--depth', '1', '--filter=blob:none', '--sparse', repoUrl, tempDir]);
125
+ await execFileAsync('git', ['-C', tempDir, 'sparse-checkout', 'set', subPath]);
120
126
  if (ref) {
121
- await execAsync(`git -C ${tempDir} fetch --depth 1 origin ${ref}`);
122
- await execAsync(`git -C ${tempDir} checkout ${ref}`);
127
+ await execFileAsync('git', ['-C', tempDir, 'fetch', '--depth', '1', 'origin', ref]);
128
+ await execFileAsync('git', ['-C', tempDir, 'checkout', ref]);
123
129
  }
124
- // Move the skill directory to target
125
130
  const sourcePath = path.join(tempDir, subPath);
126
131
  if (!fs.existsSync(sourcePath)) {
127
132
  throw new Error(`Path "${subPath}" not found in repository`);
@@ -129,7 +134,6 @@ async function sparseClone(repoUrl, targetPath, subPath, ref) {
129
134
  fs.renameSync(sourcePath, targetPath);
130
135
  }
131
136
  finally {
132
- // Clean up temp directory
133
137
  if (fs.existsSync(tempDir)) {
134
138
  fs.rmSync(tempDir, { recursive: true });
135
139
  }
@@ -139,8 +143,14 @@ async function sparseClone(repoUrl, targetPath, subPath, ref) {
139
143
  * Perform a full shallow clone.
140
144
  */
141
145
  async function fullClone(repoUrl, targetPath, ref) {
142
- const refArg = ref ? `--branch ${ref}` : '';
143
- await execAsync(`git clone --depth 1 ${refArg} ${repoUrl} ${targetPath}`);
146
+ if (ref)
147
+ validateGitArg(ref, 'ref');
148
+ const args = ['clone', '--depth', '1'];
149
+ if (ref) {
150
+ args.push('--branch', ref);
151
+ }
152
+ args.push(repoUrl, targetPath);
153
+ await execFileAsync('git', args);
144
154
  // Remove .git directory to save space
145
155
  const gitDir = path.join(targetPath, '.git');
146
156
  if (fs.existsSync(gitDir)) {
@@ -165,9 +175,10 @@ export async function updateFromGitHub(skillName, registry) {
165
175
  export async function validateGitHubSource(source) {
166
176
  try {
167
177
  const parsed = parseGitHubSource(source);
178
+ validateGitArg(parsed.owner, 'owner');
179
+ validateGitArg(parsed.repo, 'repo');
168
180
  const repoUrl = `https://github.com/${parsed.owner}/${parsed.repo}.git`;
169
- // Use git ls-remote to check if repo exists
170
- await execAsync(`git ls-remote --exit-code ${repoUrl} HEAD`);
181
+ await execFileAsync('git', ['ls-remote', '--exit-code', repoUrl, 'HEAD']);
171
182
  return true;
172
183
  }
173
184
  catch {
@@ -1 +1 @@
1
- {"version":3,"file":"vercel-loader.d.ts","sourceRoot":"","sources":["../../../src/skills/loader/vercel-loader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,KAAK,EACV,UAAU,EAIX,MAAM,mBAAmB,CAAA;AAK1B;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAA;IAEjB,uCAAuC;IACvC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAAA;IAEzB,sCAAsC;IACtC,QAAQ,EAAE,aAAa,CAAA;IAEvB,6CAA6C;IAC7C,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAE3B,wCAAwC;IACxC,KAAK,CAAC,EAAE,OAAO,CAAA;IAEf,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,KAAK,CAAC,CA8EhB;AAsKD;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,UAAU,CAAC,CAyCrB;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,KAAK,CAAC,CAwBhB;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC,CAO7D"}
1
+ {"version":3,"file":"vercel-loader.d.ts","sourceRoot":"","sources":["../../../src/skills/loader/vercel-loader.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,KAAK,EACV,UAAU,EAIX,MAAM,mBAAmB,CAAA;AAc1B;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAA;IAEjB,uCAAuC;IACvC,KAAK,EAAE,OAAO,GAAG,QAAQ,CAAA;IAEzB,sCAAsC;IACtC,QAAQ,EAAE,aAAa,CAAA;IAEvB,6CAA6C;IAC7C,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAE3B,wCAAwC;IACxC,KAAK,CAAC,EAAE,OAAO,CAAA;IAEf,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,KAAK,CAAC,CA8EhB;AAwKD;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,UAAU,CAAC,CAyCrB;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,KAAK,CAAC,CAwBhB;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC,CAO7D"}
@@ -4,14 +4,21 @@
4
4
  * Bridge layer to load skills from the Vercel Skills ecosystem (skills.sh)
5
5
  * and convert them to RevealUI's format.
6
6
  */
7
- import { exec } from 'node:child_process';
7
+ import { execFile } from 'node:child_process';
8
8
  import * as fs from 'node:fs';
9
9
  import * as path from 'node:path';
10
10
  import { promisify } from 'node:util';
11
11
  import { logger } from '@revealui/core/observability/logger';
12
12
  import { parseSkillMd } from '../parser/index.js';
13
13
  import { parseVercelSource } from './vercel-types.js';
14
- const execAsync = promisify(exec);
14
+ const execFileAsync = promisify(execFile);
15
+ /** Validate shell-unsafe characters in git arguments (R4-C1 fix) */
16
+ const SAFE_GIT_ARG = /^[a-zA-Z0-9._\-/]+$/;
17
+ function validateGitArg(value, name) {
18
+ if (!SAFE_GIT_ARG.test(value)) {
19
+ throw new Error(`Invalid ${name}: "${value}". Only alphanumeric, dots, hyphens, underscores, and slashes allowed.`);
20
+ }
21
+ }
15
22
  /**
16
23
  * Load a skill from the Vercel Skills ecosystem.
17
24
  *
@@ -115,9 +122,8 @@ async function installViaVercelCli(source, options) {
115
122
  if (options.ref) {
116
123
  args.push('--ref', options.ref);
117
124
  }
118
- const command = `npx ${args.join(' ')}`;
119
125
  try {
120
- const { stdout, stderr } = await execAsync(command, {
126
+ const { stdout, stderr } = await execFileAsync('npx', args, {
121
127
  cwd: options.dir,
122
128
  timeout: 60000, // 60 second timeout
123
129
  });
@@ -191,18 +197,17 @@ async function fallbackGitClone(source, targetPath) {
191
197
  * Perform a sparse checkout for a specific path.
192
198
  */
193
199
  async function sparseClone(repoUrl, targetPath, subPath, ref) {
200
+ validateGitArg(subPath, 'subPath');
201
+ if (ref)
202
+ validateGitArg(ref, 'ref');
194
203
  const tempDir = `${targetPath}.tmp`;
195
204
  try {
196
- // Initialize sparse checkout
197
- await execAsync(`git clone --depth 1 --filter=blob:none --sparse ${repoUrl} ${tempDir}`);
198
- // Configure sparse checkout
199
- await execAsync(`git -C ${tempDir} sparse-checkout set ${subPath}`);
200
- // Checkout specific ref if provided
205
+ await execFileAsync('git', ['clone', '--depth', '1', '--filter=blob:none', '--sparse', repoUrl, tempDir]);
206
+ await execFileAsync('git', ['-C', tempDir, 'sparse-checkout', 'set', subPath]);
201
207
  if (ref) {
202
- await execAsync(`git -C ${tempDir} fetch --depth 1 origin ${ref}`);
203
- await execAsync(`git -C ${tempDir} checkout ${ref}`);
208
+ await execFileAsync('git', ['-C', tempDir, 'fetch', '--depth', '1', 'origin', ref]);
209
+ await execFileAsync('git', ['-C', tempDir, 'checkout', ref]);
204
210
  }
205
- // Move the skill directory to target
206
211
  const sourcePath = path.join(tempDir, subPath);
207
212
  if (!fs.existsSync(sourcePath)) {
208
213
  throw new Error(`Path "${subPath}" not found in repository`);
@@ -210,7 +215,6 @@ async function sparseClone(repoUrl, targetPath, subPath, ref) {
210
215
  fs.renameSync(sourcePath, targetPath);
211
216
  }
212
217
  finally {
213
- // Clean up temp directory
214
218
  if (fs.existsSync(tempDir)) {
215
219
  fs.rmSync(tempDir, { recursive: true });
216
220
  }
@@ -220,8 +224,14 @@ async function sparseClone(repoUrl, targetPath, subPath, ref) {
220
224
  * Perform a full shallow clone.
221
225
  */
222
226
  async function fullClone(repoUrl, targetPath, ref) {
223
- const refArg = ref ? `--branch ${ref}` : '';
224
- await execAsync(`git clone --depth 1 ${refArg} ${repoUrl} ${targetPath}`);
227
+ if (ref)
228
+ validateGitArg(ref, 'ref');
229
+ const args = ['clone', '--depth', '1'];
230
+ if (ref) {
231
+ args.push('--branch', ref);
232
+ }
233
+ args.push(repoUrl, targetPath);
234
+ await execFileAsync('git', args);
225
235
  // Remove .git directory to save space
226
236
  const gitDir = path.join(targetPath, '.git');
227
237
  if (fs.existsSync(gitDir)) {
@@ -304,7 +314,7 @@ export async function updateVercelSkill(skillName, registry) {
304
314
  */
305
315
  export async function isVercelCliAvailable() {
306
316
  try {
307
- await execAsync('npx skills --version', { timeout: 5000 });
317
+ await execFileAsync('npx', ['skills', '--version'], { timeout: 5000 });
308
318
  return true;
309
319
  }
310
320
  catch {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@revealui/ai",
3
- "version": "0.1.3",
4
- "description": "AI system for RevealUI - memory, LLM, orchestration, and tools",
3
+ "version": "0.2.0",
4
+ "description": "[Pro] AI system for RevealUI - memory, LLM, orchestration, and tools",
5
5
  "keywords": [
6
6
  "agent",
7
7
  "ai",
@@ -16,13 +16,18 @@
16
16
  "tools",
17
17
  "vector-search"
18
18
  ],
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "https://github.com/RevealUIStudio/revealui.git",
22
+ "directory": "packages/ai"
23
+ },
19
24
  "license": "SEE LICENSE IN ../../LICENSE.commercial",
20
25
  "dependencies": {
21
26
  "lru-cache": "^11.2.5",
22
27
  "zod": "^4.3.5",
23
- "@revealui/db": "^0.2.0",
24
- "@revealui/core": "0.2.1",
25
- "@revealui/contracts": "1.1.0"
28
+ "@revealui/db": "0.3.0",
29
+ "@revealui/core": "0.3.0",
30
+ "@revealui/contracts": "1.3.0"
26
31
  },
27
32
  "devDependencies": {
28
33
  "@testing-library/react": "^16.3.2",
@@ -116,24 +121,26 @@
116
121
  "files": [
117
122
  "dist"
118
123
  ],
124
+ "funding": {
125
+ "type": "commercial",
126
+ "url": "https://revealui.com/pro"
127
+ },
119
128
  "main": "./dist/index.js",
120
129
  "module": "./dist/index.js",
121
130
  "peerDependencies": {
122
131
  "drizzle-orm": "^0.45.1",
123
132
  "react": "^18.0.0 || ^19.0.0"
124
133
  },
125
- "type": "module",
126
- "types": "./dist/index.d.ts",
127
134
  "publishConfig": {
128
- "registry": "https://registry.npmjs.org",
129
135
  "access": "public"
130
136
  },
137
+ "type": "module",
138
+ "types": "./dist/index.d.ts",
131
139
  "scripts": {
132
140
  "build": "tsc",
133
141
  "clean": "rm -rf dist",
134
142
  "dev": "tsc --watch",
135
143
  "lint": "biome check .",
136
- "lint:eslint": "eslint .",
137
144
  "test": "vitest run",
138
145
  "test:coverage": "vitest run --coverage",
139
146
  "test:integration": "vitest run --root . --config vitest.integration.config.ts",
@@ -1,21 +0,0 @@
1
- /**
2
- * Simple Logger Utility
3
- *
4
- * Provides a minimal logging interface that can be easily replaced
5
- * with a proper logging service later. Respects environment and log levels.
6
- */
7
- export interface Logger {
8
- info: (...args: unknown[]) => void;
9
- warn: (...args: unknown[]) => void;
10
- error: (...args: unknown[]) => void;
11
- debug: (...args: unknown[]) => void;
12
- }
13
- /**
14
- * Creates a logger instance with optional prefix
15
- */
16
- export declare function createLogger(prefix?: string): Logger;
17
- /**
18
- * Default logger instance
19
- */
20
- export declare const defaultLogger: Logger;
21
- //# sourceMappingURL=logger.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/memory/utils/logger.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IAClC,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IAClC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IACnC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;CACpC;AA0DD;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,MAAqC,CAAA"}
@@ -1,62 +0,0 @@
1
- /**
2
- * Simple Logger Utility
3
- *
4
- * Provides a minimal logging interface that can be easily replaced
5
- * with a proper logging service later. Respects environment and log levels.
6
- */
7
- /**
8
- * Environment-aware logger implementation
9
- * Only logs when appropriate for the environment and log level
10
- */
11
- class SimpleLogger {
12
- prefix;
13
- minLevel;
14
- isProduction;
15
- constructor(prefix = '[Memory]') {
16
- this.prefix = prefix;
17
- this.isProduction = process.env.NODE_ENV === 'production';
18
- this.minLevel = process.env.LOG_LEVEL || (this.isProduction ? 'warn' : 'debug');
19
- }
20
- shouldLog(level) {
21
- // Never log debug or info in production
22
- if (this.isProduction && (level === 'debug' || level === 'info')) {
23
- return false;
24
- }
25
- const levels = ['debug', 'info', 'warn', 'error'];
26
- return levels.indexOf(level) >= levels.indexOf(this.minLevel);
27
- }
28
- info(...args) {
29
- // Info logs are never shown in production
30
- if (process.env.NODE_ENV !== 'production') {
31
- console.log(this.prefix, ...args);
32
- }
33
- // In production: complete no-op
34
- }
35
- warn(...args) {
36
- // Warning logs are never shown in production
37
- if (process.env.NODE_ENV !== 'production') {
38
- console.warn(this.prefix, ...args);
39
- }
40
- // In production: complete no-op
41
- }
42
- error(...args) {
43
- if (this.shouldLog('error')) {
44
- console.error(this.prefix, ...args);
45
- }
46
- }
47
- debug(...args) {
48
- if (process.env.NODE_ENV !== 'production') {
49
- console.debug(this.prefix, ...args);
50
- }
51
- }
52
- }
53
- /**
54
- * Creates a logger instance with optional prefix
55
- */
56
- export function createLogger(prefix) {
57
- return new SimpleLogger(prefix);
58
- }
59
- /**
60
- * Default logger instance
61
- */
62
- export const defaultLogger = new SimpleLogger('[Memory]');