@danielsimonjr/memoryjs 2.6.0 → 2.8.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.cjs CHANGED
@@ -3416,6 +3416,144 @@ var init_WorkerPoolManager = __esm({
3416
3416
  }
3417
3417
  });
3418
3418
 
3419
+ // src/utils/WorkerTaskManager.ts
3420
+ function getWorkerTaskManager() {
3421
+ if (!DEFAULT_INSTANCE) DEFAULT_INSTANCE = new WorkerTaskManager();
3422
+ return DEFAULT_INSTANCE;
3423
+ }
3424
+ async function batchProcessViaWorkers(items, workerType, methodName, mapArgs, opts = {}) {
3425
+ if (items.length === 0) return [];
3426
+ const wtm = getWorkerTaskManager();
3427
+ const promises = items.map(
3428
+ (item, i) => wtm.submit(workerType, methodName, mapArgs(item, i), opts)
3429
+ );
3430
+ return Promise.all(promises);
3431
+ }
3432
+ var SUBMISSION_COUNTER, WorkerTaskManager, DEFAULT_INSTANCE;
3433
+ var init_WorkerTaskManager = __esm({
3434
+ "src/utils/WorkerTaskManager.ts"() {
3435
+ "use strict";
3436
+ init_cjs_shims();
3437
+ init_taskScheduler();
3438
+ init_WorkerPoolManager();
3439
+ init_logger();
3440
+ SUBMISSION_COUNTER = 0;
3441
+ WorkerTaskManager = class {
3442
+ queue;
3443
+ poolManager;
3444
+ touchedPoolIds = /* @__PURE__ */ new Set();
3445
+ cancelledTaskIds = /* @__PURE__ */ new Set();
3446
+ handleStatus = /* @__PURE__ */ new Map();
3447
+ constructor(opts = {}) {
3448
+ this.queue = new TaskQueue({
3449
+ concurrency: opts.concurrency,
3450
+ timeout: opts.defaultTimeout,
3451
+ // We dispatch to WorkerPoolManager ourselves — the queue's
3452
+ // internal-worker-pool path would double-up.
3453
+ useWorkerPool: false
3454
+ });
3455
+ this.poolManager = getWorkerPoolManager();
3456
+ }
3457
+ /**
3458
+ * Submit a task and await its result. Throws on failure / cancellation.
3459
+ *
3460
+ * @param workerType — routing key. Maps to a named `WorkerPoolManager` pool.
3461
+ * @param methodName — function name exposed by the worker module.
3462
+ * @param args — positional arguments passed to the worker function.
3463
+ */
3464
+ async submit(workerType, methodName, args, opts = {}) {
3465
+ const handle = this.submitWithHandle(workerType, methodName, args, opts);
3466
+ return handle.result;
3467
+ }
3468
+ /**
3469
+ * Submit a task and return a handle for cancellation + status polling.
3470
+ */
3471
+ submitWithHandle(workerType, methodName, args, opts = {}) {
3472
+ const id = `wtm-${Date.now()}-${++SUBMISSION_COUNTER}`;
3473
+ this.handleStatus.set(id, "pending" /* PENDING */);
3474
+ const task = {
3475
+ id,
3476
+ priority: opts.priority ?? 1 /* NORMAL */,
3477
+ timeout: opts.timeout,
3478
+ input: { workerType, methodName, args },
3479
+ fn: async (input) => {
3480
+ if (this.cancelledTaskIds.has(id)) {
3481
+ throw new Error(`Task ${id} cancelled before dispatch`);
3482
+ }
3483
+ this.handleStatus.set(id, "running" /* RUNNING */);
3484
+ const pool = this.poolManager.getPool(input.workerType, opts.poolConfig);
3485
+ this.touchedPoolIds.add(input.workerType);
3486
+ return await pool.exec(input.methodName, input.args);
3487
+ }
3488
+ };
3489
+ const result = this.queue.enqueue(task).then(async (res) => {
3490
+ this.handleStatus.set(id, res.status);
3491
+ if (res.status === "completed" /* COMPLETED */) {
3492
+ return res.result;
3493
+ }
3494
+ if (res.status === "cancelled" /* CANCELLED */ || this.cancelledTaskIds.has(id)) {
3495
+ throw new Error(`Task ${id} cancelled`);
3496
+ }
3497
+ const err2 = res.error ?? new Error(`Task ${id} failed: ${res.status}`);
3498
+ throw err2;
3499
+ });
3500
+ return {
3501
+ id,
3502
+ result,
3503
+ cancel: () => {
3504
+ this.cancelledTaskIds.add(id);
3505
+ const evicted = this.queue.cancel(id);
3506
+ if (evicted) {
3507
+ this.handleStatus.set(id, "cancelled" /* CANCELLED */);
3508
+ }
3509
+ return evicted;
3510
+ },
3511
+ status: () => this.handleStatus.get(id) ?? "pending" /* PENDING */
3512
+ };
3513
+ }
3514
+ /**
3515
+ * Aggregated stats across the queue + touched pools.
3516
+ */
3517
+ getStats() {
3518
+ const pools = [];
3519
+ for (const poolId of this.touchedPoolIds) {
3520
+ const stats = this.poolManager.getPoolStats(poolId);
3521
+ if (stats) {
3522
+ pools.push({
3523
+ poolId,
3524
+ workers: stats.totalWorkers,
3525
+ activeTasks: stats.activeTasks,
3526
+ pendingTasks: stats.pendingTasks,
3527
+ totalTasksExecuted: stats.totalTasksExecuted
3528
+ });
3529
+ }
3530
+ }
3531
+ return { queue: this.queue.getStats(), pools };
3532
+ }
3533
+ /**
3534
+ * Drain the queue (wait for all pending + running tasks) and return their
3535
+ * results in completion order. Pool workers are NOT terminated — call
3536
+ * `shutdown()` for that.
3537
+ */
3538
+ async drain() {
3539
+ return this.queue.drain();
3540
+ }
3541
+ /**
3542
+ * Shut down the queue + the underlying WorkerPoolManager pools touched by
3543
+ * this instance. Idempotent. Returns after every owned worker has exited.
3544
+ */
3545
+ async shutdown() {
3546
+ try {
3547
+ await this.queue.shutdown();
3548
+ } catch (e) {
3549
+ logger.warn("[WorkerTaskManager.shutdown] queue.shutdown failed:", e);
3550
+ }
3551
+ }
3552
+ };
3553
+ DEFAULT_INSTANCE = null;
3554
+ }
3555
+ });
3556
+
3419
3557
  // src/utils/BatchProcessor.ts
