@fractary/codex-mcp 0.3.3 → 0.3.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.
package/dist/index.js DELETED
@@ -1,444 +0,0 @@
1
- // src/server.ts
2
- import { resolveReference as resolveReference2 } from "@fractary/codex";
3
-
4
- // src/tools.ts
5
- import { resolveReference } from "@fractary/codex";
6
- var CODEX_TOOLS = [
7
- {
8
- name: "codex_document_fetch",
9
- description: "Fetch a document from the Codex knowledge base by URI. Returns the document content.",
10
- inputSchema: {
11
- type: "object",
12
- properties: {
13
- uri: {
14
- type: "string",
15
- description: "Codex URI in format: codex://org/project/path/to/file.md"
16
- },
17
- branch: {
18
- type: "string",
19
- description: "Git branch to fetch from (default: main)"
20
- },
21
- noCache: {
22
- type: "boolean",
23
- description: "Bypass cache and fetch fresh content"
24
- }
25
- },
26
- required: ["uri"]
27
- }
28
- },
29
- {
30
- name: "codex_search",
31
- description: "Search for documents in the Codex knowledge base.",
32
- inputSchema: {
33
- type: "object",
34
- properties: {
35
- query: {
36
- type: "string",
37
- description: "Search query string"
38
- },
39
- org: {
40
- type: "string",
41
- description: "Filter by organization"
42
- },
43
- project: {
44
- type: "string",
45
- description: "Filter by project"
46
- },
47
- limit: {
48
- type: "number",
49
- description: "Maximum number of results (default: 10)"
50
- },
51
- type: {
52
- type: "string",
53
- description: "Filter by artifact type (e.g., docs, specs, logs)"
54
- }
55
- },
56
- required: ["query"]
57
- }
58
- },
59
- {
60
- name: "codex_cache_list",
61
- description: "List documents in the Codex cache.",
62
- inputSchema: {
63
- type: "object",
64
- properties: {
65
- org: {
66
- type: "string",
67
- description: "Filter by organization"
68
- },
69
- project: {
70
- type: "string",
71
- description: "Filter by project"
72
- },
73
- includeExpired: {
74
- type: "boolean",
75
- description: "Include expired cache entries"
76
- }
77
- }
78
- }
79
- },
80
- {
81
- name: "codex_cache_clear",
82
- description: "Clear cached documents matching a pattern.",
83
- inputSchema: {
84
- type: "object",
85
- properties: {
86
- pattern: {
87
- type: "string",
88
- description: "URI pattern to invalidate (supports regex)"
89
- }
90
- },
91
- required: ["pattern"]
92
- }
93
- }
94
- ];
95
- function textResult(text, isError = false) {
96
- return {
97
- content: [{ type: "text", text }],
98
- isError
99
- };
100
- }
101
- function resourceResult(uri, content, mimeType) {
102
- return {
103
- content: [
104
- {
105
- type: "resource",
106
- resource: {
107
- uri,
108
- mimeType,
109
- text: content
110
- }
111
- }
112
- ]
113
- };
114
- }
115
- async function handleFetch(args, ctx) {
116
- const { uri, branch, noCache } = args;
117
- if (!uri || typeof uri !== "string") {
118
- return textResult("URI is required and must be a string", true);
119
- }
120
- if (branch && typeof branch !== "string") {
121
- return textResult("Branch must be a string", true);
122
- }
123
- const ref = resolveReference(uri);
124
- if (!ref) {
125
- return textResult(`Invalid codex URI: ${uri}`, true);
126
- }
127
- try {
128
- let result;
129
- if (noCache) {
130
- result = await ctx.storage.fetch(ref, { branch });
131
- await ctx.cache.set(uri, result);
132
- } else {
133
- result = await ctx.cache.get(ref, { branch });
134
- }
135
- const content = result.content.toString("utf-8");
136
- return resourceResult(uri, content, result.contentType);
137
- } catch (error) {
138
- const message = error instanceof Error ? error.message : String(error);
139
- return textResult(`Failed to fetch ${uri}: ${message}`, true);
140
- }
141
- }
142
- async function handleSearch(args, ctx) {
143
- const { query, org, project, limit = 10 } = args;
144
- if (!query || typeof query !== "string") {
145
- return textResult("Query is required and must be a string", true);
146
- }
147
- if (query.length > 500) {
148
- return textResult("Query too long (max 500 characters)", true);
149
- }
150
- if (typeof limit !== "number" || limit < 1 || limit > 100) {
151
- return textResult("Limit must be a number between 1 and 100", true);
152
- }
153
- const stats = await ctx.cache.getStats();
154
- if (stats.entryCount === 0) {
155
- return textResult("No documents in cache. Use codex_document_fetch to load documents first.");
156
- }
157
- const message = `Search functionality requires a search index.
158
- Query: "${query}"
159
- Filters: org=${org || "any"}, project=${project || "any"}
160
- Limit: ${limit}
161
-
162
- To fetch documents, use codex_document_fetch with a specific URI like:
163
- codex://org/project/docs/file.md`;
164
- return textResult(message);
165
- }
166
- async function handleList(args, ctx) {
167
- const { org, project, includeExpired } = args;
168
- const stats = await ctx.cache.getStats();
169
- let message = `Cache Statistics:
170
- - Total entries: ${stats.entryCount}
171
- - Memory entries: ${stats.memoryEntries}
172
- - Memory size: ${formatBytes(stats.memorySize)}
173
- - Total size: ${formatBytes(stats.totalSize)}
174
- - Fresh: ${stats.freshCount}
175
- - Stale: ${stats.staleCount}
176
- - Expired: ${stats.expiredCount}`;
177
- if (org) {
178
- message += `
179
-
180
- Filtered by org: ${org}`;
181
- }
182
- if (project) {
183
- message += `
184
- Filtered by project: ${project}`;
185
- }
186
- if (includeExpired) {
187
- message += `
188
- Including expired entries`;
189
- }
190
- return textResult(message);
191
- }
192
- function validateRegexPattern(pattern) {
193
- if (pattern.length > 1e3) {
194
- return { valid: false, error: "Pattern too long (max 1000 characters)" };
195
- }
196
- const redosPatterns = [
197
- /(\.\*){3,}/,
198
- // Multiple consecutive .*
199
- /(\+\+|\*\*|\?\?)/,
200
- // Nested quantifiers
201
- /(\([^)]*){10,}/,
202
- // Too many groups
203
- /(\[[^\]]{100,})/
204
- // Very long character classes
205
- ];
206
- for (const redos of redosPatterns) {
207
- if (redos.test(pattern)) {
208
- return { valid: false, error: "Pattern contains potentially dangerous constructs" };
209
- }
210
- }
211
- try {
212
- new RegExp(pattern);
213
- return { valid: true };
214
- } catch (error) {
215
- const message = error instanceof Error ? error.message : "Invalid regex";
216
- return { valid: false, error: message };
217
- }
218
- }
219
- async function handleCacheClear(args, ctx) {
220
- const { pattern } = args;
221
- if (!pattern || typeof pattern !== "string") {
222
- return textResult("Pattern is required and must be a string", true);
223
- }
224
- const validation = validateRegexPattern(pattern);
225
- if (!validation.valid) {
226
- return textResult(`Invalid pattern: ${validation.error}`, true);
227
- }
228
- try {
229
- const regex = new RegExp(pattern);
230
- const count = await ctx.cache.invalidatePattern(regex);
231
- return textResult(`Cleared ${count} cache entries matching pattern: ${pattern}`);
232
- } catch (error) {
233
- const message = error instanceof Error ? error.message : String(error);
234
- return textResult(`Failed to clear cache: ${message}`, true);
235
- }
236
- }
237
- async function handleToolCall(name, args, ctx) {
238
- switch (name) {
239
- case "codex_document_fetch":
240
- return handleFetch(args, ctx);
241
- case "codex_search":
242
- return handleSearch(args, ctx);
243
- case "codex_cache_list":
244
- return handleList(args, ctx);
245
- case "codex_cache_clear":
246
- return handleCacheClear(args, ctx);
247
- default:
248
- return textResult(`Unknown tool: ${name}`, true);
249
- }
250
- }
251
- function formatBytes(bytes) {
252
- if (bytes === 0) return "0 B";
253
- const k = 1024;
254
- const sizes = ["B", "KB", "MB", "GB"];
255
- const i = Math.floor(Math.log(bytes) / Math.log(k));
256
- return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`;
257
- }
258
-
259
- // src/server.ts
260
- var McpServer = class {
261
- config;
262
- toolContext;
263
- constructor(config) {
264
- this.config = {
265
- name: config.name ?? "codex",
266
- version: config.version ?? "1.0.0",
267
- cache: config.cache,
268
- storage: config.storage
269
- };
270
- this.toolContext = {
271
- cache: config.cache,
272
- storage: config.storage
273
- };
274
- }
275
- /**
276
- * Get server info
277
- */
278
- getServerInfo() {
279
- return {
280
- name: this.config.name,
281
- version: this.config.version,
282
- capabilities: this.getCapabilities()
283
- };
284
- }
285
- /**
286
- * Get server capabilities
287
- */
288
- getCapabilities() {
289
- return {
290
- tools: {
291
- listChanged: false
292
- },
293
- resources: {
294
- subscribe: false,
295
- listChanged: false
296
- }
297
- };
298
- }
299
- /**
300
- * List available tools
301
- */
302
- listTools() {
303
- return CODEX_TOOLS;
304
- }
305
- /**
306
- * Call a tool
307
- */
308
- async callTool(name, args) {
309
- return handleToolCall(name, args, this.toolContext);
310
- }
311
- /**
312
- * List available resources
313
- */
314
- async listResources() {
315
- const resources = [];
316
- const stats = await this.config.cache.getStats();
317
- resources.push({
318
- uri: "codex://cache/summary",
319
- name: "Cache Summary",
320
- description: `${stats.entryCount} cached documents`,
321
- mimeType: "text/plain"
322
- });
323
- return resources;
324
- }
325
- /**
326
- * List resource templates
327
- */
328
- listResourceTemplates() {
329
- return [
330
- {
331
- uriTemplate: "codex://{org}/{project}/{path}",
332
- name: "Codex Document",
333
- description: "Fetch a document from the Codex knowledge base",
334
- mimeType: "text/markdown"
335
- }
336
- ];
337
- }
338
- /**
339
- * Read a resource
340
- */
341
- async readResource(uri) {
342
- if (uri === "codex://cache/summary") {
343
- const stats = await this.config.cache.getStats();
344
- return [
345
- {
346
- uri,
347
- mimeType: "text/plain",
348
- text: `Cache Statistics:
349
- - Total entries: ${stats.entryCount}
350
- - Memory entries: ${stats.memoryEntries}
351
- - Fresh: ${stats.freshCount}
352
- - Stale: ${stats.staleCount}
353
- - Expired: ${stats.expiredCount}`
354
- }
355
- ];
356
- }
357
- const ref = resolveReference2(uri);
358
- if (!ref) {
359
- throw new Error(`Invalid codex URI: ${uri}`);
360
- }
361
- const result = await this.config.cache.get(ref);
362
- return [
363
- {
364
- uri,
365
- mimeType: result.contentType,
366
- text: result.content.toString("utf-8")
367
- }
368
- ];
369
- }
370
- /**
371
- * Handle JSON-RPC request
372
- *
373
- * This method handles the low-level MCP protocol messages.
374
- */
375
- async handleRequest(method, params) {
376
- switch (method) {
377
- case "initialize":
378
- return {
379
- protocolVersion: "2024-11-05",
380
- serverInfo: this.getServerInfo(),
381
- capabilities: this.getCapabilities()
382
- };
383
- case "tools/list":
384
- return { tools: this.listTools() };
385
- case "tools/call": {
386
- const { name, arguments: args } = params;
387
- return await this.callTool(name, args);
388
- }
389
- case "resources/list":
390
- return { resources: await this.listResources() };
391
- case "resources/templates/list":
392
- return { resourceTemplates: this.listResourceTemplates() };
393
- case "resources/read": {
394
- const { uri } = params;
395
- return { contents: await this.readResource(uri) };
396
- }
397
- case "prompts/list":
398
- return { prompts: [] };
399
- default:
400
- throw new Error(`Unknown method: ${method}`);
401
- }
402
- }
403
- /**
404
- * Process a JSON-RPC message
405
- */
406
- async processMessage(message) {
407
- let id = null;
408
- try {
409
- const request = JSON.parse(message);
410
- id = request.id;
411
- const { method, params } = request;
412
- const result = await this.handleRequest(method, params);
413
- return JSON.stringify({
414
- jsonrpc: "2.0",
415
- id,
416
- result
417
- });
418
- } catch (error) {
419
- const errorMessage = error instanceof Error ? error.message : String(error);
420
- return JSON.stringify({
421
- jsonrpc: "2.0",
422
- id,
423
- error: {
424
- code: -32603,
425
- message: errorMessage
426
- }
427
- });
428
- }
429
- }
430
- };
431
- function createMcpServer(config) {
432
- return new McpServer(config);
433
- }
434
- export {
435
- CODEX_TOOLS,
436
- McpServer,
437
- createMcpServer,
438
- handleCacheClear,
439
- handleFetch,
440
- handleList,
441
- handleSearch,
442
- handleToolCall
443
- };
444
- //# sourceMappingURL=index.js.map
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/server.ts","../src/tools.ts"],"sourcesContent":["/**\n * MCP Server implementation\n *\n * Implements a Model Context Protocol server for the Codex SDK.\n * This server can be used standalone or embedded in other applications.\n */\n\nimport type { CacheManager } from '@fractary/codex'\nimport type { StorageManager } from '@fractary/codex'\nimport { resolveReference } from '@fractary/codex'\nimport type {\n McpServerInfo,\n McpCapabilities,\n McpTool,\n McpResource,\n McpResourceTemplate,\n ResourceContent,\n ToolResult,\n} from './types.js'\nimport { CODEX_TOOLS, handleToolCall, type ToolHandlerContext } from './tools.js'\n\n/**\n * MCP Server configuration\n */\nexport interface McpServerConfig {\n /** Server name */\n name?: string\n /** Server version */\n version?: string\n /** Cache manager instance */\n cache: CacheManager\n /** Storage manager instance */\n storage: StorageManager\n}\n\n/**\n * MCP Server for Codex\n *\n * Provides a Model Context Protocol server implementation that exposes\n * Codex functionality as MCP tools and resources.\n */\nexport class McpServer {\n private config: Required<Omit<McpServerConfig, 'cache' | 'storage'>> & Pick<McpServerConfig, 'cache' | 'storage'>\n private toolContext: ToolHandlerContext\n\n constructor(config: McpServerConfig) {\n this.config = {\n name: config.name ?? 'codex',\n version: config.version ?? '1.0.0',\n cache: config.cache,\n storage: config.storage,\n }\n\n this.toolContext = {\n cache: config.cache,\n storage: config.storage,\n }\n }\n\n /**\n * Get server info\n */\n getServerInfo(): McpServerInfo {\n return {\n name: this.config.name,\n version: this.config.version,\n capabilities: this.getCapabilities(),\n }\n }\n\n /**\n * Get server capabilities\n */\n getCapabilities(): McpCapabilities {\n return {\n tools: {\n listChanged: false,\n },\n resources: {\n subscribe: false,\n listChanged: false,\n },\n }\n }\n\n /**\n * List available tools\n */\n listTools(): McpTool[] {\n return CODEX_TOOLS\n }\n\n /**\n * Call a tool\n */\n async callTool(name: string, args: Record<string, unknown>): Promise<ToolResult> {\n return handleToolCall(name, args, this.toolContext)\n }\n\n /**\n * List available resources\n */\n async listResources(): Promise<McpResource[]> {\n // List cached documents as resources\n const resources: McpResource[] = []\n\n // Get cache stats for info\n const stats = await this.config.cache.getStats()\n\n // Add a summary resource\n resources.push({\n uri: 'codex://cache/summary',\n name: 'Cache Summary',\n description: `${stats.entryCount} cached documents`,\n mimeType: 'text/plain',\n })\n\n return resources\n }\n\n /**\n * List resource templates\n */\n listResourceTemplates(): McpResourceTemplate[] {\n return [\n {\n uriTemplate: 'codex://{org}/{project}/{path}',\n name: 'Codex Document',\n description: 'Fetch a document from the Codex knowledge base',\n mimeType: 'text/markdown',\n },\n ]\n }\n\n /**\n * Read a resource\n */\n async readResource(uri: string): Promise<ResourceContent[]> {\n // Handle special URIs\n if (uri === 'codex://cache/summary') {\n const stats = await this.config.cache.getStats()\n return [\n {\n uri,\n mimeType: 'text/plain',\n text: `Cache Statistics:\n- Total entries: ${stats.entryCount}\n- Memory entries: ${stats.memoryEntries}\n- Fresh: ${stats.freshCount}\n- Stale: ${stats.staleCount}\n- Expired: ${stats.expiredCount}`,\n },\n ]\n }\n\n // Resolve and fetch the reference\n const ref = resolveReference(uri)\n if (!ref) {\n throw new Error(`Invalid codex URI: ${uri}`)\n }\n\n const result = await this.config.cache.get(ref)\n return [\n {\n uri,\n mimeType: result.contentType,\n text: result.content.toString('utf-8'),\n },\n ]\n }\n\n /**\n * Handle JSON-RPC request\n *\n * This method handles the low-level MCP protocol messages.\n */\n async handleRequest(method: string, params?: Record<string, unknown>): Promise<unknown> {\n switch (method) {\n case 'initialize':\n return {\n protocolVersion: '2024-11-05',\n serverInfo: this.getServerInfo(),\n capabilities: this.getCapabilities(),\n }\n\n case 'tools/list':\n return { tools: this.listTools() }\n\n case 'tools/call': {\n const { name, arguments: args } = params as { name: string; arguments: Record<string, unknown> }\n return await this.callTool(name, args)\n }\n\n case 'resources/list':\n return { resources: await this.listResources() }\n\n case 'resources/templates/list':\n return { resourceTemplates: this.listResourceTemplates() }\n\n case 'resources/read': {\n const { uri } = params as { uri: string }\n return { contents: await this.readResource(uri) }\n }\n\n case 'prompts/list':\n return { prompts: [] }\n\n default:\n throw new Error(`Unknown method: ${method}`)\n }\n }\n\n /**\n * Process a JSON-RPC message\n */\n async processMessage(message: string): Promise<string> {\n let id: unknown = null\n\n try {\n const request = JSON.parse(message)\n id = request.id\n const { method, params } = request\n\n const result = await this.handleRequest(method, params)\n\n return JSON.stringify({\n jsonrpc: '2.0',\n id,\n result,\n })\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n\n return JSON.stringify({\n jsonrpc: '2.0',\n id,\n error: {\n code: -32603,\n message: errorMessage,\n },\n })\n }\n }\n}\n\n/**\n * Create an MCP server\n */\nexport function createMcpServer(config: McpServerConfig): McpServer {\n return new McpServer(config)\n}\n","/**\n * MCP Tool definitions and handlers\n *\n * Implements the tools exposed by the Codex MCP server.\n */\n\nimport type { CacheManager } from '@fractary/codex'\nimport type { StorageManager } from '@fractary/codex'\nimport { resolveReference } from '@fractary/codex'\nimport type {\n McpTool,\n ToolResult,\n FetchToolArgs,\n SearchToolArgs,\n ListToolArgs,\n CacheClearToolArgs,\n} from './types.js'\n\n/**\n * Tool definitions for the MCP server\n */\nexport const CODEX_TOOLS: McpTool[] = [\n {\n name: 'codex_document_fetch',\n description: 'Fetch a document from the Codex knowledge base by URI. Returns the document content.',\n inputSchema: {\n type: 'object',\n properties: {\n uri: {\n type: 'string',\n description: 'Codex URI in format: codex://org/project/path/to/file.md',\n },\n branch: {\n type: 'string',\n description: 'Git branch to fetch from (default: main)',\n },\n noCache: {\n type: 'boolean',\n description: 'Bypass cache and fetch fresh content',\n },\n },\n required: ['uri'],\n },\n },\n {\n name: 'codex_search',\n description: 'Search for documents in the Codex knowledge base.',\n inputSchema: {\n type: 'object',\n properties: {\n query: {\n type: 'string',\n description: 'Search query string',\n },\n org: {\n type: 'string',\n description: 'Filter by organization',\n },\n project: {\n type: 'string',\n description: 'Filter by project',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of results (default: 10)',\n },\n type: {\n type: 'string',\n description: 'Filter by artifact type (e.g., docs, specs, logs)',\n },\n },\n required: ['query'],\n },\n },\n {\n name: 'codex_cache_list',\n description: 'List documents in the Codex cache.',\n inputSchema: {\n type: 'object',\n properties: {\n org: {\n type: 'string',\n description: 'Filter by organization',\n },\n project: {\n type: 'string',\n description: 'Filter by project',\n },\n includeExpired: {\n type: 'boolean',\n description: 'Include expired cache entries',\n },\n },\n },\n },\n {\n name: 'codex_cache_clear',\n description: 'Clear cached documents matching a pattern.',\n inputSchema: {\n type: 'object',\n properties: {\n pattern: {\n type: 'string',\n description: 'URI pattern to invalidate (supports regex)',\n },\n },\n required: ['pattern'],\n },\n },\n]\n\n/**\n * Tool handler context\n */\nexport interface ToolHandlerContext {\n cache: CacheManager\n storage: StorageManager\n}\n\n/**\n * Create a text result\n */\nfunction textResult(text: string, isError = false): ToolResult {\n return {\n content: [{ type: 'text', text }],\n isError,\n }\n}\n\n/**\n * Create a resource result\n */\nfunction resourceResult(uri: string, content: string, mimeType?: string): ToolResult {\n return {\n content: [\n {\n type: 'resource',\n resource: {\n uri,\n mimeType,\n text: content,\n },\n },\n ],\n }\n}\n\n/**\n * Handle codex_document_fetch tool\n */\nexport async function handleFetch(args: FetchToolArgs, ctx: ToolHandlerContext): Promise<ToolResult> {\n const { uri, branch, noCache } = args\n\n // Validate input\n if (!uri || typeof uri !== 'string') {\n return textResult('URI is required and must be a string', true)\n }\n\n if (branch && typeof branch !== 'string') {\n return textResult('Branch must be a string', true)\n }\n\n // Resolve the reference\n const ref = resolveReference(uri)\n if (!ref) {\n return textResult(`Invalid codex URI: ${uri}`, true)\n }\n\n try {\n let result\n\n if (noCache) {\n // Bypass cache, fetch directly\n result = await ctx.storage.fetch(ref, { branch })\n // Still cache the result for next time\n await ctx.cache.set(uri, result)\n } else {\n // Use cache\n result = await ctx.cache.get(ref, { branch })\n }\n\n const content = result.content.toString('utf-8')\n return resourceResult(uri, content, result.contentType)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n return textResult(`Failed to fetch ${uri}: ${message}`, true)\n }\n}\n\n/**\n * Handle codex_search tool\n *\n * Note: This is a basic implementation that searches cached entries.\n * A more sophisticated implementation might use a search index.\n */\nexport async function handleSearch(args: SearchToolArgs, ctx: ToolHandlerContext): Promise<ToolResult> {\n const { query, org, project, limit = 10 } = args\n\n // Validate input\n if (!query || typeof query !== 'string') {\n return textResult('Query is required and must be a string', true)\n }\n\n if (query.length > 500) {\n return textResult('Query too long (max 500 characters)', true)\n }\n\n if (typeof limit !== 'number' || limit < 1 || limit > 100) {\n return textResult('Limit must be a number between 1 and 100', true)\n }\n\n // Get all cached entries\n const stats = await ctx.cache.getStats()\n if (stats.entryCount === 0) {\n return textResult('No documents in cache. Use codex_document_fetch to load documents first.')\n }\n\n // This is a simplified search - in a real implementation,\n // we would use a proper search index\n // For now, we search through the cached URIs and content\n\n // Note: This is a placeholder. The actual search implementation\n // would depend on having access to the cache persistence layer's\n // list of URIs and their content.\n\n const message = `Search functionality requires a search index.\nQuery: \"${query}\"\nFilters: org=${org || 'any'}, project=${project || 'any'}\nLimit: ${limit}\n\nTo fetch documents, use codex_document_fetch with a specific URI like:\ncodex://org/project/docs/file.md`\n\n return textResult(message)\n}\n\n/**\n * Handle codex_cache_list tool\n */\nexport async function handleList(args: ListToolArgs, ctx: ToolHandlerContext): Promise<ToolResult> {\n const { org, project, includeExpired } = args\n\n // Get cache stats and any available info\n const stats = await ctx.cache.getStats()\n\n let message = `Cache Statistics:\n- Total entries: ${stats.entryCount}\n- Memory entries: ${stats.memoryEntries}\n- Memory size: ${formatBytes(stats.memorySize)}\n- Total size: ${formatBytes(stats.totalSize)}\n- Fresh: ${stats.freshCount}\n- Stale: ${stats.staleCount}\n- Expired: ${stats.expiredCount}`\n\n if (org) {\n message += `\\n\\nFiltered by org: ${org}`\n }\n if (project) {\n message += `\\nFiltered by project: ${project}`\n }\n if (includeExpired) {\n message += `\\nIncluding expired entries`\n }\n\n return textResult(message)\n}\n\n/**\n * Validate and sanitize regex pattern to prevent ReDoS attacks\n */\nfunction validateRegexPattern(pattern: string): { valid: boolean; error?: string } {\n // Check pattern length (prevent extremely long patterns)\n if (pattern.length > 1000) {\n return { valid: false, error: 'Pattern too long (max 1000 characters)' }\n }\n\n // Check for common ReDoS patterns\n const redosPatterns = [\n /(\\.\\*){3,}/, // Multiple consecutive .*\n /(\\+\\+|\\*\\*|\\?\\?)/, // Nested quantifiers\n /(\\([^)]*){10,}/, // Too many groups\n /(\\[[^\\]]{100,})/, // Very long character classes\n ]\n\n for (const redos of redosPatterns) {\n if (redos.test(pattern)) {\n return { valid: false, error: 'Pattern contains potentially dangerous constructs' }\n }\n }\n\n // Try to compile the regex to check for syntax errors\n try {\n new RegExp(pattern)\n return { valid: true }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Invalid regex'\n return { valid: false, error: message }\n }\n}\n\n/**\n * Handle codex_cache_clear tool\n */\nexport async function handleCacheClear(args: CacheClearToolArgs, ctx: ToolHandlerContext): Promise<ToolResult> {\n const { pattern } = args\n\n if (!pattern || typeof pattern !== 'string') {\n return textResult('Pattern is required and must be a string', true)\n }\n\n // Validate pattern to prevent ReDoS\n const validation = validateRegexPattern(pattern)\n if (!validation.valid) {\n return textResult(`Invalid pattern: ${validation.error}`, true)\n }\n\n try {\n const regex = new RegExp(pattern)\n const count = await ctx.cache.invalidatePattern(regex)\n\n return textResult(`Cleared ${count} cache entries matching pattern: ${pattern}`)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n return textResult(`Failed to clear cache: ${message}`, true)\n }\n}\n\n/**\n * Route a tool call to its handler\n */\nexport async function handleToolCall(\n name: string,\n args: Record<string, unknown>,\n ctx: ToolHandlerContext\n): Promise<ToolResult> {\n switch (name) {\n case 'codex_document_fetch':\n return handleFetch(args as unknown as FetchToolArgs, ctx)\n case 'codex_search':\n return handleSearch(args as unknown as SearchToolArgs, ctx)\n case 'codex_cache_list':\n return handleList(args as unknown as ListToolArgs, ctx)\n case 'codex_cache_clear':\n return handleCacheClear(args as unknown as CacheClearToolArgs, ctx)\n default:\n return textResult(`Unknown tool: ${name}`, true)\n }\n}\n\n/**\n * Format bytes to human readable string\n */\nfunction formatBytes(bytes: number): string {\n if (bytes === 0) return '0 B'\n const k = 1024\n const sizes = ['B', 'KB', 'MB', 'GB']\n const i = Math.floor(Math.log(bytes) / Math.log(k))\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(2))} ${sizes[i]}`\n}\n"],"mappings":"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","names":["resolveReference","resolveReference"]}
File without changes
File without changes