amai 0.0.5 → 0.0.6

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.
@@ -1,8 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
- var WebSocket = require('ws');
5
- var events = require('events');
4
+ var WebSocket2 = require('ws');
6
5
  var zod = require('zod');
7
6
  var promises = require('fs/promises');
8
7
  var path9 = require('path');
@@ -18,7 +17,7 @@ var cors = require('hono/cors');
18
17
 
19
18
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
20
19
 
21
- var WebSocket__default = /*#__PURE__*/_interopDefault(WebSocket);
20
+ var WebSocket2__default = /*#__PURE__*/_interopDefault(WebSocket2);
22
21
  var path9__default = /*#__PURE__*/_interopDefault(path9);
23
22
  var fs3__default = /*#__PURE__*/_interopDefault(fs3);
24
23
  var os2__default = /*#__PURE__*/_interopDefault(os2);
@@ -1421,15 +1420,6 @@ var startHttpServer = (connection) => {
1421
1420
  controller.enqueue(encoder.encode(`data: ${JSON.stringify({ connected: initialStatus === "open" })}
1422
1421
 
1423
1422
  `));
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
1423
  const heartbeatInterval = setInterval(() => {
1434
1424
  try {
1435
1425
  const currentStatus = wsConnection ? getConnectionStatus(wsConnection) : "closed";
@@ -1440,7 +1430,6 @@ var startHttpServer = (connection) => {
1440
1430
  }
1441
1431
  }, 15e3);
1442
1432
  c.req.raw.signal.addEventListener("abort", () => {
1443
- statusEmitter.off("status", statusHandler);
1444
1433
  clearInterval(heartbeatInterval);
1445
1434
  });
1446
1435
  }
@@ -1664,6 +1653,20 @@ function getTokens() {
1664
1653
  const data = JSON.parse(raw);
1665
1654
  return data;
1666
1655
  }
1656
+ var getUserId = () => {
1657
+ try {
1658
+ if (!fs3__default.default.existsSync(CREDENTIALS_PATH)) {
1659
+ return;
1660
+ }
1661
+ const raw = fs3__default.default.readFileSync(CREDENTIALS_PATH, "utf8");
1662
+ const data = JSON.parse(raw);
1663
+ return {
1664
+ userId: data.user.id
1665
+ };
1666
+ } catch {
1667
+ throw new Error("Error while getting userId");
1668
+ }
1669
+ };
1667
1670
  var ExplanationSchema = zod.z.object({
1668
1671
  explanation: zod.z.string().describe("One sentence explanation as to why this tool is being used")
1669
1672
  });
@@ -1752,8 +1755,201 @@ var runTerminalCommand = async (input, projectCwd) => {
1752
1755
  }
1753
1756
  };
1754
1757
 
