@hauptsache.net/clickup-mcp 1.1.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,9 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.downloadImages = void 0;
6
7
  exports.isTaskId = isTaskId;
7
8
  exports.getCurrentUser = getCurrentUser;
8
- exports.limitImages = limitImages;
9
9
  exports.getSpaceDetails = getSpaceDetails;
10
10
  exports.getTaskSearchIndex = getTaskSearchIndex;
11
11
  exports.generateTaskUrl = generateTaskUrl;
@@ -18,6 +18,9 @@ exports.formatSpaceLink = formatSpaceLink;
18
18
  exports.extractTaskIdFromUrl = extractTaskIdFromUrl;
19
19
  exports.isClickUpUrl = isClickUpUrl;
20
20
  exports.formatLinksSection = formatLinksSection;
21
+ exports.getSpaceSearchIndex = getSpaceSearchIndex;
22
+ exports.getSpaceContent = getSpaceContent;
23
+ exports.getAllTeamMembers = getAllTeamMembers;
21
24
  const config_1 = require("./config");
22
25
  const fuse_js_1 = __importDefault(require("fuse.js"));
23
26
  const GLOBAL_REFRESH_INTERVAL = 60000; // 60 seconds - that is the rate limit time frame
@@ -29,62 +32,39 @@ function isTaskId(str) {
29
32
  // Task IDs are 6-9 characters long and contain only alphanumeric characters
30
33
  return /^[a-z0-9]{6,9}$/i.test(str);
31
34
  }
32
- // Cache for current user info to avoid repeated API calls
33
- let cachedUserData = null;
35
+ // Cache for current user info to avoid repeated API calls and race conditions
36
+ let cachedUserPromise = null;
34
37
  /**
35
38
  * Get current authenticated user information from ClickUp API
36
- * Caches the result after first successful fetch to avoid repeated API calls during the session
39
+ * Caches the promise to prevent race conditions on concurrent calls
37
40
  */
