@ridit/lens 0.3.7 → 0.3.9

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 (96) hide show
  1. package/dist/index.mjs +105368 -274002
  2. package/package.json +13 -19
  3. package/src/colors.ts +15 -15
  4. package/src/commands/chat.tsx +32 -23
  5. package/src/commands/provider.tsx +11 -238
  6. package/src/commands/repo.tsx +66 -120
  7. package/src/commands/timeline.tsx +11 -22
  8. package/src/components/ChatView.tsx +238 -0
  9. package/src/components/Message.tsx +46 -0
  10. package/src/components/ToolCall.tsx +67 -0
  11. package/src/components/chat/ChatView.tsx +550 -0
  12. package/src/components/chat/Message.tsx +152 -0
  13. package/src/components/chat/StatusBar.tsx +214 -0
  14. package/src/components/chat/TextArea.tsx +173 -176
  15. package/src/components/provider/ApiKeyStep.tsx +207 -199
  16. package/src/components/provider/ModelStep.tsx +90 -88
  17. package/src/components/provider/ProviderSetup.tsx +331 -0
  18. package/src/components/provider/ProviderTypeStep.tsx +53 -61
  19. package/src/components/repo/StepRow.tsx +68 -69
  20. package/src/components/timeline/TimelineView.tsx +840 -0
  21. package/src/components/toolcall-utils.ts +103 -0
  22. package/src/components/watch/RunView.tsx +497 -0
  23. package/src/hooks/useChatInput.ts +49 -0
  24. package/src/hooks/useCommandHandler.ts +117 -0
  25. package/src/index.tsx +386 -139
  26. package/src/utils/git.ts +149 -155
  27. package/src/utils/repo.ts +62 -69
  28. package/src/utils/thinking.tsx +64 -0
  29. package/src/utils/watch.ts +165 -307
  30. package/tests/message.test.ts +38 -0
  31. package/tests/toolcall-utils.test.ts +111 -0
  32. package/tsconfig.json +8 -24
  33. package/CLAUDE.md +0 -50
  34. package/LENS.md +0 -48
  35. package/LICENSE +0 -21
  36. package/README.md +0 -93
  37. package/addons/README.md +0 -55
  38. package/addons/clean-cache.js +0 -48
  39. package/addons/generate-readme.js +0 -67
  40. package/addons/git-stats.js +0 -29
  41. package/addons/run-tests.js +0 -127
  42. package/src/commands/commit.tsx +0 -668
  43. package/src/commands/review.tsx +0 -294
  44. package/src/commands/run.tsx +0 -56
  45. package/src/commands/task.tsx +0 -36
  46. package/src/components/chat/ChatMessage.tsx +0 -195
  47. package/src/components/chat/ChatOverlays.tsx +0 -399
  48. package/src/components/chat/ChatRunner.tsx +0 -517
  49. package/src/components/chat/hooks/useChat.ts +0 -631
  50. package/src/components/chat/hooks/useChatInput.ts +0 -79
  51. package/src/components/chat/hooks/useCommandHandlers.ts +0 -327
  52. package/src/components/provider/ProviderPicker.tsx +0 -76
  53. package/src/components/provider/RemoveProviderStep.tsx +0 -82
  54. package/src/components/repo/DiffViewer.tsx +0 -175
  55. package/src/components/repo/FileReviewer.tsx +0 -70
  56. package/src/components/repo/FileViewer.tsx +0 -60
  57. package/src/components/repo/IssueFixer.tsx +0 -666
  58. package/src/components/repo/LensFileMenu.tsx +0 -115
  59. package/src/components/repo/NoProviderPrompt.tsx +0 -28
  60. package/src/components/repo/PreviewRunner.tsx +0 -217
  61. package/src/components/repo/RepoAnalysis.tsx +0 -534
  62. package/src/components/task/TaskRunner.tsx +0 -396
  63. package/src/components/timeline/CommitDetail.tsx +0 -272
  64. package/src/components/timeline/CommitList.tsx +0 -162
  65. package/src/components/timeline/TimelineChat.tsx +0 -166
  66. package/src/components/timeline/TimelineRunner.tsx +0 -1285
  67. package/src/components/watch/RunRunner.tsx +0 -929
  68. package/src/prompts/fewshot.ts +0 -252
  69. package/src/prompts/index.ts +0 -2
  70. package/src/prompts/system.ts +0 -285
  71. package/src/tools/chart.ts +0 -202
  72. package/src/tools/convert-image.ts +0 -312
  73. package/src/tools/files.ts +0 -253
  74. package/src/tools/git.ts +0 -603
  75. package/src/tools/index.ts +0 -17
  76. package/src/tools/pdf.ts +0 -164
  77. package/src/tools/shell.ts +0 -96
  78. package/src/tools/view-image.ts +0 -335
  79. package/src/tools/web.ts +0 -212
  80. package/src/types/chat.ts +0 -86
  81. package/src/types/config.ts +0 -20
  82. package/src/types/repo.ts +0 -54
  83. package/src/utils/addons/loadAddons.ts +0 -34
  84. package/src/utils/ai.ts +0 -321
  85. package/src/utils/chat.ts +0 -326
  86. package/src/utils/chatHistory.ts +0 -121
  87. package/src/utils/config.ts +0 -61
  88. package/src/utils/files.ts +0 -105
  89. package/src/utils/intentClassifier.ts +0 -58
  90. package/src/utils/lensfile.ts +0 -142
  91. package/src/utils/llm.ts +0 -81
  92. package/src/utils/memory.ts +0 -209
  93. package/src/utils/preview.ts +0 -119
  94. package/src/utils/stats.ts +0 -174
  95. package/src/utils/tools/builtins.ts +0 -377
  96. package/src/utils/tools/registry.ts +0 -105