1758
+ // src/lib/rpc-handlers.ts
1759
+ var rpcHandlers = {
1760
+ "daemon:get_workspace_folders": async () => {
1761
+ const projects = projectRegistry.list();
1762
+ return {
1763
+ folders: projects.map((p) => ({
1764
+ id: p.id,
1765
+ cwd: p.cwd,
1766
+ name: p.name,
1767
+ active: p.active
1768
+ }))
1769
+ };
1770
+ },
1771
+ "daemon:get_environment": async ({ gitRepositoryUrl }) => {
1772
+ const projects = projectRegistry.list();
1773
+ if (projects.length === 0) {
1774
+ const error = {
1775
+ _tag: "ProjectUnlinkedError",
1776
+ 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>\``
1777
+ };
1778
+ throw error;
1779
+ }
1780
+ return {
1781
+ project: projects[0],
1782
+ env: {
1783
+ platform: process.platform,
1784
+ arch: process.arch,
1785
+ nodeVersion: process.version
1786
+ }
1787
+ };
1788
+ },
1789
+ "daemon:get_context": async ({ cwd }) => {
1790
+ try {
1791
+ const files = getContext(cwd);
1792
+ return { files, cwd };
1793
+ } catch (error) {
1794
+ const rpcError = {
1795
+ _tag: "ContextError",
1796
+ message: error.message || "Failed to get context"
1797
+ };
1798
+ throw rpcError;
1799
+ }
1800
+ },
1801
+ "daemon:get_ide_projects": async () => {
1802
+ const projects = await scanIdeProjects();
1803
+ return { projects };
1804
+ },
1805
+ "daemon:register_project": async ({ projectId, cwd, name }) => {
1806
+ if (!projectId || !cwd) {
1807
+ const error = {
1808
+ _tag: "ValidationError",
1809
+ message: "projectId and cwd are required"
1810
+ };
1811
+ throw error;
1812
+ }
1813
+ projectRegistry.register(projectId, cwd, name);
1814
+ return { success: true, projectId, cwd };
1815
+ },
1816
+ "daemon:unregister_project": async ({ projectId }) => {
1817
+ if (!projectId) {
1818
+ const error = {
1819
+ _tag: "ValidationError",
1820
+ message: "projectId is required"
1821
+ };
1822
+ throw error;
1823
+ }
1824
+ projectRegistry.unregister(projectId);
1825
+ return { success: true, projectId };
1826
+ },
1827
+ "daemon:get_project": async ({ projectId }) => {
1828
+ const project = projectRegistry.getProject(projectId);
1829
+ if (!project) {
1830
+ const error = {
1831
+ _tag: "ProjectNotFoundError",
1832
+ message: `Project not found: ${projectId}`
1833
+ };
1834
+ throw error;
1835
+ }
1836
+ return { project };
1837
+ },
1838
+ "daemon:list_projects": async () => {
1839
+ const projects = projectRegistry.list();
1840
+ return { projects };
1841
+ },
1842
+ "daemon:status": async () => {
1843
+ return {
1844
+ connected: true,
1845
+ timestamp: Date.now(),
1846
+ platform: process.platform,
1847
+ arch: process.arch
1848
+ };
1849
+ }
1850
+ };
1851
+ var reconnectTimeout = null;
1852
+ var connectToUserStreams = async (serverUrl) => {
1853
+ const userId = getUserId();
1854
+ if (!userId?.userId) {
1855
+ throw new Error("User ID not found");
1856
+ }
1857
+ const params = new URLSearchParams({
1858
+ userId: userId.userId,
1859
+ type: "cli"
1860
+ });
1861
+ const tokens = getTokens();
1862
+ if (!tokens) {
1863
+ throw new Error("No tokens found");
1864
+ }
1865
+ const wsUrl = `${serverUrl}/api/v1/user-streams?${params.toString()}`;
1866
+ const ws = new WebSocket2__default.default(wsUrl, {
1867
+ headers: {
1868
+ Authorization: `Bearer ${tokens.access_token}`
1869
+ }
1870
+ });
1871
+ ws.on("open", () => {
1872
+ console.log(pc2__default.default.green("CLI connected to user-streams"));
1873
+ if (reconnectTimeout) {
1874
+ clearTimeout(reconnectTimeout);
1875
+ reconnectTimeout = null;
1876
+ }
1877
+ });
1878
+ ws.on("message", async (event) => {
1879
+ try {
1880
+ const message = JSON.parse(event.toString());
1881
+ if (message._tag === "rpc_call") {
1882
+ const { requestId, method, input } = message;
1883
+ console.log(pc2__default.default.gray(`RPC call: ${method}`));
1884
+ const handler = rpcHandlers[method];
1885
+ if (!handler) {
1886
+ ws.send(JSON.stringify({
1887
+ _tag: "rpc_result",
1888
+ requestId,
1889
+ data: {
1890
+ _tag: "UnknownMethodError",
1891
+ message: `Unknown RPC method: ${method}`
1892
+ }
1893
+ }));
1894
+ console.log(pc2__default.default.yellow(`Unknown RPC method: ${method}`));
1895
+ return;
1896
+ }
1897
+ try {
1898
+ const result = await handler(input || {});
1899
+ ws.send(JSON.stringify({
1900
+ _tag: "rpc_result",
1901
+ requestId,
1902
+ data: result
1903
+ }));
1904
+ console.log(pc2__default.default.green(`RPC completed: ${method}`));
1905
+ } catch (error) {
1906
+ const rpcError = error._tag ? error : {
1907
+ _tag: "RpcError",
1908
+ message: error.message || String(error)
1909
+ };
1910
+ ws.send(JSON.stringify({
1911
+ _tag: "rpc_result",
1912
+ requestId,
1913
+ data: rpcError
1914
+ }));
1915
+ console.log(pc2__default.default.red(`RPC failed: ${method} - ${rpcError.message}`));
1916
+ }
1917
+ return;
1918
+ }
1919
+ if (message.type === "presence_request") {
1920
+ if (message.status === "connected") {
1921
+ ws.send(JSON.stringify({
1922
+ type: "presence_request",
1923
+ status: "connected"
1924
+ }));
1925
+ }
1926
+ if (message.status === "disconnected") {
1927
+ ws.send(JSON.stringify({
1928
+ type: "presence_request",
1929
+ status: "disconnected"
1930
+ }));
1931
+ }
1932
+ }
1933
+ } catch (parseError) {
1934
+ console.error(pc2__default.default.red(`Failed to parse message: ${parseError}`));
1935
+ }
1936
+ });
1937
+ ws.on("close", (code, reason) => {
1938
+ console.log(pc2__default.default.yellow(`CLI disconnected from user-streams (code: ${code})`));
1939
+ console.log(pc2__default.default.gray("Reconnecting in 5 seconds..."));
1940
+ reconnectTimeout = setTimeout(() => {
1941
+ connectToUserStreams(serverUrl).catch((err) => {
1942
+ console.error(pc2__default.default.red(`Reconnection failed: ${err.message}`));
1943
+ });
1944
+ }, 5e3);
1945
+ });
1946
+ ws.on("error", (error) => {
1947
+ console.error(pc2__default.default.red(`User streams WebSocket error: ${error.message}`));
1948
+ });
1949
+ return ws;
1950
+ };
1951
+
1755
1952
  // src/server.ts
