amai 0.0.2 → 0.0.4

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 CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  var pc4 = require('picocolors');
5
5
  var WebSocket = require('ws');
6
+ var events = require('events');
6
7
  var zod = require('zod');
7
8
  var promises = require('fs/promises');
8
9
  var path9 = require('path');
@@ -1261,10 +1262,50 @@ var startHttpServer = (connection) => {
1261
1262
  }
1262
1263
  const app = new hono.Hono();
1263
1264
  app.use(cors.cors());
1264
- app.post("/daemon/status/stream", (c) => {
1265
+ app.post("/daemon/status", (c) => {
1265
1266
  const status = wsConnection ? getConnectionStatus(wsConnection) : "closed";
1266
1267
  return c.json({ connected: status === "open" });
1267
1268
  });
1269
+ app.get("/daemon/status/stream", (c) => {
1270
+ const encoder = new TextEncoder();
1271
+ const stream = new ReadableStream({
1272
+ start(controller) {
1273
+ const initialStatus = wsConnection ? getConnectionStatus(wsConnection) : "closed";
1274
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify({ connected: initialStatus === "open" })}
1275
+
1276
+ `));
1277
+ const statusHandler = (data) => {
1278
+ try {
1279
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}
1280
+
1281
+ `));
1282
+ } catch {
1283
+ }
1284
+ };
1285
+ statusEmitter.on("status", statusHandler);
1286
+ const heartbeatInterval = setInterval(() => {
1287
+ try {
1288
+ const currentStatus = wsConnection ? getConnectionStatus(wsConnection) : "closed";
1289
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify({ connected: currentStatus === "open" })}
1290
+
1291
+ `));
1292
+ } catch {
1293
+ }
1294
+ }, 15e3);
1295
+ c.req.raw.signal.addEventListener("abort", () => {
1296
+ statusEmitter.off("status", statusHandler);
1297
+ clearInterval(heartbeatInterval);
1298
+ });
1299
+ }
1300
+ });
1301
+ return new Response(stream, {
1302
+ headers: {
1303
+ "Content-Type": "text/event-stream",
1304
+ "Cache-Control": "no-cache",
1305
+ "Connection": "keep-alive"
1306
+ }
1307
+ });
1308
+ });
1268
1309
  app.get("context", async (c) => {
1269
1310
  const context = getContext(process.cwd());
1270
1311
  return c.body(JSON.stringify(context));
@@ -1506,8 +1547,96 @@ async function login() {
1506
1547
  throw error;
1507
1548
  }
1508
1549
  }
1550
+ var ExplanationSchema = zod.z.object({
1551
+ explanation: zod.z.string().describe("One sentence explanation as to why this tool is being used")
1552
+ });
1553
+ zod.z.object({
1554
+ command: zod.z.string().describe("The terminal command to execute"),
1555
+ is_background: zod.z.boolean().describe("Whether the command should be run in the background")
1556
+ }).merge(ExplanationSchema);
1557
+ var runSecureTerminalCommand = async (command, timeout) => {
1558
+ try {
1559
+ return new Promise((resolve, reject) => {
1560
+ const child = child_process.spawn(command, {
1561
+ cwd: process.cwd(),
1562
+ stdio: ["pipe", "pipe", "pipe"],
1563
+ shell: true
1564
+ });
1565
+ let stdout = "";
1566
+ let stderr = "";
1567
+ let timeoutId = null;
1568
+ if (timeoutId > 0) {
1569
+ timeoutId = setTimeout(() => {
1570
+ child.kill("SIGKILL");
1571
+ reject(new Error(`Command timed out after ${timeout}ms`));
1572
+ }, timeout);
1573
+ }
1574
+ child.stdout?.on("data", (data) => {
1575
+ stdout += data.toString();
1576
+ });
1577
+ child.stderr?.on("data", (data) => {
1578
+ stderr += data.toString();
1579
+ });
1580
+ child.stdout.on("close", (code) => {
1581
+ if (timeoutId) {
1582
+ clearTimeout(timeoutId);
1583
+ }
1584
+ resolve({ stdout, stderr, exitCode: code || 0 });
1585
+ });
1586
+ child.stderr.on("error", (error) => {
1587
+ if (timeoutId) {
1588
+ clearTimeout(timeoutId);
1589
+ }
1590
+ reject(error);
1591
+ });
1592
+ });
1593
+ } catch {
1594
+ console.error("Error while ecexuting the securedShell command");
1595
+ }
1596
+ };
1597
+ var runTerminalCommand = async (input, projectCwd) => {
1598
+ try {
1599
+ if (input?.is_background) {
1600
+ const child = child_process.spawn(input.command, {
1601
+ cwd: projectCwd,
1602
+ detached: true,
1603
+ stdio: "ignore",
1604
+ shell: true
1605
+ });
1606
+ child.unref();
1607
+ console.log(`[LOCAL] Background command started: ${input.command}`);
1608
+ return {
1609
+ success: true,
1610
+ message: `Background command started: ${input.command}`,
1611
+ isBackground: true
1612
+ };
1613
+ } else {
1614
+ const result = await runSecureTerminalCommand(
1615
+ input.command,
1616
+ 3e4
1617
+ // 30 second timeout
1618
+ );
1619
+ const success = result?.exitCode === 0;
1620
+ return {
1621
+ success,
1622
+ stdout: result?.stdout?.trim(),
1623
+ stderr: result?.stderr?.trim(),
1624
+ exitCode: result?.exitCode,
1625
+ message: success ? `Command executed successfully: ${input.command}` : `Command failed with exit code ${result?.exitCode}: ${input.command}`
1626
+ };
1627
+ }
1628
+ } catch (error) {
1629
+ console.error("Error while executing the terminal command", error);
1630
+ return {
1631
+ success: false,
1632
+ message: "Error while executing the terminal command",
1633
+ error: error.message
1634
+ };
1635
+ }
1636
+ };
1509
1637
 
1510
1638
  // src/server.ts
1639
+ var statusEmitter = new events.EventEmitter();
1511
1640
  var toolExecutors = {
1512
1641
  editFile: editFiles,
1513
1642
  deleteFile,
@@ -1515,7 +1644,8 @@ var toolExecutors = {
1515
1644
  glob: globTool,
1516
1645
  listDirectory: list,
1517
1646
  readFile: read_file,
1518
- stringReplace: apply_patch
1647
+ stringReplace: apply_patch,
1648
+ runTerminalCommand
1519
1649
  };
1520
1650
  function getConnectionStatus(ws) {
1521
1651
  return ws.readyState === WebSocket__default.default.CONNECTING ? "connecting" : ws.readyState === WebSocket__default.default.OPEN ? "open" : ws.readyState === WebSocket__default.default.CLOSING ? "closing" : "closed";
@@ -1533,6 +1663,7 @@ function connectToServer2(serverUrl = DEFAULT_SERVER_URL) {
1533
1663
  });
1534
1664
  ws.on("open", () => {
1535
1665
  console.log(pc4__default.default.green("Connected to server agent streams"));
1666
+ statusEmitter.emit("status", { connected: true });
1536
1667
  });
1537
1668
  ws.on("message", async (data) => {
1538
1669
  const message = JSON.parse(data.toString());
@@ -1562,10 +1693,12 @@ function connectToServer2(serverUrl = DEFAULT_SERVER_URL) {
1562
1693
  });
1563
1694
  ws.on("close", () => {
1564
1695
  console.log(pc4__default.default.red("Disconnected from server. Reconnecting in 5s..."));
1696
+ statusEmitter.emit("status", { connected: false });
1565
1697
  setTimeout(() => connectToServer2(serverUrl), 5e3);
1566
1698
  });
1567
1699
  ws.on("error", (error) => {
1568
1700
  console.error(pc4__default.default.red(`WebSocket error: ${error.message}`));
1701
+ statusEmitter.emit("status", { connected: false });
1569
1702
  });
1570
1703
  return ws;
1571
1704
  }
@@ -1762,7 +1895,7 @@ function getDaemonPid() {
1762
1895
  return null;
1763
1896
  }
1764
1897
  }
1765
- var VERSION = "0.0.2";
1898
+ var VERSION = "0.0.4";
1766
1899
  var PROJECT_DIR = process.cwd();
1767
1900
  function promptUser(question) {
1768
1901
  const rl = readline__default.default.createInterface({
package/dist/cli.js CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import pc4 from 'picocolors';
3
3
  import WebSocket from 'ws';
4
+ import { EventEmitter } from 'events';
4
5
  import { z } from 'zod';
5
6
  import { readFile, writeFile, stat, access, readdir, glob, unlink, mkdir } from 'fs/promises';
6
7
  import path9, { dirname } from 'path';
@@ -1249,10 +1250,50 @@ var startHttpServer = (connection) => {
1249
1250
  }
1250
1251
  const app = new Hono();
1251
1252
  app.use(cors());
1252
- app.post("/daemon/status/stream", (c) => {
1253
+ app.post("/daemon/status", (c) => {
1253
1254
  const status = wsConnection ? getConnectionStatus(wsConnection) : "closed";
1254
1255
  return c.json({ connected: status === "open" });
1255
1256
  });
1257
+ app.get("/daemon/status/stream", (c) => {
1258
+ const encoder = new TextEncoder();
1259
+ const stream = new ReadableStream({
1260
+ start(controller) {
1261
+ const initialStatus = wsConnection ? getConnectionStatus(wsConnection) : "closed";
1262
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify({ connected: initialStatus === "open" })}
1263
+
1264
+ `));
1265
+ const statusHandler = (data) => {
1266
+ try {
1267
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}
1268
+
1269
+ `));
1270
+ } catch {
1271
+ }
1272
+ };
1273
+ statusEmitter.on("status", statusHandler);
1274
+ const heartbeatInterval = setInterval(() => {
1275
+ try {
1276
+ const currentStatus = wsConnection ? getConnectionStatus(wsConnection) : "closed";
1277
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify({ connected: currentStatus === "open" })}
1278
+
1279
+ `));
1280
+ } catch {
1281
+ }
1282
+ }, 15e3);
1283
+ c.req.raw.signal.addEventListener("abort", () => {
1284
+ statusEmitter.off("status", statusHandler);
1285
+ clearInterval(heartbeatInterval);
1286
+ });
1287
+ }
1288
+ });
1289
+ return new Response(stream, {
1290
+ headers: {
1291
+ "Content-Type": "text/event-stream",
1292
+ "Cache-Control": "no-cache",
1293
+ "Connection": "keep-alive"
1294
+ }
1295
+ });
1296
+ });
1256
1297
  app.get("context", async (c) => {
1257
1298
  const context = getContext(process.cwd());
1258
1299
  return c.body(JSON.stringify(context));
@@ -1494,8 +1535,96 @@ async function login() {
1494
1535
  throw error;
1495
1536
  }
1496
1537
  }
1538
+ var ExplanationSchema = z.object({
1539
+ explanation: z.string().describe("One sentence explanation as to why this tool is being used")
1540
+ });
1541
+ z.object({
1542
+ command: z.string().describe("The terminal command to execute"),
1543
+ is_background: z.boolean().describe("Whether the command should be run in the background")
1544
+ }).merge(ExplanationSchema);
1545
+ var runSecureTerminalCommand = async (command, timeout) => {
1546
+ try {
1547
+ return new Promise((resolve, reject) => {
1548
+ const child = spawn(command, {
1549
+ cwd: process.cwd(),
1550
+ stdio: ["pipe", "pipe", "pipe"],
1551
+ shell: true
1552
+ });
1553
+ let stdout = "";
1554
+ let stderr = "";
1555
+ let timeoutId = null;
1556
+ if (timeoutId > 0) {
1557
+ timeoutId = setTimeout(() => {
1558
+ child.kill("SIGKILL");
1559
+ reject(new Error(`Command timed out after ${timeout}ms`));
1560
+ }, timeout);
1561
+ }
1562
+ child.stdout?.on("data", (data) => {
1563
+ stdout += data.toString();
1564
+ });
1565
+ child.stderr?.on("data", (data) => {
1566
+ stderr += data.toString();
1567
+ });
1568
+ child.stdout.on("close", (code) => {
1569
+ if (timeoutId) {
1570
+ clearTimeout(timeoutId);
1571
+ }
1572
+ resolve({ stdout, stderr, exitCode: code || 0 });
1573
+ });
1574
+ child.stderr.on("error", (error) => {
1575
+ if (timeoutId) {
1576
+ clearTimeout(timeoutId);
1577
+ }
1578
+ reject(error);
1579
+ });
1580
+ });
1581
+ } catch {
1582
+ console.error("Error while ecexuting the securedShell command");
1583
+ }
1584
+ };
1585
+ var runTerminalCommand = async (input, projectCwd) => {
1586
+ try {
1587
+ if (input?.is_background) {
1588
+ const child = spawn(input.command, {
1589
+ cwd: projectCwd,
1590
+ detached: true,
1591
+ stdio: "ignore",
1592
+ shell: true
1593
+ });
1594
+ child.unref();
1595
+ console.log(`[LOCAL] Background command started: ${input.command}`);
1596
+ return {
1597
+ success: true,
1598
+ message: `Background command started: ${input.command}`,
1599
+ isBackground: true
1600
+ };
1601
+ } else {
1602
+ const result = await runSecureTerminalCommand(
1603
+ input.command,
1604
+ 3e4
1605
+ // 30 second timeout
1606
+ );
1607
+ const success = result?.exitCode === 0;
1608
+ return {
1609
+ success,
1610
+ stdout: result?.stdout?.trim(),
1611
+ stderr: result?.stderr?.trim(),
1612
+ exitCode: result?.exitCode,
1613
+ message: success ? `Command executed successfully: ${input.command}` : `Command failed with exit code ${result?.exitCode}: ${input.command}`
1614
+ };
1615
+ }
1616
+ } catch (error) {
1617
+ console.error("Error while executing the terminal command", error);
1618
+ return {
1619
+ success: false,
1620
+ message: "Error while executing the terminal command",
1621
+ error: error.message
1622
+ };
1623
+ }
1624
+ };
1497
1625
 
1498
1626
  // src/server.ts
1627
+ var statusEmitter = new EventEmitter();
1499
1628
  var toolExecutors = {
1500
1629
  editFile: editFiles,
1501
1630
  deleteFile,
@@ -1503,7 +1632,8 @@ var toolExecutors = {
1503
1632
  glob: globTool,
1504
1633
  listDirectory: list,
1505
1634
  readFile: read_file,
1506
- stringReplace: apply_patch
1635
+ stringReplace: apply_patch,
1636
+ runTerminalCommand
1507
1637
  };
1508
1638
  function getConnectionStatus(ws) {
1509
1639
  return ws.readyState === WebSocket.CONNECTING ? "connecting" : ws.readyState === WebSocket.OPEN ? "open" : ws.readyState === WebSocket.CLOSING ? "closing" : "closed";
@@ -1521,6 +1651,7 @@ function connectToServer2(serverUrl = DEFAULT_SERVER_URL) {
1521
1651
  });
1522
1652
  ws.on("open", () => {
1523
1653
  console.log(pc4.green("Connected to server agent streams"));
1654
+ statusEmitter.emit("status", { connected: true });
1524
1655
  });
1525
1656
  ws.on("message", async (data) => {
1526
1657
  const message = JSON.parse(data.toString());
@@ -1550,10 +1681,12 @@ function connectToServer2(serverUrl = DEFAULT_SERVER_URL) {
1550
1681
  });
1551
1682
  ws.on("close", () => {
1552
1683
  console.log(pc4.red("Disconnected from server. Reconnecting in 5s..."));
1684
+ statusEmitter.emit("status", { connected: false });
1553
1685
  setTimeout(() => connectToServer2(serverUrl), 5e3);
1554
1686
  });
1555
1687
  ws.on("error", (error) => {
1556
1688
  console.error(pc4.red(`WebSocket error: ${error.message}`));
1689
+ statusEmitter.emit("status", { connected: false });
1557
1690
  });
1558
1691
  return ws;
1559
1692
  }
@@ -1750,7 +1883,7 @@ function getDaemonPid() {
1750
1883
  return null;
1751
1884
  }
1752
1885
  }
1753
- var VERSION = "0.0.2";
1886
+ var VERSION = "0.0.4";
1754
1887
  var PROJECT_DIR = process.cwd();
1755
1888
  function promptUser(question) {
1756
1889
  const rl = readline.createInterface({
@@ -2,6 +2,7 @@
2
2
  'use strict';
3
3
 
4
4
  var WebSocket = require('ws');
5
+ var events = require('events');
5
6
  var zod = require('zod');
6
7
  var promises = require('fs/promises');
7
8
  var path9 = require('path');
@@ -1256,10 +1257,50 @@ var startHttpServer = (connection) => {
1256
1257
  }
1257
1258
  const app = new hono.Hono();
1258
1259
  app.use(cors.cors());
1259
- app.post("/daemon/status/stream", (c) => {
1260
+ app.post("/daemon/status", (c) => {
1260
1261
  const status = wsConnection ? getConnectionStatus(wsConnection) : "closed";
1261
1262
  return c.json({ connected: status === "open" });
1262
1263
  });
1264
+ app.get("/daemon/status/stream", (c) => {
1265
+ const encoder = new TextEncoder();
1266
+ const stream = new ReadableStream({
1267
+ start(controller) {
1268
+ const initialStatus = wsConnection ? getConnectionStatus(wsConnection) : "closed";
1269
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify({ connected: initialStatus === "open" })}
1270
+
1271
+ `));
1272
+ const statusHandler = (data) => {
1273
+ try {
1274
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}
1275
+
1276
+ `));
1277
+ } catch {
1278
+ }
1279
+ };
1280
+ statusEmitter.on("status", statusHandler);
1281
+ const heartbeatInterval = setInterval(() => {
1282
+ try {
1283
+ const currentStatus = wsConnection ? getConnectionStatus(wsConnection) : "closed";
1284
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify({ connected: currentStatus === "open" })}
1285
+
1286
+ `));
1287
+ } catch {
1288
+ }
1289
+ }, 15e3);
1290
+ c.req.raw.signal.addEventListener("abort", () => {
1291
+ statusEmitter.off("status", statusHandler);
1292
+ clearInterval(heartbeatInterval);
1293
+ });
1294
+ }
1295
+ });
1296
+ return new Response(stream, {
1297
+ headers: {
1298
+ "Content-Type": "text/event-stream",
1299
+ "Cache-Control": "no-cache",
1300
+ "Connection": "keep-alive"
1301
+ }
1302
+ });
1303
+ });
1263
1304
  app.get("context", async (c) => {
1264
1305
  const context = getContext(process.cwd());
1265
1306
  return c.body(JSON.stringify(context));
@@ -1361,8 +1402,96 @@ function getTokens() {
1361
1402
  const data = JSON.parse(raw);
1362
1403
  return data;
1363
1404
  }
1405
+ var ExplanationSchema = zod.z.object({
1406
+ explanation: zod.z.string().describe("One sentence explanation as to why this tool is being used")
1407
+ });
1408
+ zod.z.object({
1409
+ command: zod.z.string().describe("The terminal command to execute"),
1410
+ is_background: zod.z.boolean().describe("Whether the command should be run in the background")
1411
+ }).merge(ExplanationSchema);
1412
+ var runSecureTerminalCommand = async (command, timeout) => {
1413
+ try {
1414
+ return new Promise((resolve, reject) => {
1415
+ const child = child_process.spawn(command, {
1416
+ cwd: process.cwd(),
1417
+ stdio: ["pipe", "pipe", "pipe"],
1418
+ shell: true
1419
+ });
1420
+ let stdout = "";
1421
+ let stderr = "";
1422
+ let timeoutId = null;
1423
+ if (timeoutId > 0) {
1424
+ timeoutId = setTimeout(() => {
1425
+ child.kill("SIGKILL");
1426
+ reject(new Error(`Command timed out after ${timeout}ms`));
1427
+ }, timeout);
1428
+ }
1429
+ child.stdout?.on("data", (data) => {
1430
+ stdout += data.toString();
1431
+ });
1432
+ child.stderr?.on("data", (data) => {
1433
+ stderr += data.toString();
1434
+ });
1435
+ child.stdout.on("close", (code) => {
1436
+ if (timeoutId) {
1437
+ clearTimeout(timeoutId);
1438
+ }
1439
+ resolve({ stdout, stderr, exitCode: code || 0 });
1440
+ });
1441
+ child.stderr.on("error", (error) => {
1442
+ if (timeoutId) {
1443
+ clearTimeout(timeoutId);
1444
+ }
1445
+ reject(error);
1446
+ });
1447
+ });
1448
+ } catch {
1449
+ console.error("Error while ecexuting the securedShell command");
1450
+ }
1451
+ };
1452
+ var runTerminalCommand = async (input, projectCwd) => {
1453
+ try {
1454
+ if (input?.is_background) {
1455
+ const child = child_process.spawn(input.command, {
1456
+ cwd: projectCwd,
1457
+ detached: true,
1458
+ stdio: "ignore",
1459
+ shell: true
1460
+ });
1461
+ child.unref();
1462
+ console.log(`[LOCAL] Background command started: ${input.command}`);
1463
+ return {
1464
+ success: true,
1465
+ message: `Background command started: ${input.command}`,
1466
+ isBackground: true
1467
+ };
1468
+ } else {
1469
+ const result = await runSecureTerminalCommand(
1470
+ input.command,
1471
+ 3e4
1472
+ // 30 second timeout
1473
+ );
1474
+ const success = result?.exitCode === 0;
1475
+ return {
1476
+ success,
1477
+ stdout: result?.stdout?.trim(),
1478
+ stderr: result?.stderr?.trim(),
1479
+ exitCode: result?.exitCode,
1480
+ message: success ? `Command executed successfully: ${input.command}` : `Command failed with exit code ${result?.exitCode}: ${input.command}`
1481
+ };
1482
+ }
1483
+ } catch (error) {
1484
+ console.error("Error while executing the terminal command", error);
1485
+ return {
1486
+ success: false,
1487
+ message: "Error while executing the terminal command",
1488
+ error: error.message
1489
+ };
1490
+ }
1491
+ };
1364
1492
 
1365
1493
  // src/server.ts
1494
+ var statusEmitter = new events.EventEmitter();
1366
1495
  var toolExecutors = {
1367
1496
  editFile: editFiles,
1368
1497
  deleteFile,
@@ -1370,7 +1499,8 @@ var toolExecutors = {
1370
1499
  glob: globTool,
1371
1500
  listDirectory: list,
1372
1501
  readFile: read_file,
1373
- stringReplace: apply_patch
1502
+ stringReplace: apply_patch,
1503
+ runTerminalCommand
1374
1504
  };
1375
1505
  function getConnectionStatus(ws) {
1376
1506
  return ws.readyState === WebSocket__default.default.CONNECTING ? "connecting" : ws.readyState === WebSocket__default.default.OPEN ? "open" : ws.readyState === WebSocket__default.default.CLOSING ? "closing" : "closed";
@@ -1388,6 +1518,7 @@ function connectToServer2(serverUrl = DEFAULT_SERVER_URL) {
1388
1518
  });
1389
1519
  ws.on("open", () => {
1390
1520
  console.log(pc2__default.default.green("Connected to server agent streams"));
1521
+ statusEmitter.emit("status", { connected: true });
1391
1522
  });
1392
1523
  ws.on("message", async (data) => {
1393
1524
  const message = JSON.parse(data.toString());
@@ -1417,10 +1548,12 @@ function connectToServer2(serverUrl = DEFAULT_SERVER_URL) {
1417
1548
  });
1418
1549
  ws.on("close", () => {
1419
1550
  console.log(pc2__default.default.red("Disconnected from server. Reconnecting in 5s..."));
1551
+ statusEmitter.emit("status", { connected: false });
1420
1552
  setTimeout(() => connectToServer2(serverUrl), 5e3);
1421
1553
  });
1422
1554
  ws.on("error", (error) => {
1423
1555
  console.error(pc2__default.default.red(`WebSocket error: ${error.message}`));
1556
+ statusEmitter.emit("status", { connected: false });
1424
1557
  });
1425
1558
  return ws;
1426
1559
  }
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import WebSocket from 'ws';
3
+ import { EventEmitter } from 'events';
3
4
  import { z } from 'zod';
4
5
  import { readFile, writeFile, stat, access, readdir, glob, unlink, mkdir } from 'fs/promises';
5
6
  import path9 from 'path';
@@ -1246,10 +1247,50 @@ var startHttpServer = (connection) => {
1246
1247
  }
1247
1248
  const app = new Hono();
1248
1249
  app.use(cors());
1249
- app.post("/daemon/status/stream", (c) => {
1250
+ app.post("/daemon/status", (c) => {
1250
1251
  const status = wsConnection ? getConnectionStatus(wsConnection) : "closed";
1251
1252
  return c.json({ connected: status === "open" });
1252
1253
  });
1254
+ app.get("/daemon/status/stream", (c) => {
1255
+ const encoder = new TextEncoder();
1256
+ const stream = new ReadableStream({
1257
+ start(controller) {
1258
+ const initialStatus = wsConnection ? getConnectionStatus(wsConnection) : "closed";
1259
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify({ connected: initialStatus === "open" })}
1260
+
1261
+ `));
1262
+ const statusHandler = (data) => {
1263
+ try {
1264
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}
1265
+
1266
+ `));
1267
+ } catch {
1268
+ }
1269
+ };
1270
+ statusEmitter.on("status", statusHandler);
1271
+ const heartbeatInterval = setInterval(() => {
1272
+ try {
1273
+ const currentStatus = wsConnection ? getConnectionStatus(wsConnection) : "closed";
1274
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify({ connected: currentStatus === "open" })}
1275
+
1276
+ `));
1277
+ } catch {
1278
+ }
1279
+ }, 15e3);
1280
+ c.req.raw.signal.addEventListener("abort", () => {
1281
+ statusEmitter.off("status", statusHandler);
1282
+ clearInterval(heartbeatInterval);
1283
+ });
1284
+ }
1285
+ });
1286
+ return new Response(stream, {
1287
+ headers: {
1288
+ "Content-Type": "text/event-stream",
1289
+ "Cache-Control": "no-cache",
1290
+ "Connection": "keep-alive"
1291
+ }
1292
+ });
1293
+ });
1253
1294
  app.get("context", async (c) => {
1254
1295
  const context = getContext(process.cwd());
1255
1296
  return c.body(JSON.stringify(context));
@@ -1351,8 +1392,96 @@ function getTokens() {
1351
1392
  const data = JSON.parse(raw);
1352
1393
  return data;
1353
1394
  }
1395
+ var ExplanationSchema = z.object({
1396
+ explanation: z.string().describe("One sentence explanation as to why this tool is being used")
1397
+ });
1398
+ z.object({
1399
+ command: z.string().describe("The terminal command to execute"),
1400
+ is_background: z.boolean().describe("Whether the command should be run in the background")
1401
+ }).merge(ExplanationSchema);
1402
+ var runSecureTerminalCommand = async (command, timeout) => {
1403
+ try {
1404
+ return new Promise((resolve, reject) => {
1405
+ const child = spawn(command, {
1406
+ cwd: process.cwd(),
1407
+ stdio: ["pipe", "pipe", "pipe"],
1408
+ shell: true
1409
+ });
1410
+ let stdout = "";
1411
+ let stderr = "";
1412
+ let timeoutId = null;
1413
+ if (timeoutId > 0) {
1414
+ timeoutId = setTimeout(() => {
1415
+ child.kill("SIGKILL");
1416
+ reject(new Error(`Command timed out after ${timeout}ms`));
1417
+ }, timeout);
1418
+ }
1419
+ child.stdout?.on("data", (data) => {
1420
+ stdout += data.toString();
1421
+ });
1422
+ child.stderr?.on("data", (data) => {
1423
+ stderr += data.toString();
1424
+ });
1425
+ child.stdout.on("close", (code) => {
1426
+ if (timeoutId) {
1427
+ clearTimeout(timeoutId);
1428
+ }
1429
+ resolve({ stdout, stderr, exitCode: code || 0 });
1430
+ });
1431
+ child.stderr.on("error", (error) => {
1432
+ if (timeoutId) {
1433
+ clearTimeout(timeoutId);
1434
+ }
1435
+ reject(error);
1436
+ });
1437
+ });
1438
+ } catch {
1439
+ console.error("Error while ecexuting the securedShell command");
1440
+ }
1441
+ };
1442
+ var runTerminalCommand = async (input, projectCwd) => {
1443
+ try {
1444
+ if (input?.is_background) {
1445
+ const child = spawn(input.command, {
1446
+ cwd: projectCwd,
1447
+ detached: true,
1448
+ stdio: "ignore",
1449
+ shell: true
1450
+ });
1451
+ child.unref();
1452
+ console.log(`[LOCAL] Background command started: ${input.command}`);
1453
+ return {
1454
+ success: true,
1455
+ message: `Background command started: ${input.command}`,
1456
+ isBackground: true
1457
+ };
1458
+ } else {
1459
+ const result = await runSecureTerminalCommand(
1460
+ input.command,
1461
+ 3e4
1462
+ // 30 second timeout
1463
+ );
1464
+ const success = result?.exitCode === 0;
1465
+ return {
1466
+ success,
1467
+ stdout: result?.stdout?.trim(),
1468
+ stderr: result?.stderr?.trim(),
1469
+ exitCode: result?.exitCode,
1470
+ message: success ? `Command executed successfully: ${input.command}` : `Command failed with exit code ${result?.exitCode}: ${input.command}`
1471
+ };
1472
+ }
1473
+ } catch (error) {
1474
+ console.error("Error while executing the terminal command", error);
1475
+ return {
1476
+ success: false,
1477
+ message: "Error while executing the terminal command",
1478
+ error: error.message
1479
+ };
1480
+ }
1481
+ };
1354
1482
 
1355
1483
  // src/server.ts
1484
+ var statusEmitter = new EventEmitter();
1356
1485
  var toolExecutors = {
1357
1486
  editFile: editFiles,
1358
1487
  deleteFile,
@@ -1360,7 +1489,8 @@ var toolExecutors = {
1360
1489
  glob: globTool,
1361
1490
  listDirectory: list,
1362
1491
  readFile: read_file,
1363
- stringReplace: apply_patch
1492
+ stringReplace: apply_patch,
1493
+ runTerminalCommand
1364
1494
  };
1365
1495
  function getConnectionStatus(ws) {
1366
1496
  return ws.readyState === WebSocket.CONNECTING ? "connecting" : ws.readyState === WebSocket.OPEN ? "open" : ws.readyState === WebSocket.CLOSING ? "closing" : "closed";
@@ -1378,6 +1508,7 @@ function connectToServer2(serverUrl = DEFAULT_SERVER_URL) {
1378
1508
  });
1379
1509
  ws.on("open", () => {
1380
1510
  console.log(pc2.green("Connected to server agent streams"));
1511
+ statusEmitter.emit("status", { connected: true });
1381
1512
  });
1382
1513
  ws.on("message", async (data) => {
1383
1514
  const message = JSON.parse(data.toString());
@@ -1407,10 +1538,12 @@ function connectToServer2(serverUrl = DEFAULT_SERVER_URL) {
1407
1538
  });
1408
1539
  ws.on("close", () => {
1409
1540
  console.log(pc2.red("Disconnected from server. Reconnecting in 5s..."));
1541
+ statusEmitter.emit("status", { connected: false });
1410
1542
  setTimeout(() => connectToServer2(serverUrl), 5e3);
1411
1543
  });
1412
1544
  ws.on("error", (error) => {
1413
1545
  console.error(pc2.red(`WebSocket error: ${error.message}`));
1546
+ statusEmitter.emit("status", { connected: false });
1414
1547
  });
1415
1548
  return ws;
1416
1549
  }
package/dist/server.cjs CHANGED
@@ -2,6 +2,7 @@
2
2
  'use strict';
3
3
 
4
4
  var WebSocket = require('ws');
5
+ var events = require('events');
5
6
  var zod = require('zod');
6
7
  var promises = require('fs/promises');
7
8
  var path9 = require('path');
@@ -1256,10 +1257,50 @@ var startHttpServer = (connection) => {
1256
1257
  }
1257
1258
  const app = new hono.Hono();
1258
1259
  app.use(cors.cors());
1259
- app.post("/daemon/status/stream", (c) => {
1260
+ app.post("/daemon/status", (c) => {
1260
1261
  const status = wsConnection ? getConnectionStatus(wsConnection) : "closed";
1261
1262
  return c.json({ connected: status === "open" });
1262
1263
  });
1264
+ app.get("/daemon/status/stream", (c) => {
1265
+ const encoder = new TextEncoder();
1266
+ const stream = new ReadableStream({
1267
+ start(controller) {
1268
+ const initialStatus = wsConnection ? getConnectionStatus(wsConnection) : "closed";
1269
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify({ connected: initialStatus === "open" })}
1270
+
1271
+ `));
1272
+ const statusHandler = (data) => {
1273
+ try {
1274
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}
1275
+
1276
+ `));
1277
+ } catch {
1278
+ }
1279
+ };
1280
+ statusEmitter.on("status", statusHandler);
1281
+ const heartbeatInterval = setInterval(() => {
1282
+ try {
1283
+ const currentStatus = wsConnection ? getConnectionStatus(wsConnection) : "closed";
1284
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify({ connected: currentStatus === "open" })}
1285
+
1286
+ `));
1287
+ } catch {
1288
+ }
1289
+ }, 15e3);
1290
+ c.req.raw.signal.addEventListener("abort", () => {
1291
+ statusEmitter.off("status", statusHandler);
1292
+ clearInterval(heartbeatInterval);
1293
+ });
1294
+ }
1295
+ });
1296
+ return new Response(stream, {
1297
+ headers: {
1298
+ "Content-Type": "text/event-stream",
1299
+ "Cache-Control": "no-cache",
1300
+ "Connection": "keep-alive"
1301
+ }
1302
+ });
1303
+ });
1263
1304
  app.get("context", async (c) => {
1264
1305
  const context = getContext(process.cwd());
1265
1306
  return c.body(JSON.stringify(context));
@@ -1361,8 +1402,96 @@ function getTokens() {
1361
1402
  const data = JSON.parse(raw);
1362
1403
  return data;
1363
1404
  }
1405
+ var ExplanationSchema = zod.z.object({
1406
+ explanation: zod.z.string().describe("One sentence explanation as to why this tool is being used")
1407
+ });
1408
+ zod.z.object({
1409
+ command: zod.z.string().describe("The terminal command to execute"),
1410
+ is_background: zod.z.boolean().describe("Whether the command should be run in the background")
1411
+ }).merge(ExplanationSchema);
1412
+ var runSecureTerminalCommand = async (command, timeout) => {
1413
+ try {
1414
+ return new Promise((resolve, reject) => {
1415
+ const child = child_process.spawn(command, {
1416
+ cwd: process.cwd(),
1417
+ stdio: ["pipe", "pipe", "pipe"],
1418
+ shell: true
1419
+ });
1420
+ let stdout = "";
1421
+ let stderr = "";
1422
+ let timeoutId = null;
1423
+ if (timeoutId > 0) {
1424
+ timeoutId = setTimeout(() => {
1425
+ child.kill("SIGKILL");
1426
+ reject(new Error(`Command timed out after ${timeout}ms`));
1427
+ }, timeout);
1428
+ }
1429
+ child.stdout?.on("data", (data) => {
1430
+ stdout += data.toString();
1431
+ });
1432
+ child.stderr?.on("data", (data) => {
1433
+ stderr += data.toString();
1434
+ });
1435
+ child.stdout.on("close", (code) => {
1436
+ if (timeoutId) {
1437
+ clearTimeout(timeoutId);
1438
+ }
1439
+ resolve({ stdout, stderr, exitCode: code || 0 });
1440
+ });
1441
+ child.stderr.on("error", (error) => {
1442
+ if (timeoutId) {
1443
+ clearTimeout(timeoutId);
1444
+ }
1445
+ reject(error);
1446
+ });
1447
+ });
1448
+ } catch {
1449
+ console.error("Error while ecexuting the securedShell command");
1450
+ }
1451
+ };
1452
+ var runTerminalCommand = async (input, projectCwd) => {
1453
+ try {
1454
+ if (input?.is_background) {
1455
+ const child = child_process.spawn(input.command, {
1456
+ cwd: projectCwd,
1457
+ detached: true,
1458
+ stdio: "ignore",
1459
+ shell: true
1460
+ });
1461
+ child.unref();
1462
+ console.log(`[LOCAL] Background command started: ${input.command}`);
1463
+ return {
1464
+ success: true,
1465
+ message: `Background command started: ${input.command}`,
1466
+ isBackground: true
1467
+ };
1468
+ } else {
1469
+ const result = await runSecureTerminalCommand(
1470
+ input.command,
1471
+ 3e4
1472
+ // 30 second timeout
1473
+ );
1474
+ const success = result?.exitCode === 0;
1475
+ return {
1476
+ success,
1477
+ stdout: result?.stdout?.trim(),
1478
+ stderr: result?.stderr?.trim(),
1479
+ exitCode: result?.exitCode,
1480
+ message: success ? `Command executed successfully: ${input.command}` : `Command failed with exit code ${result?.exitCode}: ${input.command}`
1481
+ };
1482
+ }
1483
+ } catch (error) {
1484
+ console.error("Error while executing the terminal command", error);
1485
+ return {
1486
+ success: false,
1487
+ message: "Error while executing the terminal command",
1488
+ error: error.message
1489
+ };
1490
+ }
1491
+ };
1364
1492
 
1365
1493
  // src/server.ts
1494
+ var statusEmitter = new events.EventEmitter();
1366
1495
  var toolExecutors = {
1367
1496
  editFile: editFiles,
1368
1497
  deleteFile,
@@ -1370,7 +1499,8 @@ var toolExecutors = {
1370
1499
  glob: globTool,
1371
1500
  listDirectory: list,
1372
1501
  readFile: read_file,
1373
- stringReplace: apply_patch
1502
+ stringReplace: apply_patch,
1503
+ runTerminalCommand
1374
1504
  };
1375
1505
  function getConnectionStatus(ws) {
1376
1506
  return ws.readyState === WebSocket__default.default.CONNECTING ? "connecting" : ws.readyState === WebSocket__default.default.OPEN ? "open" : ws.readyState === WebSocket__default.default.CLOSING ? "closing" : "closed";
@@ -1388,6 +1518,7 @@ function connectToServer2(serverUrl = DEFAULT_SERVER_URL) {
1388
1518
  });
1389
1519
  ws.on("open", () => {
1390
1520
  console.log(pc2__default.default.green("Connected to server agent streams"));
1521
+ statusEmitter.emit("status", { connected: true });
1391
1522
  });
1392
1523
  ws.on("message", async (data) => {
1393
1524
  const message = JSON.parse(data.toString());
@@ -1417,10 +1548,12 @@ function connectToServer2(serverUrl = DEFAULT_SERVER_URL) {
1417
1548
  });
1418
1549
  ws.on("close", () => {
1419
1550
  console.log(pc2__default.default.red("Disconnected from server. Reconnecting in 5s..."));
1551
+ statusEmitter.emit("status", { connected: false });
1420
1552
  setTimeout(() => connectToServer2(serverUrl), 5e3);
1421
1553
  });
1422
1554
  ws.on("error", (error) => {
1423
1555
  console.error(pc2__default.default.red(`WebSocket error: ${error.message}`));
1556
+ statusEmitter.emit("status", { connected: false });
1424
1557
  });
1425
1558
  return ws;
1426
1559
  }
@@ -1435,3 +1568,4 @@ async function main() {
1435
1568
  exports.connectToServer = connectToServer2;
1436
1569
  exports.getConnectionStatus = getConnectionStatus;
1437
1570
  exports.main = main;
1571
+ exports.statusEmitter = statusEmitter;
package/dist/server.d.cts CHANGED
@@ -1,7 +1,9 @@
1
1
  import WebSocket from 'ws';
2
+ import { EventEmitter } from 'events';
2
3
 
4
+ declare const statusEmitter: EventEmitter<[never]>;
3
5
  declare function getConnectionStatus(ws: WebSocket): 'connecting' | 'open' | 'closing' | 'closed';
4
6
  declare function connectToServer(serverUrl?: string): WebSocket;
5
7
  declare function main(): Promise<void>;
6
8
 
7
- export { connectToServer, getConnectionStatus, main };
9
+ export { connectToServer, getConnectionStatus, main, statusEmitter };
package/dist/server.d.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  import WebSocket from 'ws';
2
+ import { EventEmitter } from 'events';
2
3
 
4
+ declare const statusEmitter: EventEmitter<[never]>;
3
5
  declare function getConnectionStatus(ws: WebSocket): 'connecting' | 'open' | 'closing' | 'closed';
4
6
  declare function connectToServer(serverUrl?: string): WebSocket;
5
7
  declare function main(): Promise<void>;
6
8
 
7
- export { connectToServer, getConnectionStatus, main };
9
+ export { connectToServer, getConnectionStatus, main, statusEmitter };
package/dist/server.js CHANGED
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import WebSocket from 'ws';
3
+ import { EventEmitter } from 'events';
3
4
  import { z } from 'zod';
4
5
  import { readFile, writeFile, stat, access, readdir, glob, unlink, mkdir } from 'fs/promises';
5
6
  import path9 from 'path';
6
7
  import fs3, { readdirSync } from 'fs';
7
8
  import os2 from 'os';
8
- import { exec } from 'child_process';
9
+ import { exec, spawn } from 'child_process';
9
10
  import { promisify } from 'util';
10
11
  import pc2 from 'picocolors';
11
12
  import { Hono } from 'hono';
@@ -1246,10 +1247,50 @@ var startHttpServer = (connection) => {
1246
1247
  }
1247
1248
  const app = new Hono();
1248
1249
  app.use(cors());
1249
- app.post("/daemon/status/stream", (c) => {
1250
+ app.post("/daemon/status", (c) => {
1250
1251
  const status = wsConnection ? getConnectionStatus(wsConnection) : "closed";
1251
1252
  return c.json({ connected: status === "open" });
1252
1253
  });
1254
+ app.get("/daemon/status/stream", (c) => {
1255
+ const encoder = new TextEncoder();
1256
+ const stream = new ReadableStream({
1257
+ start(controller) {
1258
+ const initialStatus = wsConnection ? getConnectionStatus(wsConnection) : "closed";
1259
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify({ connected: initialStatus === "open" })}
1260
+
1261
+ `));
1262
+ const statusHandler = (data) => {
1263
+ try {
1264
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}
1265
+
1266
+ `));
1267
+ } catch {
1268
+ }
1269
+ };
1270
+ statusEmitter.on("status", statusHandler);
1271
+ const heartbeatInterval = setInterval(() => {
1272
+ try {
1273
+ const currentStatus = wsConnection ? getConnectionStatus(wsConnection) : "closed";
1274
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify({ connected: currentStatus === "open" })}
1275
+
1276
+ `));
1277
+ } catch {
1278
+ }
1279
+ }, 15e3);
1280
+ c.req.raw.signal.addEventListener("abort", () => {
1281
+ statusEmitter.off("status", statusHandler);
1282
+ clearInterval(heartbeatInterval);
1283
+ });
1284
+ }
1285
+ });
1286
+ return new Response(stream, {
1287
+ headers: {
1288
+ "Content-Type": "text/event-stream",
1289
+ "Cache-Control": "no-cache",
1290
+ "Connection": "keep-alive"
1291
+ }
1292
+ });
1293
+ });
1253
1294
  app.get("context", async (c) => {
1254
1295
  const context = getContext(process.cwd());
1255
1296
  return c.body(JSON.stringify(context));
@@ -1351,8 +1392,96 @@ function getTokens() {
1351
1392
  const data = JSON.parse(raw);
1352
1393
  return data;
1353
1394
  }
1395
+ var ExplanationSchema = z.object({
1396
+ explanation: z.string().describe("One sentence explanation as to why this tool is being used")
1397
+ });
1398
+ z.object({
1399
+ command: z.string().describe("The terminal command to execute"),
1400
+ is_background: z.boolean().describe("Whether the command should be run in the background")
1401
+ }).merge(ExplanationSchema);
1402
+ var runSecureTerminalCommand = async (command, timeout) => {
1403
+ try {
1404
+ return new Promise((resolve, reject) => {
1405
+ const child = spawn(command, {
1406
+ cwd: process.cwd(),
1407
+ stdio: ["pipe", "pipe", "pipe"],
1408
+ shell: true
1409
+ });
1410
+ let stdout = "";
1411
+ let stderr = "";
1412
+ let timeoutId = null;
1413
+ if (timeoutId > 0) {
1414
+ timeoutId = setTimeout(() => {
1415
+ child.kill("SIGKILL");
1416
+ reject(new Error(`Command timed out after ${timeout}ms`));
1417
+ }, timeout);
1418
+ }
1419
+ child.stdout?.on("data", (data) => {
1420
+ stdout += data.toString();
1421
+ });
1422
+ child.stderr?.on("data", (data) => {
1423
+ stderr += data.toString();
1424
+ });
1425
+ child.stdout.on("close", (code) => {
1426
+ if (timeoutId) {
1427
+ clearTimeout(timeoutId);
1428
+ }
1429
+ resolve({ stdout, stderr, exitCode: code || 0 });
1430
+ });
1431
+ child.stderr.on("error", (error) => {
1432
+ if (timeoutId) {
1433
+ clearTimeout(timeoutId);
1434
+ }
1435
+ reject(error);
1436
+ });
1437
+ });
1438
+ } catch {
1439
+ console.error("Error while ecexuting the securedShell command");
1440
+ }
1441
+ };
1442
+ var runTerminalCommand = async (input, projectCwd) => {
1443
+ try {
1444
+ if (input?.is_background) {
1445
+ const child = spawn(input.command, {
1446
+ cwd: projectCwd,
1447
+ detached: true,
1448
+ stdio: "ignore",
1449
+ shell: true
1450
+ });
1451
+ child.unref();
1452
+ console.log(`[LOCAL] Background command started: ${input.command}`);
1453
+ return {
1454
+ success: true,
1455
+ message: `Background command started: ${input.command}`,
1456
+ isBackground: true
1457
+ };
1458
+ } else {
1459
+ const result = await runSecureTerminalCommand(
1460
+ input.command,
1461
+ 3e4
1462
+ // 30 second timeout
1463
+ );
1464
+ const success = result?.exitCode === 0;
1465
+ return {
1466
+ success,
1467
+ stdout: result?.stdout?.trim(),
1468
+ stderr: result?.stderr?.trim(),
1469
+ exitCode: result?.exitCode,
1470
+ message: success ? `Command executed successfully: ${input.command}` : `Command failed with exit code ${result?.exitCode}: ${input.command}`
1471
+ };
1472
+ }
1473
+ } catch (error) {
1474
+ console.error("Error while executing the terminal command", error);
1475
+ return {
1476
+ success: false,
1477
+ message: "Error while executing the terminal command",
1478
+ error: error.message
1479
+ };
1480
+ }
1481
+ };
1354
1482
 
1355
1483
  // src/server.ts
1484
+ var statusEmitter = new EventEmitter();
1356
1485
  var toolExecutors = {
1357
1486
  editFile: editFiles,
1358
1487
  deleteFile,
@@ -1360,7 +1489,8 @@ var toolExecutors = {
1360
1489
  glob: globTool,
1361
1490
  listDirectory: list,
1362
1491
  readFile: read_file,
1363
- stringReplace: apply_patch
1492
+ stringReplace: apply_patch,
1493
+ runTerminalCommand
1364
1494
  };
1365
1495
  function getConnectionStatus(ws) {
1366
1496
  return ws.readyState === WebSocket.CONNECTING ? "connecting" : ws.readyState === WebSocket.OPEN ? "open" : ws.readyState === WebSocket.CLOSING ? "closing" : "closed";
@@ -1378,6 +1508,7 @@ function connectToServer2(serverUrl = DEFAULT_SERVER_URL) {
1378
1508
  });
1379
1509
  ws.on("open", () => {
1380
1510
  console.log(pc2.green("Connected to server agent streams"));
1511
+ statusEmitter.emit("status", { connected: true });
1381
1512
  });
1382
1513
  ws.on("message", async (data) => {
1383
1514
  const message = JSON.parse(data.toString());
@@ -1407,10 +1538,12 @@ function connectToServer2(serverUrl = DEFAULT_SERVER_URL) {
1407
1538
  });
1408
1539
  ws.on("close", () => {
1409
1540
  console.log(pc2.red("Disconnected from server. Reconnecting in 5s..."));
1541
+ statusEmitter.emit("status", { connected: false });
1410
1542
  setTimeout(() => connectToServer2(serverUrl), 5e3);
1411
1543
  });
1412
1544
  ws.on("error", (error) => {
1413
1545
  console.error(pc2.red(`WebSocket error: ${error.message}`));
1546
+ statusEmitter.emit("status", { connected: false });
1414
1547
  });
1415
1548
  return ws;
1416
1549
  }
@@ -1422,4 +1555,4 @@ async function main() {
1422
1555
  startHttpServer(connection);
1423
1556
  }
1424
1557
 
1425
- export { connectToServer2 as connectToServer, getConnectionStatus, main };
1558
+ export { connectToServer2 as connectToServer, getConnectionStatus, main, statusEmitter };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "amai",
3
3
  "type": "module",
4
- "version": "0.0.2",
4
+ "version": "0.0.4",
5
5
  "description": "ama rpc daemon",
6
6
  "keywords": [
7
7
  "ama",