amai 0.0.10 → 0.0.12
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 +765 -434
- package/dist/cli.js +761 -430
- package/dist/lib/daemon-entry.cjs +740 -409
- package/dist/lib/daemon-entry.js +736 -405
- package/dist/server.cjs +710 -379
- package/dist/server.js +706 -375
- package/package.json +60 -60
package/dist/cli.cjs
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var pc5 = require('picocolors');
|
|
5
5
|
var WebSocket = require('ws');
|
|
6
6
|
var zod = require('zod');
|
|
7
|
-
var fs5 = require('fs/promises');
|
|
8
7
|
var path10 = require('path');
|
|
9
|
-
var
|
|
8
|
+
var fs8 = require('fs');
|
|
10
9
|
var os3 = require('os');
|
|
11
|
-
var
|
|
12
|
-
var util = require('util');
|
|
10
|
+
var fs7 = require('fs/promises');
|
|
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
|
var url = require('url');
|
|
17
17
|
var readline = require('readline');
|
|
18
18
|
|
|
@@ -21,10 +21,10 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
21
21
|
|
|
22
22
|
var pc5__default = /*#__PURE__*/_interopDefault(pc5);
|
|
23
23
|
var WebSocket__default = /*#__PURE__*/_interopDefault(WebSocket);
|
|
24
|
-
var fs5__default = /*#__PURE__*/_interopDefault(fs5);
|
|
25
24
|
var path10__default = /*#__PURE__*/_interopDefault(path10);
|
|
26
|
-
var
|
|
25
|
+
var fs8__default = /*#__PURE__*/_interopDefault(fs8);
|
|
27
26
|
var os3__default = /*#__PURE__*/_interopDefault(os3);
|
|
27
|
+
var fs7__default = /*#__PURE__*/_interopDefault(fs7);
|
|
28
28
|
var readline__default = /*#__PURE__*/_interopDefault(readline);
|
|
29
29
|
|
|
30
30
|
var DEFAULT_SERVER_URL = "wss://ama-production-a628.up.railway.app";
|
|
@@ -42,14 +42,14 @@ var ProjectRegistry = class {
|
|
|
42
42
|
}
|
|
43
43
|
load() {
|
|
44
44
|
try {
|
|
45
|
-
if (
|
|
46
|
-
const data =
|
|
45
|
+
if (fs8__default.default.existsSync(REGISTRY_FILE)) {
|
|
46
|
+
const data = fs8__default.default.readFileSync(REGISTRY_FILE, "utf8");
|
|
47
47
|
const parsed = JSON.parse(data);
|
|
48
48
|
if (!Array.isArray(parsed)) {
|
|
49
49
|
console.error("Invalid project registry format: expected array, got", typeof parsed);
|
|
50
50
|
const backupFile = REGISTRY_FILE + ".backup." + Date.now();
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
fs8__default.default.copyFileSync(REGISTRY_FILE, backupFile);
|
|
52
|
+
fs8__default.default.unlinkSync(REGISTRY_FILE);
|
|
53
53
|
return;
|
|
54
54
|
}
|
|
55
55
|
const projects = parsed;
|
|
@@ -62,11 +62,11 @@ var ProjectRegistry = class {
|
|
|
62
62
|
}
|
|
63
63
|
} catch (error) {
|
|
64
64
|
console.error("Failed to load project registry:", error);
|
|
65
|
-
if (
|
|
65
|
+
if (fs8__default.default.existsSync(REGISTRY_FILE)) {
|
|
66
66
|
try {
|
|
67
67
|
const backupFile = REGISTRY_FILE + ".backup." + Date.now();
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
fs8__default.default.copyFileSync(REGISTRY_FILE, backupFile);
|
|
69
|
+
fs8__default.default.unlinkSync(REGISTRY_FILE);
|
|
70
70
|
console.log("Corrupted registry file backed up and removed. Starting fresh.");
|
|
71
71
|
} catch (backupError) {
|
|
72
72
|
}
|
|
@@ -75,11 +75,11 @@ var ProjectRegistry = class {
|
|
|
75
75
|
}
|
|
76
76
|
save() {
|
|
77
77
|
try {
|
|
78
|
-
if (!
|
|
79
|
-
|
|
78
|
+
if (!fs8__default.default.existsSync(AMA_DIR)) {
|
|
79
|
+
fs8__default.default.mkdirSync(AMA_DIR, { recursive: true });
|
|
80
80
|
}
|
|
81
81
|
const projects = Array.from(this.projects.values());
|
|
82
|
-
|
|
82
|
+
fs8__default.default.writeFileSync(REGISTRY_FILE, JSON.stringify(projects, null, 2), "utf8");
|
|
83
83
|
} catch (error) {
|
|
84
84
|
console.error("Failed to save project registry:", error);
|
|
85
85
|
}
|
|
@@ -168,6 +168,60 @@ zod.z.object({
|
|
|
168
168
|
),
|
|
169
169
|
end_line_one_indexed: zod.z.number().optional().describe("The one-indexed line number to end reading at (inclusive).")
|
|
170
170
|
});
|
|
171
|
+
async function readFileContent(absolute_file_path, relative_file_path, should_read_entire_file, start_line_one_indexed, end_line_one_indexed) {
|
|
172
|
+
const file = Bun.file(absolute_file_path);
|
|
173
|
+
const exists = await file.exists();
|
|
174
|
+
if (!exists) {
|
|
175
|
+
return {
|
|
176
|
+
success: false,
|
|
177
|
+
message: `File not found: ${relative_file_path}`,
|
|
178
|
+
error: "FILE_NOT_FOUND"
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
const fileContent = await file.text();
|
|
183
|
+
const lines = fileContent.split(/\r?\n/);
|
|
184
|
+
const totalLines = lines.length;
|
|
185
|
+
if (should_read_entire_file) {
|
|
186
|
+
return {
|
|
187
|
+
success: true,
|
|
188
|
+
message: `Successfully read entire file: ${relative_file_path} (${totalLines} lines)`,
|
|
189
|
+
content: fileContent,
|
|
190
|
+
totalLines
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
const startIndex = start_line_one_indexed - 1;
|
|
194
|
+
if (startIndex >= totalLines) {
|
|
195
|
+
return {
|
|
196
|
+
success: false,
|
|
197
|
+
message: "start_line_one_indexed must be less than or equal to the total number of lines in the file",
|
|
198
|
+
error: "INVALID_LINE_RANGE"
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
const normalizedEnd = Math.min(end_line_one_indexed, totalLines);
|
|
202
|
+
const selectedLines = lines.slice(startIndex, normalizedEnd).join("\n");
|
|
203
|
+
const linesRead = normalizedEnd - start_line_one_indexed + 1;
|
|
204
|
+
return {
|
|
205
|
+
success: true,
|
|
206
|
+
message: `Successfully read lines ${start_line_one_indexed}-${normalizedEnd} from file: ${relative_file_path} (${linesRead} lines of ${totalLines} total)`,
|
|
207
|
+
content: selectedLines,
|
|
208
|
+
totalLines
|
|
209
|
+
};
|
|
210
|
+
} catch (error) {
|
|
211
|
+
if (error?.code === "EISDIR") {
|
|
212
|
+
return {
|
|
213
|
+
success: false,
|
|
214
|
+
message: `Path is not a file: ${relative_file_path}`,
|
|
215
|
+
error: "NOT_A_FILE"
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
return {
|
|
219
|
+
success: false,
|
|
220
|
+
message: `Failed to read file: ${relative_file_path}`,
|
|
221
|
+
error: "READ_ERROR"
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
171
225
|
var read_file = async function(input, projectCwd) {
|
|
172
226
|
const { relative_file_path, should_read_entire_file, start_line_one_indexed, end_line_one_indexed } = input;
|
|
173
227
|
try {
|
|
@@ -208,6 +262,7 @@ var read_file = async function(input, projectCwd) {
|
|
|
208
262
|
};
|
|
209
263
|
}
|
|
210
264
|
}
|
|
265
|
+
let absolute_file_path;
|
|
211
266
|
if (projectCwd) {
|
|
212
267
|
const validation = validatePath(relative_file_path, projectCwd);
|
|
213
268
|
if (!validation.valid) {
|
|
@@ -217,128 +272,17 @@ var read_file = async function(input, projectCwd) {
|
|
|
217
272
|
error: "ACCESS_DENIED"
|
|
218
273
|
};
|
|
219
274
|
}
|
|
220
|
-
|
|
221
|
-
try {
|
|
222
|
-
const fileStats = await fs5.stat(absolute_file_path);
|
|
223
|
-
if (!fileStats.isFile()) {
|
|
224
|
-
return {
|
|
225
|
-
success: false,
|
|
226
|
-
message: `Path is not a file: ${relative_file_path}`,
|
|
227
|
-
error: "NOT_A_FILE"
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
} catch (error) {
|
|
231
|
-
if (error?.code === "ENOENT") {
|
|
232
|
-
return {
|
|
233
|
-
success: false,
|
|
234
|
-
message: `File not found: ${relative_file_path}`,
|
|
235
|
-
error: "FILE_NOT_FOUND"
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
return {
|
|
239
|
-
success: false,
|
|
240
|
-
message: `Failed to access file: ${relative_file_path}`,
|
|
241
|
-
error: "READ_ERROR"
|
|
242
|
-
};
|
|
243
|
-
}
|
|
244
|
-
try {
|
|
245
|
-
const fileContent = await fs5.readFile(absolute_file_path, "utf-8");
|
|
246
|
-
const lines = fileContent.split(/\r?\n/);
|
|
247
|
-
const totalLines = lines.length;
|
|
248
|
-
if (should_read_entire_file) {
|
|
249
|
-
return {
|
|
250
|
-
success: true,
|
|
251
|
-
message: `Successfully read entire file: ${relative_file_path} (${totalLines} lines)`,
|
|
252
|
-
content: fileContent,
|
|
253
|
-
totalLines
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
const startIndex = start_line_one_indexed - 1;
|
|
257
|
-
if (startIndex >= totalLines) {
|
|
258
|
-
return {
|
|
259
|
-
success: false,
|
|
260
|
-
message: "start_line_one_indexed must be less than or equal to the total number of lines in the file",
|
|
261
|
-
error: "INVALID_LINE_RANGE"
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
const normalizedEnd = Math.min(end_line_one_indexed, totalLines);
|
|
265
|
-
const selectedLines = lines.slice(startIndex, normalizedEnd).join("\n");
|
|
266
|
-
const linesRead = normalizedEnd - start_line_one_indexed + 1;
|
|
267
|
-
return {
|
|
268
|
-
success: true,
|
|
269
|
-
message: `Successfully read lines ${start_line_one_indexed}-${normalizedEnd} from file: ${relative_file_path} (${linesRead} lines of ${totalLines} total)`,
|
|
270
|
-
content: selectedLines,
|
|
271
|
-
totalLines
|
|
272
|
-
};
|
|
273
|
-
} catch {
|
|
274
|
-
return {
|
|
275
|
-
success: false,
|
|
276
|
-
message: `Failed to read file: ${relative_file_path}`,
|
|
277
|
-
error: "READ_ERROR"
|
|
278
|
-
};
|
|
279
|
-
}
|
|
275
|
+
absolute_file_path = validation.resolvedPath;
|
|
280
276
|
} else {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
}
|
|
291
|
-
} catch (error) {
|
|
292
|
-
if (error?.code === "ENOENT") {
|
|
293
|
-
return {
|
|
294
|
-
success: false,
|
|
295
|
-
message: `File not found: ${relative_file_path}`,
|
|
296
|
-
error: "FILE_NOT_FOUND"
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
return {
|
|
300
|
-
success: false,
|
|
301
|
-
message: `Failed to access file: ${relative_file_path}`,
|
|
302
|
-
error: "READ_ERROR"
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
try {
|
|
306
|
-
const fileContent = await fs5.readFile(absolute_file_path, "utf-8");
|
|
307
|
-
const lines = fileContent.split(/\r?\n/);
|
|
308
|
-
const totalLines = lines.length;
|
|
309
|
-
if (should_read_entire_file) {
|
|
310
|
-
return {
|
|
311
|
-
success: true,
|
|
312
|
-
message: `Successfully read entire file: ${relative_file_path} (${totalLines} lines)`,
|
|
313
|
-
content: fileContent,
|
|
314
|
-
totalLines
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
const startIndex = start_line_one_indexed - 1;
|
|
318
|
-
if (startIndex >= totalLines) {
|
|
319
|
-
return {
|
|
320
|
-
success: false,
|
|
321
|
-
message: "start_line_one_indexed must be less than or equal to the total number of lines in the file",
|
|
322
|
-
error: "INVALID_LINE_RANGE"
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
const normalizedEnd = Math.min(end_line_one_indexed, totalLines);
|
|
326
|
-
const selectedLines = lines.slice(startIndex, normalizedEnd).join("\n");
|
|
327
|
-
const linesRead = normalizedEnd - start_line_one_indexed + 1;
|
|
328
|
-
return {
|
|
329
|
-
success: true,
|
|
330
|
-
message: `Successfully read lines ${start_line_one_indexed}-${normalizedEnd} from file: ${relative_file_path} (${linesRead} lines of ${totalLines} total)`,
|
|
331
|
-
content: selectedLines,
|
|
332
|
-
totalLines
|
|
333
|
-
};
|
|
334
|
-
} catch {
|
|
335
|
-
return {
|
|
336
|
-
success: false,
|
|
337
|
-
message: `Failed to read file: ${relative_file_path}`,
|
|
338
|
-
error: "READ_ERROR"
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
}
|
|
277
|
+
absolute_file_path = path10__default.default.resolve(relative_file_path);
|
|
278
|
+
}
|
|
279
|
+
return await readFileContent(
|
|
280
|
+
absolute_file_path,
|
|
281
|
+
relative_file_path,
|
|
282
|
+
should_read_entire_file,
|
|
283
|
+
start_line_one_indexed,
|
|
284
|
+
end_line_one_indexed
|
|
285
|
+
);
|
|
342
286
|
} catch {
|
|
343
287
|
return {
|
|
344
288
|
success: false,
|
|
@@ -429,13 +373,13 @@ var Diff = class {
|
|
|
429
373
|
editLength++;
|
|
430
374
|
};
|
|
431
375
|
if (callback) {
|
|
432
|
-
(function
|
|
376
|
+
(function exec3() {
|
|
433
377
|
setTimeout(function() {
|
|
434
378
|
if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
|
|
435
379
|
return callback(void 0);
|
|
436
380
|
}
|
|
437
381
|
if (!execEditLength()) {
|
|
438
|
-
|
|
382
|
+
exec3();
|
|
439
383
|
}
|
|
440
384
|
}, 0);
|
|
441
385
|
})();
|
|
@@ -662,17 +606,19 @@ var apply_patch = async function(input, projectCwd) {
|
|
|
662
606
|
}
|
|
663
607
|
const basePath = projectCwd || process.cwd();
|
|
664
608
|
const absolute_file_path = resolveProjectPath(file_path, basePath);
|
|
609
|
+
const file = Bun.file(absolute_file_path);
|
|
610
|
+
const exists = await file.exists();
|
|
611
|
+
if (!exists) {
|
|
612
|
+
return {
|
|
613
|
+
success: false,
|
|
614
|
+
message: `File not found: ${file_path}`,
|
|
615
|
+
error: "FILE_NOT_FOUND"
|
|
616
|
+
};
|
|
617
|
+
}
|
|
665
618
|
let fileContent;
|
|
666
619
|
try {
|
|
667
|
-
fileContent = await
|
|
620
|
+
fileContent = await file.text();
|
|
668
621
|
} catch (error) {
|
|
669
|
-
if (error?.code === "ENOENT") {
|
|
670
|
-
return {
|
|
671
|
-
success: false,
|
|
672
|
-
message: `File not found: ${file_path}`,
|
|
673
|
-
error: "FILE_NOT_FOUND"
|
|
674
|
-
};
|
|
675
|
-
}
|
|
676
622
|
return {
|
|
677
623
|
success: false,
|
|
678
624
|
message: `Failed to read file: ${file_path}`,
|
|
@@ -696,7 +642,7 @@ var apply_patch = async function(input, projectCwd) {
|
|
|
696
642
|
}
|
|
697
643
|
const newContent = fileContent.replace(old_string, new_string);
|
|
698
644
|
try {
|
|
699
|
-
await
|
|
645
|
+
await Bun.write(absolute_file_path, newContent);
|
|
700
646
|
const diffStats = calculateDiffStats(fileContent, newContent);
|
|
701
647
|
return {
|
|
702
648
|
success: true,
|
|
@@ -742,28 +688,27 @@ var editFiles = async function(input, projectCwd) {
|
|
|
742
688
|
const basePath = projectCwd || process.cwd();
|
|
743
689
|
const filePath = resolveProjectPath(target_file, basePath);
|
|
744
690
|
const dirPath = path10__default.default.dirname(filePath);
|
|
745
|
-
await
|
|
691
|
+
await fs7.mkdir(dirPath, { recursive: true });
|
|
746
692
|
let isNewFile = providedNewFile;
|
|
747
693
|
let existingContent = "";
|
|
694
|
+
const file = Bun.file(filePath);
|
|
748
695
|
if (isNewFile === void 0) {
|
|
749
|
-
|
|
750
|
-
|
|
696
|
+
const exists = await file.exists();
|
|
697
|
+
if (exists) {
|
|
698
|
+
existingContent = await file.text();
|
|
751
699
|
isNewFile = false;
|
|
752
|
-
}
|
|
700
|
+
} else {
|
|
753
701
|
isNewFile = true;
|
|
754
702
|
}
|
|
755
703
|
} else if (!isNewFile) {
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
704
|
+
const exists = await file.exists();
|
|
705
|
+
if (exists) {
|
|
706
|
+
existingContent = await file.text();
|
|
707
|
+
} else {
|
|
759
708
|
isNewFile = true;
|
|
760
709
|
}
|
|
761
710
|
}
|
|
762
|
-
|
|
763
|
-
await fs6__default.default.promises.writeFile(filePath, content);
|
|
764
|
-
} catch (writeError) {
|
|
765
|
-
throw writeError;
|
|
766
|
-
}
|
|
711
|
+
await Bun.write(filePath, content);
|
|
767
712
|
const diffStats = calculateDiffStats(existingContent, content);
|
|
768
713
|
if (isNewFile) {
|
|
769
714
|
return {
|
|
@@ -826,25 +771,31 @@ var deleteFile = async function(input, projectCwd) {
|
|
|
826
771
|
error: "INVALID_FILE_PATH"
|
|
827
772
|
};
|
|
828
773
|
}
|
|
829
|
-
const
|
|
830
|
-
|
|
774
|
+
const file = Bun.file(absolute_file_path);
|
|
775
|
+
const exists = await file.exists();
|
|
776
|
+
if (!exists) {
|
|
831
777
|
return {
|
|
832
778
|
success: false,
|
|
833
|
-
message: `
|
|
834
|
-
error: "
|
|
779
|
+
message: `File not found: ${realPath}`,
|
|
780
|
+
error: "FILE_NOT_FOUND"
|
|
835
781
|
};
|
|
836
782
|
}
|
|
837
|
-
|
|
783
|
+
let originalContent;
|
|
784
|
+
try {
|
|
785
|
+
originalContent = await file.text();
|
|
786
|
+
} catch {
|
|
838
787
|
return {
|
|
839
788
|
success: false,
|
|
840
789
|
message: `Failed to read file before deletion: ${realPath}`,
|
|
841
|
-
error: "
|
|
790
|
+
error: "READ_ERROR"
|
|
842
791
|
};
|
|
843
|
-
}
|
|
844
|
-
|
|
792
|
+
}
|
|
793
|
+
try {
|
|
794
|
+
await fs7.unlink(absolute_file_path);
|
|
795
|
+
} catch {
|
|
845
796
|
return {
|
|
846
797
|
success: false,
|
|
847
|
-
message: `Failed to delete file
|
|
798
|
+
message: `Failed to delete file: ${realPath}`,
|
|
848
799
|
error: "DELETE_ERROR"
|
|
849
800
|
};
|
|
850
801
|
}
|
|
@@ -861,72 +812,218 @@ var deleteFile = async function(input, projectCwd) {
|
|
|
861
812
|
};
|
|
862
813
|
}
|
|
863
814
|
};
|
|
815
|
+
var GREP_LIMITS = {
|
|
816
|
+
DEFAULT_MAX_MATCHES: 200,
|
|
817
|
+
MAX_LINE_LENGTH: 500,
|
|
818
|
+
MAX_TOTAL_OUTPUT_SIZE: 1 * 1024 * 1024,
|
|
819
|
+
TRUNCATION_MESSAGE: "\n[Results truncated due to size limits. Use more specific patterns or file filters to narrow your search.]"
|
|
820
|
+
};
|
|
864
821
|
zod.z.object({
|
|
865
822
|
query: zod.z.string().describe("The regex pattern to search for"),
|
|
866
823
|
options: zod.z.object({
|
|
867
824
|
includePattern: zod.z.string().optional().describe('Glob pattern for files to include (e.g., "*.ts")'),
|
|
868
825
|
excludePattern: zod.z.string().optional().describe("Glob pattern for files to exclude"),
|
|
869
|
-
caseSensitive: zod.z.boolean().optional().describe("Whether the search should be case sensitive")
|
|
870
|
-
|
|
826
|
+
caseSensitive: zod.z.boolean().optional().describe("Whether the search should be case sensitive"),
|
|
827
|
+
path: zod.z.string().optional().describe("Subdirectory to search in")
|
|
828
|
+
}).optional()
|
|
871
829
|
});
|
|
872
|
-
|
|
830
|
+
async function getRipgrepPath() {
|
|
831
|
+
const paths = [
|
|
832
|
+
"/opt/homebrew/bin/rg",
|
|
833
|
+
"/usr/local/bin/rg",
|
|
834
|
+
"/usr/bin/rg",
|
|
835
|
+
"rg"
|
|
836
|
+
// Fallback to PATH
|
|
837
|
+
];
|
|
838
|
+
for (const rgPath of paths) {
|
|
839
|
+
try {
|
|
840
|
+
const proc = Bun.spawn(["which", rgPath], { stdout: "pipe", stderr: "pipe" });
|
|
841
|
+
await proc.exited;
|
|
842
|
+
if (proc.exitCode === 0) {
|
|
843
|
+
return rgPath;
|
|
844
|
+
}
|
|
845
|
+
} catch {
|
|
846
|
+
continue;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
return "rg";
|
|
850
|
+
}
|
|
851
|
+
async function getMtimesBatched(files) {
|
|
852
|
+
const mtimeMap = /* @__PURE__ */ new Map();
|
|
853
|
+
const BATCH_SIZE = 50;
|
|
854
|
+
for (let i = 0; i < files.length; i += BATCH_SIZE) {
|
|
855
|
+
const batch = files.slice(i, i + BATCH_SIZE);
|
|
856
|
+
const results = await Promise.all(
|
|
857
|
+
batch.map(async (filePath) => {
|
|
858
|
+
const mtime = await Bun.file(filePath).stat().then((stats) => stats.mtime.getTime()).catch(() => 0);
|
|
859
|
+
return { path: filePath, mtime };
|
|
860
|
+
})
|
|
861
|
+
);
|
|
862
|
+
results.forEach(({ path: path16, mtime }) => mtimeMap.set(path16, mtime));
|
|
863
|
+
}
|
|
864
|
+
return mtimeMap;
|
|
865
|
+
}
|
|
873
866
|
var grepTool = async function(input, projectCwd) {
|
|
874
867
|
const { query, options } = input;
|
|
868
|
+
if (!query || query.trim() === "") {
|
|
869
|
+
return {
|
|
870
|
+
success: false,
|
|
871
|
+
message: "Missing required parameter: query",
|
|
872
|
+
error: "MISSING_QUERY"
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
875
|
try {
|
|
876
|
-
const { includePattern, excludePattern
|
|
877
|
-
|
|
878
|
-
if (
|
|
876
|
+
const { includePattern, excludePattern, caseSensitive, path: subPath } = options || {};
|
|
877
|
+
let searchDir = projectCwd || process.cwd();
|
|
878
|
+
if (subPath) {
|
|
879
|
+
searchDir = path10__default.default.isAbsolute(subPath) ? subPath : path10__default.default.resolve(searchDir, subPath);
|
|
880
|
+
if (projectCwd) {
|
|
881
|
+
const validation = validatePath(subPath, projectCwd);
|
|
882
|
+
if (!validation.valid) {
|
|
883
|
+
return {
|
|
884
|
+
success: false,
|
|
885
|
+
message: validation.error || "Path validation failed",
|
|
886
|
+
error: "ACCESS_DENIED"
|
|
887
|
+
};
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
if (!fs8__default.default.existsSync(searchDir)) {
|
|
879
892
|
return {
|
|
880
893
|
success: false,
|
|
881
|
-
message:
|
|
882
|
-
error: "
|
|
894
|
+
message: `Directory not found: ${searchDir}`,
|
|
895
|
+
error: "DIR_NOT_FOUND"
|
|
883
896
|
};
|
|
884
897
|
}
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
898
|
+
const rgPath = await getRipgrepPath();
|
|
899
|
+
const args2 = [
|
|
900
|
+
"-n",
|
|
901
|
+
// Line numbers
|
|
902
|
+
"--with-filename",
|
|
903
|
+
// Always show filename
|
|
904
|
+
"--no-heading",
|
|
905
|
+
// Don't group by file
|
|
906
|
+
"--color=never",
|
|
907
|
+
// No ANSI colors
|
|
908
|
+
"--max-count=100",
|
|
909
|
+
// Max matches per file
|
|
910
|
+
"--max-columns=1000"
|
|
911
|
+
// Truncate long lines
|
|
912
|
+
];
|
|
913
|
+
if (!caseSensitive) {
|
|
914
|
+
args2.push("-i");
|
|
888
915
|
}
|
|
889
916
|
if (includePattern) {
|
|
890
|
-
|
|
891
|
-
}
|
|
892
|
-
if (
|
|
893
|
-
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
917
|
+
args2.push("--glob", includePattern);
|
|
918
|
+
}
|
|
919
|
+
if (excludePattern) {
|
|
920
|
+
args2.push("--glob", `!${excludePattern}`);
|
|
921
|
+
}
|
|
922
|
+
args2.push("--glob", "!node_modules/**");
|
|
923
|
+
args2.push("--glob", "!.git/**");
|
|
924
|
+
args2.push("--glob", "!dist/**");
|
|
925
|
+
args2.push("--glob", "!build/**");
|
|
926
|
+
args2.push("--glob", "!*.min.js");
|
|
927
|
+
args2.push("--glob", "!*.min.css");
|
|
928
|
+
args2.push("--glob", "!package-lock.json");
|
|
929
|
+
args2.push("--glob", "!yarn.lock");
|
|
930
|
+
args2.push("--glob", "!bun.lockb");
|
|
931
|
+
args2.push("--regexp", query);
|
|
932
|
+
args2.push(searchDir);
|
|
933
|
+
const proc = Bun.spawn([rgPath, ...args2], {
|
|
934
|
+
stdout: "pipe",
|
|
935
|
+
stderr: "pipe"
|
|
936
|
+
});
|
|
937
|
+
const stdout = await new Response(proc.stdout).text();
|
|
938
|
+
const stderr = await new Response(proc.stderr).text();
|
|
939
|
+
const exitCode = await proc.exited;
|
|
940
|
+
if (exitCode === 1) {
|
|
941
|
+
return {
|
|
942
|
+
success: true,
|
|
943
|
+
matches: [],
|
|
944
|
+
detailedMatches: [],
|
|
945
|
+
query,
|
|
946
|
+
matchCount: 0,
|
|
947
|
+
message: `No matches found for pattern: ${query}`
|
|
948
|
+
};
|
|
949
|
+
}
|
|
950
|
+
if (exitCode !== 0) {
|
|
951
|
+
return {
|
|
952
|
+
success: false,
|
|
953
|
+
message: `Ripgrep error: ${stderr || "Unknown error"}`,
|
|
954
|
+
error: "GREP_EXEC_ERROR"
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
const lines = stdout.trim().split("\n").filter((line) => line.length > 0);
|
|
958
|
+
const rawMatches = [];
|
|
959
|
+
const uniqueFiles = /* @__PURE__ */ new Set();
|
|
960
|
+
for (const line of lines) {
|
|
961
|
+
const firstColon = line.indexOf(":");
|
|
962
|
+
const secondColon = line.indexOf(":", firstColon + 1);
|
|
963
|
+
if (firstColon > 0 && secondColon > firstColon) {
|
|
964
|
+
const file = line.substring(0, firstColon);
|
|
965
|
+
const lineNumber = parseInt(line.substring(firstColon + 1, secondColon), 10);
|
|
966
|
+
let content = line.substring(secondColon + 1);
|
|
967
|
+
if (content.length > GREP_LIMITS.MAX_LINE_LENGTH) {
|
|
968
|
+
content = content.substring(0, GREP_LIMITS.MAX_LINE_LENGTH) + "...";
|
|
910
969
|
}
|
|
911
|
-
|
|
970
|
+
rawMatches.push({
|
|
912
971
|
file,
|
|
913
972
|
lineNumber,
|
|
914
|
-
content
|
|
973
|
+
content: content.trim(),
|
|
974
|
+
mtime: 0
|
|
915
975
|
});
|
|
916
|
-
|
|
917
|
-
} else {
|
|
918
|
-
matches.push(rawMatch);
|
|
976
|
+
uniqueFiles.add(file);
|
|
919
977
|
}
|
|
920
978
|
}
|
|
979
|
+
const mtimeMap = await getMtimesBatched(Array.from(uniqueFiles));
|
|
980
|
+
for (const match of rawMatches) {
|
|
981
|
+
match.mtime = mtimeMap.get(match.file) || 0;
|
|
982
|
+
}
|
|
983
|
+
rawMatches.sort((a, b) => {
|
|
984
|
+
if (b.mtime !== a.mtime) {
|
|
985
|
+
return b.mtime - a.mtime;
|
|
986
|
+
}
|
|
987
|
+
return a.file.localeCompare(b.file);
|
|
988
|
+
});
|
|
989
|
+
const truncated = rawMatches.length > GREP_LIMITS.DEFAULT_MAX_MATCHES;
|
|
990
|
+
const finalMatches = truncated ? rawMatches.slice(0, GREP_LIMITS.DEFAULT_MAX_MATCHES) : rawMatches;
|
|
991
|
+
const detailedMatches = finalMatches.map((m) => ({
|
|
992
|
+
file: m.file,
|
|
993
|
+
lineNumber: m.lineNumber,
|
|
994
|
+
content: m.content
|
|
995
|
+
}));
|
|
996
|
+
const matches = finalMatches.map(
|
|
997
|
+
(m) => `${m.file}:${m.lineNumber}:${m.content}`
|
|
998
|
+
);
|
|
999
|
+
const groupedOutput = [`Found ${finalMatches.length} matches`];
|
|
1000
|
+
let currentFile = "";
|
|
1001
|
+
for (const match of finalMatches) {
|
|
1002
|
+
if (currentFile !== match.file) {
|
|
1003
|
+
if (currentFile !== "") {
|
|
1004
|
+
groupedOutput.push("");
|
|
1005
|
+
}
|
|
1006
|
+
currentFile = match.file;
|
|
1007
|
+
groupedOutput.push(`${match.file}:`);
|
|
1008
|
+
}
|
|
1009
|
+
groupedOutput.push(` Line ${match.lineNumber}: ${match.content}`);
|
|
1010
|
+
}
|
|
1011
|
+
if (truncated) {
|
|
1012
|
+
groupedOutput.push("");
|
|
1013
|
+
groupedOutput.push(GREP_LIMITS.TRUNCATION_MESSAGE);
|
|
1014
|
+
}
|
|
921
1015
|
return {
|
|
922
1016
|
success: true,
|
|
923
1017
|
matches,
|
|
924
1018
|
detailedMatches,
|
|
925
1019
|
query,
|
|
926
|
-
matchCount:
|
|
927
|
-
|
|
1020
|
+
matchCount: finalMatches.length,
|
|
1021
|
+
truncated,
|
|
1022
|
+
message: `Found ${finalMatches.length} matches for pattern: ${query}`,
|
|
1023
|
+
content: groupedOutput.join("\n")
|
|
928
1024
|
};
|
|
929
1025
|
} catch (error) {
|
|
1026
|
+
console.error("[grep] error:", error);
|
|
930
1027
|
return {
|
|
931
1028
|
success: false,
|
|
932
1029
|
message: error?.message || String(error),
|
|
@@ -935,9 +1032,25 @@ var grepTool = async function(input, projectCwd) {
|
|
|
935
1032
|
}
|
|
936
1033
|
};
|
|
937
1034
|
zod.z.object({
|
|
938
|
-
pattern: zod.z.string().describe('Glob pattern (e.g., "**/*.js")'),
|
|
939
|
-
path: zod.z.string().optional().describe("
|
|
1035
|
+
pattern: zod.z.string().describe('Glob pattern to match files (e.g., "**/*.js", "src/**/*.ts", "*.json"). Supports standard glob syntax with *, **, and ? wildcards'),
|
|
1036
|
+
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")
|
|
940
1037
|
});
|
|
1038
|
+
var RESULT_LIMIT = 100;
|
|
1039
|
+
var MTIME_BATCH_SIZE = 50;
|
|
1040
|
+
async function getMtimesBatched2(files) {
|
|
1041
|
+
const results = [];
|
|
1042
|
+
for (let i = 0; i < files.length; i += MTIME_BATCH_SIZE) {
|
|
1043
|
+
const batch = files.slice(i, i + MTIME_BATCH_SIZE);
|
|
1044
|
+
const batchResults = await Promise.all(
|
|
1045
|
+
batch.map(async (filePath) => {
|
|
1046
|
+
const mtime = await Bun.file(filePath).stat().then((stats) => stats.mtime.getTime()).catch(() => 0);
|
|
1047
|
+
return { path: filePath, mtime };
|
|
1048
|
+
})
|
|
1049
|
+
);
|
|
1050
|
+
results.push(...batchResults);
|
|
1051
|
+
}
|
|
1052
|
+
return results;
|
|
1053
|
+
}
|
|
941
1054
|
var globTool = async function(input, projectCwd) {
|
|
942
1055
|
const { pattern, path: inputPath } = input;
|
|
943
1056
|
if (!pattern) {
|
|
@@ -950,6 +1063,13 @@ var globTool = async function(input, projectCwd) {
|
|
|
950
1063
|
try {
|
|
951
1064
|
const basePath = projectCwd || process.cwd();
|
|
952
1065
|
const searchPath = inputPath ? resolveProjectPath(inputPath, basePath) : basePath;
|
|
1066
|
+
if (!fs8__default.default.existsSync(searchPath)) {
|
|
1067
|
+
return {
|
|
1068
|
+
success: false,
|
|
1069
|
+
message: `Directory not found: ${searchPath}`,
|
|
1070
|
+
error: "DIR_NOT_FOUND"
|
|
1071
|
+
};
|
|
1072
|
+
}
|
|
953
1073
|
if (projectCwd && inputPath) {
|
|
954
1074
|
const validation = validatePath(inputPath, projectCwd);
|
|
955
1075
|
if (!validation.valid) {
|
|
@@ -960,21 +1080,49 @@ var globTool = async function(input, projectCwd) {
|
|
|
960
1080
|
};
|
|
961
1081
|
}
|
|
962
1082
|
}
|
|
963
|
-
const
|
|
964
|
-
cwd: searchPath
|
|
965
|
-
});
|
|
1083
|
+
const glob = new Bun.Glob(pattern);
|
|
966
1084
|
const files = [];
|
|
967
|
-
|
|
968
|
-
|
|
1085
|
+
let truncated = false;
|
|
1086
|
+
for await (const match of glob.scan({
|
|
1087
|
+
cwd: searchPath,
|
|
1088
|
+
absolute: true,
|
|
1089
|
+
onlyFiles: true,
|
|
1090
|
+
followSymlinks: false
|
|
1091
|
+
})) {
|
|
1092
|
+
if (match.includes("/node_modules/") || match.includes("/.git/")) {
|
|
1093
|
+
continue;
|
|
1094
|
+
}
|
|
1095
|
+
if (files.length >= RESULT_LIMIT) {
|
|
1096
|
+
truncated = true;
|
|
1097
|
+
break;
|
|
1098
|
+
}
|
|
1099
|
+
files.push(match);
|
|
1100
|
+
}
|
|
1101
|
+
const filesWithMtime = await getMtimesBatched2(files);
|
|
1102
|
+
filesWithMtime.sort((a, b) => b.mtime - a.mtime);
|
|
1103
|
+
const output = [];
|
|
1104
|
+
if (filesWithMtime.length === 0) {
|
|
1105
|
+
output.push("No files found");
|
|
1106
|
+
} else {
|
|
1107
|
+
output.push(...filesWithMtime.map((f) => f.path));
|
|
1108
|
+
if (truncated) {
|
|
1109
|
+
output.push("");
|
|
1110
|
+
output.push("(Results are truncated. Consider using a more specific path or pattern.)");
|
|
1111
|
+
}
|
|
969
1112
|
}
|
|
970
1113
|
const searchLocation = inputPath ? ` in "${inputPath}"` : " in current directory";
|
|
971
|
-
const message = `Found ${
|
|
1114
|
+
const message = `Found ${filesWithMtime.length} matches for pattern "${pattern}"${searchLocation}`;
|
|
972
1115
|
return {
|
|
973
1116
|
success: true,
|
|
974
1117
|
message,
|
|
975
|
-
|
|
1118
|
+
metadata: {
|
|
1119
|
+
count: filesWithMtime.length,
|
|
1120
|
+
truncated
|
|
1121
|
+
},
|
|
1122
|
+
content: output.join("\n")
|
|
976
1123
|
};
|
|
977
1124
|
} catch (error) {
|
|
1125
|
+
console.error("[glob] error:", error);
|
|
978
1126
|
return {
|
|
979
1127
|
success: false,
|
|
980
1128
|
message: `Failed to find files matching pattern: ${pattern}`,
|
|
@@ -982,59 +1130,120 @@ var globTool = async function(input, projectCwd) {
|
|
|
982
1130
|
};
|
|
983
1131
|
}
|
|
984
1132
|
};
|
|
985
|
-
var
|
|
986
|
-
"node_modules
|
|
987
|
-
"__pycache__
|
|
988
|
-
".git
|
|
989
|
-
"dist
|
|
990
|
-
"build
|
|
991
|
-
"target
|
|
992
|
-
"vendor
|
|
993
|
-
"bin
|
|
994
|
-
"obj
|
|
995
|
-
".idea
|
|
996
|
-
".vscode
|
|
997
|
-
".zig-cache
|
|
1133
|
+
var IGNORE_PATTERNS = [
|
|
1134
|
+
"node_modules",
|
|
1135
|
+
"__pycache__",
|
|
1136
|
+
".git",
|
|
1137
|
+
"dist",
|
|
1138
|
+
"build",
|
|
1139
|
+
"target",
|
|
1140
|
+
"vendor",
|
|
1141
|
+
"bin",
|
|
1142
|
+
"obj",
|
|
1143
|
+
".idea",
|
|
1144
|
+
".vscode",
|
|
1145
|
+
".zig-cache",
|
|
998
1146
|
"zig-out",
|
|
999
1147
|
".coverage",
|
|
1000
|
-
"coverage
|
|
1001
|
-
"
|
|
1002
|
-
"
|
|
1003
|
-
"
|
|
1004
|
-
"
|
|
1005
|
-
"
|
|
1006
|
-
"
|
|
1007
|
-
"
|
|
1008
|
-
"
|
|
1009
|
-
"
|
|
1148
|
+
"coverage",
|
|
1149
|
+
"tmp",
|
|
1150
|
+
"temp",
|
|
1151
|
+
".cache",
|
|
1152
|
+
"cache",
|
|
1153
|
+
"logs",
|
|
1154
|
+
".venv",
|
|
1155
|
+
"venv",
|
|
1156
|
+
"env",
|
|
1157
|
+
".next",
|
|
1158
|
+
".turbo",
|
|
1159
|
+
".vercel",
|
|
1160
|
+
".output"
|
|
1010
1161
|
];
|
|
1011
|
-
var
|
|
1162
|
+
var RESULT_LIMIT2 = 500;
|
|
1163
|
+
var MTIME_BATCH_SIZE2 = 50;
|
|
1012
1164
|
zod.z.object({
|
|
1013
|
-
path: zod.z.string().optional(),
|
|
1014
|
-
recursive: zod.z.boolean().optional().describe("Whether to list files recursively"),
|
|
1015
|
-
maxDepth: zod.z.number().optional().describe("Maximum recursion depth (default:
|
|
1165
|
+
path: zod.z.string().optional().describe("Relative path to the directory to list"),
|
|
1166
|
+
recursive: zod.z.boolean().optional().describe("Whether to list files recursively (default: true)"),
|
|
1167
|
+
maxDepth: zod.z.number().optional().describe("Maximum recursion depth (default: 3)"),
|
|
1016
1168
|
pattern: zod.z.string().optional().describe("File extension (e.g., '.ts') or glob-like pattern"),
|
|
1017
|
-
|
|
1018
|
-
includeFiles: zod.z.boolean().optional().describe("Whether to include files in results (default: true)")
|
|
1169
|
+
showHidden: zod.z.boolean().optional().describe("Whether to show hidden files (default: false)")
|
|
1019
1170
|
});
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1171
|
+
function shouldIgnore(name, showHidden) {
|
|
1172
|
+
if (!showHidden && name.startsWith(".") && name !== ".") {
|
|
1173
|
+
return true;
|
|
1174
|
+
}
|
|
1175
|
+
return IGNORE_PATTERNS.includes(name);
|
|
1176
|
+
}
|
|
1177
|
+
function matchPattern(name, pattern) {
|
|
1178
|
+
if (!pattern) return true;
|
|
1179
|
+
if (pattern.startsWith(".") && !pattern.includes("*")) {
|
|
1180
|
+
return name.endsWith(pattern);
|
|
1181
|
+
}
|
|
1182
|
+
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
1183
|
+
const regex = new RegExp(`^${escaped}$`, "i");
|
|
1184
|
+
return regex.test(name);
|
|
1185
|
+
}
|
|
1186
|
+
async function getMtimesBatched3(entries) {
|
|
1187
|
+
for (let i = 0; i < entries.length; i += MTIME_BATCH_SIZE2) {
|
|
1188
|
+
const batch = entries.slice(i, i + MTIME_BATCH_SIZE2);
|
|
1189
|
+
await Promise.all(
|
|
1190
|
+
batch.map(async (entry) => {
|
|
1191
|
+
entry.mtime = await Bun.file(entry.absolutePath).stat().then((stats) => stats.mtime.getTime()).catch(() => 0);
|
|
1192
|
+
})
|
|
1193
|
+
);
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
function buildTreeOutput(entries, basePath) {
|
|
1197
|
+
const tree = /* @__PURE__ */ new Map();
|
|
1198
|
+
for (const entry of entries) {
|
|
1199
|
+
const dir = path10__default.default.dirname(entry.relativePath);
|
|
1200
|
+
const dirKey = dir === "." ? "" : dir;
|
|
1201
|
+
if (!tree.has(dirKey)) {
|
|
1202
|
+
tree.set(dirKey, []);
|
|
1203
|
+
}
|
|
1204
|
+
tree.get(dirKey).push(entry);
|
|
1205
|
+
}
|
|
1206
|
+
for (const [, items] of tree) {
|
|
1207
|
+
items.sort((a, b) => {
|
|
1208
|
+
if (a.type !== b.type) {
|
|
1209
|
+
return a.type === "directory" ? -1 : 1;
|
|
1210
|
+
}
|
|
1211
|
+
return a.name.localeCompare(b.name);
|
|
1212
|
+
});
|
|
1213
|
+
}
|
|
1214
|
+
const lines = [`${basePath}/`];
|
|
1215
|
+
function renderLevel(dirPath, indent) {
|
|
1216
|
+
const items = tree.get(dirPath) || [];
|
|
1217
|
+
for (let i = 0; i < items.length; i++) {
|
|
1218
|
+
const item = items[i];
|
|
1219
|
+
const isLast = i === items.length - 1;
|
|
1220
|
+
const prefix = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
1221
|
+
const childIndent = indent + (isLast ? " " : "\u2502 ");
|
|
1222
|
+
if (item.type === "directory") {
|
|
1223
|
+
lines.push(`${indent}${prefix}${item.name}/`);
|
|
1224
|
+
const childPath = dirPath ? `${dirPath}/${item.name}` : item.name;
|
|
1225
|
+
renderLevel(childPath, childIndent);
|
|
1226
|
+
} else {
|
|
1227
|
+
lines.push(`${indent}${prefix}${item.name}`);
|
|
1228
|
+
}
|
|
1029
1229
|
}
|
|
1030
1230
|
}
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1231
|
+
renderLevel("", "");
|
|
1232
|
+
return lines.join("\n");
|
|
1233
|
+
}
|
|
1234
|
+
var list = async function(input, projectCwd) {
|
|
1235
|
+
const {
|
|
1236
|
+
path: relativePath,
|
|
1237
|
+
recursive = true,
|
|
1238
|
+
maxDepth = 3,
|
|
1239
|
+
pattern,
|
|
1240
|
+
showHidden = false
|
|
1241
|
+
} = input;
|
|
1242
|
+
if (maxDepth !== void 0 && (!Number.isInteger(maxDepth) || maxDepth < 0)) {
|
|
1034
1243
|
return {
|
|
1035
1244
|
success: false,
|
|
1036
|
-
message: "
|
|
1037
|
-
error: "
|
|
1245
|
+
message: "maxDepth must be a non-negative integer",
|
|
1246
|
+
error: "INVALID_MAX_DEPTH"
|
|
1038
1247
|
};
|
|
1039
1248
|
}
|
|
1040
1249
|
try {
|
|
@@ -1050,88 +1259,119 @@ var list = async function(input, projectCwd) {
|
|
|
1050
1259
|
};
|
|
1051
1260
|
}
|
|
1052
1261
|
}
|
|
1053
|
-
|
|
1054
|
-
await fs5.access(absolutePath);
|
|
1055
|
-
} catch {
|
|
1262
|
+
if (!fs8__default.default.existsSync(absolutePath)) {
|
|
1056
1263
|
return {
|
|
1057
1264
|
success: false,
|
|
1058
|
-
message: `
|
|
1059
|
-
error: "
|
|
1265
|
+
message: `Directory not found: ${absolutePath}`,
|
|
1266
|
+
error: "DIR_NOT_FOUND"
|
|
1060
1267
|
};
|
|
1061
1268
|
}
|
|
1062
|
-
const
|
|
1063
|
-
if (!
|
|
1269
|
+
const stats = fs8__default.default.statSync(absolutePath);
|
|
1270
|
+
if (!stats.isDirectory()) {
|
|
1064
1271
|
return {
|
|
1065
1272
|
success: false,
|
|
1066
|
-
message: `
|
|
1067
|
-
error: "
|
|
1273
|
+
message: `Path is not a directory: ${absolutePath}`,
|
|
1274
|
+
error: "NOT_A_DIRECTORY"
|
|
1068
1275
|
};
|
|
1069
1276
|
}
|
|
1070
1277
|
const collected = [];
|
|
1071
|
-
|
|
1072
|
-
if (!pattern) return null;
|
|
1073
|
-
if (pattern.startsWith(".") && !pattern.includes("*") && !pattern.includes("?")) {
|
|
1074
|
-
return (entryName) => entryName.endsWith(pattern);
|
|
1075
|
-
}
|
|
1076
|
-
const escaped = pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
1077
|
-
const regex = new RegExp(`^${escaped}$`);
|
|
1078
|
-
return (entryName) => regex.test(entryName);
|
|
1079
|
-
})();
|
|
1080
|
-
const matchPattern = (entryName) => {
|
|
1081
|
-
if (!patternMatcher) return true;
|
|
1082
|
-
return patternMatcher(entryName);
|
|
1083
|
-
};
|
|
1084
|
-
const maxDepthNormalized = recursive ? maxDepth ?? Infinity : 0;
|
|
1278
|
+
let truncated = false;
|
|
1085
1279
|
const walk = async (currentDir, depth) => {
|
|
1086
|
-
|
|
1280
|
+
if (collected.length >= RESULT_LIMIT2) {
|
|
1281
|
+
truncated = true;
|
|
1282
|
+
return;
|
|
1283
|
+
}
|
|
1284
|
+
let entries;
|
|
1285
|
+
try {
|
|
1286
|
+
entries = fs8__default.default.readdirSync(currentDir, { withFileTypes: true });
|
|
1287
|
+
} catch {
|
|
1288
|
+
return;
|
|
1289
|
+
}
|
|
1290
|
+
entries.sort((a, b) => {
|
|
1291
|
+
if (a.isDirectory() !== b.isDirectory()) {
|
|
1292
|
+
return a.isDirectory() ? -1 : 1;
|
|
1293
|
+
}
|
|
1294
|
+
return a.name.localeCompare(b.name);
|
|
1295
|
+
});
|
|
1087
1296
|
for (const entry of entries) {
|
|
1297
|
+
if (collected.length >= RESULT_LIMIT2) {
|
|
1298
|
+
truncated = true;
|
|
1299
|
+
break;
|
|
1300
|
+
}
|
|
1301
|
+
if (shouldIgnore(entry.name, showHidden)) {
|
|
1302
|
+
continue;
|
|
1303
|
+
}
|
|
1088
1304
|
const entryAbsolutePath = path10__default.default.join(currentDir, entry.name);
|
|
1089
|
-
const entryRelativePath = path10__default.default.relative(absolutePath, entryAbsolutePath)
|
|
1305
|
+
const entryRelativePath = path10__default.default.relative(absolutePath, entryAbsolutePath);
|
|
1090
1306
|
if (entry.isDirectory()) {
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
if (recursive && depth < maxDepthNormalized && !isExcluded) {
|
|
1307
|
+
collected.push({
|
|
1308
|
+
name: entry.name,
|
|
1309
|
+
absolutePath: entryAbsolutePath,
|
|
1310
|
+
relativePath: entryRelativePath,
|
|
1311
|
+
type: "directory",
|
|
1312
|
+
mtime: 0,
|
|
1313
|
+
depth
|
|
1314
|
+
});
|
|
1315
|
+
if (recursive && depth < maxDepth) {
|
|
1101
1316
|
await walk(entryAbsolutePath, depth + 1);
|
|
1102
1317
|
}
|
|
1103
1318
|
} else if (entry.isFile()) {
|
|
1104
|
-
if (
|
|
1319
|
+
if (matchPattern(entry.name, pattern)) {
|
|
1105
1320
|
collected.push({
|
|
1106
1321
|
name: entry.name,
|
|
1107
1322
|
absolutePath: entryAbsolutePath,
|
|
1108
1323
|
relativePath: entryRelativePath,
|
|
1109
|
-
type: "file"
|
|
1324
|
+
type: "file",
|
|
1325
|
+
mtime: 0,
|
|
1326
|
+
depth
|
|
1110
1327
|
});
|
|
1111
1328
|
}
|
|
1112
1329
|
}
|
|
1113
1330
|
}
|
|
1114
1331
|
};
|
|
1115
1332
|
await walk(absolutePath, 0);
|
|
1333
|
+
await getMtimesBatched3(collected);
|
|
1116
1334
|
const totalFiles = collected.filter((item) => item.type === "file").length;
|
|
1117
1335
|
const totalDirectories = collected.filter((item) => item.type === "directory").length;
|
|
1118
|
-
|
|
1336
|
+
const treeOutput = buildTreeOutput(collected, relativePath || path10__default.default.basename(absolutePath));
|
|
1337
|
+
let message = `Listed ${collected.length} items`;
|
|
1338
|
+
if (relativePath) {
|
|
1339
|
+
message += ` in "${relativePath}"`;
|
|
1340
|
+
}
|
|
1341
|
+
message += ` (${totalFiles} files, ${totalDirectories} directories)`;
|
|
1119
1342
|
if (recursive) {
|
|
1120
|
-
message += `
|
|
1343
|
+
message += ` [depth: ${maxDepth}]`;
|
|
1121
1344
|
}
|
|
1122
1345
|
if (pattern) {
|
|
1123
|
-
message += `
|
|
1346
|
+
message += ` [filter: ${pattern}]`;
|
|
1124
1347
|
}
|
|
1125
|
-
|
|
1348
|
+
if (truncated) {
|
|
1349
|
+
message += ` [TRUNCATED at ${RESULT_LIMIT2} items]`;
|
|
1350
|
+
}
|
|
1351
|
+
const files = collected.map((item) => ({
|
|
1352
|
+
name: item.name,
|
|
1353
|
+
path: item.relativePath,
|
|
1354
|
+
type: item.type
|
|
1355
|
+
}));
|
|
1126
1356
|
return {
|
|
1127
1357
|
success: true,
|
|
1128
1358
|
message,
|
|
1129
|
-
|
|
1359
|
+
metadata: {
|
|
1360
|
+
totalFiles,
|
|
1361
|
+
totalDirectories,
|
|
1362
|
+
totalItems: collected.length,
|
|
1363
|
+
truncated,
|
|
1364
|
+
maxDepth,
|
|
1365
|
+
recursive
|
|
1366
|
+
},
|
|
1367
|
+
files,
|
|
1368
|
+
content: treeOutput
|
|
1130
1369
|
};
|
|
1131
1370
|
} catch (error) {
|
|
1371
|
+
console.error("[list] error:", error);
|
|
1132
1372
|
return {
|
|
1133
1373
|
success: false,
|
|
1134
|
-
message: `Failed to list
|
|
1374
|
+
message: `Failed to list directory: ${error}`,
|
|
1135
1375
|
error: "LIST_ERROR"
|
|
1136
1376
|
};
|
|
1137
1377
|
}
|
|
@@ -1149,10 +1389,10 @@ var CREDENTIALS_DIR = path10__default.default.join(os3__default.default.homedir(
|
|
|
1149
1389
|
var CREDENTIALS_PATH = path10__default.default.join(CREDENTIALS_DIR, "credentials.json");
|
|
1150
1390
|
function isAuthenticated() {
|
|
1151
1391
|
try {
|
|
1152
|
-
if (!
|
|
1392
|
+
if (!fs8__default.default.existsSync(CREDENTIALS_PATH)) {
|
|
1153
1393
|
return false;
|
|
1154
1394
|
}
|
|
1155
|
-
const raw =
|
|
1395
|
+
const raw = fs8__default.default.readFileSync(CREDENTIALS_PATH, "utf8");
|
|
1156
1396
|
const data = JSON.parse(raw);
|
|
1157
1397
|
return Boolean(data && data.access_token);
|
|
1158
1398
|
} catch {
|
|
@@ -1161,10 +1401,10 @@ function isAuthenticated() {
|
|
|
1161
1401
|
}
|
|
1162
1402
|
function saveTokens(tokens) {
|
|
1163
1403
|
try {
|
|
1164
|
-
if (!
|
|
1165
|
-
|
|
1404
|
+
if (!fs8__default.default.existsSync(CREDENTIALS_DIR)) {
|
|
1405
|
+
fs8__default.default.mkdirSync(CREDENTIALS_DIR, { recursive: true });
|
|
1166
1406
|
}
|
|
1167
|
-
|
|
1407
|
+
fs8__default.default.writeFileSync(
|
|
1168
1408
|
CREDENTIALS_PATH,
|
|
1169
1409
|
JSON.stringify(tokens, null, 2),
|
|
1170
1410
|
"utf8"
|
|
@@ -1175,18 +1415,18 @@ function saveTokens(tokens) {
|
|
|
1175
1415
|
}
|
|
1176
1416
|
function logout() {
|
|
1177
1417
|
try {
|
|
1178
|
-
if (
|
|
1179
|
-
|
|
1418
|
+
if (fs8__default.default.existsSync(CREDENTIALS_PATH)) {
|
|
1419
|
+
fs8__default.default.unlinkSync(CREDENTIALS_PATH);
|
|
1180
1420
|
}
|
|
1181
1421
|
} catch (error) {
|
|
1182
1422
|
console.error(pc5__default.default.red("Failed to logout"), error);
|
|
1183
1423
|
}
|
|
1184
1424
|
}
|
|
1185
1425
|
function getTokens() {
|
|
1186
|
-
if (!
|
|
1426
|
+
if (!fs8__default.default.existsSync(CREDENTIALS_PATH)) {
|
|
1187
1427
|
return null;
|
|
1188
1428
|
}
|
|
1189
|
-
const raw =
|
|
1429
|
+
const raw = fs8__default.default.readFileSync(CREDENTIALS_PATH, "utf8");
|
|
1190
1430
|
const data = JSON.parse(raw);
|
|
1191
1431
|
return data;
|
|
1192
1432
|
}
|
|
@@ -1285,10 +1525,10 @@ async function login() {
|
|
|
1285
1525
|
}
|
|
1286
1526
|
var getUserId = () => {
|
|
1287
1527
|
try {
|
|
1288
|
-
if (!
|
|
1528
|
+
if (!fs8__default.default.existsSync(CREDENTIALS_PATH)) {
|
|
1289
1529
|
return;
|
|
1290
1530
|
}
|
|
1291
|
-
const raw =
|
|
1531
|
+
const raw = fs8__default.default.readFileSync(CREDENTIALS_PATH, "utf8");
|
|
1292
1532
|
const data = JSON.parse(raw);
|
|
1293
1533
|
return {
|
|
1294
1534
|
userId: data.user.id
|
|
@@ -1337,7 +1577,7 @@ zod.z.object({
|
|
|
1337
1577
|
command: zod.z.string().describe("The terminal command to execute (e.g., 'ls -la', 'pwd', 'echo $HOME')"),
|
|
1338
1578
|
is_background: zod.z.boolean().describe("Whether the command should be run in the background")
|
|
1339
1579
|
}).merge(ExplanationSchema);
|
|
1340
|
-
var runSecureTerminalCommand = async (command, timeout) => {
|
|
1580
|
+
var runSecureTerminalCommand = async (command, timeout, cwd) => {
|
|
1341
1581
|
try {
|
|
1342
1582
|
if (isHarmfulCommand(command)) {
|
|
1343
1583
|
console.log(`[CLI] Harmful command detected: ${command}`);
|
|
@@ -1347,42 +1587,44 @@ var runSecureTerminalCommand = async (command, timeout) => {
|
|
|
1347
1587
|
error: "HARMFUL_COMMAND_DETECTED"
|
|
1348
1588
|
};
|
|
1349
1589
|
}
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
shell: true
|
|
1355
|
-
});
|
|
1356
|
-
let stdout = "";
|
|
1357
|
-
let stderr = "";
|
|
1358
|
-
let timeoutId = null;
|
|
1359
|
-
if (timeoutId > 0) {
|
|
1360
|
-
timeoutId = setTimeout(() => {
|
|
1361
|
-
child.kill("SIGKILL");
|
|
1362
|
-
reject(new Error(`Command timed out after ${timeout}ms`));
|
|
1363
|
-
}, timeout);
|
|
1364
|
-
}
|
|
1365
|
-
child.stdout?.on("data", (data) => {
|
|
1366
|
-
stdout += data.toString();
|
|
1367
|
-
});
|
|
1368
|
-
child.stderr?.on("data", (data) => {
|
|
1369
|
-
stderr += data.toString();
|
|
1370
|
-
});
|
|
1371
|
-
child.stdout.on("close", (code) => {
|
|
1372
|
-
if (timeoutId) {
|
|
1373
|
-
clearTimeout(timeoutId);
|
|
1374
|
-
}
|
|
1375
|
-
resolve({ stdout, stderr, exitCode: code || 0 });
|
|
1376
|
-
});
|
|
1377
|
-
child.stderr.on("error", (error) => {
|
|
1378
|
-
if (timeoutId) {
|
|
1379
|
-
clearTimeout(timeoutId);
|
|
1380
|
-
}
|
|
1381
|
-
reject(error);
|
|
1382
|
-
});
|
|
1590
|
+
const proc = Bun.spawn(["sh", "-c", command], {
|
|
1591
|
+
cwd: cwd || process.cwd(),
|
|
1592
|
+
stdout: "pipe",
|
|
1593
|
+
stderr: "pipe"
|
|
1383
1594
|
});
|
|
1384
|
-
|
|
1385
|
-
|
|
1595
|
+
let timedOut = false;
|
|
1596
|
+
let timeoutId = null;
|
|
1597
|
+
if (timeout > 0) {
|
|
1598
|
+
timeoutId = setTimeout(() => {
|
|
1599
|
+
timedOut = true;
|
|
1600
|
+
proc.kill();
|
|
1601
|
+
}, timeout);
|
|
1602
|
+
}
|
|
1603
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
1604
|
+
new Response(proc.stdout).text(),
|
|
1605
|
+
new Response(proc.stderr).text(),
|
|
1606
|
+
proc.exited
|
|
1607
|
+
]);
|
|
1608
|
+
if (timeoutId) {
|
|
1609
|
+
clearTimeout(timeoutId);
|
|
1610
|
+
}
|
|
1611
|
+
if (timedOut) {
|
|
1612
|
+
return {
|
|
1613
|
+
success: false,
|
|
1614
|
+
message: `Command timed out after ${timeout}ms`,
|
|
1615
|
+
error: "TIMEOUT",
|
|
1616
|
+
stdout,
|
|
1617
|
+
stderr
|
|
1618
|
+
};
|
|
1619
|
+
}
|
|
1620
|
+
return { stdout, stderr, exitCode };
|
|
1621
|
+
} catch (error) {
|
|
1622
|
+
console.error("Error while executing the securedShell command", error);
|
|
1623
|
+
return {
|
|
1624
|
+
success: false,
|
|
1625
|
+
message: "Error while executing the securedShell command",
|
|
1626
|
+
error: error.message
|
|
1627
|
+
};
|
|
1386
1628
|
}
|
|
1387
1629
|
};
|
|
1388
1630
|
var runTerminalCommand = async (input, projectCwd) => {
|
|
@@ -1396,13 +1638,12 @@ var runTerminalCommand = async (input, projectCwd) => {
|
|
|
1396
1638
|
error: "HARMFUL_COMMAND_DETECTED"
|
|
1397
1639
|
};
|
|
1398
1640
|
}
|
|
1399
|
-
const
|
|
1400
|
-
cwd: projectCwd,
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
shell: true
|
|
1641
|
+
const proc = Bun.spawn(["sh", "-c", input.command], {
|
|
1642
|
+
cwd: projectCwd || process.cwd(),
|
|
1643
|
+
stdout: "ignore",
|
|
1644
|
+
stderr: "ignore"
|
|
1404
1645
|
});
|
|
1405
|
-
|
|
1646
|
+
proc.unref();
|
|
1406
1647
|
console.log(`[LOCAL] Background command started: ${input.command}`);
|
|
1407
1648
|
return {
|
|
1408
1649
|
success: true,
|
|
@@ -1412,9 +1653,13 @@ var runTerminalCommand = async (input, projectCwd) => {
|
|
|
1412
1653
|
} else {
|
|
1413
1654
|
const result = await runSecureTerminalCommand(
|
|
1414
1655
|
input.command,
|
|
1415
|
-
3e4
|
|
1656
|
+
3e4,
|
|
1416
1657
|
// 30 second timeout
|
|
1658
|
+
projectCwd
|
|
1417
1659
|
);
|
|
1660
|
+
if (result?.error && !result?.exitCode) {
|
|
1661
|
+
return result;
|
|
1662
|
+
}
|
|
1418
1663
|
const success = result?.exitCode === 0;
|
|
1419
1664
|
return {
|
|
1420
1665
|
success,
|
|
@@ -1433,9 +1678,9 @@ var runTerminalCommand = async (input, projectCwd) => {
|
|
|
1433
1678
|
};
|
|
1434
1679
|
}
|
|
1435
1680
|
};
|
|
1436
|
-
var ignoreFiles = ["node_modules", ".git", ".next", ".env", ".env.local", ".env.development.local", ".env.test.local", ".env.production.local"];
|
|
1681
|
+
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"];
|
|
1437
1682
|
var getContext = (dir, base = dir, allFiles = []) => {
|
|
1438
|
-
const filePath =
|
|
1683
|
+
const filePath = fs8.readdirSync(dir, { withFileTypes: true });
|
|
1439
1684
|
for (const file of filePath) {
|
|
1440
1685
|
if (ignoreFiles.includes(file.name)) continue;
|
|
1441
1686
|
const fullPath = path10__default.default.join(dir, file.name);
|
|
@@ -1455,28 +1700,34 @@ var IDE_PROJECTS_PATHS = {
|
|
|
1455
1700
|
};
|
|
1456
1701
|
function getWorkspaceStoragePath(ide) {
|
|
1457
1702
|
const platform = os3__default.default.platform();
|
|
1458
|
-
const appName = "Cursor" ;
|
|
1703
|
+
const appName = ide === "cursor" ? "Cursor" : "Code";
|
|
1704
|
+
const appNameLower = appName.toLowerCase();
|
|
1459
1705
|
if (platform === "darwin") {
|
|
1460
1706
|
return path10__default.default.join(HOME, "Library", "Application Support", appName, "User", "workspaceStorage");
|
|
1461
1707
|
} else if (platform === "win32") {
|
|
1462
1708
|
return path10__default.default.join(process.env.APPDATA || "", appName, "User", "workspaceStorage");
|
|
1463
1709
|
} else {
|
|
1464
|
-
|
|
1710
|
+
const capitalizedPath = path10__default.default.join(HOME, ".config", appName, "User", "workspaceStorage");
|
|
1711
|
+
const lowercasePath = path10__default.default.join(HOME, ".config", appNameLower, "User", "workspaceStorage");
|
|
1712
|
+
if (fs8__default.default.existsSync(capitalizedPath)) {
|
|
1713
|
+
return capitalizedPath;
|
|
1714
|
+
}
|
|
1715
|
+
return lowercasePath;
|
|
1465
1716
|
}
|
|
1466
1717
|
}
|
|
1467
1718
|
function scanWorkspaceStorage(ide) {
|
|
1468
1719
|
const projects = [];
|
|
1469
|
-
const storagePath = getWorkspaceStoragePath();
|
|
1470
|
-
if (!
|
|
1720
|
+
const storagePath = getWorkspaceStoragePath(ide);
|
|
1721
|
+
if (!fs8__default.default.existsSync(storagePath)) {
|
|
1471
1722
|
return projects;
|
|
1472
1723
|
}
|
|
1473
1724
|
try {
|
|
1474
|
-
const workspaces =
|
|
1725
|
+
const workspaces = fs8__default.default.readdirSync(storagePath);
|
|
1475
1726
|
for (const workspace of workspaces) {
|
|
1476
1727
|
const workspaceJsonPath = path10__default.default.join(storagePath, workspace, "workspace.json");
|
|
1477
|
-
if (
|
|
1728
|
+
if (fs8__default.default.existsSync(workspaceJsonPath)) {
|
|
1478
1729
|
try {
|
|
1479
|
-
const content =
|
|
1730
|
+
const content = fs8__default.default.readFileSync(workspaceJsonPath, "utf-8");
|
|
1480
1731
|
const data = JSON.parse(content);
|
|
1481
1732
|
if (data.folder && typeof data.folder === "string") {
|
|
1482
1733
|
let projectPath = data.folder;
|
|
@@ -1484,7 +1735,7 @@ function scanWorkspaceStorage(ide) {
|
|
|
1484
1735
|
projectPath = projectPath.replace("file://", "");
|
|
1485
1736
|
projectPath = decodeURIComponent(projectPath);
|
|
1486
1737
|
}
|
|
1487
|
-
if (
|
|
1738
|
+
if (fs8__default.default.existsSync(projectPath) && fs8__default.default.statSync(projectPath).isDirectory()) {
|
|
1488
1739
|
projects.push({
|
|
1489
1740
|
name: path10__default.default.basename(projectPath),
|
|
1490
1741
|
path: projectPath,
|
|
@@ -1508,11 +1759,11 @@ var scanIdeProjects = async () => {
|
|
|
1508
1759
|
const seenPaths = /* @__PURE__ */ new Set();
|
|
1509
1760
|
const addProject = (projectPath, ide) => {
|
|
1510
1761
|
try {
|
|
1511
|
-
const resolvedPath =
|
|
1512
|
-
if (
|
|
1762
|
+
const resolvedPath = fs8__default.default.realpathSync(projectPath);
|
|
1763
|
+
if (fs8__default.default.existsSync(resolvedPath) && fs8__default.default.statSync(resolvedPath).isDirectory() && !seenPaths.has(resolvedPath)) {
|
|
1513
1764
|
const isIdeProjectsDir = Object.values(IDE_PROJECTS_PATHS).some((ideDir) => {
|
|
1514
1765
|
try {
|
|
1515
|
-
return
|
|
1766
|
+
return fs8__default.default.realpathSync(ideDir) === resolvedPath;
|
|
1516
1767
|
} catch {
|
|
1517
1768
|
return false;
|
|
1518
1769
|
}
|
|
@@ -1533,32 +1784,36 @@ var scanIdeProjects = async () => {
|
|
|
1533
1784
|
for (const project of cursorProjects) {
|
|
1534
1785
|
addProject(project.path, "cursor");
|
|
1535
1786
|
}
|
|
1787
|
+
const vscodeProjects = scanWorkspaceStorage("vscode");
|
|
1788
|
+
for (const project of vscodeProjects) {
|
|
1789
|
+
addProject(project.path, "vscode");
|
|
1790
|
+
}
|
|
1536
1791
|
for (const [ide, dirPath] of Object.entries(IDE_PROJECTS_PATHS)) {
|
|
1537
|
-
if (ide === "cursor") continue;
|
|
1538
|
-
if (
|
|
1539
|
-
const projects =
|
|
1792
|
+
if (ide === "cursor" || ide === "vscode") continue;
|
|
1793
|
+
if (fs8__default.default.existsSync(dirPath)) {
|
|
1794
|
+
const projects = fs8__default.default.readdirSync(dirPath);
|
|
1540
1795
|
projects.forEach((project) => {
|
|
1541
1796
|
const projectPath = path10__default.default.join(dirPath, project);
|
|
1542
1797
|
try {
|
|
1543
|
-
const stats =
|
|
1798
|
+
const stats = fs8__default.default.lstatSync(projectPath);
|
|
1544
1799
|
let actualPath = null;
|
|
1545
1800
|
if (stats.isSymbolicLink()) {
|
|
1546
|
-
actualPath =
|
|
1801
|
+
actualPath = fs8__default.default.realpathSync(projectPath);
|
|
1547
1802
|
} else if (stats.isFile()) {
|
|
1548
1803
|
try {
|
|
1549
|
-
let content =
|
|
1804
|
+
let content = fs8__default.default.readFileSync(projectPath, "utf-8").trim();
|
|
1550
1805
|
if (content.startsWith("~/") || content === "~") {
|
|
1551
1806
|
content = content.replace(/^~/, HOME);
|
|
1552
1807
|
}
|
|
1553
1808
|
const resolvedContent = path10__default.default.isAbsolute(content) ? content : path10__default.default.resolve(path10__default.default.dirname(projectPath), content);
|
|
1554
|
-
if (
|
|
1555
|
-
actualPath =
|
|
1809
|
+
if (fs8__default.default.existsSync(resolvedContent) && fs8__default.default.statSync(resolvedContent).isDirectory()) {
|
|
1810
|
+
actualPath = fs8__default.default.realpathSync(resolvedContent);
|
|
1556
1811
|
}
|
|
1557
1812
|
} catch {
|
|
1558
1813
|
return;
|
|
1559
1814
|
}
|
|
1560
1815
|
} else if (stats.isDirectory()) {
|
|
1561
|
-
actualPath =
|
|
1816
|
+
actualPath = fs8__default.default.realpathSync(projectPath);
|
|
1562
1817
|
}
|
|
1563
1818
|
if (actualPath) {
|
|
1564
1819
|
addProject(actualPath, ide);
|
|
@@ -1582,7 +1837,7 @@ var Global;
|
|
|
1582
1837
|
})(Global || (Global = {}));
|
|
1583
1838
|
|
|
1584
1839
|
// src/snapshot/snapshot.ts
|
|
1585
|
-
var
|
|
1840
|
+
var execAsync = util.promisify(child_process.exec);
|
|
1586
1841
|
var Snapshot;
|
|
1587
1842
|
((Snapshot2) => {
|
|
1588
1843
|
const log = {
|
|
@@ -1592,7 +1847,7 @@ var Snapshot;
|
|
|
1592
1847
|
};
|
|
1593
1848
|
async function runGit(command, options = {}) {
|
|
1594
1849
|
try {
|
|
1595
|
-
const { stdout, stderr } = await
|
|
1850
|
+
const { stdout, stderr } = await execAsync(command, {
|
|
1596
1851
|
cwd: options.cwd,
|
|
1597
1852
|
env: { ...process.env, ...options.env },
|
|
1598
1853
|
encoding: "utf-8",
|
|
@@ -1616,8 +1871,8 @@ var Snapshot;
|
|
|
1616
1871
|
const worktree = project.cwd;
|
|
1617
1872
|
const git = gitdir(projectId);
|
|
1618
1873
|
try {
|
|
1619
|
-
await
|
|
1620
|
-
const gitExists = await
|
|
1874
|
+
await fs7__default.default.mkdir(git, { recursive: true });
|
|
1875
|
+
const gitExists = await fs7__default.default.access(path10__default.default.join(git, "HEAD")).then(() => true).catch(() => false);
|
|
1621
1876
|
if (!gitExists) {
|
|
1622
1877
|
await runGit(`git init`, {
|
|
1623
1878
|
env: { GIT_DIR: git, GIT_WORK_TREE: worktree }
|
|
@@ -1702,7 +1957,7 @@ var Snapshot;
|
|
|
1702
1957
|
for (const file of newFiles) {
|
|
1703
1958
|
const fullPath = path10__default.default.join(worktree, file);
|
|
1704
1959
|
try {
|
|
1705
|
-
await
|
|
1960
|
+
await fs7__default.default.unlink(fullPath);
|
|
1706
1961
|
log.info("deleted newly created file", { file: fullPath });
|
|
1707
1962
|
} catch {
|
|
1708
1963
|
}
|
|
@@ -1739,7 +1994,7 @@ var Snapshot;
|
|
|
1739
1994
|
log.info("file existed in snapshot but checkout failed, keeping", { file });
|
|
1740
1995
|
} else {
|
|
1741
1996
|
log.info("file did not exist in snapshot, deleting", { file });
|
|
1742
|
-
await
|
|
1997
|
+
await fs7__default.default.unlink(file).catch(() => {
|
|
1743
1998
|
});
|
|
1744
1999
|
}
|
|
1745
2000
|
}
|
|
@@ -2085,6 +2340,81 @@ var connectToUserStreams = async (serverUrl) => {
|
|
|
2085
2340
|
});
|
|
2086
2341
|
return ws;
|
|
2087
2342
|
};
|
|
2343
|
+
var toolCallSchema = zod.z.object({
|
|
2344
|
+
tool: zod.z.string().describe("The name of the tool to execute"),
|
|
2345
|
+
parameters: zod.z.record(zod.z.string(), zod.z.unknown()).describe("Parameters for the tool")
|
|
2346
|
+
});
|
|
2347
|
+
zod.z.object({
|
|
2348
|
+
tool_calls: zod.z.array(toolCallSchema).min(1, "Provide at least one tool call").max(10, "Maximum of 10 tools allowed in batch").describe("Array of tool calls to execute in parallel")
|
|
2349
|
+
});
|
|
2350
|
+
var DISALLOWED_TOOLS = /* @__PURE__ */ new Set(["batch"]);
|
|
2351
|
+
var batchableToolExecutors = {
|
|
2352
|
+
deleteFile,
|
|
2353
|
+
grep: grepTool,
|
|
2354
|
+
glob: globTool,
|
|
2355
|
+
listDirectory: list,
|
|
2356
|
+
readFile: read_file,
|
|
2357
|
+
runTerminalCommand
|
|
2358
|
+
};
|
|
2359
|
+
var batchTool = async function(input, projectCwd) {
|
|
2360
|
+
const { tool_calls } = input;
|
|
2361
|
+
const callsToExecute = tool_calls.slice(0, 10);
|
|
2362
|
+
const discardedCalls = tool_calls.slice(10);
|
|
2363
|
+
const executeCall = async (call) => {
|
|
2364
|
+
try {
|
|
2365
|
+
if (DISALLOWED_TOOLS.has(call.tool)) {
|
|
2366
|
+
return {
|
|
2367
|
+
tool: call.tool,
|
|
2368
|
+
success: false,
|
|
2369
|
+
error: `Tool '${call.tool}' is not allowed in batch. Disallowed tools: ${Array.from(DISALLOWED_TOOLS).join(", ")}`
|
|
2370
|
+
};
|
|
2371
|
+
}
|
|
2372
|
+
const executor = batchableToolExecutors[call.tool];
|
|
2373
|
+
if (!executor) {
|
|
2374
|
+
const availableTools = Object.keys(batchableToolExecutors).join(", ");
|
|
2375
|
+
return {
|
|
2376
|
+
tool: call.tool,
|
|
2377
|
+
success: false,
|
|
2378
|
+
error: `Tool '${call.tool}' not found. Available tools for batching: ${availableTools}`
|
|
2379
|
+
};
|
|
2380
|
+
}
|
|
2381
|
+
const result = await executor(call.parameters, projectCwd);
|
|
2382
|
+
return {
|
|
2383
|
+
tool: call.tool,
|
|
2384
|
+
success: result.success !== false,
|
|
2385
|
+
// Treat undefined success as true
|
|
2386
|
+
result
|
|
2387
|
+
};
|
|
2388
|
+
} catch (error) {
|
|
2389
|
+
return {
|
|
2390
|
+
tool: call.tool,
|
|
2391
|
+
success: false,
|
|
2392
|
+
error: error.message || String(error)
|
|
2393
|
+
};
|
|
2394
|
+
}
|
|
2395
|
+
};
|
|
2396
|
+
const results = await Promise.all(callsToExecute.map(executeCall));
|
|
2397
|
+
for (const call of discardedCalls) {
|
|
2398
|
+
results.push({
|
|
2399
|
+
tool: call.tool,
|
|
2400
|
+
success: false,
|
|
2401
|
+
error: "Maximum of 10 tools allowed in batch"
|
|
2402
|
+
});
|
|
2403
|
+
}
|
|
2404
|
+
const successfulCalls = results.filter((r) => r.success).length;
|
|
2405
|
+
const failedCalls = results.length - successfulCalls;
|
|
2406
|
+
const outputMessage = failedCalls > 0 ? `Executed ${successfulCalls}/${results.length} tools successfully. ${failedCalls} failed.` : `All ${successfulCalls} tools executed successfully.
|
|
2407
|
+
|
|
2408
|
+
Keep using the batch tool for optimal performance in your next response!`;
|
|
2409
|
+
return {
|
|
2410
|
+
success: failedCalls === 0,
|
|
2411
|
+
message: outputMessage,
|
|
2412
|
+
totalCalls: results.length,
|
|
2413
|
+
successful: successfulCalls,
|
|
2414
|
+
failed: failedCalls,
|
|
2415
|
+
results
|
|
2416
|
+
};
|
|
2417
|
+
};
|
|
2088
2418
|
|
|
2089
2419
|
// src/server.ts
|
|
2090
2420
|
var INITIAL_RECONNECT_DELAY2 = 1e3;
|
|
@@ -2107,7 +2437,8 @@ var toolExecutors = {
|
|
|
2107
2437
|
listDirectory: list,
|
|
2108
2438
|
readFile: read_file,
|
|
2109
2439
|
stringReplace: apply_patch,
|
|
2110
|
-
runTerminalCommand
|
|
2440
|
+
runTerminalCommand,
|
|
2441
|
+
batch: batchTool
|
|
2111
2442
|
};
|
|
2112
2443
|
function connectToServer(serverUrl = DEFAULT_SERVER_URL) {
|
|
2113
2444
|
const tokens = getTokens();
|
|
@@ -2188,7 +2519,7 @@ async function main() {
|
|
|
2188
2519
|
await connectToUserStreams(serverUrl);
|
|
2189
2520
|
startHttpServer();
|
|
2190
2521
|
}
|
|
2191
|
-
var
|
|
2522
|
+
var execAsync2 = util.promisify(child_process.exec);
|
|
2192
2523
|
var CODE_SERVER_VERSION = "4.96.4";
|
|
2193
2524
|
function getPlatformInfo() {
|
|
2194
2525
|
const platform = process.platform;
|
|
@@ -2222,50 +2553,50 @@ function getCodeServerBin() {
|
|
|
2222
2553
|
}
|
|
2223
2554
|
function isCodeServerInstalled() {
|
|
2224
2555
|
const binPath = getCodeServerBin();
|
|
2225
|
-
return
|
|
2556
|
+
return fs8__default.default.existsSync(binPath);
|
|
2226
2557
|
}
|
|
2227
2558
|
async function installCodeServer() {
|
|
2228
2559
|
const { ext } = getPlatformInfo();
|
|
2229
2560
|
const downloadUrl = getDownloadUrl();
|
|
2230
2561
|
const tarballPath = path10__default.default.join(AMA_DIR, `code-server.${ext}`);
|
|
2231
|
-
if (!
|
|
2232
|
-
|
|
2562
|
+
if (!fs8__default.default.existsSync(AMA_DIR)) {
|
|
2563
|
+
fs8__default.default.mkdirSync(AMA_DIR, { recursive: true });
|
|
2233
2564
|
}
|
|
2234
|
-
if (!
|
|
2235
|
-
|
|
2565
|
+
if (!fs8__default.default.existsSync(CODE_DIR)) {
|
|
2566
|
+
fs8__default.default.mkdirSync(CODE_DIR, { recursive: true });
|
|
2236
2567
|
}
|
|
2237
|
-
if (!
|
|
2238
|
-
|
|
2568
|
+
if (!fs8__default.default.existsSync(STORAGE_DIR)) {
|
|
2569
|
+
fs8__default.default.mkdirSync(STORAGE_DIR, { recursive: true });
|
|
2239
2570
|
}
|
|
2240
|
-
console.log(pc5__default.default.cyan(`
|
|
2571
|
+
console.log(pc5__default.default.cyan(`downloading code-server v${CODE_SERVER_VERSION}...`));
|
|
2241
2572
|
console.log(pc5__default.default.gray(downloadUrl));
|
|
2242
2573
|
const response = await fetch(downloadUrl);
|
|
2243
2574
|
if (!response.ok) {
|
|
2244
2575
|
throw new Error(`Failed to download code-server: ${response.statusText}`);
|
|
2245
2576
|
}
|
|
2246
2577
|
const buffer = await response.arrayBuffer();
|
|
2247
|
-
await
|
|
2578
|
+
await fs8__default.default.promises.writeFile(tarballPath, Buffer.from(buffer));
|
|
2248
2579
|
console.log(pc5__default.default.cyan("Extracting code-server..."));
|
|
2249
|
-
await
|
|
2250
|
-
await
|
|
2580
|
+
await execAsync2(`tar -xzf ${tarballPath} -C ${CODE_DIR}`);
|
|
2581
|
+
await fs8__default.default.promises.unlink(tarballPath);
|
|
2251
2582
|
const binPath = getCodeServerBin();
|
|
2252
|
-
if (
|
|
2253
|
-
await
|
|
2583
|
+
if (fs8__default.default.existsSync(binPath)) {
|
|
2584
|
+
await fs8__default.default.promises.chmod(binPath, 493);
|
|
2254
2585
|
}
|
|
2255
|
-
console.log(pc5__default.default.green("
|
|
2586
|
+
console.log(pc5__default.default.green("code-server installed successfully"));
|
|
2256
2587
|
}
|
|
2257
2588
|
async function killExistingCodeServer() {
|
|
2258
2589
|
try {
|
|
2259
2590
|
if (process.platform === "win32") {
|
|
2260
|
-
await
|
|
2591
|
+
await execAsync2("netstat -ano | findstr :8081 | findstr LISTENING").then(async ({ stdout }) => {
|
|
2261
2592
|
const pid = stdout.trim().split(/\s+/).pop();
|
|
2262
|
-
if (pid) await
|
|
2593
|
+
if (pid) await execAsync2(`taskkill /PID ${pid} /F`);
|
|
2263
2594
|
}).catch(() => {
|
|
2264
2595
|
});
|
|
2265
2596
|
} else {
|
|
2266
|
-
await
|
|
2597
|
+
await execAsync2("lsof -ti:8081").then(async ({ stdout }) => {
|
|
2267
2598
|
const pid = stdout.trim();
|
|
2268
|
-
if (pid) await
|
|
2599
|
+
if (pid) await execAsync2(`kill -9 ${pid}`);
|
|
2269
2600
|
}).catch(() => {
|
|
2270
2601
|
});
|
|
2271
2602
|
}
|
|
@@ -2275,8 +2606,8 @@ async function killExistingCodeServer() {
|
|
|
2275
2606
|
async function setupDefaultSettings() {
|
|
2276
2607
|
const userDir = path10__default.default.join(STORAGE_DIR, "User");
|
|
2277
2608
|
const settingsPath = path10__default.default.join(userDir, "settings.json");
|
|
2278
|
-
if (!
|
|
2279
|
-
|
|
2609
|
+
if (!fs8__default.default.existsSync(userDir)) {
|
|
2610
|
+
fs8__default.default.mkdirSync(userDir, { recursive: true });
|
|
2280
2611
|
}
|
|
2281
2612
|
const defaultSettings = {
|
|
2282
2613
|
// Disable signature verification for Open VSX extensions
|
|
@@ -2294,9 +2625,9 @@ async function setupDefaultSettings() {
|
|
|
2294
2625
|
"workbench.activityBar.location": "top"
|
|
2295
2626
|
};
|
|
2296
2627
|
let existingSettings = {};
|
|
2297
|
-
if (
|
|
2628
|
+
if (fs8__default.default.existsSync(settingsPath)) {
|
|
2298
2629
|
try {
|
|
2299
|
-
const content = await
|
|
2630
|
+
const content = await fs8__default.default.promises.readFile(settingsPath, "utf-8");
|
|
2300
2631
|
existingSettings = JSON.parse(content);
|
|
2301
2632
|
} catch {
|
|
2302
2633
|
}
|
|
@@ -2304,7 +2635,7 @@ async function setupDefaultSettings() {
|
|
|
2304
2635
|
const mergedSettings = { ...defaultSettings, ...existingSettings };
|
|
2305
2636
|
mergedSettings["workbench.colorTheme"] = "Min Dark";
|
|
2306
2637
|
mergedSettings["extensions.verifySignature"] = false;
|
|
2307
|
-
await
|
|
2638
|
+
await fs8__default.default.promises.writeFile(settingsPath, JSON.stringify(mergedSettings, null, 2));
|
|
2308
2639
|
console.log(pc5__default.default.green("ama code-server settings configured"));
|
|
2309
2640
|
}
|
|
2310
2641
|
async function installExtensions() {
|
|
@@ -2315,7 +2646,7 @@ async function installExtensions() {
|
|
|
2315
2646
|
for (const ext of extensions) {
|
|
2316
2647
|
try {
|
|
2317
2648
|
console.log(pc5__default.default.cyan(`ama installing extension: ${ext}...`));
|
|
2318
|
-
await
|
|
2649
|
+
await execAsync2(`"${binPath}" --user-data-dir "${STORAGE_DIR}" --install-extension ${ext}`);
|
|
2319
2650
|
console.log(pc5__default.default.green(`ama extension ${ext} installed`));
|
|
2320
2651
|
} catch (error) {
|
|
2321
2652
|
console.log(pc5__default.default.yellow(`ama failed to install extension ${ext}`), error);
|
|
@@ -2325,7 +2656,7 @@ async function installExtensions() {
|
|
|
2325
2656
|
async function startCodeServer(cwd) {
|
|
2326
2657
|
const binPath = getCodeServerBin();
|
|
2327
2658
|
const workDir = cwd || process.cwd();
|
|
2328
|
-
if (!
|
|
2659
|
+
if (!fs8__default.default.existsSync(binPath)) {
|
|
2329
2660
|
throw new Error("ama code-server is not installed. Run installCodeServer() first.");
|
|
2330
2661
|
}
|
|
2331
2662
|
await killExistingCodeServer();
|
|
@@ -2333,12 +2664,12 @@ async function startCodeServer(cwd) {
|
|
|
2333
2664
|
await installExtensions();
|
|
2334
2665
|
const workspaceStoragePath = path10__default.default.join(STORAGE_DIR, "User", "workspaceStorage");
|
|
2335
2666
|
try {
|
|
2336
|
-
if (
|
|
2337
|
-
await
|
|
2667
|
+
if (fs8__default.default.existsSync(workspaceStoragePath)) {
|
|
2668
|
+
await fs8__default.default.promises.rm(workspaceStoragePath, { recursive: true, force: true });
|
|
2338
2669
|
}
|
|
2339
2670
|
const stateDbPath = path10__default.default.join(STORAGE_DIR, "User", "globalStorage", "state.vscdb");
|
|
2340
|
-
if (
|
|
2341
|
-
await
|
|
2671
|
+
if (fs8__default.default.existsSync(stateDbPath)) {
|
|
2672
|
+
await fs8__default.default.promises.unlink(stateDbPath);
|
|
2342
2673
|
}
|
|
2343
2674
|
} catch {
|
|
2344
2675
|
}
|
|
@@ -2369,11 +2700,11 @@ var __dirname$1 = path10.dirname(__filename$1);
|
|
|
2369
2700
|
var DAEMON_PID_FILE = path10__default.default.join(AMA_DIR, "daemon.pid");
|
|
2370
2701
|
var DAEMON_LOG_FILE = path10__default.default.join(AMA_DIR, "daemon.log");
|
|
2371
2702
|
function isDaemonRunning() {
|
|
2372
|
-
if (!
|
|
2703
|
+
if (!fs8__default.default.existsSync(DAEMON_PID_FILE)) {
|
|
2373
2704
|
return false;
|
|
2374
2705
|
}
|
|
2375
2706
|
try {
|
|
2376
|
-
const pid = Number(
|
|
2707
|
+
const pid = Number(fs8__default.default.readFileSync(DAEMON_PID_FILE, "utf8"));
|
|
2377
2708
|
process.kill(pid, 0);
|
|
2378
2709
|
return true;
|
|
2379
2710
|
} catch {
|
|
@@ -2381,30 +2712,30 @@ function isDaemonRunning() {
|
|
|
2381
2712
|
}
|
|
2382
2713
|
}
|
|
2383
2714
|
function stopDaemon() {
|
|
2384
|
-
if (!
|
|
2715
|
+
if (!fs8__default.default.existsSync(DAEMON_PID_FILE)) {
|
|
2385
2716
|
return false;
|
|
2386
2717
|
}
|
|
2387
2718
|
try {
|
|
2388
|
-
const pid = Number(
|
|
2719
|
+
const pid = Number(fs8__default.default.readFileSync(DAEMON_PID_FILE, "utf8"));
|
|
2389
2720
|
process.kill(pid, "SIGTERM");
|
|
2390
|
-
|
|
2721
|
+
fs8__default.default.unlinkSync(DAEMON_PID_FILE);
|
|
2391
2722
|
return true;
|
|
2392
2723
|
} catch (error) {
|
|
2393
2724
|
return false;
|
|
2394
2725
|
}
|
|
2395
2726
|
}
|
|
2396
2727
|
function startDaemon() {
|
|
2397
|
-
if (!
|
|
2398
|
-
|
|
2728
|
+
if (!fs8__default.default.existsSync(AMA_DIR)) {
|
|
2729
|
+
fs8__default.default.mkdirSync(AMA_DIR, { recursive: true });
|
|
2399
2730
|
}
|
|
2400
2731
|
if (isDaemonRunning()) {
|
|
2401
2732
|
stopDaemon();
|
|
2402
2733
|
}
|
|
2403
2734
|
const daemonScript = path10__default.default.join(__dirname$1, "lib", "daemon-entry.js");
|
|
2404
|
-
if (!
|
|
2735
|
+
if (!fs8__default.default.existsSync(daemonScript)) {
|
|
2405
2736
|
throw new Error(`Daemon entry script not found at: ${daemonScript}. Please rebuild the project.`);
|
|
2406
2737
|
}
|
|
2407
|
-
const logFd =
|
|
2738
|
+
const logFd = fs8__default.default.openSync(DAEMON_LOG_FILE, "a");
|
|
2408
2739
|
const daemon = child_process.spawn(process.execPath, [daemonScript], {
|
|
2409
2740
|
detached: true,
|
|
2410
2741
|
stdio: ["ignore", logFd, logFd],
|
|
@@ -2412,20 +2743,20 @@ function startDaemon() {
|
|
|
2412
2743
|
cwd: process.cwd()
|
|
2413
2744
|
});
|
|
2414
2745
|
daemon.unref();
|
|
2415
|
-
|
|
2416
|
-
|
|
2746
|
+
fs8__default.default.writeFileSync(DAEMON_PID_FILE, String(daemon.pid));
|
|
2747
|
+
fs8__default.default.closeSync(logFd);
|
|
2417
2748
|
}
|
|
2418
2749
|
function getDaemonPid() {
|
|
2419
|
-
if (!
|
|
2750
|
+
if (!fs8__default.default.existsSync(DAEMON_PID_FILE)) {
|
|
2420
2751
|
return null;
|
|
2421
2752
|
}
|
|
2422
2753
|
try {
|
|
2423
|
-
return Number(
|
|
2754
|
+
return Number(fs8__default.default.readFileSync(DAEMON_PID_FILE, "utf8"));
|
|
2424
2755
|
} catch {
|
|
2425
2756
|
return null;
|
|
2426
2757
|
}
|
|
2427
2758
|
}
|
|
2428
|
-
var VERSION = "0.0.
|
|
2759
|
+
var VERSION = "0.0.12";
|
|
2429
2760
|
var PROJECT_DIR = process.cwd();
|
|
2430
2761
|
var LOGO = `
|
|
2431
2762
|
__ _ _ __ ___ __ _
|
|
@@ -2480,13 +2811,13 @@ async function checkForUpdates() {
|
|
|
2480
2811
|
}
|
|
2481
2812
|
function runNpmInstall() {
|
|
2482
2813
|
return new Promise((resolve, reject) => {
|
|
2483
|
-
const child = child_process.spawn("
|
|
2814
|
+
const child = child_process.spawn("bun", ["add", "-g", "amai@latest"], {
|
|
2484
2815
|
stdio: "inherit",
|
|
2485
2816
|
shell: true
|
|
2486
2817
|
});
|
|
2487
2818
|
child.on("close", (code) => {
|
|
2488
2819
|
if (code === 0) resolve();
|
|
2489
|
-
else reject(new Error(`
|
|
2820
|
+
else reject(new Error(`bun add exited with code ${code}`));
|
|
2490
2821
|
});
|
|
2491
2822
|
child.on("error", reject);
|
|
2492
2823
|
});
|
|
@@ -2592,11 +2923,11 @@ if (args[0] === "update") {
|
|
|
2592
2923
|
process.exit(1);
|
|
2593
2924
|
}
|
|
2594
2925
|
const resolvedPath = path10__default.default.resolve(projectPath);
|
|
2595
|
-
if (!
|
|
2926
|
+
if (!fs8__default.default.existsSync(resolvedPath)) {
|
|
2596
2927
|
console.error(pc5__default.default.red(`path does not exist: ${resolvedPath}`));
|
|
2597
2928
|
process.exit(1);
|
|
2598
2929
|
}
|
|
2599
|
-
if (!
|
|
2930
|
+
if (!fs8__default.default.statSync(resolvedPath).isDirectory()) {
|
|
2600
2931
|
console.error(pc5__default.default.red(`path is not a directory: ${resolvedPath}`));
|
|
2601
2932
|
process.exit(1);
|
|
2602
2933
|
}
|