@burdenoff/vibe-agent 1.0.1 → 1.0.3
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/README.md +14 -14
- package/dist/app.d.ts +4 -4
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +145 -130
- package/dist/app.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +463 -333
- package/dist/cli.js.map +1 -1
- package/dist/db/schema.d.ts +15 -15
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +65 -62
- package/dist/db/schema.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +18 -18
- package/dist/index.js.map +1 -1
- package/dist/middleware/ModuleAuth.d.ts +2 -2
- package/dist/middleware/ModuleAuth.d.ts.map +1 -1
- package/dist/middleware/ModuleAuth.js +32 -29
- package/dist/middleware/ModuleAuth.js.map +1 -1
- package/dist/middleware/auth.d.ts +1 -1
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +4 -4
- package/dist/middleware/auth.js.map +1 -1
- package/dist/migrations/remove-notes-prompts.d.ts.map +1 -1
- package/dist/migrations/remove-notes-prompts.js +26 -26
- package/dist/migrations/remove-notes-prompts.js.map +1 -1
- package/dist/routes/bookmarks.d.ts +1 -1
- package/dist/routes/bookmarks.d.ts.map +1 -1
- package/dist/routes/bookmarks.js +53 -44
- package/dist/routes/bookmarks.js.map +1 -1
- package/dist/routes/config.d.ts +1 -1
- package/dist/routes/config.d.ts.map +1 -1
- package/dist/routes/config.js +29 -27
- package/dist/routes/config.js.map +1 -1
- package/dist/routes/files.d.ts +1 -1
- package/dist/routes/files.d.ts.map +1 -1
- package/dist/routes/files.js +175 -134
- package/dist/routes/files.js.map +1 -1
- package/dist/routes/git.d.ts +1 -1
- package/dist/routes/git.d.ts.map +1 -1
- package/dist/routes/git.js +183 -169
- package/dist/routes/git.js.map +1 -1
- package/dist/routes/moduleRegistry.d.ts +3 -3
- package/dist/routes/moduleRegistry.d.ts.map +1 -1
- package/dist/routes/moduleRegistry.js +58 -58
- package/dist/routes/moduleRegistry.js.map +1 -1
- package/dist/routes/notifications.d.ts +1 -1
- package/dist/routes/notifications.d.ts.map +1 -1
- package/dist/routes/notifications.js +69 -64
- package/dist/routes/notifications.js.map +1 -1
- package/dist/routes/port-forward.d.ts +1 -1
- package/dist/routes/port-forward.d.ts.map +1 -1
- package/dist/routes/port-forward.js +59 -50
- package/dist/routes/port-forward.js.map +1 -1
- package/dist/routes/projects.d.ts +1 -1
- package/dist/routes/projects.d.ts.map +1 -1
- package/dist/routes/projects.js +134 -120
- package/dist/routes/projects.js.map +1 -1
- package/dist/routes/ssh.d.ts +1 -1
- package/dist/routes/ssh.d.ts.map +1 -1
- package/dist/routes/ssh.js +47 -47
- package/dist/routes/ssh.js.map +1 -1
- package/dist/routes/tasks.d.ts +1 -1
- package/dist/routes/tasks.d.ts.map +1 -1
- package/dist/routes/tasks.js +53 -49
- package/dist/routes/tasks.js.map +1 -1
- package/dist/routes/tmux.d.ts +1 -1
- package/dist/routes/tmux.d.ts.map +1 -1
- package/dist/routes/tmux.js +337 -241
- package/dist/routes/tmux.js.map +1 -1
- package/dist/routes/tunnel.d.ts +2 -2
- package/dist/routes/tunnel.d.ts.map +1 -1
- package/dist/routes/tunnel.js +115 -74
- package/dist/routes/tunnel.js.map +1 -1
- package/dist/services/ModulePermissions.d.ts +2 -2
- package/dist/services/ModulePermissions.d.ts.map +1 -1
- package/dist/services/ModulePermissions.js +50 -40
- package/dist/services/ModulePermissions.js.map +1 -1
- package/dist/services/ModuleRegistryService.d.ts +10 -10
- package/dist/services/ModuleRegistryService.d.ts.map +1 -1
- package/dist/services/ModuleRegistryService.js +156 -131
- package/dist/services/ModuleRegistryService.js.map +1 -1
- package/dist/services/agent.service.d.ts.map +1 -1
- package/dist/services/agent.service.js +24 -21
- package/dist/services/agent.service.js.map +1 -1
- package/dist/services/bootstrap.d.ts +1 -1
- package/dist/services/bootstrap.d.ts.map +1 -1
- package/dist/services/bootstrap.js +146 -69
- package/dist/services/bootstrap.js.map +1 -1
- package/dist/services/service-manager.d.ts +2 -2
- package/dist/services/service-manager.d.ts.map +1 -1
- package/dist/services/service-manager.js +75 -63
- package/dist/services/service-manager.js.map +1 -1
- package/package.json +1 -1
package/dist/routes/git.js
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import { v4 as uuidv4 } from
|
|
2
|
-
import { promises as fs, readFileSync } from
|
|
3
|
-
import path from
|
|
1
|
+
import { v4 as uuidv4 } from "uuid";
|
|
2
|
+
import { promises as fs, readFileSync } from "fs";
|
|
3
|
+
import path from "path";
|
|
4
4
|
export const gitRoutes = async (fastify) => {
|
|
5
5
|
// Get all git repositories
|
|
6
|
-
fastify.get(
|
|
6
|
+
fastify.get("/", async (_request, _reply) => {
|
|
7
7
|
const repositories = fastify.db.getAllGitRepositories();
|
|
8
8
|
return { repositories };
|
|
9
9
|
});
|
|
10
10
|
// Get repository by ID
|
|
11
|
-
fastify.get(
|
|
11
|
+
fastify.get("/:id", async (request, reply) => {
|
|
12
12
|
const { id } = request.params;
|
|
13
13
|
const repository = fastify.db.getGitRepository(id);
|
|
14
14
|
if (!repository) {
|
|
15
|
-
return reply.code(404).send({ error:
|
|
15
|
+
return reply.code(404).send({ error: "Repository not found" });
|
|
16
16
|
}
|
|
17
17
|
return { repository };
|
|
18
18
|
});
|
|
19
19
|
// Scan directory for git repositories
|
|
20
|
-
fastify.post(
|
|
20
|
+
fastify.post("/scan", async (request, reply) => {
|
|
21
21
|
const { directory, includeSubmodules = true } = request.body;
|
|
22
22
|
try {
|
|
23
23
|
// Validate directory exists
|
|
24
24
|
const stats = await fs.stat(directory);
|
|
25
25
|
if (!stats.isDirectory()) {
|
|
26
|
-
return reply.code(400).send({ error:
|
|
26
|
+
return reply.code(400).send({ error: "Path is not a directory" });
|
|
27
27
|
}
|
|
28
28
|
const repositories = await scanForGitRepositories(directory, includeSubmodules);
|
|
29
29
|
// Save repositories to database
|
|
@@ -39,42 +39,42 @@ export const gitRoutes = async (fastify) => {
|
|
|
39
39
|
// Create new repository
|
|
40
40
|
const newRepo = fastify.db.createGitRepository({
|
|
41
41
|
id: uuidv4(),
|
|
42
|
-
...repo
|
|
42
|
+
...repo,
|
|
43
43
|
});
|
|
44
44
|
savedRepos.push(newRepo);
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
// Emit scan complete event
|
|
48
|
-
fastify.io.emit(
|
|
48
|
+
fastify.io.emit("git:scan-complete", {
|
|
49
49
|
directory,
|
|
50
|
-
count: savedRepos.length
|
|
50
|
+
count: savedRepos.length,
|
|
51
51
|
});
|
|
52
52
|
return {
|
|
53
53
|
repositories: savedRepos,
|
|
54
54
|
scannedPath: directory,
|
|
55
|
-
totalFound: savedRepos.length
|
|
55
|
+
totalFound: savedRepos.length,
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
58
|
catch (error) {
|
|
59
59
|
return reply.code(500).send({
|
|
60
|
-
error:
|
|
61
|
-
details: error instanceof Error ? error.message :
|
|
60
|
+
error: "Failed to scan directory",
|
|
61
|
+
details: error instanceof Error ? error.message : "Unknown error",
|
|
62
62
|
});
|
|
63
63
|
}
|
|
64
64
|
});
|
|
65
65
|
// Scan remote directory via SSH
|
|
66
|
-
fastify.post(
|
|
67
|
-
const { connectionId, directory, includeSubmodules = true } = request.body;
|
|
66
|
+
fastify.post("/scan-remote", async (request, reply) => {
|
|
67
|
+
const { connectionId, directory, includeSubmodules = true, } = request.body;
|
|
68
68
|
try {
|
|
69
69
|
const connectionConfig = fastify.db.getSSHConnection(connectionId);
|
|
70
70
|
if (!connectionConfig) {
|
|
71
|
-
return reply.code(404).send({ error:
|
|
71
|
+
return reply.code(404).send({ error: "SSH connection not found" });
|
|
72
72
|
}
|
|
73
73
|
// Use SSH to scan remote directory
|
|
74
|
-
const { Client } = await import(
|
|
74
|
+
const { Client } = await import("ssh2");
|
|
75
75
|
const conn = new Client();
|
|
76
76
|
return new Promise((resolve) => {
|
|
77
|
-
conn.on(
|
|
77
|
+
conn.on("ready", () => {
|
|
78
78
|
// Command to find git repositories
|
|
79
79
|
const findCommand = includeSubmodules
|
|
80
80
|
? `find ${directory} -name ".git" -type d 2>/dev/null | sed 's/\\/.git$//'`
|
|
@@ -83,42 +83,42 @@ export const gitRoutes = async (fastify) => {
|
|
|
83
83
|
if (err) {
|
|
84
84
|
conn.end();
|
|
85
85
|
return resolve(reply.code(500).send({
|
|
86
|
-
error:
|
|
87
|
-
details: err.message
|
|
86
|
+
error: "Failed to execute remote command",
|
|
87
|
+
details: err.message,
|
|
88
88
|
}));
|
|
89
89
|
}
|
|
90
|
-
let output =
|
|
91
|
-
stream.on(
|
|
90
|
+
let output = "";
|
|
91
|
+
stream.on("data", (data) => {
|
|
92
92
|
output += data.toString();
|
|
93
93
|
});
|
|
94
|
-
stream.on(
|
|
94
|
+
stream.on("close", async () => {
|
|
95
95
|
conn.end();
|
|
96
|
-
const paths = output.split(
|
|
96
|
+
const paths = output.split("\n").filter((p) => p.trim());
|
|
97
97
|
const repositories = [];
|
|
98
98
|
for (const repoPath of paths) {
|
|
99
99
|
const name = path.basename(repoPath);
|
|
100
|
-
const parentPath = paths.find(p => p !== repoPath && repoPath.startsWith(p +
|
|
100
|
+
const parentPath = paths.find((p) => p !== repoPath && repoPath.startsWith(p + "/"));
|
|
101
101
|
repositories.push({
|
|
102
102
|
path: repoPath,
|
|
103
103
|
name,
|
|
104
104
|
parentPath: parentPath || undefined,
|
|
105
105
|
isSubmodule: !!parentPath,
|
|
106
|
-
projectType: await detectProjectType(repoPath, true)
|
|
106
|
+
projectType: await detectProjectType(repoPath, true),
|
|
107
107
|
});
|
|
108
108
|
}
|
|
109
109
|
resolve({
|
|
110
110
|
repositories,
|
|
111
111
|
scannedPath: directory,
|
|
112
112
|
connectionId,
|
|
113
|
-
totalFound: repositories.length
|
|
113
|
+
totalFound: repositories.length,
|
|
114
114
|
});
|
|
115
115
|
});
|
|
116
116
|
});
|
|
117
117
|
});
|
|
118
|
-
conn.on(
|
|
118
|
+
conn.on("error", (err) => {
|
|
119
119
|
resolve(reply.code(500).send({
|
|
120
|
-
error:
|
|
121
|
-
details: err.message
|
|
120
|
+
error: "SSH connection failed",
|
|
121
|
+
details: err.message,
|
|
122
122
|
}));
|
|
123
123
|
});
|
|
124
124
|
// Connect with appropriate auth
|
|
@@ -138,68 +138,67 @@ export const gitRoutes = async (fastify) => {
|
|
|
138
138
|
}
|
|
139
139
|
catch (error) {
|
|
140
140
|
return reply.code(500).send({
|
|
141
|
-
error:
|
|
142
|
-
details: error instanceof Error ? error.message :
|
|
141
|
+
error: "Failed to scan remote directory",
|
|
142
|
+
details: error instanceof Error ? error.message : "Unknown error",
|
|
143
143
|
});
|
|
144
144
|
}
|
|
145
145
|
});
|
|
146
146
|
// Update repository metadata
|
|
147
|
-
fastify.put(
|
|
147
|
+
fastify.put("/:id", async (request, reply) => {
|
|
148
148
|
const { id } = request.params;
|
|
149
149
|
const updates = request.body;
|
|
150
150
|
try {
|
|
151
151
|
const repository = fastify.db.getGitRepository(id);
|
|
152
152
|
if (!repository) {
|
|
153
|
-
return reply.code(404).send({ error:
|
|
153
|
+
return reply.code(404).send({ error: "Repository not found" });
|
|
154
154
|
}
|
|
155
155
|
fastify.db.updateGitRepository(id, updates);
|
|
156
156
|
return { success: true };
|
|
157
157
|
}
|
|
158
158
|
catch (error) {
|
|
159
159
|
return reply.code(500).send({
|
|
160
|
-
error:
|
|
161
|
-
details: error instanceof Error ? error.message :
|
|
160
|
+
error: "Failed to update repository",
|
|
161
|
+
details: error instanceof Error ? error.message : "Unknown error",
|
|
162
162
|
});
|
|
163
163
|
}
|
|
164
164
|
});
|
|
165
165
|
// Delete repository from tracking
|
|
166
|
-
fastify.delete(
|
|
166
|
+
fastify.delete("/:id", async (request, reply) => {
|
|
167
167
|
const { id } = request.params;
|
|
168
168
|
try {
|
|
169
169
|
const repository = fastify.db.getGitRepository(id);
|
|
170
170
|
if (!repository) {
|
|
171
|
-
return reply.code(404).send({ error:
|
|
171
|
+
return reply.code(404).send({ error: "Repository not found" });
|
|
172
172
|
}
|
|
173
173
|
fastify.db.deleteGitRepository(id);
|
|
174
174
|
return { success: true };
|
|
175
175
|
}
|
|
176
176
|
catch (error) {
|
|
177
177
|
return reply.code(500).send({
|
|
178
|
-
error:
|
|
179
|
-
details: error instanceof Error ? error.message :
|
|
178
|
+
error: "Failed to delete repository",
|
|
179
|
+
details: error instanceof Error ? error.message : "Unknown error",
|
|
180
180
|
});
|
|
181
181
|
}
|
|
182
182
|
});
|
|
183
183
|
// Fix repository hierarchy
|
|
184
|
-
fastify.post(
|
|
184
|
+
fastify.post("/fix-hierarchy", async (_request, reply) => {
|
|
185
185
|
try {
|
|
186
186
|
const repositories = fastify.db.getAllGitRepositories();
|
|
187
187
|
let fixed = 0;
|
|
188
188
|
for (const repo of repositories) {
|
|
189
189
|
// Check if this repo is inside another repo
|
|
190
|
-
const parentRepo = repositories.find(r => r.path !== repo.path &&
|
|
191
|
-
repo.path.startsWith(r.path + '/'));
|
|
190
|
+
const parentRepo = repositories.find((r) => r.path !== repo.path && repo.path.startsWith(r.path + "/"));
|
|
192
191
|
if (parentRepo && repo.parentPath !== parentRepo.path) {
|
|
193
192
|
fastify.db.updateGitRepository(repo.id, {
|
|
194
193
|
parentPath: parentRepo.path,
|
|
195
|
-
isSubmodule: true
|
|
194
|
+
isSubmodule: true,
|
|
196
195
|
});
|
|
197
196
|
fixed++;
|
|
198
197
|
}
|
|
199
198
|
else if (!parentRepo && (repo.parentPath || repo.isSubmodule)) {
|
|
200
199
|
fastify.db.updateGitRepository(repo.id, {
|
|
201
200
|
parentPath: undefined,
|
|
202
|
-
isSubmodule: false
|
|
201
|
+
isSubmodule: false,
|
|
203
202
|
});
|
|
204
203
|
fixed++;
|
|
205
204
|
}
|
|
@@ -207,13 +206,13 @@ export const gitRoutes = async (fastify) => {
|
|
|
207
206
|
return {
|
|
208
207
|
success: true,
|
|
209
208
|
fixed,
|
|
210
|
-
total: repositories.length
|
|
209
|
+
total: repositories.length,
|
|
211
210
|
};
|
|
212
211
|
}
|
|
213
212
|
catch (error) {
|
|
214
213
|
return reply.code(500).send({
|
|
215
|
-
error:
|
|
216
|
-
details: error instanceof Error ? error.message :
|
|
214
|
+
error: "Failed to fix hierarchy",
|
|
215
|
+
details: error instanceof Error ? error.message : "Unknown error",
|
|
217
216
|
});
|
|
218
217
|
}
|
|
219
218
|
});
|
|
@@ -224,7 +223,7 @@ async function scanForGitRepositories(directory, includeSubmodules, parentPath)
|
|
|
224
223
|
try {
|
|
225
224
|
const entries = await fs.readdir(directory, { withFileTypes: true });
|
|
226
225
|
// Check if this directory is a git repository
|
|
227
|
-
const hasGit = entries.some(e => e.name ===
|
|
226
|
+
const hasGit = entries.some((e) => e.name === ".git" && e.isDirectory());
|
|
228
227
|
if (hasGit) {
|
|
229
228
|
const repo = {
|
|
230
229
|
path: directory,
|
|
@@ -232,7 +231,7 @@ async function scanForGitRepositories(directory, includeSubmodules, parentPath)
|
|
|
232
231
|
parentPath,
|
|
233
232
|
isSubmodule: !!parentPath,
|
|
234
233
|
projectType: await detectProjectType(directory),
|
|
235
|
-
vitePort: await detectVitePort(directory)
|
|
234
|
+
vitePort: await detectVitePort(directory),
|
|
236
235
|
};
|
|
237
236
|
repositories.push(repo);
|
|
238
237
|
// If not including submodules, return early
|
|
@@ -250,14 +249,14 @@ async function scanForGitRepositories(directory, includeSubmodules, parentPath)
|
|
|
250
249
|
// Recursively scan subdirectories
|
|
251
250
|
for (const entry of entries) {
|
|
252
251
|
if (entry.isDirectory() &&
|
|
253
|
-
entry.name !==
|
|
254
|
-
entry.name !==
|
|
255
|
-
entry.name !==
|
|
256
|
-
entry.name !==
|
|
257
|
-
entry.name !==
|
|
258
|
-
entry.name !==
|
|
259
|
-
entry.name !==
|
|
260
|
-
!entry.name.startsWith(
|
|
252
|
+
entry.name !== ".git" &&
|
|
253
|
+
entry.name !== "node_modules" &&
|
|
254
|
+
entry.name !== "__pycache__" &&
|
|
255
|
+
entry.name !== ".venv" &&
|
|
256
|
+
entry.name !== "venv" &&
|
|
257
|
+
entry.name !== "dist" &&
|
|
258
|
+
entry.name !== "build" &&
|
|
259
|
+
!entry.name.startsWith(".")) {
|
|
261
260
|
const subPath = path.join(directory, entry.name);
|
|
262
261
|
const subRepos = await scanForGitRepositories(subPath, includeSubmodules, parentPath);
|
|
263
262
|
repositories.push(...subRepos);
|
|
@@ -278,172 +277,187 @@ async function detectProjectType(directory, remote = false) {
|
|
|
278
277
|
try {
|
|
279
278
|
const entries = await fs.readdir(directory);
|
|
280
279
|
// Node.js project (check for specific frameworks too)
|
|
281
|
-
if (entries.includes(
|
|
280
|
+
if (entries.includes("package.json")) {
|
|
282
281
|
// Try to detect specific Node.js frameworks
|
|
283
282
|
try {
|
|
284
|
-
const packageJson = JSON.parse(await fs.readFile(path.join(directory,
|
|
285
|
-
const deps = {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
283
|
+
const packageJson = JSON.parse(await fs.readFile(path.join(directory, "package.json"), "utf8"));
|
|
284
|
+
const deps = {
|
|
285
|
+
...packageJson.dependencies,
|
|
286
|
+
...packageJson.devDependencies,
|
|
287
|
+
};
|
|
288
|
+
if (deps.react || deps["@types/react"])
|
|
289
|
+
return "react";
|
|
290
|
+
if (deps.vue || deps["@vue/cli"])
|
|
291
|
+
return "vue";
|
|
292
|
+
if (deps.angular || deps["@angular/core"])
|
|
293
|
+
return "angular";
|
|
294
|
+
if (deps.next || deps["@types/next"])
|
|
295
|
+
return "nextjs";
|
|
296
|
+
if (deps.nuxt || deps["@nuxt/core"])
|
|
297
|
+
return "nuxtjs";
|
|
298
|
+
if (deps.svelte || deps["@sveltejs/kit"])
|
|
299
|
+
return "svelte";
|
|
298
300
|
if (deps.express || deps.fastify || deps.koa)
|
|
299
|
-
return
|
|
301
|
+
return "nodejs-backend";
|
|
300
302
|
if (deps.electron)
|
|
301
|
-
return
|
|
303
|
+
return "electron";
|
|
302
304
|
if (deps.gatsby)
|
|
303
|
-
return
|
|
305
|
+
return "gatsby";
|
|
304
306
|
if (deps.vite)
|
|
305
|
-
return
|
|
307
|
+
return "vite";
|
|
306
308
|
}
|
|
307
309
|
catch {
|
|
308
310
|
// Fallback to generic nodejs
|
|
309
311
|
}
|
|
310
|
-
return
|
|
312
|
+
return "nodejs";
|
|
311
313
|
}
|
|
312
314
|
// Python project
|
|
313
|
-
if (entries.includes(
|
|
314
|
-
entries.includes(
|
|
315
|
-
entries.includes(
|
|
316
|
-
entries.includes(
|
|
317
|
-
entries.includes(
|
|
318
|
-
entries.includes(
|
|
319
|
-
entries.includes(
|
|
315
|
+
if (entries.includes("setup.py") ||
|
|
316
|
+
entries.includes("requirements.txt") ||
|
|
317
|
+
entries.includes("pyproject.toml") ||
|
|
318
|
+
entries.includes("Pipfile") ||
|
|
319
|
+
entries.includes("poetry.lock") ||
|
|
320
|
+
entries.includes("conda.yml") ||
|
|
321
|
+
entries.includes("environment.yml")) {
|
|
320
322
|
// Try to detect specific Python frameworks
|
|
321
323
|
try {
|
|
322
|
-
if (entries.includes(
|
|
323
|
-
return
|
|
324
|
-
if (entries.includes(
|
|
325
|
-
return
|
|
326
|
-
if (entries.includes(
|
|
327
|
-
return
|
|
328
|
-
if (entries.includes(
|
|
329
|
-
return
|
|
330
|
-
if (entries.includes(
|
|
331
|
-
const reqs = await fs.readFile(path.join(directory,
|
|
332
|
-
if (reqs.includes(
|
|
333
|
-
return
|
|
334
|
-
if (reqs.includes(
|
|
335
|
-
return
|
|
336
|
-
if (reqs.includes(
|
|
337
|
-
return
|
|
338
|
-
if (reqs.includes(
|
|
339
|
-
return
|
|
340
|
-
if (reqs.includes(
|
|
341
|
-
return
|
|
342
|
-
if (reqs.includes(
|
|
343
|
-
return
|
|
324
|
+
if (entries.includes("manage.py"))
|
|
325
|
+
return "django";
|
|
326
|
+
if (entries.includes("app.py") || entries.includes("application.py"))
|
|
327
|
+
return "flask";
|
|
328
|
+
if (entries.includes("main.py"))
|
|
329
|
+
return "fastapi";
|
|
330
|
+
if (entries.includes("streamlit_app.py"))
|
|
331
|
+
return "streamlit";
|
|
332
|
+
if (entries.includes("requirements.txt")) {
|
|
333
|
+
const reqs = await fs.readFile(path.join(directory, "requirements.txt"), "utf8");
|
|
334
|
+
if (reqs.includes("django"))
|
|
335
|
+
return "django";
|
|
336
|
+
if (reqs.includes("flask"))
|
|
337
|
+
return "flask";
|
|
338
|
+
if (reqs.includes("fastapi"))
|
|
339
|
+
return "fastapi";
|
|
340
|
+
if (reqs.includes("streamlit"))
|
|
341
|
+
return "streamlit";
|
|
342
|
+
if (reqs.includes("tensorflow") || reqs.includes("pytorch"))
|
|
343
|
+
return "python-ml";
|
|
344
|
+
if (reqs.includes("jupyter"))
|
|
345
|
+
return "jupyter";
|
|
344
346
|
}
|
|
345
347
|
}
|
|
346
348
|
catch {
|
|
347
349
|
// Fallback to generic python
|
|
348
350
|
}
|
|
349
|
-
return
|
|
351
|
+
return "python";
|
|
350
352
|
}
|
|
351
353
|
// Go project
|
|
352
|
-
if (entries.includes(
|
|
353
|
-
return
|
|
354
|
+
if (entries.includes("go.mod") || entries.includes("go.sum")) {
|
|
355
|
+
return "go";
|
|
354
356
|
}
|
|
355
357
|
// Rust project
|
|
356
|
-
if (entries.includes(
|
|
357
|
-
return
|
|
358
|
+
if (entries.includes("Cargo.toml") || entries.includes("Cargo.lock")) {
|
|
359
|
+
return "rust";
|
|
358
360
|
}
|
|
359
361
|
// Java project
|
|
360
|
-
if (entries.includes(
|
|
361
|
-
return
|
|
362
|
-
if (entries.includes(
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
362
|
+
if (entries.includes("pom.xml"))
|
|
363
|
+
return "maven";
|
|
364
|
+
if (entries.includes("build.gradle") ||
|
|
365
|
+
entries.includes("build.gradle.kts"))
|
|
366
|
+
return "gradle";
|
|
367
|
+
if (entries.some((e) => e.endsWith(".java")))
|
|
368
|
+
return "java";
|
|
366
369
|
// Ruby project
|
|
367
|
-
if (entries.includes(
|
|
370
|
+
if (entries.includes("Gemfile")) {
|
|
368
371
|
try {
|
|
369
|
-
const gemfile = await fs.readFile(path.join(directory,
|
|
370
|
-
if (gemfile.includes(
|
|
371
|
-
return
|
|
372
|
-
if (gemfile.includes(
|
|
373
|
-
return
|
|
372
|
+
const gemfile = await fs.readFile(path.join(directory, "Gemfile"), "utf8");
|
|
373
|
+
if (gemfile.includes("rails"))
|
|
374
|
+
return "rails";
|
|
375
|
+
if (gemfile.includes("sinatra"))
|
|
376
|
+
return "sinatra";
|
|
374
377
|
}
|
|
375
378
|
catch {
|
|
376
379
|
// Fallback
|
|
377
380
|
}
|
|
378
|
-
return
|
|
381
|
+
return "ruby";
|
|
379
382
|
}
|
|
380
383
|
// PHP project
|
|
381
|
-
if (entries.includes(
|
|
384
|
+
if (entries.includes("composer.json")) {
|
|
382
385
|
try {
|
|
383
|
-
const composer = JSON.parse(await fs.readFile(path.join(directory,
|
|
384
|
-
const deps = { ...composer.require, ...composer[
|
|
385
|
-
if (deps.laravel || deps[
|
|
386
|
-
return
|
|
387
|
-
if (deps.symfony || deps[
|
|
388
|
-
return
|
|
389
|
-
if (deps.wordpress || entries.includes(
|
|
390
|
-
return
|
|
386
|
+
const composer = JSON.parse(await fs.readFile(path.join(directory, "composer.json"), "utf8"));
|
|
387
|
+
const deps = { ...composer.require, ...composer["require-dev"] };
|
|
388
|
+
if (deps.laravel || deps["laravel/framework"])
|
|
389
|
+
return "laravel";
|
|
390
|
+
if (deps.symfony || deps["symfony/symfony"])
|
|
391
|
+
return "symfony";
|
|
392
|
+
if (deps.wordpress || entries.includes("wp-config.php"))
|
|
393
|
+
return "wordpress";
|
|
391
394
|
}
|
|
392
395
|
catch {
|
|
393
396
|
// Fallback
|
|
394
397
|
}
|
|
395
|
-
return
|
|
398
|
+
return "php";
|
|
396
399
|
}
|
|
397
400
|
// .NET project
|
|
398
|
-
if (entries.some(e => e.endsWith(
|
|
399
|
-
|
|
401
|
+
if (entries.some((e) => e.endsWith(".csproj") ||
|
|
402
|
+
e.endsWith(".sln") ||
|
|
403
|
+
e.endsWith(".fsproj") ||
|
|
404
|
+
e.endsWith(".vbproj"))) {
|
|
405
|
+
return "dotnet";
|
|
400
406
|
}
|
|
401
407
|
// C/C++ project
|
|
402
|
-
if (entries.includes(
|
|
403
|
-
entries.
|
|
404
|
-
|
|
408
|
+
if (entries.includes("CMakeLists.txt") ||
|
|
409
|
+
entries.includes("Makefile") ||
|
|
410
|
+
entries.some((e) => e.endsWith(".c") ||
|
|
411
|
+
e.endsWith(".cpp") ||
|
|
412
|
+
e.endsWith(".h") ||
|
|
413
|
+
e.endsWith(".hpp"))) {
|
|
414
|
+
return "cpp";
|
|
405
415
|
}
|
|
406
416
|
// Swift project
|
|
407
|
-
if (entries.includes(
|
|
408
|
-
|
|
417
|
+
if (entries.includes("Package.swift") ||
|
|
418
|
+
entries.some((e) => e.endsWith(".xcodeproj") || e.endsWith(".xcworkspace"))) {
|
|
419
|
+
return "swift";
|
|
409
420
|
}
|
|
410
421
|
// Kotlin project
|
|
411
|
-
if (entries.some(e => e.endsWith(
|
|
412
|
-
return
|
|
422
|
+
if (entries.some((e) => e.endsWith(".kt") || e.endsWith(".kts"))) {
|
|
423
|
+
return "kotlin";
|
|
413
424
|
}
|
|
414
425
|
// Scala project
|
|
415
|
-
if (entries.includes(
|
|
416
|
-
|
|
426
|
+
if (entries.includes("build.sbt") ||
|
|
427
|
+
entries.some((e) => e.endsWith(".scala"))) {
|
|
428
|
+
return "scala";
|
|
417
429
|
}
|
|
418
430
|
// R project
|
|
419
|
-
if (entries.includes(
|
|
420
|
-
|
|
431
|
+
if (entries.includes("DESCRIPTION") ||
|
|
432
|
+
entries.some((e) => e.endsWith(".R") || e.endsWith(".Rmd"))) {
|
|
433
|
+
return "r";
|
|
421
434
|
}
|
|
422
435
|
// Dart/Flutter project
|
|
423
|
-
if (entries.includes(
|
|
424
|
-
return
|
|
436
|
+
if (entries.includes("pubspec.yaml")) {
|
|
437
|
+
return "flutter";
|
|
425
438
|
}
|
|
426
439
|
// Unity project
|
|
427
|
-
if (entries.includes(
|
|
428
|
-
return
|
|
440
|
+
if (entries.includes("ProjectSettings") && entries.includes("Assets")) {
|
|
441
|
+
return "unity";
|
|
429
442
|
}
|
|
430
443
|
// Docker project
|
|
431
|
-
if (entries.includes(
|
|
432
|
-
|
|
444
|
+
if (entries.includes("Dockerfile") ||
|
|
445
|
+
entries.includes("docker-compose.yml")) {
|
|
446
|
+
return "docker";
|
|
433
447
|
}
|
|
434
448
|
// Terraform project
|
|
435
|
-
if (entries.some(e => e.endsWith(
|
|
436
|
-
return
|
|
449
|
+
if (entries.some((e) => e.endsWith(".tf") || e.endsWith(".tfvars"))) {
|
|
450
|
+
return "terraform";
|
|
437
451
|
}
|
|
438
452
|
// Documentation/Static sites
|
|
439
|
-
if (entries.includes(
|
|
440
|
-
return
|
|
441
|
-
if (entries.includes(
|
|
442
|
-
return
|
|
443
|
-
if (entries.includes(
|
|
444
|
-
return
|
|
445
|
-
if (entries.includes(
|
|
446
|
-
return
|
|
453
|
+
if (entries.includes("_config.yml"))
|
|
454
|
+
return "jekyll";
|
|
455
|
+
if (entries.includes("mkdocs.yml"))
|
|
456
|
+
return "mkdocs";
|
|
457
|
+
if (entries.includes("docusaurus.config.js"))
|
|
458
|
+
return "docusaurus";
|
|
459
|
+
if (entries.includes("hugo.toml") || entries.includes("config.toml"))
|
|
460
|
+
return "hugo";
|
|
447
461
|
}
|
|
448
462
|
catch {
|
|
449
463
|
// Ignore errors
|
|
@@ -453,8 +467,8 @@ async function detectProjectType(directory, remote = false) {
|
|
|
453
467
|
// Helper function to detect Vite port
|
|
454
468
|
async function detectVitePort(directory) {
|
|
455
469
|
try {
|
|
456
|
-
const viteConfigPath = path.join(directory,
|
|
457
|
-
const viteConfigTsPath = path.join(directory,
|
|
470
|
+
const viteConfigPath = path.join(directory, "vite.config.js");
|
|
471
|
+
const viteConfigTsPath = path.join(directory, "vite.config.ts");
|
|
458
472
|
let configPath;
|
|
459
473
|
try {
|
|
460
474
|
await fs.access(viteConfigPath);
|
|
@@ -469,7 +483,7 @@ async function detectVitePort(directory) {
|
|
|
469
483
|
return undefined;
|
|
470
484
|
}
|
|
471
485
|
}
|
|
472
|
-
const content = await fs.readFile(configPath,
|
|
486
|
+
const content = await fs.readFile(configPath, "utf-8");
|
|
473
487
|
// Look for port configuration
|
|
474
488
|
const portMatch = content.match(/port:\s*(\d+)/);
|
|
475
489
|
if (portMatch) {
|
|
@@ -485,7 +499,7 @@ async function detectVitePort(directory) {
|
|
|
485
499
|
async function shouldSkipDirectory(directory) {
|
|
486
500
|
try {
|
|
487
501
|
// Check for .gitignore
|
|
488
|
-
const gitignorePath = path.join(directory,
|
|
502
|
+
const gitignorePath = path.join(directory, ".gitignore");
|
|
489
503
|
await fs.access(gitignorePath);
|
|
490
504
|
// For now, we'll use a simple heuristic
|
|
491
505
|
// In a real implementation, you'd parse .gitignore properly
|