@aiderdesk/aiderdesk 0.66.0 → 0.68.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/out/renderer/assets/{arc-BXuUWHai.js → arc-Cju-fnUJ.js} +1 -1
  2. package/out/renderer/assets/{architectureDiagram-3BPJPVTR-Bm9oFTP_.js → architectureDiagram-3BPJPVTR-hVK8LPcC.js} +3 -3
  3. package/out/renderer/assets/{blockDiagram-GPEHLZMM-DQ2DevZl.js → blockDiagram-GPEHLZMM-B04Ulwbh.js} +4 -4
  4. package/out/renderer/assets/{c4Diagram-AAUBKEIU-BdR46VbA.js → c4Diagram-AAUBKEIU-DSP8EUB6.js} +2 -2
  5. package/out/renderer/assets/{channel-DUdp1NJ7.js → channel-CM1Bn7Zy.js} +1 -1
  6. package/out/renderer/assets/{chunk-2J33WTMH-Dzi-idRV.js → chunk-2J33WTMH-Bd_3pGvb.js} +1 -1
  7. package/out/renderer/assets/{chunk-4BX2VUAB-DEyFpixF.js → chunk-4BX2VUAB-Csrpxz3N.js} +1 -1
  8. package/out/renderer/assets/{chunk-55IACEB6-DyyQMIZa.js → chunk-55IACEB6-BB7RTMZZ.js} +1 -1
  9. package/out/renderer/assets/{chunk-727SXJPM-vXEiesCP.js → chunk-727SXJPM-D6Y9H3aA.js} +5 -5
  10. package/out/renderer/assets/{chunk-AQP2D5EJ-B0SWmbrS.js → chunk-AQP2D5EJ-D5f9Zgag.js} +3 -3
  11. package/out/renderer/assets/{chunk-FMBD7UC4-CoPwvBCa.js → chunk-FMBD7UC4-Bstyl64g.js} +1 -1
  12. package/out/renderer/assets/{chunk-ND2GUHAM-ku5t5SwP.js → chunk-ND2GUHAM-CVaUW2HV.js} +1 -1
  13. package/out/renderer/assets/{chunk-QZHKN3VN-DBGBAqit.js → chunk-QZHKN3VN-AMfy7Nbn.js} +1 -1
  14. package/out/renderer/assets/{classDiagram-4FO5ZUOK-DTyjsHX9.js → classDiagram-4FO5ZUOK-CPmL8t3E.js} +6 -6
  15. package/out/renderer/assets/{classDiagram-v2-Q7XG4LA2-DTyjsHX9.js → classDiagram-v2-Q7XG4LA2-CPmL8t3E.js} +6 -6
  16. package/out/renderer/assets/{cose-bilkent-S5V4N54A-wGfE9wIx.js → cose-bilkent-S5V4N54A-px_eCLil.js} +1 -1
  17. package/out/renderer/assets/{dagre-BM42HDAG-cwyj1-l0.js → dagre-BM42HDAG-c63xhfuM.js} +3 -3
  18. package/out/renderer/assets/{diagram-2AECGRRQ-BYvCxkOs.js → diagram-2AECGRRQ-DISIyKng.js} +3 -3
  19. package/out/renderer/assets/{diagram-5GNKFQAL--ZlqvgmY.js → diagram-5GNKFQAL-BSkGLBgD.js} +4 -4
  20. package/out/renderer/assets/{diagram-KO2AKTUF-CoPNrPhx.js → diagram-KO2AKTUF-xiSl-Lui.js} +3 -3
  21. package/out/renderer/assets/{diagram-LMA3HP47-wjhxYTWf.js → diagram-LMA3HP47-lJ69G8gJ.js} +3 -3
  22. package/out/renderer/assets/{diagram-OG6HWLK6-DhYpewbd.js → diagram-OG6HWLK6-AoDpX3QT.js} +4 -4
  23. package/out/renderer/assets/{erDiagram-TEJ5UH35-DolRLBng.js → erDiagram-TEJ5UH35-O7UNRkDw.js} +4 -4
  24. package/out/renderer/assets/{flowDiagram-I6XJVG4X-DjAbl_XC.js → flowDiagram-I6XJVG4X-Dd9XTtIY.js} +6 -6
  25. package/out/renderer/assets/{ganttDiagram-6RSMTGT7-AF7-XgtX.js → ganttDiagram-6RSMTGT7-Bc7FUk0Y.js} +1 -1
  26. package/out/renderer/assets/{gitGraphDiagram-PVQCEYII-BMZLakzH.js → gitGraphDiagram-PVQCEYII-DwEksAhs.js} +4 -4
  27. package/out/renderer/assets/{graph-B_ifajWk.js → graph-BPvbzKl1.js} +1 -1
  28. package/out/renderer/assets/{index-3bI-dJm8.js → index-BmQl7j8n.js} +3399 -2428
  29. package/out/renderer/assets/{index-B62bIfbt.css → index-z-BItG-u.css} +36 -16
  30. package/out/renderer/assets/{infoDiagram-5YYISTIA-0f7Qxxvp.js → infoDiagram-5YYISTIA-DvophXOV.js} +2 -2
  31. package/out/renderer/assets/{ishikawaDiagram-YF4QCWOH-BX_EIAMn.js → ishikawaDiagram-YF4QCWOH-CDT4EDOF.js} +1 -1
  32. package/out/renderer/assets/{journeyDiagram-JHISSGLW-Dmitv8wD.js → journeyDiagram-JHISSGLW-B5FCPOti.js} +4 -4
  33. package/out/renderer/assets/jsx-dev-runtime-DuBp-Rhq.js +49 -0
  34. package/out/renderer/assets/{kanban-definition-UN3LZRKU-By2GFUNB.js → kanban-definition-UN3LZRKU-CM_TQl4S.js} +2 -2
  35. package/out/renderer/assets/{layout-DAkKffy1.js → layout-DdBKGefG.js} +2 -2
  36. package/out/renderer/assets/{mindmap-definition-RKZ34NQL-yIrV1m0y.js → mindmap-definition-RKZ34NQL-BeGrpK-H.js} +3 -3
  37. package/out/renderer/assets/{pieDiagram-4H26LBE5-PV9y5rw_.js → pieDiagram-4H26LBE5-CnMhRK3I.js} +4 -4
  38. package/out/renderer/assets/{quadrantDiagram-W4KKPZXB-DeX0zTCp.js → quadrantDiagram-W4KKPZXB-O_Q_JI2s.js} +1 -1
  39. package/out/renderer/assets/{requirementDiagram-4Y6WPE33-Bzfk_KE-.js → requirementDiagram-4Y6WPE33-vf9wLf04.js} +3 -3
  40. package/out/renderer/assets/{sankeyDiagram-5OEKKPKP-BuCv8QIY.js → sankeyDiagram-5OEKKPKP-CE4n-uB4.js} +1 -1
  41. package/out/renderer/assets/{sequenceDiagram-3UESZ5HK-Zg7Ukud8.js → sequenceDiagram-3UESZ5HK-DebEZhql.js} +3 -3
  42. package/out/renderer/assets/{stateDiagram-AJRCARHV-CLaqfYR8.js → stateDiagram-AJRCARHV-DCsVosBt.js} +6 -6
  43. package/out/renderer/assets/{stateDiagram-v2-BHNVJYJU-Cmm1ljQ4.js → stateDiagram-v2-BHNVJYJU-8oguEvt8.js} +4 -4
  44. package/out/renderer/assets/{timeline-definition-PNZ67QCA-DQBaAVcC.js → timeline-definition-PNZ67QCA-CSfXVnNf.js} +2 -2
  45. package/out/renderer/assets/{vennDiagram-CIIHVFJN-CuplbU_R.js → vennDiagram-CIIHVFJN-DxOEVeC4.js} +1 -1
  46. package/out/renderer/assets/{wardley-L42UT6IY-BiqfHMim.js → wardley-L42UT6IY-Cz6T4MDn.js} +1 -1
  47. package/out/renderer/assets/{wardleyDiagram-YWT4CUSO-BaV0FnUu.js → wardleyDiagram-YWT4CUSO-B4sA3LOJ.js} +3 -3
  48. package/out/renderer/assets/{xychartDiagram-2RQKCTM6-DA_Miw-n.js → xychartDiagram-2RQKCTM6-DbJjruqS.js} +1 -1
  49. package/out/renderer/index.html +2 -2
  50. package/out/resources/prompts/workflow.hbs +2 -2
  51. package/out/resources/skills/extension-creator/SKILL.md +24 -0
  52. package/out/resources/skills/extension-creator/references/examples-gallery.md +11 -0
  53. package/out/resources/skills/extension-creator/references/extension-interface.md +4 -0
  54. package/out/resources/skills/extension-creator/references/external-libraries.md +159 -0
  55. package/out/resources/skills/extension-creator/references/ui-components.md +24 -0
  56. package/out/runner.js +860 -205
  57. 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
- autoApproveLocked: zod.z.boolean().optional(),
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
- autoApprove: zod.z.boolean().optional(),
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.task.autoApprove) {
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
- autoApprove: task?.autoApprove ?? false,
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,13 +2439,26 @@ const getDefaultProjectSettings = (store, providerModels, baseDir, defaultAgentP
2411
2439
  modelEditFormats: {},
2412
2440
  currentMode: "agent",
2413
2441
  agentProfileId: defaultAgentProfileId,
2414
- autoApproveLocked: false,
2442
+ autonomyModeLocked: false,
2415
2443
  updatedFilesGroupMode: "flat",
2416
2444
  disabledRuleFiles: [],
2417
2445
  contextSidebarSectionsOrder: [],
2418
2446
  contextSidebarSectionsHidden: []
2419
2447
  };
2420
2448
  };
2449
+ const DEFAULT_FETCH_TIMEOUT_MS = 12e4;
2450
+ const fetchWithTimeout = async (url, timeoutMs = DEFAULT_FETCH_TIMEOUT_MS) => {
2451
+ const controller = new AbortController();
2452
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
2453
+ try {
2454
+ const response = await fetch(url, { signal: controller.signal });
2455
+ clearTimeout(timeoutId);
2456
+ return response;
2457
+ } catch (error) {
2458
+ clearTimeout(timeoutId);
2459
+ throw error;
2460
+ }
2461
+ };
2421
2462
  const filenamify = filenamifyImport.default;
