@bike4mind/cli 0.2.29-feat-session-permission.18841 → 0.2.29-feat-cli-websocket-streaming.18841

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.
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CurationArtifactType
4
- } from "./chunk-5GSDPBTM.js";
4
+ } from "./chunk-KPOK6V6E.js";
5
5
 
6
6
  // ../../b4m-core/packages/services/dist/src/notebookCurationService/artifactExtractor.js
7
7
  var ARTIFACT_TAG_REGEX = /<artifact\s+(.*?)>([\s\S]*?)<\/artifact>/gi;
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  BadRequestError,
4
4
  secureParameters
5
- } from "./chunk-S7BPPS33.js";
5
+ } from "./chunk-TY6Z2UV2.js";
6
6
  import {
7
7
  CompletionApiUsageTransaction,
8
8
  GenericCreditDeductTransaction,
@@ -12,7 +12,7 @@ import {
12
12
  TextGenerationUsageTransaction,
13
13
  TransferCreditTransaction,
14
14
  VideoGenerationUsageTransaction
15
- } from "./chunk-5GSDPBTM.js";
15
+ } from "./chunk-KPOK6V6E.js";
16
16
 
17
17
  // ../../b4m-core/packages/services/dist/src/creditService/subtractCredits.js
18
18
  import { z } from "zod";
@@ -7,11 +7,11 @@ import {
7
7
  getSettingsMap,
8
8
  getSettingsValue,
9
9
  secureParameters
10
- } from "./chunk-S7BPPS33.js";
10
+ } from "./chunk-TY6Z2UV2.js";
11
11
  import {
12
12
  KnowledgeType,
13
13
  SupportedFabFileMimeTypes
14
- } from "./chunk-5GSDPBTM.js";
14
+ } from "./chunk-KPOK6V6E.js";
15
15
 
16
16
  // ../../b4m-core/packages/services/dist/src/fabFileService/create.js
17
17
  import { z } from "zod";
@@ -1012,6 +1012,29 @@ var VoiceSessionSendTranscriptAction = z10.object({
1012
1012
  conversationItemId: z10.string(),
1013
1013
  timestamp: z10.coerce.date().optional()
1014
1014
  });
1015
+ var CliCompletionRequestAction = z10.object({
1016
+ action: z10.literal("cli_completion_request"),
1017
+ accessToken: z10.string(),
1018
+ requestId: z10.string().uuid(),
1019
+ model: z10.string(),
1020
+ messages: z10.array(z10.object({
1021
+ role: z10.enum(["user", "assistant", "system"]),
1022
+ content: z10.union([z10.string(), z10.array(z10.unknown())])
1023
+ })),
1024
+ options: z10.object({
1025
+ temperature: z10.number().optional(),
1026
+ maxTokens: z10.number().optional(),
1027
+ stream: z10.boolean().optional(),
1028
+ tools: z10.array(z10.unknown()).optional()
1029
+ }).optional()
1030
+ });
1031
+ var CliToolRequestAction = z10.object({
1032
+ action: z10.literal("cli_tool_request"),
1033
+ accessToken: z10.string(),
1034
+ requestId: z10.string().uuid(),
1035
+ toolName: z10.string(),
1036
+ input: z10.record(z10.unknown())
1037
+ });
1015
1038
  var VoiceSessionEndedAction = z10.object({
1016
1039
  action: z10.literal("voice_session_ended"),
1017
1040
  userId: z10.string(),
@@ -1258,6 +1281,36 @@ var ResearchModeStreamAction = z10.object({
1258
1281
  completionInfo: z10.any().optional()
1259
1282
  }).optional()
1260
1283
  });
