@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
package/src/tools/web.ts
DELETED
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
function stripTags(html: string): string {
|
|
2
|
-
return html
|
|
3
|
-
.replace(/<[^>]+>/g, " ")
|
|
4
|
-
.replace(/ /g, " ")
|
|
5
|
-
.replace(/&/g, "&")
|
|
6
|
-
.replace(/</g, "<")
|
|
7
|
-
.replace(/>/g, ">")
|
|
8
|
-
.replace(/"/g, '"')
|
|
9
|
-
.replace(/&#\d+;/g, " ")
|
|
10
|
-
.replace(/\s+/g, " ")
|
|
11
|
-
.trim();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function extractTables(html: string): string {
|
|
15
|
-
const tables: string[] = [];
|
|
16
|
-
const tableRe = /<table[\s\S]*?<\/table>/gi;
|
|
17
|
-
let tMatch: RegExpExecArray | null;
|
|
18
|
-
|
|
19
|
-
while ((tMatch = tableRe.exec(html)) !== null) {
|
|
20
|
-
const tableHtml = tMatch[0]!;
|
|
21
|
-
const rows: string[][] = [];
|
|
22
|
-
const rowRe = /<tr[\s\S]*?<\/tr>/gi;
|
|
23
|
-
let rMatch: RegExpExecArray | null;
|
|
24
|
-
while ((rMatch = rowRe.exec(tableHtml)) !== null) {
|
|
25
|
-
const cells: string[] = [];
|
|
26
|
-
const cellRe = /<t[dh][^>]*>([\s\S]*?)<\/t[dh]>/gi;
|
|
27
|
-
let cMatch: RegExpExecArray | null;
|
|
28
|
-
while ((cMatch = cellRe.exec(rMatch[0]!)) !== null) {
|
|
29
|
-
cells.push(stripTags(cMatch[1] ?? ""));
|
|
30
|
-
}
|
|
31
|
-
if (cells.length > 0) rows.push(cells);
|
|
32
|
-
}
|
|
33
|
-
if (rows.length < 2) continue;
|
|
34
|
-
const cols = Math.max(...rows.map((r) => r.length));
|
|
35
|
-
const padded = rows.map((r) => {
|
|
36
|
-
while (r.length < cols) r.push("");
|
|
37
|
-
return r;
|
|
38
|
-
});
|
|
39
|
-
const widths = Array.from({ length: cols }, (_, ci) =>
|
|
40
|
-
Math.max(...padded.map((r) => (r[ci] ?? "").length), 3),
|
|
41
|
-
);
|
|
42
|
-
const fmt = (r: string[]) =>
|
|
43
|
-
r.map((c, ci) => c.padEnd(widths[ci] ?? 0)).join(" | ");
|
|
44
|
-
const header = fmt(padded[0]!);
|
|
45
|
-
const sep = widths.map((w) => "-".repeat(w)).join("-|-");
|
|
46
|
-
const body = padded.slice(1).map(fmt).join("\n");
|
|
47
|
-
tables.push(`${header}\n${sep}\n${body}`);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return tables.length > 0
|
|
51
|
-
? `=== TABLES (${tables.length}) ===\n\n${tables.join("\n\n---\n\n")}`
|
|
52
|
-
: "";
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function extractLists(html: string): string {
|
|
56
|
-
const lists: string[] = [];
|
|
57
|
-
const listRe = /<[ou]l[\s\S]*?<\/[ou]l>/gi;
|
|
58
|
-
let lMatch: RegExpExecArray | null;
|
|
59
|
-
while ((lMatch = listRe.exec(html)) !== null) {
|
|
60
|
-
const items: string[] = [];
|
|
61
|
-
const itemRe = /<li[^>]*>([\s\S]*?)<\/li>/gi;
|
|
62
|
-
let iMatch: RegExpExecArray | null;
|
|
63
|
-
while ((iMatch = itemRe.exec(lMatch[0]!)) !== null) {
|
|
64
|
-
const text = stripTags(iMatch[1] ?? "");
|
|
65
|
-
if (text.length > 2) items.push(`• ${text}`);
|
|
66
|
-
}
|
|
67
|
-
if (items.length > 1) lists.push(items.join("\n"));
|
|
68
|
-
}
|
|
69
|
-
return lists.length > 0
|
|
70
|
-
? `=== LISTS ===\n\n${lists.slice(0, 5).join("\n\n")}`
|
|
71
|
-
: "";
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export async function fetchUrl(url: string): Promise<string> {
|
|
75
|
-
const res = await fetch(url, {
|
|
76
|
-
headers: {
|
|
77
|
-
"User-Agent":
|
|
78
|
-
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
|
79
|
-
Accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
80
|
-
"Accept-Language": "en-US,en;q=0.5",
|
|
81
|
-
},
|
|
82
|
-
signal: AbortSignal.timeout(15000),
|
|
83
|
-
});
|
|
84
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
|
85
|
-
|
|
86
|
-
const contentType = res.headers.get("content-type") ?? "";
|
|
87
|
-
if (contentType.includes("application/json")) {
|
|
88
|
-
const json = await res.json();
|
|
89
|
-
return JSON.stringify(json, null, 2).slice(0, 8000);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const html = await res.text();
|
|
93
|
-
const titleMatch = html.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
|
|
94
|
-
const title = titleMatch ? stripTags(titleMatch[1]!) : "No title";
|
|
95
|
-
|
|
96
|
-
const tables = extractTables(html);
|
|
97
|
-
const lists = extractLists(html);
|
|
98
|
-
const bodyText = stripTags(
|
|
99
|
-
html
|
|
100
|
-
.replace(/<script[\s\S]*?<\/script>/gi, "")
|
|
101
|
-
.replace(/<style[\s\S]*?<\/style>/gi, "")
|
|
102
|
-
.replace(/<nav[\s\S]*?<\/nav>/gi, "")
|
|
103
|
-
.replace(/<footer[\s\S]*?<\/footer>/gi, "")
|
|
104
|
-
.replace(/<header[\s\S]*?<\/header>/gi, ""),
|
|
105
|
-
)
|
|
106
|
-
.replace(/\s{3,}/g, "\n\n")
|
|
107
|
-
.slice(0, 3000);
|
|
108
|
-
|
|
109
|
-
const parts = [`PAGE: ${title}`, `URL: ${url}`];
|
|
110
|
-
if (tables) parts.push(tables);
|
|
111
|
-
if (lists) parts.push(lists);
|
|
112
|
-
parts.push(`=== TEXT ===\n${bodyText}`);
|
|
113
|
-
return parts.join("\n\n");
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// ── Search ────────────────────────────────────────────────────────────────────
|
|
117
|
-
|
|
118
|
-
export async function searchWeb(query: string): Promise<string> {
|
|
119
|
-
const encoded = encodeURIComponent(query);
|
|
120
|
-
|
|
121
|
-
const ddgUrl = `https://api.duckduckgo.com/?q=${encoded}&format=json&no_html=1&skip_disambig=1`;
|
|
122
|
-
try {
|
|
123
|
-
const res = await fetch(ddgUrl, {
|
|
124
|
-
headers: { "User-Agent": "Lens/1.0" },
|
|
125
|
-
signal: AbortSignal.timeout(8000),
|
|
126
|
-
});
|
|
127
|
-
if (res.ok) {
|
|
128
|
-
const data = (await res.json()) as {
|
|
129
|
-
AbstractText?: string;
|
|
130
|
-
AbstractURL?: string;
|
|
131
|
-
RelatedTopics?: { Text?: string; FirstURL?: string }[];
|
|
132
|
-
Answer?: string;
|
|
133
|
-
Infobox?: { content?: { label: string; value: string }[] };
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
const parts: string[] = [`Search: ${query}`];
|
|
137
|
-
if (data.Answer) parts.push(`Answer: ${data.Answer}`);
|
|
138
|
-
if (data.AbstractText) {
|
|
139
|
-
parts.push(`Summary: ${data.AbstractText}`);
|
|
140
|
-
if (data.AbstractURL) parts.push(`Source: ${data.AbstractURL}`);
|
|
141
|
-
}
|
|
142
|
-
if (data.Infobox?.content?.length) {
|
|
143
|
-
const fields = data.Infobox.content
|
|
144
|
-
.slice(0, 8)
|
|
145
|
-
.map((f) => ` ${f.label}: ${f.value}`)
|
|
146
|
-
.join("\n");
|
|
147
|
-
parts.push(`Info:\n${fields}`);
|
|
148
|
-
}
|
|
149
|
-
if (data.RelatedTopics?.length) {
|
|
150
|
-
const topics = (data.RelatedTopics as { Text?: string }[])
|
|
151
|
-
.filter((t) => t.Text)
|
|
152
|
-
.slice(0, 5)
|
|
153
|
-
.map((t) => ` - ${t.Text}`)
|
|
154
|
-
.join("\n");
|
|
155
|
-
if (topics) parts.push(`Related:\n${topics}`);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const result = parts.join("\n\n");
|
|
159
|
-
if (result.length > 60) return result;
|
|
160
|
-
}
|
|
161
|
-
} catch {
|
|
162
|
-
// fall through to HTML scrape
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
try {
|
|
166
|
-
const htmlUrl = `https://html.duckduckgo.com/html/?q=${encoded}`;
|
|
167
|
-
const res = await fetch(htmlUrl, {
|
|
168
|
-
headers: {
|
|
169
|
-
"User-Agent":
|
|
170
|
-
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
|
171
|
-
Accept: "text/html",
|
|
172
|
-
},
|
|
173
|
-
signal: AbortSignal.timeout(10000),
|
|
174
|
-
});
|
|
175
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
176
|
-
const html = await res.text();
|
|
177
|
-
|
|
178
|
-
const snippets: string[] = [];
|
|
179
|
-
const snippetRe = /class="result__snippet"[^>]*>([\s\S]*?)<\/a>/g;
|
|
180
|
-
let m: RegExpExecArray | null;
|
|
181
|
-
while ((m = snippetRe.exec(html)) !== null && snippets.length < 6) {
|
|
182
|
-
const text = m[1]!
|
|
183
|
-
.replace(/<[^>]+>/g, " ")
|
|
184
|
-
.replace(/ /g, " ")
|
|
185
|
-
.replace(/&/g, "&")
|
|
186
|
-
.replace(/</g, "<")
|
|
187
|
-
.replace(/>/g, ">")
|
|
188
|
-
.replace(/"/g, '"')
|
|
189
|
-
.replace(/\s+/g, " ")
|
|
190
|
-
.trim();
|
|
191
|
-
if (text.length > 20) snippets.push(`- ${text}`);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const links: string[] = [];
|
|
195
|
-
const linkRe = /class="result__a"[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/g;
|
|
196
|
-
while ((m = linkRe.exec(html)) !== null && links.length < 5) {
|
|
197
|
-
const title = m[2]!.replace(/<[^>]+>/g, "").trim();
|
|
198
|
-
const href = m[1]!;
|
|
199
|
-
if (title && href) links.push(` ${title} \u2014 ${href}`);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
if (snippets.length === 0 && links.length === 0)
|
|
203
|
-
return `No results found for: ${query}`;
|
|
204
|
-
|
|
205
|
-
const parts = [`Search results for: ${query}`];
|
|
206
|
-
if (snippets.length > 0) parts.push(`Snippets:\n${snippets.join("\n")}`);
|
|
207
|
-
if (links.length > 0) parts.push(`Links:\n${links.join("\n")}`);
|
|
208
|
-
return parts.join("\n\n");
|
|
209
|
-
} catch (err) {
|
|
210
|
-
return `Search failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
211
|
-
}
|
|
212
|
-
}
|
package/src/types/chat.ts
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import type { FilePatch, DiffLine } from "../components/repo/DiffViewer";
|
|
2
|
-
|
|
3
|
-
// ── Tool calls ────────────────────────────────────────────────────────────────
|
|
4
|
-
|
|
5
|
-
export type ToolCall =
|
|
6
|
-
| { type: "shell"; command: string }
|
|
7
|
-
| { type: "fetch"; url: string }
|
|
8
|
-
| { type: "read-file"; filePath: string }
|
|
9
|
-
| { type: "read-folder"; folderPath: string }
|
|
10
|
-
| { type: "grep"; pattern: string; glob: string }
|
|
11
|
-
| { type: "write-file"; filePath: string; fileContent: string }
|
|
12
|
-
| { type: "delete-file"; filePath: string }
|
|
13
|
-
| { type: "delete-folder"; folderPath: string }
|
|
14
|
-
| { type: "open-url"; url: string }
|
|
15
|
-
| { type: "generate-pdf"; filePath: string; content: string }
|
|
16
|
-
| { type: "search"; query: string };
|
|
17
|
-
|
|
18
|
-
// ── Messages ──────────────────────────────────────────────────────────────────
|
|
19
|
-
|
|
20
|
-
export type Message =
|
|
21
|
-
| { role: "user" | "assistant"; type: "text"; content: string }
|
|
22
|
-
| {
|
|
23
|
-
role: "assistant";
|
|
24
|
-
type: "tool";
|
|
25
|
-
toolName:
|
|
26
|
-
| "shell"
|
|
27
|
-
| "fetch"
|
|
28
|
-
| "read-file"
|
|
29
|
-
| "read-folder"
|
|
30
|
-
| "grep"
|
|
31
|
-
| "write-file"
|
|
32
|
-
| "delete-file"
|
|
33
|
-
| "delete-folder"
|
|
34
|
-
| "open-url"
|
|
35
|
-
| "generate-pdf"
|
|
36
|
-
| "search";
|
|
37
|
-
content: string;
|
|
38
|
-
result: string;
|
|
39
|
-
approved: boolean;
|
|
40
|
-
}
|
|
41
|
-
| {
|
|
42
|
-
role: "assistant";
|
|
43
|
-
type: "plan";
|
|
44
|
-
content: string;
|
|
45
|
-
patches: FilePatch[];
|
|
46
|
-
applied: boolean;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
// ── Chat stage ────────────────────────────────────────────────────────────────
|
|
50
|
-
|
|
51
|
-
export type ChatStage =
|
|
52
|
-
| { type: "picking-provider" }
|
|
53
|
-
| { type: "loading" }
|
|
54
|
-
| { type: "idle" }
|
|
55
|
-
| { type: "thinking" }
|
|
56
|
-
| { type: "error"; message: string }
|
|
57
|
-
| {
|
|
58
|
-
type: "permission";
|
|
59
|
-
tool: ToolCall;
|
|
60
|
-
pendingMessages: Message[];
|
|
61
|
-
resolve: (approved: boolean) => void;
|
|
62
|
-
}
|
|
63
|
-
| {
|
|
64
|
-
type: "preview";
|
|
65
|
-
patches: FilePatch[];
|
|
66
|
-
diffLines: DiffLine[][];
|
|
67
|
-
scrollOffset: number;
|
|
68
|
-
pendingMessages: Message[];
|
|
69
|
-
}
|
|
70
|
-
| {
|
|
71
|
-
type: "viewing-file";
|
|
72
|
-
file: { path: string; isNew: boolean; patch: FilePatch };
|
|
73
|
-
diffLines: DiffLine[];
|
|
74
|
-
scrollOffset: number;
|
|
75
|
-
}
|
|
76
|
-
| { type: "clone-offer"; repoUrl: string; launchAnalysis?: boolean }
|
|
77
|
-
| { type: "cloning"; repoUrl: string }
|
|
78
|
-
| { type: "clone-exists"; repoUrl: string; repoPath: string }
|
|
79
|
-
| {
|
|
80
|
-
type: "clone-done";
|
|
81
|
-
repoUrl: string;
|
|
82
|
-
destPath: string;
|
|
83
|
-
fileCount: number;
|
|
84
|
-
launchAnalysis?: boolean;
|
|
85
|
-
}
|
|
86
|
-
| { type: "clone-error"; message: string };
|
package/src/types/config.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export type ProviderType =
|
|
2
|
-
| "anthropic"
|
|
3
|
-
| "gemini"
|
|
4
|
-
| "openai"
|
|
5
|
-
| "ollama"
|
|
6
|
-
| "custom";
|
|
7
|
-
|
|
8
|
-
export type Provider = {
|
|
9
|
-
id: string;
|
|
10
|
-
type: ProviderType;
|
|
11
|
-
name: string;
|
|
12
|
-
apiKey?: string;
|
|
13
|
-
baseUrl?: string;
|
|
14
|
-
model: string;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export type Config = {
|
|
18
|
-
providers: Provider[];
|
|
19
|
-
defaultProviderId?: string;
|
|
20
|
-
};
|
package/src/types/repo.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
export type Step =
|
|
2
|
-
| { type: "cloning"; status: "pending" | "done" }
|
|
3
|
-
| { type: "folder-exists"; status: "pending"; repoPath: string }
|
|
4
|
-
| { type: "fetching-tree"; status: "pending" | "done" }
|
|
5
|
-
| { type: "reading-files"; status: "pending" | "done" }
|
|
6
|
-
| { type: "error"; message: string };
|
|
7
|
-
|
|
8
|
-
export type ReviewStage = "list" | "file";
|
|
9
|
-
|
|
10
|
-
export type FileTree = {
|
|
11
|
-
name: string;
|
|
12
|
-
children?: FileTree[];
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export type ImportantFile = {
|
|
16
|
-
path: string;
|
|
17
|
-
content: string;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export type AIProvider =
|
|
21
|
-
| "anthropic"
|
|
22
|
-
| "gemini"
|
|
23
|
-
| "ollama"
|
|
24
|
-
| "openai"
|
|
25
|
-
| "custom";
|
|
26
|
-
|
|
27
|
-
export type AnalysisResult = {
|
|
28
|
-
overview: string;
|
|
29
|
-
importantFolders: string[];
|
|
30
|
-
|
|
31
|
-
tooling: Record<string, string>;
|
|
32
|
-
|
|
33
|
-
keyFiles: string[];
|
|
34
|
-
|
|
35
|
-
patterns: string[];
|
|
36
|
-
|
|
37
|
-
architecture: string;
|
|
38
|
-
suggestions: string[];
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export type PackageManager =
|
|
42
|
-
| "npm"
|
|
43
|
-
| "yarn"
|
|
44
|
-
| "pnpm"
|
|
45
|
-
| "bun"
|
|
46
|
-
| "pip"
|
|
47
|
-
| "unknown";
|
|
48
|
-
|
|
49
|
-
export type PreviewInfo = {
|
|
50
|
-
packageManager: PackageManager;
|
|
51
|
-
installCmd: string;
|
|
52
|
-
devCmd: string;
|
|
53
|
-
port: number | null;
|
|
54
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import os from "os";
|
|
3
|
-
import { existsSync, readdirSync } from "fs";
|
|
4
|
-
import { pathToFileURL } from "url";
|
|
5
|
-
|
|
6
|
-
const ADDONS_DIR = path.join(os.homedir(), ".lens", "addons");
|
|
7
|
-
|
|
8
|
-
export async function loadAddons(): Promise<void> {
|
|
9
|
-
if (!existsSync(ADDONS_DIR)) {
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const files = readdirSync(ADDONS_DIR).filter(
|
|
14
|
-
(f) => f.endsWith(".js") && !f.startsWith("_"),
|
|
15
|
-
);
|
|
16
|
-
|
|
17
|
-
for (let i = 0; i < files.length; i++) {
|
|
18
|
-
const file = files[i];
|
|
19
|
-
if (!file) return;
|
|
20
|
-
|
|
21
|
-
const fullPath = path.join(ADDONS_DIR, file);
|
|
22
|
-
const fileUrl = pathToFileURL(fullPath).href;
|
|
23
|
-
const isLast = i === files.length - 1;
|
|
24
|
-
try {
|
|
25
|
-
await import(fileUrl);
|
|
26
|
-
console.log(`[addons] loaded: ${file}${isLast ? "\n" : ""}`);
|
|
27
|
-
} catch (err) {
|
|
28
|
-
console.error(
|
|
29
|
-
`[addons] failed to load ${file}:`,
|
|
30
|
-
err instanceof Error ? err.message : String(err),
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|