stellar-memory 0.5.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/LICENSE +21 -0
- package/README.md +362 -0
- package/dist/api/routes/analytics.d.ts +15 -0
- package/dist/api/routes/analytics.js +131 -0
- package/dist/api/routes/analytics.js.map +1 -0
- package/dist/api/routes/conflicts.d.ts +12 -0
- package/dist/api/routes/conflicts.js +67 -0
- package/dist/api/routes/conflicts.js.map +1 -0
- package/dist/api/routes/consolidation.d.ts +11 -0
- package/dist/api/routes/consolidation.js +63 -0
- package/dist/api/routes/consolidation.js.map +1 -0
- package/dist/api/routes/constellation.d.ts +4 -0
- package/dist/api/routes/constellation.js +84 -0
- package/dist/api/routes/constellation.js.map +1 -0
- package/dist/api/routes/memories.d.ts +4 -0
- package/dist/api/routes/memories.js +219 -0
- package/dist/api/routes/memories.js.map +1 -0
- package/dist/api/routes/observations.d.ts +10 -0
- package/dist/api/routes/observations.js +42 -0
- package/dist/api/routes/observations.js.map +1 -0
- package/dist/api/routes/orbit.d.ts +4 -0
- package/dist/api/routes/orbit.js +71 -0
- package/dist/api/routes/orbit.js.map +1 -0
- package/dist/api/routes/projects.d.ts +15 -0
- package/dist/api/routes/projects.js +121 -0
- package/dist/api/routes/projects.js.map +1 -0
- package/dist/api/routes/scan.d.ts +4 -0
- package/dist/api/routes/scan.js +403 -0
- package/dist/api/routes/scan.js.map +1 -0
- package/dist/api/routes/sun.d.ts +4 -0
- package/dist/api/routes/sun.js +43 -0
- package/dist/api/routes/sun.js.map +1 -0
- package/dist/api/routes/system.d.ts +4 -0
- package/dist/api/routes/system.js +70 -0
- package/dist/api/routes/system.js.map +1 -0
- package/dist/api/routes/temporal.d.ts +13 -0
- package/dist/api/routes/temporal.js +82 -0
- package/dist/api/routes/temporal.js.map +1 -0
- package/dist/api/server.d.ts +2 -0
- package/dist/api/server.js +99 -0
- package/dist/api/server.js.map +1 -0
- package/dist/api/websocket.d.ts +53 -0
- package/dist/api/websocket.js +168 -0
- package/dist/api/websocket.js.map +1 -0
- package/dist/cli/index.d.ts +12 -0
- package/dist/cli/index.js +35 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +10 -0
- package/dist/cli/init.js +163 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/engine/analytics.d.ts +93 -0
- package/dist/engine/analytics.js +437 -0
- package/dist/engine/analytics.js.map +1 -0
- package/dist/engine/conflict.d.ts +54 -0
- package/dist/engine/conflict.js +322 -0
- package/dist/engine/conflict.js.map +1 -0
- package/dist/engine/consolidation.d.ts +83 -0
- package/dist/engine/consolidation.js +368 -0
- package/dist/engine/consolidation.js.map +1 -0
- package/dist/engine/constellation.d.ts +66 -0
- package/dist/engine/constellation.js +382 -0
- package/dist/engine/constellation.js.map +1 -0
- package/dist/engine/corona.d.ts +53 -0
- package/dist/engine/corona.js +181 -0
- package/dist/engine/corona.js.map +1 -0
- package/dist/engine/embedding.d.ts +44 -0
- package/dist/engine/embedding.js +168 -0
- package/dist/engine/embedding.js.map +1 -0
- package/dist/engine/gravity.d.ts +63 -0
- package/dist/engine/gravity.js +121 -0
- package/dist/engine/gravity.js.map +1 -0
- package/dist/engine/multiproject.d.ts +75 -0
- package/dist/engine/multiproject.js +241 -0
- package/dist/engine/multiproject.js.map +1 -0
- package/dist/engine/observation.d.ts +82 -0
- package/dist/engine/observation.js +357 -0
- package/dist/engine/observation.js.map +1 -0
- package/dist/engine/orbit.d.ts +91 -0
- package/dist/engine/orbit.js +249 -0
- package/dist/engine/orbit.js.map +1 -0
- package/dist/engine/planet.d.ts +64 -0
- package/dist/engine/planet.js +432 -0
- package/dist/engine/planet.js.map +1 -0
- package/dist/engine/procedural.d.ts +71 -0
- package/dist/engine/procedural.js +259 -0
- package/dist/engine/procedural.js.map +1 -0
- package/dist/engine/quality.d.ts +48 -0
- package/dist/engine/quality.js +245 -0
- package/dist/engine/quality.js.map +1 -0
- package/dist/engine/repository.d.ts +79 -0
- package/dist/engine/repository.js +13 -0
- package/dist/engine/repository.js.map +1 -0
- package/dist/engine/sun.d.ts +61 -0
- package/dist/engine/sun.js +240 -0
- package/dist/engine/sun.js.map +1 -0
- package/dist/engine/temporal.d.ts +67 -0
- package/dist/engine/temporal.js +283 -0
- package/dist/engine/temporal.js.map +1 -0
- package/dist/engine/types.d.ts +179 -0
- package/dist/engine/types.js +27 -0
- package/dist/engine/types.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/connector-registry.d.ts +20 -0
- package/dist/mcp/connector-registry.js +35 -0
- package/dist/mcp/connector-registry.js.map +1 -0
- package/dist/mcp/server.d.ts +13 -0
- package/dist/mcp/server.js +242 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/daemon-tool.d.ts +16 -0
- package/dist/mcp/tools/daemon-tool.js +58 -0
- package/dist/mcp/tools/daemon-tool.js.map +1 -0
- package/dist/mcp/tools/ingestion-tools.d.ts +20 -0
- package/dist/mcp/tools/ingestion-tools.js +34 -0
- package/dist/mcp/tools/ingestion-tools.js.map +1 -0
- package/dist/mcp/tools/memory-tools.d.ts +122 -0
- package/dist/mcp/tools/memory-tools.js +1037 -0
- package/dist/mcp/tools/memory-tools.js.map +1 -0
- package/dist/scanner/cloud/github.d.ts +34 -0
- package/dist/scanner/cloud/github.js +260 -0
- package/dist/scanner/cloud/github.js.map +1 -0
- package/dist/scanner/cloud/google-drive.d.ts +30 -0
- package/dist/scanner/cloud/google-drive.js +289 -0
- package/dist/scanner/cloud/google-drive.js.map +1 -0
- package/dist/scanner/cloud/notion.d.ts +33 -0
- package/dist/scanner/cloud/notion.js +231 -0
- package/dist/scanner/cloud/notion.js.map +1 -0
- package/dist/scanner/cloud/slack.d.ts +38 -0
- package/dist/scanner/cloud/slack.js +282 -0
- package/dist/scanner/cloud/slack.js.map +1 -0
- package/dist/scanner/cloud/types.d.ts +73 -0
- package/dist/scanner/cloud/types.js +9 -0
- package/dist/scanner/cloud/types.js.map +1 -0
- package/dist/scanner/index.d.ts +35 -0
- package/dist/scanner/index.js +420 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/scanner/local/filesystem.d.ts +33 -0
- package/dist/scanner/local/filesystem.js +203 -0
- package/dist/scanner/local/filesystem.js.map +1 -0
- package/dist/scanner/local/git.d.ts +24 -0
- package/dist/scanner/local/git.js +161 -0
- package/dist/scanner/local/git.js.map +1 -0
- package/dist/scanner/local/parsers/code.d.ts +3 -0
- package/dist/scanner/local/parsers/code.js +127 -0
- package/dist/scanner/local/parsers/code.js.map +1 -0
- package/dist/scanner/local/parsers/index.d.ts +11 -0
- package/dist/scanner/local/parsers/index.js +24 -0
- package/dist/scanner/local/parsers/index.js.map +1 -0
- package/dist/scanner/local/parsers/json-parser.d.ts +3 -0
- package/dist/scanner/local/parsers/json-parser.js +117 -0
- package/dist/scanner/local/parsers/json-parser.js.map +1 -0
- package/dist/scanner/local/parsers/markdown.d.ts +3 -0
- package/dist/scanner/local/parsers/markdown.js +120 -0
- package/dist/scanner/local/parsers/markdown.js.map +1 -0
- package/dist/scanner/local/parsers/text.d.ts +3 -0
- package/dist/scanner/local/parsers/text.js +41 -0
- package/dist/scanner/local/parsers/text.js.map +1 -0
- package/dist/scanner/metadata-scanner.d.ts +67 -0
- package/dist/scanner/metadata-scanner.js +356 -0
- package/dist/scanner/metadata-scanner.js.map +1 -0
- package/dist/scanner/types.d.ts +47 -0
- package/dist/scanner/types.js +19 -0
- package/dist/scanner/types.js.map +1 -0
- package/dist/service/daemon.d.ts +23 -0
- package/dist/service/daemon.js +105 -0
- package/dist/service/daemon.js.map +1 -0
- package/dist/service/scheduler.d.ts +73 -0
- package/dist/service/scheduler.js +281 -0
- package/dist/service/scheduler.js.map +1 -0
- package/dist/storage/database.d.ts +10 -0
- package/dist/storage/database.js +265 -0
- package/dist/storage/database.js.map +1 -0
- package/dist/storage/queries.d.ts +85 -0
- package/dist/storage/queries.js +865 -0
- package/dist/storage/queries.js.map +1 -0
- package/dist/storage/sqlite-repository.d.ts +32 -0
- package/dist/storage/sqlite-repository.js +68 -0
- package/dist/storage/sqlite-repository.js.map +1 -0
- package/dist/storage/vec.d.ts +62 -0
- package/dist/storage/vec.js +111 -0
- package/dist/storage/vec.js.map +1 -0
- package/dist/utils/config.d.ts +5 -0
- package/dist/utils/config.js +60 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/logger.d.ts +36 -0
- package/dist/utils/logger.js +86 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/time.d.ts +21 -0
- package/dist/utils/time.js +42 -0
- package/dist/utils/time.js.map +1 -0
- package/dist/utils/tokenizer.d.ts +13 -0
- package/dist/utils/tokenizer.js +46 -0
- package/dist/utils/tokenizer.js.map +1 -0
- package/package.json +77 -0
- package/scripts/check-node.mjs +36 -0
- package/scripts/setup.mjs +157 -0
|
@@ -0,0 +1,1037 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mcp/tools/memory-tools.ts — Handler functions for memory-related MCP tools.
|
|
3
|
+
*
|
|
4
|
+
* Exported functions:
|
|
5
|
+
* handleStatus — status tool
|
|
6
|
+
* handleCommit — commit tool
|
|
7
|
+
* handleRecall — recall tool
|
|
8
|
+
* handleRemember — remember tool
|
|
9
|
+
* handleOrbit — orbit tool
|
|
10
|
+
* handleForget — forget tool
|
|
11
|
+
* handleExport — export tool
|
|
12
|
+
*
|
|
13
|
+
* Each function receives only the parsed tool arguments it needs plus any
|
|
14
|
+
* dependencies injected at call-site. It returns the MCP response object
|
|
15
|
+
* `{ content: [{ type: 'text', text: string }] }`.
|
|
16
|
+
*
|
|
17
|
+
* No McpServer or SDK imports are needed here — that coupling lives in server.ts.
|
|
18
|
+
*/
|
|
19
|
+
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
|
|
20
|
+
import { ORBIT_ZONES } from '../../engine/types.js';
|
|
21
|
+
import { getSunContent, commitToSun } from '../../engine/sun.js';
|
|
22
|
+
import { createMemory, recallMemoriesAsync, forgetMemory } from '../../engine/planet.js';
|
|
23
|
+
import { recalculateOrbits, getOrbitZone } from '../../engine/orbit.js';
|
|
24
|
+
import { getMemoriesByProject } from '../../storage/queries.js';
|
|
25
|
+
import { getConfig } from '../../utils/config.js';
|
|
26
|
+
import { listDataSources } from '../../scanner/index.js';
|
|
27
|
+
import { extractRelationships, getConstellationGraph, findRelatedMemories, } from '../../engine/constellation.js';
|
|
28
|
+
import { switchProject, getCurrentProject, listAllProjects, createProject, getProjectStats, markUniversal, getUniversalContext, detectUniversalCandidates, } from '../../engine/multiproject.js';
|
|
29
|
+
import { getFullAnalytics, getSurvivalCurve, getOrbitMovements, getTopicClusters, detectAccessPatterns, getMemoryHealth, generateReport, } from '../../engine/analytics.js';
|
|
30
|
+
import { calculateQuality, getQualityFeedback } from '../../engine/quality.js';
|
|
31
|
+
import { detectConflicts, formatConflictWarnings, getUnresolvedConflicts, resolveConflict as resolveConflictEngine, } from '../../engine/conflict.js';
|
|
32
|
+
import { detectSupersession, supersedeMemory, getContextAtTime, getEvolutionChain, getTemporalSummary, setTemporalBounds, } from '../../engine/temporal.js';
|
|
33
|
+
import { processConversation } from '../../engine/observation.js';
|
|
34
|
+
import { findConsolidationCandidates, runConsolidation } from '../../engine/consolidation.js';
|
|
35
|
+
import { getProceduralMemories, formatProceduralSection, } from '../../engine/procedural.js';
|
|
36
|
+
import { corona } from '../../engine/corona.js';
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// Corona lazy initialization
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
let coronaReady = false;
|
|
41
|
+
function ensureCorona() {
|
|
42
|
+
if (!coronaReady) {
|
|
43
|
+
corona.warmup(resolveProject());
|
|
44
|
+
coronaReady = true;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
// Async background task error tracking
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
const bgErrors = {
|
|
51
|
+
embedding: 0,
|
|
52
|
+
constellation: 0,
|
|
53
|
+
consolidation: 0,
|
|
54
|
+
};
|
|
55
|
+
/** Increment a background error counter. Called from fire-and-forget tasks. */
|
|
56
|
+
export function trackBgError(category) {
|
|
57
|
+
bgErrors[category]++;
|
|
58
|
+
}
|
|
59
|
+
/** Get background error stats snapshot. */
|
|
60
|
+
export function getBgErrorStats() {
|
|
61
|
+
return { ...bgErrors };
|
|
62
|
+
}
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// Shared helpers
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
function resolveProject() {
|
|
67
|
+
// getCurrentProject() reflects runtime switches via the galaxy tool;
|
|
68
|
+
// falls back to the config default on first call (same initial value).
|
|
69
|
+
return getCurrentProject();
|
|
70
|
+
}
|
|
71
|
+
function labelToZoneKey(label) {
|
|
72
|
+
for (const [key, info] of Object.entries(ORBIT_ZONES)) {
|
|
73
|
+
if (info.label === label)
|
|
74
|
+
return key;
|
|
75
|
+
}
|
|
76
|
+
return 'forgotten';
|
|
77
|
+
}
|
|
78
|
+
function formatDistance(distance) {
|
|
79
|
+
const label = getOrbitZone(distance);
|
|
80
|
+
return `${distance.toFixed(2)} AU (${label})`;
|
|
81
|
+
}
|
|
82
|
+
function formatMemoryLine(m) {
|
|
83
|
+
const pct = (m.importance * 100).toFixed(0);
|
|
84
|
+
return ` [${m.type.toUpperCase()}] ${m.summary} | ${m.distance.toFixed(2)} AU | ${pct}% | ${m.id}`;
|
|
85
|
+
}
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
// status
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
export async function handleStatus(args) {
|
|
90
|
+
try {
|
|
91
|
+
const proj = resolveProject();
|
|
92
|
+
ensureCorona();
|
|
93
|
+
const effectiveLimit = args.limit ?? 50;
|
|
94
|
+
const effectiveZone = args.zone ?? 'all';
|
|
95
|
+
const effectiveShow = args.show ?? 'memories';
|
|
96
|
+
const lines = [];
|
|
97
|
+
if (effectiveShow === 'memories' || effectiveShow === 'all') {
|
|
98
|
+
const all = getMemoriesByProject(proj);
|
|
99
|
+
const memories = all.slice(0, effectiveLimit);
|
|
100
|
+
const filtered = effectiveZone === 'all'
|
|
101
|
+
? memories
|
|
102
|
+
: memories.filter((m) => {
|
|
103
|
+
const zoneKey = labelToZoneKey(getOrbitZone(m.distance));
|
|
104
|
+
return zoneKey === effectiveZone;
|
|
105
|
+
});
|
|
106
|
+
const byZone = {};
|
|
107
|
+
for (const m of filtered) {
|
|
108
|
+
const zoneKey = labelToZoneKey(getOrbitZone(m.distance));
|
|
109
|
+
const bucket = byZone[zoneKey] ?? [];
|
|
110
|
+
bucket.push(m);
|
|
111
|
+
byZone[zoneKey] = bucket;
|
|
112
|
+
}
|
|
113
|
+
const zoneOrder = ['core', 'near', 'active', 'archive', 'fading', 'forgotten'];
|
|
114
|
+
// Stats summary
|
|
115
|
+
const unresolvedConflicts = getUnresolvedConflicts(proj);
|
|
116
|
+
const proceduralCount = all.filter(m => m.type === 'procedural').length;
|
|
117
|
+
const qualityValues = all.map(m => m.quality_score).filter((q) => q !== undefined && q !== null);
|
|
118
|
+
const avgQuality = qualityValues.length > 0
|
|
119
|
+
? qualityValues.reduce((a, b) => a + b, 0) / qualityValues.length
|
|
120
|
+
: null;
|
|
121
|
+
const coronaStats = corona.stats();
|
|
122
|
+
lines.push(`☀ Project: ${proj} | ${filtered.length} memories | corona: ${coronaStats.core} core, ${coronaStats.near} near cached`);
|
|
123
|
+
if (filtered.length > 0) {
|
|
124
|
+
const zoneCounts = zoneOrder
|
|
125
|
+
.map((z) => `${z}: ${(byZone[z] ?? []).length}`)
|
|
126
|
+
.join(' ');
|
|
127
|
+
lines.push(` ${zoneCounts}`);
|
|
128
|
+
}
|
|
129
|
+
// Extended stats
|
|
130
|
+
const statsLine = [];
|
|
131
|
+
if (avgQuality !== null)
|
|
132
|
+
statsLine.push(`avg quality: ${(avgQuality * 100).toFixed(0)}%`);
|
|
133
|
+
if (unresolvedConflicts.length > 0)
|
|
134
|
+
statsLine.push(`conflicts: ${unresolvedConflicts.length}`);
|
|
135
|
+
if (proceduralCount > 0)
|
|
136
|
+
statsLine.push(`procedural: ${proceduralCount}`);
|
|
137
|
+
// Background error stats
|
|
138
|
+
const errors = getBgErrorStats();
|
|
139
|
+
const totalBgErrors = errors.embedding + errors.constellation + errors.consolidation;
|
|
140
|
+
if (totalBgErrors > 0)
|
|
141
|
+
statsLine.push(`bg errors: ${totalBgErrors}`);
|
|
142
|
+
if (statsLine.length > 0)
|
|
143
|
+
lines.push(` ${statsLine.join(' | ')}`);
|
|
144
|
+
if (filtered.length === 0) {
|
|
145
|
+
lines.push(effectiveZone !== 'all'
|
|
146
|
+
? `No memories in zone "${effectiveZone}".`
|
|
147
|
+
: 'No memories yet. Use remember or scan to add some.');
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
lines.push('');
|
|
151
|
+
for (const zoneName of zoneOrder) {
|
|
152
|
+
const zoneMemories = byZone[zoneName];
|
|
153
|
+
if (!zoneMemories || zoneMemories.length === 0)
|
|
154
|
+
continue;
|
|
155
|
+
lines.push(`▸ ${ORBIT_ZONES[zoneName].label} (${zoneMemories.length})`);
|
|
156
|
+
for (const m of zoneMemories)
|
|
157
|
+
lines.push(formatMemoryLine(m));
|
|
158
|
+
lines.push('');
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (effectiveShow === 'sources' || effectiveShow === 'all') {
|
|
163
|
+
if (effectiveShow === 'all')
|
|
164
|
+
lines.push('─────────────────────────────────');
|
|
165
|
+
const sources = listDataSources();
|
|
166
|
+
if (sources.length === 0) {
|
|
167
|
+
lines.push('No data sources registered yet. Use scan to index a directory.');
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
lines.push(`Data sources (${sources.length}):`);
|
|
171
|
+
lines.push('');
|
|
172
|
+
for (const ds of sources) {
|
|
173
|
+
const lastScan = ds.last_scanned_at
|
|
174
|
+
? new Date(ds.last_scanned_at).toLocaleString()
|
|
175
|
+
: 'never';
|
|
176
|
+
const sizeMB = (ds.total_size / 1_048_576).toFixed(2);
|
|
177
|
+
lines.push(` ${ds.path} | ${ds.status} | ${ds.file_count} files (${sizeMB} MB) | last: ${lastScan} | id: ${ds.id}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
if (err instanceof McpError)
|
|
185
|
+
throw err;
|
|
186
|
+
throw new McpError(ErrorCode.InternalError, `status failed: ${String(err)}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// ---------------------------------------------------------------------------
|
|
190
|
+
// commit
|
|
191
|
+
// ---------------------------------------------------------------------------
|
|
192
|
+
export async function handleCommit(args) {
|
|
193
|
+
try {
|
|
194
|
+
const proj = resolveProject();
|
|
195
|
+
const config = getConfig();
|
|
196
|
+
commitToSun(proj, {
|
|
197
|
+
current_work: args.current_work,
|
|
198
|
+
decisions: args.decisions ?? [],
|
|
199
|
+
next_steps: args.next_steps ?? [],
|
|
200
|
+
errors: args.errors ?? [],
|
|
201
|
+
context: args.context ?? '',
|
|
202
|
+
});
|
|
203
|
+
const changes = recalculateOrbits(proj, config);
|
|
204
|
+
const lines = [
|
|
205
|
+
`✓ Committed | decisions: ${(args.decisions ?? []).length} | steps: ${(args.next_steps ?? []).length} | errors: ${(args.errors ?? []).length} | orbit changes: ${changes.length}`,
|
|
206
|
+
];
|
|
207
|
+
// Include procedural section if any procedural memories exist
|
|
208
|
+
const proceduralMems = getProceduralMemories(proj);
|
|
209
|
+
if (proceduralMems.length > 0) {
|
|
210
|
+
lines.push('');
|
|
211
|
+
lines.push(formatProceduralSection(proceduralMems));
|
|
212
|
+
}
|
|
213
|
+
// Include temporal summary
|
|
214
|
+
const temporalSummary = getTemporalSummary(proj);
|
|
215
|
+
if (temporalSummary) {
|
|
216
|
+
lines.push('');
|
|
217
|
+
lines.push(temporalSummary);
|
|
218
|
+
}
|
|
219
|
+
// Include unresolved conflict count
|
|
220
|
+
const unresolvedConflicts = getUnresolvedConflicts(proj);
|
|
221
|
+
if (unresolvedConflicts.length > 0) {
|
|
222
|
+
lines.push('');
|
|
223
|
+
lines.push(`Unresolved conflicts: ${unresolvedConflicts.length} — use resolve_conflict tool to review.`);
|
|
224
|
+
}
|
|
225
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
226
|
+
}
|
|
227
|
+
catch (err) {
|
|
228
|
+
if (err instanceof McpError)
|
|
229
|
+
throw err;
|
|
230
|
+
throw new McpError(ErrorCode.InternalError, `commit failed: ${String(err)}`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// ---------------------------------------------------------------------------
|
|
234
|
+
// recall
|
|
235
|
+
// ---------------------------------------------------------------------------
|
|
236
|
+
export async function handleRecall(args) {
|
|
237
|
+
try {
|
|
238
|
+
const proj = resolveProject();
|
|
239
|
+
const limit = args.limit ?? 10;
|
|
240
|
+
ensureCorona();
|
|
241
|
+
const memoryType = args.type === 'all' || args.type === undefined ? undefined : args.type;
|
|
242
|
+
// If `at` is provided, use temporal point-in-time query instead of normal recall
|
|
243
|
+
let results;
|
|
244
|
+
if (args.at) {
|
|
245
|
+
results = getContextAtTime(proj, args.at).slice(0, limit);
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
// Exclude memories already visible in the Sun resource (corona cache)
|
|
249
|
+
// to avoid token-wasting duplication between Sun and recall output.
|
|
250
|
+
const coreIds = corona.getCoreMemories().map(m => m.id);
|
|
251
|
+
const nearIds = corona.getNearMemories().map(m => m.id);
|
|
252
|
+
const excludeIds = new Set([...coreIds, ...nearIds]);
|
|
253
|
+
results = await recallMemoriesAsync(proj, args.query, {
|
|
254
|
+
type: memoryType,
|
|
255
|
+
maxDistance: args.max_au,
|
|
256
|
+
limit,
|
|
257
|
+
excludeIds,
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
// Optionally merge universal memories from other projects
|
|
261
|
+
let universals = [];
|
|
262
|
+
if (args.include_universal) {
|
|
263
|
+
universals = getUniversalContext(proj, Math.ceil(limit / 2));
|
|
264
|
+
}
|
|
265
|
+
if (results.length === 0 && universals.length === 0) {
|
|
266
|
+
return {
|
|
267
|
+
content: [{ type: 'text', text: `No memories found matching "${args.query}".` }],
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
const temporalNote = args.at ? ` (at ${args.at})` : ' (pulled closer to Sun)';
|
|
271
|
+
const lines = [
|
|
272
|
+
`Recall: "${args.query}" — ${results.length} result${results.length === 1 ? '' : 's'}${temporalNote}`,
|
|
273
|
+
'',
|
|
274
|
+
];
|
|
275
|
+
for (const m of results) {
|
|
276
|
+
const preview = m.content.slice(0, 100) + (m.content.length > 100 ? '…' : '');
|
|
277
|
+
const tags = m.tags.length > 0 ? ` [${m.tags.join(', ')}]` : '';
|
|
278
|
+
const shortId = m.id.slice(0, 8);
|
|
279
|
+
lines.push(`[${m.type.toUpperCase()}] ${m.summary}${tags} | ${formatDistance(m.distance)} | ${shortId}`);
|
|
280
|
+
lines.push(` ${preview}`);
|
|
281
|
+
// Include top 3 related memories (constellation)
|
|
282
|
+
const related = findRelatedMemories(m.id, proj, 3);
|
|
283
|
+
if (related.length > 0) {
|
|
284
|
+
lines.push(` Related: ${related.map(r => `${r.summary.slice(0, 40)} (${r.id.slice(0, 8)})`).join(', ')}`);
|
|
285
|
+
}
|
|
286
|
+
lines.push('');
|
|
287
|
+
}
|
|
288
|
+
if (universals.length > 0) {
|
|
289
|
+
lines.push(`Universal memories (${universals.length} from other projects):`);
|
|
290
|
+
lines.push('');
|
|
291
|
+
for (const m of universals) {
|
|
292
|
+
const preview = m.content.slice(0, 120) + (m.content.length > 120 ? '…' : '');
|
|
293
|
+
lines.push(`[UNIVERSAL/${m.project}] ${m.summary} | ${m.id}`);
|
|
294
|
+
lines.push(` ${preview}`);
|
|
295
|
+
lines.push('');
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
299
|
+
}
|
|
300
|
+
catch (err) {
|
|
301
|
+
if (err instanceof McpError)
|
|
302
|
+
throw err;
|
|
303
|
+
throw new McpError(ErrorCode.InternalError, `recall failed: ${String(err)}`);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
// ---------------------------------------------------------------------------
|
|
307
|
+
// remember
|
|
308
|
+
// ---------------------------------------------------------------------------
|
|
309
|
+
export async function handleRemember(args) {
|
|
310
|
+
try {
|
|
311
|
+
const proj = resolveProject();
|
|
312
|
+
const memory = createMemory({
|
|
313
|
+
project: proj,
|
|
314
|
+
content: args.content,
|
|
315
|
+
summary: args.summary,
|
|
316
|
+
type: (args.type ?? 'observation'),
|
|
317
|
+
impact: args.impact,
|
|
318
|
+
tags: args.tags,
|
|
319
|
+
});
|
|
320
|
+
// Background: auto-extract relationships with existing memories.
|
|
321
|
+
// Fire-and-forget — does not block the response.
|
|
322
|
+
extractRelationships(memory, proj).catch(() => {
|
|
323
|
+
trackBgError('constellation');
|
|
324
|
+
});
|
|
325
|
+
// Set valid_from to now on the new memory
|
|
326
|
+
setTemporalBounds(memory.id, new Date().toISOString(), undefined);
|
|
327
|
+
// Calculate quality score
|
|
328
|
+
const existingMemories = getMemoriesByProject(proj);
|
|
329
|
+
const quality = calculateQuality(memory, existingMemories);
|
|
330
|
+
const qualityFeedback = getQualityFeedback(quality);
|
|
331
|
+
// Detect conflicts
|
|
332
|
+
const conflicts = await detectConflicts(memory, proj);
|
|
333
|
+
const conflictWarnings = formatConflictWarnings(conflicts);
|
|
334
|
+
// Detect temporal supersession — auto-supersede if detected
|
|
335
|
+
const supersessionCandidate = detectSupersession(memory, existingMemories);
|
|
336
|
+
let supersessionNote = '';
|
|
337
|
+
if (supersessionCandidate) {
|
|
338
|
+
supersedeMemory(supersessionCandidate.id, memory.id);
|
|
339
|
+
supersessionNote = `\nSuperseded: ${supersessionCandidate.id.slice(0, 8)} → this memory (${supersessionCandidate.summary.slice(0, 60)})`;
|
|
340
|
+
}
|
|
341
|
+
const zoneLabel = getOrbitZone(memory.distance);
|
|
342
|
+
const lines = [
|
|
343
|
+
`✦ Stored [${memory.type.toUpperCase()}] at ${memory.distance.toFixed(2)} AU (${zoneLabel}) | ID: ${memory.id} | quality: ${(quality.overall * 100).toFixed(0)}%`,
|
|
344
|
+
];
|
|
345
|
+
if (supersessionNote)
|
|
346
|
+
lines.push(supersessionNote);
|
|
347
|
+
if (qualityFeedback)
|
|
348
|
+
lines.push(`\nQuality tip: ${qualityFeedback}`);
|
|
349
|
+
if (conflictWarnings)
|
|
350
|
+
lines.push(`\n${conflictWarnings}`);
|
|
351
|
+
return {
|
|
352
|
+
content: [{
|
|
353
|
+
type: 'text',
|
|
354
|
+
text: lines.join(''),
|
|
355
|
+
}],
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
catch (err) {
|
|
359
|
+
if (err instanceof McpError)
|
|
360
|
+
throw err;
|
|
361
|
+
throw new McpError(ErrorCode.InternalError, `remember failed: ${String(err)}`);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
// ---------------------------------------------------------------------------
|
|
365
|
+
// orbit
|
|
366
|
+
// ---------------------------------------------------------------------------
|
|
367
|
+
export async function handleOrbit(_args) {
|
|
368
|
+
try {
|
|
369
|
+
const proj = resolveProject();
|
|
370
|
+
const config = getConfig();
|
|
371
|
+
const changes = recalculateOrbits(proj, config);
|
|
372
|
+
if (changes.length === 0) {
|
|
373
|
+
return {
|
|
374
|
+
content: [{ type: 'text', text: `Orbit: ${proj} — no changes. All memories are stable.` }],
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
let closerCount = 0;
|
|
378
|
+
let furtherCount = 0;
|
|
379
|
+
const lines = [];
|
|
380
|
+
for (const change of changes) {
|
|
381
|
+
const delta = change.new_distance - change.old_distance;
|
|
382
|
+
const direction = delta < 0 ? '↓' : '↑';
|
|
383
|
+
const absAU = Math.abs(delta).toFixed(2);
|
|
384
|
+
if (delta < 0)
|
|
385
|
+
closerCount++;
|
|
386
|
+
else
|
|
387
|
+
furtherCount++;
|
|
388
|
+
const oldZone = getOrbitZone(change.old_distance);
|
|
389
|
+
const newZone = getOrbitZone(change.new_distance);
|
|
390
|
+
const zoneChange = oldZone !== newZone ? ` ${oldZone}→${newZone}` : '';
|
|
391
|
+
lines.push(` ${direction}${absAU} AU (${change.old_distance.toFixed(2)}→${change.new_distance.toFixed(2)})${zoneChange} | ${change.trigger} | ${change.memory_id}`);
|
|
392
|
+
}
|
|
393
|
+
const header = `Orbit: ${proj} — ${changes.length} change${changes.length === 1 ? '' : 's'} | ↓${closerCount} closer ↑${furtherCount} further`;
|
|
394
|
+
return { content: [{ type: 'text', text: [header, '', ...lines].join('\n') }] };
|
|
395
|
+
}
|
|
396
|
+
catch (err) {
|
|
397
|
+
if (err instanceof McpError)
|
|
398
|
+
throw err;
|
|
399
|
+
throw new McpError(ErrorCode.InternalError, `orbit failed: ${String(err)}`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
// ---------------------------------------------------------------------------
|
|
403
|
+
// forget
|
|
404
|
+
// ---------------------------------------------------------------------------
|
|
405
|
+
export async function handleForget(args) {
|
|
406
|
+
try {
|
|
407
|
+
const effectiveMode = args.mode ?? 'push';
|
|
408
|
+
// Clean up constellation edges before forgetting
|
|
409
|
+
const { cleanupEdges } = await import('../../engine/constellation.js');
|
|
410
|
+
cleanupEdges(args.id);
|
|
411
|
+
forgetMemory(args.id, effectiveMode);
|
|
412
|
+
if (effectiveMode === 'delete') {
|
|
413
|
+
return { content: [{ type: 'text', text: `✗ Deleted memory ${args.id} (constellation edges removed).` }] };
|
|
414
|
+
}
|
|
415
|
+
const oortDistance = 95.0;
|
|
416
|
+
const zoneLabel = getOrbitZone(oortDistance);
|
|
417
|
+
return {
|
|
418
|
+
content: [{
|
|
419
|
+
type: 'text',
|
|
420
|
+
text: `↑ Pushed ${args.id} to ${oortDistance.toFixed(2)} AU (${zoneLabel}) — still recoverable via recall. Constellation edges removed.`,
|
|
421
|
+
}],
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
catch (err) {
|
|
425
|
+
if (err instanceof McpError)
|
|
426
|
+
throw err;
|
|
427
|
+
throw new McpError(ErrorCode.InternalError, `forget failed: ${String(err)}`);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
// ---------------------------------------------------------------------------
|
|
431
|
+
// export
|
|
432
|
+
// ---------------------------------------------------------------------------
|
|
433
|
+
export async function handleExport(args) {
|
|
434
|
+
try {
|
|
435
|
+
const proj = resolveProject();
|
|
436
|
+
const effectiveFormat = args.format ?? 'json';
|
|
437
|
+
let memories = getMemoriesByProject(proj);
|
|
438
|
+
if (args.type && args.type !== 'all') {
|
|
439
|
+
memories = memories.filter((m) => m.type === args.type);
|
|
440
|
+
}
|
|
441
|
+
if (args.zone && args.zone !== 'all') {
|
|
442
|
+
memories = memories.filter((m) => labelToZoneKey(getOrbitZone(m.distance)) === args.zone);
|
|
443
|
+
}
|
|
444
|
+
if (effectiveFormat === 'json') {
|
|
445
|
+
const payload = memories.map((m) => ({
|
|
446
|
+
id: m.id,
|
|
447
|
+
type: m.type,
|
|
448
|
+
summary: m.summary,
|
|
449
|
+
content: m.content,
|
|
450
|
+
tags: m.tags,
|
|
451
|
+
distance: m.distance,
|
|
452
|
+
importance: m.importance,
|
|
453
|
+
created_at: m.created_at,
|
|
454
|
+
}));
|
|
455
|
+
return { content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }] };
|
|
456
|
+
}
|
|
457
|
+
// markdown format
|
|
458
|
+
const lines = [
|
|
459
|
+
`# Stellar Memory Export`,
|
|
460
|
+
`Project: ${proj} | ${memories.length} memories | ${new Date().toISOString()}`,
|
|
461
|
+
'',
|
|
462
|
+
];
|
|
463
|
+
for (const m of memories) {
|
|
464
|
+
const zoneLabel = getOrbitZone(m.distance);
|
|
465
|
+
const tagsStr = m.tags.length > 0 ? m.tags.join(', ') : '—';
|
|
466
|
+
const dateStr = m.created_at.slice(0, 10);
|
|
467
|
+
lines.push(`## [${m.type.toUpperCase()}] ${m.summary}`);
|
|
468
|
+
lines.push(`- **Distance**: ${m.distance.toFixed(2)} AU (${zoneLabel})`);
|
|
469
|
+
lines.push(`- **Impact**: ${m.importance.toFixed(2)}`);
|
|
470
|
+
lines.push(`- **Tags**: ${tagsStr}`);
|
|
471
|
+
lines.push(`- **Created**: ${dateStr}`);
|
|
472
|
+
lines.push('');
|
|
473
|
+
lines.push(m.content);
|
|
474
|
+
lines.push('');
|
|
475
|
+
lines.push('---');
|
|
476
|
+
lines.push('');
|
|
477
|
+
}
|
|
478
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
479
|
+
}
|
|
480
|
+
catch (err) {
|
|
481
|
+
if (err instanceof McpError)
|
|
482
|
+
throw err;
|
|
483
|
+
throw new McpError(ErrorCode.InternalError, `export failed: ${String(err)}`);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
// ---------------------------------------------------------------------------
|
|
487
|
+
// constellation
|
|
488
|
+
// ---------------------------------------------------------------------------
|
|
489
|
+
export async function handleConstellation(args) {
|
|
490
|
+
try {
|
|
491
|
+
const proj = resolveProject();
|
|
492
|
+
const action = args.action ?? 'graph';
|
|
493
|
+
if (action === 'extract') {
|
|
494
|
+
// Fetch the memory to extract relationships for
|
|
495
|
+
const { getMemoryById } = await import('../../storage/queries.js');
|
|
496
|
+
const memory = getMemoryById(args.id);
|
|
497
|
+
if (!memory) {
|
|
498
|
+
throw new McpError(ErrorCode.InvalidParams, `Memory not found: ${args.id}`);
|
|
499
|
+
}
|
|
500
|
+
const edges = await extractRelationships(memory, proj);
|
|
501
|
+
const text = edges.length === 0
|
|
502
|
+
? `No relationships found for memory ${args.id} (weight threshold not met).`
|
|
503
|
+
: [
|
|
504
|
+
`Extracted ${edges.length} relationship${edges.length === 1 ? '' : 's'} for ${args.id}:`,
|
|
505
|
+
'',
|
|
506
|
+
...edges.map(e => ` [${e.relation}] → ${e.target_id} (weight: ${e.weight.toFixed(3)})`),
|
|
507
|
+
].join('\n');
|
|
508
|
+
return { content: [{ type: 'text', text }] };
|
|
509
|
+
}
|
|
510
|
+
if (action === 'related') {
|
|
511
|
+
const limit = args.limit ?? 10;
|
|
512
|
+
const related = findRelatedMemories(args.id, proj, limit);
|
|
513
|
+
if (related.length === 0) {
|
|
514
|
+
return {
|
|
515
|
+
content: [{ type: 'text', text: `No related memories found for ${args.id}.` }],
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
const lines = [
|
|
519
|
+
`Related memories for ${args.id} (${related.length}):`,
|
|
520
|
+
'',
|
|
521
|
+
...related.map(m => ` [${m.type.toUpperCase()}] ${m.summary} | ${m.distance.toFixed(2)} AU | ${m.id}`),
|
|
522
|
+
];
|
|
523
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
524
|
+
}
|
|
525
|
+
// Default: graph
|
|
526
|
+
const depth = args.depth ?? 1;
|
|
527
|
+
const { nodes, edges } = getConstellationGraph(args.id, proj, depth);
|
|
528
|
+
if (edges.length === 0) {
|
|
529
|
+
return {
|
|
530
|
+
content: [{
|
|
531
|
+
type: 'text',
|
|
532
|
+
text: `Constellation for ${args.id}: no edges yet. Use action="extract" to auto-discover relationships.`,
|
|
533
|
+
}],
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
const lines = [
|
|
537
|
+
`Constellation graph for ${args.id} (depth=${depth}):`,
|
|
538
|
+
` ${nodes.length} nodes ${edges.length} edges`,
|
|
539
|
+
'',
|
|
540
|
+
'Edges:',
|
|
541
|
+
...edges.map(e => ` ${e.source_id.slice(0, 8)} --[${e.relation}]--> ${e.target_id.slice(0, 8)} (w=${e.weight.toFixed(3)})`),
|
|
542
|
+
'',
|
|
543
|
+
'Nodes:',
|
|
544
|
+
...nodes.map(n => ` [${n.type.toUpperCase()}] ${n.summary} | ${n.distance.toFixed(2)} AU | ${n.id}`),
|
|
545
|
+
];
|
|
546
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
547
|
+
}
|
|
548
|
+
catch (err) {
|
|
549
|
+
if (err instanceof McpError)
|
|
550
|
+
throw err;
|
|
551
|
+
throw new McpError(ErrorCode.InternalError, `constellation failed: ${String(err)}`);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
// ---------------------------------------------------------------------------
|
|
555
|
+
// galaxy — multi-project management
|
|
556
|
+
// ---------------------------------------------------------------------------
|
|
557
|
+
export async function handleGalaxy(args) {
|
|
558
|
+
try {
|
|
559
|
+
const lines = [];
|
|
560
|
+
switch (args.action) {
|
|
561
|
+
case 'switch': {
|
|
562
|
+
if (!args.project)
|
|
563
|
+
throw new McpError(ErrorCode.InvalidParams, 'project is required for action="switch"');
|
|
564
|
+
const result = switchProject(args.project);
|
|
565
|
+
lines.push(`Switched project: ${result.previous} → ${result.current}`);
|
|
566
|
+
lines.push(`Memories in "${result.current}": ${result.memoryCount}`);
|
|
567
|
+
break;
|
|
568
|
+
}
|
|
569
|
+
case 'list': {
|
|
570
|
+
const projects = listAllProjects();
|
|
571
|
+
const current = getCurrentProject();
|
|
572
|
+
lines.push(`Galaxy — ${projects.length} project${projects.length === 1 ? '' : 's'} (active: ${current})`);
|
|
573
|
+
lines.push('');
|
|
574
|
+
for (const p of projects) {
|
|
575
|
+
const active = p.project === current ? ' *' : '';
|
|
576
|
+
const univFlag = p.hasUniversal ? ' [universal]' : '';
|
|
577
|
+
const updated = p.lastUpdated.slice(0, 10);
|
|
578
|
+
lines.push(` ${p.project}${active}${univFlag} | ${p.memoryCount} memories | updated: ${updated}`);
|
|
579
|
+
}
|
|
580
|
+
break;
|
|
581
|
+
}
|
|
582
|
+
case 'create': {
|
|
583
|
+
if (!args.project)
|
|
584
|
+
throw new McpError(ErrorCode.InvalidParams, 'project is required for action="create"');
|
|
585
|
+
const result = createProject(args.project);
|
|
586
|
+
lines.push(result.created
|
|
587
|
+
? `Created project "${result.project}".`
|
|
588
|
+
: `Project "${result.project}" already exists.`);
|
|
589
|
+
break;
|
|
590
|
+
}
|
|
591
|
+
case 'stats': {
|
|
592
|
+
const proj = args.project ?? getCurrentProject();
|
|
593
|
+
const stats = getProjectStats(proj);
|
|
594
|
+
lines.push(`Stats — project: ${proj}`);
|
|
595
|
+
lines.push(`Total memories: ${stats.memoryCount}`);
|
|
596
|
+
lines.push(`Universal: ${stats.universalCount}`);
|
|
597
|
+
lines.push(`Oldest memory: ${stats.oldestMemory.slice(0, 10) || '—'}`);
|
|
598
|
+
lines.push(`Newest memory: ${stats.newestMemory.slice(0, 10) || '—'}`);
|
|
599
|
+
lines.push('');
|
|
600
|
+
lines.push('Zone distribution:');
|
|
601
|
+
for (const [zone, count] of Object.entries(stats.zoneDistribution)) {
|
|
602
|
+
lines.push(` ${zone.padEnd(10)} ${count}`);
|
|
603
|
+
}
|
|
604
|
+
lines.push('');
|
|
605
|
+
lines.push('Type distribution:');
|
|
606
|
+
for (const [type, count] of Object.entries(stats.typeDistribution)) {
|
|
607
|
+
lines.push(` ${type.padEnd(12)} ${count}`);
|
|
608
|
+
}
|
|
609
|
+
break;
|
|
610
|
+
}
|
|
611
|
+
case 'mark_universal': {
|
|
612
|
+
if (!args.memory_id)
|
|
613
|
+
throw new McpError(ErrorCode.InvalidParams, 'memory_id is required for action="mark_universal"');
|
|
614
|
+
const flag = args.is_universal ?? true;
|
|
615
|
+
markUniversal(args.memory_id, flag);
|
|
616
|
+
lines.push(`Memory ${args.memory_id} marked as ${flag ? 'universal' : 'project-specific'}.`);
|
|
617
|
+
break;
|
|
618
|
+
}
|
|
619
|
+
case 'universal_context': {
|
|
620
|
+
const proj = args.project ?? getCurrentProject();
|
|
621
|
+
const limit = args.limit ?? 10;
|
|
622
|
+
const memories = getUniversalContext(proj, limit);
|
|
623
|
+
if (memories.length === 0) {
|
|
624
|
+
lines.push('No universal memories from other projects.');
|
|
625
|
+
}
|
|
626
|
+
else {
|
|
627
|
+
lines.push(`Universal context for "${proj}" (${memories.length} memories from other projects):`);
|
|
628
|
+
lines.push('');
|
|
629
|
+
for (const m of memories) {
|
|
630
|
+
lines.push(`[${m.project}/${m.type.toUpperCase()}] ${m.summary} | ${m.id}`);
|
|
631
|
+
lines.push(` ${m.content.slice(0, 120)}${m.content.length > 120 ? '…' : ''}`);
|
|
632
|
+
lines.push('');
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
break;
|
|
636
|
+
}
|
|
637
|
+
case 'candidates': {
|
|
638
|
+
const proj = args.project ?? getCurrentProject();
|
|
639
|
+
const candidates = detectUniversalCandidates(proj);
|
|
640
|
+
if (candidates.length === 0) {
|
|
641
|
+
lines.push(`No universal candidates found in project "${proj}".`);
|
|
642
|
+
}
|
|
643
|
+
else {
|
|
644
|
+
lines.push(`Universal candidates in "${proj}" (${candidates.length}) — review and mark with mark_universal:`);
|
|
645
|
+
lines.push('');
|
|
646
|
+
for (const m of candidates) {
|
|
647
|
+
lines.push(`[${m.type.toUpperCase()}] ${m.summary} | importance: ${(m.importance * 100).toFixed(0)}% | ${m.id}`);
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
break;
|
|
651
|
+
}
|
|
652
|
+
default:
|
|
653
|
+
throw new McpError(ErrorCode.InvalidParams, `Unknown action: ${String(args.action)}`);
|
|
654
|
+
}
|
|
655
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
656
|
+
}
|
|
657
|
+
catch (err) {
|
|
658
|
+
if (err instanceof McpError)
|
|
659
|
+
throw err;
|
|
660
|
+
throw new McpError(ErrorCode.InternalError, `galaxy failed: ${String(err)}`);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
// ---------------------------------------------------------------------------
|
|
664
|
+
// analytics — memory insights and pattern detection
|
|
665
|
+
// ---------------------------------------------------------------------------
|
|
666
|
+
export async function handleAnalytics(args) {
|
|
667
|
+
try {
|
|
668
|
+
const proj = args.project ?? resolveProject();
|
|
669
|
+
const lines = [];
|
|
670
|
+
// Support both `report` (new) and `action` (legacy) param names
|
|
671
|
+
const effectiveAction = args.report ?? args.action ?? 'overview';
|
|
672
|
+
switch (effectiveAction) {
|
|
673
|
+
case 'survival': {
|
|
674
|
+
const curve = getSurvivalCurve(proj);
|
|
675
|
+
lines.push(`Memory survival curve — project: ${proj}`);
|
|
676
|
+
lines.push('');
|
|
677
|
+
lines.push('Age (days) Surviving Accessed Forgotten');
|
|
678
|
+
lines.push('─────────────────────────────────────────');
|
|
679
|
+
for (const row of curve) {
|
|
680
|
+
const age = String(row.ageInDays).padStart(10);
|
|
681
|
+
const surv = String(row.survivingCount).padStart(9);
|
|
682
|
+
const acc = String(row.accessedCount).padStart(8);
|
|
683
|
+
const forg = String(row.forgottenCount).padStart(9);
|
|
684
|
+
lines.push(`${age} ${surv} ${acc} ${forg}`);
|
|
685
|
+
}
|
|
686
|
+
break;
|
|
687
|
+
}
|
|
688
|
+
case 'movements': {
|
|
689
|
+
const days = args.days ?? 30;
|
|
690
|
+
const movements = getOrbitMovements(proj, days);
|
|
691
|
+
if (movements.length === 0) {
|
|
692
|
+
lines.push(`No orbit movements in the last ${days} days for project "${proj}".`);
|
|
693
|
+
}
|
|
694
|
+
else {
|
|
695
|
+
lines.push(`Orbit movements — project: ${proj} (last ${days} days, top ${movements.length})`);
|
|
696
|
+
lines.push('');
|
|
697
|
+
for (const m of movements) {
|
|
698
|
+
const dir = m.netMovement < 0 ? '↓' : '↑';
|
|
699
|
+
lines.push(`${dir} ${m.summary} (${m.movements.length} moves, net: ${m.netMovement > 0 ? '+' : ''}${m.netMovement.toFixed(2)} AU) | ${m.memoryId}`);
|
|
700
|
+
for (const mv of m.movements.slice(-3)) {
|
|
701
|
+
lines.push(` ${mv.timestamp.slice(0, 16)} ${mv.oldDistance.toFixed(2)}→${mv.newDistance.toFixed(2)} AU [${mv.trigger}]`);
|
|
702
|
+
}
|
|
703
|
+
lines.push('');
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
break;
|
|
707
|
+
}
|
|
708
|
+
case 'clusters': {
|
|
709
|
+
const topicClusters = getTopicClusters(proj);
|
|
710
|
+
if (topicClusters.length === 0) {
|
|
711
|
+
lines.push(`No topic clusters found for project "${proj}". Add tags to your memories.`);
|
|
712
|
+
}
|
|
713
|
+
else {
|
|
714
|
+
lines.push(`Topic clusters — project: ${proj} (${topicClusters.length} topics)`);
|
|
715
|
+
lines.push('');
|
|
716
|
+
lines.push('Topic Count Avg Imp Avg Dist Recent');
|
|
717
|
+
lines.push('────────────────────────────────────────────────────');
|
|
718
|
+
for (const cl of topicClusters) {
|
|
719
|
+
const topicLabel = cl.topic.slice(0, 18).padEnd(18);
|
|
720
|
+
const clCount = String(cl.memoryCount).padStart(5);
|
|
721
|
+
const imp = (cl.avgImportance * 100).toFixed(0).padStart(6) + '%';
|
|
722
|
+
const dist = cl.avgDistance.toFixed(1).padStart(7) + ' AU';
|
|
723
|
+
const recent = String(cl.recentActivity).padStart(6);
|
|
724
|
+
lines.push(`${topicLabel} ${clCount} ${imp} ${dist} ${recent}`);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
break;
|
|
728
|
+
}
|
|
729
|
+
case 'patterns': {
|
|
730
|
+
const patterns = detectAccessPatterns(proj);
|
|
731
|
+
if (patterns.length === 0) {
|
|
732
|
+
lines.push(`No access patterns detected yet for project "${proj}". Keep using recall to build history.`);
|
|
733
|
+
}
|
|
734
|
+
else {
|
|
735
|
+
lines.push(`Access patterns — project: ${proj}`);
|
|
736
|
+
lines.push('');
|
|
737
|
+
for (const p of patterns) {
|
|
738
|
+
lines.push(`[${p.pattern.toUpperCase()}] ${p.description}`);
|
|
739
|
+
lines.push(` Frequency: ${p.frequency}`);
|
|
740
|
+
lines.push('');
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
break;
|
|
744
|
+
}
|
|
745
|
+
case 'health': {
|
|
746
|
+
const h = getMemoryHealth(proj);
|
|
747
|
+
lines.push(`Memory health — project: ${proj}`);
|
|
748
|
+
lines.push('');
|
|
749
|
+
lines.push(`Total memories: ${h.totalMemories}`);
|
|
750
|
+
lines.push(`Active ratio (close zones): ${(h.activeRatio * 100).toFixed(1)}%`);
|
|
751
|
+
lines.push(`Stale ratio (30+ days idle): ${(h.staleRatio * 100).toFixed(1)}%`);
|
|
752
|
+
lines.push(`Avg quality score: ${(h.qualityAvg * 100).toFixed(1)}%`);
|
|
753
|
+
lines.push(`Conflict ratio: ${(h.conflictRatio * 100).toFixed(1)}%`);
|
|
754
|
+
lines.push(`Consolidation opportunities: ${h.consolidationOpportunities}`);
|
|
755
|
+
if (h.recommendations.length > 0) {
|
|
756
|
+
lines.push('');
|
|
757
|
+
lines.push('Recommendations:');
|
|
758
|
+
for (const rec of h.recommendations) {
|
|
759
|
+
lines.push(` - ${rec}`);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
else {
|
|
763
|
+
lines.push('');
|
|
764
|
+
lines.push('Memory system is healthy. No action needed.');
|
|
765
|
+
}
|
|
766
|
+
break;
|
|
767
|
+
}
|
|
768
|
+
case 'report':
|
|
769
|
+
case 'full': {
|
|
770
|
+
const report = generateReport(proj);
|
|
771
|
+
lines.push(report);
|
|
772
|
+
break;
|
|
773
|
+
}
|
|
774
|
+
case 'topics': {
|
|
775
|
+
// Alias for 'clusters'
|
|
776
|
+
const clusters = getTopicClusters(proj);
|
|
777
|
+
if (clusters.length === 0) {
|
|
778
|
+
lines.push(`No topic clusters found for project "${proj}". Add tags to your memories.`);
|
|
779
|
+
}
|
|
780
|
+
else {
|
|
781
|
+
lines.push(`Topic clusters — project: ${proj} (${clusters.length} topics)`);
|
|
782
|
+
lines.push('');
|
|
783
|
+
lines.push('Topic Count Avg Imp Avg Dist Recent');
|
|
784
|
+
lines.push('────────────────────────────────────────────────────');
|
|
785
|
+
for (const cl of clusters) {
|
|
786
|
+
const topic = cl.topic.slice(0, 18).padEnd(18);
|
|
787
|
+
const count = String(cl.memoryCount).padStart(5);
|
|
788
|
+
const imp = (cl.avgImportance * 100).toFixed(0).padStart(6) + '%';
|
|
789
|
+
const dist = cl.avgDistance.toFixed(1).padStart(7) + ' AU';
|
|
790
|
+
const recent = String(cl.recentActivity).padStart(6);
|
|
791
|
+
lines.push(`${topic} ${count} ${imp} ${dist} ${recent}`);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
break;
|
|
795
|
+
}
|
|
796
|
+
case 'summary':
|
|
797
|
+
case 'overview': {
|
|
798
|
+
const a = getFullAnalytics(proj);
|
|
799
|
+
lines.push(`Analytics — project: ${proj}`);
|
|
800
|
+
lines.push(`Total memories: ${a.total_memories}`);
|
|
801
|
+
lines.push(`Avg importance: ${(a.avg_importance * 100).toFixed(1)}%`);
|
|
802
|
+
lines.push(`Avg quality: ${(a.avg_quality * 100).toFixed(1)}%`);
|
|
803
|
+
lines.push(`Recall success rate: ${(a.recall_success_rate * 100).toFixed(1)}%`);
|
|
804
|
+
lines.push(`Consolidations: ${a.consolidation_count}`);
|
|
805
|
+
lines.push(`Open conflicts: ${a.conflict_count}`);
|
|
806
|
+
lines.push('');
|
|
807
|
+
lines.push('Zone distribution:');
|
|
808
|
+
for (const [zone, count] of Object.entries(a.zone_distribution)) {
|
|
809
|
+
lines.push(` ${zone.padEnd(10)} ${count}`);
|
|
810
|
+
}
|
|
811
|
+
lines.push('');
|
|
812
|
+
lines.push('Type distribution:');
|
|
813
|
+
for (const [type, count] of Object.entries(a.type_distribution).sort(([, a], [, b]) => b - a)) {
|
|
814
|
+
lines.push(` ${type.padEnd(12)} ${count}`);
|
|
815
|
+
}
|
|
816
|
+
if (a.top_tags.length > 0) {
|
|
817
|
+
lines.push('');
|
|
818
|
+
lines.push('Top tags:');
|
|
819
|
+
for (const { tag, count } of a.top_tags.slice(0, 10)) {
|
|
820
|
+
lines.push(` ${tag.padEnd(20)} ${count}`);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
break;
|
|
824
|
+
}
|
|
825
|
+
default:
|
|
826
|
+
throw new McpError(ErrorCode.InvalidParams, `Unknown analytics report: ${String(effectiveAction)}`);
|
|
827
|
+
}
|
|
828
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
829
|
+
}
|
|
830
|
+
catch (err) {
|
|
831
|
+
if (err instanceof McpError)
|
|
832
|
+
throw err;
|
|
833
|
+
throw new McpError(ErrorCode.InternalError, `analytics failed: ${String(err)}`);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
// ---------------------------------------------------------------------------
|
|
837
|
+
// sun resource handler (not a tool, but lives logically with memory tools)
|
|
838
|
+
// ---------------------------------------------------------------------------
|
|
839
|
+
export function handleSunResource(uriHref) {
|
|
840
|
+
const config = getConfig();
|
|
841
|
+
const proj = resolveProject();
|
|
842
|
+
ensureCorona();
|
|
843
|
+
let content = getSunContent(proj);
|
|
844
|
+
// Append procedural memories section (Navigation Rules)
|
|
845
|
+
const proceduralMems = getProceduralMemories(proj);
|
|
846
|
+
if (proceduralMems.length > 0) {
|
|
847
|
+
content += '\n\n' + formatProceduralSection(proceduralMems);
|
|
848
|
+
}
|
|
849
|
+
// Append temporal summary
|
|
850
|
+
const temporalSummary = getTemporalSummary(proj);
|
|
851
|
+
if (temporalSummary) {
|
|
852
|
+
content += '\n\n' + temporalSummary;
|
|
853
|
+
}
|
|
854
|
+
// Append unresolved conflict count
|
|
855
|
+
const unresolvedConflicts = getUnresolvedConflicts(proj);
|
|
856
|
+
if (unresolvedConflicts.length > 0) {
|
|
857
|
+
content += `\n\nUnresolved conflicts: ${unresolvedConflicts.length} — use resolve_conflict tool to review.`;
|
|
858
|
+
}
|
|
859
|
+
return { contents: [{ uri: uriHref, text: content }] };
|
|
860
|
+
}
|
|
861
|
+
// ---------------------------------------------------------------------------
|
|
862
|
+
// New tool handlers
|
|
863
|
+
// ---------------------------------------------------------------------------
|
|
864
|
+
export async function handleObserve(args) {
|
|
865
|
+
try {
|
|
866
|
+
const proj = args.project ?? resolveProject();
|
|
867
|
+
const stats = await processConversation(args.conversation, proj);
|
|
868
|
+
const text = [
|
|
869
|
+
`Observation complete for project "${proj}":`,
|
|
870
|
+
` Memories created: ${stats.memoriesCreated}`,
|
|
871
|
+
` Memories reinforced: ${stats.memoriesReinforced}`,
|
|
872
|
+
` Conflicts detected: ${stats.conflictsDetected}`,
|
|
873
|
+
].join('\n');
|
|
874
|
+
return { content: [{ type: 'text', text }] };
|
|
875
|
+
}
|
|
876
|
+
catch (err) {
|
|
877
|
+
if (err instanceof McpError)
|
|
878
|
+
throw err;
|
|
879
|
+
throw new McpError(ErrorCode.InternalError, `observe failed: ${String(err)}`);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
export async function handleConsolidate(args) {
|
|
883
|
+
try {
|
|
884
|
+
const proj = args.project ?? resolveProject();
|
|
885
|
+
const dryRun = args.dry_run ?? true;
|
|
886
|
+
if (dryRun) {
|
|
887
|
+
const candidates = await findConsolidationCandidates(proj);
|
|
888
|
+
if (candidates.length === 0) {
|
|
889
|
+
return {
|
|
890
|
+
content: [{ type: 'text', text: `No consolidation candidates found in project "${proj}".` }],
|
|
891
|
+
};
|
|
892
|
+
}
|
|
893
|
+
const lines = [
|
|
894
|
+
`Consolidation candidates in "${proj}" (${candidates.length} groups) — dry run:`,
|
|
895
|
+
'',
|
|
896
|
+
];
|
|
897
|
+
for (const { memories, similarity } of candidates) {
|
|
898
|
+
lines.push(` Group (similarity: ${(similarity * 100).toFixed(0)}%, ${memories.length} memories):`);
|
|
899
|
+
for (const m of memories) {
|
|
900
|
+
lines.push(` [${m.type.toUpperCase()}] ${m.summary} | ${m.id.slice(0, 8)}`);
|
|
901
|
+
}
|
|
902
|
+
lines.push('');
|
|
903
|
+
}
|
|
904
|
+
lines.push('Run with dry_run=false to merge these groups.');
|
|
905
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
906
|
+
}
|
|
907
|
+
const stats = await runConsolidation(proj);
|
|
908
|
+
const text = [
|
|
909
|
+
`Consolidation complete for "${proj}":`,
|
|
910
|
+
` Groups found: ${stats.groupsFound}`,
|
|
911
|
+
` Memories consolidated: ${stats.memoriesConsolidated}`,
|
|
912
|
+
` New memories created: ${stats.newMemoriesCreated}`,
|
|
913
|
+
].join('\n');
|
|
914
|
+
return { content: [{ type: 'text', text }] };
|
|
915
|
+
}
|
|
916
|
+
catch (err) {
|
|
917
|
+
if (err instanceof McpError)
|
|
918
|
+
throw err;
|
|
919
|
+
throw new McpError(ErrorCode.InternalError, `consolidate failed: ${String(err)}`);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
export async function handleResolveConflict(args) {
|
|
923
|
+
try {
|
|
924
|
+
const proj = args.project ?? resolveProject();
|
|
925
|
+
if (args.action === 'list') {
|
|
926
|
+
const conflicts = getUnresolvedConflicts(proj);
|
|
927
|
+
if (conflicts.length === 0) {
|
|
928
|
+
return {
|
|
929
|
+
content: [{ type: 'text', text: `No unresolved conflicts in project "${proj}".` }],
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
const lines = [
|
|
933
|
+
`Unresolved conflicts in "${proj}" (${conflicts.length}):`,
|
|
934
|
+
'',
|
|
935
|
+
];
|
|
936
|
+
for (const c of conflicts) {
|
|
937
|
+
lines.push(` [${c.severity.toUpperCase()}] ${c.id}`);
|
|
938
|
+
lines.push(` Memory: ${c.memory_id.slice(0, 8)}`);
|
|
939
|
+
lines.push(` Conflicts: ${c.conflicting_memory_id.slice(0, 8)}`);
|
|
940
|
+
lines.push(` Reason: ${c.description}`);
|
|
941
|
+
lines.push('');
|
|
942
|
+
}
|
|
943
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
944
|
+
}
|
|
945
|
+
if (args.action === 'resolve' || args.action === 'dismiss') {
|
|
946
|
+
if (!args.conflict_id) {
|
|
947
|
+
throw new McpError(ErrorCode.InvalidParams, 'conflict_id is required for resolve/dismiss actions');
|
|
948
|
+
}
|
|
949
|
+
const resolution = args.resolution ?? (args.action === 'dismiss' ? 'Dismissed by user' : 'Resolved by user');
|
|
950
|
+
const resolveAction = args.resolve_action ?? (args.action === 'dismiss' ? 'dismiss' : 'supersede');
|
|
951
|
+
resolveConflictEngine(args.conflict_id, resolution, resolveAction);
|
|
952
|
+
return {
|
|
953
|
+
content: [{
|
|
954
|
+
type: 'text',
|
|
955
|
+
text: `Conflict ${args.conflict_id.slice(0, 8)} resolved with action "${resolveAction}": ${resolution}`,
|
|
956
|
+
}],
|
|
957
|
+
};
|
|
958
|
+
}
|
|
959
|
+
throw new McpError(ErrorCode.InvalidParams, `Unknown action: ${String(args.action)}`);
|
|
960
|
+
}
|
|
961
|
+
catch (err) {
|
|
962
|
+
if (err instanceof McpError)
|
|
963
|
+
throw err;
|
|
964
|
+
throw new McpError(ErrorCode.InternalError, `resolve_conflict failed: ${String(err)}`);
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
export async function handleTemporal(args) {
|
|
968
|
+
try {
|
|
969
|
+
const proj = args.project ?? resolveProject();
|
|
970
|
+
switch (args.action) {
|
|
971
|
+
case 'at': {
|
|
972
|
+
if (!args.timestamp)
|
|
973
|
+
throw new McpError(ErrorCode.InvalidParams, 'timestamp is required for action="at"');
|
|
974
|
+
const memories = getContextAtTime(proj, args.timestamp);
|
|
975
|
+
if (memories.length === 0) {
|
|
976
|
+
return {
|
|
977
|
+
content: [{ type: 'text', text: `No memories active at ${args.timestamp} in "${proj}".` }],
|
|
978
|
+
};
|
|
979
|
+
}
|
|
980
|
+
const lines = [
|
|
981
|
+
`Context at ${args.timestamp} — "${proj}" (${memories.length} active memories):`,
|
|
982
|
+
'',
|
|
983
|
+
...memories.slice(0, 20).map(m => ` [${m.type.toUpperCase()}] ${m.summary} | ${m.distance.toFixed(2)} AU | ${m.id.slice(0, 8)}`),
|
|
984
|
+
];
|
|
985
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
986
|
+
}
|
|
987
|
+
case 'chain': {
|
|
988
|
+
if (!args.memory_id)
|
|
989
|
+
throw new McpError(ErrorCode.InvalidParams, 'memory_id is required for action="chain"');
|
|
990
|
+
const chain = getEvolutionChain(args.memory_id);
|
|
991
|
+
if (chain.length === 0) {
|
|
992
|
+
return {
|
|
993
|
+
content: [{ type: 'text', text: `No evolution chain found for memory ${args.memory_id}.` }],
|
|
994
|
+
};
|
|
995
|
+
}
|
|
996
|
+
const lines = [
|
|
997
|
+
`Evolution chain for ${args.memory_id.slice(0, 8)} (${chain.length} entries, oldest first):`,
|
|
998
|
+
'',
|
|
999
|
+
...chain.map((m, i) => {
|
|
1000
|
+
const date = m.created_at.slice(0, 10);
|
|
1001
|
+
const superseded = m.superseded_by ? ` → ${m.superseded_by.slice(0, 8)}` : ' [current]';
|
|
1002
|
+
return ` ${i + 1}. [${date}] ${m.summary.slice(0, 80)}${superseded}`;
|
|
1003
|
+
}),
|
|
1004
|
+
];
|
|
1005
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
1006
|
+
}
|
|
1007
|
+
case 'summary': {
|
|
1008
|
+
const summary = getTemporalSummary(proj);
|
|
1009
|
+
return { content: [{ type: 'text', text: summary }] };
|
|
1010
|
+
}
|
|
1011
|
+
case 'set_bounds': {
|
|
1012
|
+
if (!args.memory_id)
|
|
1013
|
+
throw new McpError(ErrorCode.InvalidParams, 'memory_id is required for action="set_bounds"');
|
|
1014
|
+
setTemporalBounds(args.memory_id, args.valid_from, args.valid_until);
|
|
1015
|
+
const parts = [];
|
|
1016
|
+
if (args.valid_from)
|
|
1017
|
+
parts.push(`valid_from: ${args.valid_from}`);
|
|
1018
|
+
if (args.valid_until)
|
|
1019
|
+
parts.push(`valid_until: ${args.valid_until}`);
|
|
1020
|
+
return {
|
|
1021
|
+
content: [{
|
|
1022
|
+
type: 'text',
|
|
1023
|
+
text: `Temporal bounds set for ${args.memory_id.slice(0, 8)}: ${parts.join(', ')}`,
|
|
1024
|
+
}],
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
1027
|
+
default:
|
|
1028
|
+
throw new McpError(ErrorCode.InvalidParams, `Unknown action: ${String(args.action)}`);
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
catch (err) {
|
|
1032
|
+
if (err instanceof McpError)
|
|
1033
|
+
throw err;
|
|
1034
|
+
throw new McpError(ErrorCode.InternalError, `temporal failed: ${String(err)}`);
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
//# sourceMappingURL=memory-tools.js.map
|