@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.
- package/dist/index.mjs +105368 -274002
- package/package.json +13 -19
- package/src/colors.ts +15 -15
- package/src/commands/chat.tsx +32 -23
- package/src/commands/provider.tsx +11 -238
- package/src/commands/repo.tsx +66 -120
- package/src/commands/timeline.tsx +11 -22
- package/src/components/ChatView.tsx +238 -0
- package/src/components/Message.tsx +46 -0
- package/src/components/ToolCall.tsx +67 -0
- package/src/components/chat/ChatView.tsx +550 -0
- package/src/components/chat/Message.tsx +152 -0
- package/src/components/chat/StatusBar.tsx +214 -0
- package/src/components/chat/TextArea.tsx +173 -176
- package/src/components/provider/ApiKeyStep.tsx +207 -199
- package/src/components/provider/ModelStep.tsx +90 -88
- package/src/components/provider/ProviderSetup.tsx +331 -0
- package/src/components/provider/ProviderTypeStep.tsx +53 -61
- package/src/components/repo/StepRow.tsx +68 -69
- package/src/components/timeline/TimelineView.tsx +840 -0
- package/src/components/toolcall-utils.ts +103 -0
- package/src/components/watch/RunView.tsx +497 -0
- package/src/hooks/useChatInput.ts +49 -0
- package/src/hooks/useCommandHandler.ts +117 -0
- package/src/index.tsx +386 -139
- package/src/utils/git.ts +149 -155
- package/src/utils/repo.ts +62 -69
- package/src/utils/thinking.tsx +64 -0
- package/src/utils/watch.ts +165 -307
- package/tests/message.test.ts +38 -0
- package/tests/toolcall-utils.test.ts +111 -0
- package/tsconfig.json +8 -24
- package/CLAUDE.md +0 -50
- package/LENS.md +0 -48
- package/LICENSE +0 -21
- package/README.md +0 -93
- package/addons/README.md +0 -55
- package/addons/clean-cache.js +0 -48
- package/addons/generate-readme.js +0 -67
- package/addons/git-stats.js +0 -29
- package/addons/run-tests.js +0 -127
- package/src/commands/commit.tsx +0 -668
- package/src/commands/review.tsx +0 -294
- package/src/commands/run.tsx +0 -56
- package/src/commands/task.tsx +0 -36
- package/src/components/chat/ChatMessage.tsx +0 -195
- package/src/components/chat/ChatOverlays.tsx +0 -399
- package/src/components/chat/ChatRunner.tsx +0 -517
- package/src/components/chat/hooks/useChat.ts +0 -631
- package/src/components/chat/hooks/useChatInput.ts +0 -79
- package/src/components/chat/hooks/useCommandHandlers.ts +0 -327
- package/src/components/provider/ProviderPicker.tsx +0 -76
- package/src/components/provider/RemoveProviderStep.tsx +0 -82
- package/src/components/repo/DiffViewer.tsx +0 -175
- package/src/components/repo/FileReviewer.tsx +0 -70
- package/src/components/repo/FileViewer.tsx +0 -60
- package/src/components/repo/IssueFixer.tsx +0 -666
- package/src/components/repo/LensFileMenu.tsx +0 -115
- package/src/components/repo/NoProviderPrompt.tsx +0 -28
- package/src/components/repo/PreviewRunner.tsx +0 -217
- package/src/components/repo/RepoAnalysis.tsx +0 -534
- package/src/components/task/TaskRunner.tsx +0 -396
- package/src/components/timeline/CommitDetail.tsx +0 -272
- package/src/components/timeline/CommitList.tsx +0 -162
- package/src/components/timeline/TimelineChat.tsx +0 -166
- package/src/components/timeline/TimelineRunner.tsx +0 -1285
- package/src/components/watch/RunRunner.tsx +0 -929
- package/src/prompts/fewshot.ts +0 -252
- package/src/prompts/index.ts +0 -2
- package/src/prompts/system.ts +0 -285
- package/src/tools/chart.ts +0 -202
- package/src/tools/convert-image.ts +0 -312
- package/src/tools/files.ts +0 -253
- package/src/tools/git.ts +0 -603
- package/src/tools/index.ts +0 -17
- package/src/tools/pdf.ts +0 -164
- package/src/tools/shell.ts +0 -96
- package/src/tools/view-image.ts +0 -335
- package/src/tools/web.ts +0 -212
- package/src/types/chat.ts +0 -86
- package/src/types/config.ts +0 -20
- package/src/types/repo.ts +0 -54
- package/src/utils/addons/loadAddons.ts +0 -34
- package/src/utils/ai.ts +0 -321
- package/src/utils/chat.ts +0 -326
- package/src/utils/chatHistory.ts +0 -121
- package/src/utils/config.ts +0 -61
- package/src/utils/files.ts +0 -105
- package/src/utils/intentClassifier.ts +0 -58
- package/src/utils/lensfile.ts +0 -142
- package/src/utils/llm.ts +0 -81
- package/src/utils/memory.ts +0 -209
- package/src/utils/preview.ts +0 -119
- package/src/utils/stats.ts +0 -174
- package/src/utils/tools/builtins.ts +0 -377
- package/src/utils/tools/registry.ts +0 -105
|
@@ -1,534 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import { Box, Text, Static, useInput } from "ink";
|
|
3
|
-
import Spinner from "ink-spinner";
|
|
4
|
-
import figures from "figures";
|
|
5
|
-
import { useState, useRef } from "react";
|
|
6
|
-
import { writeFileSync } from "fs";
|
|
7
|
-
import path from "path";
|
|
8
|
-
import { ACCENT } from "../../colors";
|
|
9
|
-
import {
|
|
10
|
-
requestFileList,
|
|
11
|
-
analyzeRepo,
|
|
12
|
-
extractToolingPatch,
|
|
13
|
-
} from "../../utils/ai";
|
|
14
|
-
import { ProviderPicker } from "../provider/ProviderPicker";
|
|
15
|
-
import { PreviewRunner } from "./PreviewRunner";
|
|
16
|
-
import { IssueFixer } from "./IssueFixer";
|
|
17
|
-
import { writeLensFile, patchLensFile } from "../../utils/lensfile";
|
|
18
|
-
import { callChat } from "../../utils/chat";
|
|
19
|
-
import { StaticMessage } from "../chat/ChatMessage";
|
|
20
|
-
import { InputBox, TypewriterText, ShortcutBar } from "../chat/ChatOverlays";
|
|
21
|
-
import type { Provider } from "../../types/config";
|
|
22
|
-
import type { AnalysisResult, ImportantFile } from "../../types/repo";
|
|
23
|
-
import type { Message } from "../../types/chat";
|
|
24
|
-
import { useThinkingPhrase } from "../../utils/thinking";
|
|
25
|
-
|
|
26
|
-
type AnalysisStage =
|
|
27
|
-
| { type: "picking-provider" }
|
|
28
|
-
| { type: "requesting-files" }
|
|
29
|
-
| { type: "analyzing" }
|
|
30
|
-
| { type: "done"; result: AnalysisResult }
|
|
31
|
-
| { type: "writing" }
|
|
32
|
-
| { type: "written"; filePath: string }
|
|
33
|
-
| { type: "previewing" }
|
|
34
|
-
| { type: "fixing"; result: AnalysisResult }
|
|
35
|
-
| { type: "asking"; result: AnalysisResult }
|
|
36
|
-
| { type: "error"; message: string };
|
|
37
|
-
|
|
38
|
-
const OUTPUT_FILES = ["CLAUDE.md", "copilot-instructions.md"] as const;
|
|
39
|
-
type OutputFile = (typeof OUTPUT_FILES)[number];
|
|
40
|
-
|
|
41
|
-
function buildMarkdown(repoUrl: string, result: AnalysisResult): string {
|
|
42
|
-
const toolingLines = Object.entries(result.tooling ?? {})
|
|
43
|
-
.map(([k, v]) => `- **${k}**: ${v}`)
|
|
44
|
-
.join("\n");
|
|
45
|
-
|
|
46
|
-
return `# Repository Analysis
|
|
47
|
-
|
|
48
|
-
> ${repoUrl}
|
|
49
|
-
|
|
50
|
-
## Overview
|
|
51
|
-
${result.overview}
|
|
52
|
-
|
|
53
|
-
## Architecture
|
|
54
|
-
${result.architecture ?? ""}
|
|
55
|
-
|
|
56
|
-
## Tooling
|
|
57
|
-
${toolingLines || "- Not determined"}
|
|
58
|
-
|
|
59
|
-
## Important Folders
|
|
60
|
-
${result.importantFolders.map((f) => `- ${f}`).join("\n")}
|
|
61
|
-
|
|
62
|
-
## Key Files
|
|
63
|
-
${(result.keyFiles ?? []).map((f) => `- ${f}`).join("\n")}
|
|
64
|
-
|
|
65
|
-
## Patterns & Idioms
|
|
66
|
-
${(result.patterns ?? []).map((p) => `- ${p}`).join("\n")}
|
|
67
|
-
|
|
68
|
-
## Suggestions
|
|
69
|
-
${result.suggestions.map((s) => `- ${s}`).join("\n")}
|
|
70
|
-
`;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function buildQASystemPrompt(repoUrl: string, result: AnalysisResult): string {
|
|
74
|
-
const toolingLines = Object.entries(result.tooling ?? {})
|
|
75
|
-
.map(([k, v]) => `- ${k}: ${v}`)
|
|
76
|
-
.join("\n");
|
|
77
|
-
|
|
78
|
-
return `You are a codebase assistant for the repository at ${repoUrl}.
|
|
79
|
-
|
|
80
|
-
Here is what you know about this codebase:
|
|
81
|
-
|
|
82
|
-
Overview:
|
|
83
|
-
${result.overview}
|
|
84
|
-
|
|
85
|
-
Architecture:
|
|
86
|
-
${result.architecture ?? "Not determined"}
|
|
87
|
-
|
|
88
|
-
Tooling:
|
|
89
|
-
${toolingLines || "Not determined"}
|
|
90
|
-
|
|
91
|
-
Important Folders:
|
|
92
|
-
${result.importantFolders.map((f) => `- ${f}`).join("\n")}
|
|
93
|
-
|
|
94
|
-
Key Files:
|
|
95
|
-
${(result.keyFiles ?? []).map((f) => `- ${f}`).join("\n")}
|
|
96
|
-
|
|
97
|
-
Patterns & Idioms:
|
|
98
|
-
${(result.patterns ?? []).map((p) => `- ${p}`).join("\n")}
|
|
99
|
-
|
|
100
|
-
Answer questions about this codebase concisely and accurately. If you're unsure about something not covered in the analysis, say so clearly rather than guessing.`;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function AskingFilesStep() {
|
|
104
|
-
const phrase = useThinkingPhrase(true, "model");
|
|
105
|
-
return (
|
|
106
|
-
<Box gap={1}>
|
|
107
|
-
<Text color={ACCENT}>
|
|
108
|
-
<Spinner />
|
|
109
|
-
</Text>
|
|
110
|
-
<Text color={ACCENT}>{phrase}</Text>
|
|
111
|
-
</Box>
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function AnalyzingStep() {
|
|
116
|
-
const phrase = useThinkingPhrase(true, "summary");
|
|
117
|
-
return (
|
|
118
|
-
<Box gap={1}>
|
|
119
|
-
<Text color={ACCENT}>
|
|
120
|
-
<Spinner />
|
|
121
|
-
</Text>
|
|
122
|
-
<Text color={ACCENT}>{phrase}</Text>
|
|
123
|
-
</Box>
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// ─── CodebaseQA ──────────────────────────────────────────────────────────────
|
|
128
|
-
|
|
129
|
-
type QAStage = "idle" | "thinking";
|
|
130
|
-
|
|
131
|
-
function CodebaseQA({
|
|
132
|
-
repoUrl,
|
|
133
|
-
result,
|
|
134
|
-
provider,
|
|
135
|
-
onExit,
|
|
136
|
-
}: {
|
|
137
|
-
repoUrl: string;
|
|
138
|
-
result: AnalysisResult;
|
|
139
|
-
provider: Provider;
|
|
140
|
-
onExit: () => void;
|
|
141
|
-
}) {
|
|
142
|
-
const [committed, setCommitted] = useState<Message[]>([]);
|
|
143
|
-
const [allMessages, setAllMessages] = useState<Message[]>([]);
|
|
144
|
-
const [inputValue, setInputValue] = useState("");
|
|
145
|
-
const [inputKey, setInputKey] = useState(0);
|
|
146
|
-
const [qaStage, setQaStage] = useState<QAStage>("idle");
|
|
147
|
-
const abortRef = useRef<AbortController | null>(null);
|
|
148
|
-
const systemPrompt = buildQASystemPrompt(repoUrl, result);
|
|
149
|
-
const thinkingPhrase = useThinkingPhrase(qaStage === "thinking");
|
|
150
|
-
|
|
151
|
-
useInput((_, key) => {
|
|
152
|
-
if (key.escape) {
|
|
153
|
-
if (qaStage === "thinking") {
|
|
154
|
-
abortRef.current?.abort();
|
|
155
|
-
abortRef.current = null;
|
|
156
|
-
setQaStage("idle");
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
onExit();
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
const sendQuestion = (text: string) => {
|
|
164
|
-
const trimmed = text.trim();
|
|
165
|
-
if (!trimmed) return;
|
|
166
|
-
|
|
167
|
-
const userMsg: Message = { role: "user", type: "text", content: trimmed };
|
|
168
|
-
const nextAll = [...allMessages, userMsg];
|
|
169
|
-
setCommitted((prev) => [...prev, userMsg]);
|
|
170
|
-
setAllMessages(nextAll);
|
|
171
|
-
setQaStage("thinking");
|
|
172
|
-
|
|
173
|
-
const abort = new AbortController();
|
|
174
|
-
abortRef.current = abort;
|
|
175
|
-
|
|
176
|
-
callChat(provider, systemPrompt, nextAll, abort.signal)
|
|
177
|
-
.then((result) => {
|
|
178
|
-
const assistantMsg: Message = {
|
|
179
|
-
role: "assistant",
|
|
180
|
-
type: "text",
|
|
181
|
-
content: result.text,
|
|
182
|
-
};
|
|
183
|
-
setCommitted((prev) => [...prev, assistantMsg]);
|
|
184
|
-
setAllMessages([...nextAll, assistantMsg]);
|
|
185
|
-
setQaStage("idle");
|
|
186
|
-
})
|
|
187
|
-
.catch((err: unknown) => {
|
|
188
|
-
if (err instanceof Error && err.name === "AbortError") {
|
|
189
|
-
setQaStage("idle");
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
const errMsg: Message = {
|
|
193
|
-
role: "assistant",
|
|
194
|
-
type: "text",
|
|
195
|
-
content: `Error: ${err instanceof Error ? err.message : "Request failed"}`,
|
|
196
|
-
};
|
|
197
|
-
setCommitted((prev) => [...prev, errMsg]);
|
|
198
|
-
setAllMessages([...nextAll, errMsg]);
|
|
199
|
-
setQaStage("idle");
|
|
200
|
-
});
|
|
201
|
-
};
|
|
202
|
-
|
|
203
|
-
return (
|
|
204
|
-
<Box flexDirection="column">
|
|
205
|
-
<Static items={committed}>
|
|
206
|
-
{(msg, i) => <StaticMessage key={i} msg={msg} />}
|
|
207
|
-
</Static>
|
|
208
|
-
|
|
209
|
-
{qaStage === "thinking" && (
|
|
210
|
-
<Box gap={1}>
|
|
211
|
-
<Text color={ACCENT}>●</Text>
|
|
212
|
-
<TypewriterText text={thinkingPhrase} />
|
|
213
|
-
<Text color="gray" dimColor>
|
|
214
|
-
· esc cancel
|
|
215
|
-
</Text>
|
|
216
|
-
</Box>
|
|
217
|
-
)}
|
|
218
|
-
|
|
219
|
-
{qaStage === "idle" && (
|
|
220
|
-
<Box flexDirection="column">
|
|
221
|
-
<InputBox
|
|
222
|
-
value={inputValue}
|
|
223
|
-
onChange={setInputValue}
|
|
224
|
-
onSubmit={(val) => {
|
|
225
|
-
if (val.trim()) sendQuestion(val.trim());
|
|
226
|
-
setInputValue("");
|
|
227
|
-
setInputKey((k) => k + 1);
|
|
228
|
-
}}
|
|
229
|
-
inputKey={inputKey}
|
|
230
|
-
/>
|
|
231
|
-
<Text color="gray" dimColor>
|
|
232
|
-
enter send · esc back
|
|
233
|
-
</Text>
|
|
234
|
-
</Box>
|
|
235
|
-
)}
|
|
236
|
-
</Box>
|
|
237
|
-
);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// ─── RepoAnalysis ─────────────────────────────────────────────────────────────
|
|
241
|
-
|
|
242
|
-
export const RepoAnalysis = ({
|
|
243
|
-
repoUrl,
|
|
244
|
-
repoPath,
|
|
245
|
-
fileTree,
|
|
246
|
-
files: initialFiles,
|
|
247
|
-
preloadedResult,
|
|
248
|
-
onExit,
|
|
249
|
-
}: {
|
|
250
|
-
repoUrl: string;
|
|
251
|
-
repoPath: string;
|
|
252
|
-
fileTree: string[];
|
|
253
|
-
files: ImportantFile[];
|
|
254
|
-
preloadedResult?: AnalysisResult;
|
|
255
|
-
onExit?: () => void;
|
|
256
|
-
}) => {
|
|
257
|
-
const [stage, setStage] = useState<AnalysisStage>(
|
|
258
|
-
preloadedResult
|
|
259
|
-
? { type: "done", result: preloadedResult }
|
|
260
|
-
: { type: "picking-provider" },
|
|
261
|
-
);
|
|
262
|
-
const [selectedOutput, setSelectedOutput] = useState<0 | 1 | 2 | 3 | 4>(0);
|
|
263
|
-
const [requestedFiles, setRequestedFiles] = useState<ImportantFile[]>([]);
|
|
264
|
-
const [provider, setProvider] = useState<Provider | null>(null);
|
|
265
|
-
|
|
266
|
-
const OPTIONS = [
|
|
267
|
-
...OUTPUT_FILES,
|
|
268
|
-
"Preview repo",
|
|
269
|
-
"Fix issues",
|
|
270
|
-
"Ask questions",
|
|
271
|
-
] as const;
|
|
272
|
-
|
|
273
|
-
const handleProviderDone = (p: Provider) => {
|
|
274
|
-
setProvider(p);
|
|
275
|
-
setStage({ type: "requesting-files" });
|
|
276
|
-
|
|
277
|
-
requestFileList(repoUrl, repoPath, fileTree, p)
|
|
278
|
-
.then((files) => {
|
|
279
|
-
setRequestedFiles(files);
|
|
280
|
-
|
|
281
|
-
extractToolingPatch(repoUrl, files.length > 0 ? files : initialFiles, p)
|
|
282
|
-
.then((patch) => {
|
|
283
|
-
if (patch) patchLensFile(repoPath, patch);
|
|
284
|
-
})
|
|
285
|
-
.catch(() => {});
|
|
286
|
-
|
|
287
|
-
setStage({ type: "analyzing" });
|
|
288
|
-
return analyzeRepo(repoUrl, files.length > 0 ? files : initialFiles, p);
|
|
289
|
-
})
|
|
290
|
-
.then((result) => {
|
|
291
|
-
writeLensFile(repoPath, result);
|
|
292
|
-
setStage({ type: "done", result });
|
|
293
|
-
})
|
|
294
|
-
.catch((err: unknown) =>
|
|
295
|
-
setStage({
|
|
296
|
-
type: "error",
|
|
297
|
-
message: err instanceof Error ? err.message : "Analysis failed",
|
|
298
|
-
}),
|
|
299
|
-
);
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
useInput((_, key) => {
|
|
303
|
-
if (stage.type !== "done") return;
|
|
304
|
-
if (key.leftArrow)
|
|
305
|
-
setSelectedOutput((i) => Math.max(0, i - 1) as 0 | 1 | 2 | 3 | 4);
|
|
306
|
-
if (key.rightArrow)
|
|
307
|
-
setSelectedOutput(
|
|
308
|
-
(i) => Math.min(OPTIONS.length - 1, i + 1) as 0 | 1 | 2 | 3 | 4,
|
|
309
|
-
);
|
|
310
|
-
if (key.return) {
|
|
311
|
-
if (selectedOutput === 2) {
|
|
312
|
-
setStage({ type: "previewing" });
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
|
-
if (selectedOutput === 3) {
|
|
316
|
-
setStage({ type: "fixing", result: stage.result });
|
|
317
|
-
return;
|
|
318
|
-
}
|
|
319
|
-
if (selectedOutput === 4) {
|
|
320
|
-
setStage({ type: "asking", result: stage.result });
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
const fileName = OUTPUT_FILES[selectedOutput] as OutputFile;
|
|
324
|
-
setStage({ type: "writing" });
|
|
325
|
-
try {
|
|
326
|
-
const filePath = path.join(repoPath, fileName);
|
|
327
|
-
writeFileSync(filePath, buildMarkdown(repoUrl, stage.result), "utf-8");
|
|
328
|
-
setStage({ type: "written", filePath });
|
|
329
|
-
} catch (err: unknown) {
|
|
330
|
-
setStage({
|
|
331
|
-
type: "error",
|
|
332
|
-
message: err instanceof Error ? err.message : "Write failed",
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
if (key.escape) setStage({ type: "written", filePath: "" });
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
if (stage.type === "picking-provider") {
|
|
340
|
-
return <ProviderPicker onDone={handleProviderDone} />;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
if (stage.type === "requesting-files") {
|
|
344
|
-
return <AskingFilesStep />;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
if (stage.type === "analyzing") {
|
|
348
|
-
return (
|
|
349
|
-
<Box flexDirection="column" marginTop={1} gap={1}>
|
|
350
|
-
<AnalyzingStep />
|
|
351
|
-
{requestedFiles.length > 0 && (
|
|
352
|
-
<Box flexDirection="column" marginLeft={2}>
|
|
353
|
-
<Text color="gray">Reading {requestedFiles.length} files:</Text>
|
|
354
|
-
{requestedFiles.map((f) => (
|
|
355
|
-
<Text key={f.path} color="gray">
|
|
356
|
-
{figures.bullet} {f.path}
|
|
357
|
-
</Text>
|
|
358
|
-
))}
|
|
359
|
-
</Box>
|
|
360
|
-
)}
|
|
361
|
-
</Box>
|
|
362
|
-
);
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
if (stage.type === "writing") {
|
|
366
|
-
return (
|
|
367
|
-
<Box marginTop={1}>
|
|
368
|
-
<Text color={ACCENT}>
|
|
369
|
-
<Spinner />
|
|
370
|
-
</Text>
|
|
371
|
-
<Box marginLeft={1}>
|
|
372
|
-
<Text>Writing file...</Text>
|
|
373
|
-
</Box>
|
|
374
|
-
</Box>
|
|
375
|
-
);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
if (stage.type === "written") {
|
|
379
|
-
setTimeout(() => {
|
|
380
|
-
if (onExit) onExit();
|
|
381
|
-
else process.exit(0);
|
|
382
|
-
}, 100);
|
|
383
|
-
return (
|
|
384
|
-
<Text color="green">
|
|
385
|
-
{figures.tick}{" "}
|
|
386
|
-
{stage.filePath ? `Written to ${stage.filePath}` : "Skipped"}
|
|
387
|
-
</Text>
|
|
388
|
-
);
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
if (stage.type === "previewing") {
|
|
392
|
-
return (
|
|
393
|
-
<Box flexDirection="column">
|
|
394
|
-
<Text color="cyan" bold>
|
|
395
|
-
{figures.play} Preview — {repoPath}
|
|
396
|
-
</Text>
|
|
397
|
-
<PreviewRunner
|
|
398
|
-
repoPath={repoPath}
|
|
399
|
-
onExit={() => {
|
|
400
|
-
setTimeout(() => {
|
|
401
|
-
if (onExit) onExit();
|
|
402
|
-
else process.exit(0);
|
|
403
|
-
}, 100);
|
|
404
|
-
}}
|
|
405
|
-
/>
|
|
406
|
-
</Box>
|
|
407
|
-
);
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
if (stage.type === "fixing") {
|
|
411
|
-
return (
|
|
412
|
-
<IssueFixer
|
|
413
|
-
repoPath={repoPath}
|
|
414
|
-
result={stage.result}
|
|
415
|
-
requestedFiles={requestedFiles}
|
|
416
|
-
provider={provider!}
|
|
417
|
-
onDone={() => setStage({ type: "done", result: stage.result })}
|
|
418
|
-
/>
|
|
419
|
-
);
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
if (stage.type === "asking") {
|
|
423
|
-
return (
|
|
424
|
-
<CodebaseQA
|
|
425
|
-
repoUrl={repoUrl}
|
|
426
|
-
result={stage.result}
|
|
427
|
-
provider={provider!}
|
|
428
|
-
onExit={() => setStage({ type: "done", result: stage.result })}
|
|
429
|
-
/>
|
|
430
|
-
);
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
if (stage.type === "error") {
|
|
434
|
-
return (
|
|
435
|
-
<Text color="red">
|
|
436
|
-
{figures.cross} {stage.message}
|
|
437
|
-
</Text>
|
|
438
|
-
);
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
const { result } = stage;
|
|
442
|
-
|
|
443
|
-
return (
|
|
444
|
-
<Box flexDirection="column" marginTop={1} gap={1}>
|
|
445
|
-
<Box flexDirection="column">
|
|
446
|
-
<Text bold color="cyan">
|
|
447
|
-
{figures.info} Overview
|
|
448
|
-
</Text>
|
|
449
|
-
<Text color="white">{result.overview}</Text>
|
|
450
|
-
</Box>
|
|
451
|
-
|
|
452
|
-
<Box flexDirection="column">
|
|
453
|
-
<Text bold color="cyan">
|
|
454
|
-
{figures.pointerSmall} Architecture
|
|
455
|
-
</Text>
|
|
456
|
-
<Text color="white">{result.architecture}</Text>
|
|
457
|
-
</Box>
|
|
458
|
-
|
|
459
|
-
<Box flexDirection="column">
|
|
460
|
-
<Text bold color="cyan">
|
|
461
|
-
{figures.pointerSmall} Tooling
|
|
462
|
-
</Text>
|
|
463
|
-
{Object.entries(result.tooling ?? {}).map(([k, v]) => (
|
|
464
|
-
<Text key={k} color="white">
|
|
465
|
-
{" "}
|
|
466
|
-
{figures.bullet} <Text bold>{k}</Text>: {v}
|
|
467
|
-
</Text>
|
|
468
|
-
))}
|
|
469
|
-
</Box>
|
|
470
|
-
|
|
471
|
-
<Box flexDirection="column">
|
|
472
|
-
<Text bold color="cyan">
|
|
473
|
-
{figures.pointerSmall} Important Folders
|
|
474
|
-
</Text>
|
|
475
|
-
{result.importantFolders.map((f) => (
|
|
476
|
-
<Text key={f} color="white">
|
|
477
|
-
{" "}
|
|
478
|
-
{figures.bullet} {f}
|
|
479
|
-
</Text>
|
|
480
|
-
))}
|
|
481
|
-
</Box>
|
|
482
|
-
|
|
483
|
-
<Box flexDirection="column">
|
|
484
|
-
<Text bold color="cyan">
|
|
485
|
-
{figures.pointerSmall} Key Files
|
|
486
|
-
</Text>
|
|
487
|
-
{(result.keyFiles ?? []).map((f) => (
|
|
488
|
-
<Text key={f} color="white">
|
|
489
|
-
{" "}
|
|
490
|
-
{figures.bullet} {f}
|
|
491
|
-
</Text>
|
|
492
|
-
))}
|
|
493
|
-
</Box>
|
|
494
|
-
|
|
495
|
-
<Box flexDirection="column">
|
|
496
|
-
<Text bold color="cyan">
|
|
497
|
-
{figures.pointerSmall} Patterns & Idioms
|
|
498
|
-
</Text>
|
|
499
|
-
{(result.patterns ?? []).map((p) => (
|
|
500
|
-
<Text key={p} color="white">
|
|
501
|
-
{" "}
|
|
502
|
-
{figures.bullet} {p}
|
|
503
|
-
</Text>
|
|
504
|
-
))}
|
|
505
|
-
</Box>
|
|
506
|
-
|
|
507
|
-
<Box flexDirection="column">
|
|
508
|
-
<Text bold color="green">
|
|
509
|
-
{figures.tick} Suggestions
|
|
510
|
-
</Text>
|
|
511
|
-
{result.suggestions.map((s) => (
|
|
512
|
-
<Text key={s} color="white">
|
|
513
|
-
{" "}
|
|
514
|
-
{figures.bullet} {s}
|
|
515
|
-
</Text>
|
|
516
|
-
))}
|
|
517
|
-
</Box>
|
|
518
|
-
|
|
519
|
-
<Box flexDirection="column" marginTop={1} gap={1}>
|
|
520
|
-
<Text bold color="cyan">
|
|
521
|
-
Actions
|
|
522
|
-
</Text>
|
|
523
|
-
<Box gap={2}>
|
|
524
|
-
{OPTIONS.map((f, i) => (
|
|
525
|
-
<Text key={f} color={selectedOutput === i ? "cyan" : "gray"}>
|
|
526
|
-
{selectedOutput === i ? figures.arrowRight : " "} {f}
|
|
527
|
-
</Text>
|
|
528
|
-
))}
|
|
529
|
-
</Box>
|
|
530
|
-
<Text color="gray">← → switch · enter to select · esc to skip</Text>
|
|
531
|
-
</Box>
|
|
532
|
-
</Box>
|
|
533
|
-
);
|
|
534
|
-
};
|