@devness/useai-cli 0.4.19 → 0.4.21

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.
Files changed (2) hide show
  1. package/dist/index.js +75 -44
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -30,7 +30,7 @@ var SYSTEMD_SERVICE_PATH = join(homedir(), ".config", "systemd", "user", "useai-
30
30
  var WINDOWS_STARTUP_SCRIPT_PATH = join(process.env["APPDATA"] ?? join(homedir(), "AppData", "Roaming"), "Microsoft", "Windows", "Start Menu", "Programs", "Startup", "useai-daemon.vbs");
31
31
 
32
32
  // ../shared/dist/constants/version.js
33
- var VERSION = "0.4.17";
33
+ var VERSION = "0.4.20";
34
34
 
35
35
  // ../shared/dist/constants/defaults.js
36
36
  var DEFAULT_CONFIG = {
@@ -4589,7 +4589,7 @@ function buildNodePath() {
4589
4589
 
4590
4590
  // ../shared/dist/daemon/ensure.js
4591
4591
  import { existsSync as existsSync5, readFileSync as readFileSync2, unlinkSync } from "fs";
4592
- import { spawn } from "child_process";
4592
+ import { execSync as execSync2, spawn } from "child_process";
4593
4593
  function readPidFile() {
4594
4594
  if (!existsSync5(DAEMON_PID_FILE))
4595
4595
  return null;
@@ -4627,33 +4627,55 @@ async function fetchDaemonHealth(port) {
4627
4627
  return null;
4628
4628
  }
4629
4629
  }
4630
- async function killDaemon() {
4631
- const pid = readPidFile();
4632
- if (!pid)
4633
- return;
4634
- if (!isProcessRunning(pid.pid)) {
4635
- try {
4636
- unlinkSync(DAEMON_PID_FILE);
4637
- } catch {
4638
- }
4639
- return;
4630
+ function findPidsByPort(port) {
4631
+ try {
4632
+ const output = execSync2(`lsof -ti :${port}`, { encoding: "utf-8", timeout: 3e3 });
4633
+ return output.trim().split("\n").map((s) => parseInt(s, 10)).filter((n) => !isNaN(n) && n > 0);
4634
+ } catch {
4635
+ return [];
4640
4636
  }
4637
+ }
4638
+ async function killPid(pid) {
4639
+ if (!isProcessRunning(pid))
4640
+ return;
4641
4641
  try {
4642
- process.kill(pid.pid, "SIGTERM");
4642
+ process.kill(pid, "SIGTERM");
4643
4643
  } catch {
4644
4644
  return;
4645
4645
  }
4646
4646
  const start = Date.now();
4647
4647
  while (Date.now() - start < 5e3) {
4648
- if (!isProcessRunning(pid.pid)) {
4648
+ if (!isProcessRunning(pid))
4649
4649
  return;
4650
- }
4651
4650
  await new Promise((r) => setTimeout(r, 200));
4652
4651
  }
4653
4652
  try {
4654
- process.kill(pid.pid, "SIGKILL");
4653
+ process.kill(pid, "SIGKILL");
4655
4654
  } catch {
4656
4655
  }
4656
+ }
4657
+ async function killDaemon() {
4658
+ const pidData = readPidFile();
4659
+ const port = pidData?.port ?? DAEMON_PORT;
4660
+ if (pidData && isProcessRunning(pidData.pid)) {
4661
+ await killPid(pidData.pid);
4662
+ try {
4663
+ if (existsSync5(DAEMON_PID_FILE))
4664
+ unlinkSync(DAEMON_PID_FILE);
4665
+ } catch {
4666
+ }
4667
+ return;
4668
+ }
4669
+ if (pidData) {
4670
+ try {
4671
+ unlinkSync(DAEMON_PID_FILE);
4672
+ } catch {
4673
+ }
4674
+ }
4675
+ const pids = findPidsByPort(port);
4676
+ if (pids.length > 0) {
4677
+ await Promise.all(pids.map((p) => killPid(p)));
4678
+ }
4657
4679
  try {
4658
4680
  if (existsSync5(DAEMON_PID_FILE))
4659
4681
  unlinkSync(DAEMON_PID_FILE);
@@ -4661,15 +4683,21 @@ async function killDaemon() {
4661
4683
  }
4662
4684
  }
4663
4685
  async function ensureDaemon() {
4664
- if (await checkDaemonHealth())
4686
+ const health = await fetchDaemonHealth();
4687
+ if (health && health.version === VERSION)
4665
4688
  return true;
4666
- const pid = readPidFile();
4667
- if (pid && isProcessRunning(pid.pid)) {
4689
+ if (health) {
4668
4690
  await killDaemon();
4669
- } else if (pid) {
4670
- try {
4671
- unlinkSync(DAEMON_PID_FILE);
4672
- } catch {
4691
+ }
4692
+ if (!health) {
4693
+ const pid = readPidFile();
4694
+ if (pid && isProcessRunning(pid.pid)) {
4695
+ await killDaemon();
4696
+ } else if (pid) {
4697
+ try {
4698
+ unlinkSync(DAEMON_PID_FILE);
4699
+ } catch {
4700
+ }
4673
4701
  }
4674
4702
  }
4675
4703
  let npxPath;
@@ -4694,7 +4722,7 @@ async function ensureDaemon() {
4694
4722
 
4695
4723
  // ../shared/dist/daemon/autostart.js
4696
4724
  import { existsSync as existsSync6, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2 } from "fs";
4697
- import { execSync as execSync2 } from "child_process";
4725
+ import { execSync as execSync3 } from "child_process";
4698
4726
  import { dirname } from "path";
4699
4727
  function detectPlatform() {
4700
4728
  switch (process.platform) {
@@ -4719,7 +4747,7 @@ function buildPlist(npxPath, nodePath) {
4719
4747
  <array>
4720
4748
  <string>${npxPath}</string>
4721
4749
  <string>-y</string>
4722
- <string>@devness/useai</string>
4750
+ <string>@devness/useai@latest</string>
4723
4751
  <string>daemon</string>
4724
4752
  <string>--port</string>
4725
4753
  <string>${DAEMON_PORT}</string>
@@ -4752,14 +4780,14 @@ function installMacos() {
4752
4780
  mkdirSync2(dirname(LAUNCHD_PLIST_PATH), { recursive: true });
4753
4781
  writeFileSync2(LAUNCHD_PLIST_PATH, buildPlist(npxPath, nodePath));
4754
4782
  try {
4755
- execSync2(`launchctl unload "${LAUNCHD_PLIST_PATH}" 2>/dev/null`, { stdio: "ignore" });
4783
+ execSync3(`launchctl unload "${LAUNCHD_PLIST_PATH}" 2>/dev/null`, { stdio: "ignore" });
4756
4784
  } catch {
4757
4785
  }
4758
- execSync2(`launchctl load "${LAUNCHD_PLIST_PATH}"`, { stdio: "ignore" });
4786
+ execSync3(`launchctl load "${LAUNCHD_PLIST_PATH}"`, { stdio: "ignore" });
4759
4787
  }
4760
4788
  function removeMacos() {
4761
4789
  try {
4762
- execSync2(`launchctl unload "${LAUNCHD_PLIST_PATH}" 2>/dev/null`, { stdio: "ignore" });
4790
+ execSync3(`launchctl unload "${LAUNCHD_PLIST_PATH}" 2>/dev/null`, { stdio: "ignore" });
4763
4791
  } catch {
4764
4792
  }
4765
4793
  try {
@@ -4778,7 +4806,7 @@ After=network.target
4778
4806
 
4779
4807
  [Service]
4780
4808
  Type=simple
4781
- ExecStart=${npxPath} -y @devness/useai daemon --port ${DAEMON_PORT}
4809
+ ExecStart=${npxPath} -y @devness/useai@latest daemon --port ${DAEMON_PORT}
4782
4810
  Restart=on-failure
4783
4811
  RestartSec=10
4784
4812
  Environment=PATH=${nodePath}
@@ -4792,12 +4820,12 @@ function installLinux() {
4792
4820
  const nodePath = buildNodePath();
4793
4821
  mkdirSync2(dirname(SYSTEMD_SERVICE_PATH), { recursive: true });
4794
4822
  writeFileSync2(SYSTEMD_SERVICE_PATH, buildSystemdUnit(npxPath, nodePath));
4795
- execSync2("systemctl --user daemon-reload", { stdio: "ignore" });
4796
- execSync2("systemctl --user enable --now useai-daemon.service", { stdio: "ignore" });
4823
+ execSync3("systemctl --user daemon-reload", { stdio: "ignore" });
4824
+ execSync3("systemctl --user enable --now useai-daemon.service", { stdio: "ignore" });
4797
4825
  }
4798
4826
  function removeLinux() {
4799
4827
  try {
4800
- execSync2("systemctl --user disable --now useai-daemon.service", { stdio: "ignore" });
4828
+ execSync3("systemctl --user disable --now useai-daemon.service", { stdio: "ignore" });
4801
4829
  } catch {
4802
4830
  }
4803
4831
  try {
@@ -4806,7 +4834,7 @@ function removeLinux() {
4806
4834
  } catch {
4807
4835
  }
4808
4836
  try {
4809
- execSync2("systemctl --user daemon-reload", { stdio: "ignore" });
4837
+ execSync3("systemctl --user daemon-reload", { stdio: "ignore" });
4810
4838
  } catch {
4811
4839
  }
4812
4840
  }
@@ -4815,7 +4843,7 @@ function isLinuxInstalled() {
4815
4843
  }
4816
4844
  function buildVbsScript(npxPath) {
4817
4845
  return `Set WshShell = CreateObject("WScript.Shell")
4818
- WshShell.Run """${npxPath}"" -y @devness/useai daemon --port ${DAEMON_PORT}", 0, False
4846
+ WshShell.Run """${npxPath}"" -y @devness/useai@latest daemon --port ${DAEMON_PORT}", 0, False
4819
4847
  `;
4820
4848
  }
4821
4849
  function installWindows() {
@@ -5052,7 +5080,7 @@ function removeClaudeCodeHooks() {
5052
5080
  }
5053
5081
 
5054
5082
  // src/services/tools.ts
5055
- import { execSync as execSync3 } from "child_process";
5083
+ import { execSync as execSync4 } from "child_process";
5056
5084
  import { existsSync as existsSync8, readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, unlinkSync as unlinkSync4 } from "fs";
5057
5085
  import { dirname as dirname2, join as join4 } from "path";
5058
5086
  import { homedir as homedir4 } from "os";
@@ -5089,7 +5117,7 @@ function installVscodeHttp(configPath) {
5089
5117
  }
5090
5118
  function hasBinary(name) {
5091
5119
  try {
5092
- execSync3(`which ${name}`, { stdio: "ignore" });
5120
+ execSync4(`which ${name}`, { stdio: "ignore" });
5093
5121
  return true;
5094
5122
  } catch {
5095
5123
  return false;
@@ -5898,20 +5926,23 @@ var startCommand = new Command8("start").description("Start the UseAI daemon").o
5898
5926
  console.log(chalk7.dim(` Try: useai daemon start --foreground`));
5899
5927
  }
5900
5928
  });
5901
- var stopCommand = new Command8("stop").description("Stop the UseAI daemon").action(async () => {
5929
+ var stopCommand = new Command8("stop").description("Stop the UseAI daemon").option("-p, --port <port>", "Port to stop daemon on", String(DAEMON_PORT)).action(async (opts) => {
5930
+ const port = parseInt(opts.port, 10);
5902
5931
  const pid = readPidFile();
5903
- if (!pid) {
5904
- console.log(chalk7.dim(" Daemon is not running (no PID file found)"));
5932
+ if (pid && isProcessRunning(pid.pid)) {
5933
+ console.log(chalk7.dim(` Stopping daemon (PID ${pid.pid})...`));
5934
+ await killDaemon();
5935
+ console.log(chalk7.green(` \u2713 Daemon stopped`));
5905
5936
  return;
5906
5937
  }
5907
- if (!isProcessRunning(pid.pid)) {
5908
- console.log(chalk7.dim(" Daemon is not running (stale PID file)"));
5938
+ const pids = findPidsByPort(port);
5939
+ if (pids.length > 0) {
5940
+ console.log(chalk7.dim(` Stopping daemon on port ${port} (PIDs: ${pids.join(", ")})...`));
5909
5941
  await killDaemon();
5942
+ console.log(chalk7.green(` \u2713 Daemon stopped`));
5910
5943
  return;
5911
5944
  }
5912
- console.log(chalk7.dim(` Stopping daemon (PID ${pid.pid})...`));
5913
- await killDaemon();
5914
- console.log(chalk7.green(` \u2713 Daemon stopped`));
5945
+ console.log(chalk7.dim(" Daemon is not running"));
5915
5946
  });
5916
5947
  var statusCommand2 = new Command8("status").description("Show daemon status").action(async () => {
5917
5948
  const pid = readPidFile();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devness/useai-cli",
3
- "version": "0.4.19",
3
+ "version": "0.4.21",
4
4
  "description": "CLI tool for useai.dev — stats, sync, publish your AI development workflow",
5
5
  "author": "nabeelkausari",
6
6
  "license": "MIT",