@@ -1,253 +0,0 @@
1
- import path from "path";
2
- import {
3
- existsSync,
4
- mkdirSync,
5
- readdirSync,
6
- readFileSync,
7
- statSync,
8
- writeFileSync,
9
- } from "fs";
10
- import type { FilePatch } from "../components/repo/DiffViewer";
11
-
12
- const SKIP_DIRS = new Set([
13
- "node_modules",
14
- ".git",
15
- "dist",
16
- "build",
17
- ".next",
18
- "out",
19
- "coverage",
20
- "__pycache__",
21
- ".venv",
22
- "venv",
23
- ]);
24
-
25
- export function walkDir(
26
- dir: string,
27
- base = dir,
28
- results: string[] = [],
29
- ): string[] {
30
- let entries: string[];
31
- try {
32
- entries = readdirSync(dir, { encoding: "utf-8" });
33
- } catch {
34
- return results;
35
- }
36
- for (const entry of entries) {
37
- if (results.length >= 100) return results;
38
- if (SKIP_DIRS.has(entry)) continue;
39
- const full = path.join(dir, entry);
40
- const rel = path.relative(base, full).replace(/\\/g, "/");
41
- let isDir = false;
42
- try {
43
- isDir = statSync(full).isDirectory();
44
- } catch {
45
- continue;
46
- }
47
- if (isDir) walkDir(full, base, results);
48
- else results.push(rel);
49
- }
50
- return results;
51
- }
52
-
53
- export function applyPatches(repoPath: string, patches: FilePatch[]): void {
54
- for (const patch of patches) {
55
- const fullPath = path.join(repoPath, patch.path);
56
- const dir = path.dirname(fullPath);
57
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
58
- writeFileSync(fullPath, patch.content, "utf-8");
59
- }
60
- }
61
-
62
- export function readFile(filePath: string, repoPath: string): string {
63
- const candidates = path.isAbsolute(filePath)
64
- ? [filePath]
65
- : [filePath, path.join(repoPath, filePath)];
66
- for (const candidate of candidates) {
67
- if (existsSync(candidate)) {
68
- try {
69
- const content = readFileSync(candidate, "utf-8");
70
- const lines = content.split("\n").length;
71
- return `File: ${candidate} (${lines} lines)\n\n${content.slice(0, 8000)}${
72
- content.length > 8000 ? "\n\n… (truncated)" : ""
73
- }`;
74
- } catch (err) {
75
- return `Error reading file: ${err instanceof Error ? err.message : String(err)}`;
76
- }
77
- }
78
- }
79
- return `File not found: ${filePath}. If reading from a cloned repo, use the full absolute path e.g. C:\\Users\\...\\repo\\file.ts`;
80
- }
81
-
82
- export function readFolder(folderPath: string, repoPath: string): string {
83
- const sanitized = folderPath
84
- .replace(/^(ls|dir|find|tree|cat|read|ls -la?|ls -al?)\s+/i, "")
85
- .trim();
86
-
87
- const candidates = path.isAbsolute(sanitized)
88
- ? [sanitized]
89
- : [sanitized, path.join(repoPath, sanitized)];
90
-
91
- for (const candidate of candidates) {
92
- if (!existsSync(candidate)) continue;
93
- let stat: ReturnType<typeof statSync>;
94
- try {
95
- stat = statSync(candidate);
96
- } catch {
97
- continue;
98
- }
99
- if (!stat.isDirectory()) {
100
- return `Not a directory: ${candidate}. Use read-file to read a file.`;
101
- }
102
-
103
- let entries: string[];
104
- try {
105
- entries = readdirSync(candidate, { encoding: "utf-8" });
106
- } catch (err) {
107
- return `Error reading folder: ${err instanceof Error ? err.message : String(err)}`;
108
- }
109
-
110
- const files: string[] = [];
111
- const subfolders: string[] = [];
112
-
113
- for (const entry of entries) {
114
- if (entry.startsWith(".") && entry !== ".env") continue;
115
- const full = path.join(candidate, entry);
116
- try {
117
- if (statSync(full).isDirectory()) subfolders.push(`${entry}/`);
118
- else files.push(entry);
119
- } catch {}
120
- }
121
-
122
- const total = files.length + subfolders.length;
123
- const lines: string[] = [`Folder: ${candidate} (${total} entries)`, ""];
124
- if (files.length > 0) {
125
- lines.push("Files:");
126
- files.forEach((f) => lines.push(` ${f}`));
127
- }
128
- if (subfolders.length > 0) {
129
- if (files.length > 0) lines.push("");
130
- lines.push("Subfolders:");
131
- subfolders.forEach((d) => lines.push(` ${d}`));
132
- }
133
- if (total === 0) lines.push("(empty folder)");
134
- return lines.join("\n");
135
- }
136
-
137
- return `Folder not found: ${sanitized}`;
138
- }
139
-
140
- export function grepFiles(
141
- pattern: string,
142
- glob: string,
143
- repoPath: string,
144
- ): string {
145
- let regex: RegExp;
146
- try {
147
- regex = new RegExp(pattern, "i");
148
- } catch {
149
- regex = new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "i");
150
- }
151
-
152
- const globToFilter = (g: string): ((rel: string) => boolean) => {
153
- const cleaned = g.replace(/^\*\*\//, "");
154
- const parts = cleaned.split("/");
155
- const ext = parts[parts.length - 1];
156
- const prefix = parts.slice(0, -1).join("/");
157
- return (rel: string) => {
158
- if (ext?.startsWith("*.")) {
159
- if (!rel.endsWith(ext.slice(1))) return false;
160
- } else if (ext && !ext.includes("*")) {
161
- if (!rel.endsWith(ext)) return false;
162
- }
163
- if (prefix && !prefix.includes("*")) {
164
- if (!rel.startsWith(prefix)) return false;
165
- }
166
- return true;
167
- };
168
- };
169
-
170
- const filter = globToFilter(glob);
171
- const allFiles = walkDir(repoPath);
172
- const matchedFiles = allFiles.filter(filter);
173
- if (matchedFiles.length === 0) return `No files matched glob: ${glob}`;
174
-
175
- const results: string[] = [];
176
- let totalMatches = 0;
177
-
178
- for (const relPath of matchedFiles) {
179
- const fullPath = path.join(repoPath, relPath);
180
- let content: string;
181
- try {
182
- content = readFileSync(fullPath, "utf-8");
183
- } catch {
184
- continue;
185
- }
186
- const fileLines = content.split("\n");
187
- const fileMatches: string[] = [];
188
- fileLines.forEach((line, i) => {
189
- if (regex.test(line)) {
190
- fileMatches.push(` ${i + 1}: ${line.trimEnd()}`);
191
- totalMatches++;
192
- }
193
- });
194
- if (fileMatches.length > 0)
195
- results.push(`${relPath}\n${fileMatches.join("\n")}`);
196
- if (totalMatches >= 200) {
197
- results.push("(truncated — too many matches)");
198
- break;
199
- }
200
- }
201
-
202
- if (results.length === 0)
203
- return `No matches for /${pattern}/ in ${matchedFiles.length} file(s) matching ${glob}`;
204
-
205
- return `grep /${pattern}/ ${glob} — ${totalMatches} match(es) in ${results.length} file(s)\n\n${results.join("\n\n")}`;
206
- }
207
-
208
- export function writeFile(
209
- filePath: string,
210
- content: string,
211
- repoPath: string,
212
- ): string {
213
- const fullPath = path.isAbsolute(filePath)
214
- ? filePath
215
- : path.join(repoPath, filePath);
216
- try {
217
- const dir = path.dirname(fullPath);
218
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
219
- writeFileSync(fullPath, content, "utf-8");
220
- const lines = content.split("\n").length;
221
- return `Written: ${fullPath} (${lines} lines, ${content.length} bytes)`;
222
- } catch (err) {
223
- return `Error writing file: ${err instanceof Error ? err.message : String(err)}`;
224
- }
225
- }
226
-
227
- export function deleteFile(filePath: string, repoPath: string): string {
228
- const fullPath = path.isAbsolute(filePath)
229
- ? filePath
230
- : path.join(repoPath, filePath);
231
- try {
232
- if (!existsSync(fullPath)) return `File not found: ${fullPath}`;
233
- const { unlinkSync } = require("fs") as typeof import("fs");
234
- unlinkSync(fullPath);
235
- return `Deleted: ${fullPath}`;
236
- } catch (err) {
237
- return `Error deleting file: ${err instanceof Error ? err.message : String(err)}`;
238
- }
239
- }
240
-
241
- export function deleteFolder(folderPath: string, repoPath: string): string {
242
- const fullPath = path.isAbsolute(folderPath)
243
- ? folderPath
244
- : path.join(repoPath, folderPath);
245
- try {
246
- if (!existsSync(fullPath)) return `Folder not found: ${fullPath}`;
247
- const { rmSync } = require("fs") as typeof import("fs");
248
- rmSync(fullPath, { recursive: true, force: true });
249
- return `Deleted folder: ${fullPath}`;
250
- } catch (err) {
251
- return `Error deleting folder: ${err instanceof Error ? err.message : String(err)}`;
252
- }
253
- }