swixter 0.1.3 → 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 +244 -47
  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.3";
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 existsSync11 } 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 (!existsSync11(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 (existsSync11(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,9 +29427,12 @@ 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";
29435
+ import { existsSync as existsSync11 } from "node:fs";
29432
29436
  import { dirname as dirname9, join as join9 } from "node:path";
29433
29437
  import { fileURLToPath } from "node:url";
29434
29438
 
@@ -30446,13 +30450,13 @@ function openBrowser(url2) {
30446
30450
  });
30447
30451
  }
30448
30452
  function getUiDir() {
30449
- const isDev = true;
30450
- if (isDev) {
30451
- return join9(__dirname2, "..", "..", "ui", "dist");
30453
+ const bundledUiDir = join9(__dirname2, "..", "ui");
30454
+ if (existsSync11(join9(bundledUiDir, "index.html"))) {
30455
+ return bundledUiDir;
30452
30456
  }
30453
- return join9(__dirname2, "..", "..", "ui");
30457
+ return join9(__dirname2, "..", "..", "ui", "dist");
30454
30458
  }
30455
- async function startServer(portArg) {
30459
+ async function startServer(portArg, options) {
30456
30460
  const port = portArg || await findAvailablePort(3141);
30457
30461
  const host = "127.0.0.1";
30458
30462
  const router = new Router;
@@ -30520,7 +30524,9 @@ async function startServer(portArg) {
30520
30524
  console.log(` Server: ${import_picocolors11.default.cyan(url2)}`);
30521
30525
  console.log(` Press ${import_picocolors11.default.bold("Ctrl+C")} to stop`);
30522
30526
  console.log();
30523
- openBrowser(url2);
30527
+ if (!options?.noBrowser) {
30528
+ openBrowser(url2);
30529
+ }
30524
30530
  const handle = {
30525
30531
  host,
30526
30532
  port,
@@ -30537,45 +30543,230 @@ async function startServer(portArg) {
30537
30543
  return handle;
30538
30544
  }
30539
30545
 
30540
- // src/cli/ui.ts
30541
- async function handleUiCommand(args) {
30542
- 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;
30543
30561
  try {
30544
- const server = await startServer(port);
30545
- process.on("SIGINT", () => {
30546
- console.log();
30547
- console.log(import_picocolors12.default.dim("Shutting down..."));
30548
- server.close(() => {
30549
- process.exit(0);
30550
- });
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)
30551
30593
  });
30552
- process.stdin.resume();
30553
- } catch (error46) {
30554
- 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();
30555
30696
  process.exit(1);
30556
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();
30557
30707
  }
30558
- function getPortFromArgs(args) {
30559
- 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);
30560
30718
  return;
30561
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;
30562
30753
  for (let i2 = 0;i2 < args.length; i2++) {
30563
30754
  const arg = args[i2];
30564
- if (arg === "--port" || arg === "-p") {
30565
- const portStr = args[i2 + 1];
30566
- if (!portStr) {
30567
- console.error(import_picocolors12.default.red("Error: --port requires a value"));
30568
- process.exit(1);
30569
- }
30570
- const port = parseInt(portStr, 10);
30571
- if (isNaN(port) || port < 1 || port > 65535) {
30572
- console.error(import_picocolors12.default.red("Error: Invalid port number"));
30573
- 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;
30574
30765
  }
30575
- return port;
30766
+ i2++;
30576
30767
  }
30577
30768
  }
30578
- return;
30769
+ return result;
30579
30770
  }
30580
30771
 
30581
30772
  // src/cli/index.ts
@@ -30600,6 +30791,12 @@ ${import_picocolors13.default.bold("Web UI:")}
30600
30791
  ${import_picocolors13.default.cyan("ui")} ${import_picocolors13.default.dim("Launch local Web UI")}
30601
30792
  ${import_picocolors13.default.dim("swixter ui [--port <port>]")}
30602
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")}
30603
30800
 
30604
30801
  ${import_picocolors13.default.bold("Proxy Commands:")}
30605
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.3",
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",