2422
2463
  const getFilePathSuggestions = async (currentPath, directoriesOnly = false) => {
2423
2464
  try {
@@ -3259,7 +3300,7 @@ File size limit (${sizeLimit.toFixed(1)} KB) exceeded. Use shell commands (e.g.,
3259
3300
  }
3260
3301
  return resultLines.join("\n");
3261
3302
  };
3262
- const truncateToolResult = async (content, maxLines = 1e3, maxSizeKB = 50, maxTokens = 5e4) => {
3303
+ const truncateToolResult = async (content, maxLines = 1e3, maxSizeKB = 50, maxTokens = 5e4, saveToFile = true, truncationSuffix) => {
3263
3304
  const lines = content.split("\n");
3264
3305
  const sizeBytes = Buffer.byteLength(content, "utf8");
3265
3306
  const sizeKB = sizeBytes / 1024;
@@ -3267,10 +3308,13 @@ const truncateToolResult = async (content, maxLines = 1e3, maxSizeKB = 50, maxTo
3267
3308
  if (lines.length <= maxLines && sizeKB <= maxSizeKB && tokenCount <= maxTokens) {
3268
3309
  return content;
3269
3310
  }
3270
- const id = Date.now().toString(36) + Math.random().toString(36).substring(2, 8);
3271
- const tmpFileName = `aider-desk-tool-result-${id}.txt`;
3272
- const tmpFilePath = path.join(os.tmpdir(), tmpFileName);
3273
- await fs.writeFile(tmpFilePath, content, "utf8");
3311
+ let tmpFilePath;
3312
+ if (saveToFile) {
3313
+ const id = Date.now().toString(36) + Math.random().toString(36).substring(2, 8);
3314
+ const tmpFileName = `aider-desk-tool-result-${id}.txt`;
3315
+ tmpFilePath = path.join(os.tmpdir(), tmpFileName);
3316
+ await fs.writeFile(tmpFilePath, content, "utf8");
3317
+ }
3274
3318
  const reasons = [];
3275
3319
  if (lines.length > maxLines) {
3276
3320
  reasons.push(`${lines.length} lines exceeded limit of ${maxLines}`);
@@ -3281,6 +3325,13 @@ const truncateToolResult = async (content, maxLines = 1e3, maxSizeKB = 50, maxTo
3281
3325
  if (tokenCount > maxTokens) {
3282
3326
  reasons.push(`${tokenCount} tokens exceeded limit of ${maxTokens}`);
3283
3327
  }
3328
+ const getSuffix = () => {
3329
+ if (truncationSuffix) {
3330
+ return truncationSuffix;
3331
+ }
3332
+ const fileNote = tmpFilePath ? ` Full content saved to ${tmpFilePath}.` : "";
3333
+ return `Content truncated (${reasons.join(", ")}).${fileNote}`;
3334
+ };
3284
3335
  if (tokenCount > maxTokens) {
3285
3336
  const headBudget = Math.floor(maxTokens / 2);
3286
3337
  const tailBudget = maxTokens - headBudget;
@@ -3313,6 +3364,14 @@ const truncateToolResult = async (content, maxLines = 1e3, maxSizeKB = 50, maxTo
3313
3364
  ... ${omittedLines} lines omitted (${reasons.join(", ")}). Full content saved to ${tmpFilePath}.
3314
3365
 
3315
3366
  `;
3367
+ if (truncationSuffix) {
3368
+ const suffixNotice = `
3369
+
3370
+ ... ${omittedLines} lines omitted. ${truncationSuffix}
3371
+
3372
+ `;
3373
+ return headLines.join("\n") + suffixNotice + tailLines.join("\n");
3374
+ }
3316
3375
  return headLines.join("\n") + truncationNotice + tailLines.join("\n");
3317
3376
  }
3318
3377
  let preview;
@@ -3324,7 +3383,7 @@ const truncateToolResult = async (content, maxLines = 1e3, maxSizeKB = 50, maxTo
3324
3383
  preview = lines.slice(0, maxLines).join("\n");
3325
3384
  }
3326
3385
  return preview + `
3327
- ... Content truncated (${reasons.join(", ")}). Full content saved to ${tmpFilePath}.`;
3386
+ ... ${getSuffix()}`;
3328
3387
  };
3329
3388
  const NETWORK_ERROR_CODES = ["ECONNRESET", "EPIPE", "ETIMEDOUT", "ECONNREFUSED", "ENOTFOUND", "ENETUNREACH", "EAI_AGAIN"];
3330
3389
  const UNDICI_ERROR_PREFIX = "UND_ERR_";
@@ -3744,10 +3803,17 @@ Do not use escape characters \\ in the string like \\n or \\" and others. Do not
3744
3803
  }
3745
3804
  const results = [];
3746
3805
  const outputLineRegex = /^(.+?)([:-])(\d+)\2(.*)$/;
3806
+ let pendingBeforeContext = [];
3807
+ let afterContextBreak = false;
3747
3808
  for (let rawLine of outputLines) {
3748
3809
  if (rawLine.endsWith("\r")) {
3749
3810
  rawLine = rawLine.slice(0, -1);
3750
3811
  }
3812
+ if (rawLine === "--") {
3813
+ pendingBeforeContext = [];
3814
+ afterContextBreak = true;
3815
+ continue;
3816
+ }
3751
3817
  const line = rawLine;
3752
3818
  const match = outputLineRegex.exec(line);
3753
3819
  if (!match) {
@@ -3761,18 +3827,28 @@ Do not use escape characters \\ in the string like \\n or \\" and others. Do not
3761
3827
  const filePath = rawFilePath.startsWith("./") ? rawFilePath.slice(2) : rawFilePath;
3762
3828
  const isMatch = separator === ":";
3763
3829
  if (isMatch) {
3830
+ const context = pendingBeforeContext.length > 0 ? [...pendingBeforeContext, content] : void 0;
3764
3831
  results.push({
3765
3832
  filePath,
3766
3833
  lineNumber: lineNum,
3767
- lineContent: content
3834
+ lineContent: content,
3835
+ context
3768
3836
  });
3837
+ pendingBeforeContext = [];
3838
+ afterContextBreak = false;
3769
3839
  } else {
3770
- const lastResult = results[results.length - 1];
3771
- if (lastResult) {
3772
- if (!lastResult.context) {
3773
- lastResult.context = [];
3840
+ if (afterContextBreak) {
3841
+ pendingBeforeContext.push(content);
3842
+ } else {
3843
+ const lastResult = results[results.length - 1];
3844
+ if (lastResult) {
3845
+ if (!lastResult.context) {
3846
+ lastResult.context = [];
3847
+ }
3848
+ lastResult.context.push(content);
3849
+ } else {
3850
+ pendingBeforeContext.push(content);
3774
3851
  }
3775
- lastResult.context.push(content);
3776
3852
  }
3777
3853
  }
3778
3854
  if (results.length >= maxResults) {
@@ -4462,15 +4538,15 @@ const createTasksToolset = (settings, task, profile, promptContext) => {
4462
4538
  parentTaskId: zod.z.string().nullable().optional().describe(
4463
4539
  "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
4540
  ),
4465
- autoApprove: zod.z.boolean().optional().default(false).describe(
4466
- "If true, the task will be created with auto-approve enabled. Set autoApprove to true when no planning is needed, just execution of the task with all the work."
4541
+ autonomyMode: zod.z.enum(AutonomyMode).optional().describe(
4542
+ '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
4543
  ),
4468
4544
  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
4545
  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
4546
  executeInBackground: zod.z.boolean().optional().default(false).describe("If true, the task will be created and executed in the background.")
4471
4547
  }),
4472
4548
  execute: async (input, { toolCallId }) => {
4473
- const { prompt, name, agentProfileId, modelId, mode = "agent", asSubtask = false, autoApprove, worktree, executeAndWait, executeInBackground } = input;
4549
+ const { prompt, name, agentProfileId, modelId, mode = "agent", asSubtask = false, autonomyMode, worktree, executeAndWait, executeInBackground } = input;
4474
4550
  const parentTaskId = asSubtask ? task.task.parentId || task.taskId : "parentTaskId" in input ? input.parentTaskId : void 0;
4475
4551
  task.addToolMessage(toolCallId, TASKS_TOOL_GROUP_NAME, TASKS_TOOL_CREATE_TASK, input, void 0, void 0, promptContext);
4476
4552
  const toolName = `${TASKS_TOOL_GROUP_NAME}${TOOL_GROUP_NAME_SEPARATOR}${TASKS_TOOL_CREATE_TASK}`;
@@ -4488,7 +4564,7 @@ Parent Task ID: ${parentTaskId || "none (top-level task)"}` : ""}`;
4488
4564
  const newTask = await task.getProject().createNewTask({
4489
4565
  parentId: parentTaskId || null,
4490
4566
  name: name || "",
4491
- autoApprove,
4567
+ autonomyMode,
4492
4568
  workingMode: worktree ? "worktree" : "local"
4493
4569
  });
4494
4570
  const updates = {};
@@ -4566,6 +4642,66 @@ Parent Task ID: ${parentTaskId || "none (top-level task)"}` : ""}`;
4566
4642
  }
4567
4643
  }
4568
4644
  });
4645
+ const runPromptTool = ai.tool({
4646
+ description: TASKS_TOOL_DESCRIPTIONS[TASKS_TOOL_RUN_PROMPT],
4647
+ inputSchema: zod.z.object({
4648
+ taskId: zod.z.string().describe("The ID of the existing task to run the prompt on"),
4649
+ prompt: zod.z.string().describe("The prompt to run on the task"),
4650
+ mode: zod.z.string().optional().describe("Optional mode to use for the prompt. Use only when explicitly requested by the user."),
4651
+ 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.")
4652
+ }),
4653
+ execute: async (input, { toolCallId }) => {
4654
+ const { taskId, prompt, mode, executeAndWait = true } = input;
4655
+ task.addToolMessage(
4656
+ toolCallId,
4657
+ TASKS_TOOL_GROUP_NAME,
4658
+ TASKS_TOOL_RUN_PROMPT,
4659
+ { taskId, prompt, mode, executeAndWait },
4660
+ void 0,
4661
+ void 0,
4662
+ promptContext
4663
+ );
4664
+ const toolName = `${TASKS_TOOL_GROUP_NAME}${TOOL_GROUP_NAME_SEPARATOR}${TASKS_TOOL_RUN_PROMPT}`;
4665
+ const questionKey = toolName;
4666
+ const questionText = `Approve running prompt on task ${taskId}?`;
4667
+ const questionSubject = `Task ID: ${taskId}
4668
+ Prompt: ${prompt}${executeAndWait ? "\nWait for completion: true" : "\nRun in background: true"}`;
4669
+ const [isApproved, userInput] = await approvalManager.handleToolApproval(toolName, input, questionKey, questionText, questionSubject);
4670
+ if (!isApproved) {
4671
+ return `Running prompt on task denied by user. Reason: ${userInput}`;
4672
+ }
4673
+ try {
4674
+ const targetTask = task.getProject().getTask(taskId);
4675
+ if (!targetTask) {
4676
+ return `Task with ID ${taskId} not found`;
4677
+ }
4678
+ const effectiveMode = mode || targetTask.task.currentMode || "agent";
4679
+ const run = targetTask.runPrompt(prompt, effectiveMode, false);
4680
+ if (executeAndWait) {
4681
+ await run;
4682
+ }
4683
+ const taskState = targetTask.task.state;
4684
+ const contextMessages = await targetTask.getContextMessages();
4685
+ let resultMessage = executeAndWait ? "Prompt has been executed successfully" : "Prompt has been started in the background";
4686
+ if (executeAndWait && taskState === DefaultTaskState.Interrupted) {
4687
+ resultMessage = "Task has been interrupted";
4688
+ } else if (executeAndWait && taskState === DefaultTaskState.Delegated) {
4689
+ resultMessage = "Task has been delegated to a subagent";
4690
+ }
4691
+ return {
4692
+ taskId,
4693
+ result: resultMessage,
4694
+ state: taskState,
4695
+ ...executeAndWait && contextMessages.length > 0 && {
4696
+ lastMessage: contextMessages[contextMessages.length - 1]
4697
+ }
4698
+ };
4699
+ } catch (error) {
4700
+ const errorMessage = error instanceof Error ? error.message : String(error);
4701
+ return `Error running prompt on task: ${errorMessage}`;
4702
+ }
4703
+ }
4704
+ });
4569
4705
  const searchTaskTool = ai.tool({
4570
4706
  description: TASKS_TOOL_DESCRIPTIONS[TASKS_TOOL_SEARCH_TASK],
4571
4707
  inputSchema: zod.z.object({
@@ -4632,6 +4768,7 @@ Please, consider reporting an issue at https://github.com/hotovo/aider-desk/issu
4632
4768
  [`${TASKS_TOOL_GROUP_NAME}${TOOL_GROUP_NAME_SEPARATOR}${TASKS_TOOL_GET_TASK_MESSAGE}`]: getTaskMessageTool,
4633
4769
  [`${TASKS_TOOL_GROUP_NAME}${TOOL_GROUP_NAME_SEPARATOR}${TASKS_TOOL_CREATE_TASK}`]: createTaskTool,
4634
4770
  [`${TASKS_TOOL_GROUP_NAME}${TOOL_GROUP_NAME_SEPARATOR}${TASKS_TOOL_DELETE_TASK}`]: deleteTaskTool,
4771
+ [`${TASKS_TOOL_GROUP_NAME}${TOOL_GROUP_NAME_SEPARATOR}${TASKS_TOOL_RUN_PROMPT}`]: runPromptTool,
4635
4772
  [`${TASKS_TOOL_GROUP_NAME}${TOOL_GROUP_NAME_SEPARATOR}${TASKS_TOOL_SEARCH_TASK}`]: searchTaskTool
4636
4773
  };
4637
4774
  const filteredTools = {};
@@ -4865,7 +5002,7 @@ const createAiderToolset = (task, profile, promptContext) => {
4865
5002
  }
4866
5003
  task.addToolMessage(toolCallId, AIDER_TOOL_GROUP_NAME, AIDER_TOOL_RUN_PROMPT, { prompt }, void 0, void 0, aiderPromptContext);
4867
5004
  const responses = await task.sendPromptToAider(prompt, aiderPromptContext, "code", [], void 0, {
4868
- autoApprove: task.task.autoApprove,
5005
+ autoApprove: task.task.autonomyMode !== AutonomyMode.Manual,
4869
5006
  denyCommands: true
4870
5007
  });
4871
5008
  task.addLogMessage("loading");
@@ -6071,7 +6208,8 @@ const addImportantReminders = async (task, profile, projectProfiles, userRequest
6071
6208
  ${subagents}`);
6072
6209
  }
6073
6210
  }
6074
- if (!task.task.autoApprove && !profile.isSubagent) {
6211
+ const shouldPresentPlan = task.task.autonomyMode !== AutonomyMode.Autonomous;
6212
+ if (shouldPresentPlan && !profile.isSubagent) {
6075
6213
  reminders.push("Before making any complex changes, present the plan and wait for my approval.");
6076
6214
  }
6077
6215
  if (task.getTaskDir() !== task.getProjectDir()) {
@@ -6577,7 +6715,7 @@ ${fileList}`
6577
6715
  task.addToolMessage(options.toolCallId, serverName, messageToolName, effectiveInput, void 0, void 0, promptContext);
6578
6716
  const toolCalledExtensionResult = await this.extensionManager.dispatchEvent(
6579
6717
  "onToolCalled",
6580
- { toolName, agentProfile: profile, input: effectiveInput, abortSignal: options.abortSignal || abortSignal },
6718
+ { toolCallId: options.toolCallId, toolName, agentProfile: profile, input: effectiveInput, abortSignal: options.abortSignal || abortSignal },
6581
6719
  task.project,
6582
6720
  task
6583
6721
  );
@@ -6594,7 +6732,7 @@ ${fileList}`
6594
6732
  }
6595
6733
  const toolFinishedExtensionResult = await this.extensionManager.dispatchEvent(
6596
6734
  "onToolFinished",
6597
- { toolName, agentProfile: profile, input: effectiveInput, output: result },
6735
+ { toolCallId: options.toolCallId, toolName, agentProfile: profile, input: effectiveInput, output: result },
6598
6736
  task.project,
6599
6737
  task
6600
6738
  );
@@ -6770,7 +6908,8 @@ ${fileList}`
6770
6908
  };
6771
6909
  })
6772
6910
  ] : prompt,
6773
- promptContext
6911
+ promptContext,
6912
+ timestamp: Date.now()
6774
6913
  } : null;
6775
6914
  if (userRequestMessage) {
6776
6915
  logger.info("User request message created:", {
@@ -7037,31 +7176,6 @@ ${fileList}`
7037
7176
  return extensionResult2.optimizedMessages ?? optimized;
7038
7177
  };
7039
7178
  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
7179
  return {
7066
7180
  providerOptions,
7067
7181
  model: ai.wrapLanguageModel({
@@ -7086,7 +7200,7 @@ ${fileList}`
7086
7200
  let iterationCount = 0;
7087
7201
  let retryCount = 0;
7088
7202
  while (true) {
7089
- logger.info(`Starting iteration ${iterationCount}`);
7203
+ logger.info(`Starting iteration ${iterationCount}`, { task: task.taskId });
7090
7204
  iterationCount++;
7091
7205
  if (profile.maxIterations > 0 && iterationCount > profile.maxIterations) {
7092
7206
  logger.warn(`Max iterations (${profile.maxIterations}) reached. Stopping agent.`);
@@ -7783,14 +7897,16 @@ ${fileList}`
7783
7897
  ...message,
7784
7898
  id: currentResponseId,
7785
7899
  usageReport,
7786
- promptContext
7900
+ promptContext,
7901
+ timestamp: Date.now()
7787
7902
  });
7788
7903
  } else if (message.role === "tool") {
7789
7904
  messages.push({
7790
7905
  ...message,
7791
7906
  // @ts-expect-error the id is there
7792
7907
  id: message.id || uuid.v4(),
7793
- promptContext
7908
+ promptContext,
7909
+ timestamp: Date.now()
7794
7910
  });
7795
7911
  }
7796
7912
  });
@@ -7903,6 +8019,52 @@ ${extractTextContent(userRequestMessage.content)}`;
7903
8019
  return true;
7904
8020
  }
7905
8021
  }
8022
+ let isDockerCache;
8023
+ const isDocker = () => {
8024
+ if (isDockerCache !== void 0) {
8025
+ return isDockerCache;
8026
+ }
8027
+ try {
8028
+ isDockerCache = fs__namespace.existsSync("/.dockerenv") || fs__namespace.existsSync("/run/.containerenv");
8029
+ } catch {
8030
+ isDockerCache = false;
8031
+ }
8032
+ return isDockerCache;
8033
+ };
8034
+ const isNetworkDrive = (drivePath) => {
8035
+ try {
8036
+ const driveLetter = drivePath.charAt(0).toUpperCase();
8037
+ const output = child_process.execSync(`net use ${driveLetter}:`, {
8038
+ encoding: "utf8",
8039
+ timeout: 5e3,
8040
+ stdio: ["pipe", "pipe", "pipe"]
8041
+ });
8042
+ return output.includes("\\\\") || output.includes("//");
8043
+ } catch {
8044
+ return false;
8045
+ }
8046
+ };
8047
+ const shouldUsePolling = (watchPath, mode = FileWatchMode.Auto) => {
8048
+ if (mode === FileWatchMode.Polling) {
8049
+ return true;
8050
+ }
8051
+ if (mode === FileWatchMode.Native) {
8052
+ return false;
8053
+ }
8054
+ if (isDocker()) {
8055
+ logger.debug(`[FileWatch] Docker environment detected, using polling for ${watchPath}`);
8056
+ return true;
8057
+ }
8058
+ if (process.platform === "win32") {
8059
+ const isUncPath = watchPath.startsWith("\\\\") || watchPath.startsWith("//");
8060
+ const isNetworkLetterDrive = /^[A-Za-z]:/.test(watchPath) && isNetworkDrive(watchPath);
8061
+ if (isUncPath || isNetworkLetterDrive) {
8062
+ logger.debug(`[FileWatch] Network path detected (${watchPath}), using polling`);
8063
+ return true;
8064
+ }
8065
+ }
8066
+ return false;
8067
+ };
7906
8068
  const getGlobalAgentsDir = () => path__namespace.join(os.homedir(), AIDER_DESK_AGENTS_DIR);
7907
8069
  const getProjectAgentsDir = (projectDir) => path__namespace.join(projectDir, AIDER_DESK_AGENTS_DIR);
7908
8070
  const getAgentsDirForProfile = (profile) => profile.projectDir ? getProjectAgentsDir(profile.projectDir) : getGlobalAgentsDir();
@@ -7935,9 +8097,10 @@ const getAllRuleFilesForProfile = async (profile, dirName) => {
7935
8097
  return ruleFiles;
7936
8098
  };
7937
8099
  class AgentProfileManager {
7938
- constructor(eventManager, extensionManager) {
8100
+ constructor(eventManager, extensionManager, store) {
7939
8101
  this.eventManager = eventManager;
7940
8102
  this.extensionManager = extensionManager;
8103
+ this.store = store;
7941
8104
  this.extensionsChangeListener = () => {
7942
8105
  this.sendAgentProfilesUpdated();
7943
8106
  };
@@ -8052,12 +8215,12 @@ class AgentProfileManager {
8052
8215
  }
8053
8216
  const watcher = chokidar.watch(agentsDir, {
8054
8217
  persistent: true,
8055
- usePolling: true,
8218
+ usePolling: shouldUsePolling(agentsDir, this.store.getSettings().fileWatchMode),
8056
8219
  ignoreInitial: true
8057
8220
  });
8058
8221
  const rulesWatcher = chokidar.watch(path__namespace.join(agentsDir, "*", AIDER_DESK_RULES_DIR), {
8059
8222
  persistent: true,
8060
- usePolling: true,
8223
+ usePolling: shouldUsePolling(agentsDir, this.store.getSettings().fileWatchMode),
8061
8224
  ignoreInitial: true
8062
8225
  });
8063
8226
  const reloadFunction = () => this.debounceReloadProfiles(agentsDir);
@@ -8455,6 +8618,22 @@ class AgentProfileManager {
8455
8618
  this.directoryWatchers.clear();
8456
8619
  this.profiles.clear();
8457
8620
  }
8621
+ async settingsChanged(oldSettings, newSettings) {
8622
+ if (oldSettings.fileWatchMode === newSettings.fileWatchMode) {
8623
+ return;
8624
+ }
8625
+ const watchedDirs = Array.from(this.directoryWatchers.keys());
8626
+ for (const watcher of this.directoryWatchers.values()) {
8627
+ await watcher.close();
8628
+ }
8629
+ this.directoryWatchers.clear();
8630
+ for (const dir of watchedDirs) {
8631
+ if (dir.endsWith("-rules")) {
8632
+ continue;
8633
+ }
8634
+ await this.setupWatcherForDirectory(dir);
8635
+ }
8636
+ }
8458
8637
  getDefaultAgentProfileId() {
8459
8638
  for (const defaultProfile of DEFAULT_AGENT_PROFILES) {
8460
8639
  if (this.profiles.has(defaultProfile.id)) {
@@ -9037,7 +9216,8 @@ const InitProjectRulesFileSchema = zod.z.object({
9037
9216
  const CreateNewTaskSchema = zod.z.object({
9038
9217
  projectDir: zod.z.string().min(1, "Project directory is required"),
9039
9218
  parentId: zod.z.string().nullable().optional(),
9040
- name: zod.z.string().optional()
9219
+ name: zod.z.string().optional(),
9220
+ activate: zod.z.boolean().optional()
9041
9221
  });
9042
9222
  const UpdateTaskSchema = zod.z.object({
9043
9223
  projectDir: zod.z.string().min(1, "Project directory is required"),
@@ -9335,8 +9515,8 @@ class ProjectApi extends BaseApi {
9335
9515
  if (!parsed) {
9336
9516
  return;
9337
9517
  }
9338
- const { projectDir, parentId, name } = parsed;
9339
- const params = { parentId, name };
9518
+ const { projectDir, parentId, name, activate } = parsed;
9519
+ const params = { parentId, name, activate };
9340
9520
  const task = await this.eventsHandler.createNewTask(projectDir, params);
9341
9521
  res.status(200).json(task);
9342
9522
  })
@@ -10663,6 +10843,18 @@ class ExtensionsApi extends BaseApi {
10663
10843
  res.status(200).json(result);
10664
10844
  })
10665
10845
  );
10846
+ router.post(
10847
+ "/extensions/load-library",
10848
+ this.handleRequest(async (req, res) => {
10849
+ const { librarySpec } = req.body;
10850
+ if (!librarySpec) {
10851
+ res.status(400).json({ message: "librarySpec is required" });
10852
+ return;
10853
+ }
10854
+ const source = await this.eventsHandler.loadExtensionLibrary(librarySpec);
10855
+ res.status(200).type("application/javascript").send(source);
10856
+ })
10857
+ );
10666
10858
  router.get(
10667
10859
  "/extensions/config-component",
10668
10860
  this.handleRequest(async (req, res) => {
@@ -11402,10 +11594,11 @@ class ShellCommandError extends Error {
11402
11594
  }
11403
11595
  const execAsync$1 = util.promisify(child_process.exec);
11404
11596
  class CustomCommandManager {
11405
- constructor(project, eventManager, extensionManager) {
11597
+ constructor(project, eventManager, extensionManager, store) {
11406
11598
  this.project = project;
11407
11599
  this.eventManager = eventManager;
11408
11600
  this.extensionManager = extensionManager;
11601
+ this.store = store;
11409
11602
  }
11410
11603
  commands = /* @__PURE__ */ new Map();
11411
11604
  watchers = [];
@@ -11445,7 +11638,7 @@ class CustomCommandManager {
11445
11638
  }
11446
11639
  const watcher = chokidar.watch(commandsDir, {
11447
11640
  persistent: true,
11448
- usePolling: true,
11641
+ usePolling: shouldUsePolling(commandsDir, this.store.getSettings().fileWatchMode),
11449
11642
  ignoreInitial: true
11450
11643
  });
11451
11644
  watcher.on("add", async () => {
@@ -11503,7 +11696,7 @@ class CustomCommandManager {
11503
11696
  const args = Array.isArray(parsed.arguments) ? parsed.arguments : [];
11504
11697
  const template = parsed.__content?.trim() || "";
11505
11698
  const includeContext = typeof parsed.includeContext === "boolean" ? parsed.includeContext : true;
11506
- const autoApprove = typeof parsed.autoApprove === "boolean" ? parsed.autoApprove : void 0;
11699
+ const autonomyMode = typeof parsed.autonomyMode === "string" && ["manual", "guided", "autonomous"].includes(parsed.autonomyMode) ? parsed.autonomyMode : void 0;
11507
11700
  const skills = typeof parsed.skills === "string" && parsed.skills.trim() ? parsed.skills.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
11508
11701
  commands.set(name, {
11509
11702
  name,
@@ -11511,7 +11704,7 @@ class CustomCommandManager {
11511
11704
  arguments: args,
11512
11705
  template,
11513
11706
  includeContext,
11514
- autoApprove,
11707
+ autonomyMode,
11515
11708
  skills
11516
11709
  });
11517
11710
  } catch (err) {
@@ -11644,6 +11837,14 @@ class CustomCommandManager {
11644
11837
  this.watchers.forEach((watcher) => watcher.close());
11645
11838
  this.watchers = [];
11646
11839
  }
11840
+ async settingsChanged(oldSettings, newSettings) {
11841
+ if (oldSettings.fileWatchMode === newSettings.fileWatchMode) {
11842
+ return;
11843
+ }
11844
+ this.watchers.forEach((watcher) => watcher.close());
11845
+ this.watchers = [];
11846
+ await this.setupFileWatchers();
11847
+ }
11647
11848
  }
11648
11849
  const migrateContextMessage = (message) => {
11649
11850
  if (Array.isArray(message.content)) {
@@ -11778,7 +11979,8 @@ class ContextManager {
11778
11979
  id: uuid.v4(),
11779
11980
  role: roleOrMessage,
11780
11981
  content: content || "",
11781
- usageReport
11982
+ usageReport,
11983
+ timestamp: Date.now()
11782
11984
  };
11783
11985
  } else {
11784
11986
  message = roleOrMessage;
@@ -12427,6 +12629,7 @@ ${JSON.stringify(part.output.value)}`
12427
12629
  toolMessage.response = JSON.stringify(part.output.value);
12428
12630
  toolMessage.usageReport = message.usageReport || toolMessage.usageReport;
12429
12631
  toolMessage.promptContext = promptContext;
12632
+ toolMessage.finished = true;
12430
12633
  }
12431
12634
  if (serverName === AIDER_TOOL_GROUP_NAME && toolName === AIDER_TOOL_RUN_PROMPT && part.output?.value && typeof part.output.value === "object" && "responses" in part.output.value) {
12432
12635
  const responses = part.output.value.responses;
@@ -12444,7 +12647,8 @@ ${JSON.stringify(part.output.value)}`
12444
12647
  commitMessage: response.commitMessage,
12445
12648
  diff: response.diff,
12446
12649
  usageReport: response.usageReport,
12447
- promptContext: message.promptContext
12650
+ promptContext: message.promptContext,
12651
+ timestamp: message.timestamp
12448
12652
  };
12449
12653
  messagesData.push(responseCompletedData);
12450
12654
  });
@@ -12483,7 +12687,8 @@ ${JSON.stringify(part.output.value)}`
12483
12687
  baseDir: this.task.getProjectDir(),
12484
12688
  taskId: this.taskId,
12485
12689
  usageReport: subMessage.usageReport,
12486
- promptContext: subMessage.promptContext
12690
+ promptContext: subMessage.promptContext,
12691
+ timestamp: subMessage.timestamp
12487
12692
  };
12488
12693
  messagesData.push(responseCompletedData);
12489
12694
  }
@@ -12499,7 +12704,8 @@ ${JSON.stringify(part.output.value)}`
12499
12704
  toolName: subToolName,
12500
12705
  args: subPart.input,
12501
12706
  usageReport: void 0,
12502
- promptContext: subMessage.promptContext
12707
+ promptContext: subMessage.promptContext,
12708
+ timestamp: subMessage.timestamp
12503
12709
  };
12504
12710
  messagesData.push(toolData);
12505
12711
  }
@@ -12513,7 +12719,8 @@ ${JSON.stringify(part.output.value)}`
12513
12719
  baseDir: this.task.getProjectDir(),
12514
12720
  taskId: this.taskId,
12515
12721
  usageReport: subMessage.usageReport,
12516
- promptContext: subMessage.promptContext
12722
+ promptContext: subMessage.promptContext,
12723
+ timestamp: subMessage.timestamp
12517
12724
  };
12518
12725
  messagesData.push(responseCompletedData);
12519
12726
  }
@@ -12523,6 +12730,7 @@ ${JSON.stringify(part.output.value)}`
12523
12730
  const toolMessage2 = messagesData.find((message2) => message2.type === "tool" && message2.id === subPart.toolCallId);
12524
12731
  if (toolMessage2) {
12525
12732
  toolMessage2.response = JSON.stringify(subPart.output.value);
12733
+ toolMessage2.finished = true;
12526
12734
  }
12527
12735
  }
12528
12736
  }
@@ -12556,7 +12764,8 @@ ${JSON.stringify(part.output.value)}`
12556
12764
  commitMessage: message.commitMessage,
12557
12765
  diff: message.diff,
12558
12766
  usageReport: message.usageReport,
12559
- promptContext: message.promptContext
12767
+ promptContext: message.promptContext,
12768
+ timestamp: message.timestamp
12560
12769
  };
12561
12770
  messagesData.push(responseCompletedData);
12562
12771
  reasoning = "";
@@ -12585,7 +12794,8 @@ ${JSON.stringify(part.output.value)}`
12585
12794
  toolName,
12586
12795
  args: toolCall.input,
12587
12796
  usageReport: message.usageReport,
12588
- promptContext: message.promptContext
12797
+ promptContext: message.promptContext,
12798
+ timestamp: message.timestamp
12589
12799
  };
12590
12800
  messagesData.push(toolData);
12591
12801
  } else if (part.type === "tool-result") {
@@ -12600,6 +12810,7 @@ ${JSON.stringify(part.output.value)}`
12600
12810
  if (toolMessage) {
12601
12811
  toolMessage.response = JSON.stringify(toolResultData.output);
12602
12812
  toolMessage.usageReport = message.usageReport || toolMessage.usageReport;
12813
+ toolMessage.finished = true;
12603
12814
  const promptContext = extractPromptContextFromToolResult(toolResultData.output);
12604
12815
  if (promptContext) {
12605
12816
  toolMessage.promptContext = promptContext;
@@ -12619,7 +12830,8 @@ ${JSON.stringify(part.output.value)}`
12619
12830
  taskId: this.taskId,
12620
12831
  reflectedMessage: message.reflectedMessage,
12621
12832
  usageReport: message.usageReport,
12622
- promptContext: message.promptContext
12833
+ promptContext: message.promptContext,
12834
+ timestamp: message.timestamp
12623
12835
  };
12624
12836
  messagesData.push(responseCompletedData);
12625
12837
  }
@@ -12637,7 +12849,8 @@ ${JSON.stringify(part.output.value)}`
12637
12849
  taskId: this.taskId,
12638
12850
  content,
12639
12851
  images: images && images.length > 0 ? images : void 0,
12640
- promptContext: message.promptContext
12852
+ promptContext: message.promptContext,
12853
+ timestamp: message.timestamp
12641
12854
  };
12642
12855
  messagesData.push(userMessageData);
12643
12856
  } else if (message.role === "tool" && Array.isArray(message.content)) {
@@ -13395,7 +13608,16 @@ class SkillManager {
13395
13608
  loadSkillsFromDir(projectSkillsDir, "project"),
13396
13609
  loadSkillsFromDir(AIDER_DESK_BUILTIN_SKILLS_DIR, "builtin")
13397
13610
  ]);
13398
- return [...projectSkills, ...globalSkills, ...builtinSkills, ...extensionSkills];
13611
+ const allSkills = [...extensionSkills, ...projectSkills, ...globalSkills, ...builtinSkills];
13612
+ const seen = /* @__PURE__ */ new Set();
13613
+ const deduped = [];
13614
+ for (const skill of allSkills) {
13615
+ if (!seen.has(skill.name)) {
13616
+ seen.add(skill.name);
13617
+ deduped.push(skill);
13618
+ }
13619
+ }
13620
+ return deduped;
13399
13621
  }
13400
13622
  async getSkills(contextMessages) {
13401
13623
  const skills = await this.loadAllSkills();
@@ -15211,6 +15433,12 @@ Git output: ${err.stderr || err.stdout || err.message}`
15211
15433
  await this.pruneDeleted(projectDir);
15212
15434
  }
15213
15435
  }
15436
+ var CompactionLevel = /* @__PURE__ */ ((CompactionLevel2) => {
15437
+ CompactionLevel2[CompactionLevel2["One"] = 1] = "One";
15438
+ CompactionLevel2[CompactionLevel2["Two"] = 2] = "Two";
15439
+ CompactionLevel2[CompactionLevel2["Three"] = 3] = "Three";
15440
+ return CompactionLevel2;
15441
+ })(CompactionLevel || {});
15214
15442
  const extractFilePath = (args) => {
15215
15443
  if (typeof args === "object" && args !== null && "filePath" in args) {
15216
15444
  return args.filePath;
@@ -15327,10 +15555,9 @@ const getProtectedStartIndex = (messages, protectedMessageCount) => {
15327
15555
  return Math.max(0, messages.length - protectedMessageCount);
15328
15556
  };
15329
15557
  const mergeConsecutiveAssistantMessages = (messages) => {
15330
- const result = cloneMessages(messages);
15331
- for (let i = result.length - 2; i >= 0; i--) {
15332
- const current = result[i];
15333
- const next = result[i + 1];
15558
+ for (let i = messages.length - 2; i >= 0; i--) {
15559
+ const current = messages[i];
15560
+ const next = messages[i + 1];
15334
15561
  if (current.role !== "assistant" || next.role !== "assistant") {
15335
15562
  continue;
15336
15563
  }
@@ -15343,35 +15570,95 @@ const mergeConsecutiveAssistantMessages = (messages) => {
15343
15570
  const nextTextParts = Array.isArray(next.content) ? next.content.filter((p) => p.type === "text") : [];
15344
15571
  const mergedText = [...currentTextParts, ...nextTextParts].map((p) => p.text).filter(Boolean).join("\n\n");
15345
15572
  current.content = mergedText ? [{ type: "text", text: mergedText }] : [];
15346
- result.splice(i + 1, 1);
15573
+ messages.splice(i + 1, 1);
15347
15574
  }
15348
- return result.filter((msg) => {
15575
+ return messages.filter((msg) => {
15349
15576
  if (msg.role === "assistant" && Array.isArray(msg.content) && msg.content.length === 0) {
15350
15577
  return false;
15351
15578
  }
15352
15579
  return true;
15353
15580
  });
15354
15581
  };
15355
- const smartCompactMessages = (messages, protectedMessageCount = 10) => {
15582
+ const truncateNonPowerToolResults = async (messages, protectedMessageCount = 10, compactionLevel = 1) => {
15583
+ const protectedStart = getProtectedStartIndex(messages, protectedMessageCount);
15584
+ const redactionMessage = "Result redacted due to compaction, run again if needed.";
15585
+ for (let i = 0; i < protectedStart; i++) {
15586
+ const msg = messages[i];
15587
+ if (msg.role !== "tool") {
15588
+ continue;
15589
+ }
15590
+ for (let j = 0; j < msg.content.length; j++) {
15591
+ const part = msg.content[j];
15592
+ if (part.type !== "tool-result") {
15593
+ continue;
15594
+ }
15595
+ const [serverName] = extractServerNameToolName(part.toolName);
15596
+ if (isPowerTool(serverName)) {
15597
+ continue;
15598
+ }
15599
+ if (compactionLevel >= 3) {
15600
+ if (part.output.type === "text" || part.output.type === "error-text") {
15601
+ part.output = {
15602
+ type: part.output.type,
15603
+ value: redactionMessage
15604
+ };
15605
+ } else {
15606
+ part.output = {
15607
+ type: "text",
15608
+ value: redactionMessage
15609
+ };
15610
+ }
15611
+ continue;
15612
+ }
15613
+ if (part.output.type !== "text" && part.output.type !== "error-text") {
15614
+ continue;
15615
+ }
15616
+ const outputText = part.output.value;
15617
+ if (!outputText) {
15618
+ continue;
15619
+ }
15620
+ const maxLines = compactionLevel >= 2 ? 10 : 20;
15621
+ const maxSizeKB = compactionLevel >= 2 ? 1 : 2;
15622
+ const maxTokens = compactionLevel >= 2 ? 1e3 : 2e3;
15623
+ const truncated = await truncateToolResult(
15624
+ outputText,
15625
+ maxLines,
15626
+ maxSizeKB,
15627
+ maxTokens,
15628
+ false,
15629
+ "Output truncated due to compaction, re-execute the tool if full output is needed."
15630
+ );
15631
+ if (truncated !== outputText) {
15632
+ part.output = {
15633
+ type: part.output.type,
15634
+ value: truncated
15635
+ };
15636
+ }
15637
+ }
15638
+ }
15639
+ return messages;
15640
+ };
15641
+ const smartCompactMessages = async (messages, protectedMessageCount = 10, compactionLevel = 1) => {
15356
15642
  let result = cloneMessages(messages);
15357
15643
  result = removeErroredTools(result, protectedMessageCount);
15358
15644
  result = collapseFileEdits(result, protectedMessageCount);
15359
15645
  result = removeStaleFileReads(result, protectedMessageCount);
15360
- result = removeObsoleteSearches(result, protectedMessageCount);
15361
- result = compactSemanticSearches(result, protectedMessageCount);
15362
- result = deduplicateBash(result, protectedMessageCount);
15646
+ result = compactFileReads(result, protectedMessageCount, compactionLevel);
15647
+ result = removeObsoleteSearches(result, protectedMessageCount, compactionLevel);
15648
+ result = compactSemanticSearches(result, protectedMessageCount, compactionLevel);
15649
+ result = deduplicateBash(result, protectedMessageCount, compactionLevel);
15363
15650
  result = redactFetchOutputs(result, protectedMessageCount);
15651
+ result = await truncateNonPowerToolResults(result, protectedMessageCount, compactionLevel);
15364
15652
  result = mergeConsecutiveAssistantMessages(result);
15365
15653
  return result;
15366
15654
  };
15367
15655
  const removeErroredTools = (messages, protectedMessageCount = 10) => {
15368
- const result = cloneMessages(messages);
15369
- const protectedStart = getProtectedStartIndex(result, protectedMessageCount);
15656
+ const protectedStart = getProtectedStartIndex(messages, protectedMessageCount);
15370
15657
  for (let i = protectedStart - 1; i >= 0; i--) {
15371
- if (i >= result.length) {
15658
+ if (i >= messages.length) {
15372
15659
  continue;
15373
15660
  }
15374
- const msg = result[i];
15661
+ const msg = messages[i];
15375
15662
  if (msg.role !== "tool") {
15376
15663
  continue;
15377
15664
  }
@@ -15381,22 +15668,21 @@ const removeErroredTools = (messages, protectedMessageCount = 10) => {
15381
15668
  continue;
15382
15669
  }
15383
15670
  if (isErrorResult(info.output) || isNoOpResult(info.output)) {
15384
- removeToolCallFromAssistant(result, info.toolCallId);
15385
- removeToolResult(result, info.toolCallId);
15671
+ removeToolCallFromAssistant(messages, info.toolCallId);
15672
+ removeToolResult(messages, info.toolCallId);
15386
15673
  }
15387
15674
  }
15388
15675
  }
15389
- return result;
15676
+ return messages;
15390
15677
  };
15391
15678
  const collapseFileEdits = (messages, protectedMessageCount = 10) => {
15392
- const result = cloneMessages(messages);
15393
- const protectedStart = getProtectedStartIndex(result, protectedMessageCount);
15679
+ const protectedStart = getProtectedStartIndex(messages, protectedMessageCount);
15394
15680
  const fileEditGroups = /* @__PURE__ */ new Map();
15395
15681
  for (let i = 0; i < protectedStart; i++) {
15396
- if (i >= result.length) {
15682
+ if (i >= messages.length) {
15397
15683
  break;
15398
15684
  }
15399
- const msg = result[i];
15685
+ const msg = messages[i];
15400
15686
  if (msg.role !== "tool") {
15401
15687
  continue;
15402
15688
  }
@@ -15411,7 +15697,7 @@ const collapseFileEdits = (messages, protectedMessageCount = 10) => {
15411
15697
  if (toolName !== POWER_TOOL_FILE_EDIT && toolName !== POWER_TOOL_FILE_WRITE) {
15412
15698
  continue;
15413
15699
  }
15414
- const callInfo = findAssistantToolCall(result, part.toolCallId);
15700
+ const callInfo = findAssistantToolCall(messages, part.toolCallId);
15415
15701
  if (!callInfo) {
15416
15702
  continue;
15417
15703
  }
@@ -15443,22 +15729,21 @@ const collapseFileEdits = (messages, protectedMessageCount = 10) => {
15443
15729
  }
15444
15730
  ]
15445
15731
  };
15446
- const assistantIndex = result.findIndex((m) => m.id === lastEdit.assistantMessageId);
15732
+ const assistantIndex = messages.findIndex((m) => m.id === lastEdit.assistantMessageId);
15447
15733
  const insertIndex = assistantIndex !== -1 ? assistantIndex + 1 : 0;
15448
- result.splice(insertIndex, 0, syntheticMessage);
15734
+ messages.splice(insertIndex, 0, syntheticMessage);
15449
15735
  for (const edit of edits) {
15450
- removeToolCallFromAssistant(result, edit.toolCallId);
15451
- removeToolResult(result, edit.toolCallId);
15736
+ removeToolCallFromAssistant(messages, edit.toolCallId);
15737
+ removeToolResult(messages, edit.toolCallId);
15452
15738
  }
15453
15739
  }
15454
- return result;
15740
+ return messages;
15455
15741
  };
15456
15742
  const removeStaleFileReads = (messages, protectedMessageCount = 10) => {
15457
- const result = cloneMessages(messages);
15458
- const protectedStart = getProtectedStartIndex(result, protectedMessageCount);
15743
+ const protectedStart = getProtectedStartIndex(messages, protectedMessageCount);
15459
15744
  const editedFilePaths = /* @__PURE__ */ new Set();
15460
- for (let i = 0; i < result.length; i++) {
15461
- const msg = result[i];
15745
+ for (let i = 0; i < messages.length; i++) {
15746
+ const msg = messages[i];
15462
15747
  if (msg.role === "assistant" && Array.isArray(msg.content)) {
15463
15748
  for (const part of msg.content) {
15464
15749
  if (part.type === "text") {
@@ -15484,7 +15769,7 @@ const removeStaleFileReads = (messages, protectedMessageCount = 10) => {
15484
15769
  if (toolName !== POWER_TOOL_FILE_EDIT && toolName !== POWER_TOOL_FILE_WRITE) {
15485
15770
  continue;
15486
15771
  }
15487
- const callInfo = findAssistantToolCall(result, part.toolCallId);
15772
+ const callInfo = findAssistantToolCall(messages, part.toolCallId);
15488
15773
  if (callInfo) {
15489
15774
  const filePath = extractFilePath(callInfo.input);
15490
15775
  if (filePath) {
@@ -15494,8 +15779,8 @@ const removeStaleFileReads = (messages, protectedMessageCount = 10) => {
15494
15779
  }
15495
15780
  }
15496
15781
  const protectedReadFilePaths = /* @__PURE__ */ new Set();
15497
- for (let i = protectedStart; i < result.length; i++) {
15498
- const msg = result[i];
15782
+ for (let i = protectedStart; i < messages.length; i++) {
15783
+ const msg = messages[i];
15499
15784
  if (msg.role !== "tool") {
15500
15785
  continue;
15501
15786
  }
@@ -15507,7 +15792,7 @@ const removeStaleFileReads = (messages, protectedMessageCount = 10) => {
15507
15792
  if (!isPowerTool(serverName) || toolName !== POWER_TOOL_FILE_READ) {
15508
15793
  continue;
15509
15794
  }
15510
- const callInfo = findAssistantToolCall(result, part.toolCallId);
15795
+ const callInfo = findAssistantToolCall(messages, part.toolCallId);
15511
15796
  if (callInfo) {
15512
15797
  const filePath = extractFilePath(callInfo.input);
15513
15798
  if (filePath) {
@@ -15518,10 +15803,10 @@ const removeStaleFileReads = (messages, protectedMessageCount = 10) => {
15518
15803
  }
15519
15804
  const readFileGroups = /* @__PURE__ */ new Map();
15520
15805
  for (let i = protectedStart - 1; i >= 0; i--) {
15521
- if (i >= result.length) {
15806
+ if (i >= messages.length) {
15522
15807
  continue;
15523
15808
  }
15524
- const msg = result[i];
15809
+ const msg = messages[i];
15525
15810
  if (msg.role !== "tool") {
15526
15811
  continue;
15527
15812
  }
@@ -15533,7 +15818,7 @@ const removeStaleFileReads = (messages, protectedMessageCount = 10) => {
15533
15818
  if (!isPowerTool(serverName) || toolName !== POWER_TOOL_FILE_READ) {
15534
15819
  continue;
15535
15820
  }
15536
- const callInfo = findAssistantToolCall(result, part.toolCallId);
15821
+ const callInfo = findAssistantToolCall(messages, part.toolCallId);
15537
15822
  if (!callInfo) {
15538
15823
  continue;
15539
15824
  }
@@ -15542,8 +15827,8 @@ const removeStaleFileReads = (messages, protectedMessageCount = 10) => {
15542
15827
  continue;
15543
15828
  }
15544
15829
  if (editedFilePaths.has(filePath) || protectedReadFilePaths.has(filePath)) {
15545
- removeToolCallFromAssistant(result, part.toolCallId);
15546
- removeToolResult(result, part.toolCallId);
15830
+ removeToolCallFromAssistant(messages, part.toolCallId);
15831
+ removeToolResult(messages, part.toolCallId);
15547
15832
  continue;
15548
15833
  }
15549
15834
  if (!readFileGroups.has(filePath)) {
@@ -15561,18 +15846,58 @@ const removeStaleFileReads = (messages, protectedMessageCount = 10) => {
15561
15846
  }
15562
15847
  const toRemove = reads.slice(0, -1);
15563
15848
  for (const read of toRemove) {
15564
- removeToolCallFromAssistant(result, read.toolCallId);
15565
- removeToolResult(result, read.toolCallId);
15849
+ removeToolCallFromAssistant(messages, read.toolCallId);
15850
+ removeToolResult(messages, read.toolCallId);
15566
15851
  }
15567
15852
  }
15568
- return result;
15853
+ return messages;
15854
+ };
15855
+ const compactFileReads = (messages, protectedMessageCount = 10, compactionLevel = 1) => {
15856
+ const protectedStart = getProtectedStartIndex(messages, protectedMessageCount);
15857
+ const maxLines = compactionLevel === 3 ? 0 : compactionLevel === 2 ? 20 : 50;
15858
+ for (let i = 0; i < protectedStart; i++) {
15859
+ if (i >= messages.length) {
15860
+ break;
15861
+ }
15862
+ const msg = messages[i];
15863
+ if (msg.role !== "tool") {
15864
+ continue;
15865
+ }
15866
+ for (let j = 0; j < msg.content.length; j++) {
15867
+ const part = msg.content[j];
15868
+ if (part.type !== "tool-result") {
15869
+ continue;
15870
+ }
15871
+ const [serverName, toolName] = extractServerNameToolName(part.toolName);
15872
+ if (!isPowerTool(serverName) || toolName !== POWER_TOOL_FILE_READ) {
15873
+ continue;
15874
+ }
15875
+ if (part.output.type !== "text") {
15876
+ continue;
15877
+ }
15878
+ if (compactionLevel === 3) {
15879
+ part.output = {
15880
+ type: "text",
15881
+ value: "<result redacted due to compaction, read the file again if content is needed>"
15882
+ };
15883
+ continue;
15884
+ }
15885
+ const lines = part.output.value.split("\n");
15886
+ if (lines.length > maxLines) {
15887
+ part.output = {
15888
+ type: "text",
15889
+ value: lines.slice(0, maxLines).join("\n") + "\n<truncated due to compaction, read the file again if full content is needed>"
15890
+ };
15891
+ }
15892
+ }
15893
+ }
15894
+ return messages;
15569
15895
  };
15570
- const removeObsoleteSearches = (messages, protectedMessageCount = 10) => {
15571
- const result = cloneMessages(messages);
15572
- const protectedStart = getProtectedStartIndex(result, protectedMessageCount);
15896
+ const removeObsoleteSearches = (messages, protectedMessageCount = 10, compactionLevel = 1) => {
15897
+ const protectedStart = getProtectedStartIndex(messages, protectedMessageCount);
15573
15898
  const fileModificationPositions = [];
15574
- for (let i = 0; i < result.length; i++) {
15575
- const msg = result[i];
15899
+ for (let i = 0; i < messages.length; i++) {
15900
+ const msg = messages[i];
15576
15901
  if (msg.role === "assistant" && Array.isArray(msg.content)) {
15577
15902
  for (const part of msg.content) {
15578
15903
  if (part.type === "text" && part.text.includes("<file-edited")) {
@@ -15599,14 +15924,14 @@ const removeObsoleteSearches = (messages, protectedMessageCount = 10) => {
15599
15924
  }
15600
15925
  }
15601
15926
  const hasFileModifications = fileModificationPositions.length > 0;
15602
- if (!hasFileModifications) {
15603
- return result;
15927
+ if (!hasFileModifications && compactionLevel < 3) {
15928
+ return messages;
15604
15929
  }
15605
15930
  for (let i = protectedStart - 1; i >= 0; i--) {
15606
- if (i >= result.length) {
15931
+ if (i >= messages.length) {
15607
15932
  continue;
15608
15933
  }
15609
- const msg = result[i];
15934
+ const msg = messages[i];
15610
15935
  if (msg.role !== "tool") {
15611
15936
  continue;
15612
15937
  }
@@ -15621,24 +15946,23 @@ const removeObsoleteSearches = (messages, protectedMessageCount = 10) => {
15621
15946
  if (toolName !== POWER_TOOL_GLOB && toolName !== POWER_TOOL_GREP) {
15622
15947
  continue;
15623
15948
  }
15624
- const hasLaterModification = fileModificationPositions.some((pos) => pos > i);
15625
- if (hasLaterModification) {
15626
- removeToolCallFromAssistant(result, part.toolCallId);
15627
- removeToolResult(result, part.toolCallId);
15949
+ const shouldRemove = compactionLevel >= 3 || fileModificationPositions.some((pos) => pos > i);
15950
+ if (shouldRemove) {
15951
+ removeToolCallFromAssistant(messages, part.toolCallId);
15952
+ removeToolResult(messages, part.toolCallId);
15628
15953
  }
15629
15954
  }
15630
15955
  }
15631
- return result;
15956
+ return messages;
15632
15957
  };
15633
- const compactSemanticSearches = (messages, protectedMessageCount = 10) => {
15634
- const result = cloneMessages(messages);
15635
- const protectedStart = getProtectedStartIndex(result, protectedMessageCount);
15958
+ const compactSemanticSearches = (messages, protectedMessageCount = 10, compactionLevel = 1) => {
15959
+ const protectedStart = getProtectedStartIndex(messages, protectedMessageCount);
15636
15960
  const searchIndices = [];
15637
15961
  for (let i = 0; i < protectedStart; i++) {
15638
- if (i >= result.length) {
15962
+ if (i >= messages.length) {
15639
15963
  break;
15640
15964
  }
15641
- const msg = result[i];
15965
+ const msg = messages[i];
15642
15966
  if (msg.role !== "tool") {
15643
15967
  continue;
15644
15968
  }
@@ -15654,38 +15978,45 @@ const compactSemanticSearches = (messages, protectedMessageCount = 10) => {
15654
15978
  searchIndices.push({ messageIndex: i, partIndex: j, toolCallId: part.toolCallId });
15655
15979
  }
15656
15980
  }
15657
- if (searchIndices.length <= 1) {
15658
- return result;
15981
+ if (searchIndices.length <= 1 && compactionLevel < 3) {
15982
+ return messages;
15983
+ }
15984
+ if (compactionLevel >= 3) {
15985
+ for (const search2 of searchIndices) {
15986
+ removeToolCallFromAssistant(messages, search2.toolCallId);
15987
+ removeToolResult(messages, search2.toolCallId);
15988
+ }
15989
+ return messages;
15659
15990
  }
15660
15991
  const toRemove = searchIndices.slice(0, -1);
15661
15992
  const toKeep = searchIndices[searchIndices.length - 1];
15662
15993
  for (const search2 of toRemove) {
15663
- removeToolCallFromAssistant(result, search2.toolCallId);
15664
- removeToolResult(result, search2.toolCallId);
15994
+ removeToolCallFromAssistant(messages, search2.toolCallId);
15995
+ removeToolResult(messages, search2.toolCallId);
15665
15996
  }
15666
- const keptToolIdx = result.findIndex((m) => m.role === "tool" && m.content.some((p) => p.type === "tool-result" && p.toolCallId === toKeep.toolCallId));
15997
+ const maxLines = compactionLevel === 2 ? 20 : 50;
15998
+ const keptToolIdx = messages.findIndex((m) => m.role === "tool" && m.content.some((p) => p.type === "tool-result" && p.toolCallId === toKeep.toolCallId));
15667
15999
  if (keptToolIdx !== -1) {
15668
- const keptMsg = result[keptToolIdx];
16000
+ const keptMsg = messages[keptToolIdx];
15669
16001
  const keptPartIdx = keptMsg.content.findIndex((p) => p.type === "tool-result" && p.toolCallId === toKeep.toolCallId);
15670
16002
  const keptPart = keptMsg.content[keptPartIdx];
15671
16003
  if (keptPart && keptPart.output.type === "text") {
15672
16004
  const lines = keptPart.output.value.split("\n");
15673
- if (lines.length > 50) {
16005
+ if (lines.length > maxLines) {
15674
16006
  keptPart.output = {
15675
16007
  type: "text",
15676
- value: lines.slice(0, 50).join("\n") + "\n<truncated due to compaction, run again if full output is needed>"
16008
+ value: lines.slice(0, maxLines).join("\n") + "\n<truncated due to compaction, run again if full output is needed>"
15677
16009
  };
15678
16010
  }
15679
16011
  }
15680
16012
  }
15681
- return result;
16013
+ return messages;
15682
16014
  };
15683
- const deduplicateBash = (messages, protectedMessageCount = 10) => {
15684
- const result = cloneMessages(messages);
15685
- const protectedStart = getProtectedStartIndex(result, protectedMessageCount);
16015
+ const deduplicateBash = (messages, protectedMessageCount = 10, compactionLevel = 1) => {
16016
+ const protectedStart = getProtectedStartIndex(messages, protectedMessageCount);
15686
16017
  const bashCommands = /* @__PURE__ */ new Map();
15687
16018
  for (let i = 0; i < protectedStart; i++) {
15688
- const msg = result[i];
16019
+ const msg = messages[i];
15689
16020
  if (msg.role !== "tool") {
15690
16021
  continue;
15691
16022
  }
@@ -15697,7 +16028,7 @@ const deduplicateBash = (messages, protectedMessageCount = 10) => {
15697
16028
  if (!isPowerTool(serverName) || toolName !== POWER_TOOL_BASH) {
15698
16029
  continue;
15699
16030
  }
15700
- const callInfo = findAssistantToolCall(result, part.toolCallId);
16031
+ const callInfo = findAssistantToolCall(messages, part.toolCallId);
15701
16032
  if (!callInfo) {
15702
16033
  continue;
15703
16034
  }
@@ -15720,15 +16051,15 @@ const deduplicateBash = (messages, protectedMessageCount = 10) => {
15720
16051
  }
15721
16052
  const toRemove = occurrences.slice(0, -1);
15722
16053
  for (const occ of toRemove) {
15723
- removeToolCallFromAssistant(result, occ.toolCallId);
15724
- removeToolResult(result, occ.toolCallId);
16054
+ removeToolCallFromAssistant(messages, occ.toolCallId);
16055
+ removeToolResult(messages, occ.toolCallId);
15725
16056
  }
15726
16057
  }
15727
16058
  for (let i = 0; i < protectedStart; i++) {
15728
- if (i >= result.length) {
16059
+ if (i >= messages.length) {
15729
16060
  break;
15730
16061
  }
15731
- const msg = result[i];
16062
+ const msg = messages[i];
15732
16063
  if (msg.role !== "tool") {
15733
16064
  continue;
15734
16065
  }
@@ -15741,6 +16072,13 @@ const deduplicateBash = (messages, protectedMessageCount = 10) => {
15741
16072
  if (!isPowerTool(serverName) || toolName !== POWER_TOOL_BASH) {
15742
16073
  continue;
15743
16074
  }
16075
+ if (compactionLevel >= 3) {
16076
+ part.output = {
16077
+ type: "text",
16078
+ value: "<result redacted due to compaction, run again if needed>"
16079
+ };
16080
+ continue;
16081
+ }
15744
16082
  if (part.output.type !== "text") {
15745
16083
  continue;
15746
16084
  }
@@ -15751,11 +16089,12 @@ const deduplicateBash = (messages, protectedMessageCount = 10) => {
15751
16089
  const stderr = typeof parsed.stderr === "string" ? parsed.stderr : "";
15752
16090
  const redactionMessage = "<output redacted due to compaction, run again if output is needed>";
15753
16091
  let modified = false;
15754
- if (stdout.length > 30) {
16092
+ const redactionThreshold = compactionLevel >= 2 ? 0 : 30;
16093
+ if (stdout.length > redactionThreshold) {
15755
16094
  parsed.stdout = redactionMessage;
15756
16095
  modified = true;
15757
16096
  }
15758
- if (stderr.length > 30) {
16097
+ if (stderr.length > redactionThreshold) {
15759
16098
  parsed.stderr = redactionMessage;
15760
16099
  modified = true;
15761
16100
  }
@@ -15770,13 +16109,12 @@ const deduplicateBash = (messages, protectedMessageCount = 10) => {
15770
16109
  }
15771
16110
  }
15772
16111
  }
15773
- return result;
16112
+ return messages;
15774
16113
  };
15775
16114
  const redactFetchOutputs = (messages, protectedMessageCount = 10) => {
15776
- const result = cloneMessages(messages);
15777
- const protectedStart = getProtectedStartIndex(result, protectedMessageCount);
16115
+ const protectedStart = getProtectedStartIndex(messages, protectedMessageCount);
15778
16116
  for (let i = 0; i < protectedStart; i++) {
15779
- const msg = result[i];
16117
+ const msg = messages[i];
15780
16118
  if (msg.role !== "tool") {
15781
16119
  continue;
15782
16120
  }
@@ -15798,7 +16136,7 @@ const redactFetchOutputs = (messages, protectedMessageCount = 10) => {
15798
16136
  }
15799
16137
  }
15800
16138
  }
15801
- return result;
16139
+ return messages;
15802
16140
  };
15803
16141
  const INTERNAL_TASK_ID = "internal";
15804
16142
  const RESPONSE_CHUNK_FLUSH_INTERVAL_MS = 10;
@@ -15886,6 +16224,8 @@ class Task {
15886
16224
  tokensInfo;
15887
16225
  queuedPrompts = [];
15888
16226
  isCompacting = false;
16227
+ lastSmartCompactionMessageCount = 0;
16228
+ smartCompactionLevel = CompactionLevel.One;
15889
16229
  taskDataPath;
15890
16230
  contextManager;
15891
16231
  agent;
@@ -16375,7 +16715,8 @@ class Task {
16375
16715
  id: promptContext.id,
16376
16716
  role: MessageRole.User,
16377
16717
  content: prompt,
16378
- promptContext
16718
+ promptContext,
16719
+ timestamp: Date.now()
16379
16720
  });
16380
16721
  this.addUserMessage(promptContext.id, prompt);
16381
16722
  await this.saveTask({
@@ -16408,7 +16749,8 @@ class Task {
16408
16749
  id: promptContext.id,
16409
16750
  role: MessageRole.User,
16410
16751
  content: prompt,
16411
- promptContext
16752
+ promptContext,
16753
+ timestamp: Date.now()
16412
16754
  });
16413
16755
  let messages = this.contextManager.toConnectorMessages();
16414
16756
  let files = this.contextManager.getContextFiles();
@@ -16427,8 +16769,9 @@ class Task {
16427
16769
  promptContext = extensionResult.promptContext;
16428
16770
  messages = extensionResult.messages;
16429
16771
  files = extensionResult.files;
16772
+ const effectiveAutonomyMode = extensionResult.autonomyMode ?? this.task.autonomyMode ?? DEFAULT_AUTONOMY_MODE;
16430
16773
  let responses = await this.sendPromptToAider(prompt, promptContext, mode, messages, files, {
16431
- autoApprove: extensionResult.autoApprove ?? this.task.autoApprove,
16774
+ autoApprove: effectiveAutonomyMode === AutonomyMode.Autonomous,
16432
16775
  denyCommands: extensionResult.denyCommands
16433
16776
  });
16434
16777
  logger.debug("Responses:", { responses });
@@ -16813,7 +17156,8 @@ ${contentText}</agent-response>`;
16813
17156
  diff: message.diff,
16814
17157
  usageReport,
16815
17158
  sequenceNumber: message.sequenceNumber,
16816
- promptContext: message.promptContext
17159
+ promptContext: message.promptContext,
17160
+ timestamp: Date.now()
16817
17161
  };
16818
17162
  const extensionResult = await this.extensionManager.dispatchEvent("onResponseCompleted", { response: data }, this.project, this);
16819
17163
  data = extensionResult.response;
@@ -16880,14 +17224,20 @@ ${contentText}</agent-response>`;
16880
17224
  if (!determinedAnswer) {
16881
17225
  determinedAnswer = normalizedAnswer === "a" || normalizedAnswer === "y" ? "y" : "n";
16882
17226
  }
16883
- if ((normalizedAnswer === "d" || normalizedAnswer === "a") && (determinedAnswer == "y" || determinedAnswer == "n")) {
16884
- logger.debug('Storing answer for question due to "d" or "a" input:', {
17227
+ if (normalizedAnswer === "a") {
17228
+ logger.debug('Storing answer for question due to "a" (Always) input:', {
17229
+ baseDir: this.project.baseDir,
17230
+ questionKey: this.getQuestionKey(this.currentQuestion),
17231
+ rawInput: answer
17232
+ });
17233
+ this.storedQuestionAnswers.set(this.getQuestionKey(this.currentQuestion), "y");
17234
+ } else if (normalizedAnswer === "d") {
17235
+ logger.debug(`Storing answer for question due to "d" (Don't ask again) input:`, {
16885
17236
  baseDir: this.project.baseDir,
16886
17237
  questionKey: this.getQuestionKey(this.currentQuestion),
16887
- rawInput: answer,
16888
- determinedAndStoredAnswer: determinedAnswer
17238
+ rawInput: answer
16889
17239
  });
16890
- this.storedQuestionAnswers.set(this.getQuestionKey(this.currentQuestion), determinedAnswer);
17240
+ this.storedQuestionAnswers.set(this.getQuestionKey(this.currentQuestion), "n");
16891
17241
  }
16892
17242
  const questionToAnswer = this.currentQuestion;
16893
17243
  if (!this.currentQuestion.internal) {
@@ -17050,11 +17400,21 @@ ${contentText}</agent-response>`;
17050
17400
  void this.updateContextInfo(true, true);
17051
17401
  }
17052
17402
  async askQuestion(questionData, awaitAnswer = true) {
17053
- const extensionResult = await this.extensionManager.dispatchEvent("onQuestionAsked", { question: questionData }, this.project, this);
17403
+ let storedAnswer = this.storedQuestionAnswers.get(this.getQuestionKey(questionData));
17404
+ const extensionResult = await this.extensionManager.dispatchEvent(
17405
+ "onQuestionAsked",
17406
+ {
17407
+ question: questionData,
17408
+ storedAnswer
17409
+ },
17410
+ this.project,
17411
+ this
17412
+ );
17054
17413
  if (extensionResult.answer) {
17055
17414
  logger.info("Question answered by extension", {
17056
17415
  question: questionData.text,
17057
- answer: extensionResult.answer
17416
+ answer: extensionResult.answer,
17417
+ storedAnswer
17058
17418
  });
17059
17419
  return [extensionResult.answer, void 0];
17060
17420
  }
@@ -17064,7 +17424,7 @@ ${contentText}</agent-response>`;
17064
17424
  this.currentQuestionResolves.push(resolve);
17065
17425
  });
17066
17426
  }
17067
- const storedAnswer = this.storedQuestionAnswers.get(this.getQuestionKey(questionData));
17427
+ storedAnswer = this.storedQuestionAnswers.get(this.getQuestionKey(questionData));
17068
17428
  if (questionData.isGroupQuestion && !questionData.answers) {
17069
17429
  questionData.answers = [
17070
17430
  { text: "(Y)es", shortkey: "y" },
@@ -17405,7 +17765,8 @@ ${contentText}</agent-response>`;
17405
17765
  message,
17406
17766
  finished,
17407
17767
  promptContext,
17408
- actionIds
17768
+ actionIds,
17769
+ timestamp: Date.now()
17409
17770
  };
17410
17771
  this.eventManager.sendLog(data);
17411
17772
  }
@@ -17556,6 +17917,7 @@ ${contentText}</agent-response>`;
17556
17917
  lastAgentProviderMetadata: null
17557
17918
  });
17558
17919
  }
17920
+ this.smartCompactionLevel = CompactionLevel.One;
17559
17921
  this.contextManager.clearMessages(true, createSnapshot);
17560
17922
  await this.runCommand("clear", addToHistory);
17561
17923
  this.eventManager.sendClearTask(this.project.baseDir, this.taskId, true, false);
@@ -17757,7 +18119,8 @@ ${contentText}</agent-response>`;
17757
18119
  response,
17758
18120
  usageReport,
17759
18121
  promptContext,
17760
- finished
18122
+ finished,
18123
+ timestamp: Date.now()
17761
18124
  };
17762
18125
  if (response && usageReport && saveToDb) {
17763
18126
  this.dataManager.saveMessage(id, "tool", this.project.baseDir, usageReport.model, usageReport, {
@@ -17798,7 +18161,8 @@ ${contentText}</agent-response>`;
17798
18161
  taskId: this.taskId,
17799
18162
  content,
17800
18163
  images,
17801
- promptContext
18164
+ promptContext,
18165
+ timestamp: Date.now()
17802
18166
  };
17803
18167
  this.eventManager.sendUserMessage(data);
17804
18168
  }
@@ -17841,7 +18205,9 @@ ${contentText}</agent-response>`;
17841
18205
  const removedMessages = this.contextManager.removeMessagesUpToUserMessage(messageId);
17842
18206
  const originalUserMessage = removedMessages[0];
17843
18207
  if (!originalUserMessage || originalUserMessage.role !== MessageRole.User) {
17844
- logger.warn("Could not find the specified user message to redo.", { messageId });
18208
+ logger.warn("Could not find the specified user message to redo.", {
18209
+ messageId
18210
+ });
17845
18211
  return;
17846
18212
  }
17847
18213
  const originalText = extractTextContent(originalUserMessage.content);
@@ -17958,7 +18324,14 @@ ${contentText}</agent-response>`;
17958
18324
  return [];
17959
18325
  }
17960
18326
  await this.contextManager.backupContext();
17961
- const compactedMessages = smartCompactMessages(contextMessages);
18327
+ const messagesSinceLastCompaction = contextMessages.length - this.lastSmartCompactionMessageCount;
18328
+ if (messagesSinceLastCompaction <= 3) {
18329
+ this.smartCompactionLevel = Math.min(this.smartCompactionLevel + 1, CompactionLevel.Three);
18330
+ } else if (messagesSinceLastCompaction > 5) {
18331
+ this.smartCompactionLevel = CompactionLevel.One;
18332
+ }
18333
+ const compactedMessages = await smartCompactMessages(contextMessages, 10, this.smartCompactionLevel);
18334
+ this.lastSmartCompactionMessageCount = compactedMessages.length;
17962
18335
  this.contextManager.setContextMessages(compactedMessages);
17963
18336
  await this.contextManager.loadMessages(compactedMessages, false);
17964
18337
  await this.updateContextInfo();
@@ -18121,7 +18494,7 @@ ${contentText}</agent-response>`;
18121
18494
  const newTaskData = await this.project.createNewTask({
18122
18495
  parentId: this.task.parentId || this.taskId,
18123
18496
  sendEvent: false,
18124
- autoApprove: execute ? this.task.autoApprove : void 0,
18497
+ autonomyMode: execute ? this.task.autonomyMode : void 0,
18125
18498
  activate: true
18126
18499
  });
18127
18500
  const newTask = this.project.getTask(newTaskData.id);
@@ -18441,7 +18814,12 @@ ${error.stderr}`,
18441
18814
  }
18442
18815
  }
18443
18816
  }
18444
- const systemPrompt = await this.promptsManager.getSystemPrompt(this.store.getSettings(), this, profile, command.autoApprove ?? this.task.autoApprove);
18817
+ const systemPrompt = await this.promptsManager.getSystemPrompt(
18818
+ this.store.getSettings(),
18819
+ this,
18820
+ profile,
18821
+ command.autonomyMode ?? this.task.autonomyMode ?? DEFAULT_AUTONOMY_MODE
18822
+ );
18445
18823
  const messages = command.includeContext === false ? [] : void 0;
18446
18824
  const contextFiles = command.includeContext === false ? [] : void 0;
18447
18825
  this.addLogMessage("loading", "Executing custom command...");
@@ -18876,7 +19254,13 @@ ${diff}
18876
19254
  if (success) {
18877
19255
  const newHead = await this.worktreeManager.getHeadCommit(this.task.worktree.path);
18878
19256
  if (newHead) {
18879
- await this.saveTask({ worktree: { ...this.task.worktree, baseCommit: newHead, baseBranch: effectiveFromBranch } });
19257
+ await this.saveTask({
19258
+ worktree: {
19259
+ ...this.task.worktree,
19260
+ baseCommit: newHead,
19261
+ baseBranch: effectiveFromBranch
19262
+ }
19263
+ });
18880
19264
  }
18881
19265
  this.addLogMessage("info", "Worktree rebased successfully", true);
18882
19266
  return;
@@ -19192,7 +19576,7 @@ ${diff}
19192
19576
  const newTaskData = await this.project.createNewTask({
19193
19577
  name: taskName,
19194
19578
  sendEvent: false,
19195
- autoApprove: true,
19579
+ autonomyMode: AutonomyMode.Autonomous,
19196
19580
  activate: true,
19197
19581
  mode,
19198
19582
  parentId: this.task.parentId || this.taskId,
@@ -19332,7 +19716,7 @@ class Project {
19332
19716
  this.promptsManager = promptsManager;
19333
19717
  this.extensionManager = extensionManager;
19334
19718
  this.pythonInstaller = pythonInstaller;
19335
- this.customCommandManager = new CustomCommandManager(this, this.eventManager, this.extensionManager);
19719
+ this.customCommandManager = new CustomCommandManager(this, this.eventManager, this.extensionManager, this.store);
19336
19720
  this.tasksLoadingPromise = this.loadTasks();
19337
19721
  }
19338
19722
  customCommandManager;
@@ -19408,9 +19792,7 @@ class Project {
19408
19792
  ...normalizedParams
19409
19793
  };
19410
19794
  }
19411
- const projectSettings = this.getProjectSettings();
19412
19795
  const taskData = {
19413
- autoApprove: projectSettings.autoApproveLocked ? true : initialTaskData.autoApprove,
19414
19796
  ...initialTaskData
19415
19797
  };
19416
19798
  const extResult = await this.extensionManager.dispatchEvent("onTaskCreated", { task: taskData }, this);
@@ -19712,6 +20094,7 @@ class Project {
19712
20094
  this.forEachTask((task) => {
19713
20095
  void task.settingsChanged(oldSettings, newSettings);
19714
20096
  });
20097
+ void this.customCommandManager.settingsChanged(oldSettings, newSettings);
19715
20098
  }
19716
20099
  async projectSettingsChanged(oldSettings, newSettings) {
19717
20100
  this.forEachTask((task) => {
@@ -19961,7 +20344,8 @@ class EventManager {
19961
20344
  baseDir,
19962
20345
  taskId,
19963
20346
  command,
19964
- output
20347
+ output,
20348
+ timestamp: Date.now()
19965
20349
  };
19966
20350
  this.sendToWindows("command-output", data);
19967
20351
  this.broadcastToEventConnectors("command-output", data);
@@ -22570,6 +22954,117 @@ const mistralProviderStrategy = {
22570
22954
  getAiderMapping: getMistralAiderMapping,
22571
22955
  getModelInfo: getDefaultModelInfo
22572
22956
  };
22957
+ const NEURALWATT_BASE_URL = "https://api.neuralwatt.com/v1";
22958
+ const loadNeuralwattModels = async (profile, settings) => {
22959
+ if (!isNeuralwattProvider(profile.provider)) {
22960
+ return { models: [], success: false };
22961
+ }
22962
+ const provider = profile.provider;
22963
+ const apiKey = provider.apiKey || "";
22964
+ const apiKeyEnv = getEffectiveEnvironmentVariable("NEURALWATT_API_KEY", settings);
22965
+ const effectiveApiKey = apiKey || apiKeyEnv?.value || "";
22966
+ if (!effectiveApiKey) {
22967
+ logger.debug("Neuralwatt API key is required. Please set it in Providers settings or via NEURALWATT_API_KEY environment variable.");
22968
+ return { models: [], success: false };
22969
+ }
22970
+ try {
22971
+ const response = await fetch(`${NEURALWATT_BASE_URL}/models`, {
22972
+ headers: { Authorization: `Bearer ${effectiveApiKey}` }
22973
+ });
22974
+ if (!response.ok) {
22975
+ const errorMsg = `Neuralwatt models API response failed: ${response.status} ${response.statusText} ${await response.text()}`;
22976
+ logger.error(errorMsg, { status: response.status, statusText: response.statusText });
22977
+ return { models: [], success: false, error: errorMsg };
22978
+ }
22979
+ const data = await response.json();
22980
+ logger.debug(`Received response from Neuralwatt models API for profile ${profile.id}`, { data });
22981
+ const models = data.data?.map((model) => {
22982
+ const metadata = model.metadata;
22983
+ const pricing = metadata?.pricing;
22984
+ const limits = metadata?.limits;
22985
+ const capabilities = metadata?.capabilities;
22986
+ return {
22987
+ id: model.id,
22988
+ providerId: profile.id,
22989
+ maxInputTokens: limits?.max_context_length ?? model.max_model_len,
22990
+ maxOutputTokensLimit: limits?.max_output_tokens ?? void 0,
22991
+ inputCostPerToken: pricing ? pricing.input_per_million / 1e6 : void 0,
22992
+ outputCostPerToken: pricing ? pricing.output_per_million / 1e6 : void 0,
22993
+ cacheReadInputTokenCost: pricing?.cached_input_per_million != null ? pricing.cached_input_per_million / 1e6 : void 0,
22994
+ supportsTools: capabilities?.tools
22995
+ };
22996
+ }) || [];
22997
+ logger.info(`Loaded ${models.length} Neuralwatt models for profile ${profile.id}`);
22998
+ return { models, success: true };
22999
+ } catch (error) {
23000
+ const errorMsg = typeof error === "string" ? error : error instanceof Error ? error.message : "Unknown error loading Neuralwatt models";
23001
+ logger.error("Error loading Neuralwatt models:", error);
23002
+ return { models: [], success: false, error: errorMsg };
23003
+ }
23004
+ };
23005
+ const hasNeuralwattEnvVars = (settings) => {
23006
+ return !!getEffectiveEnvironmentVariable("NEURALWATT_API_KEY", settings, void 0)?.value;
23007
+ };
23008
+ const getNeuralwattAiderMapping = (provider, modelId) => {
23009
+ const neuralwattProvider = provider.provider;
23010
+ const envVars = {};
23011
+ if (neuralwattProvider.apiKey) {
23012
+ envVars.OPENAI_API_KEY = neuralwattProvider.apiKey;
23013
+ }
23014
+ envVars.OPENAI_API_BASE = NEURALWATT_BASE_URL;
23015
+ return {
23016
+ modelName: `openai/${modelId}`,
23017
+ environmentVariables: envVars
23018
+ };
23019
+ };
23020
+ const createNeuralwattLlm = (profile, model, settings, projectDir) => {
23021
+ const provider = profile.provider;
23022
+ let apiKey = provider.apiKey;
23023
+ if (!apiKey) {
23024
+ const effectiveVar = getEffectiveEnvironmentVariable("NEURALWATT_API_KEY", settings, projectDir);
23025
+ if (effectiveVar) {
23026
+ apiKey = effectiveVar.value;
23027
+ logger.debug(`Loaded NEURALWATT_API_KEY from ${effectiveVar.source}`);
23028
+ }
23029
+ }
23030
+ if (!apiKey) {
23031
+ throw new Error("Neuralwatt API key is required in Providers settings or Aider environment variables (NEURALWATT_API_KEY)");
23032
+ }
23033
+ const compatibleProvider = openaiCompatible.createOpenAICompatible({
23034
+ name: "neuralwatt",
23035
+ apiKey,
23036
+ baseURL: NEURALWATT_BASE_URL,
23037
+ headers: profile.headers
23038
+ });
23039
+ return compatibleProvider(model.id);
23040
+ };
23041
+ const getNeuralwattUsageReport = (task, provider, model, usage, providerMetadata) => {
23042
+ const totalSentTokens = usage.inputTokens || 0;
23043
+ const receivedTokens = usage.outputTokens || 0;
23044
+ const cacheReadTokens = usage.cachedInputTokens || 0;
23045
+ const sentTokens = totalSentTokens - cacheReadTokens;
23046
+ logger.info("Neuralwatt usage report", {
23047
+ providerMetadata,
23048
+ usage
23049
+ });
23050
+ const messageCost = calculateCost(model, sentTokens, receivedTokens, cacheReadTokens);
23051
+ return {
23052
+ model: `${provider.id}/${model.id}`,
23053
+ sentTokens,
23054
+ receivedTokens,
23055
+ cacheReadTokens,
23056
+ messageCost,
23057
+ agentTotalCost: task.task.agentTotalCost + messageCost
23058
+ };
23059
+ };
23060
+ const neuralwattProviderStrategy = {
23061
+ createLlm: createNeuralwattLlm,
23062
+ getUsageReport: getNeuralwattUsageReport,
23063
+ loadModels: loadNeuralwattModels,
23064
+ hasEnvVars: hasNeuralwattEnvVars,
23065
+ getAiderMapping: getNeuralwattAiderMapping,
23066
+ getModelInfo: getDefaultModelInfo
23067
+ };
22573
23068
  const loadOllamaModels = async (profile, settings) => {
22574
23069
  if (!isOllamaProvider(profile.provider)) {
22575
23070
  return { models: [], success: false };
@@ -23933,6 +24428,7 @@ class ModelManager {
23933
24428
  lmstudio: lmStudioProviderStrategy,
23934
24429
  minimax: minimaxProviderStrategy,
23935
24430
  mistral: mistralProviderStrategy,
24431
+ neuralwatt: neuralwattProviderStrategy,
23936
24432
  ollama: ollamaProviderStrategy,
23937
24433
  openai: openaiProviderStrategy,
23938
24434
  "openai-compatible": openaiCompatibleProviderStrategy,
@@ -25284,7 +25780,7 @@ class MemoryManager {
25284
25780
  done: this.embeddingProgress.done,
25285
25781
  total: this.embeddingProgress.total,
25286
25782
  finished: true,
25287
- error: "Failed to load @huggingface/transformers. This is usually a packaging issue with native dependencies (e.g. sharp/libvips)."
25783
+ error: "Failed to load @huggingface/transformers. This is usually a packaging issue with native dependencies."
25288
25784
  };
25289
25785
  logger.error("Failed to load transformers module. Memory embedding will be unavailable.", error);
25290
25786
  return;
@@ -25456,7 +25952,7 @@ class MemoryManager {
25456
25952
  done: this.embeddingProgress.done,
25457
25953
  total: this.embeddingProgress.total,
25458
25954
  finished: true,
25459
- error: "Failed to load @huggingface/transformers. This is usually a packaging issue with native dependencies (e.g. sharp/libvips)."
25955
+ error: "Failed to load @huggingface/transformers. This is usually a packaging issue with native dependencies."
25460
25956
  };
25461
25957
  logger.error("Failed to load transformers module. Memory embedding will be unavailable.", error);
25462
25958
  return;
@@ -26112,6 +26608,18 @@ class ExtensionContextImpl {
26112
26608
  return [];
26113
26609
  }
26114
26610
  }
26611
+ getProviders() {
26612
+ if (!this.modelManager) {
26613
+ this.log("ModelManager not available, returning empty providers", "warn");
26614
+ return [];
26615
+ }
26616
+ try {
26617
+ return this.modelManager.getProviders();
26618
+ } catch (error) {
26619
+ this.log(`Failed to get providers: ${error}`, "error");
26620
+ return [];
26621
+ }
26622
+ }
26115
26623
  async getSetting(key) {
26116
26624
  if (!this.store) {
26117
26625
  throw new Error("Store not available");
@@ -26202,8 +26710,11 @@ class ExtensionContextImpl {
26202
26710
  }
26203
26711
  return this.memoryManager;
26204
26712
  }
26713
+ async truncateToolResult(content, maxLines, maxSizeKB, maxTokens, saveToFile, truncationSuffix) {
26714
+ return truncateToolResult(content, maxLines, maxSizeKB, maxTokens, saveToFile, truncationSuffix);
26715
+ }
26205
26716
  }
26206
- const CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
26717
+ const CACHE_TTL_MS$1 = 24 * 60 * 60 * 1e3;
26207
26718
  class ExtensionFetcher {
26208
26719
  cache = /* @__PURE__ */ new Map();
26209
26720
  getAvailableExtensionsPromise = null;
@@ -26234,7 +26745,7 @@ class ExtensionFetcher {
26234
26745
  async fetchExtensionsFromRepo(repoUrl, forceRefresh) {
26235
26746
  const cached = this.cache.get(repoUrl);
26236
26747
  const now = Date.now();
26237
- if (!forceRefresh && cached && now - cached.timestamp < CACHE_TTL_MS) {
26748
+ if (!forceRefresh && cached && now - cached.timestamp < CACHE_TTL_MS$1) {
26238
26749
  logger.debug(`[ExtensionFetcher] Using cached extensions for ${repoUrl}`);
26239
26750
  return cached.extensions;
26240
26751
  }
@@ -26546,6 +27057,67 @@ class ExtensionFetcher {
26546
27057
  return this.convertToGitHubRawUrl(webUrl);
26547
27058
  }
26548
27059
  }
27060
+ const ESM_SH_BASE_URL = "https://esm.sh";
27061
+ const CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
27062
+ const sanitizeLibraryName = (name) => {
27063
+ return name.replace(/[^a-zA-Z0-9_-]/g, "_");
27064
+ };
27065
+ class ExtensionLibraryLoader {
27066
+ cacheDir;
27067
+ constructor() {
27068
+ this.cacheDir = path.join(AIDER_DESK_CACHE_DIR, "extension-libraries");
27069
+ }
27070
+ getCachePath(librarySpec) {
27071
+ const sanitized = sanitizeLibraryName(librarySpec);
27072
+ return path.join(this.cacheDir, `${sanitized}.js`);
27073
+ }
27074
+ getMetaPath(librarySpec) {
27075
+ const sanitized = sanitizeLibraryName(librarySpec);
27076
+ return path.join(this.cacheDir, `${sanitized}.meta.json`);
27077
+ }
27078
+ async loadLibrary(librarySpec) {
27079
+ const cachePath = this.getCachePath(librarySpec);
27080
+ const metaPath = this.getMetaPath(librarySpec);
27081
+ try {
27082
+ await fs.access(cachePath);
27083
+ await fs.access(metaPath);
27084
+ try {
27085
+ const meta = JSON.parse(await fs.readFile(metaPath, "utf-8"));
27086
+ const age = Date.now() - new Date(meta.fetchedAt).getTime();
27087
+ if (age < CACHE_TTL_MS) {
27088
+ logger.debug(`[ExtensionLibraryLoader] Cache hit for ${librarySpec}`);
27089
+ return await fs.readFile(cachePath, "utf-8");
27090
+ }
27091
+ logger.info(`[ExtensionLibraryLoader] Cache stale for ${librarySpec} (age: ${Math.round(age / 1e3 / 60)}min), re-fetching`);
27092
+ } catch {
27093
+ logger.warn(`[ExtensionLibraryLoader] Failed to read meta for ${librarySpec}, re-fetching`);
27094
+ }
27095
+ } catch {
27096
+ }
27097
+ logger.info(`[ExtensionLibraryLoader] Fetching ${librarySpec} from esm.sh`);
27098
+ const url = `${ESM_SH_BASE_URL}/${librarySpec}?external=react,react-dom,react/jsx-runtime,react/jsx-dev-runtime&bundle-deps&bundle`;
27099
+ let response = await fetchWithTimeout(url);
27100
+ if (!response.ok) {
27101
+ throw new Error(`Failed to fetch library ${librarySpec} from esm.sh: ${response.status} ${response.statusText}`);
27102
+ }
27103
+ let source = await response.text();
27104
+ const redirectMatch = source.match(/export\s+\*\s+from\s+["']([^"']+)["']/);
27105
+ if (redirectMatch) {
27106
+ const bundleUrl = `${ESM_SH_BASE_URL}${redirectMatch[1]}`;
27107
+ logger.debug(`[ExtensionLibraryLoader] Following redirect to ${bundleUrl}`);
27108
+ response = await fetchWithTimeout(bundleUrl);
27109
+ if (!response.ok) {
27110
+ throw new Error(`Failed to fetch bundle for ${librarySpec} from esm.sh: ${response.status} ${response.statusText}`);
27111
+ }
27112
+ source = await response.text();
27113
+ }
27114
+ await fs.mkdir(this.cacheDir, { recursive: true });
27115
+ await fs.writeFile(cachePath, source, "utf-8");
27116
+ await fs.writeFile(metaPath, JSON.stringify({ librarySpec, fetchedAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf-8");
27117
+ logger.info(`[ExtensionLibraryLoader] Cached ${librarySpec}`);
27118
+ return source;
27119
+ }
27120
+ }
26549
27121
  class ExtensionManager {
26550
27122
  constructor(store, modelManager, eventManager, telemetryManager, memoryManager, registry = new ExtensionRegistry()) {
26551
27123
  this.store = store;
@@ -26556,6 +27128,7 @@ class ExtensionManager {
26556
27128
  this.registry = registry;
26557
27129
  this.loader = new ExtensionLoader();
26558
27130
  this.fetcher = new ExtensionFetcher();
27131
+ this.libraryLoader = new ExtensionLibraryLoader();
26559
27132
  }
26560
27133
  loader;
26561
27134
  fetcher;
@@ -26563,6 +27136,7 @@ class ExtensionManager {
26563
27136
  projectWatchers = /* @__PURE__ */ new Map();
26564
27137
  initialized = false;
26565
27138
  listeners = [];
27139
+ libraryLoader;
26566
27140
  debouncedNotifyListeners = debounce(() => {
26567
27141
  const extensions = this.registry.getExtensions();
26568
27142
  for (const listener of this.listeners) {
@@ -26607,6 +27181,9 @@ class ExtensionManager {
26607
27181
  logger.debug("[Extensions] Repository list changed, refreshing extension cache");
26608
27182
  void this.fetcher.getAvailableExtensions(newRepositories, true);
26609
27183
  }
27184
+ if (oldSettings.fileWatchMode !== newSettings.fileWatchMode) {
27185
+ void this.restartWatchers();
27186
+ }
26610
27187
  }
26611
27188
  addListener(listener) {
26612
27189
  this.listeners.push(listener);
@@ -26911,7 +27488,7 @@ class ExtensionManager {
26911
27488
  };
26912
27489
  const watcher = chokidar.watch(dir, {
26913
27490
  persistent: true,
26914
- usePolling: true,
27491
+ usePolling: shouldUsePolling(dir, this.store.getSettings().fileWatchMode),
26915
27492
  ignoreInitial: true,
26916
27493
  ignored: (filePath) => {
26917
27494
  const basename = path.basename(filePath);
@@ -26995,6 +27572,25 @@ class ExtensionManager {
26995
27572
  logger.debug(`[Extensions] Stopped watching project extensions: ${projectDir}`);
26996
27573
  }
26997
27574
  }
27575
+ async restartWatchers() {
27576
+ const projectDirs = Array.from(this.projectWatchers.keys());
27577
+ await this.stopGlobalWatcher();
27578
+ for (const dir of projectDirs) {
27579
+ await this.stopProjectWatcher(dir);
27580
+ }
27581
+ await this.startHotReloadWatcher();
27582
+ for (const dir of projectDirs) {
27583
+ const projectExtensionsDir = path.join(dir, AIDER_DESK_EXTENSIONS_DIR);
27584
+ const watcher = await this.setupWatcherForDir(projectExtensionsDir, async () => {
27585
+ logger.debug(`[Extensions] Project extensions changed for ${dir}, reloading...`);
27586
+ await this.unloadExtensionsForDir(projectExtensionsDir);
27587
+ await this.loadExtensionsForDir(projectExtensionsDir);
27588
+ });
27589
+ if (watcher) {
27590
+ this.projectWatchers.set(dir, watcher);
27591
+ }
27592
+ }
27593
+ }
26998
27594
  static TOOL_NAME_REGEX = /^[a-z][a-z0-9_-]*$/;
26999
27595
  validateToolDefinition(tool) {
27000
27596
  const errors = [];
@@ -27395,6 +27991,39 @@ class ExtensionManager {
27395
27991
  }
27396
27992
  return collectedComponents;
27397
27993
  }
27994
+ getUIComponentsLibraries(project) {
27995
+ const librariesByExtension = /* @__PURE__ */ new Map();
27996
+ const allExtensions = this.registry.getExtensions(project?.baseDir);
27997
+ const extensions = this.filterEnabledExtensions(allExtensions);
27998
+ for (const loaded of extensions) {
27999
+ const { instance, initialized, metadata } = loaded;
28000
+ if (!initialized || !instance.getUIComponentsLibraries) {
28001
+ continue;
28002
+ }
28003
+ try {
28004
+ const libraries = instance.getUIComponentsLibraries();
28005
+ if (typeof libraries !== "object" || libraries === null || Array.isArray(libraries)) {
28006
+ logger.error(`[Extensions] Extension '${metadata.name}' getUIComponentsLibraries() did not return a Record<string, string>`);
28007
+ continue;
28008
+ }
28009
+ const validLibs = {};
28010
+ for (const [key, spec] of Object.entries(libraries)) {
28011
+ if (typeof key === "string" && typeof spec === "string") {
28012
+ validLibs[key] = spec;
28013
+ }
28014
+ }
28015
+ if (Object.keys(validLibs).length > 0) {
28016
+ librariesByExtension.set(loaded.id, validLibs);
28017
+ }
28018
+ } catch (error) {
28019
+ logger.error(`[Extensions] Failed to get UI component libraries from extension '${metadata.name}':`, error);
28020
+ }
28021
+ }
28022
+ return librariesByExtension;
28023
+ }
28024
+ async loadExtensionLibrary(librarySpec) {
28025
+ return await this.libraryLoader.loadLibrary(librarySpec);
28026
+ }
27398
28027
  /**
27399
28028
  * Check if an extension provides a settings config component.
27400
28029
  * Uses the dedicated getConfigComponent() method on the Extension interface.
@@ -27913,7 +28542,7 @@ class ExtensionManager {
27913
28542
  }
27914
28543
  }
27915
28544
  class EventsHandler {
27916
- constructor(projectManager, store, mcpManager, versionsManager, modelManager, telemetryManager, dataManager, terminalManager, cloudflareTunnelManager, eventManager, agentProfileManager, memoryManager, extensionManager, proxyManager, windowManager) {
28545
+ constructor(projectManager, store, mcpManager, versionsManager, modelManager, telemetryManager, dataManager, terminalManager, cloudflareTunnelManager, eventManager, agentProfileManager, memoryManager, extensionManager, proxyManager, promptsManager, windowManager) {
27917
28546
  this.projectManager = projectManager;
27918
28547
  this.store = store;
27919
28548
  this.mcpManager = mcpManager;
@@ -27928,6 +28557,7 @@ class EventsHandler {
27928
28557
  this.memoryManager = memoryManager;
27929
28558
  this.extensionManager = extensionManager;
27930
28559
  this.proxyManager = proxyManager;
28560
+ this.promptsManager = promptsManager;
27931
28561
  this.windowManager = windowManager;
27932
28562
  }
27933
28563
  loadSettings() {
@@ -27941,6 +28571,8 @@ class EventsHandler {
27941
28571
  this.telemetryManager.settingsChanged(oldSettings, newSettings);
27942
28572
  void this.memoryManager.settingsChanged(oldSettings, newSettings);
27943
28573
  this.extensionManager.settingsChanged(oldSettings, newSettings);
28574
+ void this.agentProfileManager.settingsChanged(oldSettings, newSettings);
28575
+ void this.promptsManager.settingsChanged(oldSettings, newSettings);
27944
28576
  this.eventManager.sendSettingsUpdated(newSettings);
27945
28577
  return this.store.getSettings();
27946
28578
  }
@@ -28816,15 +29448,20 @@ ${error instanceof Error ? error.message : String(error)}`);
28816
29448
  const task = taskId && project ? project.getTask(taskId) ?? void 0 : void 0;
28817
29449
  const components = this.extensionManager.getUIComponents(project, task);
28818
29450
  const filtered = placement ? components.filter((c) => c.component.placement === placement) : components;
29451
+ const librariesByExtension = this.extensionManager.getUIComponentsLibraries(project);
28819
29452
  return filtered.map((c) => ({
28820
29453
  extensionId: c.extensionId,
28821
29454
  componentId: c.component.id,
28822
29455
  placement: c.component.placement,
28823
29456
  jsx: c.component.jsx,
28824
29457
  loadData: c.component.loadData,
28825
- noDataCache: c.component.noDataCache
29458
+ noDataCache: c.component.noDataCache,
29459
+ libraries: librariesByExtension.get(c.extensionId)
28826
29460
  }));
28827
29461
  }
29462
+ async loadExtensionLibrary(librarySpec) {
29463
+ return await this.extensionManager.loadExtensionLibrary(librarySpec);
29464
+ }
28828
29465
  async getUIExtensionData(extensionId, componentId, projectDir, taskId) {
28829
29466
  logger.debug("Getting UI extension data:", {
28830
29467
  extensionId,
@@ -28921,8 +29558,9 @@ const registerAllHelpers = () => {
28921
29558
  registerFormattingHelpers();
28922
29559
  };
28923
29560
  class PromptsManager {
28924
- constructor(extensionManager, defaultTemplatesDir = AIDER_DESK_DEFAULT_PROMPTS_DIR, globalPromptsDir = AIDER_DESK_GLOBAL_PROMPTS_DIR) {
29561
+ constructor(extensionManager, store, defaultTemplatesDir = AIDER_DESK_DEFAULT_PROMPTS_DIR, globalPromptsDir = AIDER_DESK_GLOBAL_PROMPTS_DIR) {
28925
29562
  this.extensionManager = extensionManager;
29563
+ this.store = store;
28926
29564
  this.defaultTemplatesDir = defaultTemplatesDir;
28927
29565
  this.globalPromptsDir = globalPromptsDir;
28928
29566
  registerAllHelpers();
@@ -29016,7 +29654,7 @@ class PromptsManager {
29016
29654
  }
29017
29655
  const watcher = chokidar.watch(this.globalPromptsDir, {
29018
29656
  persistent: true,
29019
- usePolling: true,
29657
+ usePolling: shouldUsePolling(this.globalPromptsDir, this.store.getSettings().fileWatchMode),
29020
29658
  ignoreInitial: true
29021
29659
  });
29022
29660
  const debouncedReload = debounce(async () => {
@@ -29041,7 +29679,7 @@ class PromptsManager {
29041
29679
  await this.compileProjectTemplates(projectDir);
29042
29680
  const watcher = chokidar.watch(projectPromptsDir, {
29043
29681
  persistent: true,
29044
- usePolling: true,
29682
+ usePolling: shouldUsePolling(projectPromptsDir, this.store.getSettings().fileWatchMode),
29045
29683
  ignoreInitial: true
29046
29684
  });
29047
29685
  const debouncedReload = debounce(async () => {
@@ -29070,6 +29708,20 @@ class PromptsManager {
29070
29708
  this.projectTemplatesCache.clear();
29071
29709
  logger.info("PromptsManager disposed");
29072
29710
  }
29711
+ async settingsChanged(oldSettings, newSettings) {
29712
+ if (oldSettings.fileWatchMode === newSettings.fileWatchMode) {
29713
+ return;
29714
+ }
29715
+ const watchedProjects = Array.from(this.watchers.keys()).filter((k) => k !== "global");
29716
+ for (const watcher of this.watchers.values()) {
29717
+ await watcher.close();
29718
+ }
29719
+ this.watchers.clear();
29720
+ await this.setupGlobalWatcher();
29721
+ for (const projectDir of watchedProjects) {
29722
+ await this.watchProject(projectDir);
29723
+ }
29724
+ }
29073
29725
  async render(name, data, projectDir, task) {
29074
29726
  const projectTemplates = this.projectTemplatesCache.get(projectDir);
29075
29727
  const projectTemplate = projectTemplates?.get(name);
@@ -29095,7 +29747,7 @@ class PromptsManager {
29095
29747
  }
29096
29748
  return prompt;
29097
29749
  }
29098
- calculateToolPermissions = (settings, agentProfile, autoApprove) => {
29750
+ calculateToolPermissions = (settings, agentProfile, autonomyMode) => {
29099
29751
  const { usePowerTools = false, useMemoryTools = false, useSkillsTools = false } = agentProfile;
29100
29752
  const memoryEnabled = settings.memory.enabled && useMemoryTools;
29101
29753
  const isAllowed = (tool) => agentProfile.toolApprovals[tool] !== ToolApprovalState.Never;
@@ -29124,11 +29776,12 @@ class PromptsManager {
29124
29776
  skills: {
29125
29777
  allowed: useSkillsTools && isAllowed(`${SKILLS_TOOL_GROUP_NAME}${TOOL_GROUP_NAME_SEPARATOR}${SKILLS_TOOL_ACTIVATE_SKILL}`)
29126
29778
  },
29127
- autoApprove
29779
+ autonomyMode
29128
29780
  };
29129
29781
  };
29130
- getSystemPrompt = async (settings, task, agentProfile, autoApprove = task.task.autoApprove ?? false, additionalInstructions) => {
29131
- const toolPermissions = this.calculateToolPermissions(settings, agentProfile, autoApprove);
29782
+ getSystemPrompt = async (settings, task, agentProfile, autonomyMode, additionalInstructions) => {
29783
+ const effectiveAutonomyMode = autonomyMode ?? task.task.autonomyMode ?? DEFAULT_AUTONOMY_MODE;
29784
+ const toolPermissions = this.calculateToolPermissions(settings, agentProfile, effectiveAutonomyMode);
29132
29785
  toolPermissions.powerTools.anyEnabled = Object.values(toolPermissions.powerTools).some((v) => v);
29133
29786
  const rulesFiles = await this.getRulesContent(task, agentProfile);
29134
29787
  const customInstructions = [agentProfile.customInstructions, additionalInstructions].filter(Boolean).join("\n\n").trim();
@@ -29537,12 +30190,12 @@ const initManagers = async (store, windowManager) => {
29537
30190
  extensionManager.init().catch((error) => {
29538
30191
  logger.error("[Extensions] Extension system initialization failed, continuing without extensions:", error);
29539
30192
  });
29540
- const promptsManager = new PromptsManager(extensionManager);
30193
+ const promptsManager = new PromptsManager(extensionManager, store);
29541
30194
  promptsManager.init().catch((error) => {
29542
30195
  logger.error("[Prompts] Prompts system initialization failed:", error);
29543
30196
  });
29544
30197
  const worktreeManager = new WorktreeManager();
29545
- const agentProfileManager = new AgentProfileManager(eventManager, extensionManager);
30198
+ const agentProfileManager = new AgentProfileManager(eventManager, extensionManager, store);
29546
30199
  agentProfileManager.init().catch((error) => {
29547
30200
  logger.error("[AgentProfile] Agent profile system initialization failed:", error);
29548
30201
  });
@@ -29579,6 +30232,7 @@ const initManagers = async (store, windowManager) => {
29579
30232
  memoryManager,
29580
30233
  extensionManager,
29581
30234
  proxyManager,
30235
+ promptsManager,
29582
30236
  windowManager
29583
30237
  );
29584
30238
  const serverController = new ServerController(httpServer, projectManager, eventsHandler, store, pythonInstaller);
@@ -30210,7 +30864,8 @@ const DEFAULT_SETTINGS = {
30210
30864
  proxy: {
30211
30865
  enabled: false,
30212
30866
  url: ""
30213
- }
30867
+ },
30868
+ fileWatchMode: FileWatchMode.Auto
30214
30869
  };
30215
30870
  const compareBaseDirs = (baseDir1, baseDir2) => {
30216
30871
  return normalizeBaseDir(baseDir1) === normalizeBaseDir(baseDir2);