anywhere-ai 0.0.27 → 0.0.29

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.
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
+ }) : x)(function(x) {
5
+ if (typeof require !== "undefined") return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
8
+
9
+ export {
10
+ __require
11
+ };
package/dist/cli.js CHANGED
@@ -2,47 +2,144 @@
2
2
 
3
3
  // src/cli.ts
4
4
  import fs from "fs/promises";
5
- import { readFileSync } from "fs";
5
+ import { readFileSync, existsSync, writeFileSync, unlinkSync, openSync } from "fs";
6
6
  import os from "os";
7
7
  import path from "path";
8
8
  import crypto from "crypto";
9
9
  import { spawn, spawnSync, execSync } from "child_process";
10
10
  import readline from "readline";
11
11
  import qrcode from "qrcode";
12
+ var ANYWHERE_DIR = path.join(os.homedir(), ".anywhere");
13
+ var CONFIG_PATH = path.join(ANYWHERE_DIR, "config.json");
14
+ var PID_PATH = path.join(ANYWHERE_DIR, "server.pid");
15
+ var LOG_PATH = path.join(ANYWHERE_DIR, "server.log");
16
+ var STATUS_PATH = path.join(ANYWHERE_DIR, "status.json");
12
17
  var args = process.argv.slice(2);
13
18
  var command = args.find((a) => !a.startsWith("-"));
14
19
  if (args.includes("--version") || args.includes("-v")) {
15
- console.log(`anywhere-ai v${"0.0.27"}`);
20
+ console.log(`anywhere-ai v${"0.0.29"}`);
16
21
  process.exit(0);
17
22
  }
18
23
  if (args.includes("--help") || args.includes("-h") || command === "help") {
19
- console.log(`anywhere-ai v${"0.0.27"} \u2014 Mobile coding agent
24
+ console.log(`anywhere-ai v${"0.0.29"} \u2014 Mobile coding agent
20
25
 
21
26
  Usage: anywhere-ai [command] [options]
22
27
 
23
28
  Commands:
29
+ status Show server status and connection info
30
+ stop Stop the background server
31
+ logs Tail server logs
24
32
  regenerate-token Generate a new auth token
25
33
 
26
34
  Options:
27
35
  --help, -h Show this help message
28
36
  --version, -v Show version
37
+ --daemon, -d Run server in background
29
38
  --no-tunnel Skip Cloudflare tunnel`);
30
39
  process.exit(0);
31
40
  }
41
+ function getDaemonPid() {
42
+ try {
43
+ const pid = parseInt(readFileSync(PID_PATH, "utf-8").trim(), 10);
44
+ process.kill(pid, 0);
45
+ return pid;
46
+ } catch {
47
+ try {
48
+ unlinkSync(PID_PATH);
49
+ } catch {
50
+ }
51
+ return null;
52
+ }
53
+ }
54
+ if (command === "stop" || args.includes("--stop")) {
55
+ const pid = getDaemonPid();
56
+ if (!pid) {
57
+ console.log("No server running.");
58
+ process.exit(0);
59
+ }
60
+ process.kill(pid, "SIGTERM");
61
+ try {
62
+ unlinkSync(PID_PATH);
63
+ } catch {
64
+ }
65
+ try {
66
+ unlinkSync(STATUS_PATH);
67
+ } catch {
68
+ }
69
+ console.log(`Server stopped (PID ${pid}).`);
70
+ process.exit(0);
71
+ }
72
+ if (command === "status") {
73
+ const pid = getDaemonPid();
74
+ if (!pid) {
75
+ console.log("No server running.");
76
+ process.exit(0);
77
+ }
78
+ try {
79
+ const status = JSON.parse(readFileSync(STATUS_PATH, "utf-8"));
80
+ const uptimeMs = Date.now() - status.startedAt;
81
+ const hours = Math.floor(uptimeMs / 36e5);
82
+ const mins = Math.floor(uptimeMs % 36e5 / 6e4);
83
+ console.log(`Anywhere server running (PID ${pid})`);
84
+ console.log(` Tunnel: ${status.serverURL}`);
85
+ if (status.localURL && status.localURL !== status.serverURL) {
86
+ console.log(` Direct: ${status.localURL}`);
87
+ }
88
+ console.log(` Token: ${status.authToken}`);
89
+ console.log(` Uptime: ${hours}h ${mins}m`);
90
+ console.log(` Logs: ${LOG_PATH}`);
91
+ } catch {
92
+ console.log(`Server running (PID ${pid}) but no status info available.`);
93
+ console.log(` Logs: ${LOG_PATH}`);
94
+ }
95
+ process.exit(0);
96
+ }
97
+ if (command === "logs") {
98
+ if (!existsSync(LOG_PATH)) {
99
+ console.log("No log file found. Start the server first.");
100
+ process.exit(0);
101
+ }
102
+ const tail = spawn("tail", ["-f", "-n", "50", LOG_PATH], { stdio: "inherit" });
103
+ tail.on("exit", () => process.exit(0));
104
+ process.on("SIGINT", () => {
105
+ tail.kill();
106
+ process.exit(0);
107
+ });
108
+ await new Promise(() => {
109
+ });
110
+ }
32
111
  if (command === "regenerate-token") {
33
- const configPath = path.join(os.homedir(), ".anywhere", "config.json");
34
112
  try {
35
- await fs.access(configPath);
113
+ await fs.access(CONFIG_PATH);
36
114
  } catch {
37
115
  console.error("No config found. Run `anywhere-ai` first to set up.");
38
116
  process.exit(1);
39
117
  }
40
- const config2 = JSON.parse(await fs.readFile(configPath, "utf-8"));
118
+ const config2 = JSON.parse(await fs.readFile(CONFIG_PATH, "utf-8"));
41
119
  config2.authToken = crypto.randomBytes(16).toString("hex");
42
- await fs.writeFile(configPath, JSON.stringify(config2, null, 2));
120
+ await fs.writeFile(CONFIG_PATH, JSON.stringify(config2, null, 2));
43
121
  console.log("New auth token: " + config2.authToken);
44
122
  process.exit(0);
45
123
  }
124
+ var existingPid = getDaemonPid();
125
+ if (existingPid) {
126
+ console.log(`Server already running (PID ${existingPid}). Use 'anywhere-ai stop' first.`);
127
+ process.exit(1);
128
+ }
129
+ async function checkForUpdate() {
130
+ try {
131
+ const res = await fetch("https://registry.npmjs.org/anywhere-ai/latest", { signal: AbortSignal.timeout(3e3) });
132
+ const data = await res.json();
133
+ if (data.version && data.version !== "0.0.29") {
134
+ console.log(`
135
+ Update available: v${"0.0.29"} \u2192 v${data.version}`);
136
+ console.log(` Run: npx anywhere-ai@latest
137
+ `);
138
+ }
139
+ } catch {
140
+ }
141
+ }
142
+ checkForUpdate();
46
143
  function ask(question, preserveCase = false) {
47
144
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
48
145
  return new Promise((resolve) => {
@@ -52,8 +149,6 @@ function ask(question, preserveCase = false) {
52
149
  });
53
150
  });
54
151
  }
55
- var ANYWHERE_DIR = path.join(os.homedir(), ".anywhere");
56
- var CONFIG_PATH = path.join(ANYWHERE_DIR, "config.json");
57
152
  async function createConfigFile() {
58
153
  try {
59
154
  await fs.access(CONFIG_PATH);
@@ -319,7 +414,52 @@ if (!args.includes("--no-tunnel")) {
319
414
  }
320
415
  var localURL = isVPS ? "http://" + publicIP + ":" + port : "http://" + (localIP || "localhost") + ":" + port;
321
416
  var serverURL = tunnelURL || localURL;
322
- await printBanner(serverURL, localURL);
417
+ var isDaemonized = args.includes("--_daemonized");
418
+ if (!isDaemonized) {
419
+ await printBanner(serverURL, localURL);
420
+ }
421
+ writeFileSync(PID_PATH, String(process.pid));
422
+ writeFileSync(STATUS_PATH, JSON.stringify({
423
+ serverURL,
424
+ localURL,
425
+ authToken: config.authToken,
426
+ startedAt: Date.now(),
427
+ pid: process.pid
428
+ }, null, 2));
429
+ var isDaemon = args.includes("--daemon") || args.includes("-d");
430
+ if (isDaemon) {
431
+ const logFd = openSync(LOG_PATH, "a");
432
+ const child = spawn(process.execPath, [new URL(import.meta.url).pathname, ...args.filter((a) => a !== "--daemon" && a !== "-d"), "--_daemonized"], {
433
+ detached: true,
434
+ stdio: ["ignore", logFd, logFd],
435
+ env: { ...process.env }
436
+ });
437
+ child.unref();
438
+ writeFileSync(PID_PATH, String(child.pid));
439
+ writeFileSync(STATUS_PATH, JSON.stringify({
440
+ serverURL,
441
+ localURL,
442
+ authToken: config.authToken,
443
+ startedAt: Date.now(),
444
+ pid: child.pid
445
+ }, null, 2));
446
+ console.log(`
447
+ Running in background (PID ${child.pid})`);
448
+ console.log(` Logs: ${LOG_PATH}`);
449
+ console.log(` Status: anywhere-ai status`);
450
+ console.log(` Stop: anywhere-ai stop
451
+ `);
452
+ intentionalShutdown = true;
453
+ if (serverProcess) {
454
+ serverProcess.kill();
455
+ serverProcess = null;
456
+ }
457
+ if (tunnelProcess) {
458
+ tunnelProcess.kill();
459
+ tunnelProcess = null;
460
+ }
461
+ process.exit(0);
462
+ }
323
463
  function cleanup() {
324
464
  intentionalShutdown = true;
325
465
  if (serverProcess) {
@@ -330,6 +470,14 @@ function cleanup() {
330
470
  tunnelProcess.kill();
331
471
  tunnelProcess = null;
332
472
  }
473
+ try {
474
+ unlinkSync(PID_PATH);
475
+ } catch {
476
+ }
477
+ try {
478
+ unlinkSync(STATUS_PATH);
479
+ } catch {
480
+ }
333
481
  process.exit();
334
482
  }
335
483
  process.on("SIGINT", cleanup);
package/dist/server.js CHANGED
@@ -501,9 +501,7 @@ chats.post("/:id/message", async (c) => {
501
501
  const blocks = msg.message?.content;
502
502
  if (Array.isArray(blocks)) {
503
503
  for (const b of blocks) {
504
- if (b.type === "tool_use") {
505
- console.log(`[stream] tool_use: ${b.name}`);
506
- } else if (b.type === "tool_result" && b.is_error) {
504
+ if (b.type === "tool_result" && b.is_error) {
507
505
  const resultText = Array.isArray(b.content) ? b.content.filter((r) => r.type === "text").map((r) => r.text).join("").slice(0, 1e3) : String(b.content ?? "").slice(0, 1e3);
508
506
  console.log(`[stream] tool_result ERROR: ${resultText.slice(0, 500)}`);
509
507
  }
@@ -899,19 +897,15 @@ gh.get("/repos", async (c) => {
899
897
  gh.get("/pr", async (c) => {
900
898
  try {
901
899
  const cwd = c.req.query("cwd");
902
- console.log("[gh/pr GET] cwd:", cwd);
903
900
  const root = await getRepoRoot(cwd);
904
- console.log("[gh/pr GET] resolved root:", root);
905
901
  if (!root) return c.json({ exists: false });
906
902
  const { stdout } = await execAsync2(
907
903
  "gh pr view --json number,title,url",
908
904
  { cwd: root }
909
905
  );
910
906
  const pr = JSON.parse(stdout);
911
- console.log("[gh/pr GET] found PR:", pr);
912
907
  return c.json({ exists: true, pr });
913
- } catch (err) {
914
- console.log("[gh/pr GET] no PR found:", err?.stderr?.trim() || err?.message);
908
+ } catch {
915
909
  return c.json({ exists: false });
916
910
  }
917
911
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anywhere-ai",
3
- "version": "0.0.27",
3
+ "version": "0.0.29",
4
4
  "type": "module",
5
5
  "description": "Code on any repo from your phone",
6
6
  "bin": {