@bastani/atomic 0.9.23-alpha.1 → 0.9.24-alpha.1
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/CHANGELOG.md +29 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/CHANGELOG.md +6 -0
- package/dist/builtin/mcp/README.md +1 -0
- package/dist/builtin/mcp/index.bundle.mjs +244 -58
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +6 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +18 -0
- package/dist/builtin/workflows/builtin/{chunk-d3xhj946.js → chunk-cpw5gtzg.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-kgn5wz1c.js → chunk-e1254zvd.js} +139 -15
- package/dist/builtin/workflows/builtin/{chunk-hj8mh07f.js → chunk-qy6g0baf.js} +1 -1
- package/dist/builtin/workflows/builtin/goal.js +2 -2
- package/dist/builtin/workflows/builtin/index.js +3 -3
- package/dist/builtin/workflows/builtin/ralph.js +2 -2
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/skills/prompt-engineer/SKILL.md +1 -0
- package/dist/builtin/workflows/skills/prompt-engineer/references/claude_sonnet_5_5.md +131 -0
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +187 -25
- package/dist/builtin/workflows/src/index.js +147 -17
- package/dist/core/agent-session-events.js +1 -1
- package/dist/core/agent-session-events.js.map +1 -1
- package/dist/core/agent-session-state.js +5 -2
- package/dist/core/agent-session-state.js.map +1 -1
- package/dist/core/extensions/api-types.d.ts +12 -0
- package/dist/core/extensions/api-types.d.ts.map +1 -1
- package/dist/core/extensions/api-types.js.map +1 -1
- package/dist/core/extensions/loader-api.d.ts.map +1 -1
- package/dist/core/extensions/loader-api.js +42 -0
- package/dist/core/extensions/loader-api.js.map +1 -1
- package/dist/core/extensions/loader-bindings.d.ts.map +1 -1
- package/dist/core/extensions/loader-bindings.js +13 -7
- package/dist/core/extensions/loader-bindings.js.map +1 -1
- package/dist/core/extensions/loader-resources.d.ts +3 -0
- package/dist/core/extensions/loader-resources.d.ts.map +1 -1
- package/dist/core/extensions/loader-resources.js.map +1 -1
- package/dist/core/extensions/loader-runtime.d.ts.map +1 -1
- package/dist/core/extensions/loader-runtime.js +2 -0
- package/dist/core/extensions/loader-runtime.js.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.js +2 -0
- package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
- package/dist/core/extensions/mcp-server-registry.d.ts +22 -0
- package/dist/core/extensions/mcp-server-registry.d.ts.map +1 -0
- package/dist/core/extensions/mcp-server-registry.js +51 -0
- package/dist/core/extensions/mcp-server-registry.js.map +1 -0
- package/dist/core/extensions/runtime-types.d.ts +3 -0
- package/dist/core/extensions/runtime-types.d.ts.map +1 -1
- package/dist/core/extensions/runtime-types.js.map +1 -1
- package/dist/core/keybindings.d.ts +1 -1
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +1 -1
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/mcp-servers.d.ts +39 -0
- package/dist/core/mcp-servers.d.ts.map +1 -0
- package/dist/core/mcp-servers.js +2 -0
- package/dist/core/mcp-servers.js.map +1 -0
- package/dist/core/model-resolver-defaults.js +2 -2
- package/dist/core/model-resolver-defaults.js.map +1 -1
- package/dist/core/package-manager-manifest.d.ts +3 -0
- package/dist/core/package-manager-manifest.d.ts.map +1 -1
- package/dist/core/package-manager-manifest.js +14 -0
- package/dist/core/package-manager-manifest.js.map +1 -1
- package/dist/core/package-manager-mcp-servers.d.ts +4 -0
- package/dist/core/package-manager-mcp-servers.d.ts.map +1 -0
- package/dist/core/package-manager-mcp-servers.js +53 -0
- package/dist/core/package-manager-mcp-servers.js.map +1 -0
- package/dist/core/package-manager-resource-accumulator.d.ts.map +1 -1
- package/dist/core/package-manager-resource-accumulator.js +2 -0
- package/dist/core/package-manager-resource-accumulator.js.map +1 -1
- package/dist/core/package-manager-resource-collector.d.ts.map +1 -1
- package/dist/core/package-manager-resource-collector.js +2 -0
- package/dist/core/package-manager-resource-collector.js.map +1 -1
- package/dist/core/package-manager-resource-patterns.d.ts +4 -0
- package/dist/core/package-manager-resource-patterns.d.ts.map +1 -1
- package/dist/core/package-manager-resource-patterns.js +36 -12
- package/dist/core/package-manager-resource-patterns.js.map +1 -1
- package/dist/core/package-manager-types.d.ts +14 -0
- package/dist/core/package-manager-types.d.ts.map +1 -1
- package/dist/core/package-manager-types.js.map +1 -1
- package/dist/core/package-manager.d.ts +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resource-loader-core.d.ts +4 -0
- package/dist/core/resource-loader-core.d.ts.map +1 -1
- package/dist/core/resource-loader-core.js +7 -0
- package/dist/core/resource-loader-core.js.map +1 -1
- package/dist/core/resource-loader-helpers.d.ts.map +1 -1
- package/dist/core/resource-loader-helpers.js +1 -0
- package/dist/core/resource-loader-helpers.js.map +1 -1
- package/dist/core/resource-loader-internals.d.ts +2 -0
- package/dist/core/resource-loader-internals.d.ts.map +1 -1
- package/dist/core/resource-loader-internals.js.map +1 -1
- package/dist/core/resource-loader-package-resources.d.ts +3 -0
- package/dist/core/resource-loader-package-resources.d.ts.map +1 -1
- package/dist/core/resource-loader-package-resources.js +25 -2
- package/dist/core/resource-loader-package-resources.js.map +1 -1
- package/dist/core/resource-loader-reload.d.ts.map +1 -1
- package/dist/core/resource-loader-reload.js +4 -1
- package/dist/core/resource-loader-reload.js.map +1 -1
- package/dist/core/session-manager-core.d.ts +2 -0
- package/dist/core/session-manager-core.d.ts.map +1 -1
- package/dist/core/session-manager-core.js +6 -1
- package/dist/core/session-manager-core.js.map +1 -1
- package/dist/core/settings-types.d.ts +1 -0
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.js.map +1 -1
- package/dist/extensions/llama/provider.d.ts +1 -1
- package/dist/extensions/llama/provider.d.ts.map +1 -1
- package/dist/extensions/llama/provider.js +37 -10
- package/dist/extensions/llama/provider.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/chat-input-actions.d.ts +12 -0
- package/dist/modes/interactive/chat-input-actions.d.ts.map +1 -1
- package/dist/modes/interactive/chat-input-actions.js +44 -18
- package/dist/modes/interactive/chat-input-actions.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-editor.d.ts +11 -0
- package/dist/modes/interactive/components/chat-session-host-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-editor.js +7 -1
- package/dist/modes/interactive/components/chat-session-host-editor.js.map +1 -1
- package/dist/modes/interactive/interactive-hotkeys-debug.js +1 -1
- package/dist/modes/interactive/interactive-hotkeys-debug.js.map +1 -1
- package/dist/modes/interactive/interactive-input-handling.js +3 -1
- package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-helpers.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-helpers.js +1 -6
- package/dist/modes/interactive/interactive-mode-helpers.js.map +1 -1
- package/dist/utils/clipboard-native.d.ts +2 -0
- package/dist/utils/clipboard-native.d.ts.map +1 -1
- package/dist/utils/clipboard-native.js.map +1 -1
- package/dist/utils/clipboard.d.ts +7 -0
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +37 -1
- package/dist/utils/clipboard.js.map +1 -1
- package/docs/extensions/api-reference.md +19 -0
- package/docs/extensions.md +4 -0
- package/docs/keybindings.md +2 -2
- package/docs/llama-cpp.md +13 -0
- package/docs/mcp-servers.md +18 -0
- package/docs/models/evals.md +16 -4
- package/docs/packages/authoring.md +27 -0
- package/docs/packages/reference.md +3 -2
- package/docs/packages.md +3 -2
- package/docs/skills.md +3 -1
- package/examples/extensions/gondolin/package-lock.json +3 -3
- package/npm-shrinkwrap.json +46 -46
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.9.24-alpha.1] - 2026-09-28
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Added inherited Claude Sonnet 5.5 support for Anthropic with adaptive thinking, mid-conversation effort, and a 1M context window.
|
|
10
|
+
- llama.cpp models are now also listed as classifier models with the same ID, so a local model can make `model: "auto"` routing decisions the way TypeSafe Jev does. Because an explicit `routerModel` resolves a classifier before a chat model, `routerModel: "llama.cpp/<id>"` now routes with the classifier instead of the chat model ([#10119](https://github.com/earendil-works/pi/pull/10119)).
|
|
11
|
+
- Packages can contribute MCP servers with `"atomic": { "mcpServers": "./mcp.json" }` or an inline `mcpServers` object, and extensions can add runtime-computed servers with `pi.registerMcpServer(name, config)` from the factory or `session_start`. Contributed servers are the lowest-precedence MCP layer, so a same-named server in any user or project MCP config replaces them. Package filters accept `mcpServers` name patterns, project packages contribute servers only in trusted projects, and workflow stages see the same servers ([#3355](https://github.com/bastani-inc/atomic/issues/3355)).
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Recorded Claude Sonnet 5.5 results in the evals snapshot used by automatic model routing: Artificial Analysis Intelligence Index rows for max, xhigh, high, medium and low effort, Cognition FrontierCode 1.1, and Anthropic's published OSWorld, AutomationBench, BenchCAD, Humanity's Last Exam (with tools) and Terminal-Bench-Science scores.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- OpenCode Go now defaults to Kimi K3 (`kimi-k3`). models.dev deprecated Kimi K2.6 for OpenCode Go, which removed it from the built-in catalog, so the previous default no longer resolved.
|
|
20
|
+
- Together now defaults to Kimi K3 (`moonshotai/Kimi-K3`). models.dev removed Kimi K2.6 from Together, which removed it from the built-in catalog, so the previous default no longer resolved.
|
|
21
|
+
- Fixed extension tool schemas leaking TypeBox `~kind`/`~optional` metadata into provider requests, which made Fireworks reject every request with `JSON Schema not supported` ([#3330](https://github.com/bastani-inc/atomic/issues/3330)).
|
|
22
|
+
- Resuming a session no longer appends a spurious system-prompt `tools` update when only the order of the active tools changed, so the resumed session keeps its prompt cache and the model is no longer told that unchanged tools were removed ([#3346](https://github.com/bastani-inc/atomic/issues/3346)).
|
|
23
|
+
- Switching sessions with `/resume` or closing a session before sending a message no longer leaves a header-only session file behind ([#3347](https://github.com/bastani-inc/atomic/issues/3347)).
|
|
24
|
+
- Fixed pasting files copied in Finder with `Ctrl+V` inserting the file icon as an image instead of the file paths. Copied files now paste as their paths, shell-quoted in bash mode, and clipboard read errors are reported instead of pasting the icon ([#10136](https://github.com/earendil-works/pi/pull/10136)).
|
|
25
|
+
|
|
26
|
+
## [0.9.23] - 2026-09-27
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- Long sessions no longer leak one open file per bash command. A finished command now releases its output file, an output file with no output is deleted, and output files left behind by Atomic processes that have exited are removed. On macOS, where a child process cannot receive a file descriptor numbered 10240 or higher, the leak eventually made every bash call and spawn fail with `Bad file descriptor`; if a spawn still fails that way, the error now names the cause ([#3313](https://github.com/bastani-inc/atomic/issues/3313)).
|
|
31
|
+
- Resuming a run that failed in a `ctx.tool` call now works when the call ran in parallel with other tools. Siblings that were cancelled or also threw when the run failed are run again on resume, in any order, instead of failing with `replay topology mismatch` or `unfinished or missing completed tool checkpoint`. A resume rejected by changed code no longer runs the failed tool or makes the run unresumable, including after Atomic restarts ([#3314](https://github.com/bastani-inc/atomic/issues/3314)).
|
|
32
|
+
- `model: "auto"` routing no longer ignores benchmark results when fewer than four models are available. Each model's results are now ranked against every model in the evals catalog rather than only the models you can route to, so with just two or three models (for example Opus and Haiku) the stronger model is no longer outranked on price alone, and a model scores the same however many models are enabled.
|
|
33
|
+
|
|
5
34
|
## [0.9.23-alpha.1] - 2026-09-27
|
|
6
35
|
|
|
7
36
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/intercom",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.24-alpha.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension providing a private coordination channel between parent and child agent sessions. Fork of: https://github.com/nicobailon/pi-intercom",
|
|
6
6
|
"contributors": [
|
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.9.24-alpha.1] - 2026-09-28
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- MCP servers contributed by packages and by `pi.registerMcpServer()` load as the lowest-precedence config layer, including registrations made after MCP has started. A same-named server in any MCP config file replaces a contributed one, and `"disabled": true` on a server entry, alone or with other fields, removes it. `/mcp` and connection errors show which package or extension contributed each server ([#3355](https://github.com/bastani-inc/atomic/issues/3355)).
|
|
15
|
+
|
|
10
16
|
## [0.9.20] - 2026-09-24
|
|
11
17
|
|
|
12
18
|
### Fixed
|
|
@@ -141,6 +141,7 @@ Pi-specific files are the write targets for imported or shared global servers wh
|
|
|
141
141
|
| `directTools` | `true`, `string[]`, or `false` — register tools individually instead of through proxy |
|
|
142
142
|
| `excludeTools` | `string[]` of tool names to hide (matches original names like `get_screenshot` and prefixed names like `figma_get_screenshot`) |
|
|
143
143
|
| `debug` | Show server stderr (default: false) |
|
|
144
|
+
| `disabled` | `true` removes the server from the effective config; `{ "disabled": true }` alone turns off a server contributed by a package or extension |
|
|
144
145
|
|
|
145
146
|
`timeoutMs` is an **inactivity timeout**, not a total wall-clock limit. Each MCP progress notification resets the timer, so a tool that continues reporting progress can run indefinitely. The value must be a finite number greater than zero; invalid values produce a configuration error when the MCP config loads.
|
|
146
147
|
|
|
@@ -6517,15 +6517,51 @@ function getMcpDiscoverySummary(overridePath, cwd = process.cwd()) {
|
|
|
6517
6517
|
repoPrompt: detectRepoPrompt(summaryWithoutRepoPrompt, cwd)
|
|
6518
6518
|
};
|
|
6519
6519
|
}
|
|
6520
|
-
function loadMcpConfig(overridePath, cwd = process.cwd()) {
|
|
6521
|
-
let config = { mcpServers:
|
|
6520
|
+
function loadMcpConfig(overridePath, cwd = process.cwd(), contributions = []) {
|
|
6521
|
+
let config = { mcpServers: validateContributedServers(contributions) };
|
|
6522
6522
|
for (const source of getConfigSources(overridePath, cwd)) {
|
|
6523
6523
|
const loaded = readValidatedConfig(source.readPath, `MCP config from ${source.readPath}`);
|
|
6524
6524
|
if (!loaded)
|
|
6525
6525
|
continue;
|
|
6526
6526
|
config = mergeConfigs(config, expandImports(loaded, cwd));
|
|
6527
6527
|
}
|
|
6528
|
-
return config;
|
|
6528
|
+
return withoutDisabledServers(config);
|
|
6529
|
+
}
|
|
6530
|
+
function describeMcpContributionSource(contribution) {
|
|
6531
|
+
const { origin, sourceInfo } = contribution;
|
|
6532
|
+
if (origin === "package")
|
|
6533
|
+
return `package ${sourceInfo.source}`;
|
|
6534
|
+
return sourceInfo.origin === "package" ? `extension from package ${sourceInfo.source}` : `extension ${sourceInfo.path}`;
|
|
6535
|
+
}
|
|
6536
|
+
function getContributedServerSources(overridePath, cwd, contributions) {
|
|
6537
|
+
const sources = new Map;
|
|
6538
|
+
if (contributions.length === 0)
|
|
6539
|
+
return sources;
|
|
6540
|
+
for (const [name, provenance] of getServerProvenance(overridePath, cwd, contributions)) {
|
|
6541
|
+
if (provenance.kind === "contributed" && provenance.source)
|
|
6542
|
+
sources.set(name, provenance.source);
|
|
6543
|
+
}
|
|
6544
|
+
return sources;
|
|
6545
|
+
}
|
|
6546
|
+
function validateContributedServers(contributions) {
|
|
6547
|
+
const servers = {};
|
|
6548
|
+
for (const contribution of contributions) {
|
|
6549
|
+
try {
|
|
6550
|
+
Object.assign(servers, validateMcpServerTimeouts({ [contribution.name]: contribution.config }));
|
|
6551
|
+
} catch (error) {
|
|
6552
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
6553
|
+
const message = `Ignoring MCP server "${contribution.name}" from ${describeMcpContributionSource(contribution)}: ${reason}`;
|
|
6554
|
+
if (!reportOwnedMcpLog("warn"))
|
|
6555
|
+
console.warn(message);
|
|
6556
|
+
}
|
|
6557
|
+
}
|
|
6558
|
+
return servers;
|
|
6559
|
+
}
|
|
6560
|
+
function withoutDisabledServers(config) {
|
|
6561
|
+
const enabled = Object.entries(config.mcpServers).filter(([, entry]) => entry.disabled !== true);
|
|
6562
|
+
if (enabled.length === Object.keys(config.mcpServers).length)
|
|
6563
|
+
return config;
|
|
6564
|
+
return { ...config, mcpServers: Object.fromEntries(enabled) };
|
|
6529
6565
|
}
|
|
6530
6566
|
function getConfigSources(overridePath, cwd = process.cwd()) {
|
|
6531
6567
|
const userPath = getPiGlobalConfigPath(overridePath);
|
|
@@ -6806,9 +6842,16 @@ function writeSharedServerEntry(filePath, serverName, entry) {
|
|
|
6806
6842
|
writeRawConfigObject(filePath, raw);
|
|
6807
6843
|
return filePath;
|
|
6808
6844
|
}
|
|
6809
|
-
function getServerProvenance(overridePath, cwd = process.cwd()) {
|
|
6845
|
+
function getServerProvenance(overridePath, cwd = process.cwd(), contributions = []) {
|
|
6810
6846
|
const provenance = new Map;
|
|
6811
6847
|
const userPath = getPiGlobalConfigPath(overridePath);
|
|
6848
|
+
for (const contribution of contributions) {
|
|
6849
|
+
provenance.set(contribution.name, {
|
|
6850
|
+
path: userPath,
|
|
6851
|
+
kind: "contributed",
|
|
6852
|
+
source: describeMcpContributionSource(contribution)
|
|
6853
|
+
});
|
|
6854
|
+
}
|
|
6812
6855
|
for (const source of getConfigSources(overridePath, cwd)) {
|
|
6813
6856
|
const loaded = readValidatedConfig(source.readPath, `MCP config from ${source.readPath}`);
|
|
6814
6857
|
if (!loaded)
|
|
@@ -6822,7 +6865,7 @@ function getServerProvenance(overridePath, cwd = process.cwd()) {
|
|
|
6822
6865
|
const imported = JSON.parse(readFileSync2(importPath, "utf-8"));
|
|
6823
6866
|
const servers = extractServers(imported, importKind);
|
|
6824
6867
|
for (const name of Object.keys(servers)) {
|
|
6825
|
-
if (!provenance.has(name)) {
|
|
6868
|
+
if (!provenance.has(name) || provenance.get(name)?.kind === "contributed") {
|
|
6826
6869
|
provenance.set(name, { path: userPath, kind: "import", importKind });
|
|
6827
6870
|
}
|
|
6828
6871
|
}
|
|
@@ -6854,7 +6897,7 @@ function writeDirectToolsConfig(changes, provenance, fullConfig) {
|
|
|
6854
6897
|
const raw = readRawConfigObject(filePath);
|
|
6855
6898
|
const servers = getServersObject(raw);
|
|
6856
6899
|
for (const { name, value, prov } of entries) {
|
|
6857
|
-
if (prov.kind === "import") {
|
|
6900
|
+
if (prov.kind === "import" || prov.kind === "contributed") {
|
|
6858
6901
|
const fullDef = fullConfig.mcpServers[name];
|
|
6859
6902
|
if (fullDef) {
|
|
6860
6903
|
servers[name] = { ...fullDef, directTools: value };
|
|
@@ -7193,6 +7236,11 @@ class McpLifecycleManager {
|
|
|
7193
7236
|
this.serverSettings.set(name, settings);
|
|
7194
7237
|
}
|
|
7195
7238
|
}
|
|
7239
|
+
unregisterServer(name) {
|
|
7240
|
+
this.allServers.delete(name);
|
|
7241
|
+
this.keepAliveServers.delete(name);
|
|
7242
|
+
this.serverSettings.delete(name);
|
|
7243
|
+
}
|
|
7196
7244
|
setGlobalIdleTimeout(minutes) {
|
|
7197
7245
|
this.globalIdleTimeout = minutes * 60 * 1000;
|
|
7198
7246
|
}
|
|
@@ -7200,6 +7248,8 @@ class McpLifecycleManager {
|
|
|
7200
7248
|
this.onIdleShutdown = callback;
|
|
7201
7249
|
}
|
|
7202
7250
|
startHealthChecks(intervalMs = 30000) {
|
|
7251
|
+
if (this.healthCheckInterval)
|
|
7252
|
+
return;
|
|
7203
7253
|
this.healthCheckInterval = setInterval(() => {
|
|
7204
7254
|
this.checkConnections();
|
|
7205
7255
|
}, intervalMs);
|
|
@@ -7238,6 +7288,7 @@ class McpLifecycleManager {
|
|
|
7238
7288
|
async gracefulShutdown() {
|
|
7239
7289
|
if (this.healthCheckInterval) {
|
|
7240
7290
|
clearInterval(this.healthCheckInterval);
|
|
7291
|
+
this.healthCheckInterval = undefined;
|
|
7241
7292
|
}
|
|
7242
7293
|
await this.manager.closeAll();
|
|
7243
7294
|
}
|
|
@@ -22249,7 +22300,9 @@ var init_ui_resource_handler = __esm(() => {
|
|
|
22249
22300
|
// dist/builtin/mcp/init.ts
|
|
22250
22301
|
var exports_init = {};
|
|
22251
22302
|
__export(exports_init, {
|
|
22303
|
+
applyMcpConfigChanges: () => applyMcpConfigChanges,
|
|
22252
22304
|
flushMetadataCache: () => flushMetadataCache,
|
|
22305
|
+
formatMcpServerName: () => formatMcpServerName,
|
|
22253
22306
|
getFailureAgeSeconds: () => getFailureAgeSeconds,
|
|
22254
22307
|
initializeMcp: () => initializeMcp,
|
|
22255
22308
|
lazyConnect: () => lazyConnect,
|
|
@@ -22260,7 +22313,8 @@ __export(exports_init, {
|
|
|
22260
22313
|
import { existsSync as existsSync6 } from "node:fs";
|
|
22261
22314
|
async function initializeMcp(pi, ctx) {
|
|
22262
22315
|
const configPath = pi.getFlag("mcp-config");
|
|
22263
|
-
const
|
|
22316
|
+
const contributions = pi.getMcpServerContributions?.() ?? [];
|
|
22317
|
+
const config = loadMcpConfig(configPath, ctx.cwd, contributions);
|
|
22264
22318
|
const manager = new McpServerManager;
|
|
22265
22319
|
const lifecycle = new McpLifecycleManager(manager);
|
|
22266
22320
|
try {
|
|
@@ -22284,6 +22338,7 @@ async function initializeMcp(pi, ctx) {
|
|
|
22284
22338
|
lifecycle,
|
|
22285
22339
|
toolMetadata,
|
|
22286
22340
|
config,
|
|
22341
|
+
contributedSources: getContributedServerSources(configPath, ctx.cwd, contributions),
|
|
22287
22342
|
failureTracker,
|
|
22288
22343
|
uiResourceHandler,
|
|
22289
22344
|
consentManager,
|
|
@@ -22310,16 +22365,7 @@ async function initializeMcp(pi, ctx) {
|
|
|
22310
22365
|
}
|
|
22311
22366
|
const prefix = config.settings?.toolPrefix ?? "server";
|
|
22312
22367
|
for (const [name, definition] of serverEntries) {
|
|
22313
|
-
|
|
22314
|
-
const idleOverride = definition.idleTimeout ?? (lifecycleMode === "eager" ? 0 : undefined);
|
|
22315
|
-
lifecycle.registerServer(name, definition, idleOverride !== undefined ? { idleTimeout: idleOverride } : undefined);
|
|
22316
|
-
if (lifecycleMode === "keep-alive") {
|
|
22317
|
-
lifecycle.markKeepAlive(name, definition);
|
|
22318
|
-
}
|
|
22319
|
-
if (cache?.servers?.[name] && isServerCacheValid(cache.servers[name], definition)) {
|
|
22320
|
-
const metadata = reconstructToolMetadata(name, cache.servers[name], prefix, definition);
|
|
22321
|
-
toolMetadata.set(name, metadata);
|
|
22322
|
-
}
|
|
22368
|
+
registerServer(state, name, definition, cache, prefix);
|
|
22323
22369
|
}
|
|
22324
22370
|
const startupServers = serverEntries.filter(([, definition]) => {
|
|
22325
22371
|
const mode = definition.lifecycle ?? "lazy";
|
|
@@ -22343,7 +22389,7 @@ async function initializeMcp(pi, ctx) {
|
|
|
22343
22389
|
for (const { name, definition, connection, error } of results) {
|
|
22344
22390
|
if (error || !connection) {
|
|
22345
22391
|
if (ctx.hasUI) {
|
|
22346
|
-
ctx.ui.notify(`MCP: Failed to connect to ${name}: ${error}`, "error");
|
|
22392
|
+
ctx.ui.notify(`MCP: Failed to connect to ${formatMcpServerName(state, name)}: ${error}`, "error");
|
|
22347
22393
|
}
|
|
22348
22394
|
reportMcpDiagnostic(pi, "MCP startup connection failed");
|
|
22349
22395
|
continue;
|
|
@@ -22362,18 +22408,7 @@ async function initializeMcp(pi, ctx) {
|
|
|
22362
22408
|
const msg = failedCount > 0 ? `MCP: ${connectedCount}/${startupServers.length} servers connected (${totalTools} tools)` : `MCP: ${connectedCount} servers connected (${totalTools} tools)`;
|
|
22363
22409
|
ctx.ui.notify(msg, "info");
|
|
22364
22410
|
}
|
|
22365
|
-
|
|
22366
|
-
updateServerMetadata(state, serverName);
|
|
22367
|
-
updateMetadataCache(state, serverName);
|
|
22368
|
-
state.failureTracker.delete(serverName);
|
|
22369
|
-
updateStatusBar(state);
|
|
22370
|
-
});
|
|
22371
|
-
lifecycle.setIdleShutdownCallback((serverName) => {
|
|
22372
|
-
const idleMinutes = getEffectiveIdleTimeoutMinutes(state, serverName);
|
|
22373
|
-
logger.debug(`${serverName} shut down (idle ${idleMinutes}m)`);
|
|
22374
|
-
updateStatusBar(state);
|
|
22375
|
-
});
|
|
22376
|
-
lifecycle.startHealthChecks();
|
|
22411
|
+
startLifecycle(state);
|
|
22377
22412
|
return state;
|
|
22378
22413
|
} catch (error) {
|
|
22379
22414
|
try {
|
|
@@ -22385,6 +22420,61 @@ async function initializeMcp(pi, ctx) {
|
|
|
22385
22420
|
throw error;
|
|
22386
22421
|
}
|
|
22387
22422
|
}
|
|
22423
|
+
function formatMcpServerName(state, name) {
|
|
22424
|
+
const source = state.contributedSources?.get(name);
|
|
22425
|
+
return source ? `${name} (${source})` : name;
|
|
22426
|
+
}
|
|
22427
|
+
function registerServer(state, name, definition, cache, prefix) {
|
|
22428
|
+
const lifecycleMode = definition.lifecycle ?? "lazy";
|
|
22429
|
+
const idleOverride = definition.idleTimeout ?? (lifecycleMode === "eager" ? 0 : undefined);
|
|
22430
|
+
state.lifecycle.registerServer(name, definition, idleOverride !== undefined ? { idleTimeout: idleOverride } : undefined);
|
|
22431
|
+
if (lifecycleMode === "keep-alive") {
|
|
22432
|
+
state.lifecycle.markKeepAlive(name, definition);
|
|
22433
|
+
}
|
|
22434
|
+
if (cache?.servers?.[name] && isServerCacheValid(cache.servers[name], definition)) {
|
|
22435
|
+
const metadata = reconstructToolMetadata(name, cache.servers[name], prefix, definition);
|
|
22436
|
+
state.toolMetadata.set(name, metadata);
|
|
22437
|
+
}
|
|
22438
|
+
}
|
|
22439
|
+
function startLifecycle(state) {
|
|
22440
|
+
state.lifecycle.setReconnectCallback((serverName) => {
|
|
22441
|
+
updateServerMetadata(state, serverName);
|
|
22442
|
+
updateMetadataCache(state, serverName);
|
|
22443
|
+
state.failureTracker.delete(serverName);
|
|
22444
|
+
updateStatusBar(state);
|
|
22445
|
+
});
|
|
22446
|
+
state.lifecycle.setIdleShutdownCallback((serverName) => {
|
|
22447
|
+
const idleMinutes = getEffectiveIdleTimeoutMinutes(state, serverName);
|
|
22448
|
+
logger.debug(`${serverName} shut down (idle ${idleMinutes}m)`);
|
|
22449
|
+
updateStatusBar(state);
|
|
22450
|
+
});
|
|
22451
|
+
state.lifecycle.startHealthChecks();
|
|
22452
|
+
}
|
|
22453
|
+
async function applyMcpConfigChanges(state, configPath, cwd, contributions) {
|
|
22454
|
+
const previous = state.config.mcpServers;
|
|
22455
|
+
const next = loadMcpConfig(configPath, cwd, contributions).mcpServers;
|
|
22456
|
+
const changed = [...new Set([...Object.keys(previous), ...Object.keys(next)])].filter((name) => JSON.stringify(previous[name]) !== JSON.stringify(next[name]));
|
|
22457
|
+
state.config = { ...state.config, mcpServers: next };
|
|
22458
|
+
state.contributedSources = getContributedServerSources(configPath, cwd, contributions);
|
|
22459
|
+
if (changed.length === 0)
|
|
22460
|
+
return changed;
|
|
22461
|
+
const cache = loadMetadataCache();
|
|
22462
|
+
const settings = state.config.settings;
|
|
22463
|
+
const prefix = settings?.toolPrefix ?? "server";
|
|
22464
|
+
state.lifecycle.setGlobalIdleTimeout(typeof settings?.idleTimeout === "number" ? settings.idleTimeout : 10);
|
|
22465
|
+
for (const name of changed) {
|
|
22466
|
+
await state.manager.close(name);
|
|
22467
|
+
state.lifecycle.unregisterServer(name);
|
|
22468
|
+
state.toolMetadata.delete(name);
|
|
22469
|
+
state.failureTracker.delete(name);
|
|
22470
|
+
const definition = next[name];
|
|
22471
|
+
if (definition)
|
|
22472
|
+
registerServer(state, name, definition, cache, prefix);
|
|
22473
|
+
}
|
|
22474
|
+
startLifecycle(state);
|
|
22475
|
+
updateStatusBar(state);
|
|
22476
|
+
return changed;
|
|
22477
|
+
}
|
|
22388
22478
|
function updateServerMetadata(state, serverName) {
|
|
22389
22479
|
const connection = state.manager.getConnection(serverName);
|
|
22390
22480
|
if (!connection || connection.status !== "connected")
|
|
@@ -23148,6 +23238,7 @@ function buildServerStates(config, cache, provenance, callbacks, authOnly, prefi
|
|
|
23148
23238
|
expanded: false,
|
|
23149
23239
|
source: prov?.kind ?? "user",
|
|
23150
23240
|
importKind: prov?.importKind,
|
|
23241
|
+
contributedBy: prov?.source,
|
|
23151
23242
|
excludeTools: definition.excludeTools,
|
|
23152
23243
|
exposeResources: definition.exposeResources !== false,
|
|
23153
23244
|
connectionStatus: callbacks.getConnectionStatus(serverName),
|
|
@@ -23323,7 +23414,8 @@ function renderServerRow(context, server, isCursor) {
|
|
|
23323
23414
|
const expandIcon = server.expanded ? "▾" : "▸";
|
|
23324
23415
|
const prefix = isCursor ? fg2(t.selected, expandIcon) : fg2(t.border, server.expanded ? expandIcon : "·");
|
|
23325
23416
|
const nameStr = isCursor ? bold(fg2(t.selected, server.name)) : server.name;
|
|
23326
|
-
const
|
|
23417
|
+
const originLabel = server.source === "import" ? ` (${server.importKind ?? "import"})` : server.source === "contributed" ? ` (${server.contributedBy ?? "contributed"})` : "";
|
|
23418
|
+
const importLabel = originLabel ? fg2(t.description, originLabel) : "";
|
|
23327
23419
|
const statusLabel = renderConnectionStatus(context, server);
|
|
23328
23420
|
if (!server.hasCachedData && !context.authOnly) {
|
|
23329
23421
|
return `${prefix} ${nameStr}${importLabel} ${fg2(t.description, "(not cached)")}${statusLabel}`;
|
|
@@ -23692,9 +23784,8 @@ class McpPanel {
|
|
|
23692
23784
|
if (item.toolIndex !== undefined) {
|
|
23693
23785
|
const tool = server.tools[item.toolIndex];
|
|
23694
23786
|
tool.isDirect = !tool.isDirect;
|
|
23695
|
-
if (tool.isDirect
|
|
23696
|
-
this.
|
|
23697
|
-
}
|
|
23787
|
+
if (tool.isDirect)
|
|
23788
|
+
this.noteCopyToUserConfig(server);
|
|
23698
23789
|
this.updateDirty();
|
|
23699
23790
|
}
|
|
23700
23791
|
}
|
|
@@ -23748,23 +23839,28 @@ class McpPanel {
|
|
|
23748
23839
|
this.tui.requestRender();
|
|
23749
23840
|
});
|
|
23750
23841
|
}
|
|
23842
|
+
noteCopyToUserConfig(server) {
|
|
23843
|
+
if (server.source === "import") {
|
|
23844
|
+
this.importNotice = `Imported from ${server.importKind ?? "external"} — will copy to user config on save`;
|
|
23845
|
+
} else if (server.source === "contributed") {
|
|
23846
|
+
this.importNotice = `Contributed by ${server.contributedBy ?? "a package"} — will copy to user config on save`;
|
|
23847
|
+
}
|
|
23848
|
+
}
|
|
23751
23849
|
toggleItem(item) {
|
|
23752
23850
|
if (this.authOnly)
|
|
23753
23851
|
return;
|
|
23754
23852
|
const server = this.servers[item.serverIndex];
|
|
23755
23853
|
if (item.type === "server") {
|
|
23756
23854
|
const newState = !server.tools.every((tool) => tool.isDirect);
|
|
23757
|
-
if (
|
|
23758
|
-
this.
|
|
23759
|
-
}
|
|
23855
|
+
if (newState)
|
|
23856
|
+
this.noteCopyToUserConfig(server);
|
|
23760
23857
|
for (const tool of server.tools)
|
|
23761
23858
|
tool.isDirect = newState;
|
|
23762
23859
|
} else if (item.toolIndex !== undefined) {
|
|
23763
23860
|
const tool = server.tools[item.toolIndex];
|
|
23764
23861
|
tool.isDirect = !tool.isDirect;
|
|
23765
|
-
if (tool.isDirect
|
|
23766
|
-
this.
|
|
23767
|
-
}
|
|
23862
|
+
if (tool.isDirect)
|
|
23863
|
+
this.noteCopyToUserConfig(server);
|
|
23768
23864
|
}
|
|
23769
23865
|
this.updateDirty();
|
|
23770
23866
|
}
|
|
@@ -23865,7 +23961,7 @@ async function showStatus(state, ctx) {
|
|
|
23865
23961
|
status = "cached";
|
|
23866
23962
|
}
|
|
23867
23963
|
const toolSuffix = failed ? "" : ` (${toolCount} tools${status === "cached" ? ", cached" : ""})`;
|
|
23868
|
-
lines.push(`${statusIcon} ${name}: ${status}${toolSuffix}`);
|
|
23964
|
+
lines.push(`${statusIcon} ${formatMcpServerName(state, name)}: ${status}${toolSuffix}`);
|
|
23869
23965
|
}
|
|
23870
23966
|
if (Object.keys(state.config.mcpServers).length === 0) {
|
|
23871
23967
|
lines.push("No MCP servers configured");
|
|
@@ -23925,7 +24021,7 @@ async function reconnectServers(state, ctx, targetServer) {
|
|
|
23925
24021
|
const message = error instanceof Error ? error.message : String(error);
|
|
23926
24022
|
state.failureTracker.set(name, Date.now());
|
|
23927
24023
|
if (ctx.hasUI) {
|
|
23928
|
-
ctx.ui.notify(`MCP: Failed to reconnect to ${name}: ${message}`, "error");
|
|
24024
|
+
ctx.ui.notify(`MCP: Failed to reconnect to ${formatMcpServerName(state, name)}: ${message}`, "error");
|
|
23929
24025
|
}
|
|
23930
24026
|
}
|
|
23931
24027
|
}
|
|
@@ -24091,7 +24187,7 @@ async function openMcpPanel(state, pi, ctx, configOverridePath) {
|
|
|
24091
24187
|
const config = state.config;
|
|
24092
24188
|
const cache = loadMetadataCache();
|
|
24093
24189
|
const configPath = pi.getFlag("mcp-config") ?? configOverridePath;
|
|
24094
|
-
const provenanceMap = getServerProvenance(configPath, ctx.cwd);
|
|
24190
|
+
const provenanceMap = getServerProvenance(configPath, ctx.cwd, pi.getMcpServerContributions?.() ?? []);
|
|
24095
24191
|
const { lines: noticeLines, fingerprint } = buildSharedConfigNoticeLines(configPath, ctx.cwd);
|
|
24096
24192
|
const callbacks = buildMcpPanelCallbacks(state, config, ctx);
|
|
24097
24193
|
await Promise.resolve().then(() => init_mcp_panel());
|
|
@@ -24125,7 +24221,7 @@ async function openMcpAuthPanel(state, pi, ctx, configOverridePath) {
|
|
|
24125
24221
|
}
|
|
24126
24222
|
const cache = loadMetadataCache();
|
|
24127
24223
|
const configPath = pi.getFlag("mcp-config") ?? configOverridePath;
|
|
24128
|
-
const provenanceMap = getServerProvenance(configPath, ctx.cwd);
|
|
24224
|
+
const provenanceMap = getServerProvenance(configPath, ctx.cwd, pi.getMcpServerContributions?.() ?? []);
|
|
24129
24225
|
const callbacks = buildMcpPanelCallbacks(state, config, ctx);
|
|
24130
24226
|
await Promise.resolve().then(() => init_mcp_panel());
|
|
24131
24227
|
await new Promise((resolve) => {
|
|
@@ -27076,13 +27172,29 @@ function mcpAdapter(pi) {
|
|
|
27076
27172
|
let renderConfig;
|
|
27077
27173
|
let initPromise = null;
|
|
27078
27174
|
let lifecycleGeneration = 0;
|
|
27079
|
-
let
|
|
27175
|
+
let registeredDirectTools = new Map;
|
|
27176
|
+
const retiredDirectToolNames = new Set;
|
|
27080
27177
|
let registeredProxyTool = false;
|
|
27081
27178
|
let startupWarmupCancel = null;
|
|
27082
27179
|
let activeSession = null;
|
|
27083
27180
|
let stateOwner = null;
|
|
27084
27181
|
const cleanupBarrier = new McpSessionCleanupBarrier;
|
|
27085
27182
|
const unpublishedCleanupFailures = [];
|
|
27183
|
+
let contributionRevision = 0;
|
|
27184
|
+
let contributionRefresh = Promise.resolve();
|
|
27185
|
+
const getContributions = () => pi.getMcpServerContributions?.() ?? [];
|
|
27186
|
+
const getConfigPath = () => pi.getFlag("mcp-config") ?? earlyConfigPath;
|
|
27187
|
+
function forgetDirectToolRegistrations() {
|
|
27188
|
+
registeredDirectTools = new Map([...registeredDirectTools.keys()].map((name) => [name, ""]));
|
|
27189
|
+
}
|
|
27190
|
+
function startsWithSession(server) {
|
|
27191
|
+
return server?.lifecycle === "eager" || server?.lifecycle === "keep-alive";
|
|
27192
|
+
}
|
|
27193
|
+
function registerProxyToolIfNeeded(config, directToolState) {
|
|
27194
|
+
if (config.settings?.disableProxyTool !== true || directToolState.directToolCount === 0 || directToolState.missingConfiguredDirectToolServers.length > 0) {
|
|
27195
|
+
registerProxyTool();
|
|
27196
|
+
}
|
|
27197
|
+
}
|
|
27086
27198
|
async function registerDirectToolsFromConfig(config, cache, subagentPolicy) {
|
|
27087
27199
|
const [{ resolveDirectTools, createDirectToolExecutor, getMissingConfiguredDirectToolServers }, { truncateAtWord }] = await Promise.all([
|
|
27088
27200
|
Promise.resolve().then(() => (init_direct_tools(), exports_direct_tools)),
|
|
@@ -27091,10 +27203,22 @@ function mcpAdapter(pi) {
|
|
|
27091
27203
|
const prefix = config.settings?.toolPrefix ?? "server";
|
|
27092
27204
|
const directTools = subagentPolicy?.mcpDirectTools;
|
|
27093
27205
|
const directSpecs = resolveDirectTools(config, cache, prefix, directTools === undefined ? undefined : [...directTools]);
|
|
27206
|
+
const resolvedNames = new Set(directSpecs.map((spec) => spec.prefixedName));
|
|
27207
|
+
const obsoleteNames = [...registeredDirectTools.keys()].filter((name) => !resolvedNames.has(name));
|
|
27208
|
+
const revivedNames = directSpecs.map((spec) => spec.prefixedName).filter((name) => retiredDirectToolNames.has(name));
|
|
27209
|
+
const activeNames = new Set(obsoleteNames.length > 0 ? pi.getActiveTools() : []);
|
|
27210
|
+
for (const name of obsoleteNames) {
|
|
27211
|
+
registeredDirectTools.delete(name);
|
|
27212
|
+
if (activeNames.has(name))
|
|
27213
|
+
retiredDirectToolNames.add(name);
|
|
27214
|
+
}
|
|
27215
|
+
for (const name of revivedNames)
|
|
27216
|
+
retiredDirectToolNames.delete(name);
|
|
27094
27217
|
for (const spec of directSpecs) {
|
|
27095
|
-
|
|
27218
|
+
const signature = JSON.stringify([spec.serverName, spec.originalName, spec.description, spec.inputSchema]);
|
|
27219
|
+
if (registeredDirectTools.get(spec.prefixedName) === signature)
|
|
27096
27220
|
continue;
|
|
27097
|
-
|
|
27221
|
+
registeredDirectTools.set(spec.prefixedName, signature);
|
|
27098
27222
|
pi.registerTool({
|
|
27099
27223
|
name: spec.prefixedName,
|
|
27100
27224
|
label: `MCP: ${spec.originalName}`,
|
|
@@ -27108,6 +27232,10 @@ function mcpAdapter(pi) {
|
|
|
27108
27232
|
}
|
|
27109
27233
|
const refreshTools = pi.refreshTools;
|
|
27110
27234
|
refreshTools?.();
|
|
27235
|
+
if (obsoleteNames.length > 0 || revivedNames.length > 0) {
|
|
27236
|
+
const obsolete = new Set(obsoleteNames);
|
|
27237
|
+
pi.setActiveTools([...pi.getActiveTools().filter((name) => !obsolete.has(name)), ...revivedNames]);
|
|
27238
|
+
}
|
|
27111
27239
|
return {
|
|
27112
27240
|
directToolCount: directSpecs.length,
|
|
27113
27241
|
missingConfiguredDirectToolServers: getMissingConfiguredDirectToolServers(config, cache, directTools)
|
|
@@ -27188,6 +27316,7 @@ function mcpAdapter(pi) {
|
|
|
27188
27316
|
throw new Error(`${STALE_INITIALIZATION_PREFIX} before startup`);
|
|
27189
27317
|
}
|
|
27190
27318
|
let candidate = null;
|
|
27319
|
+
const revision = contributionRevision;
|
|
27191
27320
|
try {
|
|
27192
27321
|
candidate = await initializeMcp(pi, session.ctx);
|
|
27193
27322
|
const initializedState = candidate;
|
|
@@ -27198,9 +27327,7 @@ function mcpAdapter(pi) {
|
|
|
27198
27327
|
if (!isCurrentSession(session) || initPromise !== expectedPromise.current) {
|
|
27199
27328
|
throw new Error(`${STALE_INITIALIZATION_PREFIX} after tool registration`);
|
|
27200
27329
|
}
|
|
27201
|
-
|
|
27202
|
-
registerProxyTool();
|
|
27203
|
-
}
|
|
27330
|
+
registerProxyToolIfNeeded(initializedState.config, directToolState);
|
|
27204
27331
|
updateStatusBar(initializedState);
|
|
27205
27332
|
let cancelWarmup = null;
|
|
27206
27333
|
const warmup = scheduleMcpStartupWarmup(initializedState, {
|
|
@@ -27222,6 +27349,8 @@ function mcpAdapter(pi) {
|
|
|
27222
27349
|
startupWarmupCancel = cancelWarmup;
|
|
27223
27350
|
stateOwner = session;
|
|
27224
27351
|
state = initializedState;
|
|
27352
|
+
if (revision !== contributionRevision)
|
|
27353
|
+
scheduleContributionRefresh(session);
|
|
27225
27354
|
return initializedState;
|
|
27226
27355
|
} catch (error) {
|
|
27227
27356
|
if (candidate && state !== candidate) {
|
|
@@ -27268,6 +27397,56 @@ function mcpAdapter(pi) {
|
|
|
27268
27397
|
});
|
|
27269
27398
|
return attempt;
|
|
27270
27399
|
}
|
|
27400
|
+
function scheduleContributionRefresh(session) {
|
|
27401
|
+
contributionRefresh = contributionRefresh.then(() => refreshContributedServers(session)).catch((error) => {
|
|
27402
|
+
if (!isCurrentSession(session) || isStaleExtensionContextError(error))
|
|
27403
|
+
return;
|
|
27404
|
+
if (!reportOwnedMcpLog("error"))
|
|
27405
|
+
console.error("MCP: failed to apply contributed MCP server changes", error);
|
|
27406
|
+
});
|
|
27407
|
+
}
|
|
27408
|
+
async function refreshContributedServers(session) {
|
|
27409
|
+
if (!isCurrentSession(session))
|
|
27410
|
+
return;
|
|
27411
|
+
const configPath = getConfigPath();
|
|
27412
|
+
const contributions = getContributions();
|
|
27413
|
+
const current = state;
|
|
27414
|
+
if (current && isOwnedState(current, session)) {
|
|
27415
|
+
await Promise.resolve().then(() => init_init());
|
|
27416
|
+
const changed = await applyMcpConfigChanges(current, configPath, session.ctx.cwd, contributions);
|
|
27417
|
+
renderConfig = current.config;
|
|
27418
|
+
if (!isOwnedState(current, session))
|
|
27419
|
+
return;
|
|
27420
|
+
registerProxyToolIfNeeded(current.config, await registerDirectTools(current, session.ctx.subagentPolicy));
|
|
27421
|
+
for (const name of changed) {
|
|
27422
|
+
if (!startsWithSession(current.config.mcpServers[name]))
|
|
27423
|
+
continue;
|
|
27424
|
+
lazyConnect(current, name).then(async (connected) => {
|
|
27425
|
+
if (!isOwnedState(current, session)) {
|
|
27426
|
+
await current.manager.close(name);
|
|
27427
|
+
} else if (connected) {
|
|
27428
|
+
registerProxyToolIfNeeded(current.config, await registerDirectTools(current, session.ctx.subagentPolicy));
|
|
27429
|
+
} else if (current.failureTracker.has(name)) {
|
|
27430
|
+
current.ui?.notify(`MCP: Failed to connect to ${formatMcpServerName(current, name)}`, "error");
|
|
27431
|
+
}
|
|
27432
|
+
}).catch(() => {
|
|
27433
|
+
return;
|
|
27434
|
+
});
|
|
27435
|
+
}
|
|
27436
|
+
return;
|
|
27437
|
+
}
|
|
27438
|
+
const config = loadMcpConfig(configPath, session.ctx.cwd, contributions);
|
|
27439
|
+
renderConfig = config;
|
|
27440
|
+
await Promise.resolve().then(() => init_metadata_cache());
|
|
27441
|
+
if (!isCurrentSession(session))
|
|
27442
|
+
return;
|
|
27443
|
+
registerProxyToolIfNeeded(config, await registerDirectToolsFromConfig(config, loadMetadataCache()));
|
|
27444
|
+
if (isCurrentSession(session) && !state && !initPromise && Object.values(config.mcpServers).some(startsWithSession)) {
|
|
27445
|
+
ensureMcpInitialized().catch(() => {
|
|
27446
|
+
return;
|
|
27447
|
+
});
|
|
27448
|
+
}
|
|
27449
|
+
}
|
|
27271
27450
|
pi.on("session_start", async (_event, ctx) => {
|
|
27272
27451
|
const generation = ++lifecycleGeneration;
|
|
27273
27452
|
const previousState = state;
|
|
@@ -27276,7 +27455,7 @@ function mcpAdapter(pi) {
|
|
|
27276
27455
|
renderConfig = undefined;
|
|
27277
27456
|
stateOwner = null;
|
|
27278
27457
|
initPromise = null;
|
|
27279
|
-
|
|
27458
|
+
forgetDirectToolRegistrations();
|
|
27280
27459
|
cancelStartupWarmup();
|
|
27281
27460
|
const previousStateCleanup = cleanupSessionResources(previousState, "session_restart", "MCP: failed to shut down previous session state");
|
|
27282
27461
|
const cleanup = cleanupBarrier.retain([retiredInitialization, previousStateCleanup]);
|
|
@@ -27284,8 +27463,9 @@ function mcpAdapter(pi) {
|
|
|
27284
27463
|
await cleanup;
|
|
27285
27464
|
if (!isStartCurrent())
|
|
27286
27465
|
return;
|
|
27466
|
+
const revision = contributionRevision;
|
|
27287
27467
|
try {
|
|
27288
|
-
const config = loadMcpConfig(earlyConfigPath, ctx.cwd);
|
|
27468
|
+
const config = loadMcpConfig(earlyConfigPath, ctx.cwd, getContributions());
|
|
27289
27469
|
await Promise.resolve().then(() => init_metadata_cache());
|
|
27290
27470
|
if (!isStartCurrent())
|
|
27291
27471
|
return;
|
|
@@ -27293,9 +27473,7 @@ function mcpAdapter(pi) {
|
|
|
27293
27473
|
const directToolState = await registerDirectToolsFromConfig(config, loadMetadataCache());
|
|
27294
27474
|
if (!isStartCurrent())
|
|
27295
27475
|
return;
|
|
27296
|
-
|
|
27297
|
-
registerProxyTool();
|
|
27298
|
-
}
|
|
27476
|
+
registerProxyToolIfNeeded(config, directToolState);
|
|
27299
27477
|
} catch (error) {
|
|
27300
27478
|
if (!isStartCurrent() || isStaleExtensionContextError(error))
|
|
27301
27479
|
return;
|
|
@@ -27305,12 +27483,20 @@ function mcpAdapter(pi) {
|
|
|
27305
27483
|
}
|
|
27306
27484
|
if (!isStartCurrent())
|
|
27307
27485
|
return;
|
|
27308
|
-
|
|
27309
|
-
|
|
27486
|
+
const session = { generation, ctx, cleanup };
|
|
27487
|
+
activeSession = session;
|
|
27488
|
+
if (ctx.hasUI || Object.values(renderConfig?.mcpServers ?? {}).some(startsWithSession)) {
|
|
27310
27489
|
ensureMcpInitialized().catch(() => {
|
|
27311
27490
|
return;
|
|
27312
27491
|
});
|
|
27313
27492
|
}
|
|
27493
|
+
if (revision !== contributionRevision)
|
|
27494
|
+
scheduleContributionRefresh(session);
|
|
27495
|
+
});
|
|
27496
|
+
pi.onMcpServerContributionsChanged?.(() => {
|
|
27497
|
+
contributionRevision++;
|
|
27498
|
+
if (activeSession)
|
|
27499
|
+
scheduleContributionRefresh(activeSession);
|
|
27314
27500
|
});
|
|
27315
27501
|
pi.on("session_shutdown", async () => {
|
|
27316
27502
|
++lifecycleGeneration;
|
|
@@ -27321,7 +27507,7 @@ function mcpAdapter(pi) {
|
|
|
27321
27507
|
renderConfig = undefined;
|
|
27322
27508
|
stateOwner = null;
|
|
27323
27509
|
initPromise = null;
|
|
27324
|
-
|
|
27510
|
+
forgetDirectToolRegistrations();
|
|
27325
27511
|
cancelStartupWarmup();
|
|
27326
27512
|
const stateCleanup = cleanupSessionResources(currentState, "session_shutdown", "MCP: session shutdown cleanup failed");
|
|
27327
27513
|
const failures = [];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/mcp",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.24-alpha.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension that adapts MCP (Model Context Protocol) servers into the coding agent. Fork of: https://github.com/nicobailon/pi-mcp-adapter",
|
|
6
6
|
"contributors": [
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.9.23] - 2026-09-27
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- `model: "auto"` routing no longer ignores benchmark results when fewer than four models are available. Each model's results are now ranked against every model in the evals catalog rather than only the models you can route to, so with just two or three models (for example Opus and Haiku) the stronger model is no longer outranked on price alone, and a model scores the same however many models are enabled.
|
|
10
|
+
|
|
5
11
|
## [0.9.23-alpha.1] - 2026-09-27
|
|
6
12
|
|
|
7
13
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/subagents",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.24-alpha.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension for delegating tasks to subagents with parallel execution. Fork of: https://github.com/nicobailon/pi-subagents",
|
|
6
6
|
"contributors": [
|