zidane 5.6.7 → 5.6.8
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.
- package/dist/{agent-D70rr6Uk.d.ts → agent-CZEvtmJk.d.ts} +45 -2
- package/dist/agent-CZEvtmJk.d.ts.map +1 -0
- package/dist/chat.d.ts +261 -5
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +3 -3
- package/dist/{index-BjwwNjQd.d.ts → index-BBH6XWFt.d.ts} +2 -2
- package/dist/{index-BjwwNjQd.d.ts.map → index-BBH6XWFt.d.ts.map} +1 -1
- package/dist/{index-8mn3PIaa.d.ts → index-Cf-131kQ.d.ts} +2 -2
- package/dist/index-Cf-131kQ.d.ts.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +7 -7
- package/dist/{login-Btpliwct.js → login-CwLWX6vP.js} +17 -37
- package/dist/login-CwLWX6vP.js.map +1 -0
- package/dist/{mcp-ngMS0S6N.js → mcp-Wzf0qxaj.js} +120 -26
- package/dist/mcp-Wzf0qxaj.js.map +1 -0
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +1 -1
- package/dist/{messages-B5k4DAXy.js → messages-BfmXLDT4.js} +56 -2
- package/dist/messages-BfmXLDT4.js.map +1 -0
- package/dist/{presets-BXmWG3kd.js → presets-DAA0NaK_.js} +2 -2
- package/dist/{presets-BXmWG3kd.js.map → presets-DAA0NaK_.js.map} +1 -1
- package/dist/presets.d.ts +2 -2
- package/dist/presets.js +1 -1
- package/dist/{providers-CaJE2ToS.js → providers-C_ahnRBS.js} +2 -2
- package/dist/{providers-CaJE2ToS.js.map → providers-C_ahnRBS.js.map} +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +2 -2
- package/dist/restate.d.ts +1 -1
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/{session-BoEW_wCR.js → session-PUzXZlG6.js} +2 -2
- package/dist/{session-BoEW_wCR.js.map → session-PUzXZlG6.js.map} +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/session.js +2 -2
- package/dist/skills.d.ts +2 -2
- package/dist/{tools-FerA0zSl.js → tools-B9aQpZVx.js} +6 -4
- package/dist/tools-B9aQpZVx.js.map +1 -0
- package/dist/tools.d.ts +2 -2
- package/dist/tools.js +1 -1
- package/dist/{transcript-anchors-C5Sp1Snh.d.ts → transcript-anchors-CoSZb1PE.d.ts} +42 -4
- package/dist/transcript-anchors-CoSZb1PE.d.ts.map +1 -0
- package/dist/tui.d.ts +47 -14
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +703 -148
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-D-OQYUgS.js → turn-operations-D2rHrTQv.js} +375 -14
- package/dist/turn-operations-D2rHrTQv.js.map +1 -0
- package/dist/types.d.ts +2 -2
- package/docs/CHAT.md +4 -1
- package/docs/SKILL.md +1 -0
- package/docs/TUI.md +1 -0
- package/package.json +1 -1
- package/dist/agent-D70rr6Uk.d.ts.map +0 -1
- package/dist/index-8mn3PIaa.d.ts.map +0 -1
- package/dist/login-Btpliwct.js.map +0 -1
- package/dist/mcp-ngMS0S6N.js.map +0 -1
- package/dist/messages-B5k4DAXy.js.map +0 -1
- package/dist/tools-FerA0zSl.js.map +0 -1
- package/dist/transcript-anchors-C5Sp1Snh.d.ts.map +0 -1
- package/dist/turn-operations-D-OQYUgS.js.map +0 -1
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { H as previewLine, R as fmtTokens, U as shortId, a as multiEdit, c as grep, d as resolveOldString, f as styleReplacementForVia, i as readFile$1, l as glob, n as createSpawnTool, o as listFiles, t as writeFile$1, u as edit, y as shell } from "./tools-
|
|
1
|
+
import { H as previewLine, R as fmtTokens, U as shortId, a as multiEdit, c as grep, d as resolveOldString, f as styleReplacementForVia, i as readFile$1, l as glob, n as createSpawnTool, o as listFiles, t as writeFile$1, u as edit, y as shell } from "./tools-B9aQpZVx.js";
|
|
2
2
|
import { c as errorMessage } from "./errors-DdZXnyXE.js";
|
|
3
3
|
import { r as toolResultToText } from "./types-oKPBdCmL.js";
|
|
4
|
-
import { r as normalizeMcpServers } from "./mcp-
|
|
4
|
+
import { r as normalizeMcpServers, t as connectMcpServers } from "./mcp-Wzf0qxaj.js";
|
|
5
5
|
import { a as discoverSkills } from "./interpolate-DM1UcKeQ.js";
|
|
6
6
|
import { n as formatTokenUsage } from "./stats-Lc3zL3RM.js";
|
|
7
|
-
import { n as definePreset, t as composePresets } from "./presets-
|
|
8
|
-
import { a as writeFileAtomic, i as anthropic, n as openai, r as cerebras, t as openrouter } from "./providers-
|
|
7
|
+
import { n as definePreset, t as composePresets } from "./presets-DAA0NaK_.js";
|
|
8
|
+
import { a as writeFileAtomic, i as anthropic, n as openai, r as cerebras, t as openrouter } from "./providers-C_ahnRBS.js";
|
|
9
9
|
import { createRequire } from "node:module";
|
|
10
10
|
import { dirname, isAbsolute, join, posix, relative, resolve, sep } from "node:path";
|
|
11
11
|
import { homedir, tmpdir } from "node:os";
|
|
@@ -7903,6 +7903,326 @@ function patchMcpCredential(store, name, patch) {
|
|
|
7903
7903
|
});
|
|
7904
7904
|
}
|
|
7905
7905
|
//#endregion
|
|
7906
|
+
//#region src/chat/mcp-rows.ts
|
|
7907
|
+
/**
|
|
7908
|
+
* Flatten a server catalog plus the per-server expanded set into the
|
|
7909
|
+
* visible-row list a renderer cycles through.
|
|
7910
|
+
*
|
|
7911
|
+
* - `catalog` — filtered / ordered server list (post-search,
|
|
7912
|
+
* post-allow-list).
|
|
7913
|
+
* - `expanded` — names of servers whose tool list is open.
|
|
7914
|
+
* Servers not in this set render as a single
|
|
7915
|
+
* server-header row.
|
|
7916
|
+
* - `toolsByServer` — per-server full tool catalog (from
|
|
7917
|
+
* `chat/mcp-tools-cache.ts`). Missing key →
|
|
7918
|
+
* `'tool-empty'` placeholder under the
|
|
7919
|
+
* expanded server.
|
|
7920
|
+
*/
|
|
7921
|
+
function buildVisibleMcpRows(catalog, expanded, toolsByServer) {
|
|
7922
|
+
const out = [];
|
|
7923
|
+
for (const entry of catalog) {
|
|
7924
|
+
out.push({
|
|
7925
|
+
kind: "server",
|
|
7926
|
+
entry
|
|
7927
|
+
});
|
|
7928
|
+
if (!expanded.has(entry.config.name)) continue;
|
|
7929
|
+
const tools = toolsByServer[entry.config.name] ?? [];
|
|
7930
|
+
if (tools.length === 0) {
|
|
7931
|
+
out.push({
|
|
7932
|
+
kind: "tool-empty",
|
|
7933
|
+
serverName: entry.config.name
|
|
7934
|
+
});
|
|
7935
|
+
continue;
|
|
7936
|
+
}
|
|
7937
|
+
for (const tool of tools) out.push({
|
|
7938
|
+
kind: "tool",
|
|
7939
|
+
serverName: entry.config.name,
|
|
7940
|
+
tool
|
|
7941
|
+
});
|
|
7942
|
+
}
|
|
7943
|
+
return out;
|
|
7944
|
+
}
|
|
7945
|
+
/**
|
|
7946
|
+
* Server name a row "belongs to" for catalog / toggle / auth lookups.
|
|
7947
|
+
* For a server row that's its own name; for tool / tool-empty rows
|
|
7948
|
+
* it's the parent server's name.
|
|
7949
|
+
*/
|
|
7950
|
+
function parentServerName(row) {
|
|
7951
|
+
return row.kind === "server" ? row.entry.config.name : row.serverName;
|
|
7952
|
+
}
|
|
7953
|
+
/**
|
|
7954
|
+
* Index in `rows` of the server header for the given parent name. `-1`
|
|
7955
|
+
* when not present. Used by collapse handlers to snap the cursor up
|
|
7956
|
+
* to the parent BEFORE shrinking the row list — otherwise the cursor
|
|
7957
|
+
* would land on whichever sibling row now occupies the same flat
|
|
7958
|
+
* index.
|
|
7959
|
+
*/
|
|
7960
|
+
function indexOfServerRow(rows, parentName) {
|
|
7961
|
+
return rows.findIndex((r) => r.kind === "server" && r.entry.config.name === parentName);
|
|
7962
|
+
}
|
|
7963
|
+
//#endregion
|
|
7964
|
+
//#region src/chat/mcp-tool-toggle.ts
|
|
7965
|
+
/**
|
|
7966
|
+
* Bind a single MCP server's per-tool toggle to
|
|
7967
|
+
* `Settings.disabledMcpTools[serverName]`.
|
|
7968
|
+
*
|
|
7969
|
+
* `catalog` is the FULL list of tools the server advertises (i.e. the
|
|
7970
|
+
* cached `listTools()` payload from `chat/mcp-tools-cache.ts`). The
|
|
7971
|
+
* hook needs it both to render `enabledSet` (every catalog tool not in
|
|
7972
|
+
* the persisted deny-list) and to garbage-collect stale deny-list
|
|
7973
|
+
* entries on every write.
|
|
7974
|
+
*/
|
|
7975
|
+
function useMcpToolToggleSet(opts) {
|
|
7976
|
+
const { settings, setSetting } = useSettings();
|
|
7977
|
+
const setDisabled = useCallback((next) => setSetting("disabledMcpTools", next), [setSetting]);
|
|
7978
|
+
const catalogNames = useMemo(() => opts.catalog.map((t) => t.name), [opts.catalog]);
|
|
7979
|
+
const persistedDenyAll = settings.disabledMcpTools;
|
|
7980
|
+
return useMemo(() => buildToolToggle({
|
|
7981
|
+
serverName: opts.serverName,
|
|
7982
|
+
catalogNames,
|
|
7983
|
+
persistedDenyAll,
|
|
7984
|
+
setDisabledMcpTools: setDisabled
|
|
7985
|
+
}), [
|
|
7986
|
+
opts.serverName,
|
|
7987
|
+
catalogNames,
|
|
7988
|
+
persistedDenyAll,
|
|
7989
|
+
setDisabled
|
|
7990
|
+
]);
|
|
7991
|
+
}
|
|
7992
|
+
/**
|
|
7993
|
+
* Bind every server in `catalogByServer` to its own per-tool toggle in
|
|
7994
|
+
* a single hook call. Returns a `serverName → McpToolToggleSet` map.
|
|
7995
|
+
*
|
|
7996
|
+
* Use this when a host needs handlers for multiple servers at once
|
|
7997
|
+
* (the TUI's MCP settings panel keyboard dispatcher is the canonical
|
|
7998
|
+
* example) — calling {@link useMcpToolToggleSet} in a `for` / `.map`
|
|
7999
|
+
* over a dynamic catalog would change the hook-call order whenever a
|
|
8000
|
+
* server is added or removed, violating React's rules-of-hooks. This
|
|
8001
|
+
* hook calls `useMemo` exactly once regardless of server count.
|
|
8002
|
+
*
|
|
8003
|
+
* Servers absent from `catalogByServer` get no entry in the result.
|
|
8004
|
+
* The persisted deny-list still keeps their entries on disk — they
|
|
8005
|
+
* just stay invisible to this consumer until the catalog re-includes
|
|
8006
|
+
* them.
|
|
8007
|
+
*/
|
|
8008
|
+
function useMcpToolToggleMap(opts) {
|
|
8009
|
+
const { settings, setSetting } = useSettings();
|
|
8010
|
+
const setDisabled = useCallback((next) => setSetting("disabledMcpTools", next), [setSetting]);
|
|
8011
|
+
const persistedDenyAll = settings.disabledMcpTools;
|
|
8012
|
+
return useMemo(() => {
|
|
8013
|
+
const out = {};
|
|
8014
|
+
for (const [serverName, catalog] of Object.entries(opts.catalogByServer)) out[serverName] = buildToolToggle({
|
|
8015
|
+
serverName,
|
|
8016
|
+
catalogNames: catalog.map((t) => t.name),
|
|
8017
|
+
persistedDenyAll,
|
|
8018
|
+
setDisabledMcpTools: setDisabled
|
|
8019
|
+
});
|
|
8020
|
+
return out;
|
|
8021
|
+
}, [
|
|
8022
|
+
opts.catalogByServer,
|
|
8023
|
+
persistedDenyAll,
|
|
8024
|
+
setDisabled
|
|
8025
|
+
]);
|
|
8026
|
+
}
|
|
8027
|
+
/**
|
|
8028
|
+
* Pure factory shared by both hook flavors. Captures `persistedDenyAll`
|
|
8029
|
+
* + `setDisabledMcpTools` at the call site so toggle handlers stay
|
|
8030
|
+
* referentially stable across renders that don't touch the underlying
|
|
8031
|
+
* settings entry — important for `useKeyboard` to avoid re-binding on
|
|
8032
|
+
* every catalog change.
|
|
8033
|
+
*
|
|
8034
|
+
* Exported for direct use by non-React consumers (CLI, GUI shells)
|
|
8035
|
+
* that want the same write semantics without the hook plumbing.
|
|
8036
|
+
*/
|
|
8037
|
+
function buildToolToggle(args) {
|
|
8038
|
+
const { serverName, catalogNames, persistedDenyAll, setDisabledMcpTools } = args;
|
|
8039
|
+
const persistedDeny = persistedDenyAll?.[serverName];
|
|
8040
|
+
const catalogSet = new Set(catalogNames);
|
|
8041
|
+
const enabledSet = (() => {
|
|
8042
|
+
if (!persistedDeny || persistedDeny.length === 0) return new Set(catalogNames);
|
|
8043
|
+
const deny = new Set(persistedDeny);
|
|
8044
|
+
return new Set(catalogNames.filter((name) => !deny.has(name)));
|
|
8045
|
+
})();
|
|
8046
|
+
const toggle = (toolName) => {
|
|
8047
|
+
const currentDeny = new Set(persistedDeny ?? []);
|
|
8048
|
+
if (currentDeny.has(toolName)) currentDeny.delete(toolName);
|
|
8049
|
+
else currentDeny.add(toolName);
|
|
8050
|
+
const nextForServer = [...currentDeny].filter((n) => catalogSet.has(n)).sort();
|
|
8051
|
+
const nextMap = { ...persistedDenyAll ?? {} };
|
|
8052
|
+
if (nextForServer.length === 0) delete nextMap[serverName];
|
|
8053
|
+
else nextMap[serverName] = nextForServer;
|
|
8054
|
+
setDisabledMcpTools(Object.keys(nextMap).length === 0 ? void 0 : nextMap);
|
|
8055
|
+
};
|
|
8056
|
+
return {
|
|
8057
|
+
enabledSet,
|
|
8058
|
+
toggle
|
|
8059
|
+
};
|
|
8060
|
+
}
|
|
8061
|
+
//#endregion
|
|
8062
|
+
//#region src/chat/mcp-tools-cache.ts
|
|
8063
|
+
/**
|
|
8064
|
+
* Disk filename. Versioned so a future schema change (e.g. adding
|
|
8065
|
+
* provenance / TTL) can ship a parallel `v2` file without colliding.
|
|
8066
|
+
*/
|
|
8067
|
+
const CACHE_FILENAME = "mcp-tools-cache.json";
|
|
8068
|
+
/**
|
|
8069
|
+
* Resolve the on-disk cache path under a host's data directory. Exposed
|
|
8070
|
+
* for tests + advanced hosts that want to inspect / delete the file
|
|
8071
|
+
* without re-implementing the path convention.
|
|
8072
|
+
*/
|
|
8073
|
+
function mcpToolsCachePath(dataDir) {
|
|
8074
|
+
return resolve(dataDir, CACHE_FILENAME);
|
|
8075
|
+
}
|
|
8076
|
+
/**
|
|
8077
|
+
* Best-effort cache read. Returns `{}` when the file is missing, when
|
|
8078
|
+
* JSON.parse rejects, or when the top-level shape isn't a plain object —
|
|
8079
|
+
* a corrupt cache must never crash the host on startup.
|
|
8080
|
+
*
|
|
8081
|
+
* Per-entry shape validation is light (presence of an array `tools`):
|
|
8082
|
+
* deeper validation would lock the cache to a single zidane version,
|
|
8083
|
+
* which is the opposite of what a long-lived cache wants. Entries that
|
|
8084
|
+
* survive the light check feed back through `McpToolSchema`'s `unknown`
|
|
8085
|
+
* `inputSchema` so downstream readers stay tolerant of upstream churn.
|
|
8086
|
+
*/
|
|
8087
|
+
function loadMcpToolsCache(opts) {
|
|
8088
|
+
const path = mcpToolsCachePath(opts.dataDir);
|
|
8089
|
+
if (!existsSync(path)) return {};
|
|
8090
|
+
try {
|
|
8091
|
+
const raw = readFileSync(path, "utf-8");
|
|
8092
|
+
const parsed = JSON.parse(raw);
|
|
8093
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
8094
|
+
const out = {};
|
|
8095
|
+
for (const [name, entry] of Object.entries(parsed)) if (isCachedEntry(entry)) out[name] = entry;
|
|
8096
|
+
return out;
|
|
8097
|
+
} catch {
|
|
8098
|
+
return {};
|
|
8099
|
+
}
|
|
8100
|
+
}
|
|
8101
|
+
/**
|
|
8102
|
+
* Atomic full-cache write. Used by {@link subscribeMcpToolsCache} after
|
|
8103
|
+
* each upsert. Failures bubble up as the underlying `writeFileAtomic`
|
|
8104
|
+
* error — the caller logs under `ZIDANE_DEBUG` and swallows.
|
|
8105
|
+
*/
|
|
8106
|
+
function saveMcpToolsCache(opts) {
|
|
8107
|
+
writeFileAtomic(mcpToolsCachePath(opts.dataDir), `${JSON.stringify(opts.cache, null, 2)}\n`, { ensureDir: true });
|
|
8108
|
+
}
|
|
8109
|
+
/**
|
|
8110
|
+
* Drop entries for one or more servers, or wipe the cache when no
|
|
8111
|
+
* server is named. Idempotent — entries that aren't present are
|
|
8112
|
+
* silently skipped. Returns the resulting cache so callers can refresh
|
|
8113
|
+
* any in-memory mirror without re-reading from disk.
|
|
8114
|
+
*
|
|
8115
|
+
* Intended for a future "rescan server" affordance in the settings UI
|
|
8116
|
+
* (clear → trigger a real bootstrap → cache repopulates on the
|
|
8117
|
+
* `mcp:tools:list` hook).
|
|
8118
|
+
*/
|
|
8119
|
+
function clearMcpToolsCache(opts) {
|
|
8120
|
+
const current = loadMcpToolsCache(opts);
|
|
8121
|
+
if (!opts.serverNames) {
|
|
8122
|
+
saveMcpToolsCache({
|
|
8123
|
+
dataDir: opts.dataDir,
|
|
8124
|
+
cache: {}
|
|
8125
|
+
});
|
|
8126
|
+
return {};
|
|
8127
|
+
}
|
|
8128
|
+
const next = { ...current };
|
|
8129
|
+
for (const name of opts.serverNames) delete next[name];
|
|
8130
|
+
saveMcpToolsCache({
|
|
8131
|
+
dataDir: opts.dataDir,
|
|
8132
|
+
cache: next
|
|
8133
|
+
});
|
|
8134
|
+
return next;
|
|
8135
|
+
}
|
|
8136
|
+
/**
|
|
8137
|
+
* Subscribe to `mcp:tools:list` and persist every successful bootstrap
|
|
8138
|
+
* into the on-disk cache. Returns an unsubscribe function — call it
|
|
8139
|
+
* during agent teardown so a long-lived host (Settings modal that
|
|
8140
|
+
* outlives one agent) doesn't accumulate stale subscribers.
|
|
8141
|
+
*
|
|
8142
|
+
* Each write loads the current cache, upserts the named entry, then
|
|
8143
|
+
* atomic-writes the full file. The read-modify-write is safe under
|
|
8144
|
+
* Node single-threaded event loop semantics — concurrent bootstraps in
|
|
8145
|
+
* the same process serialize through the hook bus.
|
|
8146
|
+
*
|
|
8147
|
+
* Optional `onChange` callback fires synchronously after every
|
|
8148
|
+
* successful disk write with the entry that was just upserted. Lets a
|
|
8149
|
+
* React host trigger a state refresh without polling the disk.
|
|
8150
|
+
*
|
|
8151
|
+
* Write failures are swallowed (logged under `ZIDANE_DEBUG`): the cache
|
|
8152
|
+
* is an accelerator, not a correctness boundary. If the disk is full
|
|
8153
|
+
* the agent run still works — the settings UI just shows stale data
|
|
8154
|
+
* until the next successful write.
|
|
8155
|
+
*/
|
|
8156
|
+
function subscribeMcpToolsCache(hooks, opts) {
|
|
8157
|
+
return hooks.hook("mcp:tools:list", (ctx) => {
|
|
8158
|
+
const entry = {
|
|
8159
|
+
tools: [...ctx.tools],
|
|
8160
|
+
updatedAt: Date.now(),
|
|
8161
|
+
transport: ctx.transport
|
|
8162
|
+
};
|
|
8163
|
+
try {
|
|
8164
|
+
const next = {
|
|
8165
|
+
...loadMcpToolsCache({ dataDir: opts.dataDir }),
|
|
8166
|
+
[ctx.name]: entry
|
|
8167
|
+
};
|
|
8168
|
+
saveMcpToolsCache({
|
|
8169
|
+
dataDir: opts.dataDir,
|
|
8170
|
+
cache: next
|
|
8171
|
+
});
|
|
8172
|
+
opts.onChange?.({
|
|
8173
|
+
name: ctx.name,
|
|
8174
|
+
...entry
|
|
8175
|
+
});
|
|
8176
|
+
} catch (err) {
|
|
8177
|
+
if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/chat] mcp-tools-cache write failed for "${ctx.name}": ${errorMessage(err)}\n`);
|
|
8178
|
+
}
|
|
8179
|
+
});
|
|
8180
|
+
}
|
|
8181
|
+
/**
|
|
8182
|
+
* Force-refresh the on-disk tools cache by opening a transient MCP
|
|
8183
|
+
* connection to every server, capturing the `mcp:tools:list` hook on
|
|
8184
|
+
* the way through, and closing the connection immediately. The
|
|
8185
|
+
* underlying `connectMcpServers` runs every server's bootstrap in
|
|
8186
|
+
* parallel, so the wall-clock cost collapses to the slowest server.
|
|
8187
|
+
*
|
|
8188
|
+
* Two design choices worth noting:
|
|
8189
|
+
*
|
|
8190
|
+
* - **Shared hook bus.** The caller passes the SAME `Hookable`
|
|
8191
|
+
* instance that has the cache subscriber wired (typically
|
|
8192
|
+
* `agent.hooks` after `subscribeMcpToolsCache(agent.hooks, …)`
|
|
8193
|
+
* ran). That way `mcp:tools:list` fires on the bus the
|
|
8194
|
+
* subscriber is listening to and the cache lands on disk
|
|
8195
|
+
* without a separate write path.
|
|
8196
|
+
* - **Transient, NOT shared with the live agent.** The connection
|
|
8197
|
+
* opened here is closed immediately. The agent's own MCP
|
|
8198
|
+
* connection is untouched, so a refresh never disrupts an
|
|
8199
|
+
* in-flight tool call.
|
|
8200
|
+
*
|
|
8201
|
+
* The function intentionally swallows per-server failures (they're
|
|
8202
|
+
* already surfaced via `mcp:bootstrap:end ok: false` for any host
|
|
8203
|
+
* that wired the listener). The Promise resolves once every server's
|
|
8204
|
+
* bootstrap settles, success or otherwise.
|
|
8205
|
+
*/
|
|
8206
|
+
async function refreshMcpToolsCatalog(opts) {
|
|
8207
|
+
if (opts.servers.length === 0) return;
|
|
8208
|
+
await (await connectMcpServers(opts.servers, void 0, opts.hooks, opts.buildAuthProvider ? { buildAuthProvider: opts.buildAuthProvider } : void 0)).close().catch((err) => {
|
|
8209
|
+
if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/chat] mcp-tools-cache transient close failed: ${errorMessage(err)}\n`);
|
|
8210
|
+
});
|
|
8211
|
+
}
|
|
8212
|
+
/**
|
|
8213
|
+
* Type-narrowing check used by {@link loadMcpToolsCache}. Kept private
|
|
8214
|
+
* — callers that want a richer validation surface should layer it on
|
|
8215
|
+
* top of the loose disk shape rather than tightening this predicate.
|
|
8216
|
+
*/
|
|
8217
|
+
function isCachedEntry(value) {
|
|
8218
|
+
if (!value || typeof value !== "object") return false;
|
|
8219
|
+
const entry = value;
|
|
8220
|
+
if (!Array.isArray(entry.tools)) return false;
|
|
8221
|
+
if (typeof entry.updatedAt !== "number" || !Number.isFinite(entry.updatedAt)) return false;
|
|
8222
|
+
if (entry.transport !== "stdio" && entry.transport !== "sse" && entry.transport !== "streamable-http") return false;
|
|
8223
|
+
return true;
|
|
8224
|
+
}
|
|
8225
|
+
//#endregion
|
|
7906
8226
|
//#region src/chat/project-user-paths.ts
|
|
7907
8227
|
/**
|
|
7908
8228
|
* Shared search-path builder for project + user config discovery.
|
|
@@ -8174,14 +8494,46 @@ function discoverProjectMcps(opts = {}) {
|
|
|
8174
8494
|
* - `enabled === [names]` → allowlist; servers not in the list are
|
|
8175
8495
|
* dropped.
|
|
8176
8496
|
*
|
|
8497
|
+
* `disabledTools` is the per-server tool deny-list from
|
|
8498
|
+
* `Settings.disabledMcpTools`. For each server that survives the
|
|
8499
|
+
* server-level enable filter, the per-tool names are merged into
|
|
8500
|
+
* `McpServerConfig.disabledTools` via **union** with anything the JSON
|
|
8501
|
+
* file already pinned — a tool listed in either source is dropped.
|
|
8502
|
+
* Union (not override) keeps JSON-side policy stable: a server file
|
|
8503
|
+
* that pins `disabledTools: ['dangerous_tool']` can't be re-enabled
|
|
8504
|
+
* via the UI by accident.
|
|
8505
|
+
*
|
|
8506
|
+
* `enabledTools` (JSON-side allowlist) takes precedence over the
|
|
8507
|
+
* UI-side deny-list when both are set on the same server — the
|
|
8508
|
+
* allowlist's "only these" semantics would be meaningless if a UI
|
|
8509
|
+
* deny-list could subtract from it again. We don't emit `disabledTools`
|
|
8510
|
+
* when `enabledTools` is present.
|
|
8511
|
+
*
|
|
8177
8512
|
* Returns a fresh array — callers can mutate without affecting the
|
|
8178
|
-
* underlying discovery list.
|
|
8513
|
+
* underlying discovery list. Per-server config objects are also fresh
|
|
8514
|
+
* copies (shallow), so the merged `disabledTools` doesn't leak back
|
|
8515
|
+
* onto the discovery catalog.
|
|
8179
8516
|
*/
|
|
8180
8517
|
function buildMcpServers(opts) {
|
|
8181
|
-
|
|
8182
|
-
|
|
8183
|
-
|
|
8184
|
-
return
|
|
8518
|
+
const survivors = filterByEnabled(opts.discovered, opts.enabled);
|
|
8519
|
+
const deny = opts.disabledTools;
|
|
8520
|
+
if (!deny || Object.keys(deny).length === 0) return survivors.map((d) => ({ ...d.config }));
|
|
8521
|
+
return survivors.map((d) => {
|
|
8522
|
+
const next = { ...d.config };
|
|
8523
|
+
const uiDeny = deny[d.config.name];
|
|
8524
|
+
if (!uiDeny || uiDeny.length === 0) return next;
|
|
8525
|
+
if (next.enabledTools && next.enabledTools.length > 0) return next;
|
|
8526
|
+
const merged = new Set(next.disabledTools ?? []);
|
|
8527
|
+
for (const name of uiDeny) merged.add(name);
|
|
8528
|
+
next.disabledTools = [...merged].sort();
|
|
8529
|
+
return next;
|
|
8530
|
+
});
|
|
8531
|
+
}
|
|
8532
|
+
function filterByEnabled(discovered, enabled) {
|
|
8533
|
+
if (enabled === void 0) return discovered;
|
|
8534
|
+
if (enabled.length === 0) return [];
|
|
8535
|
+
const allow = new Set(enabled);
|
|
8536
|
+
return discovered.filter((d) => allow.has(d.config.name));
|
|
8185
8537
|
}
|
|
8186
8538
|
//#endregion
|
|
8187
8539
|
//#region src/chat/model-catalog.ts
|
|
@@ -9810,7 +10162,7 @@ const TOOL_DISPLAY = {
|
|
|
9810
10162
|
format: (input) => {
|
|
9811
10163
|
const command = stringField(input, "command");
|
|
9812
10164
|
if (!command) return null;
|
|
9813
|
-
return { target: truncate(command
|
|
10165
|
+
return { target: truncate(command, 200) };
|
|
9814
10166
|
}
|
|
9815
10167
|
},
|
|
9816
10168
|
shell_kill: {
|
|
@@ -9866,7 +10218,7 @@ const TOOL_DISPLAY = {
|
|
|
9866
10218
|
format: (input) => {
|
|
9867
10219
|
const task = stringField(input, "task");
|
|
9868
10220
|
if (!task) return null;
|
|
9869
|
-
return { target: truncate(task
|
|
10221
|
+
return { target: truncate(task, 120) };
|
|
9870
10222
|
}
|
|
9871
10223
|
},
|
|
9872
10224
|
tool_search: {
|
|
@@ -10011,8 +10363,17 @@ function sentenceCase(s) {
|
|
|
10011
10363
|
words[0] = (words[0][0]?.toUpperCase() ?? "") + words[0].slice(1);
|
|
10012
10364
|
return words.join(" ");
|
|
10013
10365
|
}
|
|
10366
|
+
/**
|
|
10367
|
+
* Collapse internal whitespace (including newlines) to single spaces
|
|
10368
|
+
* and clip to `max` columns with a trailing `…`. The whitespace
|
|
10369
|
+
* normalisation is the load-bearing bit — tool input strings like a
|
|
10370
|
+
* shell heredoc or a multi-line Python `-c` script otherwise render
|
|
10371
|
+
* across several rows in the transcript even though the `↳ Tool …`
|
|
10372
|
+
* line is meant to be a single-line scannable summary.
|
|
10373
|
+
*/
|
|
10014
10374
|
function truncate(s, max) {
|
|
10015
|
-
|
|
10375
|
+
const clean = s.replace(/\s+/g, " ").trim();
|
|
10376
|
+
return clean.length <= max ? clean : `${clean.slice(0, max - 1)}…`;
|
|
10016
10377
|
}
|
|
10017
10378
|
function byteLengthUtf8(s) {
|
|
10018
10379
|
let bytes = 0;
|
|
@@ -10188,6 +10549,6 @@ function countNeighbors(turnIds, turnId) {
|
|
|
10188
10549
|
};
|
|
10189
10550
|
}
|
|
10190
10551
|
//#endregion
|
|
10191
|
-
export {
|
|
10552
|
+
export { mcpToolsCachePath as $, ensureKeybindingsFile as $n, modelsForDescriptor as $r, CATPPUCCIN_MACCHIATO as $t, getSafelist as A, COMMUNICATION_DOCTRINE as Ai, applyEditPayload as An, parseSemver as Ar, clipHintsToWidth as At, oauthUsesManualCodePaste as B, buildPlanSystem as Bi, tokenize as Bn, readProviderCredential as Br, SETTINGS_CATEGORIES as Bt, resolveSessionExportTarget as C, isTodoTool as Ci, stripSpawnTokensLine as Cn, bootTick as Cr, isInteractionTool as Ct, useSafeModeQueue as D, setTodosForRun as Di, toolResultText as Dn, compareSemver as Dr, useInteractionsActions as Dt, useSafeModeActions as E, selectActiveTodos as Ei, toolCallPreview as En, checkForUpdate as Er, serializeInteractionResponse as Et, suggestSafelistEntry as F, PLAN_MODE_DOCTRINE as Fi, extractEditPayload as Fn, shouldAutoCompact as Fr, buildHints as Ft, indexOfEntry as G, resolveApprovalForPayload as Gn, OUTPUT_RESERVE_TOKENS as Gr, useSettings as Gt, supportsOAuth as H, maskToOutcomeKinds as Hn, setProviderCredential as Hr, SETTINGS_TOGGLES as Ht, writeProjects as I, PLAN_MODE_DOCTRINE_NO_PROMPTS as Ii, filetypeFromPath as In, detectAuth as Ir, shortChord as It, discoverProjectMcps as J, summarizeOutcomes as Jn, credKeyOf as Jr, resolveChipColor as Jt, buildMcpServers as K, rewriteMultiEditHeader as Kn, anthropicDescriptor as Kr, BUILTIN_THEMES as Kt, splitPromptSegments as L, SUBAGENT_GUIDANCE as Li, previewEditPayload as Ln, applyApiKeyEnv as Lr, listProjectFiles as Lt, matchesSafelistEntry as M, IDENTITY_PREFIX as Mi, buildUnifiedDiff as Mn, performSelfUpdate as Mr, truncateTrailing as Mt, projectsFilePath as N, INTERACTION_GUIDANCE as Ni, computeInlineDiff as Nn, resolvePlatformPackage as Nr, cleanTitle as Nt, IMPLICITLY_SAFE_TOOLS as O, useActiveTodos as Oi, turnSelectionOwnership as On, detectLibc as Or, useInteractionsQueue as Ot, readProjects as P, INTERACTION_GUIDANCE_NO_PROMPTS as Pi, computeLineDiff as Pn, AUTO_COMPACT_MIN_GROWTH_FRACTION as Pr, generateSessionTitle as Pt, loadMcpToolsCache as Q, KEYBINDING_KEY_COL_WIDTH as Qn, modelSupportsReasoning as Qr, CATPPUCCIN_LATTE as Qt, formatPathForCwd as R, TOKEN_DISCIPLINE_DOCTRINE as Ri, splitLines as Rn, credentialsPath as Rr, useEnabledToggleSet as Rt, renderSession as S, getTodosForRun as Si, selectableTurnIds as Sn, bootProfileEnabled as Sr, createInteractionTools as St, SafeModeProvider as T, pruneTodosByRun as Ti, titleFromTurns as Tn, useUpdateCheck as Tr, pendingInteractionsFromTurns as Tt, buildModelCatalog as U, mergeApprovalAndBodyOutcomes as Un, writeCredentials as Ur, SettingsProvider as Ut, runOAuthLogin as V, envSection as Vi, buildEditOutcomesAnnotation as Vn, removeProviderCredential as Vr, SETTINGS_CHOICES as Vt, filterModelCatalog as W, parseEditOutcomesFromResult as Wn, BUILTIN_PROVIDERS as Wr, clampFps as Wt, projectUserPaths as X, KEYBINDING_DEFS as Xn, getContextWindow as Xr, VAPORWAVE_THEME as Xt, parseMcpsFile as Y, DEFAULT_KEYBINDINGS as Yn, effectiveContextWindow as Yr, resolveTheme as Yt, clearMcpToolsCache as Z, KEYBINDING_DEF_BY_ACTION as Zn, getModelInfo as Zr, CATPPUCCIN_FRAPPE as Zt, turnContextSize as _, TODOWRITE_TOOL as _i, lastContextSizeFromTurns as _n, mergeReferences as _r, splitMarkdownCodeBlocks as _t, computeTurnAnchors as a, findGitRoot$1 as ai, ConfigProvider as an, parseBindingSpec as ar, useMcpToolToggleSet as at, defaultSkillScanPaths as b, createTodoTools as bi, marginTopFor as bn, buildLinearRamp as br, PRESENT_PLAN_TOOL as bt, formatToolCall as c, DEFAULT_AGENT_ID as ci, resolveStoragePaths as cn, SKILLS_TRIGGER as cr, parentServerName as ct, useSelectStyle as d, PLAN_AGENT as di, createStateStore as dn, FILES_TRIGGER as dr, patchMcpCredential as dt, openaiDescriptor as ei, CATPPUCCIN_MOCHA as en, formatBindingForDisplay as er, refreshMcpToolsCatalog as et, useSurfaces as f, accentColor as fi, deriveSessionTitle as fn, createFilesCompletionProvider as fr, McpAuthProvider as ft, finalizeStreamingMarkdownForOwner as g, TODOS_METADATA_KEY as gi, isVisible as gn, findActiveTrigger as gr, reduceMcpAuth as gt, finalizeStreamingMarkdown as h, TODOREAD_TOOL as hi, isTurnHighlighted as hn, collectReferences as hr, getMcpAuthStatus as ht, turnAsText as i, renderAgentsMdBlock as ii, useDiscoveryOptional as in, mergeKeybindings as ir, useMcpToolToggleMap as it, isOnSafelist as j, DOING_TASKS_DOCTRINE as ji, buildContextualDiff as jn, performInPlaceSelfUpdate as jr, hintsLength as jt, addToSafelist as k, ACTIONS_WITH_CARE_DOCTRINE as ki, updateToolEventOutcomes as kn, detectPackageManager as kr, EMPTY_HINTS as kt, ThemeProvider as l, DEFAULT_BUDGET_EXCLUDE_TOOLS as li, resolveStorageDirs as ln, createSkillsCompletionProvider as lr, createFileMcpCredentialStore as lt, useTheme as m, singleAgentRegistry as mi, isEditErrorResult as mn, applyInsert as mr, useMcpAuthState as mt, deleteTurnSafely as n, piIdOf as ni, DiscoveryProvider as nn, keybindingsPath as nr, subscribeMcpToolsCache as nt, TOOL_DISPLAY as o, BUILD_AGENT as oi, useConfig as on, readKeybindings as or, buildVisibleMcpRows as ot, useSyntaxStyles as p, resolveAgentId as pi, eventsFromTurns as pn, uniqueFilesFromReferences as pr, useMcpAuthDispatch as pt, defaultMcpsConfigPaths as q, stripEditOutcomesAnnotation as qn, cerebrasDescriptor as qr, DEFAULT_THEME as qt, truncateTurnsAt as r, discoverAgentsMd as ri, useDiscovery as rn, matchesBinding as rr, buildToolToggle as rt, displayNameFor as s, BUILTIN_AGENTS as si, resolveConfig as sn, stripJsonComments as sr, indexOfServerRow as st, countNeighbors as t, openrouterDescriptor as ti, createDiscoverySlot as tn, groupBindings as tr, saveMcpToolsCache as tt, useColors as u, DEFAULT_PERSIST_EXCLUDE_TOOLS as ui, EDIT_TOOL_NAMES as un, uniqueSkillNamesFromReferences as ur, mcpCredentialsPath as ut, useStreamBuffer as v, TODO_STATUS_GLYPHS as vi, listSessionMeta as vn, useCompletion as vr, ASK_USER_TOOL as vt, writeSessionExport as w, pickActiveRunId as wi, sumRunCosts as wn, buildUpdateHint as wr, makeRequestInteraction as wt, discoverProjectSkills as x, getArchivedTodosForRun as xi, saveState as xn, tryOpenBrowser as xr, buildResumedToolResultsTurn as xt, buildSkillsConfig as y, TODO_WRITE_COUNTS_METADATA_KEY as yi, loadState as yn, blendHsl as yr, InteractionsProvider as yt, fetchOAuthRedirect as z, buildBuildSystem as zi, summarizeEditPayload as zn, readCredentials as zr, DEFAULT_SETTINGS as zt };
|
|
10192
10553
|
|
|
10193
|
-
//# sourceMappingURL=turn-operations-
|
|
10554
|
+
//# sourceMappingURL=turn-operations-D2rHrTQv.js.map
|