openfox 2.0.133 → 2.0.134

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 (82) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/CHANGELOG.md +12 -0
  3. package/dist/{chat-handler-T47GATL5.js → chat-handler-YCZE2XEJ.js} +23 -22
  4. package/dist/chunk-24YKXKCG.js +35 -0
  5. package/dist/chunk-2OMGR7LN.js +45 -0
  6. package/dist/{chunk-OUQZZEIQ.js → chunk-5IXCCMFU.js} +335 -187
  7. package/dist/{chunk-MQMPIXON.js → chunk-5UMXFLET.js} +3 -3
  8. package/dist/{chunk-5JWJEZJ3.js → chunk-5UQ4CKOA.js} +2 -2
  9. package/dist/{chunk-P5MSY7ZI.js → chunk-7HGBJFIJ.js} +22 -17
  10. package/dist/{chunk-7JVBDBXE.js → chunk-7QMWYNVF.js} +2 -2
  11. package/dist/{chunk-P57IBMK4.js → chunk-AATMPL7S.js} +4 -4
  12. package/dist/{chunk-ZL4IAFF3.js → chunk-BZND27IB.js} +3 -3
  13. package/dist/{chunk-FGNJMKDV.js → chunk-CSYOWFPU.js} +5 -5
  14. package/dist/{chunk-LQKXJPKP.js → chunk-CTWZPN7G.js} +5 -1
  15. package/dist/{chunk-BKMWZTNO.js → chunk-DWA4IE65.js} +14 -2
  16. package/dist/{chunk-RRUSYVQD.js → chunk-FAQDLL2X.js} +8 -8
  17. package/dist/{chunk-HCYSGLY2.js → chunk-HF3NDXB4.js} +1 -1
  18. package/dist/{chunk-6EZDW4JS.js → chunk-J3NMNYGM.js} +2 -2
  19. package/dist/{chunk-HXHPKGJE.js → chunk-J5HOUEPE.js} +614 -157
  20. package/dist/{chunk-A7CB4USC.js → chunk-M4J2L4VH.js} +132 -45
  21. package/dist/{chunk-M5T4RDPJ.js → chunk-MEEUXRFL.js} +2 -2
  22. package/dist/{chunk-OMMPTN6X.js → chunk-MRE4OYKI.js} +69 -27
  23. package/dist/{chunk-MGEYAYGU.js → chunk-O3RCSKUH.js} +2 -2
  24. package/dist/{chunk-ELYHHEYL.js → chunk-ORCQ3EXQ.js} +2 -2
  25. package/dist/{chunk-FEIRWXLX.js → chunk-OZWHRBDY.js} +64 -17
  26. package/dist/{chunk-TACWRDDC.js → chunk-QDARWVQ2.js} +2 -2
  27. package/dist/{chunk-VXG3AFFY.js → chunk-QICVOQNX.js} +8 -8
  28. package/dist/chunk-QTLYD2FF.js +7 -0
  29. package/dist/{chunk-Y6ZGHOKM.js → chunk-YLVOU7T7.js} +4 -4
  30. package/dist/{chunk-GFW2HWJ6.js → chunk-YOPXAI2W.js} +37 -16
  31. package/dist/{chunk-CLDCHOEA.js → chunk-ZMK4VX7V.js} +2 -2
  32. package/dist/{chunk-KWAHD2JA.js → chunk-ZTBKMVV6.js} +2 -2
  33. package/dist/cli/dev.js +4 -1
  34. package/dist/cli/index.js +4 -1
  35. package/dist/{client-2K6PPPJJ.js → client-VVYOWXRR.js} +4 -4
  36. package/dist/{compactor-OEJAA2YP.js → compactor-PD6DQ4NY.js} +9 -9
  37. package/dist/{dynamic-context-NJZKAZE3.js → dynamic-context-WKEXQCTK.js} +10 -10
  38. package/dist/{events-ZJPRGVL2.js → events-3WSNI7XC.js} +6 -6
  39. package/dist/{folding-QRZOHY2I.js → folding-H7JTX6KI.js} +4 -4
  40. package/dist/{http-client-P4XTKAZA.js → http-client-A445WYZU.js} +3 -3
  41. package/dist/{install-VA2F6X6Z.js → install-AVTFA344.js} +64 -15
  42. package/dist/{launch-UKXVO37B.js → launch-FJ65HRV4.js} +23 -22
  43. package/dist/{manager-TMBFBCQL.js → manager-ZACEUL5P.js} +4 -4
  44. package/dist/{mcp-YU7AM3UV.js → mcp-SQ4DOGPT.js} +22 -9
  45. package/dist/{orchestrator-GX22Y5EM.js → orchestrator-OT66EDXO.js} +22 -21
  46. package/dist/package.json +3 -1
  47. package/dist/{path-security-CBACXAMS.js → path-security-5CFMMULR.js} +10 -10
  48. package/dist/{platform-5LQXOZO3.js → platform-XPMZKAUB.js} +3 -3
  49. package/dist/{processor-V35OLKRV.js → processor-CHMHMMIE.js} +22 -21
  50. package/dist/{project-creator-6AGQTNXB.js → project-creator-T3A4H3YV.js} +42 -29
  51. package/dist/{protocol-BMUoqwYH.d.ts → protocol-Nr_H1_oC.d.ts} +3 -1
  52. package/dist/{protocol-Y7MRKRUO.js → protocol-XO4ZROAU.js} +3 -3
  53. package/dist/provider/index.d.ts +4 -4
  54. package/dist/provider-JWUNG2TD.js +507 -0
  55. package/dist/{provider-manager-BO5ZBG3T.js → provider-manager-2KKZ37XJ.js} +5 -5
  56. package/dist/pwa-V5PFB4OQ.js +502 -0
  57. package/dist/{registry-CMSSZHDC.js → registry-BEIR7Y5G.js} +3 -3
  58. package/dist/{serve-XRVT3D7Z.js → serve-HSDVY37K.js} +47 -36
  59. package/dist/server/index.d.ts +3 -3
  60. package/dist/server/index.js +27 -26
  61. package/dist/{server-GXMZMPXI.js → server-3UVLECD5.js} +26 -25
  62. package/dist/{service-WKABQHKL.js → service-M77VWL2M.js} +97 -32
  63. package/dist/{service-O3LCO3TQ.js → service-XIUNS5XV.js} +7 -6
  64. package/dist/{session-overrides-OECQYRDK.js → session-overrides-Y5B4XQPU.js} +5 -5
  65. package/dist/{sessions-NMPX5ICI.js → sessions-IGINPPBP.js} +4 -4
  66. package/dist/{settings-MDCRNQBY.js → settings-ZJPM6PQV.js} +2 -2
  67. package/dist/shared/index.d.ts +31 -4
  68. package/dist/shared/index.js +16 -2
  69. package/dist/{tasks-WOC3QUFA.js → tasks-3JJWJJ3X.js} +34 -18
  70. package/dist/{tools-CW6POKUL.js → tools-WWIWD3O7.js} +20 -19
  71. package/dist/{types-CoY8Ka1C.d.ts → types-BlQjLBui.d.ts} +1 -1
  72. package/dist/{types-BIkpxjaj.d.ts → types-G10ho8PT.d.ts} +1 -1
  73. package/dist/update-Q6SH7UP2.js +76 -0
  74. package/dist/web/assets/index-C48qmBAI.js +313 -0
  75. package/dist/web/index.html +1 -1
  76. package/dist/web/sw.js +1 -1
  77. package/package.json +3 -1
  78. package/dist/chunk-JKGHTBEV.js +0 -7
  79. package/dist/provider-NWRGNGS3.js +0 -403
  80. package/dist/pwa-2GRFSXD7.js +0 -363
  81. package/dist/update-VC3Y3EOP.js +0 -49
  82. package/dist/web/assets/index-ATAQvBwl.js +0 -312
@@ -6,11 +6,12 @@ import {
6
6
  import {
7
7
  getGateConfig,
8
8
  isTaskConflictError,
9
- isTaskGateError
10
- } from "./chunk-FEIRWXLX.js";
9
+ isTaskGateError,
10
+ serverT
11
+ } from "./chunk-OZWHRBDY.js";
11
12
  import {
12
13
  getSessionDisabledServers
13
- } from "./chunk-TACWRDDC.js";
14
+ } from "./chunk-QDARWVQ2.js";
14
15
  import {
15
16
  TurnMetrics,
16
17
  clearLLMFailure,
@@ -41,7 +42,7 @@ import {
41
42
  spawnShellProcess,
42
43
  startProcessCommand,
43
44
  stopProcess
44
- } from "./chunk-MQMPIXON.js";
45
+ } from "./chunk-5UMXFLET.js";
45
46
  import {
46
47
  getMaxPerSession,
47
48
  getSessionProcessCount,
@@ -59,12 +60,12 @@ import {
59
60
  getEnabledSkillMetadata,
60
61
  isSkillEnabled,
61
62
  loadAllSkills
62
- } from "./chunk-BKMWZTNO.js";
63
+ } from "./chunk-DWA4IE65.js";
63
64
  import {
64
65
  COMPACTION_PROMPT,
65
66
  buildBasePrompt,
66
67
  computeEffectiveTools
67
- } from "./chunk-7JVBDBXE.js";
68
+ } from "./chunk-7QMWYNVF.js";
68
69
  import {
69
70
  AskUserInterrupt,
70
71
  askUserTool
@@ -76,12 +77,12 @@ import {
76
77
  registerPathConfirmation,
77
78
  requestPathAccess,
78
79
  resolveRelativeTraversals
79
- } from "./chunk-Y6ZGHOKM.js";
80
+ } from "./chunk-YLVOU7T7.js";
80
81
  import {
81
82
  getCurrentContextWindowId,
82
83
  getCurrentWindowMessageOptions,
83
84
  getEventStore
84
- } from "./chunk-FGNJMKDV.js";
85
+ } from "./chunk-CSYOWFPU.js";
85
86
  import {
86
87
  buildContextMessagesFromEventHistory,
87
88
  foldContextState,
@@ -91,13 +92,13 @@ import {
91
92
  handleToolResult,
92
93
  reorderToolMessages,
93
94
  stripOrphanedToolCalls
94
- } from "./chunk-M5T4RDPJ.js";
95
+ } from "./chunk-MEEUXRFL.js";
95
96
  import {
96
97
  findAgentById,
97
98
  getRuntimeConfig,
98
99
  getSubAgents,
99
100
  loadAllAgentsDefault
100
- } from "./chunk-ELYHHEYL.js";
101
+ } from "./chunk-ORCQ3EXQ.js";
101
102
  import {
102
103
  createChatDoneMessage,
103
104
  createChatLLMRetryFailedMessage,
@@ -107,7 +108,7 @@ import {
107
108
  createChatPathConfirmationMessage,
108
109
  createChatStatsMessage,
109
110
  createQueueStateMessage
110
- } from "./chunk-P57IBMK4.js";
111
+ } from "./chunk-AATMPL7S.js";
111
112
  import {
112
113
  getModelProfile,
113
114
  modelSupportsVision
@@ -127,7 +128,7 @@ import {
127
128
  SETTINGS_KEYS,
128
129
  getSetting,
129
130
  setSetting
130
- } from "./chunk-LQKXJPKP.js";
131
+ } from "./chunk-CTWZPN7G.js";
131
132
  import {
132
133
  logger
133
134
  } from "./chunk-K44MW7JJ.js";
