anywhere-ai 0.0.35 → 0.0.37

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.js CHANGED
@@ -17,11 +17,11 @@ var STATUS_PATH = path.join(ANYWHERE_DIR, "status.json");
17
17
  var args = process.argv.slice(2);
18
18
  var command = args.find((a) => !a.startsWith("-"));
19
19
  if (args.includes("--version") || args.includes("-v")) {
20
- console.log(`anywhere-ai v${"0.0.35"}`);
20
+ console.log(`anywhere-ai v${"0.0.37"}`);
21
21
  process.exit(0);
22
22
  }
23
23
  if (args.includes("--help") || args.includes("-h") || command === "help") {
24
- console.log(`anywhere-ai v${"0.0.35"} \u2014 Mobile coding agent
24
+ console.log(`anywhere-ai v${"0.0.37"} \u2014 Mobile coding agent
25
25
 
26
26
  Usage: npx anywhere-ai [command] [options]
27
27
 
@@ -124,16 +124,25 @@ if (command === "regenerate-token") {
124
124
  var isDaemon = !args.includes("--foreground");
125
125
  var existingPid = getDaemonPid();
126
126
  if (existingPid) {
127
- console.log(`Server already running (PID ${existingPid}). Use 'npx anywhere-ai stop' first.`);
128
- process.exit(1);
127
+ console.log(`Stopping existing server (PID ${existingPid})...`);
128
+ process.kill(existingPid, "SIGTERM");
129
+ try {
130
+ unlinkSync(PID_PATH);
131
+ } catch {
132
+ }
133
+ try {
134
+ unlinkSync(STATUS_PATH);
135
+ } catch {
136
+ }
137
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
129
138
  }
130
139
  async function checkForUpdate() {
131
140
  try {
132
141
  const res = await fetch("https://registry.npmjs.org/anywhere-ai/latest", { signal: AbortSignal.timeout(3e3) });
133
142
  const data = await res.json();
134
- if (data.version && data.version !== "0.0.35") {
143
+ if (data.version && data.version !== "0.0.37") {
135
144
  console.log(`
136
- Update available: v${"0.0.35"} \u2192 v${data.version}`);
145
+ Update available: v${"0.0.37"} \u2192 v${data.version}`);
137
146
  console.log(` Run: npx anywhere-ai@latest
138
147
  `);
139
148
  }
package/dist/server.js CHANGED
@@ -186,6 +186,15 @@ var sendMessage = async ({
186
186
  }) => {
187
187
  await session.send(prompt);
188
188
  };
189
+ var abortSession = (sessionId) => {
190
+ const session = sessions.get(sessionId);
191
+ if (!session) return false;
192
+ session.close();
193
+ sessions.delete(sessionId);
194
+ activeSessions.delete(sessionId);
195
+ setPermissionCallback(sessionId, null);
196
+ return true;
197
+ };
189
198
  var getSession = async ({
190
199
  sessionId,
191
200
  model,
@@ -478,10 +487,16 @@ chats.post("/new", async (c) => {
478
487
  });
479
488
  }
480
489
  } catch (err) {
481
- console.error(err);
482
- await stream.writeSSE({
483
- data: JSON.stringify({ error: "Stream error" })
484
- });
490
+ const aborted = err?.message?.includes("aborted by user");
491
+ if (aborted) {
492
+ console.log(`[stream] session aborted by user: ${finalSessionId}`);
493
+ await stream.writeSSE({ data: JSON.stringify({ aborted: true }) });
494
+ } else {
495
+ console.error(err);
496
+ await stream.writeSSE({
497
+ data: JSON.stringify({ error: "Stream error" })
498
+ });
499
+ }
485
500
  } finally {
486
501
  setPermissionCallback(tempId, null);
487
502
  if (finalSessionId) {
@@ -553,12 +568,18 @@ chats.post("/:id/message", async (c) => {
553
568
  });
554
569
  }
555
570
  } catch (err) {
556
- console.error(err);
557
- await stream.writeSSE({
558
- data: JSON.stringify({ error: "Stream error" })
559
- });
560
- generateChatName(prompt, sessionId).catch(() => {
561
- });
571
+ const aborted = err?.message?.includes("aborted by user");
572
+ if (aborted) {
573
+ console.log(`[stream] session aborted by user: ${sessionId}`);
574
+ await stream.writeSSE({ data: JSON.stringify({ aborted: true }) });
575
+ } else {
576
+ console.error(err);
577
+ await stream.writeSSE({
578
+ data: JSON.stringify({ error: "Stream error" })
579
+ });
580
+ generateChatName(prompt, sessionId).catch(() => {
581
+ });
582
+ }
562
583
  } finally {
563
584
  sseStream = null;
564
585
  setPermissionCallback(sessionId, null);
@@ -587,6 +608,19 @@ chats.post("/:id/permission", async (c) => {
587
608
  }
588
609
  return c.json({ ok: true });
589
610
  });
611
+ chats.post("/:id/abort", async (c) => {
612
+ const sessionId = c.req.param("id");
613
+ if (!sessionId || /[\/\\]/.test(sessionId))
614
+ return c.json({ error: "Invalid session ID" }, 400);
615
+ if (!activeSessions.has(sessionId)) {
616
+ return c.json({ error: "Session is not currently streaming" }, 404);
617
+ }
618
+ const aborted = abortSession(sessionId);
619
+ if (!aborted) {
620
+ return c.json({ error: "Session not found" }, 404);
621
+ }
622
+ return c.json({ ok: true });
623
+ });
590
624
  var listEntryCache = /* @__PURE__ */ new Map();
591
625
  function parseListEntry(content, sessionId, fileMtimeIso, chatName) {
592
626
  const lines = content.split("\n").filter(Boolean);
@@ -693,7 +727,7 @@ chats.get("/", async (c) => {
693
727
  return c.json({ result: allChats });
694
728
  } catch (error) {
695
729
  console.error("[GET /chats] error:", error);
696
- return c.json({ result: [] });
730
+ return c.json({ error: "Failed to list chats" }, 500);
697
731
  }
698
732
  });
699
733
  chats.get("/:id", async (c) => {
@@ -721,7 +755,13 @@ chats.get("/:id", async (c) => {
721
755
  } else {
722
756
  const content = await readFile2(file, "utf-8");
723
757
  const lines = content.split("\n").filter(Boolean);
724
- const parsed = lines.map((line) => JSON.parse(line));
758
+ const parsed = lines.flatMap((line) => {
759
+ try {
760
+ return [JSON.parse(line)];
761
+ } catch {
762
+ return [];
763
+ }
764
+ });
725
765
  for (const obj of parsed) {
726
766
  if (obj.type === "user" && obj.cwd && !cwd) cwd = obj.cwd;
727
767
  }
@@ -815,7 +855,7 @@ git.get("/status", async (c) => {
815
855
  try {
816
856
  const cwd = c.req.query("cwd");
817
857
  const root = await getRepoRoot(cwd);
818
- if (!root) return c.json({ files: [], error: "Not a git repository" });
858
+ if (!root) return c.json({ error: "Not a git repository" }, 400);
819
859
  const { stdout: statusOut } = await execAsync("git status --porcelain", {
820
860
  cwd: root
821
861
  });
@@ -882,7 +922,7 @@ git.get("/status", async (c) => {
882
922
  return c.json({ files });
883
923
  } catch (error) {
884
924
  console.error("git status error:", error);
885
- return c.json({ files: [] });
925
+ return c.json({ error: "Failed to get git status" }, 500);
886
926
  }
887
927
  });
888
928
  git.get("/diff", async (c) => {
@@ -974,7 +1014,7 @@ gh.get("/repos", async (c) => {
974
1014
  );
975
1015
  return c.json({ username, repos: all });
976
1016
  } catch (error) {
977
- return c.json([]);
1017
+ return c.json({ error: "Failed to list repos" }, 500);
978
1018
  }
979
1019
  });
980
1020
  gh.get("/pr", async (c) => {
@@ -1028,6 +1068,8 @@ app.use("/v1/*", bearerAuth({ token }));
1028
1068
  app.route("/v1/chats", chats);
1029
1069
  app.route("/v1/git", git);
1030
1070
  app.route("/v1/gh", gh);
1071
+ app.notFound((c) => c.json({ error: "Not found" }, 404));
1072
+ app.onError((err, c) => c.json({ error: err.message || "Internal server error" }, 500));
1031
1073
  serve(
1032
1074
  {
1033
1075
  fetch: app.fetch,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anywhere-ai",
3
- "version": "0.0.35",
3
+ "version": "0.0.37",
4
4
  "type": "module",
5
5
  "description": "Code on any repo from your phone",
6
6
  "bin": {