@aiderdesk/aiderdesk 0.70.0 → 0.71.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.
Files changed (75) hide show
  1. package/README.md +49 -0
  2. package/out/cli.js +1006 -1
  3. package/out/renderer/assets/{AgentSettings-4fCr6MRo.js → AgentSettings-BKSogFrU.js} +133 -125
  4. package/out/renderer/assets/{InfoIcon-Cend8bQ6.js → InfoIcon-XbMgPv1i.js} +1 -1
  5. package/out/renderer/assets/{Onboarding-SfOrsd7I.js → Onboarding-DsxeAj-M.js} +4 -4
  6. package/out/renderer/assets/{ProviderHeader-IIBa8Q98.js → ProviderHeader-CQHU1_fp.js} +384 -165
  7. package/out/renderer/assets/{SettingsPage-1PPq3lwt.js → SettingsPage-jGXWkGLq.js} +643 -265
  8. package/out/renderer/assets/{UsageDashboard-C73v7_7A.js → UsageDashboard-BcWDkudQ.js} +3 -3
  9. package/out/renderer/assets/{arc-DooaZ_2W.js → arc-CbTCDvhP.js} +1 -1
  10. package/out/renderer/assets/{architectureDiagram-3BPJPVTR-BZRfdU_l.js → architectureDiagram-3BPJPVTR-BYGjkH2o.js} +3 -3
  11. package/out/renderer/assets/{blockDiagram-GPEHLZMM-GVLrld7f.js → blockDiagram-GPEHLZMM-BNslNypY.js} +4 -4
  12. package/out/renderer/assets/{c4Diagram-AAUBKEIU-CuLHxnUp.js → c4Diagram-AAUBKEIU-BOUV-4Hf.js} +2 -2
  13. package/out/renderer/assets/{channel-CBp4QC42.js → channel-gTXtcW6n.js} +1 -1
  14. package/out/renderer/assets/{chunk-2J33WTMH-CLGSY5ry.js → chunk-2J33WTMH-cVAo2nRo.js} +1 -1
  15. package/out/renderer/assets/{chunk-4BX2VUAB-DfOAmq0y.js → chunk-4BX2VUAB-QUppBCep.js} +1 -1
  16. package/out/renderer/assets/{chunk-55IACEB6-CjDMk8wF.js → chunk-55IACEB6-B7ATOpEx.js} +1 -1
  17. package/out/renderer/assets/{chunk-727SXJPM-4GHP5or6.js → chunk-727SXJPM-DNHjk-uw.js} +5 -5
  18. package/out/renderer/assets/{chunk-AQP2D5EJ-B8ex3L6d.js → chunk-AQP2D5EJ-C_nuud1y.js} +3 -3
  19. package/out/renderer/assets/{chunk-FMBD7UC4-DXVKqz45.js → chunk-FMBD7UC4-DoAO6UdZ.js} +1 -1
  20. package/out/renderer/assets/{chunk-ND2GUHAM-CJf331B5.js → chunk-ND2GUHAM-hRnym-e6.js} +1 -1
  21. package/out/renderer/assets/{chunk-QZHKN3VN-CmRmlYwi.js → chunk-QZHKN3VN-BkTqSMpi.js} +1 -1
  22. package/out/renderer/assets/{classDiagram-4FO5ZUOK-BB0WWhct.js → classDiagram-4FO5ZUOK-097_YN8Y.js} +6 -6
  23. package/out/renderer/assets/{classDiagram-v2-Q7XG4LA2-BB0WWhct.js → classDiagram-v2-Q7XG4LA2-097_YN8Y.js} +6 -6
  24. package/out/renderer/assets/{cose-bilkent-S5V4N54A-C1ovVUkK.js → cose-bilkent-S5V4N54A-CU24fSZY.js} +1 -1
  25. package/out/renderer/assets/{dagre-BM42HDAG-BN2vkdYj.js → dagre-BM42HDAG-CXQk6wIx.js} +3 -3
  26. package/out/renderer/assets/{diagram-2AECGRRQ-Gmur2BYD.js → diagram-2AECGRRQ-cp5zubxu.js} +3 -3
  27. package/out/renderer/assets/{diagram-5GNKFQAL-CO-0qbfq.js → diagram-5GNKFQAL-Dz1liaVJ.js} +4 -4
  28. package/out/renderer/assets/{diagram-KO2AKTUF-B0BourUo.js → diagram-KO2AKTUF-C_a_DDR7.js} +3 -3
  29. package/out/renderer/assets/{diagram-LMA3HP47-CZSemlgR.js → diagram-LMA3HP47-DMzt3Wms.js} +3 -3
  30. package/out/renderer/assets/{diagram-OG6HWLK6-DIg_VSi2.js → diagram-OG6HWLK6-DXgo41ZN.js} +4 -4
  31. package/out/renderer/assets/{erDiagram-TEJ5UH35-CeDB_1TN.js → erDiagram-TEJ5UH35-Duy8-ZVE.js} +4 -4
  32. package/out/renderer/assets/{flowDiagram-I6XJVG4X-CAYyZ6xk.js → flowDiagram-I6XJVG4X-C79uBv3j.js} +6 -6
  33. package/out/renderer/assets/{ganttDiagram-6RSMTGT7-28qx3HO3.js → ganttDiagram-6RSMTGT7-COUQHYqH.js} +3 -3
  34. package/out/renderer/assets/{gitGraphDiagram-PVQCEYII-C0C5PVgG.js → gitGraphDiagram-PVQCEYII-D3-KSp5g.js} +4 -4
  35. package/out/renderer/assets/{graph-BmyvWy9U.js → graph-CojOaclU.js} +1 -1
  36. package/out/renderer/assets/{index-CCixlVbO.js → index-BDc7WeA_.js} +1 -1
  37. package/out/renderer/assets/{index-CqkLi8Rn.js → index-BX1dnn54.js} +1 -1
  38. package/out/renderer/assets/{index-BkEUNx2M.js → index-BxH3Vzns.js} +129 -30
  39. package/out/renderer/assets/{index-CleisQX7.js → index-CZVPwEh7.js} +1 -1
  40. package/out/renderer/assets/{index-DHgg9rnw.js → index-CcbWMGtO.js} +1 -1
  41. package/out/renderer/assets/{index-LwoRwQcK.js → index-CoN3I29h.js} +1 -1
  42. package/out/renderer/assets/{index-D4QsfuBU.css → index-DJwDiyPe.css} +8 -0
  43. package/out/renderer/assets/{index-CjWyE7Qc.js → index-DqOJFqtI.js} +1 -1
  44. package/out/renderer/assets/{index-DDyjc4hl.js → index-DqOyb6kJ.js} +1 -1
  45. package/out/renderer/assets/{index-DiXCQ0pX.js → index-LigRSjJQ.js} +2274 -1492
  46. package/out/renderer/assets/{index-D1hWSFOH.js → index-uk-xw9ke.js} +1 -1
  47. package/out/renderer/assets/{infoDiagram-5YYISTIA-BR2qewYU.js → infoDiagram-5YYISTIA-Dhu3XDyU.js} +2 -2
  48. package/out/renderer/assets/{ishikawaDiagram-YF4QCWOH-mBtVTtfu.js → ishikawaDiagram-YF4QCWOH-Zv844Inp.js} +1 -1
  49. package/out/renderer/assets/{journeyDiagram-JHISSGLW-BLwLxSRJ.js → journeyDiagram-JHISSGLW-CiEy0k__.js} +4 -4
  50. package/out/renderer/assets/{jsx-dev-runtime-C3x5nPQV.js → jsx-dev-runtime-BblfdcBq.js} +1 -1
  51. package/out/renderer/assets/{kanban-definition-UN3LZRKU-DEQMBIes.js → kanban-definition-UN3LZRKU-Bg7Tn0_t.js} +2 -2
  52. package/out/renderer/assets/{layout-COZ2dLJC.js → layout-C7gScUZ3.js} +2 -2
  53. package/out/renderer/assets/{linear-BwuiC9BD.js → linear-C8mfmsRG.js} +1 -1
  54. package/out/renderer/assets/{mindmap-definition-RKZ34NQL-BEdOr2LN.js → mindmap-definition-RKZ34NQL-CT41c9xA.js} +3 -3
  55. package/out/renderer/assets/{pieDiagram-4H26LBE5-C2CIjhWa.js → pieDiagram-4H26LBE5-4MIz5Tk3.js} +4 -4
  56. package/out/renderer/assets/{quadrantDiagram-W4KKPZXB-ByG1Fnbm.js → quadrantDiagram-W4KKPZXB-srrdZ4mO.js} +2 -2
  57. package/out/renderer/assets/{requirementDiagram-4Y6WPE33-CPNEbV2R.js → requirementDiagram-4Y6WPE33-hCfEAv72.js} +3 -3
  58. package/out/renderer/assets/{sankeyDiagram-5OEKKPKP-DseN3BYS.js → sankeyDiagram-5OEKKPKP-D3Dmoahf.js} +1 -1
  59. package/out/renderer/assets/{sequenceDiagram-3UESZ5HK-DGbPycPW.js → sequenceDiagram-3UESZ5HK-B_R1OT73.js} +3 -3
  60. package/out/renderer/assets/{stateDiagram-AJRCARHV-I_wGtDx-.js → stateDiagram-AJRCARHV-T81AxWaT.js} +6 -6
  61. package/out/renderer/assets/{stateDiagram-v2-BHNVJYJU-MVwIUdrA.js → stateDiagram-v2-BHNVJYJU-DotM3iTY.js} +4 -4
  62. package/out/renderer/assets/{time-DKSwLtIL.js → time-NQi4RUKr.js} +1 -1
  63. package/out/renderer/assets/{timeline-definition-PNZ67QCA-0o1eLzXF.js → timeline-definition-PNZ67QCA-CuIJOcqs.js} +2 -2
  64. package/out/renderer/assets/{vennDiagram-CIIHVFJN-BbPtgu5r.js → vennDiagram-CIIHVFJN-BP9XceqR.js} +1 -1
  65. package/out/renderer/assets/{wardley-L42UT6IY-C6O9NaAx.js → wardley-L42UT6IY-Cs8sx4Yc.js} +1 -1
  66. package/out/renderer/assets/{wardleyDiagram-YWT4CUSO-C0NB17Hf.js → wardleyDiagram-YWT4CUSO-BleVwqnB.js} +3 -3
  67. package/out/renderer/assets/{xychartDiagram-2RQKCTM6-CM1NB5k6.js → xychartDiagram-2RQKCTM6-CoEiSbj_.js} +2 -2
  68. package/out/renderer/index.html +2 -2
  69. package/out/runner.js +613 -287
  70. package/package.json +20 -20
  71. package/scripts/generate-package.mjs +1 -2
  72. package/scripts/publish-next.mjs +22 -0
  73. package/out/renderer/assets/gemini-cli-BKI4k4GP.png +0 -0
  74. package/out/resources/mcp-server/aider-desk-mcp-server.js +0 -39437
  75. package/patches/ai-sdk-provider-gemini-cli+1.5.1.patch +0 -373