1284
+ var CliCompletionChunkAction = z10.object({
1285
+ action: z10.literal("cli_completion_chunk"),
1286
+ requestId: z10.string(),
1287
+ chunk: z10.object({
1288
+ type: z10.enum(["content", "tool_use"]),
1289
+ text: z10.string(),
1290
+ tools: z10.array(z10.unknown()).optional(),
1291
+ usage: z10.object({
1292
+ inputTokens: z10.number().optional(),
1293
+ outputTokens: z10.number().optional()
1294
+ }).optional(),
1295
+ thinking: z10.array(z10.unknown()).optional()
1296
+ })
1297
+ });
1298
+ var CliCompletionDoneAction = z10.object({
1299
+ action: z10.literal("cli_completion_done"),
1300
+ requestId: z10.string()
1301
+ });
1302
+ var CliCompletionErrorAction = z10.object({
1303
+ action: z10.literal("cli_completion_error"),
1304
+ requestId: z10.string(),
1305
+ error: z10.string()
1306
+ });
1307
+ var CliToolResponseAction = z10.object({
1308
+ action: z10.literal("cli_tool_response"),
1309
+ requestId: z10.string(),
1310
+ success: z10.boolean(),
1311
+ content: z10.unknown().optional(),
1312
+ error: z10.string().optional()
1313
+ });
1261
1314
  var SessionCreatedAction = shareableDocumentSchema.extend({
1262
1315
  action: z10.literal("session.created"),
1263
1316
  id: z10.string(),
@@ -1292,7 +1345,9 @@ var MessageDataToServer = z10.discriminatedUnion("action", [
1292
1345
  DataUnsubscribeRequestAction,
1293
1346
  HeartbeatAction,
1294
1347
  VoiceSessionSendTranscriptAction,
1295
- VoiceSessionEndedAction
1348
+ VoiceSessionEndedAction,
1349
+ CliCompletionRequestAction,
1350
+ CliToolRequestAction
1296
1351
  ]);
1297
1352
  var MessageDataToClient = z10.discriminatedUnion("action", [
1298
1353
  DataSubscriptionUpdateAction,
@@ -1314,7 +1369,11 @@ var MessageDataToClient = z10.discriminatedUnion("action", [
1314
1369
  SpiderProgressUpdateAction,
1315
1370
  SpiderCompleteAction,
1316
1371
  SpiderErrorAction,
1317
- SessionCreatedAction
1372
+ SessionCreatedAction,
1373
+ CliCompletionChunkAction,
1374
+ CliCompletionDoneAction,
1375
+ CliCompletionErrorAction,
1376
+ CliToolResponseAction
1318
1377
  ]);
1319
1378
 
1320
1379
  // ../../b4m-core/packages/common/dist/src/schemas/cliCompletions.js
@@ -7926,6 +7985,8 @@ export {
7926
7985
  DataUnsubscribeRequestAction,
7927
7986
  HeartbeatAction,
7928
7987
  VoiceSessionSendTranscriptAction,
7988
+ CliCompletionRequestAction,
7989
+ CliToolRequestAction,
7929
7990
  VoiceSessionEndedAction,
7930
7991
  DataSubscriptionUpdateAction,
7931
7992
  LLMStatusUpdateAction,
@@ -7946,6 +8007,10 @@ export {
7946
8007
  UpdateResearchTaskStatusAction,
7947
8008
  ImportHistoryJobProgressUpdateAction,
7948
8009
  ResearchModeStreamAction,
8010
+ CliCompletionChunkAction,
8011
+ CliCompletionDoneAction,
8012
+ CliCompletionErrorAction,
8013
+ CliToolResponseAction,
7949
8014
  SessionCreatedAction,
7950
8015
  MessageDataToServer,
7951
8016
  MessageDataToClient,
@@ -6,12 +6,12 @@ import {
6
6
  getSettingsByNames,
7
7
  obfuscateApiKey,
8
8
  secureParameters
9
- } from "./chunk-S7BPPS33.js";
9
+ } from "./chunk-TY6Z2UV2.js";
10
10
  import {
11
11
  ApiKeyType,
12
12
  MementoTier,
13
13
  isSupportedEmbeddingModel
14
- } from "./chunk-5GSDPBTM.js";
14
+ } from "./chunk-KPOK6V6E.js";
15
15
 
16
16
  // ../../b4m-core/packages/services/dist/src/apiKeyService/get.js
17
17
  import { z } from "zod";
@@ -15,7 +15,7 @@ import {
15
15
  dayjsConfig_default,
16
16
  extractSnippetMeta,
17
17
  settingsMap
18
- } from "./chunk-5GSDPBTM.js";
18
+ } from "./chunk-KPOK6V6E.js";
19
19
  import {
20
20
  Logger
21
21
  } from "./chunk-OCYRD7D6.js";
@@ -2,9 +2,9 @@
2
2
  import {
3
3
  createFabFile,
4
4
  createFabFileSchema
5
- } from "./chunk-ELTTBWAQ.js";
6
- import "./chunk-S7BPPS33.js";
7
- import "./chunk-5GSDPBTM.js";
5
+ } from "./chunk-EC2VEDD2.js";
6
+ import "./chunk-TY6Z2UV2.js";
7
+ import "./chunk-KPOK6V6E.js";
8
8
  import "./chunk-OCYRD7D6.js";
9
9
  export {
10
10
  createFabFile,
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  getEffectiveApiKey,
6
6
  getOpenWeatherKey,
7
7
  getSerperKey
8
- } from "./chunk-BCOGDPUB.js";
8
+ } from "./chunk-QQL3OBKL.js";
9
9
  import {
10
10
  ConfigStore,
11
11
  logger
@@ -14,8 +14,8 @@ import {
14
14
  selectActiveBackgroundAgents,
15
15
  useCliStore
16
16
  } from "./chunk-TVW4ZESU.js";
17
- import "./chunk-PKKJ44C5.js";
18
- import "./chunk-ELTTBWAQ.js";
17
+ import "./chunk-BXCARBUQ.js";
18
+ import "./chunk-EC2VEDD2.js";
19
19
  import {
20
20
  BFLImageService,
21
21
  BaseStorage,
@@ -27,7 +27,7 @@ import {
27
27
  OpenAIBackend,
28
28
  OpenAIImageService,
29
29
  XAIImageService
30
- } from "./chunk-S7BPPS33.js";
30
+ } from "./chunk-TY6Z2UV2.js";
31
31
  import {
32
32
  AiEvents,
33
33
  ApiKeyEvents,
@@ -83,7 +83,7 @@ import {
83
83
  XAI_IMAGE_MODELS,
84
84
  b4mLLMTools,
85
85
  getMcpProviderMetadata
86
- } from "./chunk-5GSDPBTM.js";
86
+ } from "./chunk-KPOK6V6E.js";
87
87
  import {
88
88
  Logger
89
89
  } from "./chunk-OCYRD7D6.js";
@@ -93,7 +93,7 @@ import React21, { useState as useState9, useEffect as useEffect6, useCallback as
93
93
  import { render, Box as Box20, Text as Text20, useApp, useInput as useInput9 } from "ink";
94
94
  import { execSync } from "child_process";
95
95
  import { randomBytes as randomBytes5 } from "crypto";
96
- import { v4 as uuidv411 } from "uuid";
96
+ import { v4 as uuidv413 } from "uuid";
97
97
 
98
98
  // src/components/App.tsx
99
99
  import React15, { useState as useState5, useEffect as useEffect4 } from "react";
@@ -1260,12 +1260,10 @@ function PermissionPrompt({
1260
1260
  }) {
1261
1261
  const items = canBeTrusted ? [
1262
1262
  { label: "\u2713 Allow once", value: "allow-once" },
1263
- { label: "\u2713 Allow for this session", value: "allow-session" },
1264
1263
  { label: "\u2713 Always allow (trust this tool)", value: "allow-always" },
1265
1264
  { label: "\u2717 Deny", value: "deny" }
1266
1265
  ] : [
1267
1266
  { label: "\u2713 Allow once", value: "allow-once" },
1268
- { label: "\u2713 Allow for this session", value: "allow-session" },
1269
1267
  { label: "\u2717 Deny", value: "deny" }
1270
1268
  ];
1271
1269
  const [selectedIndex, setSelectedIndex] = useState3(0);
@@ -11440,6 +11438,10 @@ var ServerToolExecutor = class {
11440
11438
  };
11441
11439
 
11442
11440
  // src/llm/ToolRouter.ts
11441
+ var wsToolExecutor = null;
11442
+ function setWebSocketToolExecutor(executor) {
11443
+ wsToolExecutor = executor;
11444
+ }
11443
11445
  var SERVER_TOOLS = ["weather_info", "web_search", "web_fetch"];
11444
11446
  var LOCAL_TOOLS = [
11445
11447
  "file_read",
@@ -11462,7 +11464,15 @@ function isLocalTool(toolName) {
11462
11464
  }
11463
11465
  async function executeTool(toolName, input, apiClient, localToolFn) {
11464
11466
  if (isServerTool(toolName)) {
11465
- logger.debug(`[ToolRouter] Routing ${toolName} to server`);
11467
+ if (wsToolExecutor) {
11468
+ logger.debug(`[ToolRouter] Routing ${toolName} to server via WebSocket`);
11469
+ const result = await wsToolExecutor.execute(toolName, input);
11470
+ if (!result.success) {
11471
+ return `Error executing ${toolName}: ${result.error || "Tool execution failed"}`;
11472
+ }
11473
+ return typeof result.content === "string" ? result.content : JSON.stringify(result.content ?? "");
11474
+ }
11475
+ logger.debug(`[ToolRouter] Routing ${toolName} to server via HTTP`);
11466
11476
  const executor = new ServerToolExecutor(apiClient);
11467
11477
  return await executor.executeTool(toolName, input);
11468
11478
  } else if (isLocalTool(toolName)) {
@@ -11766,9 +11776,6 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
11766
11776
  if (response.action === "deny") {
11767
11777
  throw new PermissionDeniedError(toolName, args);
11768
11778
  }
11769
- if (response.action === "allow-session") {
11770
- permissionManager.trustToolForSession(toolName);
11771
- }
11772
11779
  if (response.action === "allow-always") {
11773
11780
  const canTrust = permissionManager.trustTool(toolName);
11774
11781
  if (canTrust) {
@@ -11973,7 +11980,6 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
11973
11980
  var PermissionManager = class {
11974
11981
  constructor(trustedTools = [], customCategories, deniedTools) {
11975
11982
  this.trustedTools = /* @__PURE__ */ new Set();
11976
- this.sessionTrustedTools = /* @__PURE__ */ new Set();
11977
11983
  this.deniedTools = /* @__PURE__ */ new Set();
11978
11984
  this.trustedTools = new Set(trustedTools);
11979
11985
  this.customCategories = new Map(Object.entries(customCategories || {}));
@@ -11999,9 +12005,6 @@ var PermissionManager = class {
11999
12005
  if (category === "auto_approve") {
12000
12006
  return false;
12001
12007
  }
12002
- if (this.sessionTrustedTools.has(toolName)) {
12003
- return false;
12004
- }
12005
12008
  if (category === "prompt_always") {
12006
12009
  return true;
12007
12010
  }
@@ -12069,29 +12072,6 @@ var PermissionManager = class {
12069
12072
  getDeniedTools() {
12070
12073
  return Array.from(this.deniedTools).sort();
12071
12074
  }
12072
- /**
12073
- * Trust a tool for the current session only (in-memory, no persistence)
12074
- * Works for all tool categories including prompt_always, but NOT project-denied tools
12075
- */
12076
- trustToolForSession(toolName) {
12077
- if (this.deniedTools.has(toolName)) {
12078
- return false;
12079
- }
12080
- this.sessionTrustedTools.add(toolName);
12081
- return true;
12082
- }
12083
- /**
12084
- * Check if a tool is trusted for the current session
12085
- */
12086
- isSessionTrusted(toolName) {
12087
- return this.sessionTrustedTools.has(toolName);
12088
- }
12089
- /**
12090
- * Clear all session-scoped trust (called on exit or session reset)
12091
- */
12092
- clearSessionTrust() {
12093
- this.sessionTrustedTools.clear();
12094
- }
12095
12075
  /**
12096
12076
  * Clear all trusted tools
12097
12077
  */
@@ -13422,6 +13402,186 @@ var ServerLlmBackend = class {
13422
13402
  }
13423
13403
  };
13424
13404
 
13405
+ // src/llm/WebSocketLlmBackend.ts
13406
+ import { v4 as uuidv411 } from "uuid";
13407
+ function stripThinkingBlocks2(text) {
13408
+ return text.replace(/<think>[\s\S]*?<\/think>/g, "").trim();
13409
+ }
13410
+ var WebSocketLlmBackend = class {
13411
+ constructor(options) {
13412
+ this.wsManager = options.wsManager;
13413
+ this.apiClient = options.apiClient;
13414
+ this.currentModel = options.model;
13415
+ this.tokenGetter = options.tokenGetter;
13416
+ }
13417
+ /**
13418
+ * Make LLM completion request via WebSocket.
13419
+ * Mirrors ServerLlmBackend accumulation logic — collects all chunks,
13420
+ * calls callback once at completion with full accumulated content.
13421
+ */
13422
+ async complete(model, messages, options, callback) {
13423
+ logger.debug(`[WebSocketLlmBackend] Starting complete() with model: ${model}`);
13424
+ if (options.abortSignal?.aborted) {
13425
+ logger.debug("[WebSocketLlmBackend] Request aborted before start");
13426
+ return;
13427
+ }
13428
+ if (!this.wsManager.isConnected) {
13429
+ throw new Error("WebSocket is not connected");
13430
+ }
13431
+ const requestId = uuidv411();
13432
+ const token = await this.tokenGetter();
13433
+ if (!token) {
13434
+ throw new Error("No access token available");
13435
+ }
13436
+ return new Promise((resolve3, reject) => {
13437
+ const isVerbose = process.env.B4M_VERBOSE === "1";
13438
+ const isUltraVerbose = process.env.B4M_DEBUG_STREAM === "1";
13439
+ const streamLogger = new StreamLogger(logger, "WebSocketLlmBackend", isVerbose, isUltraVerbose);
13440
+ streamLogger.streamStart();
13441
+ let eventCount = 0;
13442
+ let accumulatedText = "";
13443
+ let lastUsageInfo = {};
13444
+ let toolsUsed = [];
13445
+ let thinkingBlocks = [];
13446
+ let settled = false;
13447
+ const cleanup = () => {
13448
+ this.wsManager.offRequest(requestId);
13449
+ };
13450
+ const settleResolve = () => {
13451
+ if (settled) return;
13452
+ settled = true;
13453
+ cleanup();
13454
+ resolve3();
13455
+ };
13456
+ const settleReject = (err) => {
13457
+ if (settled) return;
13458
+ settled = true;
13459
+ cleanup();
13460
+ reject(err);
13461
+ };
13462
+ if (options.abortSignal) {
13463
+ const abortHandler = () => {
13464
+ logger.debug("[WebSocketLlmBackend] Abort signal received");
13465
+ settleResolve();
13466
+ };
13467
+ if (options.abortSignal.aborted) {
13468
+ settleResolve();
13469
+ return;
13470
+ }
13471
+ options.abortSignal.addEventListener("abort", abortHandler, { once: true });
13472
+ }
13473
+ this.wsManager.onRequest(requestId, (message) => {
13474
+ if (options.abortSignal?.aborted) return;
13475
+ const action = message.action;
13476
+ if (action === "cli_completion_chunk") {
13477
+ eventCount++;
13478
+ const chunk = message.chunk;
13479
+ streamLogger.onEvent(eventCount, JSON.stringify(chunk));
13480
+ if (chunk.type === "content") {
13481
+ const textChunk = chunk.text || "";
13482
+ accumulatedText += textChunk;
13483
+ streamLogger.onContent(eventCount, textChunk, accumulatedText);
13484
+ if (chunk.usage) {
13485
+ lastUsageInfo = {
13486
+ inputTokens: chunk.usage.inputTokens,
13487
+ outputTokens: chunk.usage.outputTokens
13488
+ };
13489
+ }
13490
+ } else if (chunk.type === "tool_use") {
13491
+ streamLogger.onCriticalEvent(eventCount, "TOOL_USE", `tools: ${chunk.tools?.length}`);
13492
+ const textChunk = chunk.text || "";
13493
+ if (textChunk) accumulatedText += textChunk;
13494
+ if (chunk.tools && chunk.tools.length > 0) {
13495
+ toolsUsed = chunk.tools;
13496
+ }
13497
+ if (chunk.thinking && chunk.thinking.length > 0) {
13498
+ thinkingBlocks = chunk.thinking;
13499
+ }
13500
+ if (chunk.usage) {
13501
+ lastUsageInfo = {
13502
+ inputTokens: chunk.usage.inputTokens,
13503
+ outputTokens: chunk.usage.outputTokens
13504
+ };
13505
+ }
13506
+ }
13507
+ } else if (action === "cli_completion_done") {
13508
+ streamLogger.streamComplete(accumulatedText);
13509
+ const cleanedText = stripThinkingBlocks2(accumulatedText);
13510
+ if (toolsUsed.length > 0) {
13511
+ const info = {
13512
+ toolsUsed,
13513
+ thinking: thinkingBlocks.length > 0 ? thinkingBlocks : void 0,
13514
+ ...lastUsageInfo
13515
+ };
13516
+ callback([cleanedText], info).then(() => settleResolve()).catch((err) => settleReject(err));
13517
+ } else if (cleanedText) {
13518
+ callback([cleanedText], lastUsageInfo).then(() => settleResolve()).catch((err) => settleReject(err));
13519
+ } else {
13520
+ settleResolve();
13521
+ }
13522
+ } else if (action === "cli_completion_error") {
13523
+ const errorMsg = message.error || "Server error";
13524
+ streamLogger.onCriticalEvent(eventCount, "ERROR", errorMsg);
13525
+ settleReject(new Error(errorMsg));
13526
+ }
13527
+ });
13528
+ try {
13529
+ this.wsManager.send({
13530
+ action: "cli_completion_request",
13531
+ accessToken: token,
13532
+ requestId,
13533
+ model,
13534
+ messages,
13535
+ options: {
13536
+ temperature: options.temperature,
13537
+ maxTokens: options.maxTokens,
13538
+ stream: true,
13539
+ tools: options.tools || []
13540
+ }
13541
+ });
13542
+ } catch (err) {
13543
+ settleReject(err instanceof Error ? err : new Error(String(err)));
13544
+ }
13545
+ });
13546
+ }
13547
+ /**
13548
+ * Get available models from server (REST call, not streaming).
13549
+ * Delegates to ApiClient — same as ServerLlmBackend.
13550
+ */
13551
+ async getModelInfo() {
13552
+ try {
13553
+ logger.debug("[WebSocketLlmBackend] Fetching models from /api/models");
13554
+ const response = await this.apiClient.get("/api/models");
13555
+ if (!response || typeof response !== "object" || !Array.isArray(response.models)) {
13556
+ logger.warn("[WebSocketLlmBackend] Invalid API response format, using fallback models");
13557
+ return this.getFallbackModels();
13558
+ }
13559
+ const filteredModels = response.models.filter(
13560
+ (model) => model.type === "text" && model.supportsTools === true
13561
+ );
13562
+ if (filteredModels.length === 0) {
13563
+ logger.warn("[WebSocketLlmBackend] No CLI-compatible models found, using fallback");
13564
+ return this.getFallbackModels();
13565
+ }
13566
+ logger.debug(`[WebSocketLlmBackend] Loaded ${filteredModels.length} models`);
13567
+ return filteredModels;
13568
+ } catch (error) {
13569
+ logger.warn(
13570
+ `[WebSocketLlmBackend] Failed to fetch models: ${error instanceof Error ? error.message : String(error)}`
13571
+ );
13572
+ return this.getFallbackModels();
13573
+ }
13574
+ }
13575
+ getFallbackModels() {
13576
+ return [
13577
+ { id: "claude-sonnet-4-5-20250929", name: "Claude 4.5 Sonnet" },
13578
+ { id: "claude-3-5-haiku-20241022", name: "Claude 3.5 Haiku" },
13579
+ { id: "gpt-4o", name: "GPT-4o" },
13580
+ { id: "gpt-4o-mini", name: "GPT-4o Mini" }
13581
+ ];
13582
+ }
13583
+ };
13584
+
13425
13585
  // src/llm/NotifyingLlmBackend.ts
13426
13586
  var NotifyingLlmBackend = class {
13427
13587
  constructor(inner, backgroundManager) {
@@ -13456,6 +13616,223 @@ Please acknowledge these background agent results and incorporate them into your
13456
13616
  }
13457
13617
  };
13458
13618
 
13619
+ // src/ws/WebSocketConnectionManager.ts
13620
+ var WebSocketConnectionManager = class {
13621
+ constructor(wsUrl, getToken) {
13622
+ this.ws = null;
13623
+ this.heartbeatInterval = null;
13624
+ this.reconnectAttempts = 0;
13625
+ this.maxReconnectDelay = 3e4;
13626
+ this.handlers = /* @__PURE__ */ new Map();
13627
+ this.connected = false;
13628
+ this.connecting = false;
13629
+ this.closed = false;
13630
+ this.wsUrl = wsUrl;
13631
+ this.getToken = getToken;
13632
+ }
13633
+ /**
13634
+ * Connect to the WebSocket server.
13635
+ * Resolves when connection is established, rejects on failure.
13636
+ */
13637
+ async connect() {
13638
+ if (this.connected || this.connecting) return;
13639
+ this.connecting = true;
13640
+ const token = await this.getToken();
13641
+ if (!token) {
13642
+ this.connecting = false;
13643
+ throw new Error("No access token available for WebSocket connection");
13644
+ }
13645
+ return new Promise((resolve3, reject) => {
13646
+ const url = `${this.wsUrl}?token=${token}`;
13647
+ logger.debug(`[WS] Connecting to ${this.wsUrl}...`);
13648
+ this.ws = new WebSocket(url);
13649
+ this.ws.onopen = () => {
13650
+ logger.debug("[WS] Connected");
13651
+ this.connected = true;
13652
+ this.connecting = false;
13653
+ this.reconnectAttempts = 0;
13654
+ this.startHeartbeat();
13655
+ resolve3();
13656
+ };
13657
+ this.ws.onmessage = (event) => {
13658
+ try {
13659
+ const data = typeof event.data === "string" ? event.data : event.data.toString();
13660
+ const message = JSON.parse(data);
13661
+ const requestId = message.requestId;
13662
+ if (requestId && this.handlers.has(requestId)) {
13663
+ this.handlers.get(requestId)(message);
13664
+ } else {
13665
+ logger.debug(`[WS] Unhandled message: ${message.action || "unknown"}`);
13666
+ }
13667
+ } catch (err) {
13668
+ logger.debug(`[WS] Failed to parse message: ${err}`);
13669
+ }
13670
+ };
13671
+ this.ws.onclose = () => {
13672
+ logger.debug("[WS] Connection closed");
13673
+ this.cleanup();
13674
+ if (!this.closed) {
13675
+ this.scheduleReconnect();
13676
+ }
13677
+ };
13678
+ this.ws.onerror = (err) => {
13679
+ logger.debug(`[WS] Error: ${err}`);
13680
+ if (this.connecting) {
13681
+ this.connecting = false;
13682
+ this.connected = false;
13683
+ reject(new Error("WebSocket connection failed"));
13684
+ }
13685
+ };
13686
+ });
13687
+ }
13688
+ /** Whether the connection is currently established */
13689
+ get isConnected() {
13690
+ return this.connected;
13691
+ }
13692
+ /**
13693
+ * Send a JSON message over the WebSocket connection.
13694
+ */
13695
+ send(data) {
13696
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
13697
+ throw new Error("WebSocket is not connected");
13698
+ }
13699
+ this.ws.send(JSON.stringify(data));
13700
+ }
13701
+ /**
13702
+ * Register a handler for messages matching a specific requestId.
13703
+ */
13704
+ onRequest(requestId, handler) {
13705
+ this.handlers.set(requestId, handler);
13706
+ }
13707
+ /**
13708
+ * Remove a handler for a specific requestId.
13709
+ */
13710
+ offRequest(requestId) {
13711
+ this.handlers.delete(requestId);
13712
+ }
13713
+ /**
13714
+ * Close the connection and stop all heartbeat/reconnect logic.
13715
+ */
13716
+ disconnect() {
13717
+ this.closed = true;
13718
+ this.cleanup();
13719
+ if (this.ws) {
13720
+ this.ws.close();
13721
+ this.ws = null;
13722
+ }
13723
+ this.handlers.clear();
13724
+ }
13725
+ startHeartbeat() {
13726
+ this.stopHeartbeat();
13727
+ this.heartbeatInterval = setInterval(
13728
+ () => {
13729
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
13730
+ this.ws.send(JSON.stringify({ action: "heartbeat" }));
13731
+ logger.debug("[WS] Heartbeat sent");
13732
+ }
13733
+ },
13734
+ 5 * 60 * 1e3
13735
+ );
13736
+ }
13737
+ stopHeartbeat() {
13738
+ if (this.heartbeatInterval) {
13739
+ clearInterval(this.heartbeatInterval);
13740
+ this.heartbeatInterval = null;
13741
+ }
13742
+ }
13743
+ cleanup() {
13744
+ this.connected = false;
13745
+ this.connecting = false;
13746
+ this.stopHeartbeat();
13747
+ }
13748
+ scheduleReconnect() {
13749
+ if (this.closed) return;
13750
+ this.reconnectAttempts++;
13751
+ const delay = Math.min(1e3 * Math.pow(2, this.reconnectAttempts - 1), this.maxReconnectDelay);
13752
+ logger.debug(`[WS] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);
13753
+ setTimeout(async () => {
13754
+ if (this.closed) return;
13755
+ try {
13756
+ await this.connect();
13757
+ } catch {
13758
+ logger.debug("[WS] Reconnection failed");
13759
+ }
13760
+ }, delay);
13761
+ }
13762
+ };
13763
+
13764
+ // src/ws/WebSocketToolExecutor.ts
13765
+ import { v4 as uuidv412 } from "uuid";
13766
+ var WebSocketToolExecutor = class {
13767
+ constructor(wsManager, tokenGetter) {
13768
+ this.wsManager = wsManager;
13769
+ this.tokenGetter = tokenGetter;
13770
+ }
13771
+ /**
13772
+ * Execute a server-side tool via WebSocket.
13773
+ * Returns the tool result or throws on error.
13774
+ */
13775
+ async execute(toolName, input, abortSignal) {
13776
+ if (!this.wsManager.isConnected) {
13777
+ throw new Error("WebSocket is not connected");
13778
+ }
13779
+ const token = await this.tokenGetter();
13780
+ if (!token) {
13781
+ throw new Error("No access token available");
13782
+ }
13783
+ const requestId = uuidv412();
13784
+ return new Promise((resolve3, reject) => {
13785
+ let settled = false;
13786
+ const cleanup = () => {
13787
+ this.wsManager.offRequest(requestId);
13788
+ };
13789
+ const settleResolve = (result) => {
13790
+ if (settled) return;
13791
+ settled = true;
13792
+ cleanup();
13793
+ resolve3(result);
13794
+ };
13795
+ const settleReject = (err) => {
13796
+ if (settled) return;
13797
+ settled = true;
13798
+ cleanup();
13799
+ reject(err);
13800
+ };
13801
+ if (abortSignal) {
13802
+ const abortHandler = () => {
13803
+ settleReject(new Error("Tool execution aborted"));
13804
+ };
13805
+ if (abortSignal.aborted) {
13806
+ settleReject(new Error("Tool execution aborted"));
13807
+ return;
13808
+ }
13809
+ abortSignal.addEventListener("abort", abortHandler, { once: true });
13810
+ }
13811
+ this.wsManager.onRequest(requestId, (message) => {
13812
+ const action = message.action;
13813
+ if (action === "cli_tool_response") {
13814
+ settleResolve({
13815
+ success: message.success,
13816
+ content: message.content,
13817
+ error: message.error
13818
+ });
13819
+ }
13820
+ });
13821
+ try {
13822
+ this.wsManager.send({
13823
+ action: "cli_tool_request",
13824
+ accessToken: token,
13825
+ requestId,
13826
+ toolName,
13827
+ input
13828
+ });
13829
+ } catch (err) {
13830
+ settleReject(err instanceof Error ? err : new Error(String(err)));
13831
+ }
13832
+ });
13833
+ }
13834
+ };
13835
+
13459
13836
  // src/auth/ApiClient.ts
13460
13837
  import axios11 from "axios";
13461
13838
  var ApiClient = class {
@@ -13593,7 +13970,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
13593
13970
  // package.json
13594
13971
  var package_default = {
13595
13972
  name: "@bike4mind/cli",
13596
- version: "0.2.29-feat-session-permission.18841+6d9c4deb5",
13973
+ version: "0.2.29-feat-cli-websocket-streaming.18841+5c940d031",
13597
13974
  type: "module",
13598
13975
  description: "Interactive CLI tool for Bike4Mind with ReAct agents",
13599
13976
  license: "UNLICENSED",
@@ -13703,10 +14080,10 @@ var package_default = {
13703
14080
  },
13704
14081
  devDependencies: {
13705
14082
  "@bike4mind/agents": "0.1.0",
13706
- "@bike4mind/common": "2.50.1-feat-session-permission.18841+6d9c4deb5",
13707
- "@bike4mind/mcp": "1.29.1-feat-session-permission.18841+6d9c4deb5",
13708
- "@bike4mind/services": "2.48.1-feat-session-permission.18841+6d9c4deb5",
13709
- "@bike4mind/utils": "2.5.1-feat-session-permission.18841+6d9c4deb5",
14083
+ "@bike4mind/common": "2.50.1-feat-cli-websocket-streaming.18841+5c940d031",
14084
+ "@bike4mind/mcp": "1.29.1-feat-cli-websocket-streaming.18841+5c940d031",
14085
+ "@bike4mind/services": "2.48.1-feat-cli-websocket-streaming.18841+5c940d031",
14086
+ "@bike4mind/utils": "2.5.1-feat-cli-websocket-streaming.18841+5c940d031",
13710
14087
  "@types/better-sqlite3": "^7.6.13",
13711
14088
  "@types/diff": "^5.0.9",
13712
14089
  "@types/jsonwebtoken": "^9.0.4",
@@ -13723,7 +14100,7 @@ var package_default = {
13723
14100
  optionalDependencies: {
13724
14101
  "@vscode/ripgrep": "^1.17.0"
13725
14102
  },
13726
- gitHead: "6d9c4deb5a83cfc1087043d22f407d3444a91cca"
14103
+ gitHead: "5c940d031610617c76d3c12cc611b71db8bb4caf"
13727
14104
  };
13728
14105
 
13729
14106
  // src/config/constants.ts
@@ -15531,7 +15908,8 @@ function CliApp() {
15531
15908
  agentStore: null,
15532
15909
  abortController: null,
15533
15910
  contextContent: "",
15534
- backgroundManager: null
15911
+ backgroundManager: null,
15912
+ wsManager: null
15535
15913
  });
15536
15914
  const [isInitialized, setIsInitialized] = useState9(false);
15537
15915
  const [initError, setInitError] = useState9(null);
@@ -15559,6 +15937,10 @@ function CliApp() {
15559
15937
  })
15560
15938
  );
15561
15939
  }
15940
+ if (state.wsManager) {
15941
+ state.wsManager.disconnect();
15942
+ setWebSocketToolExecutor(null);
15943
+ }
15562
15944
  if (state.agent) {
15563
15945
  state.agent.removeAllListeners();
15564
15946
  }
@@ -15577,7 +15959,7 @@ function CliApp() {
15577
15959
  setTimeout(() => {
15578
15960
  process.exit(0);
15579
15961
  }, 100);
15580
- }, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore]);
15962
+ }, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore, state.wsManager]);
15581
15963
  useInput9((input, key) => {
15582
15964
  if (key.escape) {
15583
15965
  if (state.abortController) {
@@ -15647,7 +16029,7 @@ function CliApp() {
15647
16029
  if (!isAuthenticated) {
15648
16030
  console.log("\u2139\uFE0F AI features disabled. Available commands: /login, /help, /config\n");
15649
16031
  const minimalSession = {
15650
- id: uuidv411(),
16032
+ id: uuidv413(),
15651
16033
  name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
15652
16034
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
15653
16035
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -15675,10 +16057,41 @@ function CliApp() {
15675
16057
  console.log(`\u{1F30D} API Environment: ${envName} (${apiBaseURL})`);
15676
16058
  }
15677
16059
  const apiClient = new ApiClient(apiBaseURL, state.configStore);
15678
- const llm = new ServerLlmBackend({
15679
- apiClient,
15680
- model: config.defaultModel
15681
- });
16060
+ const tokenGetter = async () => {
16061
+ const tokens = await state.configStore.getAuthTokens();
16062
+ return tokens?.accessToken ?? null;
16063
+ };
16064
+ let wsManager = null;
16065
+ let llm;
16066
+ try {
16067
+ const serverConfig = await apiClient.get("/api/settings/serverConfig");
16068
+ const wsUrl = serverConfig?.websocketUrl;
16069
+ if (wsUrl) {
16070
+ wsManager = new WebSocketConnectionManager(wsUrl, tokenGetter);
16071
+ await wsManager.connect();
16072
+ const wsToolExecutor2 = new WebSocketToolExecutor(wsManager, tokenGetter);
16073
+ setWebSocketToolExecutor(wsToolExecutor2);
16074
+ llm = new WebSocketLlmBackend({
16075
+ wsManager,
16076
+ apiClient,
16077
+ model: config.defaultModel,
16078
+ tokenGetter
16079
+ });
16080
+ logger.debug("\u{1F50C} Using WebSocket transport (bypasses CloudFront timeout)");
16081
+ } else {
16082
+ throw new Error("No websocketUrl in server config");
16083
+ }
16084
+ } catch (wsError) {
16085
+ logger.debug(
16086
+ `[WS] WebSocket unavailable, using SSE fallback: ${wsError instanceof Error ? wsError.message : String(wsError)}`
16087
+ );
16088
+ wsManager = null;
16089
+ setWebSocketToolExecutor(null);
16090
+ llm = new ServerLlmBackend({
16091
+ apiClient,
16092
+ model: config.defaultModel
16093
+ });
16094
+ }
15682
16095
  const models = await llm.getModelInfo();
15683
16096
  if (models.length === 0) {
15684
16097
  throw new Error("No models available from server.");
@@ -15691,7 +16104,7 @@ function CliApp() {
15691
16104
  }
15692
16105
  llm.currentModel = modelInfo.id;
15693
16106
  const newSession = {
15694
- id: uuidv411(),
16107
+ id: uuidv413(),
15695
16108
  name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
15696
16109
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
15697
16110
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -15911,8 +16324,10 @@ ${contextResult.mergedContent}` : "";
15911
16324
  // Store agent store for agent management commands
15912
16325
  contextContent: contextResult.mergedContent,
15913
16326
  // Store raw context for compact instructions
15914
- backgroundManager
16327
+ backgroundManager,
15915
16328
  // Store for grouped notification turn tracking
16329
+ wsManager
16330
+ // WebSocket connection manager (null if using SSE fallback)
15916
16331
  }));
15917
16332
  setStoreSession(newSession);
15918
16333
  const bannerLines = [
@@ -16007,13 +16422,13 @@ ${contextResult.mergedContent}` : "";
16007
16422
  messageContent = multimodalMessage.content;
16008
16423
  }
16009
16424
  const userMessage = {
16010
- id: uuidv411(),
16425
+ id: uuidv413(),
16011
16426
  role: "user",
16012
16427
  content: userMessageContent,
16013
16428
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
16014
16429
  };
16015
16430
  const pendingAssistantMessage = {
16016
- id: uuidv411(),
16431
+ id: uuidv413(),
16017
16432
  role: "assistant",
16018
16433
  content: "...",
16019
16434
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -16219,13 +16634,13 @@ ${contextResult.mergedContent}` : "";
16219
16634
  userMessageContent = message;
16220
16635
  }
16221
16636
  const userMessage = {
16222
- id: uuidv411(),
16637
+ id: uuidv413(),
16223
16638
  role: "user",
16224
16639
  content: userMessageContent,
16225
16640
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
16226
16641
  };
16227
16642
  const pendingAssistantMessage = {
16228
- id: uuidv411(),
16643
+ id: uuidv413(),
16229
16644
  role: "assistant",
16230
16645
  content: "...",
16231
16646
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -16303,7 +16718,7 @@ ${contextResult.mergedContent}` : "";
16303
16718
  const currentSession = useCliStore.getState().session;
16304
16719
  if (currentSession) {
16305
16720
  const cancelMessage = {
16306
- id: uuidv411(),
16721
+ id: uuidv413(),
16307
16722
  role: "assistant",
16308
16723
  content: "\u26A0\uFE0F Operation cancelled by user",
16309
16724
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -16348,7 +16763,7 @@ ${contextResult.mergedContent}` : "";
16348
16763
  setState((prev) => ({ ...prev, abortController }));
16349
16764
  try {
16350
16765
  const pendingAssistantMessage = {
16351
- id: uuidv411(),
16766
+ id: uuidv413(),
16352
16767
  role: "assistant",
16353
16768
  content: "...",
16354
16769
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -16376,7 +16791,7 @@ ${contextResult.mergedContent}` : "";
16376
16791
  const currentSession = useCliStore.getState().session;
16377
16792
  if (!currentSession) return;
16378
16793
  const continuationMessage = {
16379
- id: uuidv411(),
16794
+ id: uuidv413(),
16380
16795
  role: "assistant",
16381
16796
  content: "---\n\n**Background Agent Results:**\n\n" + result.finalAnswer,
16382
16797
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -16435,13 +16850,13 @@ ${contextResult.mergedContent}` : "";
16435
16850
  isError = true;
16436
16851
  }
16437
16852
  const userMessage = {
16438
- id: uuidv411(),
16853
+ id: uuidv413(),
16439
16854
  role: "user",
16440
16855
  content: `$ ${command}`,
16441
16856
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
16442
16857
  };
16443
16858
  const assistantMessage = {
16444
- id: uuidv411(),
16859
+ id: uuidv413(),
16445
16860
  role: "assistant",
16446
16861
  content: isError ? `\u274C Error:
16447
16862
  ${output}` : output.trim() || "(no output)",
@@ -16910,7 +17325,7 @@ Keyboard Shortcuts:
16910
17325
  console.clear();
16911
17326
  const model = state.session?.model || state.config?.defaultModel || "claude-sonnet";
16912
17327
  const newSession = {
16913
- id: uuidv411(),
17328
+ id: uuidv413(),
16914
17329
  name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
16915
17330
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
16916
17331
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -17405,9 +17820,9 @@ No usage data available for the last ${USAGE_DAYS} days.`);
17405
17820
  return { ...prev, config: updatedConfig };
17406
17821
  });
17407
17822
  if (modelChanged && state.agent) {
17408
- const llm = state.agent.context.llm;
17409
- if (llm) {
17410
- llm.currentModel = updatedConfig.defaultModel;
17823
+ const backend = state.agent.context.llm;
17824
+ if (backend) {
17825
+ backend.currentModel = updatedConfig.defaultModel;
17411
17826
  }
17412
17827
  }
17413
17828
  };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CurationArtifactType
4
- } from "./chunk-5GSDPBTM.js";
4
+ } from "./chunk-KPOK6V6E.js";
5
5
 
6
6
  // ../../b4m-core/packages/services/dist/src/notebookCurationService/llmMarkdownGenerator.js
7
7
  var DEFAULT_OPTIONS = {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CurationArtifactType
4
- } from "./chunk-5GSDPBTM.js";
4
+ } from "./chunk-KPOK6V6E.js";
5
5
 
6
6
  // ../../b4m-core/packages/services/dist/src/notebookCurationService/markdownGenerator.js
7
7
  var DEFAULT_OPTIONS = {
@@ -2,9 +2,9 @@
2
2
  import {
3
3
  findMostSimilarMemento,
4
4
  getRelevantMementos
5
- } from "./chunk-BCOGDPUB.js";
6
- import "./chunk-S7BPPS33.js";
7
- import "./chunk-5GSDPBTM.js";
5
+ } from "./chunk-QQL3OBKL.js";
6
+ import "./chunk-TY6Z2UV2.js";
7
+ import "./chunk-KPOK6V6E.js";
8
8
  import "./chunk-OCYRD7D6.js";
9
9
  export {
10
10
  findMostSimilarMemento,
@@ -41,6 +41,12 @@ import {
41
41
  ChatModels,
42
42
  CitableSourceSchema,
43
43
  ClaudeArtifactMimeTypes,
44
+ CliCompletionChunkAction,
45
+ CliCompletionDoneAction,
46
+ CliCompletionErrorAction,
47
+ CliCompletionRequestAction,
48
+ CliToolRequestAction,
49
+ CliToolResponseAction,
44
50
  CollectionType,
45
51
  CompletionApiUsageTransaction,
46
52
  CompletionRequestSchema,
@@ -340,7 +346,7 @@ import {
340
346
  validateReactArtifactV2,
341
347
  validateSvgArtifactV2,
342
348
  wikiMarkupToAdf
343
- } from "./chunk-5GSDPBTM.js";
349
+ } from "./chunk-KPOK6V6E.js";
344
350
  export {
345
351
  ALL_IMAGE_MODELS,
346
352
  ALL_IMAGE_SIZES,
@@ -384,6 +390,12 @@ export {
384
390
  ChatModels,
385
391
  CitableSourceSchema,
386
392
  ClaudeArtifactMimeTypes,
393
+ CliCompletionChunkAction,
394
+ CliCompletionDoneAction,
395
+ CliCompletionErrorAction,
396
+ CliCompletionRequestAction,
397
+ CliToolRequestAction,
398
+ CliToolResponseAction,
387
399
  CollectionType,
388
400
  CompletionApiUsageTransaction,
389
401
  CompletionRequestSchema,
@@ -134,8 +134,8 @@ import {
134
134
  validateMermaidSyntax,
135
135
  warmUpSettingsCache,
136
136
  withRetry
137
- } from "./chunk-S7BPPS33.js";
138
- import "./chunk-5GSDPBTM.js";
137
+ } from "./chunk-TY6Z2UV2.js";
138
+ import "./chunk-KPOK6V6E.js";
139
139
  import {
140
140
  Logger,
141
141
  NotificationDeduplicator,
@@ -2,9 +2,9 @@
2
2
  import {
3
3
  SubtractCreditsSchema,
4
4
  subtractCredits
5
- } from "./chunk-PKKJ44C5.js";
6
- import "./chunk-S7BPPS33.js";
7
- import "./chunk-5GSDPBTM.js";
5
+ } from "./chunk-BXCARBUQ.js";
6
+ import "./chunk-TY6Z2UV2.js";
7
+ import "./chunk-KPOK6V6E.js";
8
8
  import "./chunk-OCYRD7D6.js";
9
9
  export {
10
10
  SubtractCreditsSchema,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bike4mind/cli",
3
- "version": "0.2.29-feat-session-permission.18841+6d9c4deb5",
3
+ "version": "0.2.29-feat-cli-websocket-streaming.18841+5c940d031",
4
4
  "type": "module",
5
5
  "description": "Interactive CLI tool for Bike4Mind with ReAct agents",
6
6
  "license": "UNLICENSED",
@@ -110,10 +110,10 @@
110
110
  },
111
111
  "devDependencies": {
112
112
  "@bike4mind/agents": "0.1.0",
113
- "@bike4mind/common": "2.50.1-feat-session-permission.18841+6d9c4deb5",
114
- "@bike4mind/mcp": "1.29.1-feat-session-permission.18841+6d9c4deb5",
115
- "@bike4mind/services": "2.48.1-feat-session-permission.18841+6d9c4deb5",
116
- "@bike4mind/utils": "2.5.1-feat-session-permission.18841+6d9c4deb5",
113
+ "@bike4mind/common": "2.50.1-feat-cli-websocket-streaming.18841+5c940d031",
114
+ "@bike4mind/mcp": "1.29.1-feat-cli-websocket-streaming.18841+5c940d031",
115
+ "@bike4mind/services": "2.48.1-feat-cli-websocket-streaming.18841+5c940d031",
116
+ "@bike4mind/utils": "2.5.1-feat-cli-websocket-streaming.18841+5c940d031",
117
117
  "@types/better-sqlite3": "^7.6.13",
118
118
  "@types/diff": "^5.0.9",
119
119
  "@types/jsonwebtoken": "^9.0.4",
@@ -130,5 +130,5 @@
130
130
  "optionalDependencies": {
131
131
  "@vscode/ripgrep": "^1.17.0"
132
132
  },
133
- "gitHead": "6d9c4deb5a83cfc1087043d22f407d3444a91cca"
133
+ "gitHead": "5c940d031610617c76d3c12cc611b71db8bb4caf"
134
134
  }