openfox 2.0.14 → 2.0.15

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 (30) hide show
  1. package/dist/{chat-handler-ITXCBFJK.js → chat-handler-RYOG3WJP.js} +8 -6
  2. package/dist/{chunk-4U45A7B3.js → chunk-2GX5EIIU.js} +111 -45
  3. package/dist/{chunk-LNEBVOH6.js → chunk-3IKRNKPI.js} +6 -6
  4. package/dist/{chunk-4W2Z4B5U.js → chunk-EKTGRBDC.js} +36 -41
  5. package/dist/{chunk-3QB2RMX2.js → chunk-F4PMNP7S.js} +2 -2
  6. package/dist/{chunk-TIKQWNYK.js → chunk-J7KOV4ST.js} +2 -2
  7. package/dist/{chunk-4ZTQO5JP.js → chunk-KPKSN362.js} +262 -6
  8. package/dist/{chunk-PP6VQXQW.js → chunk-SNQT7LNU.js} +2 -1
  9. package/dist/{chunk-5BDVM6YI.js → chunk-YD6NDTKF.js} +1 -1
  10. package/dist/{chunk-7GJ6XYAF.js → chunk-Z64KW2HD.js} +20 -16
  11. package/dist/cli/dev.js +1 -1
  12. package/dist/cli/index.js +1 -1
  13. package/dist/{config-YFHA5MWV.js → config-Z66BQTNX.js} +2 -2
  14. package/dist/{orchestrator-VP74KOXI.js → orchestrator-KRCVDTZ6.js} +7 -5
  15. package/dist/package.json +1 -2
  16. package/dist/{processor-CCXZYLX6.js → processor-JHR3Z42W.js} +8 -6
  17. package/dist/{protocol-BE5dRtYw.d.ts → protocol-BC1QSQ-Y.d.ts} +7 -1
  18. package/dist/{protocol-YYWMFR35.js → protocol-BKNLAEPJ.js} +3 -3
  19. package/dist/{provider-QUJQLVOM.js → provider-YBTRC77Y.js} +3 -3
  20. package/dist/{serve-GA2UIHHB.js → serve-AV74ODQ6.js} +9 -9
  21. package/dist/server/index.d.ts +19 -1
  22. package/dist/server/index.js +8 -7
  23. package/dist/{server-EA6W7YIC.js → server-P7E2IPVL.js} +10 -8
  24. package/dist/shared/index.d.ts +2 -2
  25. package/dist/shared/index.js +1 -1
  26. package/dist/{tools-DUC54GEH.js → tools-WEE4XDTL.js} +6 -4
  27. package/dist/web/assets/{index-D0qVcBva.js → index-BMz5-yAf.js} +31 -31
  28. package/dist/web/index.html +1 -1
  29. package/dist/web/sw.js +1 -1
  30. package/package.json +1 -2
@@ -2,29 +2,29 @@ import {
2
2
  appendCompactionPrompt
3
3
  } from "./chunk-FWJ6YXGA.js";
4
4
  import {
5
- computeDynamicContextHash,
6
5
  injectWorkflowKickoffIfNeeded,
7
6
  runAgentTurn,
8
7
  runChatTurn
9
- } from "./chunk-7GJ6XYAF.js";
8
+ } from "./chunk-Z64KW2HD.js";
10
9
  import {
10
+ applyDynamicContext,
11
11
  checkAborted,
12
+ computeDynamicContextHash,
12
13
  deleteItemFromDir,
13
14
  devServerManager,
14
15
  executeSubAgent,
15
16
  findAgentById,
16
17
  getAllInstructions,
17
18
  getEnabledSkillMetadata,
18
- getSubAgents,
19
+ getToolFingerprint,
19
20
  getToolRegistryForAgent,
20
21
  jsonSerializer,
21
22
  loadAllAgentsDefault,
22
23
  saveItemToDir,
23
24
  spawnShellProcess
24
- } from "./chunk-4ZTQO5JP.js";
25
+ } from "./chunk-KPKSN362.js";
25
26
  import {
26
27
  TurnMetrics,
27
- buildTopLevelSystemPrompt,
28
28
  createMessageStartEvent
29
29
  } from "./chunk-L7TDUIQY.js";
30
30
  import {
@@ -49,7 +49,7 @@ import {
49
49
  parseClientMessage,
50
50
  serializeServerMessage,
51
51
  storedEventToServerMessage
52
- } from "./chunk-3QB2RMX2.js";
52
+ } from "./chunk-F4PMNP7S.js";
53
53
  import {
54
54
  provideAnswer
55
55
  } from "./chunk-EU3WWTFH.js";
