@bike4mind/cli 0.2.10-slack-metrics-admin-dashboard.17271 → 0.2.11-cli-cancel-pending-message.17326

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4,9 +4,9 @@ import {
4
4
  getEffectiveApiKey,
5
5
  getOpenWeatherKey,
6
6
  getSerperKey
7
- } from "./chunk-GO75FMLY.js";
8
- import "./chunk-VZU4Z7WI.js";
9
- import "./chunk-AQBZVAYO.js";
7
+ } from "./chunk-DGAIF2QC.js";
8
+ import "./chunk-RBZRTCAY.js";
9
+ import "./chunk-RA3CZOUX.js";
10
10
  import {
11
11
  BFLImageService,
12
12
  BaseStorage,
@@ -15,7 +15,7 @@ import {
15
15
  OpenAIBackend,
16
16
  OpenAIImageService,
17
17
  XAIImageService
18
- } from "./chunk-GCVIRGIN.js";
18
+ } from "./chunk-SQBLLN7K.js";
19
19
  import {
20
20
  Logger
21
21
  } from "./chunk-AMDXHL6S.js";
@@ -73,7 +73,7 @@ import {
73
73
  XAI_IMAGE_MODELS,
74
74
  b4mLLMTools,
75
75
  getMcpProviderMetadata
76
- } from "./chunk-DJPXSSP4.js";
76
+ } from "./chunk-WCYNJOOX.js";
77
77
  import {
78
78
  __require
79
79
  } from "./chunk-PDX44BCA.js";
