shieldcortex 3.0.4 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -2
- package/dashboard/.next/standalone/dashboard/.next/BUILD_ID +1 -1
- package/dashboard/.next/standalone/dashboard/.next/build-manifest.json +2 -2
- package/dashboard/.next/standalone/dashboard/.next/prerender-manifest.json +3 -3
- package/dashboard/.next/standalone/dashboard/.next/required-server-files.json +4 -4
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.rsc +3 -3
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_full.segment.rsc +3 -3
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/app/page/react-loadable-manifest.json +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/chunks/ssr/dashboard_3051539d._.js +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/pages/404.html +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/pages/500.html +2 -2
- package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.js +1 -1
- package/dashboard/.next/standalone/dashboard/.next/server/server-reference-manifest.json +1 -1
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/9232a2d99b47b21f.js +3 -0
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/98e2c181d5c4349f.js +1 -0
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/9cb86821c1107fd6.js +9 -0
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/a56c497e02afd4ba.css +3 -0
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/a90355d73183a5e6.js +1 -0
- package/dashboard/.next/standalone/dashboard/node_modules/@img/sharp-darwin-arm64/lib/sharp-darwin-arm64.node +0 -0
- package/dashboard/.next/standalone/{node_modules/@img/sharp-linux-x64 → dashboard/node_modules/@img/sharp-darwin-arm64}/package.json +7 -13
- package/dashboard/.next/standalone/dashboard/node_modules/@img/{sharp-libvips-linux-x64 → sharp-libvips-darwin-arm64}/README.md +2 -2
- package/dashboard/.next/standalone/dashboard/node_modules/@img/{sharp-libvips-linux-x64 → sharp-libvips-darwin-arm64}/lib/glib-2.0/include/glibconfig.h +8 -9
- package/dashboard/.next/standalone/dashboard/node_modules/@img/{sharp-libvips-linux-x64/lib/libvips-cpp.so.8.17.3 → sharp-libvips-darwin-arm64/lib/libvips-cpp.8.17.3.dylib} +0 -0
- package/dashboard/.next/standalone/dashboard/node_modules/@img/{sharp-libvips-linux-x64 → sharp-libvips-darwin-arm64}/package.json +5 -11
- package/dashboard/.next/standalone/dashboard/server.js +1 -1
- package/dashboard/.next/standalone/{dashboard/node_modules/@img/sharp-linux-x64 → node_modules/@img/sharp-darwin-arm64}/package.json +7 -13
- package/dashboard/.next/standalone/node_modules/@img/{sharp-libvips-linux-x64 → sharp-libvips-darwin-arm64}/package.json +5 -11
- package/dist/api/routes/memories.js +366 -1
- package/dist/api/routes/recall.js +53 -0
- package/dist/api/routes/system.js +67 -2
- package/dist/cloud/cli.d.ts +1 -0
- package/dist/cloud/cli.js +40 -0
- package/dist/cloud/config.d.ts +10 -0
- package/dist/cloud/config.js +54 -0
- package/dist/cloud/graph-sync.d.ts +45 -0
- package/dist/cloud/graph-sync.js +260 -0
- package/dist/cloud/memory-sync.d.ts +37 -0
- package/dist/cloud/memory-sync.js +186 -0
- package/dist/cloud/sync-queue.d.ts +24 -0
- package/dist/cloud/sync-queue.js +126 -7
- package/dist/database/init.js +53 -0
- package/dist/graph/backfill.js +3 -5
- package/dist/graph/resolve.d.ts +10 -0
- package/dist/graph/resolve.js +63 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +61 -4
- package/dist/memory/search.d.ts +1 -0
- package/dist/memory/search.js +4 -0
- package/dist/memory/store.js +188 -30
- package/dist/memory/types.d.ts +33 -0
- package/dist/service/install.d.ts +1 -0
- package/dist/service/install.js +43 -1
- package/dist/tools/context.d.ts +4 -4
- package/dist/tools/forget.d.ts +6 -6
- package/dist/tools/recall.d.ts +11 -11
- package/dist/tools/remember.d.ts +19 -4
- package/dist/tools/remember.js +17 -1
- package/hooks/openclaw/cortex-memory/handler.ts +8 -0
- package/package.json +1 -1
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/313c0d327bbf244a.js +0 -9
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/3cc7e8d4f73cf5d2.js +0 -1
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/49c1cec591af1460.js +0 -3
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/ca21f348cb163905.js +0 -1
- package/dashboard/.next/standalone/dashboard/.next/static/chunks/f4ca424319f58dc7.css +0 -3
- package/dashboard/.next/standalone/dashboard/node_modules/@img/sharp-libvips-linuxmusl-x64/README.md +0 -46
- package/dashboard/.next/standalone/dashboard/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/glib-2.0/include/glibconfig.h +0 -221
- package/dashboard/.next/standalone/dashboard/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/index.js +0 -1
- package/dashboard/.next/standalone/dashboard/node_modules/@img/sharp-libvips-linuxmusl-x64/lib/libvips-cpp.so.8.17.3 +0 -0
- package/dashboard/.next/standalone/dashboard/node_modules/@img/sharp-libvips-linuxmusl-x64/package.json +0 -42
- package/dashboard/.next/standalone/dashboard/node_modules/@img/sharp-libvips-linuxmusl-x64/versions.json +0 -30
- package/dashboard/.next/standalone/dashboard/node_modules/@img/sharp-linux-x64/lib/sharp-linux-x64.node +0 -0
- package/dashboard/.next/standalone/dashboard/node_modules/@img/sharp-linuxmusl-x64/lib/sharp-linuxmusl-x64.node +0 -0
- package/dashboard/.next/standalone/dashboard/node_modules/@img/sharp-linuxmusl-x64/package.json +0 -46
- package/dashboard/.next/standalone/node_modules/@img/sharp-libvips-linuxmusl-x64/package.json +0 -42
- package/dashboard/.next/standalone/node_modules/@img/sharp-linuxmusl-x64/package.json +0 -46
- /package/dashboard/.next/standalone/dashboard/.next/static/{BEvyMAX62LQMyt5iSb-F9 → ctp9eCBcHDpTWtUYMwJK7}/_buildManifest.js +0 -0
- /package/dashboard/.next/standalone/dashboard/.next/static/{BEvyMAX62LQMyt5iSb-F9 → ctp9eCBcHDpTWtUYMwJK7}/_clientMiddlewareManifest.json +0 -0
- /package/dashboard/.next/standalone/dashboard/.next/static/{BEvyMAX62LQMyt5iSb-F9 → ctp9eCBcHDpTWtUYMwJK7}/_ssgManifest.js +0 -0
- /package/dashboard/.next/standalone/dashboard/node_modules/@img/{sharp-libvips-linux-x64 → sharp-libvips-darwin-arm64}/lib/index.js +0 -0
- /package/dashboard/.next/standalone/dashboard/node_modules/@img/{sharp-libvips-linux-x64 → sharp-libvips-darwin-arm64}/versions.json +0 -0
package/dist/memory/store.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Core CRUD operations for the memory database.
|
|
5
5
|
* Handles storage, retrieval, and management of memories.
|
|
6
6
|
*/
|
|
7
|
+
import { randomUUID } from 'crypto';
|
|
7
8
|
import { getDatabase, isDatabaseInitialized } from '../database/init.js';
|
|
8
9
|
import { DEFAULT_CONFIG, } from './types.js';
|
|
9
10
|
import { calculateSalience, suggestCategory, extractTags, } from './salience.js';
|
|
@@ -14,9 +15,11 @@ import { emitMemoryCreated, emitMemoryAccessed, emitMemoryDeleted, emitMemoryUpd
|
|
|
14
15
|
import { generateEmbedding, cosineSimilarity } from '../embeddings/index.js';
|
|
15
16
|
import { isPaused } from '../api/control.js';
|
|
16
17
|
import { extractFromMemory } from '../graph/extract.js';
|
|
17
|
-
import { processExtractionResult } from '../graph/resolve.js';
|
|
18
|
+
import { processExtractionResult, removeMemoryGraph, replaceMemoryGraph } from '../graph/resolve.js';
|
|
18
19
|
import { runDefencePipeline, storeFragmentationData } from '../defence/index.js';
|
|
19
20
|
import { syncQuarantineToCloud } from '../cloud/quarantine-sync.js';
|
|
21
|
+
import { syncGraphDeleteForMemoryToCloud, syncGraphForMemoryToCloud } from '../cloud/graph-sync.js';
|
|
22
|
+
import { syncMemoryDeleteToCloud, syncMemoryUpsertToCloud } from '../cloud/memory-sync.js';
|
|
20
23
|
import { isFeatureEnabled } from '../license/gate.js';
|
|
21
24
|
import { checkAccess } from '../defence/trust/access-control.js';
|
|
22
25
|
import { scoreSource } from '../defence/trust/source-scorer.js';
|
|
@@ -119,12 +122,39 @@ function safeJsonParse(value, fallback) {
|
|
|
119
122
|
return fallback;
|
|
120
123
|
}
|
|
121
124
|
}
|
|
125
|
+
function inferSourceDetails(input, source) {
|
|
126
|
+
const tags = (input.tags ?? []).map((tag) => tag.toLowerCase());
|
|
127
|
+
if (tags.includes('openclaw-hook')) {
|
|
128
|
+
return { sourceKind: 'hook', captureMethod: tags.includes('auto-extracted') ? 'auto' : 'hook', sourceValue: 'hook:openclaw' };
|
|
129
|
+
}
|
|
130
|
+
if (tags.includes('realtime-plugin') || tags.includes('llm-output')) {
|
|
131
|
+
return { sourceKind: 'plugin', captureMethod: tags.includes('auto-extracted') ? 'auto' : 'plugin', sourceValue: 'agent:openclaw-plugin' };
|
|
132
|
+
}
|
|
133
|
+
if (source?.type === 'hook') {
|
|
134
|
+
return { sourceKind: 'hook', captureMethod: 'hook', sourceValue: `${source.type}:${source.identifier}` };
|
|
135
|
+
}
|
|
136
|
+
if (source?.type === 'agent') {
|
|
137
|
+
return { sourceKind: 'agent', captureMethod: 'plugin', sourceValue: `${source.type}:${source.identifier}` };
|
|
138
|
+
}
|
|
139
|
+
if (source?.type === 'api') {
|
|
140
|
+
return { sourceKind: 'api', captureMethod: 'api', sourceValue: `${source.type}:${source.identifier}` };
|
|
141
|
+
}
|
|
142
|
+
if (source?.type === 'cli') {
|
|
143
|
+
return { sourceKind: 'cli', captureMethod: 'manual', sourceValue: `${source.type}:${source.identifier}` };
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
sourceKind: input.sourceKind ?? 'user',
|
|
147
|
+
captureMethod: input.captureMethod ?? (tags.includes('auto-extracted') ? 'auto' : 'manual'),
|
|
148
|
+
sourceValue: input.source ?? (source ? `${source.type}:${source.identifier}` : 'user:direct'),
|
|
149
|
+
};
|
|
150
|
+
}
|
|
122
151
|
/**
|
|
123
152
|
* Convert database row to Memory object
|
|
124
153
|
*/
|
|
125
154
|
export function rowToMemory(row) {
|
|
126
155
|
return {
|
|
127
156
|
id: row.id,
|
|
157
|
+
uuid: row.uuid,
|
|
128
158
|
type: row.type,
|
|
129
159
|
category: row.category,
|
|
130
160
|
title: row.title,
|
|
@@ -135,11 +165,22 @@ export function rowToMemory(row) {
|
|
|
135
165
|
accessCount: row.access_count,
|
|
136
166
|
lastAccessed: new Date(row.last_accessed),
|
|
137
167
|
createdAt: new Date(row.created_at),
|
|
168
|
+
updatedAt: new Date(row.updated_at ?? row.created_at),
|
|
138
169
|
decayedScore: row.decayed_score ?? row.salience,
|
|
139
170
|
metadata: safeJsonParse(row.metadata, {}),
|
|
140
171
|
embedding: row.embedding,
|
|
141
172
|
scope: row.scope ?? 'project',
|
|
142
173
|
transferable: Boolean(row.transferable),
|
|
174
|
+
status: (row.status ?? 'active'),
|
|
175
|
+
pinned: Boolean(row.pinned),
|
|
176
|
+
reviewedAt: row.reviewed_at ? new Date(row.reviewed_at) : null,
|
|
177
|
+
reviewedBy: row.reviewed_by ?? null,
|
|
178
|
+
sourceKind: (row.source_kind ?? 'user'),
|
|
179
|
+
captureMethod: (row.capture_method ?? 'manual'),
|
|
180
|
+
trustScore: Number(row.trust_score ?? 1),
|
|
181
|
+
sensitivityLevel: row.sensitivity_level ?? 'INTERNAL',
|
|
182
|
+
source: row.source ?? null,
|
|
183
|
+
cloudExcluded: Boolean(row.cloud_excluded),
|
|
143
184
|
};
|
|
144
185
|
}
|
|
145
186
|
/**
|
|
@@ -352,9 +393,16 @@ export function addMemory(input, config = DEFAULT_CONFIG, source) {
|
|
|
352
393
|
const scope = input.scope ??
|
|
353
394
|
(detectGlobalPattern(input.content, category, tags) ? 'global' : 'project');
|
|
354
395
|
const transferable = input.transferable ?? (scope === 'global' ? 1 : 0);
|
|
396
|
+
const sourceDetails = inferSourceDetails({ ...input, tags }, source);
|
|
397
|
+
const status = input.status ?? 'active';
|
|
398
|
+
const pinned = input.pinned ? 1 : 0;
|
|
399
|
+
const cloudExcluded = input.cloudExcluded ? 1 : 0;
|
|
355
400
|
const stmt = db.prepare(`
|
|
356
|
-
INSERT INTO memories (
|
|
357
|
-
|
|
401
|
+
INSERT INTO memories (
|
|
402
|
+
uuid, type, category, title, content, project, tags, salience, metadata, scope, transferable,
|
|
403
|
+
status, pinned, reviewed_at, reviewed_by, source_kind, capture_method, cloud_excluded, updated_at
|
|
404
|
+
)
|
|
405
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
|
|
358
406
|
`);
|
|
359
407
|
// Anti-bloat: Truncate content if too large
|
|
360
408
|
const truncationResult = truncateContent(input.content);
|
|
@@ -366,10 +414,15 @@ export function addMemory(input, config = DEFAULT_CONFIG, source) {
|
|
|
366
414
|
};
|
|
367
415
|
// Transaction: INSERT + defence UPDATE must be atomic to prevent wrong trust scores
|
|
368
416
|
const insertedId = db.transaction(() => {
|
|
369
|
-
const
|
|
417
|
+
const memoryUuid = randomUUID();
|
|
418
|
+
const result = stmt.run(memoryUuid, type, category, input.title, truncationResult.content, input.project || null, JSON.stringify(tags), salience, JSON.stringify(input.metadata || {}), scope, transferable, status, pinned, input.reviewedBy ? new Date().toISOString() : null, input.reviewedBy ?? null, sourceDetails.sourceKind, sourceDetails.captureMethod, cloudExcluded);
|
|
370
419
|
if (defenceResult) {
|
|
371
420
|
db.prepare(`UPDATE memories SET trust_score = ?, sensitivity_level = ?, source = ? WHERE id = ?`)
|
|
372
|
-
.run(defenceResult.trust.score, defenceResult.sensitivity.level,
|
|
421
|
+
.run(defenceResult.trust.score, defenceResult.sensitivity.level, sourceDetails.sourceValue, result.lastInsertRowid);
|
|
422
|
+
}
|
|
423
|
+
else {
|
|
424
|
+
db.prepare(`UPDATE memories SET source = ?, trust_score = COALESCE(trust_score, ?), sensitivity_level = COALESCE(sensitivity_level, ?) WHERE id = ?`)
|
|
425
|
+
.run(sourceDetails.sourceValue, input.trustScore ?? 1.0, input.sensitivityLevel ?? 'INTERNAL', result.lastInsertRowid);
|
|
373
426
|
}
|
|
374
427
|
return result.lastInsertRowid;
|
|
375
428
|
})();
|
|
@@ -380,6 +433,9 @@ export function addMemory(input, config = DEFAULT_CONFIG, source) {
|
|
|
380
433
|
persistEvent('memory_created', { memory });
|
|
381
434
|
// Webhook notification (fire-and-forget)
|
|
382
435
|
dispatchWebhook('memory_created', { id: memory.id, title: memory.title, category: memory.category });
|
|
436
|
+
if (isFeatureEnabled('cloud_sync')) {
|
|
437
|
+
syncMemoryUpsertToCloud(memory);
|
|
438
|
+
}
|
|
383
439
|
// ORGANIC FEATURE: Auto-link to related memories
|
|
384
440
|
// This builds the knowledge graph automatically as memories are created
|
|
385
441
|
try {
|
|
@@ -397,6 +453,9 @@ export function addMemory(input, config = DEFAULT_CONFIG, source) {
|
|
|
397
453
|
const extraction = extractFromMemory(input.title, truncationResult.content, category);
|
|
398
454
|
if (extraction.entities.length > 0) {
|
|
399
455
|
processExtractionResult(extraction, memory.id);
|
|
456
|
+
if (isFeatureEnabled('cloud_sync')) {
|
|
457
|
+
syncGraphForMemoryToCloud(memory.id);
|
|
458
|
+
}
|
|
400
459
|
}
|
|
401
460
|
}
|
|
402
461
|
catch (e) {
|
|
@@ -443,30 +502,32 @@ export function addMemory(input, config = DEFAULT_CONFIG, source) {
|
|
|
443
502
|
});
|
|
444
503
|
// Anti-bloat: Check if limits exceeded and trigger async cleanup
|
|
445
504
|
// We use setImmediate to not block the insert response
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
505
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
506
|
+
setImmediate(() => {
|
|
507
|
+
try {
|
|
508
|
+
if (!isDatabaseInitialized()) {
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
const stats = getMemoryStats();
|
|
512
|
+
if (stats.shortTerm > config.maxShortTermMemories ||
|
|
513
|
+
stats.longTerm > config.maxLongTermMemories) {
|
|
514
|
+
// Import dynamically to avoid circular dependency
|
|
515
|
+
import('./consolidate.js').then(({ enforceMemoryLimits }) => {
|
|
516
|
+
if (typeof enforceMemoryLimits === 'function') {
|
|
517
|
+
enforceMemoryLimits(config);
|
|
518
|
+
}
|
|
519
|
+
}).catch((e) => {
|
|
520
|
+
// Log but don't fail - consolidation will happen on next scheduled run
|
|
521
|
+
console.warn('[shieldcortex] Async cleanup import failed:', e instanceof Error ? e.message : e);
|
|
522
|
+
});
|
|
523
|
+
}
|
|
450
524
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
// Import dynamically to avoid circular dependency
|
|
455
|
-
import('./consolidate.js').then(({ enforceMemoryLimits }) => {
|
|
456
|
-
if (typeof enforceMemoryLimits === 'function') {
|
|
457
|
-
enforceMemoryLimits(config);
|
|
458
|
-
}
|
|
459
|
-
}).catch((e) => {
|
|
460
|
-
// Log but don't fail - consolidation will happen on next scheduled run
|
|
461
|
-
console.warn('[shieldcortex] Async cleanup import failed:', e instanceof Error ? e.message : e);
|
|
462
|
-
});
|
|
525
|
+
catch (e) {
|
|
526
|
+
// Log unexpected errors in async cleanup
|
|
527
|
+
console.warn('[shieldcortex] Async cleanup check failed:', e instanceof Error ? e.message : e);
|
|
463
528
|
}
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
// Log unexpected errors in async cleanup
|
|
467
|
-
console.warn('[shieldcortex] Async cleanup check failed:', e instanceof Error ? e.message : e);
|
|
468
|
-
}
|
|
469
|
-
});
|
|
529
|
+
});
|
|
530
|
+
}
|
|
470
531
|
return memory;
|
|
471
532
|
}
|
|
472
533
|
/**
|
|
@@ -529,15 +590,69 @@ export function updateMemory(id, updates) {
|
|
|
529
590
|
fields.push('metadata = ?');
|
|
530
591
|
values.push(JSON.stringify(updates.metadata));
|
|
531
592
|
}
|
|
593
|
+
if (updates.status !== undefined) {
|
|
594
|
+
fields.push('status = ?');
|
|
595
|
+
values.push(updates.status);
|
|
596
|
+
}
|
|
597
|
+
if (updates.pinned !== undefined) {
|
|
598
|
+
fields.push('pinned = ?');
|
|
599
|
+
values.push(updates.pinned ? 1 : 0);
|
|
600
|
+
}
|
|
601
|
+
if (updates.reviewedBy !== undefined) {
|
|
602
|
+
fields.push('reviewed_by = ?');
|
|
603
|
+
values.push(updates.reviewedBy);
|
|
604
|
+
fields.push('reviewed_at = ?');
|
|
605
|
+
values.push(updates.reviewedBy ? new Date().toISOString() : null);
|
|
606
|
+
}
|
|
607
|
+
if (updates.sourceKind !== undefined) {
|
|
608
|
+
fields.push('source_kind = ?');
|
|
609
|
+
values.push(updates.sourceKind);
|
|
610
|
+
}
|
|
611
|
+
if (updates.captureMethod !== undefined) {
|
|
612
|
+
fields.push('capture_method = ?');
|
|
613
|
+
values.push(updates.captureMethod);
|
|
614
|
+
}
|
|
615
|
+
if (updates.trustScore !== undefined) {
|
|
616
|
+
fields.push('trust_score = ?');
|
|
617
|
+
values.push(updates.trustScore);
|
|
618
|
+
}
|
|
619
|
+
if (updates.sensitivityLevel !== undefined) {
|
|
620
|
+
fields.push('sensitivity_level = ?');
|
|
621
|
+
values.push(updates.sensitivityLevel);
|
|
622
|
+
}
|
|
623
|
+
if (updates.source !== undefined) {
|
|
624
|
+
fields.push('source = ?');
|
|
625
|
+
values.push(updates.source);
|
|
626
|
+
}
|
|
627
|
+
if (updates.cloudExcluded !== undefined) {
|
|
628
|
+
fields.push('cloud_excluded = ?');
|
|
629
|
+
values.push(updates.cloudExcluded ? 1 : 0);
|
|
630
|
+
}
|
|
532
631
|
if (fields.length === 0)
|
|
533
632
|
return existing;
|
|
534
633
|
values.push(id);
|
|
535
|
-
db.prepare(`UPDATE memories SET ${fields.join(', ')} WHERE id = ?`).run(...values);
|
|
634
|
+
db.prepare(`UPDATE memories SET ${fields.join(', ')}, updated_at = CURRENT_TIMESTAMP WHERE id = ?`).run(...values);
|
|
536
635
|
const updatedMemory = getMemoryById(id);
|
|
636
|
+
const shouldRefreshGraph = updates.title !== undefined ||
|
|
637
|
+
updates.content !== undefined ||
|
|
638
|
+
updates.category !== undefined;
|
|
639
|
+
if (shouldRefreshGraph) {
|
|
640
|
+
try {
|
|
641
|
+
const extraction = extractFromMemory(updatedMemory.title, updatedMemory.content, updatedMemory.category);
|
|
642
|
+
replaceMemoryGraph(updatedMemory.id, extraction);
|
|
643
|
+
}
|
|
644
|
+
catch (e) {
|
|
645
|
+
console.error('[shieldcortex] Entity extraction refresh failed:', e);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
537
648
|
// Emit event for real-time dashboard (in-process)
|
|
538
649
|
emitMemoryUpdated(updatedMemory);
|
|
539
650
|
// Persist event for cross-process IPC (MCP → Dashboard)
|
|
540
651
|
persistEvent('memory_updated', { memory: updatedMemory });
|
|
652
|
+
if (isFeatureEnabled('cloud_sync')) {
|
|
653
|
+
syncMemoryUpsertToCloud(updatedMemory);
|
|
654
|
+
syncGraphForMemoryToCloud(updatedMemory.id);
|
|
655
|
+
}
|
|
541
656
|
return updatedMemory;
|
|
542
657
|
}
|
|
543
658
|
/**
|
|
@@ -558,9 +673,21 @@ export function deleteMemory(id, source) {
|
|
|
558
673
|
}
|
|
559
674
|
// Get memory before deletion for event
|
|
560
675
|
const memory = getMemoryById(id);
|
|
676
|
+
if (memory) {
|
|
677
|
+
try {
|
|
678
|
+
removeMemoryGraph(id);
|
|
679
|
+
}
|
|
680
|
+
catch (e) {
|
|
681
|
+
console.error('[shieldcortex] Graph cleanup before delete failed:', e);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
561
684
|
const result = db.prepare('DELETE FROM memories WHERE id = ?').run(id);
|
|
562
685
|
// Emit event for real-time dashboard (in-process)
|
|
563
686
|
if (result.changes > 0 && memory) {
|
|
687
|
+
if (isFeatureEnabled('cloud_sync')) {
|
|
688
|
+
syncMemoryDeleteToCloud(memory);
|
|
689
|
+
syncGraphDeleteForMemoryToCloud(memory);
|
|
690
|
+
}
|
|
564
691
|
emitMemoryDeleted(id, memory.title);
|
|
565
692
|
// Persist event for cross-process IPC (MCP → Dashboard)
|
|
566
693
|
persistEvent('memory_deleted', { memoryId: id, title: memory.title });
|
|
@@ -837,6 +964,12 @@ async function searchMemoriesInternal(options, config, source, execution) {
|
|
|
837
964
|
sql += ' AND m.type = ?';
|
|
838
965
|
params.push(options.type);
|
|
839
966
|
}
|
|
967
|
+
if (!options.includeArchived) {
|
|
968
|
+
sql += ` AND m.status != 'archived'`;
|
|
969
|
+
}
|
|
970
|
+
if (!options.includeSuppressed) {
|
|
971
|
+
sql += ` AND m.status != 'suppressed'`;
|
|
972
|
+
}
|
|
840
973
|
if (options.minSalience) {
|
|
841
974
|
sql += ' AND m.salience >= ?';
|
|
842
975
|
params.push(options.minSalience);
|
|
@@ -875,12 +1008,33 @@ async function searchMemoriesInternal(options, config, source, execution) {
|
|
|
875
1008
|
const vectorSimilarity = vectorResults.get(memory.id) || 0;
|
|
876
1009
|
const vectorBoost = vectorSimilarity * 0.3;
|
|
877
1010
|
const priorityBoost = calculatePriority(memory) * 0.05;
|
|
1011
|
+
const contradictionCount = db.prepare(`SELECT COUNT(*) as count FROM memory_links WHERE relationship = 'contradicts' AND (source_id = ? OR target_id = ?)`).get(memory.id, memory.id).count;
|
|
1012
|
+
const contradictionPenalty = Math.min(0.12, contradictionCount * 0.03);
|
|
1013
|
+
const eligibilityReasons = [];
|
|
1014
|
+
if (memory.status === 'archived')
|
|
1015
|
+
eligibilityReasons.push('Archived memories are excluded from normal recall');
|
|
1016
|
+
if (memory.status === 'suppressed')
|
|
1017
|
+
eligibilityReasons.push('Suppressed memories are excluded from normal recall');
|
|
1018
|
+
if (memory.cloudExcluded)
|
|
1019
|
+
eligibilityReasons.push('Excluded from cloud sync');
|
|
1020
|
+
if (memory.trustScore < 0.7)
|
|
1021
|
+
eligibilityReasons.push(`Low trust source (${memory.trustScore.toFixed(2)})`);
|
|
1022
|
+
if (contradictionCount > 0)
|
|
1023
|
+
eligibilityReasons.push(`${contradictionCount} contradiction link${contradictionCount === 1 ? '' : 's'} attached`);
|
|
878
1024
|
const relevanceScore = (ftsScore * 0.25 +
|
|
879
1025
|
vectorBoost +
|
|
880
1026
|
decayedScore * 0.2 +
|
|
881
1027
|
priorityBoost +
|
|
882
|
-
recencyBoost + categoryBoost + linkBoost + tagBoost + activationBoost
|
|
883
|
-
|
|
1028
|
+
recencyBoost + categoryBoost + linkBoost + tagBoost + activationBoost -
|
|
1029
|
+
contradictionPenalty);
|
|
1030
|
+
const result = {
|
|
1031
|
+
memory,
|
|
1032
|
+
relevanceScore,
|
|
1033
|
+
recallEligibility: {
|
|
1034
|
+
eligible: eligibilityReasons.length === 0,
|
|
1035
|
+
reasons: eligibilityReasons,
|
|
1036
|
+
},
|
|
1037
|
+
};
|
|
884
1038
|
if (execution.includeExplanation) {
|
|
885
1039
|
result.explanation = buildSearchExplanation(memory, scoringContext, {
|
|
886
1040
|
ftsScore,
|
|
@@ -893,8 +1047,12 @@ async function searchMemoriesInternal(options, config, source, execution) {
|
|
|
893
1047
|
linkBoost,
|
|
894
1048
|
tagBoost,
|
|
895
1049
|
activationBoost,
|
|
1050
|
+
contradictionPenalty,
|
|
896
1051
|
finalScore: relevanceScore,
|
|
897
1052
|
});
|
|
1053
|
+
if (result.explanation) {
|
|
1054
|
+
result.explanation.eligibility = result.recallEligibility;
|
|
1055
|
+
}
|
|
898
1056
|
}
|
|
899
1057
|
return result;
|
|
900
1058
|
});
|
package/dist/memory/types.d.ts
CHANGED
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
* Core type definitions for the ShieldCortex memory system
|
|
3
3
|
*/
|
|
4
4
|
export type MemoryType = 'short_term' | 'long_term' | 'episodic';
|
|
5
|
+
export type MemoryStatus = 'active' | 'archived' | 'suppressed' | 'canonical';
|
|
6
|
+
export type MemorySourceKind = 'user' | 'cli' | 'hook' | 'plugin' | 'agent' | 'import' | 'cloud' | 'api' | 'system';
|
|
7
|
+
export type MemoryCaptureMethod = 'manual' | 'hook' | 'plugin' | 'import' | 'cloud' | 'api' | 'auto' | 'review';
|
|
5
8
|
export type MemoryCategory = 'architecture' | 'pattern' | 'preference' | 'error' | 'context' | 'learning' | 'todo' | 'note' | 'relationship' | 'custom';
|
|
6
9
|
export interface Memory {
|
|
7
10
|
id: number;
|
|
11
|
+
uuid: string;
|
|
8
12
|
type: MemoryType;
|
|
9
13
|
category: MemoryCategory;
|
|
10
14
|
title: string;
|
|
@@ -15,11 +19,22 @@ export interface Memory {
|
|
|
15
19
|
accessCount: number;
|
|
16
20
|
lastAccessed: Date;
|
|
17
21
|
createdAt: Date;
|
|
22
|
+
updatedAt: Date;
|
|
18
23
|
decayedScore: number;
|
|
19
24
|
metadata: Record<string, unknown>;
|
|
20
25
|
embedding?: Buffer;
|
|
21
26
|
scope: 'project' | 'global';
|
|
22
27
|
transferable: boolean;
|
|
28
|
+
status: MemoryStatus;
|
|
29
|
+
pinned: boolean;
|
|
30
|
+
reviewedAt: Date | null;
|
|
31
|
+
reviewedBy: string | null;
|
|
32
|
+
sourceKind: MemorySourceKind;
|
|
33
|
+
captureMethod: MemoryCaptureMethod;
|
|
34
|
+
trustScore: number;
|
|
35
|
+
sensitivityLevel: string;
|
|
36
|
+
source: string | null;
|
|
37
|
+
cloudExcluded: boolean;
|
|
23
38
|
}
|
|
24
39
|
export interface MemoryInput {
|
|
25
40
|
type?: MemoryType;
|
|
@@ -32,6 +47,15 @@ export interface MemoryInput {
|
|
|
32
47
|
metadata?: Record<string, unknown>;
|
|
33
48
|
scope?: 'project' | 'global';
|
|
34
49
|
transferable?: boolean;
|
|
50
|
+
status?: MemoryStatus;
|
|
51
|
+
pinned?: boolean;
|
|
52
|
+
reviewedBy?: string | null;
|
|
53
|
+
sourceKind?: MemorySourceKind;
|
|
54
|
+
captureMethod?: MemoryCaptureMethod;
|
|
55
|
+
trustScore?: number;
|
|
56
|
+
sensitivityLevel?: string;
|
|
57
|
+
source?: string | null;
|
|
58
|
+
cloudExcluded?: boolean;
|
|
35
59
|
}
|
|
36
60
|
export interface SearchOptions {
|
|
37
61
|
query: string;
|
|
@@ -43,6 +67,8 @@ export interface SearchOptions {
|
|
|
43
67
|
limit?: number;
|
|
44
68
|
includeDecayed?: boolean;
|
|
45
69
|
includeGlobal?: boolean;
|
|
70
|
+
includeArchived?: boolean;
|
|
71
|
+
includeSuppressed?: boolean;
|
|
46
72
|
}
|
|
47
73
|
export interface SearchResult {
|
|
48
74
|
memory: Memory;
|
|
@@ -53,6 +79,7 @@ export interface SearchResult {
|
|
|
53
79
|
score: number;
|
|
54
80
|
}[];
|
|
55
81
|
explanation?: SearchExplanation;
|
|
82
|
+
recallEligibility?: RecallEligibility;
|
|
56
83
|
}
|
|
57
84
|
export interface SearchScoreBreakdown {
|
|
58
85
|
ftsScore: number;
|
|
@@ -65,14 +92,20 @@ export interface SearchScoreBreakdown {
|
|
|
65
92
|
linkBoost: number;
|
|
66
93
|
tagBoost: number;
|
|
67
94
|
activationBoost: number;
|
|
95
|
+
contradictionPenalty: number;
|
|
68
96
|
finalScore: number;
|
|
69
97
|
matchedTags: string[];
|
|
70
98
|
matchedCategory: string | null;
|
|
71
99
|
}
|
|
100
|
+
export interface RecallEligibility {
|
|
101
|
+
eligible: boolean;
|
|
102
|
+
reasons: string[];
|
|
103
|
+
}
|
|
72
104
|
export interface SearchExplanation {
|
|
73
105
|
query: string;
|
|
74
106
|
reasons: string[];
|
|
75
107
|
breakdown: SearchScoreBreakdown;
|
|
108
|
+
eligibility?: RecallEligibility;
|
|
76
109
|
}
|
|
77
110
|
export interface ConsolidationResult {
|
|
78
111
|
consolidated: number;
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* - Windows: VBS script in Startup folder
|
|
8
8
|
*/
|
|
9
9
|
export declare function installService(): Promise<void>;
|
|
10
|
+
export declare function repairService(): Promise<void>;
|
|
10
11
|
export declare function uninstallService(options?: {
|
|
11
12
|
cleanLogs?: boolean;
|
|
12
13
|
}): Promise<void>;
|
package/dist/service/install.js
CHANGED
|
@@ -31,6 +31,33 @@ function getServiceConfig() {
|
|
|
31
31
|
logsDir,
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
|
+
function inspectServiceEntryPoint(platform, servicePath) {
|
|
35
|
+
if (!fs.existsSync(servicePath)) {
|
|
36
|
+
return { entryPoint: null, stale: false };
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const content = fs.readFileSync(servicePath, 'utf-8');
|
|
40
|
+
let entryPoint = null;
|
|
41
|
+
if (platform === 'macos') {
|
|
42
|
+
const matches = [...content.matchAll(/<string>([^<]+)<\/string>/g)].map((match) => match[1]);
|
|
43
|
+
entryPoint = matches.find((value) => value.endsWith('index.js')) ?? null;
|
|
44
|
+
}
|
|
45
|
+
else if (platform === 'linux') {
|
|
46
|
+
const match = content.match(/ExecStart=\S+\s+(\S+index\.js)/);
|
|
47
|
+
entryPoint = match?.[1] ?? null;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
const match = content.match(/Run\s+\"\"[^\"]+\"\"\s+\"\"([^\"]+index\.js)\"\"/);
|
|
51
|
+
entryPoint = match?.[1] ?? null;
|
|
52
|
+
}
|
|
53
|
+
const currentEntryPoint = getServiceConfig().entryPoint;
|
|
54
|
+
const stale = !!entryPoint && (entryPoint.includes('/.npm/_npx/') || entryPoint !== currentEntryPoint);
|
|
55
|
+
return { entryPoint, stale };
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return { entryPoint: null, stale: false };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
34
61
|
function getServicePath(platform) {
|
|
35
62
|
switch (platform) {
|
|
36
63
|
case 'macos':
|
|
@@ -91,6 +118,10 @@ export async function installService() {
|
|
|
91
118
|
console.log(` API: http://localhost:3001`);
|
|
92
119
|
console.log(` Dashboard: http://localhost:3030`);
|
|
93
120
|
}
|
|
121
|
+
export async function repairService() {
|
|
122
|
+
await uninstallService();
|
|
123
|
+
await installService();
|
|
124
|
+
}
|
|
94
125
|
function cleanLogsDirectory() {
|
|
95
126
|
const logsDir = path.join(os.homedir(), '.shieldcortex', 'logs');
|
|
96
127
|
if (fs.existsSync(logsDir)) {
|
|
@@ -131,9 +162,14 @@ export async function serviceStatus() {
|
|
|
131
162
|
const platform = detectPlatform();
|
|
132
163
|
const servicePath = getServicePath(platform);
|
|
133
164
|
const installed = fs.existsSync(servicePath);
|
|
165
|
+
const inspection = inspectServiceEntryPoint(platform, servicePath);
|
|
134
166
|
console.log(`Platform: ${platform}`);
|
|
135
167
|
console.log(`Installed: ${installed ? 'yes' : 'no'}`);
|
|
136
168
|
console.log(`Path: ${servicePath}`);
|
|
169
|
+
if (inspection.entryPoint) {
|
|
170
|
+
console.log(`Entry: ${inspection.entryPoint}`);
|
|
171
|
+
console.log(`Healthy: ${inspection.stale ? 'no (repair recommended)' : 'yes'}`);
|
|
172
|
+
}
|
|
137
173
|
if (!installed)
|
|
138
174
|
return;
|
|
139
175
|
// Check if running
|
|
@@ -158,12 +194,18 @@ export async function serviceStatus() {
|
|
|
158
194
|
catch {
|
|
159
195
|
console.log('Running: no');
|
|
160
196
|
}
|
|
197
|
+
if (inspection.stale) {
|
|
198
|
+
console.log('Repair: shieldcortex service repair');
|
|
199
|
+
}
|
|
161
200
|
}
|
|
162
201
|
export async function handleServiceCommand(subcommand) {
|
|
163
202
|
switch (subcommand) {
|
|
164
203
|
case 'install':
|
|
165
204
|
await installService();
|
|
166
205
|
break;
|
|
206
|
+
case 'repair':
|
|
207
|
+
await repairService();
|
|
208
|
+
break;
|
|
167
209
|
case 'uninstall':
|
|
168
210
|
await uninstallService({ cleanLogs: process.argv.includes('--clean-logs') });
|
|
169
211
|
break;
|
|
@@ -171,7 +213,7 @@ export async function handleServiceCommand(subcommand) {
|
|
|
171
213
|
await serviceStatus();
|
|
172
214
|
break;
|
|
173
215
|
default:
|
|
174
|
-
console.log('Usage: shieldcortex service <install|uninstall|status>');
|
|
216
|
+
console.log('Usage: shieldcortex service <install|repair|uninstall|status>');
|
|
175
217
|
process.exit(1);
|
|
176
218
|
}
|
|
177
219
|
}
|
package/dist/tools/context.d.ts
CHANGED
|
@@ -15,23 +15,23 @@ export declare const getContextSchema: z.ZodObject<{
|
|
|
15
15
|
type: z.ZodEnum<["user", "cli", "hook", "email", "web", "agent", "file", "api", "tool_response"]>;
|
|
16
16
|
identifier: z.ZodString;
|
|
17
17
|
}, "strip", z.ZodTypeAny, {
|
|
18
|
-
type: "
|
|
18
|
+
type: "user" | "cli" | "hook" | "agent" | "api" | "email" | "web" | "file" | "tool_response";
|
|
19
19
|
identifier: string;
|
|
20
20
|
}, {
|
|
21
|
-
type: "
|
|
21
|
+
type: "user" | "cli" | "hook" | "agent" | "api" | "email" | "web" | "file" | "tool_response";
|
|
22
22
|
identifier: string;
|
|
23
23
|
}>>;
|
|
24
24
|
}, "strip", z.ZodTypeAny, {
|
|
25
25
|
format: "summary" | "detailed" | "raw";
|
|
26
26
|
source?: {
|
|
27
|
-
type: "
|
|
27
|
+
type: "user" | "cli" | "hook" | "agent" | "api" | "email" | "web" | "file" | "tool_response";
|
|
28
28
|
identifier: string;
|
|
29
29
|
} | undefined;
|
|
30
30
|
project?: string | undefined;
|
|
31
31
|
query?: string | undefined;
|
|
32
32
|
}, {
|
|
33
33
|
source?: {
|
|
34
|
-
type: "
|
|
34
|
+
type: "user" | "cli" | "hook" | "agent" | "api" | "email" | "web" | "file" | "tool_response";
|
|
35
35
|
identifier: string;
|
|
36
36
|
} | undefined;
|
|
37
37
|
project?: string | undefined;
|
package/dist/tools/forget.d.ts
CHANGED
|
@@ -17,34 +17,34 @@ export declare const forgetSchema: z.ZodObject<{
|
|
|
17
17
|
type: z.ZodEnum<["user", "cli", "hook", "email", "web", "agent", "file", "api", "tool_response"]>;
|
|
18
18
|
identifier: z.ZodString;
|
|
19
19
|
}, "strip", z.ZodTypeAny, {
|
|
20
|
-
type: "
|
|
20
|
+
type: "user" | "cli" | "hook" | "agent" | "api" | "email" | "web" | "file" | "tool_response";
|
|
21
21
|
identifier: string;
|
|
22
22
|
}, {
|
|
23
|
-
type: "
|
|
23
|
+
type: "user" | "cli" | "hook" | "agent" | "api" | "email" | "web" | "file" | "tool_response";
|
|
24
24
|
identifier: string;
|
|
25
25
|
}>>;
|
|
26
26
|
}, "strip", z.ZodTypeAny, {
|
|
27
27
|
dryRun: boolean;
|
|
28
28
|
confirm: boolean;
|
|
29
29
|
source?: {
|
|
30
|
-
type: "
|
|
30
|
+
type: "user" | "cli" | "hook" | "agent" | "api" | "email" | "web" | "file" | "tool_response";
|
|
31
31
|
identifier: string;
|
|
32
32
|
} | undefined;
|
|
33
33
|
project?: string | undefined;
|
|
34
34
|
id?: number | undefined;
|
|
35
|
-
query?: string | undefined;
|
|
36
35
|
category?: "architecture" | "pattern" | "preference" | "error" | "context" | "learning" | "todo" | "note" | "relationship" | "custom" | undefined;
|
|
36
|
+
query?: string | undefined;
|
|
37
37
|
olderThan?: number | undefined;
|
|
38
38
|
belowSalience?: number | undefined;
|
|
39
39
|
}, {
|
|
40
40
|
source?: {
|
|
41
|
-
type: "
|
|
41
|
+
type: "user" | "cli" | "hook" | "agent" | "api" | "email" | "web" | "file" | "tool_response";
|
|
42
42
|
identifier: string;
|
|
43
43
|
} | undefined;
|
|
44
44
|
project?: string | undefined;
|
|
45
45
|
id?: number | undefined;
|
|
46
|
-
query?: string | undefined;
|
|
47
46
|
category?: "architecture" | "pattern" | "preference" | "error" | "context" | "learning" | "todo" | "note" | "relationship" | "custom" | undefined;
|
|
47
|
+
query?: string | undefined;
|
|
48
48
|
olderThan?: number | undefined;
|
|
49
49
|
belowSalience?: number | undefined;
|
|
50
50
|
dryRun?: boolean | undefined;
|