openfox 2.0.67 → 2.0.69

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 (40) hide show
  1. package/dist/{chat-handler-72DFHK5K.js → chat-handler-K3DWIGHG.js} +7 -6
  2. package/dist/{chunk-B6JUWVTK.js → chunk-46OR4W3L.js} +7 -7
  3. package/dist/{chunk-TMHWQYWE.js → chunk-64GN6OPR.js} +2 -2
  4. package/dist/{chunk-5EO6SEGV.js → chunk-7OW6X764.js} +2 -2
  5. package/dist/{chunk-B7WGOK7G.js → chunk-E4POUD2M.js} +2 -2
  6. package/dist/{chunk-BL5LOLVA.js → chunk-JHGKXQBO.js} +161 -28
  7. package/dist/{chunk-YU6DZAVA.js → chunk-PVWAE43V.js} +55 -100
  8. package/dist/{chunk-TJO4QFDQ.js → chunk-QFSDJIUS.js} +2 -2
  9. package/dist/chunk-UN26GIQG.js +54 -0
  10. package/dist/{chunk-PYRH4G2J.js → chunk-UTSSFPYA.js} +5 -5
  11. package/dist/{chunk-MQHMT5WF.js → chunk-VFYNKALW.js} +3 -3
  12. package/dist/{chunk-2GRUQN2B.js → chunk-WHVCGVQX.js} +384 -68
  13. package/dist/{chunk-ZLON3JTI.js → chunk-YQ3MEZJL.js} +2 -2
  14. package/dist/cli/dev.js +1 -1
  15. package/dist/cli/index.js +1 -1
  16. package/dist/{client-BUX62J2K.js → client-63U5CTPE.js} +3 -3
  17. package/dist/{client-pure-U6ZYUPJQ.js → client-pure-XHH4RRLB.js} +2 -2
  18. package/dist/{compactor-74CZVUWI.js → compactor-IPMMFFHM.js} +4 -4
  19. package/dist/{orchestrator-FEMPJOZD.js → orchestrator-PUV4WG77.js} +6 -5
  20. package/dist/package.json +3 -2
  21. package/dist/{processor-QB3NMRMO.js → processor-O2QW27BD.js} +7 -6
  22. package/dist/{protocol-42f_Png6.d.ts → protocol-DIhV-tAc.d.ts} +1 -1
  23. package/dist/provider/index.d.ts +4 -4
  24. package/dist/{provider-BDH6JGZB.js → provider-IBIWR4AI.js} +4 -4
  25. package/dist/{provider-manager-D3KIOD5E.js → provider-manager-7C3JVOLW.js} +4 -4
  26. package/dist/{serve-32FAA4FX.js → serve-Q34XBLR5.js} +11 -10
  27. package/dist/server/index.d.ts +3 -3
  28. package/dist/server/index.js +10 -9
  29. package/dist/{server-OYE7GERR.js → server-RLNPHLY2.js} +8 -7
  30. package/dist/shared/index.d.ts +3 -3
  31. package/dist/{tools-INWP6FGV.js → tools-CALGWIV2.js} +5 -4
  32. package/dist/{types-vezAEt_y.d.ts → types-BsfYpEai.d.ts} +2 -1
  33. package/dist/{types-apiMd7Df.d.ts → types-CBC6lLqc.d.ts} +1 -1
  34. package/dist/update-server-MYYQUNZX.js +10 -0
  35. package/dist/web/assets/{index-BELeAs12.css → index-BVTG7SRG.css} +1 -1
  36. package/dist/web/assets/{index-C3n65CNu.js → index-oKJVe9Cz.js} +75 -73
  37. package/dist/web/index.html +2 -2
  38. package/dist/web/sw.js +1 -1
  39. package/package.json +3 -2
  40. package/plugins-registry.json +14 -0
@@ -2,17 +2,18 @@ import {
2
2
  buildRunChatTurnParams,
3
3
  finalizeTurnCompletion,
4
4
  generateSessionNameForSession
5
- } from "./chunk-TMHWQYWE.js";
5
+ } from "./chunk-64GN6OPR.js";
6
6
  import {
7
7
  runChatTurn
8
- } from "./chunk-PYRH4G2J.js";
9
- import "./chunk-YU6DZAVA.js";
10
- import "./chunk-TJO4QFDQ.js";
8
+ } from "./chunk-UTSSFPYA.js";
9
+ import "./chunk-PVWAE43V.js";
10
+ import "./chunk-QFSDJIUS.js";
11
11
  import "./chunk-4QBDV6LX.js";
12
12
  import "./chunk-KXVFHMSM.js";
13
13
  import "./chunk-TFCHWMOJ.js";
14
14
  import "./chunk-PK2RMVMB.js";