@@ -151,7 +152,7 @@ async function requestUserConfirmation(context, toolLabel, desc) {
151
152
  if (context.dangerLevel === "dangerous") return Promise.resolve(true);
152
153
  if (toolLabel === "workspace" || toolLabel === "command") {
153
154
  try {
154
- const { getSetting: getSetting2, SETTINGS_KEYS: SETTINGS_KEYS2 } = await import("./settings-MDCRNQBY.js");
155
+ const { getSetting: getSetting2, SETTINGS_KEYS: SETTINGS_KEYS2 } = await import("./settings-ZJPM6PQV.js");
155
156
  if (getSetting2(SETTINGS_KEYS2.CONFIRM_ON_WORKSPACE_ACTIONS) !== "true") {
156
157
  return Promise.resolve(true);
157
158
  }
@@ -194,7 +195,13 @@ function validateAction(action, allowed, startTime) {
194
195
  if (!action || !allowed.includes(action)) {
195
196
  return {
196
197
  success: false,
197
- error: `Invalid action: ${action}. Must be one of: ${allowed.join(", ")}`,
198
+ error: serverT(
199
+ {
200
+ en: "Invalid action: {{action}}. Must be one of: {{allowed}}",
201
+ fr: "Action invalide : {{action}}. Doit \xEAtre l\u2019une des actions suivantes : {{allowed}}"
202
+ },
203
+ { action: action ?? "", allowed: allowed.join(", ") }
204
+ ),
198
205
  durationMs: Date.now() - startTime,
199
206
  truncated: false
200
207
  };
@@ -205,7 +212,13 @@ function checkActionPermission(action, permittedActions, startTime) {
205
212
  if (action && permittedActions && permittedActions.length > 0 && !permittedActions.includes(action)) {
206
213
  return {
207
214
  success: false,
208
- error: `Action '${action}' not allowed. Available: ${permittedActions.join(", ")}`,
215
+ error: serverT(
216
+ {
217
+ en: "Action '{{action}}' not allowed. Available: {{available}}",
218
+ fr: "Action \xAB {{action}} \xBB non autoris\xE9e. Disponibles : {{available}}"
219
+ },
220
+ { action: action ?? "", available: permittedActions.join(", ") }
221
+ ),
209
222
  durationMs: Date.now() - startTime,
210
223
  truncated: false
211
224
  };
@@ -268,7 +281,10 @@ function createTool(name, definition, handler2) {
268
281
  }
269
282
  return {
270
283
  success: false,
271
- error: error instanceof Error ? error.message : "Unknown error in tool execution",
284
+ error: error instanceof Error ? error.message : serverT({
285
+ en: "Unknown error in tool execution",
286
+ fr: "Erreur inconnue lors de l\u2019ex\xE9cution de l\u2019outil"
287
+ }),
272
288
  durationMs: Date.now() - startTime,
273
289
  truncated: false
274
290
  };
@@ -607,16 +623,30 @@ var readFileTool = createTool(
607
623
  }
608
624
  if (stats.size > OUTPUT_LIMITS.read_file.maxFileBytes) {
609
625
  return helpers.error(
610
- `File size (${stats.size} bytes) exceeds maximum file size (20MB). Use shell command to process large files.`
626
+ serverT(
627
+ {
628
+ en: "File size ({{size}} bytes) exceeds maximum file size (20MB). Use shell command to process large files.",
629
+ fr: "La taille du fichier ({{size}} octets) d\xE9passe la taille maximale (20 Mo). Utilisez une commande shell pour traiter les fichiers volumineux."
630
+ },
631
+ { size: stats.size }
632
+ )
611
633
  );
612
634
  }
613
635
  if (stats.size > OUTPUT_LIMITS.read_file.maxImageBytes) {
614
636
  return helpers.error(
615
- `File size (${stats.size} bytes) exceeds image size limit (2MB). Use shell command to process large files.`
637
+ serverT(
638
+ {
639
+ en: "File size ({{size}} bytes) exceeds image size limit (2MB). Use shell command to process large files.",
640
+ fr: "La taille du fichier ({{size}} octets) d\xE9passe la limite pour les images (2 Mo). Utilisez une commande shell pour traiter les fichiers volumineux."
641
+ },
642
+ { size: stats.size }
643
+ )
616
644
  );
617
645
  }
618
646
  } catch {
619
- return helpers.error(`File not found: ${args.path}`);
647
+ return helpers.error(
648
+ serverT({ en: "File not found: {{path}}", fr: "Fichier introuvable : {{path}}" }, { path: args.path })
649
+ );
620
650
  }
621
651
  const rawBuffer = await readFile2(fullPath);
622
652
  const mimeType = await detectImageType(rawBuffer, args.path);
@@ -632,15 +662,22 @@ var readFileTool = createTool(
632
662
  relative2(context.workdir, fullPath)
633
663
  );
634
664
  }
635
- return helpers.success(`[Image: ${args.path} (${mimeType}, ${rawBuffer.length} bytes)]`, false, {
636
- metadata: {
637
- mimeType,
638
- size: rawBuffer.length,
639
- base64Data,
640
- dataUrl,
641
- path: fullPath
665
+ return helpers.success(
666
+ serverT(
667
+ { en: "[Image: {{path}} ({{mime}}, {{size}} bytes)]", fr: "[Image : {{path}} ({{mime}}, {{size}} octets)]" },
668
+ { path: args.path, mime: mimeType, size: rawBuffer.length }
669
+ ),
670
+ false,
671
+ {
672
+ metadata: {
673
+ mimeType,
674
+ size: rawBuffer.length,
675
+ base64Data,
676
+ dataUrl,
677
+ path: fullPath
678
+ }
642
679
  }
643
- });
680
+ );
644
681
  }
645
682
  if (isPdfBuffer(rawBuffer)) {
646
683
  try {
@@ -795,7 +832,9 @@ var writeFileTool = createTool(
795
832
  const readFiles = context.sessionManager.getReadFiles(context.sessionId);
796
833
  const validation = await validateFileForWrite(fullPath, readFiles, context.workdir);
797
834
  if (!validation.valid) {
798
- return helpers.error(validation.error?.message ?? "File validation failed");
835
+ return helpers.error(
836
+ validation.error?.message ?? serverT({ en: "File validation failed", fr: "\xC9chec de la validation du fichier" })
837
+ );
799
838
  }
800
839
  const dir = dirname(fullPath);
801
840
  await mkdir(dir, { recursive: true });
@@ -804,7 +843,13 @@ var writeFileTool = createTool(
804
843
  await writeFile(fullPath, encoded);
805
844
  const lineCount = args.content.split("\n").length;
806
845
  const byteCount = encoded.length;
807
- let output = `Successfully wrote ${lineCount} lines (${byteCount} bytes) to ${args.path}`;
846
+ let output = serverT(
847
+ {
848
+ en: "Successfully wrote {{lines}} lines ({{bytes}} bytes) to {{path}}",
849
+ fr: "{{lines}} lignes ({{bytes}} octets) \xE9crites avec succ\xE8s dans {{path}}"
850
+ },
851
+ { lines: lineCount, bytes: byteCount, path: args.path }
852
+ );
808
853
  let diagnostics = [];
809
854
  if (context.lspManager) {
810
855
  diagnostics = await context.lspManager.notifyFileChange(fullPath, args.content);
@@ -992,13 +1037,17 @@ var editFileTool = createTool(
992
1037
  const readFiles = context.sessionManager.getReadFiles(context.sessionId);
993
1038
  const validation = await validateFileForWrite(fullPath, readFiles, context.workdir);
994
1039
  if (!validation.valid) {
995
- return helpers.error(validation.error?.message ?? "File validation failed");
1040
+ return helpers.error(
1041
+ validation.error?.message ?? serverT({ en: "File validation failed", fr: "\xC9chec de la validation du fichier" })
1042
+ );
996
1043
  }
997
1044
  let rawBuffer;
998
1045
  try {
999
1046
  rawBuffer = await readFile3(fullPath);
1000
1047
  } catch {
1001
- return helpers.error(`File not found: ${args.path}`);
1048
+ return helpers.error(
1049
+ serverT({ en: "File not found: {{path}}", fr: "Fichier introuvable : {{path}}" }, { path: args.path })
1050
+ );
1002
1051
  }
1003
1052
  const { encoding, bomSize } = detectEncoding(rawBuffer);
1004
1053
  const content = decodeContent(rawBuffer, encoding);
@@ -1009,17 +1058,24 @@ var editFileTool = createTool(
1009
1058
  if (occurrences === 0) {
1010
1059
  const preview = args.old_string.length > 100 ? args.old_string.slice(0, 100) + "..." : args.old_string;
1011
1060
  return helpers.error(
1012
- `old_string not found in file.
1013
-
1014
- Searched for:
1015
- ${preview}
1016
-
1017
- Make sure whitespace and indentation match exactly.`
1061
+ serverT(
1062
+ {
1063
+ en: "old_string not found in file.\n\nSearched for:\n{{preview}}\n\nMake sure whitespace and indentation match exactly.",
1064
+ fr: "old_string introuvable dans le fichier.\n\nRecherch\xE9 :\n{{preview}}\n\nV\xE9rifiez que les espaces et l\u2019indentation correspondent exactement."
1065
+ },
1066
+ { preview }
1067
+ )
1018
1068
  );
1019
1069
  }
1020
1070
  if (occurrences > 1 && !replaceAll) {
1021
1071
  return helpers.error(
1022
- `Found ${occurrences} matches for old_string. Use replace_all: true to replace all, or provide more context to make the match unique.`
1072
+ serverT(
1073
+ {
1074
+ en: "Found {{count}} matches for old_string. Use replace_all: true to replace all, or provide more context to make the match unique.",
1075
+ fr: "{{count}} correspondances trouv\xE9es pour old_string. Utilisez replace_all : true pour tout remplacer, ou fournissez plus de contexte pour rendre la correspondance unique."
1076
+ },
1077
+ { count: occurrences }
1078
+ )
1023
1079
  );
1024
1080
  }
1025
1081
  const contextResult = extractEditContext(
@@ -1055,7 +1111,12 @@ Make sure whitespace and indentation match exactly.`
1055
1111
  } else {
1056
1112
  const index = normalizedContent.indexOf(normalizedOldString);
1057
1113
  if (index === -1) {
1058
- return helpers.error("old_string not found in file (unexpected)");
1114
+ return helpers.error(
1115
+ serverT({
1116
+ en: "old_string not found in file (unexpected)",
1117
+ fr: "old_string introuvable dans le fichier (inattendu)"
1118
+ })
1119
+ );
1059
1120
  }
1060
1121
  replacedContent = normalizedContent.slice(0, index) + normalizedNewString + normalizedContent.slice(index + normalizedOldString.length);
1061
1122
  }
@@ -1065,7 +1126,13 @@ Make sure whitespace and indentation match exactly.`
1065
1126
  );
1066
1127
  const encoded = encodeContent(restoredContent, encoding, bomSize > 0);
1067
1128
  await writeFile2(fullPath, encoded);
1068
- let output = `Successfully replaced ${replaceAll ? occurrences : 1} occurrence(s) in ${args.path}`;
1129
+ let output = serverT(
1130
+ {
1131
+ en: "Successfully replaced {{count}} occurrence(s) in {{path}}",
1132
+ fr: "{{count}} occurrence(s) remplac\xE9e(s) avec succ\xE8s dans {{path}}"
1133
+ },
1134
+ { count: replaceAll ? occurrences : 1, path: args.path }
1135
+ );
1069
1136
  let diagnostics = [];
1070
1137
  if (context.lspManager) {
1071
1138
  diagnostics = await context.lspManager.notifyFileChange(fullPath, restoredContent);
@@ -1204,16 +1271,31 @@ var runCommandTool = createTool(
1204
1271
  const timeout = args.timeout ?? 12e4;
1205
1272
  if (hasBackgroundAmpersand(args.command)) {
1206
1273
  return helpers.error(
1207
- `Use background_process tool (action: "start") for background/long-running commands instead of '&'. See the tool description for details.`
1274
+ serverT({
1275
+ en: `Use background_process tool (action: "start") for background/long-running commands instead of '&'. See the tool description for details.`,
1276
+ fr: "Utilisez l\u2019outil background_process (action : \xAB start \xBB) pour les commandes d\u2019arri\xE8re-plan ou de longue dur\xE9e au lieu de \xAB & \xBB. Consultez la description de l\u2019outil pour plus de d\xE9tails."
1277
+ })
1208
1278
  );
1209
1279
  }
1210
1280
  const mutationMatch = detectGitMutation(args.command);
1211
1281
  if (mutationMatch) {
1212
- const desc = `Command "${args.command}" modifies Git state (${mutationMatch}). Allow this Git operation?`;
1282
+ const desc = serverT(
1283
+ {
1284
+ en: 'Command "{{cmd}}" modifies Git state ({{mutation}}). Allow this Git operation?',
1285
+ fr: "La commande \xAB {{cmd}} \xBB modifie l\u2019\xE9tat Git ({{mutation}}). Autoriser cette op\xE9ration Git ?"
1286
+ },
1287
+ { cmd: args.command, mutation: mutationMatch }
1288
+ );
1213
1289
  const approved = await requestUserConfirmation(context, "command", desc);
1214
1290
  if (!approved) {
1215
1291
  return helpers.error(
1216
- `User denied: "${mutationMatch}" modifies Git state. Use the workspace tool to switch workspaces or branches.`
1292
+ serverT(
1293
+ {
1294
+ en: 'User denied: "{{mutation}}" modifies Git state. Use the workspace tool to switch workspaces or branches.',
1295
+ fr: "Refus\xE9 par l\u2019utilisateur : \xAB {{mutation}} \xBB modifie l\u2019\xE9tat Git. Utilisez l\u2019outil workspace pour changer de workspace ou de branche."
1296
+ },
1297
+ { mutation: mutationMatch }
1298
+ )
1217
1299
  );
1218
1300
  }
1219
1301
  }
@@ -1271,7 +1353,12 @@ ${result.stderr}`;
1271
1353
  const wasInterrupted = output.includes("[interrupted by user]");
1272
1354
  return helpers.success(output, truncated, {
1273
1355
  success: result.exitCode === 0,
1274
- ...result.exitCode !== 0 && !wasInterrupted ? { error: `Command exited with code ${result.exitCode}` } : {}
1356
+ ...result.exitCode !== 0 && !wasInterrupted ? {
1357
+ error: serverT(
1358
+ { en: "Command exited with code {{code}}", fr: "La commande s\u2019est termin\xE9e avec le code {{code}}" },
1359
+ { code: result.exitCode }
1360
+ )
1361
+ } : {}
1275
1362
  });
1276
1363
  }
1277
1364
  );
@@ -1412,10 +1499,14 @@ function normalizeId(id) {
1412
1499
  return String(id);
1413
1500
  }
1414
1501
  function requireKeyAndId(args, helpers, entries) {
1415
- if (!args.key) return helpers.error("Missing required field: key");
1416
- if (normalizeId(args.id) === void 0) return helpers.error("Missing required field: id");
1502
+ if (!args.key) return helpers.error(serverT({ en: "Missing required field: key", fr: "Champ requis manquant : key" }));
1503
+ if (normalizeId(args.id) === void 0)
1504
+ return helpers.error(serverT({ en: "Missing required field: id", fr: "Champ requis manquant : id" }));
1417
1505
  const current = entries[args.key];
1418
- if (!current) return helpers.error(`Key "${args.key}" not found.`);
1506
+ if (!current)
1507
+ return helpers.error(
1508
+ serverT({ en: 'Key "{{key}}" not found.', fr: "Cl\xE9 \xAB {{key}} \xBB introuvable." }, { key: args.key ?? "" })
1509
+ );
1419
1510
  return current;
1420
1511
  }
1421
1512
  var sessionMetadataTool = createTool(
@@ -1466,18 +1557,26 @@ var sessionMetadataTool = createTool(
1466
1557
  const entries = session.metadataEntries ?? {};
1467
1558
  if (args.action === "list") {
1468
1559
  const keys = Object.keys(entries);
1469
- if (keys.length === 0) return helpers.success("No metadata keys defined.");
1560
+ if (keys.length === 0)
1561
+ return helpers.success(serverT({ en: "No metadata keys defined.", fr: "Aucune cl\xE9 de m\xE9tadonn\xE9es d\xE9finie." }));
1470
1562
  return helpers.success(
1471
1563
  `Metadata keys:
1472
1564
  ${keys.map((k) => `- ${k} (${entries[k]?.length ?? 0} items)`).join("\n")}`
1473
1565
  );
1474
1566
  }
1475
1567
  if (args.action === "schema") {
1476
- if (!args.key) return helpers.error("Missing required field: key");
1568
+ if (!args.key)
1569
+ return helpers.error(serverT({ en: "Missing required field: key", fr: "Champ requis manquant : key" }));
1477
1570
  const schema = SCHEMAS[args.key];
1478
1571
  if (!schema)
1479
1572
  return helpers.success(
1480
- `No schema defined for key "${args.key}". Items have id, description, and status fields.`
1573
+ serverT(
1574
+ {
1575
+ en: 'No schema defined for key "{{key}}". Items have id, description, and status fields.',
1576
+ fr: "Aucun sch\xE9ma d\xE9fini pour la cl\xE9 \xAB {{key}} \xBB. Les \xE9l\xE9ments ont des champs id, description et status."
1577
+ },
1578
+ { key: args.key ?? "" }
1579
+ )
1481
1580
  );
1482
1581
  return helpers.success(
1483
1582
  `Key: ${args.key}
@@ -1487,14 +1586,25 @@ ${Object.entries(schema.fields).map(([f, t]) => ` ${f}: ${t}`).join("\n")}`
1487
1586
  );
1488
1587
  }
1489
1588
  if (args.action === "get") {
1490
- if (!args.key) return helpers.error("Missing required field: key");
1589
+ if (!args.key)
1590
+ return helpers.error(serverT({ en: "Missing required field: key", fr: "Champ requis manquant : key" }));
1491
1591
  const keyEntries = entries[args.key];
1492
- if (!keyEntries || keyEntries.length === 0) return helpers.success(`No entries for key "${args.key}".`);
1592
+ if (!keyEntries || keyEntries.length === 0)
1593
+ return helpers.success(
1594
+ serverT(
1595
+ { en: 'No entries for key "{{key}}".', fr: "Aucune entr\xE9e pour la cl\xE9 \xAB {{key}} \xBB." },
1596
+ { key: args.key ?? "" }
1597
+ )
1598
+ );
1493
1599
  return helpers.success(JSON.stringify(keyEntries, null, 2));
1494
1600
  }
1495
1601
  if (args.action === "add") {
1496
- if (!args.key) return helpers.error("Missing required field: key");
1497
- if (!args.description) return helpers.error("Missing required field: description");
1602
+ if (!args.key)
1603
+ return helpers.error(serverT({ en: "Missing required field: key", fr: "Champ requis manquant : key" }));
1604
+ if (!args.description)
1605
+ return helpers.error(
1606
+ serverT({ en: "Missing required field: description", fr: "Champ requis manquant : description" })
1607
+ );
1498
1608
  const current = entries[args.key] ?? [];
1499
1609
  const newEntry = {
1500
1610
  id: normalizeId(args.id) ?? (current.length + 1).toString(),
@@ -1503,14 +1613,28 @@ ${Object.entries(schema.fields).map(([f, t]) => ` ${f}: ${t}`).join("\n")}`
1503
1613
  };
1504
1614
  const updated = [...current, newEntry];
1505
1615
  context.sessionManager.setMetadataEntries(context.sessionId, args.key, updated);
1506
- return helpers.success(`Added item "${newEntry.id}" to "${args.key}". Total: ${updated.length} items.`);
1616
+ return helpers.success(
1617
+ serverT(
1618
+ {
1619
+ en: 'Added item "{{id}}" to "{{key}}". Total: {{count}} items.',
1620
+ fr: "\xC9l\xE9ment \xAB {{id}} \xBB ajout\xE9 \xE0 \xAB {{key}} \xBB. Total : {{count}} \xE9l\xE9ments."
1621
+ },
1622
+ { id: newEntry.id, key: args.key ?? "", count: updated.length }
1623
+ )
1624
+ );
1507
1625
  }
1508
1626
  if (args.action === "update") {
1509
1627
  const current = requireKeyAndId(args, helpers, entries);
1510
1628
  if (!Array.isArray(current)) return current;
1511
1629
  const id = normalizeId(args.id);
1512
1630
  const idx = current.findIndex((e) => e.id === id);
1513
- if (idx === -1) return helpers.error(`Item "${id}" not found in "${args.key}".`);
1631
+ if (idx === -1)
1632
+ return helpers.error(
1633
+ serverT(
1634
+ { en: 'Item "{{id}}" not found in "{{key}}".', fr: "\xC9l\xE9ment \xAB {{id}} \xBB introuvable dans \xAB {{key}} \xBB." },
1635
+ { id, key: args.key ?? "" }
1636
+ )
1637
+ );
1514
1638
  const updated = current.map(
1515
1639
  (e, i) => i === idx ? {
1516
1640
  ...e,
@@ -1519,18 +1643,37 @@ ${Object.entries(schema.fields).map(([f, t]) => ` ${f}: ${t}`).join("\n")}`
1519
1643
  } : e
1520
1644
  );
1521
1645
  context.sessionManager.setMetadataEntries(context.sessionId, args.key, updated);
1522
- return helpers.success(`Updated item "${id}" in "${args.key}".`);
1646
+ return helpers.success(
1647
+ serverT(
1648
+ { en: 'Updated item "{{id}}" in "{{key}}".', fr: "\xC9l\xE9ment \xAB {{id}} \xBB mis \xE0 jour dans \xAB {{key}} \xBB." },
1649
+ { id, key: args.key ?? "" }
1650
+ )
1651
+ );
1523
1652
  }
1524
1653
  if (args.action === "remove") {
1525
1654
  const current = requireKeyAndId(args, helpers, entries);
1526
1655
  if (!Array.isArray(current)) return current;
1527
1656
  const id = normalizeId(args.id);
1528
1657
  const updated = current.filter((e) => e.id !== id);
1529
- if (updated.length === current.length) return helpers.error(`Item "${id}" not found in "${args.key}".`);
1658
+ if (updated.length === current.length)
1659
+ return helpers.error(
1660
+ serverT(
1661
+ { en: 'Item "{{id}}" not found in "{{key}}".', fr: "\xC9l\xE9ment \xAB {{id}} \xBB introuvable dans \xAB {{key}} \xBB." },
1662
+ { id, key: args.key ?? "" }
1663
+ )
1664
+ );
1530
1665
  context.sessionManager.setMetadataEntries(context.sessionId, args.key, updated);
1531
- return helpers.success(`Removed item "${id}" from "${args.key}". ${updated.length} items remaining.`);
1666
+ return helpers.success(
1667
+ serverT(
1668
+ {
1669
+ en: 'Removed item "{{id}}" from "{{key}}". {{count}} items remaining.',
1670
+ fr: "\xC9l\xE9ment \xAB {{id}} \xBB supprim\xE9 de \xAB {{key}} \xBB. {{count}} \xE9l\xE9ments restants."
1671
+ },
1672
+ { id, key: args.key ?? "", count: updated.length }
1673
+ )
1674
+ );
1532
1675
  }
1533
- return helpers.error("Unexpected error");
1676
+ return helpers.error(serverT({ en: "Unexpected error", fr: "Erreur inattendue" }));
1534
1677
  }
1535
1678
  );
1536
1679
 
@@ -1623,7 +1766,12 @@ function createToolProgressHandler(append, messageId, callId, _sessionId) {
1623
1766
 
1624
1767
  // src/server/chat/execute-tools.ts
1625
1768
  import stripAnsi2 from "strip-ansi";
1626
- var INTERRUPTED_ERROR = "Tool execution was interrupted by user";
1769
+ function interruptedError() {
1770
+ return serverT({
1771
+ en: "Tool execution was interrupted by user",
1772
+ fr: "L\u2019ex\xE9cution de l\u2019outil a \xE9t\xE9 interrompue par l\u2019utilisateur"
1773
+ });
1774
+ }
1627
1775
  function extractSubAgentPrompt(args) {
1628
1776
  return args["prompt"] || args["query"] || args["task"] || "";
1629
1777
  }
@@ -1642,7 +1790,7 @@ async function transformSubAgentAliases(toolCalls, toolRegistry, projectDir) {
1642
1790
  function createInterruptedResult(startTime) {
1643
1791
  return {
1644
1792
  success: false,
1645
- error: INTERRUPTED_ERROR,
1793
+ error: interruptedError(),
1646
1794
  durationMs: startTime ? Date.now() - startTime : 0,
1647
1795
  truncated: false
1648
1796
  };
@@ -1663,7 +1811,13 @@ async function executeTools(assistantMsgId, toolCalls, ctx, append) {
1663
1811
  if (error instanceof PathAccessDeniedError) {
1664
1812
  return {
1665
1813
  success: false,
1666
- error: `User denied access to ${error.paths.join(", ")}. If you need this file, explain why and ask for permission.`,
1814
+ error: serverT(
1815
+ {
1816
+ en: "User denied access to {{paths}}. If you need this file, explain why and ask for permission.",
1817
+ fr: "Acc\xE8s refus\xE9 par l\u2019utilisateur : {{paths}}. Si vous avez besoin de ce fichier, expliquez pourquoi et demandez l\u2019autorisation."
1818
+ },
1819
+ { paths: error.paths.join(", ") }
1820
+ ),
1667
1821
  durationMs: Date.now() - startTime,
1668
1822
  truncated: false
1669
1823
  };
@@ -1676,7 +1830,15 @@ async function executeTools(assistantMsgId, toolCalls, ctx, append) {
1676
1830
  const { awaitAnswer } = await import("./ask-UBIRH3SO.js");
1677
1831
  const answerPromise = awaitAnswer(error.callId);
1678
1832
  if (!answerPromise) {
1679
- throw new Error(`No pending question found for callId: ${error.callId}`);
1833
+ throw new Error(
1834
+ serverT(
1835
+ {
1836
+ en: "No pending question found for callId: {{id}}",
1837
+ fr: "Aucune question en attente trouv\xE9e pour callId : {{id}}"
1838
+ },
1839
+ { id: error.callId }
1840
+ )
1841
+ );
1680
1842
  }
1681
1843
  const answer = await answerPromise;
1682
1844
  return {
@@ -1698,7 +1860,7 @@ async function executeTools(assistantMsgId, toolCalls, ctx, append) {
1698
1860
  return {
1699
1861
  toolCall,
1700
1862
  toolResult: toolResult2,
1701
- content: `Error: ${INTERRUPTED_ERROR}`,
1863
+ content: serverT({ en: "Error: {{message}}", fr: "Erreur : {{message}}" }, { message: interruptedError() }),
1702
1864
  index
1703
1865
  };
1704
1866
  }
@@ -1709,7 +1871,13 @@ async function executeTools(assistantMsgId, toolCalls, ctx, append) {
1709
1871
  } else {
1710
1872
  const toolResult2 = {
1711
1873
  success: false,
1712
- error: `Failed to parse tool call arguments: ${toolCall.parseError}. Please ensure your JSON function call arguments are valid.`,
1874
+ error: serverT(
1875
+ {
1876
+ en: "Failed to parse tool call arguments: {{error}}. Please ensure your JSON function call arguments are valid.",
1877
+ fr: "\xC9chec de l\u2019analyse des arguments de l\u2019appel d\u2019outil : {{error}}. Assurez-vous que vos arguments JSON d\u2019appel de fonction sont valides."
1878
+ },
1879
+ { error: toolCall.parseError ?? "" }
1880
+ ),
1713
1881
  durationMs: 0,
1714
1882
  truncated: false
1715
1883
  };
@@ -1717,7 +1885,10 @@ async function executeTools(assistantMsgId, toolCalls, ctx, append) {
1717
1885
  return {
1718
1886
  toolCall,
1719
1887
  toolResult: toolResult2,
1720
- content: `Error: ${toolResult2.error}`,
1888
+ content: serverT(
1889
+ { en: "Error: {{message}}", fr: "Erreur : {{message}}" },
1890
+ { message: toolResult2.error ?? "" }
1891
+ ),
1721
1892
  index
1722
1893
  };
1723
1894
  }
@@ -1760,9 +1931,10 @@ async function executeTools(assistantMsgId, toolCalls, ctx, append) {
1760
1931
  stepDoneCalled = true;
1761
1932
  }
1762
1933
  const rawContent = stripAnsi2(
1763
- toolResult.success ? toolResult.output ?? "Success" : toolResult.output ? `${toolResult.output}
1764
-
1765
- Error: ${toolResult.error}` : `Error: ${toolResult.error}`
1934
+ toolResult.success ? toolResult.output ?? serverT({ en: "Success", fr: "Succ\xE8s" }) : toolResult.output ? serverT(
1935
+ { en: "{{output}}\n\nError: {{error}}", fr: "{{output}}\n\nErreur : {{error}}" },
1936
+ { output: toolResult.output, error: toolResult.error ?? "" }
1937
+ ) : serverT({ en: "Error: {{error}}", fr: "Erreur : {{error}}" }, { error: toolResult.error ?? "" })
1766
1938
  );
1767
1939
  const { clean: content, corrupted } = sanitizeUtf8(rawContent);
1768
1940
  if (corrupted) {
@@ -2082,7 +2254,7 @@ ${CONTINUE_PROMPT}` : CONTINUE_PROMPT;
2082
2254
  return { failed: { error: attemptResult.error } };
2083
2255
  }
2084
2256
  if (!config.subAgentMetadata) {
2085
- config.onMessage?.(createChatLLMRetryMessage(decision.attempt, decision.delayMs));
2257
+ config.onMessage?.(createChatLLMRetryMessage(decision.attempt, decision.delayMs, attemptResult.error));
2086
2258
  }
2087
2259
  const waitResult = await sleepThroughRetryBackoff(decision.delayMs, sessionId, signal);
2088
2260
  if (waitResult === "aborted") throw new Error("Aborted");
@@ -2094,7 +2266,16 @@ ${CONTINUE_PROMPT}` : CONTINUE_PROMPT;
2094
2266
  if (!retryLimiter.canRetry()) {
2095
2267
  append({
2096
2268
  type: "chat.error",
2097
- data: { error: `Auto-retry limit exceeded after ${retryLimiter.maxRetries()} retries`, recoverable: false }
2269
+ data: {
2270
+ error: serverT(
2271
+ {
2272
+ en: "Auto-retry limit exceeded after {{count}} retries",
2273
+ fr: "Limite de relance automatique d\xE9pass\xE9e apr\xE8s {{count}} tentatives"
2274
+ },
2275
+ { count: retryLimiter.maxRetries() }
2276
+ ),
2277
+ recoverable: false
2278
+ }
2098
2279
  });
2099
2280
  append(createChatDoneEvent(assistantMsgId, "error", void 0, agentType));
2100
2281
  throw new Error("Auto-retry limit exceeded");
@@ -2154,7 +2335,7 @@ ${CONTINUE_PROMPT}` : CONTINUE_PROMPT;
2154
2335
  currentMaxTokensOverride = void 0;
2155
2336
  if (!compacting) {
2156
2337
  const contextState = sessionManager.getContextState(sessionId);
2157
- const { shouldCompact, appendCompactionPrompt } = await import("./compactor-OEJAA2YP.js");
2338
+ const { shouldCompact, appendCompactionPrompt } = await import("./compactor-PD6DQ4NY.js");
2158
2339
  if (shouldCompact(
2159
2340
  contextState.currentTokens,
2160
2341
  contextState.maxTokens,
@@ -2319,7 +2500,13 @@ ${COMPACTION_PROMPT}`,
2319
2500
  if (!summary) {
2320
2501
  append({
2321
2502
  type: "chat.error",
2322
- data: { error: "Compaction produced empty summary, continuing with full context", recoverable: true }
2503
+ data: {
2504
+ error: serverT({
2505
+ en: "Compaction produced empty summary, continuing with full context",
2506
+ fr: "La compaction a produit un r\xE9sum\xE9 vide, poursuite avec le contexte complet"
2507
+ }),
2508
+ recoverable: true
2509
+ }
2323
2510
  });
2324
2511
  logger.warn("Compaction produced empty summary, continuing", { sessionId });
2325
2512
  compacting = false;
@@ -3187,7 +3374,7 @@ var callSubAgentTool = {
3187
3374
  };
3188
3375
  }
3189
3376
  try {
3190
- const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-CW6POKUL.js");
3377
+ const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-WWIWD3O7.js");
3191
3378
  const toolRegistry = getToolRegistryForAgent2(agentDef);
3192
3379
  const turnMetrics = new TurnMetrics();
3193
3380
  const result = await executeSubAgent({
@@ -3236,10 +3423,17 @@ ${skill.prompt}`;
3236
3423
  var handler = async (args, context, helpers) => {
3237
3424
  const { skillId } = args;
3238
3425
  if (!skillId) {
3239
- return helpers.error("Missing required parameter: skillId");
3426
+ return helpers.error(
3427
+ serverT({ en: "Missing required parameter: skillId", fr: "Param\xE8tre requis manquant : skillId" })
3428
+ );
3240
3429
  }
3241
3430
  if (!isSkillEnabled(skillId)) {
3242
- return helpers.error(`Skill "${skillId}" is not enabled.`);
3431
+ return helpers.error(
3432
+ serverT(
3433
+ { en: 'Skill "{{id}}" is not enabled.', fr: "La comp\xE9tence \xAB {{id}} \xBB n\u2019est pas activ\xE9e." },
3434
+ { id: skillId }
3435
+ )
3436
+ );
3243
3437
  }
3244
3438
  const config = getRuntimeConfig();
3245
3439
  const configDir = getGlobalConfigDir(config.mode ?? "production");
@@ -3247,7 +3441,15 @@ var handler = async (args, context, helpers) => {
3247
3441
  const skill = findSkillById(skillId, allSkills);
3248
3442
  if (!skill) {
3249
3443
  const available = allSkills.map((s) => s.metadata.id).join(", ");
3250
- return helpers.error(`Skill "${skillId}" not found. Available skills: ${available}`);
3444
+ return helpers.error(
3445
+ serverT(
3446
+ {
3447
+ en: 'Skill "{{id}}" not found. Available skills: {{available}}',
3448
+ fr: "Comp\xE9tence \xAB {{id}} \xBB introuvable. Comp\xE9tences disponibles : {{available}}"
3449
+ },
3450
+ { id: skillId, available }
3451
+ )
3452
+ );
3251
3453
  }
3252
3454
  return helpers.success(formatSkillPrompt(skill));
3253
3455
  };
@@ -3374,7 +3576,9 @@ var webFetchTool = createTool(
3374
3576
  const url = args.url;
3375
3577
  const format = args.format ?? "markdown";
3376
3578
  if (!url.startsWith("http://") && !url.startsWith("https://")) {
3377
- return helpers.error("URL must start with http:// or https://");
3579
+ return helpers.error(
3580
+ serverT({ en: "URL must start with http:// or https://", fr: "L\u2019URL doit commencer par http:// ou https://" })
3581
+ );
3378
3582
  }
3379
3583
  const timeoutMs = (args.timeout ?? DEFAULT_TIMEOUT_MS / 1e3) * 1e3;
3380
3584
  const signal = buildSignal(timeoutMs, context.signal);
@@ -3386,22 +3590,40 @@ var webFetchTool = createTool(
3386
3590
  const initial = await fetch(url, { signal, headers });
3387
3591
  const response = initial.status === 403 && initial.headers.get("cf-mitigated") === "challenge" ? await fetch(url, { signal, headers: { ...headers, "User-Agent": "openfox" } }) : initial;
3388
3592
  if (!response.ok) {
3389
- return helpers.error(`Request failed with status code: ${response.status}`);
3593
+ return helpers.error(
3594
+ serverT(
3595
+ {
3596
+ en: "Request failed with status code: {{status}}",
3597
+ fr: "\xC9chec de la requ\xEAte avec le code de statut : {{status}}"
3598
+ },
3599
+ { status: response.status }
3600
+ )
3601
+ );
3390
3602
  }
3391
3603
  const contentLength = response.headers.get("content-length");
3392
3604
  if (contentLength && parseInt(contentLength) > MAX_RESPONSE_SIZE) {
3393
- return helpers.error("Response too large (exceeds 5MB limit)");
3605
+ return helpers.error(
3606
+ serverT({
3607
+ en: "Response too large (exceeds 5MB limit)",
3608
+ fr: "R\xE9ponse trop volumineuse (d\xE9passe la limite de 5 Mo)"
3609
+ })
3610
+ );
3394
3611
  }
3395
3612
  const arrayBuffer = await response.arrayBuffer();
3396
3613
  if (arrayBuffer.byteLength > MAX_RESPONSE_SIZE) {
3397
- return helpers.error("Response too large (exceeds 5MB limit)");
3614
+ return helpers.error(
3615
+ serverT({
3616
+ en: "Response too large (exceeds 5MB limit)",
3617
+ fr: "R\xE9ponse trop volumineuse (d\xE9passe la limite de 5 Mo)"
3618
+ })
3619
+ );
3398
3620
  }
3399
3621
  const contentType = response.headers.get("content-type") || "";
3400
3622
  const mime = contentType.split(";")[0]?.trim().toLowerCase() || "";
3401
3623
  const isImage = mime.startsWith("image/") && mime !== "image/svg+xml" && mime !== "image/vnd.fastbidsheet";
3402
3624
  if (isImage) {
3403
3625
  const base64Data = Buffer.from(arrayBuffer).toString("base64");
3404
- return helpers.success("Image fetched successfully", false, {
3626
+ return helpers.success(serverT({ en: "Image fetched successfully", fr: "Image r\xE9cup\xE9r\xE9e avec succ\xE8s" }), false, {
3405
3627
  metadata: {
3406
3628
  mimeType: mime,
3407
3629
  base64Data,
@@ -3882,7 +4104,19 @@ var devServerTool = createTool(
3882
4104
  }
3883
4105
  if (!status.config) {
3884
4106
  return helpers.error(
3885
- 'No .openfox/dev.json config found. Create one in the project root:\n\n{\n "command": "npm run dev",\n "url": "http://localhost:3000",\n "hotReload": true,\n "disableInspect": false\n}\n\n(Worktrees inherit the project root config automatically.)'
4107
+ serverT(
4108
+ {
4109
+ en: "No .openfox/dev.json config found. Create one in the project root:\n\n{{config}}\n\n(Worktrees inherit the project root config automatically.)",
4110
+ fr: "Aucun fichier .openfox/dev.json trouv\xE9. Cr\xE9ez-en un \xE0 la racine du projet :\n\n{{config}}\n\n(Les worktrees h\xE9ritent automatiquement de la configuration du projet.)"
4111
+ },
4112
+ {
4113
+ config: JSON.stringify(
4114
+ { command: "npm run dev", url: "http://localhost:3000", hotReload: true, disableInspect: false },
4115
+ null,
4116
+ 2
4117
+ )
4118
+ }
4119
+ )
3886
4120
  );
3887
4121
  }
3888
4122
  return helpers.success(
@@ -3918,7 +4152,7 @@ var stepDoneTool = {
3918
4152
  async execute(_args, _context) {
3919
4153
  return {
3920
4154
  success: true,
3921
- output: "Step completion signal recorded.",
4155
+ output: serverT({ en: "Step completion signal recorded.", fr: "Signal de fin d\u2019\xE9tape enregistr\xE9." }),
3922
4156
  durationMs: 0,
3923
4157
  truncated: false
3924
4158
  };
@@ -3926,6 +4160,9 @@ var stepDoneTool = {
3926
4160
  };
3927
4161
 
3928
4162
  // src/server/tools/background-process/index.ts
4163
+ function processNotFoundError(id) {
4164
+ return serverT({ en: "Process not found: {{id}}", fr: "Processus introuvable : {{id}}" }, { id: id ?? "" });
4165
+ }
3929
4166
  var backgroundProcessTool = createTool(
3930
4167
  "background_process",
3931
4168
  {
@@ -3998,17 +4235,28 @@ These processes run independently of agent turns and persist across session comp
3998
4235
  const maxPerSession = getMaxPerSession();
3999
4236
  if (count >= maxPerSession) {
4000
4237
  return helpers.error(
4001
- `Maximum number of background processes (${maxPerSession}) reached. Stop existing processes before starting new ones.`
4238
+ serverT(
4239
+ {
4240
+ en: "Maximum number of background processes ({{count}}) reached. Stop existing processes before starting new ones.",
4241
+ fr: "Nombre maximal de processus en arri\xE8re-plan ({{count}}) atteint. Arr\xEAtez des processus existants avant d\u2019en d\xE9marrer de nouveaux."
4242
+ },
4243
+ { count: maxPerSession }
4244
+ )
4002
4245
  );
4003
4246
  }
4004
4247
  const name = args.name ?? args.command?.split(" ")[0] ?? "process";
4005
4248
  const process2 = createProcess(sessionId, name, args.command, cwd, args.timeout);
4006
4249
  if (!process2) {
4007
- return helpers.error(`Failed to create process. Maximum limit may have been reached.`);
4250
+ return helpers.error(
4251
+ serverT({
4252
+ en: "Failed to create process. Maximum limit may have been reached.",
4253
+ fr: "\xC9chec de la cr\xE9ation du processus. La limite maximale a peut-\xEAtre \xE9t\xE9 atteinte."
4254
+ })
4255
+ );
4008
4256
  }
4009
4257
  const pid = startProcessCommand(process2.id, sessionId, args.command, cwd);
4010
4258
  if (!pid) {
4011
- return helpers.error(`Failed to start process.`);
4259
+ return helpers.error(serverT({ en: "Failed to start process.", fr: "\xC9chec du d\xE9marrage du processus." }));
4012
4260
  }
4013
4261
  return helpers.success(
4014
4262
  JSON.stringify(
@@ -4026,11 +4274,17 @@ These processes run independently of agent turns and persist across session comp
4026
4274
  }
4027
4275
  case "stop": {
4028
4276
  const proc = getProcessStatus(args.processId, sessionId);
4029
- if (!proc) {
4030
- return helpers.error(`Process not found: ${args.processId}`);
4031
- }
4277
+ if (!proc) return helpers.error(processNotFoundError(args.processId));
4032
4278
  if (proc.status !== "running") {
4033
- return helpers.error(`Process is not running (status: ${proc.status}). Cannot stop.`);
4279
+ return helpers.error(
4280
+ serverT(
4281
+ {
4282
+ en: "Process is not running (status: {{status}}). Cannot stop.",
4283
+ fr: "Le processus n\u2019est pas en cours d\u2019ex\xE9cution (statut : {{status}}). Impossible de l\u2019arr\xEAter."
4284
+ },
4285
+ { status: proc.status }
4286
+ )
4287
+ );
4034
4288
  }
4035
4289
  await stopProcess(args.processId, sessionId);
4036
4290
  return helpers.success(
@@ -4061,9 +4315,7 @@ These processes run independently of agent turns and persist across session comp
4061
4315
  }
4062
4316
  case "status": {
4063
4317
  const proc = getProcessStatus(args.processId, sessionId);
4064
- if (!proc) {
4065
- return helpers.error(`Process not found: ${args.processId}`);
4066
- }
4318
+ if (!proc) return helpers.error(processNotFoundError(args.processId));
4067
4319
  const uptime = proc.startedAt ? Date.now() - proc.startedAt : null;
4068
4320
  return helpers.success(
4069
4321
  JSON.stringify(
@@ -4078,9 +4330,7 @@ These processes run independently of agent turns and persist across session comp
4078
4330
  }
4079
4331
  case "logs": {
4080
4332
  const proc = getProcessStatus(args.processId, sessionId);
4081
- if (!proc) {
4082
- return helpers.error(`Process not found: ${args.processId}`);
4083
- }
4333
+ if (!proc) return helpers.error(processNotFoundError(args.processId));
4084
4334
  const since = args.since ?? 0;
4085
4335
  const maxLines = Math.min(args.maxLines ?? 500, 2e3);
4086
4336
  const { lines, totalLines, nextOffset, hasMore } = getProcessLogs(args.processId, since, maxLines);
@@ -4100,7 +4350,9 @@ These processes run independently of agent turns and persist across session comp
4100
4350
  );
4101
4351
  }
4102
4352
  default:
4103
- return helpers.error(`Unknown action: ${args.action}`);
4353
+ return helpers.error(
4354
+ serverT({ en: "Unknown action: {{action}}", fr: "Action inconnue : {{action}}" }, { action: args.action })
4355
+ );
4104
4356
  }
4105
4357
  }
4106
4358
  );
@@ -4200,13 +4452,18 @@ var mcpConfigTool = createTool(
4200
4452
  if (actionError) return actionError;
4201
4453
  if (args.action === "bootstrap") {
4202
4454
  if (!mcpBootstrapForTools) {
4203
- return helpers.error("MCP bootstrap is not available for this server");
4455
+ return helpers.error(
4456
+ serverT({
4457
+ en: "MCP bootstrap is not available for this server",
4458
+ fr: "Le bootstrap MCP n\u2019est pas disponible pour ce serveur"
4459
+ })
4460
+ );
4204
4461
  }
4205
4462
  const config = await mcpBootstrapForTools();
4206
4463
  return helpers.success(JSON.stringify(config, null, 2));
4207
4464
  }
4208
4465
  if (!mcpManagerForTools) {
4209
- return helpers.error("MCP manager not available");
4466
+ return helpers.error(serverT({ en: "MCP manager not available", fr: "Gestionnaire MCP indisponible" }));
4210
4467
  }
4211
4468
  async function persistAndRebuild(updater) {
4212
4469
  const globalConfig = await loadGlobalConfig(mcpConfigMode, mcpConfigPath);
@@ -4214,59 +4471,85 @@ var mcpConfigTool = createTool(
4214
4471
  const updated = updater(mcpServers);
4215
4472
  await saveGlobalConfig(mcpConfigMode, { ...globalConfig, mcpServers: updated }, mcpConfigPath);
4216
4473
  }
4217
- const APPLY_PROMPT_MESSAGE = "Tool changes are announced automatically.";
4474
+ const APPLY_PROMPT_MESSAGE = serverT({
4475
+ en: "Tool changes are announced automatically.",
4476
+ fr: "Les modifications d\u2019outils sont annonc\xE9es automatiquement."
4477
+ });
4218
4478
  async function notifyContextChanged(sessionId) {
4219
4479
  context.sessionManager.setDynamicContextChanged(sessionId, true);
4220
4480
  mcpNotifyChanged?.(sessionId);
4221
- const { injectContextDriftReminders } = await import("./dynamic-context-NJZKAZE3.js");
4481
+ const { injectContextDriftReminders } = await import("./dynamic-context-WKEXQCTK.js");
4222
4482
  await injectContextDriftReminders(context.sessionManager, sessionId);
4223
4483
  }
4224
4484
  async function rebuildTools() {
4225
- const { setMcpTools: setMcpTools2 } = await import("./tools-CW6POKUL.js");
4485
+ const { setMcpTools: setMcpTools2 } = await import("./tools-WWIWD3O7.js");
4226
4486
  const mcpTools = createMcpTools(mcpManagerForTools);
4227
4487
  setMcpTools2(mcpTools);
4228
4488
  }
4229
4489
  if (args.action === "list") {
4230
4490
  const servers = mcpManagerForTools.getAllServers();
4231
4491
  if (servers.length === 0) {
4232
- return helpers.success("No MCP servers configured.");
4492
+ return helpers.success(serverT({ en: "No MCP servers configured.", fr: "Aucun serveur MCP configur\xE9." }));
4233
4493
  }
4234
- const { getSessionDisabledServers: getSessionDisabledServers2 } = await import("./session-overrides-OECQYRDK.js");
4494
+ const { getSessionDisabledServers: getSessionDisabledServers2 } = await import("./session-overrides-Y5B4XQPU.js");
4235
4495
  const disabledForSession = new Set(context.sessionId ? getSessionDisabledServers2(context.sessionId) : []);
4236
4496
  const visibleServers = servers.filter((server) => !disabledForSession.has(server.name));
4237
4497
  if (visibleServers.length === 0) {
4238
- return helpers.success("No MCP servers configured.");
4498
+ return helpers.success(serverT({ en: "No MCP servers configured.", fr: "Aucun serveur MCP configur\xE9." }));
4239
4499
  }
4240
4500
  const lines = [];
4241
4501
  for (const server of visibleServers) {
4242
4502
  const connStr = server.status === "connected" ? "\u25CF" : server.status === "error" ? "\u2717" : "\u25CB";
4243
4503
  const cmdStr = server.config.command ? `${server.config.command} ${(server.config.args ?? []).join(" ")}` : server.config.url ?? "";
4244
4504
  const hasCachedTools = server.tools.length > 0;
4245
- const sourceLabel = server.status === "connected" ? " (live)" : hasCachedTools ? " (from cache)" : "";
4505
+ const sourceLabel = server.status === "connected" ? serverT({ en: " (live)", fr: " (en direct)" }) : hasCachedTools ? serverT({ en: " (from cache)", fr: " (depuis le cache)" }) : "";
4246
4506
  const statusLine = server.error ? `${server.status}${sourceLabel}: ${server.error}` : `${server.status}${sourceLabel}`;
4247
4507
  lines.push(`${connStr} ${server.name} (${server.config.transport}) \u2014 ${statusLine}`);
4248
4508
  lines.push(` ${cmdStr}`);
4249
- lines.push(` ${server.tools.length} tools, ~${server.estimatedTokens} tokens`);
4509
+ lines.push(
4510
+ serverT(
4511
+ { en: " {{count}} tools, ~{{tokens}} tokens", fr: " {{count}} outils, ~{{tokens}} tokens" },
4512
+ { count: server.tools.length, tokens: server.estimatedTokens }
4513
+ )
4514
+ );
4250
4515
  const enabledTools = server.tools.filter((t) => t.enabled);
4251
4516
  const disabledTools = server.tools.filter((t) => !t.enabled);
4252
4517
  if (enabledTools.length > 0) {
4253
- lines.push(` Enabled: ${enabledTools.map((t) => t.name).join(", ")}`);
4518
+ lines.push(
4519
+ serverT(
4520
+ { en: " Enabled: {{list}}", fr: " Activ\xE9s : {{list}}" },
4521
+ { list: enabledTools.map((t) => t.name).join(", ") }
4522
+ )
4523
+ );
4254
4524
  }
4255
4525
  if (disabledTools.length > 0) {
4256
- lines.push(` Disabled: ${disabledTools.map((t) => t.name).join(", ")}`);
4526
+ lines.push(
4527
+ serverT(
4528
+ { en: " Disabled: {{list}}", fr: " D\xE9sactiv\xE9s : {{list}}" },
4529
+ { list: disabledTools.map((t) => t.name).join(", ") }
4530
+ )
4531
+ );
4257
4532
  }
4258
4533
  }
4259
4534
  return helpers.success(lines.join("\n"));
4260
4535
  }
4261
4536
  if (args.action === "add") {
4262
- if (!args.name) return helpers.error("Missing required field: name");
4537
+ if (!args.name)
4538
+ return helpers.error(serverT({ en: "Missing required field: name", fr: "Champ requis manquant : name" }));
4263
4539
  if (args.transport === "http") {
4264
- if (!args.url) return helpers.error("url is required for http transport");
4540
+ if (!args.url)
4541
+ return helpers.error(
4542
+ serverT({ en: "url is required for http transport", fr: "url est requis pour le transport http" })
4543
+ );
4265
4544
  } else if (!args.command) {
4266
- return helpers.error("command is required for stdio transport");
4545
+ return helpers.error(
4546
+ serverT({ en: "command is required for stdio transport", fr: "command est requis pour le transport stdio" })
4547
+ );
4267
4548
  }
4268
4549
  if (args.timeout !== void 0 && (typeof args.timeout !== "number" || args.timeout <= 0)) {
4269
- return helpers.error("timeout must be a positive number");
4550
+ return helpers.error(
4551
+ serverT({ en: "timeout must be a positive number", fr: "timeout doit \xEAtre un nombre positif" })
4552
+ );
4270
4553
  }
4271
4554
  const serverCfg = {
4272
4555
  transport: args.transport ?? "stdio",
@@ -4286,12 +4569,27 @@ var mcpConfigTool = createTool(
4286
4569
  await notifyContextChanged(context.sessionId);
4287
4570
  const server = mcpManagerForTools.getServer(args.name);
4288
4571
  const toolCount = server?.tools.length ?? 0;
4289
- return helpers.success(`Added MCP server "${args.name}" (${toolCount} tools discovered). ${APPLY_PROMPT_MESSAGE}`);
4572
+ return helpers.success(
4573
+ serverT(
4574
+ {
4575
+ en: 'Added MCP server "{{name}}" ({{count}} tools discovered). {{prompt}}',
4576
+ fr: "Serveur MCP \xAB {{name}} \xBB ajout\xE9 ({{count}} outils d\xE9couverts). {{prompt}}"
4577
+ },
4578
+ { name: args.name ?? "", count: toolCount, prompt: APPLY_PROMPT_MESSAGE }
4579
+ )
4580
+ );
4290
4581
  }
4291
4582
  if (args.action === "update") {
4292
- if (!args.name) return helpers.error("Missing required field: name");
4583
+ if (!args.name)
4584
+ return helpers.error(serverT({ en: "Missing required field: name", fr: "Champ requis manquant : name" }));
4293
4585
  const existing = mcpManagerForTools.getServer(args.name);
4294
- if (!existing) return helpers.error(`MCP server "${args.name}" not found`);
4586
+ if (!existing)
4587
+ return helpers.error(
4588
+ serverT(
4589
+ { en: 'MCP server "{{name}}" not found', fr: "Serveur MCP \xAB {{name}} \xBB introuvable" },
4590
+ { name: args.name ?? "" }
4591
+ )
4592
+ );
4295
4593
  const globalConfig = await loadGlobalConfig(mcpConfigMode, mcpConfigPath);
4296
4594
  const mcpServers = { ...globalConfig.mcpServers ?? {} };
4297
4595
  const patch = {
@@ -4320,11 +4618,18 @@ var mcpConfigTool = createTool(
4320
4618
  const server = mcpManagerForTools.getServer(args.name);
4321
4619
  const toolCount = server?.tools.length ?? 0;
4322
4620
  return helpers.success(
4323
- `Updated MCP server "${args.name}" (${toolCount} tools discovered). ${APPLY_PROMPT_MESSAGE}`
4621
+ serverT(
4622
+ {
4623
+ en: 'Updated MCP server "{{name}}" ({{count}} tools discovered). {{prompt}}',
4624
+ fr: "Serveur MCP \xAB {{name}} \xBB mis \xE0 jour ({{count}} outils d\xE9couverts). {{prompt}}"
4625
+ },
4626
+ { name: args.name ?? "", count: toolCount, prompt: APPLY_PROMPT_MESSAGE }
4627
+ )
4324
4628
  );
4325
4629
  }
4326
4630
  if (args.action === "remove") {
4327
- if (!args.name) return helpers.error("Missing required field: name");
4631
+ if (!args.name)
4632
+ return helpers.error(serverT({ en: "Missing required field: name", fr: "Champ requis manquant : name" }));
4328
4633
  await persistAndRebuild((mcpServers) => {
4329
4634
  delete mcpServers[args.name];
4330
4635
  return mcpServers;
@@ -4332,12 +4637,22 @@ var mcpConfigTool = createTool(
4332
4637
  mcpManagerForTools.removeServer(args.name);
4333
4638
  await rebuildTools();
4334
4639
  await notifyContextChanged(context.sessionId);
4335
- return helpers.success(`Removed MCP server "${args.name}". ${APPLY_PROMPT_MESSAGE}`);
4640
+ return helpers.success(
4641
+ serverT(
4642
+ { en: 'Removed MCP server "{{name}}". {{prompt}}', fr: "Serveur MCP \xAB {{name}} \xBB supprim\xE9. {{prompt}}" },
4643
+ { name: args.name ?? "", prompt: APPLY_PROMPT_MESSAGE }
4644
+ )
4645
+ );
4336
4646
  }
4337
4647
  if (args.action === "toggle-tool") {
4338
- if (!args.name) return helpers.error("Missing required field: name");
4339
- if (!args.toolName) return helpers.error("Missing required field: toolName");
4340
- if (args.enabled === void 0) return helpers.error("Missing required field: enabled");
4648
+ if (!args.name)
4649
+ return helpers.error(serverT({ en: "Missing required field: name", fr: "Champ requis manquant : name" }));
4650
+ if (!args.toolName)
4651
+ return helpers.error(
4652
+ serverT({ en: "Missing required field: toolName", fr: "Champ requis manquant : toolName" })
4653
+ );
4654
+ if (args.enabled === void 0)
4655
+ return helpers.error(serverT({ en: "Missing required field: enabled", fr: "Champ requis manquant : enabled" }));
4341
4656
  const server = mcpManagerForTools.getServer(args.name);
4342
4657
  const currentDisabled = (server?.tools ?? []).filter((t) => !t.enabled).map((t) => t.name);
4343
4658
  const afterDisabled = args.enabled ? currentDisabled.filter((n) => n !== args.toolName) : [...currentDisabled, args.toolName];
@@ -4358,10 +4673,21 @@ var mcpConfigTool = createTool(
4358
4673
  await rebuildTools();
4359
4674
  await notifyContextChanged(context.sessionId);
4360
4675
  return helpers.success(
4361
- `Tool "${args.toolName}" ${args.enabled ? "enabled" : "disabled"} on server "${args.name}". ${APPLY_PROMPT_MESSAGE}`
4676
+ serverT(
4677
+ {
4678
+ en: 'Tool "{{tool}}" {{state}} on server "{{name}}". {{prompt}}',
4679
+ fr: "Outil \xAB {{tool}} \xBB {{state}} sur le serveur \xAB {{name}} \xBB. {{prompt}}"
4680
+ },
4681
+ {
4682
+ tool: args.toolName ?? "",
4683
+ state: args.enabled ? serverT({ en: "enabled", fr: "activ\xE9" }) : serverT({ en: "disabled", fr: "d\xE9sactiv\xE9" }),
4684
+ name: args.name ?? "",
4685
+ prompt: APPLY_PROMPT_MESSAGE
4686
+ }
4687
+ )
4362
4688
  );
4363
4689
  }
4364
- return helpers.error("Unexpected error");
4690
+ return helpers.error(serverT({ en: "Unexpected error", fr: "Erreur inattendue" }));
4365
4691
  }
4366
4692
  );
4367
4693
 
@@ -4474,7 +4800,10 @@ var webSearchTool = createTool(
4474
4800
  const active = getActiveEngine();
4475
4801
  if (!active) {
4476
4802
  return helpers.error(
4477
- "web_search requires at least one search engine configured. Set the TAVILY_API_KEY environment variable, or configure SearXNG via SEARXNG_URL (and optionally SEARXNG_API_KEY). You can also configure these in Settings > Advanced > Search Engine."
4803
+ serverT({
4804
+ en: "web_search requires at least one search engine configured. Set the TAVILY_API_KEY environment variable, or configure SearXNG via SEARXNG_URL (and optionally SEARXNG_API_KEY). You can also configure these in Settings > Advanced > Search Engine.",
4805
+ fr: "web_search n\xE9cessite au moins un moteur de recherche configur\xE9. D\xE9finissez la variable d\u2019environnement TAVILY_API_KEY, ou configurez SearXNG via SEARXNG_URL (et \xE9ventuellement SEARXNG_API_KEY). Vous pouvez aussi les configurer dans Param\xE8tres > Avanc\xE9 > Moteur de recherche."
4806
+ })
4478
4807
  );
4479
4808
  }
4480
4809
  const signal = buildSignal(DEFAULT_TIMEOUT_MS2, context.signal);
@@ -4488,14 +4817,24 @@ var webSearchTool = createTool(
4488
4817
  results = await searchSearxng(query, maxResults, searxngConfig, signal);
4489
4818
  }
4490
4819
  if (results.length === 0) {
4491
- return helpers.success("No search results found.", false);
4820
+ return helpers.success(
4821
+ serverT({ en: "No search results found.", fr: "Aucun r\xE9sultat de recherche trouv\xE9." }),
4822
+ false
4823
+ );
4492
4824
  }
4493
4825
  return helpers.success(formatResults(results), false);
4494
4826
  } catch (error) {
4495
4827
  if (error instanceof DOMException && error.name === "AbortError") {
4496
- return helpers.error("Search request timed out (15s). Try a more specific query.");
4828
+ return helpers.error(
4829
+ serverT({
4830
+ en: "Search request timed out (15s). Try a more specific query.",
4831
+ fr: "La recherche a expir\xE9 (15 s). Essayez une requ\xEAte plus pr\xE9cise."
4832
+ })
4833
+ );
4497
4834
  }
4498
- return helpers.error(error instanceof Error ? error.message : "Search request failed");
4835
+ return helpers.error(
4836
+ error instanceof Error ? error.message : serverT({ en: "Search request failed", fr: "\xC9chec de la requ\xEAte de recherche" })
4837
+ );
4499
4838
  }
4500
4839
  }
4501
4840
  );
@@ -4559,22 +4898,43 @@ Actions:
4559
4898
  const { sessionId, sessionManager } = context;
4560
4899
  const validActions = ["switch", "list", "delete"];
4561
4900
  if (!validActions.includes(args.action)) {
4562
- return helpers.error(`Invalid action: ${args.action}. Must be one of: ${validActions.join(", ")}`);
4901
+ return helpers.error(
4902
+ serverT(
4903
+ {
4904
+ en: "Invalid action: {{action}}. Must be one of: {{allowed}}",
4905
+ fr: "Action invalide : {{action}}. Doit \xEAtre l\u2019une des actions suivantes : {{allowed}}"
4906
+ },
4907
+ { action: args.action, allowed: validActions.join(", ") }
4908
+ )
4909
+ );
4563
4910
  }
4564
4911
  switch (args.action) {
4565
4912
  case "switch": {
4566
4913
  if (!args.target || typeof args.target !== "string") {
4567
- return helpers.error('Parameter "target" is required for action=switch ("original" or a workspace name)');
4914
+ return helpers.error(
4915
+ serverT({
4916
+ en: 'Parameter "target" is required for action=switch ("original" or a workspace name)',
4917
+ fr: "Le param\xE8tre \xAB target \xBB est requis pour action=switch (\xAB original \xBB ou un nom de workspace)"
4918
+ })
4919
+ );
4568
4920
  }
4569
4921
  if (await isGitRepository(context.workdir) === false) {
4570
- return helpers.error("Project is not a git repository");
4922
+ return helpers.error(
4923
+ serverT({ en: "Project is not a git repository", fr: "Le projet n\u2019est pas un d\xE9p\xF4t git" })
4924
+ );
4571
4925
  }
4572
4926
  const currentSession = sessionManager.getSession(sessionId);
4573
4927
  const isBranchChange = args.branch !== void 0 && currentSession != null && args.target !== "original" && currentSession.workspace?.split("/").pop() === args.target;
4574
4928
  const label = args.target === "original" ? "original project" : `workspace "${args.target}"`;
4575
4929
  const desc = isBranchChange ? `Change branch to "${args.branch}" on ${label}` : `Switch to ${label}${args.branch ? ` on branch "${args.branch}"` : ""}`;
4576
4930
  const approved = await requestUserConfirmation(context, "workspace", desc);
4577
- if (!approved) return helpers.error(`User denied: ${isBranchChange ? "branch change" : `switch to ${label}`}`);
4931
+ if (!approved)
4932
+ return helpers.error(
4933
+ serverT(
4934
+ { en: "User denied: {{what}}", fr: "Refus\xE9 par l\u2019utilisateur : {{what}}" },
4935
+ { what: isBranchChange ? "branch change" : `switch to ${label}` }
4936
+ )
4937
+ );
4578
4938
  const updated = await sessionManager.switchWorkspace(sessionId, args.target, args.branch, args.sourceBranch);
4579
4939
  const wsName = args.target === "original" ? "original" : updated.workspace?.split("/").pop() ?? args.target;
4580
4940
  const branch = await getGitBranch(updated.workspace ?? updated.workdir);
@@ -4584,7 +4944,13 @@ Actions:
4584
4944
  workspace: wsName,
4585
4945
  path: updated.workspace ?? updated.workdir,
4586
4946
  branch,
4587
- message: args.target === "original" ? "Switched to original project" : `Switched to workspace "${wsName}" on branch "${branch ?? "unknown"}"`
4947
+ message: args.target === "original" ? serverT({ en: "Switched to original project", fr: "Basculement vers le projet d\u2019origine" }) : serverT(
4948
+ {
4949
+ en: 'Switched to workspace "{{name}}" on branch "{{branch}}"',
4950
+ fr: "Basculement vers le workspace \xAB {{name}} \xBB sur la branche \xAB {{branch}} \xBB"
4951
+ },
4952
+ { name: wsName, branch: branch ?? "unknown" }
4953
+ )
4588
4954
  },
4589
4955
  null,
4590
4956
  2
@@ -4593,9 +4959,9 @@ Actions:
4593
4959
  }
4594
4960
  case "list": {
4595
4961
  const session = sessionManager.getSession(sessionId);
4596
- if (!session) return helpers.error("Session not found");
4962
+ if (!session) return helpers.error(serverT({ en: "Session not found", fr: "Session introuvable" }));
4597
4963
  const project = sessionManager.getProject(session.projectId);
4598
- if (!project) return helpers.error("Project not found");
4964
+ if (!project) return helpers.error(serverT({ en: "Project not found", fr: "Projet introuvable" }));
4599
4965
  const currentBranch = await getGitBranch(sessionManager.getEffectiveWorkdir(session.id));
4600
4966
  const named = await listWorkspaces(project.name, project.workdir);
4601
4967
  const activeWsName = session.workspace?.split("/").pop() ?? null;
@@ -4611,11 +4977,24 @@ Actions:
4611
4977
  }
4612
4978
  case "delete": {
4613
4979
  if (!args.target || typeof args.target !== "string") {
4614
- return helpers.error('Parameter "target" is required for action=delete (the workspace name)');
4980
+ return helpers.error(
4981
+ serverT({
4982
+ en: 'Parameter "target" is required for action=delete (the workspace name)',
4983
+ fr: "Le param\xE8tre \xAB target \xBB est requis pour action=delete (le nom du workspace)"
4984
+ })
4985
+ );
4615
4986
  }
4616
- if (args.target === "original") return helpers.error("Cannot delete the original workspace");
4987
+ if (args.target === "original")
4988
+ return helpers.error(
4989
+ serverT({
4990
+ en: "Cannot delete the original workspace",
4991
+ fr: "Impossible de supprimer le workspace d\u2019origine"
4992
+ })
4993
+ );
4617
4994
  if (await isGitRepository(context.workdir) === false) {
4618
- return helpers.error("Project is not a git repository");
4995
+ return helpers.error(
4996
+ serverT({ en: "Project is not a git repository", fr: "Le projet n\u2019est pas un d\xE9p\xF4t git" })
4997
+ );
4619
4998
  }
4620
4999
  const forceDesc = args.force ? " (will auto-switch other sessions to original)" : "";
4621
5000
  const approved = await requestUserConfirmation(
@@ -4623,13 +5002,25 @@ Actions:
4623
5002
  "workspace",
4624
5003
  `Delete workspace "${args.target}"${forceDesc}`
4625
5004
  );
4626
- if (!approved) return helpers.error(`User denied: delete workspace "${args.target}"`);
5005
+ if (!approved)
5006
+ return helpers.error(
5007
+ serverT(
5008
+ {
5009
+ en: 'User denied: delete workspace "{{name}}"',
5010
+ fr: "Refus\xE9 par l\u2019utilisateur : supprimer le workspace \xAB {{name}} \xBB"
5011
+ },
5012
+ { name: args.target }
5013
+ )
5014
+ );
4627
5015
  await sessionManager.deleteWorkspace(sessionId, args.target, args.force === true);
4628
5016
  return helpers.success(
4629
5017
  JSON.stringify(
4630
5018
  {
4631
5019
  workspace: args.target,
4632
- message: `Workspace "${args.target}" has been deleted`
5020
+ message: serverT(
5021
+ { en: 'Workspace "{{name}}" has been deleted', fr: "Le workspace \xAB {{name}} \xBB a \xE9t\xE9 supprim\xE9" },
5022
+ { name: args.target }
5023
+ )
4633
5024
  },
4634
5025
  null,
4635
5026
  2
@@ -4637,7 +5028,9 @@ Actions:
4637
5028
  );
4638
5029
  }
4639
5030
  default:
4640
- return helpers.error(`Unknown action: ${args.action}`);
5031
+ return helpers.error(
5032
+ serverT({ en: "Unknown action: {{action}}", fr: "Action inconnue : {{action}}" }, { action: args.action })
5033
+ );
4641
5034
  }
4642
5035
  }
4643
5036
  );
@@ -4709,7 +5102,7 @@ var projectTasksTool = createTool(
4709
5102
  const permError = validateActionWithPermission(action, VALID_ACTIONS, "project_tasks", context.permittedActions);
4710
5103
  if (permError) return permError;
4711
5104
  const session = context.sessionManager.getSession(context.sessionId);
4712
- if (!session) return helpers.error("Session not found");
5105
+ if (!session) return helpers.error(serverT({ en: "Session not found", fr: "Session introuvable" }));
4713
5106
  const projectId = session.projectId;
4714
5107
  const svc = getTasksService();
4715
5108
  const actor = { actor: "agent", actorName: "agent" };
@@ -4719,7 +5112,13 @@ var projectTasksTool = createTool(
4719
5112
  const status = args.status;
4720
5113
  if (status !== void 0 && !LIST_STATUSES.includes(status)) {
4721
5114
  return helpers.error(
4722
- `Invalid "status" filter for action=list: "${String(status)}". Expected one of: todo, in_progress, done, all.`
5115
+ serverT(
5116
+ {
5117
+ en: 'Invalid "status" filter for action=list: "{{status}}". Expected one of: todo, in_progress, done, all.',
5118
+ fr: "Filtre \xAB status \xBB invalide pour action=list : \xAB {{status}} \xBB. Valeurs attendues : todo, in_progress, done, all."
5119
+ },
5120
+ { status: String(status) }
5121
+ )
4723
5122
  );
4724
5123
  }
4725
5124
  const page = parseListPage(args.limit, args.offset);
@@ -4758,7 +5157,13 @@ var projectTasksTool = createTool(
4758
5157
  return helpers.success(JSON.stringify(taskForAgent(task), null, 2));
4759
5158
  }
4760
5159
  case "edit": {
4761
- if (!args.taskId) return helpers.error('Parameter "taskId" is required for action=edit');
5160
+ if (!args.taskId)
5161
+ return helpers.error(
5162
+ serverT({
5163
+ en: 'Parameter "taskId" is required for action=edit',
5164
+ fr: "Le param\xE8tre \xAB taskId \xBB est requis pour action=edit"
5165
+ })
5166
+ );
4762
5167
  const result = await svc.update(
4763
5168
  projectId,
4764
5169
  args.taskId,
@@ -4775,9 +5180,20 @@ var projectTasksTool = createTool(
4775
5180
  return helpers.success(JSON.stringify(taskForAgent(result.task), null, 2));
4776
5181
  }
4777
5182
  case "move": {
4778
- if (!args.taskId) return helpers.error('Parameter "taskId" is required for action=move');
5183
+ if (!args.taskId)
5184
+ return helpers.error(
5185
+ serverT({
5186
+ en: 'Parameter "taskId" is required for action=move',
5187
+ fr: "Le param\xE8tre \xAB taskId \xBB est requis pour action=move"
5188
+ })
5189
+ );
4779
5190
  if (!args.to)
4780
- return helpers.error('Parameter "to" is required for action=move ("todo" | "in_progress" | "done")');
5191
+ return helpers.error(
5192
+ serverT({
5193
+ en: 'Parameter "to" is required for action=move ("todo" | "in_progress" | "done")',
5194
+ fr: "Le param\xE8tre \xAB to \xBB est requis pour action=move (\xAB todo \xBB | \xAB in_progress \xBB | \xAB done \xBB)"
5195
+ })
5196
+ );
4781
5197
  const result = await svc.move(projectId, args.taskId, args.to, {
4782
5198
  actor: "agent",
4783
5199
  actorName: "agent",
@@ -4788,9 +5204,27 @@ var projectTasksTool = createTool(
4788
5204
  return helpers.success(JSON.stringify(taskForAgent(result.task), null, 2));
4789
5205
  }
4790
5206
  case "set_gate_value": {
4791
- if (!args.taskId) return helpers.error('Parameter "taskId" is required for action=set_gate_value');
4792
- if (!args.gateId) return helpers.error('Parameter "gateId" is required for action=set_gate_value');
4793
- if (args.value === void 0) return helpers.error('Parameter "value" is required for action=set_gate_value');
5207
+ if (!args.taskId)
5208
+ return helpers.error(
5209
+ serverT({
5210
+ en: 'Parameter "taskId" is required for action=set_gate_value',
5211
+ fr: "Le param\xE8tre \xAB taskId \xBB est requis pour action=set_gate_value"
5212
+ })
5213
+ );
5214
+ if (!args.gateId)
5215
+ return helpers.error(
5216
+ serverT({
5217
+ en: 'Parameter "gateId" is required for action=set_gate_value',
5218
+ fr: "Le param\xE8tre \xAB gateId \xBB est requis pour action=set_gate_value"
5219
+ })
5220
+ );
5221
+ if (args.value === void 0)
5222
+ return helpers.error(
5223
+ serverT({
5224
+ en: 'Parameter "value" is required for action=set_gate_value',
5225
+ fr: "Le param\xE8tre \xAB value \xBB est requis pour action=set_gate_value"
5226
+ })
5227
+ );
4794
5228
  const result = await svc.setGateValue(
4795
5229
  projectId,
4796
5230
  args.taskId,
@@ -4803,9 +5237,18 @@ var projectTasksTool = createTool(
4803
5237
  return helpers.success(JSON.stringify(taskForAgent(result.task), null, 2));
4804
5238
  }
4805
5239
  case "delete": {
4806
- if (!args.taskId) return helpers.error('Parameter "taskId" is required for action=delete');
5240
+ if (!args.taskId)
5241
+ return helpers.error(
5242
+ serverT({
5243
+ en: 'Parameter "taskId" is required for action=delete',
5244
+ fr: "Le param\xE8tre \xAB taskId \xBB est requis pour action=delete"
5245
+ })
5246
+ );
4807
5247
  const task = svc.get(projectId, args.taskId);
4808
- if (!task) return helpers.error(`Task not found: ${args.taskId}`);
5248
+ if (!task)
5249
+ return helpers.error(
5250
+ serverT({ en: "Task not found: {{id}}", fr: "T\xE2che introuvable : {{id}}" }, { id: args.taskId ?? "" })
5251
+ );
4809
5252
  await svc.remove(projectId, args.taskId, actor);
4810
5253
  return helpers.success(
4811
5254
  JSON.stringify(
@@ -4816,18 +5259,32 @@ var projectTasksTool = createTool(
4816
5259
  );
4817
5260
  }
4818
5261
  default:
4819
- return helpers.error(`Unknown action: ${String(action)}`);
5262
+ return helpers.error(
5263
+ serverT(
5264
+ { en: "Unknown action: {{action}}", fr: "Action inconnue : {{action}}" },
5265
+ { action: String(action) }
5266
+ )
5267
+ );
4820
5268
  }
4821
5269
  } catch (error) {
4822
5270
  if (isTaskGateError(error)) {
4823
5271
  const missing = error.missing.map((m) => `'${m.name}' (${m.gateId}): ${m.description}`).join("; ");
4824
5272
  return helpers.error(
4825
- `Move blocked by column gates. Missing required gate fields: ${missing}. Fill them with action=set_gate_value (taskId, gateId, value=<acceptable proof>) and then call move again. You set these values as part of your work \u2014 this is the intended loop, not a dead end.`
5273
+ serverT(
5274
+ {
5275
+ en: "Move blocked by column gates. Missing required gate fields: {{missing}}. Fill them with action=set_gate_value (taskId, gateId, value=<acceptable proof>) and then call move again. You set these values as part of your work \u2014 this is the intended loop, not a dead end.",
5276
+ fr: "D\xE9placement bloqu\xE9 par les portes de colonne. Champs de porte requis manquants : {{missing}}. Renseignez-les avec action=set_gate_value (taskId, gateId, value=<preuve acceptable>) puis appelez \xE0 nouveau move. Vous d\xE9finissez ces valeurs dans le cadre de votre travail \u2014 c\u2019est la boucle pr\xE9vue, pas une impasse."
5277
+ },
5278
+ { missing }
5279
+ )
4826
5280
  );
4827
5281
  }
4828
5282
  if (isTaskConflictError(error)) {
4829
5283
  return helpers.error(
4830
- `Task changed, refresh and retry. Another actor modified this task since your last read. Re-list and retry with the latest updatedAt.`
5284
+ serverT({
5285
+ en: "Task changed, refresh and retry. Another actor modified this task since your last read. Re-list and retry with the latest updatedAt.",
5286
+ fr: "T\xE2che modifi\xE9e, actualisez et r\xE9essayez. Un autre acteur a modifi\xE9 cette t\xE2che depuis votre derni\xE8re lecture. Re-listez et r\xE9essayez avec le updatedAt le plus r\xE9cent."
5287
+ })
4831
5288
  );
4832
5289
  }
4833
5290
  throw error;
@@ -5158,4 +5615,4 @@ export {
5158
5615
  getToolRegistryForAgent,
5159
5616
  createToolRegistry
5160
5617
  };
5161
- //# sourceMappingURL=chunk-HXHPKGJE.js.map
5618
+ //# sourceMappingURL=chunk-J5HOUEPE.js.map