@@ -58,7 +58,7 @@ import {
58
58
  } from "./chunk-VUQCQXXJ.js";
59
59
  import {
60
60
  createServerMessage
61
- } from "./chunk-5BDVM6YI.js";
61
+ } from "./chunk-YD6NDTKF.js";
62
62
  import {
63
63
  getGlobalConfigDir
64
64
  } from "./chunk-CQGTEGKL.js";
@@ -1173,9 +1173,12 @@ async function isValidToken(token) {
1173
1173
  }
1174
1174
 
1175
1175
  // src/server/ws/server.ts
1176
- var _mcpManager;
1177
- function setMcpManagerForWs(mgr) {
1178
- _mcpManager = mgr;
1176
+ var resolveMcpReady = null;
1177
+ var mcpReadyPromise = new Promise((resolve) => {
1178
+ resolveMcpReady = resolve;
1179
+ });
1180
+ function signalMcpReady() {
1181
+ resolveMcpReady?.();
1179
1182
  }
1180
1183
  function moduleGitBranch(cwd) {
1181
1184
  return new Promise((resolve) => {
@@ -1687,7 +1690,8 @@ function createWebSocketServer(httpServer, config, getLLMClient, getActiveProvid
1687
1690
  return false;
1688
1691
  },
1689
1692
  close: (cb) => wss.close(cb),
1690
- broadcastForSession
1693
+ broadcastForSession,
1694
+ broadcastAll
1691
1695
  };
1692
1696
  }
1693
1697
  async function handleClientMessage(ws, client, message, _getLLMClient, _getActiveProvider, sessionManager, _broadcastForSession, _providerManager, _getSessionLLMClient, _getSessionStatsIdentity, llmForSession, statsForSession, _startTurnWithCompletionChain, cleanupAfterTurn, enqueueSendFn) {
@@ -1766,18 +1770,21 @@ async function handleClientMessage(ws, client, message, _getLLMClient, _getActiv
1766
1770
  ;
1767
1771
  (async () => {
1768
1772
  try {
1773
+ await mcpReadyPromise;
1769
1774
  const { content: instructionContent } = await getAllInstructions(session.workdir, session.projectId);
1770
1775
  const runtimeConfig = getRuntimeConfig();
1771
1776
  const configDir = getGlobalConfigDir(runtimeConfig.mode ?? "production");
1772
1777
  const skills = await getEnabledSkillMetadata(configDir, runtimeConfig.workdir);
1773
- const dynamicInputs = JSON.stringify({
1774
- instructions: instructionContent,
1775
- skills: skills.map((s) => s.id).sort()
1776
- });
1777
- const currentHash = createHash2("sha256").update(dynamicInputs).digest("hex");
1778
+ const { createToolRegistry } = await import("./tools-WEE4XDTL.js");
1779
+ const allTools = createToolRegistry().definitions;
1780
+ const toolFingerprint = getToolFingerprint(allTools);
1781
+ const currentHash = computeDynamicContextHash(instructionContent, skills, toolFingerprint);
1778
1782
  if (currentHash !== cachedHash) {
1779
1783
  sessionManager.setDynamicContextChanged(session.id, true);
1780
1784
  sendContextState();
1785
+ } else if (sessionManager.getDynamicContextChanged(session.id)) {
1786
+ sessionManager.setDynamicContextChanged(session.id, false);
1787
+ sendContextState();
1781
1788
  }
1782
1789
  } catch {
1783
1790
  }
@@ -1836,18 +1843,24 @@ async function handleClientMessage(ws, client, message, _getLLMClient, _getActiv
1836
1843
  const session = sessionManager.requireSession(sessionId);
1837
1844
  (async () => {
1838
1845
  try {
1846
+ await mcpReadyPromise;
1839
1847
  const { content: instructionContent } = await getAllInstructions(session.workdir, session.projectId);
1840
1848
  const runtimeConfig = getRuntimeConfig();
1841
1849
  const configDir = getGlobalConfigDir(runtimeConfig.mode ?? "production");
1842
1850
  const skills = await getEnabledSkillMetadata(configDir, runtimeConfig.workdir);
1843
- const mcpTools = _mcpManager ? _mcpManager.getToolDefinitions() : [];
1844
- const toolFingerprint = mcpTools.map(
1845
- (t) => `${t.function.name}:${JSON.stringify(t.function.parameters)}`
1846
- ).sort().join("|");
1851
+ const { createToolRegistry } = await import("./tools-WEE4XDTL.js");
1852
+ const allTools = createToolRegistry().definitions;
1853
+ const toolFingerprint = getToolFingerprint(allTools);
1847
1854
  const currentHash = computeDynamicContextHash(instructionContent, skills, toolFingerprint);
1848
1855
  const cachedHash = sessionManager.getCachedPrompt(sessionId)?.hash;
1849
1856
  if (cachedHash) {
1850
1857
  if (currentHash !== cachedHash) {
1858
+ logger.debug("checkDynamic: hash mismatch", {
1859
+ sessionId,
1860
+ cachedHash,
1861
+ currentHash,
1862
+ toolCount: allTools.length
1863
+ });
1851
1864
  if (!sessionManager.getDynamicContextChanged(sessionId)) {
1852
1865
  sessionManager.setDynamicContextChanged(sessionId, true);
1853
1866
  const newContextState = sessionManager.getContextState(sessionId);
@@ -1881,25 +1894,7 @@ async function handleClientMessage(ws, client, message, _getLLMClient, _getActiv
1881
1894
  ;
1882
1895
  (async () => {
1883
1896
  try {
1884
- const { content: instructionContent } = await getAllInstructions(session.workdir, session.projectId);
1885
- const runtimeConfig = getRuntimeConfig();
1886
- const configDir = getGlobalConfigDir(runtimeConfig.mode ?? "production");
1887
- const skills = await getEnabledSkillMetadata(configDir, runtimeConfig.workdir);
1888
- const mcpTools = _mcpManager ? _mcpManager.getToolDefinitions() : [];
1889
- const toolFingerprint = mcpTools.map(
1890
- (t) => `${t.function.name}:${JSON.stringify(t.function.parameters)}`
1891
- ).sort().join("|");
1892
- const dynamicHash = computeDynamicContextHash(instructionContent, skills, toolFingerprint);
1893
- const allAgents = await loadAllAgentsDefault();
1894
- const subAgentDefs = getSubAgents(allAgents);
1895
- const systemPrompt = buildTopLevelSystemPrompt(
1896
- session.workdir,
1897
- instructionContent || void 0,
1898
- skills,
1899
- subAgentDefs
1900
- );
1901
- sessionManager.setCachedPrompt(sessionId, systemPrompt, mcpTools, dynamicHash);
1902
- sessionManager.setDynamicContextChanged(sessionId, false);
1897
+ await applyDynamicContext(sessionManager, sessionId);
1903
1898
  const newContextState = sessionManager.getContextState(sessionId);
1904
1899
  sendForSession(sessionId, createContextStateMessage(newContextState));
1905
1900
  send({ type: "ack", payload: {}, id: message.id });
@@ -2071,7 +2066,7 @@ export {
2071
2066
  verifyPassword,
2072
2067
  tokenFromPassword,
2073
2068
  isValidToken,
2074
- setMcpManagerForWs,
2069
+ signalMcpReady,
2075
2070
  createWebSocketServer
2076
2071
  };
2077
- //# sourceMappingURL=chunk-4W2Z4B5U.js.map
2072
+ //# sourceMappingURL=chunk-EKTGRBDC.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createServerMessage,
3
3
  isClientMessage
4
- } from "./chunk-5BDVM6YI.js";
4
+ } from "./chunk-YD6NDTKF.js";
5
5
 
6
6
  // src/server/ws/protocol.ts
7
7
  function enrichMessagesWithToolResults(messages) {
@@ -339,4 +339,4 @@ export {
339
339
  createQueueStateMessage,
340
340
  storedEventToServerMessage
341
341
  };
342
- //# sourceMappingURL=chunk-3QB2RMX2.js.map
342
+ //# sourceMappingURL=chunk-F4PMNP7S.js.map
@@ -9,7 +9,7 @@ import {
9
9
  import {
10
10
  createContextStateMessage,
11
11
  createSessionStateMessage
12
- } from "./chunk-3QB2RMX2.js";
12
+ } from "./chunk-F4PMNP7S.js";
13
13
  import {
14
14
  getPendingQuestionsForSession
15
15
  } from "./chunk-EU3WWTFH.js";
@@ -154,4 +154,4 @@ export {
154
154
  needsNameGenerationCheck,
155
155
  applyGeneratedSessionName
156
156
  };
157
- //# sourceMappingURL=chunk-TIKQWNYK.js.map
157
+ //# sourceMappingURL=chunk-J7KOV4ST.js.map
@@ -31,6 +31,9 @@ import {
31
31
  getMaxPerSession,
32
32
  getSessionProcessCount
33
33
  } from "./chunk-VRGRAQDG.js";
34
+ import {
35
+ createMcpTools
36
+ } from "./chunk-NWO6GRYE.js";
34
37
  import {
35
38
  getCurrentContextWindowId,
36
39
  getCurrentWindowMessageOptions,
@@ -52,7 +55,7 @@ import {
52
55
  createChatMessageUpdatedMessage,
53
56
  createChatPathConfirmationMessage,
54
57
  createQueueStateMessage
55
- } from "./chunk-3QB2RMX2.js";
58
+ } from "./chunk-F4PMNP7S.js";
56
59
  import {
57
60
  AskUserInterrupt,
58
61
  askUserTool
@@ -62,6 +65,10 @@ import {
62
65
  deleteSetting,
63
66
  getSetting
64
67
  } from "./chunk-RFNEDBVO.js";
68
+ import {
69
+ loadGlobalConfig,
70
+ saveGlobalConfig
71
+ } from "./chunk-SNQT7LNU.js";
65
72
  import {
66
73
  getGlobalConfigDir
67
74
  } from "./chunk-CQGTEGKL.js";
@@ -806,6 +813,14 @@ function formatDiagnosticsForLLM(diagnostics) {
806
813
  }
807
814
  return output;
808
815
  }
816
+ function appendLspInstallHint(output, lspManager, path) {
817
+ if (!lspManager) return output;
818
+ const hint = lspManager.getInstallHint(path);
819
+ if (!hint) return output;
820
+ return output + `
821
+
822
+ \u26A0\uFE0F Language server not installed. To enable diagnostics: \`${hint}\``;
823
+ }
809
824
 
810
825
  // src/server/tools/write.ts
811
826
  var writeFileTool = createTool(
@@ -849,6 +864,7 @@ var writeFileTool = createTool(
849
864
  if (context.lspManager) {
850
865
  diagnostics = await context.lspManager.notifyFileChange(fullPath, args.content);
851
866
  output += formatDiagnosticsForLLM(diagnostics);
867
+ output = appendLspInstallHint(output, context.lspManager, fullPath);
852
868
  }
853
869
  const newHash = await computeFileHash(fullPath);
854
870
  if (newHash) {
@@ -1102,6 +1118,7 @@ Make sure whitespace and indentation match exactly.`
1102
1118
  if (context.lspManager) {
1103
1119
  diagnostics = await context.lspManager.notifyFileChange(fullPath, newContent);
1104
1120
  output += formatDiagnosticsForLLM(diagnostics);
1121
+ output = appendLspInstallHint(output, context.lspManager, fullPath);
1105
1122
  }
1106
1123
  const newHash = await computeFileHash(fullPath);
1107
1124
  if (newHash) {
@@ -2677,10 +2694,10 @@ async function describeImageFromDataUrl(dataUrl, visionModel, options) {
2677
2694
  import { createHash as createHash2 } from "crypto";
2678
2695
  async function loadVisionModelFromGlobalConfig() {
2679
2696
  try {
2680
- const { loadGlobalConfig, getVisionFallback } = await import("./config-YFHA5MWV.js");
2697
+ const { loadGlobalConfig: loadGlobalConfig2, getVisionFallback } = await import("./config-Z66BQTNX.js");
2681
2698
  const runtimeConfig = getRuntimeConfig();
2682
2699
  const mode = runtimeConfig.mode ?? "production";
2683
- const globalConfig = await loadGlobalConfig(mode);
2700
+ const globalConfig = await loadGlobalConfig2(mode);
2684
2701
  const fallback = getVisionFallback(globalConfig);
2685
2702
  if (fallback?.enabled && fallback.model) {
2686
2703
  return { baseUrl: fallback.url, model: fallback.model, timeout: fallback.timeout * 1e3 };
@@ -3132,7 +3149,7 @@ var callSubAgentTool = {
3132
3149
  };
3133
3150
  }
3134
3151
  try {
3135
- const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-DUC54GEH.js");
3152
+ const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-WEE4XDTL.js");
3136
3153
  const toolRegistry = getToolRegistryForAgent2(agentDef);
3137
3154
  const turnMetrics = new TurnMetrics();
3138
3155
  const result = await executeSubAgent({
@@ -3919,6 +3936,238 @@ These processes run independently of agent turns and persist across session comp
3919
3936
  }
3920
3937
  );
3921
3938
 
3939
+ // src/server/chat/dynamic-context.ts
3940
+ import { createHash as createHash3 } from "crypto";
3941
+ function computeDynamicContextHash(instructionContent, skills, toolFingerprint) {
3942
+ const dynamicInputs = JSON.stringify({
3943
+ instructions: instructionContent,
3944
+ skills: skills.map((s) => s.id).sort(),
3945
+ ...toolFingerprint ? { tools: toolFingerprint } : {}
3946
+ });
3947
+ return createHash3("sha256").update(dynamicInputs).digest("hex");
3948
+ }
3949
+ function getToolFingerprint(tools) {
3950
+ return tools.map((t) => `${t.function.name}:${JSON.stringify(t.function.parameters)}`).sort().join("|");
3951
+ }
3952
+ async function computeContextHash(sessionManager, sessionId) {
3953
+ const session = sessionManager.requireSession(sessionId);
3954
+ const { content: instructionContent } = await getAllInstructions(session.workdir, session.projectId);
3955
+ const runtimeConfig = getRuntimeConfig();
3956
+ const configDir = getGlobalConfigDir(runtimeConfig.mode ?? "production");
3957
+ const skills = await getEnabledSkillMetadata(configDir, runtimeConfig.workdir);
3958
+ const { createToolRegistry: createToolRegistry2 } = await import("./tools-WEE4XDTL.js");
3959
+ const allTools = createToolRegistry2().definitions;
3960
+ const toolFingerprint = getToolFingerprint(allTools);
3961
+ const hash = computeDynamicContextHash(instructionContent, skills, toolFingerprint);
3962
+ return { hash, instructionContent, skills, allTools };
3963
+ }
3964
+ async function applyDynamicContext(sessionManager, sessionId) {
3965
+ const { hash, instructionContent, skills, allTools } = await computeContextHash(sessionManager, sessionId);
3966
+ const allAgents = await loadAllAgentsDefault();
3967
+ const subAgentDefs = getSubAgents(allAgents);
3968
+ const systemPrompt = buildTopLevelSystemPrompt(
3969
+ sessionManager.requireSession(sessionId).workdir,
3970
+ instructionContent || void 0,
3971
+ skills,
3972
+ subAgentDefs
3973
+ );
3974
+ sessionManager.setCachedPrompt(sessionId, systemPrompt, allTools, hash);
3975
+ sessionManager.setDynamicContextChanged(sessionId, false);
3976
+ sessionManager.clearDebugDump(sessionId);
3977
+ logger.debug("applyDynamicContext done", { sessionId, hash, toolCount: allTools.length });
3978
+ }
3979
+
3980
+ // src/server/tools/mcp-config.ts
3981
+ var mcpManagerForTools = null;
3982
+ var mcpConfigMode = "production";
3983
+ var mcpNotifyChanged = null;
3984
+ function setMcpManagerForTools(manager) {
3985
+ mcpManagerForTools = manager;
3986
+ }
3987
+ function setMcpConfigMode(mode) {
3988
+ mcpConfigMode = mode;
3989
+ }
3990
+ function setNotifyMcpServersChanged(fn) {
3991
+ mcpNotifyChanged = fn;
3992
+ }
3993
+ var mcpConfigTool = createTool(
3994
+ "mcp_config",
3995
+ {
3996
+ type: "function",
3997
+ function: {
3998
+ name: "mcp_config",
3999
+ 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.",
4000
+ parameters: {
4001
+ type: "object",
4002
+ properties: {
4003
+ action: {
4004
+ type: "string",
4005
+ enum: ["list", "add", "remove", "toggle-tool"],
4006
+ description: "Action: list (show servers), add (add new server), remove (delete a server), toggle-tool (enable/disable a tool)"
4007
+ },
4008
+ name: {
4009
+ type: "string",
4010
+ description: "Server name (required for: add, remove, toggle-tool)"
4011
+ },
4012
+ transport: {
4013
+ type: "string",
4014
+ enum: ["stdio", "http"],
4015
+ description: "Transport type (for add). Default: stdio"
4016
+ },
4017
+ command: {
4018
+ type: "string",
4019
+ description: 'Command for stdio transport (e.g. "npx")'
4020
+ },
4021
+ args: {
4022
+ type: "array",
4023
+ items: { type: "string" },
4024
+ description: "Command arguments for stdio transport"
4025
+ },
4026
+ env: {
4027
+ type: "object",
4028
+ additionalProperties: { type: "string" },
4029
+ description: "Environment variables for stdio transport"
4030
+ },
4031
+ url: {
4032
+ type: "string",
4033
+ description: 'Server URL for HTTP transport (e.g. "https://mcp.example.com/mcp")'
4034
+ },
4035
+ headers: {
4036
+ type: "object",
4037
+ additionalProperties: { type: "string" },
4038
+ description: 'HTTP headers for HTTP transport (e.g. {"Authorization": "Bearer xxx"})'
4039
+ },
4040
+ toolName: {
4041
+ type: "string",
4042
+ description: "Tool name to toggle (required for: toggle-tool)"
4043
+ },
4044
+ enabled: {
4045
+ type: "boolean",
4046
+ description: "Whether the tool should be enabled (required for: toggle-tool)"
4047
+ }
4048
+ },
4049
+ required: ["action"]
4050
+ }
4051
+ }
4052
+ },
4053
+ async (args, context, helpers) => {
4054
+ const actionError = validateActionWithPermission(
4055
+ args.action,
4056
+ ["list", "add", "remove", "toggle-tool"],
4057
+ "mcp_config",
4058
+ context.permittedActions
4059
+ );
4060
+ if (actionError) return actionError;
4061
+ if (!mcpManagerForTools) {
4062
+ return helpers.error("MCP manager not available");
4063
+ }
4064
+ async function persistAndRebuild(updater) {
4065
+ const globalConfig = await loadGlobalConfig(mcpConfigMode);
4066
+ const mcpServers = { ...globalConfig.mcpServers ?? {} };
4067
+ const updated = updater(mcpServers);
4068
+ await saveGlobalConfig(mcpConfigMode, { ...globalConfig, mcpServers: updated });
4069
+ }
4070
+ async function rebuildTools() {
4071
+ const { setMcpTools: setMcpTools2 } = await import("./tools-WEE4XDTL.js");
4072
+ const mcpTools = createMcpTools(mcpManagerForTools);
4073
+ setMcpTools2(mcpTools);
4074
+ }
4075
+ if (args.action === "list") {
4076
+ const servers = mcpManagerForTools.getAllServers();
4077
+ if (servers.length === 0) {
4078
+ return helpers.success("No MCP servers configured.");
4079
+ }
4080
+ const lines = [];
4081
+ for (const server of servers) {
4082
+ const connStr = server.status === "connected" ? "\u25CF" : server.status === "error" ? "\u2717" : "\u25CB";
4083
+ const cmdStr = server.config.command ? `${server.config.command} ${(server.config.args ?? []).join(" ")}` : server.config.url ?? "";
4084
+ lines.push(
4085
+ `${connStr} ${server.name} (${server.config.transport}) \u2014 ${server.status}${server.error ? `: ${server.error}` : ""}`
4086
+ );
4087
+ lines.push(` ${cmdStr}`);
4088
+ lines.push(` ${server.tools.length} tools, ~${server.estimatedTokens} tokens`);
4089
+ const enabledTools = server.tools.filter((t) => t.enabled);
4090
+ const disabledTools = server.tools.filter((t) => !t.enabled);
4091
+ if (enabledTools.length > 0) {
4092
+ lines.push(` Enabled: ${enabledTools.map((t) => t.name).join(", ")}`);
4093
+ }
4094
+ if (disabledTools.length > 0) {
4095
+ lines.push(` Disabled: ${disabledTools.map((t) => t.name).join(", ")}`);
4096
+ }
4097
+ }
4098
+ return helpers.success(lines.join("\n"));
4099
+ }
4100
+ if (args.action === "add") {
4101
+ if (!args.name) return helpers.error("Missing required field: name");
4102
+ if (args.transport === "http") {
4103
+ if (!args.url) return helpers.error("url is required for http transport");
4104
+ } else if (!args.command) {
4105
+ return helpers.error("command is required for stdio transport");
4106
+ }
4107
+ const serverCfg = {
4108
+ transport: args.transport ?? "stdio",
4109
+ ...args.command ? { command: args.command } : {},
4110
+ ...args.args && args.args.length > 0 ? { args: args.args } : {},
4111
+ ...args.env && Object.keys(args.env).length > 0 ? { env: args.env } : {},
4112
+ ...args.url ? { url: args.url } : {},
4113
+ ...args.headers && Object.keys(args.headers).length > 0 ? { headers: args.headers } : {}
4114
+ };
4115
+ await persistAndRebuild((mcpServers) => {
4116
+ mcpServers[args.name] = serverCfg;
4117
+ return mcpServers;
4118
+ });
4119
+ await mcpManagerForTools.addServer(args.name, serverCfg);
4120
+ await rebuildTools();
4121
+ await applyDynamicContext(context.sessionManager, context.sessionId);
4122
+ mcpNotifyChanged?.(context.sessionId);
4123
+ const server = mcpManagerForTools.getServer(args.name);
4124
+ const toolCount = server?.tools.length ?? 0;
4125
+ return helpers.success(`Added MCP server "${args.name}" (${toolCount} tools discovered).`);
4126
+ }
4127
+ if (args.action === "remove") {
4128
+ if (!args.name) return helpers.error("Missing required field: name");
4129
+ await persistAndRebuild((mcpServers) => {
4130
+ delete mcpServers[args.name];
4131
+ return mcpServers;
4132
+ });
4133
+ mcpManagerForTools.removeServer(args.name);
4134
+ await rebuildTools();
4135
+ await applyDynamicContext(context.sessionManager, context.sessionId);
4136
+ mcpNotifyChanged?.(context.sessionId);
4137
+ return helpers.success(`Removed MCP server "${args.name}".`);
4138
+ }
4139
+ if (args.action === "toggle-tool") {
4140
+ if (!args.name) return helpers.error("Missing required field: name");
4141
+ if (!args.toolName) return helpers.error("Missing required field: toolName");
4142
+ if (args.enabled === void 0) return helpers.error("Missing required field: enabled");
4143
+ const server = mcpManagerForTools.getServer(args.name);
4144
+ const currentDisabled = (server?.tools ?? []).filter((t) => !t.enabled).map((t) => t.name);
4145
+ const afterDisabled = args.enabled ? currentDisabled.filter((n) => n !== args.toolName) : [...currentDisabled, args.toolName];
4146
+ await persistAndRebuild((mcpServers) => {
4147
+ const cfg = mcpServers[args.name];
4148
+ if (cfg) {
4149
+ const updated = { ...cfg };
4150
+ if (afterDisabled.length > 0) {
4151
+ updated.disabledTools = afterDisabled;
4152
+ } else {
4153
+ delete updated.disabledTools;
4154
+ }
4155
+ mcpServers[args.name] = updated;
4156
+ }
4157
+ return mcpServers;
4158
+ });
4159
+ await mcpManagerForTools.setToolEnabled(args.name, args.toolName, args.enabled);
4160
+ await rebuildTools();
4161
+ await applyDynamicContext(context.sessionManager, context.sessionId);
4162
+ mcpNotifyChanged?.(context.sessionId);
4163
+ return helpers.success(
4164
+ `Tool "${args.toolName}" ${args.enabled ? "enabled" : "disabled"} on server "${args.name}".`
4165
+ );
4166
+ }
4167
+ return helpers.error("Unexpected error");
4168
+ }
4169
+ );
4170
+
3922
4171
  // src/server/tools/index.ts
3923
4172
  function parseToolPermissions(allowedTools) {
3924
4173
  const result = {};
@@ -4075,7 +4324,8 @@ function getAllToolsMap() {
4075
4324
  webFetchTool,
4076
4325
  devServerTool,
4077
4326
  stepDoneTool,
4078
- backgroundProcessTool
4327
+ backgroundProcessTool,
4328
+ mcpConfigTool
4079
4329
  ].map((t) => [t.name, t]);
4080
4330
  const mcpEntries = mcpToolsOverride.map((t) => [t.name, t]);
4081
4331
  return new Map([...builtInTools, ...mcpEntries]);
@@ -4183,6 +4433,12 @@ export {
4183
4433
  executeSubAgent,
4184
4434
  devServerManager,
4185
4435
  stepDoneTool,
4436
+ computeDynamicContextHash,
4437
+ getToolFingerprint,
4438
+ applyDynamicContext,
4439
+ setMcpManagerForTools,
4440
+ setMcpConfigMode,
4441
+ setNotifyMcpServersChanged,
4186
4442
  parseToolPermissions,
4187
4443
  getToolPermissions,
4188
4444
  validateToolAction,
@@ -4192,4 +4448,4 @@ export {
4192
4448
  getToolRegistryForAgent,
4193
4449
  createToolRegistry
4194
4450
  };
4195
- //# sourceMappingURL=chunk-4ZTQO5JP.js.map
4451
+ //# sourceMappingURL=chunk-KPKSN362.js.map
@@ -67,6 +67,7 @@ var mcpServerSchema = z.object({
67
67
  args: z.array(z.string()).optional(),
68
68
  env: z.record(z.string(), z.string()).optional(),
69
69
  url: z.string().optional(),
70
+ headers: z.record(z.string(), z.string()).optional(),
70
71
  disabledTools: z.array(z.string()).optional()
71
72
  });
72
73
  var defaultVisionFallback = { enabled: false, url: "http://localhost:11434", model: "qwen3.5:0.8b", timeout: 120 };
@@ -435,4 +436,4 @@ export {
435
436
  activateProvider,
436
437
  mergeConfigs
437
438
  };
438
- //# sourceMappingURL=chunk-PP6VQXQW.js.map
439
+ //# sourceMappingURL=chunk-SNQT7LNU.js.map
@@ -26,4 +26,4 @@ export {
26
26
  isClientMessage,
27
27
  isServerMessage
28
28
  };
29
- //# sourceMappingURL=chunk-5BDVM6YI.js.map
29
+ //# sourceMappingURL=chunk-YD6NDTKF.js.map
@@ -1,17 +1,20 @@
1
1
  import {
2
2
  PathAccessDeniedError,
3
3
  assembleAgentRequest,
4
+ computeDynamicContextHash,
4
5
  createAssemblyResult,
6
+ createToolRegistry,
5
7
  findAgentById,
6
8
  getAllInstructions,
7
9
  getConversationMessages,
8
10
  getEnabledSkillMetadata,
9
11
  getSubAgents,
12
+ getToolFingerprint,
10
13
  getToolRegistryForAgent,
11
14
  loadAllAgentsDefault,
12
15
  processEventsForConversation,
13
16
  runTopLevelAgentLoop
14
- } from "./chunk-4ZTQO5JP.js";
17
+ } from "./chunk-KPKSN362.js";
15
18
  import {
16
19
  TurnMetrics,
17
20
  WORKFLOW_KICKOFF_PROMPT,
@@ -36,17 +39,6 @@ import {
36
39
  logger
37
40
  } from "./chunk-K44MW7JJ.js";
38
41
 
39
- // src/server/chat/dynamic-context.ts
40
- import { createHash } from "crypto";
41
- function computeDynamicContextHash(instructionContent, skills, toolFingerprint) {
42
- const dynamicInputs = JSON.stringify({
43
- instructions: instructionContent,
44
- skills: skills.map((s) => s.id).sort(),
45
- ...toolFingerprint ? { tools: toolFingerprint } : {}
46
- });
47
- return createHash("sha256").update(dynamicInputs).digest("hex");
48
- }
49
-
50
42
  // src/server/chat/orchestrator.ts
51
43
  async function buildRetryPatterns() {
52
44
  const { getSetting, SETTINGS_KEYS } = await import("./settings-6XX56F3F.js");
@@ -238,17 +230,30 @@ async function runAgentTurn(options, turnMetrics, agentId, append, callbacks) {
238
230
  onMessage: options.onMessage,
239
231
  assembleRequest: (input) => {
240
232
  const cached = options.sessionManager.getCachedPrompt(options.sessionId);
241
- const toolFingerprint = input.promptTools.map((t) => `${t.function.name}:${JSON.stringify(t.function.parameters)}`).sort().join("|");
233
+ const liveTools = createToolRegistry().definitions;
234
+ const toolFingerprint = getToolFingerprint(liveTools);
242
235
  if (cached) {
243
236
  const currentHash = computeDynamicContextHash(instructionContent ?? "", skills, toolFingerprint);
244
237
  if (cached.hash !== currentHash) {
238
+ logger.debug("assembleRequest: hash mismatch", {
239
+ sessionId: options.sessionId,
240
+ cachedHash: cached.hash,
241
+ currentHash,
242
+ cachedTools: cached.tools.map((t) => t.function.name),
243
+ liveTools: liveTools.map((t) => t.function.name)
244
+ });
245
245
  options.sessionManager.setDynamicContextChanged(options.sessionId, true);
246
+ options.sessionManager.setDebugDump(options.sessionId, {
247
+ cachedPrompt: cached.systemPrompt.slice(0, 5e3),
248
+ cachedTools: cached.tools.map((t) => t.function.name),
249
+ liveTools: liveTools.map((t) => t.function.name)
250
+ });
246
251
  }
247
252
  return createAssemblyResult({
248
253
  systemPrompt: cached.systemPrompt,
249
254
  messages: input.messages,
250
255
  injectedFiles: input.injectedFiles,
251
- requestTools: cached.tools.length > 0 ? cached.tools : input.promptTools,
256
+ requestTools: cached.tools.length > 0 ? cached.tools : liveTools,
252
257
  toolChoice: input.toolChoice
253
258
  });
254
259
  }
@@ -311,9 +316,8 @@ function buildSnapshot(sessionManager, sessionId, _lastStats) {
311
316
  }
312
317
 
313
318
  export {
314
- computeDynamicContextHash,
315
319
  runChatTurn,
316
320
  runAgentTurn,
317
321
  injectWorkflowKickoffIfNeeded
318
322
  };
319
- //# sourceMappingURL=chunk-7GJ6XYAF.js.map
323
+ //# sourceMappingURL=chunk-Z64KW2HD.js.map
package/dist/cli/dev.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runCli
4
- } from "../chunk-LNEBVOH6.js";
4
+ } from "../chunk-3IKRNKPI.js";
5
5
  import {
6
6
  logger
7
7
  } from "../chunk-K44MW7JJ.js";
package/dist/cli/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runCli
4
- } from "../chunk-LNEBVOH6.js";
4
+ } from "../chunk-3IKRNKPI.js";
5
5
  import {
6
6
  logger
7
7
  } from "../chunk-K44MW7JJ.js";