@aiderdesk/aiderdesk 0.66.0 → 0.67.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/out/renderer/assets/{arc-BXuUWHai.js → arc-BnPy4nhx.js} +1 -1
- package/out/renderer/assets/{architectureDiagram-3BPJPVTR-Bm9oFTP_.js → architectureDiagram-3BPJPVTR-_SwpsbSs.js} +3 -3
- package/out/renderer/assets/{blockDiagram-GPEHLZMM-DQ2DevZl.js → blockDiagram-GPEHLZMM-D8Bc_xCY.js} +4 -4
- package/out/renderer/assets/{c4Diagram-AAUBKEIU-BdR46VbA.js → c4Diagram-AAUBKEIU-Ddic5IpI.js} +2 -2
- package/out/renderer/assets/{channel-DUdp1NJ7.js → channel-I2sEi2rW.js} +1 -1
- package/out/renderer/assets/{chunk-2J33WTMH-Dzi-idRV.js → chunk-2J33WTMH-Cqrw7IHw.js} +1 -1
- package/out/renderer/assets/{chunk-4BX2VUAB-DEyFpixF.js → chunk-4BX2VUAB-DKY4go9E.js} +1 -1
- package/out/renderer/assets/{chunk-55IACEB6-DyyQMIZa.js → chunk-55IACEB6-COO6Gc0F.js} +1 -1
- package/out/renderer/assets/{chunk-727SXJPM-vXEiesCP.js → chunk-727SXJPM-Bu8zhvGn.js} +5 -5
- package/out/renderer/assets/{chunk-AQP2D5EJ-B0SWmbrS.js → chunk-AQP2D5EJ-JHXEk1U1.js} +3 -3
- package/out/renderer/assets/{chunk-FMBD7UC4-CoPwvBCa.js → chunk-FMBD7UC4-BqbYNISq.js} +1 -1
- package/out/renderer/assets/{chunk-ND2GUHAM-ku5t5SwP.js → chunk-ND2GUHAM-D29ZgnDp.js} +1 -1
- package/out/renderer/assets/{chunk-QZHKN3VN-DBGBAqit.js → chunk-QZHKN3VN-B-pbtAbR.js} +1 -1
- package/out/renderer/assets/{classDiagram-4FO5ZUOK-DTyjsHX9.js → classDiagram-4FO5ZUOK-B7_tIdbP.js} +6 -6
- package/out/renderer/assets/{classDiagram-v2-Q7XG4LA2-DTyjsHX9.js → classDiagram-v2-Q7XG4LA2-B7_tIdbP.js} +6 -6
- package/out/renderer/assets/{cose-bilkent-S5V4N54A-wGfE9wIx.js → cose-bilkent-S5V4N54A-CGNgxRV6.js} +1 -1
- package/out/renderer/assets/{dagre-BM42HDAG-cwyj1-l0.js → dagre-BM42HDAG-DB-tI7Ml.js} +3 -3
- package/out/renderer/assets/{diagram-2AECGRRQ-BYvCxkOs.js → diagram-2AECGRRQ-Cdwrgy7R.js} +3 -3
- package/out/renderer/assets/{diagram-5GNKFQAL--ZlqvgmY.js → diagram-5GNKFQAL-BnvZ78_N.js} +4 -4
- package/out/renderer/assets/{diagram-KO2AKTUF-CoPNrPhx.js → diagram-KO2AKTUF-VUrfwRCk.js} +3 -3
- package/out/renderer/assets/{diagram-LMA3HP47-wjhxYTWf.js → diagram-LMA3HP47-_Vo8GrFC.js} +3 -3
- package/out/renderer/assets/{diagram-OG6HWLK6-DhYpewbd.js → diagram-OG6HWLK6-CoLz9kio.js} +4 -4
- package/out/renderer/assets/{erDiagram-TEJ5UH35-DolRLBng.js → erDiagram-TEJ5UH35-B3Bg3gW1.js} +4 -4
- package/out/renderer/assets/{flowDiagram-I6XJVG4X-DjAbl_XC.js → flowDiagram-I6XJVG4X-BgyAk0Xe.js} +6 -6
- package/out/renderer/assets/{ganttDiagram-6RSMTGT7-AF7-XgtX.js → ganttDiagram-6RSMTGT7-NnVRwQPs.js} +1 -1
- package/out/renderer/assets/{gitGraphDiagram-PVQCEYII-BMZLakzH.js → gitGraphDiagram-PVQCEYII-C4vrRnDw.js} +4 -4
- package/out/renderer/assets/{graph-B_ifajWk.js → graph-BZvTCUpv.js} +1 -1
- package/out/renderer/assets/{index-3bI-dJm8.js → index-P63PgYUG.js} +2241 -1589
- package/out/renderer/assets/{index-B62bIfbt.css → index-zdiQSGqQ.css} +28 -16
- package/out/renderer/assets/{infoDiagram-5YYISTIA-0f7Qxxvp.js → infoDiagram-5YYISTIA-zTriWVJJ.js} +2 -2
- package/out/renderer/assets/{ishikawaDiagram-YF4QCWOH-BX_EIAMn.js → ishikawaDiagram-YF4QCWOH-DHO6Yeea.js} +1 -1
- package/out/renderer/assets/{journeyDiagram-JHISSGLW-Dmitv8wD.js → journeyDiagram-JHISSGLW-CZsRcg2X.js} +4 -4
- package/out/renderer/assets/{kanban-definition-UN3LZRKU-By2GFUNB.js → kanban-definition-UN3LZRKU-DSpAeh8p.js} +2 -2
- package/out/renderer/assets/{layout-DAkKffy1.js → layout-B5A8fT-Z.js} +2 -2
- package/out/renderer/assets/{mindmap-definition-RKZ34NQL-yIrV1m0y.js → mindmap-definition-RKZ34NQL-Bns9Ab8p.js} +3 -3
- package/out/renderer/assets/{pieDiagram-4H26LBE5-PV9y5rw_.js → pieDiagram-4H26LBE5-BX36DY7W.js} +4 -4
- package/out/renderer/assets/{quadrantDiagram-W4KKPZXB-DeX0zTCp.js → quadrantDiagram-W4KKPZXB-DuD2qSni.js} +1 -1
- package/out/renderer/assets/{requirementDiagram-4Y6WPE33-Bzfk_KE-.js → requirementDiagram-4Y6WPE33-Th2uknlw.js} +3 -3
- package/out/renderer/assets/{sankeyDiagram-5OEKKPKP-BuCv8QIY.js → sankeyDiagram-5OEKKPKP-DP3WODC7.js} +1 -1
- package/out/renderer/assets/{sequenceDiagram-3UESZ5HK-Zg7Ukud8.js → sequenceDiagram-3UESZ5HK-BvpGEq-v.js} +3 -3
- package/out/renderer/assets/{stateDiagram-AJRCARHV-CLaqfYR8.js → stateDiagram-AJRCARHV-Btrfma35.js} +6 -6
- package/out/renderer/assets/{stateDiagram-v2-BHNVJYJU-Cmm1ljQ4.js → stateDiagram-v2-BHNVJYJU-v-8JiozM.js} +4 -4
- package/out/renderer/assets/{timeline-definition-PNZ67QCA-DQBaAVcC.js → timeline-definition-PNZ67QCA-prZy7cGx.js} +2 -2
- package/out/renderer/assets/{vennDiagram-CIIHVFJN-CuplbU_R.js → vennDiagram-CIIHVFJN-XCVp5OjS.js} +1 -1
- package/out/renderer/assets/{wardley-L42UT6IY-BiqfHMim.js → wardley-L42UT6IY-FZSNLjCs.js} +1 -1
- package/out/renderer/assets/{wardleyDiagram-YWT4CUSO-BaV0FnUu.js → wardleyDiagram-YWT4CUSO-Cla_7ryL.js} +3 -3
- package/out/renderer/assets/{xychartDiagram-2RQKCTM6-DA_Miw-n.js → xychartDiagram-2RQKCTM6-CKvwGbhk.js} +1 -1
- package/out/renderer/index.html +2 -2
- package/out/resources/prompts/workflow.hbs +2 -2
- package/out/runner.js +644 -184
- package/package.json +16 -3
package/out/runner.js
CHANGED
|
@@ -231,6 +231,7 @@ const TASKS_TOOL_GET_TASK_MESSAGE = "get_task_message";
|
|
|
231
231
|
const TASKS_TOOL_CREATE_TASK = "create_task";
|
|
232
232
|
const TASKS_TOOL_DELETE_TASK = "delete_task";
|
|
233
233
|
const TASKS_TOOL_SEARCH_TASK = "search_task";
|
|
234
|
+
const TASKS_TOOL_RUN_PROMPT = "run_prompt";
|
|
234
235
|
const TASKS_TOOL_SEARCH_PARENT_TASK = "search_parent_task";
|
|
235
236
|
const TASKS_TOOL_DESCRIPTIONS = {
|
|
236
237
|
[TASKS_TOOL_LIST_TASKS]: "List all tasks in the current project. Returns basic information for each task including id, name, and creation/update timestamps. Use this to get an overview of all available tasks before performing specific task operations.",
|
|
@@ -239,6 +240,7 @@ const TASKS_TOOL_DESCRIPTIONS = {
|
|
|
239
240
|
[TASKS_TOOL_CREATE_TASK]: "Create a new task in the current project with an initial prompt. Optionally use user-provided agentProfileId to use a different agent, a modelId to override the model, or a parentTaskId (if available) to create a subtask of another task. The new task will start with the provided prompt as its first user message. Use this to begin new work streams, separate different aspects of a project, or break down complex tasks into manageable subtasks. Use execute to create a task and wait for the task to be finished. Use executeInBackground to create a task in the background without waiting for the task to be finished.",
|
|
240
241
|
[TASKS_TOOL_DELETE_TASK]: "Permanently delete a task and all its associated data including messages, context files, and metadata. This action cannot be undone. Note that you cannot delete the currently active task. Use this to clean up completed or abandoned tasks, but be cautious as this removes all task history permanently.",
|
|
241
242
|
[TASKS_TOOL_SEARCH_TASK]: "Search content within a specific task using semantic search. Use natural language queries with 2-5 descriptive words including key concepts and context. Searches through task conversation history and context files. Use this to find relevant information, discussions, or code snippets within a task.",
|
|
243
|
+
[TASKS_TOOL_RUN_PROMPT]: "Run a prompt on an existing task. The task must already exist (use create_task first if needed). Use this to send additional instructions to a task, continue work on an existing task, or delegate follow-up work. By default, waits for the prompt to complete before returning. Use executeInBackground to run without waiting.",
|
|
242
244
|
[TASKS_TOOL_SEARCH_PARENT_TASK]: "Search content within parent task using semantic search. Use natural language queries with 2-5 descriptive words including key concepts and context. Automatically searches parent task conversation history and context files."
|
|
243
245
|
};
|
|
244
246
|
const WorktreeSchema = zod.z.object({
|
|
@@ -257,6 +259,13 @@ const MergeStateSchema = zod.z.object({
|
|
|
257
259
|
});
|
|
258
260
|
const AIDER_MODES = ["code", "ask", "architect", "context"];
|
|
259
261
|
const AIDER_COMMANDS = ["commit", "map", "map-refresh", "tokens", "test"];
|
|
262
|
+
var AutonomyMode = /* @__PURE__ */ ((AutonomyMode2) => {
|
|
263
|
+
AutonomyMode2["Manual"] = "manual";
|
|
264
|
+
AutonomyMode2["Guided"] = "guided";
|
|
265
|
+
AutonomyMode2["Autonomous"] = "autonomous";
|
|
266
|
+
return AutonomyMode2;
|
|
267
|
+
})(AutonomyMode || {});
|
|
268
|
+
const DEFAULT_AUTONOMY_MODE = "guided";
|
|
260
269
|
var DiffViewMode = /* @__PURE__ */ ((DiffViewMode2) => {
|
|
261
270
|
DiffViewMode2["SideBySide"] = "side-by-side";
|
|
262
271
|
DiffViewMode2["Unified"] = "unified";
|
|
@@ -300,7 +309,7 @@ const ProjectSettingsSchema = zod.z.object({
|
|
|
300
309
|
thinkingTokens: zod.z.string().optional(),
|
|
301
310
|
currentMode: zod.z.string(),
|
|
302
311
|
weakModelLocked: zod.z.boolean().optional(),
|
|
303
|
-
|
|
312
|
+
autonomyModeLocked: zod.z.boolean().optional(),
|
|
304
313
|
updatedFilesGroupMode: zod.z.enum(["grouped", "flat"]).default("flat"),
|
|
305
314
|
disabledRuleFiles: zod.z.array(zod.z.string()).default([]),
|
|
306
315
|
contextSidebarSectionsOrder: zod.z.array(zod.z.string()).default([]),
|
|
@@ -339,6 +348,12 @@ var ContextCompactionType = /* @__PURE__ */ ((ContextCompactionType2) => {
|
|
|
339
348
|
ContextCompactionType2["Smart"] = "smart";
|
|
340
349
|
return ContextCompactionType2;
|
|
341
350
|
})(ContextCompactionType || {});
|
|
351
|
+
var FileWatchMode = /* @__PURE__ */ ((FileWatchMode2) => {
|
|
352
|
+
FileWatchMode2["Auto"] = "auto";
|
|
353
|
+
FileWatchMode2["Native"] = "native";
|
|
354
|
+
FileWatchMode2["Polling"] = "polling";
|
|
355
|
+
return FileWatchMode2;
|
|
356
|
+
})(FileWatchMode || {});
|
|
342
357
|
var MemoryEmbeddingProgressPhase = /* @__PURE__ */ ((MemoryEmbeddingProgressPhase2) => {
|
|
343
358
|
MemoryEmbeddingProgressPhase2["Idle"] = "idle";
|
|
344
359
|
MemoryEmbeddingProgressPhase2["LoadingModel"] = "loading-model";
|
|
@@ -372,7 +387,7 @@ const TaskDataSchema = zod.z.object({
|
|
|
372
387
|
lastMergeState: MergeStateSchema.optional(),
|
|
373
388
|
aiderTotalCost: zod.z.number(),
|
|
374
389
|
agentTotalCost: zod.z.number(),
|
|
375
|
-
|
|
390
|
+
autonomyMode: zod.z.nativeEnum(AutonomyMode).optional(),
|
|
376
391
|
agentProfileId: zod.z.string().optional(),
|
|
377
392
|
provider: zod.z.string().optional(),
|
|
378
393
|
model: zod.z.string().optional(),
|
|
@@ -886,6 +901,9 @@ if (process.env.NODE_ENV !== "production" || process.env.AIDER_DESK_HEADLESS ===
|
|
|
886
901
|
const initEventLogging = (eventManager) => {
|
|
887
902
|
eventTransport.setEventManager(eventManager);
|
|
888
903
|
};
|
|
904
|
+
const isAutoApprove = (task) => {
|
|
905
|
+
return task.task.autonomyMode !== AutonomyMode.Manual;
|
|
906
|
+
};
|
|
889
907
|
class ApprovalManager {
|
|
890
908
|
constructor(task, profile) {
|
|
891
909
|
this.task = task;
|
|
@@ -913,7 +931,7 @@ class ApprovalManager {
|
|
|
913
931
|
key = extensionResult.key;
|
|
914
932
|
text = extensionResult.text;
|
|
915
933
|
subject = extensionResult.subject;
|
|
916
|
-
if (this.task
|
|
934
|
+
if (isAutoApprove(this.task)) {
|
|
917
935
|
return [true, void 0];
|
|
918
936
|
}
|
|
919
937
|
const isApprovedFromSet = this.alwaysApproveForRunKeys.has(key) || (this.profile.toolApprovals[key] || ToolApprovalState.Always) === ToolApprovalState.Always;
|
|
@@ -1494,6 +1512,7 @@ const AVAILABLE_PROVIDERS = [
|
|
|
1494
1512
|
"lmstudio",
|
|
1495
1513
|
"minimax",
|
|
1496
1514
|
"mistral",
|
|
1515
|
+
"neuralwatt",
|
|
1497
1516
|
"ollama",
|
|
1498
1517
|
"openai",
|
|
1499
1518
|
"openai-compatible",
|
|
@@ -1539,6 +1558,7 @@ const isOpenCodeProvider = (provider) => provider.name === "opencode";
|
|
|
1539
1558
|
const isZaiPlanProvider = (provider) => provider.name === "zai-plan";
|
|
1540
1559
|
const isMinimaxProvider = (provider) => provider.name === "minimax";
|
|
1541
1560
|
const isMistralProvider = (provider) => provider.name === "mistral";
|
|
1561
|
+
const isNeuralwattProvider = (provider) => provider.name === "neuralwatt";
|
|
1542
1562
|
const isSyntheticProvider = (provider) => provider.name === "synthetic";
|
|
1543
1563
|
const DEFAULT_PROVIDER_MODELS = {
|
|
1544
1564
|
"alibaba-plan": "qwen3-coder-plus",
|
|
@@ -1559,7 +1579,8 @@ const DEFAULT_PROVIDER_MODELS = {
|
|
|
1559
1579
|
synthetic: "hf:zai-org/GLM-4.7",
|
|
1560
1580
|
"zai-plan": "glm-5.1",
|
|
1561
1581
|
minimax: "MiniMax-M2.7",
|
|
1562
|
-
mistral: "mistral-large-latest"
|
|
1582
|
+
mistral: "mistral-large-latest",
|
|
1583
|
+
neuralwatt: "claude-sonnet-4-6"
|
|
1563
1584
|
};
|
|
1564
1585
|
const DEFAULT_AIDER_MAIN_MODEL = `anthropic/${DEFAULT_PROVIDER_MODELS.anthropic}`;
|
|
1565
1586
|
const DEFAULT_AGENT_PROFILE_ID = "default";
|
|
@@ -1964,6 +1985,12 @@ const getDefaultProviderParams = (providerName) => {
|
|
|
1964
1985
|
apiKey: ""
|
|
1965
1986
|
};
|
|
1966
1987
|
break;
|
|
1988
|
+
case "neuralwatt":
|
|
1989
|
+
provider = {
|
|
1990
|
+
name: "neuralwatt",
|
|
1991
|
+
apiKey: ""
|
|
1992
|
+
};
|
|
1993
|
+
break;
|
|
1967
1994
|
case "gemini-cli":
|
|
1968
1995
|
provider = {
|
|
1969
1996
|
name: "gemini-cli",
|
|
@@ -2086,7 +2113,7 @@ class TelemetryManager {
|
|
|
2086
2113
|
useTodoTools: profile.useTodoTools,
|
|
2087
2114
|
includeContextFiles: profile.includeContextFiles,
|
|
2088
2115
|
includeRepoMap: profile.includeRepoMap,
|
|
2089
|
-
|
|
2116
|
+
autonomyMode: task?.autonomyMode ?? "guided",
|
|
2090
2117
|
enabledMcpServersCount: profile.enabledServers.length,
|
|
2091
2118
|
totalMcpServersCount: Object.keys(this.store.getSettings().mcpServers).length
|
|
2092
2119
|
}
|
|
@@ -2245,7 +2272,8 @@ const readApiKeyFromConfFile = (filePath, envVarName) => {
|
|
|
2245
2272
|
OPENCODE_API_KEY: ["opencode"],
|
|
2246
2273
|
REQUESTY_API_KEY: ["requesty"],
|
|
2247
2274
|
SYNTHETIC_API_KEY: ["synthetic"],
|
|
2248
|
-
MISTRAL_API_KEY: ["mistral"]
|
|
2275
|
+
MISTRAL_API_KEY: ["mistral"],
|
|
2276
|
+
NEURALWATT_API_KEY: ["neuralwatt"]
|
|
2249
2277
|
};
|
|
2250
2278
|
const providerNames = envVarToProviderName[envVarName] || [envVarName.replace(/_API_KEY$/, "").toLowerCase()];
|
|
2251
2279
|
const apiKeys = Array.isArray(apiKeyValue) ? apiKeyValue : [apiKeyValue];
|
|
@@ -2411,7 +2439,7 @@ const getDefaultProjectSettings = (store, providerModels, baseDir, defaultAgentP
|
|
|
2411
2439
|
modelEditFormats: {},
|
|
2412
2440
|
currentMode: "agent",
|
|
2413
2441
|
agentProfileId: defaultAgentProfileId,
|
|
2414
|
-
|
|
2442
|
+
autonomyModeLocked: false,
|
|
2415
2443
|
updatedFilesGroupMode: "flat",
|
|
2416
2444
|
disabledRuleFiles: [],
|
|
2417
2445
|
contextSidebarSectionsOrder: [],
|
|
@@ -3259,7 +3287,7 @@ File size limit (${sizeLimit.toFixed(1)} KB) exceeded. Use shell commands (e.g.,
|
|
|
3259
3287
|
}
|
|
3260
3288
|
return resultLines.join("\n");
|
|
3261
3289
|
};
|
|
3262
|
-
const truncateToolResult = async (content, maxLines = 1e3, maxSizeKB = 50, maxTokens = 5e4) => {
|
|
3290
|
+
const truncateToolResult = async (content, maxLines = 1e3, maxSizeKB = 50, maxTokens = 5e4, saveToFile = true, truncationSuffix) => {
|
|
3263
3291
|
const lines = content.split("\n");
|
|
3264
3292
|
const sizeBytes = Buffer.byteLength(content, "utf8");
|
|
3265
3293
|
const sizeKB = sizeBytes / 1024;
|
|
@@ -3267,10 +3295,13 @@ const truncateToolResult = async (content, maxLines = 1e3, maxSizeKB = 50, maxTo
|
|
|
3267
3295
|
if (lines.length <= maxLines && sizeKB <= maxSizeKB && tokenCount <= maxTokens) {
|
|
3268
3296
|
return content;
|
|
3269
3297
|
}
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3298
|
+
let tmpFilePath;
|
|
3299
|
+
if (saveToFile) {
|
|
3300
|
+
const id = Date.now().toString(36) + Math.random().toString(36).substring(2, 8);
|
|
3301
|
+
const tmpFileName = `aider-desk-tool-result-${id}.txt`;
|
|
3302
|
+
tmpFilePath = path.join(os.tmpdir(), tmpFileName);
|
|
3303
|
+
await fs.writeFile(tmpFilePath, content, "utf8");
|
|
3304
|
+
}
|
|
3274
3305
|
const reasons = [];
|
|
3275
3306
|
if (lines.length > maxLines) {
|
|
3276
3307
|
reasons.push(`${lines.length} lines exceeded limit of ${maxLines}`);
|
|
@@ -3281,6 +3312,13 @@ const truncateToolResult = async (content, maxLines = 1e3, maxSizeKB = 50, maxTo
|
|
|
3281
3312
|
if (tokenCount > maxTokens) {
|
|
3282
3313
|
reasons.push(`${tokenCount} tokens exceeded limit of ${maxTokens}`);
|
|
3283
3314
|
}
|
|
3315
|
+
const getSuffix = () => {
|
|
3316
|
+
if (truncationSuffix) {
|
|
3317
|
+
return truncationSuffix;
|
|
3318
|
+
}
|
|
3319
|
+
const fileNote = tmpFilePath ? ` Full content saved to ${tmpFilePath}.` : "";
|
|
3320
|
+
return `Content truncated (${reasons.join(", ")}).${fileNote}`;
|
|
3321
|
+
};
|
|
3284
3322
|
if (tokenCount > maxTokens) {
|
|
3285
3323
|
const headBudget = Math.floor(maxTokens / 2);
|
|
3286
3324
|
const tailBudget = maxTokens - headBudget;
|
|
@@ -3313,6 +3351,14 @@ const truncateToolResult = async (content, maxLines = 1e3, maxSizeKB = 50, maxTo
|
|
|
3313
3351
|
... ${omittedLines} lines omitted (${reasons.join(", ")}). Full content saved to ${tmpFilePath}.
|
|
3314
3352
|
|
|
3315
3353
|
`;
|
|
3354
|
+
if (truncationSuffix) {
|
|
3355
|
+
const suffixNotice = `
|
|
3356
|
+
|
|
3357
|
+
... ${omittedLines} lines omitted. ${truncationSuffix}
|
|
3358
|
+
|
|
3359
|
+
`;
|
|
3360
|
+
return headLines.join("\n") + suffixNotice + tailLines.join("\n");
|
|
3361
|
+
}
|
|
3316
3362
|
return headLines.join("\n") + truncationNotice + tailLines.join("\n");
|
|
3317
3363
|
}
|
|
3318
3364
|
let preview;
|
|
@@ -3324,7 +3370,7 @@ const truncateToolResult = async (content, maxLines = 1e3, maxSizeKB = 50, maxTo
|
|
|
3324
3370
|
preview = lines.slice(0, maxLines).join("\n");
|
|
3325
3371
|
}
|
|
3326
3372
|
return preview + `
|
|
3327
|
-
...
|
|
3373
|
+
... ${getSuffix()}`;
|
|
3328
3374
|
};
|
|
3329
3375
|
const NETWORK_ERROR_CODES = ["ECONNRESET", "EPIPE", "ETIMEDOUT", "ECONNREFUSED", "ENOTFOUND", "ENETUNREACH", "EAI_AGAIN"];
|
|
3330
3376
|
const UNDICI_ERROR_PREFIX = "UND_ERR_";
|
|
@@ -3744,10 +3790,17 @@ Do not use escape characters \\ in the string like \\n or \\" and others. Do not
|
|
|
3744
3790
|
}
|
|
3745
3791
|
const results = [];
|
|
3746
3792
|
const outputLineRegex = /^(.+?)([:-])(\d+)\2(.*)$/;
|
|
3793
|
+
let pendingBeforeContext = [];
|
|
3794
|
+
let afterContextBreak = false;
|
|
3747
3795
|
for (let rawLine of outputLines) {
|
|
3748
3796
|
if (rawLine.endsWith("\r")) {
|
|
3749
3797
|
rawLine = rawLine.slice(0, -1);
|
|
3750
3798
|
}
|
|
3799
|
+
if (rawLine === "--") {
|
|
3800
|
+
pendingBeforeContext = [];
|
|
3801
|
+
afterContextBreak = true;
|
|
3802
|
+
continue;
|
|
3803
|
+
}
|
|
3751
3804
|
const line = rawLine;
|
|
3752
3805
|
const match = outputLineRegex.exec(line);
|
|
3753
3806
|
if (!match) {
|
|
@@ -3761,18 +3814,28 @@ Do not use escape characters \\ in the string like \\n or \\" and others. Do not
|
|
|
3761
3814
|
const filePath = rawFilePath.startsWith("./") ? rawFilePath.slice(2) : rawFilePath;
|
|
3762
3815
|
const isMatch = separator === ":";
|
|
3763
3816
|
if (isMatch) {
|
|
3817
|
+
const context = pendingBeforeContext.length > 0 ? [...pendingBeforeContext, content] : void 0;
|
|
3764
3818
|
results.push({
|
|
3765
3819
|
filePath,
|
|
3766
3820
|
lineNumber: lineNum,
|
|
3767
|
-
lineContent: content
|
|
3821
|
+
lineContent: content,
|
|
3822
|
+
context
|
|
3768
3823
|
});
|
|
3824
|
+
pendingBeforeContext = [];
|
|
3825
|
+
afterContextBreak = false;
|
|
3769
3826
|
} else {
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3827
|
+
if (afterContextBreak) {
|
|
3828
|
+
pendingBeforeContext.push(content);
|
|
3829
|
+
} else {
|
|
3830
|
+
const lastResult = results[results.length - 1];
|
|
3831
|
+
if (lastResult) {
|
|
3832
|
+
if (!lastResult.context) {
|
|
3833
|
+
lastResult.context = [];
|
|
3834
|
+
}
|
|
3835
|
+
lastResult.context.push(content);
|
|
3836
|
+
} else {
|
|
3837
|
+
pendingBeforeContext.push(content);
|
|
3774
3838
|
}
|
|
3775
|
-
lastResult.context.push(content);
|
|
3776
3839
|
}
|
|
3777
3840
|
}
|
|
3778
3841
|
if (results.length >= maxResults) {
|
|
@@ -4462,15 +4525,15 @@ const createTasksToolset = (settings, task, profile, promptContext) => {
|
|
|
4462
4525
|
parentTaskId: zod.z.string().nullable().optional().describe(
|
|
4463
4526
|
"Optional ID of the parent task. If provided, the new task will be created as a subtask of the specified parent. When asSubtask is specified as true, this is not needed as parent ID is resolved automatically."
|
|
4464
4527
|
),
|
|
4465
|
-
|
|
4466
|
-
|
|
4528
|
+
autonomyMode: zod.z.enum(AutonomyMode).optional().describe(
|
|
4529
|
+
'The autonomy mode for the new task. "manual" requires approval for every tool and plan, "guided" (default) auto-approves tools but waits for plan approval from user, "autonomous" runs without interruption.'
|
|
4467
4530
|
),
|
|
4468
4531
|
worktree: zod.z.boolean().optional().default(false).describe("If true, the task will be created in worktree mode. Use only when explicitly requested by the user."),
|
|
4469
4532
|
executeAndWait: zod.z.boolean().optional().default(false).describe("If true, the task will be created and executed immediately and the tool will wait for it to complete before returning."),
|
|
4470
4533
|
executeInBackground: zod.z.boolean().optional().default(false).describe("If true, the task will be created and executed in the background.")
|
|
4471
4534
|
}),
|
|
4472
4535
|
execute: async (input, { toolCallId }) => {
|
|
4473
|
-
const { prompt, name, agentProfileId, modelId, mode = "agent", asSubtask = false,
|
|
4536
|
+
const { prompt, name, agentProfileId, modelId, mode = "agent", asSubtask = false, autonomyMode, worktree, executeAndWait, executeInBackground } = input;
|
|
4474
4537
|
const parentTaskId = asSubtask ? task.task.parentId || task.taskId : "parentTaskId" in input ? input.parentTaskId : void 0;
|
|
4475
4538
|
task.addToolMessage(toolCallId, TASKS_TOOL_GROUP_NAME, TASKS_TOOL_CREATE_TASK, input, void 0, void 0, promptContext);
|
|
4476
4539
|
const toolName = `${TASKS_TOOL_GROUP_NAME}${TOOL_GROUP_NAME_SEPARATOR}${TASKS_TOOL_CREATE_TASK}`;
|
|
@@ -4488,7 +4551,7 @@ Parent Task ID: ${parentTaskId || "none (top-level task)"}` : ""}`;
|
|
|
4488
4551
|
const newTask = await task.getProject().createNewTask({
|
|
4489
4552
|
parentId: parentTaskId || null,
|
|
4490
4553
|
name: name || "",
|
|
4491
|
-
|
|
4554
|
+
autonomyMode,
|
|
4492
4555
|
workingMode: worktree ? "worktree" : "local"
|
|
4493
4556
|
});
|
|
4494
4557
|
const updates = {};
|
|
@@ -4566,6 +4629,66 @@ Parent Task ID: ${parentTaskId || "none (top-level task)"}` : ""}`;
|
|
|
4566
4629
|
}
|
|
4567
4630
|
}
|
|
4568
4631
|
});
|
|
4632
|
+
const runPromptTool = ai.tool({
|
|
4633
|
+
description: TASKS_TOOL_DESCRIPTIONS[TASKS_TOOL_RUN_PROMPT],
|
|
4634
|
+
inputSchema: zod.z.object({
|
|
4635
|
+
taskId: zod.z.string().describe("The ID of the existing task to run the prompt on"),
|
|
4636
|
+
prompt: zod.z.string().describe("The prompt to run on the task"),
|
|
4637
|
+
mode: zod.z.string().optional().describe("Optional mode to use for the prompt. Use only when explicitly requested by the user."),
|
|
4638
|
+
executeAndWait: zod.z.boolean().optional().default(true).describe("If true (default), the tool will wait for the prompt to complete before returning. If false, the prompt will run in the background.")
|
|
4639
|
+
}),
|
|
4640
|
+
execute: async (input, { toolCallId }) => {
|
|
4641
|
+
const { taskId, prompt, mode, executeAndWait = true } = input;
|
|
4642
|
+
task.addToolMessage(
|
|
4643
|
+
toolCallId,
|
|
4644
|
+
TASKS_TOOL_GROUP_NAME,
|
|
4645
|
+
TASKS_TOOL_RUN_PROMPT,
|
|
4646
|
+
{ taskId, prompt, mode, executeAndWait },
|
|
4647
|
+
void 0,
|
|
4648
|
+
void 0,
|
|
4649
|
+
promptContext
|
|
4650
|
+
);
|
|
4651
|
+
const toolName = `${TASKS_TOOL_GROUP_NAME}${TOOL_GROUP_NAME_SEPARATOR}${TASKS_TOOL_RUN_PROMPT}`;
|
|
4652
|
+
const questionKey = toolName;
|
|
4653
|
+
const questionText = `Approve running prompt on task ${taskId}?`;
|
|
4654
|
+
const questionSubject = `Task ID: ${taskId}
|
|
4655
|
+
Prompt: ${prompt}${executeAndWait ? "\nWait for completion: true" : "\nRun in background: true"}`;
|
|
4656
|
+
const [isApproved, userInput] = await approvalManager.handleToolApproval(toolName, input, questionKey, questionText, questionSubject);
|
|
4657
|
+
if (!isApproved) {
|
|
4658
|
+
return `Running prompt on task denied by user. Reason: ${userInput}`;
|
|
4659
|
+
}
|
|
4660
|
+
try {
|
|
4661
|
+
const targetTask = task.getProject().getTask(taskId);
|
|
4662
|
+
if (!targetTask) {
|
|
4663
|
+
return `Task with ID ${taskId} not found`;
|
|
4664
|
+
}
|
|
4665
|
+
const effectiveMode = mode || targetTask.task.currentMode || "agent";
|
|
4666
|
+
const run = targetTask.runPrompt(prompt, effectiveMode, false);
|
|
4667
|
+
if (executeAndWait) {
|
|
4668
|
+
await run;
|
|
4669
|
+
}
|
|
4670
|
+
const taskState = targetTask.task.state;
|
|
4671
|
+
const contextMessages = await targetTask.getContextMessages();
|
|
4672
|
+
let resultMessage = executeAndWait ? "Prompt has been executed successfully" : "Prompt has been started in the background";
|
|
4673
|
+
if (executeAndWait && taskState === DefaultTaskState.Interrupted) {
|
|
4674
|
+
resultMessage = "Task has been interrupted";
|
|
4675
|
+
} else if (executeAndWait && taskState === DefaultTaskState.Delegated) {
|
|
4676
|
+
resultMessage = "Task has been delegated to a subagent";
|
|
4677
|
+
}
|
|
4678
|
+
return {
|
|
4679
|
+
taskId,
|
|
4680
|
+
result: resultMessage,
|
|
4681
|
+
state: taskState,
|
|
4682
|
+
...executeAndWait && contextMessages.length > 0 && {
|
|
4683
|
+
lastMessage: contextMessages[contextMessages.length - 1]
|
|
4684
|
+
}
|
|
4685
|
+
};
|
|
4686
|
+
} catch (error) {
|
|
4687
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4688
|
+
return `Error running prompt on task: ${errorMessage}`;
|
|
4689
|
+
}
|
|
4690
|
+
}
|
|
4691
|
+
});
|
|
4569
4692
|
const searchTaskTool = ai.tool({
|
|
4570
4693
|
description: TASKS_TOOL_DESCRIPTIONS[TASKS_TOOL_SEARCH_TASK],
|
|
4571
4694
|
inputSchema: zod.z.object({
|
|
@@ -4632,6 +4755,7 @@ Please, consider reporting an issue at https://github.com/hotovo/aider-desk/issu
|
|
|
4632
4755
|
[`${TASKS_TOOL_GROUP_NAME}${TOOL_GROUP_NAME_SEPARATOR}${TASKS_TOOL_GET_TASK_MESSAGE}`]: getTaskMessageTool,
|
|
4633
4756
|
[`${TASKS_TOOL_GROUP_NAME}${TOOL_GROUP_NAME_SEPARATOR}${TASKS_TOOL_CREATE_TASK}`]: createTaskTool,
|
|
4634
4757
|
[`${TASKS_TOOL_GROUP_NAME}${TOOL_GROUP_NAME_SEPARATOR}${TASKS_TOOL_DELETE_TASK}`]: deleteTaskTool,
|
|
4758
|
+
[`${TASKS_TOOL_GROUP_NAME}${TOOL_GROUP_NAME_SEPARATOR}${TASKS_TOOL_RUN_PROMPT}`]: runPromptTool,
|
|
4635
4759
|
[`${TASKS_TOOL_GROUP_NAME}${TOOL_GROUP_NAME_SEPARATOR}${TASKS_TOOL_SEARCH_TASK}`]: searchTaskTool
|
|
4636
4760
|
};
|
|
4637
4761
|
const filteredTools = {};
|
|
@@ -4865,7 +4989,7 @@ const createAiderToolset = (task, profile, promptContext) => {
|
|
|
4865
4989
|
}
|
|
4866
4990
|
task.addToolMessage(toolCallId, AIDER_TOOL_GROUP_NAME, AIDER_TOOL_RUN_PROMPT, { prompt }, void 0, void 0, aiderPromptContext);
|
|
4867
4991
|
const responses = await task.sendPromptToAider(prompt, aiderPromptContext, "code", [], void 0, {
|
|
4868
|
-
autoApprove: task.task.
|
|
4992
|
+
autoApprove: task.task.autonomyMode !== AutonomyMode.Manual,
|
|
4869
4993
|
denyCommands: true
|
|
4870
4994
|
});
|
|
4871
4995
|
task.addLogMessage("loading");
|
|
@@ -6071,7 +6195,8 @@ const addImportantReminders = async (task, profile, projectProfiles, userRequest
|
|
|
6071
6195
|
${subagents}`);
|
|
6072
6196
|
}
|
|
6073
6197
|
}
|
|
6074
|
-
|
|
6198
|
+
const shouldPresentPlan = task.task.autonomyMode !== AutonomyMode.Autonomous;
|
|
6199
|
+
if (shouldPresentPlan && !profile.isSubagent) {
|
|
6075
6200
|
reminders.push("Before making any complex changes, present the plan and wait for my approval.");
|
|
6076
6201
|
}
|
|
6077
6202
|
if (task.getTaskDir() !== task.getProjectDir()) {
|
|
@@ -6770,7 +6895,8 @@ ${fileList}`
|
|
|
6770
6895
|
};
|
|
6771
6896
|
})
|
|
6772
6897
|
] : prompt,
|
|
6773
|
-
promptContext
|
|
6898
|
+
promptContext,
|
|
6899
|
+
timestamp: Date.now()
|
|
6774
6900
|
} : null;
|
|
6775
6901
|
if (userRequestMessage) {
|
|
6776
6902
|
logger.info("User request message created:", {
|
|
@@ -7037,31 +7163,6 @@ ${fileList}`
|
|
|
7037
7163
|
return extensionResult2.optimizedMessages ?? optimized;
|
|
7038
7164
|
};
|
|
7039
7165
|
const optimizedMessages = await getOptimizedMessages();
|
|
7040
|
-
logger.info("Optimized messages for LLM:", {
|
|
7041
|
-
count: optimizedMessages.length,
|
|
7042
|
-
lastUserMessage: (() => {
|
|
7043
|
-
for (let i = optimizedMessages.length - 1; i >= 0; i--) {
|
|
7044
|
-
if (optimizedMessages[i].role === "user") {
|
|
7045
|
-
const msg = optimizedMessages[i];
|
|
7046
|
-
return {
|
|
7047
|
-
index: i,
|
|
7048
|
-
contentType: typeof msg.content,
|
|
7049
|
-
contentIsArray: Array.isArray(msg.content),
|
|
7050
|
-
contentPreview: typeof msg.content === "string" ? msg.content.substring(0, 200) : Array.isArray(msg.content) ? msg.content.map((p) => ({
|
|
7051
|
-
type: p.type,
|
|
7052
|
-
...p.type === "text" ? { textPreview: p.text?.substring(0, 100) } : {},
|
|
7053
|
-
...p.type === "image" ? {
|
|
7054
|
-
mediaType: p.mediaType,
|
|
7055
|
-
imageType: typeof p.image,
|
|
7056
|
-
imagePreview: typeof p.image === "string" ? p.image.substring(0, 80) : void 0
|
|
7057
|
-
} : {}
|
|
7058
|
-
})) : String(msg.content).substring(0, 200)
|
|
7059
|
-
};
|
|
7060
|
-
}
|
|
7061
|
-
}
|
|
7062
|
-
return null;
|
|
7063
|
-
})()
|
|
7064
|
-
});
|
|
7065
7166
|
return {
|
|
7066
7167
|
providerOptions,
|
|
7067
7168
|
model: ai.wrapLanguageModel({
|
|
@@ -7086,7 +7187,7 @@ ${fileList}`
|
|
|
7086
7187
|
let iterationCount = 0;
|
|
7087
7188
|
let retryCount = 0;
|
|
7088
7189
|
while (true) {
|
|
7089
|
-
logger.info(`Starting iteration ${iterationCount}
|
|
7190
|
+
logger.info(`Starting iteration ${iterationCount}`, { task: task.taskId });
|
|
7090
7191
|
iterationCount++;
|
|
7091
7192
|
if (profile.maxIterations > 0 && iterationCount > profile.maxIterations) {
|
|
7092
7193
|
logger.warn(`Max iterations (${profile.maxIterations}) reached. Stopping agent.`);
|
|
@@ -7783,14 +7884,16 @@ ${fileList}`
|
|
|
7783
7884
|
...message,
|
|
7784
7885
|
id: currentResponseId,
|
|
7785
7886
|
usageReport,
|
|
7786
|
-
promptContext
|
|
7887
|
+
promptContext,
|
|
7888
|
+
timestamp: Date.now()
|
|
7787
7889
|
});
|
|
7788
7890
|
} else if (message.role === "tool") {
|
|
7789
7891
|
messages.push({
|
|
7790
7892
|
...message,
|
|
7791
7893
|
// @ts-expect-error the id is there
|
|
7792
7894
|
id: message.id || uuid.v4(),
|
|
7793
|
-
promptContext
|
|
7895
|
+
promptContext,
|
|
7896
|
+
timestamp: Date.now()
|
|
7794
7897
|
});
|
|
7795
7898
|
}
|
|
7796
7899
|
});
|
|
@@ -7903,6 +8006,52 @@ ${extractTextContent(userRequestMessage.content)}`;
|
|
|
7903
8006
|
return true;
|
|
7904
8007
|
}
|
|
7905
8008
|
}
|
|
8009
|
+
let isDockerCache;
|
|
8010
|
+
const isDocker = () => {
|
|
8011
|
+
if (isDockerCache !== void 0) {
|
|
8012
|
+
return isDockerCache;
|
|
8013
|
+
}
|
|
8014
|
+
try {
|
|
8015
|
+
isDockerCache = fs__namespace.existsSync("/.dockerenv") || fs__namespace.existsSync("/run/.containerenv");
|
|
8016
|
+
} catch {
|
|
8017
|
+
isDockerCache = false;
|
|
8018
|
+
}
|
|
8019
|
+
return isDockerCache;
|
|
8020
|
+
};
|
|
8021
|
+
const isNetworkDrive = (drivePath) => {
|
|
8022
|
+
try {
|
|
8023
|
+
const driveLetter = drivePath.charAt(0).toUpperCase();
|
|
8024
|
+
const output = child_process.execSync(`net use ${driveLetter}:`, {
|
|
8025
|
+
encoding: "utf8",
|
|
8026
|
+
timeout: 5e3,
|
|
8027
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
8028
|
+
});
|
|
8029
|
+
return output.includes("\\\\") || output.includes("//");
|
|
8030
|
+
} catch {
|
|
8031
|
+
return false;
|
|
8032
|
+
}
|
|
8033
|
+
};
|
|
8034
|
+
const shouldUsePolling = (watchPath, mode = FileWatchMode.Auto) => {
|
|
8035
|
+
if (mode === FileWatchMode.Polling) {
|
|
8036
|
+
return true;
|
|
8037
|
+
}
|
|
8038
|
+
if (mode === FileWatchMode.Native) {
|
|
8039
|
+
return false;
|
|
8040
|
+
}
|
|
8041
|
+
if (isDocker()) {
|
|
8042
|
+
logger.debug(`[FileWatch] Docker environment detected, using polling for ${watchPath}`);
|
|
8043
|
+
return true;
|
|
8044
|
+
}
|
|
8045
|
+
if (process.platform === "win32") {
|
|
8046
|
+
const isUncPath = watchPath.startsWith("\\\\") || watchPath.startsWith("//");
|
|
8047
|
+
const isNetworkLetterDrive = /^[A-Za-z]:/.test(watchPath) && isNetworkDrive(watchPath);
|
|
8048
|
+
if (isUncPath || isNetworkLetterDrive) {
|
|
8049
|
+
logger.debug(`[FileWatch] Network path detected (${watchPath}), using polling`);
|
|
8050
|
+
return true;
|
|
8051
|
+
}
|
|
8052
|
+
}
|
|
8053
|
+
return false;
|
|
8054
|
+
};
|
|
7906
8055
|
const getGlobalAgentsDir = () => path__namespace.join(os.homedir(), AIDER_DESK_AGENTS_DIR);
|
|
7907
8056
|
const getProjectAgentsDir = (projectDir) => path__namespace.join(projectDir, AIDER_DESK_AGENTS_DIR);
|
|
7908
8057
|
const getAgentsDirForProfile = (profile) => profile.projectDir ? getProjectAgentsDir(profile.projectDir) : getGlobalAgentsDir();
|
|
@@ -7935,9 +8084,10 @@ const getAllRuleFilesForProfile = async (profile, dirName) => {
|
|
|
7935
8084
|
return ruleFiles;
|
|
7936
8085
|
};
|
|
7937
8086
|
class AgentProfileManager {
|
|
7938
|
-
constructor(eventManager, extensionManager) {
|
|
8087
|
+
constructor(eventManager, extensionManager, store) {
|
|
7939
8088
|
this.eventManager = eventManager;
|
|
7940
8089
|
this.extensionManager = extensionManager;
|
|
8090
|
+
this.store = store;
|
|
7941
8091
|
this.extensionsChangeListener = () => {
|
|
7942
8092
|
this.sendAgentProfilesUpdated();
|
|
7943
8093
|
};
|
|
@@ -8052,12 +8202,12 @@ class AgentProfileManager {
|
|
|
8052
8202
|
}
|
|
8053
8203
|
const watcher = chokidar.watch(agentsDir, {
|
|
8054
8204
|
persistent: true,
|
|
8055
|
-
usePolling:
|
|
8205
|
+
usePolling: shouldUsePolling(agentsDir, this.store.getSettings().fileWatchMode),
|
|
8056
8206
|
ignoreInitial: true
|
|
8057
8207
|
});
|
|
8058
8208
|
const rulesWatcher = chokidar.watch(path__namespace.join(agentsDir, "*", AIDER_DESK_RULES_DIR), {
|
|
8059
8209
|
persistent: true,
|
|
8060
|
-
usePolling:
|
|
8210
|
+
usePolling: shouldUsePolling(agentsDir, this.store.getSettings().fileWatchMode),
|
|
8061
8211
|
ignoreInitial: true
|
|
8062
8212
|
});
|
|
8063
8213
|
const reloadFunction = () => this.debounceReloadProfiles(agentsDir);
|
|
@@ -8455,6 +8605,22 @@ class AgentProfileManager {
|
|
|
8455
8605
|
this.directoryWatchers.clear();
|
|
8456
8606
|
this.profiles.clear();
|
|
8457
8607
|
}
|
|
8608
|
+
async settingsChanged(oldSettings, newSettings) {
|
|
8609
|
+
if (oldSettings.fileWatchMode === newSettings.fileWatchMode) {
|
|
8610
|
+
return;
|
|
8611
|
+
}
|
|
8612
|
+
const watchedDirs = Array.from(this.directoryWatchers.keys());
|
|
8613
|
+
for (const watcher of this.directoryWatchers.values()) {
|
|
8614
|
+
await watcher.close();
|
|
8615
|
+
}
|
|
8616
|
+
this.directoryWatchers.clear();
|
|
8617
|
+
for (const dir of watchedDirs) {
|
|
8618
|
+
if (dir.endsWith("-rules")) {
|
|
8619
|
+
continue;
|
|
8620
|
+
}
|
|
8621
|
+
await this.setupWatcherForDirectory(dir);
|
|
8622
|
+
}
|
|
8623
|
+
}
|
|
8458
8624
|
getDefaultAgentProfileId() {
|
|
8459
8625
|
for (const defaultProfile of DEFAULT_AGENT_PROFILES) {
|
|
8460
8626
|
if (this.profiles.has(defaultProfile.id)) {
|
|
@@ -9037,7 +9203,8 @@ const InitProjectRulesFileSchema = zod.z.object({
|
|
|
9037
9203
|
const CreateNewTaskSchema = zod.z.object({
|
|
9038
9204
|
projectDir: zod.z.string().min(1, "Project directory is required"),
|
|
9039
9205
|
parentId: zod.z.string().nullable().optional(),
|
|
9040
|
-
name: zod.z.string().optional()
|
|
9206
|
+
name: zod.z.string().optional(),
|
|
9207
|
+
activate: zod.z.boolean().optional()
|
|
9041
9208
|
});
|
|
9042
9209
|
const UpdateTaskSchema = zod.z.object({
|
|
9043
9210
|
projectDir: zod.z.string().min(1, "Project directory is required"),
|
|
@@ -9335,8 +9502,8 @@ class ProjectApi extends BaseApi {
|
|
|
9335
9502
|
if (!parsed) {
|
|
9336
9503
|
return;
|
|
9337
9504
|
}
|
|
9338
|
-
const { projectDir, parentId, name } = parsed;
|
|
9339
|
-
const params = { parentId, name };
|
|
9505
|
+
const { projectDir, parentId, name, activate } = parsed;
|
|
9506
|
+
const params = { parentId, name, activate };
|
|
9340
9507
|
const task = await this.eventsHandler.createNewTask(projectDir, params);
|
|
9341
9508
|
res.status(200).json(task);
|
|
9342
9509
|
})
|
|
@@ -11402,10 +11569,11 @@ class ShellCommandError extends Error {
|
|
|
11402
11569
|
}
|
|
11403
11570
|
const execAsync$1 = util.promisify(child_process.exec);
|
|
11404
11571
|
class CustomCommandManager {
|
|
11405
|
-
constructor(project, eventManager, extensionManager) {
|
|
11572
|
+
constructor(project, eventManager, extensionManager, store) {
|
|
11406
11573
|
this.project = project;
|
|
11407
11574
|
this.eventManager = eventManager;
|
|
11408
11575
|
this.extensionManager = extensionManager;
|
|
11576
|
+
this.store = store;
|
|
11409
11577
|
}
|
|
11410
11578
|
commands = /* @__PURE__ */ new Map();
|
|
11411
11579
|
watchers = [];
|
|
@@ -11445,7 +11613,7 @@ class CustomCommandManager {
|
|
|
11445
11613
|
}
|
|
11446
11614
|
const watcher = chokidar.watch(commandsDir, {
|
|
11447
11615
|
persistent: true,
|
|
11448
|
-
usePolling:
|
|
11616
|
+
usePolling: shouldUsePolling(commandsDir, this.store.getSettings().fileWatchMode),
|
|
11449
11617
|
ignoreInitial: true
|
|
11450
11618
|
});
|
|
11451
11619
|
watcher.on("add", async () => {
|
|
@@ -11503,7 +11671,7 @@ class CustomCommandManager {
|
|
|
11503
11671
|
const args = Array.isArray(parsed.arguments) ? parsed.arguments : [];
|
|
11504
11672
|
const template = parsed.__content?.trim() || "";
|
|
11505
11673
|
const includeContext = typeof parsed.includeContext === "boolean" ? parsed.includeContext : true;
|
|
11506
|
-
const
|
|
11674
|
+
const autonomyMode = typeof parsed.autonomyMode === "string" && ["manual", "guided", "autonomous"].includes(parsed.autonomyMode) ? parsed.autonomyMode : void 0;
|
|
11507
11675
|
const skills = typeof parsed.skills === "string" && parsed.skills.trim() ? parsed.skills.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
|
|
11508
11676
|
commands.set(name, {
|
|
11509
11677
|
name,
|
|
@@ -11511,7 +11679,7 @@ class CustomCommandManager {
|
|
|
11511
11679
|
arguments: args,
|
|
11512
11680
|
template,
|
|
11513
11681
|
includeContext,
|
|
11514
|
-
|
|
11682
|
+
autonomyMode,
|
|
11515
11683
|
skills
|
|
11516
11684
|
});
|
|
11517
11685
|
} catch (err) {
|
|
@@ -11644,6 +11812,14 @@ class CustomCommandManager {
|
|
|
11644
11812
|
this.watchers.forEach((watcher) => watcher.close());
|
|
11645
11813
|
this.watchers = [];
|
|
11646
11814
|
}
|
|
11815
|
+
async settingsChanged(oldSettings, newSettings) {
|
|
11816
|
+
if (oldSettings.fileWatchMode === newSettings.fileWatchMode) {
|
|
11817
|
+
return;
|
|
11818
|
+
}
|
|
11819
|
+
this.watchers.forEach((watcher) => watcher.close());
|
|
11820
|
+
this.watchers = [];
|
|
11821
|
+
await this.setupFileWatchers();
|
|
11822
|
+
}
|
|
11647
11823
|
}
|
|
11648
11824
|
const migrateContextMessage = (message) => {
|
|
11649
11825
|
if (Array.isArray(message.content)) {
|
|
@@ -11778,7 +11954,8 @@ class ContextManager {
|
|
|
11778
11954
|
id: uuid.v4(),
|
|
11779
11955
|
role: roleOrMessage,
|
|
11780
11956
|
content: content || "",
|
|
11781
|
-
usageReport
|
|
11957
|
+
usageReport,
|
|
11958
|
+
timestamp: Date.now()
|
|
11782
11959
|
};
|
|
11783
11960
|
} else {
|
|
11784
11961
|
message = roleOrMessage;
|
|
@@ -12444,7 +12621,8 @@ ${JSON.stringify(part.output.value)}`
|
|
|
12444
12621
|
commitMessage: response.commitMessage,
|
|
12445
12622
|
diff: response.diff,
|
|
12446
12623
|
usageReport: response.usageReport,
|
|
12447
|
-
promptContext: message.promptContext
|
|
12624
|
+
promptContext: message.promptContext,
|
|
12625
|
+
timestamp: message.timestamp
|
|
12448
12626
|
};
|
|
12449
12627
|
messagesData.push(responseCompletedData);
|
|
12450
12628
|
});
|
|
@@ -12483,7 +12661,8 @@ ${JSON.stringify(part.output.value)}`
|
|
|
12483
12661
|
baseDir: this.task.getProjectDir(),
|
|
12484
12662
|
taskId: this.taskId,
|
|
12485
12663
|
usageReport: subMessage.usageReport,
|
|
12486
|
-
promptContext: subMessage.promptContext
|
|
12664
|
+
promptContext: subMessage.promptContext,
|
|
12665
|
+
timestamp: subMessage.timestamp
|
|
12487
12666
|
};
|
|
12488
12667
|
messagesData.push(responseCompletedData);
|
|
12489
12668
|
}
|
|
@@ -12499,7 +12678,8 @@ ${JSON.stringify(part.output.value)}`
|
|
|
12499
12678
|
toolName: subToolName,
|
|
12500
12679
|
args: subPart.input,
|
|
12501
12680
|
usageReport: void 0,
|
|
12502
|
-
promptContext: subMessage.promptContext
|
|
12681
|
+
promptContext: subMessage.promptContext,
|
|
12682
|
+
timestamp: subMessage.timestamp
|
|
12503
12683
|
};
|
|
12504
12684
|
messagesData.push(toolData);
|
|
12505
12685
|
}
|
|
@@ -12513,7 +12693,8 @@ ${JSON.stringify(part.output.value)}`
|
|
|
12513
12693
|
baseDir: this.task.getProjectDir(),
|
|
12514
12694
|
taskId: this.taskId,
|
|
12515
12695
|
usageReport: subMessage.usageReport,
|
|
12516
|
-
promptContext: subMessage.promptContext
|
|
12696
|
+
promptContext: subMessage.promptContext,
|
|
12697
|
+
timestamp: subMessage.timestamp
|
|
12517
12698
|
};
|
|
12518
12699
|
messagesData.push(responseCompletedData);
|
|
12519
12700
|
}
|
|
@@ -12556,7 +12737,8 @@ ${JSON.stringify(part.output.value)}`
|
|
|
12556
12737
|
commitMessage: message.commitMessage,
|
|
12557
12738
|
diff: message.diff,
|
|
12558
12739
|
usageReport: message.usageReport,
|
|
12559
|
-
promptContext: message.promptContext
|
|
12740
|
+
promptContext: message.promptContext,
|
|
12741
|
+
timestamp: message.timestamp
|
|
12560
12742
|
};
|
|
12561
12743
|
messagesData.push(responseCompletedData);
|
|
12562
12744
|
reasoning = "";
|
|
@@ -12585,7 +12767,8 @@ ${JSON.stringify(part.output.value)}`
|
|
|
12585
12767
|
toolName,
|
|
12586
12768
|
args: toolCall.input,
|
|
12587
12769
|
usageReport: message.usageReport,
|
|
12588
|
-
promptContext: message.promptContext
|
|
12770
|
+
promptContext: message.promptContext,
|
|
12771
|
+
timestamp: message.timestamp
|
|
12589
12772
|
};
|
|
12590
12773
|
messagesData.push(toolData);
|
|
12591
12774
|
} else if (part.type === "tool-result") {
|
|
@@ -12619,7 +12802,8 @@ ${JSON.stringify(part.output.value)}`
|
|
|
12619
12802
|
taskId: this.taskId,
|
|
12620
12803
|
reflectedMessage: message.reflectedMessage,
|
|
12621
12804
|
usageReport: message.usageReport,
|
|
12622
|
-
promptContext: message.promptContext
|
|
12805
|
+
promptContext: message.promptContext,
|
|
12806
|
+
timestamp: message.timestamp
|
|
12623
12807
|
};
|
|
12624
12808
|
messagesData.push(responseCompletedData);
|
|
12625
12809
|
}
|
|
@@ -12637,7 +12821,8 @@ ${JSON.stringify(part.output.value)}`
|
|
|
12637
12821
|
taskId: this.taskId,
|
|
12638
12822
|
content,
|
|
12639
12823
|
images: images && images.length > 0 ? images : void 0,
|
|
12640
|
-
promptContext: message.promptContext
|
|
12824
|
+
promptContext: message.promptContext,
|
|
12825
|
+
timestamp: message.timestamp
|
|
12641
12826
|
};
|
|
12642
12827
|
messagesData.push(userMessageData);
|
|
12643
12828
|
} else if (message.role === "tool" && Array.isArray(message.content)) {
|
|
@@ -13395,7 +13580,16 @@ class SkillManager {
|
|
|
13395
13580
|
loadSkillsFromDir(projectSkillsDir, "project"),
|
|
13396
13581
|
loadSkillsFromDir(AIDER_DESK_BUILTIN_SKILLS_DIR, "builtin")
|
|
13397
13582
|
]);
|
|
13398
|
-
|
|
13583
|
+
const allSkills = [...extensionSkills, ...projectSkills, ...globalSkills, ...builtinSkills];
|
|
13584
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13585
|
+
const deduped = [];
|
|
13586
|
+
for (const skill of allSkills) {
|
|
13587
|
+
if (!seen.has(skill.name)) {
|
|
13588
|
+
seen.add(skill.name);
|
|
13589
|
+
deduped.push(skill);
|
|
13590
|
+
}
|
|
13591
|
+
}
|
|
13592
|
+
return deduped;
|
|
13399
13593
|
}
|
|
13400
13594
|
async getSkills(contextMessages) {
|
|
13401
13595
|
const skills = await this.loadAllSkills();
|
|
@@ -15327,10 +15521,9 @@ const getProtectedStartIndex = (messages, protectedMessageCount) => {
|
|
|
15327
15521
|
return Math.max(0, messages.length - protectedMessageCount);
|
|
15328
15522
|
};
|
|
15329
15523
|
const mergeConsecutiveAssistantMessages = (messages) => {
|
|
15330
|
-
|
|
15331
|
-
|
|
15332
|
-
const
|
|
15333
|
-
const next = result[i + 1];
|
|
15524
|
+
for (let i = messages.length - 2; i >= 0; i--) {
|
|
15525
|
+
const current = messages[i];
|
|
15526
|
+
const next = messages[i + 1];
|
|
15334
15527
|
if (current.role !== "assistant" || next.role !== "assistant") {
|
|
15335
15528
|
continue;
|
|
15336
15529
|
}
|
|
@@ -15343,35 +15536,77 @@ const mergeConsecutiveAssistantMessages = (messages) => {
|
|
|
15343
15536
|
const nextTextParts = Array.isArray(next.content) ? next.content.filter((p) => p.type === "text") : [];
|
|
15344
15537
|
const mergedText = [...currentTextParts, ...nextTextParts].map((p) => p.text).filter(Boolean).join("\n\n");
|
|
15345
15538
|
current.content = mergedText ? [{ type: "text", text: mergedText }] : [];
|
|
15346
|
-
|
|
15539
|
+
messages.splice(i + 1, 1);
|
|
15347
15540
|
}
|
|
15348
|
-
return
|
|
15541
|
+
return messages.filter((msg) => {
|
|
15349
15542
|
if (msg.role === "assistant" && Array.isArray(msg.content) && msg.content.length === 0) {
|
|
15350
15543
|
return false;
|
|
15351
15544
|
}
|
|
15352
15545
|
return true;
|
|
15353
15546
|
});
|
|
15354
15547
|
};
|
|
15355
|
-
const
|
|
15548
|
+
const truncateNonPowerToolResults = async (messages, protectedMessageCount = 10) => {
|
|
15549
|
+
const protectedStart = getProtectedStartIndex(messages, protectedMessageCount);
|
|
15550
|
+
for (let i = 0; i < protectedStart; i++) {
|
|
15551
|
+
const msg = messages[i];
|
|
15552
|
+
if (msg.role !== "tool") {
|
|
15553
|
+
continue;
|
|
15554
|
+
}
|
|
15555
|
+
for (let j = 0; j < msg.content.length; j++) {
|
|
15556
|
+
const part = msg.content[j];
|
|
15557
|
+
if (part.type !== "tool-result") {
|
|
15558
|
+
continue;
|
|
15559
|
+
}
|
|
15560
|
+
const [serverName] = extractServerNameToolName(part.toolName);
|
|
15561
|
+
if (isPowerTool(serverName)) {
|
|
15562
|
+
continue;
|
|
15563
|
+
}
|
|
15564
|
+
if (part.output.type !== "text" && part.output.type !== "error-text") {
|
|
15565
|
+
continue;
|
|
15566
|
+
}
|
|
15567
|
+
const outputText = part.output.value;
|
|
15568
|
+
if (!outputText) {
|
|
15569
|
+
continue;
|
|
15570
|
+
}
|
|
15571
|
+
const truncated = await truncateToolResult(
|
|
15572
|
+
outputText,
|
|
15573
|
+
20,
|
|
15574
|
+
2,
|
|
15575
|
+
2e3,
|
|
15576
|
+
false,
|
|
15577
|
+
"Output truncated due to compaction, re-execute the tool if full output is needed."
|
|
15578
|
+
);
|
|
15579
|
+
if (truncated !== outputText) {
|
|
15580
|
+
part.output = {
|
|
15581
|
+
type: part.output.type,
|
|
15582
|
+
value: truncated
|
|
15583
|
+
};
|
|
15584
|
+
}
|
|
15585
|
+
}
|
|
15586
|
+
}
|
|
15587
|
+
return messages;
|
|
15588
|
+
};
|
|
15589
|
+
const smartCompactMessages = async (messages, protectedMessageCount = 10) => {
|
|
15356
15590
|
let result = cloneMessages(messages);
|
|
15357
15591
|
result = removeErroredTools(result, protectedMessageCount);
|
|
15358
15592
|
result = collapseFileEdits(result, protectedMessageCount);
|
|
15359
15593
|
result = removeStaleFileReads(result, protectedMessageCount);
|
|
15594
|
+
result = compactFileReads(result, protectedMessageCount);
|
|
15360
15595
|
result = removeObsoleteSearches(result, protectedMessageCount);
|
|
15361
15596
|
result = compactSemanticSearches(result, protectedMessageCount);
|
|
15362
15597
|
result = deduplicateBash(result, protectedMessageCount);
|
|
15363
15598
|
result = redactFetchOutputs(result, protectedMessageCount);
|
|
15599
|
+
result = await truncateNonPowerToolResults(result, protectedMessageCount);
|
|
15364
15600
|
result = mergeConsecutiveAssistantMessages(result);
|
|
15365
15601
|
return result;
|
|
15366
15602
|
};
|
|
15367
15603
|
const removeErroredTools = (messages, protectedMessageCount = 10) => {
|
|
15368
|
-
const
|
|
15369
|
-
const protectedStart = getProtectedStartIndex(result, protectedMessageCount);
|
|
15604
|
+
const protectedStart = getProtectedStartIndex(messages, protectedMessageCount);
|
|
15370
15605
|
for (let i = protectedStart - 1; i >= 0; i--) {
|
|
15371
|
-
if (i >=
|
|
15606
|
+
if (i >= messages.length) {
|
|
15372
15607
|
continue;
|
|
15373
15608
|
}
|
|
15374
|
-
const msg =
|
|
15609
|
+
const msg = messages[i];
|
|
15375
15610
|
if (msg.role !== "tool") {
|
|
15376
15611
|
continue;
|
|
15377
15612
|
}
|
|
@@ -15381,22 +15616,21 @@ const removeErroredTools = (messages, protectedMessageCount = 10) => {
|
|
|
15381
15616
|
continue;
|
|
15382
15617
|
}
|
|
15383
15618
|
if (isErrorResult(info.output) || isNoOpResult(info.output)) {
|
|
15384
|
-
removeToolCallFromAssistant(
|
|
15385
|
-
removeToolResult(
|
|
15619
|
+
removeToolCallFromAssistant(messages, info.toolCallId);
|
|
15620
|
+
removeToolResult(messages, info.toolCallId);
|
|
15386
15621
|
}
|
|
15387
15622
|
}
|
|
15388
15623
|
}
|
|
15389
|
-
return
|
|
15624
|
+
return messages;
|
|
15390
15625
|
};
|
|
15391
15626
|
const collapseFileEdits = (messages, protectedMessageCount = 10) => {
|
|
15392
|
-
const
|
|
15393
|
-
const protectedStart = getProtectedStartIndex(result, protectedMessageCount);
|
|
15627
|
+
const protectedStart = getProtectedStartIndex(messages, protectedMessageCount);
|
|
15394
15628
|
const fileEditGroups = /* @__PURE__ */ new Map();
|
|
15395
15629
|
for (let i = 0; i < protectedStart; i++) {
|
|
15396
|
-
if (i >=
|
|
15630
|
+
if (i >= messages.length) {
|
|
15397
15631
|
break;
|
|
15398
15632
|
}
|
|
15399
|
-
const msg =
|
|
15633
|
+
const msg = messages[i];
|
|
15400
15634
|
if (msg.role !== "tool") {
|
|
15401
15635
|
continue;
|
|
15402
15636
|
}
|
|
@@ -15411,7 +15645,7 @@ const collapseFileEdits = (messages, protectedMessageCount = 10) => {
|
|
|
15411
15645
|
if (toolName !== POWER_TOOL_FILE_EDIT && toolName !== POWER_TOOL_FILE_WRITE) {
|
|
15412
15646
|
continue;
|
|
15413
15647
|
}
|
|
15414
|
-
const callInfo = findAssistantToolCall(
|
|
15648
|
+
const callInfo = findAssistantToolCall(messages, part.toolCallId);
|
|
15415
15649
|
if (!callInfo) {
|
|
15416
15650
|
continue;
|
|
15417
15651
|
}
|
|
@@ -15443,22 +15677,21 @@ const collapseFileEdits = (messages, protectedMessageCount = 10) => {
|
|
|
15443
15677
|
}
|
|
15444
15678
|
]
|
|
15445
15679
|
};
|
|
15446
|
-
const assistantIndex =
|
|
15680
|
+
const assistantIndex = messages.findIndex((m) => m.id === lastEdit.assistantMessageId);
|
|
15447
15681
|
const insertIndex = assistantIndex !== -1 ? assistantIndex + 1 : 0;
|
|
15448
|
-
|
|
15682
|
+
messages.splice(insertIndex, 0, syntheticMessage);
|
|
15449
15683
|
for (const edit of edits) {
|
|
15450
|
-
removeToolCallFromAssistant(
|
|
15451
|
-
removeToolResult(
|
|
15684
|
+
removeToolCallFromAssistant(messages, edit.toolCallId);
|
|
15685
|
+
removeToolResult(messages, edit.toolCallId);
|
|
15452
15686
|
}
|
|
15453
15687
|
}
|
|
15454
|
-
return
|
|
15688
|
+
return messages;
|
|
15455
15689
|
};
|
|
15456
15690
|
const removeStaleFileReads = (messages, protectedMessageCount = 10) => {
|
|
15457
|
-
const
|
|
15458
|
-
const protectedStart = getProtectedStartIndex(result, protectedMessageCount);
|
|
15691
|
+
const protectedStart = getProtectedStartIndex(messages, protectedMessageCount);
|
|
15459
15692
|
const editedFilePaths = /* @__PURE__ */ new Set();
|
|
15460
|
-
for (let i = 0; i <
|
|
15461
|
-
const msg =
|
|
15693
|
+
for (let i = 0; i < messages.length; i++) {
|
|
15694
|
+
const msg = messages[i];
|
|
15462
15695
|
if (msg.role === "assistant" && Array.isArray(msg.content)) {
|
|
15463
15696
|
for (const part of msg.content) {
|
|
15464
15697
|
if (part.type === "text") {
|
|
@@ -15484,7 +15717,7 @@ const removeStaleFileReads = (messages, protectedMessageCount = 10) => {
|
|
|
15484
15717
|
if (toolName !== POWER_TOOL_FILE_EDIT && toolName !== POWER_TOOL_FILE_WRITE) {
|
|
15485
15718
|
continue;
|
|
15486
15719
|
}
|
|
15487
|
-
const callInfo = findAssistantToolCall(
|
|
15720
|
+
const callInfo = findAssistantToolCall(messages, part.toolCallId);
|
|
15488
15721
|
if (callInfo) {
|
|
15489
15722
|
const filePath = extractFilePath(callInfo.input);
|
|
15490
15723
|
if (filePath) {
|
|
@@ -15494,8 +15727,8 @@ const removeStaleFileReads = (messages, protectedMessageCount = 10) => {
|
|
|
15494
15727
|
}
|
|
15495
15728
|
}
|
|
15496
15729
|
const protectedReadFilePaths = /* @__PURE__ */ new Set();
|
|
15497
|
-
for (let i = protectedStart; i <
|
|
15498
|
-
const msg =
|
|
15730
|
+
for (let i = protectedStart; i < messages.length; i++) {
|
|
15731
|
+
const msg = messages[i];
|
|
15499
15732
|
if (msg.role !== "tool") {
|
|
15500
15733
|
continue;
|
|
15501
15734
|
}
|
|
@@ -15507,7 +15740,7 @@ const removeStaleFileReads = (messages, protectedMessageCount = 10) => {
|
|
|
15507
15740
|
if (!isPowerTool(serverName) || toolName !== POWER_TOOL_FILE_READ) {
|
|
15508
15741
|
continue;
|
|
15509
15742
|
}
|
|
15510
|
-
const callInfo = findAssistantToolCall(
|
|
15743
|
+
const callInfo = findAssistantToolCall(messages, part.toolCallId);
|
|
15511
15744
|
if (callInfo) {
|
|
15512
15745
|
const filePath = extractFilePath(callInfo.input);
|
|
15513
15746
|
if (filePath) {
|
|
@@ -15518,10 +15751,10 @@ const removeStaleFileReads = (messages, protectedMessageCount = 10) => {
|
|
|
15518
15751
|
}
|
|
15519
15752
|
const readFileGroups = /* @__PURE__ */ new Map();
|
|
15520
15753
|
for (let i = protectedStart - 1; i >= 0; i--) {
|
|
15521
|
-
if (i >=
|
|
15754
|
+
if (i >= messages.length) {
|
|
15522
15755
|
continue;
|
|
15523
15756
|
}
|
|
15524
|
-
const msg =
|
|
15757
|
+
const msg = messages[i];
|
|
15525
15758
|
if (msg.role !== "tool") {
|
|
15526
15759
|
continue;
|
|
15527
15760
|
}
|
|
@@ -15533,7 +15766,7 @@ const removeStaleFileReads = (messages, protectedMessageCount = 10) => {
|
|
|
15533
15766
|
if (!isPowerTool(serverName) || toolName !== POWER_TOOL_FILE_READ) {
|
|
15534
15767
|
continue;
|
|
15535
15768
|
}
|
|
15536
|
-
const callInfo = findAssistantToolCall(
|
|
15769
|
+
const callInfo = findAssistantToolCall(messages, part.toolCallId);
|
|
15537
15770
|
if (!callInfo) {
|
|
15538
15771
|
continue;
|
|
15539
15772
|
}
|
|
@@ -15542,8 +15775,8 @@ const removeStaleFileReads = (messages, protectedMessageCount = 10) => {
|
|
|
15542
15775
|
continue;
|
|
15543
15776
|
}
|
|
15544
15777
|
if (editedFilePaths.has(filePath) || protectedReadFilePaths.has(filePath)) {
|
|
15545
|
-
removeToolCallFromAssistant(
|
|
15546
|
-
removeToolResult(
|
|
15778
|
+
removeToolCallFromAssistant(messages, part.toolCallId);
|
|
15779
|
+
removeToolResult(messages, part.toolCallId);
|
|
15547
15780
|
continue;
|
|
15548
15781
|
}
|
|
15549
15782
|
if (!readFileGroups.has(filePath)) {
|
|
@@ -15561,18 +15794,50 @@ const removeStaleFileReads = (messages, protectedMessageCount = 10) => {
|
|
|
15561
15794
|
}
|
|
15562
15795
|
const toRemove = reads.slice(0, -1);
|
|
15563
15796
|
for (const read of toRemove) {
|
|
15564
|
-
removeToolCallFromAssistant(
|
|
15565
|
-
removeToolResult(
|
|
15797
|
+
removeToolCallFromAssistant(messages, read.toolCallId);
|
|
15798
|
+
removeToolResult(messages, read.toolCallId);
|
|
15566
15799
|
}
|
|
15567
15800
|
}
|
|
15568
|
-
return
|
|
15801
|
+
return messages;
|
|
15802
|
+
};
|
|
15803
|
+
const compactFileReads = (messages, protectedMessageCount = 10) => {
|
|
15804
|
+
const protectedStart = getProtectedStartIndex(messages, protectedMessageCount);
|
|
15805
|
+
for (let i = 0; i < protectedStart; i++) {
|
|
15806
|
+
if (i >= messages.length) {
|
|
15807
|
+
break;
|
|
15808
|
+
}
|
|
15809
|
+
const msg = messages[i];
|
|
15810
|
+
if (msg.role !== "tool") {
|
|
15811
|
+
continue;
|
|
15812
|
+
}
|
|
15813
|
+
for (let j = 0; j < msg.content.length; j++) {
|
|
15814
|
+
const part = msg.content[j];
|
|
15815
|
+
if (part.type !== "tool-result") {
|
|
15816
|
+
continue;
|
|
15817
|
+
}
|
|
15818
|
+
const [serverName, toolName] = extractServerNameToolName(part.toolName);
|
|
15819
|
+
if (!isPowerTool(serverName) || toolName !== POWER_TOOL_FILE_READ) {
|
|
15820
|
+
continue;
|
|
15821
|
+
}
|
|
15822
|
+
if (part.output.type !== "text") {
|
|
15823
|
+
continue;
|
|
15824
|
+
}
|
|
15825
|
+
const lines = part.output.value.split("\n");
|
|
15826
|
+
if (lines.length > 50) {
|
|
15827
|
+
part.output = {
|
|
15828
|
+
type: "text",
|
|
15829
|
+
value: lines.slice(0, 50).join("\n") + "\n<truncated due to compaction, read the file again if full content is needed>"
|
|
15830
|
+
};
|
|
15831
|
+
}
|
|
15832
|
+
}
|
|
15833
|
+
}
|
|
15834
|
+
return messages;
|
|
15569
15835
|
};
|
|
15570
15836
|
const removeObsoleteSearches = (messages, protectedMessageCount = 10) => {
|
|
15571
|
-
const
|
|
15572
|
-
const protectedStart = getProtectedStartIndex(result, protectedMessageCount);
|
|
15837
|
+
const protectedStart = getProtectedStartIndex(messages, protectedMessageCount);
|
|
15573
15838
|
const fileModificationPositions = [];
|
|
15574
|
-
for (let i = 0; i <
|
|
15575
|
-
const msg =
|
|
15839
|
+
for (let i = 0; i < messages.length; i++) {
|
|
15840
|
+
const msg = messages[i];
|
|
15576
15841
|
if (msg.role === "assistant" && Array.isArray(msg.content)) {
|
|
15577
15842
|
for (const part of msg.content) {
|
|
15578
15843
|
if (part.type === "text" && part.text.includes("<file-edited")) {
|
|
@@ -15600,13 +15865,13 @@ const removeObsoleteSearches = (messages, protectedMessageCount = 10) => {
|
|
|
15600
15865
|
}
|
|
15601
15866
|
const hasFileModifications = fileModificationPositions.length > 0;
|
|
15602
15867
|
if (!hasFileModifications) {
|
|
15603
|
-
return
|
|
15868
|
+
return messages;
|
|
15604
15869
|
}
|
|
15605
15870
|
for (let i = protectedStart - 1; i >= 0; i--) {
|
|
15606
|
-
if (i >=
|
|
15871
|
+
if (i >= messages.length) {
|
|
15607
15872
|
continue;
|
|
15608
15873
|
}
|
|
15609
|
-
const msg =
|
|
15874
|
+
const msg = messages[i];
|
|
15610
15875
|
if (msg.role !== "tool") {
|
|
15611
15876
|
continue;
|
|
15612
15877
|
}
|
|
@@ -15623,22 +15888,21 @@ const removeObsoleteSearches = (messages, protectedMessageCount = 10) => {
|
|
|
15623
15888
|
}
|
|
15624
15889
|
const hasLaterModification = fileModificationPositions.some((pos) => pos > i);
|
|
15625
15890
|
if (hasLaterModification) {
|
|
15626
|
-
removeToolCallFromAssistant(
|
|
15627
|
-
removeToolResult(
|
|
15891
|
+
removeToolCallFromAssistant(messages, part.toolCallId);
|
|
15892
|
+
removeToolResult(messages, part.toolCallId);
|
|
15628
15893
|
}
|
|
15629
15894
|
}
|
|
15630
15895
|
}
|
|
15631
|
-
return
|
|
15896
|
+
return messages;
|
|
15632
15897
|
};
|
|
15633
15898
|
const compactSemanticSearches = (messages, protectedMessageCount = 10) => {
|
|
15634
|
-
const
|
|
15635
|
-
const protectedStart = getProtectedStartIndex(result, protectedMessageCount);
|
|
15899
|
+
const protectedStart = getProtectedStartIndex(messages, protectedMessageCount);
|
|
15636
15900
|
const searchIndices = [];
|
|
15637
15901
|
for (let i = 0; i < protectedStart; i++) {
|
|
15638
|
-
if (i >=
|
|
15902
|
+
if (i >= messages.length) {
|
|
15639
15903
|
break;
|
|
15640
15904
|
}
|
|
15641
|
-
const msg =
|
|
15905
|
+
const msg = messages[i];
|
|
15642
15906
|
if (msg.role !== "tool") {
|
|
15643
15907
|
continue;
|
|
15644
15908
|
}
|
|
@@ -15655,17 +15919,17 @@ const compactSemanticSearches = (messages, protectedMessageCount = 10) => {
|
|
|
15655
15919
|
}
|
|
15656
15920
|
}
|
|
15657
15921
|
if (searchIndices.length <= 1) {
|
|
15658
|
-
return
|
|
15922
|
+
return messages;
|
|
15659
15923
|
}
|
|
15660
15924
|
const toRemove = searchIndices.slice(0, -1);
|
|
15661
15925
|
const toKeep = searchIndices[searchIndices.length - 1];
|
|
15662
15926
|
for (const search2 of toRemove) {
|
|
15663
|
-
removeToolCallFromAssistant(
|
|
15664
|
-
removeToolResult(
|
|
15927
|
+
removeToolCallFromAssistant(messages, search2.toolCallId);
|
|
15928
|
+
removeToolResult(messages, search2.toolCallId);
|
|
15665
15929
|
}
|
|
15666
|
-
const keptToolIdx =
|
|
15930
|
+
const keptToolIdx = messages.findIndex((m) => m.role === "tool" && m.content.some((p) => p.type === "tool-result" && p.toolCallId === toKeep.toolCallId));
|
|
15667
15931
|
if (keptToolIdx !== -1) {
|
|
15668
|
-
const keptMsg =
|
|
15932
|
+
const keptMsg = messages[keptToolIdx];
|
|
15669
15933
|
const keptPartIdx = keptMsg.content.findIndex((p) => p.type === "tool-result" && p.toolCallId === toKeep.toolCallId);
|
|
15670
15934
|
const keptPart = keptMsg.content[keptPartIdx];
|
|
15671
15935
|
if (keptPart && keptPart.output.type === "text") {
|
|
@@ -15678,14 +15942,13 @@ const compactSemanticSearches = (messages, protectedMessageCount = 10) => {
|
|
|
15678
15942
|
}
|
|
15679
15943
|
}
|
|
15680
15944
|
}
|
|
15681
|
-
return
|
|
15945
|
+
return messages;
|
|
15682
15946
|
};
|
|
15683
15947
|
const deduplicateBash = (messages, protectedMessageCount = 10) => {
|
|
15684
|
-
const
|
|
15685
|
-
const protectedStart = getProtectedStartIndex(result, protectedMessageCount);
|
|
15948
|
+
const protectedStart = getProtectedStartIndex(messages, protectedMessageCount);
|
|
15686
15949
|
const bashCommands = /* @__PURE__ */ new Map();
|
|
15687
15950
|
for (let i = 0; i < protectedStart; i++) {
|
|
15688
|
-
const msg =
|
|
15951
|
+
const msg = messages[i];
|
|
15689
15952
|
if (msg.role !== "tool") {
|
|
15690
15953
|
continue;
|
|
15691
15954
|
}
|
|
@@ -15697,7 +15960,7 @@ const deduplicateBash = (messages, protectedMessageCount = 10) => {
|
|
|
15697
15960
|
if (!isPowerTool(serverName) || toolName !== POWER_TOOL_BASH) {
|
|
15698
15961
|
continue;
|
|
15699
15962
|
}
|
|
15700
|
-
const callInfo = findAssistantToolCall(
|
|
15963
|
+
const callInfo = findAssistantToolCall(messages, part.toolCallId);
|
|
15701
15964
|
if (!callInfo) {
|
|
15702
15965
|
continue;
|
|
15703
15966
|
}
|
|
@@ -15720,15 +15983,15 @@ const deduplicateBash = (messages, protectedMessageCount = 10) => {
|
|
|
15720
15983
|
}
|
|
15721
15984
|
const toRemove = occurrences.slice(0, -1);
|
|
15722
15985
|
for (const occ of toRemove) {
|
|
15723
|
-
removeToolCallFromAssistant(
|
|
15724
|
-
removeToolResult(
|
|
15986
|
+
removeToolCallFromAssistant(messages, occ.toolCallId);
|
|
15987
|
+
removeToolResult(messages, occ.toolCallId);
|
|
15725
15988
|
}
|
|
15726
15989
|
}
|
|
15727
15990
|
for (let i = 0; i < protectedStart; i++) {
|
|
15728
|
-
if (i >=
|
|
15991
|
+
if (i >= messages.length) {
|
|
15729
15992
|
break;
|
|
15730
15993
|
}
|
|
15731
|
-
const msg =
|
|
15994
|
+
const msg = messages[i];
|
|
15732
15995
|
if (msg.role !== "tool") {
|
|
15733
15996
|
continue;
|
|
15734
15997
|
}
|
|
@@ -15770,13 +16033,12 @@ const deduplicateBash = (messages, protectedMessageCount = 10) => {
|
|
|
15770
16033
|
}
|
|
15771
16034
|
}
|
|
15772
16035
|
}
|
|
15773
|
-
return
|
|
16036
|
+
return messages;
|
|
15774
16037
|
};
|
|
15775
16038
|
const redactFetchOutputs = (messages, protectedMessageCount = 10) => {
|
|
15776
|
-
const
|
|
15777
|
-
const protectedStart = getProtectedStartIndex(result, protectedMessageCount);
|
|
16039
|
+
const protectedStart = getProtectedStartIndex(messages, protectedMessageCount);
|
|
15778
16040
|
for (let i = 0; i < protectedStart; i++) {
|
|
15779
|
-
const msg =
|
|
16041
|
+
const msg = messages[i];
|
|
15780
16042
|
if (msg.role !== "tool") {
|
|
15781
16043
|
continue;
|
|
15782
16044
|
}
|
|
@@ -15798,7 +16060,7 @@ const redactFetchOutputs = (messages, protectedMessageCount = 10) => {
|
|
|
15798
16060
|
}
|
|
15799
16061
|
}
|
|
15800
16062
|
}
|
|
15801
|
-
return
|
|
16063
|
+
return messages;
|
|
15802
16064
|
};
|
|
15803
16065
|
const INTERNAL_TASK_ID = "internal";
|
|
15804
16066
|
const RESPONSE_CHUNK_FLUSH_INTERVAL_MS = 10;
|
|
@@ -16375,7 +16637,8 @@ class Task {
|
|
|
16375
16637
|
id: promptContext.id,
|
|
16376
16638
|
role: MessageRole.User,
|
|
16377
16639
|
content: prompt,
|
|
16378
|
-
promptContext
|
|
16640
|
+
promptContext,
|
|
16641
|
+
timestamp: Date.now()
|
|
16379
16642
|
});
|
|
16380
16643
|
this.addUserMessage(promptContext.id, prompt);
|
|
16381
16644
|
await this.saveTask({
|
|
@@ -16408,7 +16671,8 @@ class Task {
|
|
|
16408
16671
|
id: promptContext.id,
|
|
16409
16672
|
role: MessageRole.User,
|
|
16410
16673
|
content: prompt,
|
|
16411
|
-
promptContext
|
|
16674
|
+
promptContext,
|
|
16675
|
+
timestamp: Date.now()
|
|
16412
16676
|
});
|
|
16413
16677
|
let messages = this.contextManager.toConnectorMessages();
|
|
16414
16678
|
let files = this.contextManager.getContextFiles();
|
|
@@ -16427,8 +16691,9 @@ class Task {
|
|
|
16427
16691
|
promptContext = extensionResult.promptContext;
|
|
16428
16692
|
messages = extensionResult.messages;
|
|
16429
16693
|
files = extensionResult.files;
|
|
16694
|
+
const effectiveAutonomyMode = extensionResult.autonomyMode ?? this.task.autonomyMode ?? DEFAULT_AUTONOMY_MODE;
|
|
16430
16695
|
let responses = await this.sendPromptToAider(prompt, promptContext, mode, messages, files, {
|
|
16431
|
-
autoApprove:
|
|
16696
|
+
autoApprove: effectiveAutonomyMode === AutonomyMode.Autonomous,
|
|
16432
16697
|
denyCommands: extensionResult.denyCommands
|
|
16433
16698
|
});
|
|
16434
16699
|
logger.debug("Responses:", { responses });
|
|
@@ -16813,7 +17078,8 @@ ${contentText}</agent-response>`;
|
|
|
16813
17078
|
diff: message.diff,
|
|
16814
17079
|
usageReport,
|
|
16815
17080
|
sequenceNumber: message.sequenceNumber,
|
|
16816
|
-
promptContext: message.promptContext
|
|
17081
|
+
promptContext: message.promptContext,
|
|
17082
|
+
timestamp: Date.now()
|
|
16817
17083
|
};
|
|
16818
17084
|
const extensionResult = await this.extensionManager.dispatchEvent("onResponseCompleted", { response: data }, this.project, this);
|
|
16819
17085
|
data = extensionResult.response;
|
|
@@ -16880,14 +17146,20 @@ ${contentText}</agent-response>`;
|
|
|
16880
17146
|
if (!determinedAnswer) {
|
|
16881
17147
|
determinedAnswer = normalizedAnswer === "a" || normalizedAnswer === "y" ? "y" : "n";
|
|
16882
17148
|
}
|
|
16883
|
-
if (
|
|
16884
|
-
logger.debug('Storing answer for question due to "
|
|
17149
|
+
if (normalizedAnswer === "a") {
|
|
17150
|
+
logger.debug('Storing answer for question due to "a" (Always) input:', {
|
|
16885
17151
|
baseDir: this.project.baseDir,
|
|
16886
17152
|
questionKey: this.getQuestionKey(this.currentQuestion),
|
|
16887
|
-
rawInput: answer
|
|
16888
|
-
determinedAndStoredAnswer: determinedAnswer
|
|
17153
|
+
rawInput: answer
|
|
16889
17154
|
});
|
|
16890
|
-
this.storedQuestionAnswers.set(this.getQuestionKey(this.currentQuestion),
|
|
17155
|
+
this.storedQuestionAnswers.set(this.getQuestionKey(this.currentQuestion), "y");
|
|
17156
|
+
} else if (normalizedAnswer === "d") {
|
|
17157
|
+
logger.debug(`Storing answer for question due to "d" (Don't ask again) input:`, {
|
|
17158
|
+
baseDir: this.project.baseDir,
|
|
17159
|
+
questionKey: this.getQuestionKey(this.currentQuestion),
|
|
17160
|
+
rawInput: answer
|
|
17161
|
+
});
|
|
17162
|
+
this.storedQuestionAnswers.set(this.getQuestionKey(this.currentQuestion), "n");
|
|
16891
17163
|
}
|
|
16892
17164
|
const questionToAnswer = this.currentQuestion;
|
|
16893
17165
|
if (!this.currentQuestion.internal) {
|
|
@@ -17050,11 +17322,21 @@ ${contentText}</agent-response>`;
|
|
|
17050
17322
|
void this.updateContextInfo(true, true);
|
|
17051
17323
|
}
|
|
17052
17324
|
async askQuestion(questionData, awaitAnswer = true) {
|
|
17053
|
-
|
|
17325
|
+
let storedAnswer = this.storedQuestionAnswers.get(this.getQuestionKey(questionData));
|
|
17326
|
+
const extensionResult = await this.extensionManager.dispatchEvent(
|
|
17327
|
+
"onQuestionAsked",
|
|
17328
|
+
{
|
|
17329
|
+
question: questionData,
|
|
17330
|
+
storedAnswer
|
|
17331
|
+
},
|
|
17332
|
+
this.project,
|
|
17333
|
+
this
|
|
17334
|
+
);
|
|
17054
17335
|
if (extensionResult.answer) {
|
|
17055
17336
|
logger.info("Question answered by extension", {
|
|
17056
17337
|
question: questionData.text,
|
|
17057
|
-
answer: extensionResult.answer
|
|
17338
|
+
answer: extensionResult.answer,
|
|
17339
|
+
storedAnswer
|
|
17058
17340
|
});
|
|
17059
17341
|
return [extensionResult.answer, void 0];
|
|
17060
17342
|
}
|
|
@@ -17064,7 +17346,7 @@ ${contentText}</agent-response>`;
|
|
|
17064
17346
|
this.currentQuestionResolves.push(resolve);
|
|
17065
17347
|
});
|
|
17066
17348
|
}
|
|
17067
|
-
|
|
17349
|
+
storedAnswer = this.storedQuestionAnswers.get(this.getQuestionKey(questionData));
|
|
17068
17350
|
if (questionData.isGroupQuestion && !questionData.answers) {
|
|
17069
17351
|
questionData.answers = [
|
|
17070
17352
|
{ text: "(Y)es", shortkey: "y" },
|
|
@@ -17405,7 +17687,8 @@ ${contentText}</agent-response>`;
|
|
|
17405
17687
|
message,
|
|
17406
17688
|
finished,
|
|
17407
17689
|
promptContext,
|
|
17408
|
-
actionIds
|
|
17690
|
+
actionIds,
|
|
17691
|
+
timestamp: Date.now()
|
|
17409
17692
|
};
|
|
17410
17693
|
this.eventManager.sendLog(data);
|
|
17411
17694
|
}
|
|
@@ -17757,7 +18040,8 @@ ${contentText}</agent-response>`;
|
|
|
17757
18040
|
response,
|
|
17758
18041
|
usageReport,
|
|
17759
18042
|
promptContext,
|
|
17760
|
-
finished
|
|
18043
|
+
finished,
|
|
18044
|
+
timestamp: Date.now()
|
|
17761
18045
|
};
|
|
17762
18046
|
if (response && usageReport && saveToDb) {
|
|
17763
18047
|
this.dataManager.saveMessage(id, "tool", this.project.baseDir, usageReport.model, usageReport, {
|
|
@@ -17798,7 +18082,8 @@ ${contentText}</agent-response>`;
|
|
|
17798
18082
|
taskId: this.taskId,
|
|
17799
18083
|
content,
|
|
17800
18084
|
images,
|
|
17801
|
-
promptContext
|
|
18085
|
+
promptContext,
|
|
18086
|
+
timestamp: Date.now()
|
|
17802
18087
|
};
|
|
17803
18088
|
this.eventManager.sendUserMessage(data);
|
|
17804
18089
|
}
|
|
@@ -17958,7 +18243,7 @@ ${contentText}</agent-response>`;
|
|
|
17958
18243
|
return [];
|
|
17959
18244
|
}
|
|
17960
18245
|
await this.contextManager.backupContext();
|
|
17961
|
-
const compactedMessages = smartCompactMessages(contextMessages);
|
|
18246
|
+
const compactedMessages = await smartCompactMessages(contextMessages);
|
|
17962
18247
|
this.contextManager.setContextMessages(compactedMessages);
|
|
17963
18248
|
await this.contextManager.loadMessages(compactedMessages, false);
|
|
17964
18249
|
await this.updateContextInfo();
|
|
@@ -18121,7 +18406,7 @@ ${contentText}</agent-response>`;
|
|
|
18121
18406
|
const newTaskData = await this.project.createNewTask({
|
|
18122
18407
|
parentId: this.task.parentId || this.taskId,
|
|
18123
18408
|
sendEvent: false,
|
|
18124
|
-
|
|
18409
|
+
autonomyMode: execute ? this.task.autonomyMode : void 0,
|
|
18125
18410
|
activate: true
|
|
18126
18411
|
});
|
|
18127
18412
|
const newTask = this.project.getTask(newTaskData.id);
|
|
@@ -18441,7 +18726,12 @@ ${error.stderr}`,
|
|
|
18441
18726
|
}
|
|
18442
18727
|
}
|
|
18443
18728
|
}
|
|
18444
|
-
const systemPrompt = await this.promptsManager.getSystemPrompt(
|
|
18729
|
+
const systemPrompt = await this.promptsManager.getSystemPrompt(
|
|
18730
|
+
this.store.getSettings(),
|
|
18731
|
+
this,
|
|
18732
|
+
profile,
|
|
18733
|
+
command.autonomyMode ?? this.task.autonomyMode ?? DEFAULT_AUTONOMY_MODE
|
|
18734
|
+
);
|
|
18445
18735
|
const messages = command.includeContext === false ? [] : void 0;
|
|
18446
18736
|
const contextFiles = command.includeContext === false ? [] : void 0;
|
|
18447
18737
|
this.addLogMessage("loading", "Executing custom command...");
|
|
@@ -19192,7 +19482,7 @@ ${diff}
|
|
|
19192
19482
|
const newTaskData = await this.project.createNewTask({
|
|
19193
19483
|
name: taskName,
|
|
19194
19484
|
sendEvent: false,
|
|
19195
|
-
|
|
19485
|
+
autonomyMode: AutonomyMode.Autonomous,
|
|
19196
19486
|
activate: true,
|
|
19197
19487
|
mode,
|
|
19198
19488
|
parentId: this.task.parentId || this.taskId,
|
|
@@ -19332,7 +19622,7 @@ class Project {
|
|
|
19332
19622
|
this.promptsManager = promptsManager;
|
|
19333
19623
|
this.extensionManager = extensionManager;
|
|
19334
19624
|
this.pythonInstaller = pythonInstaller;
|
|
19335
|
-
this.customCommandManager = new CustomCommandManager(this, this.eventManager, this.extensionManager);
|
|
19625
|
+
this.customCommandManager = new CustomCommandManager(this, this.eventManager, this.extensionManager, this.store);
|
|
19336
19626
|
this.tasksLoadingPromise = this.loadTasks();
|
|
19337
19627
|
}
|
|
19338
19628
|
customCommandManager;
|
|
@@ -19408,9 +19698,7 @@ class Project {
|
|
|
19408
19698
|
...normalizedParams
|
|
19409
19699
|
};
|
|
19410
19700
|
}
|
|
19411
|
-
const projectSettings = this.getProjectSettings();
|
|
19412
19701
|
const taskData = {
|
|
19413
|
-
autoApprove: projectSettings.autoApproveLocked ? true : initialTaskData.autoApprove,
|
|
19414
19702
|
...initialTaskData
|
|
19415
19703
|
};
|
|
19416
19704
|
const extResult = await this.extensionManager.dispatchEvent("onTaskCreated", { task: taskData }, this);
|
|
@@ -19712,6 +20000,7 @@ class Project {
|
|
|
19712
20000
|
this.forEachTask((task) => {
|
|
19713
20001
|
void task.settingsChanged(oldSettings, newSettings);
|
|
19714
20002
|
});
|
|
20003
|
+
void this.customCommandManager.settingsChanged(oldSettings, newSettings);
|
|
19715
20004
|
}
|
|
19716
20005
|
async projectSettingsChanged(oldSettings, newSettings) {
|
|
19717
20006
|
this.forEachTask((task) => {
|
|
@@ -19961,7 +20250,8 @@ class EventManager {
|
|
|
19961
20250
|
baseDir,
|
|
19962
20251
|
taskId,
|
|
19963
20252
|
command,
|
|
19964
|
-
output
|
|
20253
|
+
output,
|
|
20254
|
+
timestamp: Date.now()
|
|
19965
20255
|
};
|
|
19966
20256
|
this.sendToWindows("command-output", data);
|
|
19967
20257
|
this.broadcastToEventConnectors("command-output", data);
|
|
@@ -22570,6 +22860,117 @@ const mistralProviderStrategy = {
|
|
|
22570
22860
|
getAiderMapping: getMistralAiderMapping,
|
|
22571
22861
|
getModelInfo: getDefaultModelInfo
|
|
22572
22862
|
};
|
|
22863
|
+
const NEURALWATT_BASE_URL = "https://api.neuralwatt.com/v1";
|
|
22864
|
+
const loadNeuralwattModels = async (profile, settings) => {
|
|
22865
|
+
if (!isNeuralwattProvider(profile.provider)) {
|
|
22866
|
+
return { models: [], success: false };
|
|
22867
|
+
}
|
|
22868
|
+
const provider = profile.provider;
|
|
22869
|
+
const apiKey = provider.apiKey || "";
|
|
22870
|
+
const apiKeyEnv = getEffectiveEnvironmentVariable("NEURALWATT_API_KEY", settings);
|
|
22871
|
+
const effectiveApiKey = apiKey || apiKeyEnv?.value || "";
|
|
22872
|
+
if (!effectiveApiKey) {
|
|
22873
|
+
logger.debug("Neuralwatt API key is required. Please set it in Providers settings or via NEURALWATT_API_KEY environment variable.");
|
|
22874
|
+
return { models: [], success: false };
|
|
22875
|
+
}
|
|
22876
|
+
try {
|
|
22877
|
+
const response = await fetch(`${NEURALWATT_BASE_URL}/models`, {
|
|
22878
|
+
headers: { Authorization: `Bearer ${effectiveApiKey}` }
|
|
22879
|
+
});
|
|
22880
|
+
if (!response.ok) {
|
|
22881
|
+
const errorMsg = `Neuralwatt models API response failed: ${response.status} ${response.statusText} ${await response.text()}`;
|
|
22882
|
+
logger.error(errorMsg, { status: response.status, statusText: response.statusText });
|
|
22883
|
+
return { models: [], success: false, error: errorMsg };
|
|
22884
|
+
}
|
|
22885
|
+
const data = await response.json();
|
|
22886
|
+
logger.info(`Received response from Neuralwatt models API for profile ${profile.id}`, { data });
|
|
22887
|
+
const models = data.data?.map((model) => {
|
|
22888
|
+
const metadata = model.metadata;
|
|
22889
|
+
const pricing = metadata?.pricing;
|
|
22890
|
+
const limits = metadata?.limits;
|
|
22891
|
+
const capabilities = metadata?.capabilities;
|
|
22892
|
+
return {
|
|
22893
|
+
id: model.id,
|
|
22894
|
+
providerId: profile.id,
|
|
22895
|
+
maxInputTokens: limits?.max_context_length ?? model.max_model_len,
|
|
22896
|
+
maxOutputTokensLimit: limits?.max_output_tokens ?? void 0,
|
|
22897
|
+
inputCostPerToken: pricing ? pricing.input_per_million / 1e6 : void 0,
|
|
22898
|
+
outputCostPerToken: pricing ? pricing.output_per_million / 1e6 : void 0,
|
|
22899
|
+
cacheReadInputTokenCost: pricing?.cached_input_per_million != null ? pricing.cached_input_per_million / 1e6 : void 0,
|
|
22900
|
+
supportsTools: capabilities?.tools
|
|
22901
|
+
};
|
|
22902
|
+
}) || [];
|
|
22903
|
+
logger.info(`Loaded ${models.length} Neuralwatt models for profile ${profile.id}`);
|
|
22904
|
+
return { models, success: true };
|
|
22905
|
+
} catch (error) {
|
|
22906
|
+
const errorMsg = typeof error === "string" ? error : error instanceof Error ? error.message : "Unknown error loading Neuralwatt models";
|
|
22907
|
+
logger.error("Error loading Neuralwatt models:", error);
|
|
22908
|
+
return { models: [], success: false, error: errorMsg };
|
|
22909
|
+
}
|
|
22910
|
+
};
|
|
22911
|
+
const hasNeuralwattEnvVars = (settings) => {
|
|
22912
|
+
return !!getEffectiveEnvironmentVariable("NEURALWATT_API_KEY", settings, void 0)?.value;
|
|
22913
|
+
};
|
|
22914
|
+
const getNeuralwattAiderMapping = (provider, modelId) => {
|
|
22915
|
+
const neuralwattProvider = provider.provider;
|
|
22916
|
+
const envVars = {};
|
|
22917
|
+
if (neuralwattProvider.apiKey) {
|
|
22918
|
+
envVars.OPENAI_API_KEY = neuralwattProvider.apiKey;
|
|
22919
|
+
}
|
|
22920
|
+
envVars.OPENAI_API_BASE = NEURALWATT_BASE_URL;
|
|
22921
|
+
return {
|
|
22922
|
+
modelName: `openai/${modelId}`,
|
|
22923
|
+
environmentVariables: envVars
|
|
22924
|
+
};
|
|
22925
|
+
};
|
|
22926
|
+
const createNeuralwattLlm = (profile, model, settings, projectDir) => {
|
|
22927
|
+
const provider = profile.provider;
|
|
22928
|
+
let apiKey = provider.apiKey;
|
|
22929
|
+
if (!apiKey) {
|
|
22930
|
+
const effectiveVar = getEffectiveEnvironmentVariable("NEURALWATT_API_KEY", settings, projectDir);
|
|
22931
|
+
if (effectiveVar) {
|
|
22932
|
+
apiKey = effectiveVar.value;
|
|
22933
|
+
logger.debug(`Loaded NEURALWATT_API_KEY from ${effectiveVar.source}`);
|
|
22934
|
+
}
|
|
22935
|
+
}
|
|
22936
|
+
if (!apiKey) {
|
|
22937
|
+
throw new Error("Neuralwatt API key is required in Providers settings or Aider environment variables (NEURALWATT_API_KEY)");
|
|
22938
|
+
}
|
|
22939
|
+
const compatibleProvider = openaiCompatible.createOpenAICompatible({
|
|
22940
|
+
name: "neuralwatt",
|
|
22941
|
+
apiKey,
|
|
22942
|
+
baseURL: NEURALWATT_BASE_URL,
|
|
22943
|
+
headers: profile.headers
|
|
22944
|
+
});
|
|
22945
|
+
return compatibleProvider(model.id);
|
|
22946
|
+
};
|
|
22947
|
+
const getNeuralwattUsageReport = (task, provider, model, usage, providerMetadata) => {
|
|
22948
|
+
const totalSentTokens = usage.inputTokens || 0;
|
|
22949
|
+
const receivedTokens = usage.outputTokens || 0;
|
|
22950
|
+
const cacheReadTokens = usage.cachedInputTokens || 0;
|
|
22951
|
+
const sentTokens = totalSentTokens - cacheReadTokens;
|
|
22952
|
+
logger.info("Neuralwatt usage report", {
|
|
22953
|
+
providerMetadata,
|
|
22954
|
+
usage
|
|
22955
|
+
});
|
|
22956
|
+
const messageCost = calculateCost(model, sentTokens, receivedTokens, cacheReadTokens);
|
|
22957
|
+
return {
|
|
22958
|
+
model: `${provider.id}/${model.id}`,
|
|
22959
|
+
sentTokens,
|
|
22960
|
+
receivedTokens,
|
|
22961
|
+
cacheReadTokens,
|
|
22962
|
+
messageCost,
|
|
22963
|
+
agentTotalCost: task.task.agentTotalCost + messageCost
|
|
22964
|
+
};
|
|
22965
|
+
};
|
|
22966
|
+
const neuralwattProviderStrategy = {
|
|
22967
|
+
createLlm: createNeuralwattLlm,
|
|
22968
|
+
getUsageReport: getNeuralwattUsageReport,
|
|
22969
|
+
loadModels: loadNeuralwattModels,
|
|
22970
|
+
hasEnvVars: hasNeuralwattEnvVars,
|
|
22971
|
+
getAiderMapping: getNeuralwattAiderMapping,
|
|
22972
|
+
getModelInfo: getDefaultModelInfo
|
|
22973
|
+
};
|
|
22573
22974
|
const loadOllamaModels = async (profile, settings) => {
|
|
22574
22975
|
if (!isOllamaProvider(profile.provider)) {
|
|
22575
22976
|
return { models: [], success: false };
|
|
@@ -23933,6 +24334,7 @@ class ModelManager {
|
|
|
23933
24334
|
lmstudio: lmStudioProviderStrategy,
|
|
23934
24335
|
minimax: minimaxProviderStrategy,
|
|
23935
24336
|
mistral: mistralProviderStrategy,
|
|
24337
|
+
neuralwatt: neuralwattProviderStrategy,
|
|
23936
24338
|
ollama: ollamaProviderStrategy,
|
|
23937
24339
|
openai: openaiProviderStrategy,
|
|
23938
24340
|
"openai-compatible": openaiCompatibleProviderStrategy,
|
|
@@ -25284,7 +25686,7 @@ class MemoryManager {
|
|
|
25284
25686
|
done: this.embeddingProgress.done,
|
|
25285
25687
|
total: this.embeddingProgress.total,
|
|
25286
25688
|
finished: true,
|
|
25287
|
-
error: "Failed to load @huggingface/transformers. This is usually a packaging issue with native dependencies
|
|
25689
|
+
error: "Failed to load @huggingface/transformers. This is usually a packaging issue with native dependencies."
|
|
25288
25690
|
};
|
|
25289
25691
|
logger.error("Failed to load transformers module. Memory embedding will be unavailable.", error);
|
|
25290
25692
|
return;
|
|
@@ -25456,7 +25858,7 @@ class MemoryManager {
|
|
|
25456
25858
|
done: this.embeddingProgress.done,
|
|
25457
25859
|
total: this.embeddingProgress.total,
|
|
25458
25860
|
finished: true,
|
|
25459
|
-
error: "Failed to load @huggingface/transformers. This is usually a packaging issue with native dependencies
|
|
25861
|
+
error: "Failed to load @huggingface/transformers. This is usually a packaging issue with native dependencies."
|
|
25460
25862
|
};
|
|
25461
25863
|
logger.error("Failed to load transformers module. Memory embedding will be unavailable.", error);
|
|
25462
25864
|
return;
|
|
@@ -26112,6 +26514,18 @@ class ExtensionContextImpl {
|
|
|
26112
26514
|
return [];
|
|
26113
26515
|
}
|
|
26114
26516
|
}
|
|
26517
|
+
getProviders() {
|
|
26518
|
+
if (!this.modelManager) {
|
|
26519
|
+
this.log("ModelManager not available, returning empty providers", "warn");
|
|
26520
|
+
return [];
|
|
26521
|
+
}
|
|
26522
|
+
try {
|
|
26523
|
+
return this.modelManager.getProviders();
|
|
26524
|
+
} catch (error) {
|
|
26525
|
+
this.log(`Failed to get providers: ${error}`, "error");
|
|
26526
|
+
return [];
|
|
26527
|
+
}
|
|
26528
|
+
}
|
|
26115
26529
|
async getSetting(key) {
|
|
26116
26530
|
if (!this.store) {
|
|
26117
26531
|
throw new Error("Store not available");
|
|
@@ -26202,6 +26616,9 @@ class ExtensionContextImpl {
|
|
|
26202
26616
|
}
|
|
26203
26617
|
return this.memoryManager;
|
|
26204
26618
|
}
|
|
26619
|
+
async truncateToolResult(content, maxLines, maxSizeKB, maxTokens, saveToFile, truncationSuffix) {
|
|
26620
|
+
return truncateToolResult(content, maxLines, maxSizeKB, maxTokens, saveToFile, truncationSuffix);
|
|
26621
|
+
}
|
|
26205
26622
|
}
|
|
26206
26623
|
const CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
26207
26624
|
class ExtensionFetcher {
|
|
@@ -26607,6 +27024,9 @@ class ExtensionManager {
|
|
|
26607
27024
|
logger.debug("[Extensions] Repository list changed, refreshing extension cache");
|
|
26608
27025
|
void this.fetcher.getAvailableExtensions(newRepositories, true);
|
|
26609
27026
|
}
|
|
27027
|
+
if (oldSettings.fileWatchMode !== newSettings.fileWatchMode) {
|
|
27028
|
+
void this.restartWatchers();
|
|
27029
|
+
}
|
|
26610
27030
|
}
|
|
26611
27031
|
addListener(listener) {
|
|
26612
27032
|
this.listeners.push(listener);
|
|
@@ -26911,7 +27331,7 @@ class ExtensionManager {
|
|
|
26911
27331
|
};
|
|
26912
27332
|
const watcher = chokidar.watch(dir, {
|
|
26913
27333
|
persistent: true,
|
|
26914
|
-
usePolling:
|
|
27334
|
+
usePolling: shouldUsePolling(dir, this.store.getSettings().fileWatchMode),
|
|
26915
27335
|
ignoreInitial: true,
|
|
26916
27336
|
ignored: (filePath) => {
|
|
26917
27337
|
const basename = path.basename(filePath);
|
|
@@ -26995,6 +27415,25 @@ class ExtensionManager {
|
|
|
26995
27415
|
logger.debug(`[Extensions] Stopped watching project extensions: ${projectDir}`);
|
|
26996
27416
|
}
|
|
26997
27417
|
}
|
|
27418
|
+
async restartWatchers() {
|
|
27419
|
+
const projectDirs = Array.from(this.projectWatchers.keys());
|
|
27420
|
+
await this.stopGlobalWatcher();
|
|
27421
|
+
for (const dir of projectDirs) {
|
|
27422
|
+
await this.stopProjectWatcher(dir);
|
|
27423
|
+
}
|
|
27424
|
+
await this.startHotReloadWatcher();
|
|
27425
|
+
for (const dir of projectDirs) {
|
|
27426
|
+
const projectExtensionsDir = path.join(dir, AIDER_DESK_EXTENSIONS_DIR);
|
|
27427
|
+
const watcher = await this.setupWatcherForDir(projectExtensionsDir, async () => {
|
|
27428
|
+
logger.debug(`[Extensions] Project extensions changed for ${dir}, reloading...`);
|
|
27429
|
+
await this.unloadExtensionsForDir(projectExtensionsDir);
|
|
27430
|
+
await this.loadExtensionsForDir(projectExtensionsDir);
|
|
27431
|
+
});
|
|
27432
|
+
if (watcher) {
|
|
27433
|
+
this.projectWatchers.set(dir, watcher);
|
|
27434
|
+
}
|
|
27435
|
+
}
|
|
27436
|
+
}
|
|
26998
27437
|
static TOOL_NAME_REGEX = /^[a-z][a-z0-9_-]*$/;
|
|
26999
27438
|
validateToolDefinition(tool) {
|
|
27000
27439
|
const errors = [];
|
|
@@ -27913,7 +28352,7 @@ class ExtensionManager {
|
|
|
27913
28352
|
}
|
|
27914
28353
|
}
|
|
27915
28354
|
class EventsHandler {
|
|
27916
|
-
constructor(projectManager, store, mcpManager, versionsManager, modelManager, telemetryManager, dataManager, terminalManager, cloudflareTunnelManager, eventManager, agentProfileManager, memoryManager, extensionManager, proxyManager, windowManager) {
|
|
28355
|
+
constructor(projectManager, store, mcpManager, versionsManager, modelManager, telemetryManager, dataManager, terminalManager, cloudflareTunnelManager, eventManager, agentProfileManager, memoryManager, extensionManager, proxyManager, promptsManager, windowManager) {
|
|
27917
28356
|
this.projectManager = projectManager;
|
|
27918
28357
|
this.store = store;
|
|
27919
28358
|
this.mcpManager = mcpManager;
|
|
@@ -27928,6 +28367,7 @@ class EventsHandler {
|
|
|
27928
28367
|
this.memoryManager = memoryManager;
|
|
27929
28368
|
this.extensionManager = extensionManager;
|
|
27930
28369
|
this.proxyManager = proxyManager;
|
|
28370
|
+
this.promptsManager = promptsManager;
|
|
27931
28371
|
this.windowManager = windowManager;
|
|
27932
28372
|
}
|
|
27933
28373
|
loadSettings() {
|
|
@@ -27941,6 +28381,8 @@ class EventsHandler {
|
|
|
27941
28381
|
this.telemetryManager.settingsChanged(oldSettings, newSettings);
|
|
27942
28382
|
void this.memoryManager.settingsChanged(oldSettings, newSettings);
|
|
27943
28383
|
this.extensionManager.settingsChanged(oldSettings, newSettings);
|
|
28384
|
+
void this.agentProfileManager.settingsChanged(oldSettings, newSettings);
|
|
28385
|
+
void this.promptsManager.settingsChanged(oldSettings, newSettings);
|
|
27944
28386
|
this.eventManager.sendSettingsUpdated(newSettings);
|
|
27945
28387
|
return this.store.getSettings();
|
|
27946
28388
|
}
|
|
@@ -28921,8 +29363,9 @@ const registerAllHelpers = () => {
|
|
|
28921
29363
|
registerFormattingHelpers();
|
|
28922
29364
|
};
|
|
28923
29365
|
class PromptsManager {
|
|
28924
|
-
constructor(extensionManager, defaultTemplatesDir = AIDER_DESK_DEFAULT_PROMPTS_DIR, globalPromptsDir = AIDER_DESK_GLOBAL_PROMPTS_DIR) {
|
|
29366
|
+
constructor(extensionManager, store, defaultTemplatesDir = AIDER_DESK_DEFAULT_PROMPTS_DIR, globalPromptsDir = AIDER_DESK_GLOBAL_PROMPTS_DIR) {
|
|
28925
29367
|
this.extensionManager = extensionManager;
|
|
29368
|
+
this.store = store;
|
|
28926
29369
|
this.defaultTemplatesDir = defaultTemplatesDir;
|
|
28927
29370
|
this.globalPromptsDir = globalPromptsDir;
|
|
28928
29371
|
registerAllHelpers();
|
|
@@ -29016,7 +29459,7 @@ class PromptsManager {
|
|
|
29016
29459
|
}
|
|
29017
29460
|
const watcher = chokidar.watch(this.globalPromptsDir, {
|
|
29018
29461
|
persistent: true,
|
|
29019
|
-
usePolling:
|
|
29462
|
+
usePolling: shouldUsePolling(this.globalPromptsDir, this.store.getSettings().fileWatchMode),
|
|
29020
29463
|
ignoreInitial: true
|
|
29021
29464
|
});
|
|
29022
29465
|
const debouncedReload = debounce(async () => {
|
|
@@ -29041,7 +29484,7 @@ class PromptsManager {
|
|
|
29041
29484
|
await this.compileProjectTemplates(projectDir);
|
|
29042
29485
|
const watcher = chokidar.watch(projectPromptsDir, {
|
|
29043
29486
|
persistent: true,
|
|
29044
|
-
usePolling:
|
|
29487
|
+
usePolling: shouldUsePolling(projectPromptsDir, this.store.getSettings().fileWatchMode),
|
|
29045
29488
|
ignoreInitial: true
|
|
29046
29489
|
});
|
|
29047
29490
|
const debouncedReload = debounce(async () => {
|
|
@@ -29070,6 +29513,20 @@ class PromptsManager {
|
|
|
29070
29513
|
this.projectTemplatesCache.clear();
|
|
29071
29514
|
logger.info("PromptsManager disposed");
|
|
29072
29515
|
}
|
|
29516
|
+
async settingsChanged(oldSettings, newSettings) {
|
|
29517
|
+
if (oldSettings.fileWatchMode === newSettings.fileWatchMode) {
|
|
29518
|
+
return;
|
|
29519
|
+
}
|
|
29520
|
+
const watchedProjects = Array.from(this.watchers.keys()).filter((k) => k !== "global");
|
|
29521
|
+
for (const watcher of this.watchers.values()) {
|
|
29522
|
+
await watcher.close();
|
|
29523
|
+
}
|
|
29524
|
+
this.watchers.clear();
|
|
29525
|
+
await this.setupGlobalWatcher();
|
|
29526
|
+
for (const projectDir of watchedProjects) {
|
|
29527
|
+
await this.watchProject(projectDir);
|
|
29528
|
+
}
|
|
29529
|
+
}
|
|
29073
29530
|
async render(name, data, projectDir, task) {
|
|
29074
29531
|
const projectTemplates = this.projectTemplatesCache.get(projectDir);
|
|
29075
29532
|
const projectTemplate = projectTemplates?.get(name);
|
|
@@ -29095,7 +29552,7 @@ class PromptsManager {
|
|
|
29095
29552
|
}
|
|
29096
29553
|
return prompt;
|
|
29097
29554
|
}
|
|
29098
|
-
calculateToolPermissions = (settings, agentProfile,
|
|
29555
|
+
calculateToolPermissions = (settings, agentProfile, autonomyMode) => {
|
|
29099
29556
|
const { usePowerTools = false, useMemoryTools = false, useSkillsTools = false } = agentProfile;
|
|
29100
29557
|
const memoryEnabled = settings.memory.enabled && useMemoryTools;
|
|
29101
29558
|
const isAllowed = (tool) => agentProfile.toolApprovals[tool] !== ToolApprovalState.Never;
|
|
@@ -29124,11 +29581,12 @@ class PromptsManager {
|
|
|
29124
29581
|
skills: {
|
|
29125
29582
|
allowed: useSkillsTools && isAllowed(`${SKILLS_TOOL_GROUP_NAME}${TOOL_GROUP_NAME_SEPARATOR}${SKILLS_TOOL_ACTIVATE_SKILL}`)
|
|
29126
29583
|
},
|
|
29127
|
-
|
|
29584
|
+
autonomyMode
|
|
29128
29585
|
};
|
|
29129
29586
|
};
|
|
29130
|
-
getSystemPrompt = async (settings, task, agentProfile,
|
|
29131
|
-
const
|
|
29587
|
+
getSystemPrompt = async (settings, task, agentProfile, autonomyMode, additionalInstructions) => {
|
|
29588
|
+
const effectiveAutonomyMode = autonomyMode ?? task.task.autonomyMode ?? DEFAULT_AUTONOMY_MODE;
|
|
29589
|
+
const toolPermissions = this.calculateToolPermissions(settings, agentProfile, effectiveAutonomyMode);
|
|
29132
29590
|
toolPermissions.powerTools.anyEnabled = Object.values(toolPermissions.powerTools).some((v) => v);
|
|
29133
29591
|
const rulesFiles = await this.getRulesContent(task, agentProfile);
|
|
29134
29592
|
const customInstructions = [agentProfile.customInstructions, additionalInstructions].filter(Boolean).join("\n\n").trim();
|
|
@@ -29537,12 +29995,12 @@ const initManagers = async (store, windowManager) => {
|
|
|
29537
29995
|
extensionManager.init().catch((error) => {
|
|
29538
29996
|
logger.error("[Extensions] Extension system initialization failed, continuing without extensions:", error);
|
|
29539
29997
|
});
|
|
29540
|
-
const promptsManager = new PromptsManager(extensionManager);
|
|
29998
|
+
const promptsManager = new PromptsManager(extensionManager, store);
|
|
29541
29999
|
promptsManager.init().catch((error) => {
|
|
29542
30000
|
logger.error("[Prompts] Prompts system initialization failed:", error);
|
|
29543
30001
|
});
|
|
29544
30002
|
const worktreeManager = new WorktreeManager();
|
|
29545
|
-
const agentProfileManager = new AgentProfileManager(eventManager, extensionManager);
|
|
30003
|
+
const agentProfileManager = new AgentProfileManager(eventManager, extensionManager, store);
|
|
29546
30004
|
agentProfileManager.init().catch((error) => {
|
|
29547
30005
|
logger.error("[AgentProfile] Agent profile system initialization failed:", error);
|
|
29548
30006
|
});
|
|
@@ -29579,6 +30037,7 @@ const initManagers = async (store, windowManager) => {
|
|
|
29579
30037
|
memoryManager,
|
|
29580
30038
|
extensionManager,
|
|
29581
30039
|
proxyManager,
|
|
30040
|
+
promptsManager,
|
|
29582
30041
|
windowManager
|
|
29583
30042
|
);
|
|
29584
30043
|
const serverController = new ServerController(httpServer, projectManager, eventsHandler, store, pythonInstaller);
|
|
@@ -30210,7 +30669,8 @@ const DEFAULT_SETTINGS = {
|
|
|
30210
30669
|
proxy: {
|
|
30211
30670
|
enabled: false,
|
|
30212
30671
|
url: ""
|
|
30213
|
-
}
|
|
30672
|
+
},
|
|
30673
|
+
fileWatchMode: FileWatchMode.Auto
|
|
30214
30674
|
};
|
|
30215
30675
|
const compareBaseDirs = (baseDir1, baseDir2) => {
|
|
30216
30676
|
return normalizeBaseDir(baseDir1) === normalizeBaseDir(baseDir2);
|