38
41
  async function getCurrentUser() {
39
- // Return cached data if available
40
- if (cachedUserData) {
41
- return cachedUserData;
42
+ // Return cached promise if available
43
+ if (cachedUserPromise) {
44
+ return cachedUserPromise;
42
45
  }
43
- const userResponse = await fetch("https://api.clickup.com/api/v2/user", {
44
- headers: { Authorization: config_1.CONFIG.apiKey },
45
- });
46
- if (!userResponse.ok) {
47
- throw new Error(`Error fetching user info: ${userResponse.status} ${userResponse.statusText}`);
48
- }
49
- // Cache the result for future calls
50
- cachedUserData = await userResponse.json();
51
- return cachedUserData;
52
- }
53
- /**
54
- * Limits the number of images in the content array, replacing excess images with text placeholders
55
- * Prioritizes keeping the most recent images (assumes content is ordered with newest items last)
56
- *
57
- * @param content Array of content blocks that may contain images
58
- * @param maxImages Maximum number of images to keep
59
- * @returns Modified content array with limited images
60
- */
61
- function limitImages(content, maxImages) {
62
- // Count how many images we have
63
- const imageIndices = [];
64
- // Find all image blocks
65
- content.forEach((block, index) => {
66
- if (block.type === "image") {
67
- imageIndices.push(index);
46
+ // Create the fetch promise
47
+ const fetchPromise = (async () => {
48
+ const userResponse = await fetch("https://api.clickup.com/api/v2/user", {
49
+ headers: { Authorization: config_1.CONFIG.apiKey },
50
+ });
51
+ if (!userResponse.ok) {
52
+ throw new Error(`Error fetching user info: ${userResponse.status} ${userResponse.statusText}`);
68
53
  }
69
- });
70
- // If we have fewer images than the limit, return the original content
71
- if (imageIndices.length <= maxImages) {
72
- return content;
73
- }
74
- // Determine which images to keep (the most recent ones)
75
- // We want to keep the last 'maxImages' images
76
- const imagesToRemove = imageIndices.slice(0, imageIndices.length - maxImages);
77
- // Create a new content array with excess images replaced by text
78
- return content.map((block, index) => {
79
- if (block.type === "image" && imagesToRemove.includes(index)) {
80
- return {
81
- type: "text",
82
- text: "[Image removed due to size limitations. Only the most recent images are shown.]",
83
- };
84
- }
85
- return block;
86
- });
54
+ return await userResponse.json();
55
+ })();
56
+ // Cache the promise
57
+ cachedUserPromise = fetchPromise;
58
+ // Auto-cleanup after 60 seconds
59
+ setTimeout(() => {
60
+ cachedUserPromise = null;
61
+ console.error(`Auto-cleaned user data cache`);
62
+ }, GLOBAL_REFRESH_INTERVAL);
63
+ return fetchPromise;
87
64
  }
65
+ // Re-export image processing functions for backward compatibility
66
+ var image_processing_1 = require("./image-processing");
67
+ Object.defineProperty(exports, "downloadImages", { enumerable: true, get: function () { return image_processing_1.downloadImages; } });
88
68
  const spaceCache = new Map(); // Global cache for space details promises
89
69
  /**
90
70
  * Function to get space details, using a cache to avoid redundant fetches
@@ -111,10 +91,11 @@ function getSpaceDetails(spaceId) {
111
91
  spaceCache.set(spaceId, fetchPromise);
112
92
  return fetchPromise;
113
93
  }
114
- // Task search index management
94
+ // Task search index management - cache promises to prevent race conditions
115
95
  const taskIndices = new Map();
116
96
  /**
117
97
  * Get or create a task search index with specified filters
98
+ * Caches promises to prevent race conditions on concurrent calls
118
99
  */
119
100
  async function getTaskSearchIndex(space_ids, list_ids, assignees) {
120
101
  // Create cache key from sorted filter arrays
@@ -123,23 +104,26 @@ async function getTaskSearchIndex(space_ids, list_ids, assignees) {
123
104
  list_ids: list_ids?.sort(),
124
105
  assignees: assignees?.sort()
125
106
  });
126
- // Check for existing valid index
127
- const cachedIndex = taskIndices.get(key);
128
- if (cachedIndex) {
129
- return cachedIndex;
107
+ // Check for existing valid index promise
108
+ const cachedPromise = taskIndices.get(key);
109
+ if (cachedPromise) {
110
+ return cachedPromise;
130
111
  }
131
- // Fetch tasks with specified filters
132
- console.error(`Refreshing task index for filters: ${key}`);
133
- const tasks = await fetchTasks(space_ids, list_ids, assignees);
134
- const index = createFuseIndex(tasks);
135
- // Store with auto-cleanup
136
- taskIndices.set(key, index);
112
+ // Create the fetch promise
113
+ const fetchPromise = (async () => {
114
+ console.error(`Refreshing task index for filters: ${key}`);
115
+ const tasks = await fetchTasks(space_ids, list_ids, assignees);
116
+ const index = createFuseIndex(tasks);
117
+ console.error(`Task index created with ${tasks.length} tasks`);
118
+ return index;
119
+ })();
120
+ // Store promise with auto-cleanup
121
+ taskIndices.set(key, fetchPromise);
137
122
  setTimeout(() => {
138
123
  taskIndices.delete(key);
139
124
  console.error(`Auto-cleaned index for filters: ${key}`);
140
125
  }, GLOBAL_REFRESH_INTERVAL);
141
- console.error(`Task index created with ${tasks.length} tasks`);
142
- return index;
126
+ return fetchPromise;
143
127
  }
144
128
  /**
145
129
  * Fetch tasks using team endpoint with dynamic filters
@@ -264,3 +248,156 @@ function formatLinksSection(links) {
264
248
  const linkLines = links.map(link => `🔗 [${link.text}](${link.url})`);
265
249
  return `\n\n**📌 Quick Links:**\n${linkLines.join('\n')}`;
266
250
  }
251
+ // Space search index cache - cache promise to prevent race conditions
252
+ let spaceSearchIndexPromise = null;
253
+ /**
254
+ * Get or refresh the space search index
255
+ * Caches promise to prevent race conditions on concurrent calls
256
+ */
257
+ async function getSpaceSearchIndex() {
258
+ // Return cached promise if available
259
+ if (spaceSearchIndexPromise) {
260
+ return spaceSearchIndexPromise;
261
+ }
262
+ // Create the fetch promise
263
+ const fetchPromise = (async () => {
264
+ try {
265
+ const url = `https://api.clickup.com/api/v2/team/${config_1.CONFIG.teamId}/space`;
266
+ const response = await fetch(url, {
267
+ headers: { Authorization: config_1.CONFIG.apiKey },
268
+ });
269
+ if (!response.ok) {
270
+ throw new Error(`Error fetching spaces: ${response.status} ${response.statusText}`);
271
+ }
272
+ const data = await response.json();
273
+ const spacesData = data.spaces || [];
274
+ // Create Fuse search index
275
+ return new fuse_js_1.default(spacesData, {
276
+ keys: [
277
+ { name: 'name', weight: 0.7 },
278
+ { name: 'id', weight: 0.6 }
279
+ ],
280
+ includeScore: true,
281
+ threshold: 0.4,
282
+ minMatchCharLength: 1,
283
+ });
284
+ }
285
+ catch (error) {
286
+ console.error('Error creating space search index:', error);
287
+ return null;
288
+ }
289
+ })();
290
+ // Cache the promise
291
+ spaceSearchIndexPromise = fetchPromise;
292
+ // Auto-cleanup after 60 seconds
293
+ setTimeout(() => {
294
+ spaceSearchIndexPromise = null;
295
+ console.error('Auto-cleaned space search index');
296
+ }, GLOBAL_REFRESH_INTERVAL);
297
+ return fetchPromise;
298
+ }
299
+ const listCache = new Map(); // Cache for space lists/folders
300
+ /**
301
+ * Get lists and folders for a specific space with caching
302
+ */
303
+ async function getSpaceContent(spaceId) {
304
+ const cacheKey = `space-content-${spaceId}`;
305
+ // Check cache first
306
+ const cachedContent = listCache.get(cacheKey);
307
+ if (cachedContent) {
308
+ return cachedContent;
309
+ }
310
+ // Fetch content with parallel requests
311
+ const fetchPromise = (async () => {
312
+ try {
313
+ const [foldersResponse, listsResponse] = await Promise.all([
314
+ fetch(`https://api.clickup.com/api/v2/space/${spaceId}/folder`, {
315
+ headers: { Authorization: config_1.CONFIG.apiKey },
316
+ }),
317
+ fetch(`https://api.clickup.com/api/v2/space/${spaceId}/list`, {
318
+ headers: { Authorization: config_1.CONFIG.apiKey },
319
+ })
320
+ ]);
321
+ const folders = foldersResponse.ok ?
322
+ (await foldersResponse.json()).folders || [] : [];
323
+ const lists = listsResponse.ok ?
324
+ (await listsResponse.json()).lists || [] : [];
325
+ // For each folder, also fetch its lists
326
+ const folderListPromises = folders.map(async (folder) => {
327
+ try {
328
+ const folderListResponse = await fetch(`https://api.clickup.com/api/v2/folder/${folder.id}/list`, { headers: { Authorization: config_1.CONFIG.apiKey } });
329
+ if (folderListResponse.ok) {
330
+ const folderListData = await folderListResponse.json();
331
+ folder.lists = folderListData.lists || [];
332
+ }
333
+ return folder;
334
+ }
335
+ catch (error) {
336
+ console.error(`Error fetching lists for folder ${folder.id}:`, error);
337
+ folder.lists = [];
338
+ return folder;
339
+ }
340
+ });
341
+ const foldersWithLists = await Promise.all(folderListPromises);
342
+ return { lists, folders: foldersWithLists };
343
+ }
344
+ catch (error) {
345
+ console.error(`Error fetching space content for ${spaceId}:`, error);
346
+ return { lists: [], folders: [] };
347
+ }
348
+ })();
349
+ // Cache the promise
350
+ listCache.set(cacheKey, fetchPromise);
351
+ // Auto-cleanup after 60 seconds
352
+ setTimeout(() => {
353
+ listCache.delete(cacheKey);
354
+ console.error(`Auto-cleaned space content cache for ${spaceId}`);
355
+ }, GLOBAL_REFRESH_INTERVAL);
356
+ return fetchPromise;
357
+ }
358
+ // Cache for team members to avoid repeated API calls and race conditions
359
+ let cachedTeamMembersPromise = null;
360
+ /**
361
+ * Gets all team members from ClickUp API with caching
362
+ */
363
+ async function getAllTeamMembers() {
364
+ // Return cached promise if available
365
+ if (cachedTeamMembersPromise) {
366
+ return cachedTeamMembersPromise;
367
+ }
368
+ // Create the fetch promise
369
+ const fetchPromise = (async () => {
370
+ try {
371
+ const response = await fetch(`https://api.clickup.com/api/v2/team`, {
372
+ headers: { Authorization: config_1.CONFIG.apiKey },
373
+ });
374
+ if (!response.ok) {
375
+ console.error(`Error fetching teams: ${response.status} ${response.statusText}`);
376
+ return [];
377
+ }
378
+ const data = await response.json();
379
+ if (!data.teams || !Array.isArray(data.teams)) {
380
+ return [];
381
+ }
382
+ // Find the team that matches our configured team ID and extract all user IDs
383
+ const currentTeam = data.teams.find((team) => team.id === config_1.CONFIG.teamId);
384
+ if (!currentTeam || !currentTeam.members || !Array.isArray(currentTeam.members)) {
385
+ console.error(`Team ${config_1.CONFIG.teamId} not found or has no members`);
386
+ return [];
387
+ }
388
+ return currentTeam.members.map((member) => member.user?.id).filter(Boolean);
389
+ }
390
+ catch (error) {
391
+ console.error('Error fetching team members:', error);
392
+ return [];
393
+ }
394
+ })();
395
+ // Cache the promise
396
+ cachedTeamMembersPromise = fetchPromise;
397
+ // Auto-cleanup after 60 seconds
398
+ setTimeout(() => {
399
+ cachedTeamMembersPromise = null;
400
+ console.error(`Auto-cleaned team members cache`);
401
+ }, GLOBAL_REFRESH_INTERVAL);
402
+ return fetchPromise;
403
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"list-tools.d.ts","sourceRoot":"","sources":["../../src/tools/list-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMpE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,QAuPtD;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,QAyEvD"}
1
+ {"version":3,"file":"list-tools.d.ts","sourceRoot":"","sources":["../../src/tools/list-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMpE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,QA+GtD;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,QAyEvD"}
@@ -6,152 +6,6 @@ const zod_1 = require("zod");
6
6
  const config_1 = require("../shared/config");
7
7
  const utils_1 = require("../shared/utils");
8
8
  function registerListToolsRead(server) {
9
- server.tool("listLists", [
10
- "Lists all lists and folders in a space. They might also be referred to as boards or tables.",
11
- "Shows both direct lists (folderless) and folders containing lists. If folder_id is provided, lists only the lists within that specific folder.",
12
- "Always reference lists by their URLs when suggesting actions or creating tasks."
13
- ].join("\n"), {
14
- space_id: zod_1.z.string().min(1).describe("The ID of the space to list content from"),
15
- folder_id: zod_1.z.string().optional().describe("Optional folder ID. If provided, lists only lists within this folder. If not provided, shows both folders and folderless lists in the space."),
16
- archived: zod_1.z.boolean().optional().describe("Include archived items (default: false)")
17
- }, async ({ space_id, folder_id, archived = false }) => {
18
- try {
19
- if (folder_id) {
20
- // List lists within a specific folder
21
- const url = `https://api.clickup.com/api/v2/folder/${folder_id}/list${archived ? '?archived=true' : ''}`;
22
- const response = await fetch(url, {
23
- headers: { Authorization: config_1.CONFIG.apiKey },
24
- });
25
- if (!response.ok) {
26
- const errorText = await response.text();
27
- console.error(`API Error: ${response.status} ${response.statusText}`, errorText);
28
- throw new Error(`Error fetching lists in folder ${folder_id}: ${response.status} ${response.statusText}`);
29
- }
30
- const data = await response.json();
31
- if (!data.lists || !Array.isArray(data.lists)) {
32
- return {
33
- content: [{ type: "text", text: `No lists found in folder ${folder_id}.` }],
34
- };
35
- }
36
- const listBlocks = data.lists.map((list) => ({
37
- type: "text",
38
- text: [
39
- `type: list`,
40
- `list_id: ${list.id}`,
41
- `list_url: ${(0, utils_1.generateListUrl)(list.id)}`,
42
- `name: ${list.name}`,
43
- `space_id: ${list.space?.id || space_id}`,
44
- `folder_id: ${folder_id}`,
45
- `task_count: ${list.task_count || 0}`,
46
- ...(list.private ? [`private: true`] : []),
47
- ...(list.archived ? ['archived: true'] : []),
48
- ...(list.color ? [`color: ${list.color}`] : []),
49
- ...(list.access ? [`access: ${list.access}`] : []),
50
- ].join('\n')
51
- }));
52
- return {
53
- content: [
54
- {
55
- type: "text",
56
- text: `Found ${data.lists.length} list(s) in folder ${folder_id}:`
57
- },
58
- ...listBlocks
59
- ],
60
- };
61
- }
62
- else {
63
- // List both folders and folderless lists in the space (parallel requests)
64
- const archiveQuery = archived ? '?archived=true' : '';
65
- const [foldersResponse, listsResponse] = await Promise.all([
66
- fetch(`https://api.clickup.com/api/v2/space/${space_id}/folder${archiveQuery}`, {
67
- headers: { Authorization: config_1.CONFIG.apiKey },
68
- }),
69
- fetch(`https://api.clickup.com/api/v2/space/${space_id}/list${archiveQuery}`, {
70
- headers: { Authorization: config_1.CONFIG.apiKey },
71
- })
72
- ]);
73
- const results = [];
74
- let totalItems = 0;
75
- // Process folders
76
- if (foldersResponse.ok) {
77
- const foldersData = await foldersResponse.json();
78
- if (foldersData.folders && Array.isArray(foldersData.folders)) {
79
- const folderBlocks = foldersData.folders.map((folder) => ({
80
- type: "text",
81
- text: [
82
- `type: folder`,
83
- `folder_id: ${folder.id}`,
84
- `folder_url: ${(0, utils_1.generateFolderUrl)(folder.id)}`,
85
- `name: ${folder.name}`,
86
- `space_id: ${space_id}`,
87
- `task_count: ${folder.task_count || 0}`,
88
- ...(folder.private ? [`private: true`] : []),
89
- ...(folder.archived ? ['archived: true'] : []),
90
- ...(folder.color ? [`color: ${folder.color}`] : []),
91
- `contains_lists: true`
92
- ].join('\n')
93
- }));
94
- results.push(...folderBlocks);
95
- totalItems += foldersData.folders.length;
96
- }
97
- }
98
- else {
99
- console.warn(`Failed to fetch folders: ${foldersResponse.status} ${foldersResponse.statusText}`);
100
- }
101
- // Process folderless lists
102
- if (listsResponse.ok) {
103
- const listsData = await listsResponse.json();
104
- if (listsData.lists && Array.isArray(listsData.lists)) {
105
- const listBlocks = listsData.lists.map((list) => ({
106
- type: "text",
107
- text: [
108
- `type: list`,
109
- `list_id: ${list.id}`,
110
- `list_url: ${(0, utils_1.generateListUrl)(list.id)}`,
111
- `name: ${list.name}`,
112
- `space_id: ${list.space?.id || space_id}`,
113
- `task_count: ${list.task_count || 0}`,
114
- ...(list.private ? [`private: true`] : []),
115
- ...(list.archived ? ['archived: true'] : []),
116
- ...(list.color ? [`color: ${list.color}`] : []),
117
- ...(list.access ? [`access: ${list.access}`] : []),
118
- ].join('\n')
119
- }));
120
- results.push(...listBlocks);
121
- totalItems += listsData.lists.length;
122
- }
123
- }
124
- else {
125
- console.warn(`Failed to fetch lists: ${listsResponse.status} ${listsResponse.statusText}`);
126
- }
127
- if (totalItems === 0) {
128
- return {
129
- content: [{ type: "text", text: `No folders or lists found in space ${space_id}.` }],
130
- };
131
- }
132
- return {
133
- content: [
134
- {
135
- type: "text",
136
- text: `Found ${totalItems} item(s) in space ${space_id} (folders and lists):`
137
- },
138
- ...results
139
- ],
140
- };
141
- }
142
- }
143
- catch (error) {
144
- console.error('Error fetching space content:', error);
145
- return {
146
- content: [
147
- {
148
- type: "text",
149
- text: `Error fetching space content: ${error instanceof Error ? error.message : 'Unknown error'}`,
150
- },
151
- ],
152
- };
153
- }
154
- });
155
9
  server.tool("getListInfo", [
156
10
  "Gets comprehensive information about a list including description and available statuses.",
157
11
  "ALWAYS use the list URL (https://app.clickup.com/v/l/LIST_ID) when referencing lists.",
@@ -170,6 +24,22 @@ function registerListToolsRead(server) {
170
24
  throw new Error(`Error fetching list details: ${listResponse.status} ${listResponse.statusText}`);
171
25
  }
172
26
  const listData = await listResponse.json();
27
+ // Fetch space tags in parallel (don't let this fail the main request)
28
+ let spaceTags = [];
29
+ if (listData.space?.id) {
30
+ try {
31
+ const spaceTagsResponse = await fetch(`https://api.clickup.com/api/v2/space/${listData.space.id}/tag`, {
32
+ headers: { Authorization: config_1.CONFIG.apiKey },
33
+ });
34
+ if (spaceTagsResponse.ok) {
35
+ const spaceTagsData = await spaceTagsResponse.json();
36
+ spaceTags = spaceTagsData.tags || [];
37
+ }
38
+ }
39
+ catch (error) {
40
+ console.error(`Error fetching space tags for space ${listData.space.id}:`, error);
41
+ }
42
+ }
173
43
  const responseLines = [
174
44
  `List Information:`,
175
45
  `list_id: ${list_id}`,
@@ -193,18 +63,25 @@ function registerListToolsRead(server) {
193
63
  color: status.color || 'none',
194
64
  type: status.type || 'custom'
195
65
  }));
196
- responseLines.push('');
197
66
  responseLines.push(`Available statuses (${statuses.length} total):`);
198
67
  statuses.forEach((status) => {
199
68
  responseLines.push(` - ${status.name} (${status.type})`);
200
69
  });
201
- responseLines.push('');
202
70
  responseLines.push(`Valid status names for createTask/updateTask: ${statuses.map((s) => s.name).join(', ')}`);
203
71
  }
204
72
  else {
205
- responseLines.push('');
206
73
  responseLines.push('No statuses found for this list.');
207
74
  }
75
+ // Add space tags information
76
+ if (spaceTags.length > 0) {
77
+ const tagNames = spaceTags.map((tag) => tag.name).filter(Boolean).sort();
78
+ if (tagNames.length > 0) {
79
+ responseLines.push(`Available tags in space (shared across all lists): ${tagNames.join(', ')}`);
80
+ }
81
+ }
82
+ else if (listData.space?.id) {
83
+ responseLines.push('No tags found in this space.');
84
+ }
208
85
  return {
209
86
  content: [
210
87
  {
@@ -1,3 +1,3 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- export declare function registerSearchTools(server: McpServer): void;
2
+ export declare function registerSearchTools(server: McpServer, userData: any): void;
3
3
  //# sourceMappingURL=search-tools.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"search-tools.d.ts","sourceRoot":"","sources":["../../src/tools/search-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAQlE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,QAuMpD"}
1
+ {"version":3,"file":"search-tools.d.ts","sourceRoot":"","sources":["../../src/tools/search-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AASlE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,QA8MnE"}