@vedmalex/ai-connect 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bun/local.js CHANGED
@@ -384,7 +384,7 @@ function normalizeTransport(providerId, input) {
384
384
  };
385
385
  }
386
386
  if (descriptor.kind === "cli") {
387
- const inferredId2 = providerId === "anthropic" ? "claude-cli" : providerId === "openclaude" ? "openclaude-cli" : providerId === "openai" ? "codex-cli" : providerId === "gemini" ? "gemini-cli" : providerId === "qwen" ? "qwen-cli" : "cli";
387
+ const inferredId2 = providerId === "anthropic" ? "claude-cli" : providerId === "openclaude" ? "openclaude-cli" : providerId === "openai" ? "codex-cli" : providerId === "pi" ? "pi-cli" : "cli";
388
388
  return {
389
389
  kind: "cli",
390
390
  id: descriptor.id?.trim() || inferredId2,
@@ -401,7 +401,7 @@ function normalizeTransport(providerId, input) {
401
401
  ...descriptor.baseUrl?.trim() ? { baseUrl: descriptor.baseUrl.trim() } : {}
402
402
  };
403
403
  }
404
- const inferredId = providerId === "anthropic" ? "claude-code-acp" : providerId === "openai" ? "codex-acp" : providerId === "gemini" ? "gemini-acp" : "acp";
404
+ const inferredId = providerId === "anthropic" ? "claude-code-acp" : providerId === "openai" ? "codex-acp" : "acp";
405
405
  const normalizedLaunch = descriptor.launch ? (() => {
406
406
  const contextMode = descriptor.launch?.contextMode ?? "workspace";
407
407
  const skillsMode = descriptor.launch?.skillsMode ?? "default";
@@ -1629,18 +1629,14 @@ var MODEL_REFERENCE = {
1629
1629
  key: "gemini-3.1-flash-lite",
1630
1630
  contextLength: 1048576
1631
1631
  },
1632
+ "gemini-3.1-pro": { key: "gemini-3.1-pro", contextLength: 1048576 },
1632
1633
  "gemini-3-pro": { key: "gemini-3-pro", contextLength: 2097152 },
1633
1634
  "auto-gemini-3": { key: "auto-gemini-3", contextLength: 1048576 },
1634
1635
  "gemini-2.5-flash": { key: "gemini-2.5-flash", contextLength: 1048576 },
1635
1636
  "gemini-2.5-pro": { key: "gemini-2.5-pro", contextLength: 2097152 },
1636
1637
  "gemini-2.0-flash": { key: "gemini-2.0-flash", contextLength: 1048576 },
1637
1638
  "gemini-1.5-flash": { key: "gemini-1.5-flash", contextLength: 1048576 },
1638
- "gemini-1.5-pro": { key: "gemini-1.5-pro", contextLength: 2097152 },
1639
- // --- Qwen (catalog: qwen3-coder-plus) ---
1640
- "qwen3-coder-plus": { key: "qwen3-coder-plus", contextLength: 1048576 },
1641
- "qwen3-coder": { key: "qwen3-coder", contextLength: 262144 },
1642
- "qwen-max": { key: "qwen-max", contextLength: 32768 },
1643
- "qwen-plus": { key: "qwen-plus", contextLength: 131072 }
1639
+ "gemini-1.5-pro": { key: "gemini-1.5-pro", contextLength: 2097152 }
1644
1640
  };
1645
1641
  function normalizeModelKey(model) {
1646
1642
  let key = model.trim().toLowerCase();
@@ -6320,8 +6316,6 @@ import { pathToFileURL } from "node:url";
6320
6316
  var AI_CONNECT_DEFAULT_ACP_COMMANDS = {
6321
6317
  "anthropic:claude-code-acp": "npx -y @agentclientprotocol/claude-agent-acp@^0.25.0",
6322
6318
  "openai:codex-acp": "npx @zed-industries/codex-acp@^0.11.1",
6323
- "gemini:gemini-acp": "gemini --acp",
6324
- "qwen:qwen-acp": "qwen --acp",
6325
6319
  "opencode:opencode-acp": "opencode acp"
6326
6320
  };
6327
6321
 
@@ -6402,15 +6396,6 @@ function resolveHomeDir(env) {
6402
6396
  function resolveXdgConfigHome(env) {
6403
6397
  return env.XDG_CONFIG_HOME ?? path.join(resolveHomeDir(env), ".config");
6404
6398
  }
6405
- function resolveGeminiCliHome(env) {
6406
- return env.GEMINI_CLI_HOME ?? resolveHomeDir(env);
6407
- }
6408
- function resolveGeminiDir(env) {
6409
- return path.join(resolveGeminiCliHome(env), ".gemini");
6410
- }
6411
- function resolveQwenDir(env) {
6412
- return path.join(resolveHomeDir(env), ".qwen");
6413
- }
6414
6399
  function resolveCodexHome(env) {
6415
6400
  return env.CODEX_HOME ?? path.join(resolveHomeDir(env), ".codex");
6416
6401
  }
@@ -6456,118 +6441,6 @@ async function removeIfExists(targetPath) {
6456
6441
  }
6457
6442
  });
6458
6443
  }
6459
- async function readJsonFile(filePath) {
6460
- try {
6461
- const raw = await fs.readFile(filePath, "utf8");
6462
- const parsed = JSON.parse(raw);
6463
- return isRecord2(parsed) ? parsed : void 0;
6464
- } catch (error) {
6465
- if (error instanceof SyntaxError || error.code === "ENOENT") {
6466
- return void 0;
6467
- }
6468
- throw error;
6469
- }
6470
- }
6471
- function mergeRecordValues(current, next) {
6472
- const merged = { ...current };
6473
- for (const [key, value] of Object.entries(next)) {
6474
- const existing = merged[key];
6475
- if (isRecord2(existing) && isRecord2(value)) {
6476
- merged[key] = mergeRecordValues(existing, value);
6477
- continue;
6478
- }
6479
- merged[key] = value;
6480
- }
6481
- return merged;
6482
- }
6483
- async function writeJsonFile(filePath, value) {
6484
- await fs.mkdir(path.dirname(filePath), { recursive: true });
6485
- await fs.writeFile(filePath, `${JSON.stringify(value, null, 2)}
6486
- `, "utf8");
6487
- }
6488
- async function prepareGeminiLaunchRuntime(base, launch) {
6489
- if (launch.contextMode === "workspace" && launch.skillsMode === "default") {
6490
- return {
6491
- ...base,
6492
- launch
6493
- };
6494
- }
6495
- const sandbox = await createSandboxPaths("ai-connect-gemini-acp-");
6496
- const originalGeminiDir = resolveGeminiDir(base.env);
6497
- const sandboxGeminiDir = path.join(sandbox.root, ".gemini");
6498
- const settingsPath = path.join(sandboxGeminiDir, "settings.json");
6499
- const systemSettingsPath = path.join(sandbox.config, "gemini-settings.json");
6500
- const systemDefaultsPath = path.join(
6501
- sandbox.config,
6502
- "gemini-system-defaults.json"
6503
- );
6504
- const isolatedCwd = launch.contextMode === "clean" || launch.skillsMode === "disabled" ? sandbox.root : base.cwd;
6505
- await Promise.all(
6506
- [
6507
- "oauth_creds.json",
6508
- "google_accounts.json",
6509
- "mcp-oauth-tokens.json",
6510
- "a2a-oauth-tokens.json",
6511
- "installation_id"
6512
- ].map(
6513
- (fileName) => maybeCopyFile(
6514
- path.join(originalGeminiDir, fileName),
6515
- path.join(sandboxGeminiDir, fileName)
6516
- )
6517
- )
6518
- );
6519
- const settings = mergeRecordValues(
6520
- await readJsonFile(settingsPath) ?? {},
6521
- {
6522
- context: {
6523
- fileName: "AI_CONNECT_CONTEXT_DISABLED.md",
6524
- includeDirectoryTree: false,
6525
- memoryBoundaryMarkers: [],
6526
- includeDirectories: [],
6527
- loadMemoryFromIncludeDirectories: false,
6528
- discoveryMaxDirs: 0
6529
- },
6530
- admin: {
6531
- mcp: {
6532
- enabled: false,
6533
- config: {},
6534
- requiredConfig: {}
6535
- },
6536
- ...launch.skillsMode === "disabled" ? {
6537
- skills: {
6538
- enabled: false
6539
- }
6540
- } : {}
6541
- },
6542
- ...launch.skillsMode === "disabled" ? {
6543
- skills: {
6544
- enabled: false,
6545
- disabled: []
6546
- }
6547
- } : {}
6548
- }
6549
- );
6550
- await Promise.all([
6551
- writeJsonFile(settingsPath, settings),
6552
- writeJsonFile(systemSettingsPath, {}),
6553
- writeJsonFile(systemDefaultsPath, {})
6554
- ]);
6555
- return {
6556
- commandLine: base.commandLine,
6557
- cwd: isolatedCwd,
6558
- env: {
6559
- ...base.env,
6560
- HOME: sandbox.root,
6561
- GEMINI_CLI_HOME: sandbox.root,
6562
- GEMINI_CLI_SYSTEM_SETTINGS_PATH: systemSettingsPath,
6563
- GEMINI_CLI_SYSTEM_DEFAULTS_PATH: systemDefaultsPath
6564
- },
6565
- launch,
6566
- cleanup: async () => {
6567
- await removeIfExists(sandbox.root);
6568
- }
6569
- };
6570
- }
6571
6444
  async function prepareOpenCodeLaunchRuntime(base, launch) {
6572
6445
  if (launch.contextMode === "workspace" && launch.skillsMode === "default") {
6573
6446
  return {
@@ -6616,70 +6489,6 @@ async function prepareOpenCodeLaunchRuntime(base, launch) {
6616
6489
  }
6617
6490
  };
6618
6491
  }
6619
- async function prepareQwenLaunchRuntime(base, launch) {
6620
- if (launch.contextMode === "workspace" && launch.skillsMode === "default") {
6621
- return {
6622
- ...base,
6623
- launch
6624
- };
6625
- }
6626
- const sandbox = await createSandboxPaths("ai-connect-qwen-acp-");
6627
- const originalQwenDir = resolveQwenDir(base.env);
6628
- const sandboxQwenDir = path.join(sandbox.home, ".qwen");
6629
- const settingsPath = path.join(sandboxQwenDir, "settings.json");
6630
- const systemSettingsPath = path.join(sandbox.config, "qwen-settings.json");
6631
- const systemDefaultsPath = path.join(
6632
- sandbox.config,
6633
- "qwen-system-defaults.json"
6634
- );
6635
- await Promise.all(
6636
- [
6637
- "oauth_creds.json",
6638
- "mcp-oauth-tokens.json",
6639
- "installation_id",
6640
- ".env",
6641
- "settings.json"
6642
- ].map(
6643
- (fileName) => maybeCopyFile(
6644
- path.join(originalQwenDir, fileName),
6645
- path.join(sandboxQwenDir, fileName)
6646
- )
6647
- )
6648
- );
6649
- const settings = mergeRecordValues(
6650
- await readJsonFile(settingsPath) ?? {},
6651
- {
6652
- context: {
6653
- fileName: ["AI_CONNECT_CONTEXT_DISABLED.md"],
6654
- includeDirectories: [],
6655
- loadFromIncludeDirectories: false
6656
- },
6657
- model: {
6658
- skipStartupContext: true
6659
- }
6660
- }
6661
- );
6662
- await Promise.all([
6663
- writeJsonFile(settingsPath, settings),
6664
- writeJsonFile(systemSettingsPath, {}),
6665
- writeJsonFile(systemDefaultsPath, {})
6666
- ]);
6667
- const isolatedCwd = launch.contextMode === "clean" || launch.skillsMode === "disabled" ? sandbox.root : base.cwd;
6668
- return {
6669
- commandLine: base.commandLine,
6670
- cwd: isolatedCwd,
6671
- env: {
6672
- ...base.env,
6673
- HOME: sandbox.home,
6674
- QWEN_CODE_SYSTEM_SETTINGS_PATH: systemSettingsPath,
6675
- QWEN_CODE_SYSTEM_DEFAULTS_PATH: systemDefaultsPath
6676
- },
6677
- launch,
6678
- cleanup: async () => {
6679
- await removeIfExists(sandbox.root);
6680
- }
6681
- };
6682
- }
6683
6492
  async function prepareCodexLaunchRuntime(base, launch) {
6684
6493
  if (launch.contextMode === "workspace" && launch.skillsMode === "default") {
6685
6494
  return {
@@ -6797,15 +6606,9 @@ async function prepareAcpLaunchRuntime(route, options, commandLine, cwdOverride)
6797
6606
  ...options?.env ?? {}
6798
6607
  }
6799
6608
  };
6800
- if (route.transport.id === "gemini-acp") {
6801
- return prepareGeminiLaunchRuntime(base, launch);
6802
- }
6803
6609
  if (route.transport.id === "opencode-acp") {
6804
6610
  return prepareOpenCodeLaunchRuntime(base, launch);
6805
6611
  }
6806
- if (route.transport.id === "qwen-acp") {
6807
- return prepareQwenLaunchRuntime(base, launch);
6808
- }
6809
6612
  if (route.transport.id === "codex-acp") {
6810
6613
  return prepareCodexLaunchRuntime(base, launch);
6811
6614
  }
@@ -7386,10 +7189,6 @@ function buildAcpLifecycle(route, authRequest, mode) {
7386
7189
  steps.push("authenticate");
7387
7190
  }
7388
7191
  steps.push("session/new");
7389
- if (mode === "prompt" && route.transport.id === "gemini-acp") {
7390
- steps.push("session/set_model");
7391
- keys.push("session/set_model.modelId");
7392
- }
7393
7192
  if (mode === "prompt") {
7394
7193
  steps.push("session/prompt");
7395
7194
  }
@@ -7525,16 +7324,6 @@ var AcpConnection = class {
7525
7324
  );
7526
7325
  }
7527
7326
  const sessionId = session.sessionId;
7528
- if (context.route.transport.id === "gemini-acp") {
7529
- await measurePhase(
7530
- transport.phases ?? [],
7531
- "session/set_model",
7532
- async () => this.request("session/set_model", {
7533
- sessionId,
7534
- modelId: context.route.model
7535
- })
7536
- );
7537
- }
7538
7327
  this.activePrompt = {
7539
7328
  sessionId,
7540
7329
  text: "",
@@ -8047,9 +7836,6 @@ var AcpConnection = class {
8047
7836
  });
8048
7837
  }
8049
7838
  };
