moflo 4.8.61 → 4.8.64

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "moflo",
3
- "version": "4.8.61",
3
+ "version": "4.8.64",
4
4
  "description": "MoFlo — AI agent orchestration for Claude Code. Forked from ruflo/claude-flow with patches applied to source, plus feature-level orchestration.",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -93,6 +93,7 @@
93
93
  },
94
94
  "dependencies": {
95
95
  "js-yaml": "^4.1.1",
96
+ "lru-cache": "^11.3.5",
96
97
  "semver": "^7.7.4",
97
98
  "sql.js": "^1.14.1",
98
99
  "valibot": "^1.3.1"
@@ -111,7 +112,7 @@
111
112
  "@types/js-yaml": "^4.0.9",
112
113
  "@types/node": "^20.19.37",
113
114
  "eslint": "^8.0.0",
114
- "moflo": "^4.8.60",
115
+ "moflo": "^4.8.63",
115
116
  "tsx": "^4.21.0",
116
117
  "typescript": "^5.9.3",
117
118
  "vitest": "^4.0.0"
@@ -0,0 +1,79 @@
1
+ /**
2
+ * AgentDB-backed VectorStore adapter for AIDefence.
3
+ *
4
+ * Wraps the CLI memory-bridge (AgentDB v3 + HNSW + embeddings) so the
5
+ * 6 aidefence_* MCP tools persist learned threat patterns and mitigation
6
+ * strategies across process restarts with 150x-12,500x faster search.
7
+ *
8
+ * @moflo/aidefence stays pure-lib: this adapter lives in the CLI package
9
+ * where the bridge is already available. Arbitrary values are JSON-serialised
10
+ * into the bridge's `content` field; namespaces are prefixed with
11
+ * `aidefence:` to isolate from general memory entries.
12
+ */
13
+ import { bridgeStoreEntry, bridgeSearchEntries, bridgeGetEntry, bridgeDeleteEntry, isBridgeAvailable, } from '../memory/memory-bridge.js';
14
+ // Structural duck-typed shape of @moflo/aidefence's VectorStore interface.
15
+ // Declared locally to avoid cross-package type resolution fragility; TypeScript
16
+ // verifies compatibility structurally when passed to createAIDefence().
17
+ const NS_PREFIX = 'aidefence:';
18
+ function prefixNs(namespace) {
19
+ return `${NS_PREFIX}${namespace}`;
20
+ }
21
+ function safeParse(raw) {
22
+ try {
23
+ return JSON.parse(raw);
24
+ }
25
+ catch {
26
+ return raw;
27
+ }
28
+ }
29
+ export class AgentDBAIDefenceStore {
30
+ async store(params) {
31
+ await bridgeStoreEntry({
32
+ namespace: prefixNs(params.namespace),
33
+ key: params.key,
34
+ value: JSON.stringify(params.value),
35
+ ttl: params.ttl,
36
+ upsert: true,
37
+ });
38
+ }
39
+ async search(params) {
40
+ const queryStr = typeof params.query === 'string' ? params.query : JSON.stringify(params.query);
41
+ const result = await bridgeSearchEntries({
42
+ namespace: prefixNs(params.namespace),
43
+ query: queryStr,
44
+ limit: params.k ?? 10,
45
+ threshold: params.minSimilarity ?? 0,
46
+ });
47
+ if (!result?.results)
48
+ return [];
49
+ return result.results.map(r => ({
50
+ key: r.key,
51
+ value: safeParse(r.content),
52
+ similarity: r.score,
53
+ }));
54
+ }
55
+ async get(namespace, key) {
56
+ const result = await bridgeGetEntry({
57
+ namespace: prefixNs(namespace),
58
+ key,
59
+ });
60
+ if (!result?.found || !result.entry)
61
+ return null;
62
+ return safeParse(result.entry.content);
63
+ }
64
+ async delete(namespace, key) {
65
+ await bridgeDeleteEntry({
66
+ namespace: prefixNs(namespace),
67
+ key,
68
+ });
69
+ }
70
+ }
71
+ /**
72
+ * Return an AgentDB-backed store if the memory bridge is available,
73
+ * otherwise null so the caller can fall back to the default in-memory store.
74
+ */
75
+ export async function tryCreateAgentDBStore() {
76
+ const available = await isBridgeAvailable();
77
+ return available ? new AgentDBAIDefenceStore() : null;
78
+ }
79
+ //# sourceMappingURL=aidefence-agentdb-store.js.map
@@ -10,6 +10,7 @@
10
10
  * Created with ❤️ by motailz.com
11
11
  */
12
12
  import { autoInstallPackage } from './auto-install.js';
13
+ import { tryCreateAgentDBStore } from './aidefence-agentdb-store.js';
13
14
  import { createRequire } from 'module';
14
15
  // Create require for resolving module paths
15
16
  const require = createRequire(import.meta.url);
@@ -17,6 +18,20 @@ const require = createRequire(import.meta.url);
17
18
  let aidefenceInstance = null;
18
19
  // Track if we've attempted install this session
19
20
  let installAttempted = false;
21
+ /**
22
+ * Build createAIDefence config, attaching an AgentDB-backed vector store
23
+ * when the memory bridge is available. Falls back to the package default
24
+ * (InMemoryVectorStore) otherwise so the MCP tools still function standalone.
25
+ */
26
+ async function buildAIDefenceConfig() {
27
+ const store = await tryCreateAgentDBStore();
28
+ if (store) {
29
+ console.error('[claude-flow] aidefence: using AgentDB-backed vector store (HNSW)');
30
+ return { enableLearning: true, vectorStore: store };
31
+ }
32
+ console.error('[claude-flow] aidefence: AgentDB bridge unavailable, using in-memory store');
33
+ return { enableLearning: true };
34
+ }
20
35
  /**
21
36
  * Get or create AIDefence instance (throws if unavailable)
22
37
  */
@@ -28,7 +43,8 @@ async function getAIDefence() {
28
43
  // First attempt - try to load via dynamic import (ESM)
29
44
  try {
30
45
  const aidefence = await import(packageName);
31
- const instance = aidefence.createAIDefence({ enableLearning: true });
46
+ const config = await buildAIDefenceConfig();
47
+ const instance = aidefence.createAIDefence(config);
32
48
  if (!instance) {
33
49
  throw new Error('createAIDefence returned null');
34
50
  }
@@ -60,7 +76,8 @@ async function getAIDefence() {
60
76
  const modulePath = require.resolve(packageName);
61
77
  const cacheBust = `?t=${Date.now()}`;
62
78
  const aidefence = await import(pathToFileURL(modulePath).href + cacheBust);
63
- const instance = aidefence.createAIDefence({ enableLearning: true });
79
+ const config = await buildAIDefenceConfig();
80
+ const instance = aidefence.createAIDefence(config);
64
81
  if (!instance) {
65
82
  throw new Error('createAIDefence returned null after install');
66
83
  }
@@ -2,5 +2,5 @@
2
2
  * Auto-generated by build. Do not edit manually.
3
3
  * Source of truth: root package.json → scripts/sync-version.mjs
4
4
  */
5
- export const VERSION = '4.8.61';
5
+ export const VERSION = '4.8.64';
6
6
  //# sourceMappingURL=version.js.map
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moflo/cli",
3
- "version": "4.8.61",
3
+ "version": "4.8.64",
4
4
  "type": "module",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",
@@ -24,6 +24,9 @@ export class CacheManager extends EventEmitter {
24
24
  head = null;
25
25
  tail = null;
26
26
  currentMemory = 0;
27
+ // Cache size estimates to avoid repeated JSON.stringify
28
+ sizeCache = new Map();
29
+ maxSizeCacheEntries = 10000;
27
30
  // Statistics
28
31
  stats = {
29
32
  hits: 0,
@@ -75,17 +78,21 @@ export class CacheManager extends EventEmitter {
75
78
  // Check if key already exists
76
79
  const existingNode = this.cache.get(key);
77
80
  if (existingNode) {
78
- // Update existing entry
81
+ // Update existing entry - recalculate size if data changed
82
+ const oldSize = existingNode.estimatedSize;
83
+ const newSize = this.estimateSizeCached(key, data);
79
84
  existingNode.value.data = data;
80
85
  existingNode.value.cachedAt = now;
81
86
  existingNode.value.expiresAt = now + entryTtl;
82
87
  existingNode.value.lastAccessedAt = now;
88
+ existingNode.estimatedSize = newSize;
89
+ this.currentMemory = this.currentMemory - oldSize + newSize;
83
90
  this.moveToFront(existingNode);
84
91
  this.stats.writes++;
85
92
  return;
86
93
  }
87
- // Calculate memory for new entry
88
- const entryMemory = this.estimateSize(data);
94
+ // Calculate memory for new entry (with caching)
95
+ const entryMemory = this.estimateSizeCached(key, data);
89
96
  // Evict entries if needed for memory pressure
90
97
  if (this.config.maxMemory) {
91
98
  while (this.currentMemory + entryMemory > this.config.maxMemory &&
@@ -110,6 +117,7 @@ export class CacheManager extends EventEmitter {
110
117
  value: cachedEntry,
111
118
  prev: null,
112
119
  next: null,
120
+ estimatedSize: entryMemory, // Store computed size
113
121
  };
114
122
  // Add to cache
115
123
  this.cache.set(key, node);
@@ -128,7 +136,8 @@ export class CacheManager extends EventEmitter {
128
136
  }
129
137
  this.removeNode(node);
130
138
  this.cache.delete(key);
131
- this.currentMemory -= this.estimateSize(node.value.data);
139
+ this.currentMemory -= node.estimatedSize; // Use cached size
140
+ this.sizeCache.delete(key); // Clean up size cache
132
141
  this.emit('cache:delete', { key });
133
142
  return true;
134
143
  }
@@ -149,11 +158,13 @@ export class CacheManager extends EventEmitter {
149
158
  * Clear all entries from the cache
150
159
  */
151
160
  clear() {
161
+ const previousSize = this.cache.size;
152
162
  this.cache.clear();
163
+ this.sizeCache.clear();
153
164
  this.head = null;
154
165
  this.tail = null;
155
166
  this.currentMemory = 0;
156
- this.emit('cache:cleared', { previousSize: this.cache.size });
167
+ this.emit('cache:cleared', { previousSize });
157
168
  }
158
169
  /**
159
170
  * Get cache statistics
@@ -255,8 +266,37 @@ export class CacheManager extends EventEmitter {
255
266
  isExpired(entry) {
256
267
  return Date.now() > entry.expiresAt;
257
268
  }
269
+ /**
270
+ * OPTIMIZED: Cache size estimates to avoid repeated JSON.stringify
271
+ * This is called on every cache set and eviction, so caching saves significant CPU
272
+ */
273
+ estimateSizeCached(key, data) {
274
+ // Check if we have a cached size estimate
275
+ const cached = this.sizeCache.get(key);
276
+ if (cached !== undefined) {
277
+ return cached;
278
+ }
279
+ // Compute size
280
+ const size = this.estimateSize(data);
281
+ // Cache the result (with LRU eviction)
282
+ if (this.sizeCache.size >= this.maxSizeCacheEntries) {
283
+ const firstKey = this.sizeCache.keys().next().value;
284
+ if (firstKey !== undefined)
285
+ this.sizeCache.delete(firstKey);
286
+ }
287
+ this.sizeCache.set(key, size);
288
+ return size;
289
+ }
258
290
  estimateSize(data) {
259
291
  try {
292
+ // For primitive types, use fast path
293
+ if (typeof data === 'string') {
294
+ return data.length * 2;
295
+ }
296
+ if (typeof data === 'number' || typeof data === 'boolean') {
297
+ return 8;
298
+ }
299
+ // For objects, use JSON.stringify (but only once due to caching)
260
300
  return JSON.stringify(data).length * 2; // Rough UTF-16 estimate
261
301
  }
262
302
  catch {
@@ -298,9 +338,10 @@ export class CacheManager extends EventEmitter {
298
338
  if (!this.tail)
299
339
  return;
300
340
  const evictedKey = this.tail.key;
301
- const evictedSize = this.estimateSize(this.tail.value.data);
341
+ const evictedSize = this.tail.estimatedSize; // Use cached size
302
342
  this.removeNode(this.tail);
303
343
  this.cache.delete(evictedKey);
344
+ this.sizeCache.delete(evictedKey); // Clean up size cache
304
345
  this.currentMemory -= evictedSize;
305
346
  this.stats.evictions++;
306
347
  this.emit('cache:eviction', { key: evictedKey });