15
15
  import "./chunk-NWO6GRYE.js";
16
+ import "./chunk-UN26GIQG.js";
16
17
  import "./chunk-VLV3XWZS.js";
17
18
  import "./chunk-WGMJCFCE.js";
18
19
  import {
@@ -31,7 +32,7 @@ import "./chunk-EU3WWTFH.js";
31
32
  import "./chunk-J2GP3J3X.js";
32
33
  import "./chunk-V4IE7HJY.js";
33
34
  import "./chunk-YHEQTVFV.js";
34
- import "./chunk-BL5LOLVA.js";
35
+ import "./chunk-JHGKXQBO.js";
35
36
  import "./chunk-K44MW7JJ.js";
36
37
  import "./chunk-YD6NDTKF.js";
37
38
  import "./chunk-WGAAQASA.js";
@@ -157,4 +158,4 @@ export {
157
158
  startChatSession,
158
159
  stopSessionExecution
159
160
  };
160
- //# sourceMappingURL=chat-handler-72DFHK5K.js.map
161
+ //# sourceMappingURL=chat-handler-K3DWIGHG.js.map
@@ -3,10 +3,7 @@ import {
3
3
  computeSessionHash,
4
4
  runAgentTurn,
5
5
  runChatTurn
6
- } from "./chunk-PYRH4G2J.js";
7
- import {
8
- appendCompactionPrompt
9
- } from "./chunk-ZLON3JTI.js";
6
+ } from "./chunk-UTSSFPYA.js";
10
7
  import {
11
8
  deleteItemFromDir,
12
9
  devServerManager,
@@ -16,11 +13,14 @@ import {
16
13
  jsonSerializer,
17
14
  loadAllAgentsDefault,
18
15
  saveItemToDir
19
- } from "./chunk-YU6DZAVA.js";
16
+ } from "./chunk-PVWAE43V.js";
17
+ import {
18
+ appendCompactionPrompt
19
+ } from "./chunk-YQ3MEZJL.js";
20
20
  import {
21
21
  TurnMetrics,
22
22
  createMessageStartEvent
23
- } from "./chunk-TJO4QFDQ.js";
23
+ } from "./chunk-QFSDJIUS.js";
24
24
  import {
25
25
  checkAborted,
26
26
  onProcessEvent,
@@ -2158,4 +2158,4 @@ export {
2158
2158
  signalMcpReady,
2159
2159
  createWebSocketServer
2160
2160
  };
2161
- //# sourceMappingURL=chunk-B6JUWVTK.js.map
2161
+ //# sourceMappingURL=chunk-46OR4W3L.js.map
@@ -135,7 +135,7 @@ async function generateSessionNameForSession(sessionId, userMessage, deps, signa
135
135
  client = deps.getLLMClient();
136
136
  client.setModel(providerConfig.model);
137
137
  } else if (providerConfig) {
138
- const { createLLMClient } = await import("./client-BUX62J2K.js");
138
+ const { createLLMClient } = await import("./client-63U5CTPE.js");
139
139
  client = createLLMClient({
140
140
  llm: {
141
141
  baseUrl: providerConfig.baseUrl,
@@ -184,4 +184,4 @@ export {
184
184
  buildRunChatTurnParams,
185
185
  generateSessionNameForSession
186
186
  };
187
- //# sourceMappingURL=chunk-TMHWQYWE.js.map
187
+ //# sourceMappingURL=chunk-64GN6OPR.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createLLMClient
3
- } from "./chunk-B7WGOK7G.js";
3
+ } from "./chunk-E4POUD2M.js";
4
4
  import {
5
5
  getModelProfile
6
6
  } from "./chunk-V4IE7HJY.js";
@@ -796,4 +796,4 @@ export {
796
796
  parseDefaultModelSelection,
797
797
  createProviderManager
798
798
  };
799
- //# sourceMappingURL=chunk-5EO6SEGV.js.map
799
+ //# sourceMappingURL=chunk-7OW6X764.js.map
@@ -13,7 +13,7 @@ import {
13
13
  getThinking,
14
14
  mapFinishReason,
15
15
  parseToolArguments
16
- } from "./chunk-BL5LOLVA.js";
16
+ } from "./chunk-JHGKXQBO.js";
17
17
  import {
18
18
  LLMError,
19
19
  OpenAIHttpClient
@@ -265,4 +265,4 @@ function createLLMClient(config, initialBackend = "unknown") {
265
265
  export {
266
266
  createLLMClient
267
267
  };
268
- //# sourceMappingURL=chunk-B7WGOK7G.js.map
268
+ //# sourceMappingURL=chunk-E4POUD2M.js.map
@@ -1,3 +1,101 @@
1
+ // src/server/tools/types.ts
2
+ var OUTPUT_LIMITS = {
3
+ read_file: {
4
+ maxLines: 2e3,
5
+ maxBytes: 1e5,
6
+ maxImageBytes: 2097152,
7
+ // 2MB for images
8
+ maxPdfPages: 50,
9
+ maxFileBytes: 20971520
10
+ // 20MB general file safety limit
11
+ },
12
+ run_command: {
13
+ maxLines: 2e3,
14
+ maxBytes: 5e4
15
+ },
16
+ glob: {
17
+ maxResults: 500
18
+ },
19
+ grep: {
20
+ maxMatches: 200
21
+ },
22
+ web_fetch: {
23
+ maxBytes: 1e5
24
+ }
25
+ };
26
+
27
+ // src/server/tools/pdf-utils.ts
28
+ import { getDocument } from "pdfjs-dist/legacy/build/pdf.mjs";
29
+ var PDF_HEADER = Buffer.from("%PDF");
30
+ function isPdfBuffer(buffer) {
31
+ return buffer.length > 4 && buffer.subarray(0, 4).equals(PDF_HEADER);
32
+ }
33
+ function isPasswordError(err) {
34
+ const message = err instanceof Error ? err.message : String(err);
35
+ return message.toLowerCase().includes("password") || message.toLowerCase().includes("encrypt");
36
+ }
37
+ function formatPdfErrorMessage(err) {
38
+ if (isPasswordError(err)) {
39
+ return "This PDF is password-protected. Unlock it with an external tool first.";
40
+ }
41
+ return `Failed to read PDF: ${err instanceof Error ? err.message : String(err)}`;
42
+ }
43
+ function processPdfContent(text, maxBytes) {
44
+ let output = text;
45
+ let truncated = false;
46
+ if (output.length > maxBytes) {
47
+ output = output.slice(0, maxBytes) + "\n\n[Output truncated due to size limit]";
48
+ truncated = true;
49
+ }
50
+ const isScanned = output.replace(/\[Page \d+\/\d+\]\n/g, "").trim().length === 0;
51
+ return { output, truncated, isScanned };
52
+ }
53
+ async function extractPdfText(buffer) {
54
+ const doc = await getDocument({ data: Uint8Array.from(buffer) }).promise;
55
+ const pageCount = doc.numPages;
56
+ const rawMeta = await doc.getMetadata();
57
+ const info = rawMeta.info;
58
+ const title = info?.["Title"] || null;
59
+ const author = info?.["Author"] || null;
60
+ const pages = [];
61
+ const limitedPageCount = Math.min(pageCount, OUTPUT_LIMITS.read_file.maxPdfPages);
62
+ try {
63
+ for (let i = 1; i <= limitedPageCount; i++) {
64
+ const page = await doc.getPage(i);
65
+ try {
66
+ const content = await page.getTextContent();
67
+ const pageText = content.items.map((item) => "str" in item ? item.str : "").join(" ");
68
+ pages.push(`[Page ${i}/${pageCount}]
69
+ ${pageText}`);
70
+ } finally {
71
+ page.cleanup();
72
+ }
73
+ }
74
+ } finally {
75
+ doc.cleanup();
76
+ }
77
+ let text = pages.join("\n\n");
78
+ if (pageCount > limitedPageCount) {
79
+ text += `
80
+
81
+ [PDF has ${pageCount} pages, showing first ${limitedPageCount}. Use a shell command to process more.]`;
82
+ }
83
+ return { text, pageCount, title, author };
84
+ }
85
+
86
+ // src/shared/constants.ts
87
+ var TEXT_MIME_PREFIXES = ["text/"];
88
+ var TEXT_MIME_EXACT = [
89
+ "application/json",
90
+ "application/xml",
91
+ "application/yaml",
92
+ "application/x-yaml",
93
+ "application/javascript",
94
+ "application/xhtml+xml",
95
+ "application/x-sh",
96
+ "image/svg+xml"
97
+ ];
98
+
1
99
  // src/server/llm/client-pure.ts
2
100
  function parseToolArguments(raw, _meta) {
3
101
  const input = raw?.trim() ? raw : "{}";
@@ -22,13 +120,14 @@ function buildModelParams(params) {
22
120
  ...params.maxTokens !== void 0 && { maxTokens: params.maxTokens }
23
121
  };
24
122
  }
25
- function buildAttachmentContent(msgContent, attachments, modelSupportsVision) {
123
+ async function buildAttachmentContent(msgContent, attachments, modelSupportsVision) {
26
124
  const content = [];
27
125
  if (msgContent?.trim()) {
28
126
  content.push({ type: "text", text: msgContent });
29
127
  }
30
128
  for (const attachment of attachments) {
31
- content.push(convertAttachmentSync(attachment, modelSupportsVision));
129
+ const converted = await convertAttachment(attachment, modelSupportsVision);
130
+ content.push(converted);
32
131
  }
33
132
  return content;
34
133
  }
@@ -62,7 +161,34 @@ function buildAssistantMessage(msg, thinkingField) {
62
161
  }
63
162
  return result;
64
163
  }
65
- function convertAttachmentSync(attachment, modelSupportsVision) {
164
+ async function convertAttachment(attachment, modelSupportsVision) {
165
+ const mimeType = attachment.mimeType;
166
+ if (TEXT_MIME_EXACT.includes(mimeType) || TEXT_MIME_PREFIXES.some((p) => mimeType.startsWith(p))) {
167
+ return {
168
+ type: "text",
169
+ text: `[File: ${attachment.filename || "file"}]
170
+ ${attachment.data}`
171
+ };
172
+ }
173
+ if (mimeType === "application/pdf") {
174
+ try {
175
+ const base64Match = attachment.data.match(/^data:.*?;base64,(.+)$/);
176
+ if (base64Match?.[1]) {
177
+ const buffer = Buffer.from(base64Match[1], "base64");
178
+ const result = await extractPdfText(buffer);
179
+ return {
180
+ type: "text",
181
+ text: `[PDF: ${attachment.filename || "document.pdf"}]
182
+ ${result.text}`
183
+ };
184
+ }
185
+ } catch {
186
+ }
187
+ return {
188
+ type: "text",
189
+ text: `[PDF: ${attachment.filename || "document.pdf"}] (could not extract text)`
190
+ };
191
+ }
66
192
  if (modelSupportsVision) {
67
193
  return {
68
194
  type: "image_url",
@@ -80,41 +206,43 @@ function convertAttachmentSync(attachment, modelSupportsVision) {
80
206
  text: `[Image: ${attachment.filename || "image"}] (vision not supported, cannot describe)`
81
207
  };
82
208
  }
83
- function convertMessages(messages, modelSupportsVision, thinkingField) {
209
+ async function convertMessages(messages, modelSupportsVision, thinkingField) {
84
210
  const filtered = messages.filter((msg) => {
85
211
  return !(msg.role === "assistant" && !msg.content?.trim() && (!msg.toolCalls || msg.toolCalls.length === 0));
86
212
  });
87
- return filtered.map((msg) => {
213
+ const result = [];
214
+ for (const msg of filtered) {
88
215
  if (msg.role === "tool") {
89
216
  if (msg.attachments && msg.attachments.length > 0) {
90
- const content = buildAttachmentContent(msg.content, msg.attachments, modelSupportsVision);
91
- return {
217
+ const content = await buildAttachmentContent(msg.content, msg.attachments, modelSupportsVision);
218
+ result.push({
92
219
  role: "tool",
93
220
  content,
94
221
  tool_call_id: msg.toolCallId
95
- };
222
+ });
223
+ } else {
224
+ result.push({
225
+ role: "tool",
226
+ content: msg.content,
227
+ tool_call_id: msg.toolCallId
228
+ });
96
229
  }
97
- return {
98
- role: "tool",
99
- content: msg.content,
100
- tool_call_id: msg.toolCallId
101
- };
102
- }
103
- if (msg.role === "assistant") {
104
- return buildAssistantMessage(msg, thinkingField);
105
- }
106
- if (msg.role === "user" && msg.attachments && msg.attachments.length > 0) {
107
- const content = buildAttachmentContent(msg.content, msg.attachments, modelSupportsVision);
108
- return {
230
+ } else if (msg.role === "assistant") {
231
+ result.push(buildAssistantMessage(msg, thinkingField));
232
+ } else if (msg.role === "user" && msg.attachments && msg.attachments.length > 0) {
233
+ const content = await buildAttachmentContent(msg.content, msg.attachments, modelSupportsVision);
234
+ result.push({
109
235
  role: "user",
110
236
  content
111
- };
237
+ });
238
+ } else {
239
+ result.push({
240
+ role: msg.role,
241
+ content: msg.content
242
+ });
112
243
  }
113
- return {
114
- role: msg.role,
115
- content: msg.content
116
- };
117
- });
244
+ }
245
+ return result;
118
246
  }
119
247
  function convertTools(tools) {
120
248
  return tools.map((tool) => ({
@@ -129,7 +257,7 @@ function convertTools(tools) {
129
257
  async function buildChatCompletionCreateParams(model, request, profile, capabilities, reasoningEffort, isStreaming, thinkingField) {
130
258
  const userVisionOverride = request.modelSettings?.supportsVision;
131
259
  const modelSupportsVision = userVisionOverride ?? profile.supportsVision ?? false;
132
- const convertedMessages = convertMessages(request.messages, modelSupportsVision, thinkingField);
260
+ const convertedMessages = await convertMessages(request.messages, modelSupportsVision, thinkingField);
133
261
  const temperature = request.modelSettings?.temperature ?? request.temperature ?? profile.temperature;
134
262
  const maxTokens = request.modelSettings?.maxTokens ?? request.maxTokens ?? profile.defaultMaxTokens;
135
263
  const topP = request.modelSettings?.topP ?? profile.topP;
@@ -210,6 +338,11 @@ function mapFinishReason(reason) {
210
338
  }
211
339
 
212
340
  export {
341
+ OUTPUT_LIMITS,
342
+ isPdfBuffer,
343
+ formatPdfErrorMessage,
344
+ processPdfContent,
345
+ extractPdfText,
213
346
  parseToolArguments,
214
347
  buildModelParams,
215
348
  getThinking,
@@ -219,4 +352,4 @@ export {
219
352
  buildStreamingCreateParams,
220
353
  mapFinishReason
221
354
  };
222
- //# sourceMappingURL=chunk-BL5LOLVA.js.map
355
+ //# sourceMappingURL=chunk-JHGKXQBO.js.map
@@ -10,7 +10,7 @@ import {
10
10
  createToolCallEvent,
11
11
  createToolResultEvent,
12
12
  streamLLMPure
13
- } from "./chunk-TJO4QFDQ.js";
13
+ } from "./chunk-QFSDJIUS.js";
14
14
  import {
15
15
  startInspectProxy
16
16
  } from "./chunk-4QBDV6LX.js";
@@ -36,6 +36,9 @@ import {
36
36
  import {
37
37
  createMcpTools
38
38
  } from "./chunk-NWO6GRYE.js";
39
+ import {
40
+ applyMcpServerUpdate
41
+ } from "./chunk-UN26GIQG.js";
39
42
  import {
40
43
  listBranches
41
44
  } from "./chunk-VLV3XWZS.js";
@@ -75,6 +78,13 @@ import {
75
78
  import {
76
79
  modelSupportsVision
77
80
  } from "./chunk-V4IE7HJY.js";
81
+ import {
82
+ OUTPUT_LIMITS,
83
+ extractPdfText,
84
+ formatPdfErrorMessage,
85
+ isPdfBuffer,
86
+ processPdfContent
87
+ } from "./chunk-JHGKXQBO.js";
78
88
  import {
79
89
  logger
80
90
  } from "./chunk-K44MW7JJ.js";
@@ -90,32 +100,6 @@ import {
90
100
  import { readFile as readFile2, stat, readdir } from "fs/promises";
91
101
  import { extname, join as join2 } from "path";
92
102
 
93
- // src/server/tools/types.ts
94
- var OUTPUT_LIMITS = {
95
- read_file: {
96
- maxLines: 2e3,
97
- maxBytes: 1e5,
98
- maxImageBytes: 2097152,
99
- // 2MB for images
100
- maxPdfPages: 50,
101
- maxFileBytes: 20971520
102
- // 20MB general file safety limit
103
- },
104
- run_command: {
105
- maxLines: 2e3,
106
- maxBytes: 5e4
107
- },
108
- glob: {
109
- maxResults: 500
110
- },
111
- grep: {
112
- maxMatches: 200
113
- },
114
- web_fetch: {
115
- maxBytes: 1e5
116
- }
117
- };
118
-
119
103
  // src/server/tools/tool-helpers.ts
120
104
  import { resolve as resolve2, isAbsolute } from "path";
121
105
 
@@ -244,9 +228,9 @@ function extractAbsolutePathsFromCommand(command) {
244
228
  const paths = [];
245
229
  const home = homedir();
246
230
  let sanitized = command.replace(/https?:\/\/[^\s'"]+/g, " __URL__ ").replace(/ftp:\/\/[^\s'"]+/g, " __URL__ ");
247
- sanitized = sanitized.replace(/s\/[^/]*\/[^/]*\/[gip]*/g, " __SED__ ");
248
- sanitized = sanitized.replace(/s\|[^|]*\|[^|]*\|[gip]*/g, " __SED__ ");
249
- sanitized = sanitized.replace(/s:[^:]*:[^:]*:[gip]*/g, " __SED__ ");
231
+ sanitized = sanitized.replace(/(?<!\w)s\/[^/]*\/[^/]*\/[gip]*/g, " __SED__ ");
232
+ sanitized = sanitized.replace(/(?<!\w)s\|[^|]*\|[^|]*\|[gip]*/g, " __SED__ ");
233
+ sanitized = sanitized.replace(/(?<!\w)s:[^:]*:[^:]*:[gip]*/g, " __SED__ ");
250
234
  sanitized = sanitized.replace(
251
235
  /git\s+commit\b.*?(?:-(?:[a-zA-Z]*m)(?=\s)|--message)\s+(["'])(?:(?!\1).)*\1/g,
252
236
  (match2) => match2.replace(/\/[^\s"'|&;<>`()]+/g, " __COMMIT_MSG__ ")
@@ -863,67 +847,6 @@ function stringToUtf32(str, littleEndian) {
863
847
 
864
848
  // src/server/tools/read.ts
865
849
  import { fileTypeFromBuffer } from "file-type";
866
-
867
- // src/server/tools/pdf-utils.ts
868
- import { getDocument } from "pdfjs-dist/legacy/build/pdf.mjs";
869
- var PDF_HEADER = Buffer.from("%PDF");
870
- function isPdfBuffer(buffer) {
871
- return buffer.length > 4 && buffer.subarray(0, 4).equals(PDF_HEADER);
872
- }
873
- function isPasswordError(err) {
874
- const message = err instanceof Error ? err.message : String(err);
875
- return message.toLowerCase().includes("password") || message.toLowerCase().includes("encrypt");
876
- }
877
- function formatPdfErrorMessage(err) {
878
- if (isPasswordError(err)) {
879
- return "This PDF is password-protected. Unlock it with an external tool first.";
880
- }
881
- return `Failed to read PDF: ${err instanceof Error ? err.message : String(err)}`;
882
- }
883
- function processPdfContent(text, maxBytes) {
884
- let output = text;
885
- let truncated = false;
886
- if (output.length > maxBytes) {
887
- output = output.slice(0, maxBytes) + "\n\n[Output truncated due to size limit]";
888
- truncated = true;
889
- }
890
- const isScanned = output.replace(/\[Page \d+\/\d+\]\n/g, "").trim().length === 0;
891
- return { output, truncated, isScanned };
892
- }
893
- async function extractPdfText(buffer) {
894
- const doc = await getDocument({ data: Uint8Array.from(buffer) }).promise;
895
- const pageCount = doc.numPages;
896
- const rawMeta = await doc.getMetadata();
897
- const info = rawMeta.info;
898
- const title = info?.["Title"] || null;
899
- const author = info?.["Author"] || null;
900
- const pages = [];
901
- const limitedPageCount = Math.min(pageCount, OUTPUT_LIMITS.read_file.maxPdfPages);
902
- try {
903
- for (let i = 1; i <= limitedPageCount; i++) {
904
- const page = await doc.getPage(i);
905
- try {
906
- const content = await page.getTextContent();
907
- const pageText = content.items.map((item) => "str" in item ? item.str : "").join(" ");
908
- pages.push(`[Page ${i}/${pageCount}]
909
- ${pageText}`);
910
- } finally {
911
- page.cleanup();
912
- }
913
- }
914
- } finally {
915
- doc.cleanup();
916
- }
917
- let text = pages.join("\n\n");
918
- if (pageCount > limitedPageCount) {
919
- text += `
920
-
921
- [PDF has ${pageCount} pages, showing first ${limitedPageCount}. Use a shell command to process more.]`;
922
- }
923
- return { text, pageCount, title, author };
924
- }
925
-
926
- // src/server/tools/read.ts
927
850
  async function detectImageType(buffer, filePath) {
928
851
  const fileType = await fileTypeFromBuffer(buffer);
929
852
  const imageMimeTypes = ["image/png", "image/jpeg", "image/gif", "image/webp", "image/bmp", "image/svg+xml"];
@@ -2954,7 +2877,7 @@ ${CONTINUE_PROMPT}` : CONTINUE_PROMPT;
2954
2877
  sessionManager.setCurrentContextSize(sessionId, result.usage.promptTokens);
2955
2878
  if (!compacting) {
2956
2879
  const contextState2 = sessionManager.getContextState(sessionId);
2957
- const { shouldCompact, appendCompactionPrompt } = await import("./compactor-74CZVUWI.js");
2880
+ const { shouldCompact, appendCompactionPrompt } = await import("./compactor-IPMMFFHM.js");
2958
2881
  if (shouldCompact(contextState2.currentTokens, contextState2.maxTokens, runtimeConfig.context.compactionThreshold)) {
2959
2882
  appendCompactionPrompt(sessionId, append);
2960
2883
  compacting = true;
@@ -3859,7 +3782,7 @@ var callSubAgentTool = {
3859
3782
  };
3860
3783
  }
3861
3784
  try {
3862
- const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-INWP6FGV.js");
3785
+ const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-CALGWIV2.js");
3863
3786
  const toolRegistry = getToolRegistryForAgent2(agentDef);
3864
3787
  const turnMetrics = new TurnMetrics();
3865
3788
  const result = await executeSubAgent({
@@ -4781,18 +4704,18 @@ var mcpConfigTool = createTool(
4781
4704
  type: "function",
4782
4705
  function: {
4783
4706
  name: "mcp_config",
4784
- description: "Configure MCP servers (Model Context Protocol). Actions: list (show all servers and tools), add (add a server), remove (delete a server), toggle-tool (enable/disable a tool). Use this when the user asks to add, remove, or configure MCP servers or tools.",
4707
+ description: "Configure MCP servers (Model Context Protocol). Actions: list (show all servers and tools), add (add a server), update (modify an existing server \u2014 all fields are optional and merged with the current config, transport-incompatible fields are cleared on transport change), remove (delete a server), toggle-tool (enable/disable a tool). Use this when the user asks to add, remove, update, or configure MCP servers or tools.",
4785
4708
  parameters: {
4786
4709
  type: "object",
4787
4710
  properties: {
4788
4711
  action: {
4789
4712
  type: "string",
4790
- enum: ["list", "add", "remove", "toggle-tool"],
4791
- description: "Action: list (show servers), add (add new server), remove (delete a server), toggle-tool (enable/disable a tool)"
4713
+ enum: ["list", "add", "update", "remove", "toggle-tool"],
4714
+ description: "Action: list (show servers), add (add new server), update (modify existing server), remove (delete a server), toggle-tool (enable/disable a tool)"
4792
4715
  },
4793
4716
  name: {
4794
4717
  type: "string",
4795
- description: "Server name (required for: add, remove, toggle-tool)"
4718
+ description: "Server name (required for: add, update, remove, toggle-tool)"
4796
4719
  },
4797
4720
  transport: {
4798
4721
  type: "string",
@@ -4838,7 +4761,7 @@ var mcpConfigTool = createTool(
4838
4761
  async (args, context, helpers) => {
4839
4762
  const actionError = validateActionWithPermission(
4840
4763
  args.action,
4841
- ["list", "add", "remove", "toggle-tool"],
4764
+ ["list", "add", "update", "remove", "toggle-tool"],
4842
4765
  "mcp_config",
4843
4766
  context.permittedActions
4844
4767
  );
@@ -4858,7 +4781,7 @@ var mcpConfigTool = createTool(
4858
4781
  mcpNotifyChanged?.(sessionId);
4859
4782
  }
4860
4783
  async function rebuildTools() {
4861
- const { setMcpTools: setMcpTools2 } = await import("./tools-INWP6FGV.js");
4784
+ const { setMcpTools: setMcpTools2 } = await import("./tools-CALGWIV2.js");
4862
4785
  const mcpTools = createMcpTools(mcpManagerForTools);
4863
4786
  setMcpTools2(mcpTools);
4864
4787
  }
@@ -4914,6 +4837,38 @@ var mcpConfigTool = createTool(
4914
4837
  const toolCount = server?.tools.length ?? 0;
4915
4838
  return helpers.success(`Added MCP server "${args.name}" (${toolCount} tools discovered). ${APPLY_PROMPT_MESSAGE}`);
4916
4839
  }
4840
+ if (args.action === "update") {
4841
+ if (!args.name) return helpers.error("Missing required field: name");
4842
+ const existing = mcpManagerForTools.getServer(args.name);
4843
+ if (!existing) return helpers.error(`MCP server "${args.name}" not found`);
4844
+ const globalConfig = await loadGlobalConfig(mcpConfigMode, mcpConfigPath);
4845
+ const mcpServers = { ...globalConfig.mcpServers ?? {} };
4846
+ const patch = {
4847
+ ...args.transport !== void 0 ? { transport: args.transport } : {},
4848
+ ...args.command !== void 0 ? { command: args.command } : {},
4849
+ ...args.args !== void 0 ? { args: args.args } : {},
4850
+ ...args.env !== void 0 ? { env: args.env } : {},
4851
+ ...args.url !== void 0 ? { url: args.url } : {},
4852
+ ...args.headers !== void 0 ? { headers: args.headers } : {}
4853
+ };
4854
+ const { error: updateError } = await applyMcpServerUpdate({
4855
+ name: args.name,
4856
+ patch,
4857
+ existing,
4858
+ persistedCfg: mcpServers[args.name],
4859
+ mcpManager: mcpManagerForTools,
4860
+ save: async (cfg) => {
4861
+ mcpServers[args.name] = cfg;
4862
+ await saveGlobalConfig(mcpConfigMode, { ...globalConfig, mcpServers }, mcpConfigPath);
4863
+ }
4864
+ });
4865
+ if (updateError) return helpers.error(updateError);
4866
+ await rebuildTools();
4867
+ notifyContextChanged(context.sessionId);
4868
+ const server = mcpManagerForTools.getServer(args.name);
4869
+ const toolCount = server?.tools.length ?? 0;
4870
+ return helpers.success(`Updated MCP server "${args.name}" (${toolCount} tools discovered). ${APPLY_PROMPT_MESSAGE}`);
4871
+ }
4917
4872
  if (args.action === "remove") {
4918
4873
  if (!args.name) return helpers.error("Missing required field: name");
4919
4874
  await persistAndRebuild((mcpServers) => {
@@ -5521,4 +5476,4 @@ export {
5521
5476
  getToolRegistryForAgent,
5522
5477
  createToolRegistry
5523
5478
  };
5524
- //# sourceMappingURL=chunk-YU6DZAVA.js.map
5479
+ //# sourceMappingURL=chunk-PVWAE43V.js.map
@@ -12,7 +12,7 @@ import {
12
12
  } from "./chunk-YHEQTVFV.js";
13
13
  import {
14
14
  buildModelParams
15
- } from "./chunk-BL5LOLVA.js";
15
+ } from "./chunk-JHGKXQBO.js";
16
16
  import {
17
17
  logger
18
18
  } from "./chunk-K44MW7JJ.js";
@@ -678,4 +678,4 @@ export {
678
678
  createChatDoneEvent,
679
679
  consumeStreamGenerator
680
680
  };
681
- //# sourceMappingURL=chunk-TJO4QFDQ.js.map
681
+ //# sourceMappingURL=chunk-QFSDJIUS.js.map
@@ -0,0 +1,54 @@
1
+ // src/server/mcp/update-server.ts
2
+ function buildUpdatedServerConfig(patch, existing, persistedCfg) {
3
+ const existingTransport = existing.config.transport ?? "stdio";
4
+ const resolvedTransport = patch.transport ?? existingTransport;
5
+ const transportChanged = resolvedTransport !== existingTransport;
6
+ const mergedCommand = patch.command !== void 0 ? patch.command : transportChanged ? void 0 : existing.config.command;
7
+ const mergedArgs = patch.args !== void 0 ? patch.args : transportChanged ? void 0 : existing.config.args;
8
+ const mergedEnv = patch.env !== void 0 ? patch.env : transportChanged ? void 0 : existing.config.env;
9
+ const mergedUrl = patch.url !== void 0 ? patch.url : transportChanged ? void 0 : existing.config.url;
10
+ const mergedHeaders = patch.headers !== void 0 ? patch.headers : transportChanged ? void 0 : existing.config.headers;
11
+ if (resolvedTransport === "http" && !mergedUrl) {
12
+ return { serverCfg: {}, error: "url is required for http transport" };
13
+ }
14
+ if (resolvedTransport !== "http" && !mergedCommand) {
15
+ return { serverCfg: {}, error: "command is required for stdio transport" };
16
+ }
17
+ const serverCfg = {
18
+ transport: resolvedTransport,
19
+ ...mergedCommand ? { command: mergedCommand } : {},
20
+ ...mergedArgs && mergedArgs.length > 0 ? { args: mergedArgs } : {},
21
+ ...mergedEnv && Object.keys(mergedEnv).length > 0 ? { env: mergedEnv } : {},
22
+ ...mergedUrl ? { url: mergedUrl } : {},
23
+ ...mergedHeaders && Object.keys(mergedHeaders).length > 0 ? { headers: mergedHeaders } : {},
24
+ ...persistedCfg?.disabledTools && persistedCfg.disabledTools.length > 0 ? { disabledTools: persistedCfg.disabledTools } : {},
25
+ ...persistedCfg?.cachedTools && persistedCfg.cachedTools.length > 0 ? { cachedTools: persistedCfg.cachedTools } : {}
26
+ };
27
+ return { serverCfg };
28
+ }
29
+ async function applyMcpServerUpdate(options) {
30
+ const { name, patch, existing, persistedCfg, mcpManager, save } = options;
31
+ const { serverCfg, error } = buildUpdatedServerConfig(patch, existing, persistedCfg);
32
+ if (error) return { serverCfg: {}, error };
33
+ mcpManager.removeServer(name);
34
+ try {
35
+ await mcpManager.addServer(name, serverCfg);
36
+ } catch (addError) {
37
+ await mcpManager.addServer(name, existing.config);
38
+ throw addError;
39
+ }
40
+ try {
41
+ await save(serverCfg);
42
+ } catch (saveError) {
43
+ mcpManager.removeServer(name);
44
+ await mcpManager.addServer(name, existing.config);
45
+ throw saveError;
46
+ }
47
+ return { serverCfg };
48
+ }
49
+
50
+ export {
51
+ buildUpdatedServerConfig,
52
+ applyMcpServerUpdate
53
+ };
54
+ //# sourceMappingURL=chunk-UN26GIQG.js.map