@sudosandwich/limps 0.3.0 → 1.0.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/README.md +13 -1
- package/dist/index.js +0 -0
- package/dist/tools/read-doc.d.ts +38 -0
- package/dist/tools/read-doc.d.ts.map +1 -0
- package/dist/tools/read-doc.js +174 -0
- package/dist/tools/read-doc.js.map +1 -0
- package/dist/tools/rlm-multi-query.d.ts +54 -0
- package/dist/tools/rlm-multi-query.d.ts.map +1 -0
- package/dist/tools/rlm-multi-query.js +348 -0
- package/dist/tools/rlm-multi-query.js.map +1 -0
- package/dist/tools/rlm-query.d.ts +44 -0
- package/dist/tools/rlm-query.d.ts.map +1 -0
- package/dist/tools/rlm-query.js +228 -0
- package/dist/tools/rlm-query.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -272,6 +272,18 @@ Claude Desktop runs in a macOS sandbox and cannot access global npm binaries. Us
|
|
|
272
272
|
|
|
273
273
|
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
274
274
|
|
|
275
|
+
```json
|
|
276
|
+
{
|
|
277
|
+
"mcpServers": {
|
|
278
|
+
"limps": {
|
|
279
|
+
"command": "npx",
|
|
280
|
+
"args": ["-y", "@sudosandwich/limps"]
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
With explicit config:
|
|
275
287
|
```json
|
|
276
288
|
{
|
|
277
289
|
"mcpServers": {
|
|
@@ -283,7 +295,7 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
|
283
295
|
}
|
|
284
296
|
```
|
|
285
297
|
|
|
286
|
-
> **Note:** Run `limps init my-project` first to generate
|
|
298
|
+
> **Note:** Run `limps init my-project` first to generate a config, then use the full path above.
|
|
287
299
|
|
|
288
300
|
## Features
|
|
289
301
|
|
package/dist/index.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* read_doc tool: Read full content of any document in the repository.
|
|
3
|
+
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import type { ToolContext, ToolResult } from '../types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Input schema for read_doc tool.
|
|
8
|
+
*/
|
|
9
|
+
export declare const ReadDocInputSchema: z.ZodObject<{
|
|
10
|
+
path: z.ZodString;
|
|
11
|
+
lines: z.ZodOptional<z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>>;
|
|
12
|
+
}, z.core.$strip>;
|
|
13
|
+
export type ReadDocInput = z.infer<typeof ReadDocInputSchema>;
|
|
14
|
+
/**
|
|
15
|
+
* Output interface for read_doc tool.
|
|
16
|
+
*/
|
|
17
|
+
export interface ReadDocOutput {
|
|
18
|
+
path: string;
|
|
19
|
+
content: string;
|
|
20
|
+
metadata: {
|
|
21
|
+
size: number;
|
|
22
|
+
lines: number;
|
|
23
|
+
modified: string;
|
|
24
|
+
type: 'md' | 'jsx' | 'tsx' | 'ts' | 'json' | 'yaml' | 'other';
|
|
25
|
+
partial?: boolean;
|
|
26
|
+
range?: [number, number];
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Handle read_doc tool request.
|
|
31
|
+
* Reads full file content with optional line range.
|
|
32
|
+
*
|
|
33
|
+
* @param input - Tool input
|
|
34
|
+
* @param context - Tool context
|
|
35
|
+
* @returns Tool result
|
|
36
|
+
*/
|
|
37
|
+
export declare function handleReadDoc(input: ReadDocInput, context: ToolContext): Promise<ToolResult>;
|
|
38
|
+
//# sourceMappingURL=read-doc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-doc.d.ts","sourceRoot":"","sources":["../../src/tools/read-doc.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAI3D;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;iBAM7B,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;QAC9D,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAC1B,CAAC;CACH;AAeD;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC,CAuJrB"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* read_doc tool: Read full content of any document in the repository.
|
|
3
|
+
*/
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { readFile, stat } from 'fs/promises';
|
|
6
|
+
import { existsSync } from 'fs';
|
|
7
|
+
import { dirname } from 'path';
|
|
8
|
+
import { validatePath } from '../utils/paths.js';
|
|
9
|
+
import { notFound } from '../utils/errors.js';
|
|
10
|
+
/**
|
|
11
|
+
* Input schema for read_doc tool.
|
|
12
|
+
*/
|
|
13
|
+
export const ReadDocInputSchema = z.object({
|
|
14
|
+
path: z.string().min(1).describe('Path relative to repo root'),
|
|
15
|
+
lines: z
|
|
16
|
+
.tuple([z.number().int().positive(), z.number().int().positive()])
|
|
17
|
+
.optional()
|
|
18
|
+
.describe('Optional line range [start, end], 1-indexed'),
|
|
19
|
+
});
|
|
20
|
+
/**
|
|
21
|
+
* Get repository root from config.
|
|
22
|
+
* Uses the first docsPath entry as the repo root, or derives from plansPath.
|
|
23
|
+
*/
|
|
24
|
+
function getRepoRoot(config) {
|
|
25
|
+
// Prefer docsPaths[0] if it exists (it's the repo root)
|
|
26
|
+
if (config.docsPaths && config.docsPaths.length > 0) {
|
|
27
|
+
return config.docsPaths[0];
|
|
28
|
+
}
|
|
29
|
+
// Fallback: use plansPath parent directory
|
|
30
|
+
return dirname(config.plansPath);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Handle read_doc tool request.
|
|
34
|
+
* Reads full file content with optional line range.
|
|
35
|
+
*
|
|
36
|
+
* @param input - Tool input
|
|
37
|
+
* @param context - Tool context
|
|
38
|
+
* @returns Tool result
|
|
39
|
+
*/
|
|
40
|
+
export async function handleReadDoc(input, context) {
|
|
41
|
+
const { path, lines } = input;
|
|
42
|
+
const { config } = context;
|
|
43
|
+
try {
|
|
44
|
+
// Get repo root
|
|
45
|
+
const repoRoot = getRepoRoot(config);
|
|
46
|
+
// Validate path first
|
|
47
|
+
const validated = validatePath(path, repoRoot);
|
|
48
|
+
// Check if file exists
|
|
49
|
+
if (!existsSync(validated.absolute)) {
|
|
50
|
+
throw notFound(path);
|
|
51
|
+
}
|
|
52
|
+
// Read file stats
|
|
53
|
+
const stats = await stat(validated.absolute);
|
|
54
|
+
// Read file content
|
|
55
|
+
const content = await readFile(validated.absolute, 'utf-8');
|
|
56
|
+
// Count lines (empty file has 0 lines, not 1)
|
|
57
|
+
const lineCount = content === '' ? 0 : content.split('\n').length;
|
|
58
|
+
// Handle line range if specified
|
|
59
|
+
let finalContent = content;
|
|
60
|
+
let partial = false;
|
|
61
|
+
let range;
|
|
62
|
+
if (lines) {
|
|
63
|
+
const [start, end] = lines;
|
|
64
|
+
// Validate range
|
|
65
|
+
if (start > end) {
|
|
66
|
+
return {
|
|
67
|
+
content: [
|
|
68
|
+
{
|
|
69
|
+
type: 'text',
|
|
70
|
+
text: `Invalid line range: start (${start}) must be <= end (${end})`,
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
isError: true,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (start < 1 || end < 1) {
|
|
77
|
+
return {
|
|
78
|
+
content: [
|
|
79
|
+
{
|
|
80
|
+
type: 'text',
|
|
81
|
+
text: `Invalid line range: line numbers must be >= 1`,
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
isError: true,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
// Convert 1-indexed to 0-indexed
|
|
88
|
+
const startIdx = start - 1;
|
|
89
|
+
const endIdx = end; // end is inclusive, so we use it directly for slice
|
|
90
|
+
// Split into lines
|
|
91
|
+
const contentLines = content.split('\n');
|
|
92
|
+
// Validate range against file
|
|
93
|
+
if (startIdx > contentLines.length) {
|
|
94
|
+
return {
|
|
95
|
+
content: [
|
|
96
|
+
{
|
|
97
|
+
type: 'text',
|
|
98
|
+
text: `Line range [${start}, ${end}] exceeds file length (${lineCount} lines)`,
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
isError: true,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
// Extract range (endIdx is exclusive in slice, so we add 1)
|
|
105
|
+
const endSlice = Math.min(endIdx, contentLines.length);
|
|
106
|
+
const selectedLines = contentLines.slice(startIdx, endSlice);
|
|
107
|
+
// Rejoin lines
|
|
108
|
+
finalContent = selectedLines.join('\n');
|
|
109
|
+
partial = true;
|
|
110
|
+
range = [start, Math.min(end, lineCount)];
|
|
111
|
+
}
|
|
112
|
+
// Format output
|
|
113
|
+
const output = {
|
|
114
|
+
path: validated.relative,
|
|
115
|
+
content: finalContent,
|
|
116
|
+
metadata: {
|
|
117
|
+
size: stats.size,
|
|
118
|
+
lines: lineCount,
|
|
119
|
+
modified: stats.mtime.toISOString(),
|
|
120
|
+
type: validated.type,
|
|
121
|
+
...(partial && { partial: true, range }),
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
return {
|
|
125
|
+
content: [
|
|
126
|
+
{
|
|
127
|
+
type: 'text',
|
|
128
|
+
text: JSON.stringify(output, null, 2),
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
// Handle DocumentError
|
|
135
|
+
if (error instanceof Error && 'code' in error) {
|
|
136
|
+
const docError = error;
|
|
137
|
+
return {
|
|
138
|
+
content: [
|
|
139
|
+
{
|
|
140
|
+
type: 'text',
|
|
141
|
+
text: `Error: ${docError.message}${docError.path ? ` (path: ${docError.path})` : ''}`,
|
|
142
|
+
},
|
|
143
|
+
],
|
|
144
|
+
isError: true,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
// Handle file system errors
|
|
148
|
+
if (error instanceof Error) {
|
|
149
|
+
// Check for ENOENT (file not found)
|
|
150
|
+
if ('code' in error && error.code === 'ENOENT') {
|
|
151
|
+
throw notFound(path);
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
content: [
|
|
155
|
+
{
|
|
156
|
+
type: 'text',
|
|
157
|
+
text: `Error reading file: ${error.message}`,
|
|
158
|
+
},
|
|
159
|
+
],
|
|
160
|
+
isError: true,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
content: [
|
|
165
|
+
{
|
|
166
|
+
type: 'text',
|
|
167
|
+
text: `Unknown error: ${String(error)}`,
|
|
168
|
+
},
|
|
169
|
+
],
|
|
170
|
+
isError: true,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=read-doc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-doc.js","sourceRoot":"","sources":["../../src/tools/read-doc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* rlm_multi_query tool: Execute JavaScript code on multiple documents.
|
|
3
|
+
* Feature #4: RLM Multi-Query Tool
|
|
4
|
+
*
|
|
5
|
+
* Enables cross-document analysis with glob patterns or explicit paths.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import type { ToolContext, ToolResult } from '../types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Base input schema for rlm_multi_query tool (for registration).
|
|
11
|
+
*/
|
|
12
|
+
export declare const RlmMultiQueryInputBaseSchema: z.ZodObject<{
|
|
13
|
+
paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
14
|
+
pattern: z.ZodOptional<z.ZodString>;
|
|
15
|
+
code: z.ZodString;
|
|
16
|
+
sub_query: z.ZodOptional<z.ZodString>;
|
|
17
|
+
timeout: z.ZodDefault<z.ZodNumber>;
|
|
18
|
+
max_docs: z.ZodDefault<z.ZodNumber>;
|
|
19
|
+
}, z.core.$strip>;
|
|
20
|
+
/**
|
|
21
|
+
* Input schema for rlm_multi_query tool (with validation).
|
|
22
|
+
*/
|
|
23
|
+
export declare const RlmMultiQueryInputSchema: z.ZodObject<{
|
|
24
|
+
paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
25
|
+
pattern: z.ZodOptional<z.ZodString>;
|
|
26
|
+
code: z.ZodString;
|
|
27
|
+
sub_query: z.ZodOptional<z.ZodString>;
|
|
28
|
+
timeout: z.ZodDefault<z.ZodNumber>;
|
|
29
|
+
max_docs: z.ZodDefault<z.ZodNumber>;
|
|
30
|
+
}, z.core.$strip>;
|
|
31
|
+
export type RlmMultiQueryInput = z.infer<typeof RlmMultiQueryInputSchema>;
|
|
32
|
+
/**
|
|
33
|
+
* Output interface for rlm_multi_query tool.
|
|
34
|
+
*/
|
|
35
|
+
export interface RlmMultiQueryOutput {
|
|
36
|
+
result: unknown;
|
|
37
|
+
docs_loaded: number;
|
|
38
|
+
execution_time_ms: number;
|
|
39
|
+
sub_results?: unknown[];
|
|
40
|
+
metadata: {
|
|
41
|
+
paths: string[];
|
|
42
|
+
total_size: number;
|
|
43
|
+
result_size: number;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Handle rlm_multi_query tool request.
|
|
48
|
+
*
|
|
49
|
+
* @param input - Tool input
|
|
50
|
+
* @param context - Tool context
|
|
51
|
+
* @returns Tool result
|
|
52
|
+
*/
|
|
53
|
+
export declare function handleRlmMultiQuery(input: RlmMultiQueryInput, context: ToolContext): Promise<ToolResult>;
|
|
54
|
+
//# sourceMappingURL=rlm-multi-query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rlm-multi-query.d.ts","sourceRoot":"","sources":["../../src/tools/rlm-multi-query.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAQ3D;;GAEG;AACH,eAAO,MAAM,4BAA4B;;;;;;;iBAOvC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,wBAAwB;;;;;;;iBAOnC,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC;IACxB,QAAQ,EAAE;QACR,KAAK,EAAE,MAAM,EAAE,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AA0GD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,kBAAkB,EACzB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC,CAmPrB"}
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* rlm_multi_query tool: Execute JavaScript code on multiple documents.
|
|
3
|
+
* Feature #4: RLM Multi-Query Tool
|
|
4
|
+
*
|
|
5
|
+
* Enables cross-document analysis with glob patterns or explicit paths.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { readFile, stat, readdir } from 'fs/promises';
|
|
9
|
+
import { existsSync } from 'fs';
|
|
10
|
+
import { join, dirname } from 'path';
|
|
11
|
+
import micromatch from 'micromatch';
|
|
12
|
+
import { validatePath } from '../utils/paths.js';
|
|
13
|
+
import { validationError } from '../utils/errors.js';
|
|
14
|
+
import { createEnvironment } from '../rlm/sandbox.js';
|
|
15
|
+
import { validateCode } from '../rlm/security.js';
|
|
16
|
+
import { processSubCalls } from '../rlm/recursion.js';
|
|
17
|
+
/**
|
|
18
|
+
* Base input schema for rlm_multi_query tool (for registration).
|
|
19
|
+
*/
|
|
20
|
+
export const RlmMultiQueryInputBaseSchema = z.object({
|
|
21
|
+
paths: z.array(z.string().min(1)).optional().describe('Explicit list of document paths'),
|
|
22
|
+
pattern: z.string().optional().describe('Glob pattern (e.g., "plans/*/plan.md")'),
|
|
23
|
+
code: z.string().min(1).describe('JavaScript code to execute (docs array available)'),
|
|
24
|
+
sub_query: z.string().optional().describe('Prompt for recursive LLM processing'),
|
|
25
|
+
timeout: z.number().int().min(100).max(30000).default(5000),
|
|
26
|
+
max_docs: z.number().int().min(1).max(50).default(20).describe('Maximum documents to load'),
|
|
27
|
+
});
|
|
28
|
+
/**
|
|
29
|
+
* Input schema for rlm_multi_query tool (with validation).
|
|
30
|
+
*/
|
|
31
|
+
export const RlmMultiQueryInputSchema = RlmMultiQueryInputBaseSchema.refine((data) => data.paths || data.pattern, {
|
|
32
|
+
message: 'Either paths or pattern must be provided',
|
|
33
|
+
}).refine((data) => !(data.paths && data.pattern), {
|
|
34
|
+
message: 'Cannot provide both paths and pattern',
|
|
35
|
+
});
|
|
36
|
+
/**
|
|
37
|
+
* Get repository root from config.
|
|
38
|
+
*/
|
|
39
|
+
function getRepoRoot(config) {
|
|
40
|
+
if (config.docsPaths && config.docsPaths.length > 0) {
|
|
41
|
+
return config.docsPaths[0];
|
|
42
|
+
}
|
|
43
|
+
return dirname(config.plansPath);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Recursively find files matching a glob pattern.
|
|
47
|
+
*
|
|
48
|
+
* @param repoRoot - Repository root directory
|
|
49
|
+
* @param pattern - Glob pattern (e.g., "plans/**\/plan.md")
|
|
50
|
+
* @param maxDepth - Maximum directory depth to search
|
|
51
|
+
* @returns Array of relative file paths
|
|
52
|
+
*/
|
|
53
|
+
async function resolveGlobPattern(repoRoot, pattern, maxDepth = 10) {
|
|
54
|
+
const matches = [];
|
|
55
|
+
async function walkDirectory(dirPath, _relativePath, currentDepth) {
|
|
56
|
+
if (currentDepth > maxDepth) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (!existsSync(dirPath)) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
const entries = await readdir(dirPath, { withFileTypes: true });
|
|
64
|
+
for (const entry of entries) {
|
|
65
|
+
// Skip hidden files and directories
|
|
66
|
+
if (entry.name.startsWith('.')) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const fullPath = join(dirPath, entry.name);
|
|
70
|
+
const entryRelativePath = _relativePath ? join(_relativePath, entry.name) : entry.name;
|
|
71
|
+
if (entry.isDirectory()) {
|
|
72
|
+
// Recurse into subdirectories
|
|
73
|
+
await walkDirectory(fullPath, entryRelativePath, currentDepth + 1);
|
|
74
|
+
}
|
|
75
|
+
else if (entry.isFile()) {
|
|
76
|
+
// Check if file matches pattern
|
|
77
|
+
// Convert pattern to match against relative path from repo root
|
|
78
|
+
if (micromatch.isMatch(entryRelativePath, pattern)) {
|
|
79
|
+
matches.push(entryRelativePath);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Ignore permission errors or other issues
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
await walkDirectory(repoRoot, '', 0);
|
|
89
|
+
return matches;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Load a document and create DocVariable.
|
|
93
|
+
*/
|
|
94
|
+
async function loadDocument(repoRoot, relativePath) {
|
|
95
|
+
try {
|
|
96
|
+
// Validate path
|
|
97
|
+
const validated = validatePath(relativePath, repoRoot);
|
|
98
|
+
// Check if file exists
|
|
99
|
+
if (!existsSync(validated.absolute)) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
// Read file stats and content
|
|
103
|
+
const stats = await stat(validated.absolute);
|
|
104
|
+
const content = await readFile(validated.absolute, 'utf-8');
|
|
105
|
+
const docSize = Buffer.byteLength(content, 'utf-8');
|
|
106
|
+
return {
|
|
107
|
+
content,
|
|
108
|
+
metadata: {
|
|
109
|
+
path: validated.relative,
|
|
110
|
+
size: docSize,
|
|
111
|
+
lines: content === '' ? 0 : content.split('\n').length,
|
|
112
|
+
modified: stats.mtime.toISOString(),
|
|
113
|
+
},
|
|
114
|
+
path: validated.relative,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// Return null if file can't be loaded
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Handle rlm_multi_query tool request.
|
|
124
|
+
*
|
|
125
|
+
* @param input - Tool input
|
|
126
|
+
* @param context - Tool context
|
|
127
|
+
* @returns Tool result
|
|
128
|
+
*/
|
|
129
|
+
export async function handleRlmMultiQuery(input, context) {
|
|
130
|
+
// Validate input (defense in depth - should already be validated by tool registration)
|
|
131
|
+
try {
|
|
132
|
+
RlmMultiQueryInputSchema.parse(input);
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
// Handle Zod validation errors
|
|
136
|
+
if (error && typeof error === 'object' && 'issues' in error) {
|
|
137
|
+
const zodError = error;
|
|
138
|
+
return {
|
|
139
|
+
content: [
|
|
140
|
+
{
|
|
141
|
+
type: 'text',
|
|
142
|
+
text: `Validation error: ${zodError.issues.map((i) => i.message).join(', ')}`,
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
isError: true,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
const { paths, pattern, code, sub_query, timeout = 5000, max_docs = 20 } = input;
|
|
151
|
+
const { config } = context;
|
|
152
|
+
try {
|
|
153
|
+
// Get repo root
|
|
154
|
+
const repoRoot = getRepoRoot(config);
|
|
155
|
+
// Resolve document paths
|
|
156
|
+
let docPaths = [];
|
|
157
|
+
if (paths) {
|
|
158
|
+
// Use explicit paths
|
|
159
|
+
docPaths = paths;
|
|
160
|
+
}
|
|
161
|
+
else if (pattern) {
|
|
162
|
+
// Resolve glob pattern
|
|
163
|
+
const matchedPaths = await resolveGlobPattern(repoRoot, pattern);
|
|
164
|
+
// Enforce max_docs limit
|
|
165
|
+
if (matchedPaths.length > max_docs) {
|
|
166
|
+
throw validationError('pattern', `Pattern matched ${matchedPaths.length} documents, exceeding max_docs limit of ${max_docs}`);
|
|
167
|
+
}
|
|
168
|
+
docPaths = matchedPaths;
|
|
169
|
+
}
|
|
170
|
+
// Empty result (0 docs) should return empty array, not error (per gotchas)
|
|
171
|
+
if (docPaths.length === 0) {
|
|
172
|
+
const output = {
|
|
173
|
+
result: [],
|
|
174
|
+
docs_loaded: 0,
|
|
175
|
+
execution_time_ms: 0,
|
|
176
|
+
metadata: {
|
|
177
|
+
paths: [],
|
|
178
|
+
total_size: 0,
|
|
179
|
+
result_size: 0,
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
return {
|
|
183
|
+
content: [
|
|
184
|
+
{
|
|
185
|
+
type: 'text',
|
|
186
|
+
text: JSON.stringify(output, null, 2),
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
// Load all documents
|
|
192
|
+
const docPromises = docPaths.map((path) => loadDocument(repoRoot, path));
|
|
193
|
+
const docResults = await Promise.all(docPromises);
|
|
194
|
+
// Filter out nulls (files that couldn't be loaded)
|
|
195
|
+
const docs = docResults.filter((doc) => doc !== null);
|
|
196
|
+
// Validate code before execution
|
|
197
|
+
validateCode(code);
|
|
198
|
+
// Calculate total size
|
|
199
|
+
const totalSize = docs.reduce((sum, doc) => sum + doc.metadata.size, 0);
|
|
200
|
+
// Create sandbox environment with docs array
|
|
201
|
+
const env = await createEnvironment(docs, { timeout });
|
|
202
|
+
try {
|
|
203
|
+
// Execute code
|
|
204
|
+
const execResult = await env.execute(code);
|
|
205
|
+
// Calculate result size
|
|
206
|
+
const resultJson = JSON.stringify(execResult.result);
|
|
207
|
+
const resultSize = Buffer.byteLength(resultJson, 'utf-8');
|
|
208
|
+
// Build output
|
|
209
|
+
const output = {
|
|
210
|
+
result: execResult.result,
|
|
211
|
+
docs_loaded: docs.length,
|
|
212
|
+
execution_time_ms: Math.max(1, Math.round(execResult.executionTimeMs)), // Ensure at least 1ms
|
|
213
|
+
metadata: {
|
|
214
|
+
paths: docs.map((doc) => doc.path),
|
|
215
|
+
total_size: totalSize,
|
|
216
|
+
result_size: resultSize,
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
// Handle sub_query (Agent 3 implementation)
|
|
220
|
+
if (sub_query) {
|
|
221
|
+
try {
|
|
222
|
+
// Get sampling client from context (if available)
|
|
223
|
+
// For now, this will be undefined in real server, but tests can provide mock client
|
|
224
|
+
const samplingClient = context
|
|
225
|
+
.samplingClient;
|
|
226
|
+
// Normalize items to array
|
|
227
|
+
const items = Array.isArray(execResult.result) ? execResult.result : [execResult.result];
|
|
228
|
+
// Process sub-calls
|
|
229
|
+
const subResults = await processSubCalls(items, sub_query, {
|
|
230
|
+
maxDepth: 1, // Default to 1 for multi-query (can be made configurable later)
|
|
231
|
+
concurrency: 5,
|
|
232
|
+
timeout: timeout,
|
|
233
|
+
samplingClient,
|
|
234
|
+
});
|
|
235
|
+
// Map results to output format
|
|
236
|
+
output.sub_results = subResults.map((r) => (r.success ? r.result : { error: r.error }));
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
// If sub-call processing fails, include error in sub_results
|
|
240
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
241
|
+
output.sub_results = [
|
|
242
|
+
{
|
|
243
|
+
error: `Sub-call processing failed: ${errorMessage}`,
|
|
244
|
+
},
|
|
245
|
+
];
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return {
|
|
249
|
+
content: [
|
|
250
|
+
{
|
|
251
|
+
type: 'text',
|
|
252
|
+
text: JSON.stringify(output, null, 2),
|
|
253
|
+
},
|
|
254
|
+
],
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
finally {
|
|
258
|
+
// Always dispose environment
|
|
259
|
+
env.dispose();
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
// Handle Zod validation errors
|
|
264
|
+
if (error && typeof error === 'object' && 'issues' in error) {
|
|
265
|
+
const zodError = error;
|
|
266
|
+
return {
|
|
267
|
+
content: [
|
|
268
|
+
{
|
|
269
|
+
type: 'text',
|
|
270
|
+
text: `Validation error: ${zodError.issues.map((i) => i.message).join(', ')}`,
|
|
271
|
+
},
|
|
272
|
+
],
|
|
273
|
+
isError: true,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
// Handle DocumentError
|
|
277
|
+
if (error instanceof Error && 'code' in error) {
|
|
278
|
+
const docError = error;
|
|
279
|
+
return {
|
|
280
|
+
content: [
|
|
281
|
+
{
|
|
282
|
+
type: 'text',
|
|
283
|
+
text: `Error: ${docError.message}${docError.path ? ` (path: ${docError.path})` : ''}`,
|
|
284
|
+
},
|
|
285
|
+
],
|
|
286
|
+
isError: true,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
// Handle security errors
|
|
290
|
+
if (error instanceof Error && error.name === 'SecurityError') {
|
|
291
|
+
return {
|
|
292
|
+
content: [
|
|
293
|
+
{
|
|
294
|
+
type: 'text',
|
|
295
|
+
text: `Security error: ${error.message}`,
|
|
296
|
+
},
|
|
297
|
+
],
|
|
298
|
+
isError: true,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
// Handle timeout errors
|
|
302
|
+
if (error instanceof Error && error.name === 'TimeoutError') {
|
|
303
|
+
return {
|
|
304
|
+
content: [
|
|
305
|
+
{
|
|
306
|
+
type: 'text',
|
|
307
|
+
text: `Execution timeout: ${error.message}`,
|
|
308
|
+
},
|
|
309
|
+
],
|
|
310
|
+
isError: true,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
// Handle memory errors
|
|
314
|
+
if (error instanceof Error && error.name === 'MemoryError') {
|
|
315
|
+
return {
|
|
316
|
+
content: [
|
|
317
|
+
{
|
|
318
|
+
type: 'text',
|
|
319
|
+
text: `Memory limit exceeded: ${error.message}`,
|
|
320
|
+
},
|
|
321
|
+
],
|
|
322
|
+
isError: true,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
// Handle other errors
|
|
326
|
+
if (error instanceof Error) {
|
|
327
|
+
return {
|
|
328
|
+
content: [
|
|
329
|
+
{
|
|
330
|
+
type: 'text',
|
|
331
|
+
text: `Error executing multi-query: ${error.message}`,
|
|
332
|
+
},
|
|
333
|
+
],
|
|
334
|
+
isError: true,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
return {
|
|
338
|
+
content: [
|
|
339
|
+
{
|
|
340
|
+
type: 'text',
|
|
341
|
+
text: `Unknown error: ${String(error)}`,
|
|
342
|
+
},
|
|
343
|
+
],
|
|
344
|
+
isError: true,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
//# sourceMappingURL=rlm-multi-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rlm-multi-query.js","sourceRoot":"","sources":["../../src/tools/rlm-multi-query.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* rlm_query tool: Execute JavaScript code on a single document.
|
|
3
|
+
* Feature #2: RLM Query Tool
|
|
4
|
+
*
|
|
5
|
+
* Enables Claude to load documents as environment variables and execute
|
|
6
|
+
* filter/transform code before LLM reasoning.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import type { ToolContext, ToolResult } from '../types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Input schema for rlm_query tool.
|
|
12
|
+
*/
|
|
13
|
+
export declare const RlmQueryInputSchema: z.ZodObject<{
|
|
14
|
+
path: z.ZodString;
|
|
15
|
+
code: z.ZodString;
|
|
16
|
+
sub_query: z.ZodOptional<z.ZodString>;
|
|
17
|
+
timeout: z.ZodDefault<z.ZodNumber>;
|
|
18
|
+
max_depth: z.ZodDefault<z.ZodNumber>;
|
|
19
|
+
}, z.core.$strip>;
|
|
20
|
+
export type RlmQueryInput = z.infer<typeof RlmQueryInputSchema>;
|
|
21
|
+
/**
|
|
22
|
+
* Output interface for rlm_query tool.
|
|
23
|
+
*/
|
|
24
|
+
export interface RlmQueryOutput {
|
|
25
|
+
result: unknown;
|
|
26
|
+
sub_results?: unknown[];
|
|
27
|
+
execution_time_ms: number;
|
|
28
|
+
tokens_saved?: number;
|
|
29
|
+
metadata: {
|
|
30
|
+
path: string;
|
|
31
|
+
doc_size: number;
|
|
32
|
+
result_size: number;
|
|
33
|
+
depth: number;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Handle rlm_query tool request.
|
|
38
|
+
*
|
|
39
|
+
* @param input - Tool input
|
|
40
|
+
* @param context - Tool context
|
|
41
|
+
* @returns Tool result
|
|
42
|
+
*/
|
|
43
|
+
export declare function handleRlmQuery(input: RlmQueryInput, context: ToolContext): Promise<ToolResult>;
|
|
44
|
+
//# sourceMappingURL=rlm-query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rlm-query.d.ts","sourceRoot":"","sources":["../../src/tools/rlm-query.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAQ3D;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;iBAY9B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAqBD;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,aAAa,EACpB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC,CA6LrB"}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* rlm_query tool: Execute JavaScript code on a single document.
|
|
3
|
+
* Feature #2: RLM Query Tool
|
|
4
|
+
*
|
|
5
|
+
* Enables Claude to load documents as environment variables and execute
|
|
6
|
+
* filter/transform code before LLM reasoning.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import { readFile, stat } from 'fs/promises';
|
|
10
|
+
import { existsSync } from 'fs';
|
|
11
|
+
import { dirname } from 'path';
|
|
12
|
+
import { validatePath } from '../utils/paths.js';
|
|
13
|
+
import { notFound } from '../utils/errors.js';
|
|
14
|
+
import { createEnvironment } from '../rlm/sandbox.js';
|
|
15
|
+
import { validateCode } from '../rlm/security.js';
|
|
16
|
+
import { processSubCalls } from '../rlm/recursion.js';
|
|
17
|
+
/**
|
|
18
|
+
* Input schema for rlm_query tool.
|
|
19
|
+
*/
|
|
20
|
+
export const RlmQueryInputSchema = z.object({
|
|
21
|
+
path: z.string().min(1).describe('Document path relative to repo root'),
|
|
22
|
+
code: z.string().min(1).describe('JavaScript code to execute (doc variable available)'),
|
|
23
|
+
sub_query: z.string().optional().describe('Prompt for recursive LLM processing of results'),
|
|
24
|
+
timeout: z.number().int().min(100).max(30000).default(5000).describe('Execution timeout in ms'),
|
|
25
|
+
max_depth: z
|
|
26
|
+
.number()
|
|
27
|
+
.int()
|
|
28
|
+
.min(1)
|
|
29
|
+
.max(3)
|
|
30
|
+
.default(1)
|
|
31
|
+
.describe('Maximum recursion depth for sub_query'),
|
|
32
|
+
});
|
|
33
|
+
/**
|
|
34
|
+
* Get repository root from config.
|
|
35
|
+
*/
|
|
36
|
+
function getRepoRoot(config) {
|
|
37
|
+
if (config.docsPaths && config.docsPaths.length > 0) {
|
|
38
|
+
return config.docsPaths[0];
|
|
39
|
+
}
|
|
40
|
+
return dirname(config.plansPath);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Estimate tokens saved by filtering.
|
|
44
|
+
* Rough approximation: 4 characters per token.
|
|
45
|
+
*/
|
|
46
|
+
function estimateTokensSaved(docSize, resultSize) {
|
|
47
|
+
const charsSaved = docSize - resultSize;
|
|
48
|
+
return Math.max(0, Math.floor(charsSaved / 4));
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Handle rlm_query tool request.
|
|
52
|
+
*
|
|
53
|
+
* @param input - Tool input
|
|
54
|
+
* @param context - Tool context
|
|
55
|
+
* @returns Tool result
|
|
56
|
+
*/
|
|
57
|
+
export async function handleRlmQuery(input, context) {
|
|
58
|
+
const { path, code, sub_query, timeout = 5000 } = input;
|
|
59
|
+
const { config } = context;
|
|
60
|
+
try {
|
|
61
|
+
// Get repo root
|
|
62
|
+
const repoRoot = getRepoRoot(config);
|
|
63
|
+
// Validate path BEFORE loading (per gotchas)
|
|
64
|
+
const validated = validatePath(path, repoRoot);
|
|
65
|
+
// Check if file exists
|
|
66
|
+
if (!existsSync(validated.absolute)) {
|
|
67
|
+
throw notFound(path);
|
|
68
|
+
}
|
|
69
|
+
// Read file stats and content
|
|
70
|
+
const stats = await stat(validated.absolute);
|
|
71
|
+
const content = await readFile(validated.absolute, 'utf-8');
|
|
72
|
+
const docSize = Buffer.byteLength(content, 'utf-8');
|
|
73
|
+
// Create DocVariable
|
|
74
|
+
const docVar = {
|
|
75
|
+
content,
|
|
76
|
+
metadata: {
|
|
77
|
+
path: validated.relative,
|
|
78
|
+
size: docSize,
|
|
79
|
+
lines: content === '' ? 0 : content.split('\n').length,
|
|
80
|
+
modified: stats.mtime.toISOString(),
|
|
81
|
+
},
|
|
82
|
+
path: validated.relative,
|
|
83
|
+
};
|
|
84
|
+
// Validate code before execution (per TDD requirement)
|
|
85
|
+
validateCode(code);
|
|
86
|
+
// Create sandbox environment
|
|
87
|
+
const env = await createEnvironment(docVar, { timeout });
|
|
88
|
+
try {
|
|
89
|
+
// Execute code
|
|
90
|
+
const execResult = await env.execute(code);
|
|
91
|
+
// Calculate result size (serialize to estimate)
|
|
92
|
+
const resultJson = JSON.stringify(execResult.result);
|
|
93
|
+
const resultSize = Buffer.byteLength(resultJson, 'utf-8');
|
|
94
|
+
// Estimate tokens saved
|
|
95
|
+
const tokensSaved = estimateTokensSaved(docSize, resultSize);
|
|
96
|
+
// Build output
|
|
97
|
+
const output = {
|
|
98
|
+
result: execResult.result,
|
|
99
|
+
execution_time_ms: Math.max(1, Math.round(execResult.executionTimeMs)), // Ensure at least 1ms
|
|
100
|
+
tokens_saved: tokensSaved,
|
|
101
|
+
metadata: {
|
|
102
|
+
path: validated.relative,
|
|
103
|
+
doc_size: docSize,
|
|
104
|
+
result_size: resultSize,
|
|
105
|
+
depth: 0, // Current depth (updated if sub_query is processed)
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
// Handle sub_query (Agent 3 implementation)
|
|
109
|
+
if (sub_query) {
|
|
110
|
+
try {
|
|
111
|
+
// Get sampling client from context (if available)
|
|
112
|
+
// For now, this will be undefined in real server, but tests can provide mock client
|
|
113
|
+
const samplingClient = context
|
|
114
|
+
.samplingClient;
|
|
115
|
+
// Normalize items to array
|
|
116
|
+
const items = Array.isArray(execResult.result) ? execResult.result : [execResult.result];
|
|
117
|
+
// Process sub-calls
|
|
118
|
+
const subResults = await processSubCalls(items, sub_query, {
|
|
119
|
+
maxDepth: input.max_depth ?? 1,
|
|
120
|
+
concurrency: 5,
|
|
121
|
+
timeout: timeout,
|
|
122
|
+
samplingClient,
|
|
123
|
+
});
|
|
124
|
+
// Map results to output format
|
|
125
|
+
output.sub_results = subResults.map((r) => (r.success ? r.result : { error: r.error }));
|
|
126
|
+
output.metadata.depth = 1; // Update depth after processing sub-calls
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
// If sub-call processing fails, include error in sub_results
|
|
130
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
131
|
+
output.sub_results = [
|
|
132
|
+
{
|
|
133
|
+
error: `Sub-call processing failed: ${errorMessage}`,
|
|
134
|
+
},
|
|
135
|
+
];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
content: [
|
|
140
|
+
{
|
|
141
|
+
type: 'text',
|
|
142
|
+
text: JSON.stringify(output, null, 2),
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
// Always dispose environment
|
|
149
|
+
env.dispose();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
// Handle DocumentError
|
|
154
|
+
if (error instanceof Error && 'code' in error) {
|
|
155
|
+
const docError = error;
|
|
156
|
+
return {
|
|
157
|
+
content: [
|
|
158
|
+
{
|
|
159
|
+
type: 'text',
|
|
160
|
+
text: `Error: ${docError.message}${docError.path ? ` (path: ${docError.path})` : ''}`,
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
isError: true,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
// Handle security errors
|
|
167
|
+
if (error instanceof Error && error.name === 'SecurityError') {
|
|
168
|
+
return {
|
|
169
|
+
content: [
|
|
170
|
+
{
|
|
171
|
+
type: 'text',
|
|
172
|
+
text: `Security error: ${error.message}`,
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
isError: true,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
// Handle timeout errors
|
|
179
|
+
if (error instanceof Error && error.name === 'TimeoutError') {
|
|
180
|
+
return {
|
|
181
|
+
content: [
|
|
182
|
+
{
|
|
183
|
+
type: 'text',
|
|
184
|
+
text: `Execution timeout: ${error.message}`,
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
isError: true,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
// Handle memory errors
|
|
191
|
+
if (error instanceof Error && error.name === 'MemoryError') {
|
|
192
|
+
return {
|
|
193
|
+
content: [
|
|
194
|
+
{
|
|
195
|
+
type: 'text',
|
|
196
|
+
text: `Memory limit exceeded: ${error.message}`,
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
isError: true,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
// Handle file system errors
|
|
203
|
+
if (error instanceof Error) {
|
|
204
|
+
if ('code' in error && error.code === 'ENOENT') {
|
|
205
|
+
throw notFound(path);
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
content: [
|
|
209
|
+
{
|
|
210
|
+
type: 'text',
|
|
211
|
+
text: `Error executing query: ${error.message}`,
|
|
212
|
+
},
|
|
213
|
+
],
|
|
214
|
+
isError: true,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
content: [
|
|
219
|
+
{
|
|
220
|
+
type: 'text',
|
|
221
|
+
text: `Unknown error: ${String(error)}`,
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
isError: true,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=rlm-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rlm-query.js","sourceRoot":"","sources":["../../src/tools/rlm-query.ts"],"names":[],"mappings":"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"}
|