@prmichaelsen/remember-mcp 2.7.10 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +6 -0
- package/AGENT.md +224 -21
- package/CHANGELOG.md +47 -912
- package/README.md +35 -0
- package/agent/commands/acp.command-create.md +373 -0
- package/agent/commands/acp.design-create.md +225 -0
- package/agent/commands/acp.init.md +40 -5
- package/agent/commands/acp.package-create.md +895 -0
- package/agent/commands/acp.package-info.md +212 -0
- package/agent/commands/acp.package-install.md +207 -33
- package/agent/commands/acp.package-list.md +280 -0
- package/agent/commands/acp.package-publish.md +541 -0
- package/agent/commands/acp.package-remove.md +293 -0
- package/agent/commands/acp.package-search.md +307 -0
- package/agent/commands/acp.package-update.md +361 -0
- package/agent/commands/acp.package-validate.md +540 -0
- package/agent/commands/acp.pattern-create.md +327 -0
- package/agent/commands/acp.plan.md +553 -0
- package/agent/commands/acp.proceed.md +112 -86
- package/agent/commands/acp.project-create.md +673 -0
- package/agent/commands/acp.project-list.md +225 -0
- package/agent/commands/acp.project-set.md +227 -0
- package/agent/commands/acp.report.md +3 -0
- package/agent/commands/acp.resume.md +238 -0
- package/agent/commands/acp.status.md +1 -0
- package/agent/commands/acp.sync.md +56 -15
- package/agent/commands/acp.task-create.md +391 -0
- package/agent/commands/acp.update.md +1 -0
- package/agent/commands/acp.validate.md +62 -10
- package/agent/commands/acp.version-check-for-updates.md +6 -5
- package/agent/commands/acp.version-check.md +7 -6
- package/agent/commands/acp.version-update.md +7 -6
- package/agent/commands/command.template.md +48 -0
- package/agent/commands/git.commit.md +6 -3
- package/agent/commands/git.init.md +1 -0
- package/agent/manifest.template.yaml +13 -0
- package/agent/package.template.yaml +53 -0
- package/agent/progress.template.yaml +3 -0
- package/agent/progress.yaml +103 -5
- package/agent/scripts/acp.common.sh +1536 -0
- package/agent/scripts/acp.install.sh +293 -0
- package/agent/scripts/acp.package-create.sh +925 -0
- package/agent/scripts/acp.package-info.sh +270 -0
- package/agent/scripts/acp.package-install.sh +675 -0
- package/agent/scripts/acp.package-list.sh +263 -0
- package/agent/scripts/acp.package-publish.sh +420 -0
- package/agent/scripts/acp.package-remove.sh +272 -0
- package/agent/scripts/acp.package-search.sh +156 -0
- package/agent/scripts/acp.package-update.sh +438 -0
- package/agent/scripts/acp.package-validate.sh +954 -0
- package/agent/scripts/acp.project-list.sh +121 -0
- package/agent/scripts/acp.project-set.sh +138 -0
- package/agent/scripts/{uninstall.sh → acp.uninstall.sh} +25 -15
- package/agent/scripts/{check-for-updates.sh → acp.version-check-for-updates.sh} +24 -14
- package/agent/scripts/{version.sh → acp.version-check.sh} +20 -8
- package/agent/scripts/{update.sh → acp.version-update.sh} +44 -25
- package/agent/scripts/acp.yaml-parser.sh +853 -0
- package/agent/scripts/acp.yaml-validate.sh +205 -0
- package/agent/tasks/task-68-fix-missing-space-properties.md +192 -0
- package/agent/tasks/task-69-add-comprehensive-tool-debugging.md +454 -0
- package/dist/config.d.ts +18 -0
- package/dist/server-factory.js +296 -19
- package/dist/server.js +296 -19
- package/dist/utils/debug.d.ts +52 -0
- package/dist/utils/debug.spec.d.ts +5 -0
- package/dist/weaviate/client.d.ts +1 -1
- package/package.json +1 -1
- package/src/config.ts +33 -0
- package/src/tools/confirm.ts +70 -7
- package/src/tools/publish.ts +19 -1
- package/src/tools/query-space.ts +36 -3
- package/src/tools/search-space.ts +36 -3
- package/src/utils/debug.spec.ts +257 -0
- package/src/utils/debug.ts +138 -0
- package/src/weaviate/client.ts +42 -3
- package/agent/scripts/install.sh +0 -157
package/src/tools/confirm.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { getWeaviateClient, getMemoryCollectionName, fetchMemoryWithAllPropertie
|
|
|
11
11
|
import { ensurePublicCollection } from '../weaviate/space-schema.js';
|
|
12
12
|
import { handleToolError } from '../utils/error-handler.js';
|
|
13
13
|
import { logger } from '../utils/logger.js';
|
|
14
|
+
import { createDebugLogger } from '../utils/debug.js';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Tool definition for remember_confirm
|
|
@@ -63,7 +64,16 @@ export async function handleConfirm(
|
|
|
63
64
|
args: ConfirmArgs,
|
|
64
65
|
userId: string
|
|
65
66
|
): Promise<string> {
|
|
67
|
+
const debug = createDebugLogger({
|
|
68
|
+
tool: 'remember_confirm',
|
|
69
|
+
userId,
|
|
70
|
+
operation: 'confirm_action',
|
|
71
|
+
});
|
|
72
|
+
|
|
66
73
|
try {
|
|
74
|
+
debug.info('Tool invoked');
|
|
75
|
+
debug.trace('Arguments', { token: args.token });
|
|
76
|
+
|
|
67
77
|
logger.info('Starting confirmation', {
|
|
68
78
|
tool: 'remember_confirm',
|
|
69
79
|
userId,
|
|
@@ -71,7 +81,10 @@ export async function handleConfirm(
|
|
|
71
81
|
});
|
|
72
82
|
|
|
73
83
|
// Validate and confirm token
|
|
74
|
-
|
|
84
|
+
debug.debug('Validating confirmation token');
|
|
85
|
+
const request = await debug.time('Confirm token', async () => {
|
|
86
|
+
return await confirmationTokenService.confirmRequest(userId, args.token);
|
|
87
|
+
});
|
|
75
88
|
|
|
76
89
|
logger.debug('Token validation result', {
|
|
77
90
|
tool: 'remember_confirm',
|
|
@@ -114,6 +127,10 @@ export async function handleConfirm(
|
|
|
114
127
|
|
|
115
128
|
throw new Error(`Unknown action type: ${request.action}`);
|
|
116
129
|
} catch (error) {
|
|
130
|
+
debug.error('Tool failed', {
|
|
131
|
+
error: error instanceof Error ? error.message : String(error),
|
|
132
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
133
|
+
});
|
|
117
134
|
handleToolError(error, {
|
|
118
135
|
toolName: 'remember_confirm',
|
|
119
136
|
userId,
|
|
@@ -130,7 +147,18 @@ async function executePublishMemory(
|
|
|
130
147
|
request: ConfirmationRequest & { request_id: string },
|
|
131
148
|
userId: string
|
|
132
149
|
): Promise<string> {
|
|
150
|
+
const debug = createDebugLogger({
|
|
151
|
+
tool: 'remember_confirm',
|
|
152
|
+
userId,
|
|
153
|
+
operation: 'execute_publish',
|
|
154
|
+
});
|
|
155
|
+
|
|
133
156
|
try {
|
|
157
|
+
debug.debug('Executing publish memory action', {
|
|
158
|
+
memoryId: request.payload.memory_id,
|
|
159
|
+
spaces: request.payload.spaces,
|
|
160
|
+
});
|
|
161
|
+
|
|
134
162
|
logger.info('Executing publish memory action', {
|
|
135
163
|
function: 'executePublishMemory',
|
|
136
164
|
userId,
|
|
@@ -151,10 +179,12 @@ async function executePublishMemory(
|
|
|
151
179
|
memoryId: request.payload.memory_id,
|
|
152
180
|
});
|
|
153
181
|
|
|
154
|
-
const originalMemory = await
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
182
|
+
const originalMemory = await debug.time('Fetch original memory', async () => {
|
|
183
|
+
return await fetchMemoryWithAllProperties(
|
|
184
|
+
userCollection,
|
|
185
|
+
request.payload.memory_id
|
|
186
|
+
);
|
|
187
|
+
});
|
|
158
188
|
|
|
159
189
|
logger.info('Original memory fetch result', {
|
|
160
190
|
function: 'executePublishMemory',
|
|
@@ -188,6 +218,28 @@ async function executePublishMemory(
|
|
|
188
218
|
);
|
|
189
219
|
}
|
|
190
220
|
|
|
221
|
+
// Check if memory has already been published
|
|
222
|
+
if (originalMemory.properties.space_memory_id) {
|
|
223
|
+
const requestedSpaces = request.payload.spaces?.join(', ') || 'unknown';
|
|
224
|
+
logger.warn('Memory already published', {
|
|
225
|
+
function: 'executePublishMemory',
|
|
226
|
+
memoryId: request.payload.memory_id,
|
|
227
|
+
existingSpaceMemoryId: originalMemory.properties.space_memory_id,
|
|
228
|
+
requestedSpaces: request.payload.spaces,
|
|
229
|
+
});
|
|
230
|
+
return JSON.stringify(
|
|
231
|
+
{
|
|
232
|
+
success: false,
|
|
233
|
+
error: 'Already published',
|
|
234
|
+
message: `This memory has already been published to this space. Space memory ID: ${originalMemory.properties.space_memory_id}`,
|
|
235
|
+
space_memory_id: originalMemory.properties.space_memory_id,
|
|
236
|
+
requested_spaces: request.payload.spaces,
|
|
237
|
+
},
|
|
238
|
+
null,
|
|
239
|
+
2
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
|
|
191
243
|
// Verify ownership again
|
|
192
244
|
if (originalMemory.properties.user_id !== userId) {
|
|
193
245
|
logger.warn('Permission denied - wrong owner', {
|
|
@@ -264,8 +316,10 @@ async function executePublishMemory(
|
|
|
264
316
|
|
|
265
317
|
// Insert directly into unified public collection
|
|
266
318
|
// CRITICAL: Weaviate insert API expects {properties: {...}}, not the properties directly!
|
|
267
|
-
const result = await
|
|
268
|
-
|
|
319
|
+
const result = await debug.time('Insert into Memory_public', async () => {
|
|
320
|
+
return await publicCollection.data.insert({
|
|
321
|
+
properties: publishedMemory,
|
|
322
|
+
});
|
|
269
323
|
});
|
|
270
324
|
|
|
271
325
|
logger.info('Memory published successfully', {
|
|
@@ -273,6 +327,11 @@ async function executePublishMemory(
|
|
|
273
327
|
spaceMemoryId: result,
|
|
274
328
|
spaces: request.payload.spaces,
|
|
275
329
|
});
|
|
330
|
+
|
|
331
|
+
debug.info('Memory published successfully', {
|
|
332
|
+
spaceMemoryId: result,
|
|
333
|
+
spaces: request.payload.spaces,
|
|
334
|
+
});
|
|
276
335
|
|
|
277
336
|
// Update original memory with space_memory_id for bidirectional linking
|
|
278
337
|
try {
|
|
@@ -309,6 +368,10 @@ async function executePublishMemory(
|
|
|
309
368
|
2
|
|
310
369
|
);
|
|
311
370
|
} catch (error) {
|
|
371
|
+
debug.error('Execute publish failed', {
|
|
372
|
+
error: error instanceof Error ? error.message : String(error),
|
|
373
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
374
|
+
});
|
|
312
375
|
handleToolError(error, {
|
|
313
376
|
toolName: 'remember_confirm',
|
|
314
377
|
userId,
|
package/src/tools/publish.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { isValidSpaceId } from '../weaviate/space-schema.js';
|
|
|
12
12
|
import { handleToolError } from '../utils/error-handler.js';
|
|
13
13
|
import { SUPPORTED_SPACES } from '../types/space-memory.js';
|
|
14
14
|
import { logger } from '../utils/logger.js';
|
|
15
|
+
import { createDebugLogger } from '../utils/debug.js';
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Tool definition for remember_publish
|
|
@@ -62,7 +63,16 @@ export async function handlePublish(
|
|
|
62
63
|
args: PublishArgs,
|
|
63
64
|
userId: string
|
|
64
65
|
): Promise<string> {
|
|
66
|
+
const debug = createDebugLogger({
|
|
67
|
+
tool: 'remember_publish',
|
|
68
|
+
userId,
|
|
69
|
+
operation: 'publish_request',
|
|
70
|
+
});
|
|
71
|
+
|
|
65
72
|
try {
|
|
73
|
+
debug.info('Tool invoked');
|
|
74
|
+
debug.trace('Arguments', { args });
|
|
75
|
+
|
|
66
76
|
logger.info('Starting publish request', {
|
|
67
77
|
tool: 'remember_publish',
|
|
68
78
|
userId,
|
|
@@ -73,8 +83,10 @@ export async function handlePublish(
|
|
|
73
83
|
});
|
|
74
84
|
|
|
75
85
|
// Validate all space IDs
|
|
86
|
+
debug.debug('Validating space IDs', { spaces: args.spaces });
|
|
76
87
|
const invalidSpaces = args.spaces.filter(s => !isValidSpaceId(s));
|
|
77
88
|
if (invalidSpaces.length > 0) {
|
|
89
|
+
debug.warn('Invalid space IDs detected', { invalidSpaces });
|
|
78
90
|
logger.warn('Invalid space IDs provided', {
|
|
79
91
|
tool: 'remember_publish',
|
|
80
92
|
invalidSpaces,
|
|
@@ -124,7 +136,9 @@ export async function handlePublish(
|
|
|
124
136
|
|
|
125
137
|
const userCollection = weaviateClient.collections.get(collectionName);
|
|
126
138
|
|
|
127
|
-
const memory = await
|
|
139
|
+
const memory = await debug.time('Fetch memory from user collection', async () => {
|
|
140
|
+
return await fetchMemoryWithAllProperties(userCollection, args.memory_id);
|
|
141
|
+
});
|
|
128
142
|
|
|
129
143
|
logger.debug('Memory fetch result', {
|
|
130
144
|
tool: 'remember_publish',
|
|
@@ -232,6 +246,10 @@ export async function handlePublish(
|
|
|
232
246
|
2
|
|
233
247
|
);
|
|
234
248
|
} catch (error) {
|
|
249
|
+
debug.error('Tool failed', {
|
|
250
|
+
error: error instanceof Error ? error.message : String(error),
|
|
251
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
252
|
+
});
|
|
235
253
|
return handleToolError(error, {
|
|
236
254
|
toolName: 'remember_publish',
|
|
237
255
|
userId,
|
package/src/tools/query-space.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { getWeaviateClient } from '../weaviate/client.js';
|
|
|
11
11
|
import { ensurePublicCollection, isValidSpaceId } from '../weaviate/space-schema.js';
|
|
12
12
|
import { SUPPORTED_SPACES } from '../types/space-memory.js';
|
|
13
13
|
import { handleToolError } from '../utils/error-handler.js';
|
|
14
|
+
import { createDebugLogger } from '../utils/debug.js';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Tool definition for remember_query_space
|
|
@@ -106,8 +107,18 @@ export async function handleQuerySpace(
|
|
|
106
107
|
args: QuerySpaceArgs,
|
|
107
108
|
userId: string // May be used for private spaces in future
|
|
108
109
|
): Promise<string> {
|
|
110
|
+
const debug = createDebugLogger({
|
|
111
|
+
tool: 'remember_query_space',
|
|
112
|
+
userId,
|
|
113
|
+
operation: 'query_spaces',
|
|
114
|
+
});
|
|
115
|
+
|
|
109
116
|
try {
|
|
117
|
+
debug.info('Tool invoked');
|
|
118
|
+
debug.trace('Arguments', { args });
|
|
119
|
+
|
|
110
120
|
// Validate all space IDs
|
|
121
|
+
debug.debug('Validating space IDs', { spaces: args.spaces });
|
|
111
122
|
const invalidSpaces = args.spaces.filter(s => !isValidSpaceId(s));
|
|
112
123
|
if (invalidSpaces.length > 0) {
|
|
113
124
|
return JSON.stringify(
|
|
@@ -181,10 +192,23 @@ export async function handleQuerySpace(
|
|
|
181
192
|
|
|
182
193
|
const whereFilter = filterList.length > 0 ? Filters.and(...filterList) : undefined;
|
|
183
194
|
|
|
184
|
-
|
|
185
|
-
|
|
195
|
+
debug.debug('Executing semantic query', {
|
|
196
|
+
question: args.question,
|
|
197
|
+
filterCount: filterList.length,
|
|
186
198
|
limit: args.limit || 10,
|
|
187
|
-
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// Execute semantic search using nearText
|
|
202
|
+
const searchResults = await debug.time('Semantic query', async () => {
|
|
203
|
+
return await publicCollection.query.nearText(args.question, {
|
|
204
|
+
limit: args.limit || 10,
|
|
205
|
+
...(whereFilter && { where: whereFilter }),
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
debug.debug('Query completed', {
|
|
210
|
+
resultCount: searchResults.objects.length,
|
|
211
|
+
format: args.format || 'detailed',
|
|
188
212
|
});
|
|
189
213
|
|
|
190
214
|
// Format results based on requested format
|
|
@@ -222,9 +246,18 @@ export async function handleQuerySpace(
|
|
|
222
246
|
total: memories.length,
|
|
223
247
|
};
|
|
224
248
|
|
|
249
|
+
debug.info('Tool completed successfully', {
|
|
250
|
+
resultCount: memories.length,
|
|
251
|
+
format: 'detailed',
|
|
252
|
+
});
|
|
253
|
+
|
|
225
254
|
return JSON.stringify(result, null, 2);
|
|
226
255
|
}
|
|
227
256
|
} catch (error) {
|
|
257
|
+
debug.error('Tool failed', {
|
|
258
|
+
error: error instanceof Error ? error.message : String(error),
|
|
259
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
260
|
+
});
|
|
228
261
|
return handleToolError(error, {
|
|
229
262
|
toolName: 'remember_query_space',
|
|
230
263
|
operation: 'query spaces',
|
|
@@ -12,6 +12,7 @@ import { ensurePublicCollection, isValidSpaceId } from '../weaviate/space-schema
|
|
|
12
12
|
import { SUPPORTED_SPACES } from '../types/space-memory.js';
|
|
13
13
|
import { handleToolError } from '../utils/error-handler.js';
|
|
14
14
|
import type { SearchFilters } from '../types/memory.js';
|
|
15
|
+
import { createDebugLogger } from '../utils/debug.js';
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Tool definition for remember_search_space
|
|
@@ -113,8 +114,18 @@ export async function handleSearchSpace(
|
|
|
113
114
|
args: SearchSpaceArgs,
|
|
114
115
|
userId: string // May be used for private spaces in future
|
|
115
116
|
): Promise<string> {
|
|
117
|
+
const debug = createDebugLogger({
|
|
118
|
+
tool: 'remember_search_space',
|
|
119
|
+
userId,
|
|
120
|
+
operation: 'search_spaces',
|
|
121
|
+
});
|
|
122
|
+
|
|
116
123
|
try {
|
|
124
|
+
debug.info('Tool invoked');
|
|
125
|
+
debug.trace('Arguments', { args });
|
|
126
|
+
|
|
117
127
|
// Validate all space IDs
|
|
128
|
+
debug.debug('Validating space IDs', { spaces: args.spaces });
|
|
118
129
|
const invalidSpaces = args.spaces.filter(s => !isValidSpaceId(s));
|
|
119
130
|
if (invalidSpaces.length > 0) {
|
|
120
131
|
return JSON.stringify(
|
|
@@ -197,11 +208,24 @@ export async function handleSearchSpace(
|
|
|
197
208
|
|
|
198
209
|
const whereFilter = filterList.length > 0 ? Filters.and(...filterList) : undefined;
|
|
199
210
|
|
|
200
|
-
|
|
201
|
-
|
|
211
|
+
debug.debug('Executing hybrid search', {
|
|
212
|
+
query: args.query,
|
|
213
|
+
filterCount: filterList.length,
|
|
202
214
|
limit: args.limit || 10,
|
|
203
215
|
offset: args.offset || 0,
|
|
204
|
-
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// Execute hybrid search
|
|
219
|
+
const searchResults = await debug.time('Hybrid search query', async () => {
|
|
220
|
+
return await publicCollection.query.hybrid(args.query, {
|
|
221
|
+
limit: args.limit || 10,
|
|
222
|
+
offset: args.offset || 0,
|
|
223
|
+
...(whereFilter && { where: whereFilter }),
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
debug.debug('Search completed', {
|
|
228
|
+
resultCount: searchResults.objects.length,
|
|
205
229
|
});
|
|
206
230
|
|
|
207
231
|
// Format results
|
|
@@ -220,8 +244,17 @@ export async function handleSearchSpace(
|
|
|
220
244
|
limit: args.limit || 10,
|
|
221
245
|
};
|
|
222
246
|
|
|
247
|
+
debug.info('Tool completed successfully', {
|
|
248
|
+
resultCount: memories.length,
|
|
249
|
+
spaces: args.spaces,
|
|
250
|
+
});
|
|
251
|
+
|
|
223
252
|
return JSON.stringify(result, null, 2);
|
|
224
253
|
} catch (error) {
|
|
254
|
+
debug.error('Tool failed', {
|
|
255
|
+
error: error instanceof Error ? error.message : String(error),
|
|
256
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
257
|
+
});
|
|
225
258
|
return handleToolError(error, {
|
|
226
259
|
toolName: 'remember_search_space',
|
|
227
260
|
operation: 'search spaces',
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for debug utility
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createDebugLogger, DebugLogger } from './debug';
|
|
6
|
+
import { DebugLevel } from '../config';
|
|
7
|
+
import { logger } from './logger';
|
|
8
|
+
|
|
9
|
+
// Mock logger
|
|
10
|
+
jest.mock('./logger', () => ({
|
|
11
|
+
logger: {
|
|
12
|
+
debug: jest.fn(),
|
|
13
|
+
info: jest.fn(),
|
|
14
|
+
warn: jest.fn(),
|
|
15
|
+
error: jest.fn(),
|
|
16
|
+
},
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
// Mock config
|
|
20
|
+
jest.mock('../config', () => {
|
|
21
|
+
let mockLevel = 0; // NONE by default
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
DebugLevel: {
|
|
25
|
+
NONE: 0,
|
|
26
|
+
ERROR: 1,
|
|
27
|
+
WARN: 2,
|
|
28
|
+
INFO: 3,
|
|
29
|
+
DEBUG: 4,
|
|
30
|
+
TRACE: 5,
|
|
31
|
+
},
|
|
32
|
+
debugConfig: {
|
|
33
|
+
get level() {
|
|
34
|
+
return mockLevel;
|
|
35
|
+
},
|
|
36
|
+
set level(value: number) {
|
|
37
|
+
mockLevel = value;
|
|
38
|
+
},
|
|
39
|
+
enabled: (level: number) => mockLevel >= level,
|
|
40
|
+
},
|
|
41
|
+
// Re-export setMockDebugLevel for tests
|
|
42
|
+
__setMockDebugLevel: (level: number) => {
|
|
43
|
+
mockLevel = level;
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const { __setMockDebugLevel } = require('../config');
|
|
49
|
+
|
|
50
|
+
describe('DebugLogger', () => {
|
|
51
|
+
let debug: DebugLogger;
|
|
52
|
+
|
|
53
|
+
beforeEach(() => {
|
|
54
|
+
jest.clearAllMocks();
|
|
55
|
+
__setMockDebugLevel(DebugLevel.NONE);
|
|
56
|
+
debug = createDebugLogger({
|
|
57
|
+
tool: 'test_tool',
|
|
58
|
+
userId: 'user123',
|
|
59
|
+
operation: 'test_operation',
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe('Debug Level Filtering', () => {
|
|
64
|
+
it('should not log anything when level is NONE', () => {
|
|
65
|
+
__setMockDebugLevel(DebugLevel.NONE);
|
|
66
|
+
|
|
67
|
+
debug.trace('trace message');
|
|
68
|
+
debug.debug('debug message');
|
|
69
|
+
debug.info('info message');
|
|
70
|
+
debug.warn('warn message');
|
|
71
|
+
debug.error('error message');
|
|
72
|
+
|
|
73
|
+
expect(logger.debug).not.toHaveBeenCalled();
|
|
74
|
+
expect(logger.info).not.toHaveBeenCalled();
|
|
75
|
+
expect(logger.warn).not.toHaveBeenCalled();
|
|
76
|
+
expect(logger.error).not.toHaveBeenCalled();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should only log errors when level is ERROR', () => {
|
|
80
|
+
__setMockDebugLevel(DebugLevel.ERROR);
|
|
81
|
+
|
|
82
|
+
debug.trace('trace message');
|
|
83
|
+
debug.debug('debug message');
|
|
84
|
+
debug.info('info message');
|
|
85
|
+
debug.warn('warn message');
|
|
86
|
+
debug.error('error message');
|
|
87
|
+
|
|
88
|
+
expect(logger.debug).not.toHaveBeenCalled();
|
|
89
|
+
expect(logger.info).not.toHaveBeenCalled();
|
|
90
|
+
expect(logger.warn).not.toHaveBeenCalled();
|
|
91
|
+
expect(logger.error).toHaveBeenCalledTimes(1);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should log warnings and errors when level is WARN', () => {
|
|
95
|
+
__setMockDebugLevel(DebugLevel.WARN);
|
|
96
|
+
|
|
97
|
+
debug.trace('trace message');
|
|
98
|
+
debug.debug('debug message');
|
|
99
|
+
debug.info('info message');
|
|
100
|
+
debug.warn('warn message');
|
|
101
|
+
debug.error('error message');
|
|
102
|
+
|
|
103
|
+
expect(logger.debug).not.toHaveBeenCalled();
|
|
104
|
+
expect(logger.info).not.toHaveBeenCalled();
|
|
105
|
+
expect(logger.warn).toHaveBeenCalledTimes(1);
|
|
106
|
+
expect(logger.error).toHaveBeenCalledTimes(1);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('should log info, warnings, and errors when level is INFO', () => {
|
|
110
|
+
__setMockDebugLevel(DebugLevel.INFO);
|
|
111
|
+
|
|
112
|
+
debug.trace('trace message');
|
|
113
|
+
debug.debug('debug message');
|
|
114
|
+
debug.info('info message');
|
|
115
|
+
debug.warn('warn message');
|
|
116
|
+
debug.error('error message');
|
|
117
|
+
|
|
118
|
+
expect(logger.debug).not.toHaveBeenCalled();
|
|
119
|
+
expect(logger.info).toHaveBeenCalledTimes(1);
|
|
120
|
+
expect(logger.warn).toHaveBeenCalledTimes(1);
|
|
121
|
+
expect(logger.error).toHaveBeenCalledTimes(1);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should log debug, info, warnings, and errors when level is DEBUG', () => {
|
|
125
|
+
__setMockDebugLevel(DebugLevel.DEBUG);
|
|
126
|
+
|
|
127
|
+
debug.trace('trace message');
|
|
128
|
+
debug.debug('debug message');
|
|
129
|
+
debug.info('info message');
|
|
130
|
+
debug.warn('warn message');
|
|
131
|
+
debug.error('error message');
|
|
132
|
+
|
|
133
|
+
expect(logger.debug).toHaveBeenCalledTimes(1); // debug only
|
|
134
|
+
expect(logger.info).toHaveBeenCalledTimes(1);
|
|
135
|
+
expect(logger.warn).toHaveBeenCalledTimes(1);
|
|
136
|
+
expect(logger.error).toHaveBeenCalledTimes(1);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should log everything including trace when level is TRACE', () => {
|
|
140
|
+
__setMockDebugLevel(DebugLevel.TRACE);
|
|
141
|
+
|
|
142
|
+
debug.trace('trace message');
|
|
143
|
+
debug.debug('debug message');
|
|
144
|
+
debug.info('info message');
|
|
145
|
+
debug.warn('warn message');
|
|
146
|
+
debug.error('error message');
|
|
147
|
+
|
|
148
|
+
expect(logger.debug).toHaveBeenCalledTimes(2); // trace + debug
|
|
149
|
+
expect(logger.info).toHaveBeenCalledTimes(1);
|
|
150
|
+
expect(logger.warn).toHaveBeenCalledTimes(1);
|
|
151
|
+
expect(logger.error).toHaveBeenCalledTimes(1);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
describe('Context Propagation', () => {
|
|
156
|
+
it('should include context in all log calls', () => {
|
|
157
|
+
__setMockDebugLevel(DebugLevel.DEBUG);
|
|
158
|
+
|
|
159
|
+
debug.debug('test message', { extra: 'data' });
|
|
160
|
+
|
|
161
|
+
expect(logger.debug).toHaveBeenCalledWith(
|
|
162
|
+
'[DEBUG] test message',
|
|
163
|
+
expect.objectContaining({
|
|
164
|
+
tool: 'test_tool',
|
|
165
|
+
userId: 'user123',
|
|
166
|
+
operation: 'test_operation',
|
|
167
|
+
extra: 'data',
|
|
168
|
+
debugLevel: 'DEBUG',
|
|
169
|
+
})
|
|
170
|
+
);
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
describe('dump()', () => {
|
|
175
|
+
it('should only dump objects at TRACE level', () => {
|
|
176
|
+
__setMockDebugLevel(DebugLevel.DEBUG);
|
|
177
|
+
|
|
178
|
+
debug.dump('test object', { foo: 'bar' });
|
|
179
|
+
expect(logger.debug).not.toHaveBeenCalled();
|
|
180
|
+
|
|
181
|
+
__setMockDebugLevel(DebugLevel.TRACE);
|
|
182
|
+
debug.dump('test object', { foo: 'bar' });
|
|
183
|
+
|
|
184
|
+
expect(logger.debug).toHaveBeenCalledWith(
|
|
185
|
+
'[DUMP] test object',
|
|
186
|
+
expect.objectContaining({
|
|
187
|
+
dump: expect.stringContaining('"foo": "bar"'),
|
|
188
|
+
})
|
|
189
|
+
);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
describe('time()', () => {
|
|
194
|
+
it('should not add timing overhead when debug is disabled', async () => {
|
|
195
|
+
__setMockDebugLevel(DebugLevel.NONE);
|
|
196
|
+
|
|
197
|
+
const result = await debug.time('test operation', async () => {
|
|
198
|
+
return 'result';
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
expect(result).toBe('result');
|
|
202
|
+
expect(logger.debug).not.toHaveBeenCalled();
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('should log timing when DEBUG level is enabled', async () => {
|
|
206
|
+
__setMockDebugLevel(DebugLevel.DEBUG);
|
|
207
|
+
|
|
208
|
+
const result = await debug.time('test operation', async () => {
|
|
209
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
210
|
+
return 'result';
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
expect(result).toBe('result');
|
|
214
|
+
expect(logger.debug).toHaveBeenCalledWith(
|
|
215
|
+
'[DEBUG] test operation - Starting',
|
|
216
|
+
expect.any(Object)
|
|
217
|
+
);
|
|
218
|
+
expect(logger.debug).toHaveBeenCalledWith(
|
|
219
|
+
'[DEBUG] test operation - Completed',
|
|
220
|
+
expect.objectContaining({
|
|
221
|
+
durationMs: expect.any(Number),
|
|
222
|
+
})
|
|
223
|
+
);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('should log errors with timing on failure', async () => {
|
|
227
|
+
__setMockDebugLevel(DebugLevel.DEBUG);
|
|
228
|
+
|
|
229
|
+
const error = new Error('test error');
|
|
230
|
+
|
|
231
|
+
await expect(
|
|
232
|
+
debug.time('test operation', async () => {
|
|
233
|
+
throw error;
|
|
234
|
+
})
|
|
235
|
+
).rejects.toThrow('test error');
|
|
236
|
+
|
|
237
|
+
expect(logger.error).toHaveBeenCalledWith(
|
|
238
|
+
'[ERROR] test operation - Failed',
|
|
239
|
+
expect.objectContaining({
|
|
240
|
+
durationMs: expect.any(Number),
|
|
241
|
+
error: 'test error',
|
|
242
|
+
})
|
|
243
|
+
);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
describe('createDebugLogger()', () => {
|
|
248
|
+
it('should create a DebugLogger instance with context', () => {
|
|
249
|
+
const logger = createDebugLogger({
|
|
250
|
+
tool: 'test_tool',
|
|
251
|
+
userId: 'user123',
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
expect(logger).toBeInstanceOf(DebugLogger);
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
});
|