amai 0.0.5 → 0.0.7

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.
@@ -2,12 +2,11 @@
2
2
  'use strict';
3
3
 
4
4
  var WebSocket = require('ws');
5
- var events = require('events');
6
5
  var zod = require('zod');
7
6
  var promises = require('fs/promises');
8
- var path9 = require('path');
9
- var fs3 = require('fs');
10
- var os2 = require('os');
7
+ var path11 = require('path');
8
+ var fs4 = require('fs');
9
+ var os3 = require('os');
11
10
  var crypto = require('crypto');
12
11
  var child_process = require('child_process');
13
12
  var util = require('util');
@@ -19,18 +18,18 @@ var cors = require('hono/cors');
19
18
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
20
19
 
21
20
  var WebSocket__default = /*#__PURE__*/_interopDefault(WebSocket);
22
- var path9__default = /*#__PURE__*/_interopDefault(path9);
23
- var fs3__default = /*#__PURE__*/_interopDefault(fs3);
24
- var os2__default = /*#__PURE__*/_interopDefault(os2);
21
+ var path11__default = /*#__PURE__*/_interopDefault(path11);
22
+ var fs4__default = /*#__PURE__*/_interopDefault(fs4);
23
+ var os3__default = /*#__PURE__*/_interopDefault(os3);
25
24
  var pc2__default = /*#__PURE__*/_interopDefault(pc2);
26
25
 
27
26
  var DEFAULT_SERVER_URL = "wss://ama-production-a628.up.railway.app";
28
- var AMA_DIR = path9__default.default.join(os2__default.default.homedir(), ".amai");
29
- var CODE_DIR = path9__default.default.join(AMA_DIR, "code");
30
- var STORAGE_DIR = path9__default.default.join(AMA_DIR, "storage");
27
+ var AMA_DIR = path11__default.default.join(os3__default.default.homedir(), ".amai");
28
+ var CODE_DIR = path11__default.default.join(AMA_DIR, "code");
29
+ var STORAGE_DIR = path11__default.default.join(AMA_DIR, "storage");
31
30
 
32
31
  // src/lib/project-registry.ts
