swixter 0.1.4 → 0.1.5

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/cli/index.js +239 -43
  2. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -13999,7 +13999,7 @@ var CONFIG_VERSION = "2.0.0", EXPORT_VERSION = "1.0.0";
13999
13999
  var init_versions2 = () => {};
14000
14000
 
14001
14001
  // src/constants/meta.ts
14002
- var APP_VERSION = "0.1.4";
14002
+ var APP_VERSION = "0.1.5";
14003
14003
  var init_meta = () => {};
14004
14004
 
14005
14005
  // src/constants/install.ts
@@ -14359,7 +14359,8 @@ var init_presets = __esm(() => {
14359
14359
  id: "deepseek",
14360
14360
  name: "DeepSeek",
14361
14361
  displayName: "DeepSeek",
14362
- baseURL: "https://api.deepseek.com",
14362
+ baseURL: "https://api.deepseek.com/anthropic",
14363
+ baseURLChat: "https://api.deepseek.com",
14363
14364
  defaultModels: [
14364
14365
  "deepseek-chat",
14365
14366
  "deepseek-coder"
@@ -26527,18 +26528,18 @@ var init_client = __esm(() => {
26527
26528
  });
26528
26529
 
26529
26530
  // src/auth/token.ts
26530
- import { existsSync as existsSync12 } from "node:fs";
26531
- import { readFile as readFile9, writeFile as writeFile8, unlink as unlink2 } from "node:fs/promises";
26532
- import { join as join10 } from "node:path";
26531
+ import { existsSync as existsSync13 } from "node:fs";
26532
+ import { readFile as readFile10, writeFile as writeFile9, unlink as unlink3 } from "node:fs/promises";
26533
+ import { join as join11 } from "node:path";
26533
26534
  function getAuthFilePath() {
26534
- return join10(getConfigDir("swixter"), AUTH_FILE);
26535
+ return join11(getConfigDir("swixter"), AUTH_FILE);
26535
26536
  }
26536
26537
  async function loadAuthState() {
26537
26538
  const authPath = getAuthFilePath();
26538
- if (!existsSync12(authPath))
26539
+ if (!existsSync13(authPath))
26539
26540
  return null;
26540
26541
  try {
26541
- const content = await readFile9(authPath, "utf-8");
26542
+ const content = await readFile10(authPath, "utf-8");
26542
26543
  return JSON.parse(content);
26543
26544
  } catch {
26544
26545
  return null;
@@ -26546,12 +26547,12 @@ async function loadAuthState() {
26546
26547
  }
26547
26548
  async function saveAuthState(state) {
26548
26549
  const authPath = getAuthFilePath();
26549
- await writeFile8(authPath, JSON.stringify(state, null, 2), { mode: 384, encoding: "utf-8" });
26550
+ await writeFile9(authPath, JSON.stringify(state, null, 2), { mode: 384, encoding: "utf-8" });
26550
26551
  }
26551
26552
  async function clearAuthState() {
26552
26553
  const authPath = getAuthFilePath();
26553
- if (existsSync12(authPath)) {
26554
- await unlink2(authPath);
26554
+ if (existsSync13(authPath)) {
26555
+ await unlink3(authPath);
26555
26556
  }
26556
26557
  }
26557
26558
  function isExpired(expiresAt) {
@@ -27364,7 +27365,7 @@ __export(exports_proxy, {
27364
27365
  buildCoderProxyEnv: () => buildCoderProxyEnv,
27365
27366
  buildClaudeProxyEnv: () => buildClaudeProxyEnv
27366
27367
  });
27367
- import { spawn as spawn3 } from "node:child_process";
27368
+ import { spawn as spawn4 } from "node:child_process";
27368
27369
  function resolveProxyRuntimeBinding(input) {
27369
27370
  const occupiedPorts = new Set(input.allInstances.filter((s) => s.running).map((s) => s.port));
27370
27371
  if (input.requestedPort) {
@@ -27558,7 +27559,7 @@ async function cmdStartDaemon(config2) {
27558
27559
  if (config2.groupName) {
27559
27560
  args.push("--group", config2.groupName);
27560
27561
  }
27561
- const child = spawn3(process.execPath, [process.argv[1], ...args], {
27562
+ const child = spawn4(process.execPath, [process.argv[1], ...args], {
27562
27563
  detached: true,
27563
27564
  stdio: "ignore"
27564
27565
  });
@@ -27670,7 +27671,7 @@ async function cmdRun4(args) {
27670
27671
  });
27671
27672
  return;
27672
27673
  }
27673
- const child = spawn3(coder, coderArgs.slice(1), {
27674
+ const child = spawn4(coder, coderArgs.slice(1), {
27674
27675
  env,
27675
27676
  stdio: "inherit"
27676
27677
  });
@@ -29426,6 +29427,8 @@ async function cmdUpdate3(args) {
29426
29427
 
29427
29428
  // src/cli/ui.ts
29428
29429
  var import_picocolors12 = __toESM(require_picocolors(), 1);
29430
+ import { spawn as spawn3 } from "node:child_process";
29431
+ import { open } from "node:fs/promises";
29429
29432
 
29430
29433
  // src/server/index.ts
29431
29434
  import http2 from "node:http";
@@ -30453,7 +30456,7 @@ function getUiDir() {
30453
30456
  }
30454
30457
  return join9(__dirname2, "..", "..", "ui", "dist");
30455
30458
  }
30456
- async function startServer(portArg) {
30459
+ async function startServer(portArg, options) {
30457
30460
  const port = portArg || await findAvailablePort(3141);
30458
30461
  const host = "127.0.0.1";
30459
30462
  const router = new Router;
@@ -30521,7 +30524,9 @@ async function startServer(portArg) {
30521
30524
  console.log(` Server: ${import_picocolors11.default.cyan(url2)}`);
30522
30525
  console.log(` Press ${import_picocolors11.default.bold("Ctrl+C")} to stop`);
30523
30526
  console.log();
30524
- openBrowser(url2);
30527
+ if (!options?.noBrowser) {
30528
+ openBrowser(url2);
30529
+ }
30525
30530
  const handle = {
30526
30531
  host,
30527
30532
  port,
@@ -30538,45 +30543,230 @@ async function startServer(portArg) {
30538
30543
  return handle;
30539
30544
  }
30540
30545
 
30541
- // src/cli/ui.ts
30542
- async function handleUiCommand(args) {
30543
- const port = getPortFromArgs(args);
30546
+ // src/utils/daemon.ts
30547
+ init_paths();
30548
+ import { existsSync as existsSync12 } from "node:fs";
30549
+ import { readFile as readFile9, writeFile as writeFile8, unlink as unlink2 } from "node:fs/promises";
30550
+ import { join as join10 } from "node:path";
30551
+ function getPidFilePath() {
30552
+ return join10(getConfigDir("swixter"), "ui.pid");
30553
+ }
30554
+ function getLogFilePath() {
30555
+ return join10(getConfigDir("swixter"), "ui.log");
30556
+ }
30557
+ async function readPidFile() {
30558
+ const path = getPidFilePath();
30559
+ if (!existsSync12(path))
30560
+ return null;
30544
30561
  try {
30545
- const server = await startServer(port);
30546
- process.on("SIGINT", () => {
30547
- console.log();
30548
- console.log(import_picocolors12.default.dim("Shutting down..."));
30549
- server.close(() => {
30550
- process.exit(0);
30551
- });
30562
+ const content = await readFile9(path, "utf-8");
30563
+ return JSON.parse(content);
30564
+ } catch {
30565
+ return null;
30566
+ }
30567
+ }
30568
+ async function writePidFile(pid, port) {
30569
+ const path = getPidFilePath();
30570
+ const data = { pid, port, startTime: new Date().toISOString() };
30571
+ await writeFile8(path, JSON.stringify(data, null, 2), "utf-8");
30572
+ }
30573
+ async function removePidFile() {
30574
+ const path = getPidFilePath();
30575
+ if (existsSync12(path)) {
30576
+ await unlink2(path).catch(() => {});
30577
+ }
30578
+ }
30579
+ function isProcessAlive2(pid) {
30580
+ try {
30581
+ process.kill(pid, 0);
30582
+ return true;
30583
+ } catch {
30584
+ return false;
30585
+ }
30586
+ }
30587
+ async function isSwixterUiRunning(pid, port) {
30588
+ if (!isProcessAlive2(pid))
30589
+ return false;
30590
+ try {
30591
+ const res = await fetch(`http://127.0.0.1:${port}/api/version`, {
30592
+ signal: AbortSignal.timeout(3000)
30552
30593
  });
30553
- process.stdin.resume();
30554
- } catch (error46) {
30555
- console.error(import_picocolors12.default.red(`Failed to start server: ${error46}`));
30594
+ return res.ok;
30595
+ } catch {
30596
+ return false;
30597
+ }
30598
+ }
30599
+ async function cleanupStalePidFile() {
30600
+ const data = await readPidFile();
30601
+ if (data && !isProcessAlive2(data.pid)) {
30602
+ await removePidFile();
30603
+ }
30604
+ }
30605
+ async function stopDaemon() {
30606
+ const data = await readPidFile();
30607
+ if (!data) {
30608
+ return { success: false, message: "No daemon process is running." };
30609
+ }
30610
+ if (!isProcessAlive2(data.pid)) {
30611
+ await removePidFile();
30612
+ return { success: false, message: "Daemon process is not running (stale PID file removed)." };
30613
+ }
30614
+ try {
30615
+ process.kill(data.pid, "SIGTERM");
30616
+ await removePidFile();
30617
+ return { success: true, message: `Daemon process ${data.pid} stopped.` };
30618
+ } catch {
30619
+ await removePidFile();
30620
+ return { success: false, message: "Failed to stop daemon process (PID file removed)." };
30621
+ }
30622
+ }
30623
+
30624
+ // src/cli/ui.ts
30625
+ async function handleUiCommand(args) {
30626
+ const flags = parseFlags2(args);
30627
+ if (flags.stop) {
30628
+ const result = await stopDaemon();
30629
+ console.log();
30630
+ console.log(result.success ? import_picocolors12.default.green("✓") + " " + result.message : import_picocolors12.default.yellow("⚠") + " " + result.message);
30631
+ console.log();
30632
+ process.exit(result.success ? 0 : 1);
30633
+ }
30634
+ if (flags.status) {
30635
+ await showStatus();
30636
+ return;
30637
+ }
30638
+ if (flags.daemon) {
30639
+ await startDaemon(flags.port);
30640
+ return;
30641
+ }
30642
+ await runForeground(flags.port);
30643
+ }
30644
+ async function showStatus() {
30645
+ await cleanupStalePidFile();
30646
+ const data = await readPidFile();
30647
+ console.log();
30648
+ if (!data) {
30649
+ console.log(import_picocolors12.default.yellow("Swixter UI is not running."));
30650
+ console.log(import_picocolors12.default.dim("Run 'swixter ui --daemon' to start in background."));
30651
+ console.log();
30652
+ return;
30653
+ }
30654
+ const isRunning = await isSwixterUiRunning(data.pid, data.port);
30655
+ if (isRunning) {
30656
+ console.log(import_picocolors12.default.green("✓ Swixter UI is running"));
30657
+ console.log(` PID: ${import_picocolors12.default.cyan(String(data.pid))}`);
30658
+ console.log(` URL: ${import_picocolors12.default.cyan(`http://127.0.0.1:${data.port}`)}`);
30659
+ console.log(` Started: ${import_picocolors12.default.dim(data.startTime)}`);
30660
+ } else {
30661
+ console.log(import_picocolors12.default.yellow("⚠ Swixter UI is not running (stale PID file removed)."));
30662
+ }
30663
+ console.log();
30664
+ }
30665
+ async function startDaemon(portArg) {
30666
+ await cleanupStalePidFile();
30667
+ const existing = await readPidFile();
30668
+ if (existing && await isSwixterUiRunning(existing.pid, existing.port)) {
30669
+ console.log();
30670
+ console.log(import_picocolors12.default.yellow("Swixter UI is already running."));
30671
+ console.log(` PID: ${import_picocolors12.default.cyan(String(existing.pid))}`);
30672
+ console.log(` URL: ${import_picocolors12.default.cyan(`http://127.0.0.1:${existing.port}`)}`);
30673
+ console.log();
30674
+ openBrowser(`http://127.0.0.1:${existing.port}`);
30675
+ return;
30676
+ }
30677
+ const port = portArg || await findAvailablePort(3141);
30678
+ const childArgs = process.argv.slice(1).filter((arg) => arg !== "--daemon" && arg !== "--stop" && arg !== "--status");
30679
+ const logPath = getLogFilePath();
30680
+ const logFile = await open(logPath, "a");
30681
+ const child = spawn3(process.argv0, childArgs, {
30682
+ detached: true,
30683
+ stdio: ["ignore", logFile.fd, logFile.fd],
30684
+ env: { ...process.env, SWIXTER_UI_DAEMON: "1" }
30685
+ });
30686
+ child.unref();
30687
+ const url2 = `http://127.0.0.1:${port}`;
30688
+ const started = await waitForServer(url2, 1e4);
30689
+ if (!started) {
30690
+ try {
30691
+ process.kill(child.pid, "SIGTERM");
30692
+ } catch {}
30693
+ console.log();
30694
+ console.log(import_picocolors12.default.red("✗ Failed to start daemon (timed out waiting for server)."));
30695
+ console.log();
30556
30696
  process.exit(1);
30557
30697
  }
30698
+ await writePidFile(child.pid, port);
30699
+ console.log();
30700
+ console.log(import_picocolors12.default.green("✓ Swixter UI daemon started"));
30701
+ console.log(` PID: ${import_picocolors12.default.cyan(String(child.pid))}`);
30702
+ console.log(` URL: ${import_picocolors12.default.cyan(url2)}`);
30703
+ console.log(` Log: ${import_picocolors12.default.dim(logPath)}`);
30704
+ console.log();
30705
+ console.log(import_picocolors12.default.dim("Run 'swixter ui --stop' to stop."));
30706
+ console.log();
30558
30707
  }
30559
- function getPortFromArgs(args) {
30560
- if (!args || args.length === 0) {
30708
+ async function runForeground(portArg) {
30709
+ await cleanupStalePidFile();
30710
+ const existing = await readPidFile();
30711
+ if (existing && await isSwixterUiRunning(existing.pid, existing.port)) {
30712
+ const url2 = `http://127.0.0.1:${existing.port}`;
30713
+ console.log();
30714
+ console.log(import_picocolors12.default.green("✓ Swixter UI is already running"));
30715
+ console.log(` URL: ${import_picocolors12.default.cyan(url2)}`);
30716
+ console.log();
30717
+ openBrowser(url2);
30561
30718
  return;
30562
30719
  }
30720
+ const port = portArg || await findAvailablePort(3141);
30721
+ const noBrowser = process.env.SWIXTER_UI_DAEMON === "1";
30722
+ const server = await startServer(port, { noBrowser });
30723
+ await writePidFile(process.pid, port);
30724
+ const shutdown = () => {
30725
+ console.log();
30726
+ console.log(import_picocolors12.default.dim("Shutting down..."));
30727
+ server.close(() => {
30728
+ removePidFile().catch(() => {});
30729
+ process.exit(0);
30730
+ });
30731
+ };
30732
+ process.on("SIGINT", shutdown);
30733
+ process.on("SIGTERM", shutdown);
30734
+ process.stdin.resume();
30735
+ }
30736
+ async function waitForServer(url2, timeoutMs) {
30737
+ const start = Date.now();
30738
+ const interval = 200;
30739
+ while (Date.now() - start < timeoutMs) {
30740
+ try {
30741
+ const res = await fetch(`${url2}/api/version`);
30742
+ if (res.ok)
30743
+ return true;
30744
+ } catch {}
30745
+ await new Promise((r2) => setTimeout(r2, interval));
30746
+ }
30747
+ return false;
30748
+ }
30749
+ function parseFlags2(args) {
30750
+ const result = { daemon: false, stop: false, status: false, port: undefined };
30751
+ if (!args)
30752
+ return result;
30563
30753
  for (let i2 = 0;i2 < args.length; i2++) {
30564
30754
  const arg = args[i2];
30565
- if (arg === "--port" || arg === "-p") {
30566
- const portStr = args[i2 + 1];
30567
- if (!portStr) {
30568
- console.error(import_picocolors12.default.red("Error: --port requires a value"));
30569
- process.exit(1);
30570
- }
30571
- const port = parseInt(portStr, 10);
30572
- if (isNaN(port) || port < 1 || port > 65535) {
30573
- console.error(import_picocolors12.default.red("Error: Invalid port number"));
30574
- process.exit(1);
30755
+ if (arg === "--daemon") {
30756
+ result.daemon = true;
30757
+ } else if (arg === "--stop") {
30758
+ result.stop = true;
30759
+ } else if (arg === "--status") {
30760
+ result.status = true;
30761
+ } else if ((arg === "--port" || arg === "-p") && args[i2 + 1]) {
30762
+ const port = parseInt(args[i2 + 1], 10);
30763
+ if (!isNaN(port) && port >= 1 && port <= 65535) {
30764
+ result.port = port;
30575
30765
  }
30576
- return port;
30766
+ i2++;
30577
30767
  }
30578
30768
  }
30579
- return;
30769
+ return result;
30580
30770
  }
30581
30771
 
30582
30772
  // src/cli/index.ts
@@ -30601,6 +30791,12 @@ ${import_picocolors13.default.bold("Web UI:")}
30601
30791
  ${import_picocolors13.default.cyan("ui")} ${import_picocolors13.default.dim("Launch local Web UI")}
30602
30792
  ${import_picocolors13.default.dim("swixter ui [--port <port>]")}
30603
30793
  ${import_picocolors13.default.dim("Start local HTTP server and open browser")}
30794
+ ${import_picocolors13.default.dim("swixter ui --daemon [--port <port>]")}
30795
+ ${import_picocolors13.default.dim("Start server in background")}
30796
+ ${import_picocolors13.default.dim("swixter ui --stop")}
30797
+ ${import_picocolors13.default.dim("Stop background server")}
30798
+ ${import_picocolors13.default.dim("swixter ui --status")}
30799
+ ${import_picocolors13.default.dim("Show background server status")}
30604
30800
 
30605
30801
  ${import_picocolors13.default.bold("Proxy Commands:")}
30606
30802
  ${import_picocolors13.default.cyan("proxy")} ${import_picocolors13.default.dim("Start proxy server or run with proxy")}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swixter",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "CLI tool for managing AI coding assistant configurations - easily switch between providers (Claude Code, Codex, Continue) with Anthropic, Ollama, or custom APIs",
5
5
  "main": "dist/cli/index.js",
6
6
  "module": "dist/cli/index.js",