1756
- var statusEmitter = new events.EventEmitter();
1757
1953
  var toolExecutors = {
1758
1954
  editFile: editFiles,
1759
1955
  deleteFile,
@@ -1765,7 +1961,7 @@ var toolExecutors = {
1765
1961
  runTerminalCommand
1766
1962
  };
1767
1963
  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";
1964
+ return ws.readyState === WebSocket2__default.default.CONNECTING ? "connecting" : ws.readyState === WebSocket2__default.default.OPEN ? "open" : ws.readyState === WebSocket2__default.default.CLOSING ? "closing" : "closed";
1769
1965
  }
1770
1966
  function connectToServer2(serverUrl = DEFAULT_SERVER_URL) {
1771
1967
  const tokens = getTokens();
@@ -1773,14 +1969,13 @@ function connectToServer2(serverUrl = DEFAULT_SERVER_URL) {
1773
1969
  throw new Error("No tokens found");
1774
1970
  }
1775
1971
  const wsUrl = `${serverUrl}/agent-streams`;
1776
- const ws = new WebSocket__default.default(wsUrl, {
1972
+ const ws = new WebSocket2__default.default(wsUrl, {
1777
1973
  headers: {
1778
1974
  "Authorization": `Bearer ${tokens.access_token}`
1779
1975
  }
1780
1976
  });
1781
1977
  ws.on("open", () => {
1782
1978
  console.log(pc2__default.default.green("Connected to server agent streams"));
1783
- statusEmitter.emit("status", { connected: true });
1784
1979
  });
1785
1980
  ws.on("message", async (data) => {
1786
1981
  const message = JSON.parse(data.toString());
@@ -1810,12 +2005,10 @@ function connectToServer2(serverUrl = DEFAULT_SERVER_URL) {
1810
2005
  });
1811
2006
  ws.on("close", () => {
1812
2007
  console.log(pc2__default.default.red("Disconnected from server. Reconnecting in 5s..."));
1813
- statusEmitter.emit("status", { connected: false });
1814
2008
  setTimeout(() => connectToServer2(serverUrl), 5e3);
1815
2009
  });
1816
2010
  ws.on("error", (error) => {
1817
2011
  console.error(pc2__default.default.red(`WebSocket error: ${error.message}`));
1818
- statusEmitter.emit("status", { connected: false });
1819
2012
  });
1820
2013
  return ws;
1821
2014
  }
@@ -1824,6 +2017,7 @@ async function main() {
1824
2017
  console.log(pc2__default.default.green("Starting local amai..."));
1825
2018
  console.log(pc2__default.default.gray(`Connecting to server at ${serverUrl}`));
1826
2019
  const connection = connectToServer2(serverUrl);
2020
+ await connectToUserStreams(serverUrl);
1827
2021
  startHttpServer(connection);
1828
2022
  }
1829
2023
  var execAsync2 = util.promisify(child_process.exec);
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import WebSocket from 'ws';
3
- import { EventEmitter } from 'events';
2
+ import WebSocket2 from 'ws';
4
3
  import { z } from 'zod';
5
4
  import { readFile, writeFile, stat, access, readdir, glob, unlink, mkdir } from 'fs/promises';
6
5
  import path9 from 'path';
@@ -1411,15 +1410,6 @@ var startHttpServer = (connection) => {
1411
1410
  controller.enqueue(encoder.encode(`data: ${JSON.stringify({ connected: initialStatus === "open" })}
1412
1411
 
1413
1412
  `));
1414
- const statusHandler = (data) => {
1415
- try {
1416
- controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}
1417
-
1418
- `));
1419
- } catch {
1420
- }
1421
- };
1422
- statusEmitter.on("status", statusHandler);
1423
1413
  const heartbeatInterval = setInterval(() => {
1424
1414
  try {
1425
1415
  const currentStatus = wsConnection ? getConnectionStatus(wsConnection) : "closed";
@@ -1430,7 +1420,6 @@ var startHttpServer = (connection) => {
1430
1420
  }
1431
1421
  }, 15e3);
1432
1422
  c.req.raw.signal.addEventListener("abort", () => {
1433
- statusEmitter.off("status", statusHandler);
1434
1423
  clearInterval(heartbeatInterval);
1435
1424
  });
1436
1425
  }
@@ -1654,6 +1643,20 @@ function getTokens() {
1654
1643
  const data = JSON.parse(raw);
1655
1644
  return data;
1656
1645
  }
1646
+ var getUserId = () => {
1647
+ try {
1648
+ if (!fs3.existsSync(CREDENTIALS_PATH)) {
1649
+ return;
1650
+ }
1651
+ const raw = fs3.readFileSync(CREDENTIALS_PATH, "utf8");
1652
+ const data = JSON.parse(raw);
1653
+ return {
1654
+ userId: data.user.id
1655
+ };
1656
+ } catch {
1657
+ throw new Error("Error while getting userId");
1658
+ }
1659
+ };
1657
1660
  var ExplanationSchema = z.object({
1658
1661
  explanation: z.string().describe("One sentence explanation as to why this tool is being used")
1659
1662
  });
@@ -1742,8 +1745,201 @@ var runTerminalCommand = async (input, projectCwd) => {
1742
1745
  }
1743
1746
  };
1744
1747
 
1748
+ // src/lib/rpc-handlers.ts
1749
+ var rpcHandlers = {
1750
+ "daemon:get_workspace_folders": async () => {
1751
+ const projects = projectRegistry.list();
1752
+ return {
1753
+ folders: projects.map((p) => ({
1754
+ id: p.id,
1755
+ cwd: p.cwd,
1756
+ name: p.name,
1757
+ active: p.active
1758
+ }))
1759
+ };
1760
+ },
1761
+ "daemon:get_environment": async ({ gitRepositoryUrl }) => {
1762
+ const projects = projectRegistry.list();
1763
+ if (projects.length === 0) {
1764
+ const error = {
1765
+ _tag: "ProjectUnlinkedError",
1766
+ 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>\``
1767
+ };
1768
+ throw error;
1769
+ }
1770
+ return {
1771
+ project: projects[0],
1772
+ env: {
1773
+ platform: process.platform,
1774
+ arch: process.arch,
1775
+ nodeVersion: process.version
1776
+ }
1777
+ };
1778
+ },
1779
+ "daemon:get_context": async ({ cwd }) => {
1780
+ try {
1781
+ const files = getContext(cwd);
1782
+ return { files, cwd };
1783
+ } catch (error) {
1784
+ const rpcError = {
1785
+ _tag: "ContextError",
1786
+ message: error.message || "Failed to get context"
1787
+ };
1788
+ throw rpcError;
1789
+ }
1790
+ },
1791
+ "daemon:get_ide_projects": async () => {
1792
+ const projects = await scanIdeProjects();
1793
+ return { projects };
1794
+ },
1795
+ "daemon:register_project": async ({ projectId, cwd, name }) => {
1796
+ if (!projectId || !cwd) {
1797
+ const error = {
1798
+ _tag: "ValidationError",
1799
+ message: "projectId and cwd are required"
1800
+ };
1801
+ throw error;
1802
+ }
1803
+ projectRegistry.register(projectId, cwd, name);
1804
+ return { success: true, projectId, cwd };
1805
+ },
1806
+ "daemon:unregister_project": async ({ projectId }) => {
1807
+ if (!projectId) {
1808
+ const error = {
1809
+ _tag: "ValidationError",
1810
+ message: "projectId is required"
1811
+ };
1812
+ throw error;
1813
+ }
1814
+ projectRegistry.unregister(projectId);
1815
+ return { success: true, projectId };
1816
+ },
1817
+ "daemon:get_project": async ({ projectId }) => {
1818
+ const project = projectRegistry.getProject(projectId);
1819
+ if (!project) {
1820
+ const error = {
1821
+ _tag: "ProjectNotFoundError",
1822
+ message: `Project not found: ${projectId}`
1823
+ };
1824
+ throw error;
1825
+ }
1826
+ return { project };
1827
+ },
1828
+ "daemon:list_projects": async () => {
1829
+ const projects = projectRegistry.list();
1830
+ return { projects };
1831
+ },
1832
+ "daemon:status": async () => {
1833
+ return {
1834
+ connected: true,
1835
+ timestamp: Date.now(),
1836
+ platform: process.platform,
1837
+ arch: process.arch
1838
+ };
1839
+ }
1840
+ };
1841
+ var reconnectTimeout = null;
1842
+ var connectToUserStreams = async (serverUrl) => {
1843
+ const userId = getUserId();
1844
+ if (!userId?.userId) {
1845
+ throw new Error("User ID not found");
1846
+ }
1847
+ const params = new URLSearchParams({
1848
+ userId: userId.userId,
1849
+ type: "cli"
1850
+ });
1851
+ const tokens = getTokens();
1852
+ if (!tokens) {
1853
+ throw new Error("No tokens found");
1854
+ }
1855
+ const wsUrl = `${serverUrl}/api/v1/user-streams?${params.toString()}`;
1856
+ const ws = new WebSocket2(wsUrl, {
1857
+ headers: {
1858
+ Authorization: `Bearer ${tokens.access_token}`
1859
+ }
1860
+ });
1861
+ ws.on("open", () => {
1862
+ console.log(pc2.green("CLI connected to user-streams"));
1863
+ if (reconnectTimeout) {
1864
+ clearTimeout(reconnectTimeout);
1865
+ reconnectTimeout = null;
1866
+ }
1867
+ });
1868
+ ws.on("message", async (event) => {
1869
+ try {
1870
+ const message = JSON.parse(event.toString());
1871
+ if (message._tag === "rpc_call") {
1872
+ const { requestId, method, input } = message;
1873
+ console.log(pc2.gray(`RPC call: ${method}`));
1874
+ const handler = rpcHandlers[method];
1875
+ if (!handler) {
1876
+ ws.send(JSON.stringify({
1877
+ _tag: "rpc_result",
1878
+ requestId,
1879
+ data: {
1880
+ _tag: "UnknownMethodError",
1881
+ message: `Unknown RPC method: ${method}`
1882
+ }
1883
+ }));
1884
+ console.log(pc2.yellow(`Unknown RPC method: ${method}`));
1885
+ return;
1886
+ }
1887
+ try {
1888
+ const result = await handler(input || {});
1889
+ ws.send(JSON.stringify({
1890
+ _tag: "rpc_result",
1891
+ requestId,
1892
+ data: result
1893
+ }));
1894
+ console.log(pc2.green(`RPC completed: ${method}`));
1895
+ } catch (error) {
1896
+ const rpcError = error._tag ? error : {
1897
+ _tag: "RpcError",
1898
+ message: error.message || String(error)
1899
+ };
1900
+ ws.send(JSON.stringify({
1901
+ _tag: "rpc_result",
1902
+ requestId,
1903
+ data: rpcError
1904
+ }));
1905
+ console.log(pc2.red(`RPC failed: ${method} - ${rpcError.message}`));
1906
+ }
1907
+ return;
1908
+ }
1909
+ if (message.type === "presence_request") {
1910
+ if (message.status === "connected") {
1911
+ ws.send(JSON.stringify({
1912
+ type: "presence_request",
1913
+ status: "connected"
1914
+ }));
1915
+ }
1916
+ if (message.status === "disconnected") {
1917
+ ws.send(JSON.stringify({
1918
+ type: "presence_request",
1919
+ status: "disconnected"
1920
+ }));
1921
+ }
1922
+ }
1923
+ } catch (parseError) {
1924
+ console.error(pc2.red(`Failed to parse message: ${parseError}`));
1925
+ }
1926
+ });
1927
+ ws.on("close", (code, reason) => {
1928
+ console.log(pc2.yellow(`CLI disconnected from user-streams (code: ${code})`));
1929
+ console.log(pc2.gray("Reconnecting in 5 seconds..."));
1930
+ reconnectTimeout = setTimeout(() => {
1931
+ connectToUserStreams(serverUrl).catch((err) => {
1932
+ console.error(pc2.red(`Reconnection failed: ${err.message}`));
1933
+ });
1934
+ }, 5e3);
1935
+ });
1936
+ ws.on("error", (error) => {
1937
+ console.error(pc2.red(`User streams WebSocket error: ${error.message}`));
1938
+ });
1939
+ return ws;
1940
+ };
1941
+
1745
1942
  // src/server.ts
1746
- var statusEmitter = new EventEmitter();
1747
1943
  var toolExecutors = {
1748
1944
  editFile: editFiles,
1749
1945
  deleteFile,
@@ -1755,7 +1951,7 @@ var toolExecutors = {
1755
1951
  runTerminalCommand
1756
1952
  };
1757
1953
  function getConnectionStatus(ws) {
1758
- return ws.readyState === WebSocket.CONNECTING ? "connecting" : ws.readyState === WebSocket.OPEN ? "open" : ws.readyState === WebSocket.CLOSING ? "closing" : "closed";
1954
+ return ws.readyState === WebSocket2.CONNECTING ? "connecting" : ws.readyState === WebSocket2.OPEN ? "open" : ws.readyState === WebSocket2.CLOSING ? "closing" : "closed";
1759
1955
  }
1760
1956
  function connectToServer2(serverUrl = DEFAULT_SERVER_URL) {
1761
1957
  const tokens = getTokens();
@@ -1763,14 +1959,13 @@ function connectToServer2(serverUrl = DEFAULT_SERVER_URL) {
1763
1959
  throw new Error("No tokens found");
1764
1960
  }
1765
1961
  const wsUrl = `${serverUrl}/agent-streams`;
1766
- const ws = new WebSocket(wsUrl, {
1962
+ const ws = new WebSocket2(wsUrl, {
1767
1963
  headers: {
1768
1964
  "Authorization": `Bearer ${tokens.access_token}`
1769
1965
  }
1770
1966
  });
1771
1967
  ws.on("open", () => {
1772
1968
  console.log(pc2.green("Connected to server agent streams"));
1773
- statusEmitter.emit("status", { connected: true });
1774
1969
  });
1775
1970
  ws.on("message", async (data) => {
1776
1971
  const message = JSON.parse(data.toString());
@@ -1800,12 +1995,10 @@ function connectToServer2(serverUrl = DEFAULT_SERVER_URL) {
1800
1995
  });
1801
1996
  ws.on("close", () => {
1802
1997
  console.log(pc2.red("Disconnected from server. Reconnecting in 5s..."));
1803
- statusEmitter.emit("status", { connected: false });
1804
1998
  setTimeout(() => connectToServer2(serverUrl), 5e3);
1805
1999
  });
1806
2000
  ws.on("error", (error) => {
1807
2001
  console.error(pc2.red(`WebSocket error: ${error.message}`));
1808
- statusEmitter.emit("status", { connected: false });
1809
2002
  });
1810
2003
  return ws;
1811
2004
  }
@@ -1814,6 +2007,7 @@ async function main() {
1814
2007
  console.log(pc2.green("Starting local amai..."));
1815
2008
  console.log(pc2.gray(`Connecting to server at ${serverUrl}`));
1816
2009
  const connection = connectToServer2(serverUrl);
2010
+ await connectToUserStreams(serverUrl);
1817
2011
  startHttpServer(connection);
1818
2012
  }
1819
2013
  var execAsync2 = promisify(exec);