amai 0.0.10 → 0.0.11
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/cli.cjs +688 -433
- package/dist/cli.js +684 -429
- package/dist/lib/daemon-entry.cjs +663 -408
- package/dist/lib/daemon-entry.js +659 -404
- package/dist/server.cjs +633 -378
- package/dist/server.js +629 -374
- package/package.json +2 -2
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var WebSocket = require('ws');
|
|
5
5
|
var zod = require('zod');
|
|
6
|
-
var fs5 = require('fs/promises');
|
|
7
6
|
var path10 = require('path');
|
|
8
|
-
var
|
|
7
|
+
var fs8 = require('fs');
|
|
9
8
|
var os3 = require('os');
|
|
10
|
-
var
|
|
11
|
-
var util = require('util');
|
|
9
|
+
var fs7 = require('fs/promises');
|
|
12
10
|
var pc4 = require('picocolors');
|
|
13
11
|
var hono = require('hono');
|
|
14
12
|
var nodeServer = require('@hono/node-server');
|
|
15
13
|
var cors = require('hono/cors');
|
|
14
|
+
var child_process = require('child_process');
|
|
15
|
+
var util = require('util');
|
|
16
16
|
|
|
17
17
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
18
18
|
|
|
19
19
|
var WebSocket__default = /*#__PURE__*/_interopDefault(WebSocket);
|
|
20
|
-
var fs5__default = /*#__PURE__*/_interopDefault(fs5);
|
|
21
20
|
var path10__default = /*#__PURE__*/_interopDefault(path10);
|
|
22
|
-
var
|
|
21
|
+
var fs8__default = /*#__PURE__*/_interopDefault(fs8);
|
|
23
22
|
var os3__default = /*#__PURE__*/_interopDefault(os3);
|
|
23
|
+
var fs7__default = /*#__PURE__*/_interopDefault(fs7);
|
|
24
24
|
var pc4__default = /*#__PURE__*/_interopDefault(pc4);
|
|
25
25
|
|
|
26
26
|
var DEFAULT_SERVER_URL = "wss://ama-production-a628.up.railway.app";
|
|
@@ -37,14 +37,14 @@ var ProjectRegistry = class {
|
|
|
37
37
|
}
|
|
38
38
|
load() {
|
|
39
39
|
try {
|
|
40
|
-
if (
|
|
41
|
-
const data =
|
|
40
|
+
if (fs8__default.default.existsSync(REGISTRY_FILE)) {
|
|
41
|
+
const data = fs8__default.default.readFileSync(REGISTRY_FILE, "utf8");
|
|
42
42
|
const parsed = JSON.parse(data);
|
|
43
43
|
if (!Array.isArray(parsed)) {
|
|
44
44
|
console.error("Invalid project registry format: expected array, got", typeof parsed);
|
|
45
45
|
const backupFile = REGISTRY_FILE + ".backup." + Date.now();
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
fs8__default.default.copyFileSync(REGISTRY_FILE, backupFile);
|
|
47
|
+
fs8__default.default.unlinkSync(REGISTRY_FILE);
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
50
|
const projects = parsed;
|
|
@@ -57,11 +57,11 @@ var ProjectRegistry = class {
|
|
|
57
57
|
}
|
|
58
58
|
} catch (error) {
|
|
59
59
|
console.error("Failed to load project registry:", error);
|
|
60
|
-
if (
|
|
60
|
+
if (fs8__default.default.existsSync(REGISTRY_FILE)) {
|
|
61
61
|
try {
|
|
62
62
|
const backupFile = REGISTRY_FILE + ".backup." + Date.now();
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
fs8__default.default.copyFileSync(REGISTRY_FILE, backupFile);
|
|
64
|
+
fs8__default.default.unlinkSync(REGISTRY_FILE);
|
|
65
65
|
console.log("Corrupted registry file backed up and removed. Starting fresh.");
|
|
66
66
|
} catch (backupError) {
|
|
67
67
|
}
|
|
@@ -70,11 +70,11 @@ var ProjectRegistry = class {
|
|
|
70
70
|
}
|
|
71
71
|
save() {
|
|
72
72
|
try {
|
|
73
|
-
if (!
|
|
74
|
-
|
|
73
|
+
if (!fs8__default.default.existsSync(AMA_DIR)) {
|
|
74
|
+
fs8__default.default.mkdirSync(AMA_DIR, { recursive: true });
|
|
75
75
|
}
|
|
76
76
|
const projects = Array.from(this.projects.values());
|
|
77
|
-
|
|
77
|
+
fs8__default.default.writeFileSync(REGISTRY_FILE, JSON.stringify(projects, null, 2), "utf8");
|
|
78
78
|
} catch (error) {
|
|
79
79
|
console.error("Failed to save project registry:", error);
|
|
80
80
|
}
|
|
@@ -163,6 +163,60 @@ zod.z.object({
|
|
|
163
163
|
),
|
|
164
164
|
end_line_one_indexed: zod.z.number().optional().describe("The one-indexed line number to end reading at (inclusive).")
|
|
165
165
|
});
|
|
166
|
+
async function readFileContent(absolute_file_path, relative_file_path, should_read_entire_file, start_line_one_indexed, end_line_one_indexed) {
|
|
167
|
+
const file = Bun.file(absolute_file_path);
|
|
168
|
+
const exists = await file.exists();
|
|
169
|
+
if (!exists) {
|
|
170
|
+
return {
|
|
171
|
+
success: false,
|
|
172
|
+
message: `File not found: ${relative_file_path}`,
|
|
173
|
+
error: "FILE_NOT_FOUND"
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
const fileContent = await file.text();
|
|
178
|
+
const lines = fileContent.split(/\r?\n/);
|
|
179
|
+
const totalLines = lines.length;
|
|
180
|
+
if (should_read_entire_file) {
|
|
181
|
+
return {
|
|
182
|
+
success: true,
|
|
183
|
+
message: `Successfully read entire file: ${relative_file_path} (${totalLines} lines)`,
|
|
184
|
+
content: fileContent,
|
|
185
|
+
totalLines
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
const startIndex = start_line_one_indexed - 1;
|
|
189
|
+
if (startIndex >= totalLines) {
|
|
190
|
+
return {
|
|
191
|
+
success: false,
|
|
192
|
+
message: "start_line_one_indexed must be less than or equal to the total number of lines in the file",
|
|
193
|
+
error: "INVALID_LINE_RANGE"
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
const normalizedEnd = Math.min(end_line_one_indexed, totalLines);
|
|
197
|
+
const selectedLines = lines.slice(startIndex, normalizedEnd).join("\n");
|
|
198
|
+
const linesRead = normalizedEnd - start_line_one_indexed + 1;
|
|
199
|
+
return {
|
|
200
|
+
success: true,
|
|
201
|
+
message: `Successfully read lines ${start_line_one_indexed}-${normalizedEnd} from file: ${relative_file_path} (${linesRead} lines of ${totalLines} total)`,
|
|
202
|
+
content: selectedLines,
|
|
203
|
+
totalLines
|
|
204
|
+
};
|
|
205
|
+
} catch (error) {
|
|
206
|
+
if (error?.code === "EISDIR") {
|
|
207
|
+
return {
|
|
208
|
+
success: false,
|
|
209
|
+
message: `Path is not a file: ${relative_file_path}`,
|
|
210
|
+
error: "NOT_A_FILE"
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
success: false,
|
|
215
|
+
message: `Failed to read file: ${relative_file_path}`,
|
|
216
|
+
error: "READ_ERROR"
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
}
|
|
166
220
|
var read_file = async function(input, projectCwd) {
|
|
167
221
|
const { relative_file_path, should_read_entire_file, start_line_one_indexed, end_line_one_indexed } = input;
|
|
168
222
|
try {
|
|
@@ -203,6 +257,7 @@ var read_file = async function(input, projectCwd) {
|
|
|
203
257
|
};
|
|
204
258
|
}
|
|
205
259
|
}
|
|
260
|
+
let absolute_file_path;
|
|
206
261
|
if (projectCwd) {
|
|
207
262
|
const validation = validatePath(relative_file_path, projectCwd);
|
|
208
263
|
if (!validation.valid) {
|
|
@@ -212,128 +267,17 @@ var read_file = async function(input, projectCwd) {
|
|
|
212
267
|
error: "ACCESS_DENIED"
|
|
213
268
|
};
|
|
214
269
|
}
|
|
215
|
-
|
|
216
|
-
try {
|
|
217
|
-
const fileStats = await fs5.stat(absolute_file_path);
|
|
218
|
-
if (!fileStats.isFile()) {
|
|
219
|
-
return {
|
|
220
|
-
success: false,
|
|
221
|
-
message: `Path is not a file: ${relative_file_path}`,
|
|
222
|
-
error: "NOT_A_FILE"
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
} catch (error) {
|
|
226
|
-
if (error?.code === "ENOENT") {
|
|
227
|
-
return {
|
|
228
|
-
success: false,
|
|
229
|
-
message: `File not found: ${relative_file_path}`,
|
|
230
|
-
error: "FILE_NOT_FOUND"
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
return {
|
|
234
|
-
success: false,
|
|
235
|
-
message: `Failed to access file: ${relative_file_path}`,
|
|
236
|
-
error: "READ_ERROR"
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
try {
|
|
240
|
-
const fileContent = await fs5.readFile(absolute_file_path, "utf-8");
|
|
241
|
-
const lines = fileContent.split(/\r?\n/);
|
|
242
|
-
const totalLines = lines.length;
|
|
243
|
-
if (should_read_entire_file) {
|
|
244
|
-
return {
|
|
245
|
-
success: true,
|
|
246
|
-
message: `Successfully read entire file: ${relative_file_path} (${totalLines} lines)`,
|
|
247
|
-
content: fileContent,
|
|
248
|
-
totalLines
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
const startIndex = start_line_one_indexed - 1;
|
|
252
|
-
if (startIndex >= totalLines) {
|
|
253
|
-
return {
|
|
254
|
-
success: false,
|
|
255
|
-
message: "start_line_one_indexed must be less than or equal to the total number of lines in the file",
|
|
256
|
-
error: "INVALID_LINE_RANGE"
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
const normalizedEnd = Math.min(end_line_one_indexed, totalLines);
|
|
260
|
-
const selectedLines = lines.slice(startIndex, normalizedEnd).join("\n");
|
|
261
|
-
const linesRead = normalizedEnd - start_line_one_indexed + 1;
|
|
262
|
-
return {
|
|
263
|
-
success: true,
|
|
264
|
-
message: `Successfully read lines ${start_line_one_indexed}-${normalizedEnd} from file: ${relative_file_path} (${linesRead} lines of ${totalLines} total)`,
|
|
265
|
-
content: selectedLines,
|
|
266
|
-
totalLines
|
|
267
|
-
};
|
|
268
|
-
} catch {
|
|
269
|
-
return {
|
|
270
|
-
success: false,
|
|
271
|
-
message: `Failed to read file: ${relative_file_path}`,
|
|
272
|
-
error: "READ_ERROR"
|
|
273
|
-
};
|
|
274
|
-
}
|
|
270
|
+
absolute_file_path = validation.resolvedPath;
|
|
275
271
|
} else {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
}
|
|
286
|
-
} catch (error) {
|
|
287
|
-
if (error?.code === "ENOENT") {
|
|
288
|
-
return {
|
|
289
|
-
success: false,
|
|
290
|
-
message: `File not found: ${relative_file_path}`,
|
|
291
|
-
error: "FILE_NOT_FOUND"
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
return {
|
|
295
|
-
success: false,
|
|
296
|
-
message: `Failed to access file: ${relative_file_path}`,
|
|
297
|
-
error: "READ_ERROR"
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
try {
|
|
301
|
-
const fileContent = await fs5.readFile(absolute_file_path, "utf-8");
|
|
302
|
-
const lines = fileContent.split(/\r?\n/);
|
|
303
|
-
const totalLines = lines.length;
|
|
304
|
-
if (should_read_entire_file) {
|
|
305
|
-
return {
|
|
306
|
-
success: true,
|
|
307
|
-
message: `Successfully read entire file: ${relative_file_path} (${totalLines} lines)`,
|
|
308
|
-
content: fileContent,
|
|
309
|
-
totalLines
|
|
310
|
-
};
|
|
311
|
-
}
|
|
312
|
-
const startIndex = start_line_one_indexed - 1;
|
|
313
|
-
if (startIndex >= totalLines) {
|
|
314
|
-
return {
|
|
315
|
-
success: false,
|
|
316
|
-
message: "start_line_one_indexed must be less than or equal to the total number of lines in the file",
|
|
317
|
-
error: "INVALID_LINE_RANGE"
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
const normalizedEnd = Math.min(end_line_one_indexed, totalLines);
|
|
321
|
-
const selectedLines = lines.slice(startIndex, normalizedEnd).join("\n");
|
|
322
|
-
const linesRead = normalizedEnd - start_line_one_indexed + 1;
|
|
323
|
-
return {
|
|
324
|
-
success: true,
|
|
325
|
-
message: `Successfully read lines ${start_line_one_indexed}-${normalizedEnd} from file: ${relative_file_path} (${linesRead} lines of ${totalLines} total)`,
|
|
326
|
-
content: selectedLines,
|
|
327
|
-
totalLines
|
|
328
|
-
};
|
|
329
|
-
} catch {
|
|
330
|
-
return {
|
|
331
|
-
success: false,
|
|
332
|
-
message: `Failed to read file: ${relative_file_path}`,
|
|
333
|
-
error: "READ_ERROR"
|
|
334
|
-
};
|
|
335
|
-
}
|
|
336
|
-
}
|
|
272
|
+
absolute_file_path = path10__default.default.resolve(relative_file_path);
|
|
273
|
+
}
|
|
274
|
+
return await readFileContent(
|
|
275
|
+
absolute_file_path,
|
|
276
|
+
relative_file_path,
|
|
277
|
+
should_read_entire_file,
|
|
278
|
+
start_line_one_indexed,
|
|
279
|
+
end_line_one_indexed
|
|
280
|
+
);
|
|
337
281
|
} catch {
|
|
338
282
|
return {
|
|
339
283
|
success: false,
|
|
@@ -424,13 +368,13 @@ var Diff = class {
|
|
|
424
368
|
editLength++;
|
|
425
369
|
};
|
|
426
370
|
if (callback) {
|
|
427
|
-
(function
|
|
371
|
+
(function exec3() {
|
|
428
372
|
setTimeout(function() {
|
|
429
373
|
if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
|
|
430
374
|
return callback(void 0);
|
|
431
375
|
}
|
|
432
376
|
if (!execEditLength()) {
|
|
433
|
-
|
|
377
|
+
exec3();
|
|
434
378
|
}
|
|
435
379
|
}, 0);
|
|
436
380
|
})();
|
|
@@ -657,17 +601,19 @@ var apply_patch = async function(input, projectCwd) {
|
|
|
657
601
|
}
|
|
658
602
|
const basePath = projectCwd || process.cwd();
|
|
659
603
|
const absolute_file_path = resolveProjectPath(file_path, basePath);
|
|
604
|
+
const file = Bun.file(absolute_file_path);
|
|
605
|
+
const exists = await file.exists();
|
|
606
|
+
if (!exists) {
|
|
607
|
+
return {
|
|
608
|
+
success: false,
|
|
609
|
+
message: `File not found: ${file_path}`,
|
|
610
|
+
error: "FILE_NOT_FOUND"
|
|
611
|
+
};
|
|
612
|
+
}
|
|
660
613
|
let fileContent;
|
|
661
614
|
try {
|
|
662
|
-
fileContent = await
|
|
615
|
+
fileContent = await file.text();
|
|
663
616
|
} catch (error) {
|
|
664
|
-
if (error?.code === "ENOENT") {
|
|
665
|
-
return {
|
|
666
|
-
success: false,
|
|
667
|
-
message: `File not found: ${file_path}`,
|
|
668
|
-
error: "FILE_NOT_FOUND"
|
|
669
|
-
};
|
|
670
|
-
}
|
|
671
617
|
return {
|
|
672
618
|
success: false,
|
|
673
619
|
message: `Failed to read file: ${file_path}`,
|
|
@@ -691,7 +637,7 @@ var apply_patch = async function(input, projectCwd) {
|
|
|
691
637
|
}
|
|
692
638
|
const newContent = fileContent.replace(old_string, new_string);
|
|
693
639
|
try {
|
|
694
|
-
await
|
|
640
|
+
await Bun.write(absolute_file_path, newContent);
|
|
695
641
|
const diffStats = calculateDiffStats(fileContent, newContent);
|
|
696
642
|
return {
|
|
697
643
|
success: true,
|
|
@@ -737,28 +683,27 @@ var editFiles = async function(input, projectCwd) {
|
|
|
737
683
|
const basePath = projectCwd || process.cwd();
|
|
738
684
|
const filePath = resolveProjectPath(target_file, basePath);
|
|
739
685
|
const dirPath = path10__default.default.dirname(filePath);
|
|
740
|
-
await
|
|
686
|
+
await fs7.mkdir(dirPath, { recursive: true });
|
|
741
687
|
let isNewFile = providedNewFile;
|
|
742
688
|
let existingContent = "";
|
|
689
|
+
const file = Bun.file(filePath);
|
|
743
690
|
if (isNewFile === void 0) {
|
|
744
|
-
|
|
745
|
-
|
|
691
|
+
const exists = await file.exists();
|
|
692
|
+
if (exists) {
|
|
693
|
+
existingContent = await file.text();
|
|
746
694
|
isNewFile = false;
|
|
747
|
-
}
|
|
695
|
+
} else {
|
|
748
696
|
isNewFile = true;
|
|
749
697
|
}
|
|
750
698
|
} else if (!isNewFile) {
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
699
|
+
const exists = await file.exists();
|
|
700
|
+
if (exists) {
|
|
701
|
+
existingContent = await file.text();
|
|
702
|
+
} else {
|
|
754
703
|
isNewFile = true;
|
|
755
704
|
}
|
|
756
705
|
}
|
|
757
|
-
|
|
758
|
-
await fs6__default.default.promises.writeFile(filePath, content);
|
|
759
|
-
} catch (writeError) {
|
|
760
|
-
throw writeError;
|
|
761
|
-
}
|
|
706
|
+
await Bun.write(filePath, content);
|
|
762
707
|
const diffStats = calculateDiffStats(existingContent, content);
|
|
763
708
|
if (isNewFile) {
|
|
764
709
|
return {
|
|
@@ -821,25 +766,31 @@ var deleteFile = async function(input, projectCwd) {
|
|
|
821
766
|
error: "INVALID_FILE_PATH"
|
|
822
767
|
};
|
|
823
768
|
}
|
|
824
|
-
const
|
|
825
|
-
|
|
769
|
+
const file = Bun.file(absolute_file_path);
|
|
770
|
+
const exists = await file.exists();
|
|
771
|
+
if (!exists) {
|
|
826
772
|
return {
|
|
827
773
|
success: false,
|
|
828
|
-
message: `
|
|
829
|
-
error: "
|
|
774
|
+
message: `File not found: ${realPath}`,
|
|
775
|
+
error: "FILE_NOT_FOUND"
|
|
830
776
|
};
|
|
831
777
|
}
|
|
832
|
-
|
|
778
|
+
let originalContent;
|
|
779
|
+
try {
|
|
780
|
+
originalContent = await file.text();
|
|
781
|
+
} catch {
|
|
833
782
|
return {
|
|
834
783
|
success: false,
|
|
835
784
|
message: `Failed to read file before deletion: ${realPath}`,
|
|
836
|
-
error: "
|
|
785
|
+
error: "READ_ERROR"
|
|
837
786
|
};
|
|
838
|
-
}
|
|
839
|
-
|
|
787
|
+
}
|
|
788
|
+
try {
|
|
789
|
+
await fs7.unlink(absolute_file_path);
|
|
790
|
+
} catch {
|
|
840
791
|
return {
|
|
841
792
|
success: false,
|
|
842
|
-
message: `Failed to delete file
|
|
793
|
+
message: `Failed to delete file: ${realPath}`,
|
|
843
794
|
error: "DELETE_ERROR"
|
|
844
795
|
};
|
|
845
796
|
}
|
|
@@ -856,72 +807,218 @@ var deleteFile = async function(input, projectCwd) {
|
|
|
856
807
|
};
|
|
857
808
|
}
|
|
858
809
|
};
|
|
810
|
+
var GREP_LIMITS = {
|
|
811
|
+
DEFAULT_MAX_MATCHES: 200,
|
|
812
|
+
MAX_LINE_LENGTH: 500,
|
|
813
|
+
MAX_TOTAL_OUTPUT_SIZE: 1 * 1024 * 1024,
|
|
814
|
+
TRUNCATION_MESSAGE: "\n[Results truncated due to size limits. Use more specific patterns or file filters to narrow your search.]"
|
|
815
|
+
};
|
|
859
816
|
zod.z.object({
|
|
860
817
|
query: zod.z.string().describe("The regex pattern to search for"),
|
|
861
818
|
options: zod.z.object({
|
|
862
819
|
includePattern: zod.z.string().optional().describe('Glob pattern for files to include (e.g., "*.ts")'),
|
|
863
820
|
excludePattern: zod.z.string().optional().describe("Glob pattern for files to exclude"),
|
|
864
|
-
caseSensitive: zod.z.boolean().optional().describe("Whether the search should be case sensitive")
|
|
865
|
-
|
|
821
|
+
caseSensitive: zod.z.boolean().optional().describe("Whether the search should be case sensitive"),
|
|
822
|
+
path: zod.z.string().optional().describe("Subdirectory to search in")
|
|
823
|
+
}).optional()
|
|
866
824
|
});
|
|
867
|
-
|
|
825
|
+
async function getRipgrepPath() {
|
|
826
|
+
const paths = [
|
|
827
|
+
"/opt/homebrew/bin/rg",
|
|
828
|
+
"/usr/local/bin/rg",
|
|
829
|
+
"/usr/bin/rg",
|
|
830
|
+
"rg"
|
|
831
|
+
// Fallback to PATH
|
|
832
|
+
];
|
|
833
|
+
for (const rgPath of paths) {
|
|
834
|
+
try {
|
|
835
|
+
const proc = Bun.spawn(["which", rgPath], { stdout: "pipe", stderr: "pipe" });
|
|
836
|
+
await proc.exited;
|
|
837
|
+
if (proc.exitCode === 0) {
|
|
838
|
+
return rgPath;
|
|
839
|
+
}
|
|
840
|
+
} catch {
|
|
841
|
+
continue;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
return "rg";
|
|
845
|
+
}
|
|
846
|
+
async function getMtimesBatched(files) {
|
|
847
|
+
const mtimeMap = /* @__PURE__ */ new Map();
|
|
848
|
+
const BATCH_SIZE = 50;
|
|
849
|
+
for (let i = 0; i < files.length; i += BATCH_SIZE) {
|
|
850
|
+
const batch = files.slice(i, i + BATCH_SIZE);
|
|
851
|
+
const results = await Promise.all(
|
|
852
|
+
batch.map(async (filePath) => {
|
|
853
|
+
const mtime = await Bun.file(filePath).stat().then((stats) => stats.mtime.getTime()).catch(() => 0);
|
|
854
|
+
return { path: filePath, mtime };
|
|
855
|
+
})
|
|
856
|
+
);
|
|
857
|
+
results.forEach(({ path: path14, mtime }) => mtimeMap.set(path14, mtime));
|
|
858
|
+
}
|
|
859
|
+
return mtimeMap;
|
|
860
|
+
}
|
|
868
861
|
var grepTool = async function(input, projectCwd) {
|
|
869
862
|
const { query, options } = input;
|
|
863
|
+
if (!query || query.trim() === "") {
|
|
864
|
+
return {
|
|
865
|
+
success: false,
|
|
866
|
+
message: "Missing required parameter: query",
|
|
867
|
+
error: "MISSING_QUERY"
|
|
868
|
+
};
|
|
869
|
+
}
|
|
870
870
|
try {
|
|
871
|
-
const { includePattern, excludePattern
|
|
872
|
-
|
|
873
|
-
if (
|
|
871
|
+
const { includePattern, excludePattern, caseSensitive, path: subPath } = options || {};
|
|
872
|
+
let searchDir = projectCwd || process.cwd();
|
|
873
|
+
if (subPath) {
|
|
874
|
+
searchDir = path10__default.default.isAbsolute(subPath) ? subPath : path10__default.default.resolve(searchDir, subPath);
|
|
875
|
+
if (projectCwd) {
|
|
876
|
+
const validation = validatePath(subPath, projectCwd);
|
|
877
|
+
if (!validation.valid) {
|
|
878
|
+
return {
|
|
879
|
+
success: false,
|
|
880
|
+
message: validation.error || "Path validation failed",
|
|
881
|
+
error: "ACCESS_DENIED"
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
if (!fs8__default.default.existsSync(searchDir)) {
|
|
874
887
|
return {
|
|
875
888
|
success: false,
|
|
876
|
-
message:
|
|
877
|
-
error: "
|
|
889
|
+
message: `Directory not found: ${searchDir}`,
|
|
890
|
+
error: "DIR_NOT_FOUND"
|
|
878
891
|
};
|
|
879
892
|
}
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
893
|
+
const rgPath = await getRipgrepPath();
|
|
894
|
+
const args = [
|
|
895
|
+
"-n",
|
|
896
|
+
// Line numbers
|
|
897
|
+
"--with-filename",
|
|
898
|
+
// Always show filename
|
|
899
|
+
"--no-heading",
|
|
900
|
+
// Don't group by file
|
|
901
|
+
"--color=never",
|
|
902
|
+
// No ANSI colors
|
|
903
|
+
"--max-count=100",
|
|
904
|
+
// Max matches per file
|
|
905
|
+
"--max-columns=1000"
|
|
906
|
+
// Truncate long lines
|
|
907
|
+
];
|
|
908
|
+
if (!caseSensitive) {
|
|
909
|
+
args.push("-i");
|
|
883
910
|
}
|
|
884
911
|
if (includePattern) {
|
|
885
|
-
|
|
886
|
-
}
|
|
887
|
-
if (
|
|
888
|
-
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
912
|
+
args.push("--glob", includePattern);
|
|
913
|
+
}
|
|
914
|
+
if (excludePattern) {
|
|
915
|
+
args.push("--glob", `!${excludePattern}`);
|
|
916
|
+
}
|
|
917
|
+
args.push("--glob", "!node_modules/**");
|
|
918
|
+
args.push("--glob", "!.git/**");
|
|
919
|
+
args.push("--glob", "!dist/**");
|
|
920
|
+
args.push("--glob", "!build/**");
|
|
921
|
+
args.push("--glob", "!*.min.js");
|
|
922
|
+
args.push("--glob", "!*.min.css");
|
|
923
|
+
args.push("--glob", "!package-lock.json");
|
|
924
|
+
args.push("--glob", "!yarn.lock");
|
|
925
|
+
args.push("--glob", "!bun.lockb");
|
|
926
|
+
args.push("--regexp", query);
|
|
927
|
+
args.push(searchDir);
|
|
928
|
+
const proc = Bun.spawn([rgPath, ...args], {
|
|
929
|
+
stdout: "pipe",
|
|
930
|
+
stderr: "pipe"
|
|
931
|
+
});
|
|
932
|
+
const stdout = await new Response(proc.stdout).text();
|
|
933
|
+
const stderr = await new Response(proc.stderr).text();
|
|
934
|
+
const exitCode = await proc.exited;
|
|
935
|
+
if (exitCode === 1) {
|
|
936
|
+
return {
|
|
937
|
+
success: true,
|
|
938
|
+
matches: [],
|
|
939
|
+
detailedMatches: [],
|
|
940
|
+
query,
|
|
941
|
+
matchCount: 0,
|
|
942
|
+
message: `No matches found for pattern: ${query}`
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
if (exitCode !== 0) {
|
|
946
|
+
return {
|
|
947
|
+
success: false,
|
|
948
|
+
message: `Ripgrep error: ${stderr || "Unknown error"}`,
|
|
949
|
+
error: "GREP_EXEC_ERROR"
|
|
950
|
+
};
|
|
951
|
+
}
|
|
952
|
+
const lines = stdout.trim().split("\n").filter((line) => line.length > 0);
|
|
953
|
+
const rawMatches = [];
|
|
954
|
+
const uniqueFiles = /* @__PURE__ */ new Set();
|
|
955
|
+
for (const line of lines) {
|
|
956
|
+
const firstColon = line.indexOf(":");
|
|
957
|
+
const secondColon = line.indexOf(":", firstColon + 1);
|
|
958
|
+
if (firstColon > 0 && secondColon > firstColon) {
|
|
959
|
+
const file = line.substring(0, firstColon);
|
|
960
|
+
const lineNumber = parseInt(line.substring(firstColon + 1, secondColon), 10);
|
|
961
|
+
let content = line.substring(secondColon + 1);
|
|
962
|
+
if (content.length > GREP_LIMITS.MAX_LINE_LENGTH) {
|
|
963
|
+
content = content.substring(0, GREP_LIMITS.MAX_LINE_LENGTH) + "...";
|
|
905
964
|
}
|
|
906
|
-
|
|
965
|
+
rawMatches.push({
|
|
907
966
|
file,
|
|
908
967
|
lineNumber,
|
|
909
|
-
content
|
|
968
|
+
content: content.trim(),
|
|
969
|
+
mtime: 0
|
|
910
970
|
});
|
|
911
|
-
|
|
912
|
-
} else {
|
|
913
|
-
matches.push(rawMatch);
|
|
971
|
+
uniqueFiles.add(file);
|
|
914
972
|
}
|
|
915
973
|
}
|
|
974
|
+
const mtimeMap = await getMtimesBatched(Array.from(uniqueFiles));
|
|
975
|
+
for (const match of rawMatches) {
|
|
976
|
+
match.mtime = mtimeMap.get(match.file) || 0;
|
|
977
|
+
}
|
|
978
|
+
rawMatches.sort((a, b) => {
|
|
979
|
+
if (b.mtime !== a.mtime) {
|
|
980
|
+
return b.mtime - a.mtime;
|
|
981
|
+
}
|
|
982
|
+
return a.file.localeCompare(b.file);
|
|
983
|
+
});
|
|
984
|
+
const truncated = rawMatches.length > GREP_LIMITS.DEFAULT_MAX_MATCHES;
|
|
985
|
+
const finalMatches = truncated ? rawMatches.slice(0, GREP_LIMITS.DEFAULT_MAX_MATCHES) : rawMatches;
|
|
986
|
+
const detailedMatches = finalMatches.map((m) => ({
|
|
987
|
+
file: m.file,
|
|
988
|
+
lineNumber: m.lineNumber,
|
|
989
|
+
content: m.content
|
|
990
|
+
}));
|
|
991
|
+
const matches = finalMatches.map(
|
|
992
|
+
(m) => `${m.file}:${m.lineNumber}:${m.content}`
|
|
993
|
+
);
|
|
994
|
+
const groupedOutput = [`Found ${finalMatches.length} matches`];
|
|
995
|
+
let currentFile = "";
|
|
996
|
+
for (const match of finalMatches) {
|
|
997
|
+
if (currentFile !== match.file) {
|
|
998
|
+
if (currentFile !== "") {
|
|
999
|
+
groupedOutput.push("");
|
|
1000
|
+
}
|
|
1001
|
+
currentFile = match.file;
|
|
1002
|
+
groupedOutput.push(`${match.file}:`);
|
|
1003
|
+
}
|
|
1004
|
+
groupedOutput.push(` Line ${match.lineNumber}: ${match.content}`);
|
|
1005
|
+
}
|
|
1006
|
+
if (truncated) {
|
|
1007
|
+
groupedOutput.push("");
|
|
1008
|
+
groupedOutput.push(GREP_LIMITS.TRUNCATION_MESSAGE);
|
|
1009
|
+
}
|
|
916
1010
|
return {
|
|
917
1011
|
success: true,
|
|
918
1012
|
matches,
|
|
919
1013
|
detailedMatches,
|
|
920
1014
|
query,
|
|
921
|
-
matchCount:
|
|
922
|
-
|
|
1015
|
+
matchCount: finalMatches.length,
|
|
1016
|
+
truncated,
|
|
1017
|
+
message: `Found ${finalMatches.length} matches for pattern: ${query}`,
|
|
1018
|
+
content: groupedOutput.join("\n")
|
|
923
1019
|
};
|
|
924
1020
|
} catch (error) {
|
|
1021
|
+
console.error("[grep] error:", error);
|
|
925
1022
|
return {
|
|
926
1023
|
success: false,
|
|
927
1024
|
message: error?.message || String(error),
|
|
@@ -930,9 +1027,25 @@ var grepTool = async function(input, projectCwd) {
|
|
|
930
1027
|
}
|
|
931
1028
|
};
|
|
932
1029
|
zod.z.object({
|
|
933
|
-
pattern: zod.z.string().describe('Glob pattern (e.g., "**/*.js")'),
|
|
934
|
-
path: zod.z.string().optional().describe("
|
|
1030
|
+
pattern: zod.z.string().describe('Glob pattern to match files (e.g., "**/*.js", "src/**/*.ts", "*.json"). Supports standard glob syntax with *, **, and ? wildcards'),
|
|
1031
|
+
path: zod.z.string().optional().describe("Optional relative directory path within the project to limit the search scope. If not provided, searches from the project root")
|
|
935
1032
|
});
|
|
1033
|
+
var RESULT_LIMIT = 100;
|
|
1034
|
+
var MTIME_BATCH_SIZE = 50;
|
|
1035
|
+
async function getMtimesBatched2(files) {
|
|
1036
|
+
const results = [];
|
|
1037
|
+
for (let i = 0; i < files.length; i += MTIME_BATCH_SIZE) {
|
|
1038
|
+
const batch = files.slice(i, i + MTIME_BATCH_SIZE);
|
|
1039
|
+
const batchResults = await Promise.all(
|
|
1040
|
+
batch.map(async (filePath) => {
|
|
1041
|
+
const mtime = await Bun.file(filePath).stat().then((stats) => stats.mtime.getTime()).catch(() => 0);
|
|
1042
|
+
return { path: filePath, mtime };
|
|
1043
|
+
})
|
|
1044
|
+
);
|
|
1045
|
+
results.push(...batchResults);
|
|
1046
|
+
}
|
|
1047
|
+
return results;
|
|
1048
|
+
}
|
|
936
1049
|
var globTool = async function(input, projectCwd) {
|
|
937
1050
|
const { pattern, path: inputPath } = input;
|
|
938
1051
|
if (!pattern) {
|
|
@@ -945,6 +1058,13 @@ var globTool = async function(input, projectCwd) {
|
|
|
945
1058
|
try {
|
|
946
1059
|
const basePath = projectCwd || process.cwd();
|
|
947
1060
|
const searchPath = inputPath ? resolveProjectPath(inputPath, basePath) : basePath;
|
|
1061
|
+
if (!fs8__default.default.existsSync(searchPath)) {
|
|
1062
|
+
return {
|
|
1063
|
+
success: false,
|
|
1064
|
+
message: `Directory not found: ${searchPath}`,
|
|
1065
|
+
error: "DIR_NOT_FOUND"
|
|
1066
|
+
};
|
|
1067
|
+
}
|
|
948
1068
|
if (projectCwd && inputPath) {
|
|
949
1069
|
const validation = validatePath(inputPath, projectCwd);
|
|
950
1070
|
if (!validation.valid) {
|
|
@@ -955,21 +1075,49 @@ var globTool = async function(input, projectCwd) {
|
|
|
955
1075
|
};
|
|
956
1076
|
}
|
|
957
1077
|
}
|
|
958
|
-
const
|
|
959
|
-
cwd: searchPath
|
|
960
|
-
});
|
|
1078
|
+
const glob = new Bun.Glob(pattern);
|
|
961
1079
|
const files = [];
|
|
962
|
-
|
|
963
|
-
|
|
1080
|
+
let truncated = false;
|
|
1081
|
+
for await (const match of glob.scan({
|
|
1082
|
+
cwd: searchPath,
|
|
1083
|
+
absolute: true,
|
|
1084
|
+
onlyFiles: true,
|
|
1085
|
+
followSymlinks: false
|
|
1086
|
+
})) {
|
|
1087
|
+
if (match.includes("/node_modules/") || match.includes("/.git/")) {
|
|
1088
|
+
continue;
|
|
1089
|
+
}
|
|
1090
|
+
if (files.length >= RESULT_LIMIT) {
|
|
1091
|
+
truncated = true;
|
|
1092
|
+
break;
|
|
1093
|
+
}
|
|
1094
|
+
files.push(match);
|
|
1095
|
+
}
|
|
1096
|
+
const filesWithMtime = await getMtimesBatched2(files);
|
|
1097
|
+
filesWithMtime.sort((a, b) => b.mtime - a.mtime);
|
|
1098
|
+
const output = [];
|
|
1099
|
+
if (filesWithMtime.length === 0) {
|
|
1100
|
+
output.push("No files found");
|
|
1101
|
+
} else {
|
|
1102
|
+
output.push(...filesWithMtime.map((f) => f.path));
|
|
1103
|
+
if (truncated) {
|
|
1104
|
+
output.push("");
|
|
1105
|
+
output.push("(Results are truncated. Consider using a more specific path or pattern.)");
|
|
1106
|
+
}
|
|
964
1107
|
}
|
|
965
1108
|
const searchLocation = inputPath ? ` in "${inputPath}"` : " in current directory";
|
|
966
|
-
const message = `Found ${
|
|
1109
|
+
const message = `Found ${filesWithMtime.length} matches for pattern "${pattern}"${searchLocation}`;
|
|
967
1110
|
return {
|
|
968
1111
|
success: true,
|
|
969
1112
|
message,
|
|
970
|
-
|
|
1113
|
+
metadata: {
|
|
1114
|
+
count: filesWithMtime.length,
|
|
1115
|
+
truncated
|
|
1116
|
+
},
|
|
1117
|
+
content: output.join("\n")
|
|
971
1118
|
};
|
|
972
1119
|
} catch (error) {
|
|
1120
|
+
console.error("[glob] error:", error);
|
|
973
1121
|
return {
|
|
974
1122
|
success: false,
|
|
975
1123
|
message: `Failed to find files matching pattern: ${pattern}`,
|
|
@@ -977,59 +1125,120 @@ var globTool = async function(input, projectCwd) {
|
|
|
977
1125
|
};
|
|
978
1126
|
}
|
|
979
1127
|
};
|
|
980
|
-
var
|
|
981
|
-
"node_modules
|
|
982
|
-
"__pycache__
|
|
983
|
-
".git
|
|
984
|
-
"dist
|
|
985
|
-
"build
|
|
986
|
-
"target
|
|
987
|
-
"vendor
|
|
988
|
-
"bin
|
|
989
|
-
"obj
|
|
990
|
-
".idea
|
|
991
|
-
".vscode
|
|
992
|
-
".zig-cache
|
|
1128
|
+
var IGNORE_PATTERNS = [
|
|
1129
|
+
"node_modules",
|
|
1130
|
+
"__pycache__",
|
|
1131
|
+
".git",
|
|
1132
|
+
"dist",
|
|
1133
|
+
"build",
|
|
1134
|
+
"target",
|
|
1135
|
+
"vendor",
|
|
1136
|
+
"bin",
|
|
1137
|
+
"obj",
|
|
1138
|
+
".idea",
|
|
1139
|
+
".vscode",
|
|
1140
|
+
".zig-cache",
|
|
993
1141
|
"zig-out",
|
|
994
1142
|
".coverage",
|
|
995
|
-
"coverage
|
|
996
|
-
"
|
|
997
|
-
"
|
|
998
|
-
"
|
|
999
|
-
"
|
|
1000
|
-
"
|
|
1001
|
-
"
|
|
1002
|
-
"
|
|
1003
|
-
"
|
|
1004
|
-
"
|
|
1143
|
+
"coverage",
|
|
1144
|
+
"tmp",
|
|
1145
|
+
"temp",
|
|
1146
|
+
".cache",
|
|
1147
|
+
"cache",
|
|
1148
|
+
"logs",
|
|
1149
|
+
".venv",
|
|
1150
|
+
"venv",
|
|
1151
|
+
"env",
|
|
1152
|
+
".next",
|
|
1153
|
+
".turbo",
|
|
1154
|
+
".vercel",
|
|
1155
|
+
".output"
|
|
1005
1156
|
];
|
|
1006
|
-
var
|
|
1157
|
+
var RESULT_LIMIT2 = 500;
|
|
1158
|
+
var MTIME_BATCH_SIZE2 = 50;
|
|
1007
1159
|
zod.z.object({
|
|
1008
|
-
path: zod.z.string().optional(),
|
|
1009
|
-
recursive: zod.z.boolean().optional().describe("Whether to list files recursively"),
|
|
1010
|
-
maxDepth: zod.z.number().optional().describe("Maximum recursion depth (default:
|
|
1160
|
+
path: zod.z.string().optional().describe("Relative path to the directory to list"),
|
|
1161
|
+
recursive: zod.z.boolean().optional().describe("Whether to list files recursively (default: true)"),
|
|
1162
|
+
maxDepth: zod.z.number().optional().describe("Maximum recursion depth (default: 3)"),
|
|
1011
1163
|
pattern: zod.z.string().optional().describe("File extension (e.g., '.ts') or glob-like pattern"),
|
|
1012
|
-
|
|
1013
|
-
includeFiles: zod.z.boolean().optional().describe("Whether to include files in results (default: true)")
|
|
1164
|
+
showHidden: zod.z.boolean().optional().describe("Whether to show hidden files (default: false)")
|
|
1014
1165
|
});
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1166
|
+
function shouldIgnore(name, showHidden) {
|
|
1167
|
+
if (!showHidden && name.startsWith(".") && name !== ".") {
|
|
1168
|
+
return true;
|
|
1169
|
+
}
|
|
1170
|
+
return IGNORE_PATTERNS.includes(name);
|
|
1171
|
+
}
|
|
1172
|
+
function matchPattern(name, pattern) {
|
|
1173
|
+
if (!pattern) return true;
|
|
1174
|
+
if (pattern.startsWith(".") && !pattern.includes("*")) {
|
|
1175
|
+
return name.endsWith(pattern);
|
|
1176
|
+
}
|
|
1177
|
+
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
1178
|
+
const regex = new RegExp(`^${escaped}$`, "i");
|
|
1179
|
+
return regex.test(name);
|
|
1180
|
+
}
|
|
1181
|
+
async function getMtimesBatched3(entries) {
|
|
1182
|
+
for (let i = 0; i < entries.length; i += MTIME_BATCH_SIZE2) {
|
|
1183
|
+
const batch = entries.slice(i, i + MTIME_BATCH_SIZE2);
|
|
1184
|
+
await Promise.all(
|
|
1185
|
+
batch.map(async (entry) => {
|
|
1186
|
+
entry.mtime = await Bun.file(entry.absolutePath).stat().then((stats) => stats.mtime.getTime()).catch(() => 0);
|
|
1187
|
+
})
|
|
1188
|
+
);
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
function buildTreeOutput(entries, basePath) {
|
|
1192
|
+
const tree = /* @__PURE__ */ new Map();
|
|
1193
|
+
for (const entry of entries) {
|
|
1194
|
+
const dir = path10__default.default.dirname(entry.relativePath);
|
|
1195
|
+
const dirKey = dir === "." ? "" : dir;
|
|
1196
|
+
if (!tree.has(dirKey)) {
|
|
1197
|
+
tree.set(dirKey, []);
|
|
1198
|
+
}
|
|
1199
|
+
tree.get(dirKey).push(entry);
|
|
1200
|
+
}
|
|
1201
|
+
for (const [, items] of tree) {
|
|
1202
|
+
items.sort((a, b) => {
|
|
1203
|
+
if (a.type !== b.type) {
|
|
1204
|
+
return a.type === "directory" ? -1 : 1;
|
|
1205
|
+
}
|
|
1206
|
+
return a.name.localeCompare(b.name);
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
const lines = [`${basePath}/`];
|
|
1210
|
+
function renderLevel(dirPath, indent) {
|
|
1211
|
+
const items = tree.get(dirPath) || [];
|
|
1212
|
+
for (let i = 0; i < items.length; i++) {
|
|
1213
|
+
const item = items[i];
|
|
1214
|
+
const isLast = i === items.length - 1;
|
|
1215
|
+
const prefix = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
1216
|
+
const childIndent = indent + (isLast ? " " : "\u2502 ");
|
|
1217
|
+
if (item.type === "directory") {
|
|
1218
|
+
lines.push(`${indent}${prefix}${item.name}/`);
|
|
1219
|
+
const childPath = dirPath ? `${dirPath}/${item.name}` : item.name;
|
|
1220
|
+
renderLevel(childPath, childIndent);
|
|
1221
|
+
} else {
|
|
1222
|
+
lines.push(`${indent}${prefix}${item.name}`);
|
|
1223
|
+
}
|
|
1024
1224
|
}
|
|
1025
1225
|
}
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1226
|
+
renderLevel("", "");
|
|
1227
|
+
return lines.join("\n");
|
|
1228
|
+
}
|
|
1229
|
+
var list = async function(input, projectCwd) {
|
|
1230
|
+
const {
|
|
1231
|
+
path: relativePath,
|
|
1232
|
+
recursive = true,
|
|
1233
|
+
maxDepth = 3,
|
|
1234
|
+
pattern,
|
|
1235
|
+
showHidden = false
|
|
1236
|
+
} = input;
|
|
1237
|
+
if (maxDepth !== void 0 && (!Number.isInteger(maxDepth) || maxDepth < 0)) {
|
|
1029
1238
|
return {
|
|
1030
1239
|
success: false,
|
|
1031
|
-
message: "
|
|
1032
|
-
error: "
|
|
1240
|
+
message: "maxDepth must be a non-negative integer",
|
|
1241
|
+
error: "INVALID_MAX_DEPTH"
|
|
1033
1242
|
};
|
|
1034
1243
|
}
|
|
1035
1244
|
try {
|
|
@@ -1045,88 +1254,119 @@ var list = async function(input, projectCwd) {
|
|
|
1045
1254
|
};
|
|
1046
1255
|
}
|
|
1047
1256
|
}
|
|
1048
|
-
|
|
1049
|
-
await fs5.access(absolutePath);
|
|
1050
|
-
} catch {
|
|
1257
|
+
if (!fs8__default.default.existsSync(absolutePath)) {
|
|
1051
1258
|
return {
|
|
1052
1259
|
success: false,
|
|
1053
|
-
message: `
|
|
1054
|
-
error: "
|
|
1260
|
+
message: `Directory not found: ${absolutePath}`,
|
|
1261
|
+
error: "DIR_NOT_FOUND"
|
|
1055
1262
|
};
|
|
1056
1263
|
}
|
|
1057
|
-
const
|
|
1058
|
-
if (!
|
|
1264
|
+
const stats = fs8__default.default.statSync(absolutePath);
|
|
1265
|
+
if (!stats.isDirectory()) {
|
|
1059
1266
|
return {
|
|
1060
1267
|
success: false,
|
|
1061
|
-
message: `
|
|
1062
|
-
error: "
|
|
1268
|
+
message: `Path is not a directory: ${absolutePath}`,
|
|
1269
|
+
error: "NOT_A_DIRECTORY"
|
|
1063
1270
|
};
|
|
1064
1271
|
}
|
|
1065
1272
|
const collected = [];
|
|
1066
|
-
|
|
1067
|
-
if (!pattern) return null;
|
|
1068
|
-
if (pattern.startsWith(".") && !pattern.includes("*") && !pattern.includes("?")) {
|
|
1069
|
-
return (entryName) => entryName.endsWith(pattern);
|
|
1070
|
-
}
|
|
1071
|
-
const escaped = pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
1072
|
-
const regex = new RegExp(`^${escaped}$`);
|
|
1073
|
-
return (entryName) => regex.test(entryName);
|
|
1074
|
-
})();
|
|
1075
|
-
const matchPattern = (entryName) => {
|
|
1076
|
-
if (!patternMatcher) return true;
|
|
1077
|
-
return patternMatcher(entryName);
|
|
1078
|
-
};
|
|
1079
|
-
const maxDepthNormalized = recursive ? maxDepth ?? Infinity : 0;
|
|
1273
|
+
let truncated = false;
|
|
1080
1274
|
const walk = async (currentDir, depth) => {
|
|
1081
|
-
|
|
1275
|
+
if (collected.length >= RESULT_LIMIT2) {
|
|
1276
|
+
truncated = true;
|
|
1277
|
+
return;
|
|
1278
|
+
}
|
|
1279
|
+
let entries;
|
|
1280
|
+
try {
|
|
1281
|
+
entries = fs8__default.default.readdirSync(currentDir, { withFileTypes: true });
|
|
1282
|
+
} catch {
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
entries.sort((a, b) => {
|
|
1286
|
+
if (a.isDirectory() !== b.isDirectory()) {
|
|
1287
|
+
return a.isDirectory() ? -1 : 1;
|
|
1288
|
+
}
|
|
1289
|
+
return a.name.localeCompare(b.name);
|
|
1290
|
+
});
|
|
1082
1291
|
for (const entry of entries) {
|
|
1292
|
+
if (collected.length >= RESULT_LIMIT2) {
|
|
1293
|
+
truncated = true;
|
|
1294
|
+
break;
|
|
1295
|
+
}
|
|
1296
|
+
if (shouldIgnore(entry.name, showHidden)) {
|
|
1297
|
+
continue;
|
|
1298
|
+
}
|
|
1083
1299
|
const entryAbsolutePath = path10__default.default.join(currentDir, entry.name);
|
|
1084
|
-
const entryRelativePath = path10__default.default.relative(absolutePath, entryAbsolutePath)
|
|
1300
|
+
const entryRelativePath = path10__default.default.relative(absolutePath, entryAbsolutePath);
|
|
1085
1301
|
if (entry.isDirectory()) {
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
if (recursive && depth < maxDepthNormalized && !isExcluded) {
|
|
1302
|
+
collected.push({
|
|
1303
|
+
name: entry.name,
|
|
1304
|
+
absolutePath: entryAbsolutePath,
|
|
1305
|
+
relativePath: entryRelativePath,
|
|
1306
|
+
type: "directory",
|
|
1307
|
+
mtime: 0,
|
|
1308
|
+
depth
|
|
1309
|
+
});
|
|
1310
|
+
if (recursive && depth < maxDepth) {
|
|
1096
1311
|
await walk(entryAbsolutePath, depth + 1);
|
|
1097
1312
|
}
|
|
1098
1313
|
} else if (entry.isFile()) {
|
|
1099
|
-
if (
|
|
1314
|
+
if (matchPattern(entry.name, pattern)) {
|
|
1100
1315
|
collected.push({
|
|
1101
1316
|
name: entry.name,
|
|
1102
1317
|
absolutePath: entryAbsolutePath,
|
|
1103
1318
|
relativePath: entryRelativePath,
|
|
1104
|
-
type: "file"
|
|
1319
|
+
type: "file",
|
|
1320
|
+
mtime: 0,
|
|
1321
|
+
depth
|
|
1105
1322
|
});
|
|
1106
1323
|
}
|
|
1107
1324
|
}
|
|
1108
1325
|
}
|
|
1109
1326
|
};
|
|
1110
1327
|
await walk(absolutePath, 0);
|
|
1328
|
+
await getMtimesBatched3(collected);
|
|
1111
1329
|
const totalFiles = collected.filter((item) => item.type === "file").length;
|
|
1112
1330
|
const totalDirectories = collected.filter((item) => item.type === "directory").length;
|
|
1113
|
-
|
|
1331
|
+
const treeOutput = buildTreeOutput(collected, relativePath || path10__default.default.basename(absolutePath));
|
|
1332
|
+
let message = `Listed ${collected.length} items`;
|
|
1333
|
+
if (relativePath) {
|
|
1334
|
+
message += ` in "${relativePath}"`;
|
|
1335
|
+
}
|
|
1336
|
+
message += ` (${totalFiles} files, ${totalDirectories} directories)`;
|
|
1114
1337
|
if (recursive) {
|
|
1115
|
-
message += `
|
|
1338
|
+
message += ` [depth: ${maxDepth}]`;
|
|
1116
1339
|
}
|
|
1117
1340
|
if (pattern) {
|
|
1118
|
-
message += `
|
|
1341
|
+
message += ` [filter: ${pattern}]`;
|
|
1119
1342
|
}
|
|
1120
|
-
|
|
1343
|
+
if (truncated) {
|
|
1344
|
+
message += ` [TRUNCATED at ${RESULT_LIMIT2} items]`;
|
|
1345
|
+
}
|
|
1346
|
+
const files = collected.map((item) => ({
|
|
1347
|
+
name: item.name,
|
|
1348
|
+
path: item.relativePath,
|
|
1349
|
+
type: item.type
|
|
1350
|
+
}));
|
|
1121
1351
|
return {
|
|
1122
1352
|
success: true,
|
|
1123
1353
|
message,
|
|
1124
|
-
|
|
1354
|
+
metadata: {
|
|
1355
|
+
totalFiles,
|
|
1356
|
+
totalDirectories,
|
|
1357
|
+
totalItems: collected.length,
|
|
1358
|
+
truncated,
|
|
1359
|
+
maxDepth,
|
|
1360
|
+
recursive
|
|
1361
|
+
},
|
|
1362
|
+
files,
|
|
1363
|
+
content: treeOutput
|
|
1125
1364
|
};
|
|
1126
1365
|
} catch (error) {
|
|
1366
|
+
console.error("[list] error:", error);
|
|
1127
1367
|
return {
|
|
1128
1368
|
success: false,
|
|
1129
|
-
message: `Failed to list
|
|
1369
|
+
message: `Failed to list directory: ${error}`,
|
|
1130
1370
|
error: "LIST_ERROR"
|
|
1131
1371
|
};
|
|
1132
1372
|
}
|
|
@@ -1142,19 +1382,19 @@ var startHttpServer = () => {
|
|
|
1142
1382
|
var CREDENTIALS_DIR = path10__default.default.join(os3__default.default.homedir(), ".amai");
|
|
1143
1383
|
var CREDENTIALS_PATH = path10__default.default.join(CREDENTIALS_DIR, "credentials.json");
|
|
1144
1384
|
function getTokens() {
|
|
1145
|
-
if (!
|
|
1385
|
+
if (!fs8__default.default.existsSync(CREDENTIALS_PATH)) {
|
|
1146
1386
|
return null;
|
|
1147
1387
|
}
|
|
1148
|
-
const raw =
|
|
1388
|
+
const raw = fs8__default.default.readFileSync(CREDENTIALS_PATH, "utf8");
|
|
1149
1389
|
const data = JSON.parse(raw);
|
|
1150
1390
|
return data;
|
|
1151
1391
|
}
|
|
1152
1392
|
var getUserId = () => {
|
|
1153
1393
|
try {
|
|
1154
|
-
if (!
|
|
1394
|
+
if (!fs8__default.default.existsSync(CREDENTIALS_PATH)) {
|
|
1155
1395
|
return;
|
|
1156
1396
|
}
|
|
1157
|
-
const raw =
|
|
1397
|
+
const raw = fs8__default.default.readFileSync(CREDENTIALS_PATH, "utf8");
|
|
1158
1398
|
const data = JSON.parse(raw);
|
|
1159
1399
|
return {
|
|
1160
1400
|
userId: data.user.id
|
|
@@ -1203,7 +1443,7 @@ zod.z.object({
|
|
|
1203
1443
|
command: zod.z.string().describe("The terminal command to execute (e.g., 'ls -la', 'pwd', 'echo $HOME')"),
|
|
1204
1444
|
is_background: zod.z.boolean().describe("Whether the command should be run in the background")
|
|
1205
1445
|
}).merge(ExplanationSchema);
|
|
1206
|
-
var runSecureTerminalCommand = async (command, timeout) => {
|
|
1446
|
+
var runSecureTerminalCommand = async (command, timeout, cwd) => {
|
|
1207
1447
|
try {
|
|
1208
1448
|
if (isHarmfulCommand(command)) {
|
|
1209
1449
|
console.log(`[CLI] Harmful command detected: ${command}`);
|
|
@@ -1213,42 +1453,44 @@ var runSecureTerminalCommand = async (command, timeout) => {
|
|
|
1213
1453
|
error: "HARMFUL_COMMAND_DETECTED"
|
|
1214
1454
|
};
|
|
1215
1455
|
}
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
shell: true
|
|
1221
|
-
});
|
|
1222
|
-
let stdout = "";
|
|
1223
|
-
let stderr = "";
|
|
1224
|
-
let timeoutId = null;
|
|
1225
|
-
if (timeoutId > 0) {
|
|
1226
|
-
timeoutId = setTimeout(() => {
|
|
1227
|
-
child.kill("SIGKILL");
|
|
1228
|
-
reject(new Error(`Command timed out after ${timeout}ms`));
|
|
1229
|
-
}, timeout);
|
|
1230
|
-
}
|
|
1231
|
-
child.stdout?.on("data", (data) => {
|
|
1232
|
-
stdout += data.toString();
|
|
1233
|
-
});
|
|
1234
|
-
child.stderr?.on("data", (data) => {
|
|
1235
|
-
stderr += data.toString();
|
|
1236
|
-
});
|
|
1237
|
-
child.stdout.on("close", (code) => {
|
|
1238
|
-
if (timeoutId) {
|
|
1239
|
-
clearTimeout(timeoutId);
|
|
1240
|
-
}
|
|
1241
|
-
resolve({ stdout, stderr, exitCode: code || 0 });
|
|
1242
|
-
});
|
|
1243
|
-
child.stderr.on("error", (error) => {
|
|
1244
|
-
if (timeoutId) {
|
|
1245
|
-
clearTimeout(timeoutId);
|
|
1246
|
-
}
|
|
1247
|
-
reject(error);
|
|
1248
|
-
});
|
|
1456
|
+
const proc = Bun.spawn(["sh", "-c", command], {
|
|
1457
|
+
cwd: cwd || process.cwd(),
|
|
1458
|
+
stdout: "pipe",
|
|
1459
|
+
stderr: "pipe"
|
|
1249
1460
|
});
|
|
1250
|
-
|
|
1251
|
-
|
|
1461
|
+
let timedOut = false;
|
|
1462
|
+
let timeoutId = null;
|
|
1463
|
+
if (timeout > 0) {
|
|
1464
|
+
timeoutId = setTimeout(() => {
|
|
1465
|
+
timedOut = true;
|
|
1466
|
+
proc.kill();
|
|
1467
|
+
}, timeout);
|
|
1468
|
+
}
|
|
1469
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
1470
|
+
new Response(proc.stdout).text(),
|
|
1471
|
+
new Response(proc.stderr).text(),
|
|
1472
|
+
proc.exited
|
|
1473
|
+
]);
|
|
1474
|
+
if (timeoutId) {
|
|
1475
|
+
clearTimeout(timeoutId);
|
|
1476
|
+
}
|
|
1477
|
+
if (timedOut) {
|
|
1478
|
+
return {
|
|
1479
|
+
success: false,
|
|
1480
|
+
message: `Command timed out after ${timeout}ms`,
|
|
1481
|
+
error: "TIMEOUT",
|
|
1482
|
+
stdout,
|
|
1483
|
+
stderr
|
|
1484
|
+
};
|
|
1485
|
+
}
|
|
1486
|
+
return { stdout, stderr, exitCode };
|
|
1487
|
+
} catch (error) {
|
|
1488
|
+
console.error("Error while executing the securedShell command", error);
|
|
1489
|
+
return {
|
|
1490
|
+
success: false,
|
|
1491
|
+
message: "Error while executing the securedShell command",
|
|
1492
|
+
error: error.message
|
|
1493
|
+
};
|
|
1252
1494
|
}
|
|
1253
1495
|
};
|
|
1254
1496
|
var runTerminalCommand = async (input, projectCwd) => {
|
|
@@ -1262,13 +1504,12 @@ var runTerminalCommand = async (input, projectCwd) => {
|
|
|
1262
1504
|
error: "HARMFUL_COMMAND_DETECTED"
|
|
1263
1505
|
};
|
|
1264
1506
|
}
|
|
1265
|
-
const
|
|
1266
|
-
cwd: projectCwd,
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
shell: true
|
|
1507
|
+
const proc = Bun.spawn(["sh", "-c", input.command], {
|
|
1508
|
+
cwd: projectCwd || process.cwd(),
|
|
1509
|
+
stdout: "ignore",
|
|
1510
|
+
stderr: "ignore"
|
|
1270
1511
|
});
|
|
1271
|
-
|
|
1512
|
+
proc.unref();
|
|
1272
1513
|
console.log(`[LOCAL] Background command started: ${input.command}`);
|
|
1273
1514
|
return {
|
|
1274
1515
|
success: true,
|
|
@@ -1278,9 +1519,13 @@ var runTerminalCommand = async (input, projectCwd) => {
|
|
|
1278
1519
|
} else {
|
|
1279
1520
|
const result = await runSecureTerminalCommand(
|
|
1280
1521
|
input.command,
|
|
1281
|
-
3e4
|
|
1522
|
+
3e4,
|
|
1282
1523
|
// 30 second timeout
|
|
1524
|
+
projectCwd
|
|
1283
1525
|
);
|
|
1526
|
+
if (result?.error && !result?.exitCode) {
|
|
1527
|
+
return result;
|
|
1528
|
+
}
|
|
1284
1529
|
const success = result?.exitCode === 0;
|
|
1285
1530
|
return {
|
|
1286
1531
|
success,
|
|
@@ -1299,9 +1544,9 @@ var runTerminalCommand = async (input, projectCwd) => {
|
|
|
1299
1544
|
};
|
|
1300
1545
|
}
|
|
1301
1546
|
};
|
|
1302
|
-
var ignoreFiles = ["node_modules", ".git", ".next", ".env", ".env.local", ".env.development.local", ".env.test.local", ".env.production.local"];
|
|
1547
|
+
var ignoreFiles = ["node_modules", ".git", ".next", ".env", ".env.local", ".env.development.local", ".env.test.local", ".env.production.local", ".output", ".turbo", ".vercel", ".next", ".tanstack", ".nitro", ".wrangler", ".alchemy", ".coverage", ".nyc_output", ".cache", "tmp", "temp", ".idea", ".vscode", ".zig-cache", "zig-out", ".coverage", "coverage", "logs", ".venv", "venv", "env", ".next", ".turbo", ".vercel", ".output", ".tanstack", ".nitro", ".wrangler", ".alchemy", ".coverage", ".nyc_output", ".cache", "tmp", "temp", ".idea", ".vscode", ".zig-cache", "zig-out", ".coverage", "coverage", "logs", ".venv", "venv", "env"];
|
|
1303
1548
|
var getContext = (dir, base = dir, allFiles = []) => {
|
|
1304
|
-
const filePath =
|
|
1549
|
+
const filePath = fs8.readdirSync(dir, { withFileTypes: true });
|
|
1305
1550
|
for (const file of filePath) {
|
|
1306
1551
|
if (ignoreFiles.includes(file.name)) continue;
|
|
1307
1552
|
const fullPath = path10__default.default.join(dir, file.name);
|
|
@@ -1321,28 +1566,34 @@ var IDE_PROJECTS_PATHS = {
|
|
|
1321
1566
|
};
|
|
1322
1567
|
function getWorkspaceStoragePath(ide) {
|
|
1323
1568
|
const platform = os3__default.default.platform();
|
|
1324
|
-
const appName = "Cursor" ;
|
|
1569
|
+
const appName = ide === "cursor" ? "Cursor" : "Code";
|
|
1570
|
+
const appNameLower = appName.toLowerCase();
|
|
1325
1571
|
if (platform === "darwin") {
|
|
1326
1572
|
return path10__default.default.join(HOME, "Library", "Application Support", appName, "User", "workspaceStorage");
|
|
1327
1573
|
} else if (platform === "win32") {
|
|
1328
1574
|
return path10__default.default.join(process.env.APPDATA || "", appName, "User", "workspaceStorage");
|
|
1329
1575
|
} else {
|
|
1330
|
-
|
|
1576
|
+
const capitalizedPath = path10__default.default.join(HOME, ".config", appName, "User", "workspaceStorage");
|
|
1577
|
+
const lowercasePath = path10__default.default.join(HOME, ".config", appNameLower, "User", "workspaceStorage");
|
|
1578
|
+
if (fs8__default.default.existsSync(capitalizedPath)) {
|
|
1579
|
+
return capitalizedPath;
|
|
1580
|
+
}
|
|
1581
|
+
return lowercasePath;
|
|
1331
1582
|
}
|
|
1332
1583
|
}
|
|
1333
1584
|
function scanWorkspaceStorage(ide) {
|
|
1334
1585
|
const projects = [];
|
|
1335
|
-
const storagePath = getWorkspaceStoragePath();
|
|
1336
|
-
if (!
|
|
1586
|
+
const storagePath = getWorkspaceStoragePath(ide);
|
|
1587
|
+
if (!fs8__default.default.existsSync(storagePath)) {
|
|
1337
1588
|
return projects;
|
|
1338
1589
|
}
|
|
1339
1590
|
try {
|
|
1340
|
-
const workspaces =
|
|
1591
|
+
const workspaces = fs8__default.default.readdirSync(storagePath);
|
|
1341
1592
|
for (const workspace of workspaces) {
|
|
1342
1593
|
const workspaceJsonPath = path10__default.default.join(storagePath, workspace, "workspace.json");
|
|
1343
|
-
if (
|
|
1594
|
+
if (fs8__default.default.existsSync(workspaceJsonPath)) {
|
|
1344
1595
|
try {
|
|
1345
|
-
const content =
|
|
1596
|
+
const content = fs8__default.default.readFileSync(workspaceJsonPath, "utf-8");
|
|
1346
1597
|
const data = JSON.parse(content);
|
|
1347
1598
|
if (data.folder && typeof data.folder === "string") {
|
|
1348
1599
|
let projectPath = data.folder;
|
|
@@ -1350,7 +1601,7 @@ function scanWorkspaceStorage(ide) {
|
|
|
1350
1601
|
projectPath = projectPath.replace("file://", "");
|
|
1351
1602
|
projectPath = decodeURIComponent(projectPath);
|
|
1352
1603
|
}
|
|
1353
|
-
if (
|
|
1604
|
+
if (fs8__default.default.existsSync(projectPath) && fs8__default.default.statSync(projectPath).isDirectory()) {
|
|
1354
1605
|
projects.push({
|
|
1355
1606
|
name: path10__default.default.basename(projectPath),
|
|
1356
1607
|
path: projectPath,
|
|
@@ -1374,11 +1625,11 @@ var scanIdeProjects = async () => {
|
|
|
1374
1625
|
const seenPaths = /* @__PURE__ */ new Set();
|
|
1375
1626
|
const addProject = (projectPath, ide) => {
|
|
1376
1627
|
try {
|
|
1377
|
-
const resolvedPath =
|
|
1378
|
-
if (
|
|
1628
|
+
const resolvedPath = fs8__default.default.realpathSync(projectPath);
|
|
1629
|
+
if (fs8__default.default.existsSync(resolvedPath) && fs8__default.default.statSync(resolvedPath).isDirectory() && !seenPaths.has(resolvedPath)) {
|
|
1379
1630
|
const isIdeProjectsDir = Object.values(IDE_PROJECTS_PATHS).some((ideDir) => {
|
|
1380
1631
|
try {
|
|
1381
|
-
return
|
|
1632
|
+
return fs8__default.default.realpathSync(ideDir) === resolvedPath;
|
|
1382
1633
|
} catch {
|
|
1383
1634
|
return false;
|
|
1384
1635
|
}
|
|
@@ -1399,32 +1650,36 @@ var scanIdeProjects = async () => {
|
|
|
1399
1650
|
for (const project of cursorProjects) {
|
|
1400
1651
|
addProject(project.path, "cursor");
|
|
1401
1652
|
}
|
|
1653
|
+
const vscodeProjects = scanWorkspaceStorage("vscode");
|
|
1654
|
+
for (const project of vscodeProjects) {
|
|
1655
|
+
addProject(project.path, "vscode");
|
|
1656
|
+
}
|
|
1402
1657
|
for (const [ide, dirPath] of Object.entries(IDE_PROJECTS_PATHS)) {
|
|
1403
|
-
if (ide === "cursor") continue;
|
|
1404
|
-
if (
|
|
1405
|
-
const projects =
|
|
1658
|
+
if (ide === "cursor" || ide === "vscode") continue;
|
|
1659
|
+
if (fs8__default.default.existsSync(dirPath)) {
|
|
1660
|
+
const projects = fs8__default.default.readdirSync(dirPath);
|
|
1406
1661
|
projects.forEach((project) => {
|
|
1407
1662
|
const projectPath = path10__default.default.join(dirPath, project);
|
|
1408
1663
|
try {
|
|
1409
|
-
const stats =
|
|
1664
|
+
const stats = fs8__default.default.lstatSync(projectPath);
|
|
1410
1665
|
let actualPath = null;
|
|
1411
1666
|
if (stats.isSymbolicLink()) {
|
|
1412
|
-
actualPath =
|
|
1667
|
+
actualPath = fs8__default.default.realpathSync(projectPath);
|
|
1413
1668
|
} else if (stats.isFile()) {
|
|
1414
1669
|
try {
|
|
1415
|
-
let content =
|
|
1670
|
+
let content = fs8__default.default.readFileSync(projectPath, "utf-8").trim();
|
|
1416
1671
|
if (content.startsWith("~/") || content === "~") {
|
|
1417
1672
|
content = content.replace(/^~/, HOME);
|
|
1418
1673
|
}
|
|
1419
1674
|
const resolvedContent = path10__default.default.isAbsolute(content) ? content : path10__default.default.resolve(path10__default.default.dirname(projectPath), content);
|
|
1420
|
-
if (
|
|
1421
|
-
actualPath =
|
|
1675
|
+
if (fs8__default.default.existsSync(resolvedContent) && fs8__default.default.statSync(resolvedContent).isDirectory()) {
|
|
1676
|
+
actualPath = fs8__default.default.realpathSync(resolvedContent);
|
|
1422
1677
|
}
|
|
1423
1678
|
} catch {
|
|
1424
1679
|
return;
|
|
1425
1680
|
}
|
|
1426
1681
|
} else if (stats.isDirectory()) {
|
|
1427
|
-
actualPath =
|
|
1682
|
+
actualPath = fs8__default.default.realpathSync(projectPath);
|
|
1428
1683
|
}
|
|
1429
1684
|
if (actualPath) {
|
|
1430
1685
|
addProject(actualPath, ide);
|
|
@@ -1448,7 +1703,7 @@ var Global;
|
|
|
1448
1703
|
})(Global || (Global = {}));
|
|
1449
1704
|
|
|
1450
1705
|
// src/snapshot/snapshot.ts
|
|
1451
|
-
var
|
|
1706
|
+
var execAsync = util.promisify(child_process.exec);
|
|
1452
1707
|
var Snapshot;
|
|
1453
1708
|
((Snapshot2) => {
|
|
1454
1709
|
const log = {
|
|
@@ -1458,7 +1713,7 @@ var Snapshot;
|
|
|
1458
1713
|
};
|
|
1459
1714
|
async function runGit(command, options = {}) {
|
|
1460
1715
|
try {
|
|
1461
|
-
const { stdout, stderr } = await
|
|
1716
|
+
const { stdout, stderr } = await execAsync(command, {
|
|
1462
1717
|
cwd: options.cwd,
|
|
1463
1718
|
env: { ...process.env, ...options.env },
|
|
1464
1719
|
encoding: "utf-8",
|
|
@@ -1482,8 +1737,8 @@ var Snapshot;
|
|
|
1482
1737
|
const worktree = project.cwd;
|
|
1483
1738
|
const git = gitdir(projectId);
|
|
1484
1739
|
try {
|
|
1485
|
-
await
|
|
1486
|
-
const gitExists = await
|
|
1740
|
+
await fs7__default.default.mkdir(git, { recursive: true });
|
|
1741
|
+
const gitExists = await fs7__default.default.access(path10__default.default.join(git, "HEAD")).then(() => true).catch(() => false);
|
|
1487
1742
|
if (!gitExists) {
|
|
1488
1743
|
await runGit(`git init`, {
|
|
1489
1744
|
env: { GIT_DIR: git, GIT_WORK_TREE: worktree }
|
|
@@ -1568,7 +1823,7 @@ var Snapshot;
|
|
|
1568
1823
|
for (const file of newFiles) {
|
|
1569
1824
|
const fullPath = path10__default.default.join(worktree, file);
|
|
1570
1825
|
try {
|
|
1571
|
-
await
|
|
1826
|
+
await fs7__default.default.unlink(fullPath);
|
|
1572
1827
|
log.info("deleted newly created file", { file: fullPath });
|
|
1573
1828
|
} catch {
|
|
1574
1829
|
}
|
|
@@ -1605,7 +1860,7 @@ var Snapshot;
|
|
|
1605
1860
|
log.info("file existed in snapshot but checkout failed, keeping", { file });
|
|
1606
1861
|
} else {
|
|
1607
1862
|
log.info("file did not exist in snapshot, deleting", { file });
|
|
1608
|
-
await
|
|
1863
|
+
await fs7__default.default.unlink(file).catch(() => {
|
|
1609
1864
|
});
|
|
1610
1865
|
}
|
|
1611
1866
|
}
|
|
@@ -2054,7 +2309,7 @@ async function main() {
|
|
|
2054
2309
|
await connectToUserStreams(serverUrl);
|
|
2055
2310
|
startHttpServer();
|
|
2056
2311
|
}
|
|
2057
|
-
var
|
|
2312
|
+
var execAsync2 = util.promisify(child_process.exec);
|
|
2058
2313
|
var CODE_SERVER_VERSION = "4.96.4";
|
|
2059
2314
|
function getPlatformInfo() {
|
|
2060
2315
|
const platform = process.platform;
|
|
@@ -2088,50 +2343,50 @@ function getCodeServerBin() {
|
|
|
2088
2343
|
}
|
|
2089
2344
|
function isCodeServerInstalled() {
|
|
2090
2345
|
const binPath = getCodeServerBin();
|
|
2091
|
-
return
|
|
2346
|
+
return fs8__default.default.existsSync(binPath);
|
|
2092
2347
|
}
|
|
2093
2348
|
async function installCodeServer() {
|
|
2094
2349
|
const { ext } = getPlatformInfo();
|
|
2095
2350
|
const downloadUrl = getDownloadUrl();
|
|
2096
2351
|
const tarballPath = path10__default.default.join(AMA_DIR, `code-server.${ext}`);
|
|
2097
|
-
if (!
|
|
2098
|
-
|
|
2352
|
+
if (!fs8__default.default.existsSync(AMA_DIR)) {
|
|
2353
|
+
fs8__default.default.mkdirSync(AMA_DIR, { recursive: true });
|
|
2099
2354
|
}
|
|
2100
|
-
if (!
|
|
2101
|
-
|
|
2355
|
+
if (!fs8__default.default.existsSync(CODE_DIR)) {
|
|
2356
|
+
fs8__default.default.mkdirSync(CODE_DIR, { recursive: true });
|
|
2102
2357
|
}
|
|
2103
|
-
if (!
|
|
2104
|
-
|
|
2358
|
+
if (!fs8__default.default.existsSync(STORAGE_DIR)) {
|
|
2359
|
+
fs8__default.default.mkdirSync(STORAGE_DIR, { recursive: true });
|
|
2105
2360
|
}
|
|
2106
|
-
console.log(pc4__default.default.cyan(`
|
|
2361
|
+
console.log(pc4__default.default.cyan(`downloading code-server v${CODE_SERVER_VERSION}...`));
|
|
2107
2362
|
console.log(pc4__default.default.gray(downloadUrl));
|
|
2108
2363
|
const response = await fetch(downloadUrl);
|
|
2109
2364
|
if (!response.ok) {
|
|
2110
2365
|
throw new Error(`Failed to download code-server: ${response.statusText}`);
|
|
2111
2366
|
}
|
|
2112
2367
|
const buffer = await response.arrayBuffer();
|
|
2113
|
-
await
|
|
2368
|
+
await fs8__default.default.promises.writeFile(tarballPath, Buffer.from(buffer));
|
|
2114
2369
|
console.log(pc4__default.default.cyan("Extracting code-server..."));
|
|
2115
|
-
await
|
|
2116
|
-
await
|
|
2370
|
+
await execAsync2(`tar -xzf ${tarballPath} -C ${CODE_DIR}`);
|
|
2371
|
+
await fs8__default.default.promises.unlink(tarballPath);
|
|
2117
2372
|
const binPath = getCodeServerBin();
|
|
2118
|
-
if (
|
|
2119
|
-
await
|
|
2373
|
+
if (fs8__default.default.existsSync(binPath)) {
|
|
2374
|
+
await fs8__default.default.promises.chmod(binPath, 493);
|
|
2120
2375
|
}
|
|
2121
|
-
console.log(pc4__default.default.green("
|
|
2376
|
+
console.log(pc4__default.default.green("code-server installed successfully"));
|
|
2122
2377
|
}
|
|
2123
2378
|
async function killExistingCodeServer() {
|
|
2124
2379
|
try {
|
|
2125
2380
|
if (process.platform === "win32") {
|
|
2126
|
-
await
|
|
2381
|
+
await execAsync2("netstat -ano | findstr :8081 | findstr LISTENING").then(async ({ stdout }) => {
|
|
2127
2382
|
const pid = stdout.trim().split(/\s+/).pop();
|
|
2128
|
-
if (pid) await
|
|
2383
|
+
if (pid) await execAsync2(`taskkill /PID ${pid} /F`);
|
|
2129
2384
|
}).catch(() => {
|
|
2130
2385
|
});
|
|
2131
2386
|
} else {
|
|
2132
|
-
await
|
|
2387
|
+
await execAsync2("lsof -ti:8081").then(async ({ stdout }) => {
|
|
2133
2388
|
const pid = stdout.trim();
|
|
2134
|
-
if (pid) await
|
|
2389
|
+
if (pid) await execAsync2(`kill -9 ${pid}`);
|
|
2135
2390
|
}).catch(() => {
|
|
2136
2391
|
});
|
|
2137
2392
|
}
|
|
@@ -2141,8 +2396,8 @@ async function killExistingCodeServer() {
|
|
|
2141
2396
|
async function setupDefaultSettings() {
|
|
2142
2397
|
const userDir = path10__default.default.join(STORAGE_DIR, "User");
|
|
2143
2398
|
const settingsPath = path10__default.default.join(userDir, "settings.json");
|
|
2144
|
-
if (!
|
|
2145
|
-
|
|
2399
|
+
if (!fs8__default.default.existsSync(userDir)) {
|
|
2400
|
+
fs8__default.default.mkdirSync(userDir, { recursive: true });
|
|
2146
2401
|
}
|
|
2147
2402
|
const defaultSettings = {
|
|
2148
2403
|
// Disable signature verification for Open VSX extensions
|
|
@@ -2160,9 +2415,9 @@ async function setupDefaultSettings() {
|
|
|
2160
2415
|
"workbench.activityBar.location": "top"
|
|
2161
2416
|
};
|
|
2162
2417
|
let existingSettings = {};
|
|
2163
|
-
if (
|
|
2418
|
+
if (fs8__default.default.existsSync(settingsPath)) {
|
|
2164
2419
|
try {
|
|
2165
|
-
const content = await
|
|
2420
|
+
const content = await fs8__default.default.promises.readFile(settingsPath, "utf-8");
|
|
2166
2421
|
existingSettings = JSON.parse(content);
|
|
2167
2422
|
} catch {
|
|
2168
2423
|
}
|
|
@@ -2170,7 +2425,7 @@ async function setupDefaultSettings() {
|
|
|
2170
2425
|
const mergedSettings = { ...defaultSettings, ...existingSettings };
|
|
2171
2426
|
mergedSettings["workbench.colorTheme"] = "Min Dark";
|
|
2172
2427
|
mergedSettings["extensions.verifySignature"] = false;
|
|
2173
|
-
await
|
|
2428
|
+
await fs8__default.default.promises.writeFile(settingsPath, JSON.stringify(mergedSettings, null, 2));
|
|
2174
2429
|
console.log(pc4__default.default.green("ama code-server settings configured"));
|
|
2175
2430
|
}
|
|
2176
2431
|
async function installExtensions() {
|
|
@@ -2181,7 +2436,7 @@ async function installExtensions() {
|
|
|
2181
2436
|
for (const ext of extensions) {
|
|
2182
2437
|
try {
|
|
2183
2438
|
console.log(pc4__default.default.cyan(`ama installing extension: ${ext}...`));
|
|
2184
|
-
await
|
|
2439
|
+
await execAsync2(`"${binPath}" --user-data-dir "${STORAGE_DIR}" --install-extension ${ext}`);
|
|
2185
2440
|
console.log(pc4__default.default.green(`ama extension ${ext} installed`));
|
|
2186
2441
|
} catch (error) {
|
|
2187
2442
|
console.log(pc4__default.default.yellow(`ama failed to install extension ${ext}`), error);
|
|
@@ -2191,7 +2446,7 @@ async function installExtensions() {
|
|
|
2191
2446
|
async function startCodeServer(cwd) {
|
|
2192
2447
|
const binPath = getCodeServerBin();
|
|
2193
2448
|
const workDir = cwd || process.cwd();
|
|
2194
|
-
if (!
|
|
2449
|
+
if (!fs8__default.default.existsSync(binPath)) {
|
|
2195
2450
|
throw new Error("ama code-server is not installed. Run installCodeServer() first.");
|
|
2196
2451
|
}
|
|
2197
2452
|
await killExistingCodeServer();
|
|
@@ -2199,12 +2454,12 @@ async function startCodeServer(cwd) {
|
|
|
2199
2454
|
await installExtensions();
|
|
2200
2455
|
const workspaceStoragePath = path10__default.default.join(STORAGE_DIR, "User", "workspaceStorage");
|
|
2201
2456
|
try {
|
|
2202
|
-
if (
|
|
2203
|
-
await
|
|
2457
|
+
if (fs8__default.default.existsSync(workspaceStoragePath)) {
|
|
2458
|
+
await fs8__default.default.promises.rm(workspaceStoragePath, { recursive: true, force: true });
|
|
2204
2459
|
}
|
|
2205
2460
|
const stateDbPath = path10__default.default.join(STORAGE_DIR, "User", "globalStorage", "state.vscdb");
|
|
2206
|
-
if (
|
|
2207
|
-
await
|
|
2461
|
+
if (fs8__default.default.existsSync(stateDbPath)) {
|
|
2462
|
+
await fs8__default.default.promises.unlink(stateDbPath);
|
|
2208
2463
|
}
|
|
2209
2464
|
} catch {
|
|
2210
2465
|
}
|