@fitchmultz/pi-mcp-adapter 7.1.0 → 7.1.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/dist/index.js CHANGED
@@ -15,7 +15,7 @@ import { createMcpRuntimeOwner, createOwnedUi, isAbortError } from "./runtime-ow
15
15
  import { publishMcpStatusShutdown } from "./mcp-status.js";
16
16
  import { DEFAULT_MCP_SCRIPT_TIMEOUT_MS, runMcpScript } from "./mcp-code.js";
17
17
  import { MAX_PAGE_SIZE, paginate, rankToolMatches } from "./search-ranking.js";
18
- import { createToolLoader, supportsNativeAsync } from "./tool-loader.js";
18
+ import { createToolLoader } from "./tool-loader.js";
19
19
  import { gatewayParameters, prepareGatewayArguments } from "./gateway-arguments.js";
20
20
  import { executeResourceList, executeResourceRead } from "./resource-tools.js";
21
21
  import { guardMcpOutput, guardedMcpDetails, readMcpResult, resolveMcpOutputGuardOptions } from "./mcp-output-guard.js";
@@ -95,7 +95,6 @@ function installMcpAdapter(pi, options) {
95
95
  const envDirectToolOverride = envRaw?.split(",").map(s => s.trim()).filter(Boolean);
96
96
  const toolLoader = createToolLoader(pi, () => state, () => initPromise, beforeExecute);
97
97
  let runtimeCwd;
98
- let nativeAsyncSupported = false;
99
98
  let proxyToolRegistered = false;
100
99
  let proxyToolDescription = null;
101
100
  let directToolsFrozen = false;
@@ -112,7 +111,7 @@ function installMcpAdapter(pi, options) {
112
111
  function syncToolSurface(ctx) {
113
112
  const config = state?.config ?? currentConfig;
114
113
  const cache = loadMetadataCache(state?.metadataCacheEnabled ?? false);
115
- toolLoader.sync(config, cache, envRaw === "__none__" ? null : envDirectToolOverride, nativeAsyncSupported, specs => syncGateways(config, cache, specs));
114
+ toolLoader.sync(config, cache, envRaw === "__none__" ? null : envDirectToolOverride, specs => syncGateways(config, cache, specs));
116
115
  }
117
116
  const registeredPromptCommands = new Set();
118
117
  function registerPromptCommands(specs) {
@@ -202,7 +201,6 @@ function installMcpAdapter(pi, options) {
202
201
  }
203
202
  async function startSession(ctx) {
204
203
  runtimeCwd = ctx.cwd;
205
- nativeAsyncSupported = supportsNativeAsync(ctx);
206
204
  directToolsFrozen = false;
207
205
  const generation = ++lifecycleGeneration;
208
206
  const previousState = state;
@@ -249,7 +247,7 @@ function installMcpAdapter(pi, options) {
249
247
  toolLoader.restore(ctx);
250
248
  registerPromptCommands(resolveCachedPrompts(runtimeConfig, metadataCacheEnabled));
251
249
  const runtimeCache = loadMetadataCache(metadataCacheEnabled);
252
- toolLoader.sync(runtimeConfig, runtimeCache, envRaw === "__none__" ? null : envDirectToolOverride, nativeAsyncSupported, specs => syncGateways(runtimeConfig, runtimeCache, specs));
250
+ toolLoader.sync(runtimeConfig, runtimeCache, envRaw === "__none__" ? null : envDirectToolOverride, specs => syncGateways(runtimeConfig, runtimeCache, specs));
253
251
  const initialization = startInitialization(ctx, owner, oauthRuntime, runtimeConfig, generation);
254
252
  if (envRaw !== undefined && envRaw !== "__none__") {
255
253
  const missingEnvDirectTools = getMissingConfiguredDirectToolServers(runtimeConfig, runtimeCache, envDirectToolOverride);
@@ -264,7 +262,6 @@ function installMcpAdapter(pi, options) {
264
262
  syncToolSurface(ctx);
265
263
  });
266
264
  pi.on("model_select", (_event, ctx) => {
267
- nativeAsyncSupported = supportsNativeAsync(ctx);
268
265
  if (state)
269
266
  syncToolSurface(ctx);
270
267
  });
@@ -519,7 +516,7 @@ function installMcpAdapter(pi, options) {
519
516
  owner?.throwIfInactive();
520
517
  return state ?? { content: [{ type: "text", text: "MCP not initialized" }], details: { error: "not_initialized" } };
521
518
  }
522
- const unavailableFeatures = (enable = [], tools) => enable.filter(feature => !tools.some(tool => tool.name === (feature === "gateway" ? "mcp" : "mcp_script") && !tool.namespace));
519
+ const unavailableFeatures = (enable = [], tools) => enable.filter(feature => !tools.some(tool => tool.name === (feature === "gateway" ? "mcp" : "mcp_script")));
523
520
  async function searchAndLoad(params, signal, ctx) {
524
521
  throwIfAborted(signal);
525
522
  if (params.query === undefined && !params.enable?.length)
@@ -544,7 +541,7 @@ function installMcpAdapter(pi, options) {
544
541
  const page = paginate(matches, params.offset ?? 0, params.limit ?? 5);
545
542
  const tools = toolLoader.activate(page.items, params.enable);
546
543
  const unavailable = unavailableFeatures(params.enable, tools);
547
- const typedCount = tools.filter(tool => tool.namespace || (tool.name !== "mcp" && tool.name !== "mcp_script")).length;
544
+ const typedCount = tools.filter(tool => tool.name !== "mcp" && tool.name !== "mcp_script").length;
548
545
  const result = executeSearch(ready, params.query, params.server, typedCount < page.items.length, params.limit ?? 5, params.offset, "mcp_search");
549
546
  const guarded = await guardMcpOutput([
550
547
  ...result.content,
@@ -574,10 +571,7 @@ function installMcpAdapter(pi, options) {
574
571
  return searchAndLoad(params, signal, ctx);
575
572
  },
576
573
  };
577
- if (toolLoader.native)
578
- pi.registerToolSearch(searchDefinition);
579
- else
580
- pi.registerTool(searchDefinition);
574
+ pi.registerTool(searchDefinition);
581
575
  let scriptToolRegistered = false;
582
576
  function registerScriptTool() {
583
577
  if (scriptToolRegistered)
@@ -691,7 +691,8 @@ export class McpServerManager {
691
691
  let client;
692
692
  client = new ManagedClient({ name: `pi-mcp-${serverName}`, version: ADAPTER_VERSION }, {
693
693
  versionNegotiation: { mode: definition.protocolVersion ?? (definition.url ? "auto" : "legacy") },
694
- listMaxPages: 0,
694
+ // ponytail: reject catalogs over 1024 pages; raise this native cap if a real catalog needs more.
695
+ listMaxPages: 1024,
695
696
  ...(Object.keys(capabilities).length > 0 ? { capabilities } : {}),
696
697
  listChanged: {
697
698
  tools: {
@@ -1,37 +1,22 @@
1
- import type { AgentToolResult, ExtensionAPI, ExtensionContext, ToolDefinition } from "@earendil-works/pi-coding-agent";
1
+ import type { ExtensionAPI, ExtensionContext, ToolDefinition } from "@earendil-works/pi-coding-agent";
2
2
  import { type TSchema } from "typebox";
3
3
  import { type MetadataCache } from "./metadata-cache.ts";
4
4
  import type { McpExtensionState } from "./state.ts";
5
5
  import { type DirectToolSpec, type McpAdapterOptions, type McpConfig, type ToolMetadata } from "./types.ts";
6
- type Reference = {
7
- name: string;
8
- namespace?: string;
9
- };
10
6
  export type Feature = "gateway" | "script";
11
7
  export type FeaturePolicy = Partial<Record<Feature, {
12
8
  eager?: boolean;
13
9
  }>>;
14
- type SearchDefinition<TParams extends TSchema, TDetails> = Omit<ToolDefinition<TParams, TDetails>, "execute"> & {
15
- execute: (...args: Parameters<ToolDefinition<TParams, TDetails>["execute"]>) => Promise<AgentToolResult<TDetails> & {
16
- tools: Reference[];
17
- }>;
18
- };
19
- export type SearchAPI = ExtensionAPI & {
20
- registerToolSearch?: <TParams extends TSchema, TDetails>(definition: SearchDefinition<TParams, TDetails>) => void;
21
- getActiveToolReferences?: () => Reference[];
22
- setActiveToolReferences?: (tools: Reference[]) => void;
23
- };
24
- export declare function supportsNativeAsync(ctx: ExtensionContext): boolean;
25
- export declare function createToolLoader(pi: SearchAPI, getState: () => McpExtensionState | null, getInitPromise: () => Promise<McpExtensionState> | null, beforeExecute?: McpAdapterOptions["beforeExecute"]): {
26
- native: boolean;
10
+ export declare function createToolLoader(pi: ExtensionAPI, getState: () => McpExtensionState | null, getInitPromise: () => Promise<McpExtensionState> | null, beforeExecute?: McpAdapterOptions["beforeExecute"]): {
27
11
  registerFeature: <TParams extends TSchema, TDetails>(feature: Feature, definition: ToolDefinition<TParams, TDetails>) => void;
28
12
  restore: (ctx: ExtensionContext) => void;
29
- sync: (config: McpConfig, cache: MetadataCache | null, env?: string[] | null, asyncSupported?: boolean, registerGateways?: (pins: DirectToolSpec[]) => FeaturePolicy) => DirectToolSpec[];
13
+ sync: (config: McpConfig, cache: MetadataCache | null, env?: string[] | null, registerGateways?: (pins: DirectToolSpec[]) => FeaturePolicy) => DirectToolSpec[];
30
14
  activate: (matches: Array<{
31
15
  server: string;
32
16
  tool: ToolMetadata;
33
- }>, enable?: Feature[]) => Reference[];
17
+ }>, enable?: Feature[]) => {
18
+ name: string;
19
+ }[];
34
20
  persist: () => void;
35
21
  selectedServers: () => string[];
36
22
  };
37
- export {};
@@ -4,21 +4,11 @@ import { isServerCacheValid, reconstructToolMetadata } from "./metadata-cache.js
4
4
  import { createMcpDirectToolCallRenderer, renderMcpToolResult } from "./tool-result-renderer.js";
5
5
  import { isServerDisabled } from "./types.js";
6
6
  import { normalizeDirectToolInputSchema } from "./utils.js";
7
- import { isToolCallApprovalRequired } from "./tool-approval.js";
8
- const featureRefs = { gateway: { name: "mcp" }, script: { name: "mcp_script" } };
7
+ const featureNames = { gateway: "mcp", script: "mcp_script" };
9
8
  const ENTRY = "mcp-tool-selection";
10
9
  const key = (value) => JSON.stringify([value.server, value.tool]);
11
- const refKey = (value) => JSON.stringify([value.namespace ?? null, value.name]);
12
10
  const reserved = new Set(["read", "bash", "powershell", "edit", "write", "grep", "find", "ls", "mcp", "mcp_search", "mcp_script"]);
13
- export function supportsNativeAsync(ctx) {
14
- const compat = ctx.model?.compat;
15
- return "getPendingToolCalls" in ctx && typeof ctx.getPendingToolCalls === "function"
16
- && !!compat && "supportsAsyncTools" in compat && compat.supportsAsyncTools === true;
17
- }
18
11
  export function createToolLoader(pi, getState, getInitPromise, beforeExecute) {
19
- const native = typeof pi.registerToolSearch === "function"
20
- && typeof pi.getActiveToolReferences === "function"
21
- && typeof pi.setActiveToolReferences === "function";
22
12
  pi.registerEntryRenderer(ENTRY, () => undefined);
23
13
  const registered = new Map();
24
14
  let available = new Set();
@@ -29,24 +19,21 @@ export function createToolLoader(pi, getState, getInitPromise, beforeExecute) {
29
19
  let inactiveFeatures = new Set();
30
20
  const registeredFeatures = new Set();
31
21
  let restoring = true;
32
- const active = () => native ? pi.getActiveToolReferences() : pi.getActiveTools().map(name => ({ name }));
33
- const setActive = (refs) => {
34
- const unique = [...new Map(refs.map(ref => [refKey(ref), ref])).values()];
22
+ const active = () => pi.getActiveTools();
23
+ const setActive = (names) => {
24
+ const unique = [...new Set(names)];
35
25
  if (JSON.stringify(active()) === JSON.stringify(unique))
36
26
  return;
37
- if (native)
38
- pi.setActiveToolReferences(unique);
39
- else
40
- pi.setActiveTools(unique.map(ref => ref.name));
27
+ pi.setActiveTools(unique);
41
28
  };
42
29
  function registerFeature(feature, definition) {
43
30
  pi.registerTool(definition);
44
31
  registeredFeatures.add(feature);
45
32
  }
46
33
  function capture() {
47
- const current = new Set(active().map(refKey));
34
+ const current = new Set(active());
48
35
  for (const feature of Object.keys(features)) {
49
- if (current.has(refKey(featureRefs[feature]))) {
36
+ if (current.has(featureNames[feature])) {
50
37
  if (!features[feature]?.eager)
51
38
  selectedFeatures.add(feature);
52
39
  inactiveFeatures.delete(feature);
@@ -57,10 +44,10 @@ export function createToolLoader(pi, getState, getInitPromise, beforeExecute) {
57
44
  inactiveFeatures.add(feature);
58
45
  }
59
46
  }
60
- for (const [id, { selection, ref, pinned }] of registered) {
47
+ for (const [id, { selection, name, pinned }] of registered) {
61
48
  if (!available.has(id))
62
49
  continue;
63
- if (current.has(refKey(ref))) {
50
+ if (current.has(name)) {
64
51
  if (!pinned)
65
52
  selected.set(id, selection);
66
53
  inactive.delete(id);
@@ -97,11 +84,11 @@ export function createToolLoader(pi, getState, getInitPromise, beforeExecute) {
97
84
  }
98
85
  restoring = true;
99
86
  }
100
- function sync(config, cache, env, asyncSupported = false, registerGateways) {
87
+ function sync(config, cache, env, registerGateways) {
101
88
  if (!restoring)
102
89
  capture();
103
- const previousRefs = new Set([...registered.values()].map(item => refKey(item.ref)));
104
- const existing = new Set(pi.getAllTools().map(tool => refKey(tool)));
90
+ const previousNames = new Set([...registered.values()].map(item => item.name));
91
+ const existing = new Set(pi.getAllTools().map(tool => tool.name));
105
92
  const specs = [];
106
93
  for (const [server, definition] of Object.entries(env === null ? {} : config.mcpServers)) {
107
94
  if (isServerDisabled(definition))
@@ -114,27 +101,26 @@ export function createToolLoader(pi, getState, getInitPromise, beforeExecute) {
114
101
  if (tool.resourceUri)
115
102
  continue;
116
103
  const pinned = selection === true || (Array.isArray(selection) && selection.includes(tool.originalName));
117
- const ref = native && !pinned ? { namespace: `mcp_${server}`, name: tool.originalName } : { name: prefixedName };
118
- specs.push({ spec: { ...tool, prefixedName, serverName: server }, selection: { server, tool: tool.originalName }, ref, pinned });
104
+ specs.push({ spec: { ...tool, prefixedName, serverName: server }, selection: { server, tool: tool.originalName }, name: prefixedName, pinned });
119
105
  }
120
106
  }
121
107
  const counts = new Map();
122
- for (const { ref } of specs)
123
- counts.set(refKey(ref), (counts.get(refKey(ref)) ?? 0) + 1);
108
+ for (const { name } of specs)
109
+ counts.set(name, (counts.get(name) ?? 0) + 1);
124
110
  available = new Set();
125
111
  const enabled = [];
126
- for (const { spec, selection, ref, pinned } of specs) {
112
+ for (const { spec, selection, name, pinned } of specs) {
127
113
  const id = key(selection);
128
- const refId = refKey(ref);
129
- if ((!ref.namespace && reserved.has(ref.name)) || counts.get(refId) > 1 || (existing.has(refId) && !previousRefs.has(refId)))
114
+ if (reserved.has(name) || counts.get(name) > 1 || (existing.has(name) && !previousNames.has(name)))
130
115
  continue;
131
116
  available.add(id);
132
- const asyncTool = asyncSupported && !beforeExecute && !spec.uiResourceUri && !isToolCallApprovalRequired(config, spec.serverName, spec);
133
- const fingerprint = JSON.stringify({ spec, ref, asyncTool });
117
+ const fingerprint = JSON.stringify({ spec, name });
134
118
  if (registered.get(id)?.fingerprint !== fingerprint) {
135
119
  pi.registerTool({
136
- ...ref,
137
- ...(asyncTool ? { async: true } : {}),
120
+ name,
121
+ namespace: { name: `mcp_${spec.serverName}` },
122
+ // Inactive direct tools are not callable through codemode or nested execution.
123
+ defaultActive: false,
138
124
  ...(beforeExecute ? { executionMode: "sequential" } : {}),
139
125
  label: spec.title ?? `MCP: ${spec.originalName}`,
140
126
  description: spec.description || "(no description)",
@@ -144,22 +130,22 @@ export function createToolLoader(pi, getState, getInitPromise, beforeExecute) {
144
130
  renderResult: renderMcpToolResult,
145
131
  });
146
132
  }
147
- registered.set(id, { selection, ref, fingerprint, pinned });
133
+ registered.set(id, { selection, name, fingerprint, pinned });
148
134
  if (selected.has(id) || (pinned && !inactive.has(id)))
149
- enabled.push(ref);
135
+ enabled.push(name);
150
136
  }
151
- const permitted = new Set(pi.getAllTools().map(refKey));
152
- const pins = specs.filter(item => item.pinned && available.has(key(item.selection)) && permitted.has(refKey(item.ref))).map(item => item.spec);
137
+ const permitted = new Set(pi.getAllTools().map(tool => tool.name));
138
+ const pins = specs.filter(item => item.pinned && available.has(key(item.selection)) && permitted.has(item.name)).map(item => item.spec);
153
139
  const policy = registerGateways?.(pins);
154
140
  if (policy) {
155
- const permittedFeatures = new Set(pi.getAllTools().map(refKey));
156
- const loaderMissing = !permittedFeatures.has(refKey({ name: "mcp_search" }));
141
+ const permittedFeatures = new Set(pi.getAllTools().map(tool => tool.name));
142
+ const loaderMissing = !permittedFeatures.has("mcp_search");
157
143
  features = {};
158
- for (const feature of Object.keys(featureRefs)) {
159
- if (policy[feature] && permittedFeatures.has(refKey(featureRefs[feature]))) {
144
+ for (const feature of Object.keys(featureNames)) {
145
+ if (policy[feature] && permittedFeatures.has(featureNames[feature])) {
160
146
  features[feature] = { eager: policy[feature].eager || loaderMissing };
161
147
  if (selectedFeatures.has(feature) || (features[feature]?.eager && !inactiveFeatures.has(feature)))
162
- enabled.push(featureRefs[feature]);
148
+ enabled.push(featureNames[feature]);
163
149
  }
164
150
  else {
165
151
  selectedFeatures.delete(feature);
@@ -168,10 +154,10 @@ export function createToolLoader(pi, getState, getInitPromise, beforeExecute) {
168
154
  }
169
155
  }
170
156
  // Official 0.87 reactivates allowlisted definitions on registration. Apply our loadout last.
171
- const ownedRefs = new Set([...previousRefs, ...[...registered.values()].map(item => refKey(item.ref))]);
157
+ const ownedNames = new Set([...previousNames, ...[...registered.values()].map(item => item.name)]);
172
158
  for (const feature of registeredFeatures)
173
- ownedRefs.add(refKey(featureRefs[feature]));
174
- setActive([...active().filter(ref => !ownedRefs.has(refKey(ref))), ...enabled]);
159
+ ownedNames.add(featureNames[feature]);
160
+ setActive([...active().filter(name => !ownedNames.has(name)), ...enabled]);
175
161
  restoring = false;
176
162
  return pins;
177
163
  }
@@ -182,22 +168,22 @@ export function createToolLoader(pi, getState, getInitPromise, beforeExecute) {
182
168
  return registration ? [registration] : [];
183
169
  });
184
170
  // No await between reading and extending the current loadout: parallel searches union their selections.
185
- const permitted = new Set(pi.getAllTools().map(refKey));
186
- const requestedFeatures = [...new Set(enable)].filter(feature => features[feature] && permitted.has(refKey(featureRefs[feature])));
187
- setActive([...active(), ...requested.map(item => item.ref), ...requestedFeatures.map(feature => featureRefs[feature])]);
188
- const current = new Set(active().map(refKey));
189
- const tools = requested.filter(item => current.has(refKey(item.ref))).map(({ selection, ref }) => {
171
+ const permitted = new Set(pi.getAllTools().map(tool => tool.name));
172
+ const requestedFeatures = [...new Set(enable)].filter(feature => features[feature] && permitted.has(featureNames[feature]));
173
+ setActive([...active(), ...requested.map(item => item.name), ...requestedFeatures.map(feature => featureNames[feature])]);
174
+ const current = new Set(active());
175
+ const tools = requested.filter(item => current.has(item.name)).map(({ selection, name }) => {
190
176
  selected.set(key(selection), selection);
191
- return ref;
177
+ return { name };
192
178
  });
193
179
  for (const feature of requestedFeatures) {
194
- if (!current.has(refKey(featureRefs[feature])))
180
+ if (!current.has(featureNames[feature]))
195
181
  continue;
196
182
  selectedFeatures.add(feature);
197
- tools.push(featureRefs[feature]);
183
+ tools.push({ name: featureNames[feature] });
198
184
  }
199
185
  persist();
200
186
  return tools;
201
187
  }
202
- return { native, registerFeature, restore, sync, activate, persist, selectedServers: () => [...new Set([...selected.values()].map(item => item.server))] };
188
+ return { registerFeature, restore, sync, activate, persist, selectedServers: () => [...new Set([...selected.values()].map(item => item.server))] };
203
189
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fitchmultz/pi-mcp-adapter",
3
- "version": "7.1.0",
3
+ "version": "7.1.1",
4
4
  "description": "Fitch's independently maintained MCP adapter for Pi coding agent",
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",
@@ -35,7 +35,7 @@
35
35
  "build:bridge": "node ./scripts/build-app-bridge.mjs",
36
36
  "prepare": "node ./scripts/prepare.mjs",
37
37
  "check:compat": "node scripts/compat-host.mjs && npm run build && npm run typecheck && vitest run --exclude __tests__/interactive-visualizer-server.test.ts && npm run test:oauth && node scripts/compat-package-smoke.mjs",
38
- "typecheck": "tsc --noEmit",
38
+ "typecheck": "node ./scripts/tsc.mjs --noEmit",
39
39
  "test": "vitest run && npm run test:oauth",
40
40
  "test:watch": "vitest",
41
41
  "test:oauth": "PI_MCP_ADAPTER_TEST_AUTH_STORE=memory node --test --test-concurrency=1 mcp-auth.test.ts mcp-auth-flow.test.ts mcp-callback-server.test.ts mcp-oauth-provider.test.ts",
@@ -76,9 +76,9 @@
76
76
  "LICENSE"
77
77
  ],
78
78
  "dependencies": {
79
- "@modelcontextprotocol/client": "2.1.0",
80
- "@modelcontextprotocol/core": "2.1.0",
81
- "@modelcontextprotocol/ext-apps": "2.0.0",
79
+ "@modelcontextprotocol/client": "2.2.0",
80
+ "@modelcontextprotocol/core": "2.2.0",
81
+ "@modelcontextprotocol/ext-apps": "2.0.3",
82
82
  "@napi-rs/keyring": "2.1.0",
83
83
  "cross-spawn": "7.0.6",
84
84
  "minisearch": "7.2.0",
@@ -108,16 +108,16 @@
108
108
  }
109
109
  },
110
110
  "devDependencies": {
111
- "@earendil-works/pi-ai": "0.87.1",
112
- "@earendil-works/pi-coding-agent": "0.87.1",
113
- "@earendil-works/pi-tui": "0.87.1",
114
- "@modelcontextprotocol/server": "2.1.0",
111
+ "@earendil-works/pi-ai": "0.99.2",
112
+ "@earendil-works/pi-coding-agent": "0.99.2",
113
+ "@earendil-works/pi-tui": "0.99.2",
114
+ "@modelcontextprotocol/server": "2.2.0",
115
115
  "@types/cross-spawn": "6.0.6",
116
116
  "@types/node": "24.19.0",
117
117
  "esbuild": "0.28.2",
118
- "typebox": "1.3.34",
118
+ "typebox": "1.3.27",
119
119
  "typescript": "7.0.2",
120
- "vitest": "5.0.2"
120
+ "vitest": "5.0.3"
121
121
  },
122
- "packageManager": "npm@12.1.0"
122
+ "packageManager": "npm@12.2.0"
123
123
  }