@bike4mind/cli 0.2.36-perf-6916-parallel-cli-init.20074 → 0.2.36-perf-6916-parallel-cli-init.20076

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.
@@ -3,7 +3,7 @@
3
3
  // package.json
4
4
  var package_default = {
5
5
  name: "@bike4mind/cli",
6
- version: "0.2.36-perf-6916-parallel-cli-init.20074+37c22b9d5",
6
+ version: "0.2.36-perf-6916-parallel-cli-init.20076+e20331ff9",
7
7
  type: "module",
8
8
  description: "Interactive CLI tool for Bike4Mind with ReAct agents",
9
9
  license: "UNLICENSED",
@@ -114,10 +114,10 @@ var package_default = {
114
114
  },
115
115
  devDependencies: {
116
116
  "@bike4mind/agents": "0.1.0",
117
- "@bike4mind/common": "2.57.1-perf-6916-parallel-cli-init.20074+37c22b9d5",
118
- "@bike4mind/mcp": "1.32.5-perf-6916-parallel-cli-init.20074+37c22b9d5",
119
- "@bike4mind/services": "2.54.1-perf-6916-parallel-cli-init.20074+37c22b9d5",
120
- "@bike4mind/utils": "2.10.1-perf-6916-parallel-cli-init.20074+37c22b9d5",
117
+ "@bike4mind/common": "2.57.1-perf-6916-parallel-cli-init.20076+e20331ff9",
118
+ "@bike4mind/mcp": "1.32.5-perf-6916-parallel-cli-init.20076+e20331ff9",
119
+ "@bike4mind/services": "2.54.1-perf-6916-parallel-cli-init.20076+e20331ff9",
120
+ "@bike4mind/utils": "2.10.1-perf-6916-parallel-cli-init.20076+e20331ff9",
121
121
  "@types/better-sqlite3": "^7.6.13",
122
122
  "@types/diff": "^5.0.9",
123
123
  "@types/jsonwebtoken": "^9.0.4",
@@ -138,7 +138,7 @@ var package_default = {
138
138
  optionalDependencies: {
139
139
  "@vscode/ripgrep": "^1.17.0"
140
140
  },
141
- gitHead: "37c22b9d55bf40cfc5b92f48d7c88e0195751172"
141
+ gitHead: "e20331ff98a10af0f0841179b1d0d4f4980b8620"
142
142
  };
143
143
 
144
144
  // src/utils/updateChecker.ts
@@ -15442,8 +15442,17 @@ var McpManager = class {
15442
15442
  this.connectionStates = /* @__PURE__ */ new Map();
15443
15443
  /** Per-server deferred promise resolved once the background connection is ready */
15444
15444
  this.connectionReady = /* @__PURE__ */ new Map();
15445
+ /**
15446
+ * Serializes background cache saves so concurrent writes don't race.
15447
+ * JSON.stringify is evaluated at run-time, always capturing the latest cache state.
15448
+ */
15449
+ this.backgroundSaveQueue = Promise.resolve();
15445
15450
  this.config = config;
15446
15451
  }
15452
+ /** Subscribe to background connection state changes for live UI updates. */
15453
+ setOnStateChange(callback) {
15454
+ this.onStateChange = callback;
15455
+ }
15447
15456
  /**
15448
15457
  * Initialize MCP servers with schema caching.
15449
15458
  *
@@ -15458,6 +15467,14 @@ var McpManager = class {
15458
15467
  }
15459
15468
  logger.debug(`\u{1F4E1} Initializing ${enabledServers.length} MCP server(s)...`);
15460
15469
  const cache = await this.loadCache();
15470
+ const configuredNames = new Set(this.config.mcpServers.map((s) => s.name));
15471
+ let pruned = false;
15472
+ for (const name of Object.keys(cache.servers)) {
15473
+ if (!configuredNames.has(name)) {
15474
+ delete cache.servers[name];
15475
+ pruned = true;
15476
+ }
15477
+ }
15461
15478
  const eagerConnections = [];
15462
15479
  for (const serverConfig of enabledServers) {
15463
15480
  const configHash = this.hashServerConfig(serverConfig);
@@ -15472,6 +15489,8 @@ var McpManager = class {
15472
15489
  if (eagerConnections.length > 0) {
15473
15490
  await Promise.allSettled(eagerConnections);
15474
15491
  await this.saveCache(cache);
15492
+ } else if (pruned) {
15493
+ await this.saveCache(cache);
15475
15494
  }
15476
15495
  const connected = [...this.connectionStates.values()].filter((s) => s === "connected").length;
15477
15496
  const pending = [...this.connectionStates.values()].filter((s) => s === "connecting").length;
@@ -15492,14 +15511,12 @@ var McpManager = class {
15492
15511
  resolveReady = res;
15493
15512
  rejectReady = rej;
15494
15513
  });
15514
+ promise.catch(() => {
15515
+ });
15495
15516
  this.connectionReady.set(serverConfig.name, { resolve: resolveReady, reject: rejectReady, promise });
15496
15517
  const callTool = async (name, args) => {
15497
15518
  await promise;
15498
- const instance = this.servers.get(serverConfig.name);
15499
- if (!instance?.client) {
15500
- throw new Error(`MCP server "${serverConfig.name}" failed to connect`);
15501
- }
15502
- return instance.client.callTool(name, args);
15519
+ return this.servers.get(serverConfig.name).client.callTool(name, args);
15503
15520
  };
15504
15521
  const tools = generateMcpToolsFromCache(serverConfig.name, entry.tools, callTool);
15505
15522
  this.servers.set(serverConfig.name, { name: serverConfig.name, client: null, tools });
@@ -15517,13 +15534,14 @@ var McpManager = class {
15517
15534
  }
15518
15535
  this.connectionStates.set(serverConfig.name, "connected");
15519
15536
  this.connectionReady.get(serverConfig.name)?.resolve();
15537
+ this.onStateChange?.();
15520
15538
  logger.debug(`\u2705 Background connection to ${serverConfig.name} established`);
15521
15539
  this.writeCacheEntry(cache, serverConfig, client.tools);
15522
- this.saveCache(cache).catch(() => {
15523
- });
15540
+ this.scheduleBackgroundSave(cache);
15524
15541
  }).catch((err) => {
15525
15542
  this.connectionStates.set(serverConfig.name, "failed");
15526
15543
  this.connectionReady.get(serverConfig.name)?.reject(err);
15544
+ this.onStateChange?.();
15527
15545
  logger.debug(`\u274C Background connection to ${serverConfig.name} failed: ${err}`);
15528
15546
  });
15529
15547
  }
@@ -15560,6 +15578,9 @@ var McpManager = class {
15560
15578
  const mcpData = {
15561
15579
  serverName: serverConfig.name,
15562
15580
  getTools: async () => client.tools,
15581
+ // any: generateMcpTools accepts a loose duck-type; MCPClient.callTool return type
15582
+ // doesn't match the internal interface exactly, but runtime behaviour is correct.
15583
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
15563
15584
  callTool: async (name, args) => client.callTool(name, args)
15564
15585
  };
15565
15586
  const tools = await generateMcpTools(mcpData);
@@ -15585,6 +15606,15 @@ var McpManager = class {
15585
15606
  logger.debug(`\u26A0\uFE0F Failed to save MCP schema cache: ${error}`);
15586
15607
  }
15587
15608
  }
15609
+ /**
15610
+ * Enqueue a background cache save. Saves are serialized so concurrent background
15611
+ * connections can't interleave writes and lose each other's entries. JSON.stringify
15612
+ * is evaluated when the queued write runs, so it always captures the latest state.
15613
+ */
15614
+ scheduleBackgroundSave(cache) {
15615
+ this.backgroundSaveQueue = this.backgroundSaveQueue.then(() => this.saveCache(cache)).catch(() => {
15616
+ });
15617
+ }
15588
15618
  writeCacheEntry(cache, serverConfig, rawTools) {
15589
15619
  cache.servers[serverConfig.name] = {
15590
15620
  configHash: this.hashServerConfig(serverConfig),
@@ -3,7 +3,7 @@ import {
3
3
  fetchLatestVersion,
4
4
  forceCheckForUpdate,
5
5
  package_default
6
- } from "../chunk-HDOEES53.js";
6
+ } from "../chunk-AVTI7WL7.js";
7
7
 
8
8
  // src/commands/doctorCommand.ts
9
9
  import { execSync } from "child_process";
@@ -36,7 +36,7 @@ import {
36
36
  isReadOnlyTool,
37
37
  loadContextFiles,
38
38
  setWebSocketToolExecutor
39
- } from "../chunk-GH6BFNIP.js";
39
+ } from "../chunk-BUHNUPZ7.js";
40
40
  import "../chunk-BDQBOLYG.js";
41
41
  import "../chunk-CWQT33O7.js";
42
42
  import "../chunk-GQGOWACU.js";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  forceCheckForUpdate,
4
4
  package_default
5
- } from "../chunk-HDOEES53.js";
5
+ } from "../chunk-AVTI7WL7.js";
6
6
 
