@bike4mind/cli 0.2.11-fix-tool-pairing-integrity.17312 → 0.2.11-fix-cli-edit-file.17321
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/{artifactExtractor-JAGU7QRL.js → artifactExtractor-BZNU5FMW.js} +1 -1
- package/dist/{chunk-MU4EEXAL.js → chunk-DGAIF2QC.js} +2 -2
- package/dist/{chunk-CQW42LY2.js → chunk-RA3CZOUX.js} +2 -2
- package/dist/{chunk-A3VAT7TT.js → chunk-RBZRTCAY.js} +2 -2
- package/dist/{chunk-TFONTTOE.js → chunk-SQBLLN7K.js} +59 -88
- package/dist/{chunk-DJPXSSP4.js → chunk-WCYNJOOX.js} +4 -0
- package/dist/{create-GE45KYWN.js → create-4KCG4N2U.js} +3 -3
- package/dist/index.js +283 -134
- package/dist/{llmMarkdownGenerator-LXUGJ7QH.js → llmMarkdownGenerator-TUFLBYA3.js} +1 -1
- package/dist/{markdownGenerator-IMDG6OX6.js → markdownGenerator-2WSEU4QD.js} +1 -1
- package/dist/{mementoService-GIDVVHNG.js → mementoService-75KFGFQT.js} +3 -3
- package/dist/{src-XCR4PATL.js → src-JZRDAJFC.js} +2 -2
- package/dist/{src-YNY32ELR.js → src-UHKJ3EHY.js} +1 -1
- package/dist/{subtractCredits-HDHG6FFY.js → subtractCredits-MOVABDWW.js} +3 -3
- package/package.json +6 -6
|
@@ -6,12 +6,12 @@ import {
|
|
|
6
6
|
getSettingsByNames,
|
|
7
7
|
obfuscateApiKey,
|
|
8
8
|
secureParameters
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-SQBLLN7K.js";
|
|
10
10
|
import {
|
|
11
11
|
ApiKeyType,
|
|
12
12
|
MementoTier,
|
|
13
13
|
isSupportedEmbeddingModel
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-WCYNJOOX.js";
|
|
15
15
|
|
|
16
16
|
// ../../b4m-core/packages/services/dist/src/apiKeyService/get.js
|
|
17
17
|
import { z } from "zod";
|
|
@@ -7,11 +7,11 @@ import {
|
|
|
7
7
|
getSettingsMap,
|
|
8
8
|
getSettingsValue,
|
|
9
9
|
secureParameters
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-SQBLLN7K.js";
|
|
11
11
|
import {
|
|
12
12
|
KnowledgeType,
|
|
13
13
|
SupportedFabFileMimeTypes
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-WCYNJOOX.js";
|
|
15
15
|
|
|
16
16
|
// ../../b4m-core/packages/services/dist/src/fabFileService/create.js
|
|
17
17
|
import { z } from "zod";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
BadRequestError,
|
|
4
4
|
secureParameters
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-SQBLLN7K.js";
|
|
6
6
|
import {
|
|
7
7
|
GenericCreditDeductTransaction,
|
|
8
8
|
ImageEditUsageTransaction,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
RealtimeVoiceUsageTransaction,
|
|
11
11
|
TextGenerationUsageTransaction,
|
|
12
12
|
TransferCreditTransaction
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-WCYNJOOX.js";
|
|
14
14
|
|
|
15
15
|
// ../../b4m-core/packages/services/dist/src/creditService/subtractCredits.js
|
|
16
16
|
import { z } from "zod";
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
dayjsConfig_default,
|
|
17
17
|
extractSnippetMeta,
|
|
18
18
|
settingsMap
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-WCYNJOOX.js";
|
|
20
20
|
|
|
21
21
|
// ../../b4m-core/packages/utils/dist/src/storage/S3Storage.js
|
|
22
22
|
import { S3Client, PutObjectCommand, DeleteObjectCommand, GetObjectCommand, HeadObjectCommand } from "@aws-sdk/client-s3";
|
|
@@ -249,6 +249,17 @@ var AnthropicBackend = class {
|
|
|
249
249
|
this._api = new Anthropic({ apiKey });
|
|
250
250
|
this.logger = logger ?? new Logger();
|
|
251
251
|
}
|
|
252
|
+
/**
|
|
253
|
+
* Get thinking blocks from the last assistant content.
|
|
254
|
+
* Filters to only include thinking/redacted_thinking blocks.
|
|
255
|
+
* Returns undefined if thinking is disabled or no blocks are present.
|
|
256
|
+
*/
|
|
257
|
+
getThinkingBlocks() {
|
|
258
|
+
if (!this.isThinkingEnabled)
|
|
259
|
+
return void 0;
|
|
260
|
+
const blocks = this.lastAssistantContent.filter((block) => block?.type === "thinking" || block?.type === "redacted_thinking");
|
|
261
|
+
return blocks.length > 0 ? blocks : void 0;
|
|
262
|
+
}
|
|
252
263
|
async getModelInfo() {
|
|
253
264
|
return [
|
|
254
265
|
{
|
|
@@ -701,8 +712,12 @@ var AnthropicBackend = class {
|
|
|
701
712
|
this.logger.debug(`[Tool Execution] Last few messages:`, JSON.stringify(messages.slice(-3), null, 2));
|
|
702
713
|
await this.complete(model, messages, options, cb, toolsUsed);
|
|
703
714
|
} else {
|
|
704
|
-
|
|
705
|
-
|
|
715
|
+
const thinkingBlocks = this.getThinkingBlocks();
|
|
716
|
+
this.logger.debug(`[Tool Execution] executeTools=false, passing tool calls to callback with ${thinkingBlocks?.length || 0} thinking blocks`);
|
|
717
|
+
await cb([null], {
|
|
718
|
+
toolsUsed,
|
|
719
|
+
thinking: thinkingBlocks
|
|
720
|
+
});
|
|
706
721
|
}
|
|
707
722
|
return;
|
|
708
723
|
}
|
|
@@ -774,8 +789,12 @@ var AnthropicBackend = class {
|
|
|
774
789
|
await this.complete(model, messages, { ...options, tools: void 0, _internal: void 0 }, cb, toolsUsed);
|
|
775
790
|
}
|
|
776
791
|
} else {
|
|
777
|
-
|
|
778
|
-
|
|
792
|
+
const thinkingBlocks = this.getThinkingBlocks();
|
|
793
|
+
this.logger.debug(`[Tool Execution] executeTools=false, passing tool calls to callback with ${thinkingBlocks?.length || 0} thinking blocks`);
|
|
794
|
+
await cb([null], {
|
|
795
|
+
toolsUsed,
|
|
796
|
+
thinking: thinkingBlocks
|
|
797
|
+
});
|
|
779
798
|
}
|
|
780
799
|
return;
|
|
781
800
|
}
|
|
@@ -6248,8 +6267,6 @@ var ensureToolPairingIntegrity = (messages, logger) => {
|
|
|
6248
6267
|
return messages;
|
|
6249
6268
|
}
|
|
6250
6269
|
const toolUseIds = /* @__PURE__ */ new Set();
|
|
6251
|
-
const toolResultIds = /* @__PURE__ */ new Set();
|
|
6252
|
-
let hasToolUseBlocks = false;
|
|
6253
6270
|
let hasToolResultBlocks = false;
|
|
6254
6271
|
for (let i = 0; i < messages.length; i++) {
|
|
6255
6272
|
const message = messages[i];
|
|
@@ -6259,111 +6276,65 @@ var ensureToolPairingIntegrity = (messages, logger) => {
|
|
|
6259
6276
|
const block = content[j];
|
|
6260
6277
|
if (block.type === "tool_use" && "id" in block) {
|
|
6261
6278
|
toolUseIds.add(block.id);
|
|
6262
|
-
hasToolUseBlocks = true;
|
|
6263
6279
|
}
|
|
6264
6280
|
}
|
|
6265
6281
|
} else if (message.role === "user" && Array.isArray(message.content)) {
|
|
6266
6282
|
const content = message.content;
|
|
6267
6283
|
for (let j = 0; j < content.length; j++) {
|
|
6268
|
-
|
|
6269
|
-
if (block.type === "tool_result" && "tool_use_id" in block) {
|
|
6270
|
-
toolResultIds.add(block.tool_use_id);
|
|
6284
|
+
if (content[j].type === "tool_result") {
|
|
6271
6285
|
hasToolResultBlocks = true;
|
|
6286
|
+
break;
|
|
6272
6287
|
}
|
|
6273
6288
|
}
|
|
6274
6289
|
}
|
|
6275
6290
|
}
|
|
6276
|
-
if (!
|
|
6291
|
+
if (!hasToolResultBlocks) {
|
|
6277
6292
|
return messages;
|
|
6278
6293
|
}
|
|
6279
|
-
let
|
|
6280
|
-
let orphanedToolUseCount = 0;
|
|
6294
|
+
let orphanedCount = 0;
|
|
6281
6295
|
const result = [];
|
|
6282
6296
|
for (let i = 0; i < messages.length; i++) {
|
|
6283
6297
|
const message = messages[i];
|
|
6284
|
-
if (message.role
|
|
6285
|
-
|
|
6286
|
-
let hasOrphanedToolUse = false;
|
|
6287
|
-
for (let j = 0; j < content.length; j++) {
|
|
6288
|
-
const block = content[j];
|
|
6289
|
-
if (block.type === "tool_use" && "id" in block) {
|
|
6290
|
-
if (!toolResultIds.has(block.id)) {
|
|
6291
|
-
hasOrphanedToolUse = true;
|
|
6292
|
-
break;
|
|
6293
|
-
}
|
|
6294
|
-
}
|
|
6295
|
-
}
|
|
6296
|
-
if (!hasOrphanedToolUse) {
|
|
6297
|
-
result.push(message);
|
|
6298
|
-
continue;
|
|
6299
|
-
}
|
|
6300
|
-
const filteredContent = [];
|
|
6301
|
-
for (let j = 0; j < content.length; j++) {
|
|
6302
|
-
const block = content[j];
|
|
6303
|
-
if (block.type === "tool_use" && "id" in block) {
|
|
6304
|
-
const toolId = block.id;
|
|
6305
|
-
if (!toolResultIds.has(toolId)) {
|
|
6306
|
-
orphanedToolUseCount++;
|
|
6307
|
-
if (logger) {
|
|
6308
|
-
logger.warn(`Removing orphaned tool_use block with id: ${toolId} (no matching tool_result)`);
|
|
6309
|
-
}
|
|
6310
|
-
continue;
|
|
6311
|
-
}
|
|
6312
|
-
}
|
|
6313
|
-
filteredContent.push(block);
|
|
6314
|
-
}
|
|
6315
|
-
if (filteredContent.length > 0) {
|
|
6316
|
-
result.push({ ...message, content: filteredContent });
|
|
6317
|
-
}
|
|
6298
|
+
if (message.role !== "user" || !Array.isArray(message.content)) {
|
|
6299
|
+
result.push(message);
|
|
6318
6300
|
continue;
|
|
6319
6301
|
}
|
|
6320
|
-
|
|
6321
|
-
|
|
6322
|
-
|
|
6323
|
-
|
|
6324
|
-
|
|
6325
|
-
if (block.
|
|
6326
|
-
|
|
6327
|
-
|
|
6328
|
-
break;
|
|
6329
|
-
}
|
|
6302
|
+
const content = message.content;
|
|
6303
|
+
let hasOrphans = false;
|
|
6304
|
+
for (let j = 0; j < content.length; j++) {
|
|
6305
|
+
const block = content[j];
|
|
6306
|
+
if (block.type === "tool_result" && "tool_use_id" in block) {
|
|
6307
|
+
if (!toolUseIds.has(block.tool_use_id)) {
|
|
6308
|
+
hasOrphans = true;
|
|
6309
|
+
break;
|
|
6330
6310
|
}
|
|
6331
6311
|
}
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
}
|
|
6346
|
-
continue;
|
|
6312
|
+
}
|
|
6313
|
+
if (!hasOrphans) {
|
|
6314
|
+
result.push(message);
|
|
6315
|
+
continue;
|
|
6316
|
+
}
|
|
6317
|
+
const filteredContent = [];
|
|
6318
|
+
for (let j = 0; j < content.length; j++) {
|
|
6319
|
+
const block = content[j];
|
|
6320
|
+
if (block.type === "tool_result" && "tool_use_id" in block) {
|
|
6321
|
+
const toolUseId = block.tool_use_id;
|
|
6322
|
+
if (!toolUseIds.has(toolUseId)) {
|
|
6323
|
+
orphanedCount++;
|
|
6324
|
+
if (logger) {
|
|
6325
|
+
logger.warn(`Removing orphaned tool_result block referencing missing tool_use_id: ${toolUseId}`);
|
|
6347
6326
|
}
|
|
6327
|
+
continue;
|
|
6348
6328
|
}
|
|
6349
|
-
filteredContent.push(block);
|
|
6350
|
-
}
|
|
6351
|
-
if (filteredContent.length > 0) {
|
|
6352
|
-
result.push({ ...message, content: filteredContent });
|
|
6353
6329
|
}
|
|
6354
|
-
|
|
6330
|
+
filteredContent.push(block);
|
|
6355
6331
|
}
|
|
6356
|
-
|
|
6357
|
-
|
|
6358
|
-
if ((orphanedToolResultCount > 0 || orphanedToolUseCount > 0) && logger) {
|
|
6359
|
-
const parts = [];
|
|
6360
|
-
if (orphanedToolResultCount > 0) {
|
|
6361
|
-
parts.push(`${orphanedToolResultCount} orphaned tool_result block(s)`);
|
|
6362
|
-
}
|
|
6363
|
-
if (orphanedToolUseCount > 0) {
|
|
6364
|
-
parts.push(`${orphanedToolUseCount} orphaned tool_use block(s)`);
|
|
6332
|
+
if (filteredContent.length > 0) {
|
|
6333
|
+
result.push({ ...message, content: filteredContent });
|
|
6365
6334
|
}
|
|
6366
|
-
|
|
6335
|
+
}
|
|
6336
|
+
if (orphanedCount > 0 && logger) {
|
|
6337
|
+
logger.log(`Tool pairing integrity: removed ${orphanedCount} orphaned tool_result block(s) after truncation`);
|
|
6367
6338
|
}
|
|
6368
6339
|
return result;
|
|
6369
6340
|
};
|
|
@@ -228,6 +228,7 @@ var b4mLLMTools = z3.enum([
|
|
|
228
228
|
// File operation tools
|
|
229
229
|
"file_read",
|
|
230
230
|
"create_file",
|
|
231
|
+
"edit_local_file",
|
|
231
232
|
"glob_files",
|
|
232
233
|
"grep_search",
|
|
233
234
|
"delete_file",
|
|
@@ -5901,6 +5902,9 @@ function buildSSEEvent(text, info) {
|
|
|
5901
5902
|
outputTokens: info.outputTokens
|
|
5902
5903
|
};
|
|
5903
5904
|
}
|
|
5905
|
+
if (info?.thinking && info.thinking.length > 0) {
|
|
5906
|
+
event.thinking = info.thinking;
|
|
5907
|
+
}
|
|
5904
5908
|
return event;
|
|
5905
5909
|
}
|
|
5906
5910
|
function formatSSEError(error) {
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
createFabFile,
|
|
4
4
|
createFabFileSchema
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-RA3CZOUX.js";
|
|
6
|
+
import "./chunk-SQBLLN7K.js";
|
|
7
7
|
import "./chunk-AMDXHL6S.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-WCYNJOOX.js";
|
|
9
9
|
import "./chunk-PDX44BCA.js";
|
|
10
10
|
export {
|
|
11
11
|
createFabFile,
|
package/dist/index.js
CHANGED
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
getEffectiveApiKey,
|
|
5
5
|
getOpenWeatherKey,
|
|
6
6
|
getSerperKey
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
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-
|
|
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-
|
|
76
|
+
} from "./chunk-WCYNJOOX.js";
|
|
77
77
|
import {
|
|
78
78
|
__require
|
|
79
79
|
} from "./chunk-PDX44BCA.js";
|
|
@@ -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:
|
|
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(
|
|
831
|
-
|
|
832
|
-
if (
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
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
850
|
}
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
setSelectedIndex((prev) => prev < filteredCommands.length - 1 ? prev + 1 : 0);
|
|
854
|
-
}
|
|
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
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
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({
|
|
987
|
-
return /* @__PURE__ */ React6.createElement(Box5, { flexDirection: "column", gap: 1 },
|
|
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, {
|
|
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
|
|
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
|
|
|
@@ -1538,7 +1539,7 @@ ${errorBlock}`;
|
|
|
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,
|
|
@@ -3144,6 +3145,7 @@ ${options.context}` : this.getSystemPrompt()
|
|
|
3144
3145
|
}
|
|
3145
3146
|
if (completionInfo.toolsUsed && completionInfo.toolsUsed.length > 0) {
|
|
3146
3147
|
hadToolCalls = true;
|
|
3148
|
+
const thinkingBlocks = completionInfo.thinking || [];
|
|
3147
3149
|
for (const toolUse of completionInfo.toolsUsed) {
|
|
3148
3150
|
const toolCallId = `${toolUse.name}_${JSON.stringify(toolUse.arguments)}`;
|
|
3149
3151
|
if (processedToolIds.has(toolCallId)) {
|
|
@@ -3176,16 +3178,23 @@ ${options.context}` : this.getSystemPrompt()
|
|
|
3176
3178
|
const params = typeof toolUse.arguments === "string" ? JSON.parse(toolUse.arguments) : toolUse.arguments;
|
|
3177
3179
|
observation = await tool.toolFn(params);
|
|
3178
3180
|
const toolCallId2 = `${toolUse.name}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
3181
|
+
const assistantContent = [
|
|
3182
|
+
// Include thinking blocks first (required by Anthropic when thinking is enabled)
|
|
3183
|
+
...thinkingBlocks,
|
|
3184
|
+
// Then the tool use
|
|
3185
|
+
{
|
|
3186
|
+
type: "tool_use",
|
|
3187
|
+
id: toolCallId2,
|
|
3188
|
+
name: toolUse.name,
|
|
3189
|
+
input: params
|
|
3190
|
+
}
|
|
3191
|
+
];
|
|
3192
|
+
this.context.logger.debug(
|
|
3193
|
+
`[assistantContent] ${assistantContent.length} blocks (${thinkingBlocks.length} thinking, 1 tool_use)`
|
|
3194
|
+
);
|
|
3179
3195
|
messages.push({
|
|
3180
3196
|
role: "assistant",
|
|
3181
|
-
content:
|
|
3182
|
-
{
|
|
3183
|
-
type: "tool_use",
|
|
3184
|
-
id: toolCallId2,
|
|
3185
|
-
name: toolUse.name,
|
|
3186
|
-
input: params
|
|
3187
|
-
}
|
|
3188
|
-
]
|
|
3197
|
+
content: assistantContent
|
|
3189
3198
|
});
|
|
3190
3199
|
messages.push({
|
|
3191
3200
|
role: "user",
|
|
@@ -5476,8 +5485,8 @@ async function processAndStoreImages(images, context) {
|
|
|
5476
5485
|
const buffer = await downloadImage(image);
|
|
5477
5486
|
const fileType = await fileTypeFromBuffer2(buffer);
|
|
5478
5487
|
const filename = `${uuidv46()}.${fileType?.ext}`;
|
|
5479
|
-
const
|
|
5480
|
-
return
|
|
5488
|
+
const path17 = await context.imageGenerateStorage.upload(buffer, filename, {});
|
|
5489
|
+
return path17;
|
|
5481
5490
|
}));
|
|
5482
5491
|
}
|
|
5483
5492
|
async function updateQuestAndReturnMarkdown(storedImageUrls, context) {
|
|
@@ -6689,8 +6698,8 @@ async function processAndStoreImage(imageUrl, context) {
|
|
|
6689
6698
|
const buffer = await downloadImage2(imageUrl);
|
|
6690
6699
|
const fileType = await fileTypeFromBuffer3(buffer);
|
|
6691
6700
|
const filename = `${uuidv47()}.${fileType?.ext}`;
|
|
6692
|
-
const
|
|
6693
|
-
return
|
|
6701
|
+
const path17 = await context.imageGenerateStorage.upload(buffer, filename, {});
|
|
6702
|
+
return path17;
|
|
6694
6703
|
}
|
|
6695
6704
|
async function updateQuestAndReturnMarkdown2(storedImagePath, context) {
|
|
6696
6705
|
await context.onFinish?.("edit_image", storedImagePath);
|
|
@@ -9478,6 +9487,104 @@ BLOCKED OPERATIONS:
|
|
|
9478
9487
|
})
|
|
9479
9488
|
};
|
|
9480
9489
|
|
|
9490
|
+
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/editLocalFile/index.js
|
|
9491
|
+
import { promises as fs11 } from "fs";
|
|
9492
|
+
import { existsSync as existsSync7 } from "fs";
|
|
9493
|
+
import path13 from "path";
|
|
9494
|
+
import { diffLines as diffLines3 } from "diff";
|
|
9495
|
+
function generateDiff(original, modified) {
|
|
9496
|
+
const differences = diffLines3(original, modified);
|
|
9497
|
+
let diffString = "";
|
|
9498
|
+
let additions = 0;
|
|
9499
|
+
let deletions = 0;
|
|
9500
|
+
differences.forEach((part) => {
|
|
9501
|
+
if (part.added) {
|
|
9502
|
+
additions += part.count || 0;
|
|
9503
|
+
diffString += part.value.split("\n").filter((line) => line).map((line) => `+ ${line}`).join("\n");
|
|
9504
|
+
if (diffString && !diffString.endsWith("\n"))
|
|
9505
|
+
diffString += "\n";
|
|
9506
|
+
} else if (part.removed) {
|
|
9507
|
+
deletions += part.count || 0;
|
|
9508
|
+
diffString += part.value.split("\n").filter((line) => line).map((line) => `- ${line}`).join("\n");
|
|
9509
|
+
if (diffString && !diffString.endsWith("\n"))
|
|
9510
|
+
diffString += "\n";
|
|
9511
|
+
}
|
|
9512
|
+
});
|
|
9513
|
+
return { additions, deletions, diff: diffString.trim() };
|
|
9514
|
+
}
|
|
9515
|
+
async function editLocalFile(params) {
|
|
9516
|
+
const { path: filePath, old_string, new_string } = params;
|
|
9517
|
+
const normalizedPath = path13.normalize(filePath);
|
|
9518
|
+
const resolvedPath = path13.resolve(process.cwd(), normalizedPath);
|
|
9519
|
+
const cwd = path13.resolve(process.cwd());
|
|
9520
|
+
if (!resolvedPath.startsWith(cwd)) {
|
|
9521
|
+
throw new Error(`Access denied: Cannot edit files outside of current working directory`);
|
|
9522
|
+
}
|
|
9523
|
+
if (!existsSync7(resolvedPath)) {
|
|
9524
|
+
throw new Error(`File not found: ${filePath}`);
|
|
9525
|
+
}
|
|
9526
|
+
const currentContent = await fs11.readFile(resolvedPath, "utf-8");
|
|
9527
|
+
if (!currentContent.includes(old_string)) {
|
|
9528
|
+
const preview = old_string.length > 100 ? old_string.substring(0, 100) + "..." : old_string;
|
|
9529
|
+
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}"`);
|
|
9530
|
+
}
|
|
9531
|
+
const occurrences = currentContent.split(old_string).length - 1;
|
|
9532
|
+
if (occurrences > 1) {
|
|
9533
|
+
throw new Error(`Found ${occurrences} occurrences of the string to replace. Please provide a more specific old_string that matches exactly one location.`);
|
|
9534
|
+
}
|
|
9535
|
+
const newContent = currentContent.replace(old_string, new_string);
|
|
9536
|
+
await fs11.writeFile(resolvedPath, newContent, "utf-8");
|
|
9537
|
+
const diffResult = generateDiff(old_string, new_string);
|
|
9538
|
+
return `File edited successfully: ${filePath}
|
|
9539
|
+
Changes: +${diffResult.additions} lines, -${diffResult.deletions} lines
|
|
9540
|
+
|
|
9541
|
+
Diff:
|
|
9542
|
+
${diffResult.diff}`;
|
|
9543
|
+
}
|
|
9544
|
+
var editLocalFileTool = {
|
|
9545
|
+
name: "edit_local_file",
|
|
9546
|
+
implementation: (context) => ({
|
|
9547
|
+
toolFn: async (value) => {
|
|
9548
|
+
const params = value;
|
|
9549
|
+
context.logger.info(`\u{1F4DD} EditLocalFile: Editing file`, {
|
|
9550
|
+
path: params.path,
|
|
9551
|
+
oldStringLength: params.old_string.length,
|
|
9552
|
+
newStringLength: params.new_string.length
|
|
9553
|
+
});
|
|
9554
|
+
try {
|
|
9555
|
+
const result = await editLocalFile(params);
|
|
9556
|
+
context.logger.info("\u2705 EditLocalFile: Success", { path: params.path });
|
|
9557
|
+
return result;
|
|
9558
|
+
} catch (error) {
|
|
9559
|
+
context.logger.error("\u274C EditLocalFile: Failed", error);
|
|
9560
|
+
throw error;
|
|
9561
|
+
}
|
|
9562
|
+
},
|
|
9563
|
+
toolSchema: {
|
|
9564
|
+
name: "edit_local_file",
|
|
9565
|
+
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.",
|
|
9566
|
+
parameters: {
|
|
9567
|
+
type: "object",
|
|
9568
|
+
properties: {
|
|
9569
|
+
path: {
|
|
9570
|
+
type: "string",
|
|
9571
|
+
description: "Path to the file to edit (relative to current working directory)"
|
|
9572
|
+
},
|
|
9573
|
+
old_string: {
|
|
9574
|
+
type: "string",
|
|
9575
|
+
description: "The exact string to find and replace. Must match exactly one location in the file, including all whitespace and line endings."
|
|
9576
|
+
},
|
|
9577
|
+
new_string: {
|
|
9578
|
+
type: "string",
|
|
9579
|
+
description: "The string to replace old_string with. Can be empty to delete the old_string."
|
|
9580
|
+
}
|
|
9581
|
+
},
|
|
9582
|
+
required: ["path", "old_string", "new_string"]
|
|
9583
|
+
}
|
|
9584
|
+
}
|
|
9585
|
+
})
|
|
9586
|
+
};
|
|
9587
|
+
|
|
9481
9588
|
// ../../b4m-core/packages/services/dist/src/llm/tools/index.js
|
|
9482
9589
|
var tools = {
|
|
9483
9590
|
dice_roll: diceRollTool,
|
|
@@ -9503,6 +9610,7 @@ var tools = {
|
|
|
9503
9610
|
planet_visibility: planetVisibilityTool,
|
|
9504
9611
|
file_read: fileReadTool,
|
|
9505
9612
|
create_file: createFileTool,
|
|
9613
|
+
edit_local_file: editLocalFileTool,
|
|
9506
9614
|
glob_files: globFilesTool,
|
|
9507
9615
|
grep_search: grepSearchTool,
|
|
9508
9616
|
delete_file: deleteFileTool,
|
|
@@ -9746,10 +9854,10 @@ var ToolErrorType;
|
|
|
9746
9854
|
// src/utils/diffPreview.ts
|
|
9747
9855
|
import * as Diff from "diff";
|
|
9748
9856
|
import { readFile } from "fs/promises";
|
|
9749
|
-
import { existsSync as
|
|
9857
|
+
import { existsSync as existsSync8 } from "fs";
|
|
9750
9858
|
async function generateFileDiffPreview(args) {
|
|
9751
9859
|
try {
|
|
9752
|
-
if (!
|
|
9860
|
+
if (!existsSync8(args.path)) {
|
|
9753
9861
|
const lines2 = args.content.split("\n");
|
|
9754
9862
|
const preview = lines2.slice(0, 20).join("\n");
|
|
9755
9863
|
const hasMore = lines2.length > 20;
|
|
@@ -9771,18 +9879,26 @@ ${preview}${hasMore ? `
|
|
|
9771
9879
|
// Show 3 lines of context around changes
|
|
9772
9880
|
);
|
|
9773
9881
|
const lines = patch.split("\n");
|
|
9774
|
-
const
|
|
9775
|
-
return
|
|
9882
|
+
const diffLines4 = lines.slice(4);
|
|
9883
|
+
return diffLines4.join("\n");
|
|
9776
9884
|
} catch (error) {
|
|
9777
9885
|
return `[Error generating diff preview: ${error instanceof Error ? error.message : "Unknown error"}]`;
|
|
9778
9886
|
}
|
|
9779
9887
|
}
|
|
9888
|
+
function generateEditLocalFilePreview(args) {
|
|
9889
|
+
const patch = Diff.createPatch(args.path, args.old_string, args.new_string, "Current", "Proposed", { context: 3 });
|
|
9890
|
+
const lines = patch.split("\n");
|
|
9891
|
+
const diffLines4 = lines.slice(4);
|
|
9892
|
+
return `[Edit in: ${args.path}]
|
|
9893
|
+
|
|
9894
|
+
${diffLines4.join("\n")}`;
|
|
9895
|
+
}
|
|
9780
9896
|
async function generateFileDeletePreview(args) {
|
|
9781
9897
|
try {
|
|
9782
|
-
if (!
|
|
9898
|
+
if (!existsSync8(args.path)) {
|
|
9783
9899
|
return `[File does not exist: ${args.path}]`;
|
|
9784
9900
|
}
|
|
9785
|
-
const stats = await import("fs/promises").then((
|
|
9901
|
+
const stats = await import("fs/promises").then((fs14) => fs14.stat(args.path));
|
|
9786
9902
|
return `[File will be deleted]
|
|
9787
9903
|
|
|
9788
9904
|
Path: ${args.path}
|
|
@@ -9794,8 +9910,8 @@ Last modified: ${stats.mtime.toLocaleString()}`;
|
|
|
9794
9910
|
}
|
|
9795
9911
|
|
|
9796
9912
|
// src/utils/Logger.ts
|
|
9797
|
-
import
|
|
9798
|
-
import
|
|
9913
|
+
import fs12 from "fs/promises";
|
|
9914
|
+
import path14 from "path";
|
|
9799
9915
|
import os2 from "os";
|
|
9800
9916
|
var Logger2 = class _Logger {
|
|
9801
9917
|
constructor() {
|
|
@@ -9818,9 +9934,9 @@ var Logger2 = class _Logger {
|
|
|
9818
9934
|
*/
|
|
9819
9935
|
async initialize(sessionId) {
|
|
9820
9936
|
this.sessionId = sessionId;
|
|
9821
|
-
const debugDir =
|
|
9822
|
-
await
|
|
9823
|
-
this.logFilePath =
|
|
9937
|
+
const debugDir = path14.join(os2.homedir(), ".bike4mind", "debug");
|
|
9938
|
+
await fs12.mkdir(debugDir, { recursive: true });
|
|
9939
|
+
this.logFilePath = path14.join(debugDir, `${sessionId}.txt`);
|
|
9824
9940
|
await this.writeToFile("INFO", "=== CLI SESSION START ===");
|
|
9825
9941
|
}
|
|
9826
9942
|
/**
|
|
@@ -9884,7 +10000,7 @@ var Logger2 = class _Logger {
|
|
|
9884
10000
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").substring(0, 19);
|
|
9885
10001
|
const logEntry = `[${timestamp}] [${level}] ${message}
|
|
9886
10002
|
`;
|
|
9887
|
-
await
|
|
10003
|
+
await fs12.appendFile(this.logFilePath, logEntry, "utf-8");
|
|
9888
10004
|
} catch (error) {
|
|
9889
10005
|
console.error("File logging failed:", error);
|
|
9890
10006
|
}
|
|
@@ -10030,15 +10146,15 @@ var Logger2 = class _Logger {
|
|
|
10030
10146
|
async cleanupOldLogs() {
|
|
10031
10147
|
if (!this.fileLoggingEnabled) return;
|
|
10032
10148
|
try {
|
|
10033
|
-
const debugDir =
|
|
10034
|
-
const files = await
|
|
10149
|
+
const debugDir = path14.join(os2.homedir(), ".bike4mind", "debug");
|
|
10150
|
+
const files = await fs12.readdir(debugDir);
|
|
10035
10151
|
const now = Date.now();
|
|
10036
10152
|
const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1e3;
|
|
10037
10153
|
for (const file of files) {
|
|
10038
|
-
const filePath =
|
|
10039
|
-
const stats = await
|
|
10154
|
+
const filePath = path14.join(debugDir, file);
|
|
10155
|
+
const stats = await fs12.stat(filePath);
|
|
10040
10156
|
if (stats.mtime.getTime() < thirtyDaysAgo) {
|
|
10041
|
-
await
|
|
10157
|
+
await fs12.unlink(filePath);
|
|
10042
10158
|
}
|
|
10043
10159
|
}
|
|
10044
10160
|
} catch (error) {
|
|
@@ -10095,10 +10211,10 @@ var SERVER_TOOLS = ["weather_info", "web_search"];
|
|
|
10095
10211
|
var LOCAL_TOOLS = [
|
|
10096
10212
|
"file_read",
|
|
10097
10213
|
"create_file",
|
|
10214
|
+
"edit_local_file",
|
|
10098
10215
|
"glob_files",
|
|
10099
10216
|
"grep_search",
|
|
10100
10217
|
"delete_file",
|
|
10101
|
-
"edit_file",
|
|
10102
10218
|
"dice_roll",
|
|
10103
10219
|
"math_evaluate",
|
|
10104
10220
|
"current_datetime",
|
|
@@ -10132,21 +10248,21 @@ var NoOpStorage = class extends BaseStorage {
|
|
|
10132
10248
|
async upload(input, destination, options) {
|
|
10133
10249
|
return `/tmp/${destination}`;
|
|
10134
10250
|
}
|
|
10135
|
-
async download(
|
|
10251
|
+
async download(path17) {
|
|
10136
10252
|
throw new Error("Download not supported in CLI");
|
|
10137
10253
|
}
|
|
10138
|
-
async delete(
|
|
10254
|
+
async delete(path17) {
|
|
10139
10255
|
}
|
|
10140
|
-
async getSignedUrl(
|
|
10141
|
-
return `/tmp/${
|
|
10256
|
+
async getSignedUrl(path17) {
|
|
10257
|
+
return `/tmp/${path17}`;
|
|
10142
10258
|
}
|
|
10143
|
-
getPublicUrl(
|
|
10144
|
-
return `/tmp/${
|
|
10259
|
+
getPublicUrl(path17) {
|
|
10260
|
+
return `/tmp/${path17}`;
|
|
10145
10261
|
}
|
|
10146
|
-
async getPreview(
|
|
10147
|
-
return `/tmp/${
|
|
10262
|
+
async getPreview(path17) {
|
|
10263
|
+
return `/tmp/${path17}`;
|
|
10148
10264
|
}
|
|
10149
|
-
async getMetadata(
|
|
10265
|
+
async getMetadata(path17) {
|
|
10150
10266
|
return { size: 0, contentType: "application/octet-stream" };
|
|
10151
10267
|
}
|
|
10152
10268
|
};
|
|
@@ -10178,11 +10294,12 @@ function wrapToolWithPermission(tool, permissionManager, showPermissionPrompt, a
|
|
|
10178
10294
|
return result2;
|
|
10179
10295
|
}
|
|
10180
10296
|
let preview;
|
|
10181
|
-
if (toolName === "
|
|
10297
|
+
if (toolName === "edit_local_file" && args?.path && args?.old_string && typeof args?.new_string === "string") {
|
|
10182
10298
|
try {
|
|
10183
|
-
preview =
|
|
10299
|
+
preview = generateEditLocalFilePreview({
|
|
10184
10300
|
path: args.path,
|
|
10185
|
-
|
|
10301
|
+
old_string: args.old_string,
|
|
10302
|
+
new_string: args.new_string
|
|
10186
10303
|
});
|
|
10187
10304
|
} catch (error) {
|
|
10188
10305
|
preview = `[Could not generate preview: ${error instanceof Error ? error.message : "Unknown error"}]`;
|
|
@@ -10299,6 +10416,7 @@ function generateCliTools(userId, llm, model, permissionManager, showPermissionP
|
|
|
10299
10416
|
// File operation tools (CLI-specific, local execution)
|
|
10300
10417
|
file_read: {},
|
|
10301
10418
|
create_file: {},
|
|
10419
|
+
edit_local_file: {},
|
|
10302
10420
|
glob_files: {},
|
|
10303
10421
|
grep_search: {},
|
|
10304
10422
|
delete_file: {},
|
|
@@ -10381,6 +10499,7 @@ var DEFAULT_TOOL_CATEGORIES = {
|
|
|
10381
10499
|
// These tools can modify files, execute code, or have other dangerous side effects
|
|
10382
10500
|
// They ALWAYS require permission and cannot be trusted automatically
|
|
10383
10501
|
edit_file: "prompt_always",
|
|
10502
|
+
edit_local_file: "prompt_always",
|
|
10384
10503
|
create_file: "prompt_always",
|
|
10385
10504
|
delete_file: "prompt_always",
|
|
10386
10505
|
shell_execute: "prompt_always",
|
|
@@ -10547,8 +10666,8 @@ function getEnvironmentName(configApiConfig) {
|
|
|
10547
10666
|
}
|
|
10548
10667
|
|
|
10549
10668
|
// src/utils/contextLoader.ts
|
|
10550
|
-
import * as
|
|
10551
|
-
import * as
|
|
10669
|
+
import * as fs13 from "fs";
|
|
10670
|
+
import * as path15 from "path";
|
|
10552
10671
|
import { homedir as homedir4 } from "os";
|
|
10553
10672
|
var CONTEXT_FILE_SIZE_LIMIT = 100 * 1024;
|
|
10554
10673
|
var PROJECT_CONTEXT_FILES = [
|
|
@@ -10569,9 +10688,9 @@ function formatFileSize2(bytes) {
|
|
|
10569
10688
|
return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
10570
10689
|
}
|
|
10571
10690
|
function tryReadContextFile(dir, filename, source) {
|
|
10572
|
-
const filePath =
|
|
10691
|
+
const filePath = path15.join(dir, filename);
|
|
10573
10692
|
try {
|
|
10574
|
-
const stats =
|
|
10693
|
+
const stats = fs13.lstatSync(filePath);
|
|
10575
10694
|
if (stats.isDirectory()) {
|
|
10576
10695
|
return null;
|
|
10577
10696
|
}
|
|
@@ -10585,7 +10704,7 @@ function tryReadContextFile(dir, filename, source) {
|
|
|
10585
10704
|
error: `${source === "global" ? "Global" : "Project"} ${filename} exceeds 100KB limit (${formatFileSize2(stats.size)})`
|
|
10586
10705
|
};
|
|
10587
10706
|
}
|
|
10588
|
-
const content =
|
|
10707
|
+
const content = fs13.readFileSync(filePath, "utf-8");
|
|
10589
10708
|
return {
|
|
10590
10709
|
filename,
|
|
10591
10710
|
content,
|
|
@@ -10637,7 +10756,7 @@ ${project.content}`;
|
|
|
10637
10756
|
}
|
|
10638
10757
|
async function loadContextFiles(projectDir) {
|
|
10639
10758
|
const errors = [];
|
|
10640
|
-
const globalDir =
|
|
10759
|
+
const globalDir = path15.join(homedir4(), ".bike4mind");
|
|
10641
10760
|
const projectDirectory = projectDir || process.cwd();
|
|
10642
10761
|
const [globalResult, projectResult] = await Promise.all([
|
|
10643
10762
|
Promise.resolve(findContextFile(globalDir, GLOBAL_CONTEXT_FILES, "global")),
|
|
@@ -10673,8 +10792,8 @@ function substituteArguments(template, args) {
|
|
|
10673
10792
|
// ../../b4m-core/packages/mcp/dist/src/client.js
|
|
10674
10793
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
10675
10794
|
import { Client as Client2 } from "@modelcontextprotocol/sdk/client/index.js";
|
|
10676
|
-
import
|
|
10677
|
-
import { existsSync as
|
|
10795
|
+
import path16 from "path";
|
|
10796
|
+
import { existsSync as existsSync9, readdirSync as readdirSync3 } from "fs";
|
|
10678
10797
|
var MCPClient = class {
|
|
10679
10798
|
// Note: This class handles MCP server communication with repository filtering
|
|
10680
10799
|
mcp;
|
|
@@ -10714,18 +10833,18 @@ var MCPClient = class {
|
|
|
10714
10833
|
const root = process.env.INIT_CWD || process.cwd();
|
|
10715
10834
|
const candidatePaths = [
|
|
10716
10835
|
// When running from SST Lambda with node_modules structure (copyFiles)
|
|
10717
|
-
|
|
10836
|
+
path16.join(root, `node_modules/@bike4mind/mcp/dist/src/${this.serverName}/index.js`),
|
|
10718
10837
|
// When running from SST Lambda deployed environment (/var/task)
|
|
10719
|
-
|
|
10838
|
+
path16.join(root, `b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
10720
10839
|
// When running from SST Lambda (.sst/artifacts/mcpHandler-dev), navigate to monorepo root (3 levels up)
|
|
10721
|
-
|
|
10840
|
+
path16.join(root, `../../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
10722
10841
|
// When running from packages/client (Next.js app), navigate to monorepo root (2 levels up)
|
|
10723
|
-
|
|
10842
|
+
path16.join(root, `../../b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
10724
10843
|
// Original paths (backward compatibility)
|
|
10725
|
-
|
|
10726
|
-
|
|
10844
|
+
path16.join(root, `/b4m-core/packages/mcp/dist/src/${this.serverName}/index.js`),
|
|
10845
|
+
path16.join(root, "core", "mcp", "servers", this.serverName, "dist", "index.js")
|
|
10727
10846
|
];
|
|
10728
|
-
const serverScriptPath = candidatePaths.find((p) =>
|
|
10847
|
+
const serverScriptPath = candidatePaths.find((p) => existsSync9(p));
|
|
10729
10848
|
if (!serverScriptPath) {
|
|
10730
10849
|
const getDirectories = (source) => readdirSync3(source, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
|
|
10731
10850
|
console.error(`[MCP] Server script not found. Tried paths:`, candidatePaths);
|
|
@@ -11134,6 +11253,7 @@ var ServerLlmBackend = class {
|
|
|
11134
11253
|
let accumulatedText = "";
|
|
11135
11254
|
let lastUsageInfo = {};
|
|
11136
11255
|
let toolsUsed = [];
|
|
11256
|
+
let thinkingBlocks = [];
|
|
11137
11257
|
let receivedDone = false;
|
|
11138
11258
|
const parser = createParser({
|
|
11139
11259
|
onEvent: (event) => {
|
|
@@ -11147,9 +11267,12 @@ var ServerLlmBackend = class {
|
|
|
11147
11267
|
if (toolsUsed.length > 0) {
|
|
11148
11268
|
const info = {
|
|
11149
11269
|
toolsUsed,
|
|
11270
|
+
thinking: thinkingBlocks.length > 0 ? thinkingBlocks : void 0,
|
|
11150
11271
|
...lastUsageInfo
|
|
11151
11272
|
};
|
|
11152
|
-
logger.debug(
|
|
11273
|
+
logger.debug(
|
|
11274
|
+
`[ServerLlmBackend] Calling callback with tools, thinking blocks: ${thinkingBlocks.length}`
|
|
11275
|
+
);
|
|
11153
11276
|
callback([cleanedText], info).catch((err) => {
|
|
11154
11277
|
logger.error("[ServerLlmBackend] Callback error:", err);
|
|
11155
11278
|
reject(err);
|
|
@@ -11205,6 +11328,10 @@ var ServerLlmBackend = class {
|
|
|
11205
11328
|
if (parsed.tools && parsed.tools.length > 0) {
|
|
11206
11329
|
toolsUsed = parsed.tools;
|
|
11207
11330
|
}
|
|
11331
|
+
if (parsed.thinking && parsed.thinking.length > 0) {
|
|
11332
|
+
thinkingBlocks = parsed.thinking;
|
|
11333
|
+
logger.debug(`[ServerLlmBackend] Received ${thinkingBlocks.length} thinking blocks`);
|
|
11334
|
+
}
|
|
11208
11335
|
if (parsed.usage) {
|
|
11209
11336
|
lastUsageInfo = {
|
|
11210
11337
|
inputTokens: parsed.usage.inputTokens,
|
|
@@ -11527,7 +11654,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
|
|
|
11527
11654
|
// package.json
|
|
11528
11655
|
var package_default = {
|
|
11529
11656
|
name: "@bike4mind/cli",
|
|
11530
|
-
version: "0.2.11-fix-
|
|
11657
|
+
version: "0.2.11-fix-cli-edit-file.17321+e2e930d6a",
|
|
11531
11658
|
type: "module",
|
|
11532
11659
|
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
11533
11660
|
license: "UNLICENSED",
|
|
@@ -11631,10 +11758,10 @@ var package_default = {
|
|
|
11631
11758
|
},
|
|
11632
11759
|
devDependencies: {
|
|
11633
11760
|
"@bike4mind/agents": "0.1.0",
|
|
11634
|
-
"@bike4mind/common": "2.40.1-fix-
|
|
11635
|
-
"@bike4mind/mcp": "1.20.5-fix-
|
|
11636
|
-
"@bike4mind/services": "2.35.1-fix-
|
|
11637
|
-
"@bike4mind/utils": "2.1.5-fix-
|
|
11761
|
+
"@bike4mind/common": "2.40.1-fix-cli-edit-file.17321+e2e930d6a",
|
|
11762
|
+
"@bike4mind/mcp": "1.20.5-fix-cli-edit-file.17321+e2e930d6a",
|
|
11763
|
+
"@bike4mind/services": "2.35.1-fix-cli-edit-file.17321+e2e930d6a",
|
|
11764
|
+
"@bike4mind/utils": "2.1.5-fix-cli-edit-file.17321+e2e930d6a",
|
|
11638
11765
|
"@types/better-sqlite3": "^7.6.13",
|
|
11639
11766
|
"@types/diff": "^5.0.9",
|
|
11640
11767
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -11647,7 +11774,7 @@ var package_default = {
|
|
|
11647
11774
|
typescript: "^5.9.3",
|
|
11648
11775
|
vitest: "^3.2.4"
|
|
11649
11776
|
},
|
|
11650
|
-
gitHead: "
|
|
11777
|
+
gitHead: "e2e930d6a6add8a7c1ffa5ebc415a82dabca82e9"
|
|
11651
11778
|
};
|
|
11652
11779
|
|
|
11653
11780
|
// src/config/constants.ts
|
|
@@ -11889,6 +12016,7 @@ Focus on:
|
|
|
11889
12016
|
- Creating logical sequence of steps
|
|
11890
12017
|
- Estimating scope and priorities
|
|
11891
12018
|
|
|
12019
|
+
You have read-only access to analyze code.
|
|
11892
12020
|
You can explore the codebase to understand the current architecture before planning.
|
|
11893
12021
|
|
|
11894
12022
|
Provide a structured plan that the main agent can execute.`,
|
|
@@ -12032,7 +12160,8 @@ function CliApp() {
|
|
|
12032
12160
|
permissionPrompt: null,
|
|
12033
12161
|
trustLocationSelector: null,
|
|
12034
12162
|
rewindSelector: null,
|
|
12035
|
-
sessionSelector: null
|
|
12163
|
+
sessionSelector: null,
|
|
12164
|
+
orchestrator: null
|
|
12036
12165
|
});
|
|
12037
12166
|
const [isInitialized, setIsInitialized] = useState8(false);
|
|
12038
12167
|
const [initError, setInitError] = useState8(null);
|
|
@@ -12354,20 +12483,38 @@ Remember: Use context from previous messages to understand follow-up questions.$
|
|
|
12354
12483
|
const lastIdx = pendingMessages.length - 1;
|
|
12355
12484
|
if (lastIdx >= 0 && pendingMessages[lastIdx].role === "assistant") {
|
|
12356
12485
|
const existingSteps = pendingMessages[lastIdx].metadata?.steps || [];
|
|
12486
|
+
const MAX_INPUT_LENGTH = 500;
|
|
12487
|
+
let truncatedStep = step;
|
|
12488
|
+
if (step.type === "action" && step.metadata?.toolInput) {
|
|
12489
|
+
const inputStr = typeof step.metadata.toolInput === "string" ? step.metadata.toolInput : JSON.stringify(step.metadata.toolInput);
|
|
12490
|
+
if (inputStr.length > MAX_INPUT_LENGTH) {
|
|
12491
|
+
const truncatedInput = inputStr.slice(0, MAX_INPUT_LENGTH) + `... (${inputStr.length - MAX_INPUT_LENGTH} more chars)`;
|
|
12492
|
+
truncatedStep = {
|
|
12493
|
+
...step,
|
|
12494
|
+
metadata: {
|
|
12495
|
+
...step.metadata,
|
|
12496
|
+
toolInput: truncatedInput
|
|
12497
|
+
}
|
|
12498
|
+
};
|
|
12499
|
+
}
|
|
12500
|
+
}
|
|
12357
12501
|
updatePendingMessage(lastIdx, {
|
|
12358
12502
|
...pendingMessages[lastIdx],
|
|
12359
12503
|
metadata: {
|
|
12360
12504
|
...pendingMessages[lastIdx].metadata,
|
|
12361
|
-
steps: [...existingSteps,
|
|
12505
|
+
steps: [...existingSteps, truncatedStep]
|
|
12362
12506
|
}
|
|
12363
12507
|
});
|
|
12364
12508
|
}
|
|
12365
12509
|
};
|
|
12510
|
+
agent.on("thought", stepHandler);
|
|
12366
12511
|
agent.on("action", stepHandler);
|
|
12367
12512
|
orchestrator.setBeforeRunCallback((subagent, _subagentType) => {
|
|
12513
|
+
subagent.on("thought", stepHandler);
|
|
12368
12514
|
subagent.on("action", stepHandler);
|
|
12369
12515
|
});
|
|
12370
12516
|
orchestrator.setAfterRunCallback((subagent, _subagentType) => {
|
|
12517
|
+
subagent.off("thought", stepHandler);
|
|
12371
12518
|
subagent.off("action", stepHandler);
|
|
12372
12519
|
});
|
|
12373
12520
|
setState((prev) => ({
|
|
@@ -12378,8 +12525,10 @@ Remember: Use context from previous messages to understand follow-up questions.$
|
|
|
12378
12525
|
permissionManager,
|
|
12379
12526
|
config,
|
|
12380
12527
|
// Store config for synchronous access
|
|
12381
|
-
availableModels: models
|
|
12528
|
+
availableModels: models,
|
|
12382
12529
|
// Store models for ConfigEditor
|
|
12530
|
+
orchestrator
|
|
12531
|
+
// Store orchestrator for step handler updates
|
|
12383
12532
|
}));
|
|
12384
12533
|
setStoreSession(newSession);
|
|
12385
12534
|
setIsInitialized(true);
|
|
@@ -12434,6 +12583,7 @@ Remember: Use context from previous messages to understand follow-up questions.$
|
|
|
12434
12583
|
}
|
|
12435
12584
|
}
|
|
12436
12585
|
};
|
|
12586
|
+
state.agent.on("thought", stepHandler);
|
|
12437
12587
|
state.agent.on("action", stepHandler);
|
|
12438
12588
|
try {
|
|
12439
12589
|
let messageContent = fullTemplate;
|
|
@@ -12555,6 +12705,7 @@ Remember: Use context from previous messages to understand follow-up questions.$
|
|
|
12555
12705
|
setState((prev) => ({ ...prev, session: sessionWithError }));
|
|
12556
12706
|
setStoreSession(sessionWithError);
|
|
12557
12707
|
} finally {
|
|
12708
|
+
state.agent.off("thought", stepHandler);
|
|
12558
12709
|
state.agent.off("action", stepHandler);
|
|
12559
12710
|
}
|
|
12560
12711
|
};
|
|
@@ -12876,7 +13027,6 @@ Custom Commands:
|
|
|
12876
13027
|
logger.debug("=== Session Resumed ===");
|
|
12877
13028
|
setState((prev) => ({ ...prev, session: loadedSession }));
|
|
12878
13029
|
setStoreSession(loadedSession);
|
|
12879
|
-
useCliStore.getState().clearAgentSteps();
|
|
12880
13030
|
useCliStore.getState().clearPendingMessages();
|
|
12881
13031
|
usageCache = null;
|
|
12882
13032
|
console.log(`
|
|
@@ -13112,7 +13262,6 @@ Custom Commands:
|
|
|
13112
13262
|
logger.debug("=== New Session Started via /clear ===");
|
|
13113
13263
|
setState((prev) => ({ ...prev, session: newSession }));
|
|
13114
13264
|
setStoreSession(newSession);
|
|
13115
|
-
useCliStore.getState().clearAgentSteps();
|
|
13116
13265
|
useCliStore.getState().clearPendingMessages();
|
|
13117
13266
|
usageCache = null;
|
|
13118
13267
|
console.log("New session started.");
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
findMostSimilarMemento,
|
|
4
4
|
getRelevantMementos
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-DGAIF2QC.js";
|
|
6
|
+
import "./chunk-SQBLLN7K.js";
|
|
7
7
|
import "./chunk-AMDXHL6S.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-WCYNJOOX.js";
|
|
9
9
|
import "./chunk-PDX44BCA.js";
|
|
10
10
|
export {
|
|
11
11
|
findMostSimilarMemento,
|
|
@@ -120,7 +120,7 @@ import {
|
|
|
120
120
|
validateMermaidSyntax,
|
|
121
121
|
warmUpSettingsCache,
|
|
122
122
|
withRetry
|
|
123
|
-
} from "./chunk-
|
|
123
|
+
} from "./chunk-SQBLLN7K.js";
|
|
124
124
|
import {
|
|
125
125
|
Logger,
|
|
126
126
|
NotificationDeduplicator,
|
|
@@ -129,7 +129,7 @@ import {
|
|
|
129
129
|
postLowCreditsNotificationToSlack,
|
|
130
130
|
postMessageToSlack
|
|
131
131
|
} from "./chunk-AMDXHL6S.js";
|
|
132
|
-
import "./chunk-
|
|
132
|
+
import "./chunk-WCYNJOOX.js";
|
|
133
133
|
import "./chunk-PDX44BCA.js";
|
|
134
134
|
export {
|
|
135
135
|
AWSBackend,
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
SubtractCreditsSchema,
|
|
4
4
|
subtractCredits
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-RBZRTCAY.js";
|
|
6
|
+
import "./chunk-SQBLLN7K.js";
|
|
7
7
|
import "./chunk-AMDXHL6S.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-WCYNJOOX.js";
|
|
9
9
|
import "./chunk-PDX44BCA.js";
|
|
10
10
|
export {
|
|
11
11
|
SubtractCreditsSchema,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bike4mind/cli",
|
|
3
|
-
"version": "0.2.11-fix-
|
|
3
|
+
"version": "0.2.11-fix-cli-edit-file.17321+e2e930d6a",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -104,10 +104,10 @@
|
|
|
104
104
|
},
|
|
105
105
|
"devDependencies": {
|
|
106
106
|
"@bike4mind/agents": "0.1.0",
|
|
107
|
-
"@bike4mind/common": "2.40.1-fix-
|
|
108
|
-
"@bike4mind/mcp": "1.20.5-fix-
|
|
109
|
-
"@bike4mind/services": "2.35.1-fix-
|
|
110
|
-
"@bike4mind/utils": "2.1.5-fix-
|
|
107
|
+
"@bike4mind/common": "2.40.1-fix-cli-edit-file.17321+e2e930d6a",
|
|
108
|
+
"@bike4mind/mcp": "1.20.5-fix-cli-edit-file.17321+e2e930d6a",
|
|
109
|
+
"@bike4mind/services": "2.35.1-fix-cli-edit-file.17321+e2e930d6a",
|
|
110
|
+
"@bike4mind/utils": "2.1.5-fix-cli-edit-file.17321+e2e930d6a",
|
|
111
111
|
"@types/better-sqlite3": "^7.6.13",
|
|
112
112
|
"@types/diff": "^5.0.9",
|
|
113
113
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -120,5 +120,5 @@
|
|
|
120
120
|
"typescript": "^5.9.3",
|
|
121
121
|
"vitest": "^3.2.4"
|
|
122
122
|
},
|
|
123
|
-
"gitHead": "
|
|
123
|
+
"gitHead": "e2e930d6a6add8a7c1ffa5ebc415a82dabca82e9"
|
|
124
124
|
}
|