8050
- function isGeminiAcpFallbackCandidate(route, commandLine) {
8051
- return route.transport.id === "gemini-acp" && commandLine.includes("--acp") && !commandLine.includes("--experimental-acp");
8052
- }
8053
7839
  function cacheKeyForConnection(route, runtime, options) {
8054
7840
  const envEntries = Object.entries(options.env).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => `${key}=${value}`).join("");
8055
7841
  return [
@@ -8296,18 +8082,7 @@ function createAcpTransportManager(options) {
8296
8082
  }
8297
8083
  async function drivePrompt(context, onDelta) {
8298
8084
  const commandLine = resolveAcpCommand(context.route, options);
8299
- try {
8300
- return await runWithCommand(context, commandLine, onDelta);
8301
- } catch (error) {
8302
- if (!isGeminiAcpFallbackCandidate(context.route, commandLine)) {
8303
- throw error;
8304
- }
8305
- return await runWithCommand(
8306
- context,
8307
- commandLine.replace("--acp", "--experimental-acp"),
8308
- onDelta
8309
- );
8310
- }
8085
+ return await runWithCommand(context, commandLine, onDelta);
8311
8086
  }
8312
8087
  return {
8313
8088
  async runPrompt(context) {
@@ -8376,17 +8151,7 @@ function createAcpTransportManager(options) {
8376
8151
  },
8377
8152
  async discoverModels(context) {
8378
8153
  const commandLine = resolveAcpCommand(context.route, options);
8379
- try {
8380
- return await discoverWithCommand(context, commandLine);
8381
- } catch (error) {
8382
- if (!isGeminiAcpFallbackCandidate(context.route, commandLine)) {
8383
- throw error;
8384
- }
8385
- return await discoverWithCommand(
8386
- context,
8387
- commandLine.replace("--acp", "--experimental-acp")
8388
- );
8389
- }
8154
+ return await discoverWithCommand(context, commandLine);
8390
8155
  },
8391
8156
  async dispose() {
8392
8157
  const values = [...connectionPools.values()].flat();
@@ -8413,47 +8178,21 @@ import path2 from "node:path";
8413
8178
 
8414
8179
  // src/cli-presets.ts
8415
8180
  var AI_CONNECT_DEFAULT_CLI_PRESETS = {
8416
- gemini: {
8417
- id: "gemini",
8418
- label: "Gemini CLI",
8419
- command: "gemini",
8420
- transportId: "gemini-cli",
8421
- options: {
8422
- preset: "gemini",
8423
- argsTemplate: ["-p", "{prompt}", "--output-format", "json", "--model", "{model}"],
8424
- discovery: {
8425
- via: "acp",
8426
- acp: {
8427
- transportId: "gemini-acp"
8428
- }
8429
- },
8430
- parser: {
8431
- kind: "json",
8432
- textPath: "response",
8433
- usagePath: "stats",
8434
- errorPath: "error"
8435
- }
8436
- }
8437
- },
8438
- qwen: {
8439
- id: "qwen",
8440
- label: "Qwen CLI",
8441
- command: "qwen",
8442
- transportId: "qwen-cli",
8181
+ pi: {
8182
+ id: "pi",
8183
+ label: "pi (coding agent)",
8184
+ command: "pi",
8185
+ transportId: "pi-cli",
8443
8186
  options: {
8444
- preset: "qwen",
8445
- argsTemplate: ["-p", "{prompt}", "--output-format", "json", "--model", "{model}"],
8187
+ preset: "pi",
8188
+ // pi print mode emits the answer as plain text on stdout (no JSON wrapper),
8189
+ // and has no ACP mode — so it uses the raw `text` parser and no discovery sidecar.
8190
+ argsTemplate: ["--print", "--model", "{model}", "{prompt}"],
8446
8191
  discovery: {
8447
- via: "acp",
8448
- acp: {
8449
- transportId: "qwen-acp"
8450
- }
8192
+ via: "none"
8451
8193
  },
8452
8194
  parser: {
8453
- kind: "json",
8454
- textPath: "__preset__:qwen.result",
8455
- usagePath: "__preset__:qwen.stats",
8456
- errorPath: "__preset__:qwen.error"
8195
+ kind: "text"
8457
8196
  }
8458
8197
  }
8459
8198
  },
@@ -8537,8 +8276,7 @@ var AI_CONNECT_DEFAULT_CLI_COMMANDS = {
8537
8276
  "anthropic:openclaude-cli": AI_CONNECT_DEFAULT_CLI_PRESETS.openclaude.command,
8538
8277
  "openclaude:openclaude-cli": AI_CONNECT_DEFAULT_CLI_PRESETS.openclaude.command,
8539
8278
  "openai:codex-cli": AI_CONNECT_DEFAULT_CLI_PRESETS.codex.command,
8540
- "gemini:gemini-cli": AI_CONNECT_DEFAULT_CLI_PRESETS.gemini.command,
8541
- "qwen:qwen-cli": AI_CONNECT_DEFAULT_CLI_PRESETS.qwen.command
8279
+ "pi:pi-cli": AI_CONNECT_DEFAULT_CLI_PRESETS.pi.command
8542
8280
  };
8543
8281
  function getCliTransportPreset(presetId) {
8544
8282
  return AI_CONNECT_DEFAULT_CLI_PRESETS[presetId];
@@ -8546,14 +8284,6 @@ function getCliTransportPreset(presetId) {
8546
8284
 
8547
8285
  // src/cli.ts
8548
8286
  var CLI_PRESET_ACP_DISCOVERY_DEFAULTS = {
8549
- gemini: {
8550
- transportId: "gemini-acp",
8551
- providerId: "gemini"
8552
- },
8553
- qwen: {
8554
- transportId: "qwen-acp",
8555
- providerId: "qwen"
8556
- },
8557
8287
  claude: {
8558
8288
  transportId: "claude-code-acp",
8559
8289
  providerId: "anthropic"
@@ -8660,10 +8390,8 @@ function buildCliCwd(context, options) {
8660
8390
  }
8661
8391
  function defaultCliPresetIdForRoute(route) {
8662
8392
  switch (route.transport.id) {
8663
- case "gemini-cli":
8664
- return "gemini";
8665
- case "qwen-cli":
8666
- return "qwen";
8393
+ case "pi-cli":
8394
+ return "pi";
8667
8395
  case "claude-cli":
8668
8396
  return "claude";
8669
8397
  case "openclaude-cli":
@@ -9042,60 +8770,6 @@ function parseCliModelList(stdout, parser, selector) {
9042
8770
  }
9043
8771
  return models;
9044
8772
  }
9045
- function parseGeminiCli(stdout) {
9046
- const payload = JSON.parse(stdout);
9047
- if (typeof payload.error === "string") {
9048
- throw new AiConnectError("temporary_unavailable", payload.error);
9049
- }
9050
- if (typeof payload.response !== "string") {
9051
- throw new AiConnectError(
9052
- "temporary_unavailable",
9053
- "Gemini CLI JSON output did not include response text."
9054
- );
9055
- }
9056
- const usage = payload.stats ? statsToUsage(payload.stats) : void 0;
9057
- return {
9058
- text: payload.response,
9059
- ...usage ? { usage } : {},
9060
- data: payload
9061
- };
9062
- }
9063
- function parseQwenCli(stdout) {
9064
- const payload = JSON.parse(stdout);
9065
- if (!Array.isArray(payload)) {
9066
- throw new AiConnectError(
9067
- "temporary_unavailable",
9068
- "Qwen CLI JSON output did not return a message array."
9069
- );
9070
- }
9071
- const resultMessage = payload.find(
9072
- (entry) => entry && typeof entry === "object" && entry.type === "result"
9073
- );
9074
- if (!resultMessage) {
9075
- throw new AiConnectError(
9076
- "temporary_unavailable",
9077
- "Qwen CLI JSON output did not contain a result message."
9078
- );
9079
- }
9080
- if (resultMessage.is_error === true) {
9081
- throw new AiConnectError(
9082
- "temporary_unavailable",
9083
- typeof resultMessage.result === "string" ? resultMessage.result : "Qwen CLI returned an error result."
9084
- );
9085
- }
9086
- if (typeof resultMessage.result !== "string") {
9087
- throw new AiConnectError(
9088
- "temporary_unavailable",
9089
- "Qwen CLI result message did not contain text output."
9090
- );
9091
- }
9092
- const usage = resultMessage.stats ? statsToUsage(resultMessage.stats) : void 0;
9093
- return {
9094
- text: resultMessage.result,
9095
- ...usage ? { usage } : {},
9096
- data: payload
9097
- };
9098
- }
9099
8773
  function parseClaudeCli(stdout) {
9100
8774
  const payload = JSON.parse(stdout);
9101
8775
  const text = typeof payload.result === "string" ? payload.result : typeof payload.response === "string" ? payload.response : typeof payload.text === "string" ? payload.text : void 0;
@@ -9181,10 +8855,8 @@ function parseCliResult(route, result, outputFileContent) {
9181
8855
  }
9182
8856
  }
9183
8857
  switch (cliOptions.preset) {
9184
- case "gemini":
9185
- return parseGeminiCli(stdout);
9186
- case "qwen":
9187
- return parseQwenCli(stdout);
8858
+ case "pi":
8859
+ return parseTextCli(stdout, { kind: "text" });
9188
8860
  case "claude":
9189
8861
  case "openclaude":
9190
8862
  return parseClaudeCli(stdout);