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.
- package/dist/cli/index.js +244 -47
- 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.
|
|
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
|
|
26531
|
-
import { readFile as
|
|
26532
|
-
import { join as
|
|
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
|
|
26535
|
+
return join11(getConfigDir("swixter"), AUTH_FILE);
|
|
26535
26536
|
}
|
|
26536
26537
|
async function loadAuthState() {
|
|
26537
26538
|
const authPath = getAuthFilePath();
|
|
26538
|
-
if (!
|
|
26539
|
+
if (!existsSync13(authPath))
|
|
26539
26540
|
return null;
|
|
26540
26541
|
try {
|
|
26541
|
-
const content = await
|
|
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
|
|
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 (
|
|
26554
|
-
await
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
|
30450
|
-
if (
|
|
30451
|
-
return
|
|
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
|
-
|
|
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/
|
|
30541
|
-
|
|
30542
|
-
|
|
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
|
|
30545
|
-
|
|
30546
|
-
|
|
30547
|
-
|
|
30548
|
-
|
|
30549
|
-
|
|
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
|
-
|
|
30553
|
-
} catch
|
|
30554
|
-
|
|
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
|
|
30559
|
-
|
|
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 === "--
|
|
30565
|
-
|
|
30566
|
-
|
|
30567
|
-
|
|
30568
|
-
|
|
30569
|
-
|
|
30570
|
-
|
|
30571
|
-
|
|
30572
|
-
|
|
30573
|
-
|
|
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
|
-
|
|
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
|
+
"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",
|