@bike4mind/cli 0.2.49-fix-cli-stream-resilience-v2.21033 → 0.2.49-prod.21090

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-QLY3LGPA.js";
4
+ } from "./chunk-YRYNVLXM.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;
@@ -6,12 +6,12 @@ import {
6
6
  getSettingsByNames,
7
7
  obfuscateApiKey,
8
8
  secureParameters
9
- } from "./chunk-UDBM5N7V.js";
9
+ } from "./chunk-QU3ADG2K.js";
10
10
  import {
11
11
  ApiKeyType,
12
12
  MementoTier,
13
13
  isSupportedEmbeddingModel
14
- } from "./chunk-QLY3LGPA.js";
14
+ } from "./chunk-YRYNVLXM.js";
15
15
 
16
16
  // ../../b4m-core/packages/services/dist/src/apiKeyService/get.js
17
17
  import { z } from "zod";
@@ -3,7 +3,7 @@
3
3
  // package.json
4
4
  var package_default = {
5
5
  name: "@bike4mind/cli",
6
- version: "0.2.49-fix-cli-stream-resilience-v2.21033+6a9f2b5b5",
6
+ version: "0.2.49-prod.21090+4ff436a32",
7
7
  type: "module",
8
8
  description: "Interactive CLI tool for Bike4Mind with ReAct agents",
9
9
  license: "UNLICENSED",
@@ -64,7 +64,7 @@ var package_default = {
64
64
  "@smithy/node-http-handler": "^4.4.14",
65
65
  "async-mutex": "^0.5.0",
66
66
  axios: "^1.13.6",
67
- bcryptjs: "^2.4.3",
67
+ bcryptjs: "^3.0.2",
68
68
  "better-sqlite3": "^12.6.2",
69
69
  cheerio: "1.0.0-rc.12",
70
70
  "cli-highlight": "^2.1.11",
@@ -118,10 +118,10 @@ var package_default = {
118
118
  },
119
119
  devDependencies: {
120
120
  "@bike4mind/agents": "0.1.0",
121
- "@bike4mind/common": "2.67.1-fix-cli-stream-resilience-v2.21033+6a9f2b5b5",
122
- "@bike4mind/mcp": "1.33.11-fix-cli-stream-resilience-v2.21033+6a9f2b5b5",
123
- "@bike4mind/services": "2.63.1-fix-cli-stream-resilience-v2.21033+6a9f2b5b5",
124
- "@bike4mind/utils": "2.15.4-fix-cli-stream-resilience-v2.21033+6a9f2b5b5",
121
+ "@bike4mind/common": "2.67.1-prod.21090+4ff436a32",
122
+ "@bike4mind/mcp": "1.33.11-prod.21090+4ff436a32",
123
+ "@bike4mind/services": "2.63.1-prod.21090+4ff436a32",
124
+ "@bike4mind/utils": "2.15.4-prod.21090+4ff436a32",
125
125
  "@types/better-sqlite3": "^7.6.13",
126
126
  "@types/diff": "^5.0.9",
127
127
  "@types/jsonwebtoken": "^9.0.4",
@@ -140,7 +140,7 @@ var package_default = {
140
140
  optionalDependencies: {
141
141
  "@vscode/ripgrep": "^1.17.0"
142
142
  },
143
- gitHead: "6a9f2b5b5ef81c255f95f35bdbdc6339fe2f7c3f"
143
+ gitHead: "4ff436a32269365aba08bda30e846fad8c6142ee"
144
144
  };
145
145
 
146
146
  // src/utils/updateChecker.ts
@@ -7,11 +7,11 @@ import {
7
7
  getSettingsMap,
8
8
  getSettingsValue,
9
9
  secureParameters
10
- } from "./chunk-UDBM5N7V.js";
10
+ } from "./chunk-QU3ADG2K.js";
11
11
  import {
12
12
  KnowledgeType,
13
13
  SupportedFabFileMimeTypes
14
- } from "./chunk-QLY3LGPA.js";
14
+ } from "./chunk-YRYNVLXM.js";
15
15
 
16
16
  // ../../b4m-core/packages/services/dist/src/fabFileService/create.js
17
17
  import { z } from "zod";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ChatModels
4
- } from "./chunk-QLY3LGPA.js";
4
+ } from "./chunk-YRYNVLXM.js";
5
5
  import {
6
6
  DEFAULT_SANDBOX_CONFIG
7
7
  } from "./chunk-4BIBE3J7.js";
@@ -20,7 +20,7 @@ import {
20
20
  extractSnippetMeta,
21
21
  isGPTImageModel,
22
22
  settingsMap
23
- } from "./chunk-QLY3LGPA.js";
23
+ } from "./chunk-YRYNVLXM.js";
24
24
 
25
25
  // ../../b4m-core/packages/utils/dist/src/storage/S3Storage.js
26
26
  import { S3Client, PutObjectCommand, DeleteObjectCommand, GetObjectCommand, HeadObjectCommand } from "@aws-sdk/client-s3";
