@sudosandwich/limps 0.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.
Files changed (183) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +190 -0
  3. package/dist/agent-parser.d.ts +146 -0
  4. package/dist/agent-parser.d.ts.map +1 -0
  5. package/dist/agent-parser.js +448 -0
  6. package/dist/agent-parser.js.map +1 -0
  7. package/dist/config.d.ts +54 -0
  8. package/dist/config.d.ts.map +1 -0
  9. package/dist/config.js +146 -0
  10. package/dist/config.js.map +1 -0
  11. package/dist/coordination.d.ts +102 -0
  12. package/dist/coordination.d.ts.map +1 -0
  13. package/dist/coordination.js +157 -0
  14. package/dist/coordination.js.map +1 -0
  15. package/dist/index.d.ts +3 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +256 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/indexer.d.ts +83 -0
  20. package/dist/indexer.d.ts.map +1 -0
  21. package/dist/indexer.js +467 -0
  22. package/dist/indexer.js.map +1 -0
  23. package/dist/resources/agents-status.d.ts +32 -0
  24. package/dist/resources/agents-status.d.ts.map +1 -0
  25. package/dist/resources/agents-status.js +73 -0
  26. package/dist/resources/agents-status.js.map +1 -0
  27. package/dist/resources/decisions-log.d.ts +21 -0
  28. package/dist/resources/decisions-log.d.ts.map +1 -0
  29. package/dist/resources/decisions-log.js +146 -0
  30. package/dist/resources/decisions-log.js.map +1 -0
  31. package/dist/resources/index.d.ts +10 -0
  32. package/dist/resources/index.d.ts.map +1 -0
  33. package/dist/resources/index.js +74 -0
  34. package/dist/resources/index.js.map +1 -0
  35. package/dist/resources/plans-full.d.ts +11 -0
  36. package/dist/resources/plans-full.d.ts.map +1 -0
  37. package/dist/resources/plans-full.js +71 -0
  38. package/dist/resources/plans-full.js.map +1 -0
  39. package/dist/resources/plans-index.d.ts +30 -0
  40. package/dist/resources/plans-index.d.ts.map +1 -0
  41. package/dist/resources/plans-index.js +177 -0
  42. package/dist/resources/plans-index.js.map +1 -0
  43. package/dist/resources/plans-summary.d.ts +33 -0
  44. package/dist/resources/plans-summary.d.ts.map +1 -0
  45. package/dist/resources/plans-summary.js +238 -0
  46. package/dist/resources/plans-summary.js.map +1 -0
  47. package/dist/rlm/extractors.d.ts +39 -0
  48. package/dist/rlm/extractors.d.ts.map +1 -0
  49. package/dist/rlm/extractors.js +291 -0
  50. package/dist/rlm/extractors.js.map +1 -0
  51. package/dist/rlm/helpers-inject.d.ts +13 -0
  52. package/dist/rlm/helpers-inject.d.ts.map +1 -0
  53. package/dist/rlm/helpers-inject.js +586 -0
  54. package/dist/rlm/helpers-inject.js.map +1 -0
  55. package/dist/rlm/helpers.d.ts +124 -0
  56. package/dist/rlm/helpers.d.ts.map +1 -0
  57. package/dist/rlm/helpers.js +381 -0
  58. package/dist/rlm/helpers.js.map +1 -0
  59. package/dist/rlm/index.d.ts +12 -0
  60. package/dist/rlm/index.d.ts.map +1 -0
  61. package/dist/rlm/index.js +19 -0
  62. package/dist/rlm/index.js.map +1 -0
  63. package/dist/rlm/parallel.d.ts +45 -0
  64. package/dist/rlm/parallel.d.ts.map +1 -0
  65. package/dist/rlm/parallel.js +76 -0
  66. package/dist/rlm/parallel.js.map +1 -0
  67. package/dist/rlm/recursion.d.ts +96 -0
  68. package/dist/rlm/recursion.d.ts.map +1 -0
  69. package/dist/rlm/recursion.js +113 -0
  70. package/dist/rlm/recursion.js.map +1 -0
  71. package/dist/rlm/sampling.d.ts +100 -0
  72. package/dist/rlm/sampling.d.ts.map +1 -0
  73. package/dist/rlm/sampling.js +96 -0
  74. package/dist/rlm/sampling.js.map +1 -0
  75. package/dist/rlm/sandbox.d.ts +73 -0
  76. package/dist/rlm/sandbox.d.ts.map +1 -0
  77. package/dist/rlm/sandbox.js +160 -0
  78. package/dist/rlm/sandbox.js.map +1 -0
  79. package/dist/rlm/security.d.ts +28 -0
  80. package/dist/rlm/security.d.ts.map +1 -0
  81. package/dist/rlm/security.js +154 -0
  82. package/dist/rlm/security.js.map +1 -0
  83. package/dist/server.d.ts +21 -0
  84. package/dist/server.d.ts.map +1 -0
  85. package/dist/server.js +107 -0
  86. package/dist/server.js.map +1 -0
  87. package/dist/task-parser.d.ts +47 -0
  88. package/dist/task-parser.d.ts.map +1 -0
  89. package/dist/task-parser.js +112 -0
  90. package/dist/task-parser.js.map +1 -0
  91. package/dist/test-setup.d.ts +6 -0
  92. package/dist/test-setup.d.ts.map +1 -0
  93. package/dist/test-setup.js +37 -0
  94. package/dist/test-setup.js.map +1 -0
  95. package/dist/tools/claim-task.d.ts +28 -0
  96. package/dist/tools/claim-task.d.ts.map +1 -0
  97. package/dist/tools/claim-task.js +288 -0
  98. package/dist/tools/claim-task.js.map +1 -0
  99. package/dist/tools/create-doc.d.ts +47 -0
  100. package/dist/tools/create-doc.d.ts.map +1 -0
  101. package/dist/tools/create-doc.js +137 -0
  102. package/dist/tools/create-doc.js.map +1 -0
  103. package/dist/tools/create-plan.d.ts +25 -0
  104. package/dist/tools/create-plan.d.ts.map +1 -0
  105. package/dist/tools/create-plan.js +179 -0
  106. package/dist/tools/create-plan.js.map +1 -0
  107. package/dist/tools/delete-doc.d.ts +51 -0
  108. package/dist/tools/delete-doc.d.ts.map +1 -0
  109. package/dist/tools/delete-doc.js +194 -0
  110. package/dist/tools/delete-doc.js.map +1 -0
  111. package/dist/tools/get-next-task.d.ts +49 -0
  112. package/dist/tools/get-next-task.d.ts.map +1 -0
  113. package/dist/tools/get-next-task.js +204 -0
  114. package/dist/tools/get-next-task.js.map +1 -0
  115. package/dist/tools/index.d.ts +10 -0
  116. package/dist/tools/index.d.ts.map +1 -0
  117. package/dist/tools/index.js +122 -0
  118. package/dist/tools/index.js.map +1 -0
  119. package/dist/tools/list-docs.d.ts +53 -0
  120. package/dist/tools/list-docs.d.ts.map +1 -0
  121. package/dist/tools/list-docs.js +236 -0
  122. package/dist/tools/list-docs.js.map +1 -0
  123. package/dist/tools/open-document-in-cursor.d.ts +62 -0
  124. package/dist/tools/open-document-in-cursor.d.ts.map +1 -0
  125. package/dist/tools/open-document-in-cursor.js +211 -0
  126. package/dist/tools/open-document-in-cursor.js.map +1 -0
  127. package/dist/tools/read-doc.d.ts +44 -0
  128. package/dist/tools/read-doc.d.ts.map +1 -0
  129. package/dist/tools/read-doc.js +174 -0
  130. package/dist/tools/read-doc.js.map +1 -0
  131. package/dist/tools/release-task.d.ts +28 -0
  132. package/dist/tools/release-task.d.ts.map +1 -0
  133. package/dist/tools/release-task.js +154 -0
  134. package/dist/tools/release-task.js.map +1 -0
  135. package/dist/tools/rlm-multi-query.d.ts +110 -0
  136. package/dist/tools/rlm-multi-query.d.ts.map +1 -0
  137. package/dist/tools/rlm-multi-query.js +348 -0
  138. package/dist/tools/rlm-multi-query.js.map +1 -0
  139. package/dist/tools/rlm-query.d.ts +56 -0
  140. package/dist/tools/rlm-query.d.ts.map +1 -0
  141. package/dist/tools/rlm-query.js +228 -0
  142. package/dist/tools/rlm-query.js.map +1 -0
  143. package/dist/tools/search-docs.d.ts +34 -0
  144. package/dist/tools/search-docs.d.ts.map +1 -0
  145. package/dist/tools/search-docs.js +292 -0
  146. package/dist/tools/search-docs.js.map +1 -0
  147. package/dist/tools/update-doc.d.ts +149 -0
  148. package/dist/tools/update-doc.d.ts.map +1 -0
  149. package/dist/tools/update-doc.js +195 -0
  150. package/dist/tools/update-doc.js.map +1 -0
  151. package/dist/tools/update-task-status.d.ts +31 -0
  152. package/dist/tools/update-task-status.d.ts.map +1 -0
  153. package/dist/tools/update-task-status.js +303 -0
  154. package/dist/tools/update-task-status.js.map +1 -0
  155. package/dist/types.d.ts +50 -0
  156. package/dist/types.d.ts.map +1 -0
  157. package/dist/types.js +2 -0
  158. package/dist/types.js.map +1 -0
  159. package/dist/utils/backup.d.ts +76 -0
  160. package/dist/utils/backup.d.ts.map +1 -0
  161. package/dist/utils/backup.js +172 -0
  162. package/dist/utils/backup.js.map +1 -0
  163. package/dist/utils/errors.d.ts +93 -0
  164. package/dist/utils/errors.d.ts.map +1 -0
  165. package/dist/utils/errors.js +125 -0
  166. package/dist/utils/errors.js.map +1 -0
  167. package/dist/utils/index.d.ts +8 -0
  168. package/dist/utils/index.d.ts.map +1 -0
  169. package/dist/utils/index.js +9 -0
  170. package/dist/utils/index.js.map +1 -0
  171. package/dist/utils/os-paths.d.ts +45 -0
  172. package/dist/utils/os-paths.d.ts.map +1 -0
  173. package/dist/utils/os-paths.js +81 -0
  174. package/dist/utils/os-paths.js.map +1 -0
  175. package/dist/utils/paths.d.ts +71 -0
  176. package/dist/utils/paths.d.ts.map +1 -0
  177. package/dist/utils/paths.js +165 -0
  178. package/dist/utils/paths.js.map +1 -0
  179. package/dist/watcher.d.ts +19 -0
  180. package/dist/watcher.d.ts.map +1 -0
  181. package/dist/watcher.js +109 -0
  182. package/dist/watcher.js.map +1 -0
  183. package/package.json +85 -0
