@aiderdesk/aiderdesk 0.66.0 → 0.67.0

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