@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,399 +0,0 @@
1
- import React from "react";
2
- import { Box, Static, Text, useStdout } from "ink";
3
- import Spinner from "ink-spinner";
4
- import { TextArea } from "./TextArea";
5
- import { ACCENT, GREEN, RED } from "../../colors";
6
- import { DiffViewer } from "../repo/DiffViewer";
7
- import { StaticMessage } from "./ChatMessage";
8
- import type { DiffLine, FilePatch } from "../repo/DiffViewer";
9
- import type { Message, ToolCall, ChatStage } from "../../types/chat";
10
-
11
- function History({ committed }: { committed: Message[] }) {
12
- return (
13
- <Static items={committed}>
14
- {(msg, i) => <StaticMessage key={i} msg={msg} />}
15
- </Static>
16
- );
17
- }
18
-
19
- function Hint({ text }: { text: string }) {
20
- return (
21
- <Text color="gray" dimColor>
22
- {text}
23
- </Text>
24
- );
25
- }
26
-
27
- // ── PermissionPrompt ──────────────────────────────────────────────────────────
28
- //
29
- // Works with both the old explicit ToolCall union and the new generic
30
- // { type, _label, _display } shape produced by the plugin system.
31
-
32
- export function PermissionPrompt({
33
- tool,
34
- onDecide,
35
- }: {
36
- tool: ToolCall | { type: string; _label: string; _display: string };
37
- onDecide: (approved: boolean) => void;
38
- }) {
39
- let icon: string;
40
- let label: string;
41
- let value: string;
42
-
43
- // Generic plugin tool shape
44
- if ("_label" in tool) {
45
- const iconMap: Record<string, string> = {
46
- run: "$",
47
- fetch: "~>",
48
- read: "r",
49
- write: "w",
50
- delete: "x",
51
- "delete folder": "X",
52
- open: "↗",
53
- pdf: "P",
54
- search: "?",
55
- folder: "d",
56
- grep: "/",
57
- clone: "↓",
58
- query: "⌗",
59
- };
60
- icon = iconMap[tool._label] ?? "·";
61
- label = tool._label;
62
- value = tool._display;
63
- } else {
64
- // Legacy explicit ToolCall union
65
- if (tool.type === "shell") {
66
- icon = "$";
67
- label = "run";
68
- value = tool.command;
69
- } else if (tool.type === "fetch") {
70
- icon = "~>";
71
- label = "fetch";
72
- value = tool.url;
73
- } else if (tool.type === "read-file") {
74
- icon = "r";
75
- label = "read";
76
- value = tool.filePath;
77
- } else if (tool.type === "read-folder") {
78
- icon = "d";
79
- label = "folder";
80
- value = tool.folderPath;
81
- } else if (tool.type === "grep") {
82
- icon = "/";
83
- label = "grep";
84
- value = `${tool.pattern} ${tool.glob}`;
85
- } else if (tool.type === "delete-file") {
86
- icon = "x";
87
- label = "delete";
88
- value = tool.filePath;
89
- } else if (tool.type === "delete-folder") {
90
- icon = "X";
91
- label = "delete folder";
92
- value = tool.folderPath;
93
- } else if (tool.type === "open-url") {
94
- icon = "↗";
95
- label = "open";
96
- value = tool.url;
97
- } else if (tool.type === "generate-pdf") {
98
- icon = "P";
99
- label = "pdf";
100
- value = tool.filePath;
101
- } else if (tool.type === "write-file") {
102
- icon = "w";
103
- label = "write";
104
- value = `${tool.filePath} (${tool.fileContent.length} bytes)`;
105
- } else {
106
- icon = "?";
107
- label = "search";
108
- value = (tool as any).query ?? "";
109
- }
110
- }
111
-
112
- return (
113
- <Box flexDirection="column" marginY={1}>
114
- <Box gap={1}>
115
- <Text color={ACCENT}>{icon}</Text>
116
- <Text color="gray">{label}</Text>
117
- <Text color="white">{value}</Text>
118
- </Box>
119
- <Box gap={1} marginLeft={2}>
120
- <Text color="gray">y/enter allow · n/esc deny</Text>
121
- </Box>
122
- </Box>
123
- );
124
- }
125
-
126
- export function InputBox({
127
- value,
128
- onChange,
129
- onSubmit,
130
- inputKey,
131
- }: {
132
- value: string;
133
- onChange: (v: string) => void;
134
- onSubmit: (v: string) => void;
135
- inputKey?: number;
136
- }) {
137
- const { stdout } = useStdout();
138
- const cols = stdout?.columns ?? 80;
139
- const rule = "─".repeat(Math.max(1, cols));
140
-
141
- return (
142
- <Box flexDirection="column" marginTop={1}>
143
- <Text color="gray" dimColor>{rule}</Text>
144
- <Box gap={1}>
145
- <Text color={ACCENT}>{">"}</Text>
146
- <TextArea
147
- key={inputKey}
148
- value={value}
149
- onChange={onChange}
150
- onSubmit={onSubmit}
151
- placeholder="ask anything..."
152
- />
153
- </Box>
154
- <Text color="gray" dimColor>{rule}</Text>
155
- </Box>
156
- );
157
- }
158
-
159
- export function TypewriterText({
160
- text,
161
- color = ACCENT,
162
- speed = 38,
163
- }: {
164
- text: string;
165
- color?: string;
166
- speed?: number;
167
- }) {
168
- const [displayed, setDisplayed] = React.useState("");
169
- const [target, setTarget] = React.useState(text);
170
-
171
- React.useEffect(() => {
172
- setDisplayed("");
173
- setTarget(text);
174
- }, [text]);
175
-
176
- React.useEffect(() => {
177
- if (displayed.length >= target.length) return;
178
- const t = setTimeout(
179
- () => setDisplayed(target.slice(0, displayed.length + 1)),
180
- speed,
181
- );
182
- return () => clearTimeout(t);
183
- }, [displayed, target, speed]);
184
-
185
- return <Text color={color}>{displayed}</Text>;
186
- }
187
-
188
- export function ShortcutBar({
189
- autoApprove,
190
- forceApprove,
191
- }: {
192
- autoApprove?: boolean;
193
- forceApprove?: boolean;
194
- }) {
195
- return (
196
- <Box gap={3} marginTop={0}>
197
- <Text color="gray" dimColor>
198
- enter send · alt+enter newline · ^w del word · ^c exit
199
- </Text>
200
- {forceApprove ? (
201
- <Text color={RED}>⚡⚡ force-all</Text>
202
- ) : (
203
- <Text color={autoApprove ? GREEN : "gray"} dimColor={!autoApprove}>
204
- {autoApprove ? "⚡ auto" : "/auto"}
205
- </Text>
206
- )}
207
- </Box>
208
- );
209
- }
210
-
211
- export function CloneOfferView({
212
- stage,
213
- committed,
214
- }: {
215
- stage: Extract<ChatStage, { type: "clone-offer" }>;
216
- committed: Message[];
217
- }) {
218
- return (
219
- <Box flexDirection="column">
220
- <History committed={committed} />
221
- <Box flexDirection="column" marginY={1}>
222
- <Box gap={1}>
223
- <Text color={ACCENT}>*</Text>
224
- <Text color="white">clone </Text>
225
- <Text color={ACCENT}>{stage.repoUrl}</Text>
226
- <Text color="white">?</Text>
227
- </Box>
228
- <Hint text=" y/enter clone · n/esc skip" />
229
- </Box>
230
- </Box>
231
- );
232
- }
233
-
234
- export function CloningView({
235
- stage,
236
- committed,
237
- }: {
238
- stage: Extract<ChatStage, { type: "cloning" }>;
239
- committed: Message[];
240
- }) {
241
- return (
242
- <Box flexDirection="column">
243
- <History committed={committed} />
244
- <Box gap={1} marginTop={1}>
245
- <Text color={ACCENT}>
246
- <Spinner />
247
- </Text>
248
- <Text color="gray">cloning </Text>
249
- <Text color={ACCENT}>{stage.repoUrl}</Text>
250
- <Text color="gray">...</Text>
251
- </Box>
252
- </Box>
253
- );
254
- }
255
-
256
- export function CloneExistsView({
257
- stage,
258
- committed,
259
- }: {
260
- stage: Extract<ChatStage, { type: "clone-exists" }>;
261
- committed: Message[];
262
- }) {
263
- return (
264
- <Box flexDirection="column">
265
- <History committed={committed} />
266
- <Box flexDirection="column" marginY={1}>
267
- <Box gap={1}>
268
- <Text color="yellow">!</Text>
269
- <Text color="gray">already cloned at </Text>
270
- <Text color="white">{stage.repoPath}</Text>
271
- </Box>
272
- <Hint text=" y re-clone · n use existing" />
273
- </Box>
274
- </Box>
275
- );
276
- }
277
-
278
- export function CloneDoneView({
279
- stage,
280
- committed,
281
- }: {
282
- stage: Extract<ChatStage, { type: "clone-done" }>;
283
- committed: Message[];
284
- }) {
285
- const repoName = stage.repoUrl.split("/").pop() ?? "repo";
286
- return (
287
- <Box flexDirection="column">
288
- <History committed={committed} />
289
- <Box flexDirection="column" marginY={1}>
290
- <Box gap={1}>
291
- <Text color={GREEN}>✓</Text>
292
- <Text color="white" bold>
293
- {repoName}
294
- </Text>
295
- <Text color="gray">
296
- cloned · {stage.fileCount} files · {stage.destPath}
297
- </Text>
298
- </Box>
299
- <Hint text=" enter/esc continue" />
300
- </Box>
301
- </Box>
302
- );
303
- }
304
-
305
- export function CloneErrorView({
306
- stage,
307
- committed,
308
- }: {
309
- stage: Extract<ChatStage, { type: "clone-error" }>;
310
- committed: Message[];
311
- }) {
312
- return (
313
- <Box flexDirection="column">
314
- <History committed={committed} />
315
- <Box flexDirection="column" marginY={1}>
316
- <Box gap={1}>
317
- <Text color={RED}>✗</Text>
318
- <Text color={RED}>{stage.message}</Text>
319
- </Box>
320
- <Hint text=" enter/esc continue" />
321
- </Box>
322
- </Box>
323
- );
324
- }
325
-
326
- export function PreviewView({
327
- stage,
328
- committed,
329
- }: {
330
- stage: Extract<ChatStage, { type: "preview" }>;
331
- committed: Message[];
332
- }) {
333
- const { patches, diffLines, scrollOffset } = stage;
334
- return (
335
- <Box flexDirection="column">
336
- <History committed={committed} />
337
- <Box gap={1} marginTop={1}>
338
- <Text color={ACCENT}>*</Text>
339
- <Text color="white" bold>
340
- proposed changes
341
- </Text>
342
- <Text color="gray">
343
- ({patches.length} file{patches.length !== 1 ? "s" : ""})
344
- </Text>
345
- </Box>
346
- <Box flexDirection="column" marginLeft={2} marginTop={1}>
347
- {patches.map((p) => (
348
- <Box key={p.path} gap={1}>
349
- <Text color={p.isNew ? GREEN : "yellow"}>
350
- {p.isNew ? "+" : "~"}
351
- </Text>
352
- <Text color={p.isNew ? GREEN : "yellow"}>{p.path}</Text>
353
- {p.isNew && (
354
- <Text color="gray" dimColor>
355
- new
356
- </Text>
357
- )}
358
- </Box>
359
- ))}
360
- </Box>
361
- <DiffViewer
362
- patches={patches}
363
- diffs={diffLines}
364
- scrollOffset={scrollOffset}
365
- />
366
- <Hint text="↑↓ scroll · enter/a apply · s/esc skip" />
367
- </Box>
368
- );
369
- }
370
-
371
- export function ViewingFileView({
372
- stage,
373
- committed,
374
- }: {
375
- stage: Extract<ChatStage, { type: "viewing-file" }>;
376
- committed: Message[];
377
- }) {
378
- const { file, diffLines, scrollOffset } = stage;
379
- return (
380
- <Box flexDirection="column">
381
- <History committed={committed} />
382
- <Box gap={1} marginTop={1}>
383
- <Text color={ACCENT}>r</Text>
384
- <Text color="white" bold>
385
- {file.path}
386
- </Text>
387
- <Text color="gray" dimColor>
388
- {file.isNew ? "new" : "modified"}
389
- </Text>
390
- </Box>
391
- <DiffViewer
392
- patches={[file.patch]}
393
- diffs={[diffLines]}
394
- scrollOffset={scrollOffset}
395
- />
396
- <Hint text="↑↓ scroll · enter/esc back" />
397
- </Box>
398
- );
399
- }