@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.
- package/README.md +49 -0
- package/out/cli.js +1006 -1
- package/out/renderer/assets/{AgentSettings-4fCr6MRo.js → AgentSettings-BKSogFrU.js} +133 -125
- package/out/renderer/assets/{InfoIcon-Cend8bQ6.js → InfoIcon-XbMgPv1i.js} +1 -1
- package/out/renderer/assets/{Onboarding-SfOrsd7I.js → Onboarding-DsxeAj-M.js} +4 -4
- package/out/renderer/assets/{ProviderHeader-IIBa8Q98.js → ProviderHeader-CQHU1_fp.js} +384 -165
- package/out/renderer/assets/{SettingsPage-1PPq3lwt.js → SettingsPage-jGXWkGLq.js} +643 -265
- package/out/renderer/assets/{UsageDashboard-C73v7_7A.js → UsageDashboard-BcWDkudQ.js} +3 -3
- package/out/renderer/assets/{arc-DooaZ_2W.js → arc-CbTCDvhP.js} +1 -1
- package/out/renderer/assets/{architectureDiagram-3BPJPVTR-BZRfdU_l.js → architectureDiagram-3BPJPVTR-BYGjkH2o.js} +3 -3
- package/out/renderer/assets/{blockDiagram-GPEHLZMM-GVLrld7f.js → blockDiagram-GPEHLZMM-BNslNypY.js} +4 -4
- package/out/renderer/assets/{c4Diagram-AAUBKEIU-CuLHxnUp.js → c4Diagram-AAUBKEIU-BOUV-4Hf.js} +2 -2
- package/out/renderer/assets/{channel-CBp4QC42.js → channel-gTXtcW6n.js} +1 -1
- package/out/renderer/assets/{chunk-2J33WTMH-CLGSY5ry.js → chunk-2J33WTMH-cVAo2nRo.js} +1 -1
- package/out/renderer/assets/{chunk-4BX2VUAB-DfOAmq0y.js → chunk-4BX2VUAB-QUppBCep.js} +1 -1
- package/out/renderer/assets/{chunk-55IACEB6-CjDMk8wF.js → chunk-55IACEB6-B7ATOpEx.js} +1 -1
- package/out/renderer/assets/{chunk-727SXJPM-4GHP5or6.js → chunk-727SXJPM-DNHjk-uw.js} +5 -5
- package/out/renderer/assets/{chunk-AQP2D5EJ-B8ex3L6d.js → chunk-AQP2D5EJ-C_nuud1y.js} +3 -3
- package/out/renderer/assets/{chunk-FMBD7UC4-DXVKqz45.js → chunk-FMBD7UC4-DoAO6UdZ.js} +1 -1
- package/out/renderer/assets/{chunk-ND2GUHAM-CJf331B5.js → chunk-ND2GUHAM-hRnym-e6.js} +1 -1
- package/out/renderer/assets/{chunk-QZHKN3VN-CmRmlYwi.js → chunk-QZHKN3VN-BkTqSMpi.js} +1 -1
- package/out/renderer/assets/{classDiagram-4FO5ZUOK-BB0WWhct.js → classDiagram-4FO5ZUOK-097_YN8Y.js} +6 -6
- package/out/renderer/assets/{classDiagram-v2-Q7XG4LA2-BB0WWhct.js → classDiagram-v2-Q7XG4LA2-097_YN8Y.js} +6 -6
- package/out/renderer/assets/{cose-bilkent-S5V4N54A-C1ovVUkK.js → cose-bilkent-S5V4N54A-CU24fSZY.js} +1 -1
- package/out/renderer/assets/{dagre-BM42HDAG-BN2vkdYj.js → dagre-BM42HDAG-CXQk6wIx.js} +3 -3
- package/out/renderer/assets/{diagram-2AECGRRQ-Gmur2BYD.js → diagram-2AECGRRQ-cp5zubxu.js} +3 -3
- package/out/renderer/assets/{diagram-5GNKFQAL-CO-0qbfq.js → diagram-5GNKFQAL-Dz1liaVJ.js} +4 -4
- package/out/renderer/assets/{diagram-KO2AKTUF-B0BourUo.js → diagram-KO2AKTUF-C_a_DDR7.js} +3 -3
- package/out/renderer/assets/{diagram-LMA3HP47-CZSemlgR.js → diagram-LMA3HP47-DMzt3Wms.js} +3 -3
- package/out/renderer/assets/{diagram-OG6HWLK6-DIg_VSi2.js → diagram-OG6HWLK6-DXgo41ZN.js} +4 -4
- package/out/renderer/assets/{erDiagram-TEJ5UH35-CeDB_1TN.js → erDiagram-TEJ5UH35-Duy8-ZVE.js} +4 -4
- package/out/renderer/assets/{flowDiagram-I6XJVG4X-CAYyZ6xk.js → flowDiagram-I6XJVG4X-C79uBv3j.js} +6 -6
- package/out/renderer/assets/{ganttDiagram-6RSMTGT7-28qx3HO3.js → ganttDiagram-6RSMTGT7-COUQHYqH.js} +3 -3
- package/out/renderer/assets/{gitGraphDiagram-PVQCEYII-C0C5PVgG.js → gitGraphDiagram-PVQCEYII-D3-KSp5g.js} +4 -4
- package/out/renderer/assets/{graph-BmyvWy9U.js → graph-CojOaclU.js} +1 -1
- package/out/renderer/assets/{index-CCixlVbO.js → index-BDc7WeA_.js} +1 -1
- package/out/renderer/assets/{index-CqkLi8Rn.js → index-BX1dnn54.js} +1 -1
- package/out/renderer/assets/{index-BkEUNx2M.js → index-BxH3Vzns.js} +129 -30
- package/out/renderer/assets/{index-CleisQX7.js → index-CZVPwEh7.js} +1 -1
- package/out/renderer/assets/{index-DHgg9rnw.js → index-CcbWMGtO.js} +1 -1
- package/out/renderer/assets/{index-LwoRwQcK.js → index-CoN3I29h.js} +1 -1
- package/out/renderer/assets/{index-D4QsfuBU.css → index-DJwDiyPe.css} +8 -0
- package/out/renderer/assets/{index-CjWyE7Qc.js → index-DqOJFqtI.js} +1 -1
- package/out/renderer/assets/{index-DDyjc4hl.js → index-DqOyb6kJ.js} +1 -1
- package/out/renderer/assets/{index-DiXCQ0pX.js → index-LigRSjJQ.js} +2274 -1492
- package/out/renderer/assets/{index-D1hWSFOH.js → index-uk-xw9ke.js} +1 -1
- package/out/renderer/assets/{infoDiagram-5YYISTIA-BR2qewYU.js → infoDiagram-5YYISTIA-Dhu3XDyU.js} +2 -2
- package/out/renderer/assets/{ishikawaDiagram-YF4QCWOH-mBtVTtfu.js → ishikawaDiagram-YF4QCWOH-Zv844Inp.js} +1 -1
- package/out/renderer/assets/{journeyDiagram-JHISSGLW-BLwLxSRJ.js → journeyDiagram-JHISSGLW-CiEy0k__.js} +4 -4
- package/out/renderer/assets/{jsx-dev-runtime-C3x5nPQV.js → jsx-dev-runtime-BblfdcBq.js} +1 -1
- package/out/renderer/assets/{kanban-definition-UN3LZRKU-DEQMBIes.js → kanban-definition-UN3LZRKU-Bg7Tn0_t.js} +2 -2
- package/out/renderer/assets/{layout-COZ2dLJC.js → layout-C7gScUZ3.js} +2 -2
- package/out/renderer/assets/{linear-BwuiC9BD.js → linear-C8mfmsRG.js} +1 -1
- package/out/renderer/assets/{mindmap-definition-RKZ34NQL-BEdOr2LN.js → mindmap-definition-RKZ34NQL-CT41c9xA.js} +3 -3
- package/out/renderer/assets/{pieDiagram-4H26LBE5-C2CIjhWa.js → pieDiagram-4H26LBE5-4MIz5Tk3.js} +4 -4
- package/out/renderer/assets/{quadrantDiagram-W4KKPZXB-ByG1Fnbm.js → quadrantDiagram-W4KKPZXB-srrdZ4mO.js} +2 -2
- package/out/renderer/assets/{requirementDiagram-4Y6WPE33-CPNEbV2R.js → requirementDiagram-4Y6WPE33-hCfEAv72.js} +3 -3
- package/out/renderer/assets/{sankeyDiagram-5OEKKPKP-DseN3BYS.js → sankeyDiagram-5OEKKPKP-D3Dmoahf.js} +1 -1
- package/out/renderer/assets/{sequenceDiagram-3UESZ5HK-DGbPycPW.js → sequenceDiagram-3UESZ5HK-B_R1OT73.js} +3 -3
- package/out/renderer/assets/{stateDiagram-AJRCARHV-I_wGtDx-.js → stateDiagram-AJRCARHV-T81AxWaT.js} +6 -6
- package/out/renderer/assets/{stateDiagram-v2-BHNVJYJU-MVwIUdrA.js → stateDiagram-v2-BHNVJYJU-DotM3iTY.js} +4 -4
- package/out/renderer/assets/{time-DKSwLtIL.js → time-NQi4RUKr.js} +1 -1
- package/out/renderer/assets/{timeline-definition-PNZ67QCA-0o1eLzXF.js → timeline-definition-PNZ67QCA-CuIJOcqs.js} +2 -2
- package/out/renderer/assets/{vennDiagram-CIIHVFJN-BbPtgu5r.js → vennDiagram-CIIHVFJN-BP9XceqR.js} +1 -1
- package/out/renderer/assets/{wardley-L42UT6IY-C6O9NaAx.js → wardley-L42UT6IY-Cs8sx4Yc.js} +1 -1
- package/out/renderer/assets/{wardleyDiagram-YWT4CUSO-C0NB17Hf.js → wardleyDiagram-YWT4CUSO-BleVwqnB.js} +3 -3
- package/out/renderer/assets/{xychartDiagram-2RQKCTM6-CM1NB5k6.js → xychartDiagram-2RQKCTM6-CoEiSbj_.js} +2 -2
- package/out/renderer/index.html +2 -2
- package/out/runner.js +613 -287
- package/package.json +20 -20
- package/scripts/generate-package.mjs +1 -2
- package/scripts/publish-next.mjs +22 -0
- package/out/renderer/assets/gemini-cli-BKI4k4GP.png +0 -0
- package/out/resources/mcp-server/aider-desk-mcp-server.js +0 -39437
- 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"
|
|
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
|
-
|
|
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
|
-
|
|
3762
|
+
return false;
|
|
3816
3763
|
}
|
|
3817
|
-
const
|
|
3818
|
-
const match = outputLineRegex.exec(line);
|
|
3764
|
+
const match = outputLineRegex.exec(rawLine);
|
|
3819
3765
|
if (!match) {
|
|
3820
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3855
|
-
|
|
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 (
|
|
3860
|
-
return `Error during grep: ${
|
|
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
|
|
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"
|
|
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().
|
|
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
|
-
"/
|
|
8959
|
-
|
|
8960
|
-
|
|
8961
|
-
|
|
8962
|
-
|
|
8963
|
-
|
|
8964
|
-
|
|
8965
|
-
|
|
8966
|
-
res.status(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 --
|
|
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
|
|
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
|
-
|
|
17993
|
-
|
|
17994
|
-
|
|
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
|
-
|
|
17997
|
-
|
|
17998
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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
|
};
|