3420
3558
  async function processBatch(items, processor, options = {}) {
3421
3559
  const batchProcessor = new BatchProcessor(options);
@@ -11270,6 +11408,7 @@ var init_utils = __esm({
11270
11408
  init_taskScheduler();
11271
11409
  init_operationUtils();
11272
11410
  init_WorkerPoolManager();
11411
+ init_WorkerTaskManager();
11273
11412
  init_BatchProcessor();
11274
11413
  init_MemoryMonitor();
11275
11414
  init_relationHelpers();
@@ -13775,6 +13914,7 @@ __export(index_exports, {
13775
13914
  VisibilityResolver: () => VisibilityResolver,
13776
13915
  WorkThreadManager: () => WorkThreadManager,
13777
13916
  WorkerPoolManager: () => WorkerPoolManager,
13917
+ WorkerTaskManager: () => WorkerTaskManager,
13778
13918
  WorkingMemoryManager: () => WorkingMemoryManager,
13779
13919
  WorldModelManager: () => WorldModelManager,
13780
13920
  WorldStateSnapshot: () => WorldStateSnapshot,
@@ -13784,6 +13924,7 @@ __export(index_exports, {
13784
13924
  applyPagination: () => applyPagination,
13785
13925
  asWarning: () => asWarning,
13786
13926
  batchProcess: () => batchProcess,
13927
+ batchProcessViaWorkers: () => batchProcessViaWorkers,
13787
13928
  buildTFVector: () => buildTFVector,
13788
13929
  calculateIDF: () => calculateIDF,
13789
13930
  calculateIDFFromTokenSets: () => calculateIDFFromTokenSets,
@@ -13854,6 +13995,7 @@ __export(index_exports, {
13854
13995
  getQuickHint: () => getQuickHint,
13855
13996
  getRoleProfile: () => getRoleProfile,
13856
13997
  getWorkerPoolManager: () => getWorkerPoolManager,
13998
+ getWorkerTaskManager: () => getWorkerTaskManager,
13857
13999
  globalMemoryMonitor: () => globalMemoryMonitor,
13858
14000
  groupEntitiesByType: () => groupEntitiesByType,
13859
14001
  hasAllTags: () => hasAllTags,
@@ -21114,6 +21256,27 @@ CREATE INDEX IF NOT EXISTS idx_entities_project_id ON entities(project_id);
21114
21256
  CREATE INDEX IF NOT EXISTS idx_entities_content_hash ON entities(content_hash);
21115
21257
  CREATE INDEX IF NOT EXISTS idx_entities_tags_gin ON entities USING GIN(tags);
21116
21258
 
21259
+ -- v2.8.0 \u2014 generated tsvector column for full-text search.
21260
+ -- name is weighted A (highest), observations B, tags C. PostgreSQL 12+
21261
+ -- supports GENERATED ALWAYS AS ... STORED; the DO block makes the column
21262
+ -- add idempotent on older + newer servers without requiring CREATE OR
21263
+ -- REPLACE semantics on ALTER.
21264
+ DO $$ BEGIN
21265
+ IF NOT EXISTS (
21266
+ SELECT 1 FROM information_schema.columns
21267
+ WHERE table_name = 'entities' AND column_name = 'fts_vector'
21268
+ ) THEN
21269
+ ALTER TABLE entities ADD COLUMN fts_vector tsvector
21270
+ GENERATED ALWAYS AS (
21271
+ setweight(to_tsvector('english', name), 'A') ||
21272
+ setweight(to_tsvector('english', coalesce(array_to_string(observations, ' '), '')), 'B') ||
21273
+ setweight(to_tsvector('english', coalesce(array_to_string(tags, ' '), '')), 'C')
21274
+ ) STORED;
21275
+ END IF;
21276
+ END $$;
21277
+
21278
+ CREATE INDEX IF NOT EXISTS idx_entities_fts_gin ON entities USING GIN(fts_vector);
21279
+
21117
21280
  CREATE TABLE IF NOT EXISTS relations (
21118
21281
  from_name TEXT NOT NULL,
21119
21282
  to_name TEXT NOT NULL,
@@ -21433,6 +21596,38 @@ var PostgreSQLStorage = class {
21433
21596
  hasRelations(entityName) {
21434
21597
  return (this.outgoingRelations.get(entityName)?.length ?? 0) + (this.incomingRelations.get(entityName)?.length ?? 0) > 0;
21435
21598
  }
21599
+ // ==================== Full-text search ====================
21600
+ /**
21601
+ * tsvector-backed full-text search. Uses `plainto_tsquery` so the input is
21602
+ * free-form (no boolean operator syntax required); ranks via `ts_rank` on
21603
+ * the weighted `fts_vector` column (name × A, observations × B, tags × C).
21604
+ *
21605
+ * Results are ordered by descending score and capped at `options.limit`
21606
+ * (default 50). Empty / whitespace-only queries return `[]` without
21607
+ * issuing a SQL call.
21608
+ *
21609
+ * @example
21610
+ * ```typescript
21611
+ * const matches = await storage.fullTextSearch('authentication flow', { limit: 10 });
21612
+ * // → [{ name: 'AuthService', score: 0.62 }, ...]
21613
+ * ```
21614
+ */
21615
+ async fullTextSearch(query, options = {}) {
21616
+ const trimmed = query.trim();
21617
+ if (trimmed.length === 0) return [];
21618
+ await this.initSchema();
21619
+ const pool = await this.getPool();
21620
+ const limit = options.limit ?? 50;
21621
+ const res = await pool.query(
21622
+ `SELECT name, ts_rank(fts_vector, plainto_tsquery('english', $1))::float AS score
21623
+ FROM entities
21624
+ WHERE fts_vector @@ plainto_tsquery('english', $1)
21625
+ ORDER BY score DESC
21626
+ LIMIT $2`,
21627
+ [trimmed, limit]
21628
+ );
21629
+ return res.rows.map((r) => ({ name: r.name, score: Number(r.score) }));
21630
+ }
21436
21631
  // ==================== Utility ====================
21437
21632
  getFilePath() {
21438
21633
  return this.connectionString;
@@ -52171,6 +52366,7 @@ function extractRoleAndContent(entity) {
52171
52366
  VisibilityResolver,
52172
52367
  WorkThreadManager,
52173
52368
  WorkerPoolManager,
52369
+ WorkerTaskManager,
52174
52370
  WorkingMemoryManager,
52175
52371
  WorldModelManager,
52176
52372
  WorldStateSnapshot,
@@ -52180,6 +52376,7 @@ function extractRoleAndContent(entity) {
52180
52376
  applyPagination,
52181
52377
  asWarning,
52182
52378
  batchProcess,
52379
+ batchProcessViaWorkers,
52183
52380
  buildTFVector,
52184
52381
  calculateIDF,
52185
52382
  calculateIDFFromTokenSets,
@@ -52250,6 +52447,7 @@ function extractRoleAndContent(entity) {
52250
52447
  getQuickHint,
52251
52448
  getRoleProfile,
52252
52449
  getWorkerPoolManager,
52450
+ getWorkerTaskManager,
52253
52451
  globalMemoryMonitor,
52254
52452
  groupEntitiesByType,
52255
52453
  hasAllTags,