swixter 0.1.9 → 0.1.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.
Files changed (2) hide show
  1. package/dist/cli/index.js +523 -96
  2. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -14021,7 +14021,7 @@ var CONFIG_VERSION = "2.0.0", EXPORT_VERSION = "1.0.0";
14021
14021
  var init_versions2 = () => {};
14022
14022
 
14023
14023
  // src/constants/meta.ts
14024
- var APP_VERSION = "0.1.9";
14024
+ var APP_VERSION = "0.1.11";
14025
14025
  var init_meta = () => {};
14026
14026
 
14027
14027
  // src/constants/install.ts
@@ -14459,6 +14459,7 @@ var init_presets = __esm(() => {
14459
14459
  name: "MiniMax CN",
14460
14460
  displayName: "MiniMax (CN)",
14461
14461
  baseURL: "https://api.minimaxi.com/anthropic",
14462
+ baseURLChat: "https://api.minimaxi.com/v1",
14462
14463
  defaultModels: [
14463
14464
  "MiniMax-M2.7"
14464
14465
  ],
@@ -14474,6 +14475,7 @@ var init_presets = __esm(() => {
14474
14475
  name: "MiniMax Global",
14475
14476
  displayName: "MiniMax (Global)",
14476
14477
  baseURL: "https://api.minimax.io/anthropic",
14478
+ baseURLChat: "https://api.minimax.io/v1",
14477
14479
  defaultModels: [
14478
14480
  "MiniMax-M2.7"
14479
14481
  ],
@@ -18986,10 +18988,12 @@ import { join as join3, dirname as dirname4 } from "node:path";
18986
18988
  class CodexAdapter {
18987
18989
  name = "codex";
18988
18990
  configPath;
18989
- authPath;
18990
18991
  constructor() {
18991
- this.configPath = join3(homedir2(), ".codex", "config.toml");
18992
- this.authPath = join3(homedir2(), ".codex", "auth.json");
18992
+ const codexHome = join3(homedir2(), ".codex");
18993
+ this.configPath = join3(codexHome, "config.toml");
18994
+ }
18995
+ getProfileFilePath(profileName) {
18996
+ return join3(dirname4(this.configPath), `swixter-${profileName}.config.toml`);
18993
18997
  }
18994
18998
  async apply(profile) {
18995
18999
  try {
@@ -19019,15 +19023,17 @@ class CodexAdapter {
19019
19023
  config2.model_providers = {};
19020
19024
  }
19021
19025
  config2.model_providers[providerName] = await this.createProviderTable(profile, preset);
19022
- if (!config2.profiles) {
19023
- config2.profiles = {};
19024
- }
19025
- config2.profiles[profileName] = await this.createProfileTable(profile, providerName);
19026
- config2.profile = profileName;
19027
19026
  config2.model_provider = providerName;
19027
+ delete config2.profile;
19028
+ if (config2.profiles) {
19029
+ delete config2.profiles[profileName];
19030
+ if (Object.keys(config2.profiles).length === 0) {
19031
+ delete config2.profiles;
19032
+ }
19033
+ }
19028
19034
  const tomlContent = stringify(config2);
19029
19035
  await writeFile4(this.configPath, tomlContent, "utf-8");
19030
- await this.writeAuthJson(profile);
19036
+ await this.writeProfileFile(profile, providerName);
19031
19037
  } catch (error46) {
19032
19038
  throw new Error(`Failed to apply Codex configuration: ${error46 instanceof Error ? error46.message : String(error46)}`);
19033
19039
  }
@@ -19039,32 +19045,24 @@ class CodexAdapter {
19039
19045
  }
19040
19046
  const content = await readFile4(this.configPath, "utf-8");
19041
19047
  const config2 = parse5(content);
19042
- const profileName = `swixter-${profile.name}`;
19043
- if (config2.profile !== profileName) {
19048
+ const providerName = `swixter-${profile.name}`;
19049
+ if (config2.model_provider !== providerName) {
19044
19050
  return false;
19045
19051
  }
19046
- if (!config2.profiles || !config2.profiles[profileName]) {
19052
+ if (!config2.model_providers || !config2.model_providers[providerName]) {
19047
19053
  return false;
19048
19054
  }
19049
- const providerName = config2.profiles[profileName].model_provider;
19050
- if (!config2.model_providers || !config2.model_providers[providerName]) {
19055
+ const profileFilePath = this.getProfileFilePath(profile.name);
19056
+ if (!existsSync4(profileFilePath)) {
19051
19057
  return false;
19052
19058
  }
19053
- if (profile.apiKey) {
19054
- const envKey = await getEnvKey(profile);
19055
- if (existsSync4(this.authPath)) {
19056
- try {
19057
- const authContent = await readFile4(this.authPath, "utf-8");
19058
- const auth = JSON.parse(authContent);
19059
- if (auth[envKey] !== profile.apiKey) {
19060
- return false;
19061
- }
19062
- } catch {
19063
- return false;
19064
- }
19065
- } else {
19059
+ try {
19060
+ const profileFile = parse5(await readFile4(profileFilePath, "utf-8"));
19061
+ if (profileFile.model_provider !== providerName) {
19066
19062
  return false;
19067
19063
  }
19064
+ } catch {
19065
+ return false;
19068
19066
  }
19069
19067
  return true;
19070
19068
  } catch (error46) {
@@ -19076,8 +19074,7 @@ class CodexAdapter {
19076
19074
  const providerTable = {
19077
19075
  name: preset.displayName,
19078
19076
  base_url: profile.baseURL || baseUrl,
19079
- wire_api: "responses",
19080
- requires_openai_auth: true
19077
+ wire_api: "responses"
19081
19078
  };
19082
19079
  providerTable.env_key = await getEnvKey(profile);
19083
19080
  if (preset.headers) {
@@ -19085,45 +19082,21 @@ class CodexAdapter {
19085
19082
  }
19086
19083
  return providerTable;
19087
19084
  }
19088
- async createProfileTable(profile, providerName) {
19089
- const profileTable = {
19085
+ async writeProfileFile(profile, providerName) {
19086
+ const profileContent = {
19090
19087
  model_provider: providerName
19091
19088
  };
19092
19089
  const modelValue = getOpenAIModel(profile);
19093
19090
  if (modelValue) {
19094
- profileTable.model = modelValue;
19091
+ profileContent.model = modelValue;
19095
19092
  } else {
19096
19093
  const preset = await getPresetByIdAsync(profile.providerId);
19097
19094
  if (preset && preset.defaultModels && preset.defaultModels.length > 0) {
19098
- profileTable.model = preset.defaultModels[0];
19099
- }
19100
- }
19101
- return profileTable;
19102
- }
19103
- async writeAuthJson(profile) {
19104
- const envKey = await getEnvKey(profile);
19105
- let auth = {};
19106
- if (existsSync4(this.authPath)) {
19107
- try {
19108
- const content = await readFile4(this.authPath, "utf-8");
19109
- const parsed = JSON.parse(content);
19110
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
19111
- auth = parsed;
19112
- }
19113
- } catch {
19114
- auth = {};
19095
+ profileContent.model = preset.defaultModels[0];
19115
19096
  }
19116
19097
  }
19117
- if (profile.apiKey) {
19118
- auth[envKey] = profile.apiKey;
19119
- } else {
19120
- delete auth[envKey];
19121
- }
19122
- if (Object.keys(auth).length > 0) {
19123
- await writeFile4(this.authPath, JSON.stringify(auth, null, 2), "utf-8");
19124
- } else if (existsSync4(this.authPath)) {
19125
- await unlink(this.authPath);
19126
- }
19098
+ const profileFilePath = this.getProfileFilePath(profile.name);
19099
+ await writeFile4(profileFilePath, stringify(profileContent), "utf-8");
19127
19100
  }
19128
19101
  async getEnvExportCommands(profile) {
19129
19102
  const commands = await getEnvExportCommands(profile);
@@ -19134,6 +19107,12 @@ class CodexAdapter {
19134
19107
  return commands;
19135
19108
  }
19136
19109
  async remove(profileName) {
19110
+ const profileFilePath = this.getProfileFilePath(profileName);
19111
+ if (existsSync4(profileFilePath)) {
19112
+ try {
19113
+ await unlink(profileFilePath);
19114
+ } catch {}
19115
+ }
19137
19116
  if (!existsSync4(this.configPath)) {
19138
19117
  return;
19139
19118
  }
@@ -19141,20 +19120,23 @@ class CodexAdapter {
19141
19120
  const content = await readFile4(this.configPath, "utf-8");
19142
19121
  const config2 = parse5(content);
19143
19122
  const providerKey = `swixter-${profileName}`;
19144
- const profileKey = `swixter-${profileName}`;
19145
19123
  let modified = false;
19146
- let envKeyToRemove;
19147
19124
  if (config2.model_providers && config2.model_providers[providerKey]) {
19148
- envKeyToRemove = config2.model_providers[providerKey].env_key;
19149
19125
  delete config2.model_providers[providerKey];
19150
19126
  modified = true;
19151
19127
  }
19152
- if (config2.profiles && config2.profiles[profileKey]) {
19153
- delete config2.profiles[profileKey];
19128
+ if (config2.profiles && config2.profiles[providerKey]) {
19129
+ delete config2.profiles[providerKey];
19130
+ if (Object.keys(config2.profiles).length === 0) {
19131
+ delete config2.profiles;
19132
+ }
19154
19133
  modified = true;
19155
19134
  }
19156
- if (config2.profile === profileKey) {
19135
+ if (config2.profile === providerKey) {
19157
19136
  delete config2.profile;
19137
+ modified = true;
19138
+ }
19139
+ if (config2.model_provider === providerKey) {
19158
19140
  delete config2.model_provider;
19159
19141
  modified = true;
19160
19142
  }
@@ -19162,14 +19144,6 @@ class CodexAdapter {
19162
19144
  const tomlContent = stringify(config2);
19163
19145
  await writeFile4(this.configPath, tomlContent, "utf-8");
19164
19146
  }
19165
- if (envKeyToRemove && existsSync4(this.authPath)) {
19166
- try {
19167
- const authContent = await readFile4(this.authPath, "utf-8");
19168
- const auth = JSON.parse(authContent);
19169
- delete auth[envKeyToRemove];
19170
- await writeFile4(this.authPath, JSON.stringify(auth, null, 2), "utf-8");
19171
- } catch {}
19172
- }
19173
19147
  } catch (error46) {
19174
19148
  console.warn(`Failed to remove profile from Codex config: ${error46}`);
19175
19149
  }
@@ -19180,6 +19154,7 @@ var init_codex = __esm(() => {
19180
19154
  init_presets();
19181
19155
  init_model_helper();
19182
19156
  init_env_key_helper();
19157
+ init_env_key_helper();
19183
19158
  });
19184
19159
 
19185
19160
  // src/adapters/index.ts
@@ -21978,6 +21953,9 @@ ${import_picocolors8.default.bold("Examples:")}
21978
21953
 
21979
21954
  ${import_picocolors8.default.dim(`# Run ${CODER_CONFIG.displayName} and pass other arguments`)}
21980
21955
  ${import_picocolors8.default.green(`swixter ${CODER_NAME} r --print "What is 2+2?"`)}
21956
+
21957
+ ${import_picocolors8.default.dim(`# Run ${CODER_CONFIG.displayName} in yolo mode (skips all permission prompts)`)}
21958
+ ${import_picocolors8.default.green(`swixter ${CODER_NAME} r --yolo`)}
21981
21959
  `);
21982
21960
  }
21983
21961
  async function cmdCreate(args) {
@@ -22710,6 +22688,9 @@ async function spawnClaudeWithEnv(args, env, options) {
22710
22688
  if (idx > 0 && args[idx - 1] === "--profile") {
22711
22689
  return false;
22712
22690
  }
22691
+ if (arg === "--yolo") {
22692
+ return false;
22693
+ }
22713
22694
  return true;
22714
22695
  });
22715
22696
  const tmp = await import("node:os");
@@ -22719,6 +22700,11 @@ async function spawnClaudeWithEnv(args, env, options) {
22719
22700
  const tmpFile = path.join(tmp.tmpdir(), `swixter-settings-${Date.now()}.json`);
22720
22701
  await fs.writeFile(tmpFile, settingsContent, "utf-8");
22721
22702
  claudeArgs.push("--settings", tmpFile);
22703
+ if (options?.yolo === true) {
22704
+ if (!claudeArgs.includes("--dangerously-skip-permissions")) {
22705
+ claudeArgs.push("--dangerously-skip-permissions");
22706
+ }
22707
+ }
22722
22708
  if (options?.profileName) {
22723
22709
  console.log();
22724
22710
  console.log(import_picocolors8.default.dim(`Using profile: ${import_picocolors8.default.cyan(options.profileName)}${options.providerDisplayName ? ` (${options.providerDisplayName})` : ""}`));
@@ -22772,7 +22758,8 @@ async function cmdRun(args) {
22772
22758
  await spawnClaudeWithEnv(args, env, {
22773
22759
  profileName: profile.name,
22774
22760
  providerDisplayName: preset?.displayName,
22775
- baseURL
22761
+ baseURL,
22762
+ yolo: params.yolo === true
22776
22763
  });
22777
22764
  }
22778
22765
  async function cmdInstall(args) {
@@ -25706,19 +25693,23 @@ function parseSSEEvents(chunk) {
25706
25693
  if (currentDataLines.length > 0) {
25707
25694
  const dataStr = currentDataLines.join(`
25708
25695
  `);
25709
- try {
25710
- const data = JSON.parse(dataStr);
25711
- events.push({ event: currentEvent, data });
25712
- } catch {}
25696
+ if (dataStr === "[DONE]") {
25697
+ events.push({ event: currentEvent, data: "[DONE]" });
25698
+ } else {
25699
+ try {
25700
+ const data = JSON.parse(dataStr);
25701
+ events.push({ event: currentEvent, data });
25702
+ } catch {}
25703
+ }
25713
25704
  }
25714
25705
  currentEvent = "";
25715
25706
  currentDataLines = [];
25716
25707
  }
25717
25708
  for (const line of lines) {
25718
- if (line.startsWith("event: ")) {
25719
- currentEvent = line.slice("event: ".length);
25720
- } else if (line.startsWith("data: ")) {
25721
- currentDataLines.push(line.slice("data: ".length));
25709
+ if (line.startsWith("event:")) {
25710
+ currentEvent = line.slice("event:".length).replace(/^ /, "");
25711
+ } else if (line.startsWith("data:")) {
25712
+ currentDataLines.push(line.slice("data:".length).replace(/^ /, ""));
25722
25713
  } else if (line === "") {
25723
25714
  flushEvent();
25724
25715
  }
@@ -25877,7 +25868,7 @@ function inferClientFormat(endpoint) {
25877
25868
  return "openai_chat";
25878
25869
  }
25879
25870
  if (endpoint.includes("/v1/responses")) {
25880
- return "anthropic_responses";
25871
+ return "openai_responses";
25881
25872
  }
25882
25873
  if (endpoint.includes("/anthropic/") || endpoint.includes("/v1/messages")) {
25883
25874
  return "anthropic_messages";
@@ -26400,6 +26391,446 @@ var init_openai_chat_to_anthropic2 = __esm(() => {
26400
26391
  });
26401
26392
  });
26402
26393
 
26394
+ // src/proxy/transform/request/openai-responses-to-openai-chat.ts
26395
+ function openaiResponsesToOpenAIChatRequest(body, _ctx) {
26396
+ const r2 = body;
26397
+ const chatBody = { model: r2.model };
26398
+ const messages2 = [];
26399
+ if (typeof r2.instructions === "string" && r2.instructions.length > 0) {
26400
+ messages2.push({ role: "system", content: r2.instructions });
26401
+ }
26402
+ if (Array.isArray(r2.input)) {
26403
+ for (const item of r2.input) {
26404
+ const converted = convertInputItem(item);
26405
+ if (Array.isArray(converted))
26406
+ messages2.push(...converted);
26407
+ else if (converted)
26408
+ messages2.push(converted);
26409
+ }
26410
+ } else if (typeof r2.input === "string" && r2.input.length > 0) {
26411
+ messages2.push({ role: "user", content: r2.input });
26412
+ }
26413
+ chatBody.messages = messages2;
26414
+ if (r2.max_output_tokens !== undefined)
26415
+ chatBody.max_tokens = r2.max_output_tokens;
26416
+ if (r2.temperature !== undefined)
26417
+ chatBody.temperature = r2.temperature;
26418
+ if (r2.top_p !== undefined)
26419
+ chatBody.top_p = r2.top_p;
26420
+ if (r2.stream !== undefined)
26421
+ chatBody.stream = r2.stream;
26422
+ if (r2.parallel_tool_calls !== undefined)
26423
+ chatBody.parallel_tool_calls = r2.parallel_tool_calls;
26424
+ if (Array.isArray(r2.tools)) {
26425
+ chatBody.tools = r2.tools.filter((t) => {
26426
+ const name = t.name;
26427
+ if (typeof name !== "string" || name.length === 0)
26428
+ return false;
26429
+ return TOOL_NAME_RE.test(name);
26430
+ }).map((t) => ({
26431
+ type: "function",
26432
+ function: {
26433
+ name: t.name,
26434
+ description: t.description,
26435
+ parameters: t.parameters && typeof t.parameters === "object" ? t.parameters : { type: "object", properties: {} }
26436
+ }
26437
+ }));
26438
+ }
26439
+ if (r2.tool_choice !== undefined)
26440
+ chatBody.tool_choice = convertToolChoice2(r2.tool_choice);
26441
+ const effort = r2.reasoning?.effort;
26442
+ if (typeof effort === "string")
26443
+ chatBody.reasoning_effort = effort;
26444
+ return { body: chatBody, targetEndpoint: "/v1/chat/completions" };
26445
+ }
26446
+ function convertInputItem(item) {
26447
+ switch (item.type) {
26448
+ case "message": {
26449
+ const role = item.role === "developer" ? "system" : item.role;
26450
+ return { role, content: flattenText(item.content) };
26451
+ }
26452
+ case "function_call": {
26453
+ return {
26454
+ role: "assistant",
26455
+ content: null,
26456
+ tool_calls: [{ id: item.call_id, type: "function", function: { name: item.name, arguments: item.arguments ?? "" } }]
26457
+ };
26458
+ }
26459
+ case "function_call_output": {
26460
+ return {
26461
+ role: "tool",
26462
+ tool_call_id: item.call_id,
26463
+ content: typeof item.output === "string" ? item.output : JSON.stringify(item.output ?? "")
26464
+ };
26465
+ }
26466
+ default:
26467
+ return null;
26468
+ }
26469
+ }
26470
+ function flattenText(content) {
26471
+ if (typeof content === "string")
26472
+ return content;
26473
+ if (!Array.isArray(content))
26474
+ return content;
26475
+ const parts = [];
26476
+ for (const part of content) {
26477
+ if (part.type === "input_text" || part.type === "output_text" || part.type === "text") {
26478
+ parts.push({ type: "text", text: part.text });
26479
+ } else {
26480
+ throw new Error(`openai_responses→openai_chat: unsupported content part type "${part.type}"`);
26481
+ }
26482
+ }
26483
+ if (parts.length === 1 && parts[0].type === "text") {
26484
+ return parts[0].text;
26485
+ }
26486
+ return parts;
26487
+ }
26488
+ function convertToolChoice2(tc) {
26489
+ if (typeof tc === "string")
26490
+ return tc;
26491
+ if (tc && typeof tc === "object") {
26492
+ const t = tc;
26493
+ if (t.type === "function" && t.name) {
26494
+ return { type: "function", function: { name: t.name } };
26495
+ }
26496
+ }
26497
+ return tc;
26498
+ }
26499
+ var TOOL_NAME_RE;
26500
+ var init_openai_responses_to_openai_chat = __esm(() => {
26501
+ TOOL_NAME_RE = /^(?!.*__)[a-zA-Z][a-zA-Z0-9_-]{0,63}$/;
26502
+ });
26503
+
26504
+ // src/proxy/transform/response/openai-chat-to-openai-responses.ts
26505
+ function openAIChatToOpenAIResponsesResponse(body, _ctx) {
26506
+ const chat = body;
26507
+ const choices = chat.choices;
26508
+ const choice = choices?.[0];
26509
+ const message = choice?.message;
26510
+ const output = [];
26511
+ if (message) {
26512
+ if (typeof message.content === "string" && message.content.length > 0) {
26513
+ output.push({
26514
+ type: "message",
26515
+ id: "msg_0",
26516
+ status: "completed",
26517
+ role: "assistant",
26518
+ content: [{ type: "output_text", text: message.content, annotations: [] }]
26519
+ });
26520
+ }
26521
+ if (Array.isArray(message.tool_calls)) {
26522
+ message.tool_calls.forEach((tc, i2) => {
26523
+ const fn = tc.function || {};
26524
+ output.push({
26525
+ type: "function_call",
26526
+ id: `fc_${i2}`,
26527
+ call_id: tc.id,
26528
+ name: fn.name,
26529
+ arguments: typeof fn.arguments === "string" ? fn.arguments : JSON.stringify(fn.arguments ?? ""),
26530
+ status: "completed"
26531
+ });
26532
+ });
26533
+ }
26534
+ }
26535
+ const usage = chat.usage;
26536
+ const inputTokens = usage?.prompt_tokens ?? 0;
26537
+ const outputTokens = usage?.completion_tokens ?? 0;
26538
+ const base = chat.id ? `resp_${chat.id}` : "";
26539
+ const id = base && base !== "resp_" ? base : `resp_${Date.now()}`;
26540
+ return {
26541
+ id,
26542
+ object: "response",
26543
+ status: mapStatus(choice?.finish_reason),
26544
+ model: chat.model ?? "unknown",
26545
+ output,
26546
+ usage: {
26547
+ input_tokens: inputTokens,
26548
+ output_tokens: outputTokens,
26549
+ total_tokens: usage?.total_tokens ?? inputTokens + outputTokens
26550
+ }
26551
+ };
26552
+ }
26553
+ function mapStatus(finishReason) {
26554
+ if (finishReason === "length")
26555
+ return "incomplete";
26556
+ return "completed";
26557
+ }
26558
+
26559
+ // src/proxy/transform/streaming/openai-chat-to-openai-responses.ts
26560
+ function createOpenAIChatToOpenAIResponsesStream(source, ctx) {
26561
+ const stream = source instanceof Uint8Array ? new ReadableStream({
26562
+ start(controller) {
26563
+ controller.enqueue(source);
26564
+ controller.close();
26565
+ }
26566
+ }) : source;
26567
+ return stream.pipeThrough(createSSETransformStream(new OpenAIChatToOpenAIResponsesStreamTransformer(ctx)));
26568
+ }
26569
+ var OpenAIChatToOpenAIResponsesStreamTransformer;
26570
+ var init_openai_chat_to_openai_responses = __esm(() => {
26571
+ init_base();
26572
+ init_transform();
26573
+ init_openai_responses_to_openai_chat();
26574
+ OpenAIChatToOpenAIResponsesStreamTransformer = class OpenAIChatToOpenAIResponsesStreamTransformer extends SSEStreamTransformer {
26575
+ responseId = "";
26576
+ model = "";
26577
+ created = false;
26578
+ textOutputIndex = -1;
26579
+ textStarted = false;
26580
+ textBuf = "";
26581
+ tools = new Map;
26582
+ nextOutputIndex = 0;
26583
+ usage = null;
26584
+ finished = false;
26585
+ convertEvent(event) {
26586
+ if (event.data === "[DONE]")
26587
+ return null;
26588
+ const data = event.data;
26589
+ if (data && data.id)
26590
+ this.responseId = `resp_${data.id}`;
26591
+ if (data && data.model)
26592
+ this.model = data.model;
26593
+ if (data && data.usage)
26594
+ this.usage = data.usage;
26595
+ const choices = data?.choices;
26596
+ const choice = choices?.[0];
26597
+ if (!choice)
26598
+ return null;
26599
+ const out = [];
26600
+ if (!this.created) {
26601
+ this.created = true;
26602
+ out.push({
26603
+ event: "response.created",
26604
+ data: { type: "response.created", response: this.responseShell("in_progress") }
26605
+ });
26606
+ }
26607
+ const delta = choice.delta;
26608
+ if (delta?.content && typeof delta.content === "string") {
26609
+ out.push(...this.handleText(delta.content));
26610
+ }
26611
+ if (Array.isArray(delta?.tool_calls)) {
26612
+ for (const tc of delta.tool_calls)
26613
+ out.push(...this.handleTool(tc));
26614
+ }
26615
+ if (choice.finish_reason && !this.finished) {
26616
+ out.push(...this.finish(choice.finish_reason));
26617
+ }
26618
+ return out;
26619
+ }
26620
+ responseShell(status) {
26621
+ return { id: this.responseId, object: "response", status, model: this.model, output: [] };
26622
+ }
26623
+ handleText(text) {
26624
+ this.textBuf += text;
26625
+ const out = [];
26626
+ if (this.textOutputIndex < 0)
26627
+ this.textOutputIndex = this.nextOutputIndex++;
26628
+ if (!this.textStarted) {
26629
+ this.textStarted = true;
26630
+ out.push({
26631
+ event: "response.output_item.added",
26632
+ data: {
26633
+ type: "response.output_item.added",
26634
+ output_index: this.textOutputIndex,
26635
+ item: { type: "message", id: "msg_0", status: "in_progress", role: "assistant", content: [] }
26636
+ }
26637
+ });
26638
+ out.push({
26639
+ event: "response.content_part.added",
26640
+ data: {
26641
+ type: "response.content_part.added",
26642
+ item_id: "msg_0",
26643
+ output_index: this.textOutputIndex,
26644
+ content_index: 0,
26645
+ part: { type: "output_text", text: "", annotations: [] }
26646
+ }
26647
+ });
26648
+ }
26649
+ out.push({
26650
+ event: "response.output_text.delta",
26651
+ data: {
26652
+ type: "response.output_text.delta",
26653
+ item_id: "msg_0",
26654
+ output_index: this.textOutputIndex,
26655
+ content_index: 0,
26656
+ delta: text
26657
+ }
26658
+ });
26659
+ return out;
26660
+ }
26661
+ handleTool(tc) {
26662
+ const idx = tc.index ?? 0;
26663
+ let st = this.tools.get(idx);
26664
+ if (!st) {
26665
+ st = {
26666
+ outputIndex: this.nextOutputIndex++,
26667
+ itemId: `fc_${idx}`,
26668
+ callId: tc.id ?? `call_${idx}`,
26669
+ name: "",
26670
+ argsBuf: "",
26671
+ announced: false
26672
+ };
26673
+ this.tools.set(idx, st);
26674
+ }
26675
+ if (tc.id)
26676
+ st.callId = tc.id;
26677
+ if (tc.function?.name)
26678
+ st.name = tc.function.name;
26679
+ const out = [];
26680
+ if (!st.announced && st.name) {
26681
+ st.announced = true;
26682
+ out.push({
26683
+ event: "response.output_item.added",
26684
+ data: {
26685
+ type: "response.output_item.added",
26686
+ output_index: st.outputIndex,
26687
+ item: {
26688
+ type: "function_call",
26689
+ id: st.itemId,
26690
+ call_id: st.callId,
26691
+ name: st.name,
26692
+ arguments: "",
26693
+ status: "in_progress"
26694
+ }
26695
+ }
26696
+ });
26697
+ }
26698
+ if (tc.function?.arguments) {
26699
+ st.argsBuf += tc.function.arguments;
26700
+ if (st.announced) {
26701
+ out.push({
26702
+ event: "response.function_call_arguments.delta",
26703
+ data: {
26704
+ type: "response.function_call_arguments.delta",
26705
+ item_id: st.itemId,
26706
+ output_index: st.outputIndex,
26707
+ delta: tc.function.arguments
26708
+ }
26709
+ });
26710
+ }
26711
+ }
26712
+ return out;
26713
+ }
26714
+ finish(_finishReason) {
26715
+ if (this.finished)
26716
+ return [];
26717
+ this.finished = true;
26718
+ const out = [];
26719
+ if (this.textStarted) {
26720
+ out.push({
26721
+ event: "response.output_text.done",
26722
+ data: {
26723
+ type: "response.output_text.done",
26724
+ item_id: "msg_0",
26725
+ output_index: this.textOutputIndex,
26726
+ content_index: 0,
26727
+ text: this.textBuf
26728
+ }
26729
+ });
26730
+ out.push({
26731
+ event: "response.content_part.done",
26732
+ data: {
26733
+ type: "response.content_part.done",
26734
+ item_id: "msg_0",
26735
+ output_index: this.textOutputIndex,
26736
+ content_index: 0,
26737
+ part: { type: "output_text", text: this.textBuf, annotations: [] }
26738
+ }
26739
+ });
26740
+ out.push({
26741
+ event: "response.output_item.done",
26742
+ data: {
26743
+ type: "response.output_item.done",
26744
+ output_index: this.textOutputIndex,
26745
+ item: {
26746
+ type: "message",
26747
+ id: "msg_0",
26748
+ status: "completed",
26749
+ role: "assistant",
26750
+ content: [{ type: "output_text", text: this.textBuf, annotations: [] }]
26751
+ }
26752
+ }
26753
+ });
26754
+ }
26755
+ const outputItems = [];
26756
+ if (this.textStarted) {
26757
+ outputItems.push({
26758
+ type: "message",
26759
+ id: "msg_0",
26760
+ status: "completed",
26761
+ role: "assistant",
26762
+ content: [{ type: "output_text", text: this.textBuf, annotations: [] }]
26763
+ });
26764
+ }
26765
+ for (const st of this.tools.values()) {
26766
+ if (!st.announced)
26767
+ continue;
26768
+ out.push({
26769
+ event: "response.function_call_arguments.done",
26770
+ data: {
26771
+ type: "response.function_call_arguments.done",
26772
+ item_id: st.itemId,
26773
+ output_index: st.outputIndex,
26774
+ arguments: st.argsBuf
26775
+ }
26776
+ });
26777
+ out.push({
26778
+ event: "response.output_item.done",
26779
+ data: {
26780
+ type: "response.output_item.done",
26781
+ output_index: st.outputIndex,
26782
+ item: {
26783
+ type: "function_call",
26784
+ id: st.itemId,
26785
+ call_id: st.callId,
26786
+ name: st.name,
26787
+ arguments: st.argsBuf,
26788
+ status: "completed"
26789
+ }
26790
+ }
26791
+ });
26792
+ outputItems.push({
26793
+ type: "function_call",
26794
+ id: st.itemId,
26795
+ call_id: st.callId,
26796
+ name: st.name,
26797
+ arguments: st.argsBuf,
26798
+ status: "completed"
26799
+ });
26800
+ }
26801
+ const u2 = this.usage ?? {};
26802
+ const inputTokens = u2.prompt_tokens ?? 0;
26803
+ const outputTokens = u2.completion_tokens ?? 0;
26804
+ out.push({
26805
+ event: "response.completed",
26806
+ data: {
26807
+ type: "response.completed",
26808
+ response: {
26809
+ id: this.responseId,
26810
+ object: "response",
26811
+ status: "completed",
26812
+ model: this.model,
26813
+ output: outputItems,
26814
+ usage: {
26815
+ input_tokens: inputTokens,
26816
+ output_tokens: outputTokens,
26817
+ total_tokens: u2.total_tokens ?? inputTokens + outputTokens
26818
+ }
26819
+ }
26820
+ }
26821
+ });
26822
+ return out;
26823
+ }
26824
+ };
26825
+ registerTransformer({
26826
+ clientFormat: "openai_responses",
26827
+ targetFormat: "openai_chat",
26828
+ requestTransform: openaiResponsesToOpenAIChatRequest,
26829
+ responseTransform: openAIChatToOpenAIResponsesResponse,
26830
+ streamTransform: (stream, ctx) => createOpenAIChatToOpenAIResponsesStream(stream, ctx)
26831
+ });
26832
+ });
26833
+
26403
26834
  // src/proxy/router.ts
26404
26835
  class ProxyRouter {
26405
26836
  routes = [];
@@ -26485,8 +26916,9 @@ class ProxyForwarder {
26485
26916
  defaultTimeout = 3000000;
26486
26917
  async forward(request, profile, timeoutMs) {
26487
26918
  const preset = await getPresetByIdAsync(profile.providerId);
26488
- const baseURL = profile.baseURL || preset?.baseURL || "";
26489
- const url2 = `${baseURL}${request.path}`;
26919
+ const baseURL = (profile.baseURL || preset?.baseURL || "").replace(/\/+$/, "");
26920
+ const path = baseURL.endsWith("/v1") && request.path.startsWith("/v1/") ? request.path.slice(3) : request.path;
26921
+ const url2 = `${baseURL}${path}`;
26490
26922
  const timeout = timeoutMs || this.defaultTimeout;
26491
26923
  const headers = Object.fromEntries(Object.entries(request.headers).filter(([key]) => {
26492
26924
  const normalizedKey = key.toLowerCase();
@@ -26794,14 +27226,7 @@ class ProxyHandler {
26794
27226
  if (this.isHealthRequest(request)) {
26795
27227
  return null;
26796
27228
  }
26797
- const token = this.getBearerToken(request);
26798
- if (token === SWIXTER_PROXY_AUTH_TOKEN) {
26799
- return null;
26800
- }
26801
- return new Response(JSON.stringify({ error: "Invalid or missing proxy authentication" }), {
26802
- status: 401,
26803
- headers: { "Content-Type": "application/json" }
26804
- });
27229
+ return null;
26805
27230
  }
26806
27231
  async handleChatCompletions(request) {
26807
27232
  return this.forwardToProvider(request, "chat");
@@ -27112,6 +27537,7 @@ class ProxyHandler {
27112
27537
  }
27113
27538
  var init_handler = __esm(() => {
27114
27539
  init_openai_chat_to_anthropic2();
27540
+ init_openai_chat_to_openai_responses();
27115
27541
  init_model_helper();
27116
27542
  init_forwarder();
27117
27543
  init_manager2();
@@ -30329,9 +30755,10 @@ async function cmdApply3() {
30329
30755
  console.log(` Provider: ${import_picocolors10.default.yellow(preset?.displayName)}`);
30330
30756
  console.log(` Config file: ${import_picocolors10.default.dim(adapter.configPath)}`);
30331
30757
  console.log();
30332
- console.log(import_picocolors10.default.bold("Run Codex now: ") + import_picocolors10.default.cyan("codex"));
30758
+ console.log(import_picocolors10.default.bold("Run Codex now: ") + import_picocolors10.default.cyan("swixter codex run"));
30333
30759
  console.log();
30334
- console.log(import_picocolors10.default.dim("Environment variables are automatically managed via auth.json."));
30760
+ const envKey = profile.envKey || preset?.env_key || "OPENAI_API_KEY";
30761
+ console.log(import_picocolors10.default.dim(`Or export your key first: export ${envKey}=<your-key> then run codex`));
30335
30762
  console.log();
30336
30763
  } else {
30337
30764
  console.log(import_picocolors10.default.yellow("⚠ Profile written, but verification failed"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swixter",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
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",