@@ -82,7 +82,7 @@ import {
82
82
  import React17, { useState as useState8, useEffect as useEffect3, useCallback, useRef as useRef2 } from "react";
83
83
  import { render, Box as Box16, Text as Text16, useApp, useInput as useInput6 } from "ink";
84
84
  import { execSync } from "child_process";
85
- import { v4 as uuidv49 } from "uuid";
85
+ import { v4 as uuidv410 } from "uuid";
86
86
 
87
87
  // src/components/App.tsx
88
88
  import React11, { useState as useState4 } from "react";
@@ -107,7 +107,8 @@ function CustomTextInput({
107
107
  onChange,
108
108
  onSubmit,
109
109
  placeholder = "",
110
- showCursor = true
110
+ showCursor = true,
111
+ disabled = false
111
112
  }) {
112
113
  const [cursorOffset, setCursorOffset] = useState(value.length);
113
114
  useInput(
@@ -188,7 +189,7 @@ function CustomTextInput({
188
189
  setCursorOffset(cursorOffset + 1);
189
190
  }
190
191
  },
191
- { isActive: true }
192
+ { isActive: !disabled }
192
193
  );
193
194
  const hasValue = value.length > 0;
194
195
  if (!hasValue) {
@@ -827,56 +828,59 @@ function InputPrompt({
827
828
  useEffect(() => {
828
829
  setFileSelectedIndex(0);
829
830
  }, [filteredFiles]);
830
- useInput2((_input, key) => {
831
- if (fileAutocomplete?.active && filteredFiles.length > 0) {
832
- if (key.upArrow) {
833
- setFileSelectedIndex((prev) => prev > 0 ? prev - 1 : filteredFiles.length - 1);
834
- return;
835
- } else if (key.downArrow) {
836
- setFileSelectedIndex((prev) => prev < filteredFiles.length - 1 ? prev + 1 : 0);
837
- return;
838
- } else if (key.tab) {
839
- const selectedFile = filteredFiles[fileSelectedIndex];
840
- if (selectedFile) {
841
- insertSelectedFile(selectedFile);
831
+ useInput2(
832
+ (_input, key) => {
833
+ if (fileAutocomplete?.active && filteredFiles.length > 0) {
834
+ if (key.upArrow) {
835
+ setFileSelectedIndex((prev) => prev > 0 ? prev - 1 : filteredFiles.length - 1);
836
+ return;
837
+ } else if (key.downArrow) {
838
+ setFileSelectedIndex((prev) => prev < filteredFiles.length - 1 ? prev + 1 : 0);
839
+ return;
840
+ } else if (key.tab) {
841
+ const selectedFile = filteredFiles[fileSelectedIndex];
842
+ if (selectedFile) {
843
+ insertSelectedFile(selectedFile);
844
+ }
845
+ return;
846
+ } else if (key.escape) {
847
+ setFileAutocomplete(null);
848
+ return;
842
849
  }
843
- return;
844
- } else if (key.escape) {
845
- setFileAutocomplete(null);
846
- return;
847
- }
848
- }
849
- if (shouldShowCommandAutocomplete && filteredCommands.length > 0) {
850
- if (key.upArrow) {
851
- setSelectedIndex((prev) => prev > 0 ? prev - 1 : filteredCommands.length - 1);
852
- } else if (key.downArrow) {
853
- setSelectedIndex((prev) => prev < filteredCommands.length - 1 ? prev + 1 : 0);
854
850
  }
855
- return;
856
- }
857
- if (!shouldShowCommandAutocomplete && !fileAutocomplete?.active && history.length > 0) {
858
- if (key.upArrow) {
859
- if (historyIndex === -1) {
860
- setTempInput(value);
861
- setHistoryIndex(0);
862
- setValue(history[0]);
863
- } else if (historyIndex < history.length - 1) {
864
- const newIndex = historyIndex + 1;
865
- setHistoryIndex(newIndex);
866
- setValue(history[newIndex]);
851
+ if (shouldShowCommandAutocomplete && filteredCommands.length > 0) {
852
+ if (key.upArrow) {
853
+ setSelectedIndex((prev) => prev > 0 ? prev - 1 : filteredCommands.length - 1);
854
+ } else if (key.downArrow) {
855
+ setSelectedIndex((prev) => prev < filteredCommands.length - 1 ? prev + 1 : 0);
867
856
  }
868
- } else if (key.downArrow) {
869
- if (historyIndex > 0) {
870
- const newIndex = historyIndex - 1;
871
- setHistoryIndex(newIndex);
872
- setValue(history[newIndex]);
873
- } else if (historyIndex === 0) {
874
- setHistoryIndex(-1);
875
- setValue(tempInput);
857
+ return;
858
+ }
859
+ if (!shouldShowCommandAutocomplete && !fileAutocomplete?.active && history.length > 0) {
860
+ if (key.upArrow) {
861
+ if (historyIndex === -1) {
862
+ setTempInput(value);
863
+ setHistoryIndex(0);
864
+ setValue(history[0]);
865
+ } else if (historyIndex < history.length - 1) {
866
+ const newIndex = historyIndex + 1;
867
+ setHistoryIndex(newIndex);
868
+ setValue(history[newIndex]);
869
+ }
870
+ } else if (key.downArrow) {
871
+ if (historyIndex > 0) {
872
+ const newIndex = historyIndex - 1;
873
+ setHistoryIndex(newIndex);
874
+ setValue(history[newIndex]);
875
+ } else if (historyIndex === 0) {
876
+ setHistoryIndex(-1);
877
+ setValue(tempInput);
878
+ }
876
879
  }
877
880
  }
878
- }
879
- });
881
+ },
882
+ { isActive: !disabled }
883
+ );
880
884
  const insertSelectedFile = (file) => {
881
885
  if (!fileAutocomplete) return;
882
886
  const beforeAt = value.slice(0, fileAutocomplete.startIndex);
@@ -970,7 +974,8 @@ function InputPrompt({
970
974
  onChange: handleChange,
971
975
  onSubmit: handleSubmit,
972
976
  placeholder: getPlaceholder(),
973
- showCursor: !disabled
977
+ showCursor: !disabled,
978
+ disabled
974
979
  }
975
980
  )), shouldShowCommandAutocomplete && /* @__PURE__ */ React5.createElement(CommandAutocomplete, { commands: filteredCommands, selectedIndex }), fileAutocomplete?.active && /* @__PURE__ */ React5.createElement(FileAutocomplete, { files: filteredFiles, selectedIndex: fileSelectedIndex, query: fileAutocomplete.query }));
976
981
  }
@@ -983,8 +988,8 @@ import { Box as Box6 } from "ink";
983
988
  import React6 from "react";
984
989
  import { Box as Box5, Text as Text6 } from "ink";
985
990
  import Spinner from "ink-spinner";
986
- var ThoughtStream = React6.memo(function ThoughtStream2({ steps }) {
987
- return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column", gap: 1 }, steps.map((step, index) => /* @__PURE__ */ React6.createElement(Box5, { key: index, flexDirection: "column" }, step.type === "thought" && /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "magenta" }, "\u{1F914} Thought: "), /* @__PURE__ */ React6.createElement(Text6, null, step.content)), step.type === "action" && /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, "\u26A1 Action: "), /* @__PURE__ */ React6.createElement(Text6, { bold: true }, step.metadata?.toolName || "unknown")), step.metadata?.toolInput && /* @__PURE__ */ React6.createElement(Box5, { paddingLeft: 2 }, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, JSON.stringify(step.metadata.toolInput, null, 2)))), step.type === "observation" && /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "blue" }, "\u{1F4CA} Observation: ")), /* @__PURE__ */ React6.createElement(Box5, { paddingLeft: 2 }, /* @__PURE__ */ React6.createElement(Text6, null, step.content))), step.type === "final_answer" && /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "green", bold: true }, "\u2705 Final Answer:", " ")), /* @__PURE__ */ React6.createElement(Box5, { paddingLeft: 2 }, /* @__PURE__ */ React6.createElement(Text6, null, step.content)), step.metadata?.tokenUsage && /* @__PURE__ */ React6.createElement(Box5, { paddingLeft: 2 }, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "(", step.metadata.tokenUsage.total, " tokens)"))))), !steps.some((s) => s.type === "final_answer") && /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, /* @__PURE__ */ React6.createElement(Spinner, { type: "dots" })), /* @__PURE__ */ React6.createElement(Text6, null, " ", steps.length === 0 ? "Thinking..." : "Processing...")));
991
+ var ThoughtStream = React6.memo(function ThoughtStream2({ isThinking }) {
992
+ return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column", gap: 1 }, isThinking && /* @__PURE__ */ React6.createElement(Box5, null, /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, /* @__PURE__ */ React6.createElement(Spinner, { type: "dots" })), /* @__PURE__ */ React6.createElement(Text6, null, " Thinking...")));
988
993
  });
989
994
 
990
995
  // src/store/index.ts
@@ -1029,12 +1034,6 @@ var useCliStore = create((set) => ({
1029
1034
  // UI state
1030
1035
  isThinking: false,
1031
1036
  setIsThinking: (thinking) => set({ isThinking: thinking }),
1032
- agentSteps: [],
1033
- addAgentStep: (step) => set((state) => ({
1034
- agentSteps: [...state.agentSteps, step]
1035
- })),
1036
- setAgentSteps: (steps) => set({ agentSteps: steps }),
1037
- clearAgentSteps: () => set({ agentSteps: [] }),
1038
1037
  // Permission prompt
1039
1038
  permissionPrompt: null,
1040
1039
  setPermissionPrompt: (prompt) => set({ permissionPrompt: prompt }),
@@ -1049,11 +1048,10 @@ var useCliStore = create((set) => ({
1049
1048
  // src/components/AgentThinking.tsx
1050
1049
  var AgentThinking = React7.memo(function AgentThinking2() {
1051
1050
  const isThinking = useCliStore((state) => state.isThinking);
1052
- const agentSteps = useCliStore((state) => state.agentSteps);
1053
1051
  if (!isThinking) {
1054
1052
  return null;
1055
1053
  }
1056
- return /* @__PURE__ */ React7.createElement(Box6, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React7.createElement(ThoughtStream, { steps: agentSteps }));
1054
+ return /* @__PURE__ */ React7.createElement(Box6, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React7.createElement(ThoughtStream, { isThinking }));
1057
1055
  });
1058
1056
 
1059
1057
  // src/components/PermissionPrompt.tsx
@@ -1091,7 +1089,10 @@ function PermissionPrompt({
1091
1089
  { label: "\u2713 Allow once", value: "allow-once" },
1092
1090
  { label: "\u2717 Deny", value: "deny" }
1093
1091
  ];
1094
- const argsString = typeof args === "string" ? args : JSON.stringify(args, null, 2);
1092
+ const MAX_ARGS_LENGTH = 500;
1093
+ const rawArgsString = typeof args === "string" ? args : JSON.stringify(args, null, 2);
1094
+ const argsString = rawArgsString.length > MAX_ARGS_LENGTH ? rawArgsString.slice(0, MAX_ARGS_LENGTH) + `
1095
+ ... (${rawArgsString.length - MAX_ARGS_LENGTH} more chars)` : rawArgsString;
1095
1096
  return /* @__PURE__ */ React8.createElement(Box7, { flexDirection: "column", borderStyle: "bold", borderColor: "yellow", padding: 1, marginY: 1 }, /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "yellow" }, "\u26A0\uFE0F Permission Required")), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, "Tool: "), /* @__PURE__ */ React8.createElement(Text7, { bold: true, color: "cyan" }, toolName)), toolDescription && /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, "Action: "), /* @__PURE__ */ React8.createElement(Text7, null, toolDescription)), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text7, { bold: true }, "Arguments:"), /* @__PURE__ */ React8.createElement(Box7, { paddingLeft: 2, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text7, { dimColor: true }, argsString))), preview && /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React8.createElement(Text7, { bold: true }, "Preview:"), /* @__PURE__ */ React8.createElement(Box7, { borderStyle: "single", borderColor: "gray", paddingX: 1, flexDirection: "column" }, renderDiffPreview(preview))), !canBeTrusted && /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(Text7, { color: "red", dimColor: true }, "Note: This tool cannot be trusted due to its dangerous nature.")), /* @__PURE__ */ React8.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React8.createElement(SelectInput, { items, onSelect: (item) => onResponse(item.value) })));
1096
1097
  }
1097
1098
 
@@ -1523,7 +1524,7 @@ ${errorBlock}`;
1523
1524
  onSave: onSaveConfig,
1524
1525
  onClose: () => setShowConfigEditor(false)
1525
1526
  }
1526
- )) : permissionPrompt ? /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React11.createElement(
1527
+ )) : /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(Static, { items: messages }, (message) => /* @__PURE__ */ React11.createElement(Box10, { key: message.id, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React11.createElement(MessageItem, { message }))), /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column" }, pendingMessages.map((message) => /* @__PURE__ */ React11.createElement(Box10, { key: message.id, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React11.createElement(MessageItem, { message })))), permissionPrompt && /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React11.createElement(
1527
1528
  PermissionPrompt,
1528
1529
  {
1529
1530
  toolName: permissionPrompt.toolName,
@@ -1532,13 +1533,13 @@ ${errorBlock}`;
1532
1533
  canBeTrusted: permissionPrompt.canBeTrusted,
1533
1534
  onResponse: onPermissionResponse
1534
1535
  }
1535
- )) : /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(Static, { items: messages }, (message, index) => /* @__PURE__ */ React11.createElement(Box10, { key: `${message.timestamp}-${message.role}-${index}`, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React11.createElement(MessageItem, { message }))), /* @__PURE__ */ React11.createElement(Box10, { flexDirection: "column" }, pendingMessages.map((message, index) => /* @__PURE__ */ React11.createElement(Box10, { key: `pending-${message.timestamp}-${index}`, flexDirection: "column", paddingX: 1 }, /* @__PURE__ */ React11.createElement(MessageItem, { message })))), /* @__PURE__ */ React11.createElement(AgentThinking, null), exitRequested && /* @__PURE__ */ React11.createElement(Box10, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React11.createElement(Text10, { color: "yellow", bold: true }, "Press Ctrl+C again to exit")), /* @__PURE__ */ React11.createElement(Box10, { borderStyle: "single", borderColor: isBashMode ? "yellow" : "cyan", paddingX: 1 }, /* @__PURE__ */ React11.createElement(
1536
+ )), !permissionPrompt && /* @__PURE__ */ React11.createElement(AgentThinking, null), exitRequested && /* @__PURE__ */ React11.createElement(Box10, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React11.createElement(Text10, { color: "yellow", bold: true }, "Press Ctrl+C again to exit")), /* @__PURE__ */ React11.createElement(Box10, { borderStyle: "single", borderColor: isBashMode ? "yellow" : "cyan", paddingX: 1 }, /* @__PURE__ */ React11.createElement(
1536
1537
  InputPrompt,
1537
1538
  {
1538
1539
  onSubmit: handleSubmit,
1539
1540
  onBashCommand,
1540
1541
  onImageDetected,
1541
- disabled: isThinking,
1542
+ disabled: isThinking || !!permissionPrompt,
1542
1543
  history: commandHistory,
1543
1544
  commands,
1544
1545
  prefillInput,
@@ -1932,6 +1933,7 @@ function LoginFlow({ apiUrl = "http://localhost:3000", configStore, onSuccess, o
1932
1933
  import { promises as fs3 } from "fs";
1933
1934
  import path3 from "path";
1934
1935
  import { homedir } from "os";
1936
+ import { v4 as uuidv4 } from "uuid";
1935
1937
  var SessionStore = class {
1936
1938
  constructor(basePath) {
1937
1939
  this.basePath = basePath || path3.join(homedir(), ".bike4mind", "sessions");
@@ -1967,7 +1969,14 @@ var SessionStore = class {
1967
1969
  const filePath = path3.join(this.basePath, `${id}.json`);
1968
1970
  try {
1969
1971
  const data = await fs3.readFile(filePath, "utf-8");
1970
- return JSON.parse(data);
1972
+ const session = JSON.parse(data);
1973
+ session.messages = session.messages.map((msg) => {
1974
+ if (!msg.id) {
1975
+ return { ...msg, id: uuidv4() };
1976
+ }
1977
+ return msg;
1978
+ });
1979
+ return session;
1971
1980
  } catch (error) {
1972
1981
  if (error.code === "ENOENT") {
1973
1982
  return null;
@@ -1996,7 +2005,14 @@ var SessionStore = class {
1996
2005
  jsonFiles.map(async (file) => {
1997
2006
  const filePath = path3.join(this.basePath, file);
1998
2007
  const data = await fs3.readFile(filePath, "utf-8");
1999
- return JSON.parse(data);
2008
+ const session = JSON.parse(data);
2009
+ session.messages = session.messages.map((msg) => {
2010
+ if (!msg.id) {
2011
+ return { ...msg, id: uuidv4() };
2012
+ }
2013
+ return msg;
2014
+ });
2015
+ return session;
2000
2016
  })
2001
2017
  );
2002
2018
  return sessions.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
@@ -2050,7 +2066,7 @@ var SessionStore = class {
2050
2066
  import { promises as fs4, existsSync as existsSync3 } from "fs";
2051
2067
  import path4 from "path";
2052
2068
  import { homedir as homedir2 } from "os";
2053
- import { v4 as uuidv4 } from "uuid";
2069
+ import { v4 as uuidv42 } from "uuid";
2054
2070
  import { z } from "zod";
2055
2071
  var AuthTokensSchema = z.object({
2056
2072
  accessToken: z.string(),
@@ -2144,7 +2160,7 @@ var ProjectLocalConfigSchema = z.object({
2144
2160
  });
2145
2161
  var DEFAULT_CONFIG = {
2146
2162
  version: "0.1.0",
2147
- userId: uuidv4(),
2163
+ userId: uuidv42(),
2148
2164
  defaultModel: "claude-sonnet-4-5-20250929",
2149
2165
  toolApiKeys: {
2150
2166
  openweather: void 0,
@@ -2361,15 +2377,19 @@ var ConfigStore = class {
2361
2377
  throw error;
2362
2378
  }
2363
2379
  }
2364
- this.projectConfigDir = findProjectConfigDir();
2365
2380
  let projectConfig = null;
2366
2381
  let projectLocalConfig = null;
2367
- if (this.projectConfigDir) {
2368
- projectConfig = await loadProjectConfig(this.projectConfigDir);
2369
- projectLocalConfig = await loadProjectLocalConfig(this.projectConfigDir);
2370
- if (projectConfig) {
2371
- console.log(`\u{1F4C1} Project config loaded from: ${this.projectConfigDir}/.bike4mind/`);
2382
+ if (process.env.B4M_NO_PROJECT_CONFIG !== "1") {
2383
+ this.projectConfigDir = findProjectConfigDir();
2384
+ if (this.projectConfigDir) {
2385
+ projectConfig = await loadProjectConfig(this.projectConfigDir);
2386
+ projectLocalConfig = await loadProjectLocalConfig(this.projectConfigDir);
2387
+ if (projectConfig) {
2388
+ console.log(`\u{1F4C1} Project config loaded from: ${this.projectConfigDir}/.bike4mind/`);
2389
+ }
2372
2390
  }
2391
+ } else {
2392
+ this.projectConfigDir = null;
2373
2393
  }
2374
2394
  this.config = mergeConfigs(globalConfig, projectConfig, projectLocalConfig);
2375
2395
  return this.config;
@@ -2426,7 +2446,7 @@ var ConfigStore = class {
2426
2446
  * Reset configuration to defaults
2427
2447
  */
2428
2448
  async reset() {
2429
- this.config = { ...DEFAULT_CONFIG, userId: uuidv4() };
2449
+ this.config = { ...DEFAULT_CONFIG, userId: uuidv42() };
2430
2450
  await this.save();
2431
2451
  return this.config;
2432
2452
  }
@@ -3129,6 +3149,7 @@ ${options.context}` : this.getSystemPrompt()
3129
3149
  }
3130
3150
  if (completionInfo.toolsUsed && completionInfo.toolsUsed.length > 0) {
3131
3151
  hadToolCalls = true;
3152
+ const thinkingBlocks = completionInfo.thinking || [];
3132
3153
  for (const toolUse of completionInfo.toolsUsed) {
3133
3154
  const toolCallId = `${toolUse.name}_${JSON.stringify(toolUse.arguments)}`;
3134
3155
  if (processedToolIds.has(toolCallId)) {
@@ -3161,16 +3182,23 @@ ${options.context}` : this.getSystemPrompt()
3161
3182
  const params = typeof toolUse.arguments === "string" ? JSON.parse(toolUse.arguments) : toolUse.arguments;
3162
3183
  observation = await tool.toolFn(params);
3163
3184
  const toolCallId2 = `${toolUse.name}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
3185
+ const assistantContent = [
3186
+ // Include thinking blocks first (required by Anthropic when thinking is enabled)
3187
+ ...thinkingBlocks,
3188
+ // Then the tool use
3189
+ {
3190
+ type: "tool_use",
3191
+ id: toolCallId2,
3192
+ name: toolUse.name,
3193
+ input: params
3194
+ }
3195
+ ];
3196
+ this.context.logger.debug(
3197
+ `[assistantContent] ${assistantContent.length} blocks (${thinkingBlocks.length} thinking, 1 tool_use)`
3198
+ );
3164
3199
  messages.push({
3165
3200
  role: "assistant",
3166
- content: [
3167
- {
3168
- type: "tool_use",
3169
- id: toolCallId2,
3170
- name: toolUse.name,
3171
- input: params
3172
- }
3173
- ]
3201
+ content: assistantContent
3174
3202
  });
3175
3203
  messages.push({
3176
3204
  role: "user",
@@ -3328,6 +3356,59 @@ Remember: You are an autonomous AGENT. Act independently and solve problems proa
3328
3356
  }
3329
3357
  };
3330
3358
 
3359
+ // src/core/prompts.ts
3360
+ function buildCoreSystemPrompt(contextSection = "") {
3361
+ return `You are an autonomous AI assistant with access to tools. Your job is to help users by taking action and solving problems proactively.
3362
+
3363
+ CORE BEHAVIOR:
3364
+ - Be proactive: Take action instead of asking for permission or clarification
3365
+ - Make smart assumptions: If unclear, choose the most reasonable interpretation
3366
+ - Use conversation history: Reference previous exchanges to understand context
3367
+ - Complete tasks fully: Don't just show what to do - actually do it
3368
+
3369
+ FOR SOFTWARE ENGINEERING TASKS:
3370
+ When requested to perform tasks like fixing bugs, adding features, refactoring, or explaining code, follow this sequence:
3371
+ 1. **Understand:** Think about the user's request and the relevant codebase context. Use 'grep_search' and 'glob_files' search tools extensively (in parallel if independent) to understand file structures, existing code patterns, and conventions. Use 'file_read' to understand context and validate any assumptions you may have. If you need to read multiple files, you should make multiple parallel calls to 'file_read'.
3372
+ 2. **Plan:** Build a coherent and grounded (based on the understanding in step 1) plan for how you intend to resolve the user's task. Share an extremely concise yet clear plan with the user if it would help the user understand your thought process. As part of the plan, you should use an iterative development process that includes writing unit tests to verify your changes. Use output logs or debug statements as part of this process to arrive at a solution.
3373
+ 3. **Implement:** Use the available tools (e.g., 'edit_local_file', 'create_file', 'bash_execute' ...) to act on the plan, strictly adhering to the project's established conventions.
3374
+ 4. **Verify (Tests):** If applicable and feasible, verify the changes using the project's testing procedures. Identify the correct test commands and frameworks by examining 'README' files, build/package configuration (e.g., 'package.json'), or existing test execution patterns. NEVER assume standard test commands. When executing test commands, prefer "run once" or "CI" modes to ensure the command terminates after completion.
3375
+ 5. **Verify (Standards):** VERY IMPORTANT: After making code changes, execute the project-specific build, linting and type-checking commands (e.g., 'tsc', 'npm run lint', 'ruff check .') that you have identified for this project (or obtained from the user). This ensures code quality and adherence to standards.
3376
+ 6. **Finalize:** After all verification passes, consider the task complete. Do not remove or revert any changes or created files (like tests). Await the user's next instruction.
3377
+
3378
+ SUBAGENT DELEGATION:
3379
+ - You have access to specialized subagents via the subagent_delegate tool
3380
+ - Use subagents for focused exploration, planning, or review tasks:
3381
+ * explore: Fast read-only codebase search (e.g., "find all auth files", "locate API endpoints")
3382
+ * plan: Break down complex tasks into actionable steps
3383
+ * review: Analyze code quality and identify issues
3384
+ - Subagents keep the main conversation clean and run faster with optimized models
3385
+ - Delegate when you need to search extensively or analyze code structure
3386
+
3387
+ FOR GENERAL TASKS:
3388
+ - Use available tools to get information (weather, web search, calculations, etc.)
3389
+ - When user asks follow-up questions, use conversation context to understand what they're referring to
3390
+ - If user asks "how about X?" after a previous question, apply the same question type to X
3391
+
3392
+ ## Shell tool output token efficiency:
3393
+ IT IS CRITICAL TO FOLLOW THESE GUIDELINES TO AVOID EXCESSIVE TOKEN CONSUMPTION.
3394
+
3395
+ - Always prefer command flags that reduce output verbosity when using 'bash_execute'.
3396
+ - Aim to minimize tool output tokens while still capturing necessary information.
3397
+ - If a command is expected to produce a lot of output, use quiet or silent flags where available and appropriate.
3398
+ - Always consider the trade-off between output verbosity and the need for information. If a command's full output is essential for understanding the result, avoid overly aggressive quieting that might obscure important details.
3399
+ - If a command does not have quiet/silent flags or for commands with potentially long output that may not be useful, redirect stdout and stderr to temp files in the project's temporary directory. For example: 'command > <temp_dir>/out.log 2> <temp_dir>/err.log'.
3400
+ - After the command runs, inspect the temp files (e.g. '<temp_dir>/out.log' and '<temp_dir>/err.log') using commands like 'grep', 'tail', 'head', ... (or platform equivalents). Remove the temp files when done.
3401
+
3402
+ EXAMPLES:
3403
+ - "what should I wear in Texas?" \u2192 use weather tool for Texas
3404
+ - "how about Japan?" \u2192 use weather tool for Japan (applying same question from context)
3405
+ - "enhance README" \u2192 file_read \u2192 generate \u2192 create_file
3406
+ - "what packages installed?" \u2192 glob_files "**/package.json" \u2192 file_read
3407
+ - "find all components using React hooks" \u2192 subagent_delegate(task="find all components using React hooks", type="explore")
3408
+
3409
+ Remember: Use context from previous messages to understand follow-up questions.${contextSection}`;
3410
+ }
3411
+
3331
3412
  // ../../b4m-core/packages/services/dist/src/referService/generateCodes.js
3332
3413
  import { randomBytes } from "crypto";
3333
3414
  import range from "lodash/range.js";
@@ -4336,7 +4417,7 @@ var listFabFilesSchema = z86.object({
4336
4417
 
4337
4418
  // ../../b4m-core/packages/services/dist/src/fabFileService/update.js
4338
4419
  import mime from "mime-types";
4339
- import { v4 as uuidv42 } from "uuid";
4420
+ import { v4 as uuidv43 } from "uuid";
4340
4421
  import { z as z87 } from "zod";
4341
4422
  var updateFabFileSchema = z87.object({
4342
4423
  id: z87.string(),
@@ -4457,7 +4538,7 @@ var editFabFileSchema = z98.object({
4457
4538
 
4458
4539
  // ../../b4m-core/packages/services/dist/src/fabFileService/applyEdit.js
4459
4540
  import mime2 from "mime-types";
4460
- import { v4 as uuidv43 } from "uuid";
4541
+ import { v4 as uuidv44 } from "uuid";
4461
4542
  import { z as z99 } from "zod";
4462
4543
  var applyEditSchema = z99.object({
4463
4544
  id: z99.string(),
@@ -5285,7 +5366,7 @@ import { toFile } from "openai/uploads";
5285
5366
  import { Readable } from "stream";
5286
5367
  import { TranscribeClient, StartTranscriptionJobCommand, GetTranscriptionJobCommand, LanguageCode, MediaFormat } from "@aws-sdk/client-transcribe";
5287
5368
  import { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand } from "@aws-sdk/client-s3";
5288
- import { v4 as uuidv44 } from "uuid";
5369
+ import { v4 as uuidv45 } from "uuid";
5289
5370
 
5290
5371
  // ../../b4m-core/packages/services/dist/src/emailIngestionService/processIngestedEmail.js
5291
5372
  import { randomUUID as randomUUID5 } from "crypto";
@@ -5446,7 +5527,7 @@ var weatherTool = {
5446
5527
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/imageGeneration/index.js
5447
5528
  import axios6 from "axios";
5448
5529
  import { fileTypeFromBuffer as fileTypeFromBuffer2 } from "file-type";
5449
- import { v4 as uuidv45 } from "uuid";
5530
+ import { v4 as uuidv46 } from "uuid";
5450
5531
  async function downloadImage(url) {
5451
5532
  if (url.startsWith("data:image/")) {
5452
5533
  const base64Data = url.split(",")[1];
@@ -5460,9 +5541,9 @@ async function processAndStoreImages(images, context) {
5460
5541
  return Promise.all(images.map(async (image) => {
5461
5542
  const buffer = await downloadImage(image);
5462
5543
  const fileType = await fileTypeFromBuffer2(buffer);
5463
- const filename = `${uuidv45()}.${fileType?.ext}`;
5464
- const path16 = await context.imageGenerateStorage.upload(buffer, filename, {});
5465
- return path16;
5544
+ const filename = `${uuidv46()}.${fileType?.ext}`;
5545
+ const path17 = await context.imageGenerateStorage.upload(buffer, filename, {});
5546
+ return path17;
5466
5547
  }));
5467
5548
  }
5468
5549
  async function updateQuestAndReturnMarkdown(storedImageUrls, context) {
@@ -6629,7 +6710,7 @@ Return only the edited content without any markdown code blocks or explanations.
6629
6710
  // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/imageEdit/index.js
6630
6711
  import axios7 from "axios";
6631
6712
  import { fileTypeFromBuffer as fileTypeFromBuffer3 } from "file-type";
6632
- import { v4 as uuidv46 } from "uuid";
6713
+ import { v4 as uuidv47 } from "uuid";
6633
6714
  async function downloadImage2(url) {
6634
6715
  if (url.startsWith("data:image/")) {
6635
6716
  const base64Data = url.split(",")[1];
@@ -6673,9 +6754,9 @@ async function getImageFromFileId(fileId, context) {
6673
6754
  async function processAndStoreImage(imageUrl, context) {
6674
6755
  const buffer = await downloadImage2(imageUrl);
6675
6756
  const fileType = await fileTypeFromBuffer3(buffer);
6676
- const filename = `${uuidv46()}.${fileType?.ext}`;
6677
- const path16 = await context.imageGenerateStorage.upload(buffer, filename, {});
6678
- return path16;
6757
+ const filename = `${uuidv47()}.${fileType?.ext}`;
6758
+ const path17 = await context.imageGenerateStorage.upload(buffer, filename, {});
6759
+ return path17;
6679
6760
  }
6680
6761
  async function updateQuestAndReturnMarkdown2(storedImagePath, context) {
6681
6762
  await context.onFinish?.("edit_image", storedImagePath);
@@ -8579,7 +8660,8 @@ var fileReadTool = {
8579
8660
  return content;
8580
8661
  } catch (error) {
8581
8662
  context.logger.error("\u274C FileRead: Failed", error);
8582
- throw error;
8663
+ const errorMessage = error instanceof Error ? error.message : String(error);
8664
+ return `Error reading file: ${errorMessage}`;
8583
8665
  }
8584
8666
  },
8585
8667
  toolSchema: {
@@ -9462,6 +9544,104 @@ BLOCKED OPERATIONS:
9462
9544
  })
9463
9545
  };
9464
9546
 
9547
+ // ../../b4m-core/packages/services/dist/src/llm/tools/implementation/editLocalFile/index.js
9548
+ import { promises as fs11 } from "fs";
9549
+ import { existsSync as existsSync7 } from "fs";
9550
+ import path13 from "path";
9551
+ import { diffLines as diffLines3 } from "diff";
9552
+ function generateDiff(original, modified) {
9553
+ const differences = diffLines3(original, modified);
9554
+ let diffString = "";
9555
+ let additions = 0;
9556
+ let deletions = 0;
9557
+ differences.forEach((part) => {
9558
+ if (part.added) {
9559
+ additions += part.count || 0;
9560
+ diffString += part.value.split("\n").filter((line) => line).map((line) => `+ ${line}`).join("\n");
9561
+ if (diffString && !diffString.endsWith("\n"))
9562
+ diffString += "\n";
9563
+ } else if (part.removed) {
9564
+ deletions += part.count || 0;
9565
+ diffString += part.value.split("\n").filter((line) => line).map((line) => `- ${line}`).join("\n");
9566
+ if (diffString && !diffString.endsWith("\n"))
9567
+ diffString += "\n";
9568
+ }
9569
+ });
9570
+ return { additions, deletions, diff: diffString.trim() };
9571
+ }
9572
+ async function editLocalFile(params) {
9573
+ const { path: filePath, old_string, new_string } = params;
9574
+ const normalizedPath = path13.normalize(filePath);
9575
+ const resolvedPath = path13.resolve(process.cwd(), normalizedPath);
9576
+ const cwd = path13.resolve(process.cwd());
9577
+ if (!resolvedPath.startsWith(cwd)) {
9578
+ throw new Error(`Access denied: Cannot edit files outside of current working directory`);
9579
+ }
9580
+ if (!existsSync7(resolvedPath)) {
9581
+ throw new Error(`File not found: ${filePath}`);
9582
+ }
9583
+ const currentContent = await fs11.readFile(resolvedPath, "utf-8");
9584
+ if (!currentContent.includes(old_string)) {
9585
+ const preview = old_string.length > 100 ? old_string.substring(0, 100) + "..." : old_string;
9586
+ throw new Error(`String to replace not found in file. Make sure the old_string matches exactly (including whitespace and line endings). Searched for: "${preview}"`);
9587
+ }
9588
+ const occurrences = currentContent.split(old_string).length - 1;
9589
+ if (occurrences > 1) {
9590
+ throw new Error(`Found ${occurrences} occurrences of the string to replace. Please provide a more specific old_string that matches exactly one location.`);
9591
+ }
9592
+ const newContent = currentContent.replace(old_string, new_string);
9593
+ await fs11.writeFile(resolvedPath, newContent, "utf-8");
9594
+ const diffResult = generateDiff(old_string, new_string);
9595
+ return `File edited successfully: ${filePath}
9596
+ Changes: +${diffResult.additions} lines, -${diffResult.deletions} lines
9597
+
9598
+ Diff:
9599
+ ${diffResult.diff}`;
9600
+ }
9601
+ var editLocalFileTool = {
9602
+ name: "edit_local_file",
9603
+ implementation: (context) => ({
9604
+ toolFn: async (value) => {
9605
+ const params = value;
9606
+ context.logger.info(`\u{1F4DD} EditLocalFile: Editing file`, {
9607
+ path: params.path,
9608
+ oldStringLength: params.old_string.length,
9609
+ newStringLength: params.new_string.length
9610
+ });
9611
+ try {
9612
+ const result = await editLocalFile(params);
9613
+ context.logger.info("\u2705 EditLocalFile: Success", { path: params.path });
9614
+ return result;
9615
+ } catch (error) {
9616
+ context.logger.error("\u274C EditLocalFile: Failed", error);
9617
+ throw error;
9618
+ }
9619
+ },
9620
+ toolSchema: {
9621
+ name: "edit_local_file",
9622
+ description: "Edit a file by replacing a specific string with new content. The old_string must match exactly one location in the file (including whitespace). Use this for precise edits to existing files. For creating new files or complete rewrites, use create_file instead.",
9623
+ parameters: {
9624
+ type: "object",
9625
+ properties: {
9626
+ path: {
9627
+ type: "string",
9628
+ description: "Path to the file to edit (relative to current working directory)"
9629
+ },
9630
+ old_string: {
9631
+ type: "string",
9632
+ description: "The exact string to find and replace. Must match exactly one location in the file, including all whitespace and line endings."
9633
+ },
9634
+ new_string: {
9635
+ type: "string",
9636
+ description: "The string to replace old_string with. Can be empty to delete the old_string."
9637
+ }
9638
+ },
9639
+ required: ["path", "old_string", "new_string"]
9640
+ }
9641
+ }
9642
+ })
9643
+ };
9644
+
9465
9645
  // ../../b4m-core/packages/services/dist/src/llm/tools/index.js
9466
9646
  var tools = {
9467
9647
  dice_roll: diceRollTool,
@@ -9487,6 +9667,7 @@ var tools = {
9487
9667
  planet_visibility: planetVisibilityTool,
9488
9668
  file_read: fileReadTool,
9489
9669
  create_file: createFileTool,
9670
+ edit_local_file: editLocalFileTool,
9490
9671
  glob_files: globFilesTool,
9491
9672
  grep_search: grepSearchTool,
9492
9673
  delete_file: deleteFileTool,
@@ -9649,7 +9830,7 @@ var QuestStartBodySchema = z139.object({
9649
9830
  // ../../b4m-core/packages/services/dist/src/llm/ImageGeneration.js
9650
9831
  import axios8 from "axios";
9651
9832
  import { fileTypeFromBuffer as fileTypeFromBuffer4 } from "file-type";
9652
- import { v4 as uuidv47 } from "uuid";
9833
+ import { v4 as uuidv48 } from "uuid";
9653
9834
  import { z as z140 } from "zod";
9654
9835
  import { fromZodError as fromZodError2 } from "zod-validation-error";
9655
9836
  var ImageGenerationBodySchema = OpenAIImageGenerationInput.extend({
@@ -9670,7 +9851,7 @@ var ImageGenerationBodySchema = OpenAIImageGenerationInput.extend({
9670
9851
  // ../../b4m-core/packages/services/dist/src/llm/ImageEdit.js
9671
9852
  import axios9 from "axios";
9672
9853
  import { fileTypeFromBuffer as fileTypeFromBuffer5 } from "file-type";
9673
- import { v4 as uuidv48 } from "uuid";
9854
+ import { v4 as uuidv49 } from "uuid";
9674
9855
  import { z as z141 } from "zod";
9675
9856
  import { fromZodError as fromZodError3 } from "zod-validation-error";
9676
9857
  var ImageEditBodySchema = OpenAIImageGenerationInput.extend({
@@ -9730,10 +9911,10 @@ var ToolErrorType;
9730
9911
  // src/utils/diffPreview.ts
9731
9912
  import * as Diff from "diff";
9732
9913
  import { readFile } from "fs/promises";
9733
- import { existsSync as existsSync7 } from "fs";
9914
+ import { existsSync as existsSync8 } from "fs";
9734
9915
  async function generateFileDiffPreview(args) {
9735
9916
  try {
9736
- if (!existsSync7(args.path)) {
9917
+ if (!existsSync8(args.path)) {
9737
9918
  const lines2 = args.content.split("\n");
9738
9919
  const preview = lines2.slice(0, 20).join("\n");
9739
9920
  const hasMore = lines2.length > 20;
@@ -9755,18 +9936,26 @@ ${preview}${hasMore ? `
9755
9936
  // Show 3 lines of context around changes
9756
9937
  );
9757
9938
  const lines = patch.split("\n");
9758
- const diffLines3 = lines.slice(4);
9759
- return diffLines3.join("\n");
9939
+ const diffLines4 = lines.slice(4);
9940
+ return diffLines4.join("\n");
9760
9941
  } catch (error) {
9761
9942
  return `[Error generating diff preview: ${error instanceof Error ? error.message : "Unknown error"}]`;
9762
9943
  }
9763
9944
  }
9945
+ function generateEditLocalFilePreview(args) {
9946
+ const patch = Diff.createPatch(args.path, args.old_string, args.new_string, "Current", "Proposed", { context: 3 });
9947
+ const lines = patch.split("\n");
9948
+ const diffLines4 = lines.slice(4);
9949
+ return `[Edit in: ${args.path}]
9950
+
9951
+ ${diffLines4.join("\n")}`;
9952
+ }
9764
9953
  async function generateFileDeletePreview(args) {
9765
9954
  try {
9766
- if (!existsSync7(args.path)) {
9955
+ if (!existsSync8(args.path)) {
9767
9956
  return `[File does not exist: ${args.path}]`;
9768
9957
  }
9769
- const stats = await import("fs/promises").then((fs13) => fs13.stat(args.path));
9958
+ const stats = await import("fs/promises").then((fs14) => fs14.stat(args.path));
9770
9959
  return `[File will be deleted]
9771
9960
 
9772
9961
  Path: ${args.path}
@@ -9778,8 +9967,8 @@ Last modified: ${stats.mtime.toLocaleString()}`;
9778
9967
  }
9779
9968
 
9780
9969
  // src/utils/Logger.ts
9781
- import fs11 from "fs/promises";
9782
- import path13 from "path";
9970
+ import fs12 from "fs/promises";
9971
+ import path14 from "path";
9783
9972
  import os2 from "os";
9784
9973
  var Logger2 = class _Logger {
9785
9974
  constructor() {
@@ -9802,9 +9991,9 @@ var Logger2 = class _Logger {
9802
9991
  */
9803
9992
  async initialize(sessionId) {
9804
9993
  this.sessionId = sessionId;
9805
- const debugDir = path13.join(os2.homedir(), ".bike4mind", "debug");
9806
- await fs11.mkdir(debugDir, { recursive: true });
9807
- this.logFilePath = path13.join(debugDir, `${sessionId}.txt`);
9994
+ const debugDir = path14.join(os2.homedir(), ".bike4mind", "debug");
9995
+ await fs12.mkdir(debugDir, { recursive: true });
9996
+ this.logFilePath = path14.join(debugDir, `${sessionId}.txt`);
9808
9997
  await this.writeToFile("INFO", "=== CLI SESSION START ===");
9809
9998
  }
9810
9999
  /**
@@ -9868,7 +10057,7 @@ var Logger2 = class _Logger {
9868
10057
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").substring(0, 19);
9869
10058
  const logEntry = `[${timestamp}] [${level}] ${message}
9870
10059
  `;
9871
- await fs11.appendFile(this.logFilePath, logEntry, "utf-8");
10060
+ await fs12.appendFile(this.logFilePath, logEntry, "utf-8");
9872
10061
  } catch (error) {
9873
10062
  console.error("File logging failed:", error);
9874
10063
  }
@@ -10014,15 +10203,15 @@ var Logger2 = class _Logger {
10014
10203
  async cleanupOldLogs() {
10015
10204
  if (!this.fileLoggingEnabled) return;
10016
10205
  try {
10017
- const debugDir = path13.join(os2.homedir(), ".bike4mind", "debug");
10018
- const files = await fs11.readdir(debugDir);
10206
+ const debugDir = path14.join(os2.homedir(), ".bike4mind", "debug");
10207
+ const files = await fs12.readdir(debugDir);
10019
10208
  const now = Date.now();
10020
10209
  const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1e3;
10021
10210
  for (const file of files) {
10022
- const filePath = path13.join(debugDir, file);
10023
- const stats = await fs11.stat(filePath);
10211
+ const filePath = path14.join(debugDir, file);
10212
+ const stats = await fs12.stat(filePath);
10024
10213
  if (stats.mtime.getTime() < thirtyDaysAgo) {
10025
- await fs11.unlink(filePath);
10214
+ await fs12.unlink(filePath);
10026
10215
  }
10027
10216
  }
10028
10217
  } catch (error) {
@@ -10079,10 +10268,10 @@ var SERVER_TOOLS = ["weather_info", "web_search"];
10079
10268
  var LOCAL_TOOLS = [
10080
10269
  "file_read",
10081
10270
  "create_file",
10271
+ "edit_local_file",
10082
10272
  "glob_files",
10083
10273
  "grep_search",
10084
10274
  "delete_file",
10085
- "edit_file",
10086
10275
  "dice_roll",
10087
10276
  "math_evaluate",
10088
10277
  "current_datetime",
@@ -10116,21 +10305,21 @@ var NoOpStorage = class extends BaseStorage {
10116
10305
  async upload(input, destination, options) {
10117
10306
  return `/tmp/${destination}`;
10118
10307
  }
10119
- async download(path16) {
10308
+ async download(path17) {
10120
10309
  throw new Error("Download not supported in CLI");
10121
10310
  }
10122
- async delete(path16) {
10311
+ async delete(path17) {
10123
10312
  }
10124
- async getSignedUrl(path16) {
10125
- return `/tmp/${path16}`;
10313
+ async getSignedUrl(path17) {
10314
+ return `/tmp/${path17}`;
10126
10315
  }
10127
- getPublicUrl(path16) {
10128
- return `/tmp/${path16}`;
10316
+ getPublicUrl(path17) {
10317
+ return `/tmp/${path17}`;
10129
10318
  }
10130
- async getPreview(path16) {
10131
- return `/tmp/${path16}`;
10319
+ async getPreview(path17) {
10320
+ return `/tmp/${path17}`;
10132
10321
  }
10133
- async getMetadata(path16) {
10322
+ async getMetadata(path17) {
10134
10323
  return { size: 0, contentType: "application/octet-stream" };
10135
10324
  }
10136
10325
  };
@@ -10162,11 +10351,12 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
10162
10351
  return result2;
10163
10352
  }
10164
10353
  let preview;
10165
- if (toolName === "edit_file" && args?.path && args?.content) {
10354
+ if (toolName === "edit_local_file" && args?.path && args?.old_string && typeof args?.new_string === "string") {
10166
10355
  try {
10167
- preview = await generateFileDiffPreview({
10356
+ preview = generateEditLocalFilePreview({
10168
10357
  path: args.path,
10169
- content: args.content
10358
+ old_string: args.old_string,
10359
+ new_string: args.new_string
10170
10360
  });
10171
10361
  } catch (error) {
10172
10362
  preview = `[Could not generate preview: ${error instanceof Error ? error.message : "Unknown error"}]`;
@@ -10224,7 +10414,31 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
10224
10414
  }
10225
10415
  };
10226
10416
  }
10227
- function generateCliTools(userId, llm, model, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient) {
10417
+ var TOOL_NAME_MAPPING = {
10418
+ // Claude Code -> B4M
10419
+ read: "file_read",
10420
+ write: "create_file",
10421
+ edit: "edit_file",
10422
+ delete: "delete_file",
10423
+ glob: "glob_files",
10424
+ grep: "grep_search",
10425
+ bash: "bash_execute",
10426
+ // B4M -> Claude Code (reverse mapping)
10427
+ file_read: "read",
10428
+ create_file: "write",
10429
+ edit_file: "edit",
10430
+ delete_file: "delete",
10431
+ glob_files: "glob",
10432
+ grep_search: "grep",
10433
+ bash_execute: "bash"
10434
+ };
10435
+ function normalizeToolName(toolName) {
10436
+ if (toolName.includes("_")) {
10437
+ return toolName;
10438
+ }
10439
+ return TOOL_NAME_MAPPING[toolName] || toolName;
10440
+ }
10441
+ function generateCliTools(userId, llm, model, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient, toolFilter) {
10228
10442
  const logger2 = new CliLogger();
10229
10443
  const storage = new NoOpStorage();
10230
10444
  const user = {
@@ -10259,6 +10473,7 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
10259
10473
  // File operation tools (CLI-specific, local execution)
10260
10474
  file_read: {},
10261
10475
  create_file: {},
10476
+ edit_local_file: {},
10262
10477
  glob_files: {},
10263
10478
  grep_search: {},
10264
10479
  delete_file: {},
@@ -10294,9 +10509,24 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
10294
10509
  toolConfig,
10295
10510
  model
10296
10511
  );
10297
- const tools2 = Object.entries(toolsMap).filter(([key]) => toolConfig[key] !== void 0).map(
10512
+ let tools2 = Object.entries(toolsMap).filter(([key]) => toolConfig[key] !== void 0).map(
10298
10513
  ([_, tool]) => wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, agentContext, configStore, apiClient)
10299
10514
  );
10515
+ if (toolFilter) {
10516
+ const { allowedTools, deniedTools } = toolFilter;
10517
+ const normalizedAllowed = allowedTools?.map(normalizeToolName);
10518
+ const normalizedDenied = deniedTools?.map(normalizeToolName);
10519
+ tools2 = tools2.filter((tool) => {
10520
+ const toolName = tool.toolSchema.name;
10521
+ if (normalizedDenied && normalizedDenied.includes(toolName)) {
10522
+ return false;
10523
+ }
10524
+ if (normalizedAllowed && normalizedAllowed.length > 0) {
10525
+ return normalizedAllowed.includes(toolName);
10526
+ }
10527
+ return true;
10528
+ });
10529
+ }
10300
10530
  return { tools: tools2, agentContext };
10301
10531
  }
10302
10532
 
@@ -10326,6 +10556,7 @@ var DEFAULT_TOOL_CATEGORIES = {
10326
10556
  // These tools can modify files, execute code, or have other dangerous side effects
10327
10557
  // They ALWAYS require permission and cannot be trusted automatically
10328
10558
  edit_file: "prompt_always",
10559
+ edit_local_file: "prompt_always",
10329
10560
  create_file: "prompt_always",
10330
10561
  delete_file: "prompt_always",
10331
10562
  shell_execute: "prompt_always",
@@ -10492,8 +10723,8 @@ function getEnvironmentName(configApiConfig) {
10492
10723
  }
10493
10724
 
10494
10725
  // src/utils/contextLoader.ts
10495
- import * as fs12 from "fs";
10496
- import * as path14 from "path";
10726
+ import * as fs13 from "fs";
10727
+ import * as path15 from "path";
10497
10728
  import { homedir as homedir4 } from "os";
10498
10729
  var CONTEXT_FILE_SIZE_LIMIT = 100 * 1024;
10499
10730
  var PROJECT_CONTEXT_FILES = [
@@ -10514,9 +10745,9 @@ function formatFileSize2(bytes) {
10514
10745
  return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
10515
10746
  }
10516
10747
  function tryReadContextFile(dir, filename, source) {
10517
- const filePath = path14.join(dir, filename);
10748
+ const filePath = path15.join(dir, filename);
10518
10749
  try {
10519
- const stats = fs12.lstatSync(filePath);
10750
+ const stats = fs13.lstatSync(filePath);
10520
10751
  if (stats.isDirectory()) {
10521
10752
  return null;
10522
10753
  }
@@ -10530,7 +10761,7 @@ function tryReadContextFile(dir, filename, source) {
10530
10761
  error: `${source === "global" ? "Global" : "Project"} ${filename} exceeds 100KB limit (${formatFileSize2(stats.size)})`
10531
10762
  };
10532
10763
  }
10533
- const content = fs12.readFileSync(filePath, "utf-8");
10764
+ const content = fs13.readFileSync(filePath, "utf-8");
10534
10765
  return {
10535
10766
  filename,
10536
10767
  content,
@@ -10582,7 +10813,7 @@ ${project.content}`;
10582
10813
  }
10583
10814
  async function loadContextFiles(projectDir) {
10584
10815
  const errors = [];
10585
- const globalDir = path14.join(homedir4(), ".bike4mind");
10816
+ const globalDir = path15.join(homedir4(), ".bike4mind");
10586
10817
  const projectDirectory = projectDir || process.cwd();
10587
10818
  const [globalResult, projectResult] = await Promise.all([
10588
10819
  Promise.resolve(findContextFile(globalDir, GLOBAL_CONTEXT_FILES, "global")),
@@ -10618,8 +10849,8 @@ function substituteArguments(template, args) {
10618
10849
  // ../../b4m-core/packages/mcp/dist/src/client.js
10619
10850
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
10620
10851
  import { Client as Client2 } from "@modelcontextprotocol/sdk/client/index.js";
10621
- import path15 from "path";
10622
- import { existsSync as existsSync8, readdirSync as readdirSync3 } from "fs";
10852
+ import path16 from "path";
10853
+ import { existsSync as existsSync9, readdirSync as readdirSync3 } from "fs";
10623
10854
  var MCPClient = class {
10624
10855
  // Note: This class handles MCP server communication with repository filtering
10625
10856
  mcp;
@@ -10659,18 +10890,18 @@ var MCPClient = class {
10659
10890
  const root = process.env.INIT_CWD || process.cwd();
10660
10891
  const candidatePaths = [
10661
10892
  // When running from SST Lambda with node_modules structure (copyFiles)
10662
- path15.join(root, `node_modules/@bike4mind/mcp/dist/src/${this.serverName}/index.js`),
10893
+ path16.join(root, `node_modules/@bike4mind/mcp/dist/src/${this.serverName}/index.js`),
10663
10894
  // When running from SST Lambda deployed environment (/var/task)
10664
- path15.join(root, `b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
10895
+ path16.join(root, `b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
10665
10896
  // When running from SST Lambda (.sst/artifacts/mcpHandler-dev), navigate to monorepo root (3 levels up)
10666
- path15.join(root, `../../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
10897
+ path16.join(root, `../../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
10667
10898
  // When running from packages/client (Next.js app), navigate to monorepo root (2 levels up)
10668
- path15.join(root, `../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
10899
+ path16.join(root, `../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
10669
10900
  // Original paths (backward compatibility)
10670
- path15.join(root, `/b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
10671
- path15.join(root, "core", "mcp", "servers", this.serverName, "dist", "index.js")
10901
+ path16.join(root, `/b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
10902
+ path16.join(root, "core", "mcp", "servers", this.serverName, "dist", "index.js")
10672
10903
  ];
10673
- const serverScriptPath = candidatePaths.find((p) => existsSync8(p));
10904
+ const serverScriptPath = candidatePaths.find((p) => existsSync9(p));
10674
10905
  if (!serverScriptPath) {
10675
10906
  const getDirectories = (source) => readdirSync3(source, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
10676
10907
  console.error(`[MCP] Server script not found. Tried paths:`, candidatePaths);
@@ -11079,6 +11310,7 @@ var ServerLlmBackend = class {
11079
11310
  let accumulatedText = "";
11080
11311
  let lastUsageInfo = {};
11081
11312
  let toolsUsed = [];
11313
+ let thinkingBlocks = [];
11082
11314
  let receivedDone = false;
11083
11315
  const parser = createParser({
11084
11316
  onEvent: (event) => {
@@ -11092,9 +11324,12 @@ var ServerLlmBackend = class {
11092
11324
  if (toolsUsed.length > 0) {
11093
11325
  const info = {
11094
11326
  toolsUsed,
11327
+ thinking: thinkingBlocks.length > 0 ? thinkingBlocks : void 0,
11095
11328
  ...lastUsageInfo
11096
11329
  };
11097
- logger.debug("[ServerLlmBackend] Calling callback with tools, will wait for completion");
11330
+ logger.debug(
11331
+ `[ServerLlmBackend] Calling callback with tools, thinking blocks: ${thinkingBlocks.length}`
11332
+ );
11098
11333
  callback([cleanedText], info).catch((err) => {
11099
11334
  logger.error("[ServerLlmBackend] Callback error:", err);
11100
11335
  reject(err);
@@ -11150,6 +11385,10 @@ var ServerLlmBackend = class {
11150
11385
  if (parsed.tools && parsed.tools.length > 0) {
11151
11386
  toolsUsed = parsed.tools;
11152
11387
  }
11388
+ if (parsed.thinking && parsed.thinking.length > 0) {
11389
+ thinkingBlocks = parsed.thinking;
11390
+ logger.debug(`[ServerLlmBackend] Received ${thinkingBlocks.length} thinking blocks`);
11391
+ }
11153
11392
  if (parsed.usage) {
11154
11393
  lastUsageInfo = {
11155
11394
  inputTokens: parsed.usage.inputTokens,
@@ -11472,7 +11711,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
11472
11711
  // package.json
11473
11712
  var package_default = {
11474
11713
  name: "@bike4mind/cli",
11475
- version: "0.2.10-slack-metrics-admin-dashboard.17271+2a5835a72",
11714
+ version: "0.2.11-cli-cancel-pending-message.17326+24dfb0510",
11476
11715
  type: "module",
11477
11716
  description: "Interactive CLI tool for Bike4Mind with ReAct agents",
11478
11717
  license: "UNLICENSED",
@@ -11576,10 +11815,10 @@ var package_default = {
11576
11815
  },
11577
11816
  devDependencies: {
11578
11817
  "@bike4mind/agents": "0.1.0",
11579
- "@bike4mind/common": "2.39.1-slack-metrics-admin-dashboard.17271+2a5835a72",
11580
- "@bike4mind/mcp": "1.20.4-slack-metrics-admin-dashboard.17271+2a5835a72",
11581
- "@bike4mind/services": "2.34.2-slack-metrics-admin-dashboard.17271+2a5835a72",
11582
- "@bike4mind/utils": "2.1.4-slack-metrics-admin-dashboard.17271+2a5835a72",
11818
+ "@bike4mind/common": "2.40.1-cli-cancel-pending-message.17326+24dfb0510",
11819
+ "@bike4mind/mcp": "1.20.5-cli-cancel-pending-message.17326+24dfb0510",
11820
+ "@bike4mind/services": "2.35.1-cli-cancel-pending-message.17326+24dfb0510",
11821
+ "@bike4mind/utils": "2.1.5-cli-cancel-pending-message.17326+24dfb0510",
11583
11822
  "@types/better-sqlite3": "^7.6.13",
11584
11823
  "@types/diff": "^5.0.9",
11585
11824
  "@types/jsonwebtoken": "^9.0.4",
@@ -11592,7 +11831,7 @@ var package_default = {
11592
11831
  typescript: "^5.9.3",
11593
11832
  vitest: "^3.2.4"
11594
11833
  },
11595
- gitHead: "2a5835a72cd38a7e839d4180a2deca9bcd2e2008"
11834
+ gitHead: "24dfb0510b2c3e1385417da0a3fe6c3604cdf8f8"
11596
11835
  };
11597
11836
 
11598
11837
  // src/config/constants.ts
@@ -11600,6 +11839,354 @@ var USAGE_DAYS = 30;
11600
11839
  var MODEL_NAME_COLUMN_WIDTH = 18;
11601
11840
  var USAGE_CACHE_TTL = 5 * 60 * 1e3;
11602
11841
 
11842
+ // src/agents/SubagentOrchestrator.ts
11843
+ var SubagentOrchestrator = class {
11844
+ constructor(deps) {
11845
+ this.beforeRunCallback = null;
11846
+ this.afterRunCallback = null;
11847
+ this.deps = deps;
11848
+ }
11849
+ /**
11850
+ * Set a callback to be invoked before each subagent.run()
11851
+ * Use this to subscribe to agent events (e.g., subagent.on('action', handler))
11852
+ */
11853
+ setBeforeRunCallback(callback) {
11854
+ this.beforeRunCallback = callback;
11855
+ }
11856
+ /**
11857
+ * Set a callback to be invoked after each subagent.run()
11858
+ * Use this to unsubscribe from agent events (e.g., subagent.off('action', handler))
11859
+ */
11860
+ setAfterRunCallback(callback) {
11861
+ this.afterRunCallback = callback;
11862
+ }
11863
+ /**
11864
+ * Delegate a task to a specialized subagent
11865
+ *
11866
+ * @param options - Configuration for subagent execution
11867
+ * @returns Subagent result with summary
11868
+ */
11869
+ async delegateToSubagent(options) {
11870
+ const { task, type, thoroughness, parentSessionId, config: configOverride } = options;
11871
+ const baseConfig = this.deps.subagentConfigs.get(type);
11872
+ if (!baseConfig) {
11873
+ throw new Error(`No configuration found for subagent type: ${type}`);
11874
+ }
11875
+ const config = {
11876
+ ...baseConfig,
11877
+ ...configOverride,
11878
+ type
11879
+ };
11880
+ const model = config.model || "claude-3-5-haiku-20241022";
11881
+ const maxIterations = this.getMaxIterations(config, thoroughness);
11882
+ const toolFilter = {
11883
+ allowedTools: config.allowedTools,
11884
+ deniedTools: config.deniedTools
11885
+ };
11886
+ const agentContext = {
11887
+ currentAgent: null,
11888
+ observationQueue: []
11889
+ };
11890
+ const { tools: tools2, agentContext: updatedContext } = generateCliTools(
11891
+ this.deps.userId,
11892
+ this.deps.llm,
11893
+ model,
11894
+ this.deps.permissionManager,
11895
+ this.deps.showPermissionPrompt,
11896
+ agentContext,
11897
+ this.deps.configStore,
11898
+ this.deps.apiClient,
11899
+ toolFilter
11900
+ );
11901
+ this.deps.logger.debug(`Spawning ${type} subagent with ${tools2.length} tools, thoroughness: ${thoroughness}`);
11902
+ const subagent = new ReActAgent({
11903
+ userId: this.deps.userId,
11904
+ logger: this.deps.logger,
11905
+ llm: this.deps.llm,
11906
+ model,
11907
+ tools: tools2,
11908
+ maxIterations,
11909
+ systemPrompt: config.systemPrompt || this.getDefaultSystemPrompt(type)
11910
+ });
11911
+ updatedContext.currentAgent = subagent;
11912
+ if (this.beforeRunCallback) {
11913
+ this.beforeRunCallback(subagent, type);
11914
+ }
11915
+ const startTime = Date.now();
11916
+ const result = await subagent.run(task, {
11917
+ maxIterations
11918
+ });
11919
+ const duration = Date.now() - startTime;
11920
+ if (this.afterRunCallback) {
11921
+ this.afterRunCallback(subagent, type);
11922
+ }
11923
+ this.deps.logger.debug(
11924
+ `Subagent completed in ${duration}ms, ${result.completionInfo.iterations} iterations, ${result.completionInfo.totalTokens} tokens`
11925
+ );
11926
+ const summary = this.summarizeResult(result, type);
11927
+ const subagentResult = {
11928
+ ...result,
11929
+ subagentType: type,
11930
+ thoroughness,
11931
+ summary,
11932
+ parentSessionId
11933
+ };
11934
+ return subagentResult;
11935
+ }
11936
+ /**
11937
+ * Get max iterations based on thoroughness and config
11938
+ */
11939
+ getMaxIterations(config, thoroughness) {
11940
+ const defaults = {
11941
+ quick: 2,
11942
+ medium: 5,
11943
+ very_thorough: 10
11944
+ };
11945
+ const configIterations = config.maxIterations || defaults;
11946
+ return configIterations[thoroughness];
11947
+ }
11948
+ /**
11949
+ * Get default system prompt for subagent type
11950
+ */
11951
+ getDefaultSystemPrompt(type) {
11952
+ switch (type) {
11953
+ case "explore":
11954
+ return `You are a code exploration specialist. Your job is to search and analyze codebases efficiently.
11955
+
11956
+ Focus on:
11957
+ - Finding relevant files and functions
11958
+ - Understanding code structure and patterns
11959
+ - Providing clear, concise summaries
11960
+
11961
+ You have read-only access. Use file_read, grep_search, and glob_files to explore.
11962
+
11963
+ When you find what you're looking for, provide a clear summary including:
11964
+ 1. What you found (files, functions, patterns)
11965
+ 2. Key insights or observations
11966
+ 3. Relevant code locations
11967
+
11968
+ Be thorough but concise. Your summary will be used by the main agent.`;
11969
+ case "plan":
11970
+ return `You are a task planning specialist. Your job is to break down complex tasks into clear, actionable steps.
11971
+
11972
+ Focus on:
11973
+ - Identifying dependencies and blockers
11974
+ - Creating logical sequence of steps
11975
+ - Estimating scope and priorities
11976
+
11977
+ Provide a structured plan that the main agent can execute.`;
11978
+ case "review":
11979
+ return `You are a code review specialist. Your job is to analyze code quality and identify issues.
11980
+
11981
+ Focus on:
11982
+ - Code quality and best practices
11983
+ - Potential bugs and edge cases
11984
+ - Performance and security considerations
11985
+
11986
+ Provide actionable feedback with specific file and line references.`;
11987
+ default:
11988
+ return "You are a helpful AI assistant.";
11989
+ }
11990
+ }
11991
+ /**
11992
+ * Summarize subagent result for parent agent
11993
+ */
11994
+ summarizeResult(result, type) {
11995
+ const { finalAnswer, steps, completionInfo } = result;
11996
+ const toolCalls = steps.filter((s) => s.type === "action");
11997
+ const filesRead = toolCalls.filter((s) => s.metadata?.toolName === "file_read").length;
11998
+ const searches = toolCalls.filter((s) => s.metadata?.toolName === "grep_search").length;
11999
+ const globs = toolCalls.filter((s) => s.metadata?.toolName === "glob_files").length;
12000
+ let summary = `**${type.charAt(0).toUpperCase() + type.slice(1)} Subagent Results**
12001
+
12002
+ `;
12003
+ summary += `*Execution: ${completionInfo.iterations} iterations, ${completionInfo.toolCalls} tool calls*
12004
+
12005
+ `;
12006
+ if (type === "explore") {
12007
+ summary += `*Exploration: ${filesRead} files read, ${searches} searches, ${globs} glob patterns*
12008
+
12009
+ `;
12010
+ }
12011
+ const maxLength = 1e3;
12012
+ if (finalAnswer.length > maxLength) {
12013
+ summary += finalAnswer.slice(0, maxLength) + "\n\n...(truncated)";
12014
+ } else {
12015
+ summary += finalAnswer;
12016
+ }
12017
+ return summary;
12018
+ }
12019
+ };
12020
+
12021
+ // src/agents/configs.ts
12022
+ var EXPLORE_CONFIG = {
12023
+ type: "explore",
12024
+ model: "claude-3-5-haiku-20241022",
12025
+ systemPrompt: `You are a code exploration specialist. Your job is to search and analyze codebases efficiently.
12026
+
12027
+ Focus on:
12028
+ - Finding relevant files and functions
12029
+ - Understanding code structure and patterns
12030
+ - Providing clear, concise summaries
12031
+
12032
+ You have read-only access. Use file_read, grep_search, and glob_files to explore.
12033
+
12034
+ When you find what you're looking for, provide a clear summary including:
12035
+ 1. What you found (files, functions, patterns)
12036
+ 2. Key insights or observations
12037
+ 3. Relevant code locations
12038
+
12039
+ Be thorough but concise. Your summary will be used by the main agent.`,
12040
+ allowedTools: [
12041
+ "file_read",
12042
+ "grep_search",
12043
+ "glob_files",
12044
+ "bash_execute",
12045
+ // Only for read-only commands like ls, cat, find
12046
+ "current_datetime",
12047
+ "math_evaluate"
12048
+ ],
12049
+ deniedTools: [
12050
+ "create_file",
12051
+ "edit_file",
12052
+ "delete_file",
12053
+ "web_search",
12054
+ "weather_info",
12055
+ "blog_publish",
12056
+ "blog_edit",
12057
+ "blog_draft"
12058
+ ],
12059
+ maxIterations: {
12060
+ quick: 2,
12061
+ medium: 5,
12062
+ very_thorough: 10
12063
+ },
12064
+ defaultThoroughness: "medium"
12065
+ };
12066
+ var PLAN_CONFIG = {
12067
+ type: "plan",
12068
+ model: "claude-3-5-haiku-20241022",
12069
+ systemPrompt: `You are a task planning specialist. Your job is to break down complex tasks into clear, actionable steps.
12070
+
12071
+ Focus on:
12072
+ - Identifying dependencies and blockers
12073
+ - Creating logical sequence of steps
12074
+ - Estimating scope and priorities
12075
+
12076
+ You have read-only access to analyze code.
12077
+ You can explore the codebase to understand the current architecture before planning.
12078
+
12079
+ Provide a structured plan that the main agent can execute.`,
12080
+ allowedTools: ["file_read", "grep_search", "glob_files", "bash_execute", "current_datetime", "math_evaluate"],
12081
+ deniedTools: ["create_file", "edit_file", "delete_file", "web_search", "weather_info"],
12082
+ maxIterations: {
12083
+ quick: 3,
12084
+ medium: 7,
12085
+ very_thorough: 12
12086
+ },
12087
+ defaultThoroughness: "medium"
12088
+ };
12089
+ var REVIEW_CONFIG = {
12090
+ type: "review",
12091
+ model: "claude-sonnet-4-5-20250929",
12092
+ // Use latest Sonnet for better reasoning
12093
+ systemPrompt: `You are a code review specialist. Your job is to analyze code quality and identify issues.
12094
+
12095
+ Focus on:
12096
+ - Code quality and best practices
12097
+ - Potential bugs and edge cases
12098
+ - Performance and security considerations
12099
+
12100
+ You have read-only access to analyze code.
12101
+
12102
+ Provide actionable feedback with specific file and line references.`,
12103
+ allowedTools: ["file_read", "grep_search", "glob_files", "bash_execute", "current_datetime"],
12104
+ deniedTools: ["create_file", "edit_file", "delete_file", "web_search", "weather_info"],
12105
+ maxIterations: {
12106
+ quick: 3,
12107
+ medium: 8,
12108
+ very_thorough: 15
12109
+ },
12110
+ defaultThoroughness: "medium"
12111
+ };
12112
+ function getDefaultSubagentConfigs() {
12113
+ return /* @__PURE__ */ new Map([
12114
+ ["explore", EXPLORE_CONFIG],
12115
+ ["plan", PLAN_CONFIG],
12116
+ ["review", REVIEW_CONFIG]
12117
+ ]);
12118
+ }
12119
+
12120
+ // src/agents/delegateTool.ts
12121
+ function createSubagentDelegateTool(orchestrator, parentSessionId) {
12122
+ return {
12123
+ toolFn: async (args) => {
12124
+ const params = args;
12125
+ if (!params.task) {
12126
+ throw new Error("subagent_delegate: task parameter is required");
12127
+ }
12128
+ if (!params.type) {
12129
+ throw new Error("subagent_delegate: type parameter is required");
12130
+ }
12131
+ const thoroughness = params.thoroughness || "medium";
12132
+ const type = params.type;
12133
+ const result = await orchestrator.delegateToSubagent({
12134
+ task: params.task,
12135
+ type,
12136
+ thoroughness,
12137
+ parentSessionId
12138
+ });
12139
+ return result.summary;
12140
+ },
12141
+ toolSchema: {
12142
+ name: "subagent_delegate",
12143
+ description: `Delegate a task to a specialized subagent for focused work.
12144
+
12145
+ **When to use this tool:**
12146
+ - **Explore**: When you need to search through the codebase, find files, or understand code structure (read-only)
12147
+ - **Plan**: When you need to break down a complex task into actionable steps
12148
+ - **Review**: When you need to analyze code quality and identify potential issues
12149
+
12150
+ **Benefits:**
12151
+ - Keeps main conversation focused and clean
12152
+ - Uses specialized prompts optimized for each task type
12153
+ - Faster execution with appropriate models (Haiku for explore/plan, Sonnet for review)
12154
+
12155
+ **Example uses:**
12156
+ - "Find all files that use the authentication system" \u2192 explore
12157
+ - "Search for components that handle user input" \u2192 explore
12158
+ - "Break down implementing a new feature into steps" \u2192 plan
12159
+ - "Review this module for potential bugs" \u2192 review`,
12160
+ parameters: {
12161
+ type: "object",
12162
+ properties: {
12163
+ task: {
12164
+ type: "string",
12165
+ description: "Clear description of what you want the subagent to do. Be specific about what you're looking for or what needs to be accomplished."
12166
+ },
12167
+ type: {
12168
+ type: "string",
12169
+ enum: ["explore", "plan", "review"],
12170
+ description: `Type of subagent to use:
12171
+ - explore: Read-only codebase exploration and search (fast, uses Haiku)
12172
+ - plan: Task breakdown and planning (uses Haiku)
12173
+ - review: Code quality analysis and review (uses Sonnet for better reasoning)`
12174
+ },
12175
+ thoroughness: {
12176
+ type: "string",
12177
+ enum: ["quick", "medium", "very_thorough"],
12178
+ description: `How thoroughly to execute:
12179
+ - quick: Fast lookup, 1-2 iterations
12180
+ - medium: Balanced exploration, 3-5 iterations (default)
12181
+ - very_thorough: Comprehensive analysis, 8-10 iterations`
12182
+ }
12183
+ },
12184
+ required: ["task", "type"]
12185
+ }
12186
+ }
12187
+ };
12188
+ }
12189
+
11603
12190
  // src/index.tsx
11604
12191
  process.removeAllListeners("warning");
11605
12192
  process.on("warning", (warning) => {
@@ -11630,7 +12217,9 @@ function CliApp() {
11630
12217
  permissionPrompt: null,
11631
12218
  trustLocationSelector: null,
11632
12219
  rewindSelector: null,
11633
- sessionSelector: null
12220
+ sessionSelector: null,
12221
+ orchestrator: null,
12222
+ abortController: null
11634
12223
  });
11635
12224
  const [isInitialized, setIsInitialized] = useState8(false);
11636
12225
  const [initError, setInitError] = useState8(null);
@@ -11676,6 +12265,15 @@ function CliApp() {
11676
12265
  }, 100);
11677
12266
  }, [state.session, state.sessionStore, state.mcpManager, state.agent, state.imageStore]);
11678
12267
  useInput6((input, key) => {
12268
+ if (key.escape) {
12269
+ if (state.abortController) {
12270
+ logger.debug("[ABORT] ESC pressed - aborting current operation...");
12271
+ state.abortController.abort();
12272
+ setState((prev) => ({ ...prev, abortController: null }));
12273
+ console.log("\n\u26A0\uFE0F Operation cancelled by user (ESC)\n");
12274
+ }
12275
+ return;
12276
+ }
11679
12277
  if (key.ctrl && input === "c") {
11680
12278
  const now = Date.now();
11681
12279
  if (exitTimestamp && now - exitTimestamp < EXIT_TIMEOUT_MS) {
@@ -11730,7 +12328,7 @@ function CliApp() {
11730
12328
  if (!isAuthenticated) {
11731
12329
  console.log("\u2139\uFE0F AI features disabled. Available commands: /login, /help, /config\n");
11732
12330
  const minimalSession = {
11733
- id: uuidv49(),
12331
+ id: uuidv410(),
11734
12332
  name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
11735
12333
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
11736
12334
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -11774,7 +12372,7 @@ function CliApp() {
11774
12372
  }
11775
12373
  llm.currentModel = modelInfo.id;
11776
12374
  const newSession = {
11777
- id: uuidv49(),
12375
+ id: uuidv410(),
11778
12376
  name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
11779
12377
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
11780
12378
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -11847,7 +12445,34 @@ function CliApp() {
11847
12445
  console.log(` \u{1F4E1} ${serverName}: ${count} tool(s)`);
11848
12446
  });
11849
12447
  }
11850
- const allTools = [...b4mTools, ...mcpTools];
12448
+ const subagentConfigs = getDefaultSubagentConfigs();
12449
+ if (config.subagents) {
12450
+ if (config.subagents.explore) {
12451
+ const currentConfig = subagentConfigs.get("explore");
12452
+ subagentConfigs.set("explore", { ...currentConfig, ...config.subagents.explore });
12453
+ }
12454
+ if (config.subagents.plan) {
12455
+ const currentConfig = subagentConfigs.get("plan");
12456
+ subagentConfigs.set("plan", { ...currentConfig, ...config.subagents.plan });
12457
+ }
12458
+ if (config.subagents.review) {
12459
+ const currentConfig = subagentConfigs.get("review");
12460
+ subagentConfigs.set("review", { ...currentConfig, ...config.subagents.review });
12461
+ }
12462
+ }
12463
+ const orchestrator = new SubagentOrchestrator({
12464
+ userId: config.userId,
12465
+ llm,
12466
+ logger: silentLogger,
12467
+ permissionManager,
12468
+ showPermissionPrompt: promptFn,
12469
+ configStore: state.configStore,
12470
+ apiClient,
12471
+ subagentConfigs
12472
+ });
12473
+ const subagentDelegateTool = createSubagentDelegateTool(orchestrator, newSession.id);
12474
+ const allTools = [...b4mTools, ...mcpTools, subagentDelegateTool];
12475
+ console.log(`\u{1F916} Subagent delegation enabled (explore, plan, review)`);
11851
12476
  const projectDir = state.configStore.getProjectConfigDir();
11852
12477
  const contextResult = await loadContextFiles(projectDir);
11853
12478
  if (contextResult.globalContext) {
@@ -11866,36 +12491,7 @@ function CliApp() {
11866
12491
  Follow these project-specific instructions:
11867
12492
 
11868
12493
  ${contextResult.mergedContent}` : "";
11869
- const cliSystemPrompt = `You are an autonomous AI assistant with access to tools. Your job is to help users by taking action and solving problems proactively.
11870
-
11871
- CORE BEHAVIOR:
11872
- - Be proactive: Take action instead of asking for permission or clarification
11873
- - Make smart assumptions: If unclear, choose the most reasonable interpretation
11874
- - Use conversation history: Reference previous exchanges to understand context
11875
- - Complete tasks fully: Don't just show what to do - actually do it
11876
-
11877
- FOR CODING TASKS:
11878
- - You have file system access (file_read, create_file, glob_files, grep_search, delete_file)
11879
- - When user says "enhance", "update", "fix", "improve" a file:
11880
- * Use file_read to get current content
11881
- * Generate the improved version
11882
- * Use create_file to write it back
11883
- * Don't just show suggestions - make the changes
11884
- - When searching for code: Use grep_search or glob_files to find relevant files
11885
- - Permission system will ask for approval before any file writes
11886
-
11887
- FOR GENERAL TASKS:
11888
- - Use available tools to get information (weather, web search, calculations, etc.)
11889
- - When user asks follow-up questions, use conversation context to understand what they're referring to
11890
- - If user asks "how about X?" after a previous question, apply the same question type to X
11891
-
11892
- EXAMPLES:
11893
- - "what should I wear in Texas?" \u2192 use weather tool for Texas
11894
- - "how about Japan?" \u2192 use weather tool for Japan (applying same question from context)
11895
- - "enhance README" \u2192 file_read \u2192 generate \u2192 create_file
11896
- - "what packages installed?" \u2192 glob_files "**/package.json" \u2192 file_read
11897
-
11898
- Remember: Use context from previous messages to understand follow-up questions.${contextSection}`;
12494
+ const cliSystemPrompt = buildCoreSystemPrompt(contextSection);
11899
12495
  const maxIterations = config.preferences.maxIterations === null ? 999999 : config.preferences.maxIterations;
11900
12496
  const agent = new ReActAgent({
11901
12497
  userId: config.userId,
@@ -11910,6 +12506,45 @@ Remember: Use context from previous messages to understand follow-up questions.$
11910
12506
  });
11911
12507
  agentContext.currentAgent = agent;
11912
12508
  agent.observationQueue = agentContext.observationQueue;
12509
+ const stepHandler = (step) => {
12510
+ const { pendingMessages, updatePendingMessage } = useCliStore.getState();
12511
+ const lastIdx = pendingMessages.length - 1;
12512
+ if (lastIdx >= 0 && pendingMessages[lastIdx].role === "assistant") {
12513
+ const existingSteps = pendingMessages[lastIdx].metadata?.steps || [];
12514
+ const MAX_INPUT_LENGTH = 500;
12515
+ let truncatedStep = step;
12516
+ if (step.type === "action" && step.metadata?.toolInput) {
12517
+ const inputStr = typeof step.metadata.toolInput === "string" ? step.metadata.toolInput : JSON.stringify(step.metadata.toolInput);
12518
+ if (inputStr.length > MAX_INPUT_LENGTH) {
12519
+ const truncatedInput = inputStr.slice(0, MAX_INPUT_LENGTH) + `... (${inputStr.length - MAX_INPUT_LENGTH} more chars)`;
12520
+ truncatedStep = {
12521
+ ...step,
12522
+ metadata: {
12523
+ ...step.metadata,
12524
+ toolInput: truncatedInput
12525
+ }
12526
+ };
12527
+ }
12528
+ }
12529
+ updatePendingMessage(lastIdx, {
12530
+ ...pendingMessages[lastIdx],
12531
+ metadata: {
12532
+ ...pendingMessages[lastIdx].metadata,
12533
+ steps: [...existingSteps, truncatedStep]
12534
+ }
12535
+ });
12536
+ }
12537
+ };
12538
+ agent.on("thought", stepHandler);
12539
+ agent.on("action", stepHandler);
12540
+ orchestrator.setBeforeRunCallback((subagent, _subagentType) => {
12541
+ subagent.on("thought", stepHandler);
12542
+ subagent.on("action", stepHandler);
12543
+ });
12544
+ orchestrator.setAfterRunCallback((subagent, _subagentType) => {
12545
+ subagent.off("thought", stepHandler);
12546
+ subagent.off("action", stepHandler);
12547
+ });
11913
12548
  setState((prev) => ({
11914
12549
  ...prev,
11915
12550
  session: newSession,
@@ -11918,8 +12553,10 @@ Remember: Use context from previous messages to understand follow-up questions.$
11918
12553
  permissionManager,
11919
12554
  config,
11920
12555
  // Store config for synchronous access
11921
- availableModels: models
12556
+ availableModels: models,
11922
12557
  // Store models for ConfigEditor
12558
+ orchestrator
12559
+ // Store orchestrator for step handler updates
11923
12560
  }));
11924
12561
  setStoreSession(newSession);
11925
12562
  setIsInitialized(true);
@@ -11952,6 +12589,8 @@ Remember: Use context from previous messages to understand follow-up questions.$
11952
12589
  return;
11953
12590
  }
11954
12591
  useCliStore.getState().setIsThinking(true);
12592
+ const abortController = new AbortController();
12593
+ setState((prev) => ({ ...prev, abortController }));
11955
12594
  const currentSteps = [];
11956
12595
  const stepHandler = (step) => {
11957
12596
  currentSteps.push(step);
@@ -11974,6 +12613,7 @@ Remember: Use context from previous messages to understand follow-up questions.$
11974
12613
  }
11975
12614
  }
11976
12615
  };
12616
+ state.agent.on("thought", stepHandler);
11977
12617
  state.agent.on("action", stepHandler);
11978
12618
  try {
11979
12619
  let messageContent = fullTemplate;
@@ -11983,11 +12623,13 @@ Remember: Use context from previous messages to understand follow-up questions.$
11983
12623
  messageContent = multimodalMessage.content;
11984
12624
  }
11985
12625
  const userMessage = {
12626
+ id: uuidv410(),
11986
12627
  role: "user",
11987
12628
  content: userMessageContent,
11988
12629
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
11989
12630
  };
11990
12631
  const pendingAssistantMessage = {
12632
+ id: uuidv410(),
11991
12633
  role: "assistant",
11992
12634
  content: "...",
11993
12635
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -12008,8 +12650,13 @@ Remember: Use context from previous messages to understand follow-up questions.$
12008
12650
  content: msg.content
12009
12651
  }));
12010
12652
  const result = await state.agent.run(messageContent, {
12011
- previousMessages: previousMessages.length > 0 ? previousMessages : void 0
12653
+ previousMessages: previousMessages.length > 0 ? previousMessages : void 0,
12654
+ signal: abortController.signal
12012
12655
  });
12656
+ if (abortController.signal.aborted) {
12657
+ logger.debug("[ABORT] Custom command was cancelled, discarding result");
12658
+ return;
12659
+ }
12013
12660
  const permissionDenied = result.finalAnswer.startsWith("Permission denied for tool");
12014
12661
  if (permissionDenied) {
12015
12662
  console.log("\n\u26A0\uFE0F Action denied by user\n");
@@ -12018,7 +12665,10 @@ Remember: Use context from previous messages to understand follow-up questions.$
12018
12665
  const currentSession = useCliStore.getState().session;
12019
12666
  if (!currentSession) return;
12020
12667
  const updatedMessages = [...currentSession.messages];
12668
+ const lastMessage = updatedMessages[updatedMessages.length - 1];
12021
12669
  updatedMessages[updatedMessages.length - 1] = {
12670
+ id: lastMessage.id,
12671
+ // Preserve the original message ID
12022
12672
  role: "assistant",
12023
12673
  content: result.finalAnswer,
12024
12674
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -12050,6 +12700,33 @@ Remember: Use context from previous messages to understand follow-up questions.$
12050
12700
  useCliStore.getState().setIsThinking(false);
12051
12701
  } catch (error) {
12052
12702
  useCliStore.getState().setIsThinking(false);
12703
+ if (error instanceof Error && error.name === "AbortError") {
12704
+ logger.debug("[ABORT] Custom command aborted by user");
12705
+ const currentSession2 = useCliStore.getState().session;
12706
+ if (currentSession2) {
12707
+ const messages2 = [...currentSession2.messages];
12708
+ const lastMessage2 = messages2[messages2.length - 1];
12709
+ if (lastMessage2 && lastMessage2.role === "assistant") {
12710
+ messages2[messages2.length - 1] = {
12711
+ ...lastMessage2,
12712
+ content: "\u26A0\uFE0F Operation cancelled by user",
12713
+ metadata: {
12714
+ ...lastMessage2.metadata,
12715
+ cancelled: true
12716
+ }
12717
+ };
12718
+ }
12719
+ const sessionWithCancel = {
12720
+ ...currentSession2,
12721
+ messages: messages2,
12722
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
12723
+ };
12724
+ setState((prev) => ({ ...prev, session: sessionWithCancel }));
12725
+ setStoreSession(sessionWithCancel);
12726
+ await state.sessionStore.save(sessionWithCancel);
12727
+ }
12728
+ return;
12729
+ }
12053
12730
  if (error?.message?.includes("Permission denied")) {
12054
12731
  console.log("\n\u26A0\uFE0F Action blocked by permission settings");
12055
12732
  const currentSession2 = useCliStore.getState().session;
@@ -12090,6 +12767,8 @@ Remember: Use context from previous messages to understand follow-up questions.$
12090
12767
  setState((prev) => ({ ...prev, session: sessionWithError }));
12091
12768
  setStoreSession(sessionWithError);
12092
12769
  } finally {
12770
+ setState((prev) => ({ ...prev, abortController: null }));
12771
+ state.agent.off("thought", stepHandler);
12093
12772
  state.agent.off("action", stepHandler);
12094
12773
  }
12095
12774
  };
@@ -12108,22 +12787,8 @@ Remember: Use context from previous messages to understand follow-up questions.$
12108
12787
  return;
12109
12788
  }
12110
12789
  useCliStore.getState().setIsThinking(true);
12111
- const currentSteps = [];
12112
- const stepHandler = (step) => {
12113
- currentSteps.push(step);
12114
- const { pendingMessages, updatePendingMessage } = useCliStore.getState();
12115
- const lastIdx = pendingMessages.length - 1;
12116
- if (lastIdx >= 0 && pendingMessages[lastIdx].role === "assistant") {
12117
- updatePendingMessage(lastIdx, {
12118
- ...pendingMessages[lastIdx],
12119
- metadata: {
12120
- ...pendingMessages[lastIdx].metadata,
12121
- steps: [...currentSteps]
12122
- }
12123
- });
12124
- }
12125
- };
12126
- state.agent.on("action", stepHandler);
12790
+ const abortController = new AbortController();
12791
+ setState((prev) => ({ ...prev, abortController }));
12127
12792
  try {
12128
12793
  let messageContent = message;
12129
12794
  let userMessageContent = message;
@@ -12133,11 +12798,13 @@ Remember: Use context from previous messages to understand follow-up questions.$
12133
12798
  userMessageContent = message;
12134
12799
  }
12135
12800
  const userMessage = {
12801
+ id: uuidv410(),
12136
12802
  role: "user",
12137
12803
  content: userMessageContent,
12138
12804
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
12139
12805
  };
12140
12806
  const pendingAssistantMessage = {
12807
+ id: uuidv410(),
12141
12808
  role: "assistant",
12142
12809
  content: "...",
12143
12810
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -12159,14 +12826,21 @@ Remember: Use context from previous messages to understand follow-up questions.$
12159
12826
  content: msg.content
12160
12827
  }));
12161
12828
  const result = await state.agent.run(messageContent, {
12162
- previousMessages: previousMessages.length > 0 ? previousMessages : void 0
12829
+ previousMessages: previousMessages.length > 0 ? previousMessages : void 0,
12830
+ signal: abortController.signal
12163
12831
  });
12832
+ if (abortController.signal.aborted) {
12833
+ logger.debug("[ABORT] Operation was cancelled, discarding result");
12834
+ return;
12835
+ }
12164
12836
  const permissionDenied = result.finalAnswer.startsWith("Permission denied for tool");
12165
12837
  if (permissionDenied) {
12166
12838
  console.log("\n\u26A0\uFE0F Action denied by user\n");
12167
12839
  }
12168
12840
  const successfulToolCalls = result.steps.filter((s) => s.type === "observation").length;
12169
12841
  const finalAssistantMessage = {
12842
+ id: pendingAssistantMessage.id,
12843
+ // Preserve the original message ID
12170
12844
  role: "assistant",
12171
12845
  content: result.finalAnswer,
12172
12846
  timestamp: pendingAssistantMessage.timestamp,
@@ -12197,6 +12871,30 @@ Remember: Use context from previous messages to understand follow-up questions.$
12197
12871
  await state.sessionStore.save(updatedSession);
12198
12872
  } catch (error) {
12199
12873
  useCliStore.getState().clearPendingMessages();
12874
+ if (error instanceof Error && error.name === "AbortError") {
12875
+ logger.debug("[ABORT] Operation aborted by user");
12876
+ const currentSession = useCliStore.getState().session;
12877
+ if (currentSession) {
12878
+ const cancelMessage = {
12879
+ id: uuidv410(),
12880
+ role: "assistant",
12881
+ content: "\u26A0\uFE0F Operation cancelled by user",
12882
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
12883
+ metadata: {
12884
+ cancelled: true
12885
+ }
12886
+ };
12887
+ const sessionWithCancel = {
12888
+ ...currentSession,
12889
+ messages: [...currentSession.messages, cancelMessage],
12890
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
12891
+ };
12892
+ setState((prev) => ({ ...prev, session: sessionWithCancel }));
12893
+ setStoreSession(sessionWithCancel);
12894
+ await state.sessionStore.save(sessionWithCancel);
12895
+ }
12896
+ return;
12897
+ }
12200
12898
  if (error instanceof Error) {
12201
12899
  if (error.message.includes("Authentication failed") || error.message.includes("Authentication expired")) {
12202
12900
  console.log("\n\u274C Authentication failed");
@@ -12206,7 +12904,8 @@ Remember: Use context from previous messages to understand follow-up questions.$
12206
12904
  }
12207
12905
  console.error("Error processing message:", error);
12208
12906
  } finally {
12209
- state.agent.off("action", stepHandler);
12907
+ setState((prev) => ({ ...prev, abortController: null }));
12908
+ useCliStore.getState().setIsThinking(false);
12210
12909
  }
12211
12910
  };
12212
12911
  const handleBashCommand = useCallback(
@@ -12228,11 +12927,13 @@ Remember: Use context from previous messages to understand follow-up questions.$
12228
12927
  isError = true;
12229
12928
  }
12230
12929
  const userMessage = {
12930
+ id: uuidv410(),
12231
12931
  role: "user",
12232
12932
  content: `$ ${command}`,
12233
12933
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
12234
12934
  };
12235
12935
  const assistantMessage = {
12936
+ id: uuidv410(),
12236
12937
  role: "assistant",
12237
12938
  content: isError ? `\u274C Error:
12238
12939
  ${output}` : output.trim() || "(no output)",
@@ -12423,7 +13124,6 @@ Custom Commands:
12423
13124
  logger.debug("=== Session Resumed ===");
12424
13125
  setState((prev) => ({ ...prev, session: loadedSession }));
12425
13126
  setStoreSession(loadedSession);
12426
- useCliStore.getState().clearAgentSteps();
12427
13127
  useCliStore.getState().clearPendingMessages();
12428
13128
  usageCache = null;
12429
13129
  console.log(`
@@ -12643,7 +13343,7 @@ Custom Commands:
12643
13343
  console.clear();
12644
13344
  const model = state.session?.model || state.config?.defaultModel || "claude-sonnet";
12645
13345
  const newSession = {
12646
- id: uuidv49(),
13346
+ id: uuidv410(),
12647
13347
  name: `Session ${(/* @__PURE__ */ new Date()).toLocaleString()}`,
12648
13348
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
12649
13349
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -12659,7 +13359,6 @@ Custom Commands:
12659
13359
  logger.debug("=== New Session Started via /clear ===");
12660
13360
  setState((prev) => ({ ...prev, session: newSession }));
12661
13361
  setStoreSession(newSession);
12662
- useCliStore.getState().clearAgentSteps();
12663
13362
  useCliStore.getState().clearPendingMessages();
12664
13363
  usageCache = null;
12665
13364
  console.log("New session started.");