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.
- package/dist/cli/index.js +239 -43
- 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,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
|
-
|
|
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/
|
|
30542
|
-
|
|
30543
|
-
|
|
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
|
|
30546
|
-
|
|
30547
|
-
|
|
30548
|
-
|
|
30549
|
-
|
|
30550
|
-
|
|
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
|
-
|
|
30554
|
-
} catch
|
|
30555
|
-
|
|
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
|
|
30560
|
-
|
|
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 === "--
|
|
30566
|
-
|
|
30567
|
-
|
|
30568
|
-
|
|
30569
|
-
|
|
30570
|
-
|
|
30571
|
-
|
|
30572
|
-
|
|
30573
|
-
|
|
30574
|
-
|
|
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
|
-
|
|
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.
|
|
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",
|