lemma-mcp 0.8.2 → 0.8.4

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.
@@ -2,28 +2,36 @@ import * as core from "../memory/index.js";
2
2
  import * as guides from "../guides/index.js";
3
3
  import * as sessions from "../sessions/index.js";
4
4
  import * as virtualSession from "../sessions/virtual.js";
5
+ import { logger } from "../logger.js";
5
6
  let activeSessionId = null;
6
7
  let _notifyChange = null;
7
8
  export function setNotifyChange(fn) {
8
9
  _notifyChange = fn;
10
+ logger.debug("setNotifyChange", "notification handler registered");
9
11
  }
10
12
  function notifyMemoryChange() {
11
- if (_notifyChange)
13
+ if (_notifyChange) {
14
+ logger.notify("memory_change", "sending");
12
15
  _notifyChange();
16
+ }
13
17
  }
14
18
  export async function handleSessionStart(args) {
15
19
  const taskType = args?.task_type;
16
20
  const technologies = args?.technologies || [];
17
21
  const initialApproach = args?.initial_approach || null;
22
+ logger.flow("session_start", "start", { task_type: taskType, technologies, has_initial_approach: !!initialApproach });
18
23
  if (!taskType) {
24
+ logger.warn("session_start validation failed", { reason: "missing task_type" });
19
25
  return {
20
26
  content: [{ type: "text", text: "Error: 'task_type' parameter is required" }],
21
27
  isError: true,
22
28
  };
23
29
  }
30
+ logger.data("sessions.json", "load");
24
31
  const allSessions = sessions.loadSessions();
25
32
  const existing = sessions.findActiveSession(allSessions);
26
33
  if (existing) {
34
+ logger.flow("session_start", "abandon_existing", { session_id: existing.session_id, task_type: existing.task_type });
27
35
  existing.status = "abandoned";
28
36
  existing.task_outcome = "abandoned";
29
37
  }
@@ -31,18 +39,24 @@ export async function handleSessionStart(args) {
31
39
  session.initial_approach = initialApproach;
32
40
  activeSessionId = session.session_id;
33
41
  allSessions.push(session);
42
+ logger.data("sessions.json", "save", { session_id: session.session_id, total_sessions: allSessions.length });
34
43
  sessions.saveSessions(allSessions);
44
+ logger.data("guides.json", "load");
35
45
  const allGuides = guides.loadGuides();
36
46
  const taskDesc = [taskType, ...technologies].join(" ");
37
47
  const suggestions = guides.suggestGuides(taskDesc, allGuides);
48
+ logger.flow("session_start", "guide_suggestions", { task_desc: taskDesc, relevant: suggestions.relevant.length, suggested: suggestions.suggested.length });
38
49
  const formattedSuggestions = guides.formatSuggestions(suggestions);
50
+ logger.data("memory.json", "load");
39
51
  const allMemory = core.loadMemory();
40
52
  const projectMemory = core.filterByProject(allMemory, core.detectProject());
41
53
  const relevantResults = core.searchAndSortFragments(projectMemory, taskDesc, 3);
54
+ logger.flow("session_start", "preload_memories", { relevant_count: relevantResults.length, project_memory_count: projectMemory.length });
42
55
  for (const frag of relevantResults) {
43
56
  const boosted = core.boostOnAccess(frag);
44
57
  Object.assign(frag, boosted);
45
58
  }
59
+ logger.data("memory.json", "save", { reason: "boost_preloaded", boosted_count: relevantResults.length });
46
60
  core.saveMemory(allMemory);
47
61
  let response = `Session started: ${session.session_id} (${taskType})\n`;
48
62
  if (technologies.length > 0) {
@@ -57,6 +71,7 @@ export async function handleSessionStart(args) {
57
71
  }
58
72
  }
59
73
  response += `\n${formattedSuggestions}`;
74
+ logger.flow("session_start", "complete", { session_id: session.session_id, task_type: taskType, suggestions: suggestions.relevant.length + suggestions.suggested.length, preloaded: relevantResults.length });
60
75
  return {
61
76
  content: [{ type: "text", text: response }],
62
77
  };
@@ -65,26 +80,33 @@ export async function handleSessionEnd(args) {
65
80
  const outcome = args?.outcome;
66
81
  const finalApproach = args?.final_approach || null;
67
82
  const lessons = args?.lessons || [];
83
+ logger.flow("session_end", "start", { outcome, has_final_approach: !!finalApproach, lesson_count: lessons.length });
68
84
  if (!outcome) {
85
+ logger.warn("session_end validation failed", { reason: "missing outcome" });
69
86
  return {
70
87
  content: [{ type: "text", text: "Error: 'outcome' parameter is required" }],
71
88
  isError: true,
72
89
  };
73
90
  }
91
+ logger.data("sessions.json", "load");
74
92
  const allSessions = sessions.loadSessions();
75
93
  const session = activeSessionId
76
94
  ? sessions.findSession(allSessions, activeSessionId)
77
95
  : sessions.findActiveSession(allSessions);
78
96
  if (!session) {
97
+ logger.warn("session_end no active session", { activeSessionId });
79
98
  return {
80
99
  content: [{ type: "text", text: "Error: No active session to end." }],
81
100
  isError: true,
82
101
  };
83
102
  }
103
+ logger.flow("session_end", "session_found", { session_id: session.session_id, task_type: session.task_type });
84
104
  sessions.endSession(session, outcome, finalApproach, lessons);
105
+ logger.data("guides.json", "load");
85
106
  const allGuides = guides.loadGuides();
86
107
  const improvementLines = [];
87
108
  if (session.guides_used && session.guides_used.length > 0) {
109
+ logger.flow("session_end", "evaluating_guides", { guides_used: session.guides_used, outcome });
88
110
  for (const guideName of session.guides_used) {
89
111
  const guide = guides.findGuide(allGuides, guideName);
90
112
  if (guide) {
@@ -97,14 +119,17 @@ export async function handleSessionEnd(args) {
97
119
  if (total >= 3) {
98
120
  const rate = guide.success_count / total;
99
121
  if (rate < 0.4) {
122
+ logger.warn("session_end low guide success rate", { guide: guideName, success_rate: rate.toFixed(2), total });
100
123
  improvementLines.push(` [!] Guide "${guideName}" success rate is ${rate.toFixed(2)} (${guide.success_count}/${total}). Consider refining with guide_update.`);
101
124
  }
102
125
  }
103
126
  }
104
127
  }
105
128
  }
129
+ logger.data("guides.json", "save", { reason: "guide_success_tracking", guides_updated: session.guides_used.length });
106
130
  guides.saveGuides(allGuides);
107
131
  }
132
+ logger.data("sessions.json", "save", { session_id: session.session_id, outcome });
108
133
  sessions.saveSessions(allSessions);
109
134
  activeSessionId = null;
110
135
  let response = `Session ${session.session_id} ended: ${outcome}\n`;
@@ -115,6 +140,7 @@ export async function handleSessionEnd(args) {
115
140
  if (improvementLines.length > 0) {
116
141
  response += `\nIMPROVEMENT SUGGESTIONS:\n${improvementLines.join("\n")}\n`;
117
142
  }
143
+ logger.flow("session_end", "complete", { session_id: session.session_id, outcome, improvement_suggestions: improvementLines.length });
118
144
  return {
119
145
  content: [{ type: "text", text: response }],
120
146
  };
@@ -125,9 +151,12 @@ export async function handleMemoryRead(args) {
125
151
  const detailId = args?.id || null;
126
152
  const context = args?.context || null;
127
153
  const showAll = args?.all === true;
154
+ logger.flow("memory_read", "start", { project: currentProject, query, id: detailId, ids: args?.ids?.length, all: showAll, context });
128
155
  let memory = core.loadMemory();
156
+ logger.data("memory.json", "load", { total_fragments: memory.length });
129
157
  const detailIds = args?.ids || null;
130
158
  if (detailIds && Array.isArray(detailIds) && detailIds.length > 0) {
159
+ logger.debug("memory_read batch_ids", { ids: detailIds });
131
160
  const results = [];
132
161
  for (const did of detailIds) {
133
162
  const fragment = memory.find((f) => f.id === did);
@@ -137,18 +166,23 @@ export async function handleMemoryRead(args) {
137
166
  results.push(core.formatMemoryDetail(fragment));
138
167
  }
139
168
  else {
169
+ logger.warn("memory_read batch_id not_found", { id: did });
140
170
  results.push(`Fragment [${did}] not found.`);
141
171
  }
142
172
  }
173
+ logger.data("memory.json", "save", { reason: "boost_batch_ids", count: detailIds.length });
143
174
  core.saveMemory(memory);
144
175
  notifyMemoryChange();
176
+ logger.flow("memory_read", "complete_batch", { ids_requested: detailIds.length });
145
177
  return {
146
178
  content: [{ type: "text", text: results.join("\n\n") }],
147
179
  };
148
180
  }
149
181
  if (detailId) {
182
+ logger.flow("memory_read", "single_id_lookup", { id: detailId });
150
183
  const fragment = memory.find((f) => f.id === detailId);
151
184
  if (!fragment) {
185
+ logger.warn("memory_read id not_found", { id: detailId });
152
186
  return {
153
187
  content: [{ type: "text", text: `Error: Fragment with ID '${detailId}' not found` }],
154
188
  isError: true,
@@ -156,8 +190,10 @@ export async function handleMemoryRead(args) {
156
190
  }
157
191
  const boosted = core.boostOnAccess(fragment, context);
158
192
  Object.assign(fragment, boosted);
193
+ logger.data("memory.json", "save", { reason: "boost_single", id: detailId });
159
194
  core.saveMemory(memory);
160
195
  notifyMemoryChange();
196
+ logger.flow("memory_read", "complete_single", { id: detailId, confidence: fragment.confidence?.toFixed(2) });
161
197
  return {
162
198
  content: [{ type: "text", text: core.formatMemoryDetail(fragment) }],
163
199
  };
@@ -165,12 +201,14 @@ export async function handleMemoryRead(args) {
165
201
  const filteredMemory = showAll
166
202
  ? memory
167
203
  : core.filterByProject(memory, currentProject);
204
+ logger.debug("memory_read filter", { showAll, project: currentProject, before_filter: memory.length, after_filter: filteredMemory.length });
168
205
  let results = core.searchAndSortFragments(filteredMemory, query, 30);
169
206
  results = core.filterFragments(results, {
170
207
  minConfidence: args?.minConfidence,
171
208
  afterDate: args?.afterDate,
172
209
  beforeDate: args?.beforeDate,
173
210
  });
211
+ logger.flow("memory_read", "search_results", { query, result_count: results.length, minConfidence: args?.minConfidence });
174
212
  const resultIds = new Set(results.map((r) => r.id));
175
213
  for (const frag of memory) {
176
214
  if (resultIds.has(frag.id)) {
@@ -180,8 +218,10 @@ export async function handleMemoryRead(args) {
180
218
  }
181
219
  const scopeInfo = showAll ? "all projects" : currentProject || "global";
182
220
  const formatted = core.formatMemoryForLLM(results, scopeInfo);
221
+ logger.data("memory.json", "save", { reason: "boost_search_results", boosted_count: resultIds.size });
183
222
  core.saveMemory(memory);
184
223
  notifyMemoryChange();
224
+ logger.flow("memory_read", "complete_search", { query, results: results.length, scope: scopeInfo });
185
225
  return {
186
226
  content: [{ type: "text", text: formatted }],
187
227
  };
@@ -192,15 +232,19 @@ export async function handleMemoryAdd(args) {
192
232
  const description = args?.description || null;
193
233
  const project = args?.project === undefined ? null : args.project;
194
234
  const source = (args?.source || "ai");
235
+ logger.flow("memory_add", "start", { title, project, source, has_description: !!description, fragment_length: fragment?.length });
195
236
  if (!fragment || typeof fragment !== "string") {
237
+ logger.warn("memory_add validation failed", { reason: "missing or invalid fragment" });
196
238
  return {
197
239
  content: [{ type: "text", text: "Error: 'fragment' parameter is required and must be a string" }],
198
240
  isError: true,
199
241
  };
200
242
  }
243
+ logger.data("memory.json", "load");
201
244
  const memory = core.loadMemory();
202
245
  const similarMatch = core.findSimilarFragment(memory, fragment, project);
203
246
  if (similarMatch) {
247
+ logger.warn("memory_add duplicate_detected", { similar_id: similarMatch.id, similar_title: similarMatch.title });
204
248
  return {
205
249
  content: [{
206
250
  type: "text",
@@ -209,25 +253,35 @@ export async function handleMemoryAdd(args) {
209
253
  isError: true,
210
254
  };
211
255
  }
256
+ logger.flow("memory_add", "secret_detection", { confirm: args?.confirm });
212
257
  const { redacted, found } = core.redactSecrets(fragment);
213
258
  const hasSecrets = found.length > 0;
214
259
  const finalFragment = hasSecrets && !args?.confirm ? redacted : fragment;
260
+ if (hasSecrets) {
261
+ logger.warn("memory_add secrets_detected", { secret_types: found.map(f => f.type), confirmed: !!args?.confirm });
262
+ }
215
263
  const newFragment = core.createFragment(finalFragment, source, title, project, description);
264
+ logger.flow("memory_add", "fragment_created", { id: newFragment.id, title: newFragment.title });
216
265
  if (activeSessionId) {
266
+ logger.data("sessions.json", "load");
217
267
  const allSessions = sessions.loadSessions();
218
268
  const session = sessions.findSession(allSessions, activeSessionId);
219
269
  if (session) {
270
+ logger.flow("memory_add", "session_link", { session_id: activeSessionId, task_type: session.task_type });
220
271
  newFragment.session_id = activeSessionId;
221
272
  newFragment.task_type = session.task_type;
222
273
  session.memories_created = session.memories_created || [];
223
274
  session.memories_created.push(newFragment.id);
275
+ logger.data("sessions.json", "save", { reason: "link_memory", session_id: activeSessionId });
224
276
  sessions.saveSessions(allSessions);
225
277
  }
226
278
  }
227
279
  memory.push(newFragment);
280
+ logger.data("memory.json", "save", { reason: "add_fragment", id: newFragment.id, total: memory.length });
228
281
  core.saveMemory(memory);
229
282
  notifyMemoryChange();
230
283
  const overlaps = core.findTopicOverlaps(memory, finalFragment, project, 5);
284
+ logger.flow("memory_add", "overlap_check", { overlap_count: overlaps.length });
231
285
  const scopeInfo = newFragment.project ? ` (project: ${newFragment.project})` : " (global)";
232
286
  let response = `Added fragment [${newFragment.id}]${scopeInfo}: "${newFragment.title}"\nSummary: ${newFragment.description}`;
233
287
  if (hasSecrets) {
@@ -240,6 +294,7 @@ export async function handleMemoryAdd(args) {
240
294
  }
241
295
  response += `\nConsider: Does this update or contradict existing knowledge? Use memory_update to refine or memory_merge to consolidate.`;
242
296
  }
297
+ logger.flow("memory_add", "complete", { id: newFragment.id, title: newFragment.title, overlaps: overlaps.length });
243
298
  return {
244
299
  content: [{ type: "text", text: response }],
245
300
  };
@@ -249,15 +304,19 @@ export async function handleMemoryUpdate(args) {
249
304
  const title = args?.title;
250
305
  const fragment = args?.fragment;
251
306
  const confidence = args?.confidence;
307
+ logger.flow("memory_update", "start", { id, has_title: title !== undefined, has_fragment: fragment !== undefined, has_confidence: confidence !== undefined });
252
308
  if (!id || typeof id !== "string") {
309
+ logger.warn("memory_update validation failed", { reason: "missing or invalid id" });
253
310
  return {
254
311
  content: [{ type: "text", text: "Error: 'id' parameter is required and must be a string" }],
255
312
  isError: true,
256
313
  };
257
314
  }
315
+ logger.data("memory.json", "load");
258
316
  const memory = core.loadMemory();
259
317
  const targetIndex = memory.findIndex((f) => f.id === id);
260
318
  if (targetIndex === -1) {
319
+ logger.warn("memory_update fragment not_found", { id });
261
320
  return {
262
321
  content: [{ type: "text", text: `Error: Fragment with ID '${id}' not found` }],
263
322
  isError: true,
@@ -265,57 +324,71 @@ export async function handleMemoryUpdate(args) {
265
324
  }
266
325
  if (title !== undefined) {
267
326
  if (typeof title !== "string") {
327
+ logger.warn("memory_update validation failed", { reason: "title not string" });
268
328
  return {
269
329
  content: [{ type: "text", text: "Error: 'title' must be a string" }],
270
330
  isError: true,
271
331
  };
272
332
  }
333
+ logger.debug("memory_update updating_title", { id, new_title: title });
273
334
  memory[targetIndex].title = title;
274
335
  }
275
336
  if (fragment !== undefined) {
276
337
  if (typeof fragment !== "string") {
338
+ logger.warn("memory_update validation failed", { reason: "fragment not string" });
277
339
  return {
278
340
  content: [{ type: "text", text: "Error: 'fragment' must be a string" }],
279
341
  isError: true,
280
342
  };
281
343
  }
344
+ logger.debug("memory_update updating_fragment", { id });
282
345
  memory[targetIndex].fragment = fragment;
283
346
  memory[targetIndex].accessed++;
284
347
  }
285
348
  if (confidence !== undefined) {
286
349
  if (typeof confidence !== "number" || confidence < 0 || confidence > 1) {
350
+ logger.warn("memory_update validation failed", { reason: "confidence out of range", confidence });
287
351
  return {
288
352
  content: [{ type: "text", text: "Error: 'confidence' must be a number between 0 and 1" }],
289
353
  isError: true,
290
354
  };
291
355
  }
356
+ logger.debug("memory_update updating_confidence", { id, new_confidence: confidence });
292
357
  memory[targetIndex].confidence = confidence;
293
358
  }
359
+ logger.data("memory.json", "save", { reason: "update_fragment", id });
294
360
  core.saveMemory(memory);
295
361
  notifyMemoryChange();
362
+ logger.flow("memory_update", "complete", { id, title: memory[targetIndex].title });
296
363
  return {
297
364
  content: [{ type: "text", text: `Updated fragment [${id}]: "${memory[targetIndex].title}"` }],
298
365
  };
299
366
  }
300
367
  export async function handleMemoryForget(args) {
301
368
  const id = args?.id;
369
+ logger.flow("memory_forget", "start", { id });
302
370
  if (!id || typeof id !== "string") {
371
+ logger.warn("memory_forget validation failed", { reason: "missing or invalid id" });
303
372
  return {
304
373
  content: [{ type: "text", text: "Error: 'id' parameter is required and must be a string" }],
305
374
  isError: true,
306
375
  };
307
376
  }
377
+ logger.data("memory.json", "load");
308
378
  const memory = core.loadMemory();
309
379
  const initialLength = memory.length;
310
380
  const filtered = memory.filter((f) => f.id !== id);
311
381
  if (filtered.length === initialLength) {
382
+ logger.warn("memory_forget fragment not_found", { id });
312
383
  return {
313
384
  content: [{ type: "text", text: `Error: Fragment with ID '${id}' not found` }],
314
385
  isError: true,
315
386
  };
316
387
  }
388
+ logger.data("memory.json", "save", { reason: "forget_fragment", id, before: initialLength, after: filtered.length });
317
389
  core.saveMemory(filtered, { force: true });
318
390
  notifyMemoryChange();
391
+ logger.flow("memory_forget", "complete", { id });
319
392
  return {
320
393
  content: [{ type: "text", text: `Forgot fragment with ID: ${id}` }],
321
394
  };
@@ -323,21 +396,26 @@ export async function handleMemoryForget(args) {
323
396
  export async function handleMemoryFeedback(args) {
324
397
  const id = args?.id;
325
398
  const useful = args?.useful;
399
+ logger.flow("memory_feedback", "start", { id, useful });
326
400
  if (!id || typeof id !== "string") {
401
+ logger.warn("memory_feedback validation failed", { reason: "missing or invalid id" });
327
402
  return {
328
403
  content: [{ type: "text", text: "Error: 'id' parameter is required" }],
329
404
  isError: true,
330
405
  };
331
406
  }
332
407
  if (typeof useful !== "boolean") {
408
+ logger.warn("memory_feedback validation failed", { reason: "missing or invalid useful" });
333
409
  return {
334
410
  content: [{ type: "text", text: "Error: 'useful' parameter is required and must be a boolean" }],
335
411
  isError: true,
336
412
  };
337
413
  }
414
+ logger.data("memory.json", "load");
338
415
  const memory = core.loadMemory();
339
416
  const targetIndex = memory.findIndex((f) => f.id === id);
340
417
  if (targetIndex === -1) {
418
+ logger.warn("memory_feedback fragment not_found", { id });
341
419
  return {
342
420
  content: [{ type: "text", text: `Error: Fragment with ID '${id}' not found` }],
343
421
  isError: true,
@@ -347,8 +425,10 @@ export async function handleMemoryFeedback(args) {
347
425
  const boosted = core.boostOnAccess(memory[targetIndex]);
348
426
  Object.assign(memory[targetIndex], boosted);
349
427
  memory[targetIndex].positive_feedback = (memory[targetIndex].positive_feedback || 0) + 1;
428
+ logger.data("memory.json", "save", { reason: "positive_feedback", id, new_confidence: memory[targetIndex].confidence?.toFixed(2) });
350
429
  core.saveMemory(memory);
351
430
  notifyMemoryChange();
431
+ logger.flow("memory_feedback", "complete_positive", { id, confidence: memory[targetIndex].confidence?.toFixed(2) });
352
432
  return {
353
433
  content: [{ type: "text", text: `Positive feedback recorded for [${id}]. Confidence boosted to ${memory[targetIndex].confidence.toFixed(2)}.` }],
354
434
  };
@@ -357,8 +437,10 @@ export async function handleMemoryFeedback(args) {
357
437
  const penalized = core.recordNegativeHit(memory[targetIndex]);
358
438
  Object.assign(memory[targetIndex], penalized);
359
439
  memory[targetIndex].negative_feedback = (memory[targetIndex].negative_feedback || 0) + 1;
440
+ logger.data("memory.json", "save", { reason: "negative_feedback", id, new_confidence: memory[targetIndex].confidence?.toFixed(2) });
360
441
  core.saveMemory(memory);
361
442
  notifyMemoryChange();
443
+ logger.flow("memory_feedback", "complete_negative", { id, confidence: memory[targetIndex].confidence?.toFixed(2) });
362
444
  return {
363
445
  content: [{ type: "text", text: `Negative feedback recorded for [${id}]. Confidence reduced to ${memory[targetIndex].confidence.toFixed(2)}.` }],
364
446
  };
@@ -369,38 +451,47 @@ export async function handleMemoryMerge(args) {
369
451
  const title = args?.title;
370
452
  const fragment = args?.fragment;
371
453
  const project = args?.project === undefined ? null : args.project;
454
+ logger.flow("memory_merge", "start", { ids, title, project });
372
455
  if (!ids || !Array.isArray(ids) || ids.length < 2) {
456
+ logger.warn("memory_merge validation failed", { reason: "ids must be array with at least 2 elements" });
373
457
  return {
374
458
  content: [{ type: "text", text: "Error: 'ids' must be an array with at least 2 fragment IDs" }],
375
459
  isError: true,
376
460
  };
377
461
  }
378
462
  if (!title || typeof title !== "string") {
463
+ logger.warn("memory_merge validation failed", { reason: "title required" });
379
464
  return {
380
465
  content: [{ type: "text", text: "Error: 'title' is required and must be a string" }],
381
466
  isError: true,
382
467
  };
383
468
  }
384
469
  if (!fragment || typeof fragment !== "string") {
470
+ logger.warn("memory_merge validation failed", { reason: "fragment required" });
385
471
  return {
386
472
  content: [{ type: "text", text: "Error: 'fragment' is required and must be a string" }],
387
473
  isError: true,
388
474
  };
389
475
  }
476
+ logger.data("memory.json", "load");
390
477
  const memory = core.loadMemory();
391
478
  const notFound = ids.filter((id) => !memory.find((f) => f.id === id));
392
479
  if (notFound.length > 0) {
480
+ logger.warn("memory_merge fragments not_found", { missing: notFound });
393
481
  return {
394
482
  content: [{ type: "text", text: `Error: Fragment(s) not found: ${notFound.join(", ")}` }],
395
483
  isError: true,
396
484
  };
397
485
  }
398
486
  const newFragment = core.createFragment(fragment, "ai", title, project);
487
+ logger.flow("memory_merge", "merged_fragment_created", { new_id: newFragment.id, title });
399
488
  memory.push(newFragment);
400
489
  const mergedMemory = memory.filter((f) => !ids.includes(f.id));
490
+ logger.data("memory.json", "save", { reason: "merge_fragments", new_id: newFragment.id, removed_ids: ids, before: memory.length, after: mergedMemory.length });
401
491
  core.saveMemory(mergedMemory);
402
492
  notifyMemoryChange();
403
493
  const scopeInfo = newFragment.project ? ` (project: ${newFragment.project})` : " (global)";
494
+ logger.flow("memory_merge", "complete", { new_id: newFragment.id, merged_count: ids.length });
404
495
  return {
405
496
  content: [{ type: "text", text: `Merged ${ids.length} fragments into [${newFragment.id}]${scopeInfo}: "${newFragment.title}"\nRemoved IDs: ${ids.join(", ")}` }],
406
497
  };
@@ -410,7 +501,9 @@ export async function handleMemoryRelate(args) {
410
501
  const targetId = args?.targetId;
411
502
  const type = args?.type;
412
503
  const note = args?.note;
504
+ logger.flow("memory_relate", "start", { sourceId, targetId, type, has_note: !!note });
413
505
  if (!sourceId || !targetId || !type) {
506
+ logger.warn("memory_relate validation failed", { reason: "missing required params" });
414
507
  return {
415
508
  content: [{ type: "text", text: "Error: 'sourceId', 'targetId', and 'type' parameters are required" }],
416
509
  isError: true,
@@ -418,25 +511,30 @@ export async function handleMemoryRelate(args) {
418
511
  }
419
512
  const validTypes = ["contradicts", "supersedes", "supports", "related_to"];
420
513
  if (!validTypes.includes(type)) {
514
+ logger.warn("memory_relate validation failed", { reason: "invalid type", type });
421
515
  return {
422
516
  content: [{ type: "text", text: `Error: 'type' must be one of: ${validTypes.join(", ")}` }],
423
517
  isError: true,
424
518
  };
425
519
  }
426
520
  if (sourceId === targetId) {
521
+ logger.warn("memory_relate validation failed", { reason: "sourceId equals targetId" });
427
522
  return {
428
523
  content: [{ type: "text", text: "Error: sourceId and targetId cannot be the same" }],
429
524
  isError: true,
430
525
  };
431
526
  }
527
+ logger.data("memory.json", "load");
432
528
  const memory = core.loadMemory();
433
529
  if (!memory.find((f) => f.id === sourceId)) {
530
+ logger.warn("memory_relate source not_found", { sourceId });
434
531
  return {
435
532
  content: [{ type: "text", text: `Error: Source fragment [${sourceId}] not found` }],
436
533
  isError: true,
437
534
  };
438
535
  }
439
536
  if (!memory.find((f) => f.id === targetId)) {
537
+ logger.warn("memory_relate target not_found", { targetId });
440
538
  return {
441
539
  content: [{ type: "text", text: `Error: Target fragment [${targetId}] not found` }],
442
540
  isError: true,
@@ -444,13 +542,16 @@ export async function handleMemoryRelate(args) {
444
542
  }
445
543
  const success = core.addRelation(memory, sourceId, targetId, type, note || undefined);
446
544
  if (!success) {
545
+ logger.warn("memory_relate relation_exists", { sourceId, targetId, type });
447
546
  return {
448
547
  content: [{ type: "text", text: `Relation already exists between [${sourceId}] and [${targetId}] with type '${type}'` }],
449
548
  isError: true,
450
549
  };
451
550
  }
551
+ logger.data("memory.json", "save", { reason: "add_relation", sourceId, targetId, type });
452
552
  core.saveMemory(memory);
453
553
  notifyMemoryChange();
554
+ logger.flow("memory_relate", "complete", { sourceId, targetId, type });
454
555
  return {
455
556
  content: [{ type: "text", text: `Created relation: [${sourceId}] --${type}--> [${targetId}]${note ? ` (${note})` : ""}` }],
456
557
  };
@@ -459,16 +560,21 @@ export async function handleGuideGet(args) {
459
560
  const category = args?.category || null;
460
561
  const guideName = args?.guide || null;
461
562
  const task = args?.task || null;
563
+ logger.flow("guide_get", "start", { category, guide: guideName, task });
564
+ logger.data("guides.json", "load");
462
565
  const allGuides = guides.loadGuides();
463
566
  if (task) {
464
567
  const result = guides.suggestGuides(task, allGuides);
568
+ logger.flow("guide_get", "task_suggestions", { task, relevant: result.relevant.length, suggested: result.suggested.length });
465
569
  const formatted = guides.formatSuggestions(result);
466
570
  return {
467
571
  content: [{ type: "text", text: formatted }],
468
572
  };
469
573
  }
470
574
  if (guideName) {
575
+ logger.flow("guide_get", "single_guide_lookup", { guide: guideName });
471
576
  const guide = guides.findGuide(allGuides, guideName);
577
+ logger.flow("guide_get", "complete_single", { guide: guideName, found: !!guide });
472
578
  return {
473
579
  content: [{ type: "text", text: guides.formatGuideDetail(guide) }],
474
580
  };
@@ -476,6 +582,7 @@ export async function handleGuideGet(args) {
476
582
  const filtered = category
477
583
  ? guides.getGuidesByCategory(allGuides, category)
478
584
  : allGuides;
585
+ logger.flow("guide_get", "complete_list", { category, total: allGuides.length, filtered: filtered.length });
479
586
  const formatted = guides.formatGuidesForLLM(filtered);
480
587
  return {
481
588
  content: [{ type: "text", text: formatted }],
@@ -487,15 +594,21 @@ export async function handleGuidePractice(args) {
487
594
  const description = args?.description || "";
488
595
  const contexts = args?.contexts || [];
489
596
  const learnings = args?.learnings || [];
597
+ logger.flow("guide_practice", "start", { guide: guideName, category, outcome: args?.outcome, context_count: contexts.length, learning_count: learnings.length });
490
598
  if (!guideName || !category) {
599
+ logger.warn("guide_practice validation failed", { reason: "missing guide or category" });
491
600
  return {
492
601
  content: [{ type: "text", text: "Error: 'guide' and 'category' parameters are required" }],
493
602
  isError: true,
494
603
  };
495
604
  }
605
+ logger.data("guides.json", "load");
496
606
  const allGuides = guides.loadGuides();
607
+ const preUsageCount = guides.findGuide(allGuides, guideName)?.usage_count || 0;
497
608
  const updated = guides.practiceGuide(allGuides, guideName, category, description, contexts, learnings, args?.outcome);
609
+ logger.flow("guide_practice", "guide_updated", { guide: guideName, usage_before: preUsageCount, usage_after: updated.usage_count });
498
610
  if (activeSessionId) {
611
+ logger.data("sessions.json", "load");
499
612
  const allSessions = sessions.loadSessions();
500
613
  const session = sessions.findSession(allSessions, activeSessionId);
501
614
  if (session) {
@@ -504,13 +617,16 @@ export async function handleGuidePractice(args) {
504
617
  if (!session.guides_used.includes(guideName.toLowerCase())) {
505
618
  session.guides_used.push(guideName.toLowerCase());
506
619
  }
620
+ logger.data("sessions.json", "save", { reason: "track_guide_practice", session_id: activeSessionId, guide: guideName });
507
621
  sessions.saveSessions(allSessions);
508
622
  }
509
623
  }
624
+ logger.data("guides.json", "save", { reason: "practice_guide", guide: guideName });
510
625
  guides.saveGuides(allGuides);
511
626
  const isNew = updated.usage_count === 1;
512
627
  const action = isNew ? "Created" : "Updated";
513
628
  const response = `${action} guide "${updated.guide}" (${updated.category}): ${updated.usage_count}x usage, ${updated.learnings.length} learnings, ${updated.contexts.length} contexts`;
629
+ logger.flow("guide_practice", "complete", { guide: guideName, action, usage_count: updated.usage_count });
514
630
  return {
515
631
  content: [{ type: "text", text: response }],
516
632
  };
@@ -521,16 +637,21 @@ export async function handleGuideCreate(args) {
521
637
  const description = args?.description;
522
638
  const contexts = args?.contexts || [];
523
639
  const learnings = args?.learnings || [];
640
+ logger.flow("guide_create", "start", { guide: guideName, category, has_description: !!description });
524
641
  if (!guideName || !category || !description) {
642
+ logger.warn("guide_create validation failed", { reason: "missing guide, category, or description" });
525
643
  return {
526
644
  content: [{ type: "text", text: "Error: 'guide', 'category', and 'description' parameters are required" }],
527
645
  isError: true,
528
646
  };
529
647
  }
648
+ logger.data("guides.json", "load");
530
649
  const allGuides = guides.loadGuides();
531
650
  const existing = guides.findSimilarGuide(allGuides, guideName);
532
651
  if (existing) {
652
+ logger.flow("guide_create", "updating_existing", { guide: guideName, existing_id: existing.guide });
533
653
  existing.description = description;
654
+ logger.data("guides.json", "save", { reason: "update_existing_guide", guide: guideName });
534
655
  guides.saveGuides(allGuides);
535
656
  return {
536
657
  content: [{ type: "text", text: `Updated manual for existing guide "${existing.guide}" (${existing.category})` }],
@@ -538,7 +659,9 @@ export async function handleGuideCreate(args) {
538
659
  }
539
660
  const newGuide = guides.createGuide(guideName, category, description, contexts, learnings);
540
661
  allGuides.push(newGuide);
662
+ logger.data("guides.json", "save", { reason: "create_new_guide", guide: guideName, total: allGuides.length });
541
663
  guides.saveGuides(allGuides);
664
+ logger.flow("guide_create", "complete", { guide: guideName, category, is_new: true });
542
665
  return {
543
666
  content: [{ type: "text", text: `Created new guide "${newGuide.guide}" (${newGuide.category}) with a detailed manual.` }],
544
667
  };
@@ -547,25 +670,33 @@ export async function handleGuideDistill(args) {
547
670
  const memoryId = args?.memory_id;
548
671
  const guideName = args?.guide;
549
672
  const category = args?.category || "dev-tool";
673
+ logger.flow("guide_distill", "start", { memory_id: memoryId, guide: guideName, category });
550
674
  if (!memoryId || !guideName) {
675
+ logger.warn("guide_distill validation failed", { reason: "missing memory_id or guide" });
551
676
  return {
552
677
  content: [{ type: "text", text: "Error: 'memory_id' and 'guide' parameters are required" }],
553
678
  isError: true,
554
679
  };
555
680
  }
681
+ logger.data("memory.json", "load");
556
682
  const allMemory = core.loadMemory();
557
683
  const fragment = allMemory.find((m) => m.id === memoryId);
558
684
  if (!fragment) {
685
+ logger.warn("guide_distill memory not_found", { memory_id: memoryId });
559
686
  return {
560
687
  content: [{ type: "text", text: `Error: Memory fragment with ID '${memoryId}' not found.` }],
561
688
  isError: true,
562
689
  };
563
690
  }
691
+ logger.flow("guide_distill", "fragment_found", { memory_id: memoryId, title: fragment.title });
692
+ logger.data("guides.json", "load");
564
693
  const allGuides = guides.loadGuides();
565
694
  const updated = guides.promoteToGuide(allGuides, guideName, category, fragment.fragment, fragment.project || "global");
695
+ logger.data("guides.json", "save", { reason: "distill_memory_to_guide", memory_id: memoryId, guide: guideName });
566
696
  guides.saveGuides(allGuides);
567
697
  let response = `Successfully distilled memory [${memoryId}] into guide "${updated.guide}" (${updated.category}).\n\n`;
568
698
  response += guides.formatGuideDetail(updated);
699
+ logger.flow("guide_distill", "complete", { memory_id: memoryId, guide: guideName, category });
569
700
  return {
570
701
  content: [{ type: "text", text: response }],
571
702
  };
@@ -581,42 +712,55 @@ export async function handleGuideUpdate(args) {
581
712
  superseded_by: args?.superseded_by,
582
713
  deprecated: args?.deprecated,
583
714
  };
715
+ const fieldsToUpdate = Object.entries(updates).filter(([, v]) => v !== undefined).map(([k]) => k);
716
+ logger.flow("guide_update", "start", { guide: guideName, fields: fieldsToUpdate });
584
717
  if (!guideName) {
718
+ logger.warn("guide_update validation failed", { reason: "missing guide name" });
585
719
  return {
586
720
  content: [{ type: "text", text: "Error: 'guide' parameter is required" }],
587
721
  isError: true,
588
722
  };
589
723
  }
724
+ logger.data("guides.json", "load");
590
725
  const allGuides = guides.loadGuides();
591
726
  const updated = guides.updateGuide(allGuides, guideName, updates);
592
727
  if (!updated) {
728
+ logger.warn("guide_update guide not_found", { guide: guideName });
593
729
  return {
594
730
  content: [{ type: "text", text: `Error: Guide "${guideName}" not found.` }],
595
731
  isError: true,
596
732
  };
597
733
  }
734
+ logger.data("guides.json", "save", { reason: "update_guide", guide: guideName });
598
735
  guides.saveGuides(allGuides);
736
+ logger.flow("guide_update", "complete", { guide: guideName, updated_fields: fieldsToUpdate });
599
737
  return {
600
738
  content: [{ type: "text", text: `Updated guide "${updated.guide}":\n${guides.formatGuideDetail(updated)}` }],
601
739
  };
602
740
  }
603
741
  export async function handleGuideForget(args) {
604
742
  const guideName = args?.guide;
743
+ logger.flow("guide_forget", "start", { guide: guideName });
605
744
  if (!guideName) {
745
+ logger.warn("guide_forget validation failed", { reason: "missing guide name" });
606
746
  return {
607
747
  content: [{ type: "text", text: "Error: 'guide' parameter is required" }],
608
748
  isError: true,
609
749
  };
610
750
  }
751
+ logger.data("guides.json", "load");
611
752
  const allGuides = guides.loadGuides();
612
753
  const success = guides.deleteGuide(allGuides, guideName);
613
754
  if (!success) {
755
+ logger.warn("guide_forget guide not_found", { guide: guideName });
614
756
  return {
615
757
  content: [{ type: "text", text: `Error: Guide "${guideName}" not found.` }],
616
758
  isError: true,
617
759
  };
618
760
  }
761
+ logger.data("guides.json", "save", { reason: "forget_guide", guide: guideName, remaining: allGuides.length });
619
762
  guides.saveGuides(allGuides, { force: true });
763
+ logger.flow("guide_forget", "complete", { guide: guideName });
620
764
  return {
621
765
  content: [{ type: "text", text: `Successfully forgot guide: ${guideName}` }],
622
766
  };
@@ -628,18 +772,22 @@ export async function handleGuideMerge(args) {
628
772
  const description = args?.description || "";
629
773
  let contexts = args?.contexts;
630
774
  let learnings = args?.learnings;
775
+ logger.flow("guide_merge", "start", { guides: guideNames, new_guide: newGuideName, category });
631
776
  if (!guideNames || !Array.isArray(guideNames) || guideNames.length < 2) {
777
+ logger.warn("guide_merge validation failed", { reason: "guides must be array with at least 2 elements" });
632
778
  return {
633
779
  content: [{ type: "text", text: "Error: 'guides' must be an array with at least 2 guide names" }],
634
780
  isError: true,
635
781
  };
636
782
  }
637
783
  if (!newGuideName || !category) {
784
+ logger.warn("guide_merge validation failed", { reason: "missing guide name or category" });
638
785
  return {
639
786
  content: [{ type: "text", text: "Error: 'guide' and 'category' parameters are required" }],
640
787
  isError: true,
641
788
  };
642
789
  }
790
+ logger.data("guides.json", "load");
643
791
  const allGuides = guides.loadGuides();
644
792
  const sourceGuides = [];
645
793
  const notFound = [];
@@ -653,6 +801,7 @@ export async function handleGuideMerge(args) {
653
801
  }
654
802
  }
655
803
  if (notFound.length > 0) {
804
+ logger.warn("guide_merge guides not_found", { missing: notFound });
656
805
  return {
657
806
  content: [{ type: "text", text: `Error: Guide(s) not found: ${notFound.join(", ")}` }],
658
807
  isError: true,
@@ -667,39 +816,50 @@ export async function handleGuideMerge(args) {
667
816
  const antiPatterns = [...new Set(sourceGuides.flatMap((g) => g.anti_patterns || []))];
668
817
  const pitfalls = [...new Set(sourceGuides.flatMap((g) => g.known_pitfalls || []))];
669
818
  const totalUsage = sourceGuides.reduce((sum, g) => sum + g.usage_count, 0);
819
+ logger.flow("guide_merge", "source_stats", { source_count: sourceGuides.length, total_usage: totalUsage });
670
820
  const newGuide = guides.createGuide(newGuideName, category, description, contexts, learnings);
671
821
  newGuide.usage_count = totalUsage;
672
822
  newGuide.anti_patterns = antiPatterns;
673
823
  newGuide.known_pitfalls = pitfalls;
674
824
  allGuides.push(newGuide);
675
825
  const mergedGuides = allGuides.filter((g) => !guideNames.map((n) => n.toLowerCase()).includes(g.guide));
826
+ logger.data("guides.json", "save", { reason: "merge_guides", new_guide: newGuideName, removed: guideNames, total_usage: totalUsage });
676
827
  guides.saveGuides(mergedGuides);
677
828
  let response = `Merged ${guideNames.length} guides into "${newGuide.guide}" (${newGuide.category})\n`;
678
829
  response += `Total usage: ${totalUsage}x | Contexts: ${contexts.length} | Learnings: ${learnings.length}\n`;
679
830
  response += `Removed: ${guideNames.join(", ")}`;
831
+ logger.flow("guide_merge", "complete", { new_guide: newGuideName, merged_count: guideNames.length, total_usage: totalUsage });
680
832
  return {
681
833
  content: [{ type: "text", text: response }],
682
834
  };
683
835
  }
684
836
  export async function handleMemoryStats(args) {
685
837
  const project = args?.project || null;
838
+ logger.flow("memory_stats", "start", { project });
839
+ logger.data("memory.json", "load");
686
840
  const memory = core.loadMemory();
687
841
  const stats = core.calculateStats(memory, project);
842
+ logger.flow("memory_stats", "complete", { project, total: stats.total, avg_confidence: stats.avg_confidence?.toFixed(2) });
688
843
  return {
689
844
  content: [{ type: "text", text: core.formatStats(stats) }],
690
845
  };
691
846
  }
692
847
  export async function handleMemoryAudit(_args) {
848
+ logger.flow("memory_audit", "start");
849
+ logger.data("memory.json", "load");
693
850
  const memory = core.loadMemory();
694
851
  const result = core.auditMemory(memory);
852
+ logger.flow("memory_audit", "complete", { issues_count: result.issues?.length || 0 });
695
853
  return {
696
854
  content: [{ type: "text", text: core.formatAuditReport(result) }],
697
855
  };
698
856
  }
699
857
  export async function handleSessionStats(args) {
700
858
  const count = args?.count || 10;
859
+ logger.flow("session_stats", "start", { count });
701
860
  const recentSessions = virtualSession.getRecentSessions(count);
702
861
  const current = virtualSession.getCurrentVirtualSession();
862
+ logger.debug("session_stats data", { requested: count, recent_count: recentSessions.length, has_current: !!current });
703
863
  let output = `## Session Stats\n`;
704
864
  if (current) {
705
865
  output += `Active session: ${current.tool_calls.length} tool calls\n`;
@@ -721,60 +881,127 @@ export async function handleSessionStats(args) {
721
881
  else {
722
882
  output += `No past sessions recorded yet.\n`;
723
883
  }
884
+ logger.flow("session_stats", "complete", { count, recent_count: recentSessions.length, has_current: !!current });
724
885
  return { content: [{ type: "text", text: output }] };
725
886
  }
726
887
  export async function handleCallTool(request) {
727
888
  const { name, arguments: args } = request.params;
889
+ logger.request(name, args);
890
+ const startTime = Date.now();
728
891
  try {
729
892
  switch (name) {
730
- case "session_start":
731
- return await handleSessionStart(args);
732
- case "session_end":
733
- return await handleSessionEnd(args);
734
- case "memory_read":
735
- return await handleMemoryRead(args);
736
- case "memory_add":
737
- return await handleMemoryAdd(args);
738
- case "memory_update":
739
- return await handleMemoryUpdate(args);
740
- case "memory_forget":
741
- return await handleMemoryForget(args);
742
- case "memory_feedback":
743
- return await handleMemoryFeedback(args);
744
- case "memory_merge":
745
- return await handleMemoryMerge(args);
746
- case "memory_relate":
747
- return await handleMemoryRelate(args);
748
- case "memory_stats":
749
- return await handleMemoryStats(args);
750
- case "memory_audit":
751
- return await handleMemoryAudit(args);
752
- case "guide_get":
753
- return await handleGuideGet(args);
754
- case "guide_practice":
755
- return await handleGuidePractice(args);
756
- case "guide_create":
757
- return await handleGuideCreate(args);
758
- case "guide_distill":
759
- return await handleGuideDistill(args);
760
- case "guide_update":
761
- return await handleGuideUpdate(args);
762
- case "guide_forget":
763
- return await handleGuideForget(args);
764
- case "guide_merge":
765
- return await handleGuideMerge(args);
766
- case "session_stats":
767
- return await handleSessionStats(args);
768
- default:
769
- return {
893
+ case "session_start": {
894
+ const result = await handleSessionStart(args);
895
+ logger.response(name, !!result.isError, Date.now() - startTime);
896
+ return result;
897
+ }
898
+ case "session_end": {
899
+ const result = await handleSessionEnd(args);
900
+ logger.response(name, !!result.isError, Date.now() - startTime);
901
+ return result;
902
+ }
903
+ case "memory_read": {
904
+ const result = await handleMemoryRead(args);
905
+ logger.response(name, !!result.isError, Date.now() - startTime);
906
+ return result;
907
+ }
908
+ case "memory_add": {
909
+ const result = await handleMemoryAdd(args);
910
+ logger.response(name, !!result.isError, Date.now() - startTime);
911
+ return result;
912
+ }
913
+ case "memory_update": {
914
+ const result = await handleMemoryUpdate(args);
915
+ logger.response(name, !!result.isError, Date.now() - startTime);
916
+ return result;
917
+ }
918
+ case "memory_forget": {
919
+ const result = await handleMemoryForget(args);
920
+ logger.response(name, !!result.isError, Date.now() - startTime);
921
+ return result;
922
+ }
923
+ case "memory_feedback": {
924
+ const result = await handleMemoryFeedback(args);
925
+ logger.response(name, !!result.isError, Date.now() - startTime);
926
+ return result;
927
+ }
928
+ case "memory_merge": {
929
+ const result = await handleMemoryMerge(args);
930
+ logger.response(name, !!result.isError, Date.now() - startTime);
931
+ return result;
932
+ }
933
+ case "memory_relate": {
934
+ const result = await handleMemoryRelate(args);
935
+ logger.response(name, !!result.isError, Date.now() - startTime);
936
+ return result;
937
+ }
938
+ case "memory_stats": {
939
+ const result = await handleMemoryStats(args);
940
+ logger.response(name, !!result.isError, Date.now() - startTime);
941
+ return result;
942
+ }
943
+ case "memory_audit": {
944
+ const result = await handleMemoryAudit(args);
945
+ logger.response(name, !!result.isError, Date.now() - startTime);
946
+ return result;
947
+ }
948
+ case "guide_get": {
949
+ const result = await handleGuideGet(args);
950
+ logger.response(name, !!result.isError, Date.now() - startTime);
951
+ return result;
952
+ }
953
+ case "guide_practice": {
954
+ const result = await handleGuidePractice(args);
955
+ logger.response(name, !!result.isError, Date.now() - startTime);
956
+ return result;
957
+ }
958
+ case "guide_create": {
959
+ const result = await handleGuideCreate(args);
960
+ logger.response(name, !!result.isError, Date.now() - startTime);
961
+ return result;
962
+ }
963
+ case "guide_distill": {
964
+ const result = await handleGuideDistill(args);
965
+ logger.response(name, !!result.isError, Date.now() - startTime);
966
+ return result;
967
+ }
968
+ case "guide_update": {
969
+ const result = await handleGuideUpdate(args);
970
+ logger.response(name, !!result.isError, Date.now() - startTime);
971
+ return result;
972
+ }
973
+ case "guide_forget": {
974
+ const result = await handleGuideForget(args);
975
+ logger.response(name, !!result.isError, Date.now() - startTime);
976
+ return result;
977
+ }
978
+ case "guide_merge": {
979
+ const result = await handleGuideMerge(args);
980
+ logger.response(name, !!result.isError, Date.now() - startTime);
981
+ return result;
982
+ }
983
+ case "session_stats": {
984
+ const result = await handleSessionStats(args);
985
+ logger.response(name, !!result.isError, Date.now() - startTime);
986
+ return result;
987
+ }
988
+ default: {
989
+ logger.warn("handleCallTool unknown_tool", { tool: name });
990
+ const result = {
770
991
  content: [{ type: "text", text: `Error: Unknown tool '${name}'` }],
771
992
  isError: true,
772
993
  };
994
+ logger.response(name, true, Date.now() - startTime);
995
+ return result;
996
+ }
773
997
  }
774
998
  }
775
999
  catch (error) {
1000
+ const err = error;
1001
+ logger.error("handleCallTool exception", { tool: name, error: err.message });
1002
+ logger.response(name, true, Date.now() - startTime, { error: err.message });
776
1003
  return {
777
- content: [{ type: "text", text: `Error: ${error.message}` }],
1004
+ content: [{ type: "text", text: `Error: ${err.message}` }],
778
1005
  isError: true,
779
1006
  };
780
1007
  }