@@ -6578,57 +6578,6 @@ var GeminiBackend = class {
6578
6578
  // ../../b4m-core/packages/utils/dist/src/llm/ollamaBackend.js
6579
6579
  import { Ollama } from "ollama";
6580
6580
  import { Agent as Agent2 } from "undici";
6581
-
6582
- // ../../b4m-core/packages/utils/dist/src/llm/messageFormatConverter.js
6583
- function convertMessageToOpenAIFormat(msg) {
6584
- if (msg.role === "assistant" && msg.tool_calls) {
6585
- return [
6586
- {
6587
- ...msg,
6588
- content: null,
6589
- tool_calls: msg.tool_calls
6590
- }
6591
- ];
6592
- }
6593
- if (msg.role === "assistant" && Array.isArray(msg.content)) {
6594
- const contentBlocks = msg.content;
6595
- const toolUseBlocks = contentBlocks.filter((b) => b.type === "tool_use");
6596
- if (toolUseBlocks.length > 0) {
6597
- const textParts = contentBlocks.filter((b) => b.type === "text").map((b) => b.text).filter(Boolean);
6598
- return [
6599
- {
6600
- role: "assistant",
6601
- content: textParts.length > 0 ? textParts.join("\n") : null,
6602
- tool_calls: toolUseBlocks.map((b) => ({
6603
- id: b.id,
6604
- type: "function",
6605
- function: {
6606
- name: b.name,
6607
- arguments: typeof b.input === "string" ? b.input : JSON.stringify(b.input)
6608
- }
6609
- }))
6610
- }
6611
- ];
6612
- }
6613
- }
6614
- if (msg.role === "user" && Array.isArray(msg.content)) {
6615
- const contentBlocks = msg.content;
6616
- const toolResultBlocks = contentBlocks.filter((b) => b.type === "tool_result");
6617
- if (toolResultBlocks.length > 0) {
6618
- return toolResultBlocks.map((b) => ({
6619
- role: "tool",
6620
- content: typeof b.content === "string" ? b.content : JSON.stringify(b.content),
6621
- tool_call_id: b.tool_use_id
6622
- }));
6623
- }
6624
- }
6625
- return [msg];
6626
- }
6627
- function convertMessagesToOpenAIFormat(messages) {
6628
- return messages.flatMap(convertMessageToOpenAIFormat);
6629
- }
6630
-
6631
- // ../../b4m-core/packages/utils/dist/src/llm/ollamaBackend.js
6632
6581
  var OllamaBackend = class {
6633
6582
  _host;
6634
6583
  _api;
@@ -6792,12 +6741,9 @@ var OllamaBackend = class {
6792
6741
  /**
6793
6742
  * Map IMessage[] to Ollama's Message[], preserving tool_calls for multi-turn
6794
6743
  * tool conversations (added by pushToolMessages).
6795
- * First converts B4M standard format (tool_use/tool_result) to OpenAI-compatible
6796
- * format since Ollama uses the same tool_calls/role:tool convention.
6797
6744
  */
6798
6745
  buildMessages(messages) {
6799
- const converted = convertMessagesToOpenAIFormat(messages);
6800
- return converted.map((msg) => {
6746
+ return messages.map((msg) => {
6801
6747
  const raw = msg;
6802
6748
  const mapped = {
6803
6749
  role: msg.role,
@@ -7891,8 +7837,16 @@ Only when someone asks, remember that you are specifically the ${model} model.`;
7891
7837
  role: "system",
7892
7838
  content: systemContent
7893
7839
  };
7894
- const convertedMessages = convertMessagesToOpenAIFormat(filteredMessages);
7895
- const formattedMessages = convertedMessages;
7840
+ const formattedMessages = filteredMessages.map((msg) => {
7841
+ if (msg.role === "assistant" && msg.tool_calls) {
7842
+ return {
7843
+ ...msg,
7844
+ content: null,
7845
+ tool_calls: msg.tool_calls
7846
+ };
7847
+ }
7848
+ return msg;
7849
+ });
7896
7850
  return isO1Model ? formattedMessages : [systemMessage, ...formattedMessages];
7897
7851
  }
7898
7852
  pushToolMessages(messages, tool, result, _thinkingBlocks) {
@@ -8415,7 +8369,17 @@ var XAIBackend = class {
8415
8369
  }
8416
8370
  }
8417
8371
  formatMessages(messages) {
8418
- return convertMessagesToOpenAIFormat(messages);
8372
+ const formattedMessages = messages.map((msg) => {
8373
+ if (msg.role === "assistant" && msg.tool_calls) {
8374
+ return {
8375
+ ...msg,
8376
+ content: null,
8377
+ tool_calls: msg.tool_calls
8378
+ };
8379
+ }
8380
+ return msg;
8381
+ });
8382
+ return formattedMessages;
8419
8383
  }
8420
8384
  formatTools(tools = []) {
8421
8385
  return tools.map((tool) => ({
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  BadRequestError,
4
4
  secureParameters
5
- } from "./chunk-UDBM5N7V.js";
5
+ } from "./chunk-QU3ADG2K.js";
6
6
  import {
7
7
  CompletionApiUsageTransaction,
8
8
  GenericCreditDeductTransaction,
@@ -13,7 +13,7 @@ import {
13
13
  ToolUsageTransaction,
14
14
  TransferCreditTransaction,
15
15
  VideoGenerationUsageTransaction
16
- } from "./chunk-QLY3LGPA.js";
16
+ } from "./chunk-YRYNVLXM.js";
17
17
 
18
18
  // ../../b4m-core/packages/services/dist/src/creditService/subtractCredits.js
19
19
  import { z } from "zod";
@@ -1284,8 +1284,10 @@ var SreAgentConfigSchema = z10.object({
1284
1284
  /** Repository name (e.g. "lumina5") */
1285
1285
  repo: z10.string().default(""),
1286
1286
  /** Comma-separated GitHub usernames to request as PR reviewers */
1287
- reviewers: z10.string().default("")
1288
- }).default({ owner: "", repo: "", reviewers: "" }),
1287
+ reviewers: z10.string().default(""),
1288
+ /** HMAC secret for the system-level SRE webhook endpoint (encrypted at rest with SECRET_ENCRYPTION_KEY) */
1289
+ webhookSecret: z10.string().default("")
1290
+ }).default({ owner: "", repo: "", reviewers: "", webhookSecret: "" }),
1289
1291
  /** Per-source toggles */
1290
1292
  sources: z10.object({
1291
1293
  cloudwatch: z10.object({ enabled: z10.boolean().default(false) }).default({ enabled: false }),
@@ -4,7 +4,7 @@ import {
4
4
  getOpenWeatherKey,
5
5
  getSerperKey,
6
6
  getWolframAlphaKey
7
- } from "./chunk-7VEI22BF.js";
7
+ } from "./chunk-2K6DFEPJ.js";
8
8
  import {
9
9
  BFLImageService,
10
10
  BaseStorage,
@@ -16,14 +16,14 @@ import {
16
16
  OpenAIBackend,
17
17
  OpenAIImageService,
18
18
  XAIImageService
19
- } from "./chunk-UDBM5N7V.js";
19
+ } from "./chunk-QU3ADG2K.js";
20
20
  import {
21
21
  Logger
22
22
  } from "./chunk-PFBYGCOW.js";
23
23
  import {
24
24
  ConfigStore,
25
25
  logger
26
- } from "./chunk-W5MJV36K.js";
26
+ } from "./chunk-LZBANFHR.js";
27
27
  import {
28
28
  ALERT_THRESHOLDS,
29
29
  AiEvents,
@@ -84,7 +84,7 @@ import {
84
84
  getViewById,
85
85
  resolveNavigationIntents,
86
86
  sanitizeTelemetryError
87
- } from "./chunk-QLY3LGPA.js";
87
+ } from "./chunk-YRYNVLXM.js";
88
88
 
89
89
  // src/utils/fileSearch.ts
90
90
  import * as fs from "fs";
@@ -503,6 +503,10 @@ var COMMANDS = [
503
503
  name: "sandbox:violations:clear",
504
504
  description: "Clear all recorded sandbox violations"
505
505
  },
506
+ {
507
+ name: "terminal-setup",
508
+ description: "Configure Shift+Enter for multi-line input"
509
+ },
506
510
  {
507
511
  name: "add-dir",
508
512
  description: "Add a directory for file access",
@@ -14017,25 +14021,40 @@ var AnomalyAlertService = class _AnomalyAlertService {
14017
14021
  * Check if an alert should be sent and send it if appropriate
14018
14022
  */
14019
14023
  async checkAndAlert(telemetry) {
14024
+ console.log("[AnomalyAlert] DEBUG: checkAndAlert called", {
14025
+ enabled: this.config.enabled,
14026
+ isSlackConfigured: this.isSlackConfigured()
14027
+ });
14020
14028
  if (!this.config.enabled || !this.isSlackConfigured()) {
14029
+ console.log("[AnomalyAlert] DEBUG: Early return - not enabled or Slack not configured");
14021
14030
  return false;
14022
14031
  }
14023
14032
  const { anomalies } = telemetry;
14024
14033
  const threshold = this.config.alertThreshold ?? ALERT_THRESHOLDS.warning;
14034
+ console.log("[AnomalyAlert] DEBUG: Threshold check", {
14035
+ anomalyScore: anomalies.anomalyScore,
14036
+ threshold
14037
+ });
14025
14038
  if (anomalies.anomalyScore < threshold) {
14039
+ console.log("[AnomalyAlert] DEBUG: Score below threshold");
14026
14040
  return false;
14027
14041
  }
14042
+ console.log("[AnomalyAlert] DEBUG: Checking deduplication", { dedupKey: anomalies.dedupKey });
14028
14043
  const isDup = await this.checkDeduplication(anomalies.dedupKey);
14044
+ console.log("[AnomalyAlert] DEBUG: Dedup result", { isDup });
14029
14045
  if (isDup) {
14030
14046
  this.logger.info(`\u{1F4CA} [AnomalyAlert] Suppressed duplicate alert: ${anomalies.dedupKey}`);
14031
14047
  return false;
14032
14048
  }
14033
14049
  try {
14050
+ console.log("[AnomalyAlert] DEBUG: Sending Slack alert");
14034
14051
  const message = this.formatSlackMessage(telemetry);
14035
14052
  await this.sendSlackAlert(message);
14036
14053
  this.logger.info(`\u{1F4CA} [AnomalyAlert] Alert sent for ${anomalies.primaryAnomaly} (score: ${anomalies.anomalyScore})`);
14054
+ console.log("[AnomalyAlert] DEBUG: Alert sent successfully");
14037
14055
  return true;
14038
14056
  } catch (error) {
14057
+ console.log("[AnomalyAlert] DEBUG: Failed to send alert", { error: String(error) });
14039
14058
  this.logger.error(`\u{1F4CA} [AnomalyAlert] Failed to send alert:`, error);
14040
14059
  return false;
14041
14060
  }
@@ -16142,48 +16161,17 @@ function extractUsageInfo(parsed) {
16142
16161
  usdCost: parsed.credits?.usdCost
16143
16162
  };
16144
16163
  }
16145
- var ServerLlmBackend = class _ServerLlmBackend {
16164
+ var ServerLlmBackend = class {
16146
16165
  constructor(options) {
16147
16166
  this.completionsEndpoint = "/api/ai/v1/completions";
16148
16167
  this.apiClient = options.apiClient;
16149
16168
  this.currentModel = options.model;
16150
16169
  }
16151
- static {
16152
- /** Max retries for transient stream failures (e.g. missing [DONE]) */
16153
- this.MAX_STREAM_RETRIES = 2;
16154
- }
16155
16170
  /**
16156
16171
  * Make authenticated LLM completion request via server
16157
- * Parses SSE stream and invokes callback for each event.
16158
- * Automatically retries on transient stream failures (e.g. stream ending prematurely).
16172
+ * Parses SSE stream and invokes callback for each event
16159
16173
  */
16160
16174
  async complete(model, messages, options, callback) {
16161
- let lastError;
16162
- for (let attempt = 0; attempt <= _ServerLlmBackend.MAX_STREAM_RETRIES; attempt++) {
16163
- if (attempt > 0) {
16164
- logger.warn(
16165
- `[ServerLlmBackend] Retrying stream (attempt ${attempt + 1}/${_ServerLlmBackend.MAX_STREAM_RETRIES + 1})...`
16166
- );
16167
- }
16168
- try {
16169
- await this.completeOnce(model, messages, options, callback);
16170
- return;
16171
- } catch (error) {
16172
- lastError = error instanceof Error ? error : new Error(String(error));
16173
- const isTransientStreamError = lastError.message.includes("Stream ended prematurely");
16174
- const isAborted = options.abortSignal?.aborted;
16175
- if (!isTransientStreamError || isAborted) {
16176
- throw lastError;
16177
- }
16178
- logger.warn(`[ServerLlmBackend] Transient stream failure: ${lastError.message}`);
16179
- }
16180
- }
16181
- throw lastError ?? new Error("Stream failed after all retry attempts");
16182
- }
16183
- /**
16184
- * Single attempt at completing a streaming request.
16185
- */
16186
- async completeOnce(model, messages, options, callback) {
16187
16175
  logger.debug(`[ServerLlmBackend] Starting complete() with model: ${model}`);
16188
16176
  if (options.abortSignal?.aborted) {
16189
16177
  logger.debug("[ServerLlmBackend] Request aborted before start");
@@ -16384,30 +16372,8 @@ var ServerLlmBackend = class _ServerLlmBackend {
16384
16372
  });
16385
16373
  response.data.on("end", () => {
16386
16374
  if (!receivedDone) {
16387
- const hasAccumulatedData = accumulatedText.trim().length > 0 || toolsUsed.length > 0;
16388
- logger.warn(
16389
- `[ServerLlmBackend] Stream ended without [DONE] signal. Accumulated text: ${accumulatedText.length} chars, tools: ${toolsUsed.length}`
16390
- );
16391
- if (hasAccumulatedData) {
16392
- const cleanedText = stripThinkingBlocks(accumulatedText);
16393
- streamLogger.streamComplete(accumulatedText);
16394
- if (toolsUsed.length > 0) {
16395
- const info = {
16396
- toolsUsed,
16397
- thinking: thinkingBlocks.length > 0 ? thinkingBlocks : void 0,
16398
- ...lastUsageInfo
16399
- };
16400
- callback([cleanedText], info).catch((err) => reject(err)).then(() => resolve3());
16401
- } else if (cleanedText) {
16402
- callback([cleanedText], lastUsageInfo).catch((err) => reject(err)).then(() => resolve3());
16403
- } else {
16404
- resolve3();
16405
- }
16406
- } else {
16407
- reject(
16408
- new Error("Stream ended prematurely without receiving any data. The server may be experiencing issues.")
16409
- );
16410
- }
16375
+ logger.debug("[ServerLlmBackend] Stream ended without [DONE], resolving anyway");
16376
+ resolve3();
16411
16377
  } else {
16412
16378
  logger.debug("[ServerLlmBackend] Stream ended, [DONE] handler will resolve");
16413
16379
  }
@@ -16665,8 +16631,43 @@ var WebSocketLlmBackend = class {
16665
16631
  });
16666
16632
  });
16667
16633
  }
16668
- pushToolMessages(_messages, _tool, _result) {
16669
- throw new Error("WebSocketLlmBackend does not support pushToolMessages \u2014 tools are executed server-side");
16634
+ pushToolMessages(messages, tool, result, thinkingBlocks) {
16635
+ if (thinkingBlocks && thinkingBlocks.length > 0) {
16636
+ messages.push({
16637
+ role: "assistant",
16638
+ content: [
16639
+ ...thinkingBlocks,
16640
+ {
16641
+ type: "tool_use",
16642
+ id: tool.id,
16643
+ name: tool.name,
16644
+ input: JSON.parse(tool.parameters || "{}")
16645
+ }
16646
+ ]
16647
+ });
16648
+ } else {
16649
+ messages.push({
16650
+ role: "assistant",
16651
+ content: [
16652
+ {
16653
+ type: "tool_use",
16654
+ id: tool.id,
16655
+ name: tool.name,
16656
+ input: JSON.parse(tool.parameters || "{}")
16657
+ }
16658
+ ]
16659
+ });
16660
+ }
16661
+ messages.push({
16662
+ role: "user",
16663
+ content: [
16664
+ {
16665
+ type: "tool_result",
16666
+ tool_use_id: tool.id,
16667
+ content: result
16668
+ }
16669
+ ]
16670
+ });
16670
16671
  }
16671
16672
  /**
16672
16673
  * Get available models from server (REST call, not streaming).
@@ -3,7 +3,7 @@ import {
3
3
  fetchLatestVersion,
4
4
  forceCheckForUpdate,
5
5
  package_default
6
- } from "../chunk-AINGID72.js";
6
+ } from "../chunk-DVVQ3AZN.js";
7
7
 
8
8
  // src/commands/doctorCommand.ts
9
9
  import { execSync } from "child_process";
@@ -36,20 +36,20 @@ import {
36
36
  isReadOnlyTool,
37
37
  loadContextFiles,
38
38
  setWebSocketToolExecutor
39
- } from "../chunk-2WNNPZZS.js";
39
+ } from "../chunk-ZCOPMHYC.js";
40
40
  import "../chunk-BDQBOLYG.js";
41
- import "../chunk-7VEI22BF.js";
41
+ import "../chunk-2K6DFEPJ.js";
42
42
  import "../chunk-GQGOWACU.js";
43
- import "../chunk-X26VCD3A.js";
44
- import "../chunk-MP3FYWMR.js";
45
- import "../chunk-UDBM5N7V.js";
43
+ import "../chunk-UVP4KCPD.js";
44
+ import "../chunk-EOOKQOLY.js";
45
+ import "../chunk-QU3ADG2K.js";
46
46
  import "../chunk-PFBYGCOW.js";
47
47
  import "../chunk-BPFEGDC7.js";
48
48
  import {
49
49
  ConfigStore,
50
50
  logger
51
- } from "../chunk-W5MJV36K.js";
52
- import "../chunk-QLY3LGPA.js";
51
+ } from "../chunk-LZBANFHR.js";
52
+ import "../chunk-YRYNVLXM.js";
53
53
  import {
54
54
  DEFAULT_SANDBOX_CONFIG
55
55
  } from "../chunk-4BIBE3J7.js";
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ConfigStore
4
- } from "../chunk-W5MJV36K.js";
5
- import "../chunk-QLY3LGPA.js";
4
+ } from "../chunk-LZBANFHR.js";
5
+ import "../chunk-YRYNVLXM.js";
6
6
  import "../chunk-4BIBE3J7.js";
7
7
 
8
8
  // src/commands/mcpCommand.ts
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  forceCheckForUpdate,
4
4
  package_default
5
- } from "../chunk-AINGID72.js";
5
+ } from "../chunk-DVVQ3AZN.js";
6
6
 
7
7
  // src/commands/updateCommand.ts
8
8
  import { execSync } from "child_process";
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  createFabFile,
4
4
  createFabFileSchema
5
- } from "./chunk-MP3FYWMR.js";
6
- import "./chunk-UDBM5N7V.js";
5
+ } from "./chunk-EOOKQOLY.js";
6
+ import "./chunk-QU3ADG2K.js";
7
7
  import "./chunk-PFBYGCOW.js";
8
- import "./chunk-QLY3LGPA.js";
8
+ import "./chunk-YRYNVLXM.js";
9
9
  export {
10
10
  createFabFile,
11
11
  createFabFileSchema
package/dist/index.js CHANGED
@@ -46,25 +46,25 @@ import {
46
46
  setWebSocketToolExecutor,
47
47
  substituteArguments,
48
48
  warmFileCache
49
- } from "./chunk-2WNNPZZS.js";
49
+ } from "./chunk-ZCOPMHYC.js";
50
50
  import "./chunk-BDQBOLYG.js";
51
- import "./chunk-7VEI22BF.js";
51
+ import "./chunk-2K6DFEPJ.js";
52
52
  import "./chunk-GQGOWACU.js";
53
- import "./chunk-X26VCD3A.js";
54
- import "./chunk-MP3FYWMR.js";
53
+ import "./chunk-UVP4KCPD.js";
54
+ import "./chunk-EOOKQOLY.js";
55
55
  import {
56
56
  OllamaBackend
57
- } from "./chunk-UDBM5N7V.js";
57
+ } from "./chunk-QU3ADG2K.js";
58
58
  import "./chunk-PFBYGCOW.js";
59
59
  import "./chunk-BPFEGDC7.js";
60
60
  import {
61
61
  ConfigStore,
62
62
  logger
63
- } from "./chunk-W5MJV36K.js";
63
+ } from "./chunk-LZBANFHR.js";
64
64
  import {
65
65
  checkForUpdate,
66
66
  package_default
67
- } from "./chunk-AINGID72.js";
67
+ } from "./chunk-DVVQ3AZN.js";
68
68
  import {
69
69
  selectActiveBackgroundAgents,
70
70
  useCliStore
@@ -72,7 +72,7 @@ import {
72
72
  import {
73
73
  CREDIT_DEDUCT_TRANSACTION_TYPES,
74
74
  ChatModels
75
- } from "./chunk-QLY3LGPA.js";
75
+ } from "./chunk-YRYNVLXM.js";
76
76
  import "./chunk-4BIBE3J7.js";
77
77
 
78
78
  // src/index.tsx
@@ -169,9 +169,21 @@ function CustomTextInput({
169
169
  useInput(
170
170
  (input, key) => {
171
171
  if (key.return && !key.meta && !key.shift) {
172
+ if (value.length > 0 && value[cursorOffset - 1] === "\\") {
173
+ const newValue = value.slice(0, cursorOffset - 1) + "\n" + value.slice(cursorOffset);
174
+ emitChange(newValue);
175
+ setCursorOffset(cursorOffset);
176
+ return;
177
+ }
172
178
  onSubmit(value);
173
179
  return;
174
180
  }
181
+ if (key.return && (key.shift || key.meta)) {
182
+ const newValue = value.slice(0, cursorOffset) + "\n" + value.slice(cursorOffset);
183
+ emitChange(newValue);
184
+ setCursorOffset(cursorOffset + 1);
185
+ return;
186
+ }
175
187
  if (key.meta && !key.ctrl) {
176
188
  if (key.shift) {
177
189
  if (key.leftArrow) {
@@ -835,7 +847,10 @@ function InputPrompt({
835
847
  const handlePaste = (content) => {
836
848
  const truncated = content.length > MAX_PASTE_SIZE ? content.slice(0, MAX_PASTE_SIZE) : content;
837
849
  const lineCount = truncated.split("\n").length;
838
- setPastedContent(truncated, lineCount);
850
+ const prefix = value.trim();
851
+ const combined = prefix ? `${prefix}
852
+ ${truncated}` : truncated;
853
+ setPastedContent(combined, lineCount);
839
854
  };
840
855
  const handleChange = async (newValue) => {
841
856
  if (pastedContent) {
@@ -2940,10 +2955,11 @@ function CliApp() {
2940
2955
  throw new Error("No websocketUrl or wsCompletionUrl in server config");
2941
2956
  }
2942
2957
  } catch (wsError) {
2943
- logger.info("\u26A0\uFE0F WebSocket unavailable, using SSE fallback");
2944
- logger.debug(`[WebSocket] Fallback reason: ${wsError instanceof Error ? wsError.message : String(wsError)}`);
2958
+ console.error(
2959
+ `\u26A0\uFE0F WebSocket unavailable, using SSE fallback: ${wsError instanceof Error ? wsError.message : String(wsError)}`
2960
+ );
2945
2961
  if (wsError instanceof Error && wsError.stack) {
2946
- logger.debug(`[WebSocket] Stack: ${wsError.stack}`);
2962
+ console.error(wsError.stack);
2947
2963
  }
2948
2964
  wsManager = null;
2949
2965
  setWebSocketToolExecutor(null);
@@ -3727,11 +3743,7 @@ Pull a model: ollama pull qwen3.5`
3727
3743
  return;
3728
3744
  }
3729
3745
  }
3730
- const errorMessage = error instanceof Error ? error.message : String(error);
3731
- console.error(`
3732
- \u274C ${errorMessage}
3733
- `);
3734
- logger.debug(`Full error details: ${error instanceof Error ? error.stack || error.message : String(error)}`);
3746
+ console.error("Error processing message:", error);
3735
3747
  } finally {
3736
3748
  setState((prev) => ({ ...prev, abortController: null }));
3737
3749
  useCliStore.getState().setIsThinking(false);
@@ -4028,6 +4040,9 @@ Custom Commands:
4028
4040
  /commands:new <name> - Create a new custom command
4029
4041
  /commands:reload - Reload custom commands from disk
4030
4042
 
4043
+ Terminal Setup:
4044
+ /terminal-setup - Configure Shift+Enter for multi-line input
4045
+
4031
4046
  Keyboard Shortcuts:
4032
4047
  Ctrl+C - Press twice to exit
4033
4048
  Esc - Abort current operation
@@ -4043,7 +4058,12 @@ Keyboard Shortcuts:
4043
4058
  Ctrl+L - Clear input
4044
4059
  \u2191 / \u2193 - Navigate history / autocomplete
4045
4060
  Tab - Accept autocomplete suggestion
4046
- Shift+Cmd+Click - Open links in browser${hasCustomCommands ? "\n\n\u{1F4DD} Custom Commands Available:" : ""}${hasCustomCommands ? customCommands.map((cmd) => {
4061
+ Shift+Cmd+Click - Open links in browser
4062
+
4063
+ Multi-line Input:
4064
+ \\ + Enter - Insert newline (works everywhere)
4065
+ Option + Enter - Insert newline (macOS standard terminals)
4066
+ Shift + Enter - Insert newline (iTerm2, WezTerm, Ghostty, Kitty)${hasCustomCommands ? "\n\n\u{1F4DD} Custom Commands Available:" : ""}${hasCustomCommands ? customCommands.map((cmd) => {
4047
4067
  const source = cmd.source === "global" ? "\u{1F3E0}" : "\u{1F4C1}";
4048
4068
  const argHint = cmd.argumentHint ? ` ${cmd.argumentHint}` : "";
4049
4069
  return `
@@ -5058,6 +5078,11 @@ Allowed domains (${domains.length}):`);
5058
5078
  console.log("");
5059
5079
  break;
5060
5080
  }
5081
+ case "terminal-setup": {
5082
+ const { runTerminalSetup } = await import("./terminalSetup-C5FHMLC3.js");
5083
+ await runTerminalSetup();
5084
+ break;
5085
+ }
5061
5086
  case "add-dir": {
5062
5087
  let dirPath = args.join(" ").trim();
5063
5088
  if (!dirPath) {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CurationArtifactType
4
- } from "./chunk-QLY3LGPA.js";
4
+ } from "./chunk-YRYNVLXM.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-QLY3LGPA.js";
4
+ } from "./chunk-YRYNVLXM.js";
5
5
 
6
6
  // ../../b4m-core/packages/services/dist/src/notebookCurationService/markdownGenerator.js
7
7
  var DEFAULT_OPTIONS = {
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  findMostSimilarMemento,
4
4
  getRelevantMementos
5
- } from "./chunk-7VEI22BF.js";
6
- import "./chunk-UDBM5N7V.js";
5
+ } from "./chunk-2K6DFEPJ.js";
6
+ import "./chunk-QU3ADG2K.js";
7
7
  import "./chunk-PFBYGCOW.js";
8
- import "./chunk-QLY3LGPA.js";
8
+ import "./chunk-YRYNVLXM.js";
9
9
  export {
10
10
  findMostSimilarMemento,
11
11
  getRelevantMementos
@@ -143,7 +143,7 @@ import {
143
143
  validateUrlForFetch,
144
144
  warmUpSettingsCache,
145
145
  withRetry
146
- } from "./chunk-UDBM5N7V.js";
146
+ } from "./chunk-QU3ADG2K.js";
147
147
  import {
148
148
  Logger,
149
149
  NotificationDeduplicator,
@@ -156,7 +156,7 @@ import {
156
156
  buildRateLimitLogEntry,
157
157
  isNearLimit,
158
158
  parseRateLimitHeaders
159
- } from "./chunk-QLY3LGPA.js";
159
+ } from "./chunk-YRYNVLXM.js";
160
160
  export {
161
161
  AIVideoService,
162
162
  AWSBackend,
@@ -525,7 +525,7 @@ import {
525
525
  validateReactArtifactV2,
526
526
  validateSvgArtifactV2,
527
527
  wikiMarkupToAdf
528
- } from "./chunk-QLY3LGPA.js";
528
+ } from "./chunk-YRYNVLXM.js";
529
529
  export {
530
530
  ALERT_THRESHOLDS,
531
531
  ALL_IMAGE_MODELS,
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  SubtractCreditsSchema,
4
4
  subtractCredits
5
- } from "./chunk-X26VCD3A.js";
6
- import "./chunk-UDBM5N7V.js";
5
+ } from "./chunk-UVP4KCPD.js";
6
+ import "./chunk-QU3ADG2K.js";
7
7
  import "./chunk-PFBYGCOW.js";
8
- import "./chunk-QLY3LGPA.js";
8
+ import "./chunk-YRYNVLXM.js";
9
9
  export {
10
10
  SubtractCreditsSchema,
11
11
  subtractCredits
@@ -0,0 +1,214 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/utils/terminalSetup.ts
4
+ import { existsSync, promises as fs } from "fs";
5
+ import path from "path";
6
+ import { homedir } from "os";
7
+ var TERMINAL_INFO = {
8
+ iterm2: { name: "iTerm2", status: "native" },
9
+ wezterm: { name: "WezTerm", status: "native" },
10
+ ghostty: { name: "Ghostty", status: "native" },
11
+ kitty: { name: "Kitty", status: "native" },
12
+ vscode: { name: "VS Code", status: "configurable" },
13
+ alacritty: { name: "Alacritty", status: "configurable" },
14
+ zed: { name: "Zed", status: "manual" },
15
+ terminal_app: { name: "Terminal.app", status: "manual" },
16
+ warp: { name: "Warp", status: "manual" },
17
+ unknown: { name: "Unknown", status: "unknown" }
18
+ };
19
+ function detectTerminal() {
20
+ const termProgram = process.env["TERM_PROGRAM"] ?? "";
21
+ const term = process.env["TERM"] ?? "";
22
+ if (termProgram === "vscode" || process.env["VSCODE_PID"]) {
23
+ return { id: "vscode", ...TERMINAL_INFO.vscode };
24
+ }
25
+ if (termProgram === "iTerm.app" || process.env["ITERM_SESSION_ID"]) {
26
+ return { id: "iterm2", ...TERMINAL_INFO.iterm2 };
27
+ }
28
+ if (termProgram === "WezTerm" || process.env["WEZTERM_PANE"]) {
29
+ return { id: "wezterm", ...TERMINAL_INFO.wezterm };
30
+ }
31
+ if (termProgram === "ghostty" || term === "xterm-ghostty") {
32
+ return { id: "ghostty", ...TERMINAL_INFO.ghostty };
33
+ }
34
+ if (term === "xterm-kitty" || process.env["KITTY_PID"]) {
35
+ return { id: "kitty", ...TERMINAL_INFO.kitty };
36
+ }
37
+ if (termProgram === "Alacritty" || term === "alacritty") {
38
+ return { id: "alacritty", ...TERMINAL_INFO.alacritty };
39
+ }
40
+ if (termProgram === "WarpTerminal" || process.env["WARP_IS_LOCAL_SHELL_SESSION"]) {
41
+ return { id: "warp", ...TERMINAL_INFO.warp };
42
+ }
43
+ if (termProgram === "zed") {
44
+ return { id: "zed", ...TERMINAL_INFO.zed };
45
+ }
46
+ if (termProgram === "Apple_Terminal") {
47
+ return { id: "terminal_app", ...TERMINAL_INFO.terminal_app };
48
+ }
49
+ return { id: "unknown", ...TERMINAL_INFO.unknown };
50
+ }
51
+ var VSCODE_KEYBINDING = {
52
+ key: "shift+enter",
53
+ command: "workbench.action.terminal.sendSequence",
54
+ args: { text: "\x1B[13;2u" },
55
+ when: "terminalFocus"
56
+ };
57
+ async function setupVSCode() {
58
+ const vscodeDirs = [
59
+ path.join(homedir(), "Library", "Application Support", "Code", "User"),
60
+ // macOS
61
+ path.join(homedir(), ".config", "Code", "User"),
62
+ // Linux
63
+ path.join(homedir(), "AppData", "Roaming", "Code", "User")
64
+ // Windows
65
+ ];
66
+ const vscodeDir = vscodeDirs.find((dir) => existsSync(dir));
67
+ if (!vscodeDir) {
68
+ return {
69
+ success: false,
70
+ message: "Could not find VS Code settings directory.\nManually add this to your keybindings.json (Cmd+K Cmd+S \u2192 Open Keyboard Shortcuts JSON):\n\n" + JSON.stringify(VSCODE_KEYBINDING, null, 2)
71
+ };
72
+ }
73
+ const keybindingsPath = path.join(vscodeDir, "keybindings.json");
74
+ let keybindings = [];
75
+ if (existsSync(keybindingsPath)) {
76
+ const content = await fs.readFile(keybindingsPath, "utf-8");
77
+ const stripped = content.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
78
+ try {
79
+ keybindings = JSON.parse(stripped);
80
+ } catch {
81
+ return {
82
+ success: false,
83
+ message: "Could not parse keybindings.json. Manually add this entry:\n\n" + JSON.stringify(VSCODE_KEYBINDING, null, 2)
84
+ };
85
+ }
86
+ }
87
+ const alreadyConfigured = keybindings.some(
88
+ (binding) => binding["key"] === "shift+enter" && binding["command"] === "workbench.action.terminal.sendSequence" && binding["when"] === "terminalFocus"
89
+ );
90
+ if (alreadyConfigured) {
91
+ return {
92
+ success: true,
93
+ message: "VS Code is already configured for Shift+Enter newlines."
94
+ };
95
+ }
96
+ keybindings.push(VSCODE_KEYBINDING);
97
+ await fs.writeFile(keybindingsPath, JSON.stringify(keybindings, null, 2) + "\n", "utf-8");
98
+ return {
99
+ success: true,
100
+ message: `Updated ${keybindingsPath}
101
+ Shift+Enter will now insert a newline in the B4M CLI.
102
+ Restart your VS Code terminal for the change to take effect.`
103
+ };
104
+ }
105
+ var ALACRITTY_TOML_SNIPPET = `
106
+ # B4M CLI: Shift+Enter sends Kitty-protocol sequence for newline
107
+ [[keyboard.bindings]]
108
+ key = "Return"
109
+ mods = "Shift"
110
+ chars = "\\u001b[13;2u"
111
+ `.trim();
112
+ async function setupAlacritty() {
113
+ const configPaths = [
114
+ path.join(homedir(), ".config", "alacritty", "alacritty.toml"),
115
+ path.join(homedir(), ".alacritty.toml")
116
+ ];
117
+ const existingConfig = configPaths.find((p) => existsSync(p));
118
+ const configPath = existingConfig ?? configPaths[0];
119
+ let content = "";
120
+ if (existingConfig) {
121
+ content = await fs.readFile(configPath, "utf-8");
122
+ if (content.includes("[13;2u") || content.includes("\\u001b[13;2u")) {
123
+ return {
124
+ success: true,
125
+ message: "Alacritty is already configured for Shift+Enter newlines."
126
+ };
127
+ }
128
+ }
129
+ const newContent = content ? content.trimEnd() + "\n\n" + ALACRITTY_TOML_SNIPPET + "\n" : ALACRITTY_TOML_SNIPPET + "\n";
130
+ const configDir = path.dirname(configPath);
131
+ if (!existsSync(configDir)) {
132
+ await fs.mkdir(configDir, { recursive: true });
133
+ }
134
+ await fs.writeFile(configPath, newContent, "utf-8");
135
+ return {
136
+ success: true,
137
+ message: `Updated ${configPath}
138
+ Shift+Enter will now insert a newline in the B4M CLI.
139
+ Restart Alacritty for the change to take effect.`
140
+ };
141
+ }
142
+ function getManualInstructions(terminal) {
143
+ switch (terminal.id) {
144
+ case "zed":
145
+ return "Add this to your Zed keymap.json (Zed \u2192 Settings \u2192 Open Key Bindings):\n\n" + JSON.stringify(
146
+ [
147
+ {
148
+ context: "Terminal",
149
+ bindings: {
150
+ "shift-enter": ["terminal::SendText", "\\u001b[13;2u"]
151
+ }
152
+ }
153
+ ],
154
+ null,
155
+ 2
156
+ );
157
+ case "terminal_app":
158
+ return "macOS Terminal.app cannot send distinct Shift+Enter sequences.\n\nAlternatives:\n \u2022 Use Option+Enter (\u2325+Enter) to insert newlines\n \u2022 Type \\ then Enter to insert newlines\n \u2022 Switch to iTerm2, WezTerm, or Ghostty for native Shift+Enter support";
159
+ case "warp":
160
+ return "Warp terminal has limited keybinding customization.\n\nAlternatives:\n \u2022 Use Option+Enter (\u2325+Enter) to insert newlines\n \u2022 Type \\ then Enter to insert newlines";
161
+ default:
162
+ return "Your terminal needs to be configured to send a distinct escape sequence for Shift+Enter.\nConfigure Shift+Enter to send: \\x1b[13;2u (Kitty keyboard protocol)\n\nAlternatives that work in all terminals:\n \u2022 Option/Alt+Enter to insert newlines\n \u2022 Type \\ then Enter to insert newlines";
163
+ }
164
+ }
165
+ async function runTerminalSetup() {
166
+ const terminal = detectTerminal();
167
+ console.log(`
168
+ Detected terminal: ${terminal.name}
169
+ `);
170
+ switch (terminal.status) {
171
+ case "native":
172
+ console.log(`\u2705 ${terminal.name} natively supports Shift+Enter for newlines.
173
+ No configuration needed!
174
+ `);
175
+ break;
176
+ case "configurable": {
177
+ console.log(`Configuring ${terminal.name} for Shift+Enter support...
178
+ `);
179
+ let result;
180
+ switch (terminal.id) {
181
+ case "vscode":
182
+ result = await setupVSCode();
183
+ break;
184
+ case "alacritty":
185
+ result = await setupAlacritty();
186
+ break;
187
+ default:
188
+ result = { success: false, message: "No auto-configuration available." };
189
+ }
190
+ console.log(result.success ? `\u2705 ${result.message}` : `\u26A0\uFE0F ${result.message}`);
191
+ console.log();
192
+ break;
193
+ }
194
+ case "manual":
195
+ console.log(`\u26A0\uFE0F ${terminal.name} requires manual configuration.
196
+ `);
197
+ console.log(getManualInstructions(terminal));
198
+ console.log();
199
+ break;
200
+ case "unknown":
201
+ console.log(getManualInstructions(terminal));
202
+ console.log();
203
+ break;
204
+ }
205
+ console.log("Universal newline methods (work in all terminals):");
206
+ console.log(" \u2022 Option/Alt + Enter \u2014 insert newline");
207
+ console.log(" \u2022 \\ + Enter \u2014 insert newline (backslash-escape)");
208
+ console.log(" \u2022 Shift + Enter \u2014 insert newline (if terminal supports Kitty protocol)");
209
+ console.log();
210
+ }
211
+ export {
212
+ detectTerminal,
213
+ runTerminalSetup
214
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bike4mind/cli",
3
- "version": "0.2.49-fix-cli-stream-resilience-v2.21033+6a9f2b5b5",
3
+ "version": "0.2.49-prod.21090+4ff436a32",
4
4
  "type": "module",
5
5
  "description": "Interactive CLI tool for Bike4Mind with ReAct agents",
6
6
  "license": "UNLICENSED",
@@ -61,7 +61,7 @@
61
61
  "@smithy/node-http-handler": "^4.4.14",
62
62
  "async-mutex": "^0.5.0",
63
63
  "axios": "^1.13.6",
64
- "bcryptjs": "^2.4.3",
64
+ "bcryptjs": "^3.0.2",
65
65
  "better-sqlite3": "^12.6.2",
66
66
  "cheerio": "1.0.0-rc.12",
67
67
  "cli-highlight": "^2.1.11",
@@ -115,10 +115,10 @@
115
115
  },
116
116
  "devDependencies": {
117
117
  "@bike4mind/agents": "0.1.0",
118
- "@bike4mind/common": "2.67.1-fix-cli-stream-resilience-v2.21033+6a9f2b5b5",
119
- "@bike4mind/mcp": "1.33.11-fix-cli-stream-resilience-v2.21033+6a9f2b5b5",
120
- "@bike4mind/services": "2.63.1-fix-cli-stream-resilience-v2.21033+6a9f2b5b5",
121
- "@bike4mind/utils": "2.15.4-fix-cli-stream-resilience-v2.21033+6a9f2b5b5",
118
+ "@bike4mind/common": "2.67.1-prod.21090+4ff436a32",
119
+ "@bike4mind/mcp": "1.33.11-prod.21090+4ff436a32",
120
+ "@bike4mind/services": "2.63.1-prod.21090+4ff436a32",
121
+ "@bike4mind/utils": "2.15.4-prod.21090+4ff436a32",
122
122
  "@types/better-sqlite3": "^7.6.13",
123
123
  "@types/diff": "^5.0.9",
124
124
  "@types/jsonwebtoken": "^9.0.4",
@@ -137,5 +137,5 @@
137
137
  "optionalDependencies": {
138
138
  "@vscode/ripgrep": "^1.17.0"
139
139
  },
140
- "gitHead": "6a9f2b5b5ef81c255f95f35bdbdc6339fe2f7c3f"
140
+ "gitHead": "4ff436a32269365aba08bda30e846fad8c6142ee"
141
141
  }