amai 0.0.9 → 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 +914 -558
- package/dist/cli.js +910 -554
- package/dist/lib/daemon-entry.cjs +726 -446
- package/dist/lib/daemon-entry.js +721 -441
- package/dist/server.cjs +682 -402
- package/dist/server.js +677 -397
- package/package.json +3 -3
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
|
-
}
|
|
918
|
-
|
|
976
|
+
uniqueFiles.add(file);
|
|
977
|
+
}
|
|
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}:`);
|
|
919
1008
|
}
|
|
1009
|
+
groupedOutput.push(` Line ${match.lineNumber}: ${match.content}`);
|
|
1010
|
+
}
|
|
1011
|
+
if (truncated) {
|
|
1012
|
+
groupedOutput.push("");
|
|
1013
|
+
groupedOutput.push(GREP_LIMITS.TRUNCATION_MESSAGE);
|
|
920
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}]`;
|
|
1347
|
+
}
|
|
1348
|
+
if (truncated) {
|
|
1349
|
+
message += ` [TRUNCATED at ${RESULT_LIMIT2} items]`;
|
|
1124
1350
|
}
|
|
1125
|
-
|
|
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
|
}
|
|
@@ -1254,30 +1494,19 @@ async function pollForTokens({
|
|
|
1254
1494
|
async function login() {
|
|
1255
1495
|
try {
|
|
1256
1496
|
const device = await authorizeDevice();
|
|
1257
|
-
console.log(
|
|
1497
|
+
console.log("");
|
|
1258
1498
|
if (device.verification_uri_complete) {
|
|
1259
|
-
console.log(
|
|
1260
|
-
` 1. Open this URL in your browser: ${pc5__default.default.cyan(
|
|
1261
|
-
device.verification_uri_complete
|
|
1262
|
-
)}`
|
|
1263
|
-
);
|
|
1499
|
+
console.log(pc5__default.default.cyan(`open: ${device.verification_uri_complete}`));
|
|
1264
1500
|
} else {
|
|
1265
|
-
console.log(
|
|
1266
|
-
|
|
1267
|
-
device.verification_uri
|
|
1268
|
-
)}`
|
|
1269
|
-
);
|
|
1270
|
-
console.log(
|
|
1271
|
-
` 2. Enter this code when prompted: ${pc5__default.default.bold(device.user_code)}`
|
|
1272
|
-
);
|
|
1501
|
+
console.log(pc5__default.default.cyan(`open: ${device.verification_uri}`));
|
|
1502
|
+
console.log(pc5__default.default.gray(`code: ${device.user_code}`));
|
|
1273
1503
|
}
|
|
1274
|
-
console.log("
|
|
1275
|
-
console.log();
|
|
1504
|
+
console.log("");
|
|
1276
1505
|
console.log(
|
|
1277
1506
|
pc5__default.default.gray(
|
|
1278
|
-
`
|
|
1507
|
+
`waiting for authorization (~${Math.round(
|
|
1279
1508
|
device.expires_in / 60
|
|
1280
|
-
)}
|
|
1509
|
+
)} min)...`
|
|
1281
1510
|
)
|
|
1282
1511
|
);
|
|
1283
1512
|
const tokens = await pollForTokens({
|
|
@@ -1286,20 +1515,20 @@ async function login() {
|
|
|
1286
1515
|
expiresIn: device.expires_in,
|
|
1287
1516
|
interval: device.interval
|
|
1288
1517
|
});
|
|
1289
|
-
console.log(pc5__default.default.
|
|
1518
|
+
console.log(pc5__default.default.cyan("authenticated"));
|
|
1290
1519
|
saveTokens(tokens);
|
|
1291
1520
|
return tokens;
|
|
1292
1521
|
} catch (error) {
|
|
1293
|
-
console.error(pc5__default.default.red(error.message || "
|
|
1522
|
+
console.error(pc5__default.default.red(error.message || "login failed"));
|
|
1294
1523
|
throw error;
|
|
1295
1524
|
}
|
|
1296
1525
|
}
|
|
1297
1526
|
var getUserId = () => {
|
|
1298
1527
|
try {
|
|
1299
|
-
if (!
|
|
1528
|
+
if (!fs8__default.default.existsSync(CREDENTIALS_PATH)) {
|
|
1300
1529
|
return;
|
|
1301
1530
|
}
|
|
1302
|
-
const raw =
|
|
1531
|
+
const raw = fs8__default.default.readFileSync(CREDENTIALS_PATH, "utf8");
|
|
1303
1532
|
const data = JSON.parse(raw);
|
|
1304
1533
|
return {
|
|
1305
1534
|
userId: data.user.id
|
|
@@ -1348,7 +1577,7 @@ zod.z.object({
|
|
|
1348
1577
|
command: zod.z.string().describe("The terminal command to execute (e.g., 'ls -la', 'pwd', 'echo $HOME')"),
|
|
1349
1578
|
is_background: zod.z.boolean().describe("Whether the command should be run in the background")
|
|
1350
1579
|
}).merge(ExplanationSchema);
|
|
1351
|
-
var runSecureTerminalCommand = async (command, timeout) => {
|
|
1580
|
+
var runSecureTerminalCommand = async (command, timeout, cwd) => {
|
|
1352
1581
|
try {
|
|
1353
1582
|
if (isHarmfulCommand(command)) {
|
|
1354
1583
|
console.log(`[CLI] Harmful command detected: ${command}`);
|
|
@@ -1358,42 +1587,44 @@ var runSecureTerminalCommand = async (command, timeout) => {
|
|
|
1358
1587
|
error: "HARMFUL_COMMAND_DETECTED"
|
|
1359
1588
|
};
|
|
1360
1589
|
}
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
shell: true
|
|
1366
|
-
});
|
|
1367
|
-
let stdout = "";
|
|
1368
|
-
let stderr = "";
|
|
1369
|
-
let timeoutId = null;
|
|
1370
|
-
if (timeoutId > 0) {
|
|
1371
|
-
timeoutId = setTimeout(() => {
|
|
1372
|
-
child.kill("SIGKILL");
|
|
1373
|
-
reject(new Error(`Command timed out after ${timeout}ms`));
|
|
1374
|
-
}, timeout);
|
|
1375
|
-
}
|
|
1376
|
-
child.stdout?.on("data", (data) => {
|
|
1377
|
-
stdout += data.toString();
|
|
1378
|
-
});
|
|
1379
|
-
child.stderr?.on("data", (data) => {
|
|
1380
|
-
stderr += data.toString();
|
|
1381
|
-
});
|
|
1382
|
-
child.stdout.on("close", (code) => {
|
|
1383
|
-
if (timeoutId) {
|
|
1384
|
-
clearTimeout(timeoutId);
|
|
1385
|
-
}
|
|
1386
|
-
resolve({ stdout, stderr, exitCode: code || 0 });
|
|
1387
|
-
});
|
|
1388
|
-
child.stderr.on("error", (error) => {
|
|
1389
|
-
if (timeoutId) {
|
|
1390
|
-
clearTimeout(timeoutId);
|
|
1391
|
-
}
|
|
1392
|
-
reject(error);
|
|
1393
|
-
});
|
|
1590
|
+
const proc = Bun.spawn(["sh", "-c", command], {
|
|
1591
|
+
cwd: cwd || process.cwd(),
|
|
1592
|
+
stdout: "pipe",
|
|
1593
|
+
stderr: "pipe"
|
|
1394
1594
|
});
|
|
1395
|
-
|
|
1396
|
-
|
|
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
|
+
};
|
|
1397
1628
|
}
|
|
1398
1629
|
};
|
|
1399
1630
|
var runTerminalCommand = async (input, projectCwd) => {
|
|
@@ -1407,13 +1638,12 @@ var runTerminalCommand = async (input, projectCwd) => {
|
|
|
1407
1638
|
error: "HARMFUL_COMMAND_DETECTED"
|
|
1408
1639
|
};
|
|
1409
1640
|
}
|
|
1410
|
-
const
|
|
1411
|
-
cwd: projectCwd,
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
shell: true
|
|
1641
|
+
const proc = Bun.spawn(["sh", "-c", input.command], {
|
|
1642
|
+
cwd: projectCwd || process.cwd(),
|
|
1643
|
+
stdout: "ignore",
|
|
1644
|
+
stderr: "ignore"
|
|
1415
1645
|
});
|
|
1416
|
-
|
|
1646
|
+
proc.unref();
|
|
1417
1647
|
console.log(`[LOCAL] Background command started: ${input.command}`);
|
|
1418
1648
|
return {
|
|
1419
1649
|
success: true,
|
|
@@ -1423,9 +1653,13 @@ var runTerminalCommand = async (input, projectCwd) => {
|
|
|
1423
1653
|
} else {
|
|
1424
1654
|
const result = await runSecureTerminalCommand(
|
|
1425
1655
|
input.command,
|
|
1426
|
-
3e4
|
|
1656
|
+
3e4,
|
|
1427
1657
|
// 30 second timeout
|
|
1658
|
+
projectCwd
|
|
1428
1659
|
);
|
|
1660
|
+
if (result?.error && !result?.exitCode) {
|
|
1661
|
+
return result;
|
|
1662
|
+
}
|
|
1429
1663
|
const success = result?.exitCode === 0;
|
|
1430
1664
|
return {
|
|
1431
1665
|
success,
|
|
@@ -1444,9 +1678,9 @@ var runTerminalCommand = async (input, projectCwd) => {
|
|
|
1444
1678
|
};
|
|
1445
1679
|
}
|
|
1446
1680
|
};
|
|
1447
|
-
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"];
|
|
1448
1682
|
var getContext = (dir, base = dir, allFiles = []) => {
|
|
1449
|
-
const filePath =
|
|
1683
|
+
const filePath = fs8.readdirSync(dir, { withFileTypes: true });
|
|
1450
1684
|
for (const file of filePath) {
|
|
1451
1685
|
if (ignoreFiles.includes(file.name)) continue;
|
|
1452
1686
|
const fullPath = path10__default.default.join(dir, file.name);
|
|
@@ -1466,28 +1700,34 @@ var IDE_PROJECTS_PATHS = {
|
|
|
1466
1700
|
};
|
|
1467
1701
|
function getWorkspaceStoragePath(ide) {
|
|
1468
1702
|
const platform = os3__default.default.platform();
|
|
1469
|
-
const appName = "Cursor" ;
|
|
1703
|
+
const appName = ide === "cursor" ? "Cursor" : "Code";
|
|
1704
|
+
const appNameLower = appName.toLowerCase();
|
|
1470
1705
|
if (platform === "darwin") {
|
|
1471
1706
|
return path10__default.default.join(HOME, "Library", "Application Support", appName, "User", "workspaceStorage");
|
|
1472
1707
|
} else if (platform === "win32") {
|
|
1473
1708
|
return path10__default.default.join(process.env.APPDATA || "", appName, "User", "workspaceStorage");
|
|
1474
1709
|
} else {
|
|
1475
|
-
|
|
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;
|
|
1476
1716
|
}
|
|
1477
1717
|
}
|
|
1478
1718
|
function scanWorkspaceStorage(ide) {
|
|
1479
1719
|
const projects = [];
|
|
1480
|
-
const storagePath = getWorkspaceStoragePath();
|
|
1481
|
-
if (!
|
|
1720
|
+
const storagePath = getWorkspaceStoragePath(ide);
|
|
1721
|
+
if (!fs8__default.default.existsSync(storagePath)) {
|
|
1482
1722
|
return projects;
|
|
1483
1723
|
}
|
|
1484
1724
|
try {
|
|
1485
|
-
const workspaces =
|
|
1725
|
+
const workspaces = fs8__default.default.readdirSync(storagePath);
|
|
1486
1726
|
for (const workspace of workspaces) {
|
|
1487
1727
|
const workspaceJsonPath = path10__default.default.join(storagePath, workspace, "workspace.json");
|
|
1488
|
-
if (
|
|
1728
|
+
if (fs8__default.default.existsSync(workspaceJsonPath)) {
|
|
1489
1729
|
try {
|
|
1490
|
-
const content =
|
|
1730
|
+
const content = fs8__default.default.readFileSync(workspaceJsonPath, "utf-8");
|
|
1491
1731
|
const data = JSON.parse(content);
|
|
1492
1732
|
if (data.folder && typeof data.folder === "string") {
|
|
1493
1733
|
let projectPath = data.folder;
|
|
@@ -1495,7 +1735,7 @@ function scanWorkspaceStorage(ide) {
|
|
|
1495
1735
|
projectPath = projectPath.replace("file://", "");
|
|
1496
1736
|
projectPath = decodeURIComponent(projectPath);
|
|
1497
1737
|
}
|
|
1498
|
-
if (
|
|
1738
|
+
if (fs8__default.default.existsSync(projectPath) && fs8__default.default.statSync(projectPath).isDirectory()) {
|
|
1499
1739
|
projects.push({
|
|
1500
1740
|
name: path10__default.default.basename(projectPath),
|
|
1501
1741
|
path: projectPath,
|
|
@@ -1519,11 +1759,11 @@ var scanIdeProjects = async () => {
|
|
|
1519
1759
|
const seenPaths = /* @__PURE__ */ new Set();
|
|
1520
1760
|
const addProject = (projectPath, ide) => {
|
|
1521
1761
|
try {
|
|
1522
|
-
const resolvedPath =
|
|
1523
|
-
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)) {
|
|
1524
1764
|
const isIdeProjectsDir = Object.values(IDE_PROJECTS_PATHS).some((ideDir) => {
|
|
1525
1765
|
try {
|
|
1526
|
-
return
|
|
1766
|
+
return fs8__default.default.realpathSync(ideDir) === resolvedPath;
|
|
1527
1767
|
} catch {
|
|
1528
1768
|
return false;
|
|
1529
1769
|
}
|
|
@@ -1544,32 +1784,36 @@ var scanIdeProjects = async () => {
|
|
|
1544
1784
|
for (const project of cursorProjects) {
|
|
1545
1785
|
addProject(project.path, "cursor");
|
|
1546
1786
|
}
|
|
1787
|
+
const vscodeProjects = scanWorkspaceStorage("vscode");
|
|
1788
|
+
for (const project of vscodeProjects) {
|
|
1789
|
+
addProject(project.path, "vscode");
|
|
1790
|
+
}
|
|
1547
1791
|
for (const [ide, dirPath] of Object.entries(IDE_PROJECTS_PATHS)) {
|
|
1548
|
-
if (ide === "cursor") continue;
|
|
1549
|
-
if (
|
|
1550
|
-
const projects =
|
|
1792
|
+
if (ide === "cursor" || ide === "vscode") continue;
|
|
1793
|
+
if (fs8__default.default.existsSync(dirPath)) {
|
|
1794
|
+
const projects = fs8__default.default.readdirSync(dirPath);
|
|
1551
1795
|
projects.forEach((project) => {
|
|
1552
1796
|
const projectPath = path10__default.default.join(dirPath, project);
|
|
1553
1797
|
try {
|
|
1554
|
-
const stats =
|
|
1798
|
+
const stats = fs8__default.default.lstatSync(projectPath);
|
|
1555
1799
|
let actualPath = null;
|
|
1556
1800
|
if (stats.isSymbolicLink()) {
|
|
1557
|
-
actualPath =
|
|
1801
|
+
actualPath = fs8__default.default.realpathSync(projectPath);
|
|
1558
1802
|
} else if (stats.isFile()) {
|
|
1559
1803
|
try {
|
|
1560
|
-
let content =
|
|
1804
|
+
let content = fs8__default.default.readFileSync(projectPath, "utf-8").trim();
|
|
1561
1805
|
if (content.startsWith("~/") || content === "~") {
|
|
1562
1806
|
content = content.replace(/^~/, HOME);
|
|
1563
1807
|
}
|
|
1564
1808
|
const resolvedContent = path10__default.default.isAbsolute(content) ? content : path10__default.default.resolve(path10__default.default.dirname(projectPath), content);
|
|
1565
|
-
if (
|
|
1566
|
-
actualPath =
|
|
1809
|
+
if (fs8__default.default.existsSync(resolvedContent) && fs8__default.default.statSync(resolvedContent).isDirectory()) {
|
|
1810
|
+
actualPath = fs8__default.default.realpathSync(resolvedContent);
|
|
1567
1811
|
}
|
|
1568
1812
|
} catch {
|
|
1569
1813
|
return;
|
|
1570
1814
|
}
|
|
1571
1815
|
} else if (stats.isDirectory()) {
|
|
1572
|
-
actualPath =
|
|
1816
|
+
actualPath = fs8__default.default.realpathSync(projectPath);
|
|
1573
1817
|
}
|
|
1574
1818
|
if (actualPath) {
|
|
1575
1819
|
addProject(actualPath, ide);
|
|
@@ -1593,7 +1837,7 @@ var Global;
|
|
|
1593
1837
|
})(Global || (Global = {}));
|
|
1594
1838
|
|
|
1595
1839
|
// src/snapshot/snapshot.ts
|
|
1596
|
-
var
|
|
1840
|
+
var execAsync = util.promisify(child_process.exec);
|
|
1597
1841
|
var Snapshot;
|
|
1598
1842
|
((Snapshot2) => {
|
|
1599
1843
|
const log = {
|
|
@@ -1603,7 +1847,7 @@ var Snapshot;
|
|
|
1603
1847
|
};
|
|
1604
1848
|
async function runGit(command, options = {}) {
|
|
1605
1849
|
try {
|
|
1606
|
-
const { stdout, stderr } = await
|
|
1850
|
+
const { stdout, stderr } = await execAsync(command, {
|
|
1607
1851
|
cwd: options.cwd,
|
|
1608
1852
|
env: { ...process.env, ...options.env },
|
|
1609
1853
|
encoding: "utf-8",
|
|
@@ -1627,8 +1871,8 @@ var Snapshot;
|
|
|
1627
1871
|
const worktree = project.cwd;
|
|
1628
1872
|
const git = gitdir(projectId);
|
|
1629
1873
|
try {
|
|
1630
|
-
await
|
|
1631
|
-
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);
|
|
1632
1876
|
if (!gitExists) {
|
|
1633
1877
|
await runGit(`git init`, {
|
|
1634
1878
|
env: { GIT_DIR: git, GIT_WORK_TREE: worktree }
|
|
@@ -1713,7 +1957,7 @@ var Snapshot;
|
|
|
1713
1957
|
for (const file of newFiles) {
|
|
1714
1958
|
const fullPath = path10__default.default.join(worktree, file);
|
|
1715
1959
|
try {
|
|
1716
|
-
await
|
|
1960
|
+
await fs7__default.default.unlink(fullPath);
|
|
1717
1961
|
log.info("deleted newly created file", { file: fullPath });
|
|
1718
1962
|
} catch {
|
|
1719
1963
|
}
|
|
@@ -1750,7 +1994,7 @@ var Snapshot;
|
|
|
1750
1994
|
log.info("file existed in snapshot but checkout failed, keeping", { file });
|
|
1751
1995
|
} else {
|
|
1752
1996
|
log.info("file did not exist in snapshot, deleting", { file });
|
|
1753
|
-
await
|
|
1997
|
+
await fs7__default.default.unlink(file).catch(() => {
|
|
1754
1998
|
});
|
|
1755
1999
|
}
|
|
1756
2000
|
}
|
|
@@ -1984,7 +2228,19 @@ var rpcHandlers = {
|
|
|
1984
2228
|
return { success: true, diff };
|
|
1985
2229
|
}
|
|
1986
2230
|
};
|
|
2231
|
+
var INITIAL_RECONNECT_DELAY = 1e3;
|
|
2232
|
+
var MAX_RECONNECT_DELAY = 6e4;
|
|
2233
|
+
var BACKOFF_MULTIPLIER = 2;
|
|
1987
2234
|
var reconnectTimeout = null;
|
|
2235
|
+
var reconnectAttempts = 0;
|
|
2236
|
+
function getReconnectDelay() {
|
|
2237
|
+
const delay = Math.min(
|
|
2238
|
+
INITIAL_RECONNECT_DELAY * Math.pow(BACKOFF_MULTIPLIER, reconnectAttempts),
|
|
2239
|
+
MAX_RECONNECT_DELAY
|
|
2240
|
+
);
|
|
2241
|
+
const jitter = delay * 0.25 * (Math.random() * 2 - 1);
|
|
2242
|
+
return Math.floor(delay + jitter);
|
|
2243
|
+
}
|
|
1988
2244
|
var connectToUserStreams = async (serverUrl) => {
|
|
1989
2245
|
const userId = getUserId();
|
|
1990
2246
|
if (!userId?.userId) {
|
|
@@ -2005,7 +2261,8 @@ var connectToUserStreams = async (serverUrl) => {
|
|
|
2005
2261
|
}
|
|
2006
2262
|
});
|
|
2007
2263
|
ws.on("open", () => {
|
|
2008
|
-
|
|
2264
|
+
reconnectAttempts = 0;
|
|
2265
|
+
console.log(pc5__default.default.cyan("connected to user streams"));
|
|
2009
2266
|
if (reconnectTimeout) {
|
|
2010
2267
|
clearTimeout(reconnectTimeout);
|
|
2011
2268
|
reconnectTimeout = null;
|
|
@@ -2016,7 +2273,7 @@ var connectToUserStreams = async (serverUrl) => {
|
|
|
2016
2273
|
const message = JSON.parse(event.toString());
|
|
2017
2274
|
if (message._tag === "rpc_call") {
|
|
2018
2275
|
const { requestId, method, input } = message;
|
|
2019
|
-
console.log(pc5__default.default.gray(
|
|
2276
|
+
console.log(pc5__default.default.gray(`> ${method}`));
|
|
2020
2277
|
const handler = rpcHandlers[method];
|
|
2021
2278
|
if (!handler) {
|
|
2022
2279
|
ws.send(JSON.stringify({
|
|
@@ -2027,7 +2284,6 @@ var connectToUserStreams = async (serverUrl) => {
|
|
|
2027
2284
|
message: `Unknown RPC method: ${method}`
|
|
2028
2285
|
}
|
|
2029
2286
|
}));
|
|
2030
|
-
console.log(pc5__default.default.yellow(`Unknown RPC method: ${method}`));
|
|
2031
2287
|
return;
|
|
2032
2288
|
}
|
|
2033
2289
|
try {
|
|
@@ -2037,7 +2293,6 @@ var connectToUserStreams = async (serverUrl) => {
|
|
|
2037
2293
|
requestId,
|
|
2038
2294
|
data: result
|
|
2039
2295
|
}));
|
|
2040
|
-
console.log(pc5__default.default.green(`RPC completed: ${method}`));
|
|
2041
2296
|
} catch (error) {
|
|
2042
2297
|
const rpcError = error._tag ? error : {
|
|
2043
2298
|
_tag: "RpcError",
|
|
@@ -2048,7 +2303,7 @@ var connectToUserStreams = async (serverUrl) => {
|
|
|
2048
2303
|
requestId,
|
|
2049
2304
|
data: rpcError
|
|
2050
2305
|
}));
|
|
2051
|
-
console.log(pc5__default.default.red(`
|
|
2306
|
+
console.log(pc5__default.default.red(` ${method} failed`));
|
|
2052
2307
|
}
|
|
2053
2308
|
return;
|
|
2054
2309
|
}
|
|
@@ -2067,25 +2322,38 @@ var connectToUserStreams = async (serverUrl) => {
|
|
|
2067
2322
|
}
|
|
2068
2323
|
}
|
|
2069
2324
|
} catch (parseError) {
|
|
2070
|
-
console.error(pc5__default.default.red(`
|
|
2325
|
+
console.error(pc5__default.default.red(`parse error`));
|
|
2071
2326
|
}
|
|
2072
2327
|
});
|
|
2073
2328
|
ws.on("close", (code, reason) => {
|
|
2074
|
-
|
|
2075
|
-
|
|
2329
|
+
const delay = getReconnectDelay();
|
|
2330
|
+
reconnectAttempts++;
|
|
2331
|
+
console.log(pc5__default.default.gray(`user streams disconnected, reconnecting in ${Math.round(delay / 1e3)}s...`));
|
|
2076
2332
|
reconnectTimeout = setTimeout(() => {
|
|
2077
2333
|
connectToUserStreams(serverUrl).catch((err) => {
|
|
2078
|
-
console.error(pc5__default.default.red(`
|
|
2334
|
+
console.error(pc5__default.default.red(`reconnection failed`));
|
|
2079
2335
|
});
|
|
2080
|
-
},
|
|
2336
|
+
}, delay);
|
|
2081
2337
|
});
|
|
2082
2338
|
ws.on("error", (error) => {
|
|
2083
|
-
console.error(pc5__default.default.red(`
|
|
2339
|
+
console.error(pc5__default.default.red(`stream error: ${error.message}`));
|
|
2084
2340
|
});
|
|
2085
2341
|
return ws;
|
|
2086
2342
|
};
|
|
2087
2343
|
|
|
2088
2344
|
// src/server.ts
|
|
2345
|
+
var INITIAL_RECONNECT_DELAY2 = 1e3;
|
|
2346
|
+
var MAX_RECONNECT_DELAY2 = 6e4;
|
|
2347
|
+
var BACKOFF_MULTIPLIER2 = 2;
|
|
2348
|
+
var reconnectAttempts2 = 0;
|
|
2349
|
+
function getReconnectDelay2() {
|
|
2350
|
+
const delay = Math.min(
|
|
2351
|
+
INITIAL_RECONNECT_DELAY2 * Math.pow(BACKOFF_MULTIPLIER2, reconnectAttempts2),
|
|
2352
|
+
MAX_RECONNECT_DELAY2
|
|
2353
|
+
);
|
|
2354
|
+
const jitter = delay * 0.25 * (Math.random() * 2 - 1);
|
|
2355
|
+
return Math.floor(delay + jitter);
|
|
2356
|
+
}
|
|
2089
2357
|
var toolExecutors = {
|
|
2090
2358
|
editFile: editFiles,
|
|
2091
2359
|
deleteFile,
|
|
@@ -2108,12 +2376,13 @@ function connectToServer(serverUrl = DEFAULT_SERVER_URL) {
|
|
|
2108
2376
|
}
|
|
2109
2377
|
});
|
|
2110
2378
|
ws.on("open", () => {
|
|
2111
|
-
|
|
2379
|
+
reconnectAttempts2 = 0;
|
|
2380
|
+
console.log(pc5__default.default.cyan("connected to server"));
|
|
2112
2381
|
});
|
|
2113
2382
|
ws.on("message", async (data) => {
|
|
2114
2383
|
const message = JSON.parse(data.toString());
|
|
2115
2384
|
if (message.type === "tool_call") {
|
|
2116
|
-
console.log(
|
|
2385
|
+
console.log(pc5__default.default.gray(`> ${message.tool}`));
|
|
2117
2386
|
try {
|
|
2118
2387
|
const executor = toolExecutors[message.tool];
|
|
2119
2388
|
if (!executor) {
|
|
@@ -2125,17 +2394,16 @@ function connectToServer(serverUrl = DEFAULT_SERVER_URL) {
|
|
|
2125
2394
|
id: message.id,
|
|
2126
2395
|
result
|
|
2127
2396
|
}));
|
|
2128
|
-
console.log(pc5__default.default.green(`tool call completed: ${message.tool}`));
|
|
2129
2397
|
} catch (error) {
|
|
2130
2398
|
ws.send(JSON.stringify({
|
|
2131
2399
|
type: "tool_result",
|
|
2132
2400
|
id: message.id,
|
|
2133
2401
|
error: error.message
|
|
2134
2402
|
}));
|
|
2135
|
-
console.error(pc5__default.default.red(`
|
|
2403
|
+
console.error(pc5__default.default.red(` ${message.tool} failed: ${error.message}`));
|
|
2136
2404
|
}
|
|
2137
2405
|
} else if (message.type === "rpc_call") {
|
|
2138
|
-
console.log(
|
|
2406
|
+
console.log(pc5__default.default.gray(`> rpc: ${message.method}`));
|
|
2139
2407
|
try {
|
|
2140
2408
|
const handler = rpcHandlers[message.method];
|
|
2141
2409
|
if (!handler) {
|
|
@@ -2147,34 +2415,35 @@ function connectToServer(serverUrl = DEFAULT_SERVER_URL) {
|
|
|
2147
2415
|
id: message.id,
|
|
2148
2416
|
result
|
|
2149
2417
|
}));
|
|
2150
|
-
console.log(pc5__default.default.green(`rpc call completed: ${message.method}`));
|
|
2151
2418
|
} catch (error) {
|
|
2152
2419
|
ws.send(JSON.stringify({
|
|
2153
2420
|
type: "tool_result",
|
|
2154
2421
|
id: message.id,
|
|
2155
2422
|
error: error.message
|
|
2156
2423
|
}));
|
|
2157
|
-
console.error(pc5__default.default.red(`rpc
|
|
2424
|
+
console.error(pc5__default.default.red(` rpc failed: ${message.method}`));
|
|
2158
2425
|
}
|
|
2159
2426
|
}
|
|
2160
2427
|
});
|
|
2161
2428
|
ws.on("close", () => {
|
|
2162
|
-
|
|
2163
|
-
|
|
2429
|
+
const delay = getReconnectDelay2();
|
|
2430
|
+
reconnectAttempts2++;
|
|
2431
|
+
console.log(pc5__default.default.gray(`disconnected, reconnecting in ${Math.round(delay / 1e3)}s...`));
|
|
2432
|
+
setTimeout(() => connectToServer(serverUrl), delay);
|
|
2164
2433
|
});
|
|
2165
2434
|
ws.on("error", (error) => {
|
|
2166
|
-
console.error(pc5__default.default.red(`
|
|
2435
|
+
console.error(pc5__default.default.red(`connection error: ${error.message}`));
|
|
2167
2436
|
});
|
|
2168
2437
|
return ws;
|
|
2169
2438
|
}
|
|
2170
2439
|
async function main() {
|
|
2171
2440
|
const serverUrl = DEFAULT_SERVER_URL;
|
|
2172
|
-
console.log(pc5__default.default.
|
|
2441
|
+
console.log(pc5__default.default.gray("starting ama..."));
|
|
2173
2442
|
connectToServer(serverUrl);
|
|
2174
2443
|
await connectToUserStreams(serverUrl);
|
|
2175
2444
|
startHttpServer();
|
|
2176
2445
|
}
|
|
2177
|
-
var
|
|
2446
|
+
var execAsync2 = util.promisify(child_process.exec);
|
|
2178
2447
|
var CODE_SERVER_VERSION = "4.96.4";
|
|
2179
2448
|
function getPlatformInfo() {
|
|
2180
2449
|
const platform = process.platform;
|
|
@@ -2208,50 +2477,50 @@ function getCodeServerBin() {
|
|
|
2208
2477
|
}
|
|
2209
2478
|
function isCodeServerInstalled() {
|
|
2210
2479
|
const binPath = getCodeServerBin();
|
|
2211
|
-
return
|
|
2480
|
+
return fs8__default.default.existsSync(binPath);
|
|
2212
2481
|
}
|
|
2213
2482
|
async function installCodeServer() {
|
|
2214
2483
|
const { ext } = getPlatformInfo();
|
|
2215
2484
|
const downloadUrl = getDownloadUrl();
|
|
2216
2485
|
const tarballPath = path10__default.default.join(AMA_DIR, `code-server.${ext}`);
|
|
2217
|
-
if (!
|
|
2218
|
-
|
|
2486
|
+
if (!fs8__default.default.existsSync(AMA_DIR)) {
|
|
2487
|
+
fs8__default.default.mkdirSync(AMA_DIR, { recursive: true });
|
|
2219
2488
|
}
|
|
2220
|
-
if (!
|
|
2221
|
-
|
|
2489
|
+
if (!fs8__default.default.existsSync(CODE_DIR)) {
|
|
2490
|
+
fs8__default.default.mkdirSync(CODE_DIR, { recursive: true });
|
|
2222
2491
|
}
|
|
2223
|
-
if (!
|
|
2224
|
-
|
|
2492
|
+
if (!fs8__default.default.existsSync(STORAGE_DIR)) {
|
|
2493
|
+
fs8__default.default.mkdirSync(STORAGE_DIR, { recursive: true });
|
|
2225
2494
|
}
|
|
2226
|
-
console.log(pc5__default.default.cyan(`
|
|
2495
|
+
console.log(pc5__default.default.cyan(`downloading code-server v${CODE_SERVER_VERSION}...`));
|
|
2227
2496
|
console.log(pc5__default.default.gray(downloadUrl));
|
|
2228
2497
|
const response = await fetch(downloadUrl);
|
|
2229
2498
|
if (!response.ok) {
|
|
2230
2499
|
throw new Error(`Failed to download code-server: ${response.statusText}`);
|
|
2231
2500
|
}
|
|
2232
2501
|
const buffer = await response.arrayBuffer();
|
|
2233
|
-
await
|
|
2502
|
+
await fs8__default.default.promises.writeFile(tarballPath, Buffer.from(buffer));
|
|
2234
2503
|
console.log(pc5__default.default.cyan("Extracting code-server..."));
|
|
2235
|
-
await
|
|
2236
|
-
await
|
|
2504
|
+
await execAsync2(`tar -xzf ${tarballPath} -C ${CODE_DIR}`);
|
|
2505
|
+
await fs8__default.default.promises.unlink(tarballPath);
|
|
2237
2506
|
const binPath = getCodeServerBin();
|
|
2238
|
-
if (
|
|
2239
|
-
await
|
|
2507
|
+
if (fs8__default.default.existsSync(binPath)) {
|
|
2508
|
+
await fs8__default.default.promises.chmod(binPath, 493);
|
|
2240
2509
|
}
|
|
2241
|
-
console.log(pc5__default.default.green("
|
|
2510
|
+
console.log(pc5__default.default.green("code-server installed successfully"));
|
|
2242
2511
|
}
|
|
2243
2512
|
async function killExistingCodeServer() {
|
|
2244
2513
|
try {
|
|
2245
2514
|
if (process.platform === "win32") {
|
|
2246
|
-
await
|
|
2515
|
+
await execAsync2("netstat -ano | findstr :8081 | findstr LISTENING").then(async ({ stdout }) => {
|
|
2247
2516
|
const pid = stdout.trim().split(/\s+/).pop();
|
|
2248
|
-
if (pid) await
|
|
2517
|
+
if (pid) await execAsync2(`taskkill /PID ${pid} /F`);
|
|
2249
2518
|
}).catch(() => {
|
|
2250
2519
|
});
|
|
2251
2520
|
} else {
|
|
2252
|
-
await
|
|
2521
|
+
await execAsync2("lsof -ti:8081").then(async ({ stdout }) => {
|
|
2253
2522
|
const pid = stdout.trim();
|
|
2254
|
-
if (pid) await
|
|
2523
|
+
if (pid) await execAsync2(`kill -9 ${pid}`);
|
|
2255
2524
|
}).catch(() => {
|
|
2256
2525
|
});
|
|
2257
2526
|
}
|
|
@@ -2261,8 +2530,8 @@ async function killExistingCodeServer() {
|
|
|
2261
2530
|
async function setupDefaultSettings() {
|
|
2262
2531
|
const userDir = path10__default.default.join(STORAGE_DIR, "User");
|
|
2263
2532
|
const settingsPath = path10__default.default.join(userDir, "settings.json");
|
|
2264
|
-
if (!
|
|
2265
|
-
|
|
2533
|
+
if (!fs8__default.default.existsSync(userDir)) {
|
|
2534
|
+
fs8__default.default.mkdirSync(userDir, { recursive: true });
|
|
2266
2535
|
}
|
|
2267
2536
|
const defaultSettings = {
|
|
2268
2537
|
// Disable signature verification for Open VSX extensions
|
|
@@ -2280,9 +2549,9 @@ async function setupDefaultSettings() {
|
|
|
2280
2549
|
"workbench.activityBar.location": "top"
|
|
2281
2550
|
};
|
|
2282
2551
|
let existingSettings = {};
|
|
2283
|
-
if (
|
|
2552
|
+
if (fs8__default.default.existsSync(settingsPath)) {
|
|
2284
2553
|
try {
|
|
2285
|
-
const content = await
|
|
2554
|
+
const content = await fs8__default.default.promises.readFile(settingsPath, "utf-8");
|
|
2286
2555
|
existingSettings = JSON.parse(content);
|
|
2287
2556
|
} catch {
|
|
2288
2557
|
}
|
|
@@ -2290,7 +2559,7 @@ async function setupDefaultSettings() {
|
|
|
2290
2559
|
const mergedSettings = { ...defaultSettings, ...existingSettings };
|
|
2291
2560
|
mergedSettings["workbench.colorTheme"] = "Min Dark";
|
|
2292
2561
|
mergedSettings["extensions.verifySignature"] = false;
|
|
2293
|
-
await
|
|
2562
|
+
await fs8__default.default.promises.writeFile(settingsPath, JSON.stringify(mergedSettings, null, 2));
|
|
2294
2563
|
console.log(pc5__default.default.green("ama code-server settings configured"));
|
|
2295
2564
|
}
|
|
2296
2565
|
async function installExtensions() {
|
|
@@ -2301,7 +2570,7 @@ async function installExtensions() {
|
|
|
2301
2570
|
for (const ext of extensions) {
|
|
2302
2571
|
try {
|
|
2303
2572
|
console.log(pc5__default.default.cyan(`ama installing extension: ${ext}...`));
|
|
2304
|
-
await
|
|
2573
|
+
await execAsync2(`"${binPath}" --user-data-dir "${STORAGE_DIR}" --install-extension ${ext}`);
|
|
2305
2574
|
console.log(pc5__default.default.green(`ama extension ${ext} installed`));
|
|
2306
2575
|
} catch (error) {
|
|
2307
2576
|
console.log(pc5__default.default.yellow(`ama failed to install extension ${ext}`), error);
|
|
@@ -2311,7 +2580,7 @@ async function installExtensions() {
|
|
|
2311
2580
|
async function startCodeServer(cwd) {
|
|
2312
2581
|
const binPath = getCodeServerBin();
|
|
2313
2582
|
const workDir = cwd || process.cwd();
|
|
2314
|
-
if (!
|
|
2583
|
+
if (!fs8__default.default.existsSync(binPath)) {
|
|
2315
2584
|
throw new Error("ama code-server is not installed. Run installCodeServer() first.");
|
|
2316
2585
|
}
|
|
2317
2586
|
await killExistingCodeServer();
|
|
@@ -2319,12 +2588,12 @@ async function startCodeServer(cwd) {
|
|
|
2319
2588
|
await installExtensions();
|
|
2320
2589
|
const workspaceStoragePath = path10__default.default.join(STORAGE_DIR, "User", "workspaceStorage");
|
|
2321
2590
|
try {
|
|
2322
|
-
if (
|
|
2323
|
-
await
|
|
2591
|
+
if (fs8__default.default.existsSync(workspaceStoragePath)) {
|
|
2592
|
+
await fs8__default.default.promises.rm(workspaceStoragePath, { recursive: true, force: true });
|
|
2324
2593
|
}
|
|
2325
2594
|
const stateDbPath = path10__default.default.join(STORAGE_DIR, "User", "globalStorage", "state.vscdb");
|
|
2326
|
-
if (
|
|
2327
|
-
await
|
|
2595
|
+
if (fs8__default.default.existsSync(stateDbPath)) {
|
|
2596
|
+
await fs8__default.default.promises.unlink(stateDbPath);
|
|
2328
2597
|
}
|
|
2329
2598
|
} catch {
|
|
2330
2599
|
}
|
|
@@ -2355,11 +2624,11 @@ var __dirname$1 = path10.dirname(__filename$1);
|
|
|
2355
2624
|
var DAEMON_PID_FILE = path10__default.default.join(AMA_DIR, "daemon.pid");
|
|
2356
2625
|
var DAEMON_LOG_FILE = path10__default.default.join(AMA_DIR, "daemon.log");
|
|
2357
2626
|
function isDaemonRunning() {
|
|
2358
|
-
if (!
|
|
2627
|
+
if (!fs8__default.default.existsSync(DAEMON_PID_FILE)) {
|
|
2359
2628
|
return false;
|
|
2360
2629
|
}
|
|
2361
2630
|
try {
|
|
2362
|
-
const pid = Number(
|
|
2631
|
+
const pid = Number(fs8__default.default.readFileSync(DAEMON_PID_FILE, "utf8"));
|
|
2363
2632
|
process.kill(pid, 0);
|
|
2364
2633
|
return true;
|
|
2365
2634
|
} catch {
|
|
@@ -2367,30 +2636,30 @@ function isDaemonRunning() {
|
|
|
2367
2636
|
}
|
|
2368
2637
|
}
|
|
2369
2638
|
function stopDaemon() {
|
|
2370
|
-
if (!
|
|
2639
|
+
if (!fs8__default.default.existsSync(DAEMON_PID_FILE)) {
|
|
2371
2640
|
return false;
|
|
2372
2641
|
}
|
|
2373
2642
|
try {
|
|
2374
|
-
const pid = Number(
|
|
2643
|
+
const pid = Number(fs8__default.default.readFileSync(DAEMON_PID_FILE, "utf8"));
|
|
2375
2644
|
process.kill(pid, "SIGTERM");
|
|
2376
|
-
|
|
2645
|
+
fs8__default.default.unlinkSync(DAEMON_PID_FILE);
|
|
2377
2646
|
return true;
|
|
2378
2647
|
} catch (error) {
|
|
2379
2648
|
return false;
|
|
2380
2649
|
}
|
|
2381
2650
|
}
|
|
2382
2651
|
function startDaemon() {
|
|
2383
|
-
if (!
|
|
2384
|
-
|
|
2652
|
+
if (!fs8__default.default.existsSync(AMA_DIR)) {
|
|
2653
|
+
fs8__default.default.mkdirSync(AMA_DIR, { recursive: true });
|
|
2385
2654
|
}
|
|
2386
2655
|
if (isDaemonRunning()) {
|
|
2387
2656
|
stopDaemon();
|
|
2388
2657
|
}
|
|
2389
2658
|
const daemonScript = path10__default.default.join(__dirname$1, "lib", "daemon-entry.js");
|
|
2390
|
-
if (!
|
|
2659
|
+
if (!fs8__default.default.existsSync(daemonScript)) {
|
|
2391
2660
|
throw new Error(`Daemon entry script not found at: ${daemonScript}. Please rebuild the project.`);
|
|
2392
2661
|
}
|
|
2393
|
-
const logFd =
|
|
2662
|
+
const logFd = fs8__default.default.openSync(DAEMON_LOG_FILE, "a");
|
|
2394
2663
|
const daemon = child_process.spawn(process.execPath, [daemonScript], {
|
|
2395
2664
|
detached: true,
|
|
2396
2665
|
stdio: ["ignore", logFd, logFd],
|
|
@@ -2398,21 +2667,27 @@ function startDaemon() {
|
|
|
2398
2667
|
cwd: process.cwd()
|
|
2399
2668
|
});
|
|
2400
2669
|
daemon.unref();
|
|
2401
|
-
|
|
2402
|
-
|
|
2670
|
+
fs8__default.default.writeFileSync(DAEMON_PID_FILE, String(daemon.pid));
|
|
2671
|
+
fs8__default.default.closeSync(logFd);
|
|
2403
2672
|
}
|
|
2404
2673
|
function getDaemonPid() {
|
|
2405
|
-
if (!
|
|
2674
|
+
if (!fs8__default.default.existsSync(DAEMON_PID_FILE)) {
|
|
2406
2675
|
return null;
|
|
2407
2676
|
}
|
|
2408
2677
|
try {
|
|
2409
|
-
return Number(
|
|
2678
|
+
return Number(fs8__default.default.readFileSync(DAEMON_PID_FILE, "utf8"));
|
|
2410
2679
|
} catch {
|
|
2411
2680
|
return null;
|
|
2412
2681
|
}
|
|
2413
2682
|
}
|
|
2414
|
-
var VERSION = "0.0.
|
|
2683
|
+
var VERSION = "0.0.11";
|
|
2415
2684
|
var PROJECT_DIR = process.cwd();
|
|
2685
|
+
var LOGO = `
|
|
2686
|
+
__ _ _ __ ___ __ _
|
|
2687
|
+
/ _\` | '_ \` _ \\ / _\` |
|
|
2688
|
+
| (_| | | | | | | (_| |
|
|
2689
|
+
\\__,_|_| |_| |_|\\__,_|
|
|
2690
|
+
`;
|
|
2416
2691
|
function promptUser(question) {
|
|
2417
2692
|
const rl = readline__default.default.createInterface({
|
|
2418
2693
|
input: process.stdin,
|
|
@@ -2427,168 +2702,249 @@ function promptUser(question) {
|
|
|
2427
2702
|
}
|
|
2428
2703
|
async function startWithCodeServer() {
|
|
2429
2704
|
if (!isCodeServerInstalled()) {
|
|
2430
|
-
console.log(pc5__default.default.
|
|
2705
|
+
console.log(pc5__default.default.gray("setting up code-server..."));
|
|
2431
2706
|
try {
|
|
2432
2707
|
await installCodeServer();
|
|
2433
2708
|
} catch (error) {
|
|
2434
|
-
console.error(pc5__default.default.red(`
|
|
2435
|
-
console.log(pc5__default.default.
|
|
2709
|
+
console.error(pc5__default.default.red(`failed to install code-server: ${error.message}`));
|
|
2710
|
+
console.log(pc5__default.default.gray("continuing without code-server..."));
|
|
2436
2711
|
}
|
|
2437
2712
|
}
|
|
2438
2713
|
if (isCodeServerInstalled()) {
|
|
2439
2714
|
try {
|
|
2440
2715
|
await startCodeServer(PROJECT_DIR);
|
|
2441
2716
|
} catch (error) {
|
|
2442
|
-
console.error(pc5__default.default.red(`
|
|
2717
|
+
console.error(pc5__default.default.red(`failed to start code-server: ${error.message}`));
|
|
2443
2718
|
}
|
|
2444
2719
|
}
|
|
2445
2720
|
main();
|
|
2446
2721
|
}
|
|
2722
|
+
async function checkForUpdates() {
|
|
2723
|
+
try {
|
|
2724
|
+
const response = await fetch("https://registry.npmjs.org/amai/latest");
|
|
2725
|
+
const data = await response.json();
|
|
2726
|
+
const latestVersion = data.version;
|
|
2727
|
+
return {
|
|
2728
|
+
current: VERSION,
|
|
2729
|
+
latest: latestVersion,
|
|
2730
|
+
hasUpdate: latestVersion !== VERSION
|
|
2731
|
+
};
|
|
2732
|
+
} catch {
|
|
2733
|
+
return { current: VERSION, latest: VERSION, hasUpdate: false };
|
|
2734
|
+
}
|
|
2735
|
+
}
|
|
2736
|
+
function runNpmInstall() {
|
|
2737
|
+
return new Promise((resolve, reject) => {
|
|
2738
|
+
const child = child_process.spawn("bun", ["add", "-g", "amai@latest"], {
|
|
2739
|
+
stdio: "inherit",
|
|
2740
|
+
shell: true
|
|
2741
|
+
});
|
|
2742
|
+
child.on("close", (code) => {
|
|
2743
|
+
if (code === 0) resolve();
|
|
2744
|
+
else reject(new Error(`bun add exited with code ${code}`));
|
|
2745
|
+
});
|
|
2746
|
+
child.on("error", reject);
|
|
2747
|
+
});
|
|
2748
|
+
}
|
|
2447
2749
|
var args = process.argv.slice(2);
|
|
2750
|
+
if (args[0] === "--version" || args[0] === "-v") {
|
|
2751
|
+
console.log(pc5__default.default.gray(`amai ${VERSION}`));
|
|
2752
|
+
process.exit(0);
|
|
2753
|
+
}
|
|
2448
2754
|
if (args[0] === "--help" || args[0] === "-h") {
|
|
2449
|
-
console.log(
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
amai login
|
|
2470
|
-
amai start
|
|
2471
|
-
amai project add /path/to/project
|
|
2472
|
-
amai Start the agent (will prompt for background mode)
|
|
2473
|
-
`);
|
|
2755
|
+
console.log(pc5__default.default.cyan(LOGO));
|
|
2756
|
+
console.log(pc5__default.default.gray(` v${VERSION}`));
|
|
2757
|
+
console.log("");
|
|
2758
|
+
console.log(pc5__default.default.cyan(" usage"));
|
|
2759
|
+
console.log(pc5__default.default.gray(" amai [command]"));
|
|
2760
|
+
console.log("");
|
|
2761
|
+
console.log(pc5__default.default.cyan(" commands"));
|
|
2762
|
+
console.log(pc5__default.default.gray(" login authenticate with amai"));
|
|
2763
|
+
console.log(pc5__default.default.gray(" logout remove credentials"));
|
|
2764
|
+
console.log(pc5__default.default.gray(" start start background daemon"));
|
|
2765
|
+
console.log(pc5__default.default.gray(" stop stop background daemon"));
|
|
2766
|
+
console.log(pc5__default.default.gray(" status check daemon status"));
|
|
2767
|
+
console.log(pc5__default.default.gray(" update update to latest version"));
|
|
2768
|
+
console.log(pc5__default.default.gray(" project add register a project"));
|
|
2769
|
+
console.log(pc5__default.default.gray(" project list list projects"));
|
|
2770
|
+
console.log("");
|
|
2771
|
+
console.log(pc5__default.default.cyan(" options"));
|
|
2772
|
+
console.log(pc5__default.default.gray(" -h, --help show help"));
|
|
2773
|
+
console.log(pc5__default.default.gray(" -v, --version show version"));
|
|
2774
|
+
console.log("");
|
|
2474
2775
|
process.exit(0);
|
|
2475
2776
|
}
|
|
2476
|
-
if (args[0] === "
|
|
2477
|
-
|
|
2478
|
-
console.log(pc5__default.default.
|
|
2777
|
+
if (args[0] === "update") {
|
|
2778
|
+
(async () => {
|
|
2779
|
+
console.log(pc5__default.default.gray("checking for updates..."));
|
|
2780
|
+
const { current, latest, hasUpdate } = await checkForUpdates();
|
|
2781
|
+
if (!hasUpdate) {
|
|
2782
|
+
console.log(pc5__default.default.cyan(`already on latest version (${current})`));
|
|
2783
|
+
process.exit(0);
|
|
2784
|
+
}
|
|
2785
|
+
console.log(pc5__default.default.cyan(`update available: ${current} -> ${latest}`));
|
|
2786
|
+
const answer = await promptUser(pc5__default.default.gray("install update? (Y/n): "));
|
|
2787
|
+
if (answer === "" || answer.toLowerCase() === "y" || answer.toLowerCase() === "yes") {
|
|
2788
|
+
console.log(pc5__default.default.gray("updating..."));
|
|
2789
|
+
try {
|
|
2790
|
+
await runNpmInstall();
|
|
2791
|
+
console.log(pc5__default.default.cyan(`updated to ${latest}`));
|
|
2792
|
+
} catch (error) {
|
|
2793
|
+
console.error(pc5__default.default.red(`update failed: ${error.message}`));
|
|
2794
|
+
process.exit(1);
|
|
2795
|
+
}
|
|
2796
|
+
}
|
|
2479
2797
|
process.exit(0);
|
|
2480
|
-
}
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
console.log(pc5__default.default.
|
|
2485
|
-
startDaemon();
|
|
2486
|
-
console.log(pc5__default.default.green("ama started in background mode successfully"));
|
|
2798
|
+
})();
|
|
2799
|
+
} else if (args[0] === "start") {
|
|
2800
|
+
(async () => {
|
|
2801
|
+
if (isDaemonRunning()) {
|
|
2802
|
+
console.log(pc5__default.default.gray("amai is already running"));
|
|
2487
2803
|
process.exit(0);
|
|
2488
|
-
}
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2804
|
+
}
|
|
2805
|
+
if (!isAuthenticated()) {
|
|
2806
|
+
console.log(pc5__default.default.gray("not authenticated"));
|
|
2807
|
+
try {
|
|
2808
|
+
await login();
|
|
2809
|
+
} catch {
|
|
2810
|
+
console.error(pc5__default.default.red("login failed"));
|
|
2811
|
+
process.exit(1);
|
|
2812
|
+
}
|
|
2813
|
+
}
|
|
2493
2814
|
startDaemon();
|
|
2494
|
-
console.log(pc5__default.default.
|
|
2495
|
-
console.log(pc5__default.default.gray(`
|
|
2815
|
+
console.log(pc5__default.default.cyan("amai started"));
|
|
2816
|
+
console.log(pc5__default.default.gray(`check status: amai status`));
|
|
2496
2817
|
process.exit(0);
|
|
2497
|
-
}
|
|
2498
|
-
}
|
|
2499
|
-
if (args[0] === "stop") {
|
|
2818
|
+
})();
|
|
2819
|
+
} else if (args[0] === "stop") {
|
|
2500
2820
|
if (stopDaemon()) {
|
|
2501
|
-
console.log(pc5__default.default.
|
|
2821
|
+
console.log(pc5__default.default.cyan("daemon stopped"));
|
|
2502
2822
|
} else {
|
|
2503
|
-
console.log(pc5__default.default.
|
|
2823
|
+
console.log(pc5__default.default.gray("daemon was not running"));
|
|
2504
2824
|
}
|
|
2505
2825
|
process.exit(0);
|
|
2506
|
-
}
|
|
2507
|
-
if (args[0] === "status") {
|
|
2826
|
+
} else if (args[0] === "status") {
|
|
2508
2827
|
const running = isDaemonRunning();
|
|
2509
2828
|
const pid = getDaemonPid();
|
|
2829
|
+
console.log("");
|
|
2830
|
+
console.log(pc5__default.default.cyan(" amai status"));
|
|
2831
|
+
console.log("");
|
|
2510
2832
|
if (running && pid) {
|
|
2511
|
-
console.log(pc5__default.default.
|
|
2833
|
+
console.log(pc5__default.default.gray(` status running`));
|
|
2834
|
+
console.log(pc5__default.default.gray(` pid ${pid}`));
|
|
2512
2835
|
} else {
|
|
2513
|
-
console.log(pc5__default.default.
|
|
2836
|
+
console.log(pc5__default.default.gray(` status stopped`));
|
|
2514
2837
|
}
|
|
2838
|
+
console.log(pc5__default.default.gray(` version ${VERSION}`));
|
|
2839
|
+
console.log("");
|
|
2515
2840
|
process.exit(0);
|
|
2516
|
-
}
|
|
2517
|
-
if (args[0] === "project") {
|
|
2841
|
+
} else if (args[0] === "project") {
|
|
2518
2842
|
if (args[1] === "add") {
|
|
2519
2843
|
const projectPath = args[2];
|
|
2520
2844
|
if (!projectPath) {
|
|
2521
|
-
console.error(pc5__default.default.red("
|
|
2522
|
-
console.log("
|
|
2845
|
+
console.error(pc5__default.default.red("please provide a project path"));
|
|
2846
|
+
console.log(pc5__default.default.gray("usage: amai project add <path>"));
|
|
2523
2847
|
process.exit(1);
|
|
2524
2848
|
}
|
|
2525
2849
|
const resolvedPath = path10__default.default.resolve(projectPath);
|
|
2526
|
-
if (!
|
|
2527
|
-
console.error(pc5__default.default.red(`
|
|
2850
|
+
if (!fs8__default.default.existsSync(resolvedPath)) {
|
|
2851
|
+
console.error(pc5__default.default.red(`path does not exist: ${resolvedPath}`));
|
|
2528
2852
|
process.exit(1);
|
|
2529
2853
|
}
|
|
2530
|
-
if (!
|
|
2531
|
-
console.error(pc5__default.default.red(`
|
|
2854
|
+
if (!fs8__default.default.statSync(resolvedPath).isDirectory()) {
|
|
2855
|
+
console.error(pc5__default.default.red(`path is not a directory: ${resolvedPath}`));
|
|
2532
2856
|
process.exit(1);
|
|
2533
2857
|
}
|
|
2534
2858
|
const projectId = path10__default.default.basename(resolvedPath);
|
|
2535
2859
|
projectRegistry.register(projectId, resolvedPath);
|
|
2536
|
-
console.log(pc5__default.default.
|
|
2860
|
+
console.log(pc5__default.default.cyan(`project registered: ${projectId}`));
|
|
2861
|
+
console.log(pc5__default.default.gray(` ${resolvedPath}`));
|
|
2537
2862
|
process.exit(0);
|
|
2538
2863
|
} else if (args[1] === "list") {
|
|
2539
2864
|
const projects = projectRegistry.list();
|
|
2865
|
+
console.log("");
|
|
2866
|
+
console.log(pc5__default.default.cyan(" projects"));
|
|
2867
|
+
console.log("");
|
|
2540
2868
|
if (projects.length === 0) {
|
|
2541
|
-
console.log(pc5__default.default.
|
|
2869
|
+
console.log(pc5__default.default.gray(" no projects registered"));
|
|
2542
2870
|
} else {
|
|
2543
|
-
console.log(pc5__default.default.bold("Registered projects:"));
|
|
2544
2871
|
projects.forEach((project) => {
|
|
2545
|
-
|
|
2872
|
+
const status = project.active ? pc5__default.default.cyan("active") : pc5__default.default.gray("inactive");
|
|
2873
|
+
console.log(pc5__default.default.gray(` ${project.id} [${status}]`));
|
|
2874
|
+
console.log(pc5__default.default.gray(` ${project.cwd}`));
|
|
2546
2875
|
});
|
|
2547
2876
|
}
|
|
2877
|
+
console.log("");
|
|
2548
2878
|
process.exit(0);
|
|
2549
2879
|
} else {
|
|
2550
|
-
console.error(pc5__default.default.red(`
|
|
2551
|
-
console.log(
|
|
2880
|
+
console.error(pc5__default.default.red(`unknown project command: ${args[1]}`));
|
|
2881
|
+
console.log(pc5__default.default.gray("usage: amai project add <path> | amai project list"));
|
|
2552
2882
|
process.exit(1);
|
|
2553
2883
|
}
|
|
2554
|
-
}
|
|
2555
|
-
|
|
2556
|
-
|
|
2884
|
+
} else if (args[0] === "login" || args[0] === "--login") {
|
|
2885
|
+
(async () => {
|
|
2886
|
+
try {
|
|
2887
|
+
await login();
|
|
2888
|
+
console.log("");
|
|
2889
|
+
if (isDaemonRunning()) {
|
|
2890
|
+
console.log(pc5__default.default.gray("amai is already running"));
|
|
2891
|
+
process.exit(0);
|
|
2892
|
+
}
|
|
2893
|
+
const answer = await promptUser(pc5__default.default.gray("start amai now? (Y/n): "));
|
|
2894
|
+
const shouldStart = answer === "" || answer.toLowerCase() === "y" || answer.toLowerCase() === "yes";
|
|
2895
|
+
if (shouldStart) {
|
|
2896
|
+
const bgAnswer = await promptUser(pc5__default.default.gray("run in background? (Y/n): "));
|
|
2897
|
+
const runInBackground = bgAnswer === "" || bgAnswer.toLowerCase() === "y" || bgAnswer.toLowerCase() === "yes";
|
|
2898
|
+
if (runInBackground) {
|
|
2899
|
+
console.log(pc5__default.default.gray("starting..."));
|
|
2900
|
+
startDaemon();
|
|
2901
|
+
console.log(pc5__default.default.cyan("amai started"));
|
|
2902
|
+
console.log(pc5__default.default.gray('use "amai status" to check status'));
|
|
2903
|
+
} else {
|
|
2904
|
+
console.log(pc5__default.default.gray("starting in foreground..."));
|
|
2905
|
+
startWithCodeServer();
|
|
2906
|
+
return;
|
|
2907
|
+
}
|
|
2908
|
+
}
|
|
2909
|
+
process.exit(0);
|
|
2910
|
+
} catch {
|
|
2911
|
+
console.error(pc5__default.default.red("login failed"));
|
|
2912
|
+
process.exit(1);
|
|
2913
|
+
}
|
|
2914
|
+
})();
|
|
2557
2915
|
} else if (args[0] === "logout" || args[0] === "--logout") {
|
|
2558
2916
|
logout();
|
|
2559
|
-
console.log(pc5__default.default.
|
|
2917
|
+
console.log(pc5__default.default.cyan("logged out"));
|
|
2560
2918
|
process.exit(0);
|
|
2561
2919
|
} else {
|
|
2562
2920
|
(async () => {
|
|
2921
|
+
console.log(pc5__default.default.cyan(LOGO));
|
|
2563
2922
|
if (!isAuthenticated()) {
|
|
2564
|
-
console.log(pc5__default.default.
|
|
2923
|
+
console.log(pc5__default.default.gray("not authenticated"));
|
|
2565
2924
|
try {
|
|
2566
2925
|
await login();
|
|
2926
|
+
console.log("");
|
|
2567
2927
|
} catch {
|
|
2568
|
-
console.error(pc5__default.default.red("
|
|
2928
|
+
console.error(pc5__default.default.red("login failed"));
|
|
2569
2929
|
process.exit(1);
|
|
2570
2930
|
}
|
|
2571
2931
|
}
|
|
2572
2932
|
if (isDaemonRunning()) {
|
|
2573
|
-
console.log(pc5__default.default.
|
|
2933
|
+
console.log(pc5__default.default.gray("amai is already running"));
|
|
2934
|
+
console.log(pc5__default.default.gray('use "amai status" to check status'));
|
|
2574
2935
|
process.exit(0);
|
|
2575
2936
|
}
|
|
2576
|
-
|
|
2577
|
-
console.log(pc5__default.default.bold("How would you like to run amai?"));
|
|
2578
|
-
console.log(pc5__default.default.gray("Background mode is highly recommended for better performance and stability."));
|
|
2579
|
-
const answer = await promptUser(
|
|
2580
|
-
pc5__default.default.cyan("Run in background? (Y/n): ")
|
|
2581
|
-
);
|
|
2937
|
+
const answer = await promptUser(pc5__default.default.gray("run in background? (Y/n): "));
|
|
2582
2938
|
const runInBackground = answer === "" || answer.toLowerCase() === "y" || answer.toLowerCase() === "yes";
|
|
2583
2939
|
if (runInBackground) {
|
|
2584
|
-
console.log(pc5__default.default.
|
|
2940
|
+
console.log(pc5__default.default.gray("starting..."));
|
|
2585
2941
|
startDaemon();
|
|
2586
|
-
console.log(pc5__default.default.
|
|
2587
|
-
console.log(pc5__default.default.gray('
|
|
2588
|
-
console.log(pc5__default.default.gray('
|
|
2942
|
+
console.log(pc5__default.default.cyan("amai started"));
|
|
2943
|
+
console.log(pc5__default.default.gray('use "amai status" to check status'));
|
|
2944
|
+
console.log(pc5__default.default.gray('use "amai stop" to stop'));
|
|
2589
2945
|
process.exit(0);
|
|
2590
2946
|
} else {
|
|
2591
|
-
console.log(pc5__default.default.
|
|
2947
|
+
console.log(pc5__default.default.gray("starting in foreground..."));
|
|
2592
2948
|
startWithCodeServer();
|
|
2593
2949
|
}
|
|
2594
2950
|
})();
|