33
- var REGISTRY_FILE = path9__default.default.join(AMA_DIR, "projects.json");
32
+ var REGISTRY_FILE = path11__default.default.join(AMA_DIR, "projects.json");
34
33
  var ProjectRegistry = class {
35
34
  projects = /* @__PURE__ */ new Map();
36
35
  constructor() {
@@ -38,14 +37,14 @@ var ProjectRegistry = class {
38
37
  }
39
38
  load() {
40
39
  try {
41
- if (fs3__default.default.existsSync(REGISTRY_FILE)) {
42
- const data = fs3__default.default.readFileSync(REGISTRY_FILE, "utf8");
40
+ if (fs4__default.default.existsSync(REGISTRY_FILE)) {
41
+ const data = fs4__default.default.readFileSync(REGISTRY_FILE, "utf8");
43
42
  const parsed = JSON.parse(data);
44
43
  if (!Array.isArray(parsed)) {
45
44
  console.error("Invalid project registry format: expected array, got", typeof parsed);
46
45
  const backupFile = REGISTRY_FILE + ".backup." + Date.now();
47
- fs3__default.default.copyFileSync(REGISTRY_FILE, backupFile);
48
- fs3__default.default.unlinkSync(REGISTRY_FILE);
46
+ fs4__default.default.copyFileSync(REGISTRY_FILE, backupFile);
47
+ fs4__default.default.unlinkSync(REGISTRY_FILE);
49
48
  return;
50
49
  }
51
50
  const projects = parsed;
@@ -58,11 +57,11 @@ var ProjectRegistry = class {
58
57
  }
59
58
  } catch (error) {
60
59
  console.error("Failed to load project registry:", error);
61
- if (fs3__default.default.existsSync(REGISTRY_FILE)) {
60
+ if (fs4__default.default.existsSync(REGISTRY_FILE)) {
62
61
  try {
63
62
  const backupFile = REGISTRY_FILE + ".backup." + Date.now();
64
- fs3__default.default.copyFileSync(REGISTRY_FILE, backupFile);
65
- fs3__default.default.unlinkSync(REGISTRY_FILE);
63
+ fs4__default.default.copyFileSync(REGISTRY_FILE, backupFile);
64
+ fs4__default.default.unlinkSync(REGISTRY_FILE);
66
65
  console.log("Corrupted registry file backed up and removed. Starting fresh.");
67
66
  } catch (backupError) {
68
67
  }
@@ -71,21 +70,21 @@ var ProjectRegistry = class {
71
70
  }
72
71
  save() {
73
72
  try {
74
- if (!fs3__default.default.existsSync(AMA_DIR)) {
75
- fs3__default.default.mkdirSync(AMA_DIR, { recursive: true });
73
+ if (!fs4__default.default.existsSync(AMA_DIR)) {
74
+ fs4__default.default.mkdirSync(AMA_DIR, { recursive: true });
76
75
  }
77
76
  const projects = Array.from(this.projects.values());
78
- fs3__default.default.writeFileSync(REGISTRY_FILE, JSON.stringify(projects, null, 2), "utf8");
77
+ fs4__default.default.writeFileSync(REGISTRY_FILE, JSON.stringify(projects, null, 2), "utf8");
79
78
  } catch (error) {
80
79
  console.error("Failed to save project registry:", error);
81
80
  }
82
81
  }
83
82
  register(projectId, cwd, name) {
84
- const normalizedCwd = path9__default.default.normalize(path9__default.default.resolve(cwd));
83
+ const normalizedCwd = path11__default.default.normalize(path11__default.default.resolve(cwd));
85
84
  this.projects.set(projectId, {
86
85
  id: projectId,
87
86
  cwd: normalizedCwd,
88
- name: name || path9__default.default.basename(normalizedCwd),
87
+ name: name || path11__default.default.basename(normalizedCwd),
89
88
  active: true
90
89
  });
91
90
  this.save();
@@ -115,9 +114,9 @@ var ProjectRegistry = class {
115
114
  var projectRegistry = new ProjectRegistry();
116
115
  function isPathWithinProject(filePath, projectCwd) {
117
116
  try {
118
- const resolved = path9__default.default.resolve(projectCwd, filePath);
119
- const normalized = path9__default.default.normalize(resolved);
120
- const normalizedCwd = path9__default.default.normalize(projectCwd);
117
+ const resolved = path11__default.default.resolve(projectCwd, filePath);
118
+ const normalized = path11__default.default.normalize(resolved);
119
+ const normalizedCwd = path11__default.default.normalize(projectCwd);
121
120
  return normalized.startsWith(normalizedCwd);
122
121
  } catch {
123
122
  return false;
@@ -133,7 +132,7 @@ function validatePath(filePath, projectCwd) {
133
132
  };
134
133
  }
135
134
  try {
136
- const resolvedPath = path9__default.default.resolve(projectCwd, filePath);
135
+ const resolvedPath = path11__default.default.resolve(projectCwd, filePath);
137
136
  if (!isPathWithinProject(filePath, projectCwd)) {
138
137
  return {
139
138
  valid: false,
@@ -152,7 +151,7 @@ function validatePath(filePath, projectCwd) {
152
151
  }
153
152
  }
154
153
  function resolveProjectPath(filePath, projectCwd) {
155
- return path9__default.default.resolve(projectCwd, filePath);
154
+ return path11__default.default.resolve(projectCwd, filePath);
156
155
  }
157
156
 
158
157
  // src/tools/read-file.ts
@@ -274,7 +273,7 @@ var read_file = async function(input, projectCwd) {
274
273
  };
275
274
  }
276
275
  } else {
277
- const absolute_file_path = path9__default.default.resolve(relative_file_path);
276
+ const absolute_file_path = path11__default.default.resolve(relative_file_path);
278
277
  try {
279
278
  const fileStats = await promises.stat(absolute_file_path);
280
279
  if (!fileStats.isFile()) {
@@ -868,20 +867,20 @@ var editFiles = async function(input, projectCwd) {
868
867
  }
869
868
  const basePath = projectCwd || process.cwd();
870
869
  const filePath = resolveProjectPath(target_file, basePath);
871
- const dirPath = path9__default.default.dirname(filePath);
870
+ const dirPath = path11__default.default.dirname(filePath);
872
871
  await promises.mkdir(dirPath, { recursive: true });
873
872
  let isNewFile = providedNewFile;
874
873
  let existingContent = "";
875
874
  if (isNewFile === void 0) {
876
875
  try {
877
- existingContent = await fs3__default.default.promises.readFile(filePath, "utf-8");
876
+ existingContent = await fs4__default.default.promises.readFile(filePath, "utf-8");
878
877
  isNewFile = false;
879
878
  } catch (error) {
880
879
  isNewFile = true;
881
880
  }
882
881
  } else if (!isNewFile) {
883
882
  try {
884
- existingContent = await fs3__default.default.promises.readFile(filePath, "utf-8");
883
+ existingContent = await fs4__default.default.promises.readFile(filePath, "utf-8");
885
884
  } catch (error) {
886
885
  isNewFile = true;
887
886
  }
@@ -894,7 +893,7 @@ var editFiles = async function(input, projectCwd) {
894
893
  content
895
894
  );
896
895
  try {
897
- await fs3__default.default.promises.writeFile(filePath, content);
896
+ await fs4__default.default.promises.writeFile(filePath, content);
898
897
  } catch (writeError) {
899
898
  checkpointStore.removeCheckpoint(checkpointId);
900
899
  throw writeError;
@@ -1018,7 +1017,7 @@ var grepTool = async function(input, projectCwd) {
1018
1017
  try {
1019
1018
  const { includePattern, excludePattern: excludePattern2, caseSensitive } = options || {};
1020
1019
  const searchDir = projectCwd || process.cwd();
1021
- if (projectCwd && !path9__default.default.isAbsolute(projectCwd)) {
1020
+ if (projectCwd && !path11__default.default.isAbsolute(projectCwd)) {
1022
1021
  return {
1023
1022
  success: false,
1024
1023
  message: "Invalid project directory",
@@ -1210,8 +1209,8 @@ var list = async function(input, projectCwd) {
1210
1209
  const walk = async (currentDir, depth) => {
1211
1210
  const entries = await promises.readdir(currentDir, { withFileTypes: true });
1212
1211
  for (const entry of entries) {
1213
- const entryAbsolutePath = path9__default.default.join(currentDir, entry.name);
1214
- const entryRelativePath = path9__default.default.relative(absolutePath, entryAbsolutePath) || ".";
1212
+ const entryAbsolutePath = path11__default.default.join(currentDir, entry.name);
1213
+ const entryRelativePath = path11__default.default.relative(absolutePath, entryAbsolutePath) || ".";
1215
1214
  if (entry.isDirectory()) {
1216
1215
  const isExcluded = entry.name.match(excludePattern);
1217
1216
  if (includeDirectoriesNormalized && matchPattern(entry.name) && !isExcluded) {
@@ -1261,213 +1260,9 @@ var list = async function(input, projectCwd) {
1261
1260
  };
1262
1261
  }
1263
1262
  };
1264
- var ignoreFiles = ["node_modules", ".git", ".next", ".env", ".env.local", ".env.development.local", ".env.test.local", ".env.production.local"];
1265
- var getContext = (dir, base = dir, allFiles = []) => {
1266
- const filePath = fs3.readdirSync(dir, { withFileTypes: true });
1267
- for (const file of filePath) {
1268
- if (ignoreFiles.includes(file.name)) continue;
1269
- const fullPath = path9__default.default.join(dir, file.name);
1270
- if (file.isDirectory()) {
1271
- getContext(fullPath, base, allFiles);
1272
- } else {
1273
- allFiles.push(path9__default.default.relative(base, fullPath));
1274
- }
1275
- }
1276
- return allFiles;
1277
- };
1278
- var HOME = os2__default.default.homedir();
1279
- var IDE_PROJECTS_PATHS = {
1280
- vscode: path9__default.default.join(HOME, ".vscode", "projects"),
1281
- cursor: path9__default.default.join(HOME, ".cursor", "projects"),
1282
- claude: path9__default.default.join(HOME, ".claude", "projects")
1283
- };
1284
- function getWorkspaceStoragePath(ide) {
1285
- const platform = os2__default.default.platform();
1286
- const appName = "Cursor" ;
1287
- if (platform === "darwin") {
1288
- return path9__default.default.join(HOME, "Library", "Application Support", appName, "User", "workspaceStorage");
1289
- } else if (platform === "win32") {
1290
- return path9__default.default.join(process.env.APPDATA || "", appName, "User", "workspaceStorage");
1291
- } else {
1292
- return path9__default.default.join(HOME, ".config", appName, "User", "workspaceStorage");
1293
- }
1294
- }
1295
- function scanWorkspaceStorage(ide) {
1296
- const projects = [];
1297
- const storagePath = getWorkspaceStoragePath();
1298
- if (!fs3__default.default.existsSync(storagePath)) {
1299
- return projects;
1300
- }
1301
- try {
1302
- const workspaces = fs3__default.default.readdirSync(storagePath);
1303
- for (const workspace of workspaces) {
1304
- const workspaceJsonPath = path9__default.default.join(storagePath, workspace, "workspace.json");
1305
- if (fs3__default.default.existsSync(workspaceJsonPath)) {
1306
- try {
1307
- const content = fs3__default.default.readFileSync(workspaceJsonPath, "utf-8");
1308
- const data = JSON.parse(content);
1309
- if (data.folder && typeof data.folder === "string") {
1310
- let projectPath = data.folder;
1311
- if (projectPath.startsWith("file://")) {
1312
- projectPath = projectPath.replace("file://", "");
1313
- projectPath = decodeURIComponent(projectPath);
1314
- }
1315
- if (fs3__default.default.existsSync(projectPath) && fs3__default.default.statSync(projectPath).isDirectory()) {
1316
- projects.push({
1317
- name: path9__default.default.basename(projectPath),
1318
- path: projectPath,
1319
- type: ide
1320
- });
1321
- }
1322
- }
1323
- } catch (err) {
1324
- console.debug(`Error reading workspace.json at ${workspaceJsonPath}: ${err}`);
1325
- }
1326
- }
1327
- }
1328
- } catch (err) {
1329
- console.debug(`Error scanning workspaceStorage for ${ide}: ${err}`);
1330
- }
1331
- return projects;
1332
- }
1333
- var scanIdeProjects = async () => {
1334
- try {
1335
- const allProjects = [];
1336
- const seenPaths = /* @__PURE__ */ new Set();
1337
- const addProject = (projectPath, ide) => {
1338
- try {
1339
- const resolvedPath = fs3__default.default.realpathSync(projectPath);
1340
- if (fs3__default.default.existsSync(resolvedPath) && fs3__default.default.statSync(resolvedPath).isDirectory() && !seenPaths.has(resolvedPath)) {
1341
- const isIdeProjectsDir = Object.values(IDE_PROJECTS_PATHS).some((ideDir) => {
1342
- try {
1343
- return fs3__default.default.realpathSync(ideDir) === resolvedPath;
1344
- } catch {
1345
- return false;
1346
- }
1347
- });
1348
- if (!isIdeProjectsDir) {
1349
- seenPaths.add(resolvedPath);
1350
- allProjects.push({
1351
- name: path9__default.default.basename(resolvedPath),
1352
- path: resolvedPath,
1353
- type: ide
1354
- });
1355
- }
1356
- }
1357
- } catch {
1358
- }
1359
- };
1360
- const cursorProjects = scanWorkspaceStorage("cursor");
1361
- for (const project of cursorProjects) {
1362
- addProject(project.path, "cursor");
1363
- }
1364
- for (const [ide, dirPath] of Object.entries(IDE_PROJECTS_PATHS)) {
1365
- if (ide === "cursor") continue;
1366
- if (fs3__default.default.existsSync(dirPath)) {
1367
- const projects = fs3__default.default.readdirSync(dirPath);
1368
- projects.forEach((project) => {
1369
- const projectPath = path9__default.default.join(dirPath, project);
1370
- try {
1371
- const stats = fs3__default.default.lstatSync(projectPath);
1372
- let actualPath = null;
1373
- if (stats.isSymbolicLink()) {
1374
- actualPath = fs3__default.default.realpathSync(projectPath);
1375
- } else if (stats.isFile()) {
1376
- try {
1377
- let content = fs3__default.default.readFileSync(projectPath, "utf-8").trim();
1378
- if (content.startsWith("~/") || content === "~") {
1379
- content = content.replace(/^~/, HOME);
1380
- }
1381
- const resolvedContent = path9__default.default.isAbsolute(content) ? content : path9__default.default.resolve(path9__default.default.dirname(projectPath), content);
1382
- if (fs3__default.default.existsSync(resolvedContent) && fs3__default.default.statSync(resolvedContent).isDirectory()) {
1383
- actualPath = fs3__default.default.realpathSync(resolvedContent);
1384
- }
1385
- } catch {
1386
- return;
1387
- }
1388
- } else if (stats.isDirectory()) {
1389
- actualPath = fs3__default.default.realpathSync(projectPath);
1390
- }
1391
- if (actualPath) {
1392
- addProject(actualPath, ide);
1393
- }
1394
- } catch {
1395
- }
1396
- });
1397
- }
1398
- }
1399
- return allProjects;
1400
- } catch (error) {
1401
- console.debug(`Error scanning IDE projects: ${error}`);
1402
- return [];
1403
- }
1404
- };
1405
- var wsConnection = null;
1406
- var startHttpServer = (connection) => {
1407
- if (connection) {
1408
- wsConnection = connection;
1409
- }
1263
+ var startHttpServer = () => {
1410
1264
  const app = new hono.Hono();
1411
1265
  app.use(cors.cors());
1412
- app.post("/daemon/status", (c) => {
1413
- const status = wsConnection ? getConnectionStatus(wsConnection) : "closed";
1414
- return c.json({ connected: status === "open" });
1415
- });
1416
- app.get("/daemon/status/stream", (c) => {
1417
- const encoder = new TextEncoder();
1418
- const stream = new ReadableStream({
1419
- start(controller) {
1420
- const initialStatus = wsConnection ? getConnectionStatus(wsConnection) : "closed";
1421
- controller.enqueue(encoder.encode(`data: ${JSON.stringify({ connected: initialStatus === "open" })}
1422
-
1423
- `));
1424
- const statusHandler = (data) => {
1425
- try {
1426
- controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}
1427
-
1428
- `));
1429
- } catch {
1430
- }
1431
- };
1432
- statusEmitter.on("status", statusHandler);
1433
- const heartbeatInterval = setInterval(() => {
1434
- try {
1435
- const currentStatus = wsConnection ? getConnectionStatus(wsConnection) : "closed";
1436
- controller.enqueue(encoder.encode(`data: ${JSON.stringify({ connected: currentStatus === "open" })}
1437
-
1438
- `));
1439
- } catch {
1440
- }
1441
- }, 15e3);
1442
- c.req.raw.signal.addEventListener("abort", () => {
1443
- statusEmitter.off("status", statusHandler);
1444
- clearInterval(heartbeatInterval);
1445
- });
1446
- }
1447
- });
1448
- return new Response(stream, {
1449
- headers: {
1450
- "Content-Type": "text/event-stream",
1451
- "Cache-Control": "no-cache",
1452
- "Connection": "keep-alive"
1453
- }
1454
- });
1455
- });
1456
- app.get("context", async (c) => {
1457
- const context = getContext(process.cwd());
1458
- return c.body(JSON.stringify(context));
1459
- });
1460
- app.get("/ide-projects", async (c) => {
1461
- try {
1462
- const projects = await scanIdeProjects();
1463
- if (!projects) {
1464
- return c.json({ error: "No projects found" }, 500);
1465
- }
1466
- return c.json({ projects });
1467
- } catch (error) {
1468
- return c.json({ error: "Failed to scan IDE projects" }, 500);
1469
- }
1470
- });
1471
1266
  app.post("/projects/register", async (c) => {
1472
1267
  try {
1473
1268
  const { projectId, cwd, name } = await c.req.json();
@@ -1496,14 +1291,14 @@ var startHttpServer = (connection) => {
1496
1291
  }
1497
1292
  let resolved;
1498
1293
  if (projectCwd) {
1499
- resolved = path9__default.default.isAbsolute(filePath) ? filePath : path9__default.default.resolve(projectCwd, filePath);
1500
- const normalizedResolved = path9__default.default.normalize(resolved);
1501
- const normalizedCwd = path9__default.default.normalize(projectCwd);
1294
+ resolved = path11__default.default.isAbsolute(filePath) ? filePath : path11__default.default.resolve(projectCwd, filePath);
1295
+ const normalizedResolved = path11__default.default.normalize(resolved);
1296
+ const normalizedCwd = path11__default.default.normalize(projectCwd);
1502
1297
  if (!normalizedResolved.startsWith(normalizedCwd)) {
1503
1298
  return c.json({ error: "Path is outside project directory" }, 403);
1504
1299
  }
1505
1300
  } else {
1506
- resolved = path9__default.default.isAbsolute(filePath) ? filePath : path9__default.default.join(process.cwd(), filePath);
1301
+ resolved = path11__default.default.isAbsolute(filePath) ? filePath : path11__default.default.join(process.cwd(), filePath);
1507
1302
  }
1508
1303
  let currentContent;
1509
1304
  try {
@@ -1590,9 +1385,9 @@ var startHttpServer = (connection) => {
1590
1385
  }
1591
1386
  let resolved;
1592
1387
  if (projectCwd) {
1593
- resolved = path9__default.default.isAbsolute(filePath || checkpoint.filePath) ? filePath || checkpoint.filePath : path9__default.default.resolve(projectCwd, filePath || checkpoint.filePath);
1594
- const normalizedResolved = path9__default.default.normalize(resolved);
1595
- const normalizedCwd = path9__default.default.normalize(projectCwd);
1388
+ resolved = path11__default.default.isAbsolute(filePath || checkpoint.filePath) ? filePath || checkpoint.filePath : path11__default.default.resolve(projectCwd, filePath || checkpoint.filePath);
1389
+ const normalizedResolved = path11__default.default.normalize(resolved);
1390
+ const normalizedCwd = path11__default.default.normalize(projectCwd);
1596
1391
  if (!normalizedResolved.startsWith(normalizedCwd)) {
1597
1392
  return c.json({ error: "Path is outside project directory" }, 403);
1598
1393
  }
@@ -1654,16 +1449,30 @@ var startHttpServer = (connection) => {
1654
1449
  });
1655
1450
  nodeServer.serve({ fetch: app.fetch, port: 3456 });
1656
1451
  };
1657
- var CREDENTIALS_DIR = path9__default.default.join(os2__default.default.homedir(), ".amai");
1658
- var CREDENTIALS_PATH = path9__default.default.join(CREDENTIALS_DIR, "credentials.json");
1452
+ var CREDENTIALS_DIR = path11__default.default.join(os3__default.default.homedir(), ".amai");
1453
+ var CREDENTIALS_PATH = path11__default.default.join(CREDENTIALS_DIR, "credentials.json");
1659
1454
  function getTokens() {
1660
- if (!fs3__default.default.existsSync(CREDENTIALS_PATH)) {
1455
+ if (!fs4__default.default.existsSync(CREDENTIALS_PATH)) {
1661
1456
  return null;
1662
1457
  }
1663
- const raw = fs3__default.default.readFileSync(CREDENTIALS_PATH, "utf8");
1458
+ const raw = fs4__default.default.readFileSync(CREDENTIALS_PATH, "utf8");
1664
1459
  const data = JSON.parse(raw);
1665
1460
  return data;
1666
1461
  }
1462
+ var getUserId = () => {
1463
+ try {
1464
+ if (!fs4__default.default.existsSync(CREDENTIALS_PATH)) {
1465
+ return;
1466
+ }
1467
+ const raw = fs4__default.default.readFileSync(CREDENTIALS_PATH, "utf8");
1468
+ const data = JSON.parse(raw);
1469
+ return {
1470
+ userId: data.user.id
1471
+ };
1472
+ } catch {
1473
+ throw new Error("Error while getting userId");
1474
+ }
1475
+ };
1667
1476
  var ExplanationSchema = zod.z.object({
1668
1477
  explanation: zod.z.string().describe("One sentence explanation as to why this tool is being used")
1669
1478
  });
@@ -1751,9 +1560,343 @@ var runTerminalCommand = async (input, projectCwd) => {
1751
1560
  };
1752
1561
  }
1753
1562
  };
1563
+ var ignoreFiles = ["node_modules", ".git", ".next", ".env", ".env.local", ".env.development.local", ".env.test.local", ".env.production.local"];
1564
+ var getContext = (dir, base = dir, allFiles = []) => {
1565
+ const filePath = fs4.readdirSync(dir, { withFileTypes: true });
1566
+ for (const file of filePath) {
1567
+ if (ignoreFiles.includes(file.name)) continue;
1568
+ const fullPath = path11__default.default.join(dir, file.name);
1569
+ if (file.isDirectory()) {
1570
+ getContext(fullPath, base, allFiles);
1571
+ } else {
1572
+ allFiles.push(path11__default.default.relative(base, fullPath));
1573
+ }
1574
+ }
1575
+ return allFiles;
1576
+ };
1577
+ var HOME = os3__default.default.homedir();
1578
+ var IDE_PROJECTS_PATHS = {
1579
+ vscode: path11__default.default.join(HOME, ".vscode", "projects"),
1580
+ cursor: path11__default.default.join(HOME, ".cursor", "projects"),
1581
+ claude: path11__default.default.join(HOME, ".claude", "projects")
1582
+ };
1583
+ function getWorkspaceStoragePath(ide) {
1584
+ const platform = os3__default.default.platform();
1585
+ const appName = "Cursor" ;
1586
+ if (platform === "darwin") {
1587
+ return path11__default.default.join(HOME, "Library", "Application Support", appName, "User", "workspaceStorage");
1588
+ } else if (platform === "win32") {
1589
+ return path11__default.default.join(process.env.APPDATA || "", appName, "User", "workspaceStorage");
1590
+ } else {
1591
+ return path11__default.default.join(HOME, ".config", appName, "User", "workspaceStorage");
1592
+ }
1593
+ }
1594
+ function scanWorkspaceStorage(ide) {
1595
+ const projects = [];
1596
+ const storagePath = getWorkspaceStoragePath();
1597
+ if (!fs4__default.default.existsSync(storagePath)) {
1598
+ return projects;
1599
+ }
1600
+ try {
1601
+ const workspaces = fs4__default.default.readdirSync(storagePath);
1602
+ for (const workspace of workspaces) {
1603
+ const workspaceJsonPath = path11__default.default.join(storagePath, workspace, "workspace.json");
1604
+ if (fs4__default.default.existsSync(workspaceJsonPath)) {
1605
+ try {
1606
+ const content = fs4__default.default.readFileSync(workspaceJsonPath, "utf-8");
1607
+ const data = JSON.parse(content);
1608
+ if (data.folder && typeof data.folder === "string") {
1609
+ let projectPath = data.folder;
1610
+ if (projectPath.startsWith("file://")) {
1611
+ projectPath = projectPath.replace("file://", "");
1612
+ projectPath = decodeURIComponent(projectPath);
1613
+ }
1614
+ if (fs4__default.default.existsSync(projectPath) && fs4__default.default.statSync(projectPath).isDirectory()) {
1615
+ projects.push({
1616
+ name: path11__default.default.basename(projectPath),
1617
+ path: projectPath,
1618
+ type: ide
1619
+ });
1620
+ }
1621
+ }
1622
+ } catch (err) {
1623
+ console.debug(`Error reading workspace.json at ${workspaceJsonPath}: ${err}`);
1624
+ }
1625
+ }
1626
+ }
1627
+ } catch (err) {
1628
+ console.debug(`Error scanning workspaceStorage for ${ide}: ${err}`);
1629
+ }
1630
+ return projects;
1631
+ }
1632
+ var scanIdeProjects = async () => {
1633
+ try {
1634
+ const allProjects = [];
1635
+ const seenPaths = /* @__PURE__ */ new Set();
1636
+ const addProject = (projectPath, ide) => {
1637
+ try {
1638
+ const resolvedPath = fs4__default.default.realpathSync(projectPath);
1639
+ if (fs4__default.default.existsSync(resolvedPath) && fs4__default.default.statSync(resolvedPath).isDirectory() && !seenPaths.has(resolvedPath)) {
1640
+ const isIdeProjectsDir = Object.values(IDE_PROJECTS_PATHS).some((ideDir) => {
1641
+ try {
1642
+ return fs4__default.default.realpathSync(ideDir) === resolvedPath;
1643
+ } catch {
1644
+ return false;
1645
+ }
1646
+ });
1647
+ if (!isIdeProjectsDir) {
1648
+ seenPaths.add(resolvedPath);
1649
+ allProjects.push({
1650
+ name: path11__default.default.basename(resolvedPath),
1651
+ path: resolvedPath,
1652
+ type: ide
1653
+ });
1654
+ }
1655
+ }
1656
+ } catch {
1657
+ }
1658
+ };
1659
+ const cursorProjects = scanWorkspaceStorage("cursor");
1660
+ for (const project of cursorProjects) {
1661
+ addProject(project.path, "cursor");
1662
+ }
1663
+ for (const [ide, dirPath] of Object.entries(IDE_PROJECTS_PATHS)) {
1664
+ if (ide === "cursor") continue;
1665
+ if (fs4__default.default.existsSync(dirPath)) {
1666
+ const projects = fs4__default.default.readdirSync(dirPath);
1667
+ projects.forEach((project) => {
1668
+ const projectPath = path11__default.default.join(dirPath, project);
1669
+ try {
1670
+ const stats = fs4__default.default.lstatSync(projectPath);
1671
+ let actualPath = null;
1672
+ if (stats.isSymbolicLink()) {
1673
+ actualPath = fs4__default.default.realpathSync(projectPath);
1674
+ } else if (stats.isFile()) {
1675
+ try {
1676
+ let content = fs4__default.default.readFileSync(projectPath, "utf-8").trim();
1677
+ if (content.startsWith("~/") || content === "~") {
1678
+ content = content.replace(/^~/, HOME);
1679
+ }
1680
+ const resolvedContent = path11__default.default.isAbsolute(content) ? content : path11__default.default.resolve(path11__default.default.dirname(projectPath), content);
1681
+ if (fs4__default.default.existsSync(resolvedContent) && fs4__default.default.statSync(resolvedContent).isDirectory()) {
1682
+ actualPath = fs4__default.default.realpathSync(resolvedContent);
1683
+ }
1684
+ } catch {
1685
+ return;
1686
+ }
1687
+ } else if (stats.isDirectory()) {
1688
+ actualPath = fs4__default.default.realpathSync(projectPath);
1689
+ }
1690
+ if (actualPath) {
1691
+ addProject(actualPath, ide);
1692
+ }
1693
+ } catch {
1694
+ }
1695
+ });
1696
+ }
1697
+ }
1698
+ return allProjects;
1699
+ } catch (error) {
1700
+ console.debug(`Error scanning IDE projects: ${error}`);
1701
+ return [];
1702
+ }
1703
+ };
1704
+
1705
+ // src/lib/rpc-handlers.ts
1706
+ var rpcHandlers = {
1707
+ "daemon:get_workspace_folders": async () => {
1708
+ const projects = projectRegistry.list();
1709
+ return {
1710
+ folders: projects.map((p) => ({
1711
+ id: p.id,
1712
+ cwd: p.cwd,
1713
+ name: p.name,
1714
+ active: p.active
1715
+ }))
1716
+ };
1717
+ },
1718
+ "daemon:get_environment": async ({ gitRepositoryUrl }) => {
1719
+ const projects = projectRegistry.list();
1720
+ if (projects.length === 0) {
1721
+ const error = {
1722
+ _tag: "ProjectUnlinkedError",
1723
+ message: `Getting a local project by git repository URL "${gitRepositoryUrl}" returned an unlinked project. Please link it by running \`amai link <project name> <path to project directory>\``
1724
+ };
1725
+ throw error;
1726
+ }
1727
+ return {
1728
+ project: projects[0],
1729
+ env: {
1730
+ platform: process.platform,
1731
+ arch: process.arch,
1732
+ nodeVersion: process.version
1733
+ }
1734
+ };
1735
+ },
1736
+ "daemon:get_context": async ({ cwd }) => {
1737
+ try {
1738
+ const files = getContext(cwd);
1739
+ return { files, cwd };
1740
+ } catch (error) {
1741
+ const rpcError = {
1742
+ _tag: "ContextError",
1743
+ message: error.message || "Failed to get context"
1744
+ };
1745
+ throw rpcError;
1746
+ }
1747
+ },
1748
+ "daemon:get_ide_projects": async () => {
1749
+ const projects = await scanIdeProjects();
1750
+ return { projects };
1751
+ },
1752
+ "daemon:register_project": async ({ projectId, cwd, name }) => {
1753
+ if (!projectId || !cwd) {
1754
+ const error = {
1755
+ _tag: "ValidationError",
1756
+ message: "projectId and cwd are required"
1757
+ };
1758
+ throw error;
1759
+ }
1760
+ projectRegistry.register(projectId, cwd, name);
1761
+ return { success: true, projectId, cwd };
1762
+ },
1763
+ "daemon:unregister_project": async ({ projectId }) => {
1764
+ if (!projectId) {
1765
+ const error = {
1766
+ _tag: "ValidationError",
1767
+ message: "projectId is required"
1768
+ };
1769
+ throw error;
1770
+ }
1771
+ projectRegistry.unregister(projectId);
1772
+ return { success: true, projectId };
1773
+ },
1774
+ "daemon:get_project": async ({ projectId }) => {
1775
+ const project = projectRegistry.getProject(projectId);
1776
+ if (!project) {
1777
+ const error = {
1778
+ _tag: "ProjectNotFoundError",
1779
+ message: `Project not found: ${projectId}`
1780
+ };
1781
+ throw error;
1782
+ }
1783
+ return { project };
1784
+ },
1785
+ "daemon:list_projects": async () => {
1786
+ const projects = projectRegistry.list();
1787
+ return { projects };
1788
+ },
1789
+ "daemon:status": async () => {
1790
+ return {
1791
+ connected: true,
1792
+ timestamp: Date.now(),
1793
+ platform: process.platform,
1794
+ arch: process.arch
1795
+ };
1796
+ }
1797
+ };
1798
+ var reconnectTimeout = null;
1799
+ var connectToUserStreams = async (serverUrl) => {
1800
+ const userId = getUserId();
1801
+ if (!userId?.userId) {
1802
+ throw new Error("User ID not found");
1803
+ }
1804
+ const params = new URLSearchParams({
1805
+ userId: userId.userId,
1806
+ type: "cli"
1807
+ });
1808
+ const tokens = getTokens();
1809
+ if (!tokens) {
1810
+ throw new Error("No tokens found");
1811
+ }
1812
+ const wsUrl = `${serverUrl}/api/v1/user-streams?${params.toString()}`;
1813
+ const ws = new WebSocket__default.default(wsUrl, {
1814
+ headers: {
1815
+ Authorization: `Bearer ${tokens.access_token}`
1816
+ }
1817
+ });
1818
+ ws.on("open", () => {
1819
+ console.log(pc2__default.default.green("CLI connected to user-streams"));
1820
+ if (reconnectTimeout) {
1821
+ clearTimeout(reconnectTimeout);
1822
+ reconnectTimeout = null;
1823
+ }
1824
+ });
1825
+ ws.on("message", async (event) => {
1826
+ try {
1827
+ const message = JSON.parse(event.toString());
1828
+ if (message._tag === "rpc_call") {
1829
+ const { requestId, method, input } = message;
1830
+ console.log(pc2__default.default.gray(`RPC call: ${method}`));
1831
+ const handler = rpcHandlers[method];
1832
+ if (!handler) {
1833
+ ws.send(JSON.stringify({
1834
+ _tag: "rpc_result",
1835
+ requestId,
1836
+ data: {
1837
+ _tag: "UnknownMethodError",
1838
+ message: `Unknown RPC method: ${method}`
1839
+ }
1840
+ }));
1841
+ console.log(pc2__default.default.yellow(`Unknown RPC method: ${method}`));
1842
+ return;
1843
+ }
1844
+ try {
1845
+ const result = await handler(input || {});
1846
+ ws.send(JSON.stringify({
1847
+ _tag: "rpc_result",
1848
+ requestId,
1849
+ data: result
1850
+ }));
1851
+ console.log(pc2__default.default.green(`RPC completed: ${method}`));
1852
+ } catch (error) {
1853
+ const rpcError = error._tag ? error : {
1854
+ _tag: "RpcError",
1855
+ message: error.message || String(error)
1856
+ };
1857
+ ws.send(JSON.stringify({
1858
+ _tag: "rpc_result",
1859
+ requestId,
1860
+ data: rpcError
1861
+ }));
1862
+ console.log(pc2__default.default.red(`RPC failed: ${method} - ${rpcError.message}`));
1863
+ }
1864
+ return;
1865
+ }
1866
+ if (message.type === "presence_request") {
1867
+ if (message.status === "connected") {
1868
+ ws.send(JSON.stringify({
1869
+ type: "presence_request",
1870
+ status: "connected"
1871
+ }));
1872
+ }
1873
+ if (message.status === "disconnected") {
1874
+ ws.send(JSON.stringify({
1875
+ type: "presence_request",
1876
+ status: "disconnected"
1877
+ }));
1878
+ }
1879
+ }
1880
+ } catch (parseError) {
1881
+ console.error(pc2__default.default.red(`Failed to parse message: ${parseError}`));
1882
+ }
1883
+ });
1884
+ ws.on("close", (code, reason) => {
1885
+ console.log(pc2__default.default.yellow(`CLI disconnected from user-streams (code: ${code})`));
1886
+ console.log(pc2__default.default.gray("Reconnecting in 5 seconds..."));
1887
+ reconnectTimeout = setTimeout(() => {
1888
+ connectToUserStreams(serverUrl).catch((err) => {
1889
+ console.error(pc2__default.default.red(`Reconnection failed: ${err.message}`));
1890
+ });
1891
+ }, 5e3);
1892
+ });
1893
+ ws.on("error", (error) => {
1894
+ console.error(pc2__default.default.red(`User streams WebSocket error: ${error.message}`));
1895
+ });
1896
+ return ws;
1897
+ };
1754
1898
 
1755
1899
  // src/server.ts
1756
- var statusEmitter = new events.EventEmitter();
1757
1900
  var toolExecutors = {
1758
1901
  editFile: editFiles,
1759
1902
  deleteFile,
@@ -1764,10 +1907,7 @@ var toolExecutors = {
1764
1907
  stringReplace: apply_patch,
1765
1908
  runTerminalCommand
1766
1909
  };
1767
- function getConnectionStatus(ws) {
1768
- return ws.readyState === WebSocket__default.default.CONNECTING ? "connecting" : ws.readyState === WebSocket__default.default.OPEN ? "open" : ws.readyState === WebSocket__default.default.CLOSING ? "closing" : "closed";
1769
- }
1770
- function connectToServer2(serverUrl = DEFAULT_SERVER_URL) {
1910
+ function connectToServer(serverUrl = DEFAULT_SERVER_URL) {
1771
1911
  const tokens = getTokens();
1772
1912
  if (!tokens) {
1773
1913
  throw new Error("No tokens found");
@@ -1780,7 +1920,6 @@ function connectToServer2(serverUrl = DEFAULT_SERVER_URL) {
1780
1920
  });
1781
1921
  ws.on("open", () => {
1782
1922
  console.log(pc2__default.default.green("Connected to server agent streams"));
1783
- statusEmitter.emit("status", { connected: true });
1784
1923
  });
1785
1924
  ws.on("message", async (data) => {
1786
1925
  const message = JSON.parse(data.toString());
@@ -1810,12 +1949,10 @@ function connectToServer2(serverUrl = DEFAULT_SERVER_URL) {
1810
1949
  });
1811
1950
  ws.on("close", () => {
1812
1951
  console.log(pc2__default.default.red("Disconnected from server. Reconnecting in 5s..."));
1813
- statusEmitter.emit("status", { connected: false });
1814
- setTimeout(() => connectToServer2(serverUrl), 5e3);
1952
+ setTimeout(() => connectToServer(serverUrl), 5e3);
1815
1953
  });
1816
1954
  ws.on("error", (error) => {
1817
1955
  console.error(pc2__default.default.red(`WebSocket error: ${error.message}`));
1818
- statusEmitter.emit("status", { connected: false });
1819
1956
  });
1820
1957
  return ws;
1821
1958
  }
@@ -1823,8 +1960,9 @@ async function main() {
1823
1960
  const serverUrl = DEFAULT_SERVER_URL;
1824
1961
  console.log(pc2__default.default.green("Starting local amai..."));
1825
1962
  console.log(pc2__default.default.gray(`Connecting to server at ${serverUrl}`));
1826
- const connection = connectToServer2(serverUrl);
1827
- startHttpServer(connection);
1963
+ connectToServer(serverUrl);
1964
+ await connectToUserStreams(serverUrl);
1965
+ startHttpServer();
1828
1966
  }
1829
1967
  var execAsync2 = util.promisify(child_process.exec);
1830
1968
  var CODE_SERVER_VERSION = "4.96.4";
@@ -1853,27 +1991,27 @@ function getDownloadUrl() {
1853
1991
  }
1854
1992
  function getCodeServerDir() {
1855
1993
  const { platform, arch } = getPlatformInfo();
1856
- return path9__default.default.join(CODE_DIR, `code-server-${CODE_SERVER_VERSION}-${platform}-${arch}`);
1994
+ return path11__default.default.join(CODE_DIR, `code-server-${CODE_SERVER_VERSION}-${platform}-${arch}`);
1857
1995
  }
1858
1996
  function getCodeServerBin() {
1859
- return path9__default.default.join(getCodeServerDir(), "bin", "code-server");
1997
+ return path11__default.default.join(getCodeServerDir(), "bin", "code-server");
1860
1998
  }
1861
1999
  function isCodeServerInstalled() {
1862
2000
  const binPath = getCodeServerBin();
1863
- return fs3__default.default.existsSync(binPath);
2001
+ return fs4__default.default.existsSync(binPath);
1864
2002
  }
1865
2003
  async function installCodeServer() {
1866
2004
  const { ext } = getPlatformInfo();
1867
2005
  const downloadUrl = getDownloadUrl();
1868
- const tarballPath = path9__default.default.join(AMA_DIR, `code-server.${ext}`);
1869
- if (!fs3__default.default.existsSync(AMA_DIR)) {
1870
- fs3__default.default.mkdirSync(AMA_DIR, { recursive: true });
2006
+ const tarballPath = path11__default.default.join(AMA_DIR, `code-server.${ext}`);
2007
+ if (!fs4__default.default.existsSync(AMA_DIR)) {
2008
+ fs4__default.default.mkdirSync(AMA_DIR, { recursive: true });
1871
2009
  }
1872
- if (!fs3__default.default.existsSync(CODE_DIR)) {
1873
- fs3__default.default.mkdirSync(CODE_DIR, { recursive: true });
2010
+ if (!fs4__default.default.existsSync(CODE_DIR)) {
2011
+ fs4__default.default.mkdirSync(CODE_DIR, { recursive: true });
1874
2012
  }
1875
- if (!fs3__default.default.existsSync(STORAGE_DIR)) {
1876
- fs3__default.default.mkdirSync(STORAGE_DIR, { recursive: true });
2013
+ if (!fs4__default.default.existsSync(STORAGE_DIR)) {
2014
+ fs4__default.default.mkdirSync(STORAGE_DIR, { recursive: true });
1877
2015
  }
1878
2016
  console.log(pc2__default.default.cyan(`Downloading code-server v${CODE_SERVER_VERSION}...`));
1879
2017
  console.log(pc2__default.default.gray(downloadUrl));
@@ -1882,13 +2020,13 @@ async function installCodeServer() {
1882
2020
  throw new Error(`Failed to download code-server: ${response.statusText}`);
1883
2021
  }
1884
2022
  const buffer = await response.arrayBuffer();
1885
- await fs3__default.default.promises.writeFile(tarballPath, Buffer.from(buffer));
2023
+ await fs4__default.default.promises.writeFile(tarballPath, Buffer.from(buffer));
1886
2024
  console.log(pc2__default.default.cyan("Extracting code-server..."));
1887
2025
  await execAsync2(`tar -xzf ${tarballPath} -C ${CODE_DIR}`);
1888
- await fs3__default.default.promises.unlink(tarballPath);
2026
+ await fs4__default.default.promises.unlink(tarballPath);
1889
2027
  const binPath = getCodeServerBin();
1890
- if (fs3__default.default.existsSync(binPath)) {
1891
- await fs3__default.default.promises.chmod(binPath, 493);
2028
+ if (fs4__default.default.existsSync(binPath)) {
2029
+ await fs4__default.default.promises.chmod(binPath, 493);
1892
2030
  }
1893
2031
  console.log(pc2__default.default.green("\u2713 code-server installed successfully"));
1894
2032
  }
@@ -1913,19 +2051,19 @@ async function killExistingCodeServer() {
1913
2051
  async function startCodeServer(cwd) {
1914
2052
  const binPath = getCodeServerBin();
1915
2053
  const workDir = cwd || process.cwd();
1916
- if (!fs3__default.default.existsSync(binPath)) {
2054
+ if (!fs4__default.default.existsSync(binPath)) {
1917
2055
  throw new Error("code-server is not installed. Run installCodeServer() first.");
1918
2056
  }
1919
2057
  await killExistingCodeServer();
1920
- const workspaceStoragePath = path9__default.default.join(STORAGE_DIR, "User", "workspaceStorage");
1921
- path9__default.default.join(STORAGE_DIR, "User", "globalStorage");
2058
+ const workspaceStoragePath = path11__default.default.join(STORAGE_DIR, "User", "workspaceStorage");
2059
+ path11__default.default.join(STORAGE_DIR, "User", "globalStorage");
1922
2060
  try {
1923
- if (fs3__default.default.existsSync(workspaceStoragePath)) {
1924
- await fs3__default.default.promises.rm(workspaceStoragePath, { recursive: true, force: true });
2061
+ if (fs4__default.default.existsSync(workspaceStoragePath)) {
2062
+ await fs4__default.default.promises.rm(workspaceStoragePath, { recursive: true, force: true });
1925
2063
  }
1926
- const stateDbPath = path9__default.default.join(STORAGE_DIR, "User", "globalStorage", "state.vscdb");
1927
- if (fs3__default.default.existsSync(stateDbPath)) {
1928
- await fs3__default.default.promises.unlink(stateDbPath);
2064
+ const stateDbPath = path11__default.default.join(STORAGE_DIR, "User", "globalStorage", "state.vscdb");
2065
+ if (fs4__default.default.existsSync(stateDbPath)) {
2066
+ await fs4__default.default.promises.unlink(stateDbPath);
1929
2067
  }
1930
2068
  } catch {
1931
2069
  }
@@ -1965,7 +2103,7 @@ if (process.env.AMA_DAEMON === "1") {
1965
2103
  }
1966
2104
  if (isCodeServerInstalled()) {
1967
2105
  try {
1968
- const projectDir = process.cwd() || os2__default.default.homedir();
2106
+ const projectDir = process.cwd() || os3__default.default.homedir();
1969
2107
  await startCodeServer(projectDir);
1970
2108
  } catch (error) {
1971
2109
  console.error(pc2__default.default.red(`Failed to start code-server: ${error.message}`));