package/out/runner.js CHANGED
@@ -33,11 +33,10 @@ const os = require("os");
33
33
  const http = require("http");
34
34
  const istextorbinary = require("istextorbinary");
35
35
  const child_process = require("child_process");
36
- const util = require("util");
37
36
  const treeKill = require("tree-kill");
38
- const ai = require("ai");
39
37
  const glob = require("glob");
40
38
  const fs$1 = require("fs");
39
+ const util = require("util");
41
40
  const dotenvx = require("@dotenvx/dotenvx");
42
41
  const YAML = require("yaml");
43
42
  const posthogNode = require("posthog-node");
@@ -66,6 +65,7 @@ const debounce = require("lodash/debounce.js");
66
65
  const crypto = require("crypto");
67
66
  const undici = require("undici");
68
67
  const globalAgent = require("global-agent");
68
+ const ai = require("ai");
69
69
  const fileType = require("file-type");
70
70
  const anthropic = require("@ai-sdk/anthropic");
71
71
  const azure = require("@ai-sdk/azure");
@@ -281,6 +281,7 @@ var MessageViewMode = /* @__PURE__ */ ((MessageViewMode2) => {
281
281
  return MessageViewMode2;
282
282
  })(MessageViewMode || {});
283
283
  var ReasoningEffort = /* @__PURE__ */ ((ReasoningEffort2) => {
284
+ ReasoningEffort2["Max"] = "max";
284
285
  ReasoningEffort2["XHigh"] = "xhigh";
285
286
  ReasoningEffort2["High"] = "high";
286
287
  ReasoningEffort2["Medium"] = "medium";
@@ -820,7 +821,6 @@ const SETUP_COMPLETE_FILENAME = path.join(AIDER_DESK_DATA_DIR, "setup-complete")
820
821
  const PYTHON_VENV_DIR = path.join(AIDER_DESK_DATA_DIR, "python-venv");
821
822
  const PYTHON_COMMAND = process.platform === "win32" ? path.join(PYTHON_VENV_DIR, "Scripts", "python.exe") : path.join(PYTHON_VENV_DIR, "bin", "python");
822
823
  const AIDER_DESK_CONNECTOR_DIR = path.join(AIDER_DESK_DATA_DIR, "aider-connector");
823
- const AIDER_DESK_MCP_SERVER_DIR = path.join(AIDER_DESK_DATA_DIR, "mcp-server");
824
824
  const AIDER_DESK_BIN_DIR = path.join(AIDER_DESK_DATA_DIR, "bin");
825
825
  const UV_EXECUTABLE = process.platform === "win32" ? path.join(AIDER_DESK_BIN_DIR, "uv.exe") : path.join(AIDER_DESK_BIN_DIR, "uv");
826
826
  const RIPGREP_BINARY_PATH = process.platform === "win32" ? path.join(AIDER_DESK_BIN_DIR, "rg.exe") : path.join(AIDER_DESK_BIN_DIR, "rg");
@@ -1398,40 +1398,6 @@ const getShellPath = () => {
1398
1398
  return fallbackPath;
1399
1399
  }
1400
1400
  };
1401
- const findExecutableInPath = (executable, checkOnly = false) => {
1402
- logger.debug(`Finding executable: ${executable}`);
1403
- const shellPath = getShellPath();
1404
- const pathSep = getPathSeparator();
1405
- const paths = shellPath.split(pathSep);
1406
- const isWindows = process.platform === "win32";
1407
- logger.debug(`Searching in ${paths.length} PATH directories`);
1408
- const executableNames = isWindows ? [executable, `${executable}.exe`, `${executable}.cmd`, `${executable}.bat`] : [executable];
1409
- let searchedPaths = 0;
1410
- for (const dir of paths) {
1411
- for (const execName of executableNames) {
1412
- const fullPath = path__namespace.join(dir, execName);
1413
- searchedPaths++;
1414
- try {
1415
- if (isWindows) {
1416
- fs__namespace.accessSync(fullPath, fs__namespace.constants.F_OK);
1417
- logger.debug(`Found executable at: ${fullPath}`);
1418
- return fullPath;
1419
- } else {
1420
- child_process.execSync(`test -x "${fullPath}"`, { stdio: "ignore" });
1421
- logger.debug(`Found executable at: ${fullPath}`);
1422
- return fullPath;
1423
- }
1424
- } catch {
1425
- }
1426
- }
1427
- }
1428
- if (!checkOnly) {
1429
- logger.error(`Executable '${executable}' not found after searching ${searchedPaths} paths`, {
1430
- firstFewPaths: paths.slice(0, 5).join(", ")
1431
- });
1432
- }
1433
- return null;
1434
- };
1435
1401
  const getShellCommandArgs = (command) => {
1436
1402
  return ShellDetector.getShellCommandArgs(command);
1437
1403
  };
@@ -1502,7 +1468,6 @@ const AVAILABLE_PROVIDERS = [
1502
1468
  "cerebras",
1503
1469
  "deepseek",
1504
1470
  "gemini",
1505
- "gemini-cli",
1506
1471
  "gpustack",
1507
1472
  "groq",
1508
1473
  "kimi-plan",
@@ -1542,7 +1507,6 @@ const isLmStudioProvider = (provider) => provider.name === "lmstudio";
1542
1507
  const isDeepseekProvider = (provider) => provider.name === "deepseek";
1543
1508
  const isGroqProvider = (provider) => provider.name === "groq";
1544
1509
  const isCerebrasProvider = (provider) => provider.name === "cerebras";
1545
- const isGeminiCliProvider = (provider) => provider.name === "gemini-cli";
1546
1510
  const isBedrockProvider = (provider) => provider.name === "bedrock";
1547
1511
  const isOpenAiCompatibleProvider = (provider) => provider.name === "openai-compatible";
1548
1512
  const isLitellmProvider = (provider) => provider.name === "litellm";
@@ -1563,7 +1527,6 @@ const DEFAULT_PROVIDER_MODELS = {
1563
1527
  cerebras: "qwen-3-235b-a22b-instruct-2507",
1564
1528
  deepseek: "deepseek-v4-pro",
1565
1529
  gemini: "gemini-pro-latest",
1566
- "gemini-cli": "gemini-2.5-pro",
1567
1530
  groq: "moonshotai/kimi-k2-instruct-0905",
1568
1531
  "kimi-plan": "k2p6",
1569
1532
  openai: "gpt-5.4",
@@ -1959,7 +1922,8 @@ const getDefaultProviderParams = (providerName) => {
1959
1922
  case "zai-plan":
1960
1923
  provider = {
1961
1924
  name: "zai-plan",
1962
- apiKey: ""
1925
+ apiKey: "",
1926
+ reasoningEffort: ReasoningEffort.Max
1963
1927
  };
1964
1928
  break;
1965
1929
  case "minimax":
@@ -1977,13 +1941,8 @@ const getDefaultProviderParams = (providerName) => {
1977
1941
  case "neuralwatt":
1978
1942
  provider = {
1979
1943
  name: "neuralwatt",
1980
- apiKey: ""
1981
- };
1982
- break;
1983
- case "gemini-cli":
1984
- provider = {
1985
- name: "gemini-cli",
1986
- projectId: ""
1944
+ apiKey: "",
1945
+ reasoningEffort: ReasoningEffort.High
1987
1946
  };
1988
1947
  break;
1989
1948
  default:
@@ -3456,7 +3415,6 @@ const estimateMessageTokens = (messages) => {
3456
3415
  });
3457
3416
  return textOnlyMessages.reduce((sum, msg) => sum + gpt4o.encode(typeof msg.content === "string" ? msg.content : "").length, 0) + estimatedImageTokens;
3458
3417
  };
3459
- const execFileAsync = util.promisify(child_process.execFile);
3460
3418
  const fileLocks = /* @__PURE__ */ new Map();
3461
3419
  const withFileLock = (filePath, operation) => {
3462
3420
  logger.debug("Acquiring file lock:", { filePath });
@@ -3773,7 +3731,7 @@ Do not use escape characters \\ in the string like \\n or \\" and others. Do not
3773
3731
  return "Error: ripgrep binary is not available. Please try again or check the logs for details.";
3774
3732
  }
3775
3733
  try {
3776
- const rgArgs = ["--no-heading", "--line-number", "--color", "never", "--max-count", String(maxResults)];
3734
+ const rgArgs = ["--no-heading", "--line-number", "--color", "never"];
3777
3735
  if (!caseSensitive) {
3778
3736
  rgArgs.push("-i");
3779
3737
  }
@@ -3788,41 +3746,29 @@ Do not use escape characters \\ in the string like \\n or \\" and others. Do not
3788
3746
  args: rgArgs,
3789
3747
  cwd: taskDir
3790
3748
  });
3791
- const { stdout, stderr } = await execFileAsync(RIPGREP_BINARY_PATH, rgArgs, {
3792
- cwd: taskDir,
3793
- env: { ...process.env, TERM: "dumb", PATH: getShellPath() },
3794
- maxBuffer: 10 * 1024 * 1024,
3795
- windowsHide: true
3796
- });
3797
- logger.debug("ripgrep stdout raw:", { stdout: stdout.substring(0, 2e3) });
3798
- logger.debug("ripgrep stderr:", { stderr: stderr.substring(0, 2e3) });
3799
- const outputLines = stdout.split("\n").filter(Boolean);
3800
- logger.debug("outputLines count:", { count: outputLines.length, lines: outputLines.slice(0, 20) });
3801
- if (outputLines.length === 0) {
3802
- return `No matches found for pattern '${searchTerm}' in files matching '${filePattern}'.`;
3803
- }
3804
3749
  const results = [];
3805
3750
  const outputLineRegex = /^(.+?)([:-])(\d+)\2(.*)$/;
3806
3751
  let pendingBeforeContext = [];
3807
3752
  let afterContextBreak = false;
3808
- for (let rawLine of outputLines) {
3753
+ let stderrData = "";
3754
+ let lineBuffer = "";
3755
+ const processLine = (rawLine) => {
3809
3756
  if (rawLine.endsWith("\r")) {
3810
3757
  rawLine = rawLine.slice(0, -1);
3811
3758
  }
3812
3759
  if (rawLine === "--") {
3813
3760
  pendingBeforeContext = [];
3814
3761
  afterContextBreak = true;
3815
- continue;
3762
+ return false;
3816
3763
  }
3817
- const line = rawLine;
3818
- const match = outputLineRegex.exec(line);
3764
+ const match = outputLineRegex.exec(rawLine);
3819
3765
  if (!match) {
3820
- continue;
3766
+ return false;
3821
3767
  }
3822
3768
  const [, rawFilePath, separator, lineNumStr, content] = match;
3823
3769
  const lineNum = parseInt(lineNumStr, 10);
3824
3770
  if (isNaN(lineNum)) {
3825
- continue;
3771
+ return false;
3826
3772
  }
3827
3773
  const filePath = rawFilePath.startsWith("./") ? rawFilePath.slice(2) : rawFilePath;
3828
3774
  const isMatch = separator === ":";
@@ -3851,13 +3797,96 @@ Do not use escape characters \\ in the string like \\n or \\" and others. Do not
3851
3797
  }
3852
3798
  }
3853
3799
  }
3854
- if (results.length >= maxResults) {
3855
- break;
3800
+ return results.length >= maxResults;
3801
+ };
3802
+ let wasAborted = false;
3803
+ await new Promise((resolveStream) => {
3804
+ let streamResolved = false;
3805
+ let childProcess = null;
3806
+ let abortListener = null;
3807
+ const cleanup = () => {
3808
+ if (abortListener && abortSignal) {
3809
+ abortSignal.removeEventListener("abort", abortListener);
3810
+ }
3811
+ };
3812
+ const finish = () => {
3813
+ if (streamResolved) {
3814
+ return;
3815
+ }
3816
+ streamResolved = true;
3817
+ cleanup();
3818
+ resolveStream();
3819
+ };
3820
+ abortListener = () => {
3821
+ if (streamResolved) {
3822
+ return;
3823
+ }
3824
+ wasAborted = true;
3825
+ if (childProcess?.pid) {
3826
+ try {
3827
+ childProcess.kill("SIGKILL");
3828
+ } catch {
3829
+ }
3830
+ }
3831
+ };
3832
+ abortSignal?.addEventListener("abort", abortListener);
3833
+ try {
3834
+ childProcess = child_process.spawn(RIPGREP_BINARY_PATH, rgArgs, {
3835
+ cwd: taskDir,
3836
+ env: { ...process.env, TERM: "dumb", PATH: getShellPath() },
3837
+ windowsHide: true
3838
+ });
3839
+ } catch (spawnError) {
3840
+ stderrData = spawnError instanceof Error ? spawnError.message : String(spawnError);
3841
+ finish();
3842
+ return;
3856
3843
  }
3844
+ childProcess.stdout?.on("data", (data) => {
3845
+ if (streamResolved) {
3846
+ return;
3847
+ }
3848
+ lineBuffer += data.toString("utf-8");
3849
+ const lines = lineBuffer.split("\n");
3850
+ lineBuffer = lines.pop() || "";
3851
+ for (const rawLine of lines) {
3852
+ if (!rawLine) {
3853
+ continue;
3854
+ }
3855
+ const reachedLimit = processLine(rawLine);
3856
+ if (reachedLimit) {
3857
+ try {
3858
+ childProcess?.kill("SIGKILL");
3859
+ } catch {
3860
+ }
3861
+ finish();
3862
+ return;
3863
+ }
3864
+ }
3865
+ });
3866
+ childProcess.stderr?.on("data", (data) => {
3867
+ stderrData += data.toString("utf-8");
3868
+ });
3869
+ childProcess.on("error", (error) => {
3870
+ if (!streamResolved) {
3871
+ stderrData = error.message;
3872
+ finish();
3873
+ }
3874
+ });
3875
+ childProcess.on("close", () => {
3876
+ if (!streamResolved && lineBuffer) {
3877
+ processLine(lineBuffer);
3878
+ lineBuffer = "";
3879
+ }
3880
+ finish();
3881
+ });
3882
+ });
3883
+ if (wasAborted || abortSignal?.aborted) {
3884
+ return "Operation was cancelled by user.";
3857
3885
  }
3886
+ logger.debug("ripgrep results count:", { count: results.length, stderr: stderrData.substring(0, 500) });
3858
3887
  if (results.length === 0) {
3859
- if (stderr.trim()) {
3860
- return `Error during grep: ${stderr.trim()}`;
3888
+ if (stderrData.trim()) {
3889
+ return `Error during grep: ${stderrData.trim()}`;
3861
3890
  }
3862
3891
  return `No matches found for pattern '${searchTerm}' in files matching '${filePattern}'.`;
3863
3892
  }
@@ -6819,7 +6848,7 @@ ${fileList}${readOnlyNote}`
6819
6848
  }
6820
6849
  /**
6821
6850
  * Recursively strips unsupported JSON Schema 2019-09 keywords that are not
6822
- * recognized by some MCP servers (like gemini-cli).
6851
+ * recognized by some MCP servers.
6823
6852
  */
6824
6853
  stripUnsupportedSchemaKeywords(schema) {
6825
6854
  const unsupportedKeywords = [
@@ -6857,7 +6886,7 @@ ${fileList}${readOnlyNote}`
6857
6886
  return processObject(schema);
6858
6887
  }
6859
6888
  fixInputSchema(provider, inputSchema) {
6860
- if (provider === "gemini" || provider === "gemini-cli") {
6889
+ if (provider === "gemini") {
6861
6890
  const fixedSchema = JSON.parse(JSON.stringify(inputSchema));
6862
6891
  const strippedSchema = this.stripUnsupportedSchemaKeywords(fixedSchema);
6863
6892
  if (strippedSchema.properties) {
@@ -6898,45 +6927,14 @@ ${fileList}${readOnlyNote}`
6898
6927
  }
6899
6928
  return inputSchema;
6900
6929
  }
6901
- async runAgent(task, profile, prompt, mode = "agent", promptContext, initialContextMessages, initialContextFiles, systemPrompt, includeInContext = true, abortSignal, images) {
6930
+ async runAgent(task, profile, prompt, mode = "agent", promptContext, initialContextMessages, initialContextFiles, systemPrompt, includeInContext = true, abortSignal, images, skillsToActivate) {
6902
6931
  let contextMessages = initialContextMessages ?? await task.getContextMessages();
6903
6932
  let contextFiles = initialContextFiles ?? await task.getContextFiles();
6904
6933
  if (!systemPrompt) {
6905
6934
  systemPrompt = await this.promptsManager.getSystemPrompt(this.store.getSettings(), task, profile);
6906
6935
  }
6907
- const userRequestMessage = prompt ? {
6908
- id: promptContext?.id || uuid.v4(),
6909
- role: "user",
6910
- content: images && images.length > 0 ? [
6911
- { type: "text", text: prompt },
6912
- ...images.map((dataUrl) => {
6913
- const match = dataUrl.match(/^data:(image\/[^;]+);base64,(.+)$/);
6914
- return {
6915
- type: "image",
6916
- image: match ? match[2] : dataUrl,
6917
- mediaType: match ? match[1] : void 0
6918
- };
6919
- })
6920
- ] : prompt,
6921
- promptContext,
6922
- timestamp: Date.now()
6923
- } : null;
6924
- if (userRequestMessage) {
6925
- logger.info("User request message created:", {
6926
- id: userRequestMessage.id,
6927
- contentType: typeof userRequestMessage.content === "string" ? "string" : "parts",
6928
- ...typeof userRequestMessage.content === "string" ? { contentPreview: userRequestMessage.content.substring(0, 200) } : {
6929
- parts: userRequestMessage.content.map((part) => ({
6930
- type: part.type,
6931
- ...part.type === "text" ? { textPreview: part.text?.substring(0, 100) } : {},
6932
- ...part.type === "image" ? { mediaType: part.mediaType, imagePreview: typeof part.image === "string" ? part.image.substring(0, 80) : typeof part.image } : {}
6933
- }))
6934
- }
6935
- });
6936
- }
6937
6936
  const settings = this.store.getSettings();
6938
6937
  const projectProfiles = this.agentProfileManager.getProjectProfiles(task.project);
6939
- let resultMessages = userRequestMessage ? [userRequestMessage] : [];
6940
6938
  const providers = this.modelManager.getProviders();
6941
6939
  let provider = providers.find((p) => p.id === profile.provider);
6942
6940
  let modelName = profile.model;
@@ -6952,7 +6950,9 @@ ${fileList}${readOnlyNote}`
6952
6950
  promptContext,
6953
6951
  contextMessages,
6954
6952
  contextFiles,
6955
- systemPrompt
6953
+ systemPrompt,
6954
+ images,
6955
+ skillsToActivate
6956
6956
  },
6957
6957
  task.project,
6958
6958
  task
@@ -6969,10 +6969,56 @@ ${fileList}${readOnlyNote}`
6969
6969
  contextMessages = extensionResult.contextMessages;
6970
6970
  contextFiles = extensionResult.contextFiles;
6971
6971
  systemPrompt = extensionResult.systemPrompt;
6972
+ images = extensionResult.images ?? images;
6973
+ skillsToActivate = extensionResult.skillsToActivate;
6974
+ }
6975
+ const userRequestMessage = prompt ? {
6976
+ id: promptContext?.id || uuid.v4(),
6977
+ role: "user",
6978
+ content: images && images.length > 0 ? [
6979
+ { type: "text", text: prompt },
6980
+ ...images.map((dataUrl) => {
6981
+ const match = dataUrl.match(/^data:(image\/[^;]+);base64,(.+)$/);
6982
+ return {
6983
+ type: "image",
6984
+ image: match ? match[2] : dataUrl,
6985
+ mediaType: match ? match[1] : void 0
6986
+ };
6987
+ })
6988
+ ] : prompt,
6989
+ promptContext,
6990
+ timestamp: Date.now()
6991
+ } : null;
6992
+ if (userRequestMessage) {
6993
+ logger.info("User request message created:", {
6994
+ id: userRequestMessage.id,
6995
+ contentType: typeof userRequestMessage.content === "string" ? "string" : "parts",
6996
+ ...typeof userRequestMessage.content === "string" ? { contentPreview: userRequestMessage.content.substring(0, 200) } : {
6997
+ parts: userRequestMessage.content.map((part) => ({
6998
+ type: part.type,
6999
+ ...part.type === "text" ? { textPreview: part.text?.substring(0, 100) } : {},
7000
+ ...part.type === "image" ? { mediaType: part.mediaType, imagePreview: typeof part.image === "string" ? part.image.substring(0, 80) : typeof part.image } : {}
7001
+ }))
7002
+ }
7003
+ });
6972
7004
  }
7005
+ let resultMessages = userRequestMessage ? [userRequestMessage] : [];
6973
7006
  if (userRequestMessage && includeInContext) {
6974
7007
  await task.addContextMessage(userRequestMessage);
6975
7008
  }
7009
+ if (skillsToActivate && skillsToActivate.length > 0) {
7010
+ try {
7011
+ const skillMessages = await task.createSkillMessages(...skillsToActivate);
7012
+ if (skillMessages) {
7013
+ for (const message of skillMessages) {
7014
+ await task.addContextMessage(message);
7015
+ resultMessages.push(message);
7016
+ }
7017
+ }
7018
+ } catch (error) {
7019
+ logger.warn(`Failed to activate skills: ${error instanceof Error ? error.message : String(error)}`);
7020
+ }
7021
+ }
6976
7022
  if (!provider) {
6977
7023
  logger.error(`Provider ${profile.provider} not found`);
6978
7024
  task.addLogMessage("error", "Selected model is not configured. Select another model and try again.", true, promptContext);
@@ -8937,16 +8983,47 @@ class ContextApi extends BaseApi {
8937
8983
  }
8938
8984
  const RunPromptSchema = zod.z.object({
8939
8985
  projectDir: zod.z.string().min(1, "Project directory is required"),
8940
- taskId: zod.z.string().min(1, "Task ID is required"),
8986
+ taskId: zod.z.string().optional(),
8941
8987
  prompt: zod.z.string().min(1, "Prompt is required"),
8942
8988
  mode: zod.z.string().optional(),
8943
- images: zod.z.array(zod.z.string()).optional()
8989
+ images: zod.z.array(zod.z.string()).optional(),
8990
+ model: zod.z.string().optional(),
8991
+ agentProfileId: zod.z.string().optional()
8944
8992
  });
8993
+ const parseModelParam = (model, agentProfileId) => {
8994
+ if (!model && !agentProfileId) {
8995
+ return void 0;
8996
+ }
8997
+ const params = {};
8998
+ if (agentProfileId) {
8999
+ params.agentProfileId = agentProfileId;
9000
+ }
9001
+ if (model) {
9002
+ const slashIndex = model.indexOf("/");
9003
+ if (slashIndex > 0) {
9004
+ params.provider = model.substring(0, slashIndex);
9005
+ params.model = model.substring(slashIndex + 1);
9006
+ } else {
9007
+ params.model = model;
9008
+ }
9009
+ }
9010
+ return params;
9011
+ };
8945
9012
  const SavePromptSchema = zod.z.object({
8946
9013
  projectDir: zod.z.string().min(1, "Project directory is required"),
8947
9014
  taskId: zod.z.string().min(1, "Task ID is required"),
8948
9015
  prompt: zod.z.string().min(1, "Prompt is required")
8949
9016
  });
9017
+ const SSE_ALLOWED_EVENT_TYPES = /* @__PURE__ */ new Set([
9018
+ "response-chunk",
9019
+ "response-completed",
9020
+ "tool",
9021
+ "user-message",
9022
+ "log",
9023
+ "ask-question",
9024
+ "task-updated",
9025
+ "task-created"
9026
+ ]);
8950
9027
  class PromptApi extends BaseApi {
8951
9028
  constructor(eventsHandler) {
8952
9029
  super();
@@ -8954,18 +9031,26 @@ class PromptApi extends BaseApi {
8954
9031
  }
8955
9032
  eventsHandler;
8956
9033
  registerRoutes(router) {
8957
- router.post(
8958
- "/run-prompt",
8959
- this.handleRequest(async (req, res) => {
8960
- const parsed = this.validateRequest(RunPromptSchema, req.body, res);
8961
- if (!parsed) {
8962
- return;
8963
- }
8964
- const { projectDir, taskId, prompt, mode, images } = parsed;
8965
- const responses = await this.eventsHandler.runPrompt(projectDir, taskId, prompt, mode, images);
8966
- res.status(200).json(responses);
8967
- })
8968
- );
9034
+ router.post("/run-prompt", (req, res) => {
9035
+ const acceptsSSE = req.accepts("text/event-stream");
9036
+ const acceptsJSON = req.accepts("application/json");
9037
+ if (!acceptsSSE && !acceptsJSON) {
9038
+ res.status(406).json({ error: "Accept header must be application/json or text/event-stream" });
9039
+ return;
9040
+ }
9041
+ const parsed = RunPromptSchema.safeParse(req.body);
9042
+ if (!parsed.success) {
9043
+ res.status(400).json({ error: parsed.error.flatten() });
9044
+ return;
9045
+ }
9046
+ const { projectDir, taskId, prompt, mode, images, model, agentProfileId } = parsed.data;
9047
+ const isSSE = acceptsSSE && !acceptsJSON;
9048
+ if (isSSE) {
9049
+ void this.handleRunPromptSSE(res, projectDir, prompt, taskId, mode, images, model, agentProfileId);
9050
+ } else {
9051
+ void this.handleRunPromptJSON(res, projectDir, prompt, taskId, mode, images, model, agentProfileId);
9052
+ }
9053
+ });
8969
9054
  router.post(
8970
9055
  "/save-prompt",
8971
9056
  this.handleRequest(async (req, res) => {
@@ -8979,6 +9064,107 @@ class PromptApi extends BaseApi {
8979
9064
  })
8980
9065
  );
8981
9066
  }
9067
+ async handleRunPromptJSON(res, projectDir, prompt, taskId, mode, images, model, agentProfileId) {
9068
+ if (taskId) {
9069
+ const responses = await this.eventsHandler.runPrompt(projectDir, taskId, prompt, mode, images);
9070
+ res.status(200).json(responses);
9071
+ } else {
9072
+ const taskParams = parseModelParam(model, agentProfileId);
9073
+ const result = await this.eventsHandler.ensureProjectAndCreateTask(projectDir, taskParams);
9074
+ const responses = await this.eventsHandler.runPrompt(result.projectDir, result.taskId, prompt, mode, images);
9075
+ res.setHeader("X-Task-Id", result.taskId);
9076
+ res.status(200).json(responses);
9077
+ }
9078
+ }
9079
+ async handleRunPromptSSE(res, projectDir, prompt, taskId, mode, images, model, agentProfileId) {
9080
+ let resolvedTaskId = taskId;
9081
+ if (!resolvedTaskId) {
9082
+ const taskParams = parseModelParam(model, agentProfileId);
9083
+ const result = await this.eventsHandler.ensureProjectAndCreateTask(projectDir, taskParams);
9084
+ resolvedTaskId = result.taskId;
9085
+ }
9086
+ const baseDir = projectDir.endsWith("/") ? projectDir.slice(0, -1) : projectDir;
9087
+ res.writeHead(200, {
9088
+ "Content-Type": "text/event-stream",
9089
+ "Cache-Control": "no-cache",
9090
+ Connection: "keep-alive",
9091
+ "X-Accel-Buffering": "no",
9092
+ "X-Task-Id": resolvedTaskId
9093
+ });
9094
+ res.write(": connected\n\n");
9095
+ const eventManager = this.eventsHandler.getEventManager();
9096
+ const listenerId = `sse-${uuid.v4()}`;
9097
+ let closed = false;
9098
+ const listener = (event) => {
9099
+ if (closed) {
9100
+ return;
9101
+ }
9102
+ const data = event.data;
9103
+ if (!SSE_ALLOWED_EVENT_TYPES.has(event.type)) {
9104
+ return;
9105
+ }
9106
+ if (data.baseDir !== void 0 && data.baseDir !== baseDir) {
9107
+ return;
9108
+ }
9109
+ const eventTaskId = data.taskId || data.id;
9110
+ if (eventTaskId !== void 0 && eventTaskId !== resolvedTaskId) {
9111
+ return;
9112
+ }
9113
+ try {
9114
+ const sseData = `event: ${event.type}
9115
+ data: ${JSON.stringify(event.data)}
9116
+
9117
+ `;
9118
+ res.write(sseData);
9119
+ } catch (err) {
9120
+ logger.error("SSE run-prompt: error writing event", { err });
9121
+ cleanup();
9122
+ }
9123
+ };
9124
+ const cleanup = () => {
9125
+ if (closed) {
9126
+ return;
9127
+ }
9128
+ closed = true;
9129
+ eventManager.unsubscribeSSE(listenerId, listener);
9130
+ try {
9131
+ res.end();
9132
+ } catch {
9133
+ }
9134
+ };
9135
+ eventManager.subscribeSSE(listenerId, listener, false);
9136
+ res.on("close", () => {
9137
+ if (!closed) {
9138
+ cleanup();
9139
+ }
9140
+ });
9141
+ try {
9142
+ await this.eventsHandler.waitForTaskIdle(baseDir, resolvedTaskId);
9143
+ await this.eventsHandler.runPrompt(baseDir, resolvedTaskId, prompt, mode, images);
9144
+ if (!closed) {
9145
+ try {
9146
+ res.write(`event: stream-end
9147
+ data: ${JSON.stringify({ type: "stream-end" })}
9148
+
9149
+ `);
9150
+ } catch {
9151
+ }
9152
+ }
9153
+ } catch (error) {
9154
+ logger.error("SSE run-prompt: error running prompt", { error });
9155
+ if (!closed) {
9156
+ try {
9157
+ res.write(`event: error
9158
+ data: ${JSON.stringify({ error: String(error) })}
9159
+
9160
+ `);
9161
+ } catch {
9162
+ }
9163
+ }
9164
+ } finally {
9165
+ cleanup();
9166
+ }
9167
+ }
8982
9168
  }
8983
9169
  const SettingsDataSchema = zod.z.any();
8984
9170
  const GetRecentProjectsSchema = zod.z.object({});
@@ -10384,6 +10570,12 @@ class SystemApi extends BaseApi {
10384
10570
  eventsHandler;
10385
10571
  pythonInstaller;
10386
10572
  registerRoutes(router) {
10573
+ router.get(
10574
+ "/health",
10575
+ this.handleRequest(async (_req, res) => {
10576
+ res.status(200).json({ status: "ok" });
10577
+ })
10578
+ );
10387
10579
  router.get(
10388
10580
  "/system/env-var",
10389
10581
  this.handleRequest(async (req, res) => {
@@ -11124,7 +11316,11 @@ class ServerController {
11124
11316
  pythonInstaller;
11125
11317
  app = express();
11126
11318
  isStarted = false;
11127
- serverGuardMiddleware(_, res, next) {
11319
+ serverGuardMiddleware(req, res, next) {
11320
+ if (req.path === "/api/health") {
11321
+ next();
11322
+ return;
11323
+ }
11128
11324
  if (process.env.AIDER_DESK_HEADLESS === "true" || this.isStarted) {
11129
11325
  next();
11130
11326
  } else {
@@ -11134,6 +11330,10 @@ class ServerController {
11134
11330
  }
11135
11331
  }
11136
11332
  timeoutMiddleware(req, res, next) {
11333
+ if (req.accepts("text/event-stream")) {
11334
+ next();
11335
+ return;
11336
+ }
11137
11337
  req.setTimeout(REQUEST_TIMEOUT_MS, () => {
11138
11338
  res.status(504).json({ error: "Request timeout" });
11139
11339
  });
@@ -13204,7 +13404,8 @@ const PROXY_ENV_VAR_NAMES = ["HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY", "http_pro
13204
13404
  const getProxyEnvVars = (settings) => {
13205
13405
  if (settings.proxy?.enabled && settings.proxy?.url) {
13206
13406
  const url = settings.proxy.url;
13207
- return {
13407
+ const noProxy = settings.proxy.noProxy;
13408
+ const vars = {
13208
13409
  HTTP_PROXY: url,
13209
13410
  HTTPS_PROXY: url,
13210
13411
  ALL_PROXY: url,
@@ -13212,6 +13413,11 @@ const getProxyEnvVars = (settings) => {
13212
13413
  https_proxy: url,
13213
13414
  all_proxy: url
13214
13415
  };
13416
+ if (noProxy) {
13417
+ vars.NO_PROXY = noProxy;
13418
+ vars.no_proxy = noProxy;
13419
+ }
13420
+ return vars;
13215
13421
  }
13216
13422
  return Object.fromEntries(PROXY_ENV_VAR_NAMES.map((key) => [key, ""]));
13217
13423
  };
@@ -13223,7 +13429,7 @@ class ProxyManager {
13223
13429
  init(settings) {
13224
13430
  globalAgent.bootstrap();
13225
13431
  if (settings.proxy?.enabled && settings.proxy?.url) {
13226
- this.applyProxy(settings.proxy.url);
13432
+ this.applyProxy(settings.proxy.url, settings.proxy.noProxy);
13227
13433
  } else {
13228
13434
  this.clearProxy();
13229
13435
  }
@@ -13235,20 +13441,25 @@ class ProxyManager {
13235
13441
  settingsChanged(oldSettings, newSettings) {
13236
13442
  const oldProxy = oldSettings.proxy;
13237
13443
  const newProxy = newSettings.proxy;
13238
- if (oldProxy?.enabled !== newProxy?.enabled || oldProxy?.url !== newProxy?.url) {
13444
+ if (oldProxy?.enabled !== newProxy?.enabled || oldProxy?.url !== newProxy?.url || oldProxy?.noProxy !== newProxy?.noProxy) {
13239
13445
  if (newProxy?.enabled && newProxy?.url) {
13240
13446
  logger.info(`[ProxyManager] Applying proxy: ${newProxy.url}`);
13241
- this.applyProxy(newProxy.url);
13447
+ this.applyProxy(newProxy.url, newProxy.noProxy);
13242
13448
  } else if (this.currentUrl !== null) {
13243
13449
  logger.info("[ProxyManager] Clearing proxy");
13244
13450
  this.clearProxy();
13245
13451
  }
13246
13452
  }
13247
13453
  }
13248
- applyProxy(url) {
13454
+ applyProxy(url, noProxy) {
13249
13455
  try {
13250
13456
  global.GLOBAL_AGENT.HTTP_PROXY = url;
13251
- const proxyAgent = new undici.ProxyAgent(url);
13457
+ global.GLOBAL_AGENT.NO_PROXY = noProxy || void 0;
13458
+ const proxyAgent = new undici.EnvHttpProxyAgent({
13459
+ httpProxy: url,
13460
+ httpsProxy: url,
13461
+ noProxy: noProxy || void 0
13462
+ });
13252
13463
  undici.setGlobalDispatcher(proxyAgent);
13253
13464
  this.currentUrl = url;
13254
13465
  logger.info(`[ProxyManager] Proxy initialized: ${url}`);
@@ -13259,6 +13470,7 @@ class ProxyManager {
13259
13470
  clearProxy() {
13260
13471
  try {
13261
13472
  global.GLOBAL_AGENT.HTTP_PROXY = void 0;
13473
+ global.GLOBAL_AGENT.NO_PROXY = void 0;
13262
13474
  undici.setGlobalDispatcher(
13263
13475
  new undici.Agent({
13264
13476
  headersTimeout: 30 * 60 * 1e3,
@@ -14227,6 +14439,60 @@ class WorktreeManager {
14227
14439
  return void 0;
14228
14440
  }
14229
14441
  }
14442
+ /**
14443
+ * Check if a commit is an ancestor of another commit (or HEAD).
14444
+ * Returns true if `ancestorCommit` is reachable from `descendantRef`.
14445
+ */
14446
+ async isCommitAncestorOf(worktreePath, ancestorCommit, descendantRef = "HEAD") {
14447
+ try {
14448
+ await execWithShellPath(`git merge-base --is-ancestor ${ancestorCommit} ${descendantRef}`, { cwd: worktreePath });
14449
+ return true;
14450
+ } catch {
14451
+ return false;
14452
+ }
14453
+ }
14454
+ /**
14455
+ * Get the "onto" commit from an active rebase.
14456
+ * Returns undefined if no rebase is in progress or the file doesn't exist.
14457
+ */
14458
+ async getRebaseOntoCommit(worktreePath) {
14459
+ try {
14460
+ const { stdout: rebaseMergePath } = await execWithShellPath("git rev-parse --git-path rebase-merge", { cwd: worktreePath });
14461
+ const ontoPath = `${rebaseMergePath.trim()}/onto`;
14462
+ try {
14463
+ const { stdout: ontoCommit } = await execWithShellPath(`cat "${ontoPath}"`, { cwd: worktreePath });
14464
+ if (ontoCommit.trim()) {
14465
+ return ontoCommit.trim();
14466
+ }
14467
+ } catch {
14468
+ }
14469
+ const { stdout: rebaseApplyPath } = await execWithShellPath("git rev-parse --git-path rebase-apply", { cwd: worktreePath });
14470
+ const ontoApplyPath = `${rebaseApplyPath.trim()}/onto`;
14471
+ try {
14472
+ const { stdout: ontoCommit } = await execWithShellPath(`cat "${ontoApplyPath}"`, { cwd: worktreePath });
14473
+ if (ontoCommit.trim()) {
14474
+ return ontoCommit.trim();
14475
+ }
14476
+ } catch {
14477
+ }
14478
+ return void 0;
14479
+ } catch {
14480
+ return void 0;
14481
+ }
14482
+ }
14483
+ /**
14484
+ * Resolve a commit to the branch name that points to it.
14485
+ * Returns the first branch found, or undefined if no branch points to that exact commit.
14486
+ */
14487
+ async getBranchPointingAtCommit(projectPath, commit) {
14488
+ try {
14489
+ const { stdout } = await execWithShellPath(`git branch --points-at ${commit} --format='%(refname:short)'`, { cwd: projectPath });
14490
+ const branches = stdout.trim().split("\n").map((b) => b.trim()).filter((b) => b && !b.includes("(") && !b.includes("HEAD"));
14491
+ return branches.length > 0 ? branches[0] : void 0;
14492
+ } catch {
14493
+ return void 0;
14494
+ }
14495
+ }
14230
14496
  async getBranchesContainingCommit(projectPath, commit) {
14231
14497
  try {
14232
14498
  const { stdout } = await execWithShellPath(`git branch --contains ${commit} --format='%(refname:short)'`, { cwd: projectPath });
@@ -14335,7 +14601,15 @@ class WorktreeManager {
14335
14601
  });
14336
14602
  logger.info("Created temporary commit for uncommitted changes");
14337
14603
  }
14338
- const command = baseCommit ? `git rebase --onto ${mainBranch} ${baseCommit}` : `git rebase ${mainBranch}`;
14604
+ let effectiveBaseCommit = baseCommit;
14605
+ if (baseCommit) {
14606
+ const isValid = await this.isCommitAncestorOf(worktreePath, baseCommit);
14607
+ if (!isValid) {
14608
+ logger.warn(`baseCommit ${baseCommit} is not an ancestor of HEAD, falling back to simple rebase`, { worktreePath, mainBranch });
14609
+ effectiveBaseCommit = void 0;
14610
+ }
14611
+ }
14612
+ const command = effectiveBaseCommit ? `git rebase --onto ${mainBranch} ${effectiveBaseCommit}` : `git rebase ${mainBranch}`;
14339
14613
  executedCommands.push(`${command} (in ${worktreePath})`);
14340
14614
  const rebaseResult = await execWithShellPath(command, {
14341
14615
  cwd: worktreePath
@@ -14388,6 +14662,11 @@ class WorktreeManager {
14388
14662
  return await withLock(`git-rebase-continue-${worktreePath}`, async () => {
14389
14663
  const executedCommands = [];
14390
14664
  let lastOutput = "";
14665
+ const ontoCommit = await this.getRebaseOntoCommit(worktreePath);
14666
+ let ontoBranch;
14667
+ if (ontoCommit) {
14668
+ ontoBranch = await this.getBranchPointingAtCommit(worktreePath, ontoCommit);
14669
+ }
14391
14670
  try {
14392
14671
  const command = "git rebase --continue";
14393
14672
  executedCommands.push(`${command} (in ${worktreePath})`);
@@ -14398,6 +14677,7 @@ class WorktreeManager {
14398
14677
  lastOutput = result.stdout || result.stderr || "";
14399
14678
  await this.resetTempCommitIfExists(worktreePath);
14400
14679
  logger.info("Successfully handled temporary commit after continue rebase");
14680
+ return { ontoCommit, ontoBranch };
14401
14681
  } catch (error) {
14402
14682
  const err = error;
14403
14683
  logger.error(`Failed to continue rebase in ${worktreePath}:`, err);
@@ -14426,7 +14706,15 @@ class WorktreeManager {
14426
14706
  if (!commits.trim()) {
14427
14707
  return;
14428
14708
  }
14429
- command = baseCommit ? `git rebase --onto ${mainBranch} ${baseCommit}` : `git rebase ${mainBranch}`;
14709
+ let effectiveBaseCommit = baseCommit;
14710
+ if (baseCommit) {
14711
+ const isValid = await this.isCommitAncestorOf(worktreePath, baseCommit);
14712
+ if (!isValid) {
14713
+ logger.warn(`baseCommit ${baseCommit} is not an ancestor of HEAD, falling back to simple rebase`, { worktreePath, mainBranch });
14714
+ effectiveBaseCommit = void 0;
14715
+ }
14716
+ }
14717
+ command = effectiveBaseCommit ? `git rebase --onto ${mainBranch} ${effectiveBaseCommit}` : `git rebase ${mainBranch}`;
14430
14718
  executedCommands.push(`${command} (in ${worktreePath})`);
14431
14719
  try {
14432
14720
  const rebaseWorktreeResult = await execWithShellPath(command, {
@@ -15425,7 +15713,7 @@ Git output: ${err.stderr || err.stdout || err.message}`
15425
15713
  */
15426
15714
  async resetTempCommit(worktreePath) {
15427
15715
  try {
15428
- await execWithShellPath("git reset --mixed HEAD^", { cwd: worktreePath });
15716
+ await execWithShellPath("git reset --soft HEAD^", { cwd: worktreePath });
15429
15717
  } catch (error) {
15430
15718
  logger.error("Failed to reset temp commit:", error);
15431
15719
  throw new Error(`Failed to restore uncommitted changes: ${error instanceof Error ? error.message : String(error)}`);
@@ -16837,6 +17125,18 @@ class Task {
16837
17125
  isPromptRunning() {
16838
17126
  return !!this.currentPromptContext || this.agent.isRunning() || this.isCompacting;
16839
17127
  }
17128
+ hasQueuedPrompts() {
17129
+ return this.queuedPrompts.length > 0;
17130
+ }
17131
+ async waitForIdle() {
17132
+ while (this.isPromptRunning() || this.hasQueuedPrompts()) {
17133
+ if (this.agent.isRunning()) {
17134
+ await this.waitForCurrentAgentToFinish();
17135
+ } else {
17136
+ await new Promise((resolve) => setTimeout(resolve, 100));
17137
+ }
17138
+ }
17139
+ }
16840
17140
  async runPrompt(prompt, mode = this.task.currentMode || "agent", addToInputHistory = true, userMessageId = uuid.v4(), sendNotification = true, images) {
16841
17141
  if (this.currentQuestion) {
16842
17142
  if (await this.answerQuestion("n", prompt)) {
@@ -17003,7 +17303,7 @@ class Task {
17003
17303
  }
17004
17304
  return responses;
17005
17305
  }
17006
- async runPromptInAgent(profile, mode, prompt, promptContext = { id: uuid.v4() }, contextMessages, contextFiles, systemPrompt, waitForCurrentAgentToFinish = true, sendNotification = true, images) {
17306
+ async runPromptInAgent(profile, mode, prompt, promptContext = { id: uuid.v4() }, contextMessages, contextFiles, systemPrompt, waitForCurrentAgentToFinish = true, sendNotification = true, images, skillsToActivate) {
17007
17307
  if (waitForCurrentAgentToFinish) {
17008
17308
  await this.waitForCurrentAgentToFinish();
17009
17309
  }
@@ -17026,7 +17326,8 @@ class Task {
17026
17326
  systemPrompt,
17027
17327
  true,
17028
17328
  void 0,
17029
- images
17329
+ images,
17330
+ skillsToActivate
17030
17331
  );
17031
17332
  if (agentMessages.length > 0) {
17032
17333
  this.contextManager.toConnectorMessages(agentMessages).forEach((message) => {
@@ -17986,42 +18287,59 @@ ${contentText}</agent-response>`;
17986
18287
  const contextMessages = await this.contextManager.getContextMessages();
17987
18288
  return this.skillManager.getSkills(contextMessages);
17988
18289
  }
17989
- async activateSkill(skillName) {
18290
+ async createSkillMessages(...skillNames) {
18291
+ if (skillNames.length === 0) {
18292
+ return null;
18293
+ }
17990
18294
  const contextMessages = await this.contextManager.getContextMessages();
17991
18295
  const activatedNames = this.skillManager.getActivatedSkillNames(contextMessages);
17992
- if (activatedNames.has(skillName)) {
17993
- logger.debug("Skill already activated, skipping", { skillName });
17994
- return;
18296
+ const allMessages = [];
18297
+ for (const skillName of skillNames) {
18298
+ if (activatedNames.has(skillName)) {
18299
+ logger.debug("Skill already activated, skipping", { skillName });
18300
+ continue;
18301
+ }
18302
+ const content = await this.skillManager.getSkillContent(skillName);
18303
+ if (!content) {
18304
+ throw new Error(`Skill '${skillName}' not found`);
18305
+ }
18306
+ const [assistantMessage, toolMessage] = this.skillManager.buildActivateSkillMessages(skillName, content);
18307
+ await this.processResponseMessage(
18308
+ {
18309
+ id: assistantMessage.id,
18310
+ action: "response",
18311
+ content: "User requested the skill activation.",
18312
+ finished: true
18313
+ },
18314
+ false
18315
+ );
18316
+ const toolCallId = toolMessage.content[0].toolCallId;
18317
+ this.addToolMessage(
18318
+ toolCallId,
18319
+ SKILLS_TOOL_GROUP_NAME,
18320
+ SKILLS_TOOL_ACTIVATE_SKILL,
18321
+ { skill: skillName },
18322
+ JSON.stringify(content),
18323
+ void 0,
18324
+ void 0,
18325
+ false,
18326
+ true
18327
+ );
18328
+ allMessages.push(assistantMessage, toolMessage);
18329
+ activatedNames.add(skillName);
17995
18330
  }
17996
- const content = await this.skillManager.getSkillContent(skillName);
17997
- if (!content) {
17998
- throw new Error(`Skill '${skillName}' not found`);
18331
+ return allMessages.length > 0 ? allMessages : null;
18332
+ }
18333
+ async activateSkill(skillName) {
18334
+ const messages = await this.createSkillMessages(skillName);
18335
+ if (!messages) {
18336
+ return null;
18337
+ }
18338
+ for (const message of messages) {
18339
+ this.contextManager.addContextMessage(message);
17999
18340
  }
18000
- const [assistantMessage, toolMessage] = this.skillManager.buildActivateSkillMessages(skillName, content);
18001
- this.contextManager.addContextMessage(assistantMessage);
18002
- this.contextManager.addContextMessage(toolMessage);
18003
- await this.processResponseMessage(
18004
- {
18005
- id: assistantMessage.id,
18006
- action: "response",
18007
- content: "User requested the skill activation.",
18008
- finished: true
18009
- },
18010
- false
18011
- );
18012
- const toolCallId = toolMessage.content[0].toolCallId;
18013
- this.addToolMessage(
18014
- toolCallId,
18015
- SKILLS_TOOL_GROUP_NAME,
18016
- SKILLS_TOOL_ACTIVATE_SKILL,
18017
- { skill: skillName },
18018
- JSON.stringify(content),
18019
- void 0,
18020
- void 0,
18021
- false,
18022
- true
18023
- );
18024
18341
  await this.updateContextInfo();
18342
+ return [messages[0], messages[1]];
18025
18343
  }
18026
18344
  async deactivateSkill(skillName) {
18027
18345
  const contextMessages = await this.contextManager.getContextMessages();
@@ -19020,15 +19338,6 @@ ${error.stderr}`,
19020
19338
  this.addLogMessage("error", "No active Agent profile found");
19021
19339
  return;
19022
19340
  }
19023
- if (command.skills?.length) {
19024
- for (const skillName of command.skills) {
19025
- try {
19026
- await this.activateSkill(skillName);
19027
- } catch (error) {
19028
- logger.warn(`Failed to activate skill '${skillName}' for command '${commandName}': ${error instanceof Error ? error.message : String(error)}`);
19029
- }
19030
- }
19031
- }
19032
19341
  const systemPrompt = await this.promptsManager.getSystemPrompt(
19033
19342
  this.store.getSettings(),
19034
19343
  this,
@@ -19038,7 +19347,7 @@ ${error.stderr}`,
19038
19347
  const messages = command.includeContext === false ? [] : void 0;
19039
19348
  const contextFiles = command.includeContext === false ? [] : void 0;
19040
19349
  this.addLogMessage("loading", "Executing custom command...");
19041
- await this.runPromptInAgent(profile, mode, prompt, promptContext, messages, contextFiles, systemPrompt);
19350
+ await this.runPromptInAgent(profile, mode, prompt, promptContext, messages, contextFiles, systemPrompt, true, true, void 0, command.skills);
19042
19351
  } else {
19043
19352
  this.addLogMessage("loading", "Executing custom command...");
19044
19353
  await this.runPromptInAider(mode, prompt, promptContext);
@@ -19730,8 +20039,21 @@ ${diff}
19730
20039
  await this.waitForCurrentPromptToFinish();
19731
20040
  try {
19732
20041
  this.addLogMessage("loading", "Continuing rebase...");
19733
- await this.worktreeManager.continueRebase(this.task.worktree.path);
19734
- await this.saveTask({ lastMergeState: void 0 });
20042
+ const { ontoBranch } = await this.worktreeManager.continueRebase(this.task.worktree.path);
20043
+ const newHead = await this.worktreeManager.getHeadCommit(this.task.worktree.path);
20044
+ if (newHead) {
20045
+ await this.saveTask({
20046
+ lastMergeState: void 0,
20047
+ worktree: {
20048
+ ...this.task.worktree,
20049
+ baseCommit: newHead,
20050
+ // Update baseBranch if we could determine it from the rebase state, otherwise keep existing
20051
+ baseBranch: ontoBranch || this.task.worktree.baseBranch
20052
+ }
20053
+ });
20054
+ } else {
20055
+ await this.saveTask({ lastMergeState: void 0 });
20056
+ }
19735
20057
  this.addLogMessage("info", "Rebase completed", true);
19736
20058
  } catch (error) {
19737
20059
  logger.error("Failed to continue rebase:", error);
@@ -20529,12 +20851,15 @@ class ProjectManager {
20529
20851
  });
20530
20852
  }
20531
20853
  }
20854
+ const EVENT_BUFFER_SIZE = 200;
20532
20855
  class EventManager {
20533
20856
  constructor(windowManager) {
20534
20857
  this.windowManager = windowManager;
20535
20858
  }
20536
20859
  windowManager;
20537
20860
  eventsConnectors = [];
20861
+ sseListeners = /* @__PURE__ */ new Map();
20862
+ eventBuffer = [];
20538
20863
  // Project lifecycle events
20539
20864
  sendProjectStarted(baseDir) {
20540
20865
  const data = { baseDir };
@@ -20879,6 +21204,19 @@ class EventManager {
20879
21204
  this.unsubscribe(connector.socket, log);
20880
21205
  }
20881
21206
  });
21207
+ const event = { type: eventType, data };
21208
+ for (const listeners of this.sseListeners.values()) {
21209
+ for (const listener of listeners) {
21210
+ try {
21211
+ listener(event);
21212
+ } catch {
21213
+ }
21214
+ }
21215
+ }
21216
+ this.eventBuffer.push(event);
21217
+ if (this.eventBuffer.length > EVENT_BUFFER_SIZE) {
21218
+ this.eventBuffer.shift();
21219
+ }
20882
21220
  }
20883
21221
  // Extension UI events
20884
21222
  sendExtensionUIRefresh(options) {
@@ -20898,6 +21236,27 @@ class EventManager {
20898
21236
  this.sendToWindows("aider-connector-status", data);
20899
21237
  this.broadcastToEventConnectors("aider-connector-status", data);
20900
21238
  }
21239
+ // SSE event subscription for CLI streaming
21240
+ subscribeSSE(listenerId, listener, replayBuffer = false) {
21241
+ if (!this.sseListeners.has(listenerId)) {
21242
+ this.sseListeners.set(listenerId, /* @__PURE__ */ new Set());
21243
+ }
21244
+ this.sseListeners.get(listenerId).add(listener);
21245
+ if (replayBuffer) {
21246
+ for (const event of this.eventBuffer) {
21247
+ try {
21248
+ listener(event);
21249
+ } catch {
21250
+ }
21251
+ }
21252
+ }
21253
+ }
21254
+ unsubscribeSSE(listenerId, listener) {
21255
+ this.sseListeners.get(listenerId)?.delete(listener);
21256
+ if (this.sseListeners.get(listenerId)?.size === 0) {
21257
+ this.sseListeners.delete(listenerId);
21258
+ }
21259
+ }
20901
21260
  }
20902
21261
  const getDefaultModelInfo = (provider, modelId, allModelInfos) => {
20903
21262
  let fullModelId = `${provider.name}/${modelId}`;
@@ -21962,81 +22321,6 @@ const geminiProviderStrategy = {
21962
22321
  // Error handling
21963
22322
  isRetryable: isGeminiRetryable
21964
22323
  };
21965
- const GEMINI_CLI_MODELS = [
21966
- {
21967
- id: "gemini-3.1-pro-preview",
21968
- maxInputTokens: 1048576,
21969
- maxOutputTokens: 65536
21970
- },
21971
- {
21972
- id: "gemini-3-flash-preview",
21973
- maxInputTokens: 1048576,
21974
- maxOutputTokens: 65536
21975
- },
21976
- { id: "gemini-2.5-pro", maxInputTokens: 1048576, maxOutputTokens: 65536 },
21977
- { id: "gemini-2.5-flash", maxInputTokens: 1048576, maxOutputTokens: 65536 },
21978
- { id: "gemini-2.5-flash-lite", maxInputTokens: 1048576, maxOutputTokens: 65536 }
21979
- ];
21980
- const loadGeminiCliModels = async (profile, _settings) => {
21981
- if (!isGeminiCliProvider(profile.provider)) {
21982
- return { models: [], success: false };
21983
- }
21984
- const models = GEMINI_CLI_MODELS.map((m) => ({
21985
- id: m.id,
21986
- providerId: profile.id,
21987
- maxInputTokens: m.maxInputTokens,
21988
- maxOutputTokensLimit: m.maxOutputTokens
21989
- }));
21990
- return { models, success: true };
21991
- };
21992
- const hasGeminiCliEnvVars = () => {
21993
- return findExecutableInPath("gemini") !== null;
21994
- };
21995
- const getGeminiCliAiderMapping = (provider, modelId, _settings, _projectDir) => {
21996
- const environmentVariables = {};
21997
- if (isGeminiCliProvider(provider.provider) && provider.provider.projectId) {
21998
- environmentVariables.GOOGLE_CLOUD_PROJECT = provider.provider.projectId;
21999
- }
22000
- return {
22001
- modelName: `gemini-cli/${modelId}`,
22002
- environmentVariables
22003
- };
22004
- };
22005
- const createGeminiCliLlm = async (profile, model, _settings, _projectDir, _toolSet, _systemPrompt, _providerMetadata) => {
22006
- const projectId = isGeminiCliProvider(profile.provider) ? profile.provider.projectId : void 0;
22007
- logger.debug("Creating Gemini CLI LLM", {
22008
- model: model.id,
22009
- projectId
22010
- });
22011
- const { createGeminiProvider } = await import("ai-sdk-provider-gemini-cli");
22012
- if (projectId) {
22013
- process.env.GOOGLE_CLOUD_PROJECT = projectId;
22014
- }
22015
- const gemini = createGeminiProvider({ authType: "oauth-personal" });
22016
- return gemini(model.id);
22017
- };
22018
- const getGeminiCliUsageReport = (task, provider, model, usage, _providerMetadata) => {
22019
- return getDefaultUsageReport(task, provider, model, usage);
22020
- };
22021
- const getGeminiCliProviderParameters = () => {
22022
- return {};
22023
- };
22024
- const isGeminiCliRetryable = (error) => {
22025
- const errorMessage = error instanceof Error ? error.message : String(error);
22026
- if (errorMessage.includes("GOOGLE_CLOUD_PROJECT") || errorMessage.includes("GOOGLE_CLOUD_PROJECT_ID")) {
22027
- return false;
22028
- }
22029
- return true;
22030
- };
22031
- const geminiCliProviderStrategy = {
22032
- createLlm: createGeminiCliLlm,
22033
- getUsageReport: getGeminiCliUsageReport,
22034
- loadModels: loadGeminiCliModels,
22035
- hasEnvVars: hasGeminiCliEnvVars,
22036
- getAiderMapping: getGeminiCliAiderMapping,
22037
- getProviderParameters: getGeminiCliProviderParameters,
22038
- isRetryable: isGeminiCliRetryable
22039
- };
22040
22324
  const loadGpustackModels = async (profile, settings) => {
22041
22325
  if (!isGpustackProvider(profile.provider)) {
22042
22326
  return { models: [], success: false };
@@ -23058,13 +23342,31 @@ const getNeuralwattUsageReport = (task, provider, model, usage, providerMetadata
23058
23342
  agentTotalCost: task.task.agentTotalCost + messageCost
23059
23343
  };
23060
23344
  };
23345
+ const getNeuralwattProviderOptions = (llmProvider, model) => {
23346
+ if (!isNeuralwattProvider(llmProvider)) {
23347
+ return void 0;
23348
+ }
23349
+ const neuralwattProvider = llmProvider;
23350
+ const providerOverrides = model.providerOverrides;
23351
+ const reasoningEffort = providerOverrides?.reasoningEffort ?? neuralwattProvider.reasoningEffort;
23352
+ const mappedReasoningEffort = reasoningEffort === void 0 ? void 0 : reasoningEffort.toLowerCase();
23353
+ if (mappedReasoningEffort) {
23354
+ return {
23355
+ neuralwatt: {
23356
+ reasoningEffort: mappedReasoningEffort
23357
+ }
23358
+ };
23359
+ }
23360
+ return void 0;
23361
+ };
23061
23362
  const neuralwattProviderStrategy = {
23062
23363
  createLlm: createNeuralwattLlm,
23063
23364
  getUsageReport: getNeuralwattUsageReport,
23064
23365
  loadModels: loadNeuralwattModels,
23065
23366
  hasEnvVars: hasNeuralwattEnvVars,
23066
23367
  getAiderMapping: getNeuralwattAiderMapping,
23067
- getModelInfo: getDefaultModelInfo
23368
+ getModelInfo: getDefaultModelInfo,
23369
+ getProviderOptions: getNeuralwattProviderOptions
23068
23370
  };
23069
23371
  const loadOllamaModels = async (profile, settings) => {
23070
23372
  if (!isOllamaProvider(profile.provider)) {
@@ -24371,6 +24673,7 @@ const getZaiPlanProviderOptions = (llmProvider, model) => {
24371
24673
  if (isZaiPlanProvider(llmProvider)) {
24372
24674
  const providerOverrides = model.providerOverrides;
24373
24675
  const thinkingEnabled = providerOverrides?.thinkingEnabled ?? llmProvider.thinkingEnabled ?? true;
24676
+ const reasoningEffort = providerOverrides?.reasoningEffort ?? llmProvider.reasoningEffort ?? ReasoningEffort.Max;
24374
24677
  if (thinkingEnabled === false) {
24375
24678
  return {
24376
24679
  "zai-plan": {
@@ -24380,6 +24683,14 @@ const getZaiPlanProviderOptions = (llmProvider, model) => {
24380
24683
  }
24381
24684
  };
24382
24685
  }
24686
+ const mappedReasoningEffort = reasoningEffort === ReasoningEffort.None ? void 0 : reasoningEffort.toLowerCase();
24687
+ if (mappedReasoningEffort) {
24688
+ return {
24689
+ "zai-plan": {
24690
+ reasoningEffort: mappedReasoningEffort
24691
+ }
24692
+ };
24693
+ }
24383
24694
  }
24384
24695
  return void 0;
24385
24696
  };
@@ -24420,7 +24731,6 @@ class ModelManager {
24420
24731
  cerebras: cerebrasProviderStrategy,
24421
24732
  deepseek: deepseekProviderStrategy,
24422
24733
  gemini: geminiProviderStrategy,
24423
- "gemini-cli": geminiCliProviderStrategy,
24424
24734
  gpustack: gpustackProviderStrategy,
24425
24735
  groq: groqProviderStrategy,
24426
24736
  "alibaba-plan": alibabaPlanProviderStrategy,
@@ -26436,7 +26746,7 @@ class TaskContextImpl {
26436
26746
  async runPrompt(prompt, mode) {
26437
26747
  await this.task.runPrompt(prompt, mode);
26438
26748
  }
26439
- async runPromptInAgent(profile, mode, prompt, promptContext, contextMessages, contextFiles, systemPrompt, waitForCurrentAgentToFinish = true, sendNotification = true) {
26749
+ async runPromptInAgent(profile, mode, prompt, promptContext, contextMessages, contextFiles, systemPrompt, waitForCurrentAgentToFinish = true, sendNotification = true, skillsToActivate) {
26440
26750
  return this.task.runPromptInAgent(
26441
26751
  profile,
26442
26752
  mode,
@@ -26446,7 +26756,9 @@ class TaskContextImpl {
26446
26756
  contextFiles,
26447
26757
  systemPrompt,
26448
26758
  waitForCurrentAgentToFinish,
26449
- sendNotification
26759
+ sendNotification,
26760
+ void 0,
26761
+ skillsToActivate
26450
26762
  );
26451
26763
  }
26452
26764
  async runCustomCommand(name, args = [], mode) {
@@ -26728,6 +27040,19 @@ class ExtensionContextImpl {
26728
27040
  return false;
26729
27041
  }
26730
27042
  }
27043
+ async getElectronApp() {
27044
+ try {
27045
+ const electron = await import("electron");
27046
+ const app = electron?.app ?? electron?.default?.app;
27047
+ if (!app || typeof app.getAppMetrics !== "function") {
27048
+ return null;
27049
+ }
27050
+ return app;
27051
+ } catch (error) {
27052
+ this.log(`Failed to get Electron app: ${error}`, "debug");
27053
+ return null;
27054
+ }
27055
+ }
26731
27056
  getMemoryContext() {
26732
27057
  if (!this.memoryManager) {
26733
27058
  throw new Error("MemoryManager not available");
@@ -27622,6 +27947,7 @@ class ExtensionManager {
27622
27947
  }
27623
27948
  }
27624
27949
  static TOOL_NAME_REGEX = /^[a-z][a-z0-9_-]*$/;
27950
+ static COMMAND_NAME_REGEX = /^[a-z][a-z0-9_:-]*$/;
27625
27951
  validateToolDefinition(tool) {
27626
27952
  const errors = [];
27627
27953
  try {
@@ -27815,9 +28141,9 @@ class ExtensionManager {
27815
28141
  try {
27816
28142
  if (!command.name) {
27817
28143
  errors.push("Command name must be a non-empty string");
27818
- } else if (!ExtensionManager.TOOL_NAME_REGEX.test(command.name)) {
28144
+ } else if (!ExtensionManager.COMMAND_NAME_REGEX.test(command.name)) {
27819
28145
  errors.push(
27820
- `Command name '${command.name}' must start with a lowercase letter and contain only lowercase letters, numbers, hyphens, or underscores (e.g., 'generate-tests', 'my---command', 'command_name')`
28146
+ `Command name '${command.name}' must start with a lowercase letter and contain only lowercase letters, numbers, hyphens, underscores, or colons (e.g., 'generate-tests', 'impl:tweak', 'command_name')`
27821
28147
  );
27822
28148
  }
27823
28149
  if (!command.description || command.description.trim() === "") {
@@ -28452,7 +28778,8 @@ class ExtensionManager {
28452
28778
  return new Promise((resolve, reject) => {
28453
28779
  const child = spawn("npm", ["install"], {
28454
28780
  cwd: extensionPath,
28455
- stdio: "inherit"
28781
+ stdio: "inherit",
28782
+ shell: true
28456
28783
  });
28457
28784
  child.on("close", (code) => {
28458
28785
  if (code === 0) {
@@ -28676,6 +29003,9 @@ class EventsHandler {
28676
29003
  loadSettings() {
28677
29004
  return this.store.getSettings();
28678
29005
  }
29006
+ getEventManager() {
29007
+ return this.eventManager;
29008
+ }
28679
29009
  async saveSettings(newSettings) {
28680
29010
  const oldSettings = this.store.getSettings();
28681
29011
  this.store.saveSettings(newSettings);
@@ -28921,6 +29251,28 @@ class EventsHandler {
28921
29251
  async runPrompt(baseDir, taskId, prompt, mode, images) {
28922
29252
  return this.projectManager.getProject(baseDir).getTask(taskId)?.runPrompt(prompt, mode, true, void 0, true, images) || [];
28923
29253
  }
29254
+ async waitForTaskIdle(baseDir, taskId) {
29255
+ const project = this.projectManager.getProject(baseDir);
29256
+ const task = project?.getTask(taskId);
29257
+ if (!task) {
29258
+ throw new Error(`Task ${taskId} not found in project ${baseDir}`);
29259
+ }
29260
+ await task.waitForIdle();
29261
+ }
29262
+ async ensureProjectAndCreateTask(projectDir, params) {
29263
+ const projects = this.store.getOpenProjects();
29264
+ const baseDir = projectDir.endsWith("/") ? projectDir.slice(0, -1) : projectDir;
29265
+ const existingProject = projects.find((p) => compareBaseDirs$1(p.baseDir, baseDir));
29266
+ if (!existingProject) {
29267
+ await this.addOpenProject(baseDir);
29268
+ }
29269
+ const taskParams = {
29270
+ ...params,
29271
+ autonomyMode: params?.autonomyMode ?? AutonomyMode.Autonomous
29272
+ };
29273
+ const task = await this.createNewTask(baseDir, taskParams);
29274
+ return { taskId: task.id, projectDir: baseDir };
29275
+ }
28924
29276
  async savePrompt(baseDir, taskId, prompt) {
28925
29277
  return this.projectManager.getProject(baseDir).getTask(taskId)?.savePromptOnly(prompt);
28926
29278
  }
@@ -30431,11 +30783,6 @@ const initManagers = async (store, windowManager) => {
30431
30783
  };
30432
30784
  const performStartUp = async (pythonInstaller, updateProgress) => {
30433
30785
  logger.info("Starting AiderDesk setup process (fast path)");
30434
- updateProgress?.({
30435
- step: "Setting up MCP server",
30436
- message: "Setting up MCP server..."
30437
- });
30438
- await setupMcpServerInternal();
30439
30786
  if (fs__namespace.existsSync(SETUP_COMPLETE_FILENAME) && fs__namespace.existsSync(PYTHON_VENV_DIR)) {
30440
30787
  logger.info("Setup previously completed, will run update check in background");
30441
30788
  updateProgress?.({
@@ -30457,28 +30804,6 @@ const performStartUp = async (pythonInstaller, updateProgress) => {
30457
30804
  pythonInstaller.ensureInstalled();
30458
30805
  return true;
30459
30806
  };
30460
- const setupMcpServerInternal = async () => {
30461
- if (isDev()) {
30462
- logger.info("Skipping AiderDesk MCP server setup in dev mode");
30463
- return;
30464
- }
30465
- if (!fs__namespace.existsSync(AIDER_DESK_MCP_SERVER_DIR)) {
30466
- fs__namespace.mkdirSync(AIDER_DESK_MCP_SERVER_DIR, { recursive: true });
30467
- }
30468
- const sourceMcpServerDir = path.join(RESOURCES_DIR, "mcp-server");
30469
- if (fs__namespace.existsSync(sourceMcpServerDir)) {
30470
- const files = fs__namespace.readdirSync(sourceMcpServerDir);
30471
- for (const file of files) {
30472
- const sourceFilePath = path.join(sourceMcpServerDir, file);
30473
- const destFilePath = path.join(AIDER_DESK_MCP_SERVER_DIR, file);
30474
- if (fs__namespace.statSync(sourceFilePath).isFile()) {
30475
- fs__namespace.copyFileSync(sourceFilePath, destFilePath);
30476
- }
30477
- }
30478
- } else {
30479
- logger.error(`MCP server directory not found: ${sourceMcpServerDir}`);
30480
- }
30481
- };
30482
30807
  const migrateSettingsV0toV1 = (settings) => {
30483
30808
  let mcpConfig = settings.mcpConfig;
30484
30809
  if (typeof mcpConfig?.provider === "string") {
@@ -31009,7 +31334,8 @@ const DEFAULT_SETTINGS = {
31009
31334
  },
31010
31335
  proxy: {
31011
31336
  enabled: false,
31012
- url: ""
31337
+ url: "",
31338
+ noProxy: ""
31013
31339
  },
31014
31340
  fileWatchMode: FileWatchMode.Auto
31015
31341
  };