@bike4mind/cli 0.2.12-refactor-github-mcp.17405 → 0.2.14-feat-auto-context-customization.17477
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/{ImageStore-RQZ7OF7P.js → ImageStore-MMUOUPI2.js} +0 -1
- package/dist/{artifactExtractor-F2VLARCK.js → artifactExtractor-2BX3PCZE.js} +1 -2
- package/dist/{chunk-ID4NS6KF.js → chunk-7CKPTTMR.js} +18 -2
- package/dist/{chunk-ZHCX7BLB.js → chunk-NR4J636Y.js} +2 -2
- package/dist/{chunk-AMDXHL6S.js → chunk-OCYRD7D6.js} +1 -1
- package/dist/{chunk-OHR7UCTC.js → chunk-PGQJWOFR.js} +15 -0
- package/dist/{chunk-RJFNIMVH.js → chunk-QPYHK4UF.js} +2 -2
- package/dist/{chunk-BU5TP3BH.js → chunk-TJAFO6U3.js} +19 -2
- package/dist/create-5AIX2HIV.js +12 -0
- package/dist/{formatConverter-I7EIUVDY.js → formatConverter-5QEJDW24.js} +0 -1
- package/dist/index.js +526 -279
- package/dist/{llmMarkdownGenerator-AVPOXVE5.js → llmMarkdownGenerator-H45BINU2.js} +1 -2
- package/dist/{markdownGenerator-FBXMTP3B.js → markdownGenerator-6MBFNL4C.js} +1 -2
- package/dist/mementoService-PW22ZYQK.js +12 -0
- package/dist/{notificationDeduplicator-UW7D75QS.js → notificationDeduplicator-UTHJHMSZ.js} +1 -2
- package/dist/{src-YU4VN5YG.js → src-JWTU4FFO.js} +3 -4
- package/dist/{src-SYE7WXBJ.js → src-YVQYFV7D.js} +3 -2
- package/dist/subtractCredits-DSEUPWTG.js +12 -0
- package/dist/{utils-JPMDGUBL.js → utils-JCHWDM4Z.js} +0 -1
- package/package.json +8 -6
- package/dist/chunk-PDX44BCA.js +0 -11
- package/dist/create-MXBWYABO.js +0 -13
- package/dist/mementoService-4WLVEWPZ.js +0 -13
- package/dist/subtractCredits-FGISXF2D.js +0 -13
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-NR4J636Y.js";
|
|
8
|
+
import "./chunk-7CKPTTMR.js";
|
|
9
|
+
import "./chunk-QPYHK4UF.js";
|
|
10
10
|
import {
|
|
11
11
|
BFLImageService,
|
|
12
12
|
BaseStorage,
|
|
@@ -15,10 +15,10 @@ import {
|
|
|
15
15
|
OpenAIBackend,
|
|
16
16
|
OpenAIImageService,
|
|
17
17
|
XAIImageService
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-TJAFO6U3.js";
|
|
19
19
|
import {
|
|
20
20
|
Logger
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-OCYRD7D6.js";
|
|
22
22
|
import "./chunk-BPFEGDC7.js";
|
|
23
23
|
import {
|
|
24
24
|
AiEvents,
|
|
@@ -73,10 +73,7 @@ import {
|
|
|
73
73
|
XAI_IMAGE_MODELS,
|
|
74
74
|
b4mLLMTools,
|
|
75
75
|
getMcpProviderMetadata
|
|
76
|
-
} from "./chunk-
|
|
77
|
-
import {
|
|
78
|
-
__require
|
|
79
|
-
} from "./chunk-PDX44BCA.js";
|
|
76
|
+
} from "./chunk-PGQJWOFR.js";
|
|
80
77
|
|
|
81
78
|
// src/index.tsx
|
|
82
79
|
import React17, { useState as useState8, useEffect as useEffect3, useCallback, useRef as useRef2 } from "react";
|
|
@@ -869,10 +866,11 @@ function InputPrompt({
|
|
|
869
866
|
if (shouldShowCommandAutocomplete && filteredCommands.length > 0) {
|
|
870
867
|
if (key.upArrow) {
|
|
871
868
|
setSelectedIndex((prev) => prev > 0 ? prev - 1 : filteredCommands.length - 1);
|
|
869
|
+
return;
|
|
872
870
|
} else if (key.downArrow) {
|
|
873
871
|
setSelectedIndex((prev) => prev < filteredCommands.length - 1 ? prev + 1 : 0);
|
|
872
|
+
return;
|
|
874
873
|
}
|
|
875
|
-
return;
|
|
876
874
|
}
|
|
877
875
|
if (!shouldShowCommandAutocomplete && !fileAutocomplete?.active && history.length > 0) {
|
|
878
876
|
if (key.upArrow) {
|
|
@@ -1351,7 +1349,7 @@ function MessageItem({ message }) {
|
|
|
1351
1349
|
const isUser = message.role === "user";
|
|
1352
1350
|
return /* @__PURE__ */ React10.createElement(Box9, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React10.createElement(Box9, null, /* @__PURE__ */ React10.createElement(Text9, { bold: true, color: isUser ? "cyan" : "green" }, isUser ? "\u{1F464} You" : "\u{1F916} Assistant"), isUser && /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, " \u2022 ", new Date(message.timestamp).toLocaleTimeString())), isUser && message.content && /* @__PURE__ */ React10.createElement(Box9, { paddingLeft: 2 }, /* @__PURE__ */ React10.createElement(Text9, { backgroundColor: "whiteBright", color: "black" }, " ", message.content, " ")), !isUser && message.metadata?.steps && message.metadata.steps.length > 0 && /* @__PURE__ */ React10.createElement(Box9, { paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { dimColor: true, bold: true }, "\u{1F527} Agent Reasoning Trace (", message.metadata.steps.filter((s) => s.type === "action").length, " ", "tools used, ", message.metadata.steps.length, " total steps)", message.metadata.tokenUsage && ` \u2022 ${message.metadata.tokenUsage.total} tokens`), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, "Step types: ", message.metadata.steps.map((s) => s.type).join(", ")), message.metadata.steps.map((step, idx) => {
|
|
1353
1351
|
if (step.type === "thought") {
|
|
1354
|
-
return /* @__PURE__ */ React10.createElement(Box9, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { color: "blue" }, "\u{1F4AD} Thought:"), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, ` ${step.content
|
|
1352
|
+
return /* @__PURE__ */ React10.createElement(Box9, { key: idx, paddingLeft: 2, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React10.createElement(Text9, { color: "blue" }, "\u{1F4AD} Thought:"), /* @__PURE__ */ React10.createElement(Text9, { dimColor: true }, ` ${step.content}`));
|
|
1355
1353
|
}
|
|
1356
1354
|
if (step.type === "action") {
|
|
1357
1355
|
const toolName = step.metadata?.toolName || "unknown";
|
|
@@ -3140,7 +3138,8 @@ ${options.context}` : this.getSystemPrompt()
|
|
|
3140
3138
|
tools: this.context.tools,
|
|
3141
3139
|
maxTokens,
|
|
3142
3140
|
temperature,
|
|
3143
|
-
abortSignal: options.signal
|
|
3141
|
+
abortSignal: options.signal,
|
|
3142
|
+
tool_choice: this.context.toolChoice
|
|
3144
3143
|
},
|
|
3145
3144
|
async (texts, completionInfo) => {
|
|
3146
3145
|
for (const text of texts) {
|
|
@@ -3394,6 +3393,15 @@ Remember: You are an autonomous AGENT. Act independently and solve problems proa
|
|
|
3394
3393
|
};
|
|
3395
3394
|
|
|
3396
3395
|
// src/core/prompts.ts
|
|
3396
|
+
var TOOL_GREP_SEARCH = "grep_search";
|
|
3397
|
+
var TOOL_GLOB_FILES = "glob_files";
|
|
3398
|
+
var TOOL_FILE_READ = "file_read";
|
|
3399
|
+
var TOOL_EDIT_LOCAL_FILE = "edit_local_file";
|
|
3400
|
+
var TOOL_CREATE_FILE = "create_file";
|
|
3401
|
+
var TOOL_BASH_EXECUTE = "bash_execute";
|
|
3402
|
+
var TOOL_SUBAGENT_DELEGATE = "subagent_delegate";
|
|
3403
|
+
var TOOL_WRITE_TODOS = "write_todos";
|
|
3404
|
+
var EXPLORE_SUBAGENT_TYPE = "explore";
|
|
3397
3405
|
function buildCoreSystemPrompt(contextSection = "") {
|
|
3398
3406
|
return `You are an autonomous AI assistant with access to tools. Your job is to help users by taking action and solving problems proactively.
|
|
3399
3407
|
|
|
@@ -3405,15 +3413,17 @@ CORE BEHAVIOR:
|
|
|
3405
3413
|
|
|
3406
3414
|
FOR SOFTWARE ENGINEERING TASKS:
|
|
3407
3415
|
When requested to perform tasks like fixing bugs, adding features, refactoring, or explaining code, follow this sequence:
|
|
3408
|
-
1. **Understand:** Think about the user's request and the relevant codebase context. Use '
|
|
3416
|
+
1. **Understand:** Think about the user's request and the relevant codebase context. Use '${TOOL_GREP_SEARCH}' and '${TOOL_GLOB_FILES}' search tools extensively (in parallel if independent) to understand file structures, existing code patterns, and conventions. Use '${TOOL_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 '${TOOL_FILE_READ}'.
|
|
3417
|
+
When the task involves **complex refactoring, codebase exploration or system-wide analysis**, your **first and primary action** must be to delegate to the '${EXPLORE_SUBAGENT_TYPE}' agent using the '${TOOL_SUBAGENT_DELEGATE}' tool. Use it to build a comprehensive understanding of the code, its structure, and dependencies. For **simple, targeted searches** (like finding a specific function name, file path, or variable declaration), you should use '${TOOL_GREP_SEARCH}' or '${TOOL_GLOB_FILES}' directly.
|
|
3409
3418
|
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.
|
|
3410
|
-
|
|
3419
|
+
If '${EXPLORE_SUBAGENT_TYPE}' subagent was used, do not ignore the output of the agent, you must use it as the foundation of your plan. For complex tasks, break them down into smaller, manageable subtasks and use the \`${TOOL_WRITE_TODOS}\` tool to track your progress. 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.
|
|
3420
|
+
3. **Implement:** Use the available tools (e.g., '${TOOL_EDIT_LOCAL_FILE}', '${TOOL_CREATE_FILE}', '${TOOL_BASH_EXECUTE}' ...) to act on the plan, strictly adhering to the project's established conventions.
|
|
3411
3421
|
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.
|
|
3412
3422
|
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.
|
|
3413
3423
|
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.
|
|
3414
3424
|
|
|
3415
3425
|
SUBAGENT DELEGATION:
|
|
3416
|
-
- You have access to specialized subagents via the
|
|
3426
|
+
- You have access to specialized subagents via the ${TOOL_SUBAGENT_DELEGATE} tool
|
|
3417
3427
|
- Use subagents for focused exploration, planning, or review tasks:
|
|
3418
3428
|
* explore: Fast read-only codebase search (e.g., "find all auth files", "locate API endpoints")
|
|
3419
3429
|
* plan: Break down complex tasks into actionable steps
|
|
@@ -3429,7 +3439,7 @@ FOR GENERAL TASKS:
|
|
|
3429
3439
|
## Shell tool output token efficiency:
|
|
3430
3440
|
IT IS CRITICAL TO FOLLOW THESE GUIDELINES TO AVOID EXCESSIVE TOKEN CONSUMPTION.
|
|
3431
3441
|
|
|
3432
|
-
- Always prefer command flags that reduce output verbosity when using '
|
|
3442
|
+
- Always prefer command flags that reduce output verbosity when using '${TOOL_BASH_EXECUTE}'.
|
|
3433
3443
|
- Aim to minimize tool output tokens while still capturing necessary information.
|
|
3434
3444
|
- If a command is expected to produce a lot of output, use quiet or silent flags where available and appropriate.
|
|
3435
3445
|
- 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.
|
|
@@ -3439,9 +3449,9 @@ IT IS CRITICAL TO FOLLOW THESE GUIDELINES TO AVOID EXCESSIVE TOKEN CONSUMPTION.
|
|
|
3439
3449
|
EXAMPLES:
|
|
3440
3450
|
- "what should I wear in Texas?" \u2192 use weather tool for Texas
|
|
3441
3451
|
- "how about Japan?" \u2192 use weather tool for Japan (applying same question from context)
|
|
3442
|
-
- "enhance README" \u2192
|
|
3443
|
-
- "what packages installed?" \u2192
|
|
3444
|
-
- "find all components using React hooks" \u2192
|
|
3452
|
+
- "enhance README" \u2192 ${TOOL_FILE_READ} \u2192 generate \u2192 ${TOOL_EDIT_LOCAL_FILE}
|
|
3453
|
+
- "what packages installed?" \u2192 ${TOOL_GLOB_FILES} "**/package.json" \u2192 ${TOOL_FILE_READ}
|
|
3454
|
+
- "find all components using React hooks" \u2192 ${TOOL_SUBAGENT_DELEGATE}(task="find all components using React hooks", type="explore")
|
|
3445
3455
|
|
|
3446
3456
|
Remember: Use context from previous messages to understand follow-up questions.${contextSection}`;
|
|
3447
3457
|
}
|
|
@@ -4385,7 +4395,9 @@ var updateSchema = z77.object({
|
|
|
4385
4395
|
name: z77.string().optional(),
|
|
4386
4396
|
description: z77.string().optional(),
|
|
4387
4397
|
billingContact: z77.string().optional(),
|
|
4388
|
-
currentCredits: z77.coerce.number().optional()
|
|
4398
|
+
currentCredits: z77.coerce.number().optional(),
|
|
4399
|
+
systemPrompt: z77.string().max(1e4).optional()
|
|
4400
|
+
// ~2500 tokens
|
|
4389
4401
|
});
|
|
4390
4402
|
|
|
4391
4403
|
// ../../b4m-core/packages/services/dist/src/organizationService/delete.js
|
|
@@ -8797,98 +8809,80 @@ var createFileTool = {
|
|
|
8797
8809
|
};
|
|
8798
8810
|
|
|
8799
8811
|
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/globFiles/index.js
|
|
8800
|
-
import {
|
|
8801
|
-
import {
|
|
8812
|
+
import { glob } from "glob";
|
|
8813
|
+
import { stat } from "fs/promises";
|
|
8802
8814
|
import path9 from "path";
|
|
8803
|
-
|
|
8804
|
-
|
|
8805
|
-
|
|
8806
|
-
|
|
8807
|
-
|
|
8808
|
-
|
|
8809
|
-
|
|
8810
|
-
|
|
8811
|
-
|
|
8812
|
-
|
|
8813
|
-
|
|
8814
|
-
|
|
8815
|
-
|
|
8816
|
-
|
|
8817
|
-
if (!includeHidden && entry.name.startsWith(".")) {
|
|
8818
|
-
continue;
|
|
8819
|
-
}
|
|
8820
|
-
const relativePath = basePath ? path9.join(basePath, entry.name) : entry.name;
|
|
8821
|
-
const fullPath = path9.join(dir, entry.name);
|
|
8822
|
-
if (matchGlob(relativePath, pattern)) {
|
|
8823
|
-
matches.push(relativePath);
|
|
8824
|
-
}
|
|
8825
|
-
if (entry.isDirectory() && (pattern.includes("**") || pattern.includes("/"))) {
|
|
8826
|
-
const subMatches = await walkDir(fullPath, pattern, includeHidden, maxResults - matches.length, relativePath);
|
|
8827
|
-
matches.push(...subMatches);
|
|
8828
|
-
}
|
|
8829
|
-
}
|
|
8830
|
-
} catch (error) {
|
|
8831
|
-
}
|
|
8832
|
-
return matches;
|
|
8833
|
-
}
|
|
8834
|
-
async function listFiles(params) {
|
|
8835
|
-
const { pattern, cwd: relativeCwd, includeHidden = false, maxResults = 1e3 } = params;
|
|
8815
|
+
var DEFAULT_IGNORE_PATTERNS2 = [
|
|
8816
|
+
"**/node_modules/**",
|
|
8817
|
+
"**/.git/**",
|
|
8818
|
+
"**/dist/**",
|
|
8819
|
+
"**/build/**",
|
|
8820
|
+
"**/.next/**",
|
|
8821
|
+
"**/coverage/**",
|
|
8822
|
+
"**/.turbo/**",
|
|
8823
|
+
"**/.sst/**",
|
|
8824
|
+
"**/*.min.js",
|
|
8825
|
+
"**/*.min.css"
|
|
8826
|
+
];
|
|
8827
|
+
async function findFiles(params) {
|
|
8828
|
+
const { pattern, dir_path, case_sensitive = true, respect_git_ignore = true } = params;
|
|
8836
8829
|
const baseCwd = process.cwd();
|
|
8837
|
-
const
|
|
8838
|
-
if (!
|
|
8839
|
-
throw new Error(`Access denied: Cannot
|
|
8840
|
-
}
|
|
8841
|
-
const
|
|
8830
|
+
const targetDir = dir_path ? path9.resolve(baseCwd, path9.normalize(dir_path)) : baseCwd;
|
|
8831
|
+
if (!targetDir.startsWith(baseCwd)) {
|
|
8832
|
+
throw new Error(`Access denied: Cannot search outside of current working directory`);
|
|
8833
|
+
}
|
|
8834
|
+
const ignorePatterns = respect_git_ignore ? DEFAULT_IGNORE_PATTERNS2 : [];
|
|
8835
|
+
const matches = await glob(pattern, {
|
|
8836
|
+
cwd: targetDir,
|
|
8837
|
+
dot: false,
|
|
8838
|
+
// Don't match hidden files by default
|
|
8839
|
+
ignore: ignorePatterns,
|
|
8840
|
+
absolute: true,
|
|
8841
|
+
nodir: true,
|
|
8842
|
+
// Only return files, not directories
|
|
8843
|
+
nocase: !case_sensitive,
|
|
8844
|
+
// Case-insensitive if requested
|
|
8845
|
+
maxDepth: 20
|
|
8846
|
+
// Reasonable depth limit
|
|
8847
|
+
});
|
|
8842
8848
|
if (matches.length === 0) {
|
|
8843
|
-
return `No files found matching pattern: ${pattern}`;
|
|
8849
|
+
return `No files found matching pattern: ${pattern}${dir_path ? ` in ${dir_path}` : ""}`;
|
|
8844
8850
|
}
|
|
8845
|
-
const
|
|
8846
|
-
for (const
|
|
8851
|
+
const filesWithStats = [];
|
|
8852
|
+
for (const filePath of matches) {
|
|
8847
8853
|
try {
|
|
8848
|
-
const
|
|
8849
|
-
|
|
8850
|
-
|
|
8851
|
-
|
|
8852
|
-
size: stats.size,
|
|
8853
|
-
isDirectory: stats.isDirectory(),
|
|
8854
|
-
modified: stats.mtime.toISOString()
|
|
8854
|
+
const stats = await stat(filePath);
|
|
8855
|
+
filesWithStats.push({
|
|
8856
|
+
path: filePath,
|
|
8857
|
+
mtime: stats.mtimeMs
|
|
8855
8858
|
});
|
|
8856
|
-
} catch
|
|
8859
|
+
} catch {
|
|
8857
8860
|
continue;
|
|
8858
8861
|
}
|
|
8859
8862
|
}
|
|
8860
|
-
|
|
8861
|
-
const
|
|
8862
|
-
|
|
8863
|
-
const
|
|
8864
|
-
` : ""
|
|
8865
|
-
const
|
|
8866
|
-
|
|
8867
|
-
|
|
8868
|
-
|
|
8869
|
-
|
|
8870
|
-
return `${summary}${cwdInfo}
|
|
8863
|
+
filesWithStats.sort((a, b) => b.mtime - a.mtime);
|
|
8864
|
+
const MAX_RESULTS = 500;
|
|
8865
|
+
const truncated = filesWithStats.length > MAX_RESULTS;
|
|
8866
|
+
const results = truncated ? filesWithStats.slice(0, MAX_RESULTS) : filesWithStats;
|
|
8867
|
+
const summary = `Found ${filesWithStats.length} file(s)${truncated ? ` (showing first ${MAX_RESULTS})` : ""} matching: ${pattern}`;
|
|
8868
|
+
const dirInfo = dir_path ? `
|
|
8869
|
+
Directory: ${dir_path}` : "";
|
|
8870
|
+
const filesList = results.map((file) => path9.relative(baseCwd, file.path)).join("\n");
|
|
8871
|
+
return `${summary}${dirInfo}
|
|
8872
|
+
|
|
8871
8873
|
${filesList}`;
|
|
8872
8874
|
}
|
|
8873
|
-
function formatBytes(bytes) {
|
|
8874
|
-
if (bytes === 0)
|
|
8875
|
-
return "0 B";
|
|
8876
|
-
const k = 1024;
|
|
8877
|
-
const sizes = ["B", "KB", "MB", "GB"];
|
|
8878
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
8879
|
-
return `${(bytes / Math.pow(k, i)).toFixed(1)} ${sizes[i]}`;
|
|
8880
|
-
}
|
|
8881
8875
|
var globFilesTool = {
|
|
8882
8876
|
name: "glob_files",
|
|
8883
8877
|
implementation: (context) => ({
|
|
8884
8878
|
toolFn: async (value) => {
|
|
8885
8879
|
const params = value;
|
|
8886
|
-
context.logger.info("\u{1F50D} GlobFiles:
|
|
8880
|
+
context.logger.info("\u{1F50D} GlobFiles: Finding files", {
|
|
8887
8881
|
pattern: params.pattern,
|
|
8888
|
-
|
|
8882
|
+
dir_path: params.dir_path || "."
|
|
8889
8883
|
});
|
|
8890
8884
|
try {
|
|
8891
|
-
const result = await
|
|
8885
|
+
const result = await findFiles(params);
|
|
8892
8886
|
context.logger.info("\u2705 GlobFiles: Success");
|
|
8893
8887
|
return result;
|
|
8894
8888
|
} catch (error) {
|
|
@@ -8898,25 +8892,25 @@ var globFilesTool = {
|
|
|
8898
8892
|
},
|
|
8899
8893
|
toolSchema: {
|
|
8900
8894
|
name: "glob_files",
|
|
8901
|
-
description: "
|
|
8895
|
+
description: "Efficiently finds files matching specific glob patterns (e.g., `src/**/*.ts`, `**/*.md`), returning absolute paths sorted by modification time (newest first). Use this to locate files by name or extension when you need to discover or explore files in a project.",
|
|
8902
8896
|
parameters: {
|
|
8903
8897
|
type: "object",
|
|
8904
8898
|
properties: {
|
|
8905
8899
|
pattern: {
|
|
8906
8900
|
type: "string",
|
|
8907
|
-
description: '
|
|
8901
|
+
description: 'The glob pattern to match against file paths. Supports wildcards (*, **), character ranges ([abc]), and brace expansion ({ts,tsx}). Examples: "*.ts" for TypeScript files in current dir, "src/**/*.tsx" for all TSX files in src tree, "**/*.{js,ts}" for all JS/TS files.'
|
|
8908
8902
|
},
|
|
8909
|
-
|
|
8903
|
+
dir_path: {
|
|
8910
8904
|
type: "string",
|
|
8911
|
-
description: "
|
|
8905
|
+
description: "Optional: The absolute path to the directory to search in. If not specified, uses the current working directory. Must be within the current working directory."
|
|
8912
8906
|
},
|
|
8913
|
-
|
|
8907
|
+
case_sensitive: {
|
|
8914
8908
|
type: "boolean",
|
|
8915
|
-
description: "
|
|
8909
|
+
description: "Optional: Whether the pattern matching should be case-sensitive. Defaults to true. Set to false for case-insensitive matching on case-sensitive file systems."
|
|
8916
8910
|
},
|
|
8917
|
-
|
|
8918
|
-
type: "
|
|
8919
|
-
description: "
|
|
8911
|
+
respect_git_ignore: {
|
|
8912
|
+
type: "boolean",
|
|
8913
|
+
description: "Optional: Whether to respect common ignore patterns (node_modules, .git, dist, build, etc.). Defaults to true. Set to false to include all files."
|
|
8920
8914
|
}
|
|
8921
8915
|
},
|
|
8922
8916
|
required: ["pattern"]
|
|
@@ -8926,158 +8920,144 @@ var globFilesTool = {
|
|
|
8926
8920
|
};
|
|
8927
8921
|
|
|
8928
8922
|
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/grepSearch/index.js
|
|
8929
|
-
import {
|
|
8930
|
-
import {
|
|
8923
|
+
import { globStream } from "glob";
|
|
8924
|
+
import { readFile, stat as stat2 } from "fs/promises";
|
|
8931
8925
|
import path10 from "path";
|
|
8932
8926
|
var MAX_FILE_SIZE3 = 10 * 1024 * 1024;
|
|
8933
|
-
|
|
8934
|
-
|
|
8935
|
-
|
|
8936
|
-
|
|
8937
|
-
|
|
8938
|
-
|
|
8939
|
-
|
|
8927
|
+
var DEFAULT_IGNORE_PATTERNS3 = [
|
|
8928
|
+
"**/node_modules/**",
|
|
8929
|
+
"**/.git/**",
|
|
8930
|
+
"**/dist/**",
|
|
8931
|
+
"**/build/**",
|
|
8932
|
+
"**/.next/**",
|
|
8933
|
+
"**/coverage/**",
|
|
8934
|
+
"**/*.min.js",
|
|
8935
|
+
"**/*.min.css",
|
|
8936
|
+
"**/package-lock.json",
|
|
8937
|
+
"**/pnpm-lock.yaml",
|
|
8938
|
+
"**/yarn.lock"
|
|
8939
|
+
];
|
|
8940
|
+
async function isBinaryFile2(filePath) {
|
|
8940
8941
|
try {
|
|
8941
|
-
const
|
|
8942
|
-
|
|
8943
|
-
|
|
8944
|
-
|
|
8945
|
-
|
|
8946
|
-
|
|
8947
|
-
|
|
8948
|
-
|
|
8949
|
-
|
|
8950
|
-
const fullPath = path10.join(dir, entry.name);
|
|
8951
|
-
if (matchGlob2(relativePath, pattern)) {
|
|
8952
|
-
matches.push(relativePath);
|
|
8953
|
-
}
|
|
8954
|
-
if (entry.isDirectory() && (pattern.includes("**") || pattern.includes("/"))) {
|
|
8955
|
-
const subMatches = await walkDir2(fullPath, pattern, maxResults - matches.length, relativePath);
|
|
8956
|
-
matches.push(...subMatches);
|
|
8957
|
-
}
|
|
8958
|
-
}
|
|
8959
|
-
} catch (error) {
|
|
8942
|
+
const { openSync, readSync, closeSync } = await import("fs");
|
|
8943
|
+
const buffer = Buffer.alloc(8192);
|
|
8944
|
+
const fd = openSync(filePath, "r");
|
|
8945
|
+
const bytesRead = readSync(fd, buffer, 0, 8192, 0);
|
|
8946
|
+
closeSync(fd);
|
|
8947
|
+
const chunk = buffer.slice(0, bytesRead);
|
|
8948
|
+
return chunk.includes(0);
|
|
8949
|
+
} catch {
|
|
8950
|
+
return true;
|
|
8960
8951
|
}
|
|
8961
|
-
|
|
8952
|
+
}
|
|
8953
|
+
function isPathWithinWorkspace(targetPath, baseCwd) {
|
|
8954
|
+
const resolvedTarget = path10.resolve(targetPath);
|
|
8955
|
+
const resolvedBase = path10.resolve(baseCwd);
|
|
8956
|
+
return resolvedTarget.startsWith(resolvedBase);
|
|
8962
8957
|
}
|
|
8963
8958
|
async function searchFiles2(params) {
|
|
8964
|
-
const { pattern,
|
|
8959
|
+
const { pattern, dir_path, include } = params;
|
|
8965
8960
|
const baseCwd = process.cwd();
|
|
8966
|
-
const
|
|
8967
|
-
if (!
|
|
8968
|
-
throw new Error(`
|
|
8961
|
+
const targetDir = dir_path ? path10.resolve(baseCwd, dir_path) : baseCwd;
|
|
8962
|
+
if (!isPathWithinWorkspace(targetDir, baseCwd)) {
|
|
8963
|
+
throw new Error(`Path validation failed: "${dir_path}" resolves outside the allowed workspace directory`);
|
|
8964
|
+
}
|
|
8965
|
+
try {
|
|
8966
|
+
const stats = await stat2(targetDir);
|
|
8967
|
+
if (!stats.isDirectory()) {
|
|
8968
|
+
throw new Error(`Path is not a directory: ${dir_path}`);
|
|
8969
|
+
}
|
|
8970
|
+
} catch (error) {
|
|
8971
|
+
if (error.code === "ENOENT") {
|
|
8972
|
+
throw new Error(`Path does not exist: ${dir_path}`);
|
|
8973
|
+
}
|
|
8974
|
+
throw error;
|
|
8969
8975
|
}
|
|
8970
8976
|
let searchRegex;
|
|
8971
8977
|
try {
|
|
8972
|
-
|
|
8973
|
-
searchRegex = new RegExp(pattern, flags);
|
|
8978
|
+
searchRegex = new RegExp(pattern, "i");
|
|
8974
8979
|
} catch (error) {
|
|
8975
8980
|
throw new Error(`Invalid regex pattern: ${pattern}`);
|
|
8976
8981
|
}
|
|
8977
|
-
const
|
|
8978
|
-
const
|
|
8979
|
-
|
|
8980
|
-
|
|
8982
|
+
const globPattern = include || "**/*";
|
|
8983
|
+
const filesStream = globStream(globPattern, {
|
|
8984
|
+
cwd: targetDir,
|
|
8985
|
+
dot: false,
|
|
8986
|
+
// Skip hidden files
|
|
8987
|
+
ignore: DEFAULT_IGNORE_PATTERNS3,
|
|
8988
|
+
absolute: true,
|
|
8989
|
+
nodir: true
|
|
8990
|
+
// Only match files, not directories
|
|
8991
|
+
});
|
|
8992
|
+
const allMatches = [];
|
|
8993
|
+
let filesSearched = 0;
|
|
8994
|
+
const maxMatches = 500;
|
|
8995
|
+
for await (const filePath of filesStream) {
|
|
8996
|
+
if (allMatches.length >= maxMatches) {
|
|
8997
|
+
break;
|
|
8998
|
+
}
|
|
8999
|
+
const fileAbsPath = filePath;
|
|
8981
9000
|
try {
|
|
8982
|
-
const stats =
|
|
8983
|
-
if (stats.
|
|
9001
|
+
const stats = await stat2(fileAbsPath);
|
|
9002
|
+
if (stats.size > MAX_FILE_SIZE3) {
|
|
8984
9003
|
continue;
|
|
8985
9004
|
}
|
|
8986
|
-
if (isBinaryFile2(
|
|
9005
|
+
if (await isBinaryFile2(fileAbsPath)) {
|
|
8987
9006
|
continue;
|
|
8988
9007
|
}
|
|
8989
|
-
|
|
8990
|
-
|
|
8991
|
-
|
|
8992
|
-
|
|
8993
|
-
|
|
8994
|
-
|
|
8995
|
-
|
|
8996
|
-
|
|
8997
|
-
|
|
8998
|
-
|
|
8999
|
-
for (const file of filteredFiles) {
|
|
9000
|
-
if (matches.length >= maxResults) {
|
|
9001
|
-
break;
|
|
9002
|
-
}
|
|
9003
|
-
filesSearched++;
|
|
9004
|
-
const fullPath = path10.join(targetCwd, file);
|
|
9005
|
-
try {
|
|
9006
|
-
const content = readFileSync3(fullPath, "utf-8");
|
|
9007
|
-
const lines = content.split("\n");
|
|
9008
|
-
for (let i = 0; i < lines.length; i++) {
|
|
9009
|
-
if (matches.length >= maxResults) {
|
|
9010
|
-
break;
|
|
9011
|
-
}
|
|
9012
|
-
const line = lines[i];
|
|
9013
|
-
if (searchRegex.test(line)) {
|
|
9014
|
-
const match = {
|
|
9015
|
-
file,
|
|
9016
|
-
line: i + 1,
|
|
9017
|
-
// 1-indexed line numbers
|
|
9018
|
-
content: line.trim()
|
|
9019
|
-
};
|
|
9020
|
-
if (contextLines > 0) {
|
|
9021
|
-
const before = [];
|
|
9022
|
-
const after = [];
|
|
9023
|
-
for (let j = Math.max(0, i - contextLines); j < i; j++) {
|
|
9024
|
-
before.push(lines[j]);
|
|
9025
|
-
}
|
|
9026
|
-
for (let j = i + 1; j <= Math.min(lines.length - 1, i + contextLines); j++) {
|
|
9027
|
-
after.push(lines[j]);
|
|
9028
|
-
}
|
|
9029
|
-
match.context = { before, after };
|
|
9030
|
-
}
|
|
9031
|
-
matches.push(match);
|
|
9008
|
+
filesSearched++;
|
|
9009
|
+
const content = await readFile(fileAbsPath, "utf8");
|
|
9010
|
+
const lines = content.split(/\r?\n/);
|
|
9011
|
+
lines.forEach((line, index) => {
|
|
9012
|
+
if (allMatches.length < maxMatches && searchRegex.test(line)) {
|
|
9013
|
+
allMatches.push({
|
|
9014
|
+
filePath: path10.relative(targetDir, fileAbsPath) || path10.basename(fileAbsPath),
|
|
9015
|
+
lineNumber: index + 1,
|
|
9016
|
+
line
|
|
9017
|
+
});
|
|
9032
9018
|
}
|
|
9033
|
-
|
|
9019
|
+
});
|
|
9020
|
+
} catch (readError) {
|
|
9021
|
+
const errCode = readError.code;
|
|
9022
|
+
if (errCode !== "ENOENT" && errCode !== "EACCES") {
|
|
9023
|
+
console.debug(`Could not read ${fileAbsPath}: ${readError.message}`);
|
|
9034
9024
|
}
|
|
9035
|
-
} catch {
|
|
9036
|
-
continue;
|
|
9037
9025
|
}
|
|
9038
9026
|
}
|
|
9039
|
-
|
|
9040
|
-
|
|
9041
|
-
|
|
9027
|
+
const searchDirDisplay = dir_path || ".";
|
|
9028
|
+
const filterInfo = include ? ` (filter: "${include}")` : "";
|
|
9029
|
+
if (allMatches.length === 0) {
|
|
9030
|
+
return `No matches found for pattern "${pattern}" in "${searchDirDisplay}"${filterInfo}.
|
|
9031
|
+
Searched ${filesSearched} file(s).`;
|
|
9042
9032
|
}
|
|
9043
|
-
const
|
|
9044
|
-
|
|
9033
|
+
const matchesByFile = allMatches.reduce((acc, match) => {
|
|
9034
|
+
if (!acc[match.filePath]) {
|
|
9035
|
+
acc[match.filePath] = [];
|
|
9036
|
+
}
|
|
9037
|
+
acc[match.filePath].push(match);
|
|
9038
|
+
acc[match.filePath].sort((a, b) => a.lineNumber - b.lineNumber);
|
|
9039
|
+
return acc;
|
|
9040
|
+
}, {});
|
|
9041
|
+
const matchCount = allMatches.length;
|
|
9042
|
+
const matchTerm = matchCount === 1 ? "match" : "matches";
|
|
9043
|
+
const truncated = matchCount >= maxMatches;
|
|
9044
|
+
let result = `Found ${matchCount} ${matchTerm}${truncated ? " (truncated)" : ""} for pattern "${pattern}" in "${searchDirDisplay}"${filterInfo}:
|
|
9045
9045
|
`;
|
|
9046
|
-
|
|
9046
|
+
result += `Searched ${filesSearched} file(s)
|
|
9047
|
+
---
|
|
9047
9048
|
`;
|
|
9048
|
-
const
|
|
9049
|
-
`
|
|
9050
|
-
|
|
9051
|
-
|
|
9052
|
-
|
|
9053
|
-
|
|
9054
|
-
|
|
9055
|
-
|
|
9056
|
-
|
|
9057
|
-
|
|
9058
|
-
${match.context.before.map((l) => ` ${l}`).join("\n")}`;
|
|
9059
|
-
}
|
|
9060
|
-
if (match.context.after.length > 0) {
|
|
9061
|
-
result = `${result}
|
|
9062
|
-
Context after:
|
|
9063
|
-
${match.context.after.map((l) => ` ${l}`).join("\n")}`;
|
|
9064
|
-
}
|
|
9065
|
-
}
|
|
9066
|
-
return result;
|
|
9067
|
-
}).join("\n");
|
|
9068
|
-
return `${summary}${patternInfo}${cwdInfo}${matchesList}`;
|
|
9069
|
-
}
|
|
9070
|
-
function isBinaryFile2(filePath) {
|
|
9071
|
-
try {
|
|
9072
|
-
const buffer = Buffer.alloc(8192);
|
|
9073
|
-
const fd = __require("fs").openSync(filePath, "r");
|
|
9074
|
-
const bytesRead = __require("fs").readSync(fd, buffer, 0, 8192, 0);
|
|
9075
|
-
__require("fs").closeSync(fd);
|
|
9076
|
-
const chunk = buffer.slice(0, bytesRead);
|
|
9077
|
-
return chunk.includes(0);
|
|
9078
|
-
} catch {
|
|
9079
|
-
return true;
|
|
9049
|
+
for (const filePath in matchesByFile) {
|
|
9050
|
+
result += `File: ${filePath}
|
|
9051
|
+
`;
|
|
9052
|
+
matchesByFile[filePath].forEach((match) => {
|
|
9053
|
+
const trimmedLine = match.line.trim();
|
|
9054
|
+
const displayLine = trimmedLine.length > 200 ? trimmedLine.slice(0, 200) + "..." : trimmedLine;
|
|
9055
|
+
result += `L${match.lineNumber}: ${displayLine}
|
|
9056
|
+
`;
|
|
9057
|
+
});
|
|
9058
|
+
result += "---\n";
|
|
9080
9059
|
}
|
|
9060
|
+
return result.trim();
|
|
9081
9061
|
}
|
|
9082
9062
|
var grepSearchTool = {
|
|
9083
9063
|
name: "grep_search",
|
|
@@ -9086,8 +9066,8 @@ var grepSearchTool = {
|
|
|
9086
9066
|
const params = value;
|
|
9087
9067
|
context.logger.info("\u{1F50D} GrepSearch: Searching files", {
|
|
9088
9068
|
pattern: params.pattern,
|
|
9089
|
-
|
|
9090
|
-
|
|
9069
|
+
dir_path: params.dir_path || ".",
|
|
9070
|
+
include: params.include || "**/*"
|
|
9091
9071
|
});
|
|
9092
9072
|
try {
|
|
9093
9073
|
const result = await searchFiles2(params);
|
|
@@ -9100,33 +9080,21 @@ var grepSearchTool = {
|
|
|
9100
9080
|
},
|
|
9101
9081
|
toolSchema: {
|
|
9102
9082
|
name: "grep_search",
|
|
9103
|
-
description: "
|
|
9083
|
+
description: "Searches for a regular expression pattern within the content of files in a specified directory (or current working directory). Can filter files by a glob pattern. Returns the lines containing matches, along with their file paths and line numbers.",
|
|
9104
9084
|
parameters: {
|
|
9105
9085
|
type: "object",
|
|
9106
9086
|
properties: {
|
|
9107
9087
|
pattern: {
|
|
9108
9088
|
type: "string",
|
|
9109
|
-
description: "
|
|
9089
|
+
description: "The regular expression (regex) pattern to search for within file contents (e.g., 'function\\s+myFunction', 'import\\s+\\{.*\\}\\s+from\\s+.*')."
|
|
9110
9090
|
},
|
|
9111
|
-
|
|
9091
|
+
dir_path: {
|
|
9112
9092
|
type: "string",
|
|
9113
|
-
description:
|
|
9093
|
+
description: "Optional: The absolute path to the directory to search within. If omitted, searches the current working directory."
|
|
9114
9094
|
},
|
|
9115
|
-
|
|
9095
|
+
include: {
|
|
9116
9096
|
type: "string",
|
|
9117
|
-
description: "
|
|
9118
|
-
},
|
|
9119
|
-
caseSensitive: {
|
|
9120
|
-
type: "boolean",
|
|
9121
|
-
description: "Whether the search should be case-sensitive (default: false)"
|
|
9122
|
-
},
|
|
9123
|
-
maxResults: {
|
|
9124
|
-
type: "number",
|
|
9125
|
-
description: "Maximum number of matches to return (default: 100). Prevents overwhelming output."
|
|
9126
|
-
},
|
|
9127
|
-
contextLines: {
|
|
9128
|
-
type: "number",
|
|
9129
|
-
description: "Number of context lines to show before and after each match (default: 0). Similar to grep -C option."
|
|
9097
|
+
description: "Optional: A glob pattern to filter which files are searched (e.g., '*.js', '*.{ts,tsx}', 'src/**'). If omitted, searches all files (respecting potential global ignores)."
|
|
9130
9098
|
}
|
|
9131
9099
|
},
|
|
9132
9100
|
required: ["pattern"]
|
|
@@ -9137,7 +9105,7 @@ var grepSearchTool = {
|
|
|
9137
9105
|
|
|
9138
9106
|
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/deleteFile/index.js
|
|
9139
9107
|
import { promises as fs10 } from "fs";
|
|
9140
|
-
import { existsSync as existsSync6, statSync as
|
|
9108
|
+
import { existsSync as existsSync6, statSync as statSync5 } from "fs";
|
|
9141
9109
|
import path11 from "path";
|
|
9142
9110
|
async function deleteFile(params) {
|
|
9143
9111
|
const { path: filePath, recursive = false } = params;
|
|
@@ -9150,7 +9118,7 @@ async function deleteFile(params) {
|
|
|
9150
9118
|
if (!existsSync6(resolvedPath)) {
|
|
9151
9119
|
throw new Error(`File or directory not found: ${filePath}`);
|
|
9152
9120
|
}
|
|
9153
|
-
const stats =
|
|
9121
|
+
const stats = statSync5(resolvedPath);
|
|
9154
9122
|
const isDirectory = stats.isDirectory();
|
|
9155
9123
|
const size = stats.size;
|
|
9156
9124
|
if (isDirectory && !recursive) {
|
|
@@ -9171,7 +9139,7 @@ var deleteFileTool = {
|
|
|
9171
9139
|
toolFn: async (value) => {
|
|
9172
9140
|
const params = value;
|
|
9173
9141
|
const resolvedPath = path11.resolve(process.cwd(), path11.normalize(params.path));
|
|
9174
|
-
const isDirectory = existsSync6(resolvedPath) &&
|
|
9142
|
+
const isDirectory = existsSync6(resolvedPath) && statSync5(resolvedPath).isDirectory();
|
|
9175
9143
|
context.logger.info(`\u{1F5D1}\uFE0F DeleteFile: Deleting ${isDirectory ? "directory" : "file"}`, {
|
|
9176
9144
|
path: params.path,
|
|
9177
9145
|
recursive: params.recursive
|
|
@@ -9206,6 +9174,92 @@ var deleteFileTool = {
|
|
|
9206
9174
|
})
|
|
9207
9175
|
};
|
|
9208
9176
|
|
|
9177
|
+
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/knowledgeBaseSearch/index.js
|
|
9178
|
+
function formatSearchResults(files) {
|
|
9179
|
+
if (files.length === 0) {
|
|
9180
|
+
return "No documents found matching your search query in your knowledge base.";
|
|
9181
|
+
}
|
|
9182
|
+
const formattedFiles = files.map((file, index) => {
|
|
9183
|
+
const tags = file.tags?.map((t) => t.name).join(", ") || "none";
|
|
9184
|
+
const notes = file.notes ? `
|
|
9185
|
+
Notes: ${file.notes}` : "";
|
|
9186
|
+
const fileType = file.type || "FILE";
|
|
9187
|
+
return `${index + 1}. **${file.fileName}**
|
|
9188
|
+
Type: ${fileType} | MIME: ${file.mimeType}
|
|
9189
|
+
Tags: ${tags}${notes}`;
|
|
9190
|
+
});
|
|
9191
|
+
return `Found ${files.length} document(s) in your knowledge base:
|
|
9192
|
+
|
|
9193
|
+
` + formattedFiles.join("\n\n") + "\n\n*To use these documents in your conversation, you can ask me to reference specific files by name.*";
|
|
9194
|
+
}
|
|
9195
|
+
var knowledgeBaseSearchTool = {
|
|
9196
|
+
name: "search_knowledge_base",
|
|
9197
|
+
implementation: (context) => ({
|
|
9198
|
+
toolFn: async (value) => {
|
|
9199
|
+
const params = value;
|
|
9200
|
+
const { query, tags, file_type, max_results = 5 } = params;
|
|
9201
|
+
console.log("\u{1F4DA} Knowledge Base Search: Starting search for query:", query);
|
|
9202
|
+
if (!context.db.fabfiles) {
|
|
9203
|
+
console.error("\u274C Knowledge Base Search: fabfiles repository not available");
|
|
9204
|
+
return "Knowledge base search is not available at this time.";
|
|
9205
|
+
}
|
|
9206
|
+
try {
|
|
9207
|
+
const searchResults = await context.db.fabfiles.search(context.userId, query, {
|
|
9208
|
+
tags: tags || [],
|
|
9209
|
+
type: file_type,
|
|
9210
|
+
shared: false
|
|
9211
|
+
// Search all accessible files, not just shared
|
|
9212
|
+
}, {
|
|
9213
|
+
page: 1,
|
|
9214
|
+
limit: Math.min(max_results, 10)
|
|
9215
|
+
// Cap at 10 results
|
|
9216
|
+
}, {
|
|
9217
|
+
by: "fileName",
|
|
9218
|
+
direction: "asc"
|
|
9219
|
+
}, {
|
|
9220
|
+
includeShared: true
|
|
9221
|
+
// Include organization and explicitly shared files
|
|
9222
|
+
});
|
|
9223
|
+
console.log("\u{1F4DA} Knowledge Base Search: Found", searchResults.data.length, "results");
|
|
9224
|
+
return formatSearchResults(searchResults.data);
|
|
9225
|
+
} catch (error) {
|
|
9226
|
+
console.error("\u274C Knowledge Base Search: Error during search:", error);
|
|
9227
|
+
return "An error occurred while searching your knowledge base. Please try again.";
|
|
9228
|
+
}
|
|
9229
|
+
},
|
|
9230
|
+
toolSchema: {
|
|
9231
|
+
name: "search_knowledge_base",
|
|
9232
|
+
description: "Search the user's uploaded knowledge base (fab files). Returns relevant documents from the user's own files, organization-shared files, and files explicitly shared with them. Use this tool when the user asks about their own documents, uploaded files, or organization knowledge.",
|
|
9233
|
+
parameters: {
|
|
9234
|
+
type: "object",
|
|
9235
|
+
properties: {
|
|
9236
|
+
query: {
|
|
9237
|
+
type: "string",
|
|
9238
|
+
description: "The search query to find relevant documents by filename or content"
|
|
9239
|
+
},
|
|
9240
|
+
tags: {
|
|
9241
|
+
type: "array",
|
|
9242
|
+
items: { type: "string" },
|
|
9243
|
+
description: "Optional: filter results to only include files with these tags"
|
|
9244
|
+
},
|
|
9245
|
+
file_type: {
|
|
9246
|
+
type: "string",
|
|
9247
|
+
enum: ["pdf", "text", "image", "excel", "word", "json", "csv", "markdown", "code", "url"],
|
|
9248
|
+
description: "Optional: filter results by file type"
|
|
9249
|
+
},
|
|
9250
|
+
max_results: {
|
|
9251
|
+
type: "number",
|
|
9252
|
+
description: "Maximum number of results to return (default: 5, max: 10)",
|
|
9253
|
+
minimum: 1,
|
|
9254
|
+
maximum: 10
|
|
9255
|
+
}
|
|
9256
|
+
},
|
|
9257
|
+
required: ["query"]
|
|
9258
|
+
}
|
|
9259
|
+
}
|
|
9260
|
+
})
|
|
9261
|
+
};
|
|
9262
|
+
|
|
9209
9263
|
// ../../b4m-core/packages/services/dist/src/llm/tools/implementation/bashExecute/index.js
|
|
9210
9264
|
import { spawn } from "child_process";
|
|
9211
9265
|
import path12 from "path";
|
|
@@ -9708,6 +9762,8 @@ var tools = {
|
|
|
9708
9762
|
glob_files: globFilesTool,
|
|
9709
9763
|
grep_search: grepSearchTool,
|
|
9710
9764
|
delete_file: deleteFileTool,
|
|
9765
|
+
// Knowledge base search
|
|
9766
|
+
search_knowledge_base: knowledgeBaseSearchTool,
|
|
9711
9767
|
// Shell execution
|
|
9712
9768
|
bash_execute: bashExecuteTool
|
|
9713
9769
|
};
|
|
@@ -9947,7 +10003,7 @@ var ToolErrorType;
|
|
|
9947
10003
|
|
|
9948
10004
|
// src/utils/diffPreview.ts
|
|
9949
10005
|
import * as Diff from "diff";
|
|
9950
|
-
import { readFile } from "fs/promises";
|
|
10006
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
9951
10007
|
import { existsSync as existsSync8 } from "fs";
|
|
9952
10008
|
async function generateFileDiffPreview(args) {
|
|
9953
10009
|
try {
|
|
@@ -9962,7 +10018,7 @@ ${preview}${hasMore ? `
|
|
|
9962
10018
|
|
|
9963
10019
|
... (${lines2.length - 20} more lines)` : ""}`;
|
|
9964
10020
|
}
|
|
9965
|
-
const currentContent = await
|
|
10021
|
+
const currentContent = await readFile2(args.path, "utf-8");
|
|
9966
10022
|
const patch = Diff.createPatch(
|
|
9967
10023
|
args.path,
|
|
9968
10024
|
currentContent,
|
|
@@ -10871,6 +10927,82 @@ async function loadContextFiles(projectDir) {
|
|
|
10871
10927
|
};
|
|
10872
10928
|
}
|
|
10873
10929
|
|
|
10930
|
+
// src/utils/formatStep.ts
|
|
10931
|
+
var MAX_INPUT_LENGTH = 500;
|
|
10932
|
+
var formatStep = (step) => {
|
|
10933
|
+
if (step.type === "action" && step.metadata?.toolInput) {
|
|
10934
|
+
let parsedInput = step.metadata.toolInput;
|
|
10935
|
+
if (typeof parsedInput === "string") {
|
|
10936
|
+
try {
|
|
10937
|
+
parsedInput = JSON.parse(parsedInput);
|
|
10938
|
+
} catch {
|
|
10939
|
+
}
|
|
10940
|
+
}
|
|
10941
|
+
if (step.metadata.toolName === "edit_local_file") {
|
|
10942
|
+
const pathOnly = typeof parsedInput === "object" && parsedInput !== null && "path" in parsedInput ? { path: parsedInput.path } : parsedInput;
|
|
10943
|
+
return {
|
|
10944
|
+
...step,
|
|
10945
|
+
metadata: {
|
|
10946
|
+
...step.metadata,
|
|
10947
|
+
toolInput: pathOnly
|
|
10948
|
+
}
|
|
10949
|
+
};
|
|
10950
|
+
}
|
|
10951
|
+
if (step.metadata.toolName === "write_todos") {
|
|
10952
|
+
const todos = typeof parsedInput === "object" && parsedInput !== null && "todos" in parsedInput ? parsedInput.todos : null;
|
|
10953
|
+
const count = Array.isArray(todos) ? todos.length : 0;
|
|
10954
|
+
return {
|
|
10955
|
+
...step,
|
|
10956
|
+
metadata: {
|
|
10957
|
+
...step.metadata,
|
|
10958
|
+
toolInput: `${count} todo${count !== 1 ? "s" : ""}`
|
|
10959
|
+
}
|
|
10960
|
+
};
|
|
10961
|
+
}
|
|
10962
|
+
const inputStr = typeof parsedInput === "string" ? parsedInput : JSON.stringify(parsedInput);
|
|
10963
|
+
if (inputStr.length > MAX_INPUT_LENGTH) {
|
|
10964
|
+
const truncatedInput = inputStr.slice(0, MAX_INPUT_LENGTH) + `... (${inputStr.length - MAX_INPUT_LENGTH} more chars)`;
|
|
10965
|
+
return {
|
|
10966
|
+
...step,
|
|
10967
|
+
metadata: {
|
|
10968
|
+
...step.metadata,
|
|
10969
|
+
toolInput: truncatedInput
|
|
10970
|
+
}
|
|
10971
|
+
};
|
|
10972
|
+
}
|
|
10973
|
+
}
|
|
10974
|
+
if (step.type === "observation" && step.content) {
|
|
10975
|
+
if (step.metadata?.toolName === "file_read") {
|
|
10976
|
+
const lineCount = step.content.split("\n").length;
|
|
10977
|
+
return {
|
|
10978
|
+
...step,
|
|
10979
|
+
content: `Read ${lineCount} line${lineCount !== 1 ? "s" : ""}`
|
|
10980
|
+
};
|
|
10981
|
+
}
|
|
10982
|
+
if (step.metadata?.toolName === "grep_search") {
|
|
10983
|
+
const match = step.content.match(/^Found (\d+) file\(s\)/);
|
|
10984
|
+
if (match) {
|
|
10985
|
+
const count = parseInt(match[1], 10);
|
|
10986
|
+
return {
|
|
10987
|
+
...step,
|
|
10988
|
+
content: `Found ${count} file${count !== 1 ? "s" : ""}`
|
|
10989
|
+
};
|
|
10990
|
+
}
|
|
10991
|
+
}
|
|
10992
|
+
if (step.metadata?.toolName === "glob_files") {
|
|
10993
|
+
const match = step.content.match(/^Found (\d+) file\(s\)/);
|
|
10994
|
+
if (match) {
|
|
10995
|
+
const count = parseInt(match[1], 10);
|
|
10996
|
+
return {
|
|
10997
|
+
...step,
|
|
10998
|
+
content: `Found ${count} file${count !== 1 ? "s" : ""}`
|
|
10999
|
+
};
|
|
11000
|
+
}
|
|
11001
|
+
}
|
|
11002
|
+
}
|
|
11003
|
+
return step;
|
|
11004
|
+
};
|
|
11005
|
+
|
|
10874
11006
|
// src/utils/argumentSubstitution.ts
|
|
10875
11007
|
function substituteArguments(template, args) {
|
|
10876
11008
|
let result = template;
|
|
@@ -11786,7 +11918,7 @@ import { isAxiosError as isAxiosError2 } from "axios";
|
|
|
11786
11918
|
// package.json
|
|
11787
11919
|
var package_default = {
|
|
11788
11920
|
name: "@bike4mind/cli",
|
|
11789
|
-
version: "0.2.
|
|
11921
|
+
version: "0.2.14-feat-auto-context-customization.17477+d37aab404",
|
|
11790
11922
|
type: "module",
|
|
11791
11923
|
description: "Interactive CLI tool for Bike4Mind with ReAct agents",
|
|
11792
11924
|
license: "UNLICENSED",
|
|
@@ -11857,6 +11989,7 @@ var package_default = {
|
|
|
11857
11989
|
"eventsource-parser": "^3.0.6",
|
|
11858
11990
|
"file-type": "^18.7.0",
|
|
11859
11991
|
"fuse.js": "^7.1.0",
|
|
11992
|
+
glob: "^13.0.0",
|
|
11860
11993
|
"gray-matter": "^4.0.3",
|
|
11861
11994
|
ink: "^6.5.1",
|
|
11862
11995
|
"ink-select-input": "^6.2.0",
|
|
@@ -11891,10 +12024,10 @@ var package_default = {
|
|
|
11891
12024
|
},
|
|
11892
12025
|
devDependencies: {
|
|
11893
12026
|
"@bike4mind/agents": "0.1.0",
|
|
11894
|
-
"@bike4mind/common": "2.
|
|
11895
|
-
"@bike4mind/mcp": "1.21.
|
|
11896
|
-
"@bike4mind/services": "2.
|
|
11897
|
-
"@bike4mind/utils": "2.1.
|
|
12027
|
+
"@bike4mind/common": "2.42.1-feat-auto-context-customization.17477+d37aab404",
|
|
12028
|
+
"@bike4mind/mcp": "1.21.3-feat-auto-context-customization.17477+d37aab404",
|
|
12029
|
+
"@bike4mind/services": "2.37.1-feat-auto-context-customization.17477+d37aab404",
|
|
12030
|
+
"@bike4mind/utils": "2.1.8-feat-auto-context-customization.17477+d37aab404",
|
|
11898
12031
|
"@types/better-sqlite3": "^7.6.13",
|
|
11899
12032
|
"@types/diff": "^5.0.9",
|
|
11900
12033
|
"@types/jsonwebtoken": "^9.0.4",
|
|
@@ -11902,12 +12035,13 @@ var package_default = {
|
|
|
11902
12035
|
"@types/react": "^19.2.7",
|
|
11903
12036
|
"@types/uuid": "^9.0.7",
|
|
11904
12037
|
"@types/yargs": "^17.0.32",
|
|
12038
|
+
"ink-testing-library": "^4.0.0",
|
|
11905
12039
|
tsup: "^8.5.1",
|
|
11906
12040
|
tsx: "^4.21.0",
|
|
11907
12041
|
typescript: "^5.9.3",
|
|
11908
12042
|
vitest: "^3.2.4"
|
|
11909
12043
|
},
|
|
11910
|
-
gitHead: "
|
|
12044
|
+
gitHead: "d37aab40411dfc92c084c715054d5ea3aaaff579"
|
|
11911
12045
|
};
|
|
11912
12046
|
|
|
11913
12047
|
// src/config/constants.ts
|
|
@@ -12263,6 +12397,131 @@ function createSubagentDelegateTool(orchestrator, parentSessionId) {
|
|
|
12263
12397
|
};
|
|
12264
12398
|
}
|
|
12265
12399
|
|
|
12400
|
+
// src/tools/writeTodosTool.ts
|
|
12401
|
+
var VALID_STATUSES = ["pending", "in_progress", "completed", "cancelled"];
|
|
12402
|
+
function validateTodos(todos) {
|
|
12403
|
+
if (!Array.isArray(todos)) {
|
|
12404
|
+
throw new Error("write_todos: todos must be an array");
|
|
12405
|
+
}
|
|
12406
|
+
if (todos.length === 0) {
|
|
12407
|
+
throw new Error("write_todos: todos array cannot be empty");
|
|
12408
|
+
}
|
|
12409
|
+
let inProgressCount = 0;
|
|
12410
|
+
const validatedTodos = todos.map((item, index) => {
|
|
12411
|
+
if (!item || typeof item !== "object") {
|
|
12412
|
+
throw new Error(`write_todos: item at index ${index} must be an object`);
|
|
12413
|
+
}
|
|
12414
|
+
const { description, status } = item;
|
|
12415
|
+
if (typeof description !== "string" || description.trim() === "") {
|
|
12416
|
+
throw new Error(`write_todos: item at index ${index} must have a non-empty description`);
|
|
12417
|
+
}
|
|
12418
|
+
if (typeof status !== "string" || !VALID_STATUSES.includes(status)) {
|
|
12419
|
+
throw new Error(
|
|
12420
|
+
`write_todos: item at index ${index} has invalid status "${status}". Must be one of: ${VALID_STATUSES.join(", ")}`
|
|
12421
|
+
);
|
|
12422
|
+
}
|
|
12423
|
+
if (status === "in_progress") {
|
|
12424
|
+
inProgressCount++;
|
|
12425
|
+
}
|
|
12426
|
+
return {
|
|
12427
|
+
description: description.trim(),
|
|
12428
|
+
status
|
|
12429
|
+
};
|
|
12430
|
+
});
|
|
12431
|
+
if (inProgressCount > 1) {
|
|
12432
|
+
throw new Error(`write_todos: only one task can be 'in_progress' at a time, but found ${inProgressCount}`);
|
|
12433
|
+
}
|
|
12434
|
+
return validatedTodos;
|
|
12435
|
+
}
|
|
12436
|
+
function formatTodosOutput(todos) {
|
|
12437
|
+
const statusEmoji = {
|
|
12438
|
+
pending: "\u2B1C",
|
|
12439
|
+
in_progress: "\u{1F504}",
|
|
12440
|
+
completed: "\u2705",
|
|
12441
|
+
cancelled: "\u274C"
|
|
12442
|
+
};
|
|
12443
|
+
const lines = todos.map((todo, index) => {
|
|
12444
|
+
const emoji = statusEmoji[todo.status];
|
|
12445
|
+
return `${index + 1}. ${emoji} [${todo.status}] ${todo.description}`;
|
|
12446
|
+
});
|
|
12447
|
+
return lines.join("\n");
|
|
12448
|
+
}
|
|
12449
|
+
function createWriteTodosTool(todoStore) {
|
|
12450
|
+
return {
|
|
12451
|
+
toolFn: async (args) => {
|
|
12452
|
+
const params = args;
|
|
12453
|
+
const validatedTodos = validateTodos(params.todos);
|
|
12454
|
+
todoStore.todos = validatedTodos;
|
|
12455
|
+
if (todoStore.onUpdate) {
|
|
12456
|
+
todoStore.onUpdate(validatedTodos);
|
|
12457
|
+
}
|
|
12458
|
+
const output = formatTodosOutput(validatedTodos);
|
|
12459
|
+
return `Todo list updated successfully:
|
|
12460
|
+
|
|
12461
|
+
${output}`;
|
|
12462
|
+
},
|
|
12463
|
+
toolSchema: {
|
|
12464
|
+
name: "write_todos",
|
|
12465
|
+
description: `Create or update a list of subtasks for complex multi-step requests.
|
|
12466
|
+
|
|
12467
|
+
**When to use this tool:**
|
|
12468
|
+
- When handling complex requests that require multiple steps
|
|
12469
|
+
- To break down a large task into smaller, manageable subtasks
|
|
12470
|
+
- To track progress through a multi-step workflow
|
|
12471
|
+
|
|
12472
|
+
**Important guidelines:**
|
|
12473
|
+
- Call this tool early when receiving complex requests
|
|
12474
|
+
- Update the list immediately when starting, completing, or cancelling tasks
|
|
12475
|
+
- Only ONE task should be 'in_progress' at a time
|
|
12476
|
+
- Never batch updates - update as soon as state changes
|
|
12477
|
+
|
|
12478
|
+
**Status values:**
|
|
12479
|
+
- pending: Task not yet started
|
|
12480
|
+
- in_progress: Currently working on this task (only ONE allowed)
|
|
12481
|
+
- completed: Task finished successfully
|
|
12482
|
+
- cancelled: Task will not be completed
|
|
12483
|
+
|
|
12484
|
+
**Example:**
|
|
12485
|
+
If asked to "create a new React component with tests", break it down:
|
|
12486
|
+
1. Create component file \u2192 in_progress
|
|
12487
|
+
2. Add component logic \u2192 pending
|
|
12488
|
+
3. Create test file \u2192 pending
|
|
12489
|
+
4. Write unit tests \u2192 pending`,
|
|
12490
|
+
parameters: {
|
|
12491
|
+
type: "object",
|
|
12492
|
+
properties: {
|
|
12493
|
+
todos: {
|
|
12494
|
+
type: "array",
|
|
12495
|
+
description: "Complete list of todo items. This replaces any existing list. Each item needs a description and status.",
|
|
12496
|
+
items: {
|
|
12497
|
+
type: "object",
|
|
12498
|
+
properties: {
|
|
12499
|
+
description: {
|
|
12500
|
+
type: "string",
|
|
12501
|
+
description: "Clear, concise description of the task"
|
|
12502
|
+
},
|
|
12503
|
+
status: {
|
|
12504
|
+
type: "string",
|
|
12505
|
+
enum: ["pending", "in_progress", "completed", "cancelled"],
|
|
12506
|
+
description: "Current status of the task. Only ONE task can be 'in_progress' at a time."
|
|
12507
|
+
}
|
|
12508
|
+
},
|
|
12509
|
+
required: ["description", "status"]
|
|
12510
|
+
}
|
|
12511
|
+
}
|
|
12512
|
+
},
|
|
12513
|
+
required: ["todos"]
|
|
12514
|
+
}
|
|
12515
|
+
}
|
|
12516
|
+
};
|
|
12517
|
+
}
|
|
12518
|
+
function createTodoStore(onUpdate) {
|
|
12519
|
+
return {
|
|
12520
|
+
todos: [],
|
|
12521
|
+
onUpdate
|
|
12522
|
+
};
|
|
12523
|
+
}
|
|
12524
|
+
|
|
12266
12525
|
// src/index.tsx
|
|
12267
12526
|
process.removeAllListeners("warning");
|
|
12268
12527
|
process.on("warning", (warning) => {
|
|
@@ -12547,7 +12806,9 @@ function CliApp() {
|
|
|
12547
12806
|
subagentConfigs
|
|
12548
12807
|
});
|
|
12549
12808
|
const subagentDelegateTool = createSubagentDelegateTool(orchestrator, newSession.id);
|
|
12550
|
-
const
|
|
12809
|
+
const todoStore = createTodoStore();
|
|
12810
|
+
const writeTodosTool = createWriteTodosTool(todoStore);
|
|
12811
|
+
const allTools = [...b4mTools, ...mcpTools, subagentDelegateTool, writeTodosTool];
|
|
12551
12812
|
console.log(`\u{1F916} Subagent delegation enabled (explore, plan, review)`);
|
|
12552
12813
|
const projectDir = state.configStore.getProjectConfigDir();
|
|
12553
12814
|
const contextResult = await loadContextFiles(projectDir);
|
|
@@ -12587,26 +12848,12 @@ ${contextResult.mergedContent}` : "";
|
|
|
12587
12848
|
const lastIdx = pendingMessages.length - 1;
|
|
12588
12849
|
if (lastIdx >= 0 && pendingMessages[lastIdx].role === "assistant") {
|
|
12589
12850
|
const existingSteps = pendingMessages[lastIdx].metadata?.steps || [];
|
|
12590
|
-
const
|
|
12591
|
-
let truncatedStep = step;
|
|
12592
|
-
if (step.type === "action" && step.metadata?.toolInput) {
|
|
12593
|
-
const inputStr = typeof step.metadata.toolInput === "string" ? step.metadata.toolInput : JSON.stringify(step.metadata.toolInput);
|
|
12594
|
-
if (inputStr.length > MAX_INPUT_LENGTH) {
|
|
12595
|
-
const truncatedInput = inputStr.slice(0, MAX_INPUT_LENGTH) + `... (${inputStr.length - MAX_INPUT_LENGTH} more chars)`;
|
|
12596
|
-
truncatedStep = {
|
|
12597
|
-
...step,
|
|
12598
|
-
metadata: {
|
|
12599
|
-
...step.metadata,
|
|
12600
|
-
toolInput: truncatedInput
|
|
12601
|
-
}
|
|
12602
|
-
};
|
|
12603
|
-
}
|
|
12604
|
-
}
|
|
12851
|
+
const formattedStep = formatStep(step);
|
|
12605
12852
|
updatePendingMessage(lastIdx, {
|
|
12606
12853
|
...pendingMessages[lastIdx],
|
|
12607
12854
|
metadata: {
|
|
12608
12855
|
...pendingMessages[lastIdx].metadata,
|
|
12609
|
-
steps: [...existingSteps,
|
|
12856
|
+
steps: [...existingSteps, formattedStep]
|
|
12610
12857
|
}
|
|
12611
12858
|
});
|
|
12612
12859
|
}
|
|
@@ -12748,7 +12995,7 @@ ${contextResult.mergedContent}` : "";
|
|
|
12748
12995
|
content: result.finalAnswer,
|
|
12749
12996
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12750
12997
|
metadata: {
|
|
12751
|
-
steps: result.steps,
|
|
12998
|
+
steps: result.steps.map(formatStep),
|
|
12752
12999
|
tokenUsage: {
|
|
12753
13000
|
prompt: 0,
|
|
12754
13001
|
completion: 0,
|
|
@@ -12921,7 +13168,7 @@ ${contextResult.mergedContent}` : "";
|
|
|
12921
13168
|
completion: 0,
|
|
12922
13169
|
total: result.completionInfo.totalTokens
|
|
12923
13170
|
},
|
|
12924
|
-
steps: result.steps,
|
|
13171
|
+
steps: result.steps.map(formatStep),
|
|
12925
13172
|
// Complete history: thoughts, actions, observations
|
|
12926
13173
|
permissionDenied
|
|
12927
13174
|
}
|
|
@@ -13027,7 +13274,7 @@ ${output}` : output.trim() || "(no output)",
|
|
|
13027
13274
|
if (!imageStore) {
|
|
13028
13275
|
if (!imageStoreInitPromise.current) {
|
|
13029
13276
|
imageStoreInitPromise.current = (async () => {
|
|
13030
|
-
const { ImageStore: ImageStoreClass } = await import("./ImageStore-
|
|
13277
|
+
const { ImageStore: ImageStoreClass } = await import("./ImageStore-MMUOUPI2.js");
|
|
13031
13278
|
const newImageStore = new ImageStoreClass();
|
|
13032
13279
|
setState((prev) => ({
|
|
13033
13280
|
...prev,
|