7
7
  // src/commands/updateCommand.ts
8
8
  import { execSync } from "child_process";
package/dist/index.js CHANGED
@@ -46,7 +46,7 @@ import {
46
46
  setWebSocketToolExecutor,
47
47
  substituteArguments,
48
48
  warmFileCache
49
- } from "./chunk-GH6BFNIP.js";
49
+ } from "./chunk-BUHNUPZ7.js";
50
50
  import "./chunk-BDQBOLYG.js";
51
51
  import "./chunk-CWQT33O7.js";
52
52
  import "./chunk-GQGOWACU.js";
@@ -62,7 +62,7 @@ import {
62
62
  import {
63
63
  checkForUpdate,
64
64
  package_default
65
- } from "./chunk-HDOEES53.js";
65
+ } from "./chunk-AVTI7WL7.js";
66
66
  import {
67
67
  selectActiveBackgroundAgents,
68
68
  useCliStore
@@ -74,7 +74,7 @@ import {
74
74
  import "./chunk-4BIBE3J7.js";
75
75
 
76
76
  // src/index.tsx
77
- import React22, { useState as useState11, useEffect as useEffect7, useCallback as useCallback3, useRef as useRef3 } from "react";
77
+ import React22, { useState as useState11, useEffect as useEffect8, useCallback as useCallback3, useRef as useRef3 } from "react";
78
78
  import { render, Box as Box21, Text as Text21, useApp, useInput as useInput10 } from "ink";
79
79
  import { execSync } from "child_process";
80
80
  import { randomBytes } from "crypto";
@@ -84,7 +84,7 @@ import path2 from "path";
84
84
  import { v4 as uuidv42 } from "uuid";
85
85
 
86
86
  // src/components/App.tsx
87
- import React16, { useState as useState7, useEffect as useEffect5 } from "react";
87
+ import React16, { useState as useState7, useEffect as useEffect6 } from "react";
88
88
  import { Box as Box15, Text as Text15, Static, useInput as useInput7 } from "ink";
89
89
 
90
90
  // src/components/StatusBar.tsx
@@ -1471,9 +1471,16 @@ function ConfigEditor({ config, availableModels, onSave, onClose }) {
1471
1471
  }
1472
1472
 
1473
1473
  // src/components/McpViewer.tsx
1474
- import React13 from "react";
1474
+ import React13, { useEffect as useEffect5, useReducer } from "react";
1475
1475
  import { Box as Box12, Text as Text12, useInput as useInput6 } from "ink";
1476
1476
  function McpViewer({ config, mcpManager, onClose }) {
1477
+ const [, forceUpdate] = useReducer((x) => x + 1, 0);
1478
+ useEffect5(() => {
1479
+ if (!mcpManager) return;
1480
+ mcpManager.setOnStateChange(forceUpdate);
1481
+ return () => mcpManager.setOnStateChange(() => {
1482
+ });
1483
+ }, [mcpManager]);
1477
1484
  useInput6((input, key) => {
1478
1485
  if (key.escape || input === "q") {
1479
1486
  onClose();
@@ -1695,7 +1702,7 @@ function App({
1695
1702
  const setIsThinking = useCliStore((state) => state.setIsThinking);
1696
1703
  const pendingBackgroundTrigger = useCliStore((state) => state.pendingBackgroundTrigger);
1697
1704
  const setPendingBackgroundTrigger = useCliStore((state) => state.setPendingBackgroundTrigger);
1698
- useEffect5(() => {
1705
+ useEffect6(() => {
1699
1706
  if (pendingBackgroundTrigger && !isThinking && onBackgroundCompletion) {
1700
1707
  setPendingBackgroundTrigger(false);
1701
1708
  onBackgroundCompletion();
@@ -2003,7 +2010,7 @@ function SessionSelector({ sessions, currentSession, onSelect, onCancel }) {
2003
2010
  }
2004
2011
 
2005
2012
  // src/components/LoginFlow.tsx
2006
- import React21, { useState as useState10, useEffect as useEffect6 } from "react";
2013
+ import React21, { useState as useState10, useEffect as useEffect7 } from "react";
2007
2014
  import { Box as Box20, Text as Text20 } from "ink";
2008
2015
  import Spinner3 from "ink-spinner";
2009
2016
  import jwt from "jsonwebtoken";
@@ -2041,7 +2048,7 @@ function LoginFlow({ apiUrl = "http://localhost:3000", configStore, onSuccess, o
2041
2048
  const [deviceFlow, setDeviceFlow] = useState10(null);
2042
2049
  const [statusMessage, setStatusMessage] = useState10("Initiating device authorization...");
2043
2050
  const [error, setError] = useState10(null);
2044
- useEffect6(() => {
2051
+ useEffect7(() => {
2045
2052
  const runLoginFlow = async () => {
2046
2053
  const oauth = new OAuthClient(apiUrl);
2047
2054
  try {
@@ -2076,7 +2083,7 @@ function LoginFlow({ apiUrl = "http://localhost:3000", configStore, onSuccess, o
2076
2083
  };
2077
2084
  runLoginFlow();
2078
2085
  }, [apiUrl, configStore, onSuccess, onError]);
2079
- useEffect6(() => {
2086
+ useEffect7(() => {
2080
2087
  if (deviceFlow && status === "waiting") {
2081
2088
  open(deviceFlow.verification_uri_complete).catch((err) => {
2082
2089
  console.error("Failed to auto-open browser:", err);
@@ -3199,7 +3206,7 @@ function CliApp() {
3199
3206
  setStoreSession,
3200
3207
  setState
3201
3208
  ]);
3202
- useEffect7(() => {
3209
+ useEffect8(() => {
3203
3210
  init();
3204
3211
  }, [init]);
3205
3212
  const handleCustomCommandMessage = async (fullTemplate, displayMessage) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bike4mind/cli",
3
- "version": "0.2.36-perf-6916-parallel-cli-init.20074+37c22b9d5",
3
+ "version": "0.2.36-perf-6916-parallel-cli-init.20076+e20331ff9",
4
4
  "type": "module",
5
5
  "description": "Interactive CLI tool for Bike4Mind with ReAct agents",
6
6
  "license": "UNLICENSED",
@@ -111,10 +111,10 @@
111
111
  },
112
112
  "devDependencies": {
113
113
  "@bike4mind/agents": "0.1.0",
114
- "@bike4mind/common": "2.57.1-perf-6916-parallel-cli-init.20074+37c22b9d5",
115
- "@bike4mind/mcp": "1.32.5-perf-6916-parallel-cli-init.20074+37c22b9d5",
116
- "@bike4mind/services": "2.54.1-perf-6916-parallel-cli-init.20074+37c22b9d5",
117
- "@bike4mind/utils": "2.10.1-perf-6916-parallel-cli-init.20074+37c22b9d5",
114
+ "@bike4mind/common": "2.57.1-perf-6916-parallel-cli-init.20076+e20331ff9",
115
+ "@bike4mind/mcp": "1.32.5-perf-6916-parallel-cli-init.20076+e20331ff9",
116
+ "@bike4mind/services": "2.54.1-perf-6916-parallel-cli-init.20076+e20331ff9",
117
+ "@bike4mind/utils": "2.10.1-perf-6916-parallel-cli-init.20076+e20331ff9",
118
118
  "@types/better-sqlite3": "^7.6.13",
119
119
  "@types/diff": "^5.0.9",
120
120
  "@types/jsonwebtoken": "^9.0.4",
@@ -135,5 +135,5 @@
135
135
  "optionalDependencies": {
136
136
  "@vscode/ripgrep": "^1.17.0"
137
137
  },
138
- "gitHead": "37c22b9d55bf40cfc5b92f48d7c88e0195751172"
138
+ "gitHead": "e20331ff98a10af0f0841179b1d0d4f4980b8620"
139
139
  }