swixter 0.0.9 → 0.0.11
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/README.md +7 -2
- package/dist/cli/index.js +1042 -176
- package/package.json +4 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,31 +1,51 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from "node:module";
|
|
2
3
|
var __create = Object.create;
|
|
3
4
|
var __getProtoOf = Object.getPrototypeOf;
|
|
4
5
|
var __defProp = Object.defineProperty;
|
|
5
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
function __accessProp(key) {
|
|
9
|
+
return this[key];
|
|
10
|
+
}
|
|
11
|
+
var __toESMCache_node;
|
|
12
|
+
var __toESMCache_esm;
|
|
7
13
|
var __toESM = (mod, isNodeMode, target) => {
|
|
14
|
+
var canCache = mod != null && typeof mod === "object";
|
|
15
|
+
if (canCache) {
|
|
16
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
17
|
+
var cached = cache.get(mod);
|
|
18
|
+
if (cached)
|
|
19
|
+
return cached;
|
|
20
|
+
}
|
|
8
21
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
22
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
23
|
for (let key of __getOwnPropNames(mod))
|
|
11
24
|
if (!__hasOwnProp.call(to, key))
|
|
12
25
|
__defProp(to, key, {
|
|
13
|
-
get: (
|
|
26
|
+
get: __accessProp.bind(mod, key),
|
|
14
27
|
enumerable: true
|
|
15
28
|
});
|
|
29
|
+
if (canCache)
|
|
30
|
+
cache.set(mod, to);
|
|
16
31
|
return to;
|
|
17
32
|
};
|
|
18
33
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
34
|
+
var __returnValue = (v) => v;
|
|
35
|
+
function __exportSetter(name, newValue) {
|
|
36
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
37
|
+
}
|
|
19
38
|
var __export = (target, all) => {
|
|
20
39
|
for (var name in all)
|
|
21
40
|
__defProp(target, name, {
|
|
22
41
|
get: all[name],
|
|
23
42
|
enumerable: true,
|
|
24
43
|
configurable: true,
|
|
25
|
-
set: (
|
|
44
|
+
set: __exportSetter.bind(all, name)
|
|
26
45
|
});
|
|
27
46
|
};
|
|
28
47
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
48
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
29
49
|
|
|
30
50
|
// node_modules/picocolors/picocolors.js
|
|
31
51
|
var require_picocolors = __commonJS((exports, module) => {
|
|
@@ -13164,6 +13184,10 @@ function getConfigPath(type) {
|
|
|
13164
13184
|
const config2 = PATH_CONFIG[type];
|
|
13165
13185
|
return join(homedir(), config2.dir, config2.file);
|
|
13166
13186
|
}
|
|
13187
|
+
function getConfigDir(type) {
|
|
13188
|
+
const config2 = PATH_CONFIG[type];
|
|
13189
|
+
return join(homedir(), config2.dir);
|
|
13190
|
+
}
|
|
13167
13191
|
var PATH_CONFIG;
|
|
13168
13192
|
var init_paths = __esm(() => {
|
|
13169
13193
|
PATH_CONFIG = {
|
|
@@ -13237,7 +13261,7 @@ var CONFIG_VERSION = "2.0.0", EXPORT_VERSION = "1.0.0";
|
|
|
13237
13261
|
var init_versions2 = () => {};
|
|
13238
13262
|
|
|
13239
13263
|
// src/constants/meta.ts
|
|
13240
|
-
var APP_VERSION = "0.0.
|
|
13264
|
+
var APP_VERSION = "0.0.11";
|
|
13241
13265
|
var init_meta = () => {};
|
|
13242
13266
|
|
|
13243
13267
|
// src/constants/install.ts
|
|
@@ -13533,6 +13557,42 @@ var init_presets = __esm(() => {
|
|
|
13533
13557
|
allPresets = builtInPresets;
|
|
13534
13558
|
});
|
|
13535
13559
|
|
|
13560
|
+
// src/utils/model-helper.ts
|
|
13561
|
+
function getOpenAIModel(profile) {
|
|
13562
|
+
if (profile.models) {
|
|
13563
|
+
return;
|
|
13564
|
+
}
|
|
13565
|
+
return profile.model || profile.openaiModel;
|
|
13566
|
+
}
|
|
13567
|
+
function buildProfileEnv(profile, envVarMapping, baseURL, options) {
|
|
13568
|
+
const env = {};
|
|
13569
|
+
if (baseURL && envVarMapping.baseURL) {
|
|
13570
|
+
env[envVarMapping.baseURL] = baseURL;
|
|
13571
|
+
}
|
|
13572
|
+
if (profile.apiKey) {
|
|
13573
|
+
const apiKeyEnvName = options?.apiKeyEnvName || envVarMapping.apiKey;
|
|
13574
|
+
if (apiKeyEnvName) {
|
|
13575
|
+
env[apiKeyEnvName] = profile.apiKey;
|
|
13576
|
+
}
|
|
13577
|
+
}
|
|
13578
|
+
if (profile.authToken && envVarMapping.authToken) {
|
|
13579
|
+
env[envVarMapping.authToken] = profile.authToken;
|
|
13580
|
+
}
|
|
13581
|
+
if (profile.models) {
|
|
13582
|
+
for (const [key, value] of Object.entries(profile.models)) {
|
|
13583
|
+
const envName = envVarMapping[key];
|
|
13584
|
+
if (value && envName) {
|
|
13585
|
+
env[envName] = value;
|
|
13586
|
+
}
|
|
13587
|
+
}
|
|
13588
|
+
}
|
|
13589
|
+
const openaiModel = profile.model || profile.openaiModel;
|
|
13590
|
+
if (openaiModel && envVarMapping.openaiModel) {
|
|
13591
|
+
env[envVarMapping.openaiModel] = openaiModel;
|
|
13592
|
+
}
|
|
13593
|
+
return env;
|
|
13594
|
+
}
|
|
13595
|
+
|
|
13536
13596
|
// src/adapters/claude.ts
|
|
13537
13597
|
import { existsSync as existsSync2 } from "node:fs";
|
|
13538
13598
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "node:fs/promises";
|
|
@@ -13555,29 +13615,7 @@ class ClaudeCodeAdapter {
|
|
|
13555
13615
|
}
|
|
13556
13616
|
}
|
|
13557
13617
|
const envVars = this.coderConfig.envVarMapping;
|
|
13558
|
-
const newEnv =
|
|
13559
|
-
[envVars.baseURL]: baseURL
|
|
13560
|
-
};
|
|
13561
|
-
if (profile.apiKey) {
|
|
13562
|
-
newEnv[envVars.apiKey] = profile.apiKey;
|
|
13563
|
-
}
|
|
13564
|
-
if (profile.authToken && envVars.authToken) {
|
|
13565
|
-
newEnv[envVars.authToken] = profile.authToken;
|
|
13566
|
-
}
|
|
13567
|
-
if (profile.models) {
|
|
13568
|
-
if (profile.models.anthropicModel && envVars.anthropicModel) {
|
|
13569
|
-
newEnv[envVars.anthropicModel] = profile.models.anthropicModel;
|
|
13570
|
-
}
|
|
13571
|
-
if (profile.models.defaultHaikuModel && envVars.defaultHaikuModel) {
|
|
13572
|
-
newEnv[envVars.defaultHaikuModel] = profile.models.defaultHaikuModel;
|
|
13573
|
-
}
|
|
13574
|
-
if (profile.models.defaultOpusModel && envVars.defaultOpusModel) {
|
|
13575
|
-
newEnv[envVars.defaultOpusModel] = profile.models.defaultOpusModel;
|
|
13576
|
-
}
|
|
13577
|
-
if (profile.models.defaultSonnetModel && envVars.defaultSonnetModel) {
|
|
13578
|
-
newEnv[envVars.defaultSonnetModel] = profile.models.defaultSonnetModel;
|
|
13579
|
-
}
|
|
13580
|
-
}
|
|
13618
|
+
const newEnv = buildProfileEnv(profile, envVars, baseURL);
|
|
13581
13619
|
const managedKeys = Object.values(envVars).filter(Boolean);
|
|
13582
13620
|
const preservedEnv = {};
|
|
13583
13621
|
if (existingConfig.env) {
|
|
@@ -13605,25 +13643,13 @@ class ClaudeCodeAdapter {
|
|
|
13605
13643
|
const preset = await getPresetByIdAsync(profile.providerId);
|
|
13606
13644
|
const expectedBaseURL = profile.baseURL || preset?.baseURL || "";
|
|
13607
13645
|
const envVars = this.coderConfig.envVarMapping;
|
|
13608
|
-
const
|
|
13609
|
-
const
|
|
13610
|
-
|
|
13611
|
-
|
|
13612
|
-
if (profile.models.anthropicModel && envVars.anthropicModel) {
|
|
13613
|
-
hasMatchingModels = hasMatchingModels && config2.env?.[envVars.anthropicModel] === profile.models.anthropicModel;
|
|
13614
|
-
}
|
|
13615
|
-
if (profile.models.defaultHaikuModel && envVars.defaultHaikuModel) {
|
|
13616
|
-
hasMatchingModels = hasMatchingModels && config2.env?.[envVars.defaultHaikuModel] === profile.models.defaultHaikuModel;
|
|
13617
|
-
}
|
|
13618
|
-
if (profile.models.defaultOpusModel && envVars.defaultOpusModel) {
|
|
13619
|
-
hasMatchingModels = hasMatchingModels && config2.env?.[envVars.defaultOpusModel] === profile.models.defaultOpusModel;
|
|
13620
|
-
}
|
|
13621
|
-
if (profile.models.defaultSonnetModel && envVars.defaultSonnetModel) {
|
|
13622
|
-
hasMatchingModels = hasMatchingModels && config2.env?.[envVars.defaultSonnetModel] === profile.models.defaultSonnetModel;
|
|
13646
|
+
const expectedEnv = buildProfileEnv(profile, envVars, expectedBaseURL);
|
|
13647
|
+
for (const [key, value] of Object.entries(expectedEnv)) {
|
|
13648
|
+
if (config2.env?.[key] !== value) {
|
|
13649
|
+
return false;
|
|
13623
13650
|
}
|
|
13624
13651
|
}
|
|
13625
|
-
|
|
13626
|
-
return (noCredentials || hasApiKey || hasAuthToken) && config2.env?.[envVars.baseURL] === expectedBaseURL && hasMatchingModels;
|
|
13652
|
+
return Object.keys(expectedEnv).length > 0;
|
|
13627
13653
|
} catch (error46) {
|
|
13628
13654
|
return false;
|
|
13629
13655
|
}
|
|
@@ -16247,14 +16273,6 @@ var init_js_yaml = __esm(() => {
|
|
|
16247
16273
|
safeDump = renamed("safeDump", "dump");
|
|
16248
16274
|
});
|
|
16249
16275
|
|
|
16250
|
-
// src/utils/model-helper.ts
|
|
16251
|
-
function getOpenAIModel(profile) {
|
|
16252
|
-
if (profile.models) {
|
|
16253
|
-
return;
|
|
16254
|
-
}
|
|
16255
|
-
return profile.model || profile.openaiModel;
|
|
16256
|
-
}
|
|
16257
|
-
|
|
16258
16276
|
// src/adapters/continue.ts
|
|
16259
16277
|
import { existsSync as existsSync3 } from "node:fs";
|
|
16260
16278
|
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "node:fs/promises";
|
|
@@ -17701,6 +17719,21 @@ var init_adapters = __esm(() => {
|
|
|
17701
17719
|
});
|
|
17702
17720
|
|
|
17703
17721
|
// src/config/manager.ts
|
|
17722
|
+
var exports_manager = {};
|
|
17723
|
+
__export(exports_manager, {
|
|
17724
|
+
upsertProfile: () => upsertProfile,
|
|
17725
|
+
setActiveProfileForCoder: () => setActiveProfileForCoder,
|
|
17726
|
+
setActiveProfile: () => setActiveProfile,
|
|
17727
|
+
saveConfig: () => saveConfig,
|
|
17728
|
+
profileExists: () => profileExists,
|
|
17729
|
+
loadConfig: () => loadConfig,
|
|
17730
|
+
listProfiles: () => listProfiles,
|
|
17731
|
+
getProfile: () => getProfile,
|
|
17732
|
+
getConfigPath: () => getConfigPath2,
|
|
17733
|
+
getActiveProfileForCoder: () => getActiveProfileForCoder,
|
|
17734
|
+
getActiveProfile: () => getActiveProfile,
|
|
17735
|
+
deleteProfile: () => deleteProfile
|
|
17736
|
+
});
|
|
17704
17737
|
import { existsSync as existsSync5 } from "node:fs";
|
|
17705
17738
|
import { mkdir as mkdir5, readFile as readFile5, writeFile as writeFile5 } from "node:fs/promises";
|
|
17706
17739
|
import { dirname as dirname5 } from "node:path";
|
|
@@ -17758,6 +17791,9 @@ async function saveConfig(config2) {
|
|
|
17758
17791
|
throw new Error(`Failed to save configuration: ${error46}`);
|
|
17759
17792
|
}
|
|
17760
17793
|
}
|
|
17794
|
+
async function getActiveProfile() {
|
|
17795
|
+
return getActiveProfileForCoder("claude");
|
|
17796
|
+
}
|
|
17761
17797
|
async function getActiveProfileForCoder(coder) {
|
|
17762
17798
|
const config2 = await loadConfig();
|
|
17763
17799
|
const coderConfig = config2.coders[coder];
|
|
@@ -17766,6 +17802,9 @@ async function getActiveProfileForCoder(coder) {
|
|
|
17766
17802
|
}
|
|
17767
17803
|
return config2.profiles[coderConfig.activeProfile];
|
|
17768
17804
|
}
|
|
17805
|
+
async function setActiveProfile(profileName) {
|
|
17806
|
+
return setActiveProfileForCoder("claude", profileName);
|
|
17807
|
+
}
|
|
17769
17808
|
async function setActiveProfileForCoder(coder, profileName) {
|
|
17770
17809
|
const config2 = await loadConfig();
|
|
17771
17810
|
if (!config2.profiles[profileName]) {
|
|
@@ -17823,6 +17862,14 @@ async function listProfiles() {
|
|
|
17823
17862
|
const config2 = await loadConfig();
|
|
17824
17863
|
return Object.values(config2.profiles);
|
|
17825
17864
|
}
|
|
17865
|
+
async function getProfile(profileName) {
|
|
17866
|
+
const config2 = await loadConfig();
|
|
17867
|
+
return config2.profiles[profileName] || null;
|
|
17868
|
+
}
|
|
17869
|
+
async function profileExists(profileName) {
|
|
17870
|
+
const config2 = await loadConfig();
|
|
17871
|
+
return profileName in config2.profiles;
|
|
17872
|
+
}
|
|
17826
17873
|
var init_manager = __esm(() => {
|
|
17827
17874
|
init_types();
|
|
17828
17875
|
init_constants();
|
|
@@ -19614,7 +19661,7 @@ var require_semver2 = __commonJS((exports, module) => {
|
|
|
19614
19661
|
});
|
|
19615
19662
|
|
|
19616
19663
|
// src/cli/index.ts
|
|
19617
|
-
var
|
|
19664
|
+
var import_picocolors15 = __toESM(require_picocolors(), 1);
|
|
19618
19665
|
|
|
19619
19666
|
// node_modules/@clack/core/dist/index.mjs
|
|
19620
19667
|
var import_sisteransi = __toESM(require_src(), 1);
|
|
@@ -20336,7 +20383,8 @@ var FLAG_ALIASES = {
|
|
|
20336
20383
|
"-o": "--output",
|
|
20337
20384
|
"-i": "--input",
|
|
20338
20385
|
"-y": "--yes",
|
|
20339
|
-
"-v": "--verbose"
|
|
20386
|
+
"-v": "--verbose",
|
|
20387
|
+
"-P": "--port"
|
|
20340
20388
|
};
|
|
20341
20389
|
var VALID_COMMANDS = [
|
|
20342
20390
|
"create",
|
|
@@ -20357,7 +20405,8 @@ var GLOBAL_COMMANDS = [
|
|
|
20357
20405
|
"import",
|
|
20358
20406
|
"completion",
|
|
20359
20407
|
"help",
|
|
20360
|
-
"version"
|
|
20408
|
+
"version",
|
|
20409
|
+
"ui"
|
|
20361
20410
|
];
|
|
20362
20411
|
function resolveFlagAlias(flag) {
|
|
20363
20412
|
return FLAG_ALIASES[flag] || flag;
|
|
@@ -20436,7 +20485,7 @@ async function handleApplyPrompt(options) {
|
|
|
20436
20485
|
var import_picocolors5 = __toESM(require_picocolors(), 1);
|
|
20437
20486
|
import { spawn } from "node:child_process";
|
|
20438
20487
|
function spawnCLI(options) {
|
|
20439
|
-
const { command, args, env, displayName } = options;
|
|
20488
|
+
const { command, args, env, displayName, onExit } = options;
|
|
20440
20489
|
const finalEnv = env ? { ...process.env, ...env } : process.env;
|
|
20441
20490
|
const child = spawn(command, args, {
|
|
20442
20491
|
env: finalEnv,
|
|
@@ -20444,6 +20493,7 @@ function spawnCLI(options) {
|
|
|
20444
20493
|
shell: true
|
|
20445
20494
|
});
|
|
20446
20495
|
child.on("exit", (code) => {
|
|
20496
|
+
onExit?.();
|
|
20447
20497
|
process.exit(code || 0);
|
|
20448
20498
|
});
|
|
20449
20499
|
child.on("error", (error46) => {
|
|
@@ -20451,6 +20501,7 @@ function spawnCLI(options) {
|
|
|
20451
20501
|
console.log(import_picocolors5.default.red(`✗ Run failed: ${error46.message}`));
|
|
20452
20502
|
console.log(import_picocolors5.default.dim(`Please ensure ${displayName} CLI is installed`));
|
|
20453
20503
|
console.log();
|
|
20504
|
+
onExit?.();
|
|
20454
20505
|
process.exit(1);
|
|
20455
20506
|
});
|
|
20456
20507
|
}
|
|
@@ -21682,15 +21733,7 @@ async function cmdRun(args) {
|
|
|
21682
21733
|
env[key] = value;
|
|
21683
21734
|
}
|
|
21684
21735
|
}
|
|
21685
|
-
|
|
21686
|
-
env.ANTHROPIC_API_KEY = profile.apiKey;
|
|
21687
|
-
}
|
|
21688
|
-
if (profile.authToken) {
|
|
21689
|
-
env.ANTHROPIC_AUTH_TOKEN = profile.authToken;
|
|
21690
|
-
}
|
|
21691
|
-
if (baseURL) {
|
|
21692
|
-
env.ANTHROPIC_BASE_URL = baseURL;
|
|
21693
|
-
}
|
|
21736
|
+
Object.assign(env, buildProfileEnv(profile, CODER_CONFIG.envVarMapping, baseURL));
|
|
21694
21737
|
const claudeArgs = args.filter((arg, idx) => {
|
|
21695
21738
|
if (arg === "--profile") {
|
|
21696
21739
|
return false;
|
|
@@ -21700,6 +21743,13 @@ async function cmdRun(args) {
|
|
|
21700
21743
|
}
|
|
21701
21744
|
return true;
|
|
21702
21745
|
});
|
|
21746
|
+
const tmp = await import("node:os");
|
|
21747
|
+
const path = await import("node:path");
|
|
21748
|
+
const fs = await import("node:fs/promises");
|
|
21749
|
+
const settingsContent = JSON.stringify({ env }, null, 2);
|
|
21750
|
+
const tmpFile = path.join(tmp.tmpdir(), `swixter-settings-${Date.now()}.json`);
|
|
21751
|
+
await fs.writeFile(tmpFile, settingsContent, "utf-8");
|
|
21752
|
+
claudeArgs.push("--settings", tmpFile);
|
|
21703
21753
|
console.log();
|
|
21704
21754
|
console.log(import_picocolors8.default.dim(`Using profile: ${import_picocolors8.default.cyan(profile.name)} (${preset?.displayName})`));
|
|
21705
21755
|
console.log(import_picocolors8.default.dim(`Base URL: ${import_picocolors8.default.yellow(baseURL || "Default")}`));
|
|
@@ -21708,7 +21758,10 @@ async function cmdRun(args) {
|
|
|
21708
21758
|
command: "claude",
|
|
21709
21759
|
args: claudeArgs,
|
|
21710
21760
|
env,
|
|
21711
|
-
displayName: CODER_CONFIG.displayName
|
|
21761
|
+
displayName: CODER_CONFIG.displayName,
|
|
21762
|
+
onExit: () => {
|
|
21763
|
+
fs.unlink(tmpFile).catch(() => {});
|
|
21764
|
+
}
|
|
21712
21765
|
});
|
|
21713
21766
|
}
|
|
21714
21767
|
async function cmdInstall(args) {
|
|
@@ -22420,15 +22473,7 @@ async function cmdRun2(args) {
|
|
|
22420
22473
|
env[key] = value;
|
|
22421
22474
|
}
|
|
22422
22475
|
}
|
|
22423
|
-
|
|
22424
|
-
env.OPENAI_API_KEY = profile.apiKey;
|
|
22425
|
-
}
|
|
22426
|
-
if (baseURL) {
|
|
22427
|
-
env.OPENAI_BASE_URL = baseURL;
|
|
22428
|
-
}
|
|
22429
|
-
if (profile.model || profile.openaiModel) {
|
|
22430
|
-
env.OPENAI_MODEL = profile.model || profile.openaiModel;
|
|
22431
|
-
}
|
|
22476
|
+
Object.assign(env, buildProfileEnv(profile, CODER_CONFIG2.envVarMapping, baseURL));
|
|
22432
22477
|
const qwenArgs = [];
|
|
22433
22478
|
if (profile.apiKey) {
|
|
22434
22479
|
qwenArgs.push("--openai-api-key", profile.apiKey);
|
|
@@ -23316,12 +23361,9 @@ async function cmdRun3(args) {
|
|
|
23316
23361
|
env[key] = value;
|
|
23317
23362
|
}
|
|
23318
23363
|
}
|
|
23319
|
-
|
|
23320
|
-
|
|
23321
|
-
}
|
|
23322
|
-
if (profile.model || profile.openaiModel) {
|
|
23323
|
-
env["OPENAI_MODEL"] = profile.model || profile.openaiModel;
|
|
23324
|
-
}
|
|
23364
|
+
Object.assign(env, buildProfileEnv(profile, CODER_CONFIG3.envVarMapping, "", {
|
|
23365
|
+
apiKeyEnvName: envKey
|
|
23366
|
+
}));
|
|
23325
23367
|
const codexArgs = args.filter((arg, idx) => {
|
|
23326
23368
|
if (arg === "--profile") {
|
|
23327
23369
|
return false;
|
|
@@ -23364,6 +23406,611 @@ async function cmdUpdate3(args) {
|
|
|
23364
23406
|
await handleUpdateCommand(CODER_NAME3, CODER_CONFIG3, args);
|
|
23365
23407
|
}
|
|
23366
23408
|
|
|
23409
|
+
// src/cli/ui.ts
|
|
23410
|
+
var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
23411
|
+
|
|
23412
|
+
// src/server/index.ts
|
|
23413
|
+
var import_picocolors11 = __toESM(require_picocolors(), 1);
|
|
23414
|
+
import { createServer } from "node:http";
|
|
23415
|
+
import { dirname as dirname7, join as join6 } from "node:path";
|
|
23416
|
+
import { fileURLToPath } from "node:url";
|
|
23417
|
+
import { exec } from "node:child_process";
|
|
23418
|
+
|
|
23419
|
+
// src/server/middleware.ts
|
|
23420
|
+
function corsMiddleware(req, res, next) {
|
|
23421
|
+
const origin = req.headers.origin;
|
|
23422
|
+
if (origin && (origin.startsWith("http://127.0.0.1:") || origin.startsWith("http://localhost:"))) {
|
|
23423
|
+
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
23424
|
+
}
|
|
23425
|
+
if (req.method === "OPTIONS") {
|
|
23426
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
|
|
23427
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
|
23428
|
+
res.setHeader("Access-Control-Max-Age", "86400");
|
|
23429
|
+
res.statusCode = 204;
|
|
23430
|
+
res.end();
|
|
23431
|
+
return;
|
|
23432
|
+
}
|
|
23433
|
+
next();
|
|
23434
|
+
}
|
|
23435
|
+
function jsonBodyMiddleware(req, res, next) {
|
|
23436
|
+
if (!["POST", "PUT", "PATCH"].includes(req.method || "")) {
|
|
23437
|
+
next();
|
|
23438
|
+
return;
|
|
23439
|
+
}
|
|
23440
|
+
const contentType = req.headers["content-type"];
|
|
23441
|
+
if (!contentType?.includes("application/json")) {
|
|
23442
|
+
next();
|
|
23443
|
+
return;
|
|
23444
|
+
}
|
|
23445
|
+
const chunks = [];
|
|
23446
|
+
req.on("data", (chunk) => {
|
|
23447
|
+
chunks.push(chunk);
|
|
23448
|
+
});
|
|
23449
|
+
req.on("end", () => {
|
|
23450
|
+
try {
|
|
23451
|
+
if (chunks.length === 0) {
|
|
23452
|
+
next();
|
|
23453
|
+
return;
|
|
23454
|
+
}
|
|
23455
|
+
const body = Buffer.concat(chunks).toString("utf-8");
|
|
23456
|
+
req.body = JSON.parse(body);
|
|
23457
|
+
next();
|
|
23458
|
+
} catch (error46) {
|
|
23459
|
+
next(new Error("Invalid JSON body"));
|
|
23460
|
+
}
|
|
23461
|
+
});
|
|
23462
|
+
req.on("error", (error46) => {
|
|
23463
|
+
next(error46);
|
|
23464
|
+
});
|
|
23465
|
+
}
|
|
23466
|
+
function sendError(res, error46, statusCode = 400) {
|
|
23467
|
+
res.setHeader("Content-Type", "application/json");
|
|
23468
|
+
if (error46 instanceof Error) {
|
|
23469
|
+
res.statusCode = statusCode;
|
|
23470
|
+
res.end(JSON.stringify({
|
|
23471
|
+
error: {
|
|
23472
|
+
code: "UNKNOWN_ERROR",
|
|
23473
|
+
message: error46.message
|
|
23474
|
+
}
|
|
23475
|
+
}));
|
|
23476
|
+
return;
|
|
23477
|
+
}
|
|
23478
|
+
res.statusCode = statusCode;
|
|
23479
|
+
res.end(JSON.stringify({
|
|
23480
|
+
error: error46
|
|
23481
|
+
}));
|
|
23482
|
+
}
|
|
23483
|
+
function sendJson(res, data, statusCode = 200) {
|
|
23484
|
+
res.setHeader("Content-Type", "application/json");
|
|
23485
|
+
res.statusCode = statusCode;
|
|
23486
|
+
res.end(JSON.stringify(data));
|
|
23487
|
+
}
|
|
23488
|
+
function notFoundHandler(req, res) {
|
|
23489
|
+
res.setHeader("Content-Type", "application/json");
|
|
23490
|
+
res.statusCode = 404;
|
|
23491
|
+
res.end(JSON.stringify({
|
|
23492
|
+
error: {
|
|
23493
|
+
code: "NOT_FOUND",
|
|
23494
|
+
message: `Path ${req.url} not found`
|
|
23495
|
+
}
|
|
23496
|
+
}));
|
|
23497
|
+
}
|
|
23498
|
+
|
|
23499
|
+
// src/server/router.ts
|
|
23500
|
+
function extractParams(pattern, path) {
|
|
23501
|
+
const patternParts = pattern.replace(/\/$/, "").split("/").filter(Boolean);
|
|
23502
|
+
const pathParts = path.replace(/\/$/, "").split("/").filter(Boolean);
|
|
23503
|
+
if (patternParts.length !== pathParts.length) {
|
|
23504
|
+
return null;
|
|
23505
|
+
}
|
|
23506
|
+
const params = {};
|
|
23507
|
+
for (let i2 = 0;i2 < patternParts.length; i2++) {
|
|
23508
|
+
const patternPart = patternParts[i2];
|
|
23509
|
+
const pathPart = pathParts[i2];
|
|
23510
|
+
if (patternPart.startsWith(":")) {
|
|
23511
|
+
const paramName = patternPart.slice(1);
|
|
23512
|
+
params[paramName] = pathPart;
|
|
23513
|
+
} else if (patternPart !== pathPart) {
|
|
23514
|
+
return null;
|
|
23515
|
+
}
|
|
23516
|
+
}
|
|
23517
|
+
return params;
|
|
23518
|
+
}
|
|
23519
|
+
|
|
23520
|
+
class Router {
|
|
23521
|
+
routes = [];
|
|
23522
|
+
middleware = [];
|
|
23523
|
+
use(middleware) {
|
|
23524
|
+
this.middleware.push(middleware);
|
|
23525
|
+
}
|
|
23526
|
+
get(pattern, handler) {
|
|
23527
|
+
this.routes.push({ method: "GET", pattern, handler });
|
|
23528
|
+
}
|
|
23529
|
+
post(pattern, handler) {
|
|
23530
|
+
this.routes.push({ method: "POST", pattern, handler });
|
|
23531
|
+
}
|
|
23532
|
+
put(pattern, handler) {
|
|
23533
|
+
this.routes.push({ method: "PUT", pattern, handler });
|
|
23534
|
+
}
|
|
23535
|
+
delete(pattern, handler) {
|
|
23536
|
+
this.routes.push({ method: "DELETE", pattern, handler });
|
|
23537
|
+
}
|
|
23538
|
+
matchRoute(req) {
|
|
23539
|
+
const method = (req.method || "GET").toUpperCase();
|
|
23540
|
+
const url2 = new URL(req.url || "", `http://${req.headers.host || "localhost"}`);
|
|
23541
|
+
const path = url2.pathname;
|
|
23542
|
+
for (const route of this.routes) {
|
|
23543
|
+
if (route.method !== method) {
|
|
23544
|
+
continue;
|
|
23545
|
+
}
|
|
23546
|
+
const params = extractParams(route.pattern, path);
|
|
23547
|
+
if (params !== null) {
|
|
23548
|
+
return { route, params };
|
|
23549
|
+
}
|
|
23550
|
+
}
|
|
23551
|
+
return null;
|
|
23552
|
+
}
|
|
23553
|
+
async handle(req, res) {
|
|
23554
|
+
let middlewareIndex = 0;
|
|
23555
|
+
const runMiddleware = (error46) => {
|
|
23556
|
+
if (error46) {
|
|
23557
|
+
this.finalize(req, res, error46);
|
|
23558
|
+
return;
|
|
23559
|
+
}
|
|
23560
|
+
if (middlewareIndex < this.middleware.length) {
|
|
23561
|
+
const middleware = this.middleware[middlewareIndex++];
|
|
23562
|
+
Promise.resolve(middleware(req, res, runMiddleware)).catch(runMiddleware);
|
|
23563
|
+
return;
|
|
23564
|
+
}
|
|
23565
|
+
this.executeRoute(req, res).catch((error47) => {
|
|
23566
|
+
this.finalize(req, res, error47);
|
|
23567
|
+
});
|
|
23568
|
+
};
|
|
23569
|
+
runMiddleware();
|
|
23570
|
+
}
|
|
23571
|
+
async executeRoute(req, res) {
|
|
23572
|
+
const match = this.matchRoute(req);
|
|
23573
|
+
if (!match) {
|
|
23574
|
+
return;
|
|
23575
|
+
}
|
|
23576
|
+
const { route, params } = match;
|
|
23577
|
+
await route.handler(req, res, params);
|
|
23578
|
+
}
|
|
23579
|
+
finalize(req, res, error46) {
|
|
23580
|
+
if (error46) {
|
|
23581
|
+
sendError(res, error46, 500);
|
|
23582
|
+
return;
|
|
23583
|
+
}
|
|
23584
|
+
if (!res.writableEnded) {
|
|
23585
|
+
notFoundHandler(req, res);
|
|
23586
|
+
}
|
|
23587
|
+
}
|
|
23588
|
+
}
|
|
23589
|
+
|
|
23590
|
+
// src/server/static.ts
|
|
23591
|
+
import { createReadStream } from "node:fs";
|
|
23592
|
+
import { stat } from "node:fs/promises";
|
|
23593
|
+
import { extname, join as join4 } from "node:path";
|
|
23594
|
+
var MIME_TYPES = {
|
|
23595
|
+
".html": "text/html; charset=utf-8",
|
|
23596
|
+
".js": "application/javascript; charset=utf-8",
|
|
23597
|
+
".mjs": "application/javascript; charset=utf-8",
|
|
23598
|
+
".css": "text/css; charset=utf-8",
|
|
23599
|
+
".json": "application/json; charset=utf-8",
|
|
23600
|
+
".png": "image/png",
|
|
23601
|
+
".jpg": "image/jpeg",
|
|
23602
|
+
".jpeg": "image/jpeg",
|
|
23603
|
+
".gif": "image/gif",
|
|
23604
|
+
".svg": "image/svg+xml",
|
|
23605
|
+
".ico": "image/x-icon",
|
|
23606
|
+
".woff": "font/woff",
|
|
23607
|
+
".woff2": "font/woff2",
|
|
23608
|
+
".ttf": "font/ttf",
|
|
23609
|
+
".eot": "application/vnd.ms-fontobject",
|
|
23610
|
+
".mp4": "video/mp4",
|
|
23611
|
+
".webm": "video/webm",
|
|
23612
|
+
".ogg": "audio/ogg",
|
|
23613
|
+
".mp3": "audio/mpeg",
|
|
23614
|
+
".wav": "audio/wav",
|
|
23615
|
+
".webp": "image/webp",
|
|
23616
|
+
".avif": "image/avif"
|
|
23617
|
+
};
|
|
23618
|
+
function createStaticServe(options) {
|
|
23619
|
+
const { root, index = "index.html", spa = true } = options;
|
|
23620
|
+
return async (req, res) => {
|
|
23621
|
+
const url2 = new URL(req.url || "", `http://${req.headers.host || "localhost"}`);
|
|
23622
|
+
let filePath = join4(root, url2.pathname);
|
|
23623
|
+
try {
|
|
23624
|
+
const stats = await stat(filePath);
|
|
23625
|
+
if (stats.isDirectory()) {
|
|
23626
|
+
filePath = join4(filePath, index);
|
|
23627
|
+
await stat(filePath);
|
|
23628
|
+
}
|
|
23629
|
+
const ext = extname(filePath);
|
|
23630
|
+
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
23631
|
+
res.setHeader("Content-Type", contentType);
|
|
23632
|
+
const stream = createReadStream(filePath);
|
|
23633
|
+
stream.on("error", (error46) => {
|
|
23634
|
+
if (!res.writableEnded) {
|
|
23635
|
+
res.statusCode = 500;
|
|
23636
|
+
res.end("Internal Server Error");
|
|
23637
|
+
}
|
|
23638
|
+
});
|
|
23639
|
+
stream.pipe(res);
|
|
23640
|
+
} catch (error46) {
|
|
23641
|
+
if (spa) {
|
|
23642
|
+
try {
|
|
23643
|
+
const indexPath = join4(root, index);
|
|
23644
|
+
const stats = await stat(indexPath);
|
|
23645
|
+
if (stats.isFile()) {
|
|
23646
|
+
res.setHeader("Content-Type", "text/html; charset=utf-8");
|
|
23647
|
+
const stream = createReadStream(indexPath);
|
|
23648
|
+
stream.pipe(res);
|
|
23649
|
+
return;
|
|
23650
|
+
}
|
|
23651
|
+
} catch {}
|
|
23652
|
+
}
|
|
23653
|
+
if (!res.writableEnded) {
|
|
23654
|
+
res.statusCode = 404;
|
|
23655
|
+
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
23656
|
+
res.end("Not Found");
|
|
23657
|
+
}
|
|
23658
|
+
}
|
|
23659
|
+
};
|
|
23660
|
+
}
|
|
23661
|
+
|
|
23662
|
+
// src/server/api/profiles.ts
|
|
23663
|
+
init_manager();
|
|
23664
|
+
|
|
23665
|
+
// src/server/api/util.ts
|
|
23666
|
+
function maskApiKey(apiKey) {
|
|
23667
|
+
if (!apiKey || apiKey.length <= 8) {
|
|
23668
|
+
return "****";
|
|
23669
|
+
}
|
|
23670
|
+
const first = apiKey.slice(0, 4);
|
|
23671
|
+
const last = apiKey.slice(-4);
|
|
23672
|
+
return `${first}${"*".repeat(Math.min(apiKey.length - 8, 20))}${last}`;
|
|
23673
|
+
}
|
|
23674
|
+
function maskAuthToken(token) {
|
|
23675
|
+
if (!token || token.length <= 8) {
|
|
23676
|
+
return "****";
|
|
23677
|
+
}
|
|
23678
|
+
const first = token.slice(0, 4);
|
|
23679
|
+
const last = token.slice(-4);
|
|
23680
|
+
return `${first}${"*".repeat(Math.min(token.length - 8, 20))}${last}`;
|
|
23681
|
+
}
|
|
23682
|
+
function sanitizeProfile(profile) {
|
|
23683
|
+
return {
|
|
23684
|
+
...profile,
|
|
23685
|
+
apiKey: maskApiKey(profile.apiKey),
|
|
23686
|
+
authToken: profile.authToken ? maskAuthToken(profile.authToken) : undefined
|
|
23687
|
+
};
|
|
23688
|
+
}
|
|
23689
|
+
function generateETag(mtime, size) {
|
|
23690
|
+
const mtimeMs = Math.floor(mtime.getTime() / 1000);
|
|
23691
|
+
return `"${mtimeMs}-${size}"`;
|
|
23692
|
+
}
|
|
23693
|
+
function parseIfNoneMatch(header) {
|
|
23694
|
+
if (!header) {
|
|
23695
|
+
return null;
|
|
23696
|
+
}
|
|
23697
|
+
return header.replace(/^"|"$/g, "");
|
|
23698
|
+
}
|
|
23699
|
+
function setETagHeaders(res, mtime, size) {
|
|
23700
|
+
const etag = generateETag(mtime, size);
|
|
23701
|
+
res.setHeader("ETag", etag);
|
|
23702
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
23703
|
+
}
|
|
23704
|
+
|
|
23705
|
+
// src/server/api/profiles.ts
|
|
23706
|
+
init_presets();
|
|
23707
|
+
async function listProfiles2(req, res) {
|
|
23708
|
+
const profiles = await listProfiles();
|
|
23709
|
+
sendJson(res, profiles.map(sanitizeProfile));
|
|
23710
|
+
}
|
|
23711
|
+
async function getProfile2(req, res, params) {
|
|
23712
|
+
const { name } = params;
|
|
23713
|
+
if (!name) {
|
|
23714
|
+
sendError(res, { code: "INVALID_PARAMS", message: "Profile name is required" }, 400);
|
|
23715
|
+
return;
|
|
23716
|
+
}
|
|
23717
|
+
const profile = await getProfile(name);
|
|
23718
|
+
if (!profile) {
|
|
23719
|
+
sendError(res, { code: "PROFILE_NOT_FOUND", message: `Profile "${name}" does not exist` }, 404);
|
|
23720
|
+
return;
|
|
23721
|
+
}
|
|
23722
|
+
sendJson(res, sanitizeProfile(profile));
|
|
23723
|
+
}
|
|
23724
|
+
async function createProfile(req, res) {
|
|
23725
|
+
const body = req.body;
|
|
23726
|
+
if (!body || !body.name || !body.providerId) {
|
|
23727
|
+
sendError(res, { code: "INVALID_PARAMS", message: "name and providerId are required" }, 400);
|
|
23728
|
+
return;
|
|
23729
|
+
}
|
|
23730
|
+
const providers = await getAllPresets();
|
|
23731
|
+
const provider = providers.find((p2) => p2.id === body.providerId);
|
|
23732
|
+
if (!provider) {
|
|
23733
|
+
sendError(res, { code: "UNKNOWN_PROVIDER", message: `Provider "${body.providerId}" not found` }, 400);
|
|
23734
|
+
return;
|
|
23735
|
+
}
|
|
23736
|
+
const existing = await getProfile(body.name);
|
|
23737
|
+
if (existing) {
|
|
23738
|
+
sendError(res, { code: "PROFILE_EXISTS", message: `Profile "${body.name}" already exists` }, 409);
|
|
23739
|
+
return;
|
|
23740
|
+
}
|
|
23741
|
+
try {
|
|
23742
|
+
const now = new Date().toISOString();
|
|
23743
|
+
const profile = {
|
|
23744
|
+
name: body.name,
|
|
23745
|
+
providerId: body.providerId,
|
|
23746
|
+
apiKey: body.apiKey || "",
|
|
23747
|
+
authToken: body.authToken || "",
|
|
23748
|
+
baseURL: body.baseURL || provider.baseURL,
|
|
23749
|
+
model: body.model,
|
|
23750
|
+
openaiModel: body.openaiModel,
|
|
23751
|
+
models: body.models,
|
|
23752
|
+
envKey: body.envKey,
|
|
23753
|
+
headers: body.headers,
|
|
23754
|
+
createdAt: now,
|
|
23755
|
+
updatedAt: now
|
|
23756
|
+
};
|
|
23757
|
+
await upsertProfile(profile, body.coder);
|
|
23758
|
+
sendJson(res, sanitizeProfile(profile), 201);
|
|
23759
|
+
} catch (error46) {
|
|
23760
|
+
sendError(res, { code: "CREATE_FAILED", message: error46 instanceof Error ? error46.message : "Failed to create profile" }, 500);
|
|
23761
|
+
}
|
|
23762
|
+
}
|
|
23763
|
+
async function updateProfile(req, res, params) {
|
|
23764
|
+
const { name } = params;
|
|
23765
|
+
const body = req.body;
|
|
23766
|
+
if (!name) {
|
|
23767
|
+
sendError(res, { code: "INVALID_PARAMS", message: "Profile name is required" }, 400);
|
|
23768
|
+
return;
|
|
23769
|
+
}
|
|
23770
|
+
const existing = await getProfile(name);
|
|
23771
|
+
if (!existing) {
|
|
23772
|
+
sendError(res, { code: "PROFILE_NOT_FOUND", message: `Profile "${name}" does not exist` }, 404);
|
|
23773
|
+
return;
|
|
23774
|
+
}
|
|
23775
|
+
try {
|
|
23776
|
+
const now = new Date().toISOString();
|
|
23777
|
+
const profile = {
|
|
23778
|
+
...existing,
|
|
23779
|
+
...body,
|
|
23780
|
+
name,
|
|
23781
|
+
updatedAt: now
|
|
23782
|
+
};
|
|
23783
|
+
await upsertProfile(profile);
|
|
23784
|
+
sendJson(res, sanitizeProfile(profile));
|
|
23785
|
+
} catch (error46) {
|
|
23786
|
+
sendError(res, { code: "UPDATE_FAILED", message: error46 instanceof Error ? error46.message : "Failed to update profile" }, 500);
|
|
23787
|
+
}
|
|
23788
|
+
}
|
|
23789
|
+
async function deleteProfile2(req, res, params) {
|
|
23790
|
+
const { name } = params;
|
|
23791
|
+
if (!name) {
|
|
23792
|
+
sendError(res, { code: "INVALID_PARAMS", message: "Profile name is required" }, 400);
|
|
23793
|
+
return;
|
|
23794
|
+
}
|
|
23795
|
+
try {
|
|
23796
|
+
await deleteProfile(name);
|
|
23797
|
+
sendJson(res, { success: true, message: `Profile "${name}" deleted` });
|
|
23798
|
+
} catch (error46) {
|
|
23799
|
+
sendError(res, { code: "DELETE_FAILED", message: error46 instanceof Error ? error46.message : "Failed to delete profile" }, 500);
|
|
23800
|
+
}
|
|
23801
|
+
}
|
|
23802
|
+
|
|
23803
|
+
// src/server/api/providers.ts
|
|
23804
|
+
init_presets();
|
|
23805
|
+
init_user_providers();
|
|
23806
|
+
async function listProviders(req, res) {
|
|
23807
|
+
const providers = await getAllPresets();
|
|
23808
|
+
const userProviders = await loadUserProviders();
|
|
23809
|
+
const userIds = new Set(userProviders.map((p2) => p2.id));
|
|
23810
|
+
const result = providers.map((p2) => ({
|
|
23811
|
+
...p2,
|
|
23812
|
+
isUser: userIds.has(p2.id)
|
|
23813
|
+
}));
|
|
23814
|
+
sendJson(res, result);
|
|
23815
|
+
}
|
|
23816
|
+
async function createProvider(req, res) {
|
|
23817
|
+
const body = req.body;
|
|
23818
|
+
if (!body || !body.id || !body.name || !body.displayName) {
|
|
23819
|
+
sendError(res, { code: "INVALID_PARAMS", message: "id, name, and displayName are required" }, 400);
|
|
23820
|
+
return;
|
|
23821
|
+
}
|
|
23822
|
+
const providers = await getAllPresets();
|
|
23823
|
+
const existing = providers.find((p2) => p2.id === body.id);
|
|
23824
|
+
if (existing) {
|
|
23825
|
+
sendError(res, { code: "PROVIDER_EXISTS", message: `Provider "${body.id}" already exists` }, 409);
|
|
23826
|
+
return;
|
|
23827
|
+
}
|
|
23828
|
+
try {
|
|
23829
|
+
const provider = {
|
|
23830
|
+
id: body.id,
|
|
23831
|
+
name: body.name,
|
|
23832
|
+
displayName: body.displayName,
|
|
23833
|
+
baseURL: body.baseURL || "",
|
|
23834
|
+
defaultModels: body.defaultModels || [],
|
|
23835
|
+
authType: body.authType || "api-key",
|
|
23836
|
+
headers: body.headers,
|
|
23837
|
+
rateLimit: body.rateLimit,
|
|
23838
|
+
docs: body.docs,
|
|
23839
|
+
isChinese: body.isChinese,
|
|
23840
|
+
wire_api: body.wire_api,
|
|
23841
|
+
env_key: body.env_key
|
|
23842
|
+
};
|
|
23843
|
+
await upsertUserProvider(provider);
|
|
23844
|
+
sendJson(res, { ...provider, isUser: true }, 201);
|
|
23845
|
+
} catch (error46) {
|
|
23846
|
+
sendError(res, { code: "CREATE_FAILED", message: error46 instanceof Error ? error46.message : "Failed to create provider" }, 500);
|
|
23847
|
+
}
|
|
23848
|
+
}
|
|
23849
|
+
async function updateProvider(req, res, params) {
|
|
23850
|
+
const { id } = params;
|
|
23851
|
+
const body = req.body;
|
|
23852
|
+
if (!id) {
|
|
23853
|
+
sendError(res, { code: "INVALID_PARAMS", message: "Provider ID is required" }, 400);
|
|
23854
|
+
return;
|
|
23855
|
+
}
|
|
23856
|
+
const userProviders = await loadUserProviders();
|
|
23857
|
+
const existing = userProviders.find((p2) => p2.id === id);
|
|
23858
|
+
if (!existing) {
|
|
23859
|
+
sendError(res, { code: "NOT_USER_PROVIDER", message: `Provider "${id}" is not a user-defined provider` }, 400);
|
|
23860
|
+
return;
|
|
23861
|
+
}
|
|
23862
|
+
try {
|
|
23863
|
+
const provider = {
|
|
23864
|
+
...existing,
|
|
23865
|
+
...body,
|
|
23866
|
+
id
|
|
23867
|
+
};
|
|
23868
|
+
await upsertUserProvider(provider);
|
|
23869
|
+
sendJson(res, { ...provider, isUser: true });
|
|
23870
|
+
} catch (error46) {
|
|
23871
|
+
sendError(res, { code: "UPDATE_FAILED", message: error46 instanceof Error ? error46.message : "Failed to update provider" }, 500);
|
|
23872
|
+
}
|
|
23873
|
+
}
|
|
23874
|
+
async function deleteProvider(req, res, params) {
|
|
23875
|
+
const { id } = params;
|
|
23876
|
+
if (!id) {
|
|
23877
|
+
sendError(res, { code: "INVALID_PARAMS", message: "Provider ID is required" }, 400);
|
|
23878
|
+
return;
|
|
23879
|
+
}
|
|
23880
|
+
const userProviders = await loadUserProviders();
|
|
23881
|
+
const existing = userProviders.find((p2) => p2.id === id);
|
|
23882
|
+
if (!existing) {
|
|
23883
|
+
sendError(res, { code: "NOT_USER_PROVIDER", message: `Provider "${id}" is not a user-defined provider` }, 400);
|
|
23884
|
+
return;
|
|
23885
|
+
}
|
|
23886
|
+
try {
|
|
23887
|
+
const deleted = await deleteUserProvider(id);
|
|
23888
|
+
if (!deleted) {
|
|
23889
|
+
sendError(res, { code: "DELETE_FAILED", message: `Failed to delete provider "${id}"` }, 500);
|
|
23890
|
+
return;
|
|
23891
|
+
}
|
|
23892
|
+
sendJson(res, { success: true, message: `Provider "${id}" deleted` });
|
|
23893
|
+
} catch (error46) {
|
|
23894
|
+
sendError(res, { code: "DELETE_FAILED", message: error46 instanceof Error ? error46.message : "Failed to delete provider" }, 500);
|
|
23895
|
+
}
|
|
23896
|
+
}
|
|
23897
|
+
|
|
23898
|
+
// src/server/api/coders.ts
|
|
23899
|
+
init_coders();
|
|
23900
|
+
init_manager();
|
|
23901
|
+
init_adapters();
|
|
23902
|
+
async function listCoders(req, res) {
|
|
23903
|
+
const result = [];
|
|
23904
|
+
for (const [coderId, coderConfig] of Object.entries(CODER_REGISTRY)) {
|
|
23905
|
+
const activeProfile = await getActiveProfileForCoder(coderId);
|
|
23906
|
+
result.push({
|
|
23907
|
+
id: coderId,
|
|
23908
|
+
displayName: coderConfig.displayName,
|
|
23909
|
+
executable: coderConfig.executable,
|
|
23910
|
+
activeProfile: activeProfile ? {
|
|
23911
|
+
name: activeProfile.name,
|
|
23912
|
+
providerId: activeProfile.providerId,
|
|
23913
|
+
baseURL: activeProfile.baseURL
|
|
23914
|
+
} : null
|
|
23915
|
+
});
|
|
23916
|
+
}
|
|
23917
|
+
sendJson(res, result);
|
|
23918
|
+
}
|
|
23919
|
+
async function getActiveProfile2(req, res, params) {
|
|
23920
|
+
const { coder } = params;
|
|
23921
|
+
if (!coder) {
|
|
23922
|
+
sendError(res, { code: "INVALID_PARAMS", message: "Coder ID is required" }, 400);
|
|
23923
|
+
return;
|
|
23924
|
+
}
|
|
23925
|
+
if (!CODER_REGISTRY[coder]) {
|
|
23926
|
+
sendError(res, { code: "UNKNOWN_CODER", message: `Coder "${coder}" not found` }, 404);
|
|
23927
|
+
return;
|
|
23928
|
+
}
|
|
23929
|
+
const profile = await getActiveProfileForCoder(coder);
|
|
23930
|
+
if (!profile) {
|
|
23931
|
+
sendJson(res, { activeProfile: null });
|
|
23932
|
+
return;
|
|
23933
|
+
}
|
|
23934
|
+
sendJson(res, { activeProfile: sanitizeProfile(profile) });
|
|
23935
|
+
}
|
|
23936
|
+
async function setActiveProfile2(req, res, params) {
|
|
23937
|
+
const { coder } = params;
|
|
23938
|
+
const body = req.body;
|
|
23939
|
+
if (!coder) {
|
|
23940
|
+
sendError(res, { code: "INVALID_PARAMS", message: "Coder ID is required" }, 400);
|
|
23941
|
+
return;
|
|
23942
|
+
}
|
|
23943
|
+
if (!CODER_REGISTRY[coder]) {
|
|
23944
|
+
sendError(res, { code: "UNKNOWN_CODER", message: `Coder "${coder}" not found` }, 404);
|
|
23945
|
+
return;
|
|
23946
|
+
}
|
|
23947
|
+
if (!body || !body.profileName) {
|
|
23948
|
+
sendError(res, { code: "INVALID_PARAMS", message: "profileName is required" }, 400);
|
|
23949
|
+
return;
|
|
23950
|
+
}
|
|
23951
|
+
try {
|
|
23952
|
+
await setActiveProfileForCoder(coder, body.profileName);
|
|
23953
|
+
const profile = await getActiveProfileForCoder(coder);
|
|
23954
|
+
sendJson(res, { activeProfile: profile ? sanitizeProfile(profile) : null });
|
|
23955
|
+
} catch (error46) {
|
|
23956
|
+
sendError(res, { code: "SWITCH_FAILED", message: error46 instanceof Error ? error46.message : "Failed to switch profile" }, 500);
|
|
23957
|
+
}
|
|
23958
|
+
}
|
|
23959
|
+
async function applyProfile(req, res, params) {
|
|
23960
|
+
const { coder } = params;
|
|
23961
|
+
if (!coder) {
|
|
23962
|
+
sendError(res, { code: "INVALID_PARAMS", message: "Coder ID is required" }, 400);
|
|
23963
|
+
return;
|
|
23964
|
+
}
|
|
23965
|
+
if (!CODER_REGISTRY[coder]) {
|
|
23966
|
+
sendError(res, { code: "UNKNOWN_CODER", message: `Coder "${coder}" not found` }, 404);
|
|
23967
|
+
return;
|
|
23968
|
+
}
|
|
23969
|
+
const profile = await getActiveProfileForCoder(coder);
|
|
23970
|
+
if (!profile) {
|
|
23971
|
+
sendError(res, { code: "NO_ACTIVE_PROFILE", message: `No active profile for coder "${coder}"` }, 400);
|
|
23972
|
+
return;
|
|
23973
|
+
}
|
|
23974
|
+
try {
|
|
23975
|
+
const adapter = getAdapter(coder);
|
|
23976
|
+
await adapter.apply(profile);
|
|
23977
|
+
sendJson(res, { success: true, message: `Profile applied to ${coder}` });
|
|
23978
|
+
} catch (error46) {
|
|
23979
|
+
sendError(res, { code: "APPLY_FAILED", message: error46 instanceof Error ? error46.message : "Failed to apply profile" }, 500);
|
|
23980
|
+
}
|
|
23981
|
+
}
|
|
23982
|
+
async function verifyConfig(req, res, params) {
|
|
23983
|
+
const { coder } = params;
|
|
23984
|
+
if (!coder) {
|
|
23985
|
+
sendError(res, { code: "INVALID_PARAMS", message: "Coder ID is required" }, 400);
|
|
23986
|
+
return;
|
|
23987
|
+
}
|
|
23988
|
+
if (!CODER_REGISTRY[coder]) {
|
|
23989
|
+
sendError(res, { code: "UNKNOWN_CODER", message: `Coder "${coder}" not found` }, 404);
|
|
23990
|
+
return;
|
|
23991
|
+
}
|
|
23992
|
+
const profile = await getActiveProfileForCoder(coder);
|
|
23993
|
+
if (!profile) {
|
|
23994
|
+
sendJson(res, { verified: false, message: "No active profile" });
|
|
23995
|
+
return;
|
|
23996
|
+
}
|
|
23997
|
+
try {
|
|
23998
|
+
const adapter = getAdapter(coder);
|
|
23999
|
+
const verified = await adapter.verify(profile);
|
|
24000
|
+
sendJson(res, { verified, message: verified ? "Configuration verified" : "Verification failed" });
|
|
24001
|
+
} catch (error46) {
|
|
24002
|
+
sendJson(res, { verified: false, message: error46 instanceof Error ? error46.message : "Verification failed" });
|
|
24003
|
+
}
|
|
24004
|
+
}
|
|
24005
|
+
|
|
24006
|
+
// src/server/api/config.ts
|
|
24007
|
+
init_meta();
|
|
24008
|
+
init_versions2();
|
|
24009
|
+
init_paths();
|
|
24010
|
+
import { existsSync as existsSync7, statSync } from "node:fs";
|
|
24011
|
+
import { readFile as readFile7, writeFile as writeFile7, unlink } from "node:fs/promises";
|
|
24012
|
+
import { join as join5 } from "node:path";
|
|
24013
|
+
|
|
23367
24014
|
// src/config/export.ts
|
|
23368
24015
|
init_types();
|
|
23369
24016
|
init_manager();
|
|
@@ -23453,47 +24100,262 @@ async function importConfig(filePath, options = {}) {
|
|
|
23453
24100
|
return { imported, skipped, errors: errors3 };
|
|
23454
24101
|
}
|
|
23455
24102
|
|
|
24103
|
+
// src/server/api/config.ts
|
|
24104
|
+
async function getVersion(req, res) {
|
|
24105
|
+
sendJson(res, {
|
|
24106
|
+
appVersion: APP_VERSION,
|
|
24107
|
+
configVersion: CONFIG_VERSION,
|
|
24108
|
+
exportVersion: EXPORT_VERSION
|
|
24109
|
+
});
|
|
24110
|
+
}
|
|
24111
|
+
async function getConfigMeta(req, res) {
|
|
24112
|
+
const configPath = getConfigPath("swixter");
|
|
24113
|
+
if (!existsSync7(configPath)) {
|
|
24114
|
+
sendJson(res, {
|
|
24115
|
+
exists: false,
|
|
24116
|
+
profiles: [],
|
|
24117
|
+
mtime: null,
|
|
24118
|
+
size: 0
|
|
24119
|
+
});
|
|
24120
|
+
return;
|
|
24121
|
+
}
|
|
24122
|
+
try {
|
|
24123
|
+
const stats = statSync(configPath);
|
|
24124
|
+
const etag = generateETag(stats.mtime, stats.size);
|
|
24125
|
+
const ifNoneMatch = parseIfNoneMatch(req.headers["if-none-match"]);
|
|
24126
|
+
if (ifNoneMatch === etag) {
|
|
24127
|
+
res.statusCode = 304;
|
|
24128
|
+
res.end();
|
|
24129
|
+
return;
|
|
24130
|
+
}
|
|
24131
|
+
setETagHeaders(res, stats.mtime, stats.size);
|
|
24132
|
+
const { listProfiles: listProfiles3 } = await Promise.resolve().then(() => (init_manager(), exports_manager));
|
|
24133
|
+
const profiles = await listProfiles3();
|
|
24134
|
+
sendJson(res, {
|
|
24135
|
+
exists: true,
|
|
24136
|
+
profiles: profiles.map((p2) => ({
|
|
24137
|
+
name: p2.name,
|
|
24138
|
+
providerId: p2.providerId,
|
|
24139
|
+
updatedAt: p2.updatedAt
|
|
24140
|
+
})),
|
|
24141
|
+
mtime: stats.mtime.toISOString(),
|
|
24142
|
+
size: stats.size,
|
|
24143
|
+
etag
|
|
24144
|
+
});
|
|
24145
|
+
} catch (error46) {
|
|
24146
|
+
sendError(res, { code: "STAT_FAILED", message: "Failed to read config metadata" }, 500);
|
|
24147
|
+
}
|
|
24148
|
+
}
|
|
24149
|
+
async function exportConfigFile(req, res) {
|
|
24150
|
+
try {
|
|
24151
|
+
const configPath = getConfigPath("swixter");
|
|
24152
|
+
const content = await readFile7(configPath, "utf-8");
|
|
24153
|
+
res.setHeader("Content-Type", "application/json");
|
|
24154
|
+
res.setHeader("Content-Disposition", 'attachment; filename="swixter-config.json"');
|
|
24155
|
+
res.statusCode = 200;
|
|
24156
|
+
res.end(content);
|
|
24157
|
+
} catch (error46) {
|
|
24158
|
+
sendError(res, { code: "EXPORT_FAILED", message: "Failed to export configuration" }, 500);
|
|
24159
|
+
}
|
|
24160
|
+
}
|
|
24161
|
+
async function importConfigFile(req, res) {
|
|
24162
|
+
const body = req.body;
|
|
24163
|
+
if (!body || !body.config) {
|
|
24164
|
+
sendError(res, { code: "INVALID_PARAMS", message: "config is required" }, 400);
|
|
24165
|
+
return;
|
|
24166
|
+
}
|
|
24167
|
+
try {
|
|
24168
|
+
const tempDir = getConfigDir("swixter");
|
|
24169
|
+
const tempPath = join5(tempDir, `.import-${Date.now()}.json`);
|
|
24170
|
+
await writeFile7(tempPath, JSON.stringify(body.config), "utf-8");
|
|
24171
|
+
try {
|
|
24172
|
+
const result = await importConfig(tempPath, { overwrite: body.overwrite !== false });
|
|
24173
|
+
sendJson(res, { success: true, ...result });
|
|
24174
|
+
} finally {
|
|
24175
|
+
try {
|
|
24176
|
+
await unlink(tempPath);
|
|
24177
|
+
} catch {}
|
|
24178
|
+
}
|
|
24179
|
+
} catch (error46) {
|
|
24180
|
+
sendError(res, { code: "IMPORT_FAILED", message: error46 instanceof Error ? error46.message : "Failed to import configuration" }, 500);
|
|
24181
|
+
}
|
|
24182
|
+
}
|
|
24183
|
+
|
|
24184
|
+
// src/server/index.ts
|
|
24185
|
+
var __dirname2 = dirname7(fileURLToPath(import.meta.url));
|
|
24186
|
+
async function findAvailablePort(startPort = 3141) {
|
|
24187
|
+
const net = await import("node:net");
|
|
24188
|
+
return new Promise((resolve) => {
|
|
24189
|
+
const server = net.createServer();
|
|
24190
|
+
server.listen(startPort, "127.0.0.1", () => {
|
|
24191
|
+
const port = server.address().port;
|
|
24192
|
+
server.close(() => resolve(port));
|
|
24193
|
+
});
|
|
24194
|
+
server.on("error", () => {
|
|
24195
|
+
server.close();
|
|
24196
|
+
resolve(findAvailablePort(startPort + 1));
|
|
24197
|
+
});
|
|
24198
|
+
});
|
|
24199
|
+
}
|
|
24200
|
+
function openBrowser(url2) {
|
|
24201
|
+
const command = process.platform === "win32" ? "start" : process.platform === "darwin" ? "open" : "xdg-open";
|
|
24202
|
+
exec(`${command} ${url2}`, (error46) => {
|
|
24203
|
+
if (error46) {
|
|
24204
|
+
console.warn(import_picocolors11.default.yellow(`Could not open browser automatically: ${error46.message}`));
|
|
24205
|
+
}
|
|
24206
|
+
});
|
|
24207
|
+
}
|
|
24208
|
+
function getUiDir() {
|
|
24209
|
+
const isDev = true;
|
|
24210
|
+
if (isDev) {
|
|
24211
|
+
return join6(__dirname2, "..", "..", "ui", "dist");
|
|
24212
|
+
}
|
|
24213
|
+
return join6(__dirname2, "..", "..", "ui");
|
|
24214
|
+
}
|
|
24215
|
+
async function startServer(portArg) {
|
|
24216
|
+
const port = portArg || await findAvailablePort(3141);
|
|
24217
|
+
const host = "127.0.0.1";
|
|
24218
|
+
const router = new Router;
|
|
24219
|
+
router.use(corsMiddleware);
|
|
24220
|
+
router.use(jsonBodyMiddleware);
|
|
24221
|
+
router.get("/api/profiles", listProfiles2);
|
|
24222
|
+
router.get("/api/profiles/:name", getProfile2);
|
|
24223
|
+
router.post("/api/profiles", createProfile);
|
|
24224
|
+
router.put("/api/profiles/:name", updateProfile);
|
|
24225
|
+
router.delete("/api/profiles/:name", deleteProfile2);
|
|
24226
|
+
router.get("/api/providers", listProviders);
|
|
24227
|
+
router.post("/api/providers", createProvider);
|
|
24228
|
+
router.put("/api/providers/:id", updateProvider);
|
|
24229
|
+
router.delete("/api/providers/:id", deleteProvider);
|
|
24230
|
+
router.get("/api/coders", listCoders);
|
|
24231
|
+
router.get("/api/coders/:coder/active", getActiveProfile2);
|
|
24232
|
+
router.put("/api/coders/:coder/active", setActiveProfile2);
|
|
24233
|
+
router.post("/api/coders/:coder/apply", applyProfile);
|
|
24234
|
+
router.get("/api/coders/:coder/verify", verifyConfig);
|
|
24235
|
+
router.get("/api/version", getVersion);
|
|
24236
|
+
router.get("/api/config", getConfigMeta);
|
|
24237
|
+
router.get("/api/config/export", exportConfigFile);
|
|
24238
|
+
router.post("/api/config/import", importConfigFile);
|
|
24239
|
+
const uiDir = getUiDir();
|
|
24240
|
+
const serveStatic = createStaticServe({ root: uiDir, index: "index.html", spa: true });
|
|
24241
|
+
const server = createServer(async (req, res) => {
|
|
24242
|
+
const url2 = req.url || "";
|
|
24243
|
+
if (url2.startsWith("/api/") || url2 === "/api") {
|
|
24244
|
+
await router.handle(req, res);
|
|
24245
|
+
} else {
|
|
24246
|
+
await serveStatic(req, res);
|
|
24247
|
+
}
|
|
24248
|
+
});
|
|
24249
|
+
server.listen(port, host, () => {
|
|
24250
|
+
const url2 = `http://${host}:${port}`;
|
|
24251
|
+
console.log();
|
|
24252
|
+
console.log(import_picocolors11.default.bold(import_picocolors11.default.cyan("Swixter Web UI")));
|
|
24253
|
+
console.log();
|
|
24254
|
+
console.log(` Server: ${import_picocolors11.default.cyan(url2)}`);
|
|
24255
|
+
console.log(` Press ${import_picocolors11.default.bold("Ctrl+C")} to stop`);
|
|
24256
|
+
console.log();
|
|
24257
|
+
openBrowser(url2);
|
|
24258
|
+
});
|
|
24259
|
+
server.on("error", (error46) => {
|
|
24260
|
+
if (error46.code === "EADDRINUSE") {
|
|
24261
|
+
console.error(import_picocolors11.default.red(`Error: Port ${port} is already in use`));
|
|
24262
|
+
console.log(import_picocolors11.default.dim("Try specifying a different port with --port"));
|
|
24263
|
+
process.exit(1);
|
|
24264
|
+
} else {
|
|
24265
|
+
console.error(import_picocolors11.default.red(`Server error: ${error46.message}`));
|
|
24266
|
+
process.exit(1);
|
|
24267
|
+
}
|
|
24268
|
+
});
|
|
24269
|
+
server.on("close", () => {
|
|
24270
|
+
console.log();
|
|
24271
|
+
console.log(import_picocolors11.default.dim("Server closed"));
|
|
24272
|
+
});
|
|
24273
|
+
return server;
|
|
24274
|
+
}
|
|
24275
|
+
|
|
24276
|
+
// src/cli/ui.ts
|
|
24277
|
+
async function handleUiCommand(args) {
|
|
24278
|
+
const port = getPortFromArgs(args);
|
|
24279
|
+
try {
|
|
24280
|
+
const server = await startServer(port);
|
|
24281
|
+
process.on("SIGINT", () => {
|
|
24282
|
+
console.log();
|
|
24283
|
+
console.log(import_picocolors12.default.dim("Shutting down..."));
|
|
24284
|
+
server.close(() => {
|
|
24285
|
+
process.exit(0);
|
|
24286
|
+
});
|
|
24287
|
+
});
|
|
24288
|
+
process.stdin.resume();
|
|
24289
|
+
} catch (error46) {
|
|
24290
|
+
console.error(import_picocolors12.default.red(`Failed to start server: ${error46}`));
|
|
24291
|
+
process.exit(1);
|
|
24292
|
+
}
|
|
24293
|
+
}
|
|
24294
|
+
function getPortFromArgs(args) {
|
|
24295
|
+
if (!args || args.length === 0) {
|
|
24296
|
+
return;
|
|
24297
|
+
}
|
|
24298
|
+
for (let i2 = 0;i2 < args.length; i2++) {
|
|
24299
|
+
const arg = args[i2];
|
|
24300
|
+
if (arg === "--port" || arg === "-p") {
|
|
24301
|
+
const portStr = args[i2 + 1];
|
|
24302
|
+
if (!portStr) {
|
|
24303
|
+
console.error(import_picocolors12.default.red("Error: --port requires a value"));
|
|
24304
|
+
process.exit(1);
|
|
24305
|
+
}
|
|
24306
|
+
const port = parseInt(portStr, 10);
|
|
24307
|
+
if (isNaN(port) || port < 1 || port > 65535) {
|
|
24308
|
+
console.error(import_picocolors12.default.red("Error: Invalid port number"));
|
|
24309
|
+
process.exit(1);
|
|
24310
|
+
}
|
|
24311
|
+
return port;
|
|
24312
|
+
}
|
|
24313
|
+
}
|
|
24314
|
+
return;
|
|
24315
|
+
}
|
|
24316
|
+
|
|
23456
24317
|
// src/cli/help.ts
|
|
23457
|
-
var
|
|
24318
|
+
var import_picocolors13 = __toESM(require_picocolors(), 1);
|
|
23458
24319
|
function showGlobalHelp() {
|
|
23459
24320
|
console.log(`
|
|
23460
|
-
${
|
|
24321
|
+
${import_picocolors13.default.bold(import_picocolors13.default.cyan("Swixter - AI Coder Configuration Manager"))}
|
|
23461
24322
|
|
|
23462
|
-
${
|
|
23463
|
-
${
|
|
23464
|
-
${
|
|
24323
|
+
${import_picocolors13.default.bold("Usage:")}
|
|
24324
|
+
${import_picocolors13.default.green("swixter <coder> <command> [options]")}
|
|
24325
|
+
${import_picocolors13.default.green("swixter <global-command> [options]")}
|
|
23465
24326
|
|
|
23466
|
-
${
|
|
23467
|
-
${
|
|
23468
|
-
${
|
|
23469
|
-
${
|
|
24327
|
+
${import_picocolors13.default.bold("Supported Coders:")}
|
|
24328
|
+
${import_picocolors13.default.cyan("claude")} ${import_picocolors13.default.dim("Claude Code configuration management")}
|
|
24329
|
+
${import_picocolors13.default.cyan("codex")} ${import_picocolors13.default.dim("Codex configuration management")}
|
|
24330
|
+
${import_picocolors13.default.cyan("qwen")} ${import_picocolors13.default.dim("Continue/Qwen configuration management")}
|
|
23470
24331
|
|
|
23471
|
-
${
|
|
23472
|
-
${
|
|
23473
|
-
|
|
23474
|
-
|
|
23475
|
-
${import_picocolors11.default.cyan("completion <shell>")} ${import_picocolors11.default.dim("Generate shell auto-completion script")}
|
|
23476
|
-
${import_picocolors11.default.cyan("help")} ${import_picocolors11.default.dim("Show help information")}
|
|
23477
|
-
${import_picocolors11.default.cyan("version")} ${import_picocolors11.default.dim("Show version information")}
|
|
24332
|
+
${import_picocolors13.default.bold("Web UI:")}
|
|
24333
|
+
${import_picocolors13.default.cyan("ui")} ${import_picocolors13.default.dim("Launch local Web UI")}
|
|
24334
|
+
${import_picocolors13.default.dim("swixter ui [--port <port>]")}
|
|
24335
|
+
${import_picocolors13.default.dim("Start local HTTP server and open browser")}
|
|
23478
24336
|
|
|
23479
|
-
${
|
|
23480
|
-
${
|
|
23481
|
-
${
|
|
24337
|
+
${import_picocolors13.default.bold("Global Commands:")}
|
|
24338
|
+
${import_picocolors13.default.cyan("providers")} ${import_picocolors13.default.dim("List all available API providers")}
|
|
24339
|
+
${import_picocolors13.default.cyan("export <file>")} ${import_picocolors13.default.dim("Export all configurations to file")}
|
|
24340
|
+
${import_picocolors13.default.cyan("import <file>")} ${import_picocolors13.default.dim("Import configurations from file")}
|
|
24341
|
+
${import_picocolors13.default.cyan("completion <shell>")} ${import_picocolors13.default.dim("Generate shell auto-completion script")}
|
|
24342
|
+
${import_picocolors13.default.cyan("help")} ${import_picocolors13.default.dim("Show help information")}
|
|
24343
|
+
${import_picocolors13.default.cyan("version")} ${import_picocolors13.default.dim("Show version information")}
|
|
23482
24344
|
|
|
23483
|
-
|
|
23484
|
-
${
|
|
24345
|
+
${import_picocolors13.default.bold("Examples:")}
|
|
24346
|
+
${import_picocolors13.default.dim("# View Claude Code commands")}
|
|
24347
|
+
${import_picocolors13.default.green("swixter claude --help")}
|
|
23485
24348
|
|
|
23486
|
-
${
|
|
23487
|
-
${
|
|
24349
|
+
${import_picocolors13.default.dim("# Create Claude Code configuration")}
|
|
24350
|
+
${import_picocolors13.default.green("swixter claude create")}
|
|
23488
24351
|
|
|
23489
|
-
${
|
|
23490
|
-
${
|
|
24352
|
+
${import_picocolors13.default.dim("# Launch Web UI")}
|
|
24353
|
+
${import_picocolors13.default.green("swixter ui")}
|
|
23491
24354
|
|
|
23492
|
-
${
|
|
23493
|
-
${
|
|
24355
|
+
${import_picocolors13.default.dim("# View all providers")}
|
|
24356
|
+
${import_picocolors13.default.green("swixter providers")}
|
|
23494
24357
|
|
|
23495
|
-
${
|
|
23496
|
-
`);
|
|
24358
|
+
${import_picocolors13.default.dim("Documentation: https://github.com/dawnswwwww/swixter")}`);
|
|
23497
24359
|
}
|
|
23498
24360
|
|
|
23499
24361
|
// src/cli/completions.ts
|
|
@@ -23856,37 +24718,37 @@ function generateCompletion(shell) {
|
|
|
23856
24718
|
// src/cli/providers.ts
|
|
23857
24719
|
init_presets();
|
|
23858
24720
|
init_user_providers();
|
|
23859
|
-
var
|
|
24721
|
+
var import_picocolors14 = __toESM(require_picocolors(), 1);
|
|
23860
24722
|
init_formatting();
|
|
23861
|
-
async function
|
|
24723
|
+
async function listProviders2() {
|
|
23862
24724
|
console.log();
|
|
23863
|
-
Ie(
|
|
24725
|
+
Ie(import_picocolors14.default.cyan("Available Providers"));
|
|
23864
24726
|
const allPresets2 = await getAllPresets();
|
|
23865
24727
|
const userProviders = await loadUserProviders();
|
|
23866
24728
|
const userProviderIds = new Set(userProviders.map((p2) => p2.id));
|
|
23867
24729
|
const builtInProviderIds = new Set(getBuiltInPresets().map((p2) => p2.id));
|
|
23868
24730
|
if (allPresets2.length === 0) {
|
|
23869
|
-
console.log(
|
|
24731
|
+
console.log(import_picocolors14.default.yellow("No providers configured"));
|
|
23870
24732
|
console.log();
|
|
23871
24733
|
return;
|
|
23872
24734
|
}
|
|
23873
24735
|
console.log();
|
|
23874
|
-
console.log(
|
|
24736
|
+
console.log(import_picocolors14.default.bold("Built-in Providers:"));
|
|
23875
24737
|
allPresets2.filter((p2) => builtInProviderIds.has(p2.id) && !userProviderIds.has(p2.id)).forEach((preset) => {
|
|
23876
|
-
console.log(` ${
|
|
24738
|
+
console.log(` ${import_picocolors14.default.cyan(preset.id.padEnd(15))} ${import_picocolors14.default.dim("|")} ${preset.displayName.padEnd(30)} ${import_picocolors14.default.dim("|")} ${import_picocolors14.default.yellow(preset.baseURL || "N/A")}`);
|
|
23877
24739
|
});
|
|
23878
24740
|
const userOnlyProviders = allPresets2.filter((p2) => userProviderIds.has(p2.id));
|
|
23879
24741
|
if (userOnlyProviders.length > 0) {
|
|
23880
24742
|
console.log();
|
|
23881
|
-
console.log(
|
|
24743
|
+
console.log(import_picocolors14.default.bold("User-defined Providers:"));
|
|
23882
24744
|
userOnlyProviders.forEach((preset) => {
|
|
23883
24745
|
const isOverride = builtInProviderIds.has(preset.id);
|
|
23884
|
-
const marker = isOverride ?
|
|
23885
|
-
console.log(` ${
|
|
24746
|
+
const marker = isOverride ? import_picocolors14.default.yellow(" (override)") : "";
|
|
24747
|
+
console.log(` ${import_picocolors14.default.green(preset.id.padEnd(15))} ${import_picocolors14.default.dim("|")} ${preset.displayName.padEnd(30)} ${import_picocolors14.default.dim("|")} ${import_picocolors14.default.yellow(preset.baseURL || "N/A")}${marker}`);
|
|
23886
24748
|
});
|
|
23887
24749
|
}
|
|
23888
24750
|
console.log();
|
|
23889
|
-
console.log(
|
|
24751
|
+
console.log(import_picocolors14.default.dim(`Total: ${allPresets2.length} providers`));
|
|
23890
24752
|
console.log();
|
|
23891
24753
|
}
|
|
23892
24754
|
async function addProvider(options) {
|
|
@@ -23898,7 +24760,7 @@ async function addProvider(options) {
|
|
|
23898
24760
|
let models = options.models;
|
|
23899
24761
|
if (!options.quiet) {
|
|
23900
24762
|
console.log();
|
|
23901
|
-
Ie(
|
|
24763
|
+
Ie(import_picocolors14.default.cyan("Add Custom Provider"));
|
|
23902
24764
|
const existing = providerId ? await getUserProvider(providerId) : undefined;
|
|
23903
24765
|
providerId = await he({
|
|
23904
24766
|
message: "Provider ID (unique identifier, e.g., 'openrouter', 'deepseek')",
|
|
@@ -23993,7 +24855,7 @@ async function addProvider(options) {
|
|
|
23993
24855
|
try {
|
|
23994
24856
|
await upsertUserProvider(provider);
|
|
23995
24857
|
if (!options.quiet) {
|
|
23996
|
-
Se(
|
|
24858
|
+
Se(import_picocolors14.default.green(`${MARKERS.success} Provider "${providerId}" added successfully!`));
|
|
23997
24859
|
} else {
|
|
23998
24860
|
showSuccess(`Provider "${providerId}" added successfully!`, {
|
|
23999
24861
|
ID: providerId,
|
|
@@ -24012,10 +24874,10 @@ async function removeProvider(providerId, options) {
|
|
|
24012
24874
|
showError("Error: Provider ID is required", "Usage: swixter providers remove <provider-id>");
|
|
24013
24875
|
}
|
|
24014
24876
|
console.log();
|
|
24015
|
-
Ie(
|
|
24877
|
+
Ie(import_picocolors14.default.cyan("Remove Custom Provider"));
|
|
24016
24878
|
const userProviders = await loadUserProviders();
|
|
24017
24879
|
if (userProviders.length === 0) {
|
|
24018
|
-
Se(
|
|
24880
|
+
Se(import_picocolors14.default.yellow("No user-defined providers to remove"));
|
|
24019
24881
|
return;
|
|
24020
24882
|
}
|
|
24021
24883
|
providerId = await ve({
|
|
@@ -24042,7 +24904,7 @@ async function removeProvider(providerId, options) {
|
|
|
24042
24904
|
showError(`Error: Provider "${providerId}" not found`, "Use 'swixter providers list' to see all providers");
|
|
24043
24905
|
}
|
|
24044
24906
|
if (!options?.quiet) {
|
|
24045
|
-
Se(
|
|
24907
|
+
Se(import_picocolors14.default.green(`${MARKERS.success} Provider "${providerId}" removed successfully!`));
|
|
24046
24908
|
} else {
|
|
24047
24909
|
showSuccess(`Provider "${providerId}" removed successfully!`);
|
|
24048
24910
|
}
|
|
@@ -24056,19 +24918,19 @@ async function showProvider(providerId) {
|
|
|
24056
24918
|
showError(`Error: Provider "${providerId}" not found`, "Use 'swixter providers list' to see all providers");
|
|
24057
24919
|
}
|
|
24058
24920
|
console.log();
|
|
24059
|
-
Ie(
|
|
24921
|
+
Ie(import_picocolors14.default.cyan(`Provider: ${provider.displayName}`));
|
|
24060
24922
|
console.log();
|
|
24061
|
-
console.log(` ID: ${
|
|
24062
|
-
console.log(` Name: ${
|
|
24063
|
-
console.log(` Display Name: ${
|
|
24064
|
-
console.log(` Base URL: ${
|
|
24065
|
-
console.log(` Auth Type: ${
|
|
24923
|
+
console.log(` ID: ${import_picocolors14.default.cyan(provider.id)}`);
|
|
24924
|
+
console.log(` Name: ${import_picocolors14.default.yellow(provider.name)}`);
|
|
24925
|
+
console.log(` Display Name: ${import_picocolors14.default.yellow(provider.displayName)}`);
|
|
24926
|
+
console.log(` Base URL: ${import_picocolors14.default.yellow(provider.baseURL)}`);
|
|
24927
|
+
console.log(` Auth Type: ${import_picocolors14.default.yellow(provider.authType)}`);
|
|
24066
24928
|
if (provider.defaultModels && provider.defaultModels.length > 0) {
|
|
24067
24929
|
console.log(` Default Models:`);
|
|
24068
|
-
provider.defaultModels.forEach((model) => console.log(` - ${
|
|
24930
|
+
provider.defaultModels.forEach((model) => console.log(` - ${import_picocolors14.default.dim(model)}`));
|
|
24069
24931
|
}
|
|
24070
24932
|
if (provider.docs) {
|
|
24071
|
-
console.log(` Documentation: ${
|
|
24933
|
+
console.log(` Documentation: ${import_picocolors14.default.blue(provider.docs)}`);
|
|
24072
24934
|
}
|
|
24073
24935
|
console.log();
|
|
24074
24936
|
}
|
|
@@ -24078,7 +24940,7 @@ init_meta();
|
|
|
24078
24940
|
init_versions2();
|
|
24079
24941
|
async function cmdProviders(subcommand, args) {
|
|
24080
24942
|
if (!subcommand || subcommand === "list" || subcommand === "ls") {
|
|
24081
|
-
await
|
|
24943
|
+
await listProviders2();
|
|
24082
24944
|
return;
|
|
24083
24945
|
}
|
|
24084
24946
|
if (subcommand === "add" || subcommand === "new") {
|
|
@@ -24120,104 +24982,104 @@ async function cmdProviders(subcommand, args) {
|
|
|
24120
24982
|
await showProvider(providerId);
|
|
24121
24983
|
return;
|
|
24122
24984
|
}
|
|
24123
|
-
console.log(
|
|
24985
|
+
console.log(import_picocolors15.default.red(`Unknown providers subcommand: ${subcommand}`));
|
|
24124
24986
|
console.log();
|
|
24125
|
-
console.log(
|
|
24126
|
-
console.log(` ${
|
|
24127
|
-
console.log(` ${
|
|
24128
|
-
console.log(` ${
|
|
24129
|
-
console.log(` ${
|
|
24987
|
+
console.log(import_picocolors15.default.bold("Available subcommands:"));
|
|
24988
|
+
console.log(` ${import_picocolors15.default.cyan("list, ls")} - List all providers`);
|
|
24989
|
+
console.log(` ${import_picocolors15.default.cyan("add, new")} - Add a custom provider`);
|
|
24990
|
+
console.log(` ${import_picocolors15.default.cyan("remove, rm, delete")} - Remove a custom provider`);
|
|
24991
|
+
console.log(` ${import_picocolors15.default.cyan("show, info")} - Show provider details`);
|
|
24130
24992
|
console.log();
|
|
24131
24993
|
process.exit(1);
|
|
24132
24994
|
}
|
|
24133
24995
|
async function cmdExport(filePath) {
|
|
24134
24996
|
if (!filePath) {
|
|
24135
|
-
console.log(
|
|
24136
|
-
console.log(
|
|
24997
|
+
console.log(import_picocolors15.default.red("Error: Please specify export file path"));
|
|
24998
|
+
console.log(import_picocolors15.default.dim("Usage: swixter export <file>"));
|
|
24137
24999
|
process.exit(1);
|
|
24138
25000
|
}
|
|
24139
25001
|
try {
|
|
24140
25002
|
await exportConfig(filePath, { sanitizeKeys: false });
|
|
24141
25003
|
console.log();
|
|
24142
|
-
console.log(
|
|
24143
|
-
console.log(` File: ${
|
|
25004
|
+
console.log(import_picocolors15.default.green("✓") + " Export successful!");
|
|
25005
|
+
console.log(` File: ${import_picocolors15.default.cyan(filePath)}`);
|
|
24144
25006
|
console.log();
|
|
24145
25007
|
} catch (error46) {
|
|
24146
25008
|
console.log();
|
|
24147
|
-
console.log(
|
|
25009
|
+
console.log(import_picocolors15.default.red(`✗ Export failed: ${error46}`));
|
|
24148
25010
|
console.log();
|
|
24149
25011
|
process.exit(1);
|
|
24150
25012
|
}
|
|
24151
25013
|
}
|
|
24152
25014
|
async function cmdCompletion(shell) {
|
|
24153
25015
|
if (!shell) {
|
|
24154
|
-
console.log(
|
|
25016
|
+
console.log(import_picocolors15.default.yellow("Please specify shell type"));
|
|
24155
25017
|
console.log();
|
|
24156
|
-
console.log(
|
|
24157
|
-
console.log(` ${
|
|
25018
|
+
console.log(import_picocolors15.default.bold("Usage:"));
|
|
25019
|
+
console.log(` ${import_picocolors15.default.green("swixter completion <shell>")}`);
|
|
24158
25020
|
console.log();
|
|
24159
|
-
console.log(
|
|
24160
|
-
console.log(` ${
|
|
24161
|
-
console.log(` ${
|
|
24162
|
-
console.log(` ${
|
|
25021
|
+
console.log(import_picocolors15.default.bold("Supported shells:"));
|
|
25022
|
+
console.log(` ${import_picocolors15.default.cyan("bash")} - Bash shell`);
|
|
25023
|
+
console.log(` ${import_picocolors15.default.cyan("zsh")} - Z shell`);
|
|
25024
|
+
console.log(` ${import_picocolors15.default.cyan("fish")} - Fish shell`);
|
|
24163
25025
|
console.log();
|
|
24164
|
-
console.log(
|
|
24165
|
-
console.log(` ${
|
|
24166
|
-
console.log(` ${
|
|
24167
|
-
console.log(` ${
|
|
25026
|
+
console.log(import_picocolors15.default.bold("Examples:"));
|
|
25027
|
+
console.log(` ${import_picocolors15.default.green("swixter completion bash > ~/.local/share/bash-completion/completions/swixter")}`);
|
|
25028
|
+
console.log(` ${import_picocolors15.default.green("swixter completion zsh > ~/.zfunc/_swixter")}`);
|
|
25029
|
+
console.log(` ${import_picocolors15.default.green("swixter completion fish > ~/.config/fish/completions/swixter.fish")}`);
|
|
24168
25030
|
process.exit(1);
|
|
24169
25031
|
}
|
|
24170
25032
|
const supportedShells = ["bash", "zsh", "fish"];
|
|
24171
25033
|
if (!supportedShells.includes(shell)) {
|
|
24172
|
-
console.log(
|
|
24173
|
-
console.log(
|
|
25034
|
+
console.log(import_picocolors15.default.red(`Unsupported shell: ${shell}`));
|
|
25035
|
+
console.log(import_picocolors15.default.dim(`Supported shells: ${supportedShells.join(", ")}`));
|
|
24174
25036
|
process.exit(1);
|
|
24175
25037
|
}
|
|
24176
25038
|
try {
|
|
24177
25039
|
const script = generateCompletion(shell);
|
|
24178
25040
|
console.log(script);
|
|
24179
25041
|
} catch (error46) {
|
|
24180
|
-
console.error(
|
|
25042
|
+
console.error(import_picocolors15.default.red("Failed to generate completion script:"), error46);
|
|
24181
25043
|
process.exit(1);
|
|
24182
25044
|
}
|
|
24183
25045
|
}
|
|
24184
25046
|
async function cmdImport(filePath) {
|
|
24185
25047
|
if (!filePath) {
|
|
24186
|
-
console.log(
|
|
24187
|
-
console.log(
|
|
25048
|
+
console.log(import_picocolors15.default.red("Error: Please specify import file path"));
|
|
25049
|
+
console.log(import_picocolors15.default.dim("Usage: swixter import <file>"));
|
|
24188
25050
|
process.exit(1);
|
|
24189
25051
|
}
|
|
24190
25052
|
try {
|
|
24191
25053
|
const result = await importConfig(filePath, { overwrite: false });
|
|
24192
25054
|
console.log();
|
|
24193
|
-
console.log(
|
|
25055
|
+
console.log(import_picocolors15.default.green("✓") + " Import completed!");
|
|
24194
25056
|
console.log();
|
|
24195
|
-
console.log(` Successfully imported: ${
|
|
24196
|
-
console.log(` Skipped: ${
|
|
24197
|
-
console.log(` Errors: ${
|
|
25057
|
+
console.log(` Successfully imported: ${import_picocolors15.default.green(result.imported)} items`);
|
|
25058
|
+
console.log(` Skipped: ${import_picocolors15.default.yellow(result.skipped)} items`);
|
|
25059
|
+
console.log(` Errors: ${import_picocolors15.default.red(result.errors.length)} items`);
|
|
24198
25060
|
console.log();
|
|
24199
25061
|
if (result.errors.length > 0) {
|
|
24200
|
-
console.log(
|
|
24201
|
-
result.errors.forEach((err) => console.log(
|
|
25062
|
+
console.log(import_picocolors15.default.red("Error details:"));
|
|
25063
|
+
result.errors.forEach((err) => console.log(import_picocolors15.default.red(` - ${err}`)));
|
|
24202
25064
|
console.log();
|
|
24203
25065
|
}
|
|
24204
25066
|
} catch (error46) {
|
|
24205
25067
|
console.log();
|
|
24206
|
-
console.log(
|
|
25068
|
+
console.log(import_picocolors15.default.red(`✗ Import failed: ${error46}`));
|
|
24207
25069
|
console.log();
|
|
24208
25070
|
process.exit(1);
|
|
24209
25071
|
}
|
|
24210
25072
|
}
|
|
24211
25073
|
async function cmdVersion() {
|
|
24212
25074
|
console.log();
|
|
24213
|
-
console.log(
|
|
25075
|
+
console.log(import_picocolors15.default.bold(import_picocolors15.default.cyan("Swixter")) + import_picocolors15.default.dim(" - AI Coder Configuration Manager"));
|
|
24214
25076
|
console.log();
|
|
24215
|
-
console.log(` ${
|
|
24216
|
-
console.log(` ${
|
|
24217
|
-
console.log(` ${
|
|
25077
|
+
console.log(` ${import_picocolors15.default.bold("Version:")} ${import_picocolors15.default.green(APP_VERSION)}`);
|
|
25078
|
+
console.log(` ${import_picocolors15.default.bold("Config Version:")} ${import_picocolors15.default.cyan(CONFIG_VERSION)}`);
|
|
25079
|
+
console.log(` ${import_picocolors15.default.bold("Export Version:")} ${import_picocolors15.default.cyan(EXPORT_VERSION)}`);
|
|
24218
25080
|
console.log();
|
|
24219
|
-
console.log(
|
|
24220
|
-
console.log(
|
|
25081
|
+
console.log(import_picocolors15.default.dim(" GitHub: https://github.com/dawnswwwww/swixter"));
|
|
25082
|
+
console.log(import_picocolors15.default.dim(" NPM: https://www.npmjs.com/package/swixter"));
|
|
24221
25083
|
console.log();
|
|
24222
25084
|
}
|
|
24223
25085
|
async function main() {
|
|
@@ -24228,6 +25090,10 @@ async function main() {
|
|
|
24228
25090
|
showGlobalHelp();
|
|
24229
25091
|
return;
|
|
24230
25092
|
}
|
|
25093
|
+
if (firstArg === "ui") {
|
|
25094
|
+
await handleUiCommand(args.slice(1));
|
|
25095
|
+
return;
|
|
25096
|
+
}
|
|
24231
25097
|
if (firstArg === "claude") {
|
|
24232
25098
|
await handleClaudeCommand(args.slice(1));
|
|
24233
25099
|
return;
|
|
@@ -24260,11 +25126,11 @@ async function main() {
|
|
|
24260
25126
|
await cmdVersion();
|
|
24261
25127
|
return;
|
|
24262
25128
|
}
|
|
24263
|
-
console.log(
|
|
24264
|
-
console.log(
|
|
25129
|
+
console.log(import_picocolors15.default.red(`Unknown command: ${firstArg}`));
|
|
25130
|
+
console.log(import_picocolors15.default.dim("Run 'swixter --help' for help"));
|
|
24265
25131
|
process.exit(1);
|
|
24266
25132
|
} catch (error46) {
|
|
24267
|
-
console.error(
|
|
25133
|
+
console.error(import_picocolors15.default.red("An error occurred:"), error46);
|
|
24268
25134
|
process.exit(1);
|
|
24269
25135
|
}
|
|
24270
25136
|
}
|