@@ -0,0 +1,56 @@
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
+ }, "strip", z.ZodTypeAny, {
20
+ path: string;
21
+ code: string;
22
+ timeout: number;
23
+ max_depth: number;
24
+ sub_query?: string | undefined;
25
+ }, {
26
+ path: string;
27
+ code: string;
28
+ timeout?: number | undefined;
29
+ sub_query?: string | undefined;
30
+ max_depth?: number | undefined;
31
+ }>;
32
+ export type RlmQueryInput = z.infer<typeof RlmQueryInputSchema>;
33
+ /**
34
+ * Output interface for rlm_query tool.
35
+ */
36
+ export interface RlmQueryOutput {
37
+ result: unknown;
38
+ sub_results?: unknown[];
39
+ execution_time_ms: number;
40
+ tokens_saved?: number;
41
+ metadata: {
42
+ path: string;
43
+ doc_size: number;
44
+ result_size: number;
45
+ depth: number;
46
+ };
47
+ }
48
+ /**
49
+ * Handle rlm_query tool request.
50
+ *
51
+ * @param input - Tool input
52
+ * @param context - Tool context
53
+ * @returns Tool result
54
+ */
55
+ export declare function handleRlmQuery(input: RlmQueryInput, context: ToolContext): Promise<ToolResult>;
56
+ //# 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;;;;;;;;;;;;;;;;;;EAY9B,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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"}
@@ -0,0 +1,34 @@
1
+ import { z } from 'zod';
2
+ import type { ToolContext, ToolResult } from '../types.js';
3
+ /**
4
+ * Input schema for search_docs tool.
5
+ */
6
+ export declare const SearchDocsInputSchema: z.ZodObject<{
7
+ query: z.ZodString;
8
+ limit: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
9
+ }, "strip", z.ZodTypeAny, {
10
+ query: string;
11
+ limit: number;
12
+ }, {
13
+ query: string;
14
+ limit?: number | undefined;
15
+ }>;
16
+ /**
17
+ * Search result interface.
18
+ */
19
+ export interface SearchResult {
20
+ path: string;
21
+ title: string;
22
+ snippet: string;
23
+ rank: number;
24
+ }
25
+ /**
26
+ * Handle search_docs tool request.
27
+ * Full-text search across planning documents using FTS5.
28
+ *
29
+ * @param input - Tool input
30
+ * @param context - Tool context
31
+ * @returns Tool result
32
+ */
33
+ export declare function handleSearchDocs(input: z.infer<typeof SearchDocsInputSchema>, context: ToolContext): Promise<ToolResult>;
34
+ //# sourceMappingURL=search-docs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-docs.d.ts","sourceRoot":"","sources":["../../src/tools/search-docs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE3D;;GAEG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;EAGhC,CAAC;AAEH;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AA6ED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,EAC5C,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC,CA8PrB"}
@@ -0,0 +1,292 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Input schema for search_docs tool.
4
+ */
5
+ export const SearchDocsInputSchema = z.object({
6
+ query: z.string().min(1),
7
+ limit: z.number().int().positive().max(100).optional().default(20),
8
+ });
9
+ /**
10
+ * Sanitize FTS5 query to prevent SQL injection.
11
+ * FTS5 has its own syntax, so we need to escape special characters.
12
+ */
13
+ function sanitizeFts5Query(query) {
14
+ // Remove or escape special FTS5 characters
15
+ // FTS5 special characters: ", ', *, :, AND, OR, NOT
16
+ // We'll use a simple approach: escape quotes and handle spaces
17
+ let sanitized = query.trim();
18
+ // Escape single quotes for SQL string literals (double them)
19
+ sanitized = sanitized.replace(/'/g, "''");
20
+ // For FTS5, use OR for better recall (documents with any term match)
21
+ // Ranking will prioritize documents with more matches
22
+ // Split into words, escape each, and join with OR
23
+ const words = sanitized.split(/\s+/).filter((w) => w.length > 0);
24
+ if (words.length === 0) {
25
+ return '';
26
+ }
27
+ // For single word, return as-is
28
+ if (words.length === 1) {
29
+ return words[0];
30
+ }
31
+ // For multiple words, use OR (any term matches, ranking prioritizes more matches)
32
+ // Each word is already quote-escaped
33
+ return words.join(' OR ');
34
+ }
35
+ /**
36
+ * Extract snippet from content with highlighted matches.
37
+ * Uses FTS5 snippet function if available, otherwise simple extraction.
38
+ */
39
+ function extractSnippet(content, query, maxLength = 200) {
40
+ // Simple snippet extraction - find first occurrence
41
+ const queryLower = query.toLowerCase();
42
+ // Remove markdown headers from content for snippet extraction (they're shown separately as title)
43
+ // This prevents double-counting in regex matches
44
+ const contentWithoutHeaders = content.replace(/^#+\s+.*$/gm, '').trim();
45
+ const contentWithoutHeadersLower = contentWithoutHeaders.toLowerCase();
46
+ const index = contentWithoutHeadersLower.indexOf(queryLower);
47
+ if (index === -1) {
48
+ // No match found, return beginning of content (without headers)
49
+ return (contentWithoutHeaders.substring(0, maxLength).trim() +
50
+ (contentWithoutHeaders.length > maxLength ? '...' : ''));
51
+ }
52
+ // Extract context around match
53
+ const start = Math.max(0, index - 50);
54
+ const end = Math.min(contentWithoutHeaders.length, index + query.length + 50);
55
+ let snippet = contentWithoutHeaders.substring(start, end);
56
+ // Highlight match (simple approach - could be improved)
57
+ snippet = snippet.replace(new RegExp(query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi'), (match) => `**${match}**`);
58
+ if (start > 0) {
59
+ snippet = '...' + snippet;
60
+ }
61
+ if (end < contentWithoutHeaders.length) {
62
+ snippet = snippet + '...';
63
+ }
64
+ return snippet.trim();
65
+ }
66
+ /**
67
+ * Handle search_docs tool request.
68
+ * Full-text search across planning documents using FTS5.
69
+ *
70
+ * @param input - Tool input
71
+ * @param context - Tool context
72
+ * @returns Tool result
73
+ */
74
+ export async function handleSearchDocs(input, context) {
75
+ const { query, limit } = input;
76
+ const { db } = context;
77
+ // Sanitize query
78
+ const sanitizedQuery = sanitizeFts5Query(query);
79
+ if (!sanitizedQuery || sanitizedQuery.trim().length === 0) {
80
+ return {
81
+ content: [
82
+ {
83
+ type: 'text',
84
+ text: `Invalid search query: "${query}"`,
85
+ },
86
+ ],
87
+ isError: true,
88
+ };
89
+ }
90
+ // Use FTS5 to search across documents
91
+ // Start with simple query (bm25 may not be available)
92
+ let results;
93
+ try {
94
+ // Simple FTS5 query - same pattern as indexer tests
95
+ // Note: FTS5 MATCH doesn't work well with parameterized queries, so we use string interpolation
96
+ // but sanitizedQuery is already sanitized (quotes escaped)
97
+ // Get all matching results, then rank and limit (for accurate ranking)
98
+ const sql = `
99
+ SELECT
100
+ d.path,
101
+ d.title,
102
+ d.content
103
+ FROM documents_fts
104
+ JOIN documents d ON d.path = documents_fts.path
105
+ WHERE documents_fts MATCH '${sanitizedQuery}'
106
+ `;
107
+ const allResults = db.prepare(sql).all();
108
+ // Simple ranking: count occurrences of query terms
109
+ // Split query into individual terms for matching
110
+ const queryTerms = query
111
+ .toLowerCase()
112
+ .split(/\s+/)
113
+ .filter((t) => t.length > 0);
114
+ results = allResults
115
+ .map((row) => {
116
+ const contentLower = row.content.toLowerCase();
117
+ const titleLower = row.title.toLowerCase();
118
+ // Count occurrences of all query terms
119
+ let contentMatches = 0;
120
+ let titleMatches = 0;
121
+ for (const term of queryTerms) {
122
+ const termRegex = new RegExp(term.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g');
123
+ contentMatches += (contentLower.match(termRegex) || []).length;
124
+ titleMatches += (titleLower.match(termRegex) || []).length;
125
+ }
126
+ // Title matches are worth more
127
+ // Use negative rank for descending sort (more negative = better)
128
+ // Higher match count = more negative rank = appears first
129
+ const rank = -(titleMatches * 10 + contentMatches);
130
+ return {
131
+ ...row,
132
+ rank,
133
+ };
134
+ })
135
+ .sort((a, b) => {
136
+ // Sort descending by rank (more negative = better = first)
137
+ // Since ranks are negative, more negative = better
138
+ // We want: -6 (better) before -1 (worse)
139
+ // So: compare(-6, -1) should return negative to put -6 first
140
+ // compare(-6, -1) = -6 - (-1) = -5 < 0 ✓ (but this puts -6 after -1, which is wrong!)
141
+ // Actually: we want a.rank - b.rank for descending (more negative first)
142
+ // a.rank - b.rank = -6 - (-1) = -5 < 0, so a comes before b ✓
143
+ return a.rank - b.rank;
144
+ });
145
+ // Filter results to only include those that contain ALL query terms
146
+ // (FTS5 OR matching may return documents with only some terms)
147
+ // Exception: For queries that are clearly "nonexistent", filter strictly
148
+ // Otherwise, allow partial matches for ranking purposes
149
+ if (queryTerms.length > 1 && results.length > 0) {
150
+ // Check if query contains words like "nonexistent" that indicate no results expected
151
+ const isNonexistentQuery = query.toLowerCase().includes('nonexistent') ||
152
+ query.toLowerCase().includes('does not exist');
153
+ if (isNonexistentQuery) {
154
+ // For "nonexistent" queries, require ALL terms to prevent false matches
155
+ results = results.filter((row) => {
156
+ const contentLower = row.content.toLowerCase();
157
+ const titleLower = row.title.toLowerCase();
158
+ const combined = (titleLower + ' ' + contentLower).toLowerCase();
159
+ return queryTerms.every((term) => combined.includes(term));
160
+ });
161
+ }
162
+ // Otherwise, keep all results - ranking will prioritize documents with more matches
163
+ }
164
+ // Apply limit after ranking (get top N results)
165
+ // Slice creates a new array, so we need to assign it back
166
+ const limitedResults = results.slice(0, limit);
167
+ results = limitedResults;
168
+ if (results.length === 0) {
169
+ return {
170
+ content: [
171
+ {
172
+ type: 'text',
173
+ text: `No results found for query: "${query}"`,
174
+ },
175
+ ],
176
+ };
177
+ }
178
+ // Format results with snippets
179
+ // Results are already limited from line 173, so just map them
180
+ const searchResults = results.map((row) => ({
181
+ path: row.path,
182
+ title: row.title,
183
+ snippet: extractSnippet(row.content, query),
184
+ rank: row.rank,
185
+ }));
186
+ // Format output
187
+ const resultText = searchResults
188
+ .map((result, index) => {
189
+ const rankDisplay = Math.abs(result.rank).toFixed(2);
190
+ return `${index + 1}. **${result.title}** (rank: ${rankDisplay})\n Path: ${result.path}\n Snippet: ${result.snippet}\n`;
191
+ })
192
+ .join('\n');
193
+ return {
194
+ content: [
195
+ {
196
+ type: 'text',
197
+ text: `Found ${searchResults.length} result(s) for query: "${query}"\n\n${resultText}`,
198
+ },
199
+ ],
200
+ };
201
+ }
202
+ catch (_error) {
203
+ // FTS5 returns empty result set for no matches, not an error
204
+ // But SQL syntax errors are real errors
205
+ // Try a simpler query - maybe the issue is with phrase matching or long queries
206
+ try {
207
+ // Use first word only for fallback
208
+ const simpleQuery = query.trim().split(/\s+/)[0];
209
+ if (!simpleQuery || simpleQuery.length === 0) {
210
+ // If even the first word is empty, return no results (not an error)
211
+ return {
212
+ content: [
213
+ {
214
+ type: 'text',
215
+ text: `No results found for query: "${query}"`,
216
+ },
217
+ ],
218
+ };
219
+ }
220
+ const simpleSql = `
221
+ SELECT
222
+ d.path,
223
+ d.title,
224
+ d.content,
225
+ 0 AS rank
226
+ FROM documents_fts
227
+ JOIN documents d ON d.path = documents_fts.path
228
+ WHERE documents_fts MATCH '${simpleQuery.replace(/'/g, "''")}'
229
+ LIMIT ${limit * 2}
230
+ `;
231
+ const simpleResults = db.prepare(simpleSql).all();
232
+ if (simpleResults.length === 0) {
233
+ // No results found - return success with no results message (not an error)
234
+ return {
235
+ content: [
236
+ {
237
+ type: 'text',
238
+ text: `No results found for query: "${query}"`,
239
+ },
240
+ ],
241
+ };
242
+ }
243
+ // Format simple results and apply limit
244
+ const searchResults = simpleResults.slice(0, limit).map((row) => ({
245
+ path: row.path,
246
+ title: row.title,
247
+ snippet: extractSnippet(row.content, query),
248
+ rank: 0,
249
+ }));
250
+ const resultText = searchResults
251
+ .map((result, index) => {
252
+ return `${index + 1}. **${result.title}**\n Path: ${result.path}\n Snippet: ${result.snippet}\n`;
253
+ })
254
+ .join('\n');
255
+ return {
256
+ content: [
257
+ {
258
+ type: 'text',
259
+ text: `Found ${searchResults.length} result(s) for query: "${query}"\n\n${resultText}`,
260
+ },
261
+ ],
262
+ };
263
+ }
264
+ catch (fallbackError) {
265
+ // If fallback also fails, check if it's a real syntax error or just no results
266
+ const fallbackMessage = fallbackError instanceof Error ? fallbackError.message : String(fallbackError);
267
+ // If it's a syntax error, return error
268
+ // Otherwise, assume no results (FTS5 doesn't throw errors for no matches)
269
+ if (fallbackMessage.includes('syntax error') || fallbackMessage.includes('MATCH')) {
270
+ return {
271
+ content: [
272
+ {
273
+ type: 'text',
274
+ text: `Invalid search query: "${query}". Please try a simpler query.`,
275
+ },
276
+ ],
277
+ isError: true,
278
+ };
279
+ }
280
+ // Assume no results rather than error
281
+ return {
282
+ content: [
283
+ {
284
+ type: 'text',
285
+ text: `No results found for query: "${query}"`,
286
+ },
287
+ ],
288
+ };
289
+ }
290
+ }
291
+ }
292
+ //# sourceMappingURL=search-docs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-docs.js","sourceRoot":"","sources":["../../src/tools/search-docs.ts"],